@fluidframework/container-loader 2.0.0-dev.4.4.0.162574 → 2.0.0-dev.5.3.2.178189

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 (179) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/README.md +27 -3
  3. package/dist/catchUpMonitor.d.ts +1 -1
  4. package/dist/catchUpMonitor.d.ts.map +1 -1
  5. package/dist/catchUpMonitor.js.map +1 -1
  6. package/dist/connectionManager.d.ts +3 -2
  7. package/dist/connectionManager.d.ts.map +1 -1
  8. package/dist/connectionManager.js +32 -13
  9. package/dist/connectionManager.js.map +1 -1
  10. package/dist/connectionStateHandler.d.ts +18 -3
  11. package/dist/connectionStateHandler.d.ts.map +1 -1
  12. package/dist/connectionStateHandler.js +34 -9
  13. package/dist/connectionStateHandler.js.map +1 -1
  14. package/dist/container.d.ts +99 -70
  15. package/dist/container.d.ts.map +1 -1
  16. package/dist/container.js +260 -218
  17. package/dist/container.js.map +1 -1
  18. package/dist/containerContext.d.ts +24 -67
  19. package/dist/containerContext.d.ts.map +1 -1
  20. package/dist/containerContext.js +28 -217
  21. package/dist/containerContext.js.map +1 -1
  22. package/dist/containerStorageAdapter.d.ts +3 -3
  23. package/dist/containerStorageAdapter.d.ts.map +1 -1
  24. package/dist/containerStorageAdapter.js +29 -6
  25. package/dist/containerStorageAdapter.js.map +1 -1
  26. package/dist/contracts.d.ts +9 -3
  27. package/dist/contracts.d.ts.map +1 -1
  28. package/dist/contracts.js.map +1 -1
  29. package/dist/deltaManager.d.ts +22 -9
  30. package/dist/deltaManager.d.ts.map +1 -1
  31. package/dist/deltaManager.js +42 -31
  32. package/dist/deltaManager.js.map +1 -1
  33. package/dist/deltaQueue.d.ts +2 -3
  34. package/dist/deltaQueue.d.ts.map +1 -1
  35. package/dist/deltaQueue.js +2 -3
  36. package/dist/deltaQueue.js.map +1 -1
  37. package/dist/disposal.d.ts +13 -0
  38. package/dist/disposal.d.ts.map +1 -0
  39. package/dist/disposal.js +25 -0
  40. package/dist/disposal.js.map +1 -0
  41. package/dist/index.d.ts +1 -2
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js.map +1 -1
  44. package/dist/loader.d.ts +9 -8
  45. package/dist/loader.d.ts.map +1 -1
  46. package/dist/loader.js +47 -61
  47. package/dist/loader.js.map +1 -1
  48. package/dist/noopHeuristic.d.ts +23 -0
  49. package/dist/noopHeuristic.d.ts.map +1 -0
  50. package/dist/{collabWindowTracker.js → noopHeuristic.js} +30 -42
  51. package/dist/noopHeuristic.js.map +1 -0
  52. package/dist/packageVersion.d.ts +1 -1
  53. package/dist/packageVersion.js +1 -1
  54. package/dist/packageVersion.js.map +1 -1
  55. package/dist/protocol.d.ts +7 -12
  56. package/dist/protocol.d.ts.map +1 -1
  57. package/dist/protocol.js +17 -19
  58. package/dist/protocol.js.map +1 -1
  59. package/dist/protocolTreeDocumentStorageService.d.ts +1 -1
  60. package/dist/protocolTreeDocumentStorageService.d.ts.map +1 -1
  61. package/dist/protocolTreeDocumentStorageService.js.map +1 -1
  62. package/dist/quorum.d.ts +1 -17
  63. package/dist/quorum.d.ts.map +1 -1
  64. package/dist/quorum.js +1 -17
  65. package/dist/quorum.js.map +1 -1
  66. package/dist/retriableDocumentStorageService.d.ts +3 -2
  67. package/dist/retriableDocumentStorageService.d.ts.map +1 -1
  68. package/dist/retriableDocumentStorageService.js.map +1 -1
  69. package/dist/tsdoc-metadata.json +11 -0
  70. package/dist/utils.d.ts +2 -0
  71. package/dist/utils.d.ts.map +1 -1
  72. package/dist/utils.js +8 -1
  73. package/dist/utils.js.map +1 -1
  74. package/lib/catchUpMonitor.d.ts +1 -1
  75. package/lib/catchUpMonitor.d.ts.map +1 -1
  76. package/lib/catchUpMonitor.js.map +1 -1
  77. package/lib/connectionManager.d.ts +3 -2
  78. package/lib/connectionManager.d.ts.map +1 -1
  79. package/lib/connectionManager.js +33 -14
  80. package/lib/connectionManager.js.map +1 -1
  81. package/lib/connectionStateHandler.d.ts +18 -3
  82. package/lib/connectionStateHandler.d.ts.map +1 -1
  83. package/lib/connectionStateHandler.js +35 -10
  84. package/lib/connectionStateHandler.js.map +1 -1
  85. package/lib/container.d.ts +99 -70
  86. package/lib/container.d.ts.map +1 -1
  87. package/lib/container.js +264 -222
  88. package/lib/container.js.map +1 -1
  89. package/lib/containerContext.d.ts +24 -67
  90. package/lib/containerContext.d.ts.map +1 -1
  91. package/lib/containerContext.js +28 -217
  92. package/lib/containerContext.js.map +1 -1
  93. package/lib/containerStorageAdapter.d.ts +3 -3
  94. package/lib/containerStorageAdapter.d.ts.map +1 -1
  95. package/lib/containerStorageAdapter.js +29 -6
  96. package/lib/containerStorageAdapter.js.map +1 -1
  97. package/lib/contracts.d.ts +9 -3
  98. package/lib/contracts.d.ts.map +1 -1
  99. package/lib/contracts.js.map +1 -1
  100. package/lib/deltaManager.d.ts +22 -9
  101. package/lib/deltaManager.d.ts.map +1 -1
  102. package/lib/deltaManager.js +44 -33
  103. package/lib/deltaManager.js.map +1 -1
  104. package/lib/deltaQueue.d.ts +2 -3
  105. package/lib/deltaQueue.d.ts.map +1 -1
  106. package/lib/deltaQueue.js +2 -3
  107. package/lib/deltaQueue.js.map +1 -1
  108. package/lib/disposal.d.ts +13 -0
  109. package/lib/disposal.d.ts.map +1 -0
  110. package/lib/disposal.js +21 -0
  111. package/lib/disposal.js.map +1 -0
  112. package/lib/index.d.ts +1 -2
  113. package/lib/index.d.ts.map +1 -1
  114. package/lib/index.js +1 -1
  115. package/lib/index.js.map +1 -1
  116. package/lib/loader.d.ts +9 -8
  117. package/lib/loader.d.ts.map +1 -1
  118. package/lib/loader.js +47 -61
  119. package/lib/loader.js.map +1 -1
  120. package/lib/noopHeuristic.d.ts +23 -0
  121. package/lib/noopHeuristic.d.ts.map +1 -0
  122. package/lib/{collabWindowTracker.js → noopHeuristic.js} +30 -42
  123. package/lib/noopHeuristic.js.map +1 -0
  124. package/lib/packageVersion.d.ts +1 -1
  125. package/lib/packageVersion.js +1 -1
  126. package/lib/packageVersion.js.map +1 -1
  127. package/lib/protocol.d.ts +7 -12
  128. package/lib/protocol.d.ts.map +1 -1
  129. package/lib/protocol.js +15 -18
  130. package/lib/protocol.js.map +1 -1
  131. package/lib/protocolTreeDocumentStorageService.d.ts +1 -1
  132. package/lib/protocolTreeDocumentStorageService.d.ts.map +1 -1
  133. package/lib/protocolTreeDocumentStorageService.js.map +1 -1
  134. package/lib/quorum.d.ts +1 -17
  135. package/lib/quorum.d.ts.map +1 -1
  136. package/lib/quorum.js +1 -16
  137. package/lib/quorum.js.map +1 -1
  138. package/lib/retriableDocumentStorageService.d.ts +3 -2
  139. package/lib/retriableDocumentStorageService.d.ts.map +1 -1
  140. package/lib/retriableDocumentStorageService.js.map +1 -1
  141. package/lib/utils.d.ts +2 -0
  142. package/lib/utils.d.ts.map +1 -1
  143. package/lib/utils.js +7 -1
  144. package/lib/utils.js.map +1 -1
  145. package/package.json +22 -20
  146. package/src/catchUpMonitor.ts +1 -1
  147. package/src/connectionManager.ts +40 -22
  148. package/src/connectionStateHandler.ts +66 -17
  149. package/src/container.ts +464 -292
  150. package/src/containerContext.ts +33 -341
  151. package/src/containerStorageAdapter.ts +40 -10
  152. package/src/contracts.ts +11 -3
  153. package/src/deltaManager.ts +74 -45
  154. package/src/deltaQueue.ts +2 -3
  155. package/src/disposal.ts +25 -0
  156. package/src/index.ts +1 -8
  157. package/src/loader.ts +85 -83
  158. package/src/{collabWindowTracker.ts → noopHeuristic.ts} +37 -47
  159. package/src/packageVersion.ts +1 -1
  160. package/src/protocol.ts +18 -39
  161. package/src/protocolTreeDocumentStorageService.ts +1 -1
  162. package/src/quorum.ts +2 -31
  163. package/src/retriableDocumentStorageService.ts +4 -2
  164. package/src/utils.ts +15 -1
  165. package/dist/collabWindowTracker.d.ts +0 -19
  166. package/dist/collabWindowTracker.d.ts.map +0 -1
  167. package/dist/collabWindowTracker.js.map +0 -1
  168. package/dist/deltaManagerProxy.d.ts +0 -42
  169. package/dist/deltaManagerProxy.d.ts.map +0 -1
  170. package/dist/deltaManagerProxy.js +0 -79
  171. package/dist/deltaManagerProxy.js.map +0 -1
  172. package/lib/collabWindowTracker.d.ts +0 -19
  173. package/lib/collabWindowTracker.d.ts.map +0 -1
  174. package/lib/collabWindowTracker.js.map +0 -1
  175. package/lib/deltaManagerProxy.d.ts +0 -42
  176. package/lib/deltaManagerProxy.d.ts.map +0 -1
  177. package/lib/deltaManagerProxy.js +0 -74
  178. package/lib/deltaManagerProxy.js.map +0 -1
  179. package/src/deltaManagerProxy.ts +0 -109
