@fluidframework/container-loader 1.4.0-115997 → 2.0.0-dev-rc.1.0.0.224419

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 (333) 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-lint.json +4 -0
  6. package/api-extractor.json +2 -2
  7. package/api-report/container-loader.api.md +143 -0
  8. package/dist/{audience.js → audience.cjs} +15 -13
  9. package/dist/audience.cjs.map +1 -0
  10. package/dist/audience.d.ts +3 -6
  11. package/dist/audience.d.ts.map +1 -1
  12. package/dist/catchUpMonitor.cjs +43 -0
  13. package/dist/catchUpMonitor.cjs.map +1 -0
  14. package/dist/catchUpMonitor.d.ts +29 -0
  15. package/dist/catchUpMonitor.d.ts.map +1 -0
  16. package/dist/{connectionManager.js → connectionManager.cjs} +397 -240
  17. package/dist/connectionManager.cjs.map +1 -0
  18. package/dist/connectionManager.d.ts +23 -33
  19. package/dist/connectionManager.d.ts.map +1 -1
  20. package/dist/{connectionState.js → connectionState.cjs} +5 -7
  21. package/dist/connectionState.cjs.map +1 -0
  22. package/dist/connectionState.d.ts +3 -5
  23. package/dist/connectionState.d.ts.map +1 -1
  24. package/dist/connectionStateHandler.cjs +474 -0
  25. package/dist/connectionStateHandler.cjs.map +1 -0
  26. package/dist/connectionStateHandler.d.ts +127 -29
  27. package/dist/connectionStateHandler.d.ts.map +1 -1
  28. package/dist/container-loader-alpha.d.ts +274 -0
  29. package/dist/container-loader-beta.d.ts +75 -0
  30. package/dist/container-loader-public.d.ts +75 -0
  31. package/dist/container-loader-untrimmed.d.ts +331 -0
  32. package/dist/container.cjs +1585 -0
  33. package/dist/container.cjs.map +1 -0
  34. package/dist/container.d.ts +227 -83
  35. package/dist/container.d.ts.map +1 -1
  36. package/dist/containerContext.cjs +74 -0
  37. package/dist/containerContext.cjs.map +1 -0
  38. package/dist/containerContext.d.ts +33 -59
  39. package/dist/containerContext.d.ts.map +1 -1
  40. package/dist/containerStorageAdapter.cjs +234 -0
  41. package/dist/containerStorageAdapter.cjs.map +1 -0
  42. package/dist/containerStorageAdapter.d.ts +48 -23
  43. package/dist/containerStorageAdapter.d.ts.map +1 -1
  44. package/dist/{contracts.js → contracts.cjs} +5 -5
  45. package/dist/contracts.cjs.map +1 -0
  46. package/dist/contracts.d.ts +45 -17
  47. package/dist/contracts.d.ts.map +1 -1
  48. package/dist/debugLogger.cjs +101 -0
  49. package/dist/debugLogger.cjs.map +1 -0
  50. package/dist/debugLogger.d.ts +30 -0
  51. package/dist/debugLogger.d.ts.map +1 -0
  52. package/dist/{deltaManager.js → deltaManager.cjs} +379 -186
  53. package/dist/deltaManager.cjs.map +1 -0
  54. package/dist/deltaManager.d.ts +54 -18
  55. package/dist/deltaManager.d.ts.map +1 -1
  56. package/dist/{deltaQueue.js → deltaQueue.cjs} +29 -28
  57. package/dist/deltaQueue.cjs.map +1 -0
  58. package/dist/deltaQueue.d.ts +3 -4
  59. package/dist/deltaQueue.d.ts.map +1 -1
  60. package/dist/disposal.cjs +25 -0
  61. package/dist/disposal.cjs.map +1 -0
  62. package/dist/disposal.d.ts +13 -0
  63. package/dist/disposal.d.ts.map +1 -0
  64. package/dist/error.cjs +32 -0
  65. package/dist/error.cjs.map +1 -0
  66. package/dist/error.d.ts +23 -0
  67. package/dist/error.d.ts.map +1 -0
  68. package/dist/index.cjs +19 -0
  69. package/dist/index.cjs.map +1 -0
  70. package/dist/index.d.ts +5 -2
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/loader.cjs +148 -0
  73. package/dist/loader.cjs.map +1 -0
  74. package/dist/loader.d.ts +38 -19
  75. package/dist/loader.d.ts.map +1 -1
  76. package/dist/location-redirection-utilities/index.cjs +11 -0
  77. package/dist/location-redirection-utilities/index.cjs.map +1 -0
  78. package/dist/location-redirection-utilities/index.d.ts +6 -0
  79. package/dist/location-redirection-utilities/index.d.ts.map +1 -0
  80. package/dist/location-redirection-utilities/resolveWithLocationRedirection.cjs +53 -0
  81. package/dist/location-redirection-utilities/resolveWithLocationRedirection.cjs.map +1 -0
  82. package/dist/location-redirection-utilities/resolveWithLocationRedirection.d.ts +24 -0
  83. package/dist/location-redirection-utilities/resolveWithLocationRedirection.d.ts.map +1 -0
  84. package/dist/{collabWindowTracker.js → noopHeuristic.cjs} +37 -39
  85. package/dist/noopHeuristic.cjs.map +1 -0
  86. package/dist/noopHeuristic.d.ts +23 -0
  87. package/dist/noopHeuristic.d.ts.map +1 -0
  88. package/dist/{packageVersion.js → packageVersion.cjs} +2 -2
  89. package/dist/packageVersion.cjs.map +1 -0
  90. package/dist/packageVersion.d.ts +1 -1
  91. package/dist/packageVersion.d.ts.map +1 -1
  92. package/dist/protocol.cjs +99 -0
  93. package/dist/protocol.cjs.map +1 -0
  94. package/dist/protocol.d.ts +38 -0
  95. package/dist/protocol.d.ts.map +1 -0
  96. package/dist/{protocolTreeDocumentStorageService.js → protocolTreeDocumentStorageService.cjs} +8 -5
  97. package/dist/protocolTreeDocumentStorageService.cjs.map +1 -0
  98. package/dist/protocolTreeDocumentStorageService.d.ts +8 -4
  99. package/dist/protocolTreeDocumentStorageService.d.ts.map +1 -1
  100. package/dist/quorum.cjs +16 -0
  101. package/dist/quorum.cjs.map +1 -0
  102. package/dist/quorum.d.ts +1 -14
  103. package/dist/quorum.d.ts.map +1 -1
  104. package/dist/{retriableDocumentStorageService.js → retriableDocumentStorageService.cjs} +36 -21
  105. package/dist/retriableDocumentStorageService.cjs.map +1 -0
  106. package/dist/retriableDocumentStorageService.d.ts +7 -5
  107. package/dist/retriableDocumentStorageService.d.ts.map +1 -1
  108. package/dist/tsdoc-metadata.json +11 -0
  109. package/dist/{utils.js → utils.cjs} +52 -14
  110. package/dist/utils.cjs.map +1 -0
  111. package/dist/utils.d.ts +34 -1
  112. package/dist/utils.d.ts.map +1 -1
  113. package/lib/{audience.d.ts → audience.d.mts} +3 -10
  114. package/lib/audience.d.mts.map +1 -0
  115. package/lib/{audience.js → audience.mjs} +15 -17
  116. package/lib/audience.mjs.map +1 -0
  117. package/lib/catchUpMonitor.d.mts +29 -0
  118. package/lib/catchUpMonitor.d.mts.map +1 -0
  119. package/lib/catchUpMonitor.mjs +39 -0
  120. package/lib/catchUpMonitor.mjs.map +1 -0
  121. package/lib/{connectionManager.d.ts → connectionManager.d.mts} +23 -33
  122. package/lib/connectionManager.d.mts.map +1 -0
  123. package/lib/{connectionManager.js → connectionManager.mjs} +378 -218
  124. package/lib/connectionManager.mjs.map +1 -0
  125. package/lib/{connectionState.d.ts → connectionState.d.mts} +3 -5
  126. package/lib/connectionState.d.mts.map +1 -0
  127. package/lib/{connectionState.js → connectionState.mjs} +4 -6
  128. package/lib/connectionState.mjs.map +1 -0
  129. package/lib/connectionStateHandler.d.mts +179 -0
  130. package/lib/connectionStateHandler.d.mts.map +1 -0
  131. package/lib/connectionStateHandler.mjs +469 -0
  132. package/lib/connectionStateHandler.mjs.map +1 -0
  133. package/lib/container-loader-alpha.d.mts +274 -0
  134. package/lib/container-loader-beta.d.mts +75 -0
  135. package/lib/container-loader-public.d.mts +75 -0
  136. package/lib/container-loader-untrimmed.d.mts +331 -0
  137. package/lib/container.d.mts +382 -0
  138. package/lib/container.d.mts.map +1 -0
  139. package/lib/container.mjs +1579 -0
  140. package/lib/container.mjs.map +1 -0
  141. package/lib/containerContext.d.mts +58 -0
  142. package/lib/containerContext.d.mts.map +1 -0
  143. package/lib/containerContext.mjs +70 -0
  144. package/lib/containerContext.mjs.map +1 -0
  145. package/lib/containerStorageAdapter.d.mts +73 -0
  146. package/lib/containerStorageAdapter.d.mts.map +1 -0
  147. package/lib/containerStorageAdapter.mjs +228 -0
  148. package/lib/containerStorageAdapter.mjs.map +1 -0
  149. package/lib/{contracts.d.ts → contracts.d.mts} +45 -17
  150. package/lib/contracts.d.mts.map +1 -0
  151. package/lib/{contracts.js → contracts.mjs} +4 -4
  152. package/lib/contracts.mjs.map +1 -0
  153. package/lib/debugLogger.d.mts +30 -0
  154. package/lib/debugLogger.d.mts.map +1 -0
  155. package/lib/debugLogger.mjs +93 -0
  156. package/lib/debugLogger.mjs.map +1 -0
  157. package/lib/{deltaManager.d.ts → deltaManager.d.mts} +54 -18
  158. package/lib/deltaManager.d.mts.map +1 -0
  159. package/lib/{deltaManager.js → deltaManager.mjs} +361 -165
  160. package/lib/deltaManager.mjs.map +1 -0
  161. package/lib/{deltaQueue.d.ts → deltaQueue.d.mts} +3 -4
  162. package/lib/deltaQueue.d.mts.map +1 -0
  163. package/lib/{deltaQueue.js → deltaQueue.mjs} +25 -24
  164. package/lib/deltaQueue.mjs.map +1 -0
  165. package/lib/disposal.d.mts +13 -0
  166. package/lib/disposal.d.mts.map +1 -0
  167. package/lib/disposal.mjs +21 -0
  168. package/lib/disposal.mjs.map +1 -0
  169. package/lib/error.d.mts +23 -0
  170. package/lib/error.d.mts.map +1 -0
  171. package/lib/error.mjs +28 -0
  172. package/lib/error.mjs.map +1 -0
  173. package/lib/index.d.mts +11 -0
  174. package/lib/index.d.mts.map +1 -0
  175. package/lib/index.mjs +10 -0
  176. package/lib/index.mjs.map +1 -0
  177. package/lib/{loader.d.ts → loader.d.mts} +39 -20
  178. package/lib/loader.d.mts.map +1 -0
  179. package/lib/loader.mjs +143 -0
  180. package/lib/loader.mjs.map +1 -0
  181. package/lib/location-redirection-utilities/index.d.mts +6 -0
  182. package/lib/location-redirection-utilities/index.d.mts.map +1 -0
  183. package/lib/location-redirection-utilities/index.mjs +6 -0
  184. package/lib/location-redirection-utilities/index.mjs.map +1 -0
  185. package/lib/location-redirection-utilities/resolveWithLocationRedirection.d.mts +24 -0
  186. package/lib/location-redirection-utilities/resolveWithLocationRedirection.d.mts.map +1 -0
  187. package/lib/location-redirection-utilities/resolveWithLocationRedirection.mjs +48 -0
  188. package/lib/location-redirection-utilities/resolveWithLocationRedirection.mjs.map +1 -0
  189. package/lib/noopHeuristic.d.mts +23 -0
  190. package/lib/noopHeuristic.d.mts.map +1 -0
  191. package/lib/{collabWindowTracker.js → noopHeuristic.mjs} +33 -35
  192. package/lib/noopHeuristic.mjs.map +1 -0
  193. package/lib/{packageVersion.d.ts → packageVersion.d.mts} +1 -1
  194. package/lib/{packageVersion.d.ts.map → packageVersion.d.mts.map} +1 -1
  195. package/lib/{packageVersion.js → packageVersion.mjs} +2 -2
  196. package/lib/packageVersion.mjs.map +1 -0
  197. package/lib/protocol.d.mts +38 -0
  198. package/lib/protocol.d.mts.map +1 -0
  199. package/lib/protocol.mjs +94 -0
  200. package/lib/protocol.mjs.map +1 -0
  201. package/lib/{protocolTreeDocumentStorageService.d.ts → protocolTreeDocumentStorageService.d.mts} +8 -4
  202. package/lib/protocolTreeDocumentStorageService.d.mts.map +1 -0
  203. package/lib/{protocolTreeDocumentStorageService.js → protocolTreeDocumentStorageService.mjs} +8 -5
  204. package/lib/protocolTreeDocumentStorageService.mjs.map +1 -0
  205. package/lib/quorum.d.mts +4 -0
  206. package/lib/quorum.d.mts.map +1 -0
  207. package/lib/quorum.mjs +12 -0
  208. package/lib/quorum.mjs.map +1 -0
  209. package/lib/{retriableDocumentStorageService.d.ts → retriableDocumentStorageService.d.mts} +7 -5
  210. package/lib/retriableDocumentStorageService.d.mts.map +1 -0
  211. package/lib/{retriableDocumentStorageService.js → retriableDocumentStorageService.mjs} +35 -20
  212. package/lib/retriableDocumentStorageService.mjs.map +1 -0
  213. package/lib/utils.d.mts +67 -0
  214. package/lib/utils.d.mts.map +1 -0
  215. package/lib/{utils.js → utils.mjs} +47 -11
  216. package/lib/utils.mjs.map +1 -0
  217. package/package.json +163 -70
  218. package/prettier.config.cjs +8 -0
  219. package/src/audience.ts +59 -49
  220. package/src/catchUpMonitor.ts +61 -0
  221. package/src/connectionManager.ts +1154 -910
  222. package/src/connectionState.ts +22 -25
  223. package/src/connectionStateHandler.ts +689 -319
  224. package/src/container.ts +2476 -1792
  225. package/src/containerContext.ts +98 -330
  226. package/src/containerStorageAdapter.ts +301 -105
  227. package/src/contracts.ts +184 -146
  228. package/src/debugLogger.ts +123 -0
  229. package/src/deltaManager.ts +1165 -900
  230. package/src/deltaQueue.ts +156 -152
  231. package/src/disposal.ts +25 -0
  232. package/src/error.ts +44 -0
  233. package/src/index.ts +14 -15
  234. package/src/loader.ts +356 -427
  235. package/src/location-redirection-utilities/index.ts +9 -0
  236. package/src/location-redirection-utilities/resolveWithLocationRedirection.ts +61 -0
  237. package/src/noopHeuristic.ts +107 -0
  238. package/src/packageVersion.ts +1 -1
  239. package/src/protocol.ts +150 -0
  240. package/src/protocolTreeDocumentStorageService.ts +35 -35
  241. package/src/quorum.ts +11 -50
  242. package/src/retriableDocumentStorageService.ts +135 -95
  243. package/src/utils.ts +159 -86
  244. package/tsc-multi.test.json +4 -0
  245. package/tsconfig.json +10 -12
  246. package/dist/audience.js.map +0 -1
  247. package/dist/collabWindowTracker.d.ts +0 -19
  248. package/dist/collabWindowTracker.d.ts.map +0 -1
  249. package/dist/collabWindowTracker.js.map +0 -1
  250. package/dist/connectionManager.js.map +0 -1
  251. package/dist/connectionState.js.map +0 -1
  252. package/dist/connectionStateHandler.js +0 -280
  253. package/dist/connectionStateHandler.js.map +0 -1
  254. package/dist/container.js +0 -1284
  255. package/dist/container.js.map +0 -1
  256. package/dist/containerContext.js +0 -217
  257. package/dist/containerContext.js.map +0 -1
  258. package/dist/containerStorageAdapter.js +0 -104
  259. package/dist/containerStorageAdapter.js.map +0 -1
  260. package/dist/contracts.js.map +0 -1
  261. package/dist/deltaManager.js.map +0 -1
  262. package/dist/deltaManagerProxy.d.ts +0 -54
  263. package/dist/deltaManagerProxy.d.ts.map +0 -1
  264. package/dist/deltaManagerProxy.js +0 -115
  265. package/dist/deltaManagerProxy.js.map +0 -1
  266. package/dist/deltaQueue.js.map +0 -1
  267. package/dist/index.js +0 -16
  268. package/dist/index.js.map +0 -1
  269. package/dist/loader.js +0 -241
  270. package/dist/loader.js.map +0 -1
  271. package/dist/packageVersion.js.map +0 -1
  272. package/dist/protocolTreeDocumentStorageService.js.map +0 -1
  273. package/dist/quorum.js +0 -44
  274. package/dist/quorum.js.map +0 -1
  275. package/dist/retriableDocumentStorageService.js.map +0 -1
  276. package/dist/utils.js.map +0 -1
  277. package/lib/audience.d.ts.map +0 -1
  278. package/lib/audience.js.map +0 -1
  279. package/lib/collabWindowTracker.d.ts +0 -19
  280. package/lib/collabWindowTracker.d.ts.map +0 -1
  281. package/lib/collabWindowTracker.js.map +0 -1
  282. package/lib/connectionManager.d.ts.map +0 -1
  283. package/lib/connectionManager.js.map +0 -1
  284. package/lib/connectionState.d.ts.map +0 -1
  285. package/lib/connectionState.js.map +0 -1
  286. package/lib/connectionStateHandler.d.ts +0 -81
  287. package/lib/connectionStateHandler.d.ts.map +0 -1
  288. package/lib/connectionStateHandler.js +0 -276
  289. package/lib/connectionStateHandler.js.map +0 -1
  290. package/lib/container.d.ts +0 -238
  291. package/lib/container.d.ts.map +0 -1
  292. package/lib/container.js +0 -1276
  293. package/lib/container.js.map +0 -1
  294. package/lib/containerContext.d.ts +0 -84
  295. package/lib/containerContext.d.ts.map +0 -1
  296. package/lib/containerContext.js +0 -213
  297. package/lib/containerContext.js.map +0 -1
  298. package/lib/containerStorageAdapter.d.ts +0 -48
  299. package/lib/containerStorageAdapter.d.ts.map +0 -1
  300. package/lib/containerStorageAdapter.js +0 -99
  301. package/lib/containerStorageAdapter.js.map +0 -1
  302. package/lib/contracts.d.ts.map +0 -1
  303. package/lib/contracts.js.map +0 -1
  304. package/lib/deltaManager.d.ts.map +0 -1
  305. package/lib/deltaManager.js.map +0 -1
  306. package/lib/deltaManagerProxy.d.ts +0 -54
  307. package/lib/deltaManagerProxy.d.ts.map +0 -1
  308. package/lib/deltaManagerProxy.js +0 -110
  309. package/lib/deltaManagerProxy.js.map +0 -1
  310. package/lib/deltaQueue.d.ts.map +0 -1
  311. package/lib/deltaQueue.js.map +0 -1
  312. package/lib/index.d.ts +0 -8
  313. package/lib/index.d.ts.map +0 -1
  314. package/lib/index.js +0 -8
  315. package/lib/index.js.map +0 -1
  316. package/lib/loader.d.ts.map +0 -1
  317. package/lib/loader.js +0 -236
  318. package/lib/loader.js.map +0 -1
  319. package/lib/packageVersion.js.map +0 -1
  320. package/lib/protocolTreeDocumentStorageService.d.ts.map +0 -1
  321. package/lib/protocolTreeDocumentStorageService.js.map +0 -1
  322. package/lib/quorum.d.ts +0 -21
  323. package/lib/quorum.d.ts.map +0 -1
  324. package/lib/quorum.js +0 -38
  325. package/lib/quorum.js.map +0 -1
  326. package/lib/retriableDocumentStorageService.d.ts.map +0 -1
  327. package/lib/retriableDocumentStorageService.js.map +0 -1
  328. package/lib/utils.d.ts +0 -34
  329. package/lib/utils.d.ts.map +0 -1
  330. package/lib/utils.js.map +0 -1
  331. package/src/collabWindowTracker.ts +0 -102
  332. package/src/deltaManagerProxy.ts +0 -158
  333. package/tsconfig.esnext.json +0 -7
