@fluidframework/container-loader 1.4.0-121020 → 2.0.0-dev-rc.1.0.0.225277

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 (335) hide show
  1. package/.eslintrc.js +18 -21
  2. package/.mocharc.js +12 -0
  3. package/CHANGELOG.md +364 -0
  4. package/README.md +152 -56
  5. package/api-extractor-esm.json +4 -0
  6. package/api-extractor-lint.json +4 -0
  7. package/api-extractor.json +2 -2
  8. package/api-report/container-loader.api.md +143 -0
  9. package/dist/{audience.js → audience.cjs} +15 -13
  10. package/dist/audience.cjs.map +1 -0
  11. package/dist/audience.d.ts +4 -6
  12. package/dist/audience.d.ts.map +1 -1
  13. package/dist/catchUpMonitor.cjs +43 -0
  14. package/dist/catchUpMonitor.cjs.map +1 -0
  15. package/dist/catchUpMonitor.d.ts +29 -0
  16. package/dist/catchUpMonitor.d.ts.map +1 -0
  17. package/dist/{connectionManager.js → connectionManager.cjs} +397 -240
  18. package/dist/connectionManager.cjs.map +1 -0
  19. package/dist/connectionManager.d.ts +23 -33
  20. package/dist/connectionManager.d.ts.map +1 -1
  21. package/dist/{connectionState.js → connectionState.cjs} +5 -7
  22. package/dist/connectionState.cjs.map +1 -0
  23. package/dist/connectionState.d.ts +3 -5
  24. package/dist/connectionState.d.ts.map +1 -1
  25. package/dist/connectionStateHandler.cjs +474 -0
  26. package/dist/connectionStateHandler.cjs.map +1 -0
  27. package/dist/connectionStateHandler.d.ts +127 -29
  28. package/dist/connectionStateHandler.d.ts.map +1 -1
  29. package/dist/container-loader-alpha.d.ts +274 -0
  30. package/dist/container-loader-beta.d.ts +75 -0
  31. package/dist/container-loader-public.d.ts +75 -0
  32. package/dist/container-loader-untrimmed.d.ts +331 -0
  33. package/dist/container.cjs +1585 -0
  34. package/dist/container.cjs.map +1 -0
  35. package/dist/container.d.ts +227 -83
  36. package/dist/container.d.ts.map +1 -1
  37. package/dist/containerContext.cjs +74 -0
  38. package/dist/containerContext.cjs.map +1 -0
  39. package/dist/containerContext.d.ts +33 -59
  40. package/dist/containerContext.d.ts.map +1 -1
  41. package/dist/containerStorageAdapter.cjs +234 -0
  42. package/dist/containerStorageAdapter.cjs.map +1 -0
  43. package/dist/containerStorageAdapter.d.ts +48 -23
  44. package/dist/containerStorageAdapter.d.ts.map +1 -1
  45. package/dist/{contracts.js → contracts.cjs} +5 -5
  46. package/dist/contracts.cjs.map +1 -0
  47. package/dist/contracts.d.ts +45 -17
  48. package/dist/contracts.d.ts.map +1 -1
  49. package/dist/debugLogger.cjs +101 -0
  50. package/dist/debugLogger.cjs.map +1 -0
  51. package/dist/debugLogger.d.ts +30 -0
  52. package/dist/debugLogger.d.ts.map +1 -0
  53. package/dist/{deltaManager.js → deltaManager.cjs} +379 -186
  54. package/dist/deltaManager.cjs.map +1 -0
  55. package/dist/deltaManager.d.ts +54 -18
  56. package/dist/deltaManager.d.ts.map +1 -1
  57. package/dist/{deltaQueue.js → deltaQueue.cjs} +29 -28
  58. package/dist/deltaQueue.cjs.map +1 -0
  59. package/dist/deltaQueue.d.ts +3 -4
  60. package/dist/deltaQueue.d.ts.map +1 -1
  61. package/dist/disposal.cjs +25 -0
  62. package/dist/disposal.cjs.map +1 -0
  63. package/dist/disposal.d.ts +13 -0
  64. package/dist/disposal.d.ts.map +1 -0
  65. package/dist/error.cjs +32 -0
  66. package/dist/error.cjs.map +1 -0
  67. package/dist/error.d.ts +23 -0
  68. package/dist/error.d.ts.map +1 -0
  69. package/dist/index.cjs +19 -0
  70. package/dist/index.cjs.map +1 -0
  71. package/dist/index.d.ts +5 -2
  72. package/dist/index.d.ts.map +1 -1
  73. package/dist/loader.cjs +148 -0
  74. package/dist/loader.cjs.map +1 -0
  75. package/dist/loader.d.ts +38 -19
  76. package/dist/loader.d.ts.map +1 -1
  77. package/dist/location-redirection-utilities/index.cjs +11 -0
  78. package/dist/location-redirection-utilities/index.cjs.map +1 -0
  79. package/dist/location-redirection-utilities/index.d.ts +6 -0
  80. package/dist/location-redirection-utilities/index.d.ts.map +1 -0
  81. package/dist/location-redirection-utilities/resolveWithLocationRedirection.cjs +53 -0
  82. package/dist/location-redirection-utilities/resolveWithLocationRedirection.cjs.map +1 -0
  83. package/dist/location-redirection-utilities/resolveWithLocationRedirection.d.ts +24 -0
  84. package/dist/location-redirection-utilities/resolveWithLocationRedirection.d.ts.map +1 -0
  85. package/dist/{collabWindowTracker.js → noopHeuristic.cjs} +37 -39
  86. package/dist/noopHeuristic.cjs.map +1 -0
  87. package/dist/noopHeuristic.d.ts +23 -0
  88. package/dist/noopHeuristic.d.ts.map +1 -0
  89. package/dist/{packageVersion.js → packageVersion.cjs} +2 -2
  90. package/dist/packageVersion.cjs.map +1 -0
  91. package/dist/packageVersion.d.ts +1 -1
  92. package/dist/packageVersion.d.ts.map +1 -1
  93. package/dist/protocol.cjs +99 -0
  94. package/dist/protocol.cjs.map +1 -0
  95. package/dist/protocol.d.ts +38 -0
  96. package/dist/protocol.d.ts.map +1 -0
  97. package/dist/{protocolTreeDocumentStorageService.js → protocolTreeDocumentStorageService.cjs} +8 -5
  98. package/dist/protocolTreeDocumentStorageService.cjs.map +1 -0
  99. package/dist/protocolTreeDocumentStorageService.d.ts +8 -4
  100. package/dist/protocolTreeDocumentStorageService.d.ts.map +1 -1
  101. package/dist/quorum.cjs +16 -0
  102. package/dist/quorum.cjs.map +1 -0
  103. package/dist/quorum.d.ts +1 -14
  104. package/dist/quorum.d.ts.map +1 -1
  105. package/dist/{retriableDocumentStorageService.js → retriableDocumentStorageService.cjs} +36 -21
  106. package/dist/retriableDocumentStorageService.cjs.map +1 -0
  107. package/dist/retriableDocumentStorageService.d.ts +7 -5
  108. package/dist/retriableDocumentStorageService.d.ts.map +1 -1
  109. package/dist/tsdoc-metadata.json +11 -0
  110. package/dist/{utils.js → utils.cjs} +52 -14
  111. package/dist/utils.cjs.map +1 -0
  112. package/dist/utils.d.ts +34 -1
  113. package/dist/utils.d.ts.map +1 -1
  114. package/lib/{audience.d.ts → audience.d.mts} +5 -11
  115. package/lib/audience.d.mts.map +1 -0
  116. package/lib/{audience.js → audience.mjs} +15 -17
  117. package/lib/audience.mjs.map +1 -0
  118. package/lib/catchUpMonitor.d.mts +29 -0
  119. package/lib/catchUpMonitor.d.mts.map +1 -0
  120. package/lib/catchUpMonitor.mjs +39 -0
  121. package/lib/catchUpMonitor.mjs.map +1 -0
  122. package/lib/{connectionManager.d.ts → connectionManager.d.mts} +24 -34
  123. package/lib/connectionManager.d.mts.map +1 -0
  124. package/lib/{connectionManager.js → connectionManager.mjs} +378 -218
  125. package/lib/connectionManager.mjs.map +1 -0
  126. package/lib/{connectionState.d.ts → connectionState.d.mts} +4 -6
  127. package/lib/connectionState.d.mts.map +1 -0
  128. package/lib/{connectionState.js → connectionState.mjs} +4 -6
  129. package/lib/connectionState.mjs.map +1 -0
  130. package/lib/connectionStateHandler.d.mts +179 -0
  131. package/lib/connectionStateHandler.d.mts.map +1 -0
  132. package/lib/connectionStateHandler.mjs +469 -0
  133. package/lib/connectionStateHandler.mjs.map +1 -0
  134. package/lib/container-loader-alpha.d.mts +274 -0
  135. package/lib/container-loader-beta.d.mts +75 -0
  136. package/lib/container-loader-public.d.mts +75 -0
  137. package/lib/container-loader-untrimmed.d.mts +331 -0
  138. package/lib/container.d.mts +382 -0
  139. package/lib/container.d.mts.map +1 -0
  140. package/lib/container.mjs +1579 -0
  141. package/lib/container.mjs.map +1 -0
  142. package/lib/containerContext.d.mts +58 -0
  143. package/lib/containerContext.d.mts.map +1 -0
  144. package/lib/containerContext.mjs +70 -0
  145. package/lib/containerContext.mjs.map +1 -0
  146. package/lib/containerStorageAdapter.d.mts +73 -0
  147. package/lib/containerStorageAdapter.d.mts.map +1 -0
  148. package/lib/containerStorageAdapter.mjs +228 -0
  149. package/lib/containerStorageAdapter.mjs.map +1 -0
  150. package/lib/{contracts.d.ts → contracts.d.mts} +46 -18
  151. package/lib/contracts.d.mts.map +1 -0
  152. package/lib/{contracts.js → contracts.mjs} +4 -4
  153. package/lib/contracts.mjs.map +1 -0
  154. package/lib/debugLogger.d.mts +30 -0
  155. package/lib/debugLogger.d.mts.map +1 -0
  156. package/lib/debugLogger.mjs +93 -0
  157. package/lib/debugLogger.mjs.map +1 -0
  158. package/lib/{deltaManager.d.ts → deltaManager.d.mts} +55 -19
  159. package/lib/deltaManager.d.mts.map +1 -0
  160. package/lib/{deltaManager.js → deltaManager.mjs} +361 -165
  161. package/lib/deltaManager.mjs.map +1 -0
  162. package/lib/{deltaQueue.d.ts → deltaQueue.d.mts} +4 -5
  163. package/lib/deltaQueue.d.mts.map +1 -0
  164. package/lib/{deltaQueue.js → deltaQueue.mjs} +25 -24
  165. package/lib/deltaQueue.mjs.map +1 -0
  166. package/lib/disposal.d.mts +13 -0
  167. package/lib/disposal.d.mts.map +1 -0
  168. package/lib/disposal.mjs +21 -0
  169. package/lib/disposal.mjs.map +1 -0
  170. package/lib/error.d.mts +23 -0
  171. package/lib/error.d.mts.map +1 -0
  172. package/lib/error.mjs +28 -0
  173. package/lib/error.mjs.map +1 -0
  174. package/lib/index.d.mts +11 -0
  175. package/lib/index.d.mts.map +1 -0
  176. package/lib/index.mjs +10 -0
  177. package/lib/index.mjs.map +1 -0
  178. package/lib/{loader.d.ts → loader.d.mts} +40 -21
  179. package/lib/loader.d.mts.map +1 -0
  180. package/lib/loader.mjs +143 -0
  181. package/lib/loader.mjs.map +1 -0
  182. package/lib/location-redirection-utilities/index.d.mts +6 -0
  183. package/lib/location-redirection-utilities/index.d.mts.map +1 -0
  184. package/lib/location-redirection-utilities/index.mjs +6 -0
  185. package/lib/location-redirection-utilities/index.mjs.map +1 -0
  186. package/lib/location-redirection-utilities/resolveWithLocationRedirection.d.mts +24 -0
  187. package/lib/location-redirection-utilities/resolveWithLocationRedirection.d.mts.map +1 -0
  188. package/lib/location-redirection-utilities/resolveWithLocationRedirection.mjs +48 -0
  189. package/lib/location-redirection-utilities/resolveWithLocationRedirection.mjs.map +1 -0
  190. package/lib/noopHeuristic.d.mts +23 -0
  191. package/lib/noopHeuristic.d.mts.map +1 -0
  192. package/lib/{collabWindowTracker.js → noopHeuristic.mjs} +33 -35
  193. package/lib/noopHeuristic.mjs.map +1 -0
  194. package/lib/{packageVersion.d.ts → packageVersion.d.mts} +2 -2
  195. package/lib/packageVersion.d.mts.map +1 -0
  196. package/lib/{packageVersion.js → packageVersion.mjs} +2 -2
  197. package/lib/packageVersion.mjs.map +1 -0
  198. package/lib/protocol.d.mts +38 -0
  199. package/lib/protocol.d.mts.map +1 -0
  200. package/lib/protocol.mjs +94 -0
  201. package/lib/protocol.mjs.map +1 -0
  202. package/lib/{protocolTreeDocumentStorageService.d.ts → protocolTreeDocumentStorageService.d.mts} +9 -5
  203. package/lib/protocolTreeDocumentStorageService.d.mts.map +1 -0
  204. package/lib/{protocolTreeDocumentStorageService.js → protocolTreeDocumentStorageService.mjs} +8 -5
  205. package/lib/protocolTreeDocumentStorageService.mjs.map +1 -0
  206. package/lib/quorum.d.mts +4 -0
  207. package/lib/quorum.d.mts.map +1 -0
  208. package/lib/quorum.mjs +12 -0
  209. package/lib/quorum.mjs.map +1 -0
  210. package/lib/{retriableDocumentStorageService.d.ts → retriableDocumentStorageService.d.mts} +8 -6
  211. package/lib/retriableDocumentStorageService.d.mts.map +1 -0
  212. package/lib/{retriableDocumentStorageService.js → retriableDocumentStorageService.mjs} +35 -20
  213. package/lib/retriableDocumentStorageService.mjs.map +1 -0
  214. package/lib/utils.d.mts +67 -0
  215. package/lib/utils.d.mts.map +1 -0
  216. package/lib/{utils.js → utils.mjs} +47 -11
  217. package/lib/utils.mjs.map +1 -0
  218. package/package.json +189 -69
  219. package/prettier.config.cjs +8 -0
  220. package/src/audience.ts +59 -49
  221. package/src/catchUpMonitor.ts +61 -0
  222. package/src/connectionManager.ts +1154 -910
  223. package/src/connectionState.ts +22 -25
  224. package/src/connectionStateHandler.ts +689 -319
  225. package/src/container.ts +2476 -1792
  226. package/src/containerContext.ts +98 -330
  227. package/src/containerStorageAdapter.ts +301 -105
  228. package/src/contracts.ts +184 -146
  229. package/src/debugLogger.ts +123 -0
  230. package/src/deltaManager.ts +1165 -900
  231. package/src/deltaQueue.ts +156 -152
  232. package/src/disposal.ts +25 -0
  233. package/src/error.ts +44 -0
  234. package/src/index.ts +14 -15
  235. package/src/loader.ts +356 -427
  236. package/src/location-redirection-utilities/index.ts +9 -0
  237. package/src/location-redirection-utilities/resolveWithLocationRedirection.ts +61 -0
  238. package/src/noopHeuristic.ts +107 -0
  239. package/src/packageVersion.ts +1 -1
  240. package/src/protocol.ts +150 -0
  241. package/src/protocolTreeDocumentStorageService.ts +35 -35
  242. package/src/quorum.ts +11 -50
  243. package/src/retriableDocumentStorageService.ts +135 -95
  244. package/src/utils.ts +159 -86
  245. package/tsc-multi.test.json +4 -0
  246. package/tsconfig.json +10 -12
  247. package/dist/audience.js.map +0 -1
  248. package/dist/collabWindowTracker.d.ts +0 -19
  249. package/dist/collabWindowTracker.d.ts.map +0 -1
  250. package/dist/collabWindowTracker.js.map +0 -1
  251. package/dist/connectionManager.js.map +0 -1
  252. package/dist/connectionState.js.map +0 -1
  253. package/dist/connectionStateHandler.js +0 -280
  254. package/dist/connectionStateHandler.js.map +0 -1
  255. package/dist/container.js +0 -1284
  256. package/dist/container.js.map +0 -1
  257. package/dist/containerContext.js +0 -217
  258. package/dist/containerContext.js.map +0 -1
  259. package/dist/containerStorageAdapter.js +0 -104
  260. package/dist/containerStorageAdapter.js.map +0 -1
  261. package/dist/contracts.js.map +0 -1
  262. package/dist/deltaManager.js.map +0 -1
  263. package/dist/deltaManagerProxy.d.ts +0 -54
  264. package/dist/deltaManagerProxy.d.ts.map +0 -1
  265. package/dist/deltaManagerProxy.js +0 -115
  266. package/dist/deltaManagerProxy.js.map +0 -1
  267. package/dist/deltaQueue.js.map +0 -1
  268. package/dist/index.js +0 -16
  269. package/dist/index.js.map +0 -1
  270. package/dist/loader.js +0 -241
  271. package/dist/loader.js.map +0 -1
  272. package/dist/packageVersion.js.map +0 -1
  273. package/dist/protocolTreeDocumentStorageService.js.map +0 -1
  274. package/dist/quorum.js +0 -44
  275. package/dist/quorum.js.map +0 -1
  276. package/dist/retriableDocumentStorageService.js.map +0 -1
  277. package/dist/utils.js.map +0 -1
  278. package/lib/audience.d.ts.map +0 -1
  279. package/lib/audience.js.map +0 -1
  280. package/lib/collabWindowTracker.d.ts +0 -19
  281. package/lib/collabWindowTracker.d.ts.map +0 -1
  282. package/lib/collabWindowTracker.js.map +0 -1
  283. package/lib/connectionManager.d.ts.map +0 -1
  284. package/lib/connectionManager.js.map +0 -1
  285. package/lib/connectionState.d.ts.map +0 -1
  286. package/lib/connectionState.js.map +0 -1
  287. package/lib/connectionStateHandler.d.ts +0 -81
  288. package/lib/connectionStateHandler.d.ts.map +0 -1
  289. package/lib/connectionStateHandler.js +0 -276
  290. package/lib/connectionStateHandler.js.map +0 -1
  291. package/lib/container.d.ts +0 -238
  292. package/lib/container.d.ts.map +0 -1
  293. package/lib/container.js +0 -1276
  294. package/lib/container.js.map +0 -1
  295. package/lib/containerContext.d.ts +0 -84
  296. package/lib/containerContext.d.ts.map +0 -1
  297. package/lib/containerContext.js +0 -213
  298. package/lib/containerContext.js.map +0 -1
  299. package/lib/containerStorageAdapter.d.ts +0 -48
  300. package/lib/containerStorageAdapter.d.ts.map +0 -1
  301. package/lib/containerStorageAdapter.js +0 -99
  302. package/lib/containerStorageAdapter.js.map +0 -1
  303. package/lib/contracts.d.ts.map +0 -1
  304. package/lib/contracts.js.map +0 -1
  305. package/lib/deltaManager.d.ts.map +0 -1
  306. package/lib/deltaManager.js.map +0 -1
  307. package/lib/deltaManagerProxy.d.ts +0 -54
  308. package/lib/deltaManagerProxy.d.ts.map +0 -1
  309. package/lib/deltaManagerProxy.js +0 -110
  310. package/lib/deltaManagerProxy.js.map +0 -1
  311. package/lib/deltaQueue.d.ts.map +0 -1
  312. package/lib/deltaQueue.js.map +0 -1
  313. package/lib/index.d.ts +0 -8
  314. package/lib/index.d.ts.map +0 -1
  315. package/lib/index.js +0 -8
  316. package/lib/index.js.map +0 -1
  317. package/lib/loader.d.ts.map +0 -1
  318. package/lib/loader.js +0 -236
  319. package/lib/loader.js.map +0 -1
  320. package/lib/packageVersion.d.ts.map +0 -1
  321. package/lib/packageVersion.js.map +0 -1
  322. package/lib/protocolTreeDocumentStorageService.d.ts.map +0 -1
  323. package/lib/protocolTreeDocumentStorageService.js.map +0 -1
  324. package/lib/quorum.d.ts +0 -21
  325. package/lib/quorum.d.ts.map +0 -1
  326. package/lib/quorum.js +0 -38
  327. package/lib/quorum.js.map +0 -1
  328. package/lib/retriableDocumentStorageService.d.ts.map +0 -1
  329. package/lib/retriableDocumentStorageService.js.map +0 -1
  330. package/lib/utils.d.ts +0 -34
  331. package/lib/utils.d.ts.map +0 -1
  332. package/lib/utils.js.map +0 -1
  333. package/src/collabWindowTracker.ts +0 -102
  334. package/src/deltaManagerProxy.ts +0 -158
  335. package/tsconfig.esnext.json +0 -7
