@fluidframework/odsp-driver 0.58.0-55561 → 0.58.1001

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 (44) hide show
  1. package/dist/contracts.d.ts +4 -0
  2. package/dist/contracts.d.ts.map +1 -1
  3. package/dist/contracts.js.map +1 -1
  4. package/dist/odspCache.d.ts +8 -3
  5. package/dist/odspCache.d.ts.map +1 -1
  6. package/dist/odspCache.js +1 -1
  7. package/dist/odspCache.js.map +1 -1
  8. package/dist/odspDocumentService.d.ts +5 -0
  9. package/dist/odspDocumentService.d.ts.map +1 -1
  10. package/dist/odspDocumentService.js +87 -24
  11. package/dist/odspDocumentService.js.map +1 -1
  12. package/dist/packageVersion.d.ts +1 -1
  13. package/dist/packageVersion.d.ts.map +1 -1
  14. package/dist/packageVersion.js +1 -1
  15. package/dist/packageVersion.js.map +1 -1
  16. package/dist/vroom.d.ts +2 -1
  17. package/dist/vroom.d.ts.map +1 -1
  18. package/dist/vroom.js +6 -2
  19. package/dist/vroom.js.map +1 -1
  20. package/lib/contracts.d.ts +4 -0
  21. package/lib/contracts.d.ts.map +1 -1
  22. package/lib/contracts.js.map +1 -1
  23. package/lib/odspCache.d.ts +8 -3
  24. package/lib/odspCache.d.ts.map +1 -1
  25. package/lib/odspCache.js +1 -1
  26. package/lib/odspCache.js.map +1 -1
  27. package/lib/odspDocumentService.d.ts +5 -0
  28. package/lib/odspDocumentService.d.ts.map +1 -1
  29. package/lib/odspDocumentService.js +87 -24
  30. package/lib/odspDocumentService.js.map +1 -1
  31. package/lib/packageVersion.d.ts +1 -1
  32. package/lib/packageVersion.d.ts.map +1 -1
  33. package/lib/packageVersion.js +1 -1
  34. package/lib/packageVersion.js.map +1 -1
  35. package/lib/vroom.d.ts +2 -1
  36. package/lib/vroom.d.ts.map +1 -1
  37. package/lib/vroom.js +6 -2
  38. package/lib/vroom.js.map +1 -1
  39. package/package.json +12 -12
  40. package/src/contracts.ts +5 -0
  41. package/src/odspCache.ts +3 -3
  42. package/src/odspDocumentService.ts +110 -27
  43. package/src/packageVersion.ts +1 -1
  44. package/src/vroom.ts +6 -0
@@ -25,6 +25,10 @@ export interface ISocketStorageDiscovery {
25
25
  * passed as a parameter to `OdspDocumentService.create()` factory.
26
26
  */
27
27
  socketToken?: string;
28
+ /**
29
+ * This is the time within which client has to refresh the session on (ODSP) relay service.
30
+ */
31
+ refreshSessionDurationSeconds?: number;
28
32
  }