package/src/loader.ts CHANGED
@@ -4,147 +4,107 @@
4
4
  */
5
5
 
6
6
  import { v4 as uuid } from "uuid";
7
- import { ITelemetryBaseLogger, ITelemetryLogger } from "@fluidframework/common-definitions";
8
7
  import {
9
- FluidObject,
10
- IFluidRouter,
11
- IRequest,
12
- IRequestHeader,
13
- IResponse,
8
+ ITelemetryLoggerExt,
9
+ mixinMonitoringContext,
10
+ MonitoringContext,
11
+ PerformanceEvent,
12
+ sessionStorageConfigProvider,
13
+ createChildMonitoringContext,
14
+ UsageError,
15
+ } from "@fluidframework/telemetry-utils";
16
+ import {
17
+ ITelemetryBaseLogger,
18
+ FluidObject,
19
+ IRequest,
20
+ IConfigProviderBase,
14
21
  } from "@fluidframework/core-interfaces";
15
22
  import {
16
- IContainer,
17
- IFluidModule,
18
- IHostLoader,
19
- ILoader,
20
- ILoaderOptions as ILoaderOptions1,
21
- LoaderHeader,
22
- IProvideFluidCodeDetailsComparer,
23
- IFluidCodeDetails,
23
+ IContainer,
24
+ IFluidModule,
25
+ IHostLoader,
26
+ ILoader,
27
+ ILoaderOptions as ILoaderOptions1,
28
+ LoaderHeader,
29
+ IProvideFluidCodeDetailsComparer,
30
+ IFluidCodeDetails,
24
31
  } from "@fluidframework/container-definitions";