@@ -3,165 +3,66 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { ITelemetryLogger } from "@fluidframework/common-definitions";
7
- import { assert, LazyPromise, TypedEventEmitter } from "@fluidframework/common-utils";
6
+ import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
8
7
  import {
9
8
  IAudience,
10
9
  IContainerContext,
11
10
  IDeltaManager,
12
11
  ILoader,
13
- IRuntime,
14
12
  ICriticalContainerError,
15
13
  AttachState,
16
14
  ILoaderOptions,
17
- IRuntimeFactory,
18
- IProvideRuntimeFactory,
19
15
  IFluidCodeDetails,
20
- IFluidCodeDetailsComparer,
21
- IProvideFluidCodeDetailsComparer,
22
- ICodeDetailsLoader,
23
- IFluidModuleWithDetails,
24
16
  IBatchMessage,
25
17
  } from "@fluidframework/container-definitions";
26
- import { IRequest, IResponse, FluidObject } from "@fluidframework/core-interfaces";
18
+ import { FluidObject } from "@fluidframework/core-interfaces";
27
19
  import { IDocumentStorageService } from "@fluidframework/driver-definitions";
28
- import { isFluidResolvedUrl } from "@fluidframework/driver-utils";
29
20
  import {
30
21
  IClientConfiguration,
31
22
  IClientDetails,
32
23
  IDocumentMessage,
33
- IQuorum,
34
24
  IQuorumClients,
35
25
  ISequencedDocumentMessage,
36
- ISignalMessage,
37
26
  ISnapshotTree,
38
- ISummaryTree,
39
27
  IVersion,
40
28
  MessageType,
41
29
  ISummaryContent,
42
30
  } from "@fluidframework/protocol-definitions";