@@ -3,117 +3,157 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { assert } from "@fluidframework/common-utils";
7
- import { GenericError } from "@fluidframework/container-utils";
6
+ import { assert } from "@fluidframework/core-utils";
8
7
  import {
9
- IDocumentStorageService,
10
- IDocumentStorageServicePolicies,
11
- ISummaryContext,
8
+ FetchSource,
9
+ IDocumentStorageService,
10
+ IDocumentStorageServicePolicies,
11
+ ISummaryContext,
12
12
  } from "@fluidframework/driver-definitions";
13
13
  import {
14
- ICreateBlobResponse,
15
- ISnapshotTree,
16
- ISummaryHandle,
17
- ISummaryTree,
18
- IVersion,
14
+ ICreateBlobResponse,
15
+ ISnapshotTree,
16
+ ISummaryHandle,
17
+ ISummaryTree,
18
+ IVersion,
19
19
  } from "@fluidframework/protocol-definitions";
20
- import { IDisposable, ITelemetryLogger } from "@fluidframework/common-definitions";
20
+ import { IDisposable } from "@fluidframework/core-interfaces";
21
+ import { GenericError, ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
21
22
  import { runWithRetry } from "@fluidframework/driver-utils";
22
23
 
23
24
  export class RetriableDocumentStorageService implements IDocumentStorageService, IDisposable {
24
- private _disposed = false;
25
- constructor(
26
- private readonly internalStorageService: IDocumentStorageService,
27
- private readonly logger: ITelemetryLogger,
28
- ) {
29
- }
25
+ private _disposed = false;
26
+ private internalStorageService: IDocumentStorageService | undefined;
27
+ constructor(
28
+ private readonly internalStorageServiceP: Promise<IDocumentStorageService>,
29
+ private readonly logger: ITelemetryLoggerExt,
30
+ ) {
31
+ this.internalStorageServiceP.then((s) => (this.internalStorageService = s)).catch(() => {});
32
+ }
30
33
 
31
- public get policies(): IDocumentStorageServicePolicies | undefined {
32
- return this.internalStorageService.policies;
33
- }
34
- public get disposed() { return this._disposed; }
35
- public dispose() {
36
- this._disposed = true;
37
- }
34
+ public get policies(): IDocumentStorageServicePolicies | undefined {
35
+ if (this.internalStorageService) {
36
+ return this.internalStorageService.policies;
37
+ }
38
+ throw new Error("storage service not yet instantiated");
39
+ }
40
+ public get disposed() {
41
+ return this._disposed;
42
+ }
43
+ public dispose() {
44
+ this._disposed = true;
45
+ }
38
46
 
39
- public get repositoryUrl(): string {
40
- return this.internalStorageService.repositoryUrl;
41
- }
47
+ public get repositoryUrl(): string {
48
+ if (this.internalStorageService) {
49
+ return this.internalStorageService.repositoryUrl;
50
+ }
51
+ throw new Error("storage service not yet instantiated");
52
+ }
42
53
 
43
- public async getSnapshotTree(version?: IVersion, scenarioName?: string): Promise<ISnapshotTree | null> {
44
- return this.runWithRetry(
45
- async () => this.internalStorageService.getSnapshotTree(version, scenarioName),
46
- "storage_getSnapshotTree",
47
- );
48
- }
54
+ public async getSnapshotTree(
55
+ version?: IVersion,
56
+ scenarioName?: string,
57
+ ): Promise<ISnapshotTree | null> {
58
+ return this.runWithRetry(
59
+ async () =>
60
+ this.internalStorageServiceP.then(async (s) =>
61
+ s.getSnapshotTree(version, scenarioName),
62
+ ),
63
+ "storage_getSnapshotTree",
64
+ );
65
+ }
49
66
 
50
- public async readBlob(id: string): Promise<ArrayBufferLike> {
51
- return this.runWithRetry(
52
- async () => this.internalStorageService.readBlob(id),
53
- "storage_readBlob",
54
- );
55
- }
67
+ public async readBlob(id: string): Promise<ArrayBufferLike> {
68
+ return this.runWithRetry(
69
+ async () => this.internalStorageServiceP.then(async (s) => s.readBlob(id)),
70
+ "storage_readBlob",
71
+ );
72
+ }
56
73
 
57
- public async getVersions(versionId: string | null, count: number, scenarioName?: string): Promise<IVersion[]> {
58
- return this.runWithRetry(
59
- async () => this.internalStorageService.getVersions(versionId, count, scenarioName),
60
- "storage_getVersions",
61
- );
62
- }
74
+ public async getVersions(
75
+ versionId: string | null,
76
+ count: number,
77
+ scenarioName?: string,
78
+ fetchSource?: FetchSource,
79
+ ): Promise<IVersion[]> {
80
+ return this.runWithRetry(
81
+ async () =>
82
+ this.internalStorageServiceP.then(async (s) =>
83
+ s.getVersions(versionId, count, scenarioName, fetchSource),
84
+ ),
85
+ "storage_getVersions",
86
+ );
87
+ }
63
88
 
64
- public async uploadSummaryWithContext(summary: ISummaryTree, context: ISummaryContext): Promise<string> {
65
- // Not using retry loop here. Couple reasons:
66
- // 1. If client lost connectivity, then retry loop will result in uploading stale summary
67
- // by stale summarizer after connectivity comes back. It will cause failures for this client and for
68
- // real (new) summarizer. This problem in particular should be solved in future by supplying abort handle
69
- // on all APIs and caller (ContainerRuntime.submitSummary) aborting call on loss of connectivity
70
- // 2. Similar, if we get 429 with retryAfter = 10 minutes, it's likely not the right call to retry summary
71
- // upload in 10 minutes - it's better to keep processing ops and retry later. Though caller needs to take
72
- // retryAfter into account!
73
- // But retry loop is required for creation flow (Container.attach)
74
- assert((context.referenceSequenceNumber === 0) === (context.ackHandle === undefined),
75
- 0x251 /* "creation summary has to have seq=0 && handle === undefined" */);
76
- if (context.referenceSequenceNumber !== 0) {
77
- return this.internalStorageService.uploadSummaryWithContext(summary, context);
78
- }
89
+ public async uploadSummaryWithContext(
90
+ summary: ISummaryTree,
91
+ context: ISummaryContext,
92
+ ): Promise<string> {
93
+ // Not using retry loop here. Couple reasons:
94
+ // 1. If client lost connectivity, then retry loop will result in uploading stale summary
95
+ // by stale summarizer after connectivity comes back. It will cause failures for this client and for
96
+ // real (new) summarizer. This problem in particular should be solved in future by supplying abort handle
97
+ // on all APIs and caller (ContainerRuntime.submitSummary) aborting call on loss of connectivity
98
+ // 2. Similar, if we get 429 with retryAfter = 10 minutes, it's likely not the right call to retry summary
99
+ // upload in 10 minutes - it's better to keep processing ops and retry later. Though caller needs to take
100
+ // retryAfter into account!
101
+ // But retry loop is required for creation flow (Container.attach)
102
+ assert(
103
+ (context.referenceSequenceNumber === 0) === (context.ackHandle === undefined),
104
+ 0x251 /* "creation summary has to have seq=0 && handle === undefined" */,
105
+ );
106
+ if (context.referenceSequenceNumber !== 0) {
107
+ return this.internalStorageServiceP.then(async (s) =>
108
+ s.uploadSummaryWithContext(summary, context),
109
+ );
110
+ }
79
111
 
80
- // Creation flow with attachment blobs - need to do retries!
81
- return this.runWithRetry(
82
- async () => this.internalStorageService.uploadSummaryWithContext(summary, context),
83
- "storage_uploadSummaryWithContext",
84
- );
85
- }
112
+ // Creation flow with attachment blobs - need to do retries!
113
+ return this.runWithRetry(
114
+ async () =>
115
+ this.internalStorageServiceP.then(async (s) =>
116
+ s.uploadSummaryWithContext(summary, context),
117
+ ),
118
+ "storage_uploadSummaryWithContext",
119
+ );
120
+ }
86
121
 
87
- public async downloadSummary(handle: ISummaryHandle): Promise<ISummaryTree> {
88
- return this.runWithRetry(
89
- async () => this.internalStorageService.downloadSummary(handle),
90
- "storage_downloadSummary",
91
- );
92
- }
122
+ public async downloadSummary(handle: ISummaryHandle): Promise<ISummaryTree> {
123
+ return this.runWithRetry(
124
+ async () => this.internalStorageServiceP.then(async (s) => s.downloadSummary(handle)),
125
+ "storage_downloadSummary",
126
+ );
127
+ }
93
128
 
94
- public async createBlob(file: ArrayBufferLike): Promise<ICreateBlobResponse> {
95
- return this.runWithRetry(
96
- async () => this.internalStorageService.createBlob(file),
97
- "storage_createBlob",
98
- );
99
- }
129
+ public async createBlob(file: ArrayBufferLike): Promise<ICreateBlobResponse> {
130
+ return this.runWithRetry(
131
+ async () => this.internalStorageServiceP.then(async (s) => s.createBlob(file)),
132
+ "storage_createBlob",
133
+ );
134
+ }
100
135
 
101
- private checkStorageDisposed() {
102
- if (this._disposed) {
103
- // pre-0.58 error message: storageServiceDisposedCannotRetry
104
- throw new GenericError("Storage Service is disposed. Cannot retry", { canRetry: false });
105
- }
106
- return undefined;
107
- }
136
+ private checkStorageDisposed(callName: string, error: unknown) {
137
+ if (this._disposed) {
138
+ this.logger.sendTelemetryEvent(
139
+ {
140
+ eventName: `${callName}_abortedStorageDisposed`,
141
+ fetchCallName: callName, // fetchCallName matches logs in runWithRetry.ts
142
+ },
143
+ error,
144
+ );
145
+ // pre-0.58 error message: storageServiceDisposedCannotRetry
146
+ throw new GenericError("Storage Service is disposed. Cannot retry", {
147
+ canRetry: false,
148
+ });
149
+ }
150
+ return;
151
+ }
108
152
 
109
- private async runWithRetry<T>(api: () => Promise<T>, callName: string): Promise<T> {
110
- return runWithRetry(
111
- api,
112
- callName,
113
- this.logger,
114
- {
115
- onRetry: () => this.checkStorageDisposed(),
116
- },
117
- );
118
- }
153
+ private async runWithRetry<T>(api: () => Promise<T>, callName: string): Promise<T> {
154
+ return runWithRetry(api, callName, this.logger, {
155
+ onRetry: (_delayInMs: number, error: unknown) =>
156
+ this.checkStorageDisposed(callName, error),
157
+ });
158
+ }
119
159
  }
package/src/utils.ts CHANGED
@@ -5,45 +5,99 @@
5
5
 
6
6
  import { parse } from "url";
7
7
  import { v4 as uuid } from "uuid";
8
- import {
9
- assert,
10
- stringToBuffer,
11
- Uint8ArrayToArrayBuffer,
12
- unreachableCase,
13
- } from "@fluidframework/common-utils";
8
+ import { stringToBuffer, Uint8ArrayToArrayBuffer } from "@fluid-internal/client-utils";
9
+ import { assert, unreachableCase } from "@fluidframework/core-utils";
14
10
  import { ISummaryTree, ISnapshotTree, SummaryType } from "@fluidframework/protocol-definitions";
15
11
  import { LoggingError } from "@fluidframework/telemetry-utils";
12
+ import {
13
+ CombinedAppAndProtocolSummary,
14
+ DeltaStreamConnectionForbiddenError,
15
+ isCombinedAppAndProtocolSummary,
16
+ } from "@fluidframework/driver-utils";
17
+ import { DriverErrorTypes } from "@fluidframework/driver-definitions";
16
18
 
17
19
  // This is used when we rehydrate a container from the snapshot. Here we put the blob contents
18
20
  // in separate property: blobContents.
19
21
  export interface ISnapshotTreeWithBlobContents extends ISnapshotTree {
20
- blobsContents: { [path: string]: ArrayBufferLike; };
21
- trees: { [path: string]: ISnapshotTreeWithBlobContents; };
22
+ blobsContents: { [path: string]: ArrayBufferLike };
23
+ trees: { [path: string]: ISnapshotTreeWithBlobContents };
22
24
  }
23
25
 
26
+ /**
27
+ * Interface to represent the parsed parts of IResolvedUrl.url to help
28
+ * in getting info about different parts of the url.
29
+ * May not be compatible or relevant for any Url Resolver
30
+ * @internal
31
+ */
24
32
  export interface IParsedUrl {
25
- id: string;
26
- path: string;
27
- query: string;
28
- /**
29
- * Null means do not use snapshots, undefined means load latest snapshot
30
- * otherwise it's version ID passed to IDocumentStorageService.getVersions() to figure out what snapshot to use.
31
- * If needed, can add undefined which is treated by Container.load() as load latest snapshot.
32
- */
33
- version: string | null | undefined;
33
+ /**
34
+ * It is combination of tenantid/docId part of the url.
35
+ */
36
+ id: string;
37
+ /**
38
+ * It is the deep link path in the url.
39
+ */
40
+ path: string;
41
+ /**
42
+ * Query string part of the url.
43
+ */
44
+ query: string;
45
+ /**
46
+ * Null means do not use snapshots, undefined means load latest snapshot
47
+ * otherwise it's version ID passed to IDocumentStorageService.getVersions() to figure out what snapshot to use.
48
+ * If needed, can add undefined which is treated by Container.load() as load latest snapshot.
49
+ */
50
+ version: string | null | undefined;
51
+ }
52
+
53
+ /**
54
+ * Utility api to parse the IResolvedUrl.url into specific parts like querystring, path to get
55
+ * deep link info etc.
56
+ * Warning - This function may not be compatible with any Url Resolver's resolved url. It works
57
+ * with urls of type: protocol://<string>/.../..?<querystring>
58
+ * @param url - This is the IResolvedUrl.url part of the resolved url.
59
+ * @returns The IParsedUrl representing the input URL, or undefined if the format was not supported
60
+ * @internal
61
+ */
62
+ export function tryParseCompatibleResolvedUrl(url: string): IParsedUrl | undefined {
63
+ const parsed = parse(url, true);
64
+ if (typeof parsed.pathname !== "string") {
65
+ throw new LoggingError("Failed to parse pathname");
66
+ }
67
+ const query = parsed.search ?? "";
68
+ const regex = /^\/([^/]*\/[^/]*)(\/?.*)$/;
69
+ const match = regex.exec(parsed.pathname);
70
+ return match?.length === 3
71
+ ? { id: match[1], path: match[2], query, version: parsed.query.version as string }
72
+ : undefined;
34
73
  }
35
74
 
36
- export function parseUrl(url: string): IParsedUrl | undefined {
37
- const parsed = parse(url, true);
38
- if (typeof parsed.pathname !== "string") {
39
- throw new LoggingError("Failed to parse pathname");
40
- }
41
- const query = parsed.search ?? "";
42
- const regex = /^\/([^/]*\/[^/]*)(\/?.*)$/;
43
- const match = regex.exec(parsed.pathname);
44
- return (match?.length === 3)
45
- ? { id: match[1], path: match[2], query, version: parsed.query.version as string }
46
- : undefined;
75
+ /**
76
+ * Combine the app summary and protocol summary in 1 tree.
77
+ * @param appSummary - Summary of the app.
78
+ * @param protocolSummary - Summary of the protocol.
79
+ * @internal
80
+ */
81
+ export function combineAppAndProtocolSummary(
82
+ appSummary: ISummaryTree,
83
+ protocolSummary: ISummaryTree,
84
+ ): CombinedAppAndProtocolSummary {
85
+ assert(
86
+ !isCombinedAppAndProtocolSummary(appSummary),
87
+ 0x5a8 /* app summary is already a combined tree! */,
88
+ );
89
+ assert(
90
+ !isCombinedAppAndProtocolSummary(protocolSummary),
91
+ 0x5a9 /* protocol summary is already a combined tree! */,
92
+ );
93
+ const createNewSummary: CombinedAppAndProtocolSummary = {
94
+ type: SummaryType.Tree,
95
+ tree: {
96
+ ".protocol": protocolSummary,
97
+ ".app": appSummary,
98
+ },
99
+ };
100
+ return createNewSummary;
47
101
  }
48
102
 
49
103
  /**
@@ -57,44 +111,49 @@ export function parseUrl(url: string): IParsedUrl | undefined {
57
111
  * @param summary - summary to convert
58
112
  */
59
113
  function convertSummaryToSnapshotWithEmbeddedBlobContents(
60
- summary: ISummaryTree,
114
+ summary: ISummaryTree,
61
115
  ): ISnapshotTreeWithBlobContents {
62
- const treeNode: ISnapshotTreeWithBlobContents = {
63
- blobs: {},
64
- blobsContents: {},
65
- trees: {},
66
- id: uuid(),
67
- unreferenced: summary.unreferenced,
68
- };
69
- const keys = Object.keys(summary.tree);
70
- for (const key of keys) {
71
- const summaryObject = summary.tree[key];
116
+ const treeNode: ISnapshotTreeWithBlobContents = {
117
+ blobs: {},
118
+ blobsContents: {},
119
+ trees: {},
120
+ id: uuid(),
121
+ unreferenced: summary.unreferenced,
122
+ };
123
+ const keys = Object.keys(summary.tree);
124
+ for (const key of keys) {
125
+ const summaryObject = summary.tree[key];
72
126
 
73
- switch (summaryObject.type) {
74
- case SummaryType.Tree: {
75
- treeNode.trees[key] = convertSummaryToSnapshotWithEmbeddedBlobContents(summaryObject);
76
- break;
77
- }
78
- case SummaryType.Attachment:
79
- treeNode.blobs[key] = summaryObject.id;
80
- break;
81
- case SummaryType.Blob: {
82
- const blobId = uuid();
83
- treeNode.blobs[key] = blobId;
84
- const contentBuffer = typeof summaryObject.content === "string" ?
85
- stringToBuffer(summaryObject.content, "utf8") : Uint8ArrayToArrayBuffer(summaryObject.content);
86
- treeNode.blobsContents[blobId] = contentBuffer;
87
- break;
88
- }
89
- case SummaryType.Handle:
90
- throw new LoggingError("No handles should be there in summary in detached container!!");
91
- break;
92
- default: {
93
- unreachableCase(summaryObject, `Unknown tree type ${(summaryObject as any).type}`);
94
- }
95
- }
96
- }
97
- return treeNode;
127
+ switch (summaryObject.type) {
128
+ case SummaryType.Tree: {
129
+ treeNode.trees[key] =
130
+ convertSummaryToSnapshotWithEmbeddedBlobContents(summaryObject);
131
+ break;
132
+ }
133
+ case SummaryType.Attachment:
134
+ treeNode.blobs[key] = summaryObject.id;
135
+ break;
136
+ case SummaryType.Blob: {
137
+ const blobId = uuid();
138
+ treeNode.blobs[key] = blobId;
139
+ const contentBuffer =
140
+ typeof summaryObject.content === "string"
141
+ ? stringToBuffer(summaryObject.content, "utf8")
142
+ : Uint8ArrayToArrayBuffer(summaryObject.content);
143
+ treeNode.blobsContents[blobId] = contentBuffer;
144
+ break;
145
+ }
146
+ case SummaryType.Handle:
147
+ throw new LoggingError(
148
+ "No handles should be there in summary in detached container!!",
149
+ );
150
+ break;
151
+ default: {
152
+ unreachableCase(summaryObject, `Unknown tree type ${(summaryObject as any).type}`);
153
+ }
154
+ }
155
+ }
156
+ return treeNode;
98
157
  }
99
158
 
100
159
  /**
@@ -103,35 +162,49 @@ function convertSummaryToSnapshotWithEmbeddedBlobContents(
103
162
  * @param appSummaryTree - App Summary Tree
104
163
  */
105
164
  export function convertProtocolAndAppSummaryToSnapshotTree(
106
- protocolSummaryTree: ISummaryTree,
107
- appSummaryTree: ISummaryTree,
165
+ protocolSummaryTree: ISummaryTree,
166
+ appSummaryTree: ISummaryTree,
108
167
  ): ISnapshotTreeWithBlobContents {
109
- // Shallow copy is fine, since we are doing a deep clone below.
110
- const combinedSummary: ISummaryTree = {
111
- type: SummaryType.Tree,
112
- tree: { ...appSummaryTree.tree },
113
- };
168
+ // Shallow copy is fine, since we are doing a deep clone below.
169
+ const combinedSummary: ISummaryTree = {
170
+ type: SummaryType.Tree,
171
+ tree: { ...appSummaryTree.tree },
172
+ };
114
173
 
115
- combinedSummary.tree[".protocol"] = protocolSummaryTree;
116
- const snapshotTreeWithBlobContents =
117
- convertSummaryToSnapshotWithEmbeddedBlobContents(combinedSummary);
118
- return snapshotTreeWithBlobContents;
174
+ combinedSummary.tree[".protocol"] = protocolSummaryTree;
175
+ const snapshotTreeWithBlobContents =
176
+ convertSummaryToSnapshotWithEmbeddedBlobContents(combinedSummary);
177
+ return snapshotTreeWithBlobContents;
119
178
  }
120
179
 
121
180
  // This function converts the snapshot taken in detached container(by serialize api) to snapshotTree with which
122
181
  // a detached container can be rehydrated.
123
- export const getSnapshotTreeFromSerializedContainer = (detachedContainerSnapshot: ISummaryTree) => {
124
- const protocolSummaryTree = detachedContainerSnapshot.tree[".protocol"] as ISummaryTree;
125
- const appSummaryTree = detachedContainerSnapshot.tree[".app"] as ISummaryTree;
126
- assert(protocolSummaryTree !== undefined && appSummaryTree !== undefined,
127
- 0x1e0 /* "Protocol and App summary trees should be present" */);
128
- const snapshotTreeWithBlobContents = convertProtocolAndAppSummaryToSnapshotTree(
129
- protocolSummaryTree,
130
- appSummaryTree,
131
- );
132
- return snapshotTreeWithBlobContents;
182
+ export const getSnapshotTreeFromSerializedContainer = (
183
+ detachedContainerSnapshot: ISummaryTree,
184
+ ): ISnapshotTreeWithBlobContents => {
185
+ assert(
186
+ isCombinedAppAndProtocolSummary(detachedContainerSnapshot),
187
+ 0x1e0 /* "Protocol and App summary trees should be present" */,
188
+ );
189
+ const protocolSummaryTree = detachedContainerSnapshot.tree[".protocol"];
190
+ const appSummaryTree = detachedContainerSnapshot.tree[".app"];
191
+ const snapshotTreeWithBlobContents = convertProtocolAndAppSummaryToSnapshotTree(
192
+ protocolSummaryTree,
193
+ appSummaryTree,
194
+ );
195
+ return snapshotTreeWithBlobContents;
133
196
  };
134
197
 
135
198
  export function getProtocolSnapshotTree(snapshot: ISnapshotTree): ISnapshotTree {
136
- return ".protocol" in snapshot.trees ? snapshot.trees[".protocol"] : snapshot;
199
+ return ".protocol" in snapshot.trees ? snapshot.trees[".protocol"] : snapshot;
200
+ }
201
+
202
+ export function isDeltaStreamConnectionForbiddenError(
203
+ error: any,
204
+ ): error is DeltaStreamConnectionForbiddenError {
205
+ return (
206
+ typeof error === "object" &&
207
+ error !== null &&
208
+ error?.errorType === DriverErrorTypes.deltaStreamConnectionForbidden
209
+ );
137
210
  }
@@ -0,0 +1,4 @@
1
+ {
2
+ "targets": [{ "extname": ".cjs", "module": "CommonJS", "moduleResolution": "Node10" }],
3
+ "projects": ["./tsconfig.json", "./src/test/tsconfig.json"]
4
+ }
package/tsconfig.json CHANGED
@@ -1,14 +1,12 @@
1
1
  {
2
- "extends": "@fluidframework/build-common/ts-common-config.json",
3
- "exclude": [
4
- "src/test/**/*"
5
- ],
6
- "compilerOptions": {
7
- "rootDir": "./src",
8
- "outDir": "./dist",
9
- "composite": true
10
- },
11
- "include": [
12
- "src/**/*"
13
- ]
2
+ "extends": [
3
+ "../../../common/build/build-common/tsconfig.base.json",
4
+ "../../../common/build/build-common/tsconfig.cjs.json",
5
+ ],
6
+ "include": ["src/**/*"],
7
+ "exclude": ["src/test/**/*"],
8
+ "compilerOptions": {
9
+ "rootDir": "./src",
10
+ "outDir": "./dist",
11
+ },
14
12
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"audience.js","sourceRoot":"","sources":["../src/audience.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACH,mCAAsC;AAItC;;GAEG;AACH,MAAa,QAAS,SAAQ,qBAAY;IAA1C;;QACqB,YAAO,GAAG,IAAI,GAAG,EAAmB,CAAC;IAqD1D,CAAC;IAlDU,EAAE,CAAC,KAAa,EAAE,QAAkC;QACvD,OAAO,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IACrC,CAAC;IAED;;OAEG;IACI,SAAS,CAAC,QAAgB,EAAE,OAAgB;QAC/C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACpC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC;IAED;;;OAGG;IACI,YAAY,CAAC,QAAgB;QAChC,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACjD,IAAI,aAAa,KAAK,SAAS,EAAE;YAC7B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC9B,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;YACnD,OAAO,IAAI,CAAC;SACf;aAAM;YACH,OAAO,KAAK,CAAC;SAChB;IACL,CAAC;IAED;;OAEG;IACI,UAAU;QACb,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;IAED;;OAEG;IACI,SAAS,CAAC,QAAgB;QAC7B,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACtC,CAAC;IAED;;OAEG;IACI,KAAK;QACR,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QACtC,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE;YAC9B,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;SAC/B;IACL,CAAC;CACJ;AAtDD,4BAsDC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\nimport { EventEmitter } from \"events\";\nimport { IAudience } from \"@fluidframework/container-definitions\";\nimport { IClient } from \"@fluidframework/protocol-definitions\";\n\n/**\n * Audience represents all clients connected to the op stream.\n */\nexport class Audience extends EventEmitter implements IAudience {\n private readonly members = new Map<string, IClient>();\n\n public on(event: \"addMember\" | \"removeMember\", listener: (clientId: string, client: IClient) => void): this;\n public on(event: string, listener: (...args: any[]) => void): this {\n return super.on(event, listener);\n }\n\n /**\n * Adds a new client to the audience\n */\n public addMember(clientId: string, details: IClient) {\n this.members.set(clientId, details);\n this.emit(\"addMember\", clientId, details);\n }\n\n /**\n * Removes a client from the audience. Only emits an event if a client is actually removed\n * @returns if a client was removed from the audience\n */\n public removeMember(clientId: string): boolean {\n const removedClient = this.members.get(clientId);\n if (removedClient !== undefined) {\n this.members.delete(clientId);\n this.emit(\"removeMember\", clientId, removedClient);\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * Retrieves all the members in the audience\n */\n public getMembers(): Map<string, IClient> {\n return new Map(this.members);\n }\n\n /**\n * Retrieves a specific member of the audience\n */\n public getMember(clientId: string): IClient | undefined {\n return this.members.get(clientId);\n }\n\n /**\n * Clears the audience\n */\n public clear(): void {\n const clientIds = this.members.keys();\n for (const clientId of clientIds) {\n this.removeMember(clientId);\n }\n }\n}\n"]}
@@ -1,19 +0,0 @@
1
- /*!
2
- * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
- * Licensed under the MIT License.
4
- */
5
- import { ISequencedDocumentMessage, MessageType } from "@fluidframework/protocol-definitions";
6
- export declare class CollabWindowTracker {
7
- private readonly submit;
8
- private readonly NoopCountFrequency;
9
- private opsCountSinceNoop;
10
- private readonly timer;
11
- constructor(submit: (type: MessageType, contents: any) => void, NoopTimeFrequency?: number, NoopCountFrequency?: number);
12
- /**
13
- * Schedules as ack to the server to update the reference sequence number
14
- */
15
- scheduleSequenceNumberUpdate(message: ISequencedDocumentMessage, immediateNoOp: boolean): void;
16
- private submitNoop;
17
- stopSequenceNumberUpdate(): void;
18
- }
19
- //# sourceMappingURL=collabWindowTracker.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"collabWindowTracker.d.ts","sourceRoot":"","sources":["../src/collabWindowTracker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,yBAAyB,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AAyB9F,qBAAa,mBAAmB;IAKxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAEvB,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IANvC,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoB;gBAGrB,MAAM,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,KAAK,IAAI,EACnE,iBAAiB,GAAE,MAAiC,EACnC,kBAAkB,GAAE,MAAkC;IAa3E;;OAEG;IACI,4BAA4B,CAAC,OAAO,EAAE,yBAAyB,EAAE,aAAa,EAAE,OAAO,GAAG,IAAI;IA+BrG,OAAO,CAAC,UAAU;IAOX,wBAAwB,IAAI,IAAI;CAS1C"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"collabWindowTracker.js","sourceRoot":"","sources":["../src/collabWindowTracker.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,+DAA6D;AAC7D,+EAA8F;AAC9F,+DAAgE;AAEhE,MAAM,wBAAwB,GAAG,IAAI,CAAC;AACtC,MAAM,yBAAyB,GAAG,EAAE,CAAC;AAErC,6FAA6F;AAC7F,4GAA4G;AAC5G,yGAAyG;AACzG,2CAA2C;AAC3C,oHAAoH;AACpH,2FAA2F;AAC3F,kHAAkH;AAClH,+CAA+C;AAC/C,gHAAgH;AAChH,yFAAyF;AACzF,qHAAqH;AACrH,oDAAoD;AACpD,EAAE;AACF,kDAAkD;AAClD,oGAAoG;AACpG,iHAAiH;AACjH,sEAAsE;AACtE,4GAA4G;AAC5G,qGAAqG;AACrG,MAAa,mBAAmB;IAI5B,YACqB,MAAkD,EACnE,oBAA4B,wBAAwB,EACnC,qBAA6B,yBAAyB;QAFtD,WAAM,GAAN,MAAM,CAA4C;QAElD,uBAAkB,GAAlB,kBAAkB,CAAoC;QANnE,sBAAiB,GAAG,CAAC,CAAC;QAQ1B,IAAI,iBAAiB,KAAK,QAAQ,EAAE;YAChC,IAAI,CAAC,KAAK,GAAG,IAAI,oBAAK,CAAC,iBAAiB,EAAE,GAAG,EAAE;gBAC3C,2EAA2E;gBAC3E,mGAAmG;gBACnG,IAAI,IAAI,CAAC,iBAAiB,KAAK,CAAC,EAAE;oBAC9B,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;iBAC1C;YACL,CAAC,CAAC,CAAC;SACN;IACL,CAAC;IAED;;OAEG;IACI,4BAA4B,CAAC,OAAkC,EAAE,aAAsB;QAC1F,mEAAmE;QACnE,sDAAsD;QACtD,IAAI,aAAa,EAAE;YACf,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;YACtC,OAAO;SACV;QAED,gFAAgF;QAChF,+DAA+D;QAC/D,sFAAsF;QACtF,yCAAyC;QACzC,IAAI,CAAC,IAAA,+BAAgB,EAAC,OAAO,CAAC,EAAE;YAC5B,OAAO;SACV;QAED,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,iBAAiB,IAAI,IAAI,CAAC,kBAAkB,EAAE;YACnD,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;YACvC,OAAO;SACV;QAED,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,EAAE;YAC1B,IAAI,IAAI,CAAC,iBAAiB,KAAK,CAAC,EAAE;gBAC9B,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;aACxB;YAED,IAAA,qBAAM,EAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,iBAAiB,CAAC,CAAC;SACxD;IACL,CAAC;IAEO,UAAU,CAAC,SAAkB;QACjC,6CAA6C;QAC7C,IAAI,CAAC,MAAM,CAAC,kCAAW,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACrD,IAAA,qBAAM,EAAC,IAAI,CAAC,iBAAiB,KAAK,CAAC,EAC/B,KAAK,CAAC,8EAA8E,CAAC,CAAC;IAC9F,CAAC;IAEM,wBAAwB;QAC3B,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC;QAC3B,kGAAkG;QAClG,wGAAwG;QACxG,oDAAoD;QACpD,qGAAqG;QACrG,yFAAyF;QACzF,sBAAsB;IAC1B,CAAC;CACJ;AAtED,kDAsEC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { assert, Timer } from \"@fluidframework/common-utils\";\nimport { ISequencedDocumentMessage, MessageType } from \"@fluidframework/protocol-definitions\";\nimport { isRuntimeMessage } from \"@fluidframework/driver-utils\";\n\nconst defaultNoopTimeFrequency = 2000;\nconst defaultNoopCountFrequency = 50;\n\n// Here are key considerations when deciding conditions for when to send non-immediate noops:\n// 1. Sending them too often results in increase in file size and bandwidth, as well as catch up performance\n// 2. Sending too infrequently ensures that collab window is large, and as result Sequence DDS would have\n// large catchUp blobs - see Issue #6364\n// 3. Similarly, processes that rely on \"core\" snapshot (and can't parse trailing ops, including above), like search\n// parser in SPO, will result in non-accurate results due to presence of catch up blobs.\n// 4. Ordering service used 250ms timeout to coalesce non-immediate noops. It was changed to 2000 ms to allow more\n// aggressive noop sending from client side.\n// 5. Number of ops sent by all clients is proportional to number of \"write\" clients (every client sends noops),\n// but number of sequenced noops is a function of time (one op per 2 seconds at most).\n// We should consider impact to both outbound traffic (might be huge, depends on number of clients) and file size.\n// Please also see Issue #5629 for more discussions.\n//\n// With that, the current algorithm is as follows:\n// 1. Sent noop 2000 ms of receiving an op if no ops were sent by this client within this timeframe.\n// This will ensure that MSN moves forward with reasonable speed. If that results in too many sequenced noops,\n// server timeout of 2000ms should be reconsidered to be increased.\n// 2. If there are more than 50 ops received without sending any ops, send noop to keep collab window small.\n// Note that system ops (including noops themselves) are excluded, so it's 1 noop per 50 real ops.\nexport class CollabWindowTracker {\n private opsCountSinceNoop = 0;\n private readonly timer: Timer | undefined;\n\n constructor(\n private readonly submit: (type: MessageType, contents: any) => void,\n NoopTimeFrequency: number = defaultNoopTimeFrequency,\n private readonly NoopCountFrequency: number = defaultNoopCountFrequency,\n ) {\n if (NoopTimeFrequency !== Infinity) {\n this.timer = new Timer(NoopTimeFrequency, () => {\n // Can get here due to this.stopSequenceNumberUpdate() not resetting timer.\n // Also timer callback can fire even after timer cancellation if it was queued before cancellation.\n if (this.opsCountSinceNoop !== 0) {\n this.submitNoop(false /* immediate */);\n }\n });\n }\n }\n\n /**\n * Schedules as ack to the server to update the reference sequence number\n */\n public scheduleSequenceNumberUpdate(message: ISequencedDocumentMessage, immediateNoOp: boolean): void {\n // While processing a message, an immediate no-op can be requested.\n // i.e. to expedite approve or commit phase of quorum.\n if (immediateNoOp) {\n this.submitNoop(true /* immediate */);\n return;\n }\n\n // We don't acknowledge no-ops to avoid acknowledgement cycles (i.e. ack the MSN\n // update, which updates the MSN, then ack the update, etc...).\n // Intent here is for runtime (and DDSes) not to keep too much tracking state / memory\n // due to runtime ops from other clients.\n if (!isRuntimeMessage(message)) {\n return;\n }\n\n this.opsCountSinceNoop++;\n if (this.opsCountSinceNoop >= this.NoopCountFrequency) {\n this.submitNoop(false /* immediate */);\n return;\n }\n\n if (this.timer !== undefined) {\n if (this.opsCountSinceNoop === 1) {\n this.timer.restart();\n }\n\n assert(this.timer.hasTimer, 0x242 /* \"has timer\" */);\n }\n }\n\n private submitNoop(immediate: boolean) {\n // Anything other than null is immediate noop\n this.submit(MessageType.NoOp, immediate ? \"\" : null);\n assert(this.opsCountSinceNoop === 0,\n 0x243 /* \"stopSequenceNumberUpdate should be called as result of sending any op!\" */);\n }\n\n public stopSequenceNumberUpdate(): void {\n this.opsCountSinceNoop = 0;\n // Ideally, we cancel timer here. But that will result in too often set/reset cycle if this client\n // keeps sending ops. In most cases it's actually better to let it expire (at most - 4 times per second)\n // for nothing, then have a ton of set/reset cycles.\n // Note that Timer.restart() is smart and will not change timer expiration if we keep extending timer\n // expiration - it will restart the timer instead when it fires with adjusted expiration.\n // this.timer.clear();\n }\n}\n"]}