25
32
  import {
26
- ChildLogger,
27
- DebugLogger,
28
- IConfigProviderBase,
29
- loggerToMonitoringContext,
30
- mixinMonitoringContext,
31
- MonitoringContext,
32
- PerformanceEvent,
33
- sessionStorageConfigProvider,
34
- } from "@fluidframework/telemetry-utils";
35
- import {
36
- IDocumentServiceFactory,
37
- IDocumentStorageService,
38
- IFluidResolvedUrl,
39
- IResolvedUrl,
40
- IUrlResolver,
33
+ IDocumentServiceFactory,
34
+ IDocumentStorageService,
35
+ IResolvedUrl,
36
+ IUrlResolver,
41
37
  } from "@fluidframework/driver-definitions";
42
- import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
43
- import {
44
- ensureFluidResolvedUrl,
45
- MultiUrlResolver,
46
- MultiDocumentServiceFactory,
47
- } from "@fluidframework/driver-utils";
38
+ import { IClientDetails } from "@fluidframework/protocol-definitions";
48
39
  import { Container, IPendingContainerState } from "./container";
49
- import { IParsedUrl, parseUrl } from "./utils";
40
+ import { IParsedUrl, tryParseCompatibleResolvedUrl } from "./utils";
50
41
  import { pkgVersion } from "./packageVersion";
