@fluidframework/odsp-driver 0.52.1 → 0.53.0-46105

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/dist/createFile.d.ts.map +1 -1
  2. package/dist/createFile.js +5 -4
  3. package/dist/createFile.js.map +1 -1
  4. package/dist/epochTracker.d.ts +2 -1
  5. package/dist/epochTracker.d.ts.map +1 -1
  6. package/dist/epochTracker.js +50 -21
  7. package/dist/epochTracker.js.map +1 -1
  8. package/dist/fetchSnapshot.d.ts.map +1 -1
  9. package/dist/fetchSnapshot.js +15 -14
  10. package/dist/fetchSnapshot.js.map +1 -1
  11. package/dist/getFileLink.js +3 -3
  12. package/dist/getFileLink.js.map +1 -1
  13. package/dist/odspDeltaStorageService.d.ts +3 -3
  14. package/dist/odspDeltaStorageService.d.ts.map +1 -1
  15. package/dist/odspDeltaStorageService.js +7 -4
  16. package/dist/odspDeltaStorageService.js.map +1 -1
  17. package/dist/odspDocumentDeltaConnection.d.ts.map +1 -1
  18. package/dist/odspDocumentDeltaConnection.js +2 -0
  19. package/dist/odspDocumentDeltaConnection.js.map +1 -1
  20. package/dist/odspDocumentService.d.ts.map +1 -1
  21. package/dist/odspDocumentService.js +3 -3
  22. package/dist/odspDocumentService.js.map +1 -1
  23. package/dist/odspDocumentStorageManager.d.ts.map +1 -1
  24. package/dist/odspDocumentStorageManager.js +29 -26
  25. package/dist/odspDocumentStorageManager.js.map +1 -1
  26. package/dist/odspDriverUrlResolverForShareLink.d.ts.map +1 -1
  27. package/dist/odspDriverUrlResolverForShareLink.js +4 -3
  28. package/dist/odspDriverUrlResolverForShareLink.js.map +1 -1
  29. package/dist/odspError.d.ts.map +1 -1
  30. package/dist/odspError.js +3 -1
  31. package/dist/odspError.js.map +1 -1
  32. package/dist/odspUtils.d.ts.map +1 -1
  33. package/dist/odspUtils.js +31 -22
  34. package/dist/odspUtils.js.map +1 -1
  35. package/dist/packageVersion.d.ts +1 -1
  36. package/dist/packageVersion.d.ts.map +1 -1
  37. package/dist/packageVersion.js +1 -1
  38. package/dist/packageVersion.js.map +1 -1
  39. package/dist/zipItDataRepresentationUtils.d.ts.map +1 -1
  40. package/dist/zipItDataRepresentationUtils.js +3 -3
  41. package/dist/zipItDataRepresentationUtils.js.map +1 -1
  42. package/lib/createFile.d.ts.map +1 -1
  43. package/lib/createFile.js +6 -5
  44. package/lib/createFile.js.map +1 -1
  45. package/lib/epochTracker.d.ts +2 -1
  46. package/lib/epochTracker.d.ts.map +1 -1
  47. package/lib/epochTracker.js +50 -21
  48. package/lib/epochTracker.js.map +1 -1
  49. package/lib/fetchSnapshot.d.ts.map +1 -1
  50. package/lib/fetchSnapshot.js +15 -14
  51. package/lib/fetchSnapshot.js.map +1 -1
  52. package/lib/getFileLink.js +4 -4
  53. package/lib/getFileLink.js.map +1 -1
  54. package/lib/odspDeltaStorageService.d.ts +3 -3
  55. package/lib/odspDeltaStorageService.d.ts.map +1 -1
  56. package/lib/odspDeltaStorageService.js +7 -4
  57. package/lib/odspDeltaStorageService.js.map +1 -1
  58. package/lib/odspDocumentDeltaConnection.d.ts.map +1 -1
  59. package/lib/odspDocumentDeltaConnection.js +2 -0
  60. package/lib/odspDocumentDeltaConnection.js.map +1 -1
  61. package/lib/odspDocumentService.d.ts.map +1 -1
  62. package/lib/odspDocumentService.js +4 -4
  63. package/lib/odspDocumentService.js.map +1 -1
  64. package/lib/odspDocumentStorageManager.d.ts.map +1 -1
  65. package/lib/odspDocumentStorageManager.js +31 -28
  66. package/lib/odspDocumentStorageManager.js.map +1 -1
  67. package/lib/odspDriverUrlResolverForShareLink.d.ts.map +1 -1
  68. package/lib/odspDriverUrlResolverForShareLink.js +5 -4
  69. package/lib/odspDriverUrlResolverForShareLink.js.map +1 -1
  70. package/lib/odspError.d.ts.map +1 -1
  71. package/lib/odspError.js +3 -1
  72. package/lib/odspError.js.map +1 -1
  73. package/lib/odspUtils.d.ts.map +1 -1
  74. package/lib/odspUtils.js +33 -24
  75. package/lib/odspUtils.js.map +1 -1
  76. package/lib/packageVersion.d.ts +1 -1
  77. package/lib/packageVersion.d.ts.map +1 -1
  78. package/lib/packageVersion.js +1 -1
  79. package/lib/packageVersion.js.map +1 -1
  80. package/lib/zipItDataRepresentationUtils.d.ts.map +1 -1
  81. package/lib/zipItDataRepresentationUtils.js +3 -3
  82. package/lib/zipItDataRepresentationUtils.js.map +1 -1
  83. package/package.json +8 -8
  84. package/src/createFile.ts +13 -9
  85. package/src/epochTracker.ts +50 -20
  86. package/src/fetchSnapshot.ts +15 -8
  87. package/src/getFileLink.ts +10 -4
  88. package/src/odspDeltaStorageService.ts +10 -3
  89. package/src/odspDocumentDeltaConnection.ts +2 -0
  90. package/src/odspDocumentService.ts +8 -4
  91. package/src/odspDocumentStorageManager.ts +48 -28
  92. package/src/odspDriverUrlResolverForShareLink.ts +8 -3
  93. package/src/odspError.ts +5 -1
  94. package/src/odspUtils.ts +43 -34
  95. package/src/packageVersion.ts +1 -1
  96. package/src/zipItDataRepresentationUtils.ts +4 -7