29
33
  /**
30
34
  * Interface for error responses for the WebSocket connection
@@ -1 +1 @@
1
- {"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,GAAG,MAAM,sCAAsC,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,CAAC;AAC5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD;;GAEG;AACH,MAAM,WAAW,uBAAuB;IAEpC,EAAE,EAAE,MAAM,CAAC;IAIX,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IAEjB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IAExB;;OAEG;IACH,oBAAoB,EAAE,MAAM,CAAC;IAE7B;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC7B;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACrC,KAAK,EAAE,GAAG,CAAC,yBAAyB,EAAE,GAAG,wBAAwB,EAAE,CAAC;CACvE;AAED,MAAM,WAAW,wBAAwB;IACrC,EAAE,EAAE,GAAG,CAAC,yBAAyB,CAAC;IAClC,cAAc,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,mCAAmC;IAChD,KAAK,EAAE,uBAAuB,EAAE,CAAC;CACpC;AAED,MAAM,WAAW,uBAAuB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AAEH,MAAM,WAAW,mBAAmB;IAChC,IAAI,EAAE,WAAW,GAAG,SAAS,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,oBAAoB,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,qBAAqB;IAClC,EAAE,EAAE,MAAM,CAAC;CACd;AAED,oBAAY,oBAAoB,GAAG,0BAA0B,GAAG,2BAA2B,CAAC;AAE5F,MAAM,WAAW,yBAAyB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;CACpC;AAED,MAAM,WAAW,0BAA2B,SAAQ,yBAAyB;IACzE,KAAK,EAAE,oBAAoB,CAAC;IAE5B,YAAY,CAAC,EAAE,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,2BAA4B,SAAQ,yBAAyB;IAC1E,EAAE,EAAE,MAAM,CAAC;CACd;AAED,oBAAY,oBAAoB,GAAG,gBAAgB,GAAG,gBAAgB,CAAC;AAEvE,MAAM,WAAW,gBAAgB;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,oBAAoB,EAAE,CAAC;CACpC;AAED,MAAM,WAAW,gBAAgB;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC;CAChC;AAED;;;;GAIG;AAEH,MAAM,WAAW,0BAA0B;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IAEb,YAAY,CAAC,EAAE,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,4BAA4B;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,CAAC;CAClB;AAED,MAAM,WAAW,0BAA0B;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,oBAAY,sBAAsB,GAC5B,0BAA0B,GAC1B,4BAA4B,GAC5B,0BAA0B,CAAC;AAEjC,MAAM,WAAW,mBAAmB;IAChC,OAAO,EAAE,sBAAsB,EAAE,CAAC;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,cAAc,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAC9B,OAAO,EAAE,MAAM,CAAC;IAGhB,QAAQ,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,mBAAmB,EAAE,CAAC;IAC7B,KAAK,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAC5B,GAAG,CAAC,EAAE,wBAAwB,EAAE,CAAC;CACpC;AAED;;;GAGG;AACH,MAAM,WAAW,yBAA0B,SAAQ,iBAAiB;IAChE,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,mBAAmB;IAChC,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sBAAsB,CAAC,EAAE,MAAM,CAAA;CAClC;AAED,MAAM,WAAW,wBAAwB;IACrC,KAAK,EAAE,GAAG,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IAEnB,OAAO,EAAE,CAAC,CAAC;CACd;AAED,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAE5C,MAAM,WAAW,eAAe;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,GAAG,CAAC,yBAAyB,EAAE,CAAC;CAC9C;AAED,MAAM,WAAW,iBAAiB;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,sBAAsB;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2BAA2B,CAAC,EAAE,MAAM,CAAC;CACxC;AAED;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,iBAAiB;IAC3D,cAAc,EAAE,MAAM,CAAC;CAC1B"}
1
+ {"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"contracts.js","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAgNU,QAAA,0BAA0B,GAAG,CAAC,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport * as api from \"@fluidframework/protocol-definitions\";\nimport { HostStoragePolicy } from \"@fluidframework/odsp-driver-definitions\";\nimport { ISnapshotContents } from \"./odspUtils\";\n\n/**\n * Socket storage discovery api response\n */\nexport interface ISocketStorageDiscovery {\n // The id of the web socket\n id: string;\n\n // SPO gives us runtimeTenantId, we remap it to tenantId\n // See getSocketStorageDiscovery\n runtimeTenantId?: string;\n tenantId: string;\n\n snapshotStorageUrl: string;\n deltaStorageUrl: string;\n\n /**\n * PUSH URL\n */\n deltaStreamSocketUrl: string;\n\n /**\n * The access token for PushChannel. Optionally returned, depending on implementation.\n * OneDrive for Consumer implementation returns it and OneDrive for Business implementation\n * does not return it and instead expects token to be returned via `getWebsocketToken` callback\n * passed as a parameter to `OdspDocumentService.create()` factory.\n */\n socketToken?: string;\n}\n\n/**\n * Interface for error responses for the WebSocket connection\n */\nexport interface IOdspSocketError {\n /**\n * An error code number for the error that occurred\n * It will be a valid HTTP status code\n */\n code: number;\n\n /**\n * A message about the error that occurred for debugging / logging purposes\n * This should not be displayed to the user directly\n */\n message: string;\n\n /**\n * Optional Retry-After time in seconds\n * The client should wait this many seconds before retrying its request\n */\n retryAfter?: number;\n}\n\n/**\n * Interface for delta storage response.\n * Contains either SequencedDocumentMessages or SequencedDeltaOpMessage.\n */\nexport interface IDeltaStorageGetResponse {\n value: api.ISequencedDocumentMessage[] | ISequencedDeltaOpMessage[];\n}\n\nexport interface ISequencedDeltaOpMessage {\n op: api.ISequencedDocumentMessage;\n sequenceNumber: number;\n}\n\nexport interface IDocumentStorageGetVersionsResponse {\n value: IDocumentStorageVersion[];\n}\n\nexport interface IDocumentStorageVersion {\n message: string;\n id: string;\n}\n\n/**\n *\n * Data structures that form ODSP Summary\n *\n */\n\nexport interface IOdspSummaryPayload {\n type: \"container\" | \"channel\";\n message: string;\n sequenceNumber: number;\n entries: OdspSummaryTreeEntry[];\n}\n\nexport interface IWriteSummaryResponse {\n id: string;\n}\n\nexport type OdspSummaryTreeEntry = IOdspSummaryTreeValueEntry | IOdspSummaryTreeHandleEntry;\n\nexport interface IOdspSummaryTreeBaseEntry {\n path: string;\n type: \"blob\" | \"tree\" | \"commit\";\n}\n\nexport interface IOdspSummaryTreeValueEntry extends IOdspSummaryTreeBaseEntry {\n value: OdspSummaryTreeValue;\n // Indicates that this tree entry is unreferenced. If this is not present, the tree entry is considered referenced.\n unreferenced?: true;\n}\n\nexport interface IOdspSummaryTreeHandleEntry extends IOdspSummaryTreeBaseEntry {\n id: string;\n}\n\nexport type OdspSummaryTreeValue = IOdspSummaryTree | IOdspSummaryBlob;\n\nexport interface IOdspSummaryTree {\n type: \"tree\";\n entries?: OdspSummaryTreeEntry[];\n}\n\nexport interface IOdspSummaryBlob {\n type: \"blob\";\n content: string;\n encoding: \"base64\" | \"utf-8\";\n}\n\n/**\n *\n * Data structures that form ODSP Snapshot\n *\n */\n\nexport interface IOdspSnapshotTreeEntryTree {\n path: string;\n type: \"tree\";\n // Indicates that this tree entry is unreferenced. If this is not present, the tree entry is considered referenced.\n unreferenced?: true;\n}\n\nexport interface IOdspSnapshotTreeEntryCommit {\n id: string;\n path: string;\n type: \"commit\";\n}\n\nexport interface IOdspSnapshotTreeEntryBlob {\n id: string;\n path: string;\n type: \"blob\";\n}\n\nexport type IOdspSnapshotTreeEntry =\n | IOdspSnapshotTreeEntryTree\n | IOdspSnapshotTreeEntryCommit\n | IOdspSnapshotTreeEntryBlob;\n\nexport interface IOdspSnapshotCommit {\n entries: IOdspSnapshotTreeEntry[];\n id: string;\n sequenceNumber: number;\n}\n\n/**\n * Blob content, represents blobs in downloaded snapshot.\n */\nexport interface IOdspSnapshotBlob {\n content: string;\n // SPO only uses \"base64\" today for download.\n // We are adding undefined too, as temp way to roundtrip strings unchanged.\n encoding: \"base64\" | undefined;\n id: string;\n size: number;\n}\n\nexport interface IOdspSnapshot {\n id: string;\n trees: IOdspSnapshotCommit[];\n blobs?: IOdspSnapshotBlob[];\n ops?: ISequencedDeltaOpMessage[];\n}\n\n/**\n * Same as HostStoragePolicy, but adds options that are internal to runtime.\n * All fields should be optional.\n */\nexport interface HostStoragePolicyInternal extends HostStoragePolicy {\n summarizerClient?: boolean;\n}\n\nexport interface ICreateFileResponse {\n \"@odata.context\": string;\n driveId: string;\n id: string;\n itemId: string;\n itemUrl: string;\n sequenceNumber: number;\n sharingLink?: string;\n sharingLinkErrorReason?: string\n}\n\nexport interface IVersionedValueWithEpoch {\n value: any;\n fluidEpoch: string,\n // This is same as \"persistedCacheValueVersion\" below. This represents the version of data stored in cache.\n version: 3,\n}\n\nexport const persistedCacheValueVersion = 3;\n\nexport interface IGetOpsResponse {\n nonce: string;\n code: number;\n /** Time in seconds. Currently never set by PUSH */\n retryAfter?: number;\n messages?: api.ISequencedDocumentMessage[];\n}\n\nexport interface IFlushOpsResponse {\n nonce: string;\n code: number;\n /** Time in seconds */\n retryAfter?: number;\n lastPersistedSequenceNumber?: number;\n}\n\n/**\n * Represents the cached snapshot value.\n */\nexport interface ISnapshotCachedEntry extends ISnapshotContents {\n cacheEntryTime: number,\n}\n"]}
1
+ {"version":3,"file":"contracts.js","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAqNU,QAAA,0BAA0B,GAAG,CAAC,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport * as api from \"@fluidframework/protocol-definitions\";\nimport { HostStoragePolicy } from \"@fluidframework/odsp-driver-definitions\";\nimport { ISnapshotContents } from \"./odspUtils\";\n\n/**\n * Socket storage discovery api response\n */\nexport interface ISocketStorageDiscovery {\n // The id of the web socket\n id: string;\n\n // SPO gives us runtimeTenantId, we remap it to tenantId\n // See getSocketStorageDiscovery\n runtimeTenantId?: string;\n tenantId: string;\n\n snapshotStorageUrl: string;\n deltaStorageUrl: string;\n\n /**\n * PUSH URL\n */\n deltaStreamSocketUrl: string;\n\n /**\n * The access token for PushChannel. Optionally returned, depending on implementation.\n * OneDrive for Consumer implementation returns it and OneDrive for Business implementation\n * does not return it and instead expects token to be returned via `getWebsocketToken` callback\n * passed as a parameter to `OdspDocumentService.create()` factory.\n */\n socketToken?: string;\n\n /**\n * This is the time within which client has to refresh the session on (ODSP) relay service.\n */\n refreshSessionDurationSeconds?: number;\n}\n\n/**\n * Interface for error responses for the WebSocket connection\n */\nexport interface IOdspSocketError {\n /**\n * An error code number for the error that occurred\n * It will be a valid HTTP status code\n */\n code: number;\n\n /**\n * A message about the error that occurred for debugging / logging purposes\n * This should not be displayed to the user directly\n */\n message: string;\n\n /**\n * Optional Retry-After time in seconds\n * The client should wait this many seconds before retrying its request\n */\n retryAfter?: number;\n}\n\n/**\n * Interface for delta storage response.\n * Contains either SequencedDocumentMessages or SequencedDeltaOpMessage.\n */\nexport interface IDeltaStorageGetResponse {\n value: api.ISequencedDocumentMessage[] | ISequencedDeltaOpMessage[];\n}\n\nexport interface ISequencedDeltaOpMessage {\n op: api.ISequencedDocumentMessage;\n sequenceNumber: number;\n}\n\nexport interface IDocumentStorageGetVersionsResponse {\n value: IDocumentStorageVersion[];\n}\n\nexport interface IDocumentStorageVersion {\n message: string;\n id: string;\n}\n\n/**\n *\n * Data structures that form ODSP Summary\n *\n */\n\nexport interface IOdspSummaryPayload {\n type: \"container\" | \"channel\";\n message: string;\n sequenceNumber: number;\n entries: OdspSummaryTreeEntry[];\n}\n\nexport interface IWriteSummaryResponse {\n id: string;\n}\n\nexport type OdspSummaryTreeEntry = IOdspSummaryTreeValueEntry | IOdspSummaryTreeHandleEntry;\n\nexport interface IOdspSummaryTreeBaseEntry {\n path: string;\n type: \"blob\" | \"tree\" | \"commit\";\n}\n\nexport interface IOdspSummaryTreeValueEntry extends IOdspSummaryTreeBaseEntry {\n value: OdspSummaryTreeValue;\n // Indicates that this tree entry is unreferenced. If this is not present, the tree entry is considered referenced.\n unreferenced?: true;\n}\n\nexport interface IOdspSummaryTreeHandleEntry extends IOdspSummaryTreeBaseEntry {\n id: string;\n}\n\nexport type OdspSummaryTreeValue = IOdspSummaryTree | IOdspSummaryBlob;\n\nexport interface IOdspSummaryTree {\n type: \"tree\";\n entries?: OdspSummaryTreeEntry[];\n}\n\nexport interface IOdspSummaryBlob {\n type: \"blob\";\n content: string;\n encoding: \"base64\" | \"utf-8\";\n}\n\n/**\n *\n * Data structures that form ODSP Snapshot\n *\n */\n\nexport interface IOdspSnapshotTreeEntryTree {\n path: string;\n type: \"tree\";\n // Indicates that this tree entry is unreferenced. If this is not present, the tree entry is considered referenced.\n unreferenced?: true;\n}\n\nexport interface IOdspSnapshotTreeEntryCommit {\n id: string;\n path: string;\n type: \"commit\";\n}\n\nexport interface IOdspSnapshotTreeEntryBlob {\n id: string;\n path: string;\n type: \"blob\";\n}\n\nexport type IOdspSnapshotTreeEntry =\n | IOdspSnapshotTreeEntryTree\n | IOdspSnapshotTreeEntryCommit\n | IOdspSnapshotTreeEntryBlob;\n\nexport interface IOdspSnapshotCommit {\n entries: IOdspSnapshotTreeEntry[];\n id: string;\n sequenceNumber: number;\n}\n\n/**\n * Blob content, represents blobs in downloaded snapshot.\n */\nexport interface IOdspSnapshotBlob {\n content: string;\n // SPO only uses \"base64\" today for download.\n // We are adding undefined too, as temp way to roundtrip strings unchanged.\n encoding: \"base64\" | undefined;\n id: string;\n size: number;\n}\n\nexport interface IOdspSnapshot {\n id: string;\n trees: IOdspSnapshotCommit[];\n blobs?: IOdspSnapshotBlob[];\n ops?: ISequencedDeltaOpMessage[];\n}\n\n/**\n * Same as HostStoragePolicy, but adds options that are internal to runtime.\n * All fields should be optional.\n */\nexport interface HostStoragePolicyInternal extends HostStoragePolicy {\n summarizerClient?: boolean;\n}\n\nexport interface ICreateFileResponse {\n \"@odata.context\": string;\n driveId: string;\n id: string;\n itemId: string;\n itemUrl: string;\n sequenceNumber: number;\n sharingLink?: string;\n sharingLinkErrorReason?: string\n}\n\nexport interface IVersionedValueWithEpoch {\n value: any;\n fluidEpoch: string,\n // This is same as \"persistedCacheValueVersion\" below. This represents the version of data stored in cache.\n version: 3,\n}\n\nexport const persistedCacheValueVersion = 3;\n\nexport interface IGetOpsResponse {\n nonce: string;\n code: number;\n /** Time in seconds. Currently never set by PUSH */\n retryAfter?: number;\n messages?: api.ISequencedDocumentMessage[];\n}\n\nexport interface IFlushOpsResponse {\n nonce: string;\n code: number;\n /** Time in seconds */\n retryAfter?: number;\n lastPersistedSequenceNumber?: number;\n}\n\n/**\n * Represents the cached snapshot value.\n */\nexport interface ISnapshotCachedEntry extends ISnapshotContents {\n cacheEntryTime: number,\n}\n"]}
@@ -36,9 +36,11 @@ export declare class PromiseCacheWithOneHourSlidingExpiry<T> extends PromiseCach
36
36
  export interface INonPersistentCache {
37
37
  /**
38
38
  * Cache of joined/joining session info
39
- * This cache will use a one hour sliding expiration window.
40
39
  */
41
- readonly sessionJoinCache: PromiseCacheWithOneHourSlidingExpiry<ISocketStorageDiscovery>;
40
+ readonly sessionJoinCache: PromiseCache<string, {
41
+ entryTime: number;
42
+ joinSessionResponse: ISocketStorageDiscovery;
43
+ }>;
42
44
  /**
43
45
  * Cache of resolved/resolving file URLs
44
46
  */
@@ -54,7 +56,10 @@ export interface IOdspCache extends INonPersistentCache {
54
56
  readonly persistedCache: IPersistedFileCache;
55
57
  }
56
58
  export declare class NonPersistentCache implements INonPersistentCache {
57
- readonly sessionJoinCache: PromiseCacheWithOneHourSlidingExpiry<ISocketStorageDiscovery>;
59
+ readonly sessionJoinCache: PromiseCache<string, {
60
+ entryTime: number;
61
+ joinSessionResponse: ISocketStorageDiscovery;
62
+ }>;
58
63
  readonly fileUrlCache: PromiseCache<string, IOdspResolvedUrl>;
59
64
  }
60
65
  //# sourceMappingURL=odspCache.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"odspCache.d.ts","sourceRoot":"","sources":["../src/odspCache.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EACH,gBAAgB,EAChB,UAAU,EACV,MAAM,EACN,eAAe,EACf,WAAW,EACd,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AACtD;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAChC,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IACjC,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAClC;AAuCD;;;GAGG;AACH,qBAAa,oBAAqB,YAAW,eAAe;IAIrC,OAAO,CAAC,QAAQ,CAAC,oBAAoB;IAHxD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA0B;IAChD,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAiE;gBAEhD,oBAAoB,SAAY;IAE9D,GAAG,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC;IAMrC,GAAG,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG;IASlC,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAapD,OAAO,CAAC,YAAY;CAGvB;AAED,qBAAa,oCAAoC,CAAC,CAAC,CAAE,SAAQ,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC;gBACpE,aAAa,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,OAAO;CAGlD;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAChC;;;OAGG;IACH,QAAQ,CAAC,gBAAgB,EAAE,oCAAoC,CAAC,uBAAuB,CAAC,CAAC;IAEzF;;OAEG;IACH,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CACjE;AAED;;GAEG;AACH,MAAM,WAAW,UAAW,SAAQ,mBAAmB;IACnD;;OAEG;IACH,QAAQ,CAAC,cAAc,EAAE,mBAAmB,CAAC;CAChD;AAED,qBAAa,kBAAmB,YAAW,mBAAmB;IAC1D,SAAgB,gBAAgB,gEAAuE;IAEvG,SAAgB,YAAY,yCAAgD;CAC/E"}
1
+ {"version":3,"file":"odspCache.d.ts","sourceRoot":"","sources":["../src/odspCache.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EACH,gBAAgB,EAChB,UAAU,EACV,MAAM,EACN,eAAe,EACf,WAAW,EACd,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AACtD;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAChC,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IACjC,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAClC;AAuCD;;;GAGG;AACH,qBAAa,oBAAqB,YAAW,eAAe;IAIrC,OAAO,CAAC,QAAQ,CAAC,oBAAoB;IAHxD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA0B;IAChD,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAiE;gBAEhD,oBAAoB,SAAY;IAE9D,GAAG,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC;IAMrC,GAAG,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG;IASlC,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAapD,OAAO,CAAC,YAAY;CAGvB;AAED,qBAAa,oCAAoC,CAAC,CAAC,CAAE,SAAQ,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC;gBACpE,aAAa,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,OAAO;CAGlD;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAChC;;OAEG;IACH,QAAQ,CAAC,gBAAgB,EAAE,YAAY,CAAC,MAAM,EAAE;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,mBAAmB,EAAE,uBAAuB,CAAA;KAAC,CAAC,CAAC;IAEnH;;OAEG;IACH,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CACjE;AAED;;GAEG;AACH,MAAM,WAAW,UAAW,SAAQ,mBAAmB;IACnD;;OAEG;IACH,QAAQ,CAAC,cAAc,EAAE,mBAAmB,CAAC;CAChD;AAED,qBAAa,kBAAmB,YAAW,mBAAmB;IAC1D,SAAgB,gBAAgB;mBACS,MAAM;6BAAuB,uBAAuB;OAAK;IAElG,SAAgB,YAAY,yCAAgD;CAC/E"}
package/dist/odspCache.js CHANGED
@@ -80,7 +80,7 @@ class PromiseCacheWithOneHourSlidingExpiry extends common_utils_1.PromiseCache {
80
80
  exports.PromiseCacheWithOneHourSlidingExpiry = PromiseCacheWithOneHourSlidingExpiry;
81
81
  class NonPersistentCache {
82
82
  constructor() {
83
- this.sessionJoinCache = new PromiseCacheWithOneHourSlidingExpiry();
83
+ this.sessionJoinCache = new common_utils_1.PromiseCache();
84
84
  this.fileUrlCache = new common_utils_1.PromiseCache();
85
85
  }
86
86
  }
@@ -1 +1 @@
1
- {"version":3,"file":"odspCache.js","sourceRoot":"","sources":["../src/odspCache.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 { PromiseCache } from \"@fluidframework/common-utils\";\nimport {\n IOdspResolvedUrl,\n IFileEntry,\n IEntry,\n IPersistedCache,\n ICacheEntry,\n} from \"@fluidframework/odsp-driver-definitions\";\nimport { ISocketStorageDiscovery } from \"./contracts\";\n/**\n * Similar to IPersistedCache, but exposes cache interface for single file\n */\nexport interface IPersistedFileCache {\n get(entry: IEntry): Promise<any>;\n put(entry: IEntry, value: any): Promise<void>;\n removeEntries(): Promise<void>;\n}\n\n/**\n * Handles garbage collection of expiring cache entries.\n * Not exported.\n * (Based off of the same class in promiseCache.ts, could be consolidated)\n */\nclass GarbageCollector<TKey> {\n private readonly gcTimeouts = new Map<TKey, ReturnType<typeof setTimeout>>();\n\n constructor(\n private readonly cleanup: (key: TKey) => void,\n ) { }\n\n /**\n * Schedule GC for the given key, as applicable\n */\n public schedule(key: TKey, durationMs: number) {\n this.gcTimeouts.set(\n key,\n setTimeout(\n () => { this.cleanup(key); this.cancel(key); },\n durationMs,\n ),\n );\n }\n\n /**\n * Cancel any pending GC for the given key\n */\n public cancel(key: TKey) {\n const timeout = this.gcTimeouts.get(key);\n if (timeout !== undefined) {\n clearTimeout(timeout);\n this.gcTimeouts.delete(key);\n }\n }\n}\n\n/**\n * Default local-only implementation of IPersistedCache,\n * used if no persisted cache is provided by the host\n */\nexport class LocalPersistentCache implements IPersistedCache {\n private readonly cache = new Map<string, any>();\n private readonly gc = new GarbageCollector<string>((key) => this.cache.delete(key));\n\n public constructor(private readonly snapshotExpiryPolicy = 30 * 1000) {}\n\n async get(entry: ICacheEntry): Promise<any> {\n const key = this.keyFromEntry(entry);\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return this.cache.get(key);\n }\n\n async put(entry: ICacheEntry, value: any) {\n const key = this.keyFromEntry(entry);\n this.cache.set(key, value);\n\n // Do not keep items too long in memory\n this.gc.cancel(key);\n this.gc.schedule(key, this.snapshotExpiryPolicy);\n }\n\n async removeEntries(file: IFileEntry): Promise<void> {\n Array.from(this.cache)\n .filter(([cachekey]) => {\n const docIdFromKey = cachekey.split(\"_\");\n if (docIdFromKey[0] === file.docId) {\n return true;\n }\n })\n .map(([cachekey]) => {\n this.cache.delete(cachekey);\n });\n }\n\n private keyFromEntry(entry: ICacheEntry): string {\n return `${entry.file.docId}_${entry.type}_${entry.key}`;\n }\n}\n\nexport class PromiseCacheWithOneHourSlidingExpiry<T> extends PromiseCache<string, T> {\n constructor(removeOnError?: (e: any) => boolean) {\n super({ expiry: { policy: \"sliding\", durationMs: 3600000 }, removeOnError });\n }\n}\n\n/**\n * Internal cache interface used within driver only\n */\nexport interface INonPersistentCache {\n /**\n * Cache of joined/joining session info\n * This cache will use a one hour sliding expiration window.\n */\n readonly sessionJoinCache: PromiseCacheWithOneHourSlidingExpiry<ISocketStorageDiscovery>;\n\n /**\n * Cache of resolved/resolving file URLs\n */\n readonly fileUrlCache: PromiseCache<string, IOdspResolvedUrl>;\n}\n\n/**\n * Internal cache interface used within driver only\n */\nexport interface IOdspCache extends INonPersistentCache {\n /**\n * Persisted cache - only serializable content is allowed\n */\n readonly persistedCache: IPersistedFileCache;\n}\n\nexport class NonPersistentCache implements INonPersistentCache {\n public readonly sessionJoinCache = new PromiseCacheWithOneHourSlidingExpiry<ISocketStorageDiscovery>();\n\n public readonly fileUrlCache = new PromiseCache<string, IOdspResolvedUrl>();\n}\n"]}
1
+ {"version":3,"file":"odspCache.js","sourceRoot":"","sources":["../src/odspCache.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 { PromiseCache } from \"@fluidframework/common-utils\";\nimport {\n IOdspResolvedUrl,\n IFileEntry,\n IEntry,\n IPersistedCache,\n ICacheEntry,\n} from \"@fluidframework/odsp-driver-definitions\";\nimport { ISocketStorageDiscovery } from \"./contracts\";\n/**\n * Similar to IPersistedCache, but exposes cache interface for single file\n */\nexport interface IPersistedFileCache {\n get(entry: IEntry): Promise<any>;\n put(entry: IEntry, value: any): Promise<void>;\n removeEntries(): Promise<void>;\n}\n\n/**\n * Handles garbage collection of expiring cache entries.\n * Not exported.\n * (Based off of the same class in promiseCache.ts, could be consolidated)\n */\nclass GarbageCollector<TKey> {\n private readonly gcTimeouts = new Map<TKey, ReturnType<typeof setTimeout>>();\n\n constructor(\n private readonly cleanup: (key: TKey) => void,\n ) { }\n\n /**\n * Schedule GC for the given key, as applicable\n */\n public schedule(key: TKey, durationMs: number) {\n this.gcTimeouts.set(\n key,\n setTimeout(\n () => { this.cleanup(key); this.cancel(key); },\n durationMs,\n ),\n );\n }\n\n /**\n * Cancel any pending GC for the given key\n */\n public cancel(key: TKey) {\n const timeout = this.gcTimeouts.get(key);\n if (timeout !== undefined) {\n clearTimeout(timeout);\n this.gcTimeouts.delete(key);\n }\n }\n}\n\n/**\n * Default local-only implementation of IPersistedCache,\n * used if no persisted cache is provided by the host\n */\nexport class LocalPersistentCache implements IPersistedCache {\n private readonly cache = new Map<string, any>();\n private readonly gc = new GarbageCollector<string>((key) => this.cache.delete(key));\n\n public constructor(private readonly snapshotExpiryPolicy = 30 * 1000) {}\n\n async get(entry: ICacheEntry): Promise<any> {\n const key = this.keyFromEntry(entry);\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return this.cache.get(key);\n }\n\n async put(entry: ICacheEntry, value: any) {\n const key = this.keyFromEntry(entry);\n this.cache.set(key, value);\n\n // Do not keep items too long in memory\n this.gc.cancel(key);\n this.gc.schedule(key, this.snapshotExpiryPolicy);\n }\n\n async removeEntries(file: IFileEntry): Promise<void> {\n Array.from(this.cache)\n .filter(([cachekey]) => {\n const docIdFromKey = cachekey.split(\"_\");\n if (docIdFromKey[0] === file.docId) {\n return true;\n }\n })\n .map(([cachekey]) => {\n this.cache.delete(cachekey);\n });\n }\n\n private keyFromEntry(entry: ICacheEntry): string {\n return `${entry.file.docId}_${entry.type}_${entry.key}`;\n }\n}\n\nexport class PromiseCacheWithOneHourSlidingExpiry<T> extends PromiseCache<string, T> {\n constructor(removeOnError?: (e: any) => boolean) {\n super({ expiry: { policy: \"sliding\", durationMs: 3600000 }, removeOnError });\n }\n}\n\n/**\n * Internal cache interface used within driver only\n */\nexport interface INonPersistentCache {\n /**\n * Cache of joined/joining session info\n */\n readonly sessionJoinCache: PromiseCache<string, {entryTime: number, joinSessionResponse: ISocketStorageDiscovery}>;\n\n /**\n * Cache of resolved/resolving file URLs\n */\n readonly fileUrlCache: PromiseCache<string, IOdspResolvedUrl>;\n}\n\n/**\n * Internal cache interface used within driver only\n */\nexport interface IOdspCache extends INonPersistentCache {\n /**\n * Persisted cache - only serializable content is allowed\n */\n readonly persistedCache: IPersistedFileCache;\n}\n\nexport class NonPersistentCache implements INonPersistentCache {\n public readonly sessionJoinCache =\n new PromiseCache<string, {entryTime: number, joinSessionResponse: ISocketStorageDiscovery}>();\n\n public readonly fileUrlCache = new PromiseCache<string, IOdspResolvedUrl>();\n}\n"]}
@@ -23,6 +23,7 @@ export declare class OdspDocumentService implements IDocumentService {
23
23
  private readonly epochTracker;
24
24
  private readonly socketReferenceKeyPrefix?;
25
25
  private _policies;
26
+ private joinSessionRefreshTimer;
26
27
  /**
27
28
  * @param resolvedUrl - resolved url identifying document that will be managed by returned service instance.
28
29
  * @param getStorageToken - function that can provide the storage token. This is is also referred to as
@@ -79,7 +80,11 @@ export declare class OdspDocumentService implements IDocumentService {
79
80
  * @returns returns the document delta stream service for onedrive/sharepoint driver.
80
81
  */
81
82
  connectToDeltaStream(client: IClient): Promise<IDocumentDeltaConnection>;
83
+ private clearJoinSessionTimer;
84
+ private scheduleJoinSessionRefresh;
82
85
  private joinSession;
86
+ private joinSessionCore;
87
+ private calculateJoinSessionRefreshDelta;
83
88
  /**
84
89
  * Connects to a delta stream endpoint
85
90
  * If url #1 fails to connect, tries url #2 if applicable
@@ -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;AAOtE,OAAO,EACH,wBAAwB,EACxB,4BAA4B,EAC5B,gBAAgB,EAChB,YAAY,EACZ,uBAAuB,EACvB,wBAAwB,EAE3B,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;AAIxC;;;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,EAAE,CAAoB;IAEvC,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;IAkCP,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;YA4EvE,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;AAOtE,OAAO,EACH,wBAAwB,EACxB,4BAA4B,EAC5B,gBAAgB,EAChB,YAAY,EACZ,uBAAuB,EACvB,wBAAwB,EAE3B,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;AAIxC;;;GAGG;AACH,qBAAa,mBAAoB,YAAW,gBAAgB;aAqEpC,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;IA5E9C,OAAO,CAAC,SAAS,CAA2B;IAE5C,OAAO,CAAC,uBAAuB,CAA4C;IAC3E;;;;;;;;;;;;;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,EAAE,CAAoB;IAEvC,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;IAkCP,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;IA0DrF,OAAO,CAAC,qBAAqB;YAOf,0BAA0B;YAa1B,WAAW;YA0BX,eAAe;IAuE7B,OAAO,CAAC,gCAAgC;IAKxC;;;;;;;;;;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"}
@@ -141,26 +141,7 @@ class OdspDocumentService {
141
141
  const websocketTokenPromise = requestWebsocketTokenFromJoinSession
142
142
  ? Promise.resolve(null)
143
143
  : this.getWebsocketToken(options);
144
- const joinSessionPromise = this.joinSession(requestWebsocketTokenFromJoinSession, options).catch((e) => {
145
- const likelyFacetCodes = e;
146
- if (Array.isArray(likelyFacetCodes.facetCodes)) {
147
- for (const code of likelyFacetCodes.facetCodes) {
148
- switch (code) {
149
- case "sessionForbiddenOnPreservedFiles":
150
- case "sessionForbiddenOnModerationEnabledLibrary":
151
- case "sessionForbiddenOnRequireCheckout":
152
- // This document can only be opened in storage-only mode.
153
- // DeltaManager will recognize this error
154
- // and load without a delta stream connection.
155
- this._policies = Object.assign(Object.assign({}, this._policies), { storageOnly: true });
156
- throw new driver_utils_1.DeltaStreamConnectionForbiddenError(code, { driverVersion: packageVersion_1.pkgVersion });
157
- default:
158
- continue;
159
- }
160
- }
161
- }
162
- throw e;
163
- });
144
+ const joinSessionPromise = this.joinSession(requestWebsocketTokenFromJoinSession, options);
164
145
  const [websocketEndpoint, websocketToken, io] = await Promise.all([
165
146
  joinSessionPromise,
166
147
  websocketTokenPromise,
@@ -178,6 +159,8 @@ class OdspDocumentService {
178
159
  // On disconnect with 401/403 error code, we can just clear the joinSession cache as we will again
179
160
  // get the auth error on reconnecting and face latency.
180
161
  connection.on("disconnect", (error) => {
162
+ // Clear the join session refresh timer so that it can be restarted on reconnection.
163
+ this.clearJoinSessionTimer();
181
164
  if (typeof error === "object" && error !== null
182
165
  && error.errorType === driver_definitions_1.DriverErrorType.authorizationError) {
183
166
  this.cache.sessionJoinCache.remove(this.joinSessionKey);
@@ -195,14 +178,94 @@ class OdspDocumentService {
195
178
  }
196
179
  });
197
180
  }
181
+ clearJoinSessionTimer() {
182
+ if (this.joinSessionRefreshTimer !== undefined) {
183
+ clearTimeout(this.joinSessionRefreshTimer);
184
+ this.joinSessionRefreshTimer = undefined;
185
+ }
186
+ }
187
+ async scheduleJoinSessionRefresh(delta) {
188
+ await new Promise((resolve, reject) => {
189
+ this.joinSessionRefreshTimer = setTimeout(() => {
190
+ odspUtils_1.getWithRetryForTokenRefresh(async (options) => {
191
+ await this.joinSession(false, options);
192
+ resolve();
193
+ }).catch((error) => {
194
+ reject(error);
195
+ });
196
+ }, delta);
197
+ });
198
+ }
198
199
  async joinSession(requestSocketToken, options) {
200
+ return this.joinSessionCore(requestSocketToken, options).catch((e) => {
201
+ const likelyFacetCodes = e;
202
+ if (Array.isArray(likelyFacetCodes.facetCodes)) {
203
+ for (const code of likelyFacetCodes.facetCodes) {
204
+ switch (code) {
205
+ case "sessionForbiddenOnPreservedFiles":
206
+ case "sessionForbiddenOnModerationEnabledLibrary":
207
+ case "sessionForbiddenOnRequireCheckout":
208
+ // This document can only be opened in storage-only mode.
209
+ // DeltaManager will recognize this error
210
+ // and load without a delta stream connection.
211
+ this._policies = Object.assign(Object.assign({}, this._policies), { storageOnly: true });
212
+ throw new driver_utils_1.DeltaStreamConnectionForbiddenError(code, { driverVersion: packageVersion_1.pkgVersion });
213
+ default:
214
+ continue;
215
+ }
216
+ }
217
+ }
218
+ throw e;
219
+ });
220
+ }
221
+ async joinSessionCore(requestSocketToken, options) {
222
+ const disableJoinSessionRefresh = this.mc.config.getBoolean("Fluid.Driver.Odsp.disableJoinSessionRefresh");
199
223
  const executeFetch = async () => {
200
224
  var _a;
201
- return vroom_1.fetchJoinSession(this.odspResolvedUrl, "opStream/joinSession", "POST", this.mc.logger, this.getStorageToken, this.epochTracker, requestSocketToken, options, (_a = this.hostPolicy.sessionOptions) === null || _a === void 0 ? void 0 : _a.unauthenticatedUserDisplayName);
225
+ const joinSessionResponse = await vroom_1.fetchJoinSession(this.odspResolvedUrl, "opStream/joinSession", "POST", this.mc.logger, this.getStorageToken, this.epochTracker, requestSocketToken, options, disableJoinSessionRefresh, (_a = this.hostPolicy.sessionOptions) === null || _a === void 0 ? void 0 : _a.unauthenticatedUserDisplayName);
226
+ return {
227
+ entryTime: Date.now(),
228
+ joinSessionResponse,
229
+ };
202
230
  };
203
- // Note: The sessionCache is configured with a sliding expiry of 1 hour,
204
- // so if we've fetched the join session within the last hour we won't run executeFetch again now.
205
- return this.cache.sessionJoinCache.addOrGet(this.joinSessionKey, executeFetch);
231
+ const getResponseAndRefreshAfterDeltaMs = async () => {
232
+ var _a;
233
+ let response = await this.cache.sessionJoinCache.addOrGet(this.joinSessionKey, executeFetch);
234
+ // If the response does not contain refreshSessionDurationSeconds, then treat it as old flow and let the
235
+ // cache entry to be treated as expired after 1 hour.
236
+ response.joinSessionResponse.refreshSessionDurationSeconds = (_a = response.joinSessionResponse.refreshSessionDurationSeconds) !== null && _a !== void 0 ? _a : 3600;
237
+ return Object.assign(Object.assign({}, response), { refreshAfterDeltaMs: this.calculateJoinSessionRefreshDelta(response.entryTime, response.joinSessionResponse.refreshSessionDurationSeconds) });
238
+ };
239
+ let response = await getResponseAndRefreshAfterDeltaMs();
240
+ // This means that the cached entry has expired(This should not be possible if the response is fetched
241
+ // from the network call). In this case we remove the cached entry and fetch the new response.
242
+ if (response.refreshAfterDeltaMs <= 0) {
243
+ this.cache.sessionJoinCache.remove(this.joinSessionKey);
244
+ response = await getResponseAndRefreshAfterDeltaMs();
245
+ }
246
+ if (!disableJoinSessionRefresh) {
247
+ const props = {
248
+ entryTime: response.entryTime,
249
+ refreshSessionDurationSeconds: response.joinSessionResponse.refreshSessionDurationSeconds,
250
+ refreshAfterDeltaMs: response.refreshAfterDeltaMs,
251
+ };
252
+ if (response.refreshAfterDeltaMs > 0) {
253
+ this.scheduleJoinSessionRefresh(response.refreshAfterDeltaMs)
254
+ .catch((error) => {
255
+ this.mc.logger.sendErrorEvent(Object.assign({ eventName: "JoinSessionRefreshError" }, props), error);
256
+ });
257
+ ;
258
+ }
259
+ else {
260
+ // Logging just for informational purposes to help with debugging as this is a new feature.
261
+ this.mc.logger.sendErrorEvent(Object.assign({ eventName: "JoinSessionRefreshNotScheduled" }, props));
262
+ }
263
+ }
264
+ return response.joinSessionResponse;
265
+ }
266
+ calculateJoinSessionRefreshDelta(responseFetchTime, refreshSessionDurationSeconds) {
267
+ // 30 seconds is buffer time to refresh the session.
268
+ return responseFetchTime + ((refreshSessionDurationSeconds * 1000) - 30000) - Date.now();
206
269
  }
207
270
  /**
208
271
  * Connects to a delta stream endpoint
@@ -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 {\n ChildLogger,\n loggerToMonitoringContext,\n MonitoringContext,\n} from \"@fluidframework/telemetry-utils\";\nimport {\n IDocumentDeltaConnection,\n IDocumentDeltaStorageService,\n IDocumentService,\n IResolvedUrl,\n IDocumentStorageService,\n IDocumentServicePolicies,\n DriverErrorType,\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\";\nimport { pkgVersion as driverVersion } from \"./packageVersion\";\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 mc: MonitoringContext;\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.mc = loggerToMonitoringContext(\n 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 ??=\n this.mc.config.getBoolean(\"Fluid.Driver.Odsp.binaryFormatSnapshot\");\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.mc.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.mc.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.mc.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.mc.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, { driverVersion });\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 \"Websocket token is null\",\n OdspErrorType.fetchTokenError,\n { driverVersion });\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 // On disconnect with 401/403 error code, we can just clear the joinSession cache as we will again\n // get the auth error on reconnecting and face latency.\n connection.on(\"disconnect\", (error: any) => {\n if (typeof error === \"object\" && error !== null\n && error.errorType === DriverErrorType.authorizationError) {\n this.cache.sessionJoinCache.remove(this.joinSessionKey);\n }\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.mc.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.mc.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.mc.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.mc.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":"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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 {\n ChildLogger,\n loggerToMonitoringContext,\n MonitoringContext,\n} from \"@fluidframework/telemetry-utils\";\nimport {\n IDocumentDeltaConnection,\n IDocumentDeltaStorageService,\n IDocumentService,\n IResolvedUrl,\n IDocumentStorageService,\n IDocumentServicePolicies,\n DriverErrorType,\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\";\nimport { pkgVersion as driverVersion } from \"./packageVersion\";\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 // Timer which runs and executes the join session call after intervals.\n private joinSessionRefreshTimer: ReturnType<typeof setTimeout> | undefined;\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 mc: MonitoringContext;\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.mc = loggerToMonitoringContext(\n 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 ??=\n this.mc.config.getBoolean(\"Fluid.Driver.Odsp.binaryFormatSnapshot\");\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.mc.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.mc.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.mc.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.mc.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);\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 \"Websocket token is null\",\n OdspErrorType.fetchTokenError,\n { driverVersion });\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 // On disconnect with 401/403 error code, we can just clear the joinSession cache as we will again\n // get the auth error on reconnecting and face latency.\n connection.on(\"disconnect\", (error: any) => {\n // Clear the join session refresh timer so that it can be restarted on reconnection.\n this.clearJoinSessionTimer();\n if (typeof error === \"object\" && error !== null\n && error.errorType === DriverErrorType.authorizationError) {\n this.cache.sessionJoinCache.remove(this.joinSessionKey);\n }\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 clearJoinSessionTimer() {\n if (this.joinSessionRefreshTimer !== undefined) {\n clearTimeout(this.joinSessionRefreshTimer);\n this.joinSessionRefreshTimer = undefined;\n }\n }\n\n private async scheduleJoinSessionRefresh(delta: number) {\n await new Promise<void>((resolve, reject) => {\n this.joinSessionRefreshTimer = setTimeout(() => {\n getWithRetryForTokenRefresh(async (options) => {\n await this.joinSession(false, options);\n resolve();\n }).catch((error) => {\n reject(error);\n });\n }, delta);\n });\n }\n\n private async joinSession(\n requestSocketToken: boolean,\n options: TokenFetchOptionsEx,\n ) {\n return this.joinSessionCore(requestSocketToken, 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, { driverVersion });\n default:\n continue;\n }\n }\n }\n throw e;\n });\n }\n\n private async joinSessionCore(\n requestSocketToken: boolean,\n options: TokenFetchOptionsEx,\n ): Promise<ISocketStorageDiscovery> {\n const disableJoinSessionRefresh = this.mc.config.getBoolean(\"Fluid.Driver.Odsp.disableJoinSessionRefresh\");\n const executeFetch = async () => {\n const joinSessionResponse = await fetchJoinSession(\n this.odspResolvedUrl,\n \"opStream/joinSession\",\n \"POST\",\n this.mc.logger,\n this.getStorageToken,\n this.epochTracker,\n requestSocketToken,\n options,\n disableJoinSessionRefresh,\n this.hostPolicy.sessionOptions?.unauthenticatedUserDisplayName,\n );\n return {\n entryTime: Date.now(),\n joinSessionResponse,\n };\n };\n\n const getResponseAndRefreshAfterDeltaMs = async () => {\n let response = await this.cache.sessionJoinCache.addOrGet(this.joinSessionKey, executeFetch);\n // If the response does not contain refreshSessionDurationSeconds, then treat it as old flow and let the\n // cache entry to be treated as expired after 1 hour.\n response.joinSessionResponse.refreshSessionDurationSeconds =\n response.joinSessionResponse.refreshSessionDurationSeconds ?? 3600;\n return {\n ...response,\n refreshAfterDeltaMs: this.calculateJoinSessionRefreshDelta(\n response.entryTime, response.joinSessionResponse.refreshSessionDurationSeconds),\n }\n };\n let response = await getResponseAndRefreshAfterDeltaMs();\n // This means that the cached entry has expired(This should not be possible if the response is fetched\n // from the network call). In this case we remove the cached entry and fetch the new response.\n if (response.refreshAfterDeltaMs <= 0) {\n this.cache.sessionJoinCache.remove(this.joinSessionKey);\n response = await getResponseAndRefreshAfterDeltaMs();\n }\n if (!disableJoinSessionRefresh) {\n const props = {\n entryTime: response.entryTime,\n refreshSessionDurationSeconds:\n response.joinSessionResponse.refreshSessionDurationSeconds,\n refreshAfterDeltaMs: response.refreshAfterDeltaMs,\n };\n if (response.refreshAfterDeltaMs > 0) {\n this.scheduleJoinSessionRefresh(response.refreshAfterDeltaMs)\n .catch((error) => {\n this.mc.logger.sendErrorEvent({\n eventName: \"JoinSessionRefreshError\",\n ...props,\n },\n error,\n )\n });;\n } else {\n // Logging just for informational purposes to help with debugging as this is a new feature.\n this.mc.logger.sendErrorEvent({\n eventName: \"JoinSessionRefreshNotScheduled\",\n ...props,\n });\n }\n }\n return response.joinSessionResponse;\n }\n\n private calculateJoinSessionRefreshDelta(responseFetchTime: number, refreshSessionDurationSeconds: number) {\n // 30 seconds is buffer time to refresh the session.\n return responseFetchTime + ((refreshSessionDurationSeconds * 1000) - 30000) - Date.now();\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.mc.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.mc.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.mc.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"]}
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export declare const pkgName = "@fluidframework/odsp-driver";
8
- export declare const pkgVersion = "0.58.0-55561";
8
+ export declare const pkgVersion = "0.58.1001";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,gCAAgC,CAAC;AACrD,eAAO,MAAM,UAAU,iBAAiB,CAAC"}
1
+ {"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,gCAAgC,CAAC;AACrD,eAAO,MAAM,UAAU,cAAc,CAAC"}
@@ -8,5 +8,5 @@
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.pkgVersion = exports.pkgName = void 0;
10
10
  exports.pkgName = "@fluidframework/odsp-driver";
11
- exports.pkgVersion = "0.58.0-55561";
11
+ exports.pkgVersion = "0.58.1001";
12
12
  //# sourceMappingURL=packageVersion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,6BAA6B,CAAC;AACxC,QAAA,UAAU,GAAG,cAAc,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/odsp-driver\";\nexport const pkgVersion = \"0.58.0-55561\";\n"]}
1
+ {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,6BAA6B,CAAC;AACxC,QAAA,UAAU,GAAG,WAAW,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/odsp-driver\";\nexport const pkgVersion = \"0.58.1001\";\n"]}
package/dist/vroom.d.ts CHANGED
@@ -18,8 +18,9 @@ import { EpochTracker } from "./epochTracker";
18
18
  * @param requestSocketToken - flag indicating whether joinSession is expected to return access token
19
19
  * which is used when establishing websocket connection with collab session backend service.
20
20
  * @param options - Options to fetch the token.
21
+ * @param disableJoinSessionRefresh - Whether the caller wants to disable refreshing join session periodically.
21
22
  * @param guestDisplayName - display name used to identify guest user joining a session.
22
23
  * This is optional and used only when collab session is being joined via invite.
23
24
  */
24
- export declare function fetchJoinSession(urlParts: IOdspUrlParts, path: string, method: string, logger: ITelemetryLogger, getStorageToken: InstrumentedStorageTokenFetcher, epochTracker: EpochTracker, requestSocketToken: boolean, options: TokenFetchOptionsEx, guestDisplayName?: string): Promise<ISocketStorageDiscovery>;
25
+ export declare function fetchJoinSession(urlParts: IOdspUrlParts, path: string, method: string, logger: ITelemetryLogger, getStorageToken: InstrumentedStorageTokenFetcher, epochTracker: EpochTracker, requestSocketToken: boolean, options: TokenFetchOptionsEx, disableJoinSessionRefresh: boolean | undefined, guestDisplayName?: string): Promise<ISocketStorageDiscovery>;
25
26
  //# sourceMappingURL=vroom.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"vroom.d.ts","sourceRoot":"","sources":["../src/vroom.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAEtE,OAAO,EAAE,+BAA+B,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AACzG,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAa,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAE7D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAQ9C;;;;;;;;;;;;;GAaG;AACH,wBAAsB,gBAAgB,CAClC,QAAQ,EAAE,aAAa,EACvB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,gBAAgB,EACxB,eAAe,EAAE,+BAA+B,EAChD,YAAY,EAAE,YAAY,EAC1B,kBAAkB,EAAE,OAAO,EAC3B,OAAO,EAAE,mBAAmB,EAC5B,gBAAgB,CAAC,EAAE,MAAM,GAC1B,OAAO,CAAC,uBAAuB,CAAC,CAgElC"}
1
+ {"version":3,"file":"vroom.d.ts","sourceRoot":"","sources":["../src/vroom.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAEtE,OAAO,EAAE,+BAA+B,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AACzG,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAa,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAE7D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAQ9C;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,gBAAgB,CAClC,QAAQ,EAAE,aAAa,EACvB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,gBAAgB,EACxB,eAAe,EAAE,+BAA+B,EAChD,YAAY,EAAE,YAAY,EAC1B,kBAAkB,EAAE,OAAO,EAC3B,OAAO,EAAE,mBAAmB,EAC5B,yBAAyB,EAAE,OAAO,GAAG,SAAS,EAC9C,gBAAgB,CAAC,EAAE,MAAM,GAC1B,OAAO,CAAC,uBAAuB,CAAC,CAoElC"}
package/dist/vroom.js CHANGED
@@ -21,10 +21,11 @@ const retryUtils_1 = require("./retryUtils");
21
21
  * @param requestSocketToken - flag indicating whether joinSession is expected to return access token
22
22
  * which is used when establishing websocket connection with collab session backend service.
23
23
  * @param options - Options to fetch the token.
24
+ * @param disableJoinSessionRefresh - Whether the caller wants to disable refreshing join session periodically.
24
25
  * @param guestDisplayName - display name used to identify guest user joining a session.
25
26
  * This is optional and used only when collab session is being joined via invite.
26
27
  */
27
- async function fetchJoinSession(urlParts, path, method, logger, getStorageToken, epochTracker, requestSocketToken, options, guestDisplayName) {
28
+ async function fetchJoinSession(urlParts, path, method, logger, getStorageToken, epochTracker, requestSocketToken, options, disableJoinSessionRefresh, guestDisplayName) {
28
29
  const token = await getStorageToken(options, "JoinSession");
29
30
  const extraProps = options.refresh
30
31
  ? { hasClaims: !!options.claims, hasTenantId: !!options.tenantId }
@@ -36,6 +37,9 @@ async function fetchJoinSession(urlParts, path, method, logger, getStorageToken,
36
37
  postBody += `Authorization: Bearer ${token}\r\n`;
37
38
  postBody += `X-HTTP-Method-Override: POST\r\n`;
38
39
  postBody += `Content-Type: application/json\r\n`;
40
+ if (!disableJoinSessionRefresh) {
41
+ postBody += `prefer: FluidRemoveCheckAccess\r\n`;
42
+ }
39
43
  postBody += `_post: 1\r\n`;
40
44
  // Name should be there when socket token is requested and vice-versa.
41
45
  if (requestSocketToken && guestDisplayName !== undefined) {
@@ -56,7 +60,7 @@ async function fetchJoinSession(urlParts, path, method, logger, getStorageToken,
56
60
  // TODO SPO-specific telemetry
57
61
  event.end(Object.assign(Object.assign({}, response.propsToLog), {
58
62
  // pushV2 websocket urls will contain pushf
59
- pushv2: socketUrl.includes("pushf"), webSocketHostName }));
63
+ pushv2: socketUrl.includes("pushf"), webSocketHostName, refreshSessionDurationSeconds: response.content.refreshSessionDurationSeconds }));
60
64
  if (response.content.runtimeTenantId && !response.content.tenantId) {
61
65
  response.content.tenantId = response.content.runtimeTenantId;
62
66
  }
package/dist/vroom.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"vroom.js","sourceRoot":"","sources":["../src/vroom.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,+BAAkC;AAElC,qEAAmE;AAGnE,2CAA6D;AAC7D,mDAA6C;AAE7C,6CAA4C;AAO5C;;;;;;;;;;;;;GAaG;AACI,KAAK,UAAU,gBAAgB,CAClC,QAAuB,EACvB,IAAY,EACZ,MAAc,EACd,MAAwB,EACxB,eAAgD,EAChD,YAA0B,EAC1B,kBAA2B,EAC3B,OAA4B,EAC5B,gBAAyB;IAEzB,MAAM,KAAK,GAAG,MAAM,eAAe,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IAE5D,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO;QAC9B,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE;QAClE,CAAC,CAAC,EAAE,CAAC;IACT,OAAO,kCAAgB,CAAC,cAAc,CAClC,MAAM,kBACF,SAAS,EAAE,aAAa,EACxB,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAC9B,UAAU,GAEjB,KAAK,EAAE,KAAK,EAAE,EAAE;QACZ,MAAM,UAAU,GAAG,qBAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC/C,MAAM,YAAY,GAAG,SAAI,EAAE,CAAC;QAC5B,IAAI,QAAQ,GAAG,KAAK,YAAY,MAAM,CAAC;QACvC,QAAQ,IAAI,yBAAyB,KAAK,MAAM,CAAC;QACjD,QAAQ,IAAI,kCAAkC,CAAC;QAC/C,QAAQ,IAAI,oCAAoC,CAAC;QACjD,QAAQ,IAAI,cAAc,CAAC;QAC3B,sEAAsE;QACtE,IAAI,kBAAkB,IAAI,gBAAgB,KAAK,SAAS,EAAE;YACtD,MAAM,IAAI,GAAqB;gBAC3B,kBAAkB,EAAE,IAAI;gBACxB,gBAAgB;aACnB,CAAC;YACF,QAAQ,IAAI,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC;SACjD;QACD,QAAQ,IAAI,SAAS,YAAY,IAAI,CAAC;QACtC,MAAM,OAAO,GAA8B;YACvC,cAAc,EAAE,gCAAgC,YAAY,EAAE;SACjE,CAAC;QAEF,MAAM,QAAQ,GAAG,MAAM,yBAAY,CAC/B,KAAK,IAAI,EAAE,CAAC,YAAY,CAAC,mBAAmB,CACxC,GAAG,0BAAU,CAAC,UAAU,CAAC,WACrB,QAAQ,CAAC,OACb,UAAU,QAAQ,CAAC,MAAM,IAAI,IAAI,QAAQ,EACzC,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,EACnC,aAAa,EACb,IAAI,CACP,EACD,aAAa,EACb,MAAM,CACT,CAAC;QAEF,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,oBAAoB,CAAC;QACxD,kEAAkE;QAClE,MAAM,iBAAiB,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAElD,8BAA8B;QAC9B,KAAK,CAAC,GAAG,iCACF,QAAQ,CAAC,UAAU;YACtB,2CAA2C;YAC3C,MAAM,EAAE,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,EACnC,iBAAiB,IACnB,CAAC;QAEH,IAAI,QAAQ,CAAC,OAAO,CAAC,eAAe,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE;YAChE,QAAQ,CAAC,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,eAAe,CAAC;SAChE;QAED,OAAO,QAAQ,CAAC,OAAO,CAAC;IAC5B,CAAC,CAAC,CAAC;AACX,CAAC;AA1ED,4CA0EC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { v4 as uuid } from \"uuid\";\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { PerformanceEvent } from \"@fluidframework/telemetry-utils\";\nimport { InstrumentedStorageTokenFetcher, IOdspUrlParts } from \"@fluidframework/odsp-driver-definitions\";\nimport { ISocketStorageDiscovery } from \"./contracts\";\nimport { getOrigin, TokenFetchOptionsEx } from \"./odspUtils\";\nimport { getApiRoot } from \"./odspUrlHelper\";\nimport { EpochTracker } from \"./epochTracker\";\nimport { runWithRetry } from \"./retryUtils\";\n\ninterface IJoinSessionBody {\n requestSocketToken: boolean;\n guestDisplayName: string;\n}\n\n/**\n * Makes join session call on SPO to get information about the web socket for a document\n * @param urlParts - The SPO drive id, itemId, siteUrl that this request should be made against\n * @param path - The API path that is relevant to this request\n * @param method - The type of request, such as GET or POST\n * @param logger - A logger to use for this request\n * @param getStorageToken - A function that is able to provide the access token for this request\n * @param epochTracker - fetch wrapper which incorporates epoch logic around joinSession call\n * @param requestSocketToken - flag indicating whether joinSession is expected to return access token\n * which is used when establishing websocket connection with collab session backend service.\n * @param options - Options to fetch the token.\n * @param guestDisplayName - display name used to identify guest user joining a session.\n * This is optional and used only when collab session is being joined via invite.\n */\nexport async function fetchJoinSession(\n urlParts: IOdspUrlParts,\n path: string,\n method: string,\n logger: ITelemetryLogger,\n getStorageToken: InstrumentedStorageTokenFetcher,\n epochTracker: EpochTracker,\n requestSocketToken: boolean,\n options: TokenFetchOptionsEx,\n guestDisplayName?: string,\n): Promise<ISocketStorageDiscovery> {\n const token = await getStorageToken(options, \"JoinSession\");\n\n const extraProps = options.refresh\n ? { hasClaims: !!options.claims, hasTenantId: !!options.tenantId }\n : {};\n return PerformanceEvent.timedExecAsync(\n logger, {\n eventName: \"JoinSession\",\n attempts: options.refresh ? 2 : 1,\n ...extraProps,\n },\n async (event) => {\n const siteOrigin = getOrigin(urlParts.siteUrl);\n const formBoundary = uuid();\n let postBody = `--${formBoundary}\\r\\n`;\n postBody += `Authorization: Bearer ${token}\\r\\n`;\n postBody += `X-HTTP-Method-Override: POST\\r\\n`;\n postBody += `Content-Type: application/json\\r\\n`;\n postBody += `_post: 1\\r\\n`;\n // Name should be there when socket token is requested and vice-versa.\n if (requestSocketToken && guestDisplayName !== undefined) {\n const body: IJoinSessionBody = {\n requestSocketToken: true,\n guestDisplayName,\n };\n postBody += `\\r\\n${JSON.stringify(body)}\\r\\n`;\n }\n postBody += `\\r\\n--${formBoundary}--`;\n const headers: {[index: string]: string} = {\n \"Content-Type\": `multipart/form-data;boundary=${formBoundary}`,\n };\n\n const response = await runWithRetry(\n async () => epochTracker.fetchAndParseAsJSON<ISocketStorageDiscovery>(\n `${getApiRoot(siteOrigin)}/drives/${\n urlParts.driveId\n }/items/${urlParts.itemId}/${path}?ump=1`,\n { method, headers, body: postBody },\n \"joinSession\",\n true,\n ),\n \"joinSession\",\n logger,\n );\n\n const socketUrl = response.content.deltaStreamSocketUrl;\n // expecting socketUrl to be something like https://{hostName}/...\n const webSocketHostName = socketUrl.split(\"/\")[2];\n\n // TODO SPO-specific telemetry\n event.end({\n ...response.propsToLog,\n // pushV2 websocket urls will contain pushf\n pushv2: socketUrl.includes(\"pushf\"),\n webSocketHostName,\n });\n\n if (response.content.runtimeTenantId && !response.content.tenantId) {\n response.content.tenantId = response.content.runtimeTenantId;\n }\n\n return response.content;\n });\n}\n"]}
1
+ {"version":3,"file":"vroom.js","sourceRoot":"","sources":["../src/vroom.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { v4 as uuid } from \"uuid\";\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { PerformanceEvent } from \"@fluidframework/telemetry-utils\";\nimport { InstrumentedStorageTokenFetcher, IOdspUrlParts } from \"@fluidframework/odsp-driver-definitions\";\nimport { ISocketStorageDiscovery } from \"./contracts\";\nimport { getOrigin, TokenFetchOptionsEx } from \"./odspUtils\";\nimport { getApiRoot } from \"./odspUrlHelper\";\nimport { EpochTracker } from \"./epochTracker\";\nimport { runWithRetry } from \"./retryUtils\";\n\ninterface IJoinSessionBody {\n requestSocketToken: boolean;\n guestDisplayName: string;\n}\n\n/**\n * Makes join session call on SPO to get information about the web socket for a document\n * @param urlParts - The SPO drive id, itemId, siteUrl that this request should be made against\n * @param path - The API path that is relevant to this request\n * @param method - The type of request, such as GET or POST\n * @param logger - A logger to use for this request\n * @param getStorageToken - A function that is able to provide the access token for this request\n * @param epochTracker - fetch wrapper which incorporates epoch logic around joinSession call\n * @param requestSocketToken - flag indicating whether joinSession is expected to return access token\n * which is used when establishing websocket connection with collab session backend service.\n * @param options - Options to fetch the token.\n * @param disableJoinSessionRefresh - Whether the caller wants to disable refreshing join session periodically.\n * @param guestDisplayName - display name used to identify guest user joining a session.\n * This is optional and used only when collab session is being joined via invite.\n */\nexport async function fetchJoinSession(\n urlParts: IOdspUrlParts,\n path: string,\n method: string,\n logger: ITelemetryLogger,\n getStorageToken: InstrumentedStorageTokenFetcher,\n epochTracker: EpochTracker,\n requestSocketToken: boolean,\n options: TokenFetchOptionsEx,\n disableJoinSessionRefresh: boolean | undefined,\n guestDisplayName?: string,\n): Promise<ISocketStorageDiscovery> {\n const token = await getStorageToken(options, \"JoinSession\");\n\n const extraProps = options.refresh\n ? { hasClaims: !!options.claims, hasTenantId: !!options.tenantId }\n : {};\n return PerformanceEvent.timedExecAsync(\n logger, {\n eventName: \"JoinSession\",\n attempts: options.refresh ? 2 : 1,\n ...extraProps,\n },\n async (event) => {\n const siteOrigin = getOrigin(urlParts.siteUrl);\n const formBoundary = uuid();\n let postBody = `--${formBoundary}\\r\\n`;\n postBody += `Authorization: Bearer ${token}\\r\\n`;\n postBody += `X-HTTP-Method-Override: POST\\r\\n`;\n postBody += `Content-Type: application/json\\r\\n`;\n if (!disableJoinSessionRefresh) {\n postBody += `prefer: FluidRemoveCheckAccess\\r\\n`;\n }\n postBody += `_post: 1\\r\\n`;\n // Name should be there when socket token is requested and vice-versa.\n if (requestSocketToken && guestDisplayName !== undefined) {\n const body: IJoinSessionBody = {\n requestSocketToken: true,\n guestDisplayName,\n };\n postBody += `\\r\\n${JSON.stringify(body)}\\r\\n`;\n }\n postBody += `\\r\\n--${formBoundary}--`;\n const headers: {[index: string]: string} = {\n \"Content-Type\": `multipart/form-data;boundary=${formBoundary}`,\n };\n\n const response = await runWithRetry(\n async () => epochTracker.fetchAndParseAsJSON<ISocketStorageDiscovery>(\n `${getApiRoot(siteOrigin)}/drives/${\n urlParts.driveId\n }/items/${urlParts.itemId}/${path}?ump=1`,\n { method, headers, body: postBody },\n \"joinSession\",\n true,\n ),\n \"joinSession\",\n logger,\n );\n\n const socketUrl = response.content.deltaStreamSocketUrl;\n // expecting socketUrl to be something like https://{hostName}/...\n const webSocketHostName = socketUrl.split(\"/\")[2];\n\n // TODO SPO-specific telemetry\n event.end({\n ...response.propsToLog,\n // pushV2 websocket urls will contain pushf\n pushv2: socketUrl.includes(\"pushf\"),\n webSocketHostName,\n refreshSessionDurationSeconds: response.content.refreshSessionDurationSeconds,\n });\n\n if (response.content.runtimeTenantId && !response.content.tenantId) {\n response.content.tenantId = response.content.runtimeTenantId;\n }\n\n return response.content;\n });\n}\n"]}
@@ -25,6 +25,10 @@ export interface ISocketStorageDiscovery {
25
25
  * passed as a parameter to `OdspDocumentService.create()` factory.
26
26
  */
27
27
  socketToken?: string;
28
+ /**
29
+ * This is the time within which client has to refresh the session on (ODSP) relay service.
30
+ */
31
+ refreshSessionDurationSeconds?: number;
28
32
  }
29
33
  /**
30
34
  * Interface for error responses for the WebSocket connection