51
-
52
- function canUseCache(request: IRequest): boolean {
53
- if (request.headers === undefined) {
54
- return true;
55
- }
56
-
57
- return request.headers[LoaderHeader.cache] !== false;
42
+ import { ProtocolHandlerBuilder } from "./protocol";
43
+ import { DebugLogger } from "./debugLogger";
44
+
45
+ function ensureResolvedUrlDefined(
46
+ resolved: IResolvedUrl | undefined,
47
+ ): asserts resolved is IResolvedUrl {
48
+ if (resolved === undefined) {
49
+ throw new Error(`Object is not a IResolveUrl.`);
50
+ }
58
51
  }
59
-
52
+ /**
53
+ * @internal
54
+ */
60
55
  export class RelativeLoader implements ILoader {
61
- constructor(
62
- private readonly container: Container,
63
- private readonly loader: ILoader | undefined,
64
- ) {
65
- }
66
-
67
- public get IFluidRouter(): IFluidRouter { return this; }
68
-
69
- public async resolve(request: IRequest): Promise<IContainer> {
70
- if (request.url.startsWith("/")) {
71
- if (canUseCache(request)) {
72
- return this.container;
73
- } else {
74
- const resolvedUrl = this.container.resolvedUrl;
75
- ensureFluidResolvedUrl(resolvedUrl);
76
- const container = await Container.load(
77
- this.loader as Loader,
78
- {
79
- canReconnect: request.headers?.[LoaderHeader.reconnect],
80
- clientDetailsOverride: request.headers?.[LoaderHeader.clientDetails],
81
- resolvedUrl: { ...resolvedUrl },
82
- version: request.headers?.[LoaderHeader.version] ?? undefined,
83
- loadMode: request.headers?.[LoaderHeader.loadMode],
84
- },
85
- );
86
- return container;
87
- }
88
- }
89
-
90
- if (this.loader === undefined) {
91
- throw new Error("Cannot resolve external containers");
92
- }
93
- return this.loader.resolve(request);
94
- }
95
-
96
- public async request(request: IRequest): Promise<IResponse> {
97
- if (request.url.startsWith("/")) {
98
- const container = await this.resolve(request);
99
- return container.request(request);
100
- }
101
-
102
- if (this.loader === undefined) {
103
- return {
104
- status: 404,
105
- value: "Cannot request external containers",
106
- mimeType: "plain/text",
107
- };
108
- }
109
- return this.loader.request(request);
110
- }
111
- }
112
-
113
- function createCachedResolver(resolver: IUrlResolver) {
114
- const cacheResolver = Object.create(resolver) as IUrlResolver;
115
- const resolveCache = new Map<string, Promise<IResolvedUrl | undefined>>();
116
- cacheResolver.resolve = async (request: IRequest): Promise<IResolvedUrl | undefined> => {
117
- if (!canUseCache(request)) {
118
- return resolver.resolve(request);
119
- }
120
- if (!resolveCache.has(request.url)) {
121
- resolveCache.set(request.url, resolver.resolve(request));
122
- }
123
-
124
- return resolveCache.get(request.url);
125
- };
126
- return cacheResolver;
56
+ constructor(
57
+ private readonly container: Container,
58
+ private readonly loader: ILoader | undefined,
59
+ ) {}
60
+
61
+ public async resolve(request: IRequest): Promise<IContainer> {
62
+ if (request.url.startsWith("/")) {
63
+ ensureResolvedUrlDefined(this.container.resolvedUrl);
64
+ const container = await this.container.clone(
65
+ {
66
+ resolvedUrl: { ...this.container.resolvedUrl },
67
+ version: request.headers?.[LoaderHeader.version] ?? undefined,
68
+ loadMode: request.headers?.[LoaderHeader.loadMode],
69
+ },
70
+ {
71
+ canReconnect: request.headers?.[LoaderHeader.reconnect],
72
+ clientDetailsOverride: request.headers?.[LoaderHeader.clientDetails],
73
+ },
74
+ );
75
+ return container;
76
+ }
77
+
78
+ if (this.loader === undefined) {
79
+ throw new Error("Cannot resolve external containers");
80
+ }
81
+ return this.loader.resolve(request);
82
+ }
127
83
  }
128
84
 
85
+ /**
86
+ * @alpha
87
+ */
129
88
  export interface ILoaderOptions extends ILoaderOptions1 {
130
- summarizeProtocolTree?: boolean;
89
+ summarizeProtocolTree?: boolean;
131
90
  }
132
91
 
133
92
  /**
134
93
  * @deprecated IFluidModuleWithDetails interface is moved to
135
- * {@link @fluidframework/container-definition#IFluidModuleWithDetails}
94
+ * {@link @fluidframework/container-definitions#IFluidModuleWithDetails}
136
95
  * to have all the code loading modules in one package. #8193
137
96
  * Encapsulates a module entry point with corresponding code details.
97
+ * @alpha
138
98
  */
139
99
  export interface IFluidModuleWithDetails {
140
- /** Fluid code module that implements the runtime factory needed to instantiate the container runtime. */
141
- module: IFluidModule;
142
- /**
143
- * Code details associated with the module. Represents a document schema this module supports.
144
- * If the code loader implements the {@link @fluidframework/core-interfaces#IFluidCodeDetailsComparer} interface,
145
- * it'll be called to determine whether the module code details satisfy the new code proposal in the quorum.
146
- */
147
- details: IFluidCodeDetails;
100
+ /** Fluid code module that implements the runtime factory needed to instantiate the container runtime. */
101
+ module: IFluidModule;
102
+ /**
103
+ * Code details associated with the module. Represents a document schema this module supports.
104
+ * If the code loader implements the {@link @fluidframework/core-interfaces#IFluidCodeDetailsComparer} interface,
105
+ * it'll be called to determine whether the module code details satisfy the new code proposal in the quorum.
106
+ */
107
+ details: IFluidCodeDetails;
148
108
  }
149
109
 
150
110
  /**
@@ -152,336 +112,305 @@ export interface IFluidModuleWithDetails {
152
112
  * to have code loading modules in one package. #8193
153
113
  * Fluid code loader resolves a code module matching the document schema, i.e. code details, such as
154
114
  * a package name and package version range.
115
+ * @alpha
155
116
  */
156
- export interface ICodeDetailsLoader
157
- extends Partial<IProvideFluidCodeDetailsComparer> {
158
- /**
159
- * Load the code module (package) that is capable to interact with the document.
160
- *
161
- * @param source - Code proposal that articulates the current schema the document is written in.
162
- * @returns - Code module entry point along with the code details associated with it.
163
- */
164
- load(source: IFluidCodeDetails): Promise<IFluidModuleWithDetails>;
117
+ export interface ICodeDetailsLoader extends Partial<IProvideFluidCodeDetailsComparer> {
118
+ /**
119
+ * Load the code module (package) that is capable to interact with the document.
120
+ *
121
+ * @param source - Code proposal that articulates the current schema the document is written in.
122
+ * @returns Code module entry point along with the code details associated with it.
123
+ */
124
+ load(source: IFluidCodeDetails): Promise<IFluidModuleWithDetails>;
165
125
  }
166
126
 
167
127
  /**
168
128
  * Services and properties necessary for creating a loader
129
+ * @alpha
169
130
  */
170
131
  export interface ILoaderProps {
171
- /**
172
- * The url resolver used by the loader for resolving external urls
173
- * into Fluid urls such that the container specified by the
174
- * external url can be loaded.
175
- */
176
- readonly urlResolver: IUrlResolver;
177
- /**
178
- * The document service factory take the Fluid url provided
179
- * by the resolved url and constructs all the necessary services
180
- * for communication with the container's server.
181
- */
182
- readonly documentServiceFactory: IDocumentServiceFactory;
183
- /**
184
- * The code loader handles loading the necessary code
185
- * for running a container once it is loaded.
186
- */
187
- readonly codeLoader: ICodeDetailsLoader;
188
-
189
- /**
190
- * A property bag of options used by various layers
191
- * to control features
192
- */
193
- readonly options?: ILoaderOptions;
194
-
195
- /**
196
- * Scope is provided to all container and is a set of shared
197
- * services for container's to integrate with their host environment.
198
- */
199
- readonly scope?: FluidObject;
200
-
201
- /**
202
- * The logger that all telemetry should be pushed to.
203
- */
204
- readonly logger?: ITelemetryBaseLogger;
205
-
206
- /**
207
- * Blobs storage for detached containers.
208
- */
209
- readonly detachedBlobStorage?: IDetachedBlobStorage;
210
-
211
- /**
212
- * The configuration provider which may be used to control features.
213
- */
214
- readonly configProvider?: IConfigProviderBase;
132
+ /**
133
+ * The url resolver used by the loader for resolving external urls
134
+ * into Fluid urls such that the container specified by the
135
+ * external url can be loaded.
136
+ */
137
+ readonly urlResolver: IUrlResolver;
138
+ /**
139
+ * The document service factory take the Fluid url provided
140
+ * by the resolved url and constructs all the necessary services
141
+ * for communication with the container's server.
142
+ */
143
+ readonly documentServiceFactory: IDocumentServiceFactory;
144
+ /**
145
+ * The code loader handles loading the necessary code
146
+ * for running a container once it is loaded.
147
+ */
148
+ readonly codeLoader: ICodeDetailsLoader;
149
+
150
+ /**
151
+ * A property bag of options used by various layers
152
+ * to control features
153
+ */
154
+ readonly options?: ILoaderOptions;
155
+
156
+ /**
157
+ * Scope is provided to all container and is a set of shared
158
+ * services for container's to integrate with their host environment.
159
+ */
160
+ readonly scope?: FluidObject;
161
+
162
+ /**
163
+ * The logger that all telemetry should be pushed to.
164
+ */
165
+ readonly logger?: ITelemetryBaseLogger;
166
+
167
+ /**
168
+ * Blobs storage for detached containers.
169
+ */
170
+ readonly detachedBlobStorage?: IDetachedBlobStorage;
171
+
172
+ /**
173
+ * The configuration provider which may be used to control features.
174
+ */
175
+ readonly configProvider?: IConfigProviderBase;
176
+
177
+ /**
178
+ * Optional property for allowing the container to use a custom
179
+ * protocol implementation for handling the quorum and/or the audience.
180
+ */
181
+ readonly protocolHandlerBuilder?: ProtocolHandlerBuilder;
215
182
  }
216
183
 
217
184
  /**
218
185
  * Services and properties used by and exposed by the loader
186
+ * @alpha
219
187
  */
220
188
  export interface ILoaderServices {
221
- /**
222
- * The url resolver used by the loader for resolving external urls
223
- * into Fluid urls such that the container specified by the
224
- * external url can be loaded.
225
- */
226
- readonly urlResolver: IUrlResolver;
227
- /**
228
- * The document service factory take the Fluid url provided
229
- * by the resolved url and constructs all the necessary services
230
- * for communication with the container's server.
231
- */
232
- readonly documentServiceFactory: IDocumentServiceFactory;
233
- /**
234
- * The code loader handles loading the necessary code
235
- * for running a container once it is loaded.
236
- */
237
- readonly codeLoader: ICodeDetailsLoader;
238
-
239
- /**
240
- * A property bag of options used by various layers
241
- * to control features
242
- */
243
- readonly options: ILoaderOptions;
244
-
245
- /**
246
- * Scope is provided to all container and is a set of shared
247
- * services for container's to integrate with their host environment.
248
- */
249
- readonly scope: FluidObject;
250
-
251
- /**
252
- * The logger downstream consumers should construct their loggers from
253
- */
254
- readonly subLogger: ITelemetryLogger;
255
-
256
- /**
257
- * Blobs storage for detached containers.
258
- */
259
- readonly detachedBlobStorage?: IDetachedBlobStorage;
189
+ /**
190
+ * The url resolver used by the loader for resolving external urls
191
+ * into Fluid urls such that the container specified by the
192
+ * external url can be loaded.
193
+ */
194
+ readonly urlResolver: IUrlResolver;
195
+ /**
196
+ * The document service factory take the Fluid url provided
197
+ * by the resolved url and constructs all the necessary services
198
+ * for communication with the container's server.
199
+ */
200
+ readonly documentServiceFactory: IDocumentServiceFactory;
201
+ /**
202
+ * The code loader handles loading the necessary code
203
+ * for running a container once it is loaded.
204
+ */
205
+ readonly codeLoader: ICodeDetailsLoader;
206
+
207
+ /**
208
+ * A property bag of options used by various layers
209
+ * to control features
210
+ */
211
+ readonly options: ILoaderOptions;
212
+
213
+ /**
214
+ * Scope is provided to all container and is a set of shared
215
+ * services for container's to integrate with their host environment.
216
+ */
217
+ readonly scope: FluidObject;
218
+
219
+ /**
220
+ * The logger downstream consumers should construct their loggers from
221
+ */
222
+ readonly subLogger: ITelemetryLoggerExt;
223
+
224
+ /**
225
+ * Blobs storage for detached containers.
226
+ */
227
+ readonly detachedBlobStorage?: IDetachedBlobStorage;
228
+
229
+ /**
230
+ * Optional property for allowing the container to use a custom
231
+ * protocol implementation for handling the quorum and/or the audience.
232
+ */
233
+ readonly protocolHandlerBuilder?: ProtocolHandlerBuilder;
260
234
  }
261
235
 
262
236
  /**
263
237
  * Subset of IDocumentStorageService which only supports createBlob() and readBlob(). This is used to support
264
238
  * blobs in detached containers.
239
+ * @alpha
265
240
  */
266
241
  export type IDetachedBlobStorage = Pick<IDocumentStorageService, "createBlob" | "readBlob"> & {
267
- size: number;
268
- /**
269
- * Return an array of all blob IDs present in storage
270
- */
271
- getBlobIds(): string[];
272
- };
242
+ size: number;
243
+ /**
244
+ * Return an array of all blob IDs present in storage
245
+ */
246
+ getBlobIds(): string[];
247
+ };
273
248
 
274
249
  /**
275
250
  * Manages Fluid resource loading
251
+ * @alpha
276
252
  */
277
253
  export class Loader implements IHostLoader {
278
- private readonly containers = new Map<string, Promise<Container>>();
279
- public readonly services: ILoaderServices;
280
- private readonly mc: MonitoringContext;
281
-
282
- constructor(loaderProps: ILoaderProps) {
283
- const scope: FluidObject<ILoader> = { ...loaderProps.scope };
284
- if (loaderProps.options?.provideScopeLoader !== false) {
285
- scope.ILoader = this;
286
- }
287
- const telemetryProps = {
288
- loaderId: uuid(),
289
- loaderVersion: pkgVersion,
290
- };
291
-
292
- const subMc = mixinMonitoringContext(
293
- DebugLogger.mixinDebugLogger("fluid:telemetry", loaderProps.logger, { all: telemetryProps }),
294
- sessionStorageConfigProvider.value,
295
- loaderProps.configProvider,
296
- );
297
-
298
- this.services = {
299
- urlResolver: createCachedResolver(MultiUrlResolver.create(loaderProps.urlResolver)),
300
- documentServiceFactory: MultiDocumentServiceFactory.create(loaderProps.documentServiceFactory),
301
- codeLoader: loaderProps.codeLoader,
302
- options: loaderProps.options ?? {},
303
- scope,
304
- subLogger: subMc.logger,
305
- detachedBlobStorage: loaderProps.detachedBlobStorage,
306
- };
307
- this.mc = loggerToMonitoringContext(
308
- ChildLogger.create(this.services.subLogger, "Loader"));
309
- }
310
-
311
- public get IFluidRouter(): IFluidRouter { return this; }
312
-
313
- public async createDetachedContainer(codeDetails: IFluidCodeDetails): Promise<IContainer> {
314
- const container = await Container.createDetached(
315
- this,
316
- codeDetails,
317
- );
318
-
319
- if (this.cachingEnabled) {
320
- container.once("attached", () => {
321
- ensureFluidResolvedUrl(container.resolvedUrl);
322
- const parsedUrl = parseUrl(container.resolvedUrl.url);
323
- if (parsedUrl !== undefined) {
324
- this.addToContainerCache(parsedUrl.id, Promise.resolve(container));
325
- }
326
- });
327
- }
328
-
329
- return container;
330
- }
331
-
332
- public async rehydrateDetachedContainerFromSnapshot(snapshot: string): Promise<IContainer> {
333
- return Container.rehydrateDetachedFromSnapshot(this, snapshot);
334
- }
335
-
336
- public async resolve(request: IRequest, pendingLocalState?: string): Promise<IContainer> {
337
- const eventName = pendingLocalState === undefined ? "Resolve" : "ResolveWithPendingState";
338
- return PerformanceEvent.timedExecAsync(this.mc.logger, { eventName }, async () => {
339
- const resolved = await this.resolveCore(
340
- request,
341
- pendingLocalState !== undefined ? JSON.parse(pendingLocalState) : undefined,
342
- );
343
- return resolved.container;
344
- });
345
- }
346
-
347
- public async request(request: IRequest): Promise<IResponse> {
348
- return PerformanceEvent.timedExecAsync(this.mc.logger, { eventName: "Request" }, async () => {
349
- const resolved = await this.resolveCore(request);
350
- return resolved.container.request({
351
- ...request,
352
- url: `${resolved.parsed.path}${resolved.parsed.query}`,
353
- });
354
- });
355
- }
356
-
357
- private getKeyForContainerCache(request: IRequest, parsedUrl: IParsedUrl): string {
358
- const key = request.headers?.[LoaderHeader.version] !== undefined
359
- ? `${parsedUrl.id}@${request.headers[LoaderHeader.version]}`
360
- : parsedUrl.id;
361
- return key;
362
- }
363
-
364
- private addToContainerCache(key: string, containerP: Promise<Container>) {
365
- this.containers.set(key, containerP);
366
- containerP.then((container) => {
367
- // If the container is closed or becomes closed after we resolve it, remove it from the cache.
368
- if (container.closed) {
369
- this.containers.delete(key);
370
- } else {
371
- container.once("closed", () => {
372
- this.containers.delete(key);
373
- });
374
- }
375
- }).catch((error) => {});
376
- }
377
-
378
- private async resolveCore(
379
- request: IRequest,
380
- pendingLocalState?: IPendingContainerState,
381
- ): Promise<{ container: Container; parsed: IParsedUrl; }> {
382
- const resolvedAsFluid = await this.services.urlResolver.resolve(request);
383
- ensureFluidResolvedUrl(resolvedAsFluid);
384
-
385
- // Parse URL into data stores
386
- const parsed = parseUrl(resolvedAsFluid.url);
387
- if (parsed === undefined) {
388
- throw new Error(`Invalid URL ${resolvedAsFluid.url}`);
389
- }
390
-
391
- if (pendingLocalState !== undefined) {
392
- const parsedPendingUrl = parseUrl(pendingLocalState.url);
393
- if (parsedPendingUrl?.id !== parsed.id ||
394
- parsedPendingUrl?.path.replace(/\/$/, "") !== parsed.path.replace(/\/$/, "")) {
395
- const message = `URL ${resolvedAsFluid.url} does not match pending state URL ${pendingLocalState.url}`;
396
- throw new Error(message);
397
- }
398
- }
399
-
400
- const { canCache, fromSequenceNumber } = this.parseHeader(parsed, request);
401
- const shouldCache = pendingLocalState !== undefined ? false : canCache;
402
-
403
- let container: Container;
404
- if (shouldCache) {
405
- const key = this.getKeyForContainerCache(request, parsed);
406
- const maybeContainer = await this.containers.get(key);
407
- if (maybeContainer !== undefined) {
408
- container = maybeContainer;
409
- } else {
410
- const containerP =
411
- this.loadContainer(
412
- request,
413
- resolvedAsFluid);
414
- this.addToContainerCache(key, containerP);
415
- container = await containerP;
416
- }
417
- } else {
418
- container =
419
- await this.loadContainer(
420
- request,
421
- resolvedAsFluid,
422
- pendingLocalState);
423
- }
424
-
425
- if (container.deltaManager.lastSequenceNumber <= fromSequenceNumber) {
426
- await new Promise<void>((resolve, reject) => {
427
- function opHandler(message: ISequencedDocumentMessage) {
428
- if (message.sequenceNumber > fromSequenceNumber) {
429
- resolve();
430
- container.removeListener("op", opHandler);
431
- }
432
- }
433
-
434
- container.on("op", opHandler);
435
- });
436
- }
437
-
438
- return { container, parsed };
439
- }
440
-
441
- private get cachingEnabled() {
442
- return this.services.options.cache !== false;
443
- }
444
-
445
- private canCacheForRequest(headers: IRequestHeader): boolean {
446
- return this.cachingEnabled && headers[LoaderHeader.cache] !== false;
447
- }
448
-
449
- private parseHeader(parsed: IParsedUrl, request: IRequest) {
450
- let fromSequenceNumber = -1;
451
-
452
- request.headers = request.headers ?? {};
453
-
454
- const headerSeqNum = request.headers[LoaderHeader.sequenceNumber];
455
- if (headerSeqNum !== undefined) {
456
- fromSequenceNumber = headerSeqNum;
457
- }
458
-
459
- // If set in both query string and headers, use query string
460
- request.headers[LoaderHeader.version] = parsed.version ?? request.headers[LoaderHeader.version];
461
-
462
- const canCache = this.canCacheForRequest(request.headers);
463
-
464
- return {
465
- canCache,
466
- fromSequenceNumber,
467
- };
468
- }
469
-
470
- private async loadContainer(
471
- request: IRequest,
472
- resolved: IFluidResolvedUrl,
473
- pendingLocalState?: IPendingContainerState,
474
- ): Promise<Container> {
475
- return Container.load(
476
- this,
477
- {
478
- canReconnect: request.headers?.[LoaderHeader.reconnect],
479
- clientDetailsOverride: request.headers?.[LoaderHeader.clientDetails],
480
- resolvedUrl: resolved,
481
- version: request.headers?.[LoaderHeader.version] ?? undefined,
482
- loadMode: request.headers?.[LoaderHeader.loadMode],
483
- },
484
- pendingLocalState,
485
- );
486
- }
254
+ public readonly services: ILoaderServices;
255
+ private readonly mc: MonitoringContext;
256
+
257
+ constructor(loaderProps: ILoaderProps) {
258
+ const {
259
+ urlResolver,
260
+ documentServiceFactory,
261
+ codeLoader,
262
+ options,
263
+ scope,
264
+ logger,
265
+ detachedBlobStorage,
266
+ configProvider,
267
+ protocolHandlerBuilder,
268
+ } = loaderProps;
269
+
270
+ const telemetryProps = {
271
+ loaderId: uuid(),
272
+ loaderVersion: pkgVersion,
273
+ };
274
+
275
+ const subMc = mixinMonitoringContext(
276
+ DebugLogger.mixinDebugLogger("fluid:telemetry", logger, {
277
+ all: telemetryProps,
278
+ }),
279
+ sessionStorageConfigProvider.value,
280
+ configProvider,
281
+ );
282
+
283
+ this.services = {
284
+ urlResolver,
285
+ documentServiceFactory,
286
+ codeLoader,
287
+ options: options ?? {},
288
+ scope:
289
+ options?.provideScopeLoader !== false ? { ...scope, ILoader: this } : { ...scope },
290
+ detachedBlobStorage,
291
+ protocolHandlerBuilder,
292
+ subLogger: subMc.logger,
293
+ };
294
+ this.mc = createChildMonitoringContext({
295
+ logger: this.services.subLogger,
296
+ namespace: "Loader",
297
+ });
298
+ }
299
+
300
+ public async createDetachedContainer(
301
+ codeDetails: IFluidCodeDetails,
302
+ createDetachedProps?: {
303
+ canReconnect?: boolean;
304
+ clientDetailsOverride?: IClientDetails;
305
+ },
306
+ ): Promise<IContainer> {
307
+ return Container.createDetached(
308
+ {
309
+ ...createDetachedProps,
310
+ ...this.services,
311
+ },
312
+ codeDetails,
313
+ );
314
+ }
315
+
316
+ public async rehydrateDetachedContainerFromSnapshot(
317
+ snapshot: string,
318
+ createDetachedProps?: {
319
+ canReconnect?: boolean;
320
+ clientDetailsOverride?: IClientDetails;
321
+ },
322
+ ): Promise<IContainer> {
323
+ return Container.rehydrateDetachedFromSnapshot(
324
+ {
325
+ ...createDetachedProps,
326
+ ...this.services,
327
+ },
328
+ snapshot,
329
+ );
330
+ }
331
+
332
+ public async resolve(request: IRequest, pendingLocalState?: string): Promise<IContainer> {
333
+ const eventName = pendingLocalState === undefined ? "Resolve" : "ResolveWithPendingState";
334
+ return PerformanceEvent.timedExecAsync(this.mc.logger, { eventName }, async () => {
335
+ const resolved = await this.resolveCore(
336
+ request,
337
+ pendingLocalState !== undefined ? JSON.parse(pendingLocalState) : undefined,
338
+ );
339
+ return resolved.container;
340
+ });
341
+ }
342
+
343
+ private async resolveCore(
344
+ request: IRequest,
345
+ pendingLocalState?: IPendingContainerState,
346
+ ): Promise<{ container: Container; parsed: IParsedUrl }> {
347
+ const resolvedAsFluid = await this.services.urlResolver.resolve(request);
348
+ ensureResolvedUrlDefined(resolvedAsFluid);
349
+
350
+ // Parse URL into data stores
351
+ const parsed = tryParseCompatibleResolvedUrl(resolvedAsFluid.url);
352
+ if (parsed === undefined) {
353
+ throw new Error(`Invalid URL ${resolvedAsFluid.url}`);
354
+ }
355
+
356
+ if (pendingLocalState !== undefined) {
357
+ const parsedPendingUrl = tryParseCompatibleResolvedUrl(pendingLocalState.url);
358
+ if (
359
+ parsedPendingUrl?.id !== parsed.id ||
360
+ parsedPendingUrl?.path.replace(/\/$/, "") !== parsed.path.replace(/\/$/, "")
361
+ ) {
362
+ const message = `URL ${resolvedAsFluid.url} does not match pending state URL ${pendingLocalState.url}`;
363
+ throw new Error(message);
364
+ }
365
+ }
366
+
367
+ request.headers ??= {};
368
+ // If set in both query string and headers, use query string. Also write the value from the query string into the header either way.
369
+ request.headers[LoaderHeader.version] =
370
+ parsed.version ?? request.headers[LoaderHeader.version];
371
+ const fromSequenceNumber = request.headers[LoaderHeader.sequenceNumber] as
372
+ | number
373
+ | undefined;
374
+ const opsBeforeReturn = request.headers[LoaderHeader.loadMode]?.opsBeforeReturn as
375
+ | string
376
+ | undefined;
377
+
378
+ if (
379
+ opsBeforeReturn === "sequenceNumber" &&
380
+ (fromSequenceNumber === undefined || fromSequenceNumber < 0)
381
+ ) {
382
+ // If opsBeforeReturn is set to "sequenceNumber", then fromSequenceNumber should be set to a non-negative integer.
383
+ throw new UsageError("sequenceNumber must be set to a non-negative integer");
384
+ } else if (opsBeforeReturn !== "sequenceNumber" && fromSequenceNumber !== undefined) {
385
+ // If opsBeforeReturn is not set to "sequenceNumber", then fromSequenceNumber should be undefined (default value).
386
+ // In this case, we should throw an error since opsBeforeReturn is not explicitly set to "sequenceNumber".
387
+ throw new UsageError('opsBeforeReturn must be set to "sequenceNumber"');
388
+ }
389
+
390
+ return {
391
+ container: await this.loadContainer(request, resolvedAsFluid, pendingLocalState),
392
+ parsed,
393
+ };
394
+ }
395
+
396
+ private async loadContainer(
397
+ request: IRequest,
398
+ resolvedUrl: IResolvedUrl,
399
+ pendingLocalState?: IPendingContainerState,
400
+ ): Promise<Container> {
401
+ return Container.load(
402
+ {
403
+ resolvedUrl,
404
+ version: request.headers?.[LoaderHeader.version] ?? undefined,
405
+ loadMode: request.headers?.[LoaderHeader.loadMode],
406
+ pendingLocalState,
407
+ loadToSequenceNumber: request.headers?.[LoaderHeader.sequenceNumber],
408
+ },
409
+ {
410
+ canReconnect: request.headers?.[LoaderHeader.reconnect],
411
+ clientDetailsOverride: request.headers?.[LoaderHeader.clientDetails],
412
+ ...this.services,
413
+ },
414
+ );
415
+ }
487
416
  }