@@ -1 +1 @@
1
- {"version":3,"file":"odspDocumentDeltaConnection.js","sourceRoot":"","sources":["../src/odspDocumentDeltaConnection.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger, IEvent } from \"@fluidframework/common-definitions\";\nimport { assert, performance, Deferred, TypedEventEmitter } from \"@fluidframework/common-utils\";\nimport { DocumentDeltaConnection } from \"@fluidframework/driver-base\";\nimport { DriverError } from \"@fluidframework/driver-definitions\";\nimport { OdspError } from \"@fluidframework/odsp-driver-definitions\";\nimport { LoggingError } from \"@fluidframework/telemetry-utils\";\nimport {\n IClient,\n IConnect,\n INack,\n ISequencedDocumentMessage,\n ISignalMessage,\n} from \"@fluidframework/protocol-definitions\";\nimport { v4 as uuid } from \"uuid\";\nimport { IOdspSocketError, IGetOpsResponse, IFlushOpsResponse } from \"./contracts\";\nimport { EpochTracker } from \"./epochTracker\";\nimport { errorObjectFromSocketError } from \"./odspError\";\n\nconst protocolVersions = [\"^0.4.0\", \"^0.3.0\", \"^0.2.0\", \"^0.1.0\"];\nconst feature_get_ops = \"api_get_ops\";\nconst feature_flush_ops = \"api_flush_ops\";\n\nexport interface FlushResult {\n lastPersistedSequenceNumber?: number;\n retryAfter?: number;\n}\n\n// How long to wait before disconnecting the socket after the last reference is removed\n// This allows reconnection after receiving a nack to be smooth\nconst socketReferenceBufferTime = 2000;\n\nexport interface ISocketEvents extends IEvent {\n (event: \"server_disconnect\", listener: (error: LoggingError & OdspError) => void);\n}\n\nclass SocketReference extends TypedEventEmitter<ISocketEvents> {\n private references: number = 1;\n private delayDeleteTimeout: ReturnType<typeof setTimeout> | undefined;\n private _socket: SocketIOClient.Socket | undefined;\n\n // When making decisions about socket reuse, we do not reuse disconnected socket.\n // But we want to differentiate the following case from disconnected case:\n // Socket that never connected and never failed, it's in \"attempting to connect\" mode\n // such sockets should be reused, despite socket.disconnected === true\n private isPendingInitialConnection = true;\n\n // Map of all existing socket io sockets. [url, tenantId, documentId] -> socket\n private static readonly socketIoSockets: Map<string, SocketReference> = new Map();\n\n public static find(key: string, logger: ITelemetryLogger) {\n const socketReference = SocketReference.socketIoSockets.get(key);\n\n // Verify the socket is healthy before reusing it\n if (socketReference && socketReference.disconnected) {\n // The socket is in a bad state. fully remove the reference\n socketReference.closeSocket();\n return undefined;\n }\n\n if (socketReference) {\n // Clear the pending deletion if there is one\n socketReference.clearTimer();\n socketReference.references++;\n }\n\n return socketReference;\n }\n\n /**\n * Removes a reference for the given key\n * Once the ref count hits 0, the socket is disconnected and removed\n * @param key - socket reference key\n * @param isFatalError - true if the socket reference should be removed immediately due to a fatal error\n */\n public removeSocketIoReference(isFatalError: boolean) {\n assert(this.references > 0, 0x09f /* \"No more socketIO refs to remove!\" */);\n this.references--;\n\n // see comment in disconnected() getter\n this.isPendingInitialConnection = false;\n\n if (isFatalError || this.disconnected) {\n this.closeSocket();\n return;\n }\n\n if (this.references === 0 && this.delayDeleteTimeout === undefined) {\n this.delayDeleteTimeout = setTimeout(() => {\n // We should not get here with active users.\n assert(this.references === 0, 0x0a0 /* \"Unexpected socketIO references on timeout\" */);\n this.closeSocket();\n }, socketReferenceBufferTime);\n }\n }\n\n public get socket() {\n if (!this._socket) {\n throw new Error(`Invalid socket for key \"${this.key}`);\n }\n return this._socket;\n }\n\n public constructor(public readonly key: string, socket: SocketIOClient.Socket) {\n super();\n\n this._socket = socket;\n assert(!SocketReference.socketIoSockets.has(key), 0x220 /* \"socket key collision\" */);\n SocketReference.socketIoSockets.set(key, this);\n\n // The server always closes the socket after sending this message\n // fully remove the socket reference now\n socket.on(\"server_disconnect\", (socketError: IOdspSocketError) => {\n // Treat all errors as recoverable, and rely on joinSession / reconnection flow to\n // filter out retryable vs. non-retryable cases.\n const error = errorObjectFromSocketError(socketError, \"server_disconnect\");\n error.canRetry = true;\n\n // see comment in disconnected() getter\n // Setting it here to ensure socket reuse does not happen if new request to connect\n // comes in from \"disconnect\" listener below, before we close socket.\n this.isPendingInitialConnection = false;\n\n this.emit(\"server_disconnect\", error);\n this.closeSocket();\n });\n }\n\n private clearTimer() {\n if (this.delayDeleteTimeout !== undefined) {\n clearTimeout(this.delayDeleteTimeout);\n this.delayDeleteTimeout = undefined;\n }\n }\n\n private closeSocket() {\n if (!this._socket) { return; }\n\n this.clearTimer();\n\n assert(SocketReference.socketIoSockets.get(this.key) === this,\n 0x0a1 /* \"Socket reference set unexpectedly does not point to this socket!\" */);\n SocketReference.socketIoSockets.delete(this.key);\n\n const socket = this._socket;\n this._socket = undefined;\n\n // Delay closing socket, to make sure all users of socket observe the same event that causes\n // this instance to close, and thus properly record reason for closure.\n // All event raising is synchronous, so clients will have a chance to react before socket is\n // closed without any extra data on why it was closed.\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n Promise.resolve().then(() => { socket.disconnect(); });\n }\n\n private get disconnected() {\n if (this._socket === undefined) { return true; }\n if (this.socket.connected) { return false; }\n\n // We have a socket that is not connected. Possible cases:\n // 1) It was connected some time ago and lost connection. We do not want to reuse it.\n // 2) It failed to connect (was never connected).\n // 3) It was just created and never had a chance to connect - connection is in process.\n // We have to differentiate 1 from 2-3 (specifically 1 & 3) in order to be able to reuse socket in #3.\n // We will use the fact that socket had some activity. I.e. if socket disconnected, or client stopped using\n // socket, then removeSocketIoReference() will be called for it, and it will be the indiction that it's not #3.\n return !this.isPendingInitialConnection;\n }\n}\n\n/**\n * Represents a connection to a stream of delta updates\n */\nexport class OdspDocumentDeltaConnection extends DocumentDeltaConnection {\n /**\n * Create a OdspDocumentDeltaConnection\n * If url #1 fails to connect, will try url #2 if applicable.\n *\n * @param tenantId - the ID of the tenant\n * @param documentId - document ID\n * @param token - authorization token for storage service\n * @param io - websocket library\n * @param client - information about the client\n * @param mode - mode of the client\n * @param url - websocket URL\n * @param telemetryLogger - optional telemetry logger\n * @param timeoutMs - time limit on making the connection\n * @param epochTracker - track epoch changes\n * @param socketReferenceKeyPrefix - (optional) prefix to isolate socket reuse cache\n */\n public static async create(\n tenantId: string,\n documentId: string,\n token: string | null,\n io: SocketIOClientStatic,\n client: IClient,\n url: string,\n telemetryLogger: ITelemetryLogger,\n timeoutMs: number,\n epochTracker: EpochTracker,\n socketReferenceKeyPrefix: string | undefined): Promise<OdspDocumentDeltaConnection> {\n // enable multiplexing when the websocket url does not include the tenant/document id\n const parsedUrl = new URL(url);\n const enableMultiplexing = !parsedUrl.searchParams.has(\"documentId\") && !parsedUrl.searchParams.has(\"tenantId\");\n\n // do not include the specific tenant/doc id in the ref key when multiplexing\n // this will allow multiple documents to share the same websocket connection\n const key = socketReferenceKeyPrefix ? `${socketReferenceKeyPrefix},${url}` : url;\n const socketReferenceKey = enableMultiplexing ? key : `${key},${tenantId},${documentId}`;\n\n const socketReference = OdspDocumentDeltaConnection.getOrCreateSocketIoReference(\n io, timeoutMs, socketReferenceKey, url, enableMultiplexing, tenantId, documentId, telemetryLogger);\n\n const socket = socketReference.socket;\n\n const connectMessage: IConnect = {\n client,\n id: documentId,\n mode: client.mode,\n tenantId,\n token, // Token is going to indicate tenant level information, etc...\n versions: protocolVersions,\n nonce: uuid(),\n epoch: epochTracker.fluidEpoch,\n };\n\n // Reference to this client supporting get_ops flow.\n // back-compat: remove cast to any once new definition of IConnect comes through.\n (connectMessage as any).supportedFeatures = { [feature_get_ops]: true };\n\n const deltaConnection = new OdspDocumentDeltaConnection(\n socket,\n documentId,\n socketReference,\n telemetryLogger,\n enableMultiplexing);\n\n try {\n await deltaConnection.initialize(connectMessage, timeoutMs);\n await epochTracker.validateEpochFromPush(deltaConnection.details);\n } catch (errorObject) {\n if (errorObject !== null && typeof errorObject === \"object\") {\n // We have to special-case error types here in terms of what is re-triable.\n // These errors have to re-retried, we just need new joinSession result to connect to right server:\n // 400: Invalid tenant or document id. The WebSocket is connected to a different document\n // Document is full (with retryAfter)\n // 404: Invalid document. The document \\\"local/w1-...\\\" does not exist\n // But this has to stay not-retriable:\n // 406: Unsupported client protocol. This path is the only gatekeeper, have to fail!\n // 409: Epoch Version Mismatch. Client epoch and server epoch does not match, so app needs\n // to be refreshed.\n // This one is fine either way\n // 401/403: Code will retry once with new token either way, then it becomes fatal - on this path\n // and on join Session path.\n // 501: (Fluid not enabled): this is fine either way, as joinSession is gatekeeper\n if (errorObject.statusCode === 400 || errorObject.statusCode === 404) {\n errorObject.canRetry = true;\n }\n }\n throw errorObject;\n }\n\n return deltaConnection;\n }\n\n private socketReference: SocketReference | undefined;\n\n private readonly requestOpsNoncePrefix: string;\n private pushCallCounter = 0;\n private readonly getOpsMap: Map<string, { start: number, from: number, to: number }> = new Map();\n private flushOpNonce: string | undefined;\n private flushDeferred: Deferred<FlushResult> | undefined;\n\n /**\n * Error raising for socket.io issues\n */\n protected createErrorObject(handler: string, error?: any, canRetry = true): DriverError {\n // Note: we suspect the incoming error object is either:\n // - a socketError: add it to the OdspError object for driver to be able to parse it and reason over it.\n // - anything else: let base class handle it\n if (canRetry && Number.isInteger(error?.code) && typeof error?.message === \"string\") {\n return errorObjectFromSocketError(error as IOdspSocketError, handler) as DriverError;\n } else {\n return super.createErrorObject(handler, error, canRetry);\n }\n }\n\n /**\n * Gets or create a socket io connection for the given key\n */\n private static getOrCreateSocketIoReference(\n io: SocketIOClientStatic,\n timeoutMs: number,\n key: string,\n url: string,\n enableMultiplexing: boolean,\n tenantId: string,\n documentId: string,\n logger: ITelemetryLogger,\n ): SocketReference {\n const existingSocketReference = SocketReference.find(key, logger);\n if (existingSocketReference) {\n return existingSocketReference;\n }\n\n const query = enableMultiplexing ? undefined : { documentId, tenantId };\n\n const socket = io(\n url,\n {\n multiplex: false, // Don't rely on socket.io built-in multiplexing\n query,\n reconnection: false,\n transports: [\"websocket\"],\n timeout: timeoutMs,\n });\n\n return new SocketReference(key, socket);\n }\n\n /**\n * @param socket - websocket to be used\n * @param documentId - ID of the document\n * @param details - details of the websocket connection\n * @param socketReferenceKey - socket reference key\n * @param enableMultiplexing - If the websocket is multiplexing multiple documents\n */\n private constructor(\n socket: SocketIOClient.Socket,\n documentId: string,\n socketReference: SocketReference,\n logger: ITelemetryLogger,\n private readonly enableMultiplexing?: boolean,\n ) {\n super(socket, documentId, logger);\n this.socketReference = socketReference;\n this.requestOpsNoncePrefix = `${uuid()}-`;\n }\n\n /**\n * Retrieves ops from PUSH\n * @param from - inclusive\n * @param to - exclusive\n * @returns ops retrieved\n */\n public requestOps(from: number, to: number) {\n // Given that to is exclusive, we should be asking for at least something!\n assert(to > from, 0x272 /* \"empty request\" */);\n\n // PUSH may disable this functionality\n // back-compat: remove cast to any once latest version of IConnected is consumed\n if ((this.details as any).supportedFeatures?.[feature_get_ops] !== true) {\n return;\n }\n\n this.pushCallCounter++;\n const nonce = `${this.requestOpsNoncePrefix}${this.pushCallCounter}`;\n const start = performance.now();\n\n // We may keep keep accumulating memory for nothing, if we are not getting responses.\n // Note that we should not have overlapping requests, as DeltaManager allows only one\n // outstanding request to storage, and that's the only way to get here.\n // But requests could be cancelled, and thus overlapping requests might be in the picture\n // If it happens, we do not care about stale requests.\n // So track some number of requests, but log if we get too many in flight - that likely\n // indicates an error somewhere.\n if (this.getOpsMap.size >= 5) {\n let time = start;\n let key: string | undefined;\n for (const [keyCandidate, value] of this.getOpsMap.entries()) {\n if (value.start <= time || key === undefined) {\n time = value.start;\n key = keyCandidate;\n }\n }\n const payloadToDelete = this.getOpsMap.get(key!)!;\n this.logger.sendErrorEvent({\n eventName: \"GetOpsTooMany\",\n nonce,\n from: payloadToDelete.from,\n to: payloadToDelete.to,\n length: payloadToDelete.to - payloadToDelete.from,\n duration: performance.now() - payloadToDelete.start,\n });\n this.getOpsMap.delete(key!);\n }\n this.getOpsMap.set(\n nonce,\n {\n start,\n from,\n to,\n },\n );\n this.socket.emit(\"get_ops\", this.clientId, {\n nonce,\n from,\n to: to - 1,\n });\n }\n\n public async flush(): Promise<FlushResult> {\n // back-compat: remove cast to any once latest version of IConnected is consumed\n if ((this.details as any).supportedFeatures?.[feature_flush_ops] !== true) {\n // Once single-commit summary is enabled end-to-end, flush support is a must!\n // The only alternative is change in design where SPO fetches ops from PUSH OR\n // summary includes required ops and SPO has some validation mechanism to ensure\n // they are not forged by client.\n // If design changes, we can reconsider it, but right now it's non-recoverable failure.\n this.logger.sendErrorEvent({ eventName: \"FlushOpsNotSupported\" });\n throw new Error(\"flush() API is not supported by PUSH, required for single-commit summaries\");\n }\n\n this.pushCallCounter++;\n const nonce = `${this.requestOpsNoncePrefix}${this.pushCallCounter}`;\n // There should be only one flush ops in flight, kicked out by upload summary workflow\n // That said, it could timeout, and request could be repeated, so theoretically we can\n // get overlapping requests, but it should be very rare\n if (this.flushDeferred !== undefined) {\n this.logger.sendErrorEvent({ eventName: \"FlushOpsTooMany\" });\n this.flushDeferred.reject(\"process involving flush() was cancelled OR unsupported concurrency\");\n }\n this.socket.emit(\"flush_ops\", this.clientId, { nonce });\n\n this.flushOpNonce = nonce;\n this.flushDeferred = new Deferred<FlushResult>();\n return this.flushDeferred.promise;\n }\n\n protected serverDisconnectHandler = (error: LoggingError & OdspError) => {\n this.disposeCore(true, error);\n };\n\n protected async initialize(connectMessage: IConnect, timeout: number) {\n if (this.enableMultiplexing) {\n // multiplex compatible early handlers\n this.earlyOpHandler = (messageDocumentId: string, msgs: ISequencedDocumentMessage[]) => {\n if (this.documentId === messageDocumentId) {\n this.queuedMessages.push(...msgs);\n }\n };\n\n this.earlySignalHandler = (msg: ISignalMessage, messageDocumentId?: string) => {\n if (messageDocumentId === undefined || messageDocumentId === this.documentId) {\n this.queuedSignals.push(msg);\n }\n };\n }\n\n this.socketReference!.once(\"server_disconnect\", this.serverDisconnectHandler);\n\n this.socket.on(\"get_ops_response\", (result: IGetOpsResponse) => {\n const messages = result.messages;\n const data = this.getOpsMap.get(result.nonce);\n // Due to socket multiplexing, this client may not have asked for any data\n // If so, there it most likely does not need these ops (otherwise it already asked for them)\n // Also we may have deleted entry in this.getOpsMap due to too many requests and too slow response.\n // But not processing such result may push us into infinite loop of fast requests and dropping all responses\n if (data !== undefined || result.nonce.indexOf(this.requestOpsNoncePrefix) === 0) {\n this.getOpsMap.delete(result.nonce);\n const common = {\n eventName: \"GetOps\",\n // We need nonce only to pair with GetOpsTooMany events, i.e. when record was deleted\n nonce: data === undefined ? result.nonce : undefined,\n code: result.code,\n from: data?.from,\n to: data?.to,\n duration: data === undefined ? undefined : performance.now() - data.start,\n };\n if (messages !== undefined && messages.length > 0) {\n this.logger.sendPerformanceEvent({\n ...common,\n first: messages[0].sequenceNumber,\n last: messages[messages.length - 1].sequenceNumber,\n length: messages.length,\n });\n this.emit(\"op\", this.documentId, messages);\n } else {\n this.logger.sendPerformanceEvent({\n ...common,\n length: 0,\n });\n }\n }\n });\n\n this.socket.on(\"flush_ops_response\", (result: IFlushOpsResponse) => {\n if (this.flushOpNonce === result.nonce) {\n const seq = result.lastPersistedSequenceNumber;\n let category: \"generic\" | \"error\" = \"generic\";\n if (result.lastPersistedSequenceNumber === undefined || result.code !== 200) {\n switch (result.code) {\n case 409:\n case 429:\n category = \"error\";\n break;\n case 204:\n break;\n default:\n category = \"error\";\n break;\n }\n }\n this.logger.sendTelemetryEvent({\n eventName: \"FlushResult\",\n code: result.code,\n sequenceNumber: seq,\n category,\n });\n this.flushDeferred!.resolve(result);\n this.flushDeferred = undefined;\n this.flushOpNonce = undefined;\n }\n });\n\n await super.initialize(connectMessage, timeout);\n }\n\n protected addTrackedListener(event: string, listener: (...args: any[]) => void) {\n // override some event listeners in order to support multiple documents/clients over the same websocket\n switch (event) {\n case \"op\":\n // per document op handling\n super.addTrackedListener(event, (documentId: string, msgs: ISequencedDocumentMessage[]) => {\n if (!this.enableMultiplexing || this.documentId === documentId) {\n listener(documentId, msgs);\n }\n });\n break;\n\n case \"signal\":\n // per document signal handling\n super.addTrackedListener(event, (msg: ISignalMessage, documentId?: string) => {\n if (!this.enableMultiplexing || !documentId || documentId === this.documentId) {\n listener(msg, documentId);\n }\n });\n break;\n\n case \"nack\":\n // per client / document nack handling\n super.addTrackedListener(event, (clientIdOrDocumentId: string, message: INack[]) => {\n if (clientIdOrDocumentId.length === 0 ||\n clientIdOrDocumentId === this.documentId ||\n (this.hasDetails && clientIdOrDocumentId === this.clientId)) {\n this.emit(\"nack\", clientIdOrDocumentId, message);\n }\n });\n break;\n\n default:\n super.addTrackedListener(event, listener);\n break;\n }\n }\n\n /**\n * Disconnect from the websocket\n */\n protected disconnect(socketProtocolError: boolean, reason: any) {\n const socket = this.socketReference;\n assert(socket !== undefined, 0x0a2 /* \"reentrancy not supported!\" */);\n this.socketReference = undefined;\n\n this.socket.off(\"server_disconnect\", this.serverDisconnectHandler);\n\n if (!socketProtocolError && this.hasDetails) {\n // tell the server we are disconnecting this client from the document\n this.socket.emit(\"disconnect_document\", this.clientId, this.documentId);\n }\n\n socket.removeSocketIoReference(socketProtocolError);\n this.emit(\"disconnect\", reason);\n }\n}\n"]}
1
+ {"version":3,"file":"odspDocumentDeltaConnection.js","sourceRoot":"","sources":["../src/odspDocumentDeltaConnection.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger, IEvent } from \"@fluidframework/common-definitions\";\nimport { assert, performance, Deferred, TypedEventEmitter } from \"@fluidframework/common-utils\";\nimport { DocumentDeltaConnection } from \"@fluidframework/driver-base\";\nimport { DriverError } from \"@fluidframework/driver-definitions\";\nimport { OdspError } from \"@fluidframework/odsp-driver-definitions\";\nimport { LoggingError } from \"@fluidframework/telemetry-utils\";\nimport {\n IClient,\n IConnect,\n INack,\n ISequencedDocumentMessage,\n ISignalMessage,\n} from \"@fluidframework/protocol-definitions\";\nimport { v4 as uuid } from \"uuid\";\nimport { IOdspSocketError, IGetOpsResponse, IFlushOpsResponse } from \"./contracts\";\nimport { EpochTracker } from \"./epochTracker\";\nimport { errorObjectFromSocketError } from \"./odspError\";\nimport { pkgVersion } from \"./packageVersion\";\n\nconst protocolVersions = [\"^0.4.0\", \"^0.3.0\", \"^0.2.0\", \"^0.1.0\"];\nconst feature_get_ops = \"api_get_ops\";\nconst feature_flush_ops = \"api_flush_ops\";\n\nexport interface FlushResult {\n lastPersistedSequenceNumber?: number;\n retryAfter?: number;\n}\n\n// How long to wait before disconnecting the socket after the last reference is removed\n// This allows reconnection after receiving a nack to be smooth\nconst socketReferenceBufferTime = 2000;\n\nexport interface ISocketEvents extends IEvent {\n (event: \"server_disconnect\", listener: (error: LoggingError & OdspError) => void);\n}\n\nclass SocketReference extends TypedEventEmitter<ISocketEvents> {\n private references: number = 1;\n private delayDeleteTimeout: ReturnType<typeof setTimeout> | undefined;\n private _socket: SocketIOClient.Socket | undefined;\n\n // When making decisions about socket reuse, we do not reuse disconnected socket.\n // But we want to differentiate the following case from disconnected case:\n // Socket that never connected and never failed, it's in \"attempting to connect\" mode\n // such sockets should be reused, despite socket.disconnected === true\n private isPendingInitialConnection = true;\n\n // Map of all existing socket io sockets. [url, tenantId, documentId] -> socket\n private static readonly socketIoSockets: Map<string, SocketReference> = new Map();\n\n public static find(key: string, logger: ITelemetryLogger) {\n const socketReference = SocketReference.socketIoSockets.get(key);\n\n // Verify the socket is healthy before reusing it\n if (socketReference && socketReference.disconnected) {\n // The socket is in a bad state. fully remove the reference\n socketReference.closeSocket();\n return undefined;\n }\n\n if (socketReference) {\n // Clear the pending deletion if there is one\n socketReference.clearTimer();\n socketReference.references++;\n }\n\n return socketReference;\n }\n\n /**\n * Removes a reference for the given key\n * Once the ref count hits 0, the socket is disconnected and removed\n * @param key - socket reference key\n * @param isFatalError - true if the socket reference should be removed immediately due to a fatal error\n */\n public removeSocketIoReference(isFatalError: boolean) {\n assert(this.references > 0, 0x09f /* \"No more socketIO refs to remove!\" */);\n this.references--;\n\n // see comment in disconnected() getter\n this.isPendingInitialConnection = false;\n\n if (isFatalError || this.disconnected) {\n this.closeSocket();\n return;\n }\n\n if (this.references === 0 && this.delayDeleteTimeout === undefined) {\n this.delayDeleteTimeout = setTimeout(() => {\n // We should not get here with active users.\n assert(this.references === 0, 0x0a0 /* \"Unexpected socketIO references on timeout\" */);\n this.closeSocket();\n }, socketReferenceBufferTime);\n }\n }\n\n public get socket() {\n if (!this._socket) {\n throw new Error(`Invalid socket for key \"${this.key}`);\n }\n return this._socket;\n }\n\n public constructor(public readonly key: string, socket: SocketIOClient.Socket) {\n super();\n\n this._socket = socket;\n assert(!SocketReference.socketIoSockets.has(key), 0x220 /* \"socket key collision\" */);\n SocketReference.socketIoSockets.set(key, this);\n\n // The server always closes the socket after sending this message\n // fully remove the socket reference now\n socket.on(\"server_disconnect\", (socketError: IOdspSocketError) => {\n // Treat all errors as recoverable, and rely on joinSession / reconnection flow to\n // filter out retryable vs. non-retryable cases.\n const error = errorObjectFromSocketError(socketError, \"server_disconnect\");\n error.canRetry = true;\n\n // see comment in disconnected() getter\n // Setting it here to ensure socket reuse does not happen if new request to connect\n // comes in from \"disconnect\" listener below, before we close socket.\n this.isPendingInitialConnection = false;\n\n this.emit(\"server_disconnect\", error);\n this.closeSocket();\n });\n }\n\n private clearTimer() {\n if (this.delayDeleteTimeout !== undefined) {\n clearTimeout(this.delayDeleteTimeout);\n this.delayDeleteTimeout = undefined;\n }\n }\n\n private closeSocket() {\n if (!this._socket) { return; }\n\n this.clearTimer();\n\n assert(SocketReference.socketIoSockets.get(this.key) === this,\n 0x0a1 /* \"Socket reference set unexpectedly does not point to this socket!\" */);\n SocketReference.socketIoSockets.delete(this.key);\n\n const socket = this._socket;\n this._socket = undefined;\n\n // Delay closing socket, to make sure all users of socket observe the same event that causes\n // this instance to close, and thus properly record reason for closure.\n // All event raising is synchronous, so clients will have a chance to react before socket is\n // closed without any extra data on why it was closed.\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n Promise.resolve().then(() => { socket.disconnect(); });\n }\n\n private get disconnected() {\n if (this._socket === undefined) { return true; }\n if (this.socket.connected) { return false; }\n\n // We have a socket that is not connected. Possible cases:\n // 1) It was connected some time ago and lost connection. We do not want to reuse it.\n // 2) It failed to connect (was never connected).\n // 3) It was just created and never had a chance to connect - connection is in process.\n // We have to differentiate 1 from 2-3 (specifically 1 & 3) in order to be able to reuse socket in #3.\n // We will use the fact that socket had some activity. I.e. if socket disconnected, or client stopped using\n // socket, then removeSocketIoReference() will be called for it, and it will be the indiction that it's not #3.\n return !this.isPendingInitialConnection;\n }\n}\n\n/**\n * Represents a connection to a stream of delta updates\n */\nexport class OdspDocumentDeltaConnection extends DocumentDeltaConnection {\n /**\n * Create a OdspDocumentDeltaConnection\n * If url #1 fails to connect, will try url #2 if applicable.\n *\n * @param tenantId - the ID of the tenant\n * @param documentId - document ID\n * @param token - authorization token for storage service\n * @param io - websocket library\n * @param client - information about the client\n * @param mode - mode of the client\n * @param url - websocket URL\n * @param telemetryLogger - optional telemetry logger\n * @param timeoutMs - time limit on making the connection\n * @param epochTracker - track epoch changes\n * @param socketReferenceKeyPrefix - (optional) prefix to isolate socket reuse cache\n */\n public static async create(\n tenantId: string,\n documentId: string,\n token: string | null,\n io: SocketIOClientStatic,\n client: IClient,\n url: string,\n telemetryLogger: ITelemetryLogger,\n timeoutMs: number,\n epochTracker: EpochTracker,\n socketReferenceKeyPrefix: string | undefined): Promise<OdspDocumentDeltaConnection> {\n // enable multiplexing when the websocket url does not include the tenant/document id\n const parsedUrl = new URL(url);\n const enableMultiplexing = !parsedUrl.searchParams.has(\"documentId\") && !parsedUrl.searchParams.has(\"tenantId\");\n\n // do not include the specific tenant/doc id in the ref key when multiplexing\n // this will allow multiple documents to share the same websocket connection\n const key = socketReferenceKeyPrefix ? `${socketReferenceKeyPrefix},${url}` : url;\n const socketReferenceKey = enableMultiplexing ? key : `${key},${tenantId},${documentId}`;\n\n const socketReference = OdspDocumentDeltaConnection.getOrCreateSocketIoReference(\n io, timeoutMs, socketReferenceKey, url, enableMultiplexing, tenantId, documentId, telemetryLogger);\n\n const socket = socketReference.socket;\n\n const connectMessage: IConnect = {\n client,\n id: documentId,\n mode: client.mode,\n tenantId,\n token, // Token is going to indicate tenant level information, etc...\n versions: protocolVersions,\n nonce: uuid(),\n epoch: epochTracker.fluidEpoch,\n relayUserAgent: [client.details.environment, ` driverVersion:${pkgVersion}`].join(\";\"),\n };\n\n // Reference to this client supporting get_ops flow.\n // back-compat: remove cast to any once new definition of IConnect comes through.\n (connectMessage as any).supportedFeatures = { [feature_get_ops]: true };\n\n const deltaConnection = new OdspDocumentDeltaConnection(\n socket,\n documentId,\n socketReference,\n telemetryLogger,\n enableMultiplexing);\n\n try {\n await deltaConnection.initialize(connectMessage, timeoutMs);\n await epochTracker.validateEpochFromPush(deltaConnection.details);\n } catch (errorObject) {\n if (errorObject !== null && typeof errorObject === \"object\") {\n // We have to special-case error types here in terms of what is re-triable.\n // These errors have to re-retried, we just need new joinSession result to connect to right server:\n // 400: Invalid tenant or document id. The WebSocket is connected to a different document\n // Document is full (with retryAfter)\n // 404: Invalid document. The document \\\"local/w1-...\\\" does not exist\n // But this has to stay not-retriable:\n // 406: Unsupported client protocol. This path is the only gatekeeper, have to fail!\n // 409: Epoch Version Mismatch. Client epoch and server epoch does not match, so app needs\n // to be refreshed.\n // This one is fine either way\n // 401/403: Code will retry once with new token either way, then it becomes fatal - on this path\n // and on join Session path.\n // 501: (Fluid not enabled): this is fine either way, as joinSession is gatekeeper\n if (errorObject.statusCode === 400 || errorObject.statusCode === 404) {\n errorObject.canRetry = true;\n }\n }\n throw errorObject;\n }\n\n return deltaConnection;\n }\n\n private socketReference: SocketReference | undefined;\n\n private readonly requestOpsNoncePrefix: string;\n private pushCallCounter = 0;\n private readonly getOpsMap: Map<string, { start: number, from: number, to: number }> = new Map();\n private flushOpNonce: string | undefined;\n private flushDeferred: Deferred<FlushResult> | undefined;\n\n /**\n * Error raising for socket.io issues\n */\n protected createErrorObject(handler: string, error?: any, canRetry = true): DriverError {\n // Note: we suspect the incoming error object is either:\n // - a socketError: add it to the OdspError object for driver to be able to parse it and reason over it.\n // - anything else: let base class handle it\n if (canRetry && Number.isInteger(error?.code) && typeof error?.message === \"string\") {\n return errorObjectFromSocketError(error as IOdspSocketError, handler) as DriverError;\n } else {\n return super.createErrorObject(handler, error, canRetry);\n }\n }\n\n /**\n * Gets or create a socket io connection for the given key\n */\n private static getOrCreateSocketIoReference(\n io: SocketIOClientStatic,\n timeoutMs: number,\n key: string,\n url: string,\n enableMultiplexing: boolean,\n tenantId: string,\n documentId: string,\n logger: ITelemetryLogger,\n ): SocketReference {\n const existingSocketReference = SocketReference.find(key, logger);\n if (existingSocketReference) {\n return existingSocketReference;\n }\n\n const query = enableMultiplexing ? undefined : { documentId, tenantId };\n\n const socket = io(\n url,\n {\n multiplex: false, // Don't rely on socket.io built-in multiplexing\n query,\n reconnection: false,\n transports: [\"websocket\"],\n timeout: timeoutMs,\n });\n\n return new SocketReference(key, socket);\n }\n\n /**\n * @param socket - websocket to be used\n * @param documentId - ID of the document\n * @param details - details of the websocket connection\n * @param socketReferenceKey - socket reference key\n * @param enableMultiplexing - If the websocket is multiplexing multiple documents\n */\n private constructor(\n socket: SocketIOClient.Socket,\n documentId: string,\n socketReference: SocketReference,\n logger: ITelemetryLogger,\n private readonly enableMultiplexing?: boolean,\n ) {\n super(socket, documentId, logger);\n this.socketReference = socketReference;\n this.requestOpsNoncePrefix = `${uuid()}-`;\n }\n\n /**\n * Retrieves ops from PUSH\n * @param from - inclusive\n * @param to - exclusive\n * @returns ops retrieved\n */\n public requestOps(from: number, to: number) {\n // Given that to is exclusive, we should be asking for at least something!\n assert(to > from, 0x272 /* \"empty request\" */);\n\n // PUSH may disable this functionality\n // back-compat: remove cast to any once latest version of IConnected is consumed\n if ((this.details as any).supportedFeatures?.[feature_get_ops] !== true) {\n return;\n }\n\n this.pushCallCounter++;\n const nonce = `${this.requestOpsNoncePrefix}${this.pushCallCounter}`;\n const start = performance.now();\n\n // We may keep keep accumulating memory for nothing, if we are not getting responses.\n // Note that we should not have overlapping requests, as DeltaManager allows only one\n // outstanding request to storage, and that's the only way to get here.\n // But requests could be cancelled, and thus overlapping requests might be in the picture\n // If it happens, we do not care about stale requests.\n // So track some number of requests, but log if we get too many in flight - that likely\n // indicates an error somewhere.\n if (this.getOpsMap.size >= 5) {\n let time = start;\n let key: string | undefined;\n for (const [keyCandidate, value] of this.getOpsMap.entries()) {\n if (value.start <= time || key === undefined) {\n time = value.start;\n key = keyCandidate;\n }\n }\n const payloadToDelete = this.getOpsMap.get(key!)!;\n this.logger.sendErrorEvent({\n eventName: \"GetOpsTooMany\",\n nonce,\n from: payloadToDelete.from,\n to: payloadToDelete.to,\n length: payloadToDelete.to - payloadToDelete.from,\n duration: performance.now() - payloadToDelete.start,\n });\n this.getOpsMap.delete(key!);\n }\n this.getOpsMap.set(\n nonce,\n {\n start,\n from,\n to,\n },\n );\n this.socket.emit(\"get_ops\", this.clientId, {\n nonce,\n from,\n to: to - 1,\n });\n }\n\n public async flush(): Promise<FlushResult> {\n // back-compat: remove cast to any once latest version of IConnected is consumed\n if ((this.details as any).supportedFeatures?.[feature_flush_ops] !== true) {\n // Once single-commit summary is enabled end-to-end, flush support is a must!\n // The only alternative is change in design where SPO fetches ops from PUSH OR\n // summary includes required ops and SPO has some validation mechanism to ensure\n // they are not forged by client.\n // If design changes, we can reconsider it, but right now it's non-recoverable failure.\n this.logger.sendErrorEvent({ eventName: \"FlushOpsNotSupported\" });\n throw new Error(\"flush() API is not supported by PUSH, required for single-commit summaries\");\n }\n\n this.pushCallCounter++;\n const nonce = `${this.requestOpsNoncePrefix}${this.pushCallCounter}`;\n // There should be only one flush ops in flight, kicked out by upload summary workflow\n // That said, it could timeout, and request could be repeated, so theoretically we can\n // get overlapping requests, but it should be very rare\n if (this.flushDeferred !== undefined) {\n this.logger.sendErrorEvent({ eventName: \"FlushOpsTooMany\" });\n this.flushDeferred.reject(\"process involving flush() was cancelled OR unsupported concurrency\");\n }\n this.socket.emit(\"flush_ops\", this.clientId, { nonce });\n\n this.flushOpNonce = nonce;\n this.flushDeferred = new Deferred<FlushResult>();\n return this.flushDeferred.promise;\n }\n\n protected serverDisconnectHandler = (error: LoggingError & OdspError) => {\n this.disposeCore(true, error);\n };\n\n protected async initialize(connectMessage: IConnect, timeout: number) {\n if (this.enableMultiplexing) {\n // multiplex compatible early handlers\n this.earlyOpHandler = (messageDocumentId: string, msgs: ISequencedDocumentMessage[]) => {\n if (this.documentId === messageDocumentId) {\n this.queuedMessages.push(...msgs);\n }\n };\n\n this.earlySignalHandler = (msg: ISignalMessage, messageDocumentId?: string) => {\n if (messageDocumentId === undefined || messageDocumentId === this.documentId) {\n this.queuedSignals.push(msg);\n }\n };\n }\n\n this.socketReference!.once(\"server_disconnect\", this.serverDisconnectHandler);\n\n this.socket.on(\"get_ops_response\", (result: IGetOpsResponse) => {\n const messages = result.messages;\n const data = this.getOpsMap.get(result.nonce);\n // Due to socket multiplexing, this client may not have asked for any data\n // If so, there it most likely does not need these ops (otherwise it already asked for them)\n // Also we may have deleted entry in this.getOpsMap due to too many requests and too slow response.\n // But not processing such result may push us into infinite loop of fast requests and dropping all responses\n if (data !== undefined || result.nonce.indexOf(this.requestOpsNoncePrefix) === 0) {\n this.getOpsMap.delete(result.nonce);\n const common = {\n eventName: \"GetOps\",\n // We need nonce only to pair with GetOpsTooMany events, i.e. when record was deleted\n nonce: data === undefined ? result.nonce : undefined,\n code: result.code,\n from: data?.from,\n to: data?.to,\n duration: data === undefined ? undefined : performance.now() - data.start,\n };\n if (messages !== undefined && messages.length > 0) {\n this.logger.sendPerformanceEvent({\n ...common,\n first: messages[0].sequenceNumber,\n last: messages[messages.length - 1].sequenceNumber,\n length: messages.length,\n });\n this.emit(\"op\", this.documentId, messages);\n } else {\n this.logger.sendPerformanceEvent({\n ...common,\n length: 0,\n });\n }\n }\n });\n\n this.socket.on(\"flush_ops_response\", (result: IFlushOpsResponse) => {\n if (this.flushOpNonce === result.nonce) {\n const seq = result.lastPersistedSequenceNumber;\n let category: \"generic\" | \"error\" = \"generic\";\n if (result.lastPersistedSequenceNumber === undefined || result.code !== 200) {\n switch (result.code) {\n case 409:\n case 429:\n category = \"error\";\n break;\n case 204:\n break;\n default:\n category = \"error\";\n break;\n }\n }\n this.logger.sendTelemetryEvent({\n eventName: \"FlushResult\",\n code: result.code,\n sequenceNumber: seq,\n category,\n });\n this.flushDeferred!.resolve(result);\n this.flushDeferred = undefined;\n this.flushOpNonce = undefined;\n }\n });\n\n await super.initialize(connectMessage, timeout);\n }\n\n protected addTrackedListener(event: string, listener: (...args: any[]) => void) {\n // override some event listeners in order to support multiple documents/clients over the same websocket\n switch (event) {\n case \"op\":\n // per document op handling\n super.addTrackedListener(event, (documentId: string, msgs: ISequencedDocumentMessage[]) => {\n if (!this.enableMultiplexing || this.documentId === documentId) {\n listener(documentId, msgs);\n }\n });\n break;\n\n case \"signal\":\n // per document signal handling\n super.addTrackedListener(event, (msg: ISignalMessage, documentId?: string) => {\n if (!this.enableMultiplexing || !documentId || documentId === this.documentId) {\n listener(msg, documentId);\n }\n });\n break;\n\n case \"nack\":\n // per client / document nack handling\n super.addTrackedListener(event, (clientIdOrDocumentId: string, message: INack[]) => {\n if (clientIdOrDocumentId.length === 0 ||\n clientIdOrDocumentId === this.documentId ||\n (this.hasDetails && clientIdOrDocumentId === this.clientId)) {\n this.emit(\"nack\", clientIdOrDocumentId, message);\n }\n });\n break;\n\n default:\n super.addTrackedListener(event, listener);\n break;\n }\n }\n\n /**\n * Disconnect from the websocket\n */\n protected disconnect(socketProtocolError: boolean, reason: any) {\n const socket = this.socketReference;\n assert(socket !== undefined, 0x0a2 /* \"reentrancy not supported!\" */);\n this.socketReference = undefined;\n\n this.socket.off(\"server_disconnect\", this.serverDisconnectHandler);\n\n if (!socketProtocolError && this.hasDetails) {\n // tell the server we are disconnecting this client from the document\n this.socket.emit(\"disconnect_document\", this.clientId, this.documentId);\n }\n\n socket.removeSocketIoReference(socketProtocolError);\n this.emit(\"disconnect\", reason);\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"odspDocumentService.d.ts","sourceRoot":"","sources":["../src/odspDocumentService.ts"],"names":[],"mappings":"AAAA;;;GAGG;;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAGtE,OAAO,EACH,wBAAwB,EACxB,4BAA4B,EAC5B,gBAAgB,EAChB,YAAY,EACZ,uBAAuB,EACvB,wBAAwB,EAC3B,MAAM,oCAAoC,CAAC;AAG5C,OAAO,EACH,OAAO,EACP,yBAAyB,EAC5B,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACH,gBAAgB,EAChB,iBAAiB,EAEjB,iBAAiB,EACjB,+BAA+B,EAClC,MAAM,yCAAyC,CAAC;AAEjD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAOzC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAexC;;;GAGG;AACH,qBAAa,mBAAoB,YAAW,gBAAgB;aAoEpC,eAAe,EAAE,gBAAgB;IACjD,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAElC,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IACtC,OAAO,CAAC,QAAQ,CAAC,KAAK;IAEtB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAC;IA3E9C,OAAO,CAAC,SAAS,CAA2B;IAE5C;;;;;;;;;;;;;OAaG;WACiB,MAAM,CACtB,WAAW,EAAE,YAAY,EACzB,eAAe,EAAE,+BAA+B,EAChD,iBAAiB,EAAE,CAAC,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,GAAG,SAAS,EACvF,MAAM,EAAE,gBAAgB,EACxB,qBAAqB,EAAE,MAAM,OAAO,CAAC,oBAAoB,CAAC,EAC1D,KAAK,EAAE,UAAU,EACjB,UAAU,EAAE,iBAAiB,EAC7B,YAAY,EAAE,YAAY,EAC1B,wBAAwB,CAAC,EAAE,MAAM,GAClC,OAAO,CAAC,gBAAgB,CAAC;IAc5B,OAAO,CAAC,cAAc,CAAC,CAA6B;IAEpD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IAEzC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IAExC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA4B;IAEvD,OAAO,CAAC,SAAS,CAAC,CAAW;IAE7B,OAAO,CAAC,iBAAiB,CAAC,CAA8B;IAExD;;;;;;;;;;;;;OAaG;IACH,OAAO;IAgCP,IAAW,WAAW,IAAI,YAAY,CAErC;IACD,IAAW,QAAQ,6BAElB;IAED;;;;OAIG;IACU,gBAAgB,IAAI,OAAO,CAAC,uBAAuB,CAAC;IAuBjE;;;;OAIG;IACU,qBAAqB,IAAI,OAAO,CAAC,4BAA4B,CAAC;IA+B3E;;;;OAIG;IACU,oBAAoB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,wBAAwB,CAAC;YAiEvE,WAAW;IAsBzB;;;;;;;;;;OAUG;YACW,6BAA6B;IAkCpC,OAAO,CAAC,KAAK,CAAC,EAAE,GAAG;IAa1B,SAAS,KAAK,QAAQ,yBA8BrB;IAID,SAAS,CAAC,WAAW,CAAC,GAAG,EAAE,yBAAyB,EAAE;CAQzD"}
1
+ {"version":3,"file":"odspDocumentService.d.ts","sourceRoot":"","sources":["../src/odspDocumentService.ts"],"names":[],"mappings":"AAAA;;;GAGG;;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAGtE,OAAO,EACH,wBAAwB,EACxB,4BAA4B,EAC5B,gBAAgB,EAChB,YAAY,EACZ,uBAAuB,EACvB,wBAAwB,EAC3B,MAAM,oCAAoC,CAAC;AAG5C,OAAO,EACH,OAAO,EACP,yBAAyB,EAC5B,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACH,gBAAgB,EAChB,iBAAiB,EAEjB,iBAAiB,EACjB,+BAA+B,EAElC,MAAM,yCAAyC,CAAC;AAEjD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAOzC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAexC;;;GAGG;AACH,qBAAa,mBAAoB,YAAW,gBAAgB;aAoEpC,eAAe,EAAE,gBAAgB;IACjD,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAElC,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IACtC,OAAO,CAAC,QAAQ,CAAC,KAAK;IAEtB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAC;IA3E9C,OAAO,CAAC,SAAS,CAA2B;IAE5C;;;;;;;;;;;;;OAaG;WACiB,MAAM,CACtB,WAAW,EAAE,YAAY,EACzB,eAAe,EAAE,+BAA+B,EAChD,iBAAiB,EAAE,CAAC,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,GAAG,SAAS,EACvF,MAAM,EAAE,gBAAgB,EACxB,qBAAqB,EAAE,MAAM,OAAO,CAAC,oBAAoB,CAAC,EAC1D,KAAK,EAAE,UAAU,EACjB,UAAU,EAAE,iBAAiB,EAC7B,YAAY,EAAE,YAAY,EAC1B,wBAAwB,CAAC,EAAE,MAAM,GAClC,OAAO,CAAC,gBAAgB,CAAC;IAc5B,OAAO,CAAC,cAAc,CAAC,CAA6B;IAEpD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IAEzC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IAExC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA4B;IAEvD,OAAO,CAAC,SAAS,CAAC,CAAW;IAE7B,OAAO,CAAC,iBAAiB,CAAC,CAA8B;IAExD;;;;;;;;;;;;;OAaG;IACH,OAAO;IAgCP,IAAW,WAAW,IAAI,YAAY,CAErC;IACD,IAAW,QAAQ,6BAElB;IAED;;;;OAIG;IACU,gBAAgB,IAAI,OAAO,CAAC,uBAAuB,CAAC;IAuBjE;;;;OAIG;IACU,qBAAqB,IAAI,OAAO,CAAC,4BAA4B,CAAC;IA+B3E;;;;OAIG;IACU,oBAAoB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,wBAAwB,CAAC;YAoEvE,WAAW;IAsBzB;;;;;;;;;;OAUG;YACW,6BAA6B;IAkCpC,OAAO,CAAC,KAAK,CAAC,EAAE,GAAG;IAa1B,SAAS,KAAK,QAAQ,yBA8BrB;IAID,SAAS,CAAC,WAAW,CAAC,GAAG,EAAE,yBAAyB,EAAE;CAQzD"}
@@ -8,7 +8,7 @@ exports.OdspDocumentService = void 0;
8
8
  const common_utils_1 = require("@fluidframework/common-utils");
9
9
  const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
10
10
  const driver_utils_1 = require("@fluidframework/driver-utils");
11
- const odsp_doclib_utils_1 = require("@fluidframework/odsp-doclib-utils");
11
+ const odsp_driver_definitions_1 = require("@fluidframework/odsp-driver-definitions");
12
12
  const odspDeltaStorageService_1 = require("./odspDeltaStorageService");
13
13
  const odspDocumentDeltaConnection_1 = require("./odspDocumentDeltaConnection");
14
14
  const odspDocumentStorageManager_1 = require("./odspDocumentStorageManager");
@@ -127,7 +127,7 @@ class OdspDocumentService {
127
127
  // batch size, please see issue #5211 for data around batch sizing
128
128
  const batchSize = (_c = this.hostPolicy.opsBatchSize) !== null && _c !== void 0 ? _c : 5000;
129
129
  const concurrency = (_d = this.hostPolicy.concurrentOpsBatches) !== null && _d !== void 0 ? _d : 1;
130
- return new odspDeltaStorageService_1.OdspDeltaStorageWithCache(snapshotOps, this.logger, batchSize, concurrency, async (from, to, telemetryProps) => service.get(from, to, telemetryProps), async (from, to) => {
130
+ return new odspDeltaStorageService_1.OdspDeltaStorageWithCache(snapshotOps, this.logger, batchSize, concurrency, async (from, to, telemetryProps, fetchReason) => service.get(from, to, telemetryProps, fetchReason), async (from, to) => {
131
131
  var _a, _b;
132
132
  const res = await ((_a = this.opsCache) === null || _a === void 0 ? void 0 : _a.get(from, to));
133
133
  return (_b = res) !== null && _b !== void 0 ? _b : [];
@@ -178,7 +178,7 @@ class OdspDocumentService {
178
178
  ]);
179
179
  const finalWebsocketToken = websocketToken !== null && websocketToken !== void 0 ? websocketToken : (websocketEndpoint.socketToken || null);
180
180
  if (finalWebsocketToken === null) {
181
- odsp_doclib_utils_1.throwOdspNetworkError("pushTokenIsNull", odsp_doclib_utils_1.fetchTokenErrorCode);
181
+ throw new driver_utils_1.NonRetryableError("pushTokenIsNull", "Websocket token is null", odsp_driver_definitions_1.OdspErrorType.fetchTokenError);
182
182
  }
183
183
  try {
184
184
  const connection = await this.connectToDeltaStreamWithRetry(websocketEndpoint.tenantId, websocketEndpoint.id, finalWebsocketToken, io, client, websocketEndpoint.deltaStreamSocketUrl);
@@ -1 +1 @@
1
- {"version":3,"file":"odspDocumentService.js","sourceRoot":"","sources":["../src/odspDocumentService.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { performance } from \"@fluidframework/common-utils\";\nimport { ChildLogger, TelemetryLogger } from \"@fluidframework/telemetry-utils\";\nimport {\n IDocumentDeltaConnection,\n IDocumentDeltaStorageService,\n IDocumentService,\n IResolvedUrl,\n IDocumentStorageService,\n IDocumentServicePolicies,\n} from \"@fluidframework/driver-definitions\";\nimport { DeltaStreamConnectionForbiddenError } from \"@fluidframework/driver-utils\";\nimport { fetchTokenErrorCode, IFacetCodes, throwOdspNetworkError } from \"@fluidframework/odsp-doclib-utils\";\nimport {\n IClient,\n ISequencedDocumentMessage,\n} from \"@fluidframework/protocol-definitions\";\nimport {\n IOdspResolvedUrl,\n TokenFetchOptions,\n IEntry,\n HostStoragePolicy,\n InstrumentedStorageTokenFetcher,\n} from \"@fluidframework/odsp-driver-definitions\";\nimport { HostStoragePolicyInternal, ISocketStorageDiscovery } from \"./contracts\";\nimport { IOdspCache } from \"./odspCache\";\nimport { OdspDeltaStorageService, OdspDeltaStorageWithCache } from \"./odspDeltaStorageService\";\nimport { OdspDocumentDeltaConnection } from \"./odspDocumentDeltaConnection\";\nimport { OdspDocumentStorageService } from \"./odspDocumentStorageManager\";\nimport { getWithRetryForTokenRefresh, getOdspResolvedUrl, TokenFetchOptionsEx } from \"./odspUtils\";\nimport { fetchJoinSession } from \"./vroom\";\nimport { isOdcOrigin } from \"./odspUrlHelper\";\nimport { EpochTracker } from \"./epochTracker\";\nimport { OpsCache } from \"./opsCaching\";\nimport { RetryErrorsStorageAdapter } from \"./retryErrorsStorageAdapter\";\n\n// Gate that when set to \"1\", instructs to fetch the binary format snapshot from the spo.\nfunction gatesBinaryFormatSnapshot() {\n try {\n if (typeof localStorage === \"object\" && localStorage !== null) {\n if (localStorage.binaryFormatSnapshot === \"1\") {\n return true;\n }\n }\n } catch (e) {}\n return false;\n}\n\n/**\n * The DocumentService manages the Socket.IO connection and manages routing requests to connected\n * clients\n */\nexport class OdspDocumentService implements IDocumentService {\n private _policies: IDocumentServicePolicies;\n\n /**\n * @param resolvedUrl - resolved url identifying document that will be managed by returned service instance.\n * @param getStorageToken - function that can provide the storage token. This is is also referred to as\n * the \"Vroom\" token in SPO.\n * @param getWebsocketToken - function that can provide a token for accessing the web socket. This is also referred\n * to as the \"Push\" token in SPO. If undefined then websocket token is expected to be returned with joinSession\n * response payload.\n * @param logger - a logger that can capture performance and diagnostic information\n * @param socketIoClientFactory - A factory that returns a promise to the socket io library required by the driver\n * @param cache - This caches response for joinSession.\n * @param hostPolicy - This host constructed policy which customizes service behavior.\n * @param epochTracker - This helper class which adds epoch to backend calls made by returned service instance.\n * @param socketReferenceKeyPrefix - (optional) prefix to isolate socket reuse cache\n */\n public static async create(\n resolvedUrl: IResolvedUrl,\n getStorageToken: InstrumentedStorageTokenFetcher,\n getWebsocketToken: ((options: TokenFetchOptions) => Promise<string | null>) | undefined,\n logger: ITelemetryLogger,\n socketIoClientFactory: () => Promise<SocketIOClientStatic>,\n cache: IOdspCache,\n hostPolicy: HostStoragePolicy,\n epochTracker: EpochTracker,\n socketReferenceKeyPrefix?: string,\n ): Promise<IDocumentService> {\n return new OdspDocumentService(\n getOdspResolvedUrl(resolvedUrl),\n getStorageToken,\n getWebsocketToken,\n logger,\n socketIoClientFactory,\n cache,\n hostPolicy,\n epochTracker,\n socketReferenceKeyPrefix,\n );\n }\n\n private storageManager?: OdspDocumentStorageService;\n\n private readonly logger: TelemetryLogger;\n\n private readonly joinSessionKey: string;\n\n private readonly hostPolicy: HostStoragePolicyInternal;\n\n private _opsCache?: OpsCache;\n\n private currentConnection?: OdspDocumentDeltaConnection;\n\n /**\n * @param odspResolvedUrl - resolved url identifying document that will be managed by this service instance.\n * @param getStorageToken - function that can provide the storage token. This is is also referred to as\n * the \"Vroom\" token in SPO.\n * @param getWebsocketToken - function that can provide a token for accessing the web socket. This is also referred\n * to as the \"Push\" token in SPO. If undefined then websocket token is expected to be returned with joinSession\n * response payload.\n * @param logger - a logger that can capture performance and diagnostic information\n * @param socketIoClientFactory - A factory that returns a promise to the socket io library required by the driver\n * @param cache - This caches response for joinSession.\n * @param hostPolicy - host constructed policy which customizes service behavior.\n * @param epochTracker - This helper class which adds epoch to backend calls made by this service instance.\n * @param socketReferenceKeyPrefix - (optional) prefix to isolate socket reuse cache\n */\n private constructor(\n public readonly odspResolvedUrl: IOdspResolvedUrl,\n private readonly getStorageToken: InstrumentedStorageTokenFetcher,\n private readonly getWebsocketToken: ((options: TokenFetchOptions) => Promise<string | null>) | undefined,\n logger: ITelemetryLogger,\n private readonly socketIoClientFactory: () => Promise<SocketIOClientStatic>,\n private readonly cache: IOdspCache,\n hostPolicy: HostStoragePolicy,\n private readonly epochTracker: EpochTracker,\n private readonly socketReferenceKeyPrefix?: string,\n ) {\n this._policies = {\n // load in storage-only mode if a file version is specified\n storageOnly: odspResolvedUrl.fileVersion !== undefined,\n };\n\n this.joinSessionKey = `${this.odspResolvedUrl.hashedDocumentId}/joinsession`;\n this.logger = ChildLogger.create(logger,\n undefined,\n {\n all: {\n odc: isOdcOrigin(new URL(this.odspResolvedUrl.endpoints.snapshotStorageUrl).origin),\n },\n });\n\n this.hostPolicy = hostPolicy;\n this.hostPolicy.fetchBinarySnapshotFormat ??= gatesBinaryFormatSnapshot();\n if (this.odspResolvedUrl.summarizer) {\n this.hostPolicy = { ...this.hostPolicy, summarizerClient: true };\n }\n }\n\n public get resolvedUrl(): IResolvedUrl {\n return this.odspResolvedUrl;\n }\n public get policies() {\n return this._policies;\n }\n\n /**\n * Connects to a storage endpoint for snapshot service.\n *\n * @returns returns the document storage service for sharepoint driver.\n */\n public async connectToStorage(): Promise<IDocumentStorageService> {\n if (!this.storageManager) {\n this.storageManager = new OdspDocumentStorageService(\n this.odspResolvedUrl,\n this.getStorageToken,\n this.logger,\n true,\n this.cache,\n this.hostPolicy,\n this.epochTracker,\n // flushCallback\n async () => {\n if (this.currentConnection !== undefined && !this.currentConnection.disposed) {\n return this.currentConnection.flush();\n }\n throw new Error(\"Disconnected while uploading summary (attempt to perform flush())\");\n },\n );\n }\n\n return new RetryErrorsStorageAdapter(this.storageManager, this.logger);\n }\n\n /**\n * Connects to a delta storage endpoint for getting ops between a range.\n *\n * @returns returns the document delta storage service for sharepoint driver.\n */\n public async connectToDeltaStorage(): Promise<IDocumentDeltaStorageService> {\n const snapshotOps = this.storageManager?.ops ?? [];\n const service = new OdspDeltaStorageService(\n this.odspResolvedUrl.endpoints.deltaStorageUrl,\n this.getStorageToken,\n this.epochTracker,\n this.logger,\n );\n\n // batch size, please see issue #5211 for data around batch sizing\n const batchSize = this.hostPolicy.opsBatchSize ?? 5000;\n const concurrency = this.hostPolicy.concurrentOpsBatches ?? 1;\n return new OdspDeltaStorageWithCache(\n snapshotOps,\n this.logger,\n batchSize,\n concurrency,\n async (from, to, telemetryProps) => service.get(from, to, telemetryProps),\n async (from, to) => {\n const res = await this.opsCache?.get(from, to);\n return res as ISequencedDocumentMessage[] ?? [];\n },\n (from, to) => {\n if (this.currentConnection !== undefined && !this.currentConnection.disposed) {\n this.currentConnection.requestOps(from, to);\n }\n },\n (ops: ISequencedDocumentMessage[]) => this.opsReceived(ops),\n );\n }\n\n /**\n * Connects to a delta stream endpoint for emitting ops.\n *\n * @returns returns the document delta stream service for onedrive/sharepoint driver.\n */\n public async connectToDeltaStream(client: IClient): Promise<IDocumentDeltaConnection> {\n // Attempt to connect twice, in case we used expired token.\n return getWithRetryForTokenRefresh<IDocumentDeltaConnection>(async (options) => {\n // Presence of getWebsocketToken callback dictates whether callback is used for fetching\n // websocket token or whether it is returned with joinSession response payload\n const requestWebsocketTokenFromJoinSession = this.getWebsocketToken === undefined;\n const websocketTokenPromise = requestWebsocketTokenFromJoinSession\n ? Promise.resolve(null)\n : this.getWebsocketToken!(options);\n\n const joinSessionPromise = this.joinSession(requestWebsocketTokenFromJoinSession, options).catch((e) => {\n const likelyFacetCodes = e as IFacetCodes;\n if (Array.isArray(likelyFacetCodes.facetCodes)) {\n for (const code of likelyFacetCodes.facetCodes) {\n switch (code) {\n case \"sessionForbiddenOnPreservedFiles\":\n case \"sessionForbiddenOnModerationEnabledLibrary\":\n case \"sessionForbiddenOnRequireCheckout\":\n // This document can only be opened in storage-only mode.\n // DeltaManager will recognize this error\n // and load without a delta stream connection.\n this._policies = {...this._policies,storageOnly: true};\n throw new DeltaStreamConnectionForbiddenError(code);\n default:\n continue;\n }\n }\n }\n throw e;\n });\n\n const [websocketEndpoint, websocketToken, io] =\n await Promise.all([\n joinSessionPromise,\n websocketTokenPromise,\n this.socketIoClientFactory(),\n ]);\n\n const finalWebsocketToken = websocketToken ?? (websocketEndpoint.socketToken || null);\n if (finalWebsocketToken === null) {\n throwOdspNetworkError(\"pushTokenIsNull\", fetchTokenErrorCode);\n }\n try {\n const connection = await this.connectToDeltaStreamWithRetry(\n websocketEndpoint.tenantId,\n websocketEndpoint.id,\n finalWebsocketToken,\n io,\n client,\n websocketEndpoint.deltaStreamSocketUrl);\n connection.on(\"op\", (documentId, ops: ISequencedDocumentMessage[]) => {\n this.opsReceived(ops);\n });\n this.currentConnection = connection;\n return connection;\n } catch (error) {\n this.cache.sessionJoinCache.remove(this.joinSessionKey);\n if (typeof error === \"object\" && error !== null) {\n error.socketDocumentId = websocketEndpoint.id;\n }\n throw error;\n }\n });\n }\n\n private async joinSession(\n requestSocketToken: boolean,\n options: TokenFetchOptionsEx,\n ): Promise<ISocketStorageDiscovery> {\n const executeFetch = async () =>\n fetchJoinSession(\n this.odspResolvedUrl,\n \"opStream/joinSession\",\n \"POST\",\n this.logger,\n this.getStorageToken,\n this.epochTracker,\n requestSocketToken,\n options,\n this.hostPolicy.sessionOptions?.unauthenticatedUserDisplayName,\n );\n\n // Note: The sessionCache is configured with a sliding expiry of 1 hour,\n // so if we've fetched the join session within the last hour we won't run executeFetch again now.\n return this.cache.sessionJoinCache.addOrGet(this.joinSessionKey, executeFetch);\n }\n\n /**\n * Connects to a delta stream endpoint\n * If url #1 fails to connect, tries url #2 if applicable\n *\n * @param tenantId - the ID of the tenant\n * @param documentId - document ID\n * @param token - authorization token for storage service\n * @param io - websocket library\n * @param client - information about the client\n * @param webSocketUrl - websocket URL\n */\n private async connectToDeltaStreamWithRetry(\n tenantId: string,\n documentId: string,\n token: string | null,\n io: SocketIOClientStatic,\n client: IClient,\n webSocketUrl: string,\n ): Promise<OdspDocumentDeltaConnection> {\n const startTime = performance.now();\n const connection = await OdspDocumentDeltaConnection.create(\n tenantId,\n documentId,\n token,\n io,\n client,\n webSocketUrl,\n this.logger,\n 60000,\n this.epochTracker,\n this.socketReferenceKeyPrefix,\n );\n const duration = performance.now() - startTime;\n // This event happens rather often, so it adds up to cost of telemetry.\n // Given that most reconnects result in reusing socket and happen very quickly,\n // report event only if it took longer than threshold.\n if (duration >= 2000) {\n this.logger.sendPerformanceEvent({\n eventName: \"ConnectionSuccess\",\n duration,\n });\n }\n return connection;\n }\n\n public dispose(error?: any) {\n // Error might indicate mismatch between client & server knowlege about file\n // (DriverErrorType.fileOverwrittenInStorage).\n // For example, file might have been overwritten in storage without generating new epoch\n // In such case client cached info is stale and has to be removed.\n if (error !== undefined) {\n this.epochTracker.removeEntries().catch(() => {});\n } else {\n this._opsCache?.flushOps();\n }\n this._opsCache?.dispose();\n }\n\n protected get opsCache() {\n if (this._opsCache) {\n return this._opsCache;\n }\n\n const seqNumber = this.storageManager?.snapshotSequenceNumber;\n const batchSize = this.hostPolicy.opsCaching?.batchSize ?? 100;\n if (seqNumber === undefined || batchSize < 1) {\n return;\n }\n\n const opsKey: Omit<IEntry, \"key\"> = {\n type: \"ops\",\n };\n this._opsCache = new OpsCache(\n seqNumber,\n this.logger,\n // ICache\n {\n write: async (key: string, opsData: string) => {\n return this.cache.persistedCache.put({...opsKey, key}, opsData);\n },\n read: async (key: string) => this.cache.persistedCache.get({...opsKey, key}),\n remove: () => { this.cache.persistedCache.removeEntries().catch(() => {}); },\n },\n batchSize,\n this.hostPolicy.opsCaching?.timerGranularity ?? 5000,\n this.hostPolicy.opsCaching?.totalOpsToCache ?? 5000,\n );\n return this._opsCache;\n }\n\n // Called whenever re receive ops through any channel for this document (snapshot, delta connection, delta storage)\n // We use it to notify caching layer of how stale is snapshot stored in cache.\n protected opsReceived(ops: ISequencedDocumentMessage[]) {\n // No need for two clients to save same ops\n if (ops.length === 0 || this.odspResolvedUrl.summarizer) {\n return;\n }\n\n this.opsCache?.addOps(ops);\n }\n}\n"]}
1
+ {"version":3,"file":"odspDocumentService.js","sourceRoot":"","sources":["../src/odspDocumentService.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAGH,+DAA2D;AAC3D,qEAA+E;AAS/E,+DAAsG;AAMtG,qFAOiD;AAGjD,uEAA+F;AAC/F,+EAA4E;AAC5E,6EAA0E;AAC1E,2CAAmG;AACnG,mCAA2C;AAC3C,mDAA8C;AAE9C,6CAAwC;AACxC,2EAAwE;AAExE,yFAAyF;AACzF,SAAS,yBAAyB;IAC9B,IAAI;QACA,IAAI,OAAO,YAAY,KAAK,QAAQ,IAAI,YAAY,KAAK,IAAI,EAAE;YAC3D,IAAK,YAAY,CAAC,oBAAoB,KAAK,GAAG,EAAE;gBAC5C,OAAO,IAAI,CAAC;aACf;SACJ;KACJ;IAAC,OAAO,CAAC,EAAE,GAAE;IACd,OAAO,KAAK,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAa,mBAAmB;IAqD5B;;;;;;;;;;;;;OAaG;IACH,YACoB,eAAiC,EAChC,eAAgD,EAChD,iBAAuF,EACxG,MAAwB,EACP,qBAA0D,EAC1D,KAAiB,EAClC,UAA6B,EACZ,YAA0B,EAC1B,wBAAiC;;;QARlC,oBAAe,GAAf,eAAe,CAAkB;QAChC,oBAAe,GAAf,eAAe,CAAiC;QAChD,sBAAiB,GAAjB,iBAAiB,CAAsE;QAEvF,0BAAqB,GAArB,qBAAqB,CAAqC;QAC1D,UAAK,GAAL,KAAK,CAAY;QAEjB,iBAAY,GAAZ,YAAY,CAAc;QAC1B,6BAAwB,GAAxB,wBAAwB,CAAS;QAElD,IAAI,CAAC,SAAS,GAAG;YACb,2DAA2D;YAC3D,WAAW,EAAE,eAAe,CAAC,WAAW,KAAK,SAAS;SACzD,CAAC;QAEF,IAAI,CAAC,cAAc,GAAG,GAAG,IAAI,CAAC,eAAe,CAAC,gBAAgB,cAAc,CAAC;QAC7E,IAAI,CAAC,MAAM,GAAG,6BAAW,CAAC,MAAM,CAAC,MAAM,EACnC,SAAS,EACT;YACI,GAAG,EAAE;gBACD,GAAG,EAAE,2BAAW,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC,MAAM,CAAC;aACtF;SACJ,CAAC,CAAC;QAEP,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,YAAA,IAAI,CAAC,UAAU,EAAC,yBAAyB,uCAAzB,yBAAyB,GAAK,yBAAyB,EAAE,EAAC;QAC1E,IAAI,IAAI,CAAC,eAAe,CAAC,UAAU,EAAE;YACjC,IAAI,CAAC,UAAU,mCAAQ,IAAI,CAAC,UAAU,KAAE,gBAAgB,EAAE,IAAI,GAAE,CAAC;SACpE;IACL,CAAC;IA9FD;;;;;;;;;;;;;OAaG;IACI,MAAM,CAAC,KAAK,CAAC,MAAM,CACtB,WAAyB,EACzB,eAAgD,EAChD,iBAAuF,EACvF,MAAwB,EACxB,qBAA0D,EAC1D,KAAiB,EACjB,UAA6B,EAC7B,YAA0B,EAC1B,wBAAiC;QAEjC,OAAO,IAAI,mBAAmB,CAC1B,8BAAkB,CAAC,WAAW,CAAC,EAC/B,eAAe,EACf,iBAAiB,EACjB,MAAM,EACN,qBAAqB,EACrB,KAAK,EACL,UAAU,EACV,YAAY,EACZ,wBAAwB,CAC3B,CAAC;IACN,CAAC;IA4DD,IAAW,WAAW;QAClB,OAAO,IAAI,CAAC,eAAe,CAAC;IAChC,CAAC;IACD,IAAW,QAAQ;QACf,OAAO,IAAI,CAAC,SAAS,CAAC;IAC1B,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,gBAAgB;QACzB,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE;YACtB,IAAI,CAAC,cAAc,GAAG,IAAI,uDAA0B,CAChD,IAAI,CAAC,eAAe,EACpB,IAAI,CAAC,eAAe,EACpB,IAAI,CAAC,MAAM,EACX,IAAI,EACJ,IAAI,CAAC,KAAK,EACV,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,YAAY;YACjB,gBAAgB;YAChB,KAAK,IAAI,EAAE;gBACP,IAAI,IAAI,CAAC,iBAAiB,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE;oBAC1E,OAAO,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,CAAC;iBACzC;gBACD,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAC;YACzF,CAAC,CACJ,CAAC;SACL;QAED,OAAO,IAAI,qDAAyB,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC3E,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,qBAAqB;;QAC9B,MAAM,WAAW,eAAG,IAAI,CAAC,cAAc,0CAAE,GAAG,mCAAI,EAAE,CAAC;QACnD,MAAM,OAAO,GAAG,IAAI,iDAAuB,CACvC,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,eAAe,EAC9C,IAAI,CAAC,eAAe,EACpB,IAAI,CAAC,YAAY,EACjB,IAAI,CAAC,MAAM,CACd,CAAC;QAEF,kEAAkE;QAClE,MAAM,SAAS,SAAG,IAAI,CAAC,UAAU,CAAC,YAAY,mCAAI,IAAI,CAAC;QACvD,MAAM,WAAW,SAAG,IAAI,CAAC,UAAU,CAAC,oBAAoB,mCAAI,CAAC,CAAC;QAC9D,OAAO,IAAI,mDAAyB,CAChC,WAAW,EACX,IAAI,CAAC,MAAM,EACX,SAAS,EACT,WAAW,EACX,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,EAAE,cAAc,EAAE,WAAW,CAAC,EACnG,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE;;YACf,MAAM,GAAG,GAAG,aAAM,IAAI,CAAC,QAAQ,0CAAE,GAAG,CAAC,IAAI,EAAE,EAAE,EAAC,CAAC;YAC/C,aAAO,GAAkC,mCAAI,EAAE,CAAC;QACpD,CAAC,EACD,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE;YACT,IAAI,IAAI,CAAC,iBAAiB,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE;gBAC1E,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;aAC/C;QACL,CAAC,EACD,CAAC,GAAgC,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAC9D,CAAC;IACN,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,oBAAoB,CAAC,MAAe;QAC7C,2DAA2D;QAC3D,OAAO,uCAA2B,CAA2B,KAAK,EAAE,OAAO,EAAE,EAAE;YAC3E,wFAAwF;YACxF,8EAA8E;YAC9E,MAAM,oCAAoC,GAAG,IAAI,CAAC,iBAAiB,KAAK,SAAS,CAAC;YAClF,MAAM,qBAAqB,GAAG,oCAAoC;gBAC9D,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;gBACvB,CAAC,CAAC,IAAI,CAAC,iBAAkB,CAAC,OAAO,CAAC,CAAC;YAEvC,MAAM,kBAAkB,GAAG,IAAI,CAAC,WAAW,CAAC,oCAAoC,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;gBACnG,MAAM,gBAAgB,GAAG,CAAgB,CAAC;gBAC1C,IAAI,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC,UAAU,CAAC,EAAE;oBAC5C,KAAK,MAAM,IAAI,IAAI,gBAAgB,CAAC,UAAU,EAAE;wBAC5C,QAAQ,IAAI,EAAE;4BACV,KAAK,kCAAkC,CAAC;4BACxC,KAAK,4CAA4C,CAAC;4BAClD,KAAK,mCAAmC;gCACpC,yDAAyD;gCACzD,yCAAyC;gCACzC,8CAA8C;gCAC9C,IAAI,CAAC,SAAS,mCAAO,IAAI,CAAC,SAAS,KAAC,WAAW,EAAE,IAAI,GAAC,CAAC;gCACvD,MAAM,IAAI,kDAAmC,CAAC,IAAI,CAAC,CAAC;4BACxD;gCACI,SAAS;yBAChB;qBACJ;iBACJ;gBACD,MAAM,CAAC,CAAC;YACZ,CAAC,CAAC,CAAC;YAEH,MAAM,CAAC,iBAAiB,EAAE,cAAc,EAAE,EAAE,CAAC,GACzC,MAAM,OAAO,CAAC,GAAG,CAAC;gBACd,kBAAkB;gBAClB,qBAAqB;gBACrB,IAAI,CAAC,qBAAqB,EAAE;aAC/B,CAAC,CAAC;YAEP,MAAM,mBAAmB,GAAG,cAAc,aAAd,cAAc,cAAd,cAAc,GAAI,CAAC,iBAAiB,CAAC,WAAW,IAAI,IAAI,CAAC,CAAC;YACtF,IAAI,mBAAmB,KAAK,IAAI,EAAE;gBAC9B,MAAM,IAAI,gCAAiB,CACvB,iBAAiB,EACjB,yBAAyB,EACzB,uCAAa,CAAC,eAAe,CAAC,CAAC;aACtC;YACD,IAAI;gBACA,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,6BAA6B,CACvD,iBAAiB,CAAC,QAAQ,EAC1B,iBAAiB,CAAC,EAAE,EACpB,mBAAmB,EACnB,EAAE,EACF,MAAM,EACN,iBAAiB,CAAC,oBAAoB,CAAC,CAAC;gBAC5C,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,UAAU,EAAE,GAAgC,EAAE,EAAE;oBACjE,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;gBAC1B,CAAC,CAAC,CAAC;gBACH,IAAI,CAAC,iBAAiB,GAAG,UAAU,CAAC;gBACpC,OAAO,UAAU,CAAC;aACrB;YAAC,OAAO,KAAK,EAAE;gBACZ,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;gBACxD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE;oBAC7C,KAAK,CAAC,gBAAgB,GAAG,iBAAiB,CAAC,EAAE,CAAC;iBACjD;gBACD,MAAM,KAAK,CAAC;aACf;QACL,CAAC,CAAC,CAAC;IACP,CAAC;IAEO,KAAK,CAAC,WAAW,CACrB,kBAA2B,EAC3B,OAA4B;QAE5B,MAAM,YAAY,GAAG,KAAK,IAAI,EAAE;;YAC5B,OAAA,wBAAgB,CACZ,IAAI,CAAC,eAAe,EACpB,sBAAsB,EACtB,MAAM,EACN,IAAI,CAAC,MAAM,EACX,IAAI,CAAC,eAAe,EACpB,IAAI,CAAC,YAAY,EACjB,kBAAkB,EAClB,OAAO,QACP,IAAI,CAAC,UAAU,CAAC,cAAc,0CAAE,8BAA8B,CACjE,CAAA;SAAA,CAAC;QAEN,wEAAwE;QACxE,iGAAiG;QACjG,OAAO,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;IACnF,CAAC;IAED;;;;;;;;;;OAUG;IACK,KAAK,CAAC,6BAA6B,CACvC,QAAgB,EAChB,UAAkB,EAClB,KAAoB,EACpB,EAAwB,EACxB,MAAe,EACf,YAAoB;QAEpB,MAAM,SAAS,GAAG,0BAAW,CAAC,GAAG,EAAE,CAAC;QACpC,MAAM,UAAU,GAAG,MAAM,yDAA2B,CAAC,MAAM,CACvD,QAAQ,EACR,UAAU,EACV,KAAK,EACL,EAAE,EACF,MAAM,EACN,YAAY,EACZ,IAAI,CAAC,MAAM,EACX,KAAK,EACL,IAAI,CAAC,YAAY,EACjB,IAAI,CAAC,wBAAwB,CAChC,CAAC;QACF,MAAM,QAAQ,GAAG,0BAAW,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QAC/C,uEAAuE;QACvE,+EAA+E;QAC/E,sDAAsD;QACtD,IAAI,QAAQ,IAAI,IAAI,EAAE;YAClB,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;gBAC7B,SAAS,EAAE,mBAAmB;gBAC9B,QAAQ;aACX,CAAC,CAAC;SACN;QACD,OAAO,UAAU,CAAC;IACtB,CAAC;IAEM,OAAO,CAAC,KAAW;;QACtB,4EAA4E;QAC5E,8CAA8C;QAC9C,wFAAwF;QACxF,kEAAkE;QAClE,IAAI,KAAK,KAAK,SAAS,EAAE;YACrB,IAAI,CAAC,YAAY,CAAC,aAAa,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;SACrD;aAAM;YACH,MAAA,IAAI,CAAC,SAAS,0CAAE,QAAQ,GAAG;SAC9B;QACD,MAAA,IAAI,CAAC,SAAS,0CAAE,OAAO,GAAG;IAC9B,CAAC;IAED,IAAc,QAAQ;;QAClB,IAAI,IAAI,CAAC,SAAS,EAAE;YAChB,OAAO,IAAI,CAAC,SAAS,CAAC;SACzB;QAED,MAAM,SAAS,SAAG,IAAI,CAAC,cAAc,0CAAE,sBAAsB,CAAC;QAC9D,MAAM,SAAS,eAAG,IAAI,CAAC,UAAU,CAAC,UAAU,0CAAE,SAAS,mCAAI,GAAG,CAAC;QAC/D,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,GAAG,CAAC,EAAE;YAC1C,OAAO;SACV;QAED,MAAM,MAAM,GAAwB;YAChC,IAAI,EAAE,KAAK;SACd,CAAC;QACF,IAAI,CAAC,SAAS,GAAG,IAAI,qBAAQ,CACzB,SAAS,EACT,IAAI,CAAC,MAAM;QACX,SAAS;QACT;YACI,KAAK,EAAE,KAAK,EAAE,GAAW,EAAE,OAAe,EAAE,EAAE;gBAC1C,OAAO,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,GAAG,iCAAK,MAAM,KAAE,GAAG,KAAG,OAAO,CAAC,CAAC;YACpE,CAAC;YACD,IAAI,EAAE,KAAK,EAAE,GAAW,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,GAAG,iCAAK,MAAM,KAAE,GAAG,IAAE;YAC5E,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,aAAa,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC,CAAC,CAAC;SAC/E,EACD,SAAS,cACT,IAAI,CAAC,UAAU,CAAC,UAAU,0CAAE,gBAAgB,mCAAI,IAAI,cACpD,IAAI,CAAC,UAAU,CAAC,UAAU,0CAAE,eAAe,mCAAI,IAAI,CACtD,CAAC;QACF,OAAO,IAAI,CAAC,SAAS,CAAC;IAC1B,CAAC;IAED,mHAAmH;IACnH,8EAA8E;IACpE,WAAW,CAAC,GAAgC;;QAClD,2CAA2C;QAC3C,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,eAAe,CAAC,UAAU,EAAE;YACrD,OAAO;SACV;QAED,MAAA,IAAI,CAAC,QAAQ,0CAAE,MAAM,CAAC,GAAG,EAAE;IAC/B,CAAC;CACJ;AA7WD,kDA6WC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { performance } from \"@fluidframework/common-utils\";\nimport { ChildLogger, TelemetryLogger } from \"@fluidframework/telemetry-utils\";\nimport {\n IDocumentDeltaConnection,\n IDocumentDeltaStorageService,\n IDocumentService,\n IResolvedUrl,\n IDocumentStorageService,\n IDocumentServicePolicies,\n} from \"@fluidframework/driver-definitions\";\nimport { DeltaStreamConnectionForbiddenError, NonRetryableError } from \"@fluidframework/driver-utils\";\nimport { IFacetCodes } from \"@fluidframework/odsp-doclib-utils\";\nimport {\n IClient,\n ISequencedDocumentMessage,\n} from \"@fluidframework/protocol-definitions\";\nimport {\n IOdspResolvedUrl,\n TokenFetchOptions,\n IEntry,\n HostStoragePolicy,\n InstrumentedStorageTokenFetcher,\n OdspErrorType,\n} from \"@fluidframework/odsp-driver-definitions\";\nimport { HostStoragePolicyInternal, ISocketStorageDiscovery } from \"./contracts\";\nimport { IOdspCache } from \"./odspCache\";\nimport { OdspDeltaStorageService, OdspDeltaStorageWithCache } from \"./odspDeltaStorageService\";\nimport { OdspDocumentDeltaConnection } from \"./odspDocumentDeltaConnection\";\nimport { OdspDocumentStorageService } from \"./odspDocumentStorageManager\";\nimport { getWithRetryForTokenRefresh, getOdspResolvedUrl, TokenFetchOptionsEx } from \"./odspUtils\";\nimport { fetchJoinSession } from \"./vroom\";\nimport { isOdcOrigin } from \"./odspUrlHelper\";\nimport { EpochTracker } from \"./epochTracker\";\nimport { OpsCache } from \"./opsCaching\";\nimport { RetryErrorsStorageAdapter } from \"./retryErrorsStorageAdapter\";\n\n// Gate that when set to \"1\", instructs to fetch the binary format snapshot from the spo.\nfunction gatesBinaryFormatSnapshot() {\n try {\n if (typeof localStorage === \"object\" && localStorage !== null) {\n if (localStorage.binaryFormatSnapshot === \"1\") {\n return true;\n }\n }\n } catch (e) {}\n return false;\n}\n\n/**\n * The DocumentService manages the Socket.IO connection and manages routing requests to connected\n * clients\n */\nexport class OdspDocumentService implements IDocumentService {\n private _policies: IDocumentServicePolicies;\n\n /**\n * @param resolvedUrl - resolved url identifying document that will be managed by returned service instance.\n * @param getStorageToken - function that can provide the storage token. This is is also referred to as\n * the \"Vroom\" token in SPO.\n * @param getWebsocketToken - function that can provide a token for accessing the web socket. This is also referred\n * to as the \"Push\" token in SPO. If undefined then websocket token is expected to be returned with joinSession\n * response payload.\n * @param logger - a logger that can capture performance and diagnostic information\n * @param socketIoClientFactory - A factory that returns a promise to the socket io library required by the driver\n * @param cache - This caches response for joinSession.\n * @param hostPolicy - This host constructed policy which customizes service behavior.\n * @param epochTracker - This helper class which adds epoch to backend calls made by returned service instance.\n * @param socketReferenceKeyPrefix - (optional) prefix to isolate socket reuse cache\n */\n public static async create(\n resolvedUrl: IResolvedUrl,\n getStorageToken: InstrumentedStorageTokenFetcher,\n getWebsocketToken: ((options: TokenFetchOptions) => Promise<string | null>) | undefined,\n logger: ITelemetryLogger,\n socketIoClientFactory: () => Promise<SocketIOClientStatic>,\n cache: IOdspCache,\n hostPolicy: HostStoragePolicy,\n epochTracker: EpochTracker,\n socketReferenceKeyPrefix?: string,\n ): Promise<IDocumentService> {\n return new OdspDocumentService(\n getOdspResolvedUrl(resolvedUrl),\n getStorageToken,\n getWebsocketToken,\n logger,\n socketIoClientFactory,\n cache,\n hostPolicy,\n epochTracker,\n socketReferenceKeyPrefix,\n );\n }\n\n private storageManager?: OdspDocumentStorageService;\n\n private readonly logger: TelemetryLogger;\n\n private readonly joinSessionKey: string;\n\n private readonly hostPolicy: HostStoragePolicyInternal;\n\n private _opsCache?: OpsCache;\n\n private currentConnection?: OdspDocumentDeltaConnection;\n\n /**\n * @param odspResolvedUrl - resolved url identifying document that will be managed by this service instance.\n * @param getStorageToken - function that can provide the storage token. This is is also referred to as\n * the \"Vroom\" token in SPO.\n * @param getWebsocketToken - function that can provide a token for accessing the web socket. This is also referred\n * to as the \"Push\" token in SPO. If undefined then websocket token is expected to be returned with joinSession\n * response payload.\n * @param logger - a logger that can capture performance and diagnostic information\n * @param socketIoClientFactory - A factory that returns a promise to the socket io library required by the driver\n * @param cache - This caches response for joinSession.\n * @param hostPolicy - host constructed policy which customizes service behavior.\n * @param epochTracker - This helper class which adds epoch to backend calls made by this service instance.\n * @param socketReferenceKeyPrefix - (optional) prefix to isolate socket reuse cache\n */\n private constructor(\n public readonly odspResolvedUrl: IOdspResolvedUrl,\n private readonly getStorageToken: InstrumentedStorageTokenFetcher,\n private readonly getWebsocketToken: ((options: TokenFetchOptions) => Promise<string | null>) | undefined,\n logger: ITelemetryLogger,\n private readonly socketIoClientFactory: () => Promise<SocketIOClientStatic>,\n private readonly cache: IOdspCache,\n hostPolicy: HostStoragePolicy,\n private readonly epochTracker: EpochTracker,\n private readonly socketReferenceKeyPrefix?: string,\n ) {\n this._policies = {\n // load in storage-only mode if a file version is specified\n storageOnly: odspResolvedUrl.fileVersion !== undefined,\n };\n\n this.joinSessionKey = `${this.odspResolvedUrl.hashedDocumentId}/joinsession`;\n this.logger = ChildLogger.create(logger,\n undefined,\n {\n all: {\n odc: isOdcOrigin(new URL(this.odspResolvedUrl.endpoints.snapshotStorageUrl).origin),\n },\n });\n\n this.hostPolicy = hostPolicy;\n this.hostPolicy.fetchBinarySnapshotFormat ??= gatesBinaryFormatSnapshot();\n if (this.odspResolvedUrl.summarizer) {\n this.hostPolicy = { ...this.hostPolicy, summarizerClient: true };\n }\n }\n\n public get resolvedUrl(): IResolvedUrl {\n return this.odspResolvedUrl;\n }\n public get policies() {\n return this._policies;\n }\n\n /**\n * Connects to a storage endpoint for snapshot service.\n *\n * @returns returns the document storage service for sharepoint driver.\n */\n public async connectToStorage(): Promise<IDocumentStorageService> {\n if (!this.storageManager) {\n this.storageManager = new OdspDocumentStorageService(\n this.odspResolvedUrl,\n this.getStorageToken,\n this.logger,\n true,\n this.cache,\n this.hostPolicy,\n this.epochTracker,\n // flushCallback\n async () => {\n if (this.currentConnection !== undefined && !this.currentConnection.disposed) {\n return this.currentConnection.flush();\n }\n throw new Error(\"Disconnected while uploading summary (attempt to perform flush())\");\n },\n );\n }\n\n return new RetryErrorsStorageAdapter(this.storageManager, this.logger);\n }\n\n /**\n * Connects to a delta storage endpoint for getting ops between a range.\n *\n * @returns returns the document delta storage service for sharepoint driver.\n */\n public async connectToDeltaStorage(): Promise<IDocumentDeltaStorageService> {\n const snapshotOps = this.storageManager?.ops ?? [];\n const service = new OdspDeltaStorageService(\n this.odspResolvedUrl.endpoints.deltaStorageUrl,\n this.getStorageToken,\n this.epochTracker,\n this.logger,\n );\n\n // batch size, please see issue #5211 for data around batch sizing\n const batchSize = this.hostPolicy.opsBatchSize ?? 5000;\n const concurrency = this.hostPolicy.concurrentOpsBatches ?? 1;\n return new OdspDeltaStorageWithCache(\n snapshotOps,\n this.logger,\n batchSize,\n concurrency,\n async (from, to, telemetryProps, fetchReason) => service.get(from, to, telemetryProps, fetchReason),\n async (from, to) => {\n const res = await this.opsCache?.get(from, to);\n return res as ISequencedDocumentMessage[] ?? [];\n },\n (from, to) => {\n if (this.currentConnection !== undefined && !this.currentConnection.disposed) {\n this.currentConnection.requestOps(from, to);\n }\n },\n (ops: ISequencedDocumentMessage[]) => this.opsReceived(ops),\n );\n }\n\n /**\n * Connects to a delta stream endpoint for emitting ops.\n *\n * @returns returns the document delta stream service for onedrive/sharepoint driver.\n */\n public async connectToDeltaStream(client: IClient): Promise<IDocumentDeltaConnection> {\n // Attempt to connect twice, in case we used expired token.\n return getWithRetryForTokenRefresh<IDocumentDeltaConnection>(async (options) => {\n // Presence of getWebsocketToken callback dictates whether callback is used for fetching\n // websocket token or whether it is returned with joinSession response payload\n const requestWebsocketTokenFromJoinSession = this.getWebsocketToken === undefined;\n const websocketTokenPromise = requestWebsocketTokenFromJoinSession\n ? Promise.resolve(null)\n : this.getWebsocketToken!(options);\n\n const joinSessionPromise = this.joinSession(requestWebsocketTokenFromJoinSession, options).catch((e) => {\n const likelyFacetCodes = e as IFacetCodes;\n if (Array.isArray(likelyFacetCodes.facetCodes)) {\n for (const code of likelyFacetCodes.facetCodes) {\n switch (code) {\n case \"sessionForbiddenOnPreservedFiles\":\n case \"sessionForbiddenOnModerationEnabledLibrary\":\n case \"sessionForbiddenOnRequireCheckout\":\n // This document can only be opened in storage-only mode.\n // DeltaManager will recognize this error\n // and load without a delta stream connection.\n this._policies = {...this._policies,storageOnly: true};\n throw new DeltaStreamConnectionForbiddenError(code);\n default:\n continue;\n }\n }\n }\n throw e;\n });\n\n const [websocketEndpoint, websocketToken, io] =\n await Promise.all([\n joinSessionPromise,\n websocketTokenPromise,\n this.socketIoClientFactory(),\n ]);\n\n const finalWebsocketToken = websocketToken ?? (websocketEndpoint.socketToken || null);\n if (finalWebsocketToken === null) {\n throw new NonRetryableError(\n \"pushTokenIsNull\",\n \"Websocket token is null\",\n OdspErrorType.fetchTokenError);\n }\n try {\n const connection = await this.connectToDeltaStreamWithRetry(\n websocketEndpoint.tenantId,\n websocketEndpoint.id,\n finalWebsocketToken,\n io,\n client,\n websocketEndpoint.deltaStreamSocketUrl);\n connection.on(\"op\", (documentId, ops: ISequencedDocumentMessage[]) => {\n this.opsReceived(ops);\n });\n this.currentConnection = connection;\n return connection;\n } catch (error) {\n this.cache.sessionJoinCache.remove(this.joinSessionKey);\n if (typeof error === \"object\" && error !== null) {\n error.socketDocumentId = websocketEndpoint.id;\n }\n throw error;\n }\n });\n }\n\n private async joinSession(\n requestSocketToken: boolean,\n options: TokenFetchOptionsEx,\n ): Promise<ISocketStorageDiscovery> {\n const executeFetch = async () =>\n fetchJoinSession(\n this.odspResolvedUrl,\n \"opStream/joinSession\",\n \"POST\",\n this.logger,\n this.getStorageToken,\n this.epochTracker,\n requestSocketToken,\n options,\n this.hostPolicy.sessionOptions?.unauthenticatedUserDisplayName,\n );\n\n // Note: The sessionCache is configured with a sliding expiry of 1 hour,\n // so if we've fetched the join session within the last hour we won't run executeFetch again now.\n return this.cache.sessionJoinCache.addOrGet(this.joinSessionKey, executeFetch);\n }\n\n /**\n * Connects to a delta stream endpoint\n * If url #1 fails to connect, tries url #2 if applicable\n *\n * @param tenantId - the ID of the tenant\n * @param documentId - document ID\n * @param token - authorization token for storage service\n * @param io - websocket library\n * @param client - information about the client\n * @param webSocketUrl - websocket URL\n */\n private async connectToDeltaStreamWithRetry(\n tenantId: string,\n documentId: string,\n token: string | null,\n io: SocketIOClientStatic,\n client: IClient,\n webSocketUrl: string,\n ): Promise<OdspDocumentDeltaConnection> {\n const startTime = performance.now();\n const connection = await OdspDocumentDeltaConnection.create(\n tenantId,\n documentId,\n token,\n io,\n client,\n webSocketUrl,\n this.logger,\n 60000,\n this.epochTracker,\n this.socketReferenceKeyPrefix,\n );\n const duration = performance.now() - startTime;\n // This event happens rather often, so it adds up to cost of telemetry.\n // Given that most reconnects result in reusing socket and happen very quickly,\n // report event only if it took longer than threshold.\n if (duration >= 2000) {\n this.logger.sendPerformanceEvent({\n eventName: \"ConnectionSuccess\",\n duration,\n });\n }\n return connection;\n }\n\n public dispose(error?: any) {\n // Error might indicate mismatch between client & server knowlege about file\n // (DriverErrorType.fileOverwrittenInStorage).\n // For example, file might have been overwritten in storage without generating new epoch\n // In such case client cached info is stale and has to be removed.\n if (error !== undefined) {\n this.epochTracker.removeEntries().catch(() => {});\n } else {\n this._opsCache?.flushOps();\n }\n this._opsCache?.dispose();\n }\n\n protected get opsCache() {\n if (this._opsCache) {\n return this._opsCache;\n }\n\n const seqNumber = this.storageManager?.snapshotSequenceNumber;\n const batchSize = this.hostPolicy.opsCaching?.batchSize ?? 100;\n if (seqNumber === undefined || batchSize < 1) {\n return;\n }\n\n const opsKey: Omit<IEntry, \"key\"> = {\n type: \"ops\",\n };\n this._opsCache = new OpsCache(\n seqNumber,\n this.logger,\n // ICache\n {\n write: async (key: string, opsData: string) => {\n return this.cache.persistedCache.put({...opsKey, key}, opsData);\n },\n read: async (key: string) => this.cache.persistedCache.get({...opsKey, key}),\n remove: () => { this.cache.persistedCache.removeEntries().catch(() => {}); },\n },\n batchSize,\n this.hostPolicy.opsCaching?.timerGranularity ?? 5000,\n this.hostPolicy.opsCaching?.totalOpsToCache ?? 5000,\n );\n return this._opsCache;\n }\n\n // Called whenever re receive ops through any channel for this document (snapshot, delta connection, delta storage)\n // We use it to notify caching layer of how stale is snapshot stored in cache.\n protected opsReceived(ops: ISequencedDocumentMessage[]) {\n // No need for two clients to save same ops\n if (ops.length === 0 || this.odspResolvedUrl.summarizer) {\n return;\n }\n\n this.opsCache?.addOps(ops);\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"odspDocumentStorageManager.d.ts","sourceRoot":"","sources":["../src/odspDocumentStorageManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAQtE,OAAO,KAAK,GAAG,MAAM,sCAAsC,CAAC;AAC5D,OAAO,EACH,eAAe,EACf,uBAAuB,EACvB,mBAAmB,EACtB,MAAM,oCAAoC,CAAC;AAG5C,OAAO,EACH,gBAAgB,EAGhB,+BAA+B,EAClC,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAEH,yBAAyB,EAG5B,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAMzC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AA6G5D,qBAAa,0BAA2B,YAAW,uBAAuB;IA4DlE,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAlElC,QAAQ,CAAC,QAAQ;;;MAef;IAEF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6C;IAEzE,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAA0B;IAEhE,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAA2B;IACpE,OAAO,CAAC,IAAI,CAA8C;IAE1D,OAAO,CAAC,gBAAgB,CAAQ;IAChC,OAAO,CAAC,uBAAuB,CAAqB;IAEpD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;IACjD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAqB;IACvD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAqB;IAEtD;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAa;IAClD,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAU;IAGlD,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAsB;IAE5D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmB;IAE7C,IAAW,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,yBAAyB,EAAE,GAAG,SAAS,EAG9D;IAED,IAAW,GAAG,IAAI,GAAG,CAAC,yBAAyB,EAAE,GAAG,SAAS,CAE5D;IAED,IAAW,sBAAsB,uBAEhC;gBAGoB,eAAe,EAAE,gBAAgB,EACjC,eAAe,EAAE,+BAA+B,EAChD,MAAM,EAAE,gBAAgB,EACxB,iBAAiB,EAAE,OAAO,EAC1B,KAAK,EAAE,UAAU,EACjB,UAAU,EAAE,yBAAyB,EACrC,YAAY,EAAE,YAAY,EAC1B,aAAa,EAAE,MAAM,OAAO,CAAC,WAAW,CAAC;IAS9D,IAAW,aAAa,IAAI,MAAM,CAEjC;IAEY,UAAU,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;YAsClE,YAAY;IAkDb,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAIlD,eAAe,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,GAAG,IAAI,CAAC;IAsD1E,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;YAsJzE,aAAa;YAcb,iBAAiB;IA4ElB,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;IAMjF,wBAAwB,CAAC,OAAO,EAAE,GAAG,CAAC,YAAY,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC;IAyC9F,eAAe,CAAC,MAAM,EAAE,GAAG,CAAC,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;IAInF,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,sBAAsB;IAM9B,OAAO,CAAC,qBAAqB;YAMf,QAAQ;IAsCtB;;;;OAIG;YACW,eAAe;IA4B7B,OAAO,CAAC,iCAAiC;CAqB5C"}
1
+ {"version":3,"file":"odspDocumentStorageManager.d.ts","sourceRoot":"","sources":["../src/odspDocumentStorageManager.ts"],"names":[],"mappings":"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"}
@@ -9,7 +9,6 @@ const common_utils_1 = require("@fluidframework/common-utils");
9
9
  const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
10
10
  const driver_definitions_1 = require("@fluidframework/driver-definitions");
11
11
  const driver_utils_1 = require("@fluidframework/driver-utils");
12
- const odsp_doclib_utils_1 = require("@fluidframework/odsp-doclib-utils");
13
12
  const odsp_driver_definitions_1 = require("@fluidframework/odsp-driver-definitions");
14
13
  const fetchSnapshot_1 = require("./fetchSnapshot");
15
14
  const getUrlAndHeadersWithAuth_1 = require("./getUrlAndHeadersWithAuth");
@@ -221,9 +220,6 @@ class OdspDocumentStorageService {
221
220
  });
222
221
  this.blobCache.setBlob(blobId, blob);
223
222
  }
224
- if (!this.attributesBlobHandles.has(blobId)) {
225
- return blob;
226
- }
227
223
  return blob;
228
224
  }
229
225
  async readBlob(blobId) {
@@ -302,39 +298,46 @@ class OdspDocumentStorageService {
302
298
  const hostSnapshotOptions = this.hostPolicy.snapshotOptions;
303
299
  const odspSnapshotCacheValue = await telemetry_utils_1.PerformanceEvent.timedExecAsync(this.logger, { eventName: "ObtainSnapshot" }, async (event) => {
304
300
  const props = {};
305
- let cachedSnapshot;
301
+ let retrievedSnapshot;
302
+ // Here's the logic to grab the persistent cache snapshot implemented by the host
303
+ // Epoch tracker is responsible for communicating with the persistent cache, handling epochs and cache versions
306
304
  const cachedSnapshotP = this.epochTracker.get(odspUtils_1.createCacheSnapshotKey(this.odspResolvedUrl))
307
- .then((snapshotCachedEntry) => {
305
+ .then(async (snapshotCachedEntry) => {
308
306
  var _a;
309
307
  if (snapshotCachedEntry !== undefined) {
310
308
  // If the cached entry does not contain the entry time, then assign it a default of 30 days old.
309
+ const age = Date.now() - ((_a = snapshotCachedEntry.cacheEntryTime) !== null && _a !== void 0 ? _a : (Date.now() - 30 * 24 * 60 * 60 * 1000));
310
+ // Record the cache age
311
311
  // eslint-disable-next-line @typescript-eslint/dot-notation
312
- props["cacheEntryAge"] = Date.now() - ((_a = snapshotCachedEntry.cacheEntryTime) !== null && _a !== void 0 ? _a : (Date.now() - 30 * 24 * 60 * 60 * 1000));
312
+ props["cacheEntryAge"] = age;
313
313
  }
314
314
  return snapshotCachedEntry;
315
315
  });
316
+ // Based on the concurrentSnapshotFetch policy:
317
+ // Either retrieve both the network and cache snapshots concurrently and pick the first to return,
318
+ // or grab the cache value and then the network value if the cache value returns undefined.
316
319
  let method;
317
320
  if (this.hostPolicy.concurrentSnapshotFetch && !this.hostPolicy.summarizerClient) {
318
- const snapshotP = this.fetchSnapshot(hostSnapshotOptions);
321
+ const networkSnapshotP = this.fetchSnapshot(hostSnapshotOptions);
319
322
  // Ensure that failures on both paths are ignored initially.
320
323
  // I.e. if cache fails for some reason, we will proceed with network result.
321
324
  // And vice versa - if (for example) client is offline and network request fails first, we
322
325
  // do want to attempt to succeed with cached data!
323
326
  const promiseRaceWinner = await promiseRaceWithWinner([
324
327
  cachedSnapshotP.catch(() => undefined),
325
- snapshotP.catch(() => undefined),
328
+ networkSnapshotP.catch(() => undefined),
326
329
  ]);
327
- cachedSnapshot = promiseRaceWinner.value;
330
+ retrievedSnapshot = promiseRaceWinner.value;
328
331
  method = promiseRaceWinner.index === 0 ? "cache" : "network";
329
- if (cachedSnapshot === undefined) {
332
+ if (retrievedSnapshot === undefined) {
330
333
  // if network failed -> wait for cache ( then return network failure)
331
334
  // If cache returned empty or failed -> wait for network (success of failure)
332
335
  if (promiseRaceWinner.index === 1) {
333
- cachedSnapshot = await cachedSnapshotP;
336
+ retrievedSnapshot = await cachedSnapshotP;
334
337
  method = "cache";
335
338
  }
336
- if (cachedSnapshot === undefined) {
337
- cachedSnapshot = await snapshotP;
339
+ if (retrievedSnapshot === undefined) {
340
+ retrievedSnapshot = await networkSnapshotP;
338
341
  method = "network";
339
342
  }
340
343
  }
@@ -342,10 +345,10 @@ class OdspDocumentStorageService {
342
345
  else {
343
346
  // Note: There's a race condition here - another caller may come past the undefined check
344
347
  // while the first caller is awaiting later async code in this block.
345
- cachedSnapshot = await cachedSnapshotP;
346
- method = cachedSnapshot !== undefined ? "cache" : "network";
347
- if (cachedSnapshot === undefined) {
348
- cachedSnapshot = await this.fetchSnapshot(hostSnapshotOptions);
348
+ retrievedSnapshot = await cachedSnapshotP;
349
+ method = retrievedSnapshot !== undefined ? "cache" : "network";
350
+ if (retrievedSnapshot === undefined) {
351
+ retrievedSnapshot = await this.fetchSnapshot(hostSnapshotOptions);
349
352
  }
350
353
  }
351
354
  if (method === "network") {
@@ -353,9 +356,9 @@ class OdspDocumentStorageService {
353
356
  props["cacheEntryAge"] = undefined;
354
357
  }
355
358
  event.end(Object.assign(Object.assign({}, props), { method }));
356
- return cachedSnapshot;
357
- }, { end: true, cancel: "error" });
358
- // Successful call, redirect future calls to getVersion only!
359
+ return retrievedSnapshot;
360
+ });
361
+ // Successful call, make network calls only
359
362
  this.firstVersionCall = false;
360
363
  this._snapshotSequenceNumber = odspSnapshotCacheValue.sequenceNumber;
361
364
  const { snapshotTree, blobs, ops } = odspSnapshotCacheValue;
@@ -382,10 +385,10 @@ class OdspDocumentStorageService {
382
385
  }, async () => this.epochTracker.fetchAndParseAsJSON(url, { headers }, "versions"));
383
386
  const versionsResponse = response.content;
384
387
  if (!versionsResponse) {
385
- odsp_doclib_utils_1.throwOdspNetworkError("getVersionsReturnedNoResponse", 400);
388
+ throw new driver_utils_1.NonRetryableError("getVersionsReturnedNoResponse", "No response from /versions endpoint", driver_definitions_1.DriverErrorType.genericNetworkError);
386
389
  }
387
390
  if (!Array.isArray(versionsResponse.value)) {
388
- odsp_doclib_utils_1.throwOdspNetworkError("getVersionsReturnedNonArrayResponse", 400);
391
+ throw new driver_utils_1.NonRetryableError("getVersionsReturnedNonArrayResponse", "Incorrect response from /versions endpoint", driver_definitions_1.DriverErrorType.genericNetworkError);
389
392
  }
390
393
  return versionsResponse.value.map((version) => {
391
394
  // Parse the date from the message
@@ -496,17 +499,17 @@ class OdspDocumentStorageService {
496
499
  }
497
500
  checkSnapshotUrl() {
498
501
  if (!this.snapshotUrl) {
499
- odsp_doclib_utils_1.throwOdspNetworkError("methodNotSupportedBecauseNoSnapshotUrlWasProvided", 400);
502
+ throw new driver_utils_1.NonRetryableError("noSnapshotUrlProvided", "Method failed because no snapshot url was available", driver_definitions_1.DriverErrorType.genericError);
500
503
  }
501
504
  }
502
505
  checkAttachmentPOSTUrl() {
503
506
  if (!this.attachmentPOSTUrl) {
504
- odsp_doclib_utils_1.throwOdspNetworkError("methodNotSupportedBecauseNoAttachmentPOSTUrlWasProvided", 400);
507
+ throw new driver_utils_1.NonRetryableError("noAttachmentPOSTUrlProvided", "Method failed because no attachment POST url was available", driver_definitions_1.DriverErrorType.genericError);
505
508
  }
506
509
  }
507
510
  checkAttachmentGETUrl() {
508
511
  if (!this.attachmentGETUrl) {
509
- odsp_doclib_utils_1.throwOdspNetworkError("methodNotSupportedBecauseNoAttachmentGETUrlWasProvided", 400);
512
+ throw new driver_utils_1.NonRetryableError("noAttachmentGETUrlWasProvided", "Method failed because no attachment GET url was available", driver_definitions_1.DriverErrorType.genericError);
510
513
  }
511
514
  }
512
515
  async readTree(id) {