43
- import { PerformanceEvent } from "@fluidframework/telemetry-utils";
44
- import { UsageError } from "@fluidframework/container-utils";
45
- import { Container } from "./container";
46
-
47
- const PackageNotFactoryError = "Code package does not implement IRuntimeFactory";
48
31
 
49
32
  /**
50
- * Events that {@link ContainerContext} can emit through its lifecycle.
51
- *
52
- * "runtimeInstantiated" - When an {@link @fluidframework/container-definitions#IRuntime} has been instantiated (by
53
- * calling instantiateRuntime() on the runtime factory), and this._runtime is set.
54
- *
55
- * "disposed" - When its dispose() method is called. The {@link ContainerContext} is no longer usable at that point.
33
+ * {@inheritDoc @fluidframework/container-definitions#IContainerContext}
56
34
  */
57
- type ContextLifecycleEvents = "runtimeInstantiated" | "disposed";
58
-
59
35
  export class ContainerContext implements IContainerContext {
60
- public static async createOrLoad(
61
- container: Container,
62
- scope: FluidObject,
63
- codeLoader: ICodeDetailsLoader,
64
- codeDetails: IFluidCodeDetails,
65
- baseSnapshot: ISnapshotTree | undefined,
66
- deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>,
67
- quorum: IQuorum,
68
- loader: ILoader,
69
- submitFn: (type: MessageType, contents: any, batch: boolean, appData: any) => number,
70
- submitSummaryFn: (summaryOp: ISummaryContent, referenceSequenceNumber?: number) => number,
71
- submitBatchFn: (batch: IBatchMessage[], referenceSequenceNumber?: number) => number,
72
- submitSignalFn: (contents: any) => void,
73
- disposeFn: (error?: ICriticalContainerError) => void,
74
- closeFn: (error?: ICriticalContainerError) => void,
75
- version: string,
76
- updateDirtyContainerState: (dirty: boolean) => void,
77
- existing: boolean,
78
- pendingLocalState?: unknown,
79
- ): Promise<ContainerContext> {
80
- const context = new ContainerContext(
81
- container,
82
- scope,
83
- codeLoader,
84
- codeDetails,
85
- baseSnapshot,
86
- deltaManager,
87
- quorum,
88
- loader,
89
- submitFn,
90
- submitSummaryFn,
91
- submitBatchFn,
92
- submitSignalFn,
93
- disposeFn,
94
- closeFn,
95
- version,
96
- updateDirtyContainerState,
97
- existing,
98
- pendingLocalState,
99
- );
100
- await context.instantiateRuntime(existing);
101
- return context;
102
- }
103
-
104
- public readonly taggedLogger: ITelemetryLogger;
105
- public readonly supportedFeatures: ReadonlyMap<string, unknown>;
36
+ public readonly supportedFeatures: ReadonlyMap<string, unknown> = new Map([
37
+ /**
38
+ * This version of the loader accepts `referenceSequenceNumber`, provided by the container runtime,
39
+ * as a parameter to the `submitBatchFn` and `submitSummaryFn` functions.
40
+ * This is then used to set the reference sequence numbers of the submitted ops in the DeltaManager.
41
+ */
42
+ ["referenceSequenceNumbers", true],
43
+ ]);
106
44
 
107
45
  public get clientId(): string | undefined {
108
- return this.container.clientId;
46
+ return this._getClientId();
109
47
  }
110
48
 
111
49
  /**
112
50
  * DISCLAIMER: this id is only for telemetry purposes. Not suitable for any other usages.
113
51
  */
114
52
  public get id(): string {
115
- const resolvedUrl = this.container.resolvedUrl;
116
- if (isFluidResolvedUrl(resolvedUrl)) {
117
- return resolvedUrl.id;
118
- }
119
- return "";
120
- }
121
-
122
- public get clientDetails(): IClientDetails {
123
- return this.container.clientDetails;
53
+ return this._getContainerDiagnosticId() ?? "";
124
54
  }
125
55
 
126
- private _connected: boolean;
127
56
  /**
128
57
  * When true, ops are free to flow
129
58
  * When false, ops should be kept as pending or rejected
130
59
  */
131
60
  public get connected(): boolean {
132
- return this._connected;
133
- }
134
-
135
- public get canSummarize(): boolean {
136
- return "summarize" in this.runtime;
61
+ return this._getConnected();
137
62
  }
138
63
 
139
64
  public get serviceConfiguration(): IClientConfiguration | undefined {
140
- return this.container.serviceConfiguration;
141
- }
142
-
143
- public get audience(): IAudience {
144
- return this.container.audience;
145
- }
146
-
147
- public get options(): ILoaderOptions {
148
- return this.container.options;
149
- }
150
-
151
- public get baseSnapshot() {
152
- return this._baseSnapshot;
153
- }
154
-
155
- public get storage(): IDocumentStorageService {
156
- return this.container.storage;
157
- }
158
-
159
- private _runtime: IRuntime | undefined;
160
- private get runtime() {
161
- if (this._runtime === undefined) {
162
- throw new Error("Attempted to access runtime before it was defined");
163
- }
164
- return this._runtime;
65
+ return this._getServiceConfiguration();
165
66
  }
166
67
 
167
68
  private _disposed = false;
@@ -170,59 +71,15 @@ export class ContainerContext implements IContainerContext {
170
71
  return this._disposed;
171
72
  }
172
73
 
173
- public get codeDetails() {
174
- return this._codeDetails;
175
- }
176
-
177
- private readonly _quorum: IQuorum;
178
- public get quorum(): IQuorumClients {
179
- return this._quorum;
180
- }
181
-
182
- private readonly _fluidModuleP: Promise<IFluidModuleWithDetails>;
183
-
184
- /**
185
- * {@inheritDoc @fluidframework/container-definitions#IContainerContext.getEntryPoint}
186
- */
187
- public async getEntryPoint?(): Promise<FluidObject | undefined> {
188
- if (this._disposed) {
189
- throw new UsageError("The context is already disposed");
190
- }
191
- if (this._runtime !== undefined) {
192
- return this._runtime?.getEntryPoint?.();
193
- }
194
- return new Promise<FluidObject | undefined>((resolve, reject) => {
195
- const runtimeInstantiatedHandler = () => {
196
- assert(
197
- this._runtime !== undefined,
198
- 0x5a3 /* runtimeInstantiated fired but runtime is still undefined */,
199
- );
200
- resolve(this._runtime.getEntryPoint?.());
201
- this.lifecycleEvents.off("disposed", disposedHandler);
202
- };
203
- const disposedHandler = () => {
204
- reject(new Error("ContainerContext was disposed"));
205
- this.lifecycleEvents.off("runtimeInstantiated", runtimeInstantiatedHandler);
206
- };
207
- this.lifecycleEvents.once("runtimeInstantiated", runtimeInstantiatedHandler);
208
- this.lifecycleEvents.once("disposed", disposedHandler);
209
- });
210
- }
211
-
212
- /**
213
- * Emits events about the container context's lifecycle.
214
- * Use it to coordinate things inside the ContainerContext class.
215
- */
216
- private readonly lifecycleEvents = new TypedEventEmitter<ContextLifecycleEvents>();
217
-
218
74
  constructor(
219
- private readonly container: Container,
75
+ public readonly options: ILoaderOptions,
220
76
  public readonly scope: FluidObject,
221
- private readonly codeLoader: ICodeDetailsLoader,
222
- private readonly _codeDetails: IFluidCodeDetails,
223
- private readonly _baseSnapshot: ISnapshotTree | undefined,
77
+ public readonly baseSnapshot: ISnapshotTree | undefined,
78
+ private readonly _version: IVersion | undefined,
224
79
  public readonly deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>,
225
- quorum: IQuorum,
80
+ public readonly storage: IDocumentStorageService,
81
+ public readonly quorum: IQuorumClients,
82
+ public readonly audience: IAudience,
226
83
  public readonly loader: ILoader,
227
84
  public readonly submitFn: (
228
85
  type: MessageType,
@@ -242,194 +99,29 @@ export class ContainerContext implements IContainerContext {
242
99
  public readonly submitSignalFn: (contents: any) => void,
243
100
  public readonly disposeFn: (error?: ICriticalContainerError) => void,
244
101
  public readonly closeFn: (error?: ICriticalContainerError) => void,
245
- public readonly version: string,
246
102
  public readonly updateDirtyContainerState: (dirty: boolean) => void,
103
+ public readonly getAbsoluteUrl: (relativeUrl: string) => Promise<string | undefined>,
104
+ private readonly _getContainerDiagnosticId: () => string | undefined,
105
+ private readonly _getClientId: () => string | undefined,
106
+ private readonly _getServiceConfiguration: () => IClientConfiguration | undefined,
107
+ private readonly _getAttachState: () => AttachState,
108
+ private readonly _getConnected: () => boolean,
109
+ public readonly getSpecifiedCodeDetails: () => IFluidCodeDetails | undefined,
110
+ public readonly clientDetails: IClientDetails,
247
111
  public readonly existing: boolean,
112
+ public readonly taggedLogger: ITelemetryLoggerExt,
248
113
  public readonly pendingLocalState?: unknown,
249
- ) {
250
- this._connected = this.container.connected;
251
- this._quorum = quorum;
252
- this.taggedLogger = container.subLogger;
253
- this._fluidModuleP = new LazyPromise<IFluidModuleWithDetails>(async () =>
254
- this.loadCodeModule(_codeDetails),
255
- );
256
-
257
- this.supportedFeatures = new Map([
258
- /**
259
- * This version of the loader accepts `referenceSequenceNumber`, provided by the container runtime,
260
- * as a parameter to the `submitBatchFn` and `submitSummaryFn` functions.
261
- * This is then used to set the reference sequence numbers of the submitted ops in the DeltaManager.
262
- */
263
- ["referenceSequenceNumbers", true],
264
- ]);
265
- this.attachListener();
266
- }
267
-
268
- /**
269
- * @deprecated Temporary migratory API, to be removed when customers no longer need it.
270
- * When removed, `ContainerContext` should only take an {@link @fluidframework/container-definitions#IQuorumClients}
271
- * rather than an {@link @fluidframework/protocol-definitions#IQuorum}.
272
- * See {@link @fluidframework/container-definitions#IContainerContext} for more details.
273
- */
274
- public getSpecifiedCodeDetails(): IFluidCodeDetails | undefined {
275
- return (this._quorum.get("code") ?? this._quorum.get("code2")) as
276
- | IFluidCodeDetails
277
- | undefined;
278
- }
114
+ ) {}
279
115
 
280
116
  public dispose(error?: Error): void {
281
- if (this._disposed) {
282
- return;
283
- }
284
117
  this._disposed = true;
285
-
286
- this.lifecycleEvents.emit("disposed");
287
- this.runtime.dispose(error);
288
- this._quorum.dispose();
289
- this.deltaManager.dispose();
290
118
  }
291
119
 
292
120
  public getLoadedFromVersion(): IVersion | undefined {
293
- return this.container.loadedFromVersion;
121
+ return this._version;
294
122
  }
295
123
 
296
124
  public get attachState(): AttachState {
297
- return this.container.attachState;
298
- }
299
-
300
- /**
301
- * Create a summary. Used when attaching or serializing a detached container.
302
- *
303
- * @param blobRedirectTable - A table passed during the attach process. While detached, blob upload is supported
304
- * using IDs generated locally. After attach, these IDs cannot be used, so this table maps the old local IDs to the
305
- * new storage IDs so requests can be redirected.
306
- */
307
- public createSummary(blobRedirectTable?: Map<string, string>): ISummaryTree {
308
- return this.runtime.createSummary(blobRedirectTable);
309
- }
310
-
311
- public setConnectionState(connected: boolean, clientId?: string) {
312
- const runtime = this.runtime;
313
- this._connected = connected;
314
- runtime.setConnectionState(connected, clientId);
315
- }
316
-
317
- public process(message: ISequencedDocumentMessage, local: boolean) {
318
- this.runtime.process(message, local);
319
- }
320
-
321
- public processSignal(message: ISignalMessage, local: boolean) {
322
- this.runtime.processSignal(message, local);
323
- }
324
-
325
- public async request(path: IRequest): Promise<IResponse> {
326
- return this.runtime.request(path);
327
- }
328
-
329
- public async getAbsoluteUrl(relativeUrl: string): Promise<string | undefined> {
330
- return this.container.getAbsoluteUrl(relativeUrl);
331
- }
332
-
333
- public getPendingLocalState(): unknown {
334
- return this.runtime.getPendingLocalState();
335
- }
336
-
337
- /**
338
- * Determines if the current code details of the context
339
- * satisfy the incoming constraint code details
340
- */
341
- public async satisfies(constraintCodeDetails: IFluidCodeDetails) {
342
- const comparers: IFluidCodeDetailsComparer[] = [];
343
-
344
- const maybeCompareCodeLoader = this.codeLoader;
345
- if (maybeCompareCodeLoader.IFluidCodeDetailsComparer !== undefined) {
346
- comparers.push(maybeCompareCodeLoader.IFluidCodeDetailsComparer);
347
- }
348
-
349
- const moduleWithDetails = await this._fluidModuleP;
350
- const maybeCompareExport: Partial<IProvideFluidCodeDetailsComparer> | undefined =
351
- moduleWithDetails.module?.fluidExport;
352
- if (maybeCompareExport?.IFluidCodeDetailsComparer !== undefined) {
353
- comparers.push(maybeCompareExport.IFluidCodeDetailsComparer);
354
- }
355
-
356
- // if there are not comparers it is not possible to know
357
- // if the current satisfy the incoming, so return false,
358
- // as assuming they do not satisfy is safer .e.g we will
359
- // reload, rather than potentially running with
360
- // incompatible code
361
- if (comparers.length === 0) {
362
- return false;
363
- }
364
-
365
- for (const comparer of comparers) {
366
- const satisfies = await comparer.satisfies(
367
- moduleWithDetails.details,
368
- constraintCodeDetails,
369
- );
370
- if (satisfies === false) {
371
- return false;
372
- }
373
- }
374
- return true;
375
- }
376
-
377
- public async notifyOpReplay(message: ISequencedDocumentMessage): Promise<void> {
378
- return this.runtime.notifyOpReplay?.(message);
379
- }
380
-
381
- // #region private
382
-
383
- private async getRuntimeFactory(): Promise<IRuntimeFactory> {
384
- const fluidExport: FluidObject<IProvideRuntimeFactory> | undefined = (
385
- await this._fluidModuleP
386
- ).module?.fluidExport;
387
- const runtimeFactory = fluidExport?.IRuntimeFactory;
388
- if (runtimeFactory === undefined) {
389
- throw new Error(PackageNotFactoryError);
390
- }
391
-
392
- return runtimeFactory;
393
- }
394
-
395
- private async instantiateRuntime(existing: boolean) {
396
- const runtimeFactory = await this.getRuntimeFactory();
397
- this._runtime = await PerformanceEvent.timedExecAsync(
398
- this.taggedLogger,
399
- { eventName: "InstantiateRuntime" },
400
- async () => runtimeFactory.instantiateRuntime(this, existing),
401
- );
402
- this.lifecycleEvents.emit("runtimeInstantiated");
403
- }
404
-
405
- private attachListener() {
406
- this.container.once("attaching", () => {
407
- this.runtime.setAttachState(AttachState.Attaching);
408
- });
409
- this.container.once("attached", () => {
410
- this.runtime.setAttachState(AttachState.Attached);
411
- });
412
- }
413
-
414
- private async loadCodeModule(codeDetails: IFluidCodeDetails): Promise<IFluidModuleWithDetails> {
415
- const loadCodeResult = await PerformanceEvent.timedExecAsync(
416
- this.taggedLogger,
417
- { eventName: "CodeLoad" },
418
- async () => this.codeLoader.load(codeDetails),
419
- );
420
-
421
- if ("module" in loadCodeResult) {
422
- const { module, details } = loadCodeResult;
423
- return {
424
- module,
425
- details: details ?? codeDetails,
426
- };
427
- } else {
428
- // If "module" is not in the result, we are using a legacy ICodeLoader. Fix the result up with details.
429
- // Once usage drops to 0 we can remove this compat path.
430
- this.taggedLogger.sendTelemetryEvent({ eventName: "LegacyCodeLoader" });
431
- return loadCodeResult;
432
- }
125
+ return this._getAttachState();
433
126
  }
434
- // #endregion
435
127
  }
@@ -3,7 +3,8 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { IDisposable, ITelemetryLogger } from "@fluidframework/common-definitions";
6
+ import { IDisposable } from "@fluidframework/core-interfaces";
7
+ import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
7
8
  import { assert, bufferToString, stringToBuffer } from "@fluidframework/common-utils";
8
9
  import { ISnapshotTreeWithBlobContents } from "@fluidframework/container-definitions";
9
10
  import {
@@ -27,7 +28,6 @@ import { RetriableDocumentStorageService } from "./retriableDocumentStorageServi
27
28
 
28
29
  /**
29
30
  * Stringified blobs from a summary/snapshot tree.
30
- * @deprecated this is an internal interface and will not longer be exported in future versions
31
31
  * @internal
32
32
  */
33
33
  export interface ISerializableBlobContents {
@@ -60,7 +60,7 @@ export class ContainerStorageAdapter implements IDocumentStorageService, IDispos
60
60
  */
61
61
  public constructor(
62
62
  detachedBlobStorage: IDetachedBlobStorage | undefined,
63
- private readonly logger: ITelemetryLogger,
63
+ private readonly logger: ITelemetryLoggerExt,
64
64
  /**
65
65
  * ArrayBufferLikes or utf8 encoded strings, containing blobs from a snapshot
66
66
  */
@@ -183,7 +183,7 @@ export class ContainerStorageAdapter implements IDocumentStorageService, IDispos
183
183
  class BlobOnlyStorage implements IDocumentStorageService {
184
184
  constructor(
185
185
  private readonly detachedStorage: IDetachedBlobStorage | undefined,
186
- private readonly logger: ITelemetryLogger,
186
+ private readonly logger: ITelemetryLoggerExt,
187
187
  ) {}
188
188
 
189
189
  public async createBlob(content: ArrayBufferLike): Promise<ICreateBlobResponse> {
@@ -229,11 +229,13 @@ class BlobOnlyStorage implements IDocumentStorageService {
229
229
  }
230
230
  }
231
231
 
232
- // runtime will write a tree to the summary containing only "attachment" type entries
233
- // which reference attachment blobs by ID. However, some drivers do not support this type
234
- // and will convert them to "blob" type entries. We want to avoid saving these to reduce
235
- // the size of stashed change blobs.
232
+ // runtime will write a tree to the summary containing "attachment" type entries
233
+ // which reference attachment blobs by ID, along with a blob containing the blob redirect table.
234
+ // However, some drivers do not support the "attachment" type and will convert them to "blob" type
235
+ // entries. We want to avoid saving these to reduce the size of stashed change blobs, but we
236
+ // need to make sure the blob redirect table is saved.
236
237
  const blobsTreeName = ".blobs";
238
+ const redirectTableBlobName = ".redirectTable";
237
239
 
238
240
  /**
239
241
  * Get blob contents of a snapshot tree from storage (or, ideally, cache)
@@ -255,7 +257,9 @@ async function getBlobContentsFromTreeCore(
255
257
  ) {
256
258
  const treePs: Promise<any>[] = [];
257
259
  for (const [key, subTree] of Object.entries(tree.trees)) {
258
- if (!root || key !== blobsTreeName) {
260
+ if (root && key === blobsTreeName) {
261
+ treePs.push(getBlobManagerTreeFromTree(subTree, blobs, storage));
262
+ } else {
259
263
  treePs.push(getBlobContentsFromTreeCore(subTree, blobs, storage, false));
260
264
  }
261
265
  }
@@ -267,6 +271,18 @@ async function getBlobContentsFromTreeCore(
267
271
  return Promise.all(treePs);
268
272
  }
269
273
 
274
+ // save redirect table from .blobs tree but nothing else
275
+ async function getBlobManagerTreeFromTree(
276
+ tree: ISnapshotTree,
277
+ blobs: ISerializableBlobContents,
278
+ storage: IDocumentStorageService,
279
+ ) {
280
+ const id = tree.blobs[redirectTableBlobName];
281
+ const blob = await storage.readBlob(id);
282
+ // ArrayBufferLike will not survive JSON.stringify()
283
+ blobs[id] = bufferToString(blob, "utf8");
284
+ }
285
+
270
286
  /**
271
287
  * Extract blob contents from a snapshot tree with blob contents
272
288
  */
@@ -284,7 +300,9 @@ function getBlobContentsFromTreeWithBlobContentsCore(
284
300
  root = true,
285
301
  ) {
286
302
  for (const [key, subTree] of Object.entries(tree.trees)) {
287
- if (!root || key !== blobsTreeName) {
303
+ if (root && key === blobsTreeName) {
304
+ getBlobManagerTreeFromTreeWithBlobContents(subTree, blobs);
305
+ } else {
288
306
  getBlobContentsFromTreeWithBlobContentsCore(subTree, blobs, false);
289
307
  }
290
308
  }
@@ -295,3 +313,15 @@ function getBlobContentsFromTreeWithBlobContentsCore(
295
313
  blobs[id] = bufferToString(blob, "utf8");
296
314
  }
297
315
  }
316
+
317
+ // save redirect table from .blobs tree but nothing else
318
+ function getBlobManagerTreeFromTreeWithBlobContents(
319
+ tree: ISnapshotTreeWithBlobContents,
320
+ blobs: ISerializableBlobContents,
321
+ ) {
322
+ const id = tree.blobs[redirectTableBlobName];
323
+ const blob = tree.blobsContents[id];
324
+ assert(blob !== undefined, 0x70f /* Blob must be present in blobsContents */);
325
+ // ArrayBufferLike will not survive JSON.stringify()
326
+ blobs[id] = bufferToString(blob, "utf8");
327
+ }
package/src/contracts.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { ITelemetryProperties } from "@fluidframework/common-definitions";
6
+ import { ITelemetryProperties } from "@fluidframework/core-interfaces";
7
7
  import {
8
8
  IDeltaQueue,
9
9
  ReadOnlyInfo,
@@ -148,8 +148,6 @@ export interface IConnectionManagerFactoryArgs {
148
148
 
149
149
  /**
150
150
  * Called whenever ping/pong messages are roundtripped on connection.
151
- *
152
- * @deprecated No replacement API intended.
153
151
  */
154
152
  readonly pongHandler: (latency: number) => void;
155
153
 
@@ -167,6 +165,16 @@ export interface IConnectionManagerFactoryArgs {
167
165
  * `undefined` indicates that user permissions are not yet known.
168
166
  */
169
167
  readonly readonlyChangeHandler: (readonly?: boolean) => void;
168
+
169
+ /**
170
+ * Called whenever we try to start establishing a new connection.
171
+ */
172
+ readonly establishConnectionHandler: (reason: string) => void;
173
+
174
+ /**
175
+ * Called whenever we cancel the connection in progress.
176
+ */
177
+ readonly cancelConnectionHandler: (reason: string) => void;
170
178
  }
171
179
 
172
180
  /**