@fluidframework/odsp-driver 2.100.0 → 2.101.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/odspDelayLoadedDeltaStream.d.ts.map +1 -1
- package/dist/odspDelayLoadedDeltaStream.js +1 -3
- package/dist/odspDelayLoadedDeltaStream.js.map +1 -1
- package/dist/odspDeltaStorageService.d.ts.map +1 -1
- package/dist/odspDeltaStorageService.js +3 -1
- package/dist/odspDeltaStorageService.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/vroom.d.ts +1 -2
- package/dist/vroom.d.ts.map +1 -1
- package/dist/vroom.js +2 -6
- package/dist/vroom.js.map +1 -1
- package/lib/odspDelayLoadedDeltaStream.d.ts.map +1 -1
- package/lib/odspDelayLoadedDeltaStream.js +1 -3
- package/lib/odspDelayLoadedDeltaStream.js.map +1 -1
- package/lib/odspDeltaStorageService.d.ts.map +1 -1
- package/lib/odspDeltaStorageService.js +3 -1
- package/lib/odspDeltaStorageService.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/vroom.d.ts +1 -2
- package/lib/vroom.d.ts.map +1 -1
- package/lib/vroom.js +2 -6
- package/lib/vroom.js.map +1 -1
- package/package.json +11 -11
- package/src/odspDelayLoadedDeltaStream.ts +0 -5
- package/src/odspDeltaStorageService.ts +12 -7
- package/src/packageVersion.ts +1 -1
- package/src/vroom.ts +1 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @fluidframework/odsp-driver
|
|
2
2
|
|
|
3
|
+
## 2.101.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Remove fully-rolled-out `setSensitivityLabelHeaderPostFix` config gate ([#27261](https://github.com/microsoft/FluidFramework/pull/27261)) [69228c498d8](https://github.com/microsoft/FluidFramework/commit/69228c498d8ef491c565e64a1888e4c4ac71abd2)
|
|
8
|
+
|
|
9
|
+
The `Fluid.Driver.Odsp.setSensitivityLabelHeaderPostFix` config gate is fully rolled out, so it has been removed along with the now-dead conditional code path. The `Prefer: Return-Sensitivity-Labels` header is now always sent on join-session requests, matching the post-rollout production behavior. The `setSensitivityLabelHeader` property emitted on the `JoinSession` telemetry event has also been removed because it would always be `true`.
|
|
10
|
+
|
|
3
11
|
## 2.100.0
|
|
4
12
|
|
|
5
13
|
### Minor Changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"odspDelayLoadedDeltaStream.d.ts","sourceRoot":"","sources":["../src/odspDelayLoadedDeltaStream.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,KAAK,EACX,wBAAwB,EACxB,wBAAwB,EACxB,YAAY,EAEZ,yBAAyB,EAEzB,MAAM,6CAA6C,CAAC;AAMrD,OAAO,EACN,KAAK,iBAAiB,EAEtB,KAAK,gBAAgB,EAGrB,KAAK,+BAA+B,EAEpC,KAAK,iBAAiB,EACtB,MAAM,kDAAkD,CAAC;AAC1D,OAAO,EAEN,KAAK,iBAAiB,EAEtB,MAAM,0CAA0C,CAAC;AAIlD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAS/E;;;GAGG;AACH,qBAAa,0BAA0B;aAkCrB,eAAe,EAAE,gBAAgB;IAC1C,QAAQ,EAAE,wBAAwB;IACzC,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAGlC,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IACtC,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAC;IA5C3C,OAAO,CAAC,uBAAuB,CAA4C;IAE3E,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IAExC,OAAO,CAAC,iBAAiB,CAAC,CAA8B;IAExD,OAAO,CAAC,+BAA+B,CAAqB;IAE5D,OAAO,CAAC,sBAAsB,CAAQ;IAMtC,OAAO,CAAC,oBAAoB,CAAc;IAE1C;;;;;;;;;;;;;;OAcG;gBAEc,eAAe,EAAE,gBAAgB,EAC1C,QAAQ,EAAE,wBAAwB,EACxB,aAAa,EAAE,+BAA+B,EAC9C,iBAAiB,EAC/B,CAAC,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,GACxD,SAAS,EACK,EAAE,EAAE,iBAAiB,EACrB,KAAK,EAAE,UAAU,EACjB,UAAU,EAAE,iBAAiB,EAC7B,YAAY,EAAE,YAAY,EAC1B,WAAW,EAAE,CAAC,GAAG,EAAE,yBAAyB,EAAE,KAAK,IAAI,EACvD,qBAAqB,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,EACjE,wBAAwB,CAAC,oBAAQ;IAKnD,IAAW,WAAW,IAAI,YAAY,CAErC;IAED,IAAW,sBAAsB,IAAI,2BAA2B,GAAG,SAAS,CAE3E;IAED,IAAW,8BAA8B,IAAI,MAAM,GAAG,SAAS,CAE9D;IAED;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAa/B;;;;OAIG;IACU,oBAAoB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAmIrF,OAAO,CAAC,QAAQ,CAAC,aAAa,CAoB5B;IAEF,OAAO,CAAC,qBAAqB;YAOf,0BAA0B;YA4C1B,WAAW;YAkEX,eAAe;
|
|
1
|
+
{"version":3,"file":"odspDelayLoadedDeltaStream.d.ts","sourceRoot":"","sources":["../src/odspDelayLoadedDeltaStream.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,KAAK,EACX,wBAAwB,EACxB,wBAAwB,EACxB,YAAY,EAEZ,yBAAyB,EAEzB,MAAM,6CAA6C,CAAC;AAMrD,OAAO,EACN,KAAK,iBAAiB,EAEtB,KAAK,gBAAgB,EAGrB,KAAK,+BAA+B,EAEpC,KAAK,iBAAiB,EACtB,MAAM,kDAAkD,CAAC;AAC1D,OAAO,EAEN,KAAK,iBAAiB,EAEtB,MAAM,0CAA0C,CAAC;AAIlD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAS/E;;;GAGG;AACH,qBAAa,0BAA0B;aAkCrB,eAAe,EAAE,gBAAgB;IAC1C,QAAQ,EAAE,wBAAwB;IACzC,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAGlC,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IACtC,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAC;IA5C3C,OAAO,CAAC,uBAAuB,CAA4C;IAE3E,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IAExC,OAAO,CAAC,iBAAiB,CAAC,CAA8B;IAExD,OAAO,CAAC,+BAA+B,CAAqB;IAE5D,OAAO,CAAC,sBAAsB,CAAQ;IAMtC,OAAO,CAAC,oBAAoB,CAAc;IAE1C;;;;;;;;;;;;;;OAcG;gBAEc,eAAe,EAAE,gBAAgB,EAC1C,QAAQ,EAAE,wBAAwB,EACxB,aAAa,EAAE,+BAA+B,EAC9C,iBAAiB,EAC/B,CAAC,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,GACxD,SAAS,EACK,EAAE,EAAE,iBAAiB,EACrB,KAAK,EAAE,UAAU,EACjB,UAAU,EAAE,iBAAiB,EAC7B,YAAY,EAAE,YAAY,EAC1B,WAAW,EAAE,CAAC,GAAG,EAAE,yBAAyB,EAAE,KAAK,IAAI,EACvD,qBAAqB,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,EACjE,wBAAwB,CAAC,oBAAQ;IAKnD,IAAW,WAAW,IAAI,YAAY,CAErC;IAED,IAAW,sBAAsB,IAAI,2BAA2B,GAAG,SAAS,CAE3E;IAED,IAAW,8BAA8B,IAAI,MAAM,GAAG,SAAS,CAE9D;IAED;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAa/B;;;;OAIG;IACU,oBAAoB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAmIrF,OAAO,CAAC,QAAQ,CAAC,aAAa,CAoB5B;IAEF,OAAO,CAAC,qBAAqB;YAOf,0BAA0B;YA4C1B,WAAW;YAkEX,eAAe;IAkG7B,OAAO,CAAC,+BAA+B;IAgBvC,OAAO,CAAC,gCAAgC;IAQxC;;;;;;;;;OASG;YACW,qBAAqB;IAkC5B,OAAO,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,IAAI;CAKrC"}
|
|
@@ -280,10 +280,8 @@ class OdspDelayLoadedDeltaStream {
|
|
|
280
280
|
}
|
|
281
281
|
async joinSessionCore(requestSocketToken, options, isRefreshingJoinSession, displayName) {
|
|
282
282
|
const disableJoinSessionRefresh = this.mc.config.getBoolean("Fluid.Driver.Odsp.disableJoinSessionRefresh");
|
|
283
|
-
// Previous gate "Fluid.Driver.Odsp.setSensitivityLabelHeader" was removed because it was sensitive to a timestamp-related bug that was fixed by PR #26318; using this new gate ensures that the bug fix is present.
|
|
284
|
-
const setSensitivityLabelHeader = this.mc.config.getBoolean("Fluid.Driver.Odsp.setSensitivityLabelHeaderPostFix");
|
|
285
283
|
const executeFetch = async () => {
|
|
286
|
-
const joinSessionResponse = await (0, vroom_js_1.fetchJoinSession)(this.odspResolvedUrl, "opStream/joinSession", "POST", this.mc.logger, this.getAuthHeader, this.epochTracker, requestSocketToken, options, disableJoinSessionRefresh,
|
|
284
|
+
const joinSessionResponse = await (0, vroom_js_1.fetchJoinSession)(this.odspResolvedUrl, "opStream/joinSession", "POST", this.mc.logger, this.getAuthHeader, this.epochTracker, requestSocketToken, options, disableJoinSessionRefresh, isRefreshingJoinSession, displayName);
|
|
287
285
|
// Emit event only in case it is fetched from the network.
|
|
288
286
|
if (joinSessionResponse.sensitivityLabelsInfo !== undefined) {
|
|
289
287
|
this.emitSensitivityLabelUpdateEvent(joinSessionResponse.sensitivityLabelsInfo);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"odspDelayLoadedDeltaStream.js","sourceRoot":"","sources":["../src/odspDelayLoadedDeltaStream.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { performanceNow } from \"@fluid-internal/client-utils\";\nimport type { ISignalEnvelope } from \"@fluidframework/core-interfaces/internal\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type { IClient } from \"@fluidframework/driver-definitions\";\nimport type {\n\tIDocumentDeltaConnection,\n\tIDocumentServicePolicies,\n\tIResolvedUrl,\n\tIAnyDriverError,\n\tISequencedDocumentMessage,\n\tISignalMessage,\n} from \"@fluidframework/driver-definitions/internal\";\nimport {\n\tDeltaStreamConnectionForbiddenError,\n\tNonRetryableError,\n} from \"@fluidframework/driver-utils/internal\";\nimport { hasFacetCodes } from \"@fluidframework/odsp-doclib-utils/internal\";\nimport {\n\ttype HostStoragePolicy,\n\ttype IOdspError,\n\ttype IOdspResolvedUrl,\n\ttype ISocketStorageDiscovery,\n\ttype ISensitivityLabelsInfo,\n\ttype InstrumentedStorageTokenFetcher,\n\tOdspErrorTypes,\n\ttype TokenFetchOptions,\n} from \"@fluidframework/odsp-driver-definitions/internal\";\nimport {\n\ttype IFluidErrorBase,\n\ttype MonitoringContext,\n\tnormalizeError,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport { v4 as uuid } from \"uuid\";\n\nimport { policyLabelsUpdatesSignalType } from \"./contracts.js\";\nimport type { EpochTracker } from \"./epochTracker.js\";\nimport type { IOdspCache } from \"./odspCache.js\";\nimport { OdspDocumentDeltaConnection } from \"./odspDocumentDeltaConnection.js\";\nimport {\n\ttype TokenFetchOptionsEx,\n\tgetJoinSessionCacheKey,\n\tgetWithRetryForTokenRefresh,\n} from \"./odspUtils.js\";\nimport { pkgVersion as driverVersion } from \"./packageVersion.js\";\nimport { fetchJoinSession } from \"./vroom.js\";\n\n/**\n * This OdspDelayLoadedDeltaStream is used by OdspDocumentService.ts to delay load the delta connection\n * as they are not on critical path of loading a container.\n */\nexport class OdspDelayLoadedDeltaStream {\n\t// Timer which runs and executes the join session call after intervals.\n\tprivate joinSessionRefreshTimer: ReturnType<typeof setTimeout> | undefined;\n\n\tprivate readonly joinSessionKey: string;\n\n\tprivate currentConnection?: OdspDocumentDeltaConnection;\n\n\tprivate _relayServiceTenantAndSessionId: string | undefined;\n\n\tprivate firstConnectionAttempt = true;\n\n\t// Tracks the time at which the Policy Labels were updated the last time. This is used to resolve race conditions\n\t// between label updates from the join session and the Fluid signals and they could have same or different timestamps.\n\t// So this timestamp is updated with timestamp from the service/signals with the most recent timestamp. We could also\n\t// receive stale data from join session as that call is made at intervals, so we need to update with only most recent data.\n\tprivate labelUpdateTimestamp: number = -1;\n\n\t/**\n\t * @param odspResolvedUrl - resolved url identifying document that will be managed by this service instance.\n\t * @param policies - Document service policies.\n\t * @param getAuthHeader - function that can provide the Authentication header value. This is is also referred to as\n\t * the \"Vroom\" token in SPO.\n\t * @param getWebsocketToken - function that can provide a token for accessing the web socket. This is also referred\n\t * to as the \"Push\" token in SPO. If undefined then websocket token is expected to be returned with joinSession\n\t * response payload.\n\t * @param mc - a logger that can capture performance and diagnostic information\n\t * @param cache - This caches response for joinSession.\n\t * @param hostPolicy - host constructed policy which customizes service behavior.\n\t * @param epochTracker - This helper class which adds epoch to backend calls made by this service instance.\n\t * @param opsReceived - To register the ops received through socket.\n\t * @param socketReferenceKeyPrefix - (optional) prefix to isolate socket reuse cache\n\t */\n\tpublic constructor(\n\t\tpublic readonly odspResolvedUrl: IOdspResolvedUrl,\n\t\tpublic policies: IDocumentServicePolicies,\n\t\tprivate readonly getAuthHeader: InstrumentedStorageTokenFetcher,\n\t\tprivate readonly getWebsocketToken:\n\t\t\t| ((options: TokenFetchOptions) => Promise<string | null>)\n\t\t\t| undefined,\n\t\tprivate readonly mc: MonitoringContext,\n\t\tprivate readonly cache: IOdspCache,\n\t\tprivate readonly hostPolicy: HostStoragePolicy,\n\t\tprivate readonly epochTracker: EpochTracker,\n\t\tprivate readonly opsReceived: (ops: ISequencedDocumentMessage[]) => void,\n\t\tprivate readonly metadataUpdateHandler: (metadata: Record<string, string>) => void,\n\t\tprivate readonly socketReferenceKeyPrefix?: string,\n\t) {\n\t\tthis.joinSessionKey = getJoinSessionCacheKey(this.odspResolvedUrl);\n\t}\n\n\tpublic get resolvedUrl(): IResolvedUrl {\n\t\treturn this.odspResolvedUrl;\n\t}\n\n\tpublic get currentDeltaConnection(): OdspDocumentDeltaConnection | undefined {\n\t\treturn this.currentConnection;\n\t}\n\n\tpublic get relayServiceTenantAndSessionId(): string | undefined {\n\t\treturn this._relayServiceTenantAndSessionId;\n\t}\n\n\t/**\n\t * Annotate the given error indicating which connection step failed\n\t */\n\tprivate annotateConnectionError(\n\t\terror: unknown,\n\t\tfailedConnectionStep: string,\n\t\tseparateTokenRequest: boolean,\n\t): IFluidErrorBase {\n\t\treturn normalizeError(error, {\n\t\t\tprops: {\n\t\t\t\tfailedConnectionStep,\n\t\t\t\tseparateTokenRequest,\n\t\t\t},\n\t\t});\n\t}\n\n\t/**\n\t * Connects to a delta stream endpoint for emitting ops.\n\t *\n\t * @returns returns the document delta stream service for onedrive/sharepoint driver.\n\t */\n\tpublic async connectToDeltaStream(client: IClient): Promise<IDocumentDeltaConnection> {\n\t\tassert(\n\t\t\tthis.currentConnection === undefined,\n\t\t\t0x4ad /* Should not be called when connection is already present! */,\n\t\t);\n\t\t// Attempt to connect twice, in case we used expired token.\n\t\treturn getWithRetryForTokenRefresh<IDocumentDeltaConnection>(async (options) => {\n\t\t\t// Presence of getWebsocketToken callback dictates whether callback is used for fetching\n\t\t\t// websocket token or whether it is returned with joinSession response payload\n\t\t\tconst requestWebsocketTokenFromJoinSession = this.getWebsocketToken === undefined;\n\t\t\tconst websocketTokenPromise = requestWebsocketTokenFromJoinSession\n\t\t\t\t? // eslint-disable-next-line unicorn/no-null\n\t\t\t\t\tPromise.resolve(null)\n\t\t\t\t: this.getWebsocketToken(options);\n\n\t\t\tconst annotateAndRethrowConnectionError = (step: string) => (error: unknown) => {\n\t\t\t\tthrow this.annotateConnectionError(error, step, !requestWebsocketTokenFromJoinSession);\n\t\t\t};\n\n\t\t\t// Log telemetry for join session attempt\n\t\t\tif (this.firstConnectionAttempt) {\n\t\t\t\tthis.mc.logger.sendTelemetryEvent({\n\t\t\t\t\teventName: \"FirstJoinSessionAttemptDetails\",\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\trequestWebsocketToken: requestWebsocketTokenFromJoinSession,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst joinSessionPromise = this.joinSession(\n\t\t\t\trequestWebsocketTokenFromJoinSession,\n\t\t\t\toptions,\n\t\t\t\tfalse /* isRefreshingJoinSession */,\n\t\t\t\tundefined /* clientId */,\n\t\t\t\tthis.hostPolicy.sessionOptions?.displayName,\n\t\t\t);\n\t\t\tconst [websocketEndpoint, websocketToken] = await Promise.all([\n\t\t\t\tjoinSessionPromise.catch(annotateAndRethrowConnectionError(\"joinSession\")),\n\t\t\t\twebsocketTokenPromise.catch(annotateAndRethrowConnectionError(\"getWebsocketToken\")),\n\t\t\t]);\n\n\t\t\t// eslint-disable-next-line unicorn/no-null\n\t\t\tconst finalWebsocketToken = websocketToken ?? websocketEndpoint.socketToken ?? null;\n\t\t\tif (finalWebsocketToken === null) {\n\t\t\t\tthrow this.annotateConnectionError(\n\t\t\t\t\tnew NonRetryableError(\"Websocket token is null\", OdspErrorTypes.fetchTokenError, {\n\t\t\t\t\t\tdriverVersion,\n\t\t\t\t\t}),\n\t\t\t\t\t\"getWebsocketToken\",\n\t\t\t\t\t!requestWebsocketTokenFromJoinSession,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (websocketEndpoint.sensitivityLabelsInfo !== undefined) {\n\t\t\t\tthis.emitSensitivityLabelUpdateEvent(websocketEndpoint.sensitivityLabelsInfo);\n\t\t\t}\n\n\t\t\tconst connectionId = uuid();\n\t\t\tif (this.firstConnectionAttempt) {\n\t\t\t\tthis.firstConnectionAttempt = false;\n\t\t\t\tthis.mc.logger.sendTelemetryEvent({\n\t\t\t\t\teventName: \"FirstConnectionAttemptDetails\",\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\tconnectionId,\n\t\t\t\t\t\ttenantId: websocketEndpoint.tenantId,\n\t\t\t\t\t\tdocumentId: websocketEndpoint.id,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst connection = await this.createDeltaConnection(\n\t\t\t\t\twebsocketEndpoint.tenantId,\n\t\t\t\t\twebsocketEndpoint.id,\n\t\t\t\t\tfinalWebsocketToken,\n\t\t\t\t\tclient,\n\t\t\t\t\twebsocketEndpoint.deltaStreamSocketUrl,\n\t\t\t\t\tconnectionId,\n\t\t\t\t);\n\t\t\t\tconnection.on(\"op\", (documentId, ops: ISequencedDocumentMessage[]) => {\n\t\t\t\t\tthis.opsReceived(ops);\n\t\t\t\t});\n\t\t\t\tconnection.on(\"signal\", this.signalHandler);\n\t\t\t\t// Also process the initial signals\n\t\t\t\tthis.signalHandler(connection.initialSignals);\n\t\t\t\t// On disconnect with 401/403 error code, we can just clear the joinSession cache as we will again\n\t\t\t\t// get the auth error on reconnecting and face latency.\n\t\t\t\tconnection.once(\"disconnect\", (error: unknown) => {\n\t\t\t\t\t// Clear the join session refresh timer so that it can be restarted on reconnection.\n\t\t\t\t\tthis.clearJoinSessionTimer();\n\t\t\t\t\tif (\n\t\t\t\t\t\ttypeof error === \"object\" &&\n\t\t\t\t\t\terror !== null &&\n\t\t\t\t\t\t(error as Partial<IOdspError>).errorType === OdspErrorTypes.authorizationError\n\t\t\t\t\t) {\n\t\t\t\t\t\tthis.cache.sessionJoinCache.remove(this.joinSessionKey);\n\t\t\t\t\t}\n\t\t\t\t\t// If we hit this assert, it means that \"disconnect\" event is emitted before the connection went through\n\t\t\t\t\t// dispose flow which is not correct and could lead to a bunch of errors.\n\t\t\t\t\tassert(connection.disposed, 0x4ae /* Connection should be disposed by now */);\n\t\t\t\t\tthis.currentConnection = undefined;\n\t\t\t\t});\n\t\t\t\tthis.currentConnection = connection;\n\t\t\t\treturn connection;\n\t\t\t} catch (error) {\n\t\t\t\t// Remove join session information from cache only if it is an error is from socket event connect_document_error.\n\t\t\t\t// Otherwise keep it in cache so that this session can be re-used after disconnection.\n\t\t\t\t// Also keeping an undefined check here to account for any unknown code path that is unable to stamp the value as in that case also\n\t\t\t\t// it is safer to clear join session cache and start over.\n\t\t\t\tif (\n\t\t\t\t\terror &&\n\t\t\t\t\ttypeof error === \"object\" &&\n\t\t\t\t\t((error as IAnyDriverError).scenarioName === \"connect_document_error\" ||\n\t\t\t\t\t\t(error as IAnyDriverError).scenarioName === undefined)\n\t\t\t\t) {\n\t\t\t\t\tthis.clearJoinSessionTimer();\n\t\t\t\t\tthis.cache.sessionJoinCache.remove(this.joinSessionKey);\n\t\t\t\t}\n\t\t\t\tconst normalizedError = this.annotateConnectionError(\n\t\t\t\t\terror,\n\t\t\t\t\t\"createDeltaConnection\",\n\t\t\t\t\t!requestWebsocketTokenFromJoinSession,\n\t\t\t\t);\n\t\t\t\tif (typeof error === \"object\" && error !== null) {\n\t\t\t\t\tnormalizedError.addTelemetryProperties({\n\t\t\t\t\t\tsocketDocumentId: websocketEndpoint.id,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tthrow normalizedError;\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate readonly signalHandler = (signalsArg: ISignalMessage | ISignalMessage[]): void => {\n\t\tconst signals = Array.isArray(signalsArg) ? signalsArg : [signalsArg];\n\t\tfor (const signal of signals) {\n\t\t\t// Make sure it is not for a specific client as `PolicyLabelsUpdate` is meant for all clients.\n\t\t\tif (signal.clientId === null) {\n\t\t\t\t// We could have some issues/irregularities in parsing signals, so put it in try/catch block\n\t\t\t\t// and ignore the error as we can have labels update later on through join session response.\n\t\t\t\tlet envelope: ISignalEnvelope | undefined;\n\t\t\t\ttry {\n\t\t\t\t\tenvelope = JSON.parse(signal.content as string) as ISignalEnvelope;\n\t\t\t\t} catch {\n\t\t\t\t\t// Drop error\n\t\t\t\t}\n\t\t\t\tif (envelope?.contents?.type === policyLabelsUpdatesSignalType) {\n\t\t\t\t\tthis.emitSensitivityLabelUpdateEvent(\n\t\t\t\t\t\tenvelope.contents.content as ISensitivityLabelsInfo,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\tprivate clearJoinSessionTimer(): void {\n\t\tif (this.joinSessionRefreshTimer !== undefined) {\n\t\t\tclearTimeout(this.joinSessionRefreshTimer);\n\t\t\tthis.joinSessionRefreshTimer = undefined;\n\t\t}\n\t}\n\n\tprivate async scheduleJoinSessionRefresh(\n\t\tdelta: number,\n\t\trequestSocketToken: boolean,\n\t\tclientId: string | undefined,\n\t\tdisplayName: string | undefined,\n\t): Promise<void> {\n\t\tif (this.joinSessionRefreshTimer !== undefined) {\n\t\t\tthis.clearJoinSessionTimer();\n\t\t\t// TODO: use a stronger type\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n\t\t\tconst originalStackTraceLimit = (Error as any).stackTraceLimit;\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n\t\t\t(Error as any).stackTraceLimit = 50;\n\t\t\tthis.mc.logger.sendTelemetryEvent(\n\t\t\t\t{\n\t\t\t\t\teventName: \"DuplicateJoinSessionRefresh\",\n\t\t\t\t},\n\t\t\t\tnew Error(\"DuplicateJoinSessionRefresh\"),\n\t\t\t);\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n\t\t\t(Error as any).stackTraceLimit = originalStackTraceLimit;\n\t\t}\n\n\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\tthis.joinSessionRefreshTimer = setTimeout(() => {\n\t\t\t\tthis.clearJoinSessionTimer();\n\t\t\t\t// Clear the timer as it is going to be scheduled again as part of refreshing join session.\n\t\t\t\tgetWithRetryForTokenRefresh(async (options) => {\n\t\t\t\t\tawait this.joinSession(\n\t\t\t\t\t\trequestSocketToken,\n\t\t\t\t\t\toptions,\n\t\t\t\t\t\ttrue /* isRefreshingJoinSession */,\n\t\t\t\t\t\tclientId,\n\t\t\t\t\t\tdisplayName,\n\t\t\t\t\t);\n\t\t\t\t\tresolve();\n\t\t\t\t}).catch((error) => {\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors\n\t\t\t\t\treject(error);\n\t\t\t\t});\n\t\t\t}, delta);\n\t\t});\n\t}\n\n\tprivate async joinSession(\n\t\trequestSocketToken: boolean,\n\t\toptions: TokenFetchOptionsEx,\n\t\tisRefreshingJoinSession: boolean,\n\t\tclientId: string | undefined,\n\t\tdisplayName: string | undefined,\n\t): Promise<ISocketStorageDiscovery> {\n\t\t// If this call is to refresh the join session for the current connection but we are already disconnected in\n\t\t// the meantime or disconnected and then reconnected then do not make the call. However, we should not have\n\t\t// come here if that is the case because timer should have been disposed, but due to race condition with the\n\t\t// timer we should not make the call and throw error.\n\t\tif (\n\t\t\tisRefreshingJoinSession &&\n\t\t\t(this.currentConnection === undefined ||\n\t\t\t\t(clientId !== undefined && this.currentConnection.clientId !== clientId))\n\t\t) {\n\t\t\tthis.clearJoinSessionTimer();\n\t\t\tthrow new NonRetryableError(\n\t\t\t\t\"JoinSessionRefreshTimerNotCancelled\",\n\t\t\t\tOdspErrorTypes.genericError,\n\t\t\t\t{\n\t\t\t\t\tdriverVersion,\n\t\t\t\t\tdetails: JSON.stringify({\n\t\t\t\t\t\tschedulerClientId: clientId,\n\t\t\t\t\t\tcurrentClientId: this.currentConnection?.clientId,\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t\tconst response = await this.joinSessionCore(\n\t\t\trequestSocketToken,\n\t\t\toptions,\n\t\t\tisRefreshingJoinSession,\n\t\t\tdisplayName,\n\t\t).catch((error) => {\n\t\t\tif (hasFacetCodes(error) && error.facetCodes !== undefined) {\n\t\t\t\tfor (const code of error.facetCodes) {\n\t\t\t\t\tswitch (code) {\n\t\t\t\t\t\tcase \"sessionForbidden\":\n\t\t\t\t\t\tcase \"sessionForbiddenOnPreservedFiles\":\n\t\t\t\t\t\tcase \"sessionForbiddenOnModerationEnabledLibrary\":\n\t\t\t\t\t\tcase \"sessionForbiddenOnRequireCheckout\":\n\t\t\t\t\t\tcase \"sessionForbiddenOnCheckoutFile\":\n\t\t\t\t\t\tcase \"sessionForbiddenOnInvisibleMinorVersion\": {\n\t\t\t\t\t\t\t// This document can only be opened in storage-only mode.\n\t\t\t\t\t\t\t// DeltaManager will recognize this error\n\t\t\t\t\t\t\t// and load without a delta stream connection.\n\t\t\t\t\t\t\tthis.policies = { ...this.policies, storageOnly: true };\n\t\t\t\t\t\t\tthrow new DeltaStreamConnectionForbiddenError(\n\t\t\t\t\t\t\t\t`Storage-only due to ${code}`,\n\t\t\t\t\t\t\t\t{ driverVersion },\n\t\t\t\t\t\t\t\tcode,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdefault: {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow error;\n\t\t});\n\t\tthis._relayServiceTenantAndSessionId = `${response.tenantId}/${response.id}`;\n\t\treturn response;\n\t}\n\n\tprivate async joinSessionCore(\n\t\trequestSocketToken: boolean,\n\t\toptions: TokenFetchOptionsEx,\n\t\tisRefreshingJoinSession: boolean,\n\t\tdisplayName: string | undefined,\n\t): Promise<ISocketStorageDiscovery> {\n\t\tconst disableJoinSessionRefresh = this.mc.config.getBoolean(\n\t\t\t\"Fluid.Driver.Odsp.disableJoinSessionRefresh\",\n\t\t);\n\t\t// Previous gate \"Fluid.Driver.Odsp.setSensitivityLabelHeader\" was removed because it was sensitive to a timestamp-related bug that was fixed by PR #26318; using this new gate ensures that the bug fix is present.\n\t\tconst setSensitivityLabelHeader = this.mc.config.getBoolean(\n\t\t\t\"Fluid.Driver.Odsp.setSensitivityLabelHeaderPostFix\",\n\t\t);\n\t\tconst executeFetch = async (): Promise<{\n\t\t\tentryTime: number;\n\t\t\tjoinSessionResponse: ISocketStorageDiscovery;\n\t\t}> => {\n\t\t\tconst joinSessionResponse = await fetchJoinSession(\n\t\t\t\tthis.odspResolvedUrl,\n\t\t\t\t\"opStream/joinSession\",\n\t\t\t\t\"POST\",\n\t\t\t\tthis.mc.logger,\n\t\t\t\tthis.getAuthHeader,\n\t\t\t\tthis.epochTracker,\n\t\t\t\trequestSocketToken,\n\t\t\t\toptions,\n\t\t\t\tdisableJoinSessionRefresh,\n\t\t\t\tsetSensitivityLabelHeader,\n\t\t\t\tisRefreshingJoinSession,\n\t\t\t\tdisplayName,\n\t\t\t);\n\t\t\t// Emit event only in case it is fetched from the network.\n\t\t\tif (joinSessionResponse.sensitivityLabelsInfo !== undefined) {\n\t\t\t\tthis.emitSensitivityLabelUpdateEvent(joinSessionResponse.sensitivityLabelsInfo);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tentryTime: Date.now(),\n\t\t\t\tjoinSessionResponse,\n\t\t\t};\n\t\t};\n\n\t\tconst getResponseAndRefreshAfterDeltaMs = async (): Promise<{\n\t\t\trefreshAfterDeltaMs: number;\n\t\t\tentryTime: number;\n\t\t\tjoinSessionResponse: ISocketStorageDiscovery;\n\t\t}> => {\n\t\t\tconst _response = await this.cache.sessionJoinCache.addOrGet(\n\t\t\t\tthis.joinSessionKey,\n\t\t\t\texecuteFetch,\n\t\t\t);\n\t\t\t// If the response does not contain refreshSessionDurationSeconds, then treat it as old flow and let the\n\t\t\t// cache entry to be treated as expired after 1 hour.\n\t\t\t_response.joinSessionResponse.refreshSessionDurationSeconds =\n\t\t\t\t_response.joinSessionResponse.refreshSessionDurationSeconds ?? 3600;\n\t\t\treturn {\n\t\t\t\t..._response,\n\t\t\t\trefreshAfterDeltaMs: this.calculateJoinSessionRefreshDelta(\n\t\t\t\t\t_response.entryTime,\n\t\t\t\t\t_response.joinSessionResponse.refreshSessionDurationSeconds,\n\t\t\t\t),\n\t\t\t};\n\t\t};\n\t\tlet response = await getResponseAndRefreshAfterDeltaMs();\n\t\t// This means that the cached entry has expired(This should not be possible if the response is fetched\n\t\t// from the network call). In this case we remove the cached entry and fetch the new response.\n\t\tif (response.refreshAfterDeltaMs <= 0) {\n\t\t\tthis.cache.sessionJoinCache.remove(this.joinSessionKey);\n\t\t\tresponse = await getResponseAndRefreshAfterDeltaMs();\n\t\t}\n\t\tif (!disableJoinSessionRefresh) {\n\t\t\tconst props = {\n\t\t\t\tentryTime: response.entryTime,\n\t\t\t\trefreshSessionDurationSeconds:\n\t\t\t\t\tresponse.joinSessionResponse.refreshSessionDurationSeconds,\n\t\t\t\trefreshAfterDeltaMs: response.refreshAfterDeltaMs,\n\t\t\t};\n\t\t\tif (response.refreshAfterDeltaMs > 0) {\n\t\t\t\tthis.scheduleJoinSessionRefresh(\n\t\t\t\t\tresponse.refreshAfterDeltaMs,\n\t\t\t\t\trequestSocketToken,\n\t\t\t\t\tthis.currentConnection?.clientId,\n\t\t\t\t\tdisplayName,\n\t\t\t\t).catch((error) => {\n\t\t\t\t\t// Log the error and do nothing as the reconnection would fetch the join session.\n\t\t\t\t\tthis.mc.logger.sendTelemetryEvent(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\teventName: \"JoinSessionRefreshError\",\n\t\t\t\t\t\t\tdetails: JSON.stringify(props),\n\t\t\t\t\t\t},\n\t\t\t\t\t\terror,\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t// Logging just for informational purposes to help with debugging as this is a new feature.\n\t\t\t\tthis.mc.logger.sendTelemetryEvent({\n\t\t\t\t\teventName: \"JoinSessionRefreshNotScheduled\",\n\t\t\t\t\tdetails: JSON.stringify(props),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn response.joinSessionResponse;\n\t}\n\n\tprivate emitSensitivityLabelUpdateEvent(\n\t\tsensitivityLabelsInfo: ISensitivityLabelsInfo,\n\t): void {\n\t\tconst createdTimestamp = sensitivityLabelsInfo.timestamp;\n\t\tassert(\n\t\t\ttypeof createdTimestamp === \"number\" && createdTimestamp > 0,\n\t\t\t0x8e0 /* time should be a positive number */,\n\t\t);\n\t\tif (createdTimestamp > this.labelUpdateTimestamp) {\n\t\t\tthis.labelUpdateTimestamp = createdTimestamp;\n\t\t\tthis.metadataUpdateHandler({\n\t\t\t\tsensitivityLabelsInfo: JSON.stringify(sensitivityLabelsInfo),\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate calculateJoinSessionRefreshDelta(\n\t\tresponseFetchTime: number,\n\t\trefreshSessionDurationSeconds: number,\n\t): number {\n\t\t// 30 seconds is buffer time to refresh the session.\n\t\treturn responseFetchTime + (refreshSessionDurationSeconds * 1000 - 30000) - Date.now();\n\t}\n\n\t/**\n\t * Creates a connection to the given delta stream endpoint\n\t *\n\t * @param tenantId - the ID of the tenant\n\t * @param documentId - document ID\n\t * @param token - authorization token for delta service\n\t * @param client - information about the client\n\t * @param webSocketUrl - websocket URL\n\t * @param connectionId - connection ID for the connection\n\t */\n\tprivate async createDeltaConnection(\n\t\ttenantId: string,\n\t\tdocumentId: string,\n\t\ttoken: string | null,\n\t\tclient: IClient,\n\t\twebSocketUrl: string,\n\t\tconnectionId: string,\n\t): Promise<OdspDocumentDeltaConnection> {\n\t\tconst startTime = performanceNow();\n\t\tconst connection = await OdspDocumentDeltaConnection.create(\n\t\t\ttenantId,\n\t\t\tdocumentId,\n\t\t\ttoken,\n\t\t\tclient,\n\t\t\twebSocketUrl,\n\t\t\tthis.mc.logger,\n\t\t\t60000,\n\t\t\tthis.epochTracker,\n\t\t\tthis.socketReferenceKeyPrefix,\n\t\t\tconnectionId,\n\t\t);\n\t\tconst duration = performanceNow() - startTime;\n\t\t// This event happens rather often, so it adds up to cost of telemetry.\n\t\t// Given that most reconnects result in reusing socket and happen very quickly,\n\t\t// report event only if it took longer than threshold.\n\t\tif (duration >= 2000) {\n\t\t\tthis.mc.logger.sendPerformanceEvent({\n\t\t\t\teventName: \"ConnectionSuccess\",\n\t\t\t\tduration,\n\t\t\t});\n\t\t}\n\t\treturn connection;\n\t}\n\n\tpublic dispose(error?: unknown): void {\n\t\tthis.clearJoinSessionTimer();\n\t\tthis.currentConnection?.dispose();\n\t\tthis.currentConnection = undefined;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"odspDelayLoadedDeltaStream.js","sourceRoot":"","sources":["../src/odspDelayLoadedDeltaStream.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { performanceNow } from \"@fluid-internal/client-utils\";\nimport type { ISignalEnvelope } from \"@fluidframework/core-interfaces/internal\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type { IClient } from \"@fluidframework/driver-definitions\";\nimport type {\n\tIDocumentDeltaConnection,\n\tIDocumentServicePolicies,\n\tIResolvedUrl,\n\tIAnyDriverError,\n\tISequencedDocumentMessage,\n\tISignalMessage,\n} from \"@fluidframework/driver-definitions/internal\";\nimport {\n\tDeltaStreamConnectionForbiddenError,\n\tNonRetryableError,\n} from \"@fluidframework/driver-utils/internal\";\nimport { hasFacetCodes } from \"@fluidframework/odsp-doclib-utils/internal\";\nimport {\n\ttype HostStoragePolicy,\n\ttype IOdspError,\n\ttype IOdspResolvedUrl,\n\ttype ISocketStorageDiscovery,\n\ttype ISensitivityLabelsInfo,\n\ttype InstrumentedStorageTokenFetcher,\n\tOdspErrorTypes,\n\ttype TokenFetchOptions,\n} from \"@fluidframework/odsp-driver-definitions/internal\";\nimport {\n\ttype IFluidErrorBase,\n\ttype MonitoringContext,\n\tnormalizeError,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport { v4 as uuid } from \"uuid\";\n\nimport { policyLabelsUpdatesSignalType } from \"./contracts.js\";\nimport type { EpochTracker } from \"./epochTracker.js\";\nimport type { IOdspCache } from \"./odspCache.js\";\nimport { OdspDocumentDeltaConnection } from \"./odspDocumentDeltaConnection.js\";\nimport {\n\ttype TokenFetchOptionsEx,\n\tgetJoinSessionCacheKey,\n\tgetWithRetryForTokenRefresh,\n} from \"./odspUtils.js\";\nimport { pkgVersion as driverVersion } from \"./packageVersion.js\";\nimport { fetchJoinSession } from \"./vroom.js\";\n\n/**\n * This OdspDelayLoadedDeltaStream is used by OdspDocumentService.ts to delay load the delta connection\n * as they are not on critical path of loading a container.\n */\nexport class OdspDelayLoadedDeltaStream {\n\t// Timer which runs and executes the join session call after intervals.\n\tprivate joinSessionRefreshTimer: ReturnType<typeof setTimeout> | undefined;\n\n\tprivate readonly joinSessionKey: string;\n\n\tprivate currentConnection?: OdspDocumentDeltaConnection;\n\n\tprivate _relayServiceTenantAndSessionId: string | undefined;\n\n\tprivate firstConnectionAttempt = true;\n\n\t// Tracks the time at which the Policy Labels were updated the last time. This is used to resolve race conditions\n\t// between label updates from the join session and the Fluid signals and they could have same or different timestamps.\n\t// So this timestamp is updated with timestamp from the service/signals with the most recent timestamp. We could also\n\t// receive stale data from join session as that call is made at intervals, so we need to update with only most recent data.\n\tprivate labelUpdateTimestamp: number = -1;\n\n\t/**\n\t * @param odspResolvedUrl - resolved url identifying document that will be managed by this service instance.\n\t * @param policies - Document service policies.\n\t * @param getAuthHeader - function that can provide the Authentication header value. This is is also referred to as\n\t * the \"Vroom\" token in SPO.\n\t * @param getWebsocketToken - function that can provide a token for accessing the web socket. This is also referred\n\t * to as the \"Push\" token in SPO. If undefined then websocket token is expected to be returned with joinSession\n\t * response payload.\n\t * @param mc - a logger that can capture performance and diagnostic information\n\t * @param cache - This caches response for joinSession.\n\t * @param hostPolicy - host constructed policy which customizes service behavior.\n\t * @param epochTracker - This helper class which adds epoch to backend calls made by this service instance.\n\t * @param opsReceived - To register the ops received through socket.\n\t * @param socketReferenceKeyPrefix - (optional) prefix to isolate socket reuse cache\n\t */\n\tpublic constructor(\n\t\tpublic readonly odspResolvedUrl: IOdspResolvedUrl,\n\t\tpublic policies: IDocumentServicePolicies,\n\t\tprivate readonly getAuthHeader: InstrumentedStorageTokenFetcher,\n\t\tprivate readonly getWebsocketToken:\n\t\t\t| ((options: TokenFetchOptions) => Promise<string | null>)\n\t\t\t| undefined,\n\t\tprivate readonly mc: MonitoringContext,\n\t\tprivate readonly cache: IOdspCache,\n\t\tprivate readonly hostPolicy: HostStoragePolicy,\n\t\tprivate readonly epochTracker: EpochTracker,\n\t\tprivate readonly opsReceived: (ops: ISequencedDocumentMessage[]) => void,\n\t\tprivate readonly metadataUpdateHandler: (metadata: Record<string, string>) => void,\n\t\tprivate readonly socketReferenceKeyPrefix?: string,\n\t) {\n\t\tthis.joinSessionKey = getJoinSessionCacheKey(this.odspResolvedUrl);\n\t}\n\n\tpublic get resolvedUrl(): IResolvedUrl {\n\t\treturn this.odspResolvedUrl;\n\t}\n\n\tpublic get currentDeltaConnection(): OdspDocumentDeltaConnection | undefined {\n\t\treturn this.currentConnection;\n\t}\n\n\tpublic get relayServiceTenantAndSessionId(): string | undefined {\n\t\treturn this._relayServiceTenantAndSessionId;\n\t}\n\n\t/**\n\t * Annotate the given error indicating which connection step failed\n\t */\n\tprivate annotateConnectionError(\n\t\terror: unknown,\n\t\tfailedConnectionStep: string,\n\t\tseparateTokenRequest: boolean,\n\t): IFluidErrorBase {\n\t\treturn normalizeError(error, {\n\t\t\tprops: {\n\t\t\t\tfailedConnectionStep,\n\t\t\t\tseparateTokenRequest,\n\t\t\t},\n\t\t});\n\t}\n\n\t/**\n\t * Connects to a delta stream endpoint for emitting ops.\n\t *\n\t * @returns returns the document delta stream service for onedrive/sharepoint driver.\n\t */\n\tpublic async connectToDeltaStream(client: IClient): Promise<IDocumentDeltaConnection> {\n\t\tassert(\n\t\t\tthis.currentConnection === undefined,\n\t\t\t0x4ad /* Should not be called when connection is already present! */,\n\t\t);\n\t\t// Attempt to connect twice, in case we used expired token.\n\t\treturn getWithRetryForTokenRefresh<IDocumentDeltaConnection>(async (options) => {\n\t\t\t// Presence of getWebsocketToken callback dictates whether callback is used for fetching\n\t\t\t// websocket token or whether it is returned with joinSession response payload\n\t\t\tconst requestWebsocketTokenFromJoinSession = this.getWebsocketToken === undefined;\n\t\t\tconst websocketTokenPromise = requestWebsocketTokenFromJoinSession\n\t\t\t\t? // eslint-disable-next-line unicorn/no-null\n\t\t\t\t\tPromise.resolve(null)\n\t\t\t\t: this.getWebsocketToken(options);\n\n\t\t\tconst annotateAndRethrowConnectionError = (step: string) => (error: unknown) => {\n\t\t\t\tthrow this.annotateConnectionError(error, step, !requestWebsocketTokenFromJoinSession);\n\t\t\t};\n\n\t\t\t// Log telemetry for join session attempt\n\t\t\tif (this.firstConnectionAttempt) {\n\t\t\t\tthis.mc.logger.sendTelemetryEvent({\n\t\t\t\t\teventName: \"FirstJoinSessionAttemptDetails\",\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\trequestWebsocketToken: requestWebsocketTokenFromJoinSession,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst joinSessionPromise = this.joinSession(\n\t\t\t\trequestWebsocketTokenFromJoinSession,\n\t\t\t\toptions,\n\t\t\t\tfalse /* isRefreshingJoinSession */,\n\t\t\t\tundefined /* clientId */,\n\t\t\t\tthis.hostPolicy.sessionOptions?.displayName,\n\t\t\t);\n\t\t\tconst [websocketEndpoint, websocketToken] = await Promise.all([\n\t\t\t\tjoinSessionPromise.catch(annotateAndRethrowConnectionError(\"joinSession\")),\n\t\t\t\twebsocketTokenPromise.catch(annotateAndRethrowConnectionError(\"getWebsocketToken\")),\n\t\t\t]);\n\n\t\t\t// eslint-disable-next-line unicorn/no-null\n\t\t\tconst finalWebsocketToken = websocketToken ?? websocketEndpoint.socketToken ?? null;\n\t\t\tif (finalWebsocketToken === null) {\n\t\t\t\tthrow this.annotateConnectionError(\n\t\t\t\t\tnew NonRetryableError(\"Websocket token is null\", OdspErrorTypes.fetchTokenError, {\n\t\t\t\t\t\tdriverVersion,\n\t\t\t\t\t}),\n\t\t\t\t\t\"getWebsocketToken\",\n\t\t\t\t\t!requestWebsocketTokenFromJoinSession,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (websocketEndpoint.sensitivityLabelsInfo !== undefined) {\n\t\t\t\tthis.emitSensitivityLabelUpdateEvent(websocketEndpoint.sensitivityLabelsInfo);\n\t\t\t}\n\n\t\t\tconst connectionId = uuid();\n\t\t\tif (this.firstConnectionAttempt) {\n\t\t\t\tthis.firstConnectionAttempt = false;\n\t\t\t\tthis.mc.logger.sendTelemetryEvent({\n\t\t\t\t\teventName: \"FirstConnectionAttemptDetails\",\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\tconnectionId,\n\t\t\t\t\t\ttenantId: websocketEndpoint.tenantId,\n\t\t\t\t\t\tdocumentId: websocketEndpoint.id,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst connection = await this.createDeltaConnection(\n\t\t\t\t\twebsocketEndpoint.tenantId,\n\t\t\t\t\twebsocketEndpoint.id,\n\t\t\t\t\tfinalWebsocketToken,\n\t\t\t\t\tclient,\n\t\t\t\t\twebsocketEndpoint.deltaStreamSocketUrl,\n\t\t\t\t\tconnectionId,\n\t\t\t\t);\n\t\t\t\tconnection.on(\"op\", (documentId, ops: ISequencedDocumentMessage[]) => {\n\t\t\t\t\tthis.opsReceived(ops);\n\t\t\t\t});\n\t\t\t\tconnection.on(\"signal\", this.signalHandler);\n\t\t\t\t// Also process the initial signals\n\t\t\t\tthis.signalHandler(connection.initialSignals);\n\t\t\t\t// On disconnect with 401/403 error code, we can just clear the joinSession cache as we will again\n\t\t\t\t// get the auth error on reconnecting and face latency.\n\t\t\t\tconnection.once(\"disconnect\", (error: unknown) => {\n\t\t\t\t\t// Clear the join session refresh timer so that it can be restarted on reconnection.\n\t\t\t\t\tthis.clearJoinSessionTimer();\n\t\t\t\t\tif (\n\t\t\t\t\t\ttypeof error === \"object\" &&\n\t\t\t\t\t\terror !== null &&\n\t\t\t\t\t\t(error as Partial<IOdspError>).errorType === OdspErrorTypes.authorizationError\n\t\t\t\t\t) {\n\t\t\t\t\t\tthis.cache.sessionJoinCache.remove(this.joinSessionKey);\n\t\t\t\t\t}\n\t\t\t\t\t// If we hit this assert, it means that \"disconnect\" event is emitted before the connection went through\n\t\t\t\t\t// dispose flow which is not correct and could lead to a bunch of errors.\n\t\t\t\t\tassert(connection.disposed, 0x4ae /* Connection should be disposed by now */);\n\t\t\t\t\tthis.currentConnection = undefined;\n\t\t\t\t});\n\t\t\t\tthis.currentConnection = connection;\n\t\t\t\treturn connection;\n\t\t\t} catch (error) {\n\t\t\t\t// Remove join session information from cache only if it is an error is from socket event connect_document_error.\n\t\t\t\t// Otherwise keep it in cache so that this session can be re-used after disconnection.\n\t\t\t\t// Also keeping an undefined check here to account for any unknown code path that is unable to stamp the value as in that case also\n\t\t\t\t// it is safer to clear join session cache and start over.\n\t\t\t\tif (\n\t\t\t\t\terror &&\n\t\t\t\t\ttypeof error === \"object\" &&\n\t\t\t\t\t((error as IAnyDriverError).scenarioName === \"connect_document_error\" ||\n\t\t\t\t\t\t(error as IAnyDriverError).scenarioName === undefined)\n\t\t\t\t) {\n\t\t\t\t\tthis.clearJoinSessionTimer();\n\t\t\t\t\tthis.cache.sessionJoinCache.remove(this.joinSessionKey);\n\t\t\t\t}\n\t\t\t\tconst normalizedError = this.annotateConnectionError(\n\t\t\t\t\terror,\n\t\t\t\t\t\"createDeltaConnection\",\n\t\t\t\t\t!requestWebsocketTokenFromJoinSession,\n\t\t\t\t);\n\t\t\t\tif (typeof error === \"object\" && error !== null) {\n\t\t\t\t\tnormalizedError.addTelemetryProperties({\n\t\t\t\t\t\tsocketDocumentId: websocketEndpoint.id,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tthrow normalizedError;\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate readonly signalHandler = (signalsArg: ISignalMessage | ISignalMessage[]): void => {\n\t\tconst signals = Array.isArray(signalsArg) ? signalsArg : [signalsArg];\n\t\tfor (const signal of signals) {\n\t\t\t// Make sure it is not for a specific client as `PolicyLabelsUpdate` is meant for all clients.\n\t\t\tif (signal.clientId === null) {\n\t\t\t\t// We could have some issues/irregularities in parsing signals, so put it in try/catch block\n\t\t\t\t// and ignore the error as we can have labels update later on through join session response.\n\t\t\t\tlet envelope: ISignalEnvelope | undefined;\n\t\t\t\ttry {\n\t\t\t\t\tenvelope = JSON.parse(signal.content as string) as ISignalEnvelope;\n\t\t\t\t} catch {\n\t\t\t\t\t// Drop error\n\t\t\t\t}\n\t\t\t\tif (envelope?.contents?.type === policyLabelsUpdatesSignalType) {\n\t\t\t\t\tthis.emitSensitivityLabelUpdateEvent(\n\t\t\t\t\t\tenvelope.contents.content as ISensitivityLabelsInfo,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\tprivate clearJoinSessionTimer(): void {\n\t\tif (this.joinSessionRefreshTimer !== undefined) {\n\t\t\tclearTimeout(this.joinSessionRefreshTimer);\n\t\t\tthis.joinSessionRefreshTimer = undefined;\n\t\t}\n\t}\n\n\tprivate async scheduleJoinSessionRefresh(\n\t\tdelta: number,\n\t\trequestSocketToken: boolean,\n\t\tclientId: string | undefined,\n\t\tdisplayName: string | undefined,\n\t): Promise<void> {\n\t\tif (this.joinSessionRefreshTimer !== undefined) {\n\t\t\tthis.clearJoinSessionTimer();\n\t\t\t// TODO: use a stronger type\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n\t\t\tconst originalStackTraceLimit = (Error as any).stackTraceLimit;\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n\t\t\t(Error as any).stackTraceLimit = 50;\n\t\t\tthis.mc.logger.sendTelemetryEvent(\n\t\t\t\t{\n\t\t\t\t\teventName: \"DuplicateJoinSessionRefresh\",\n\t\t\t\t},\n\t\t\t\tnew Error(\"DuplicateJoinSessionRefresh\"),\n\t\t\t);\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n\t\t\t(Error as any).stackTraceLimit = originalStackTraceLimit;\n\t\t}\n\n\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\tthis.joinSessionRefreshTimer = setTimeout(() => {\n\t\t\t\tthis.clearJoinSessionTimer();\n\t\t\t\t// Clear the timer as it is going to be scheduled again as part of refreshing join session.\n\t\t\t\tgetWithRetryForTokenRefresh(async (options) => {\n\t\t\t\t\tawait this.joinSession(\n\t\t\t\t\t\trequestSocketToken,\n\t\t\t\t\t\toptions,\n\t\t\t\t\t\ttrue /* isRefreshingJoinSession */,\n\t\t\t\t\t\tclientId,\n\t\t\t\t\t\tdisplayName,\n\t\t\t\t\t);\n\t\t\t\t\tresolve();\n\t\t\t\t}).catch((error) => {\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors\n\t\t\t\t\treject(error);\n\t\t\t\t});\n\t\t\t}, delta);\n\t\t});\n\t}\n\n\tprivate async joinSession(\n\t\trequestSocketToken: boolean,\n\t\toptions: TokenFetchOptionsEx,\n\t\tisRefreshingJoinSession: boolean,\n\t\tclientId: string | undefined,\n\t\tdisplayName: string | undefined,\n\t): Promise<ISocketStorageDiscovery> {\n\t\t// If this call is to refresh the join session for the current connection but we are already disconnected in\n\t\t// the meantime or disconnected and then reconnected then do not make the call. However, we should not have\n\t\t// come here if that is the case because timer should have been disposed, but due to race condition with the\n\t\t// timer we should not make the call and throw error.\n\t\tif (\n\t\t\tisRefreshingJoinSession &&\n\t\t\t(this.currentConnection === undefined ||\n\t\t\t\t(clientId !== undefined && this.currentConnection.clientId !== clientId))\n\t\t) {\n\t\t\tthis.clearJoinSessionTimer();\n\t\t\tthrow new NonRetryableError(\n\t\t\t\t\"JoinSessionRefreshTimerNotCancelled\",\n\t\t\t\tOdspErrorTypes.genericError,\n\t\t\t\t{\n\t\t\t\t\tdriverVersion,\n\t\t\t\t\tdetails: JSON.stringify({\n\t\t\t\t\t\tschedulerClientId: clientId,\n\t\t\t\t\t\tcurrentClientId: this.currentConnection?.clientId,\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t\tconst response = await this.joinSessionCore(\n\t\t\trequestSocketToken,\n\t\t\toptions,\n\t\t\tisRefreshingJoinSession,\n\t\t\tdisplayName,\n\t\t).catch((error) => {\n\t\t\tif (hasFacetCodes(error) && error.facetCodes !== undefined) {\n\t\t\t\tfor (const code of error.facetCodes) {\n\t\t\t\t\tswitch (code) {\n\t\t\t\t\t\tcase \"sessionForbidden\":\n\t\t\t\t\t\tcase \"sessionForbiddenOnPreservedFiles\":\n\t\t\t\t\t\tcase \"sessionForbiddenOnModerationEnabledLibrary\":\n\t\t\t\t\t\tcase \"sessionForbiddenOnRequireCheckout\":\n\t\t\t\t\t\tcase \"sessionForbiddenOnCheckoutFile\":\n\t\t\t\t\t\tcase \"sessionForbiddenOnInvisibleMinorVersion\": {\n\t\t\t\t\t\t\t// This document can only be opened in storage-only mode.\n\t\t\t\t\t\t\t// DeltaManager will recognize this error\n\t\t\t\t\t\t\t// and load without a delta stream connection.\n\t\t\t\t\t\t\tthis.policies = { ...this.policies, storageOnly: true };\n\t\t\t\t\t\t\tthrow new DeltaStreamConnectionForbiddenError(\n\t\t\t\t\t\t\t\t`Storage-only due to ${code}`,\n\t\t\t\t\t\t\t\t{ driverVersion },\n\t\t\t\t\t\t\t\tcode,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdefault: {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow error;\n\t\t});\n\t\tthis._relayServiceTenantAndSessionId = `${response.tenantId}/${response.id}`;\n\t\treturn response;\n\t}\n\n\tprivate async joinSessionCore(\n\t\trequestSocketToken: boolean,\n\t\toptions: TokenFetchOptionsEx,\n\t\tisRefreshingJoinSession: boolean,\n\t\tdisplayName: string | undefined,\n\t): Promise<ISocketStorageDiscovery> {\n\t\tconst disableJoinSessionRefresh = this.mc.config.getBoolean(\n\t\t\t\"Fluid.Driver.Odsp.disableJoinSessionRefresh\",\n\t\t);\n\t\tconst executeFetch = async (): Promise<{\n\t\t\tentryTime: number;\n\t\t\tjoinSessionResponse: ISocketStorageDiscovery;\n\t\t}> => {\n\t\t\tconst joinSessionResponse = await fetchJoinSession(\n\t\t\t\tthis.odspResolvedUrl,\n\t\t\t\t\"opStream/joinSession\",\n\t\t\t\t\"POST\",\n\t\t\t\tthis.mc.logger,\n\t\t\t\tthis.getAuthHeader,\n\t\t\t\tthis.epochTracker,\n\t\t\t\trequestSocketToken,\n\t\t\t\toptions,\n\t\t\t\tdisableJoinSessionRefresh,\n\t\t\t\tisRefreshingJoinSession,\n\t\t\t\tdisplayName,\n\t\t\t);\n\t\t\t// Emit event only in case it is fetched from the network.\n\t\t\tif (joinSessionResponse.sensitivityLabelsInfo !== undefined) {\n\t\t\t\tthis.emitSensitivityLabelUpdateEvent(joinSessionResponse.sensitivityLabelsInfo);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tentryTime: Date.now(),\n\t\t\t\tjoinSessionResponse,\n\t\t\t};\n\t\t};\n\n\t\tconst getResponseAndRefreshAfterDeltaMs = async (): Promise<{\n\t\t\trefreshAfterDeltaMs: number;\n\t\t\tentryTime: number;\n\t\t\tjoinSessionResponse: ISocketStorageDiscovery;\n\t\t}> => {\n\t\t\tconst _response = await this.cache.sessionJoinCache.addOrGet(\n\t\t\t\tthis.joinSessionKey,\n\t\t\t\texecuteFetch,\n\t\t\t);\n\t\t\t// If the response does not contain refreshSessionDurationSeconds, then treat it as old flow and let the\n\t\t\t// cache entry to be treated as expired after 1 hour.\n\t\t\t_response.joinSessionResponse.refreshSessionDurationSeconds =\n\t\t\t\t_response.joinSessionResponse.refreshSessionDurationSeconds ?? 3600;\n\t\t\treturn {\n\t\t\t\t..._response,\n\t\t\t\trefreshAfterDeltaMs: this.calculateJoinSessionRefreshDelta(\n\t\t\t\t\t_response.entryTime,\n\t\t\t\t\t_response.joinSessionResponse.refreshSessionDurationSeconds,\n\t\t\t\t),\n\t\t\t};\n\t\t};\n\t\tlet response = await getResponseAndRefreshAfterDeltaMs();\n\t\t// This means that the cached entry has expired(This should not be possible if the response is fetched\n\t\t// from the network call). In this case we remove the cached entry and fetch the new response.\n\t\tif (response.refreshAfterDeltaMs <= 0) {\n\t\t\tthis.cache.sessionJoinCache.remove(this.joinSessionKey);\n\t\t\tresponse = await getResponseAndRefreshAfterDeltaMs();\n\t\t}\n\t\tif (!disableJoinSessionRefresh) {\n\t\t\tconst props = {\n\t\t\t\tentryTime: response.entryTime,\n\t\t\t\trefreshSessionDurationSeconds:\n\t\t\t\t\tresponse.joinSessionResponse.refreshSessionDurationSeconds,\n\t\t\t\trefreshAfterDeltaMs: response.refreshAfterDeltaMs,\n\t\t\t};\n\t\t\tif (response.refreshAfterDeltaMs > 0) {\n\t\t\t\tthis.scheduleJoinSessionRefresh(\n\t\t\t\t\tresponse.refreshAfterDeltaMs,\n\t\t\t\t\trequestSocketToken,\n\t\t\t\t\tthis.currentConnection?.clientId,\n\t\t\t\t\tdisplayName,\n\t\t\t\t).catch((error) => {\n\t\t\t\t\t// Log the error and do nothing as the reconnection would fetch the join session.\n\t\t\t\t\tthis.mc.logger.sendTelemetryEvent(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\teventName: \"JoinSessionRefreshError\",\n\t\t\t\t\t\t\tdetails: JSON.stringify(props),\n\t\t\t\t\t\t},\n\t\t\t\t\t\terror,\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t// Logging just for informational purposes to help with debugging as this is a new feature.\n\t\t\t\tthis.mc.logger.sendTelemetryEvent({\n\t\t\t\t\teventName: \"JoinSessionRefreshNotScheduled\",\n\t\t\t\t\tdetails: JSON.stringify(props),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn response.joinSessionResponse;\n\t}\n\n\tprivate emitSensitivityLabelUpdateEvent(\n\t\tsensitivityLabelsInfo: ISensitivityLabelsInfo,\n\t): void {\n\t\tconst createdTimestamp = sensitivityLabelsInfo.timestamp;\n\t\tassert(\n\t\t\ttypeof createdTimestamp === \"number\" && createdTimestamp > 0,\n\t\t\t0x8e0 /* time should be a positive number */,\n\t\t);\n\t\tif (createdTimestamp > this.labelUpdateTimestamp) {\n\t\t\tthis.labelUpdateTimestamp = createdTimestamp;\n\t\t\tthis.metadataUpdateHandler({\n\t\t\t\tsensitivityLabelsInfo: JSON.stringify(sensitivityLabelsInfo),\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate calculateJoinSessionRefreshDelta(\n\t\tresponseFetchTime: number,\n\t\trefreshSessionDurationSeconds: number,\n\t): number {\n\t\t// 30 seconds is buffer time to refresh the session.\n\t\treturn responseFetchTime + (refreshSessionDurationSeconds * 1000 - 30000) - Date.now();\n\t}\n\n\t/**\n\t * Creates a connection to the given delta stream endpoint\n\t *\n\t * @param tenantId - the ID of the tenant\n\t * @param documentId - document ID\n\t * @param token - authorization token for delta service\n\t * @param client - information about the client\n\t * @param webSocketUrl - websocket URL\n\t * @param connectionId - connection ID for the connection\n\t */\n\tprivate async createDeltaConnection(\n\t\ttenantId: string,\n\t\tdocumentId: string,\n\t\ttoken: string | null,\n\t\tclient: IClient,\n\t\twebSocketUrl: string,\n\t\tconnectionId: string,\n\t): Promise<OdspDocumentDeltaConnection> {\n\t\tconst startTime = performanceNow();\n\t\tconst connection = await OdspDocumentDeltaConnection.create(\n\t\t\ttenantId,\n\t\t\tdocumentId,\n\t\t\ttoken,\n\t\t\tclient,\n\t\t\twebSocketUrl,\n\t\t\tthis.mc.logger,\n\t\t\t60000,\n\t\t\tthis.epochTracker,\n\t\t\tthis.socketReferenceKeyPrefix,\n\t\t\tconnectionId,\n\t\t);\n\t\tconst duration = performanceNow() - startTime;\n\t\t// This event happens rather often, so it adds up to cost of telemetry.\n\t\t// Given that most reconnects result in reusing socket and happen very quickly,\n\t\t// report event only if it took longer than threshold.\n\t\tif (duration >= 2000) {\n\t\t\tthis.mc.logger.sendPerformanceEvent({\n\t\t\t\teventName: \"ConnectionSuccess\",\n\t\t\t\tduration,\n\t\t\t});\n\t\t}\n\t\treturn connection;\n\t}\n\n\tpublic dispose(error?: unknown): void {\n\t\tthis.clearJoinSessionTimer();\n\t\tthis.currentConnection?.dispose();\n\t\tthis.currentConnection = undefined;\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"odspDeltaStorageService.d.ts","sourceRoot":"","sources":["../src/odspDeltaStorageService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"odspDeltaStorageService.d.ts","sourceRoot":"","sources":["../src/odspDeltaStorageService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAIhF,OAAO,KAAK,EACX,kBAAkB,EAClB,4BAA4B,EAC5B,OAAO,EACP,yBAAyB,EACzB,MAAM,6CAA6C,CAAC;AAErD,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,kDAAkD,CAAC;AACxG,OAAO,EACN,KAAK,mBAAmB,EAExB,MAAM,0CAA0C,CAAC;AAIlD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAGlF;;GAEG;AACH,qBAAa,uBAAuB;IAElC,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAHN,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,+BAA+B,EAC9C,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,mBAAmB;IAG7C;;;;;;;OAOG;IACU,GAAG,CACf,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,cAAc,EAAE,wBAAwB,EACxC,YAAY,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,kBAAkB,CAAC;IA4EvB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM;CAOjD;AAED,qBAAa,yBAA0B,YAAW,4BAA4B;IAI5E,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAM/B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAI1B,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,oBAAoB;IAnBtC,OAAO,CAAC,cAAc,CAAQ;gBAGrB,WAAW,EAAE,yBAAyB,EAAE,GAAG,SAAS,EAC3C,MAAM,EAAE,mBAAmB,EAC3B,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,CAChC,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,cAAc,EAAE,wBAAwB,EACxC,WAAW,CAAC,EAAE,MAAM,KAChB,OAAO,CAAC,kBAAkB,CAAC,EACf,SAAS,EAAE,CAC3B,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,KACN,OAAO,CAAC,yBAAyB,EAAE,CAAC,EACxB,iBAAiB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,EACrD,WAAW,EAAE,CAAC,GAAG,EAAE,yBAAyB,EAAE,KAAK,IAAI,EACvD,oBAAoB,EAAE,MAAM,0BAA0B,GAAG,SAAS;IAG7E,aAAa,CACnB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,WAAW,CAAC,EAAE,WAAW,EACzB,UAAU,CAAC,EAAE,OAAO,EACpB,WAAW,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,yBAAyB,EAAE,CAAC;CAiGvC"}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.OdspDeltaStorageWithCache = exports.OdspDeltaStorageService = void 0;
|
|
8
|
+
const core_interfaces_1 = require("@fluidframework/core-interfaces");
|
|
8
9
|
const internal_1 = require("@fluidframework/core-utils/internal");
|
|
9
10
|
const internal_2 = require("@fluidframework/driver-base/internal");
|
|
10
11
|
const internal_3 = require("@fluidframework/driver-utils/internal");
|
|
@@ -170,7 +171,8 @@ class OdspDeltaStorageWithCache {
|
|
|
170
171
|
opsFromCache,
|
|
171
172
|
opsFromStorage,
|
|
172
173
|
reason: fetchReason,
|
|
173
|
-
}
|
|
174
|
+
}, undefined, // error
|
|
175
|
+
core_interfaces_1.LogLevel.info);
|
|
174
176
|
}
|
|
175
177
|
});
|
|
176
178
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"odspDeltaStorageService.js","sourceRoot":"","sources":["../src/odspDeltaStorageService.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { ITelemetryBaseProperties } from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport { validateMessages } from \"@fluidframework/driver-base/internal\";\nimport type {\n\tIDeltasFetchResult,\n\tIDocumentDeltaStorageService,\n\tIStream,\n\tISequencedDocumentMessage,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { requestOps, streamObserver } from \"@fluidframework/driver-utils/internal\";\nimport type { InstrumentedStorageTokenFetcher } from \"@fluidframework/odsp-driver-definitions/internal\";\nimport {\n\ttype ITelemetryLoggerExt,\n\tPerformanceEvent,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport { v4 as uuid } from \"uuid\";\n\nimport type { IDeltaStorageGetResponse, ISequencedDeltaOpMessage } from \"./contracts.js\";\nimport type { EpochTracker } from \"./epochTracker.js\";\nimport type { OdspDocumentStorageService } from \"./odspDocumentStorageManager.js\";\nimport { getWithRetryForTokenRefresh } from \"./odspUtils.js\";\n\n/**\n * Provides access to the underlying delta storage on the server for sharepoint driver.\n */\nexport class OdspDeltaStorageService {\n\tconstructor(\n\t\tprivate readonly deltaFeedUrl: string,\n\t\tprivate readonly getAuthHeader: InstrumentedStorageTokenFetcher,\n\t\tprivate readonly epochTracker: EpochTracker,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t) {}\n\n\t/**\n\t * Retrieves ops from storage\n\t * @param from - inclusive\n\t * @param to - exclusive\n\t * @param telemetryProps - properties to add when issuing telemetry events\n\t * @param scenarioName - reason for fetching ops\n\t * @returns ops retrieved & info if result was partial (i.e. more is available)\n\t */\n\tpublic async get(\n\t\tfrom: number,\n\t\tto: number,\n\t\ttelemetryProps: ITelemetryBaseProperties,\n\t\tscenarioName?: string,\n\t): Promise<IDeltasFetchResult> {\n\t\treturn getWithRetryForTokenRefresh(async (options) => {\n\t\t\t// Note - this call ends up in getSocketStorageDiscovery() and can refresh token\n\t\t\t// Thus it needs to be done before we call getAuthHeader() to reduce extra calls\n\t\t\tconst url = this.buildUrl(from, to);\n\t\t\tconst method = \"POST\";\n\t\t\tconst authHeader = await this.getAuthHeader(\n\t\t\t\t{ ...options, request: { url, method } },\n\t\t\t\t\"DeltaStorage\",\n\t\t\t);\n\n\t\t\treturn PerformanceEvent.timedExecAsync(\n\t\t\t\tthis.logger,\n\t\t\t\t{\n\t\t\t\t\teventName: \"OpsFetch\",\n\t\t\t\t\tattempts: options.refresh ? 2 : 1,\n\t\t\t\t\tfrom,\n\t\t\t\t\tto,\n\t\t\t\t\t...telemetryProps,\n\t\t\t\t\treason: scenarioName,\n\t\t\t\t},\n\t\t\t\tasync (event) => {\n\t\t\t\t\tconst formBoundary = uuid();\n\t\t\t\t\tlet postBody = `--${formBoundary}\\r\\n`;\n\t\t\t\t\tpostBody += `Authorization: ${authHeader}\\r\\n`;\n\t\t\t\t\tpostBody += `X-HTTP-Method-Override: GET\\r\\n`;\n\n\t\t\t\t\tpostBody += `_post: 1\\r\\n`;\n\t\t\t\t\tpostBody += `\\r\\n--${formBoundary}--`;\n\t\t\t\t\tconst headers: { [index: string]: string } = {\n\t\t\t\t\t\t\"Content-Type\": `multipart/form-data;boundary=${formBoundary}`,\n\t\t\t\t\t};\n\n\t\t\t\t\t// Some request take a long time (1-2 minutes) to complete, where telemetry shows very small amount\n\t\t\t\t\t// of time spent on server, and usually small payload sizes. I.e. all the time is spent somewhere in\n\t\t\t\t\t// networking. Even bigger problem - a lot of requests timeout (based on cursory look - after 1-2 minutes)\n\t\t\t\t\t// So adding some timeout to ensure we retry again in hope of faster success.\n\t\t\t\t\t// Please see https://github.com/microsoft/FluidFramework/issues/6997 for details.\n\t\t\t\t\tconst abort = new AbortController();\n\t\t\t\t\tconst timer = setTimeout(() => abort.abort(), 30000);\n\n\t\t\t\t\tconst response =\n\t\t\t\t\t\tawait this.epochTracker.fetchAndParseAsJSON<IDeltaStorageGetResponse>(\n\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\theaders,\n\t\t\t\t\t\t\t\tbody: postBody,\n\t\t\t\t\t\t\t\tmethod,\n\t\t\t\t\t\t\t\tsignal: abort.signal,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"ops\",\n\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\tscenarioName,\n\t\t\t\t\t\t);\n\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\tconst deltaStorageResponse = response.content;\n\t\t\t\t\tconst messages =\n\t\t\t\t\t\tdeltaStorageResponse.value.length > 0 && \"op\" in deltaStorageResponse.value[0]\n\t\t\t\t\t\t\t? (deltaStorageResponse.value as ISequencedDeltaOpMessage[]).map(\n\t\t\t\t\t\t\t\t\t(operation) => operation.op,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t: (deltaStorageResponse.value as ISequencedDocumentMessage[]);\n\n\t\t\t\t\tevent.end({\n\t\t\t\t\t\tlength: messages.length,\n\t\t\t\t\t\t...response.propsToLog,\n\t\t\t\t\t});\n\n\t\t\t\t\t// It is assumed that server always returns all the ops that it has in the range that was requested.\n\t\t\t\t\t// This may change in the future, if so, we need to adjust and receive \"end\" value from server in such case.\n\t\t\t\t\treturn { messages, partialResult: false };\n\t\t\t\t},\n\t\t\t);\n\t\t});\n\t}\n\n\tpublic buildUrl(from: number, to: number): string {\n\t\tconst filter = encodeURIComponent(\n\t\t\t`sequenceNumber ge ${from} and sequenceNumber le ${to - 1}`,\n\t\t);\n\t\tconst queryString = `?ump=1&filter=${filter}`;\n\t\treturn `${this.deltaFeedUrl}${queryString}`;\n\t}\n}\n\nexport class OdspDeltaStorageWithCache implements IDocumentDeltaStorageService {\n\tprivate useCacheForOps = true;\n\n\tpublic constructor(\n\t\tprivate snapshotOps: ISequencedDocumentMessage[] | undefined,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t\tprivate readonly batchSize: number,\n\t\tprivate readonly concurrency: number,\n\t\tprivate readonly getFromStorage: (\n\t\t\tfrom: number,\n\t\t\tto: number,\n\t\t\ttelemetryProps: ITelemetryBaseProperties,\n\t\t\tfetchReason?: string,\n\t\t) => Promise<IDeltasFetchResult>,\n\t\tprivate readonly getCached: (\n\t\t\tfrom: number,\n\t\t\tto: number,\n\t\t) => Promise<ISequencedDocumentMessage[]>,\n\t\tprivate readonly requestFromSocket: (from: number, to: number) => void,\n\t\tprivate readonly opsReceived: (ops: ISequencedDocumentMessage[]) => void,\n\t\tprivate readonly storageManagerGetter: () => OdspDocumentStorageService | undefined,\n\t) {}\n\n\tpublic fetchMessages(\n\t\tfromTotal: number,\n\t\ttoTotal: number | undefined,\n\t\tabortSignal?: AbortSignal,\n\t\tcachedOnly?: boolean,\n\t\tfetchReason?: string,\n\t): IStream<ISequencedDocumentMessage[]> {\n\t\t// We do not control what's in the cache. Current API assumes that fetchMessages() keeps banging on\n\t\t// storage / cache until it gets ops it needs. This would result in deadlock if fixed range is asked from\n\t\t// cache and it's not there.\n\t\t// Better implementation would be to return only what we have in cache, but that also breaks API\n\t\tassert(!cachedOnly || toTotal === undefined, 0x1e3);\n\n\t\t// Don't use cache for ops is snapshot is fetched from network or if it was not fetched at all.\n\t\tthis.useCacheForOps =\n\t\t\tthis.useCacheForOps && this.storageManagerGetter()?.isFirstSnapshotFromNetwork === false;\n\t\tlet opsFromSnapshot = 0;\n\t\tlet opsFromCache = 0;\n\t\tlet opsFromStorage = 0;\n\n\t\tconst requestCallback = async (\n\t\t\tfrom: number,\n\t\t\tto: number,\n\t\t\ttelemetryProps: ITelemetryBaseProperties,\n\t\t): Promise<IDeltasFetchResult> => {\n\t\t\tif (this.snapshotOps !== undefined && this.snapshotOps.length > 0) {\n\t\t\t\tconst messages = this.snapshotOps.filter(\n\t\t\t\t\t(op) => op.sequenceNumber >= from && op.sequenceNumber < to,\n\t\t\t\t);\n\t\t\t\tvalidateMessages(\"cached\", messages, from, this.logger);\n\t\t\t\tif (messages.length > 0 && messages[0].sequenceNumber === from) {\n\t\t\t\t\tthis.snapshotOps = this.snapshotOps.filter((op) => op.sequenceNumber >= to);\n\t\t\t\t\topsFromSnapshot += messages.length;\n\t\t\t\t\treturn { messages, partialResult: true };\n\t\t\t\t}\n\t\t\t\tthis.snapshotOps = undefined;\n\t\t\t}\n\n\t\t\t// Kick out request to PUSH for ops if it has them\n\t\t\tthis.requestFromSocket(from, to);\n\n\t\t\t// Cache in normal flow is continuous. Once there is a miss, stop consulting cache.\n\t\t\t// This saves a bit of processing time.\n\t\t\tif (this.useCacheForOps) {\n\t\t\t\tconst messagesFromCache = await this.getCached(from, to);\n\t\t\t\tvalidateMessages(\"cached\", messagesFromCache, from, this.logger);\n\t\t\t\t// Set the firstCacheMiss as true in case we didn't get all the ops.\n\t\t\t\t// This will save an extra cache read on \"DocumentOpen\" or \"PostDocumentOpen\".\n\t\t\t\tthis.useCacheForOps = from + messagesFromCache.length >= to;\n\t\t\t\tif (messagesFromCache.length > 0) {\n\t\t\t\t\topsFromCache += messagesFromCache.length;\n\t\t\t\t\treturn {\n\t\t\t\t\t\tmessages: messagesFromCache,\n\t\t\t\t\t\tpartialResult: true,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (cachedOnly) {\n\t\t\t\treturn { messages: [], partialResult: false };\n\t\t\t}\n\n\t\t\tconst ops = await this.getFromStorage(from, to, telemetryProps, fetchReason);\n\t\t\tvalidateMessages(\"storage\", ops.messages, from, this.logger);\n\t\t\topsFromStorage += ops.messages.length;\n\t\t\tthis.opsReceived(ops.messages);\n\t\t\treturn ops;\n\t\t};\n\n\t\tconst stream = requestOps(\n\t\t\tasync (from: number, to: number, telemetryProps: ITelemetryBaseProperties) => {\n\t\t\t\tconst result = await requestCallback(from, to, telemetryProps);\n\t\t\t\t// Catch all case, just in case\n\t\t\t\tvalidateMessages(\"catch all\", result.messages, from, this.logger);\n\t\t\t\treturn result;\n\t\t\t},\n\t\t\t// Staging: starting with no concurrency, listening for feedback first.\n\t\t\t// In future releases we will switch to actual concurrency\n\t\t\tthis.concurrency,\n\t\t\tfromTotal, // inclusive\n\t\t\ttoTotal, // exclusive\n\t\t\tthis.batchSize,\n\t\t\tthis.logger,\n\t\t\tabortSignal,\n\t\t\tfetchReason,\n\t\t);\n\n\t\treturn streamObserver(stream, (result) => {\n\t\t\tif (result.done && opsFromSnapshot + opsFromCache + opsFromStorage !== 0) {\n\t\t\t\tthis.logger.sendPerformanceEvent({\n\t\t\t\t\teventName: \"CacheOpsRetrieved\",\n\t\t\t\t\topsFromSnapshot,\n\t\t\t\t\topsFromCache,\n\t\t\t\t\topsFromStorage,\n\t\t\t\t\treason: fetchReason,\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"odspDeltaStorageService.js","sourceRoot":"","sources":["../src/odspDeltaStorageService.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { ITelemetryBaseProperties } from \"@fluidframework/core-interfaces\";\nimport { LogLevel } from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport { validateMessages } from \"@fluidframework/driver-base/internal\";\nimport type {\n\tIDeltasFetchResult,\n\tIDocumentDeltaStorageService,\n\tIStream,\n\tISequencedDocumentMessage,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { requestOps, streamObserver } from \"@fluidframework/driver-utils/internal\";\nimport type { InstrumentedStorageTokenFetcher } from \"@fluidframework/odsp-driver-definitions/internal\";\nimport {\n\ttype ITelemetryLoggerExt,\n\tPerformanceEvent,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport { v4 as uuid } from \"uuid\";\n\nimport type { IDeltaStorageGetResponse, ISequencedDeltaOpMessage } from \"./contracts.js\";\nimport type { EpochTracker } from \"./epochTracker.js\";\nimport type { OdspDocumentStorageService } from \"./odspDocumentStorageManager.js\";\nimport { getWithRetryForTokenRefresh } from \"./odspUtils.js\";\n\n/**\n * Provides access to the underlying delta storage on the server for sharepoint driver.\n */\nexport class OdspDeltaStorageService {\n\tconstructor(\n\t\tprivate readonly deltaFeedUrl: string,\n\t\tprivate readonly getAuthHeader: InstrumentedStorageTokenFetcher,\n\t\tprivate readonly epochTracker: EpochTracker,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t) {}\n\n\t/**\n\t * Retrieves ops from storage\n\t * @param from - inclusive\n\t * @param to - exclusive\n\t * @param telemetryProps - properties to add when issuing telemetry events\n\t * @param scenarioName - reason for fetching ops\n\t * @returns ops retrieved & info if result was partial (i.e. more is available)\n\t */\n\tpublic async get(\n\t\tfrom: number,\n\t\tto: number,\n\t\ttelemetryProps: ITelemetryBaseProperties,\n\t\tscenarioName?: string,\n\t): Promise<IDeltasFetchResult> {\n\t\treturn getWithRetryForTokenRefresh(async (options) => {\n\t\t\t// Note - this call ends up in getSocketStorageDiscovery() and can refresh token\n\t\t\t// Thus it needs to be done before we call getAuthHeader() to reduce extra calls\n\t\t\tconst url = this.buildUrl(from, to);\n\t\t\tconst method = \"POST\";\n\t\t\tconst authHeader = await this.getAuthHeader(\n\t\t\t\t{ ...options, request: { url, method } },\n\t\t\t\t\"DeltaStorage\",\n\t\t\t);\n\n\t\t\treturn PerformanceEvent.timedExecAsync(\n\t\t\t\tthis.logger,\n\t\t\t\t{\n\t\t\t\t\teventName: \"OpsFetch\",\n\t\t\t\t\tattempts: options.refresh ? 2 : 1,\n\t\t\t\t\tfrom,\n\t\t\t\t\tto,\n\t\t\t\t\t...telemetryProps,\n\t\t\t\t\treason: scenarioName,\n\t\t\t\t},\n\t\t\t\tasync (event) => {\n\t\t\t\t\tconst formBoundary = uuid();\n\t\t\t\t\tlet postBody = `--${formBoundary}\\r\\n`;\n\t\t\t\t\tpostBody += `Authorization: ${authHeader}\\r\\n`;\n\t\t\t\t\tpostBody += `X-HTTP-Method-Override: GET\\r\\n`;\n\n\t\t\t\t\tpostBody += `_post: 1\\r\\n`;\n\t\t\t\t\tpostBody += `\\r\\n--${formBoundary}--`;\n\t\t\t\t\tconst headers: { [index: string]: string } = {\n\t\t\t\t\t\t\"Content-Type\": `multipart/form-data;boundary=${formBoundary}`,\n\t\t\t\t\t};\n\n\t\t\t\t\t// Some request take a long time (1-2 minutes) to complete, where telemetry shows very small amount\n\t\t\t\t\t// of time spent on server, and usually small payload sizes. I.e. all the time is spent somewhere in\n\t\t\t\t\t// networking. Even bigger problem - a lot of requests timeout (based on cursory look - after 1-2 minutes)\n\t\t\t\t\t// So adding some timeout to ensure we retry again in hope of faster success.\n\t\t\t\t\t// Please see https://github.com/microsoft/FluidFramework/issues/6997 for details.\n\t\t\t\t\tconst abort = new AbortController();\n\t\t\t\t\tconst timer = setTimeout(() => abort.abort(), 30000);\n\n\t\t\t\t\tconst response =\n\t\t\t\t\t\tawait this.epochTracker.fetchAndParseAsJSON<IDeltaStorageGetResponse>(\n\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\theaders,\n\t\t\t\t\t\t\t\tbody: postBody,\n\t\t\t\t\t\t\t\tmethod,\n\t\t\t\t\t\t\t\tsignal: abort.signal,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"ops\",\n\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\tscenarioName,\n\t\t\t\t\t\t);\n\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\tconst deltaStorageResponse = response.content;\n\t\t\t\t\tconst messages =\n\t\t\t\t\t\tdeltaStorageResponse.value.length > 0 && \"op\" in deltaStorageResponse.value[0]\n\t\t\t\t\t\t\t? (deltaStorageResponse.value as ISequencedDeltaOpMessage[]).map(\n\t\t\t\t\t\t\t\t\t(operation) => operation.op,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t: (deltaStorageResponse.value as ISequencedDocumentMessage[]);\n\n\t\t\t\t\tevent.end({\n\t\t\t\t\t\tlength: messages.length,\n\t\t\t\t\t\t...response.propsToLog,\n\t\t\t\t\t});\n\n\t\t\t\t\t// It is assumed that server always returns all the ops that it has in the range that was requested.\n\t\t\t\t\t// This may change in the future, if so, we need to adjust and receive \"end\" value from server in such case.\n\t\t\t\t\treturn { messages, partialResult: false };\n\t\t\t\t},\n\t\t\t);\n\t\t});\n\t}\n\n\tpublic buildUrl(from: number, to: number): string {\n\t\tconst filter = encodeURIComponent(\n\t\t\t`sequenceNumber ge ${from} and sequenceNumber le ${to - 1}`,\n\t\t);\n\t\tconst queryString = `?ump=1&filter=${filter}`;\n\t\treturn `${this.deltaFeedUrl}${queryString}`;\n\t}\n}\n\nexport class OdspDeltaStorageWithCache implements IDocumentDeltaStorageService {\n\tprivate useCacheForOps = true;\n\n\tpublic constructor(\n\t\tprivate snapshotOps: ISequencedDocumentMessage[] | undefined,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t\tprivate readonly batchSize: number,\n\t\tprivate readonly concurrency: number,\n\t\tprivate readonly getFromStorage: (\n\t\t\tfrom: number,\n\t\t\tto: number,\n\t\t\ttelemetryProps: ITelemetryBaseProperties,\n\t\t\tfetchReason?: string,\n\t\t) => Promise<IDeltasFetchResult>,\n\t\tprivate readonly getCached: (\n\t\t\tfrom: number,\n\t\t\tto: number,\n\t\t) => Promise<ISequencedDocumentMessage[]>,\n\t\tprivate readonly requestFromSocket: (from: number, to: number) => void,\n\t\tprivate readonly opsReceived: (ops: ISequencedDocumentMessage[]) => void,\n\t\tprivate readonly storageManagerGetter: () => OdspDocumentStorageService | undefined,\n\t) {}\n\n\tpublic fetchMessages(\n\t\tfromTotal: number,\n\t\ttoTotal: number | undefined,\n\t\tabortSignal?: AbortSignal,\n\t\tcachedOnly?: boolean,\n\t\tfetchReason?: string,\n\t): IStream<ISequencedDocumentMessage[]> {\n\t\t// We do not control what's in the cache. Current API assumes that fetchMessages() keeps banging on\n\t\t// storage / cache until it gets ops it needs. This would result in deadlock if fixed range is asked from\n\t\t// cache and it's not there.\n\t\t// Better implementation would be to return only what we have in cache, but that also breaks API\n\t\tassert(!cachedOnly || toTotal === undefined, 0x1e3);\n\n\t\t// Don't use cache for ops is snapshot is fetched from network or if it was not fetched at all.\n\t\tthis.useCacheForOps =\n\t\t\tthis.useCacheForOps && this.storageManagerGetter()?.isFirstSnapshotFromNetwork === false;\n\t\tlet opsFromSnapshot = 0;\n\t\tlet opsFromCache = 0;\n\t\tlet opsFromStorage = 0;\n\n\t\tconst requestCallback = async (\n\t\t\tfrom: number,\n\t\t\tto: number,\n\t\t\ttelemetryProps: ITelemetryBaseProperties,\n\t\t): Promise<IDeltasFetchResult> => {\n\t\t\tif (this.snapshotOps !== undefined && this.snapshotOps.length > 0) {\n\t\t\t\tconst messages = this.snapshotOps.filter(\n\t\t\t\t\t(op) => op.sequenceNumber >= from && op.sequenceNumber < to,\n\t\t\t\t);\n\t\t\t\tvalidateMessages(\"cached\", messages, from, this.logger);\n\t\t\t\tif (messages.length > 0 && messages[0].sequenceNumber === from) {\n\t\t\t\t\tthis.snapshotOps = this.snapshotOps.filter((op) => op.sequenceNumber >= to);\n\t\t\t\t\topsFromSnapshot += messages.length;\n\t\t\t\t\treturn { messages, partialResult: true };\n\t\t\t\t}\n\t\t\t\tthis.snapshotOps = undefined;\n\t\t\t}\n\n\t\t\t// Kick out request to PUSH for ops if it has them\n\t\t\tthis.requestFromSocket(from, to);\n\n\t\t\t// Cache in normal flow is continuous. Once there is a miss, stop consulting cache.\n\t\t\t// This saves a bit of processing time.\n\t\t\tif (this.useCacheForOps) {\n\t\t\t\tconst messagesFromCache = await this.getCached(from, to);\n\t\t\t\tvalidateMessages(\"cached\", messagesFromCache, from, this.logger);\n\t\t\t\t// Set the firstCacheMiss as true in case we didn't get all the ops.\n\t\t\t\t// This will save an extra cache read on \"DocumentOpen\" or \"PostDocumentOpen\".\n\t\t\t\tthis.useCacheForOps = from + messagesFromCache.length >= to;\n\t\t\t\tif (messagesFromCache.length > 0) {\n\t\t\t\t\topsFromCache += messagesFromCache.length;\n\t\t\t\t\treturn {\n\t\t\t\t\t\tmessages: messagesFromCache,\n\t\t\t\t\t\tpartialResult: true,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (cachedOnly) {\n\t\t\t\treturn { messages: [], partialResult: false };\n\t\t\t}\n\n\t\t\tconst ops = await this.getFromStorage(from, to, telemetryProps, fetchReason);\n\t\t\tvalidateMessages(\"storage\", ops.messages, from, this.logger);\n\t\t\topsFromStorage += ops.messages.length;\n\t\t\tthis.opsReceived(ops.messages);\n\t\t\treturn ops;\n\t\t};\n\n\t\tconst stream = requestOps(\n\t\t\tasync (from: number, to: number, telemetryProps: ITelemetryBaseProperties) => {\n\t\t\t\tconst result = await requestCallback(from, to, telemetryProps);\n\t\t\t\t// Catch all case, just in case\n\t\t\t\tvalidateMessages(\"catch all\", result.messages, from, this.logger);\n\t\t\t\treturn result;\n\t\t\t},\n\t\t\t// Staging: starting with no concurrency, listening for feedback first.\n\t\t\t// In future releases we will switch to actual concurrency\n\t\t\tthis.concurrency,\n\t\t\tfromTotal, // inclusive\n\t\t\ttoTotal, // exclusive\n\t\t\tthis.batchSize,\n\t\t\tthis.logger,\n\t\t\tabortSignal,\n\t\t\tfetchReason,\n\t\t);\n\n\t\treturn streamObserver(stream, (result) => {\n\t\t\tif (result.done && opsFromSnapshot + opsFromCache + opsFromStorage !== 0) {\n\t\t\t\tthis.logger.sendPerformanceEvent(\n\t\t\t\t\t{\n\t\t\t\t\t\teventName: \"CacheOpsRetrieved\",\n\t\t\t\t\t\topsFromSnapshot,\n\t\t\t\t\t\topsFromCache,\n\t\t\t\t\t\topsFromStorage,\n\t\t\t\t\t\treason: fetchReason,\n\t\t\t\t\t},\n\t\t\t\t\tundefined, // error\n\t\t\t\t\tLogLevel.info,\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\t}\n}\n"]}
|
package/dist/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 = "2.
|
|
8
|
+
export declare const pkgVersion = "2.101.0";
|
|
9
9
|
//# sourceMappingURL=packageVersion.d.ts.map
|
package/dist/packageVersion.js
CHANGED
|
@@ -8,5 +8,5 @@
|
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.pkgVersion = exports.pkgName = void 0;
|
|
10
10
|
exports.pkgName = "@fluidframework/odsp-driver";
|
|
11
|
-
exports.pkgVersion = "2.
|
|
11
|
+
exports.pkgVersion = "2.101.0";
|
|
12
12
|
//# sourceMappingURL=packageVersion.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,6BAA6B,CAAC;AACxC,QAAA,UAAU,GAAG,SAAS,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/odsp-driver\";\nexport const pkgVersion = \"2.
|
|
1
|
+
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,6BAA6B,CAAC;AACxC,QAAA,UAAU,GAAG,SAAS,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/odsp-driver\";\nexport const pkgVersion = \"2.101.0\";\n"]}
|
package/dist/vroom.d.ts
CHANGED
|
@@ -18,11 +18,10 @@ import type { TokenFetchOptionsEx } from "./odspUtils.js";
|
|
|
18
18
|
* which is used when establishing websocket connection with collab session backend service.
|
|
19
19
|
* @param options - Options to fetch the token.
|
|
20
20
|
* @param disableJoinSessionRefresh - Whether the caller wants to disable refreshing join session periodically.
|
|
21
|
-
* @param setSensitivityLabelHeader - Whether the caller wants to set the Return-Sensitivity-Labels Prefer header in the join session request.
|
|
22
21
|
* @param isRefreshingJoinSession - whether call is to refresh the session before expiry.
|
|
23
22
|
* @param displayName - display name used to identify client joining a session.
|
|
24
23
|
* This is optional and used only when collab session is being joined by client acting in app-only mode (i.e. without user context).
|
|
25
24
|
* If not specified client display name is extracted from the access token that is used to join session.
|
|
26
25
|
*/
|
|
27
|
-
export declare const fetchJoinSession: import("./mockify.js").Mockable<(urlParts: IOdspUrlParts, path: string, method: "GET" | "POST", logger: ITelemetryLoggerExt, getAuthHeader: InstrumentedStorageTokenFetcher, epochTracker: EpochTracker, requestSocketToken: boolean, options: TokenFetchOptionsEx, disableJoinSessionRefresh: boolean | undefined,
|
|
26
|
+
export declare const fetchJoinSession: import("./mockify.js").Mockable<(urlParts: IOdspUrlParts, path: string, method: "GET" | "POST", logger: ITelemetryLoggerExt, getAuthHeader: InstrumentedStorageTokenFetcher, epochTracker: EpochTracker, requestSocketToken: boolean, options: TokenFetchOptionsEx, disableJoinSessionRefresh: boolean | undefined, isRefreshingJoinSession: boolean, displayName: string | undefined) => Promise<ISocketStorageDiscovery>>;
|
|
28
27
|
//# sourceMappingURL=vroom.d.ts.map
|
package/dist/vroom.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vroom.d.ts","sourceRoot":"","sources":["../src/vroom.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EACX,aAAa,EACb,uBAAuB,EACvB,+BAA+B,EAC/B,MAAM,kDAAkD,CAAC;AAC1D,OAAO,EACN,KAAK,mBAAmB,EAExB,MAAM,0CAA0C,CAAC;AAGlD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGtD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAQ1D
|
|
1
|
+
{"version":3,"file":"vroom.d.ts","sourceRoot":"","sources":["../src/vroom.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EACX,aAAa,EACb,uBAAuB,EACvB,+BAA+B,EAC/B,MAAM,kDAAkD,CAAC;AAC1D,OAAO,EACN,KAAK,mBAAmB,EAExB,MAAM,0CAA0C,CAAC;AAGlD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGtD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAQ1D;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,gBAAgB,6CAEjB,aAAa,QACjB,MAAM,UACJ,KAAK,GAAG,MAAM,UACd,mBAAmB,iBACZ,+BAA+B,gBAChC,YAAY,sBACN,OAAO,WAClB,mBAAmB,6BACD,OAAO,GAAG,SAAS,2BACrB,OAAO,eACnB,MAAM,GAAG,SAAS,KAC7B,QAAQ,uBAAuB,CAAC,CAuFnC,CAAC"}
|
package/dist/vroom.js
CHANGED
|
@@ -22,13 +22,12 @@ const retryUtils_js_1 = require("./retryUtils.js");
|
|
|
22
22
|
* which is used when establishing websocket connection with collab session backend service.
|
|
23
23
|
* @param options - Options to fetch the token.
|
|
24
24
|
* @param disableJoinSessionRefresh - Whether the caller wants to disable refreshing join session periodically.
|
|
25
|
-
* @param setSensitivityLabelHeader - Whether the caller wants to set the Return-Sensitivity-Labels Prefer header in the join session request.
|
|
26
25
|
* @param isRefreshingJoinSession - whether call is to refresh the session before expiry.
|
|
27
26
|
* @param displayName - display name used to identify client joining a session.
|
|
28
27
|
* This is optional and used only when collab session is being joined by client acting in app-only mode (i.e. without user context).
|
|
29
28
|
* If not specified client display name is extracted from the access token that is used to join session.
|
|
30
29
|
*/
|
|
31
|
-
exports.fetchJoinSession = (0, mockify_js_1.mockify)(async (urlParts, path, method, logger, getAuthHeader, epochTracker, requestSocketToken, options, disableJoinSessionRefresh,
|
|
30
|
+
exports.fetchJoinSession = (0, mockify_js_1.mockify)(async (urlParts, path, method, logger, getAuthHeader, epochTracker, requestSocketToken, options, disableJoinSessionRefresh, isRefreshingJoinSession, displayName) => {
|
|
32
31
|
const apiRoot = (0, odspUrlHelper_js_1.getApiRoot)(new URL(urlParts.siteUrl));
|
|
33
32
|
const url = `${apiRoot}/drives/${urlParts.driveId}/items/${urlParts.itemId}/${path}?ump=1`;
|
|
34
33
|
const authHeader = await getAuthHeader({ ...options, request: { url, method } }, "JoinSession");
|
|
@@ -40,7 +39,6 @@ exports.fetchJoinSession = (0, mockify_js_1.mockify)(async (urlParts, path, meth
|
|
|
40
39
|
requestSocketToken,
|
|
41
40
|
...tokenRefreshProps,
|
|
42
41
|
refreshingSession: isRefreshingJoinSession,
|
|
43
|
-
setSensitivityLabelHeader: setSensitivityLabelHeader ?? false,
|
|
44
42
|
};
|
|
45
43
|
return internal_1.PerformanceEvent.timedExecAsync(logger, {
|
|
46
44
|
eventName: "JoinSession",
|
|
@@ -56,9 +54,7 @@ exports.fetchJoinSession = (0, mockify_js_1.mockify)(async (urlParts, path, meth
|
|
|
56
54
|
if (!disableJoinSessionRefresh) {
|
|
57
55
|
postBody += `Prefer: FluidRemoveCheckAccess\r\n`;
|
|
58
56
|
}
|
|
59
|
-
|
|
60
|
-
postBody += `Prefer: Return-Sensitivity-Labels\r\n`;
|
|
61
|
-
}
|
|
57
|
+
postBody += `Prefer: Return-Sensitivity-Labels\r\n`;
|
|
62
58
|
postBody += `_post: 1\r\n`;
|
|
63
59
|
let requestBody;
|
|
64
60
|
if (requestSocketToken) {
|
package/dist/vroom.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vroom.js","sourceRoot":"","sources":["../src/vroom.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAQH,uEAGkD;AAClD,+BAAkC;AAGlC,6CAAuC;AACvC,yDAAgD;AAEhD,mDAA+C;AAO/C
|
|
1
|
+
{"version":3,"file":"vroom.js","sourceRoot":"","sources":["../src/vroom.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAQH,uEAGkD;AAClD,+BAAkC;AAGlC,6CAAuC;AACvC,yDAAgD;AAEhD,mDAA+C;AAO/C;;;;;;;;;;;;;;;;GAgBG;AACU,QAAA,gBAAgB,GAAG,IAAA,oBAAO,EACtC,KAAK,EACJ,QAAuB,EACvB,IAAY,EACZ,MAAsB,EACtB,MAA2B,EAC3B,aAA8C,EAC9C,YAA0B,EAC1B,kBAA2B,EAC3B,OAA4B,EAC5B,yBAA8C,EAC9C,uBAAgC,EAChC,WAA+B,EACI,EAAE;IACrC,MAAM,OAAO,GAAG,IAAA,6BAAU,EAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IACtD,MAAM,GAAG,GAAG,GAAG,OAAO,WAAW,QAAQ,CAAC,OAAO,UAAU,QAAQ,CAAC,MAAM,IAAI,IAAI,QAAQ,CAAC;IAC3F,MAAM,UAAU,GAAG,MAAM,aAAa,CACrC,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EACxC,aAAa,CACb,CAAC;IAEF,MAAM,iBAAiB,GAAG,OAAO,CAAC,OAAO;QACxC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE;QAClE,CAAC,CAAC,EAAE,CAAC;IACN,MAAM,OAAO,GAA6B;QACzC,cAAc,EAAE,OAAO,CAAC,OAAO;QAC/B,kBAAkB;QAClB,GAAG,iBAAiB;QACpB,iBAAiB,EAAE,uBAAuB;KAC1C,CAAC;IAEF,OAAO,2BAAgB,CAAC,cAAc,CACrC,MAAM,EACN;QACC,SAAS,EAAE,aAAa;QACxB,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACjC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;QAChC,GAAG,iBAAiB;KACpB,EACD,KAAK,EAAE,KAAK,EAAE,EAAE;QACf,MAAM,YAAY,GAAG,IAAA,SAAI,GAAE,CAAC;QAC5B,IAAI,QAAQ,GAAG,KAAK,YAAY,MAAM,CAAC;QACvC,QAAQ,IAAI,kBAAkB,UAAU,MAAM,CAAC;QAC/C,QAAQ,IAAI,kCAAkC,CAAC;QAC/C,QAAQ,IAAI,oCAAoC,CAAC;QACjD,IAAI,CAAC,yBAAyB,EAAE,CAAC;YAChC,QAAQ,IAAI,oCAAoC,CAAC;QAClD,CAAC;QACD,QAAQ,IAAI,uCAAuC,CAAC;QACpD,QAAQ,IAAI,cAAc,CAAC;QAE3B,IAAI,WAAyC,CAAC;QAC9C,IAAI,kBAAkB,EAAE,CAAC;YACxB,WAAW,GAAG,EAAE,GAAG,WAAW,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC;QAC5D,CAAC;QACD,IAAI,WAAW,EAAE,CAAC;YACjB,WAAW,GAAG,EAAE,GAAG,WAAW,EAAE,WAAW,EAAE,CAAC;QAC/C,CAAC;QACD,IAAI,WAAW,EAAE,CAAC;YACjB,QAAQ,IAAI,OAAO,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,MAAM,CAAC;QACtD,CAAC;QACD,QAAQ,IAAI,SAAS,YAAY,IAAI,CAAC;QACtC,MAAM,OAAO,GAAgC;YAC5C,cAAc,EAAE,gCAAgC,YAAY,EAAE;SAC9D,CAAC;QAEF,MAAM,QAAQ,GAAG,MAAM,IAAA,4BAAY,EAClC,KAAK,IAAI,EAAE,CACV,YAAY,CAAC,mBAAmB,CAC/B,GAAG,EACH,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,EACnC,aAAa,EACb,IAAI,CACJ,EACF,aAAa,EACb,MAAM,CACN,CAAC;QAEF,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,oBAAoB,CAAC;QACxD,kEAAkE;QAClE,MAAM,iBAAiB,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAElD,8BAA8B;QAC9B,KAAK,CAAC,GAAG,CAAC;YACT,GAAG,QAAQ,CAAC,UAAU;YACtB,2CAA2C;YAC3C,MAAM,EAAE,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC;YACnC,iBAAiB;YACjB,6BAA6B,EAAE,QAAQ,CAAC,OAAO,CAAC,6BAA6B;YAC7E,wBAAwB,EAAE,QAAQ,CAAC,OAAO,CAAC,qBAAqB,KAAK,SAAS;SAC9E,CAAC,CAAC;QAEH,IAAI,QAAQ,CAAC,OAAO,CAAC,eAAe,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;YACpE,QAAQ,CAAC,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,eAAe,CAAC;QAC9D,CAAC;QAED,OAAO,QAAQ,CAAC,OAAO,CAAC;IACzB,CAAC,CACD,CAAC;AACH,CAAC,CACD,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { ITelemetryBaseProperties } from \"@fluidframework/core-interfaces\";\nimport type {\n\tIOdspUrlParts,\n\tISocketStorageDiscovery,\n\tInstrumentedStorageTokenFetcher,\n} from \"@fluidframework/odsp-driver-definitions/internal\";\nimport {\n\ttype ITelemetryLoggerExt,\n\tPerformanceEvent,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport { v4 as uuid } from \"uuid\";\n\nimport type { EpochTracker } from \"./epochTracker.js\";\nimport { mockify } from \"./mockify.js\";\nimport { getApiRoot } from \"./odspUrlHelper.js\";\nimport type { TokenFetchOptionsEx } from \"./odspUtils.js\";\nimport { runWithRetry } from \"./retryUtils.js\";\n\ninterface IJoinSessionBody {\n\trequestSocketToken?: boolean;\n\tdisplayName?: string;\n}\n\n/**\n * Makes join session call on SPO to get information about the web socket for a document\n * @param urlParts - The SPO drive id, itemId, siteUrl that this request should be made against\n * @param path - The API path that is relevant to this request\n * @param method - The type of request, such as GET or POST\n * @param logger - A logger to use for this request\n * @param getAuthHeader - A function that is able to provide the access token for this request\n * @param epochTracker - fetch wrapper which incorporates epoch logic around joinSession call\n * @param requestSocketToken - flag indicating whether joinSession is expected to return access token\n * which is used when establishing websocket connection with collab session backend service.\n * @param options - Options to fetch the token.\n * @param disableJoinSessionRefresh - Whether the caller wants to disable refreshing join session periodically.\n * @param isRefreshingJoinSession - whether call is to refresh the session before expiry.\n * @param displayName - display name used to identify client joining a session.\n * This is optional and used only when collab session is being joined by client acting in app-only mode (i.e. without user context).\n * If not specified client display name is extracted from the access token that is used to join session.\n */\nexport const fetchJoinSession = mockify(\n\tasync (\n\t\turlParts: IOdspUrlParts,\n\t\tpath: string,\n\t\tmethod: \"GET\" | \"POST\",\n\t\tlogger: ITelemetryLoggerExt,\n\t\tgetAuthHeader: InstrumentedStorageTokenFetcher,\n\t\tepochTracker: EpochTracker,\n\t\trequestSocketToken: boolean,\n\t\toptions: TokenFetchOptionsEx,\n\t\tdisableJoinSessionRefresh: boolean | undefined,\n\t\tisRefreshingJoinSession: boolean,\n\t\tdisplayName: string | undefined,\n\t): Promise<ISocketStorageDiscovery> => {\n\t\tconst apiRoot = getApiRoot(new URL(urlParts.siteUrl));\n\t\tconst url = `${apiRoot}/drives/${urlParts.driveId}/items/${urlParts.itemId}/${path}?ump=1`;\n\t\tconst authHeader = await getAuthHeader(\n\t\t\t{ ...options, request: { url, method } },\n\t\t\t\"JoinSession\",\n\t\t);\n\n\t\tconst tokenRefreshProps = options.refresh\n\t\t\t? { hasClaims: !!options.claims, hasTenantId: !!options.tenantId }\n\t\t\t: {};\n\t\tconst details: ITelemetryBaseProperties = {\n\t\t\trefreshedToken: options.refresh,\n\t\t\trequestSocketToken,\n\t\t\t...tokenRefreshProps,\n\t\t\trefreshingSession: isRefreshingJoinSession,\n\t\t};\n\n\t\treturn PerformanceEvent.timedExecAsync(\n\t\t\tlogger,\n\t\t\t{\n\t\t\t\teventName: \"JoinSession\",\n\t\t\t\tattempts: options.refresh ? 2 : 1,\n\t\t\t\tdetails: JSON.stringify(details),\n\t\t\t\t...tokenRefreshProps,\n\t\t\t},\n\t\t\tasync (event) => {\n\t\t\t\tconst formBoundary = uuid();\n\t\t\t\tlet postBody = `--${formBoundary}\\r\\n`;\n\t\t\t\tpostBody += `Authorization: ${authHeader}\\r\\n`;\n\t\t\t\tpostBody += `X-HTTP-Method-Override: POST\\r\\n`;\n\t\t\t\tpostBody += `Content-Type: application/json\\r\\n`;\n\t\t\t\tif (!disableJoinSessionRefresh) {\n\t\t\t\t\tpostBody += `Prefer: FluidRemoveCheckAccess\\r\\n`;\n\t\t\t\t}\n\t\t\t\tpostBody += `Prefer: Return-Sensitivity-Labels\\r\\n`;\n\t\t\t\tpostBody += `_post: 1\\r\\n`;\n\n\t\t\t\tlet requestBody: IJoinSessionBody | undefined;\n\t\t\t\tif (requestSocketToken) {\n\t\t\t\t\trequestBody = { ...requestBody, requestSocketToken: true };\n\t\t\t\t}\n\t\t\t\tif (displayName) {\n\t\t\t\t\trequestBody = { ...requestBody, displayName };\n\t\t\t\t}\n\t\t\t\tif (requestBody) {\n\t\t\t\t\tpostBody += `\\r\\n${JSON.stringify(requestBody)}\\r\\n`;\n\t\t\t\t}\n\t\t\t\tpostBody += `\\r\\n--${formBoundary}--`;\n\t\t\t\tconst headers: { [index: string]: string } = {\n\t\t\t\t\t\"Content-Type\": `multipart/form-data;boundary=${formBoundary}`,\n\t\t\t\t};\n\n\t\t\t\tconst response = await runWithRetry(\n\t\t\t\t\tasync () =>\n\t\t\t\t\t\tepochTracker.fetchAndParseAsJSON<ISocketStorageDiscovery>(\n\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\t{ method, headers, body: postBody },\n\t\t\t\t\t\t\t\"joinSession\",\n\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t),\n\t\t\t\t\t\"joinSession\",\n\t\t\t\t\tlogger,\n\t\t\t\t);\n\n\t\t\t\tconst socketUrl = response.content.deltaStreamSocketUrl;\n\t\t\t\t// expecting socketUrl to be something like https://{hostName}/...\n\t\t\t\tconst webSocketHostName = socketUrl.split(\"/\")[2];\n\n\t\t\t\t// TODO SPO-specific telemetry\n\t\t\t\tevent.end({\n\t\t\t\t\t...response.propsToLog,\n\t\t\t\t\t// pushV2 websocket urls will contain pushf\n\t\t\t\t\tpushv2: socketUrl.includes(\"pushf\"),\n\t\t\t\t\twebSocketHostName,\n\t\t\t\t\trefreshSessionDurationSeconds: response.content.refreshSessionDurationSeconds,\n\t\t\t\t\thasSensitivityLabelsInfo: response.content.sensitivityLabelsInfo !== undefined,\n\t\t\t\t});\n\n\t\t\t\tif (response.content.runtimeTenantId && !response.content.tenantId) {\n\t\t\t\t\tresponse.content.tenantId = response.content.runtimeTenantId;\n\t\t\t\t}\n\n\t\t\t\treturn response.content;\n\t\t\t},\n\t\t);\n\t},\n);\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"odspDelayLoadedDeltaStream.d.ts","sourceRoot":"","sources":["../src/odspDelayLoadedDeltaStream.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,KAAK,EACX,wBAAwB,EACxB,wBAAwB,EACxB,YAAY,EAEZ,yBAAyB,EAEzB,MAAM,6CAA6C,CAAC;AAMrD,OAAO,EACN,KAAK,iBAAiB,EAEtB,KAAK,gBAAgB,EAGrB,KAAK,+BAA+B,EAEpC,KAAK,iBAAiB,EACtB,MAAM,kDAAkD,CAAC;AAC1D,OAAO,EAEN,KAAK,iBAAiB,EAEtB,MAAM,0CAA0C,CAAC;AAIlD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAS/E;;;GAGG;AACH,qBAAa,0BAA0B;aAkCrB,eAAe,EAAE,gBAAgB;IAC1C,QAAQ,EAAE,wBAAwB;IACzC,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAGlC,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IACtC,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAC;IA5C3C,OAAO,CAAC,uBAAuB,CAA4C;IAE3E,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IAExC,OAAO,CAAC,iBAAiB,CAAC,CAA8B;IAExD,OAAO,CAAC,+BAA+B,CAAqB;IAE5D,OAAO,CAAC,sBAAsB,CAAQ;IAMtC,OAAO,CAAC,oBAAoB,CAAc;IAE1C;;;;;;;;;;;;;;OAcG;gBAEc,eAAe,EAAE,gBAAgB,EAC1C,QAAQ,EAAE,wBAAwB,EACxB,aAAa,EAAE,+BAA+B,EAC9C,iBAAiB,EAC/B,CAAC,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,GACxD,SAAS,EACK,EAAE,EAAE,iBAAiB,EACrB,KAAK,EAAE,UAAU,EACjB,UAAU,EAAE,iBAAiB,EAC7B,YAAY,EAAE,YAAY,EAC1B,WAAW,EAAE,CAAC,GAAG,EAAE,yBAAyB,EAAE,KAAK,IAAI,EACvD,qBAAqB,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,EACjE,wBAAwB,CAAC,oBAAQ;IAKnD,IAAW,WAAW,IAAI,YAAY,CAErC;IAED,IAAW,sBAAsB,IAAI,2BAA2B,GAAG,SAAS,CAE3E;IAED,IAAW,8BAA8B,IAAI,MAAM,GAAG,SAAS,CAE9D;IAED;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAa/B;;;;OAIG;IACU,oBAAoB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAmIrF,OAAO,CAAC,QAAQ,CAAC,aAAa,CAoB5B;IAEF,OAAO,CAAC,qBAAqB;YAOf,0BAA0B;YA4C1B,WAAW;YAkEX,eAAe;
|
|
1
|
+
{"version":3,"file":"odspDelayLoadedDeltaStream.d.ts","sourceRoot":"","sources":["../src/odspDelayLoadedDeltaStream.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,KAAK,EACX,wBAAwB,EACxB,wBAAwB,EACxB,YAAY,EAEZ,yBAAyB,EAEzB,MAAM,6CAA6C,CAAC;AAMrD,OAAO,EACN,KAAK,iBAAiB,EAEtB,KAAK,gBAAgB,EAGrB,KAAK,+BAA+B,EAEpC,KAAK,iBAAiB,EACtB,MAAM,kDAAkD,CAAC;AAC1D,OAAO,EAEN,KAAK,iBAAiB,EAEtB,MAAM,0CAA0C,CAAC;AAIlD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAS/E;;;GAGG;AACH,qBAAa,0BAA0B;aAkCrB,eAAe,EAAE,gBAAgB;IAC1C,QAAQ,EAAE,wBAAwB;IACzC,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAGlC,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IACtC,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAC;IA5C3C,OAAO,CAAC,uBAAuB,CAA4C;IAE3E,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IAExC,OAAO,CAAC,iBAAiB,CAAC,CAA8B;IAExD,OAAO,CAAC,+BAA+B,CAAqB;IAE5D,OAAO,CAAC,sBAAsB,CAAQ;IAMtC,OAAO,CAAC,oBAAoB,CAAc;IAE1C;;;;;;;;;;;;;;OAcG;gBAEc,eAAe,EAAE,gBAAgB,EAC1C,QAAQ,EAAE,wBAAwB,EACxB,aAAa,EAAE,+BAA+B,EAC9C,iBAAiB,EAC/B,CAAC,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,GACxD,SAAS,EACK,EAAE,EAAE,iBAAiB,EACrB,KAAK,EAAE,UAAU,EACjB,UAAU,EAAE,iBAAiB,EAC7B,YAAY,EAAE,YAAY,EAC1B,WAAW,EAAE,CAAC,GAAG,EAAE,yBAAyB,EAAE,KAAK,IAAI,EACvD,qBAAqB,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,EACjE,wBAAwB,CAAC,oBAAQ;IAKnD,IAAW,WAAW,IAAI,YAAY,CAErC;IAED,IAAW,sBAAsB,IAAI,2BAA2B,GAAG,SAAS,CAE3E;IAED,IAAW,8BAA8B,IAAI,MAAM,GAAG,SAAS,CAE9D;IAED;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAa/B;;;;OAIG;IACU,oBAAoB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAmIrF,OAAO,CAAC,QAAQ,CAAC,aAAa,CAoB5B;IAEF,OAAO,CAAC,qBAAqB;YAOf,0BAA0B;YA4C1B,WAAW;YAkEX,eAAe;IAkG7B,OAAO,CAAC,+BAA+B;IAgBvC,OAAO,CAAC,gCAAgC;IAQxC;;;;;;;;;OASG;YACW,qBAAqB;IAkC5B,OAAO,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,IAAI;CAKrC"}
|
|
@@ -277,10 +277,8 @@ export class OdspDelayLoadedDeltaStream {
|
|
|
277
277
|
}
|
|
278
278
|
async joinSessionCore(requestSocketToken, options, isRefreshingJoinSession, displayName) {
|
|
279
279
|
const disableJoinSessionRefresh = this.mc.config.getBoolean("Fluid.Driver.Odsp.disableJoinSessionRefresh");
|
|
280
|
-
// Previous gate "Fluid.Driver.Odsp.setSensitivityLabelHeader" was removed because it was sensitive to a timestamp-related bug that was fixed by PR #26318; using this new gate ensures that the bug fix is present.
|
|
281
|
-
const setSensitivityLabelHeader = this.mc.config.getBoolean("Fluid.Driver.Odsp.setSensitivityLabelHeaderPostFix");
|
|
282
280
|
const executeFetch = async () => {
|
|
283
|
-
const joinSessionResponse = await fetchJoinSession(this.odspResolvedUrl, "opStream/joinSession", "POST", this.mc.logger, this.getAuthHeader, this.epochTracker, requestSocketToken, options, disableJoinSessionRefresh,
|
|
281
|
+
const joinSessionResponse = await fetchJoinSession(this.odspResolvedUrl, "opStream/joinSession", "POST", this.mc.logger, this.getAuthHeader, this.epochTracker, requestSocketToken, options, disableJoinSessionRefresh, isRefreshingJoinSession, displayName);
|
|
284
282
|
// Emit event only in case it is fetched from the network.
|
|
285
283
|
if (joinSessionResponse.sensitivityLabelsInfo !== undefined) {
|
|
286
284
|
this.emitSensitivityLabelUpdateEvent(joinSessionResponse.sensitivityLabelsInfo);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"odspDelayLoadedDeltaStream.js","sourceRoot":"","sources":["../src/odspDelayLoadedDeltaStream.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { performanceNow } from \"@fluid-internal/client-utils\";\nimport type { ISignalEnvelope } from \"@fluidframework/core-interfaces/internal\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type { IClient } from \"@fluidframework/driver-definitions\";\nimport type {\n\tIDocumentDeltaConnection,\n\tIDocumentServicePolicies,\n\tIResolvedUrl,\n\tIAnyDriverError,\n\tISequencedDocumentMessage,\n\tISignalMessage,\n} from \"@fluidframework/driver-definitions/internal\";\nimport {\n\tDeltaStreamConnectionForbiddenError,\n\tNonRetryableError,\n} from \"@fluidframework/driver-utils/internal\";\nimport { hasFacetCodes } from \"@fluidframework/odsp-doclib-utils/internal\";\nimport {\n\ttype HostStoragePolicy,\n\ttype IOdspError,\n\ttype IOdspResolvedUrl,\n\ttype ISocketStorageDiscovery,\n\ttype ISensitivityLabelsInfo,\n\ttype InstrumentedStorageTokenFetcher,\n\tOdspErrorTypes,\n\ttype TokenFetchOptions,\n} from \"@fluidframework/odsp-driver-definitions/internal\";\nimport {\n\ttype IFluidErrorBase,\n\ttype MonitoringContext,\n\tnormalizeError,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport { v4 as uuid } from \"uuid\";\n\nimport { policyLabelsUpdatesSignalType } from \"./contracts.js\";\nimport type { EpochTracker } from \"./epochTracker.js\";\nimport type { IOdspCache } from \"./odspCache.js\";\nimport { OdspDocumentDeltaConnection } from \"./odspDocumentDeltaConnection.js\";\nimport {\n\ttype TokenFetchOptionsEx,\n\tgetJoinSessionCacheKey,\n\tgetWithRetryForTokenRefresh,\n} from \"./odspUtils.js\";\nimport { pkgVersion as driverVersion } from \"./packageVersion.js\";\nimport { fetchJoinSession } from \"./vroom.js\";\n\n/**\n * This OdspDelayLoadedDeltaStream is used by OdspDocumentService.ts to delay load the delta connection\n * as they are not on critical path of loading a container.\n */\nexport class OdspDelayLoadedDeltaStream {\n\t// Timer which runs and executes the join session call after intervals.\n\tprivate joinSessionRefreshTimer: ReturnType<typeof setTimeout> | undefined;\n\n\tprivate readonly joinSessionKey: string;\n\n\tprivate currentConnection?: OdspDocumentDeltaConnection;\n\n\tprivate _relayServiceTenantAndSessionId: string | undefined;\n\n\tprivate firstConnectionAttempt = true;\n\n\t// Tracks the time at which the Policy Labels were updated the last time. This is used to resolve race conditions\n\t// between label updates from the join session and the Fluid signals and they could have same or different timestamps.\n\t// So this timestamp is updated with timestamp from the service/signals with the most recent timestamp. We could also\n\t// receive stale data from join session as that call is made at intervals, so we need to update with only most recent data.\n\tprivate labelUpdateTimestamp: number = -1;\n\n\t/**\n\t * @param odspResolvedUrl - resolved url identifying document that will be managed by this service instance.\n\t * @param policies - Document service policies.\n\t * @param getAuthHeader - function that can provide the Authentication header value. This is is also referred to as\n\t * the \"Vroom\" token in SPO.\n\t * @param getWebsocketToken - function that can provide a token for accessing the web socket. This is also referred\n\t * to as the \"Push\" token in SPO. If undefined then websocket token is expected to be returned with joinSession\n\t * response payload.\n\t * @param mc - a logger that can capture performance and diagnostic information\n\t * @param cache - This caches response for joinSession.\n\t * @param hostPolicy - host constructed policy which customizes service behavior.\n\t * @param epochTracker - This helper class which adds epoch to backend calls made by this service instance.\n\t * @param opsReceived - To register the ops received through socket.\n\t * @param socketReferenceKeyPrefix - (optional) prefix to isolate socket reuse cache\n\t */\n\tpublic constructor(\n\t\tpublic readonly odspResolvedUrl: IOdspResolvedUrl,\n\t\tpublic policies: IDocumentServicePolicies,\n\t\tprivate readonly getAuthHeader: InstrumentedStorageTokenFetcher,\n\t\tprivate readonly getWebsocketToken:\n\t\t\t| ((options: TokenFetchOptions) => Promise<string | null>)\n\t\t\t| undefined,\n\t\tprivate readonly mc: MonitoringContext,\n\t\tprivate readonly cache: IOdspCache,\n\t\tprivate readonly hostPolicy: HostStoragePolicy,\n\t\tprivate readonly epochTracker: EpochTracker,\n\t\tprivate readonly opsReceived: (ops: ISequencedDocumentMessage[]) => void,\n\t\tprivate readonly metadataUpdateHandler: (metadata: Record<string, string>) => void,\n\t\tprivate readonly socketReferenceKeyPrefix?: string,\n\t) {\n\t\tthis.joinSessionKey = getJoinSessionCacheKey(this.odspResolvedUrl);\n\t}\n\n\tpublic get resolvedUrl(): IResolvedUrl {\n\t\treturn this.odspResolvedUrl;\n\t}\n\n\tpublic get currentDeltaConnection(): OdspDocumentDeltaConnection | undefined {\n\t\treturn this.currentConnection;\n\t}\n\n\tpublic get relayServiceTenantAndSessionId(): string | undefined {\n\t\treturn this._relayServiceTenantAndSessionId;\n\t}\n\n\t/**\n\t * Annotate the given error indicating which connection step failed\n\t */\n\tprivate annotateConnectionError(\n\t\terror: unknown,\n\t\tfailedConnectionStep: string,\n\t\tseparateTokenRequest: boolean,\n\t): IFluidErrorBase {\n\t\treturn normalizeError(error, {\n\t\t\tprops: {\n\t\t\t\tfailedConnectionStep,\n\t\t\t\tseparateTokenRequest,\n\t\t\t},\n\t\t});\n\t}\n\n\t/**\n\t * Connects to a delta stream endpoint for emitting ops.\n\t *\n\t * @returns returns the document delta stream service for onedrive/sharepoint driver.\n\t */\n\tpublic async connectToDeltaStream(client: IClient): Promise<IDocumentDeltaConnection> {\n\t\tassert(\n\t\t\tthis.currentConnection === undefined,\n\t\t\t0x4ad /* Should not be called when connection is already present! */,\n\t\t);\n\t\t// Attempt to connect twice, in case we used expired token.\n\t\treturn getWithRetryForTokenRefresh<IDocumentDeltaConnection>(async (options) => {\n\t\t\t// Presence of getWebsocketToken callback dictates whether callback is used for fetching\n\t\t\t// websocket token or whether it is returned with joinSession response payload\n\t\t\tconst requestWebsocketTokenFromJoinSession = this.getWebsocketToken === undefined;\n\t\t\tconst websocketTokenPromise = requestWebsocketTokenFromJoinSession\n\t\t\t\t? // eslint-disable-next-line unicorn/no-null\n\t\t\t\t\tPromise.resolve(null)\n\t\t\t\t: this.getWebsocketToken(options);\n\n\t\t\tconst annotateAndRethrowConnectionError = (step: string) => (error: unknown) => {\n\t\t\t\tthrow this.annotateConnectionError(error, step, !requestWebsocketTokenFromJoinSession);\n\t\t\t};\n\n\t\t\t// Log telemetry for join session attempt\n\t\t\tif (this.firstConnectionAttempt) {\n\t\t\t\tthis.mc.logger.sendTelemetryEvent({\n\t\t\t\t\teventName: \"FirstJoinSessionAttemptDetails\",\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\trequestWebsocketToken: requestWebsocketTokenFromJoinSession,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst joinSessionPromise = this.joinSession(\n\t\t\t\trequestWebsocketTokenFromJoinSession,\n\t\t\t\toptions,\n\t\t\t\tfalse /* isRefreshingJoinSession */,\n\t\t\t\tundefined /* clientId */,\n\t\t\t\tthis.hostPolicy.sessionOptions?.displayName,\n\t\t\t);\n\t\t\tconst [websocketEndpoint, websocketToken] = await Promise.all([\n\t\t\t\tjoinSessionPromise.catch(annotateAndRethrowConnectionError(\"joinSession\")),\n\t\t\t\twebsocketTokenPromise.catch(annotateAndRethrowConnectionError(\"getWebsocketToken\")),\n\t\t\t]);\n\n\t\t\t// eslint-disable-next-line unicorn/no-null\n\t\t\tconst finalWebsocketToken = websocketToken ?? websocketEndpoint.socketToken ?? null;\n\t\t\tif (finalWebsocketToken === null) {\n\t\t\t\tthrow this.annotateConnectionError(\n\t\t\t\t\tnew NonRetryableError(\"Websocket token is null\", OdspErrorTypes.fetchTokenError, {\n\t\t\t\t\t\tdriverVersion,\n\t\t\t\t\t}),\n\t\t\t\t\t\"getWebsocketToken\",\n\t\t\t\t\t!requestWebsocketTokenFromJoinSession,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (websocketEndpoint.sensitivityLabelsInfo !== undefined) {\n\t\t\t\tthis.emitSensitivityLabelUpdateEvent(websocketEndpoint.sensitivityLabelsInfo);\n\t\t\t}\n\n\t\t\tconst connectionId = uuid();\n\t\t\tif (this.firstConnectionAttempt) {\n\t\t\t\tthis.firstConnectionAttempt = false;\n\t\t\t\tthis.mc.logger.sendTelemetryEvent({\n\t\t\t\t\teventName: \"FirstConnectionAttemptDetails\",\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\tconnectionId,\n\t\t\t\t\t\ttenantId: websocketEndpoint.tenantId,\n\t\t\t\t\t\tdocumentId: websocketEndpoint.id,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst connection = await this.createDeltaConnection(\n\t\t\t\t\twebsocketEndpoint.tenantId,\n\t\t\t\t\twebsocketEndpoint.id,\n\t\t\t\t\tfinalWebsocketToken,\n\t\t\t\t\tclient,\n\t\t\t\t\twebsocketEndpoint.deltaStreamSocketUrl,\n\t\t\t\t\tconnectionId,\n\t\t\t\t);\n\t\t\t\tconnection.on(\"op\", (documentId, ops: ISequencedDocumentMessage[]) => {\n\t\t\t\t\tthis.opsReceived(ops);\n\t\t\t\t});\n\t\t\t\tconnection.on(\"signal\", this.signalHandler);\n\t\t\t\t// Also process the initial signals\n\t\t\t\tthis.signalHandler(connection.initialSignals);\n\t\t\t\t// On disconnect with 401/403 error code, we can just clear the joinSession cache as we will again\n\t\t\t\t// get the auth error on reconnecting and face latency.\n\t\t\t\tconnection.once(\"disconnect\", (error: unknown) => {\n\t\t\t\t\t// Clear the join session refresh timer so that it can be restarted on reconnection.\n\t\t\t\t\tthis.clearJoinSessionTimer();\n\t\t\t\t\tif (\n\t\t\t\t\t\ttypeof error === \"object\" &&\n\t\t\t\t\t\terror !== null &&\n\t\t\t\t\t\t(error as Partial<IOdspError>).errorType === OdspErrorTypes.authorizationError\n\t\t\t\t\t) {\n\t\t\t\t\t\tthis.cache.sessionJoinCache.remove(this.joinSessionKey);\n\t\t\t\t\t}\n\t\t\t\t\t// If we hit this assert, it means that \"disconnect\" event is emitted before the connection went through\n\t\t\t\t\t// dispose flow which is not correct and could lead to a bunch of errors.\n\t\t\t\t\tassert(connection.disposed, 0x4ae /* Connection should be disposed by now */);\n\t\t\t\t\tthis.currentConnection = undefined;\n\t\t\t\t});\n\t\t\t\tthis.currentConnection = connection;\n\t\t\t\treturn connection;\n\t\t\t} catch (error) {\n\t\t\t\t// Remove join session information from cache only if it is an error is from socket event connect_document_error.\n\t\t\t\t// Otherwise keep it in cache so that this session can be re-used after disconnection.\n\t\t\t\t// Also keeping an undefined check here to account for any unknown code path that is unable to stamp the value as in that case also\n\t\t\t\t// it is safer to clear join session cache and start over.\n\t\t\t\tif (\n\t\t\t\t\terror &&\n\t\t\t\t\ttypeof error === \"object\" &&\n\t\t\t\t\t((error as IAnyDriverError).scenarioName === \"connect_document_error\" ||\n\t\t\t\t\t\t(error as IAnyDriverError).scenarioName === undefined)\n\t\t\t\t) {\n\t\t\t\t\tthis.clearJoinSessionTimer();\n\t\t\t\t\tthis.cache.sessionJoinCache.remove(this.joinSessionKey);\n\t\t\t\t}\n\t\t\t\tconst normalizedError = this.annotateConnectionError(\n\t\t\t\t\terror,\n\t\t\t\t\t\"createDeltaConnection\",\n\t\t\t\t\t!requestWebsocketTokenFromJoinSession,\n\t\t\t\t);\n\t\t\t\tif (typeof error === \"object\" && error !== null) {\n\t\t\t\t\tnormalizedError.addTelemetryProperties({\n\t\t\t\t\t\tsocketDocumentId: websocketEndpoint.id,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tthrow normalizedError;\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate readonly signalHandler = (signalsArg: ISignalMessage | ISignalMessage[]): void => {\n\t\tconst signals = Array.isArray(signalsArg) ? signalsArg : [signalsArg];\n\t\tfor (const signal of signals) {\n\t\t\t// Make sure it is not for a specific client as `PolicyLabelsUpdate` is meant for all clients.\n\t\t\tif (signal.clientId === null) {\n\t\t\t\t// We could have some issues/irregularities in parsing signals, so put it in try/catch block\n\t\t\t\t// and ignore the error as we can have labels update later on through join session response.\n\t\t\t\tlet envelope: ISignalEnvelope | undefined;\n\t\t\t\ttry {\n\t\t\t\t\tenvelope = JSON.parse(signal.content as string) as ISignalEnvelope;\n\t\t\t\t} catch {\n\t\t\t\t\t// Drop error\n\t\t\t\t}\n\t\t\t\tif (envelope?.contents?.type === policyLabelsUpdatesSignalType) {\n\t\t\t\t\tthis.emitSensitivityLabelUpdateEvent(\n\t\t\t\t\t\tenvelope.contents.content as ISensitivityLabelsInfo,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\tprivate clearJoinSessionTimer(): void {\n\t\tif (this.joinSessionRefreshTimer !== undefined) {\n\t\t\tclearTimeout(this.joinSessionRefreshTimer);\n\t\t\tthis.joinSessionRefreshTimer = undefined;\n\t\t}\n\t}\n\n\tprivate async scheduleJoinSessionRefresh(\n\t\tdelta: number,\n\t\trequestSocketToken: boolean,\n\t\tclientId: string | undefined,\n\t\tdisplayName: string | undefined,\n\t): Promise<void> {\n\t\tif (this.joinSessionRefreshTimer !== undefined) {\n\t\t\tthis.clearJoinSessionTimer();\n\t\t\t// TODO: use a stronger type\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n\t\t\tconst originalStackTraceLimit = (Error as any).stackTraceLimit;\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n\t\t\t(Error as any).stackTraceLimit = 50;\n\t\t\tthis.mc.logger.sendTelemetryEvent(\n\t\t\t\t{\n\t\t\t\t\teventName: \"DuplicateJoinSessionRefresh\",\n\t\t\t\t},\n\t\t\t\tnew Error(\"DuplicateJoinSessionRefresh\"),\n\t\t\t);\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n\t\t\t(Error as any).stackTraceLimit = originalStackTraceLimit;\n\t\t}\n\n\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\tthis.joinSessionRefreshTimer = setTimeout(() => {\n\t\t\t\tthis.clearJoinSessionTimer();\n\t\t\t\t// Clear the timer as it is going to be scheduled again as part of refreshing join session.\n\t\t\t\tgetWithRetryForTokenRefresh(async (options) => {\n\t\t\t\t\tawait this.joinSession(\n\t\t\t\t\t\trequestSocketToken,\n\t\t\t\t\t\toptions,\n\t\t\t\t\t\ttrue /* isRefreshingJoinSession */,\n\t\t\t\t\t\tclientId,\n\t\t\t\t\t\tdisplayName,\n\t\t\t\t\t);\n\t\t\t\t\tresolve();\n\t\t\t\t}).catch((error) => {\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors\n\t\t\t\t\treject(error);\n\t\t\t\t});\n\t\t\t}, delta);\n\t\t});\n\t}\n\n\tprivate async joinSession(\n\t\trequestSocketToken: boolean,\n\t\toptions: TokenFetchOptionsEx,\n\t\tisRefreshingJoinSession: boolean,\n\t\tclientId: string | undefined,\n\t\tdisplayName: string | undefined,\n\t): Promise<ISocketStorageDiscovery> {\n\t\t// If this call is to refresh the join session for the current connection but we are already disconnected in\n\t\t// the meantime or disconnected and then reconnected then do not make the call. However, we should not have\n\t\t// come here if that is the case because timer should have been disposed, but due to race condition with the\n\t\t// timer we should not make the call and throw error.\n\t\tif (\n\t\t\tisRefreshingJoinSession &&\n\t\t\t(this.currentConnection === undefined ||\n\t\t\t\t(clientId !== undefined && this.currentConnection.clientId !== clientId))\n\t\t) {\n\t\t\tthis.clearJoinSessionTimer();\n\t\t\tthrow new NonRetryableError(\n\t\t\t\t\"JoinSessionRefreshTimerNotCancelled\",\n\t\t\t\tOdspErrorTypes.genericError,\n\t\t\t\t{\n\t\t\t\t\tdriverVersion,\n\t\t\t\t\tdetails: JSON.stringify({\n\t\t\t\t\t\tschedulerClientId: clientId,\n\t\t\t\t\t\tcurrentClientId: this.currentConnection?.clientId,\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t\tconst response = await this.joinSessionCore(\n\t\t\trequestSocketToken,\n\t\t\toptions,\n\t\t\tisRefreshingJoinSession,\n\t\t\tdisplayName,\n\t\t).catch((error) => {\n\t\t\tif (hasFacetCodes(error) && error.facetCodes !== undefined) {\n\t\t\t\tfor (const code of error.facetCodes) {\n\t\t\t\t\tswitch (code) {\n\t\t\t\t\t\tcase \"sessionForbidden\":\n\t\t\t\t\t\tcase \"sessionForbiddenOnPreservedFiles\":\n\t\t\t\t\t\tcase \"sessionForbiddenOnModerationEnabledLibrary\":\n\t\t\t\t\t\tcase \"sessionForbiddenOnRequireCheckout\":\n\t\t\t\t\t\tcase \"sessionForbiddenOnCheckoutFile\":\n\t\t\t\t\t\tcase \"sessionForbiddenOnInvisibleMinorVersion\": {\n\t\t\t\t\t\t\t// This document can only be opened in storage-only mode.\n\t\t\t\t\t\t\t// DeltaManager will recognize this error\n\t\t\t\t\t\t\t// and load without a delta stream connection.\n\t\t\t\t\t\t\tthis.policies = { ...this.policies, storageOnly: true };\n\t\t\t\t\t\t\tthrow new DeltaStreamConnectionForbiddenError(\n\t\t\t\t\t\t\t\t`Storage-only due to ${code}`,\n\t\t\t\t\t\t\t\t{ driverVersion },\n\t\t\t\t\t\t\t\tcode,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdefault: {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow error;\n\t\t});\n\t\tthis._relayServiceTenantAndSessionId = `${response.tenantId}/${response.id}`;\n\t\treturn response;\n\t}\n\n\tprivate async joinSessionCore(\n\t\trequestSocketToken: boolean,\n\t\toptions: TokenFetchOptionsEx,\n\t\tisRefreshingJoinSession: boolean,\n\t\tdisplayName: string | undefined,\n\t): Promise<ISocketStorageDiscovery> {\n\t\tconst disableJoinSessionRefresh = this.mc.config.getBoolean(\n\t\t\t\"Fluid.Driver.Odsp.disableJoinSessionRefresh\",\n\t\t);\n\t\t// Previous gate \"Fluid.Driver.Odsp.setSensitivityLabelHeader\" was removed because it was sensitive to a timestamp-related bug that was fixed by PR #26318; using this new gate ensures that the bug fix is present.\n\t\tconst setSensitivityLabelHeader = this.mc.config.getBoolean(\n\t\t\t\"Fluid.Driver.Odsp.setSensitivityLabelHeaderPostFix\",\n\t\t);\n\t\tconst executeFetch = async (): Promise<{\n\t\t\tentryTime: number;\n\t\t\tjoinSessionResponse: ISocketStorageDiscovery;\n\t\t}> => {\n\t\t\tconst joinSessionResponse = await fetchJoinSession(\n\t\t\t\tthis.odspResolvedUrl,\n\t\t\t\t\"opStream/joinSession\",\n\t\t\t\t\"POST\",\n\t\t\t\tthis.mc.logger,\n\t\t\t\tthis.getAuthHeader,\n\t\t\t\tthis.epochTracker,\n\t\t\t\trequestSocketToken,\n\t\t\t\toptions,\n\t\t\t\tdisableJoinSessionRefresh,\n\t\t\t\tsetSensitivityLabelHeader,\n\t\t\t\tisRefreshingJoinSession,\n\t\t\t\tdisplayName,\n\t\t\t);\n\t\t\t// Emit event only in case it is fetched from the network.\n\t\t\tif (joinSessionResponse.sensitivityLabelsInfo !== undefined) {\n\t\t\t\tthis.emitSensitivityLabelUpdateEvent(joinSessionResponse.sensitivityLabelsInfo);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tentryTime: Date.now(),\n\t\t\t\tjoinSessionResponse,\n\t\t\t};\n\t\t};\n\n\t\tconst getResponseAndRefreshAfterDeltaMs = async (): Promise<{\n\t\t\trefreshAfterDeltaMs: number;\n\t\t\tentryTime: number;\n\t\t\tjoinSessionResponse: ISocketStorageDiscovery;\n\t\t}> => {\n\t\t\tconst _response = await this.cache.sessionJoinCache.addOrGet(\n\t\t\t\tthis.joinSessionKey,\n\t\t\t\texecuteFetch,\n\t\t\t);\n\t\t\t// If the response does not contain refreshSessionDurationSeconds, then treat it as old flow and let the\n\t\t\t// cache entry to be treated as expired after 1 hour.\n\t\t\t_response.joinSessionResponse.refreshSessionDurationSeconds =\n\t\t\t\t_response.joinSessionResponse.refreshSessionDurationSeconds ?? 3600;\n\t\t\treturn {\n\t\t\t\t..._response,\n\t\t\t\trefreshAfterDeltaMs: this.calculateJoinSessionRefreshDelta(\n\t\t\t\t\t_response.entryTime,\n\t\t\t\t\t_response.joinSessionResponse.refreshSessionDurationSeconds,\n\t\t\t\t),\n\t\t\t};\n\t\t};\n\t\tlet response = await getResponseAndRefreshAfterDeltaMs();\n\t\t// This means that the cached entry has expired(This should not be possible if the response is fetched\n\t\t// from the network call). In this case we remove the cached entry and fetch the new response.\n\t\tif (response.refreshAfterDeltaMs <= 0) {\n\t\t\tthis.cache.sessionJoinCache.remove(this.joinSessionKey);\n\t\t\tresponse = await getResponseAndRefreshAfterDeltaMs();\n\t\t}\n\t\tif (!disableJoinSessionRefresh) {\n\t\t\tconst props = {\n\t\t\t\tentryTime: response.entryTime,\n\t\t\t\trefreshSessionDurationSeconds:\n\t\t\t\t\tresponse.joinSessionResponse.refreshSessionDurationSeconds,\n\t\t\t\trefreshAfterDeltaMs: response.refreshAfterDeltaMs,\n\t\t\t};\n\t\t\tif (response.refreshAfterDeltaMs > 0) {\n\t\t\t\tthis.scheduleJoinSessionRefresh(\n\t\t\t\t\tresponse.refreshAfterDeltaMs,\n\t\t\t\t\trequestSocketToken,\n\t\t\t\t\tthis.currentConnection?.clientId,\n\t\t\t\t\tdisplayName,\n\t\t\t\t).catch((error) => {\n\t\t\t\t\t// Log the error and do nothing as the reconnection would fetch the join session.\n\t\t\t\t\tthis.mc.logger.sendTelemetryEvent(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\teventName: \"JoinSessionRefreshError\",\n\t\t\t\t\t\t\tdetails: JSON.stringify(props),\n\t\t\t\t\t\t},\n\t\t\t\t\t\terror,\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t// Logging just for informational purposes to help with debugging as this is a new feature.\n\t\t\t\tthis.mc.logger.sendTelemetryEvent({\n\t\t\t\t\teventName: \"JoinSessionRefreshNotScheduled\",\n\t\t\t\t\tdetails: JSON.stringify(props),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn response.joinSessionResponse;\n\t}\n\n\tprivate emitSensitivityLabelUpdateEvent(\n\t\tsensitivityLabelsInfo: ISensitivityLabelsInfo,\n\t): void {\n\t\tconst createdTimestamp = sensitivityLabelsInfo.timestamp;\n\t\tassert(\n\t\t\ttypeof createdTimestamp === \"number\" && createdTimestamp > 0,\n\t\t\t0x8e0 /* time should be a positive number */,\n\t\t);\n\t\tif (createdTimestamp > this.labelUpdateTimestamp) {\n\t\t\tthis.labelUpdateTimestamp = createdTimestamp;\n\t\t\tthis.metadataUpdateHandler({\n\t\t\t\tsensitivityLabelsInfo: JSON.stringify(sensitivityLabelsInfo),\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate calculateJoinSessionRefreshDelta(\n\t\tresponseFetchTime: number,\n\t\trefreshSessionDurationSeconds: number,\n\t): number {\n\t\t// 30 seconds is buffer time to refresh the session.\n\t\treturn responseFetchTime + (refreshSessionDurationSeconds * 1000 - 30000) - Date.now();\n\t}\n\n\t/**\n\t * Creates a connection to the given delta stream endpoint\n\t *\n\t * @param tenantId - the ID of the tenant\n\t * @param documentId - document ID\n\t * @param token - authorization token for delta service\n\t * @param client - information about the client\n\t * @param webSocketUrl - websocket URL\n\t * @param connectionId - connection ID for the connection\n\t */\n\tprivate async createDeltaConnection(\n\t\ttenantId: string,\n\t\tdocumentId: string,\n\t\ttoken: string | null,\n\t\tclient: IClient,\n\t\twebSocketUrl: string,\n\t\tconnectionId: string,\n\t): Promise<OdspDocumentDeltaConnection> {\n\t\tconst startTime = performanceNow();\n\t\tconst connection = await OdspDocumentDeltaConnection.create(\n\t\t\ttenantId,\n\t\t\tdocumentId,\n\t\t\ttoken,\n\t\t\tclient,\n\t\t\twebSocketUrl,\n\t\t\tthis.mc.logger,\n\t\t\t60000,\n\t\t\tthis.epochTracker,\n\t\t\tthis.socketReferenceKeyPrefix,\n\t\t\tconnectionId,\n\t\t);\n\t\tconst duration = performanceNow() - startTime;\n\t\t// This event happens rather often, so it adds up to cost of telemetry.\n\t\t// Given that most reconnects result in reusing socket and happen very quickly,\n\t\t// report event only if it took longer than threshold.\n\t\tif (duration >= 2000) {\n\t\t\tthis.mc.logger.sendPerformanceEvent({\n\t\t\t\teventName: \"ConnectionSuccess\",\n\t\t\t\tduration,\n\t\t\t});\n\t\t}\n\t\treturn connection;\n\t}\n\n\tpublic dispose(error?: unknown): void {\n\t\tthis.clearJoinSessionTimer();\n\t\tthis.currentConnection?.dispose();\n\t\tthis.currentConnection = undefined;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"odspDelayLoadedDeltaStream.js","sourceRoot":"","sources":["../src/odspDelayLoadedDeltaStream.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { performanceNow } from \"@fluid-internal/client-utils\";\nimport type { ISignalEnvelope } from \"@fluidframework/core-interfaces/internal\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type { IClient } from \"@fluidframework/driver-definitions\";\nimport type {\n\tIDocumentDeltaConnection,\n\tIDocumentServicePolicies,\n\tIResolvedUrl,\n\tIAnyDriverError,\n\tISequencedDocumentMessage,\n\tISignalMessage,\n} from \"@fluidframework/driver-definitions/internal\";\nimport {\n\tDeltaStreamConnectionForbiddenError,\n\tNonRetryableError,\n} from \"@fluidframework/driver-utils/internal\";\nimport { hasFacetCodes } from \"@fluidframework/odsp-doclib-utils/internal\";\nimport {\n\ttype HostStoragePolicy,\n\ttype IOdspError,\n\ttype IOdspResolvedUrl,\n\ttype ISocketStorageDiscovery,\n\ttype ISensitivityLabelsInfo,\n\ttype InstrumentedStorageTokenFetcher,\n\tOdspErrorTypes,\n\ttype TokenFetchOptions,\n} from \"@fluidframework/odsp-driver-definitions/internal\";\nimport {\n\ttype IFluidErrorBase,\n\ttype MonitoringContext,\n\tnormalizeError,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport { v4 as uuid } from \"uuid\";\n\nimport { policyLabelsUpdatesSignalType } from \"./contracts.js\";\nimport type { EpochTracker } from \"./epochTracker.js\";\nimport type { IOdspCache } from \"./odspCache.js\";\nimport { OdspDocumentDeltaConnection } from \"./odspDocumentDeltaConnection.js\";\nimport {\n\ttype TokenFetchOptionsEx,\n\tgetJoinSessionCacheKey,\n\tgetWithRetryForTokenRefresh,\n} from \"./odspUtils.js\";\nimport { pkgVersion as driverVersion } from \"./packageVersion.js\";\nimport { fetchJoinSession } from \"./vroom.js\";\n\n/**\n * This OdspDelayLoadedDeltaStream is used by OdspDocumentService.ts to delay load the delta connection\n * as they are not on critical path of loading a container.\n */\nexport class OdspDelayLoadedDeltaStream {\n\t// Timer which runs and executes the join session call after intervals.\n\tprivate joinSessionRefreshTimer: ReturnType<typeof setTimeout> | undefined;\n\n\tprivate readonly joinSessionKey: string;\n\n\tprivate currentConnection?: OdspDocumentDeltaConnection;\n\n\tprivate _relayServiceTenantAndSessionId: string | undefined;\n\n\tprivate firstConnectionAttempt = true;\n\n\t// Tracks the time at which the Policy Labels were updated the last time. This is used to resolve race conditions\n\t// between label updates from the join session and the Fluid signals and they could have same or different timestamps.\n\t// So this timestamp is updated with timestamp from the service/signals with the most recent timestamp. We could also\n\t// receive stale data from join session as that call is made at intervals, so we need to update with only most recent data.\n\tprivate labelUpdateTimestamp: number = -1;\n\n\t/**\n\t * @param odspResolvedUrl - resolved url identifying document that will be managed by this service instance.\n\t * @param policies - Document service policies.\n\t * @param getAuthHeader - function that can provide the Authentication header value. This is is also referred to as\n\t * the \"Vroom\" token in SPO.\n\t * @param getWebsocketToken - function that can provide a token for accessing the web socket. This is also referred\n\t * to as the \"Push\" token in SPO. If undefined then websocket token is expected to be returned with joinSession\n\t * response payload.\n\t * @param mc - a logger that can capture performance and diagnostic information\n\t * @param cache - This caches response for joinSession.\n\t * @param hostPolicy - host constructed policy which customizes service behavior.\n\t * @param epochTracker - This helper class which adds epoch to backend calls made by this service instance.\n\t * @param opsReceived - To register the ops received through socket.\n\t * @param socketReferenceKeyPrefix - (optional) prefix to isolate socket reuse cache\n\t */\n\tpublic constructor(\n\t\tpublic readonly odspResolvedUrl: IOdspResolvedUrl,\n\t\tpublic policies: IDocumentServicePolicies,\n\t\tprivate readonly getAuthHeader: InstrumentedStorageTokenFetcher,\n\t\tprivate readonly getWebsocketToken:\n\t\t\t| ((options: TokenFetchOptions) => Promise<string | null>)\n\t\t\t| undefined,\n\t\tprivate readonly mc: MonitoringContext,\n\t\tprivate readonly cache: IOdspCache,\n\t\tprivate readonly hostPolicy: HostStoragePolicy,\n\t\tprivate readonly epochTracker: EpochTracker,\n\t\tprivate readonly opsReceived: (ops: ISequencedDocumentMessage[]) => void,\n\t\tprivate readonly metadataUpdateHandler: (metadata: Record<string, string>) => void,\n\t\tprivate readonly socketReferenceKeyPrefix?: string,\n\t) {\n\t\tthis.joinSessionKey = getJoinSessionCacheKey(this.odspResolvedUrl);\n\t}\n\n\tpublic get resolvedUrl(): IResolvedUrl {\n\t\treturn this.odspResolvedUrl;\n\t}\n\n\tpublic get currentDeltaConnection(): OdspDocumentDeltaConnection | undefined {\n\t\treturn this.currentConnection;\n\t}\n\n\tpublic get relayServiceTenantAndSessionId(): string | undefined {\n\t\treturn this._relayServiceTenantAndSessionId;\n\t}\n\n\t/**\n\t * Annotate the given error indicating which connection step failed\n\t */\n\tprivate annotateConnectionError(\n\t\terror: unknown,\n\t\tfailedConnectionStep: string,\n\t\tseparateTokenRequest: boolean,\n\t): IFluidErrorBase {\n\t\treturn normalizeError(error, {\n\t\t\tprops: {\n\t\t\t\tfailedConnectionStep,\n\t\t\t\tseparateTokenRequest,\n\t\t\t},\n\t\t});\n\t}\n\n\t/**\n\t * Connects to a delta stream endpoint for emitting ops.\n\t *\n\t * @returns returns the document delta stream service for onedrive/sharepoint driver.\n\t */\n\tpublic async connectToDeltaStream(client: IClient): Promise<IDocumentDeltaConnection> {\n\t\tassert(\n\t\t\tthis.currentConnection === undefined,\n\t\t\t0x4ad /* Should not be called when connection is already present! */,\n\t\t);\n\t\t// Attempt to connect twice, in case we used expired token.\n\t\treturn getWithRetryForTokenRefresh<IDocumentDeltaConnection>(async (options) => {\n\t\t\t// Presence of getWebsocketToken callback dictates whether callback is used for fetching\n\t\t\t// websocket token or whether it is returned with joinSession response payload\n\t\t\tconst requestWebsocketTokenFromJoinSession = this.getWebsocketToken === undefined;\n\t\t\tconst websocketTokenPromise = requestWebsocketTokenFromJoinSession\n\t\t\t\t? // eslint-disable-next-line unicorn/no-null\n\t\t\t\t\tPromise.resolve(null)\n\t\t\t\t: this.getWebsocketToken(options);\n\n\t\t\tconst annotateAndRethrowConnectionError = (step: string) => (error: unknown) => {\n\t\t\t\tthrow this.annotateConnectionError(error, step, !requestWebsocketTokenFromJoinSession);\n\t\t\t};\n\n\t\t\t// Log telemetry for join session attempt\n\t\t\tif (this.firstConnectionAttempt) {\n\t\t\t\tthis.mc.logger.sendTelemetryEvent({\n\t\t\t\t\teventName: \"FirstJoinSessionAttemptDetails\",\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\trequestWebsocketToken: requestWebsocketTokenFromJoinSession,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst joinSessionPromise = this.joinSession(\n\t\t\t\trequestWebsocketTokenFromJoinSession,\n\t\t\t\toptions,\n\t\t\t\tfalse /* isRefreshingJoinSession */,\n\t\t\t\tundefined /* clientId */,\n\t\t\t\tthis.hostPolicy.sessionOptions?.displayName,\n\t\t\t);\n\t\t\tconst [websocketEndpoint, websocketToken] = await Promise.all([\n\t\t\t\tjoinSessionPromise.catch(annotateAndRethrowConnectionError(\"joinSession\")),\n\t\t\t\twebsocketTokenPromise.catch(annotateAndRethrowConnectionError(\"getWebsocketToken\")),\n\t\t\t]);\n\n\t\t\t// eslint-disable-next-line unicorn/no-null\n\t\t\tconst finalWebsocketToken = websocketToken ?? websocketEndpoint.socketToken ?? null;\n\t\t\tif (finalWebsocketToken === null) {\n\t\t\t\tthrow this.annotateConnectionError(\n\t\t\t\t\tnew NonRetryableError(\"Websocket token is null\", OdspErrorTypes.fetchTokenError, {\n\t\t\t\t\t\tdriverVersion,\n\t\t\t\t\t}),\n\t\t\t\t\t\"getWebsocketToken\",\n\t\t\t\t\t!requestWebsocketTokenFromJoinSession,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (websocketEndpoint.sensitivityLabelsInfo !== undefined) {\n\t\t\t\tthis.emitSensitivityLabelUpdateEvent(websocketEndpoint.sensitivityLabelsInfo);\n\t\t\t}\n\n\t\t\tconst connectionId = uuid();\n\t\t\tif (this.firstConnectionAttempt) {\n\t\t\t\tthis.firstConnectionAttempt = false;\n\t\t\t\tthis.mc.logger.sendTelemetryEvent({\n\t\t\t\t\teventName: \"FirstConnectionAttemptDetails\",\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\tconnectionId,\n\t\t\t\t\t\ttenantId: websocketEndpoint.tenantId,\n\t\t\t\t\t\tdocumentId: websocketEndpoint.id,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst connection = await this.createDeltaConnection(\n\t\t\t\t\twebsocketEndpoint.tenantId,\n\t\t\t\t\twebsocketEndpoint.id,\n\t\t\t\t\tfinalWebsocketToken,\n\t\t\t\t\tclient,\n\t\t\t\t\twebsocketEndpoint.deltaStreamSocketUrl,\n\t\t\t\t\tconnectionId,\n\t\t\t\t);\n\t\t\t\tconnection.on(\"op\", (documentId, ops: ISequencedDocumentMessage[]) => {\n\t\t\t\t\tthis.opsReceived(ops);\n\t\t\t\t});\n\t\t\t\tconnection.on(\"signal\", this.signalHandler);\n\t\t\t\t// Also process the initial signals\n\t\t\t\tthis.signalHandler(connection.initialSignals);\n\t\t\t\t// On disconnect with 401/403 error code, we can just clear the joinSession cache as we will again\n\t\t\t\t// get the auth error on reconnecting and face latency.\n\t\t\t\tconnection.once(\"disconnect\", (error: unknown) => {\n\t\t\t\t\t// Clear the join session refresh timer so that it can be restarted on reconnection.\n\t\t\t\t\tthis.clearJoinSessionTimer();\n\t\t\t\t\tif (\n\t\t\t\t\t\ttypeof error === \"object\" &&\n\t\t\t\t\t\terror !== null &&\n\t\t\t\t\t\t(error as Partial<IOdspError>).errorType === OdspErrorTypes.authorizationError\n\t\t\t\t\t) {\n\t\t\t\t\t\tthis.cache.sessionJoinCache.remove(this.joinSessionKey);\n\t\t\t\t\t}\n\t\t\t\t\t// If we hit this assert, it means that \"disconnect\" event is emitted before the connection went through\n\t\t\t\t\t// dispose flow which is not correct and could lead to a bunch of errors.\n\t\t\t\t\tassert(connection.disposed, 0x4ae /* Connection should be disposed by now */);\n\t\t\t\t\tthis.currentConnection = undefined;\n\t\t\t\t});\n\t\t\t\tthis.currentConnection = connection;\n\t\t\t\treturn connection;\n\t\t\t} catch (error) {\n\t\t\t\t// Remove join session information from cache only if it is an error is from socket event connect_document_error.\n\t\t\t\t// Otherwise keep it in cache so that this session can be re-used after disconnection.\n\t\t\t\t// Also keeping an undefined check here to account for any unknown code path that is unable to stamp the value as in that case also\n\t\t\t\t// it is safer to clear join session cache and start over.\n\t\t\t\tif (\n\t\t\t\t\terror &&\n\t\t\t\t\ttypeof error === \"object\" &&\n\t\t\t\t\t((error as IAnyDriverError).scenarioName === \"connect_document_error\" ||\n\t\t\t\t\t\t(error as IAnyDriverError).scenarioName === undefined)\n\t\t\t\t) {\n\t\t\t\t\tthis.clearJoinSessionTimer();\n\t\t\t\t\tthis.cache.sessionJoinCache.remove(this.joinSessionKey);\n\t\t\t\t}\n\t\t\t\tconst normalizedError = this.annotateConnectionError(\n\t\t\t\t\terror,\n\t\t\t\t\t\"createDeltaConnection\",\n\t\t\t\t\t!requestWebsocketTokenFromJoinSession,\n\t\t\t\t);\n\t\t\t\tif (typeof error === \"object\" && error !== null) {\n\t\t\t\t\tnormalizedError.addTelemetryProperties({\n\t\t\t\t\t\tsocketDocumentId: websocketEndpoint.id,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tthrow normalizedError;\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate readonly signalHandler = (signalsArg: ISignalMessage | ISignalMessage[]): void => {\n\t\tconst signals = Array.isArray(signalsArg) ? signalsArg : [signalsArg];\n\t\tfor (const signal of signals) {\n\t\t\t// Make sure it is not for a specific client as `PolicyLabelsUpdate` is meant for all clients.\n\t\t\tif (signal.clientId === null) {\n\t\t\t\t// We could have some issues/irregularities in parsing signals, so put it in try/catch block\n\t\t\t\t// and ignore the error as we can have labels update later on through join session response.\n\t\t\t\tlet envelope: ISignalEnvelope | undefined;\n\t\t\t\ttry {\n\t\t\t\t\tenvelope = JSON.parse(signal.content as string) as ISignalEnvelope;\n\t\t\t\t} catch {\n\t\t\t\t\t// Drop error\n\t\t\t\t}\n\t\t\t\tif (envelope?.contents?.type === policyLabelsUpdatesSignalType) {\n\t\t\t\t\tthis.emitSensitivityLabelUpdateEvent(\n\t\t\t\t\t\tenvelope.contents.content as ISensitivityLabelsInfo,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\tprivate clearJoinSessionTimer(): void {\n\t\tif (this.joinSessionRefreshTimer !== undefined) {\n\t\t\tclearTimeout(this.joinSessionRefreshTimer);\n\t\t\tthis.joinSessionRefreshTimer = undefined;\n\t\t}\n\t}\n\n\tprivate async scheduleJoinSessionRefresh(\n\t\tdelta: number,\n\t\trequestSocketToken: boolean,\n\t\tclientId: string | undefined,\n\t\tdisplayName: string | undefined,\n\t): Promise<void> {\n\t\tif (this.joinSessionRefreshTimer !== undefined) {\n\t\t\tthis.clearJoinSessionTimer();\n\t\t\t// TODO: use a stronger type\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n\t\t\tconst originalStackTraceLimit = (Error as any).stackTraceLimit;\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n\t\t\t(Error as any).stackTraceLimit = 50;\n\t\t\tthis.mc.logger.sendTelemetryEvent(\n\t\t\t\t{\n\t\t\t\t\teventName: \"DuplicateJoinSessionRefresh\",\n\t\t\t\t},\n\t\t\t\tnew Error(\"DuplicateJoinSessionRefresh\"),\n\t\t\t);\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n\t\t\t(Error as any).stackTraceLimit = originalStackTraceLimit;\n\t\t}\n\n\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\tthis.joinSessionRefreshTimer = setTimeout(() => {\n\t\t\t\tthis.clearJoinSessionTimer();\n\t\t\t\t// Clear the timer as it is going to be scheduled again as part of refreshing join session.\n\t\t\t\tgetWithRetryForTokenRefresh(async (options) => {\n\t\t\t\t\tawait this.joinSession(\n\t\t\t\t\t\trequestSocketToken,\n\t\t\t\t\t\toptions,\n\t\t\t\t\t\ttrue /* isRefreshingJoinSession */,\n\t\t\t\t\t\tclientId,\n\t\t\t\t\t\tdisplayName,\n\t\t\t\t\t);\n\t\t\t\t\tresolve();\n\t\t\t\t}).catch((error) => {\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors\n\t\t\t\t\treject(error);\n\t\t\t\t});\n\t\t\t}, delta);\n\t\t});\n\t}\n\n\tprivate async joinSession(\n\t\trequestSocketToken: boolean,\n\t\toptions: TokenFetchOptionsEx,\n\t\tisRefreshingJoinSession: boolean,\n\t\tclientId: string | undefined,\n\t\tdisplayName: string | undefined,\n\t): Promise<ISocketStorageDiscovery> {\n\t\t// If this call is to refresh the join session for the current connection but we are already disconnected in\n\t\t// the meantime or disconnected and then reconnected then do not make the call. However, we should not have\n\t\t// come here if that is the case because timer should have been disposed, but due to race condition with the\n\t\t// timer we should not make the call and throw error.\n\t\tif (\n\t\t\tisRefreshingJoinSession &&\n\t\t\t(this.currentConnection === undefined ||\n\t\t\t\t(clientId !== undefined && this.currentConnection.clientId !== clientId))\n\t\t) {\n\t\t\tthis.clearJoinSessionTimer();\n\t\t\tthrow new NonRetryableError(\n\t\t\t\t\"JoinSessionRefreshTimerNotCancelled\",\n\t\t\t\tOdspErrorTypes.genericError,\n\t\t\t\t{\n\t\t\t\t\tdriverVersion,\n\t\t\t\t\tdetails: JSON.stringify({\n\t\t\t\t\t\tschedulerClientId: clientId,\n\t\t\t\t\t\tcurrentClientId: this.currentConnection?.clientId,\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t\tconst response = await this.joinSessionCore(\n\t\t\trequestSocketToken,\n\t\t\toptions,\n\t\t\tisRefreshingJoinSession,\n\t\t\tdisplayName,\n\t\t).catch((error) => {\n\t\t\tif (hasFacetCodes(error) && error.facetCodes !== undefined) {\n\t\t\t\tfor (const code of error.facetCodes) {\n\t\t\t\t\tswitch (code) {\n\t\t\t\t\t\tcase \"sessionForbidden\":\n\t\t\t\t\t\tcase \"sessionForbiddenOnPreservedFiles\":\n\t\t\t\t\t\tcase \"sessionForbiddenOnModerationEnabledLibrary\":\n\t\t\t\t\t\tcase \"sessionForbiddenOnRequireCheckout\":\n\t\t\t\t\t\tcase \"sessionForbiddenOnCheckoutFile\":\n\t\t\t\t\t\tcase \"sessionForbiddenOnInvisibleMinorVersion\": {\n\t\t\t\t\t\t\t// This document can only be opened in storage-only mode.\n\t\t\t\t\t\t\t// DeltaManager will recognize this error\n\t\t\t\t\t\t\t// and load without a delta stream connection.\n\t\t\t\t\t\t\tthis.policies = { ...this.policies, storageOnly: true };\n\t\t\t\t\t\t\tthrow new DeltaStreamConnectionForbiddenError(\n\t\t\t\t\t\t\t\t`Storage-only due to ${code}`,\n\t\t\t\t\t\t\t\t{ driverVersion },\n\t\t\t\t\t\t\t\tcode,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdefault: {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow error;\n\t\t});\n\t\tthis._relayServiceTenantAndSessionId = `${response.tenantId}/${response.id}`;\n\t\treturn response;\n\t}\n\n\tprivate async joinSessionCore(\n\t\trequestSocketToken: boolean,\n\t\toptions: TokenFetchOptionsEx,\n\t\tisRefreshingJoinSession: boolean,\n\t\tdisplayName: string | undefined,\n\t): Promise<ISocketStorageDiscovery> {\n\t\tconst disableJoinSessionRefresh = this.mc.config.getBoolean(\n\t\t\t\"Fluid.Driver.Odsp.disableJoinSessionRefresh\",\n\t\t);\n\t\tconst executeFetch = async (): Promise<{\n\t\t\tentryTime: number;\n\t\t\tjoinSessionResponse: ISocketStorageDiscovery;\n\t\t}> => {\n\t\t\tconst joinSessionResponse = await fetchJoinSession(\n\t\t\t\tthis.odspResolvedUrl,\n\t\t\t\t\"opStream/joinSession\",\n\t\t\t\t\"POST\",\n\t\t\t\tthis.mc.logger,\n\t\t\t\tthis.getAuthHeader,\n\t\t\t\tthis.epochTracker,\n\t\t\t\trequestSocketToken,\n\t\t\t\toptions,\n\t\t\t\tdisableJoinSessionRefresh,\n\t\t\t\tisRefreshingJoinSession,\n\t\t\t\tdisplayName,\n\t\t\t);\n\t\t\t// Emit event only in case it is fetched from the network.\n\t\t\tif (joinSessionResponse.sensitivityLabelsInfo !== undefined) {\n\t\t\t\tthis.emitSensitivityLabelUpdateEvent(joinSessionResponse.sensitivityLabelsInfo);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tentryTime: Date.now(),\n\t\t\t\tjoinSessionResponse,\n\t\t\t};\n\t\t};\n\n\t\tconst getResponseAndRefreshAfterDeltaMs = async (): Promise<{\n\t\t\trefreshAfterDeltaMs: number;\n\t\t\tentryTime: number;\n\t\t\tjoinSessionResponse: ISocketStorageDiscovery;\n\t\t}> => {\n\t\t\tconst _response = await this.cache.sessionJoinCache.addOrGet(\n\t\t\t\tthis.joinSessionKey,\n\t\t\t\texecuteFetch,\n\t\t\t);\n\t\t\t// If the response does not contain refreshSessionDurationSeconds, then treat it as old flow and let the\n\t\t\t// cache entry to be treated as expired after 1 hour.\n\t\t\t_response.joinSessionResponse.refreshSessionDurationSeconds =\n\t\t\t\t_response.joinSessionResponse.refreshSessionDurationSeconds ?? 3600;\n\t\t\treturn {\n\t\t\t\t..._response,\n\t\t\t\trefreshAfterDeltaMs: this.calculateJoinSessionRefreshDelta(\n\t\t\t\t\t_response.entryTime,\n\t\t\t\t\t_response.joinSessionResponse.refreshSessionDurationSeconds,\n\t\t\t\t),\n\t\t\t};\n\t\t};\n\t\tlet response = await getResponseAndRefreshAfterDeltaMs();\n\t\t// This means that the cached entry has expired(This should not be possible if the response is fetched\n\t\t// from the network call). In this case we remove the cached entry and fetch the new response.\n\t\tif (response.refreshAfterDeltaMs <= 0) {\n\t\t\tthis.cache.sessionJoinCache.remove(this.joinSessionKey);\n\t\t\tresponse = await getResponseAndRefreshAfterDeltaMs();\n\t\t}\n\t\tif (!disableJoinSessionRefresh) {\n\t\t\tconst props = {\n\t\t\t\tentryTime: response.entryTime,\n\t\t\t\trefreshSessionDurationSeconds:\n\t\t\t\t\tresponse.joinSessionResponse.refreshSessionDurationSeconds,\n\t\t\t\trefreshAfterDeltaMs: response.refreshAfterDeltaMs,\n\t\t\t};\n\t\t\tif (response.refreshAfterDeltaMs > 0) {\n\t\t\t\tthis.scheduleJoinSessionRefresh(\n\t\t\t\t\tresponse.refreshAfterDeltaMs,\n\t\t\t\t\trequestSocketToken,\n\t\t\t\t\tthis.currentConnection?.clientId,\n\t\t\t\t\tdisplayName,\n\t\t\t\t).catch((error) => {\n\t\t\t\t\t// Log the error and do nothing as the reconnection would fetch the join session.\n\t\t\t\t\tthis.mc.logger.sendTelemetryEvent(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\teventName: \"JoinSessionRefreshError\",\n\t\t\t\t\t\t\tdetails: JSON.stringify(props),\n\t\t\t\t\t\t},\n\t\t\t\t\t\terror,\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t// Logging just for informational purposes to help with debugging as this is a new feature.\n\t\t\t\tthis.mc.logger.sendTelemetryEvent({\n\t\t\t\t\teventName: \"JoinSessionRefreshNotScheduled\",\n\t\t\t\t\tdetails: JSON.stringify(props),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn response.joinSessionResponse;\n\t}\n\n\tprivate emitSensitivityLabelUpdateEvent(\n\t\tsensitivityLabelsInfo: ISensitivityLabelsInfo,\n\t): void {\n\t\tconst createdTimestamp = sensitivityLabelsInfo.timestamp;\n\t\tassert(\n\t\t\ttypeof createdTimestamp === \"number\" && createdTimestamp > 0,\n\t\t\t0x8e0 /* time should be a positive number */,\n\t\t);\n\t\tif (createdTimestamp > this.labelUpdateTimestamp) {\n\t\t\tthis.labelUpdateTimestamp = createdTimestamp;\n\t\t\tthis.metadataUpdateHandler({\n\t\t\t\tsensitivityLabelsInfo: JSON.stringify(sensitivityLabelsInfo),\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate calculateJoinSessionRefreshDelta(\n\t\tresponseFetchTime: number,\n\t\trefreshSessionDurationSeconds: number,\n\t): number {\n\t\t// 30 seconds is buffer time to refresh the session.\n\t\treturn responseFetchTime + (refreshSessionDurationSeconds * 1000 - 30000) - Date.now();\n\t}\n\n\t/**\n\t * Creates a connection to the given delta stream endpoint\n\t *\n\t * @param tenantId - the ID of the tenant\n\t * @param documentId - document ID\n\t * @param token - authorization token for delta service\n\t * @param client - information about the client\n\t * @param webSocketUrl - websocket URL\n\t * @param connectionId - connection ID for the connection\n\t */\n\tprivate async createDeltaConnection(\n\t\ttenantId: string,\n\t\tdocumentId: string,\n\t\ttoken: string | null,\n\t\tclient: IClient,\n\t\twebSocketUrl: string,\n\t\tconnectionId: string,\n\t): Promise<OdspDocumentDeltaConnection> {\n\t\tconst startTime = performanceNow();\n\t\tconst connection = await OdspDocumentDeltaConnection.create(\n\t\t\ttenantId,\n\t\t\tdocumentId,\n\t\t\ttoken,\n\t\t\tclient,\n\t\t\twebSocketUrl,\n\t\t\tthis.mc.logger,\n\t\t\t60000,\n\t\t\tthis.epochTracker,\n\t\t\tthis.socketReferenceKeyPrefix,\n\t\t\tconnectionId,\n\t\t);\n\t\tconst duration = performanceNow() - startTime;\n\t\t// This event happens rather often, so it adds up to cost of telemetry.\n\t\t// Given that most reconnects result in reusing socket and happen very quickly,\n\t\t// report event only if it took longer than threshold.\n\t\tif (duration >= 2000) {\n\t\t\tthis.mc.logger.sendPerformanceEvent({\n\t\t\t\teventName: \"ConnectionSuccess\",\n\t\t\t\tduration,\n\t\t\t});\n\t\t}\n\t\treturn connection;\n\t}\n\n\tpublic dispose(error?: unknown): void {\n\t\tthis.clearJoinSessionTimer();\n\t\tthis.currentConnection?.dispose();\n\t\tthis.currentConnection = undefined;\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"odspDeltaStorageService.d.ts","sourceRoot":"","sources":["../src/odspDeltaStorageService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"odspDeltaStorageService.d.ts","sourceRoot":"","sources":["../src/odspDeltaStorageService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAIhF,OAAO,KAAK,EACX,kBAAkB,EAClB,4BAA4B,EAC5B,OAAO,EACP,yBAAyB,EACzB,MAAM,6CAA6C,CAAC;AAErD,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,kDAAkD,CAAC;AACxG,OAAO,EACN,KAAK,mBAAmB,EAExB,MAAM,0CAA0C,CAAC;AAIlD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAGlF;;GAEG;AACH,qBAAa,uBAAuB;IAElC,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAHN,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,+BAA+B,EAC9C,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,mBAAmB;IAG7C;;;;;;;OAOG;IACU,GAAG,CACf,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,cAAc,EAAE,wBAAwB,EACxC,YAAY,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,kBAAkB,CAAC;IA4EvB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM;CAOjD;AAED,qBAAa,yBAA0B,YAAW,4BAA4B;IAI5E,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAM/B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAI1B,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,oBAAoB;IAnBtC,OAAO,CAAC,cAAc,CAAQ;gBAGrB,WAAW,EAAE,yBAAyB,EAAE,GAAG,SAAS,EAC3C,MAAM,EAAE,mBAAmB,EAC3B,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,CAChC,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,cAAc,EAAE,wBAAwB,EACxC,WAAW,CAAC,EAAE,MAAM,KAChB,OAAO,CAAC,kBAAkB,CAAC,EACf,SAAS,EAAE,CAC3B,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,KACN,OAAO,CAAC,yBAAyB,EAAE,CAAC,EACxB,iBAAiB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,EACrD,WAAW,EAAE,CAAC,GAAG,EAAE,yBAAyB,EAAE,KAAK,IAAI,EACvD,oBAAoB,EAAE,MAAM,0BAA0B,GAAG,SAAS;IAG7E,aAAa,CACnB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,WAAW,CAAC,EAAE,WAAW,EACzB,UAAU,CAAC,EAAE,OAAO,EACpB,WAAW,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,yBAAyB,EAAE,CAAC;CAiGvC"}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
+
import { LogLevel } from "@fluidframework/core-interfaces";
|
|
5
6
|
import { assert } from "@fluidframework/core-utils/internal";
|
|
6
7
|
import { validateMessages } from "@fluidframework/driver-base/internal";
|
|
7
8
|
import { requestOps, streamObserver } from "@fluidframework/driver-utils/internal";
|
|
@@ -166,7 +167,8 @@ export class OdspDeltaStorageWithCache {
|
|
|
166
167
|
opsFromCache,
|
|
167
168
|
opsFromStorage,
|
|
168
169
|
reason: fetchReason,
|
|
169
|
-
}
|
|
170
|
+
}, undefined, // error
|
|
171
|
+
LogLevel.info);
|
|
170
172
|
}
|
|
171
173
|
});
|
|
172
174
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"odspDeltaStorageService.js","sourceRoot":"","sources":["../src/odspDeltaStorageService.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { ITelemetryBaseProperties } from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport { validateMessages } from \"@fluidframework/driver-base/internal\";\nimport type {\n\tIDeltasFetchResult,\n\tIDocumentDeltaStorageService,\n\tIStream,\n\tISequencedDocumentMessage,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { requestOps, streamObserver } from \"@fluidframework/driver-utils/internal\";\nimport type { InstrumentedStorageTokenFetcher } from \"@fluidframework/odsp-driver-definitions/internal\";\nimport {\n\ttype ITelemetryLoggerExt,\n\tPerformanceEvent,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport { v4 as uuid } from \"uuid\";\n\nimport type { IDeltaStorageGetResponse, ISequencedDeltaOpMessage } from \"./contracts.js\";\nimport type { EpochTracker } from \"./epochTracker.js\";\nimport type { OdspDocumentStorageService } from \"./odspDocumentStorageManager.js\";\nimport { getWithRetryForTokenRefresh } from \"./odspUtils.js\";\n\n/**\n * Provides access to the underlying delta storage on the server for sharepoint driver.\n */\nexport class OdspDeltaStorageService {\n\tconstructor(\n\t\tprivate readonly deltaFeedUrl: string,\n\t\tprivate readonly getAuthHeader: InstrumentedStorageTokenFetcher,\n\t\tprivate readonly epochTracker: EpochTracker,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t) {}\n\n\t/**\n\t * Retrieves ops from storage\n\t * @param from - inclusive\n\t * @param to - exclusive\n\t * @param telemetryProps - properties to add when issuing telemetry events\n\t * @param scenarioName - reason for fetching ops\n\t * @returns ops retrieved & info if result was partial (i.e. more is available)\n\t */\n\tpublic async get(\n\t\tfrom: number,\n\t\tto: number,\n\t\ttelemetryProps: ITelemetryBaseProperties,\n\t\tscenarioName?: string,\n\t): Promise<IDeltasFetchResult> {\n\t\treturn getWithRetryForTokenRefresh(async (options) => {\n\t\t\t// Note - this call ends up in getSocketStorageDiscovery() and can refresh token\n\t\t\t// Thus it needs to be done before we call getAuthHeader() to reduce extra calls\n\t\t\tconst url = this.buildUrl(from, to);\n\t\t\tconst method = \"POST\";\n\t\t\tconst authHeader = await this.getAuthHeader(\n\t\t\t\t{ ...options, request: { url, method } },\n\t\t\t\t\"DeltaStorage\",\n\t\t\t);\n\n\t\t\treturn PerformanceEvent.timedExecAsync(\n\t\t\t\tthis.logger,\n\t\t\t\t{\n\t\t\t\t\teventName: \"OpsFetch\",\n\t\t\t\t\tattempts: options.refresh ? 2 : 1,\n\t\t\t\t\tfrom,\n\t\t\t\t\tto,\n\t\t\t\t\t...telemetryProps,\n\t\t\t\t\treason: scenarioName,\n\t\t\t\t},\n\t\t\t\tasync (event) => {\n\t\t\t\t\tconst formBoundary = uuid();\n\t\t\t\t\tlet postBody = `--${formBoundary}\\r\\n`;\n\t\t\t\t\tpostBody += `Authorization: ${authHeader}\\r\\n`;\n\t\t\t\t\tpostBody += `X-HTTP-Method-Override: GET\\r\\n`;\n\n\t\t\t\t\tpostBody += `_post: 1\\r\\n`;\n\t\t\t\t\tpostBody += `\\r\\n--${formBoundary}--`;\n\t\t\t\t\tconst headers: { [index: string]: string } = {\n\t\t\t\t\t\t\"Content-Type\": `multipart/form-data;boundary=${formBoundary}`,\n\t\t\t\t\t};\n\n\t\t\t\t\t// Some request take a long time (1-2 minutes) to complete, where telemetry shows very small amount\n\t\t\t\t\t// of time spent on server, and usually small payload sizes. I.e. all the time is spent somewhere in\n\t\t\t\t\t// networking. Even bigger problem - a lot of requests timeout (based on cursory look - after 1-2 minutes)\n\t\t\t\t\t// So adding some timeout to ensure we retry again in hope of faster success.\n\t\t\t\t\t// Please see https://github.com/microsoft/FluidFramework/issues/6997 for details.\n\t\t\t\t\tconst abort = new AbortController();\n\t\t\t\t\tconst timer = setTimeout(() => abort.abort(), 30000);\n\n\t\t\t\t\tconst response =\n\t\t\t\t\t\tawait this.epochTracker.fetchAndParseAsJSON<IDeltaStorageGetResponse>(\n\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\theaders,\n\t\t\t\t\t\t\t\tbody: postBody,\n\t\t\t\t\t\t\t\tmethod,\n\t\t\t\t\t\t\t\tsignal: abort.signal,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"ops\",\n\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\tscenarioName,\n\t\t\t\t\t\t);\n\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\tconst deltaStorageResponse = response.content;\n\t\t\t\t\tconst messages =\n\t\t\t\t\t\tdeltaStorageResponse.value.length > 0 && \"op\" in deltaStorageResponse.value[0]\n\t\t\t\t\t\t\t? (deltaStorageResponse.value as ISequencedDeltaOpMessage[]).map(\n\t\t\t\t\t\t\t\t\t(operation) => operation.op,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t: (deltaStorageResponse.value as ISequencedDocumentMessage[]);\n\n\t\t\t\t\tevent.end({\n\t\t\t\t\t\tlength: messages.length,\n\t\t\t\t\t\t...response.propsToLog,\n\t\t\t\t\t});\n\n\t\t\t\t\t// It is assumed that server always returns all the ops that it has in the range that was requested.\n\t\t\t\t\t// This may change in the future, if so, we need to adjust and receive \"end\" value from server in such case.\n\t\t\t\t\treturn { messages, partialResult: false };\n\t\t\t\t},\n\t\t\t);\n\t\t});\n\t}\n\n\tpublic buildUrl(from: number, to: number): string {\n\t\tconst filter = encodeURIComponent(\n\t\t\t`sequenceNumber ge ${from} and sequenceNumber le ${to - 1}`,\n\t\t);\n\t\tconst queryString = `?ump=1&filter=${filter}`;\n\t\treturn `${this.deltaFeedUrl}${queryString}`;\n\t}\n}\n\nexport class OdspDeltaStorageWithCache implements IDocumentDeltaStorageService {\n\tprivate useCacheForOps = true;\n\n\tpublic constructor(\n\t\tprivate snapshotOps: ISequencedDocumentMessage[] | undefined,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t\tprivate readonly batchSize: number,\n\t\tprivate readonly concurrency: number,\n\t\tprivate readonly getFromStorage: (\n\t\t\tfrom: number,\n\t\t\tto: number,\n\t\t\ttelemetryProps: ITelemetryBaseProperties,\n\t\t\tfetchReason?: string,\n\t\t) => Promise<IDeltasFetchResult>,\n\t\tprivate readonly getCached: (\n\t\t\tfrom: number,\n\t\t\tto: number,\n\t\t) => Promise<ISequencedDocumentMessage[]>,\n\t\tprivate readonly requestFromSocket: (from: number, to: number) => void,\n\t\tprivate readonly opsReceived: (ops: ISequencedDocumentMessage[]) => void,\n\t\tprivate readonly storageManagerGetter: () => OdspDocumentStorageService | undefined,\n\t) {}\n\n\tpublic fetchMessages(\n\t\tfromTotal: number,\n\t\ttoTotal: number | undefined,\n\t\tabortSignal?: AbortSignal,\n\t\tcachedOnly?: boolean,\n\t\tfetchReason?: string,\n\t): IStream<ISequencedDocumentMessage[]> {\n\t\t// We do not control what's in the cache. Current API assumes that fetchMessages() keeps banging on\n\t\t// storage / cache until it gets ops it needs. This would result in deadlock if fixed range is asked from\n\t\t// cache and it's not there.\n\t\t// Better implementation would be to return only what we have in cache, but that also breaks API\n\t\tassert(!cachedOnly || toTotal === undefined, 0x1e3);\n\n\t\t// Don't use cache for ops is snapshot is fetched from network or if it was not fetched at all.\n\t\tthis.useCacheForOps =\n\t\t\tthis.useCacheForOps && this.storageManagerGetter()?.isFirstSnapshotFromNetwork === false;\n\t\tlet opsFromSnapshot = 0;\n\t\tlet opsFromCache = 0;\n\t\tlet opsFromStorage = 0;\n\n\t\tconst requestCallback = async (\n\t\t\tfrom: number,\n\t\t\tto: number,\n\t\t\ttelemetryProps: ITelemetryBaseProperties,\n\t\t): Promise<IDeltasFetchResult> => {\n\t\t\tif (this.snapshotOps !== undefined && this.snapshotOps.length > 0) {\n\t\t\t\tconst messages = this.snapshotOps.filter(\n\t\t\t\t\t(op) => op.sequenceNumber >= from && op.sequenceNumber < to,\n\t\t\t\t);\n\t\t\t\tvalidateMessages(\"cached\", messages, from, this.logger);\n\t\t\t\tif (messages.length > 0 && messages[0].sequenceNumber === from) {\n\t\t\t\t\tthis.snapshotOps = this.snapshotOps.filter((op) => op.sequenceNumber >= to);\n\t\t\t\t\topsFromSnapshot += messages.length;\n\t\t\t\t\treturn { messages, partialResult: true };\n\t\t\t\t}\n\t\t\t\tthis.snapshotOps = undefined;\n\t\t\t}\n\n\t\t\t// Kick out request to PUSH for ops if it has them\n\t\t\tthis.requestFromSocket(from, to);\n\n\t\t\t// Cache in normal flow is continuous. Once there is a miss, stop consulting cache.\n\t\t\t// This saves a bit of processing time.\n\t\t\tif (this.useCacheForOps) {\n\t\t\t\tconst messagesFromCache = await this.getCached(from, to);\n\t\t\t\tvalidateMessages(\"cached\", messagesFromCache, from, this.logger);\n\t\t\t\t// Set the firstCacheMiss as true in case we didn't get all the ops.\n\t\t\t\t// This will save an extra cache read on \"DocumentOpen\" or \"PostDocumentOpen\".\n\t\t\t\tthis.useCacheForOps = from + messagesFromCache.length >= to;\n\t\t\t\tif (messagesFromCache.length > 0) {\n\t\t\t\t\topsFromCache += messagesFromCache.length;\n\t\t\t\t\treturn {\n\t\t\t\t\t\tmessages: messagesFromCache,\n\t\t\t\t\t\tpartialResult: true,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (cachedOnly) {\n\t\t\t\treturn { messages: [], partialResult: false };\n\t\t\t}\n\n\t\t\tconst ops = await this.getFromStorage(from, to, telemetryProps, fetchReason);\n\t\t\tvalidateMessages(\"storage\", ops.messages, from, this.logger);\n\t\t\topsFromStorage += ops.messages.length;\n\t\t\tthis.opsReceived(ops.messages);\n\t\t\treturn ops;\n\t\t};\n\n\t\tconst stream = requestOps(\n\t\t\tasync (from: number, to: number, telemetryProps: ITelemetryBaseProperties) => {\n\t\t\t\tconst result = await requestCallback(from, to, telemetryProps);\n\t\t\t\t// Catch all case, just in case\n\t\t\t\tvalidateMessages(\"catch all\", result.messages, from, this.logger);\n\t\t\t\treturn result;\n\t\t\t},\n\t\t\t// Staging: starting with no concurrency, listening for feedback first.\n\t\t\t// In future releases we will switch to actual concurrency\n\t\t\tthis.concurrency,\n\t\t\tfromTotal, // inclusive\n\t\t\ttoTotal, // exclusive\n\t\t\tthis.batchSize,\n\t\t\tthis.logger,\n\t\t\tabortSignal,\n\t\t\tfetchReason,\n\t\t);\n\n\t\treturn streamObserver(stream, (result) => {\n\t\t\tif (result.done && opsFromSnapshot + opsFromCache + opsFromStorage !== 0) {\n\t\t\t\tthis.logger.sendPerformanceEvent({\n\t\t\t\t\teventName: \"CacheOpsRetrieved\",\n\t\t\t\t\topsFromSnapshot,\n\t\t\t\t\topsFromCache,\n\t\t\t\t\topsFromStorage,\n\t\t\t\t\treason: fetchReason,\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"odspDeltaStorageService.js","sourceRoot":"","sources":["../src/odspDeltaStorageService.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { ITelemetryBaseProperties } from \"@fluidframework/core-interfaces\";\nimport { LogLevel } from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport { validateMessages } from \"@fluidframework/driver-base/internal\";\nimport type {\n\tIDeltasFetchResult,\n\tIDocumentDeltaStorageService,\n\tIStream,\n\tISequencedDocumentMessage,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { requestOps, streamObserver } from \"@fluidframework/driver-utils/internal\";\nimport type { InstrumentedStorageTokenFetcher } from \"@fluidframework/odsp-driver-definitions/internal\";\nimport {\n\ttype ITelemetryLoggerExt,\n\tPerformanceEvent,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport { v4 as uuid } from \"uuid\";\n\nimport type { IDeltaStorageGetResponse, ISequencedDeltaOpMessage } from \"./contracts.js\";\nimport type { EpochTracker } from \"./epochTracker.js\";\nimport type { OdspDocumentStorageService } from \"./odspDocumentStorageManager.js\";\nimport { getWithRetryForTokenRefresh } from \"./odspUtils.js\";\n\n/**\n * Provides access to the underlying delta storage on the server for sharepoint driver.\n */\nexport class OdspDeltaStorageService {\n\tconstructor(\n\t\tprivate readonly deltaFeedUrl: string,\n\t\tprivate readonly getAuthHeader: InstrumentedStorageTokenFetcher,\n\t\tprivate readonly epochTracker: EpochTracker,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t) {}\n\n\t/**\n\t * Retrieves ops from storage\n\t * @param from - inclusive\n\t * @param to - exclusive\n\t * @param telemetryProps - properties to add when issuing telemetry events\n\t * @param scenarioName - reason for fetching ops\n\t * @returns ops retrieved & info if result was partial (i.e. more is available)\n\t */\n\tpublic async get(\n\t\tfrom: number,\n\t\tto: number,\n\t\ttelemetryProps: ITelemetryBaseProperties,\n\t\tscenarioName?: string,\n\t): Promise<IDeltasFetchResult> {\n\t\treturn getWithRetryForTokenRefresh(async (options) => {\n\t\t\t// Note - this call ends up in getSocketStorageDiscovery() and can refresh token\n\t\t\t// Thus it needs to be done before we call getAuthHeader() to reduce extra calls\n\t\t\tconst url = this.buildUrl(from, to);\n\t\t\tconst method = \"POST\";\n\t\t\tconst authHeader = await this.getAuthHeader(\n\t\t\t\t{ ...options, request: { url, method } },\n\t\t\t\t\"DeltaStorage\",\n\t\t\t);\n\n\t\t\treturn PerformanceEvent.timedExecAsync(\n\t\t\t\tthis.logger,\n\t\t\t\t{\n\t\t\t\t\teventName: \"OpsFetch\",\n\t\t\t\t\tattempts: options.refresh ? 2 : 1,\n\t\t\t\t\tfrom,\n\t\t\t\t\tto,\n\t\t\t\t\t...telemetryProps,\n\t\t\t\t\treason: scenarioName,\n\t\t\t\t},\n\t\t\t\tasync (event) => {\n\t\t\t\t\tconst formBoundary = uuid();\n\t\t\t\t\tlet postBody = `--${formBoundary}\\r\\n`;\n\t\t\t\t\tpostBody += `Authorization: ${authHeader}\\r\\n`;\n\t\t\t\t\tpostBody += `X-HTTP-Method-Override: GET\\r\\n`;\n\n\t\t\t\t\tpostBody += `_post: 1\\r\\n`;\n\t\t\t\t\tpostBody += `\\r\\n--${formBoundary}--`;\n\t\t\t\t\tconst headers: { [index: string]: string } = {\n\t\t\t\t\t\t\"Content-Type\": `multipart/form-data;boundary=${formBoundary}`,\n\t\t\t\t\t};\n\n\t\t\t\t\t// Some request take a long time (1-2 minutes) to complete, where telemetry shows very small amount\n\t\t\t\t\t// of time spent on server, and usually small payload sizes. I.e. all the time is spent somewhere in\n\t\t\t\t\t// networking. Even bigger problem - a lot of requests timeout (based on cursory look - after 1-2 minutes)\n\t\t\t\t\t// So adding some timeout to ensure we retry again in hope of faster success.\n\t\t\t\t\t// Please see https://github.com/microsoft/FluidFramework/issues/6997 for details.\n\t\t\t\t\tconst abort = new AbortController();\n\t\t\t\t\tconst timer = setTimeout(() => abort.abort(), 30000);\n\n\t\t\t\t\tconst response =\n\t\t\t\t\t\tawait this.epochTracker.fetchAndParseAsJSON<IDeltaStorageGetResponse>(\n\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\theaders,\n\t\t\t\t\t\t\t\tbody: postBody,\n\t\t\t\t\t\t\t\tmethod,\n\t\t\t\t\t\t\t\tsignal: abort.signal,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"ops\",\n\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\tscenarioName,\n\t\t\t\t\t\t);\n\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\tconst deltaStorageResponse = response.content;\n\t\t\t\t\tconst messages =\n\t\t\t\t\t\tdeltaStorageResponse.value.length > 0 && \"op\" in deltaStorageResponse.value[0]\n\t\t\t\t\t\t\t? (deltaStorageResponse.value as ISequencedDeltaOpMessage[]).map(\n\t\t\t\t\t\t\t\t\t(operation) => operation.op,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t: (deltaStorageResponse.value as ISequencedDocumentMessage[]);\n\n\t\t\t\t\tevent.end({\n\t\t\t\t\t\tlength: messages.length,\n\t\t\t\t\t\t...response.propsToLog,\n\t\t\t\t\t});\n\n\t\t\t\t\t// It is assumed that server always returns all the ops that it has in the range that was requested.\n\t\t\t\t\t// This may change in the future, if so, we need to adjust and receive \"end\" value from server in such case.\n\t\t\t\t\treturn { messages, partialResult: false };\n\t\t\t\t},\n\t\t\t);\n\t\t});\n\t}\n\n\tpublic buildUrl(from: number, to: number): string {\n\t\tconst filter = encodeURIComponent(\n\t\t\t`sequenceNumber ge ${from} and sequenceNumber le ${to - 1}`,\n\t\t);\n\t\tconst queryString = `?ump=1&filter=${filter}`;\n\t\treturn `${this.deltaFeedUrl}${queryString}`;\n\t}\n}\n\nexport class OdspDeltaStorageWithCache implements IDocumentDeltaStorageService {\n\tprivate useCacheForOps = true;\n\n\tpublic constructor(\n\t\tprivate snapshotOps: ISequencedDocumentMessage[] | undefined,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t\tprivate readonly batchSize: number,\n\t\tprivate readonly concurrency: number,\n\t\tprivate readonly getFromStorage: (\n\t\t\tfrom: number,\n\t\t\tto: number,\n\t\t\ttelemetryProps: ITelemetryBaseProperties,\n\t\t\tfetchReason?: string,\n\t\t) => Promise<IDeltasFetchResult>,\n\t\tprivate readonly getCached: (\n\t\t\tfrom: number,\n\t\t\tto: number,\n\t\t) => Promise<ISequencedDocumentMessage[]>,\n\t\tprivate readonly requestFromSocket: (from: number, to: number) => void,\n\t\tprivate readonly opsReceived: (ops: ISequencedDocumentMessage[]) => void,\n\t\tprivate readonly storageManagerGetter: () => OdspDocumentStorageService | undefined,\n\t) {}\n\n\tpublic fetchMessages(\n\t\tfromTotal: number,\n\t\ttoTotal: number | undefined,\n\t\tabortSignal?: AbortSignal,\n\t\tcachedOnly?: boolean,\n\t\tfetchReason?: string,\n\t): IStream<ISequencedDocumentMessage[]> {\n\t\t// We do not control what's in the cache. Current API assumes that fetchMessages() keeps banging on\n\t\t// storage / cache until it gets ops it needs. This would result in deadlock if fixed range is asked from\n\t\t// cache and it's not there.\n\t\t// Better implementation would be to return only what we have in cache, but that also breaks API\n\t\tassert(!cachedOnly || toTotal === undefined, 0x1e3);\n\n\t\t// Don't use cache for ops is snapshot is fetched from network or if it was not fetched at all.\n\t\tthis.useCacheForOps =\n\t\t\tthis.useCacheForOps && this.storageManagerGetter()?.isFirstSnapshotFromNetwork === false;\n\t\tlet opsFromSnapshot = 0;\n\t\tlet opsFromCache = 0;\n\t\tlet opsFromStorage = 0;\n\n\t\tconst requestCallback = async (\n\t\t\tfrom: number,\n\t\t\tto: number,\n\t\t\ttelemetryProps: ITelemetryBaseProperties,\n\t\t): Promise<IDeltasFetchResult> => {\n\t\t\tif (this.snapshotOps !== undefined && this.snapshotOps.length > 0) {\n\t\t\t\tconst messages = this.snapshotOps.filter(\n\t\t\t\t\t(op) => op.sequenceNumber >= from && op.sequenceNumber < to,\n\t\t\t\t);\n\t\t\t\tvalidateMessages(\"cached\", messages, from, this.logger);\n\t\t\t\tif (messages.length > 0 && messages[0].sequenceNumber === from) {\n\t\t\t\t\tthis.snapshotOps = this.snapshotOps.filter((op) => op.sequenceNumber >= to);\n\t\t\t\t\topsFromSnapshot += messages.length;\n\t\t\t\t\treturn { messages, partialResult: true };\n\t\t\t\t}\n\t\t\t\tthis.snapshotOps = undefined;\n\t\t\t}\n\n\t\t\t// Kick out request to PUSH for ops if it has them\n\t\t\tthis.requestFromSocket(from, to);\n\n\t\t\t// Cache in normal flow is continuous. Once there is a miss, stop consulting cache.\n\t\t\t// This saves a bit of processing time.\n\t\t\tif (this.useCacheForOps) {\n\t\t\t\tconst messagesFromCache = await this.getCached(from, to);\n\t\t\t\tvalidateMessages(\"cached\", messagesFromCache, from, this.logger);\n\t\t\t\t// Set the firstCacheMiss as true in case we didn't get all the ops.\n\t\t\t\t// This will save an extra cache read on \"DocumentOpen\" or \"PostDocumentOpen\".\n\t\t\t\tthis.useCacheForOps = from + messagesFromCache.length >= to;\n\t\t\t\tif (messagesFromCache.length > 0) {\n\t\t\t\t\topsFromCache += messagesFromCache.length;\n\t\t\t\t\treturn {\n\t\t\t\t\t\tmessages: messagesFromCache,\n\t\t\t\t\t\tpartialResult: true,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (cachedOnly) {\n\t\t\t\treturn { messages: [], partialResult: false };\n\t\t\t}\n\n\t\t\tconst ops = await this.getFromStorage(from, to, telemetryProps, fetchReason);\n\t\t\tvalidateMessages(\"storage\", ops.messages, from, this.logger);\n\t\t\topsFromStorage += ops.messages.length;\n\t\t\tthis.opsReceived(ops.messages);\n\t\t\treturn ops;\n\t\t};\n\n\t\tconst stream = requestOps(\n\t\t\tasync (from: number, to: number, telemetryProps: ITelemetryBaseProperties) => {\n\t\t\t\tconst result = await requestCallback(from, to, telemetryProps);\n\t\t\t\t// Catch all case, just in case\n\t\t\t\tvalidateMessages(\"catch all\", result.messages, from, this.logger);\n\t\t\t\treturn result;\n\t\t\t},\n\t\t\t// Staging: starting with no concurrency, listening for feedback first.\n\t\t\t// In future releases we will switch to actual concurrency\n\t\t\tthis.concurrency,\n\t\t\tfromTotal, // inclusive\n\t\t\ttoTotal, // exclusive\n\t\t\tthis.batchSize,\n\t\t\tthis.logger,\n\t\t\tabortSignal,\n\t\t\tfetchReason,\n\t\t);\n\n\t\treturn streamObserver(stream, (result) => {\n\t\t\tif (result.done && opsFromSnapshot + opsFromCache + opsFromStorage !== 0) {\n\t\t\t\tthis.logger.sendPerformanceEvent(\n\t\t\t\t\t{\n\t\t\t\t\t\teventName: \"CacheOpsRetrieved\",\n\t\t\t\t\t\topsFromSnapshot,\n\t\t\t\t\t\topsFromCache,\n\t\t\t\t\t\topsFromStorage,\n\t\t\t\t\t\treason: fetchReason,\n\t\t\t\t\t},\n\t\t\t\t\tundefined, // error\n\t\t\t\t\tLogLevel.info,\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\t}\n}\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 = "2.
|
|
8
|
+
export declare const pkgVersion = "2.101.0";
|
|
9
9
|
//# sourceMappingURL=packageVersion.d.ts.map
|
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,SAAS,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/odsp-driver\";\nexport const pkgVersion = \"2.
|
|
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,SAAS,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/odsp-driver\";\nexport const pkgVersion = \"2.101.0\";\n"]}
|
package/lib/vroom.d.ts
CHANGED
|
@@ -18,11 +18,10 @@ import type { TokenFetchOptionsEx } from "./odspUtils.js";
|
|
|
18
18
|
* which is used when establishing websocket connection with collab session backend service.
|
|
19
19
|
* @param options - Options to fetch the token.
|
|
20
20
|
* @param disableJoinSessionRefresh - Whether the caller wants to disable refreshing join session periodically.
|
|
21
|
-
* @param setSensitivityLabelHeader - Whether the caller wants to set the Return-Sensitivity-Labels Prefer header in the join session request.
|
|
22
21
|
* @param isRefreshingJoinSession - whether call is to refresh the session before expiry.
|
|
23
22
|
* @param displayName - display name used to identify client joining a session.
|
|
24
23
|
* This is optional and used only when collab session is being joined by client acting in app-only mode (i.e. without user context).
|
|
25
24
|
* If not specified client display name is extracted from the access token that is used to join session.
|
|
26
25
|
*/
|
|
27
|
-
export declare const fetchJoinSession: import("./mockify.js").Mockable<(urlParts: IOdspUrlParts, path: string, method: "GET" | "POST", logger: ITelemetryLoggerExt, getAuthHeader: InstrumentedStorageTokenFetcher, epochTracker: EpochTracker, requestSocketToken: boolean, options: TokenFetchOptionsEx, disableJoinSessionRefresh: boolean | undefined,
|
|
26
|
+
export declare const fetchJoinSession: import("./mockify.js").Mockable<(urlParts: IOdspUrlParts, path: string, method: "GET" | "POST", logger: ITelemetryLoggerExt, getAuthHeader: InstrumentedStorageTokenFetcher, epochTracker: EpochTracker, requestSocketToken: boolean, options: TokenFetchOptionsEx, disableJoinSessionRefresh: boolean | undefined, isRefreshingJoinSession: boolean, displayName: string | undefined) => Promise<ISocketStorageDiscovery>>;
|
|
28
27
|
//# sourceMappingURL=vroom.d.ts.map
|
package/lib/vroom.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vroom.d.ts","sourceRoot":"","sources":["../src/vroom.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EACX,aAAa,EACb,uBAAuB,EACvB,+BAA+B,EAC/B,MAAM,kDAAkD,CAAC;AAC1D,OAAO,EACN,KAAK,mBAAmB,EAExB,MAAM,0CAA0C,CAAC;AAGlD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGtD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAQ1D
|
|
1
|
+
{"version":3,"file":"vroom.d.ts","sourceRoot":"","sources":["../src/vroom.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EACX,aAAa,EACb,uBAAuB,EACvB,+BAA+B,EAC/B,MAAM,kDAAkD,CAAC;AAC1D,OAAO,EACN,KAAK,mBAAmB,EAExB,MAAM,0CAA0C,CAAC;AAGlD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGtD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAQ1D;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,gBAAgB,6CAEjB,aAAa,QACjB,MAAM,UACJ,KAAK,GAAG,MAAM,UACd,mBAAmB,iBACZ,+BAA+B,gBAChC,YAAY,sBACN,OAAO,WAClB,mBAAmB,6BACD,OAAO,GAAG,SAAS,2BACrB,OAAO,eACnB,MAAM,GAAG,SAAS,KAC7B,QAAQ,uBAAuB,CAAC,CAuFnC,CAAC"}
|
package/lib/vroom.js
CHANGED
|
@@ -19,13 +19,12 @@ import { runWithRetry } from "./retryUtils.js";
|
|
|
19
19
|
* which is used when establishing websocket connection with collab session backend service.
|
|
20
20
|
* @param options - Options to fetch the token.
|
|
21
21
|
* @param disableJoinSessionRefresh - Whether the caller wants to disable refreshing join session periodically.
|
|
22
|
-
* @param setSensitivityLabelHeader - Whether the caller wants to set the Return-Sensitivity-Labels Prefer header in the join session request.
|
|
23
22
|
* @param isRefreshingJoinSession - whether call is to refresh the session before expiry.
|
|
24
23
|
* @param displayName - display name used to identify client joining a session.
|
|
25
24
|
* This is optional and used only when collab session is being joined by client acting in app-only mode (i.e. without user context).
|
|
26
25
|
* If not specified client display name is extracted from the access token that is used to join session.
|
|
27
26
|
*/
|
|
28
|
-
export const fetchJoinSession = mockify(async (urlParts, path, method, logger, getAuthHeader, epochTracker, requestSocketToken, options, disableJoinSessionRefresh,
|
|
27
|
+
export const fetchJoinSession = mockify(async (urlParts, path, method, logger, getAuthHeader, epochTracker, requestSocketToken, options, disableJoinSessionRefresh, isRefreshingJoinSession, displayName) => {
|
|
29
28
|
const apiRoot = getApiRoot(new URL(urlParts.siteUrl));
|
|
30
29
|
const url = `${apiRoot}/drives/${urlParts.driveId}/items/${urlParts.itemId}/${path}?ump=1`;
|
|
31
30
|
const authHeader = await getAuthHeader({ ...options, request: { url, method } }, "JoinSession");
|
|
@@ -37,7 +36,6 @@ export const fetchJoinSession = mockify(async (urlParts, path, method, logger, g
|
|
|
37
36
|
requestSocketToken,
|
|
38
37
|
...tokenRefreshProps,
|
|
39
38
|
refreshingSession: isRefreshingJoinSession,
|
|
40
|
-
setSensitivityLabelHeader: setSensitivityLabelHeader ?? false,
|
|
41
39
|
};
|
|
42
40
|
return PerformanceEvent.timedExecAsync(logger, {
|
|
43
41
|
eventName: "JoinSession",
|
|
@@ -53,9 +51,7 @@ export const fetchJoinSession = mockify(async (urlParts, path, method, logger, g
|
|
|
53
51
|
if (!disableJoinSessionRefresh) {
|
|
54
52
|
postBody += `Prefer: FluidRemoveCheckAccess\r\n`;
|
|
55
53
|
}
|
|
56
|
-
|
|
57
|
-
postBody += `Prefer: Return-Sensitivity-Labels\r\n`;
|
|
58
|
-
}
|
|
54
|
+
postBody += `Prefer: Return-Sensitivity-Labels\r\n`;
|
|
59
55
|
postBody += `_post: 1\r\n`;
|
|
60
56
|
let requestBody;
|
|
61
57
|
if (requestSocketToken) {
|
package/lib/vroom.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vroom.js","sourceRoot":"","sources":["../src/vroom.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,OAAO,EAEN,gBAAgB,GAChB,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAE,EAAE,IAAI,IAAI,EAAE,MAAM,MAAM,CAAC;AAGlC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAO/C
|
|
1
|
+
{"version":3,"file":"vroom.js","sourceRoot":"","sources":["../src/vroom.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { ITelemetryBaseProperties } from \"@fluidframework/core-interfaces\";\nimport type {\n\tIOdspUrlParts,\n\tISocketStorageDiscovery,\n\tInstrumentedStorageTokenFetcher,\n} from \"@fluidframework/odsp-driver-definitions/internal\";\nimport {\n\ttype ITelemetryLoggerExt,\n\tPerformanceEvent,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport { v4 as uuid } from \"uuid\";\n\nimport type { EpochTracker } from \"./epochTracker.js\";\nimport { mockify } from \"./mockify.js\";\nimport { getApiRoot } from \"./odspUrlHelper.js\";\nimport type { TokenFetchOptionsEx } from \"./odspUtils.js\";\nimport { runWithRetry } from \"./retryUtils.js\";\n\ninterface IJoinSessionBody {\n\trequestSocketToken?: boolean;\n\tdisplayName?: string;\n}\n\n/**\n * Makes join session call on SPO to get information about the web socket for a document\n * @param urlParts - The SPO drive id, itemId, siteUrl that this request should be made against\n * @param path - The API path that is relevant to this request\n * @param method - The type of request, such as GET or POST\n * @param logger - A logger to use for this request\n * @param getAuthHeader - A function that is able to provide the access token for this request\n * @param epochTracker - fetch wrapper which incorporates epoch logic around joinSession call\n * @param requestSocketToken - flag indicating whether joinSession is expected to return access token\n * which is used when establishing websocket connection with collab session backend service.\n * @param options - Options to fetch the token.\n * @param disableJoinSessionRefresh - Whether the caller wants to disable refreshing join session periodically.\n * @param isRefreshingJoinSession - whether call is to refresh the session before expiry.\n * @param displayName - display name used to identify client joining a session.\n * This is optional and used only when collab session is being joined by client acting in app-only mode (i.e. without user context).\n * If not specified client display name is extracted from the access token that is used to join session.\n */\nexport const fetchJoinSession = mockify(\n\tasync (\n\t\turlParts: IOdspUrlParts,\n\t\tpath: string,\n\t\tmethod: \"GET\" | \"POST\",\n\t\tlogger: ITelemetryLoggerExt,\n\t\tgetAuthHeader: InstrumentedStorageTokenFetcher,\n\t\tepochTracker: EpochTracker,\n\t\trequestSocketToken: boolean,\n\t\toptions: TokenFetchOptionsEx,\n\t\tdisableJoinSessionRefresh: boolean | undefined,\n\t\tisRefreshingJoinSession: boolean,\n\t\tdisplayName: string | undefined,\n\t): Promise<ISocketStorageDiscovery> => {\n\t\tconst apiRoot = getApiRoot(new URL(urlParts.siteUrl));\n\t\tconst url = `${apiRoot}/drives/${urlParts.driveId}/items/${urlParts.itemId}/${path}?ump=1`;\n\t\tconst authHeader = await getAuthHeader(\n\t\t\t{ ...options, request: { url, method } },\n\t\t\t\"JoinSession\",\n\t\t);\n\n\t\tconst tokenRefreshProps = options.refresh\n\t\t\t? { hasClaims: !!options.claims, hasTenantId: !!options.tenantId }\n\t\t\t: {};\n\t\tconst details: ITelemetryBaseProperties = {\n\t\t\trefreshedToken: options.refresh,\n\t\t\trequestSocketToken,\n\t\t\t...tokenRefreshProps,\n\t\t\trefreshingSession: isRefreshingJoinSession,\n\t\t};\n\n\t\treturn PerformanceEvent.timedExecAsync(\n\t\t\tlogger,\n\t\t\t{\n\t\t\t\teventName: \"JoinSession\",\n\t\t\t\tattempts: options.refresh ? 2 : 1,\n\t\t\t\tdetails: JSON.stringify(details),\n\t\t\t\t...tokenRefreshProps,\n\t\t\t},\n\t\t\tasync (event) => {\n\t\t\t\tconst formBoundary = uuid();\n\t\t\t\tlet postBody = `--${formBoundary}\\r\\n`;\n\t\t\t\tpostBody += `Authorization: ${authHeader}\\r\\n`;\n\t\t\t\tpostBody += `X-HTTP-Method-Override: POST\\r\\n`;\n\t\t\t\tpostBody += `Content-Type: application/json\\r\\n`;\n\t\t\t\tif (!disableJoinSessionRefresh) {\n\t\t\t\t\tpostBody += `Prefer: FluidRemoveCheckAccess\\r\\n`;\n\t\t\t\t}\n\t\t\t\tpostBody += `Prefer: Return-Sensitivity-Labels\\r\\n`;\n\t\t\t\tpostBody += `_post: 1\\r\\n`;\n\n\t\t\t\tlet requestBody: IJoinSessionBody | undefined;\n\t\t\t\tif (requestSocketToken) {\n\t\t\t\t\trequestBody = { ...requestBody, requestSocketToken: true };\n\t\t\t\t}\n\t\t\t\tif (displayName) {\n\t\t\t\t\trequestBody = { ...requestBody, displayName };\n\t\t\t\t}\n\t\t\t\tif (requestBody) {\n\t\t\t\t\tpostBody += `\\r\\n${JSON.stringify(requestBody)}\\r\\n`;\n\t\t\t\t}\n\t\t\t\tpostBody += `\\r\\n--${formBoundary}--`;\n\t\t\t\tconst headers: { [index: string]: string } = {\n\t\t\t\t\t\"Content-Type\": `multipart/form-data;boundary=${formBoundary}`,\n\t\t\t\t};\n\n\t\t\t\tconst response = await runWithRetry(\n\t\t\t\t\tasync () =>\n\t\t\t\t\t\tepochTracker.fetchAndParseAsJSON<ISocketStorageDiscovery>(\n\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\t{ method, headers, body: postBody },\n\t\t\t\t\t\t\t\"joinSession\",\n\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t),\n\t\t\t\t\t\"joinSession\",\n\t\t\t\t\tlogger,\n\t\t\t\t);\n\n\t\t\t\tconst socketUrl = response.content.deltaStreamSocketUrl;\n\t\t\t\t// expecting socketUrl to be something like https://{hostName}/...\n\t\t\t\tconst webSocketHostName = socketUrl.split(\"/\")[2];\n\n\t\t\t\t// TODO SPO-specific telemetry\n\t\t\t\tevent.end({\n\t\t\t\t\t...response.propsToLog,\n\t\t\t\t\t// pushV2 websocket urls will contain pushf\n\t\t\t\t\tpushv2: socketUrl.includes(\"pushf\"),\n\t\t\t\t\twebSocketHostName,\n\t\t\t\t\trefreshSessionDurationSeconds: response.content.refreshSessionDurationSeconds,\n\t\t\t\t\thasSensitivityLabelsInfo: response.content.sensitivityLabelsInfo !== undefined,\n\t\t\t\t});\n\n\t\t\t\tif (response.content.runtimeTenantId && !response.content.tenantId) {\n\t\t\t\t\tresponse.content.tenantId = response.content.runtimeTenantId;\n\t\t\t\t}\n\n\t\t\t\treturn response.content;\n\t\t\t},\n\t\t);\n\t},\n);\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/odsp-driver",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.101.0",
|
|
4
4
|
"description": "Socket storage implementation for SPO and ODC",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -69,22 +69,22 @@
|
|
|
69
69
|
"temp-directory": "nyc/.nyc_output"
|
|
70
70
|
},
|
|
71
71
|
"dependencies": {
|
|
72
|
-
"@fluid-internal/client-utils": "~2.
|
|
73
|
-
"@fluidframework/core-interfaces": "~2.
|
|
74
|
-
"@fluidframework/core-utils": "~2.
|
|
75
|
-
"@fluidframework/driver-base": "~2.
|
|
76
|
-
"@fluidframework/driver-definitions": "~2.
|
|
77
|
-
"@fluidframework/driver-utils": "~2.
|
|
78
|
-
"@fluidframework/odsp-doclib-utils": "~2.
|
|
79
|
-
"@fluidframework/odsp-driver-definitions": "~2.
|
|
80
|
-
"@fluidframework/telemetry-utils": "~2.
|
|
72
|
+
"@fluid-internal/client-utils": "~2.101.0",
|
|
73
|
+
"@fluidframework/core-interfaces": "~2.101.0",
|
|
74
|
+
"@fluidframework/core-utils": "~2.101.0",
|
|
75
|
+
"@fluidframework/driver-base": "~2.101.0",
|
|
76
|
+
"@fluidframework/driver-definitions": "~2.101.0",
|
|
77
|
+
"@fluidframework/driver-utils": "~2.101.0",
|
|
78
|
+
"@fluidframework/odsp-doclib-utils": "~2.101.0",
|
|
79
|
+
"@fluidframework/odsp-driver-definitions": "~2.101.0",
|
|
80
|
+
"@fluidframework/telemetry-utils": "~2.101.0",
|
|
81
81
|
"socket.io-client": "^4.8.3",
|
|
82
82
|
"uuid": "^11.1.0"
|
|
83
83
|
},
|
|
84
84
|
"devDependencies": {
|
|
85
85
|
"@arethetypeswrong/cli": "^0.18.2",
|
|
86
86
|
"@biomejs/biome": "~2.4.5",
|
|
87
|
-
"@fluid-internal/mocha-test-setup": "~2.
|
|
87
|
+
"@fluid-internal/mocha-test-setup": "~2.101.0",
|
|
88
88
|
"@fluid-tools/build-cli": "^0.65.0",
|
|
89
89
|
"@fluidframework/build-common": "^2.0.3",
|
|
90
90
|
"@fluidframework/build-tools": "^0.65.0",
|
|
@@ -416,10 +416,6 @@ export class OdspDelayLoadedDeltaStream {
|
|
|
416
416
|
const disableJoinSessionRefresh = this.mc.config.getBoolean(
|
|
417
417
|
"Fluid.Driver.Odsp.disableJoinSessionRefresh",
|
|
418
418
|
);
|
|
419
|
-
// Previous gate "Fluid.Driver.Odsp.setSensitivityLabelHeader" was removed because it was sensitive to a timestamp-related bug that was fixed by PR #26318; using this new gate ensures that the bug fix is present.
|
|
420
|
-
const setSensitivityLabelHeader = this.mc.config.getBoolean(
|
|
421
|
-
"Fluid.Driver.Odsp.setSensitivityLabelHeaderPostFix",
|
|
422
|
-
);
|
|
423
419
|
const executeFetch = async (): Promise<{
|
|
424
420
|
entryTime: number;
|
|
425
421
|
joinSessionResponse: ISocketStorageDiscovery;
|
|
@@ -434,7 +430,6 @@ export class OdspDelayLoadedDeltaStream {
|
|
|
434
430
|
requestSocketToken,
|
|
435
431
|
options,
|
|
436
432
|
disableJoinSessionRefresh,
|
|
437
|
-
setSensitivityLabelHeader,
|
|
438
433
|
isRefreshingJoinSession,
|
|
439
434
|
displayName,
|
|
440
435
|
);
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import type { ITelemetryBaseProperties } from "@fluidframework/core-interfaces";
|
|
7
|
+
import { LogLevel } from "@fluidframework/core-interfaces";
|
|
7
8
|
import { assert } from "@fluidframework/core-utils/internal";
|
|
8
9
|
import { validateMessages } from "@fluidframework/driver-base/internal";
|
|
9
10
|
import type {
|
|
@@ -246,13 +247,17 @@ export class OdspDeltaStorageWithCache implements IDocumentDeltaStorageService {
|
|
|
246
247
|
|
|
247
248
|
return streamObserver(stream, (result) => {
|
|
248
249
|
if (result.done && opsFromSnapshot + opsFromCache + opsFromStorage !== 0) {
|
|
249
|
-
this.logger.sendPerformanceEvent(
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
250
|
+
this.logger.sendPerformanceEvent(
|
|
251
|
+
{
|
|
252
|
+
eventName: "CacheOpsRetrieved",
|
|
253
|
+
opsFromSnapshot,
|
|
254
|
+
opsFromCache,
|
|
255
|
+
opsFromStorage,
|
|
256
|
+
reason: fetchReason,
|
|
257
|
+
},
|
|
258
|
+
undefined, // error
|
|
259
|
+
LogLevel.info,
|
|
260
|
+
);
|
|
256
261
|
}
|
|
257
262
|
});
|
|
258
263
|
}
|
package/src/packageVersion.ts
CHANGED
package/src/vroom.ts
CHANGED
|
@@ -38,7 +38,6 @@ interface IJoinSessionBody {
|
|
|
38
38
|
* which is used when establishing websocket connection with collab session backend service.
|
|
39
39
|
* @param options - Options to fetch the token.
|
|
40
40
|
* @param disableJoinSessionRefresh - Whether the caller wants to disable refreshing join session periodically.
|
|
41
|
-
* @param setSensitivityLabelHeader - Whether the caller wants to set the Return-Sensitivity-Labels Prefer header in the join session request.
|
|
42
41
|
* @param isRefreshingJoinSession - whether call is to refresh the session before expiry.
|
|
43
42
|
* @param displayName - display name used to identify client joining a session.
|
|
44
43
|
* This is optional and used only when collab session is being joined by client acting in app-only mode (i.e. without user context).
|
|
@@ -55,7 +54,6 @@ export const fetchJoinSession = mockify(
|
|
|
55
54
|
requestSocketToken: boolean,
|
|
56
55
|
options: TokenFetchOptionsEx,
|
|
57
56
|
disableJoinSessionRefresh: boolean | undefined,
|
|
58
|
-
setSensitivityLabelHeader: boolean | undefined,
|
|
59
57
|
isRefreshingJoinSession: boolean,
|
|
60
58
|
displayName: string | undefined,
|
|
61
59
|
): Promise<ISocketStorageDiscovery> => {
|
|
@@ -74,7 +72,6 @@ export const fetchJoinSession = mockify(
|
|
|
74
72
|
requestSocketToken,
|
|
75
73
|
...tokenRefreshProps,
|
|
76
74
|
refreshingSession: isRefreshingJoinSession,
|
|
77
|
-
setSensitivityLabelHeader: setSensitivityLabelHeader ?? false,
|
|
78
75
|
};
|
|
79
76
|
|
|
80
77
|
return PerformanceEvent.timedExecAsync(
|
|
@@ -94,9 +91,7 @@ export const fetchJoinSession = mockify(
|
|
|
94
91
|
if (!disableJoinSessionRefresh) {
|
|
95
92
|
postBody += `Prefer: FluidRemoveCheckAccess\r\n`;
|
|
96
93
|
}
|
|
97
|
-
|
|
98
|
-
postBody += `Prefer: Return-Sensitivity-Labels\r\n`;
|
|
99
|
-
}
|
|
94
|
+
postBody += `Prefer: Return-Sensitivity-Labels\r\n`;
|
|
100
95
|
postBody += `_post: 1\r\n`;
|
|
101
96
|
|
|
102
97
|
let requestBody: IJoinSessionBody | undefined;
|