@fluidframework/container-loader 2.0.0-internal.4.3.0 → 2.0.0-internal.5.0.0
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.
- package/CHANGELOG.md +28 -0
- package/README.md +6 -3
- package/dist/connectionManager.d.ts +5 -3
- package/dist/connectionManager.d.ts.map +1 -1
- package/dist/connectionManager.js +19 -15
- package/dist/connectionManager.js.map +1 -1
- package/dist/connectionStateHandler.d.ts +11 -9
- package/dist/connectionStateHandler.d.ts.map +1 -1
- package/dist/connectionStateHandler.js +11 -11
- package/dist/connectionStateHandler.js.map +1 -1
- package/dist/container.d.ts +62 -36
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +71 -89
- package/dist/container.js.map +1 -1
- package/dist/containerContext.d.ts +2 -2
- package/dist/containerContext.d.ts.map +1 -1
- package/dist/containerContext.js +3 -7
- package/dist/containerContext.js.map +1 -1
- package/dist/containerStorageAdapter.d.ts +3 -3
- package/dist/containerStorageAdapter.d.ts.map +1 -1
- package/dist/containerStorageAdapter.js.map +1 -1
- package/dist/contracts.d.ts +3 -3
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js.map +1 -1
- package/dist/deltaManager.d.ts +3 -2
- package/dist/deltaManager.d.ts.map +1 -1
- package/dist/deltaManager.js +4 -5
- package/dist/deltaManager.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +9 -5
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +28 -34
- package/dist/loader.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/retriableDocumentStorageService.d.ts +3 -2
- package/dist/retriableDocumentStorageService.d.ts.map +1 -1
- package/dist/retriableDocumentStorageService.js.map +1 -1
- package/lib/connectionManager.d.ts +5 -3
- package/lib/connectionManager.d.ts.map +1 -1
- package/lib/connectionManager.js +20 -16
- package/lib/connectionManager.js.map +1 -1
- package/lib/connectionStateHandler.d.ts +11 -9
- package/lib/connectionStateHandler.d.ts.map +1 -1
- package/lib/connectionStateHandler.js +12 -12
- package/lib/connectionStateHandler.js.map +1 -1
- package/lib/container.d.ts +62 -36
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +72 -90
- package/lib/container.js.map +1 -1
- package/lib/containerContext.d.ts +2 -2
- package/lib/containerContext.d.ts.map +1 -1
- package/lib/containerContext.js +3 -7
- package/lib/containerContext.js.map +1 -1
- package/lib/containerStorageAdapter.d.ts +3 -3
- package/lib/containerStorageAdapter.d.ts.map +1 -1
- package/lib/containerStorageAdapter.js.map +1 -1
- package/lib/contracts.d.ts +3 -3
- package/lib/contracts.d.ts.map +1 -1
- package/lib/contracts.js.map +1 -1
- package/lib/deltaManager.d.ts +3 -2
- package/lib/deltaManager.d.ts.map +1 -1
- package/lib/deltaManager.js +5 -6
- package/lib/deltaManager.js.map +1 -1
- package/lib/index.d.ts +1 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/loader.d.ts +9 -5
- package/lib/loader.d.ts.map +1 -1
- package/lib/loader.js +28 -34
- package/lib/loader.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/retriableDocumentStorageService.d.ts +3 -2
- package/lib/retriableDocumentStorageService.d.ts.map +1 -1
- package/lib/retriableDocumentStorageService.js.map +1 -1
- package/package.json +27 -10
- package/src/connectionManager.ts +29 -20
- package/src/connectionStateHandler.ts +26 -17
- package/src/container.ts +169 -147
- package/src/containerContext.ts +3 -9
- package/src/containerStorageAdapter.ts +4 -4
- package/src/contracts.ts +3 -3
- package/src/deltaManager.ts +13 -8
- package/src/index.ts +1 -8
- package/src/loader.ts +56 -47
- package/src/packageVersion.ts +1 -1
- package/src/retriableDocumentStorageService.ts +3 -2
package/lib/container.js
CHANGED
|
@@ -8,7 +8,7 @@ import { v4 as uuid } from "uuid";
|
|
|
8
8
|
import { assert, performance, unreachableCase } from "@fluidframework/common-utils";
|
|
9
9
|
import { AttachState, isFluidCodeDetails, } from "@fluidframework/container-definitions";
|
|
10
10
|
import { GenericError, UsageError } from "@fluidframework/container-utils";
|
|
11
|
-
import { readAndParse, OnlineStatus, isOnline,
|
|
11
|
+
import { readAndParse, OnlineStatus, isOnline, combineAppAndProtocolSummary, runWithRetry, isCombinedAppAndProtocolSummary, } from "@fluidframework/driver-utils";
|
|
12
12
|
import { MessageType, SummaryType, } from "@fluidframework/protocol-definitions";
|
|
13
13
|
import { ChildLogger, EventEmitterWithErrorHandling, PerformanceEvent, raiseConnectedEvent, TelemetryLogger, connectedEventName, normalizeError, loggerToMonitoringContext, wrapError, } from "@fluidframework/telemetry-utils";
|
|
14
14
|
import { Audience } from "./audience";
|
|
@@ -119,14 +119,11 @@ export async function ReportIfTooLong(logger, eventName, action) {
|
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
const summarizerClientType = "summarizer";
|
|
122
|
-
/**
|
|
123
|
-
* @deprecated - In the next release Container will no longer be exported, IContainer should be used in its place.
|
|
124
|
-
*/
|
|
125
122
|
export class Container extends EventEmitterWithErrorHandling {
|
|
126
123
|
/**
|
|
127
124
|
* @internal
|
|
128
125
|
*/
|
|
129
|
-
constructor(
|
|
126
|
+
constructor(createProps, loadProps) {
|
|
130
127
|
var _a, _b, _c;
|
|
131
128
|
super((name, error) => {
|
|
132
129
|
this.mc.logger.sendErrorEvent({
|
|
@@ -134,8 +131,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
134
131
|
name: typeof name === "string" ? name : undefined,
|
|
135
132
|
}, error);
|
|
136
133
|
});
|
|
137
|
-
this.
|
|
138
|
-
this.protocolHandlerBuilder = protocolHandlerBuilder;
|
|
134
|
+
this.createProps = createProps;
|
|
139
135
|
// Tells if container can reconnect on losing fist connection
|
|
140
136
|
// If false, container gets closed on loss of connection.
|
|
141
137
|
this._canReconnect = true;
|
|
@@ -166,10 +162,9 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
166
162
|
this.savedOps = [];
|
|
167
163
|
this.setAutoReconnectTime = performance.now();
|
|
168
164
|
this._disposed = false;
|
|
169
|
-
this.clientDetailsOverride =
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
this._canReconnect = config.canReconnect;
|
|
165
|
+
this.clientDetailsOverride = createProps.clientDetailsOverride;
|
|
166
|
+
if (createProps.canReconnect !== undefined) {
|
|
167
|
+
this._canReconnect = createProps.canReconnect;
|
|
173
168
|
}
|
|
174
169
|
// Create logger for data stores to use
|
|
175
170
|
const type = this.client.details.type;
|
|
@@ -177,15 +172,15 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
177
172
|
const clientType = `${interactive ? "interactive" : "noninteractive"}${type !== undefined && type !== "" ? `/${type}` : ""}`;
|
|
178
173
|
// Need to use the property getter for docId because for detached flow we don't have the docId initially.
|
|
179
174
|
// We assign the id later so property getter is used.
|
|
180
|
-
this.subLogger = ChildLogger.create(
|
|
175
|
+
this.subLogger = ChildLogger.create(createProps.subLogger, undefined, {
|
|
181
176
|
all: {
|
|
182
177
|
clientType,
|
|
183
178
|
containerId: uuid(),
|
|
184
|
-
docId: () => { var _a
|
|
179
|
+
docId: () => { var _a; return (_a = this.resolvedUrl) === null || _a === void 0 ? void 0 : _a.id; },
|
|
185
180
|
containerAttachState: () => this._attachState,
|
|
186
181
|
containerLifecycleState: () => this._lifecycleState,
|
|
187
182
|
containerConnectionState: () => ConnectionState[this.connectionState],
|
|
188
|
-
serializedContainer:
|
|
183
|
+
serializedContainer: (loadProps === null || loadProps === void 0 ? void 0 : loadProps.pendingLocalState) !== undefined,
|
|
189
184
|
},
|
|
190
185
|
// we need to be judicious with our logging here to avoid generating too much data
|
|
191
186
|
// all data logged here should be broadly applicable, and not specific to a
|
|
@@ -211,15 +206,15 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
211
206
|
// Warning: this is only a shallow clone. Mutation of any individual loader option will mutate it for
|
|
212
207
|
// all clients that were loaded from the same loader (including summarizer clients).
|
|
213
208
|
// Tracking alternative ways to handle this in AB#4129.
|
|
214
|
-
this.options = Object.assign({}, this.
|
|
209
|
+
this.options = Object.assign({}, this.createProps.options);
|
|
215
210
|
this._deltaManager = this.createDeltaManager();
|
|
216
211
|
this.connectionStateHandler = createConnectionStateHandler({
|
|
217
212
|
logger: this.mc.logger,
|
|
218
|
-
connectionStateChanged: (value, oldState, reason) => {
|
|
213
|
+
connectionStateChanged: (value, oldState, reason, error) => {
|
|
219
214
|
if (value === ConnectionState.Connected) {
|
|
220
215
|
this._clientId = this.connectionStateHandler.pendingClientId;
|
|
221
216
|
}
|
|
222
|
-
this.logConnectionStateChangeTelemetry(value, oldState, reason);
|
|
217
|
+
this.logConnectionStateChangeTelemetry(value, oldState, reason, error);
|
|
223
218
|
if (this._lifecycleState === "loaded") {
|
|
224
219
|
this.propagateConnectionState(false /* initial transition */, value === ConnectionState.Disconnected
|
|
225
220
|
? reason
|
|
@@ -227,7 +222,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
227
222
|
}
|
|
228
223
|
},
|
|
229
224
|
shouldClientJoinWrite: () => this._deltaManager.connectionManager.shouldJoinWrite(),
|
|
230
|
-
maxClientLeaveWaitTime: this.
|
|
225
|
+
maxClientLeaveWaitTime: this.createProps.options.maxClientLeaveWaitTime,
|
|
231
226
|
logConnectionIssue: (eventName, category, details) => {
|
|
232
227
|
const mode = this.connectionMode;
|
|
233
228
|
// We get here when socket does not receive any ops on "write" connection, including
|
|
@@ -251,7 +246,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
251
246
|
this.connect();
|
|
252
247
|
}
|
|
253
248
|
},
|
|
254
|
-
}, this.deltaManager, (_a =
|
|
249
|
+
}, this.deltaManager, (_a = loadProps === null || loadProps === void 0 ? void 0 : loadProps.pendingLocalState) === null || _a === void 0 ? void 0 : _a.clientId);
|
|
255
250
|
this.on(savedContainerEvent, () => {
|
|
256
251
|
this.connectionStateHandler.containerSaved();
|
|
257
252
|
});
|
|
@@ -263,8 +258,8 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
263
258
|
: combineAppAndProtocolSummary(summaryTree, this.captureProtocolSummary());
|
|
264
259
|
// Whether the combined summary tree has been forced on by either the loader option or the monitoring context.
|
|
265
260
|
// Even if not forced on via this flag, combined summaries may still be enabled by service policy.
|
|
266
|
-
const forceEnableSummarizeProtocolTree = (_b = this.mc.config.getBoolean("Fluid.Container.summarizeProtocolTree2")) !== null && _b !== void 0 ? _b : this.
|
|
267
|
-
this.storageAdapter = new ContainerStorageAdapter(this.
|
|
261
|
+
const forceEnableSummarizeProtocolTree = (_b = this.mc.config.getBoolean("Fluid.Container.summarizeProtocolTree2")) !== null && _b !== void 0 ? _b : this.createProps.options.summarizeProtocolTree;
|
|
262
|
+
this.storageAdapter = new ContainerStorageAdapter(this.createProps.detachedBlobStorage, this.mc.logger, (_c = loadProps === null || loadProps === void 0 ? void 0 : loadProps.pendingLocalState) === null || _c === void 0 ? void 0 : _c.snapshotBlobs, addProtocolSummaryIfMissing, forceEnableSummarizeProtocolTree);
|
|
268
263
|
const isDomAvailable = typeof document === "object" &&
|
|
269
264
|
document !== null &&
|
|
270
265
|
typeof document.addEventListener === "function" &&
|
|
@@ -286,37 +281,34 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
286
281
|
document.addEventListener("visibilitychange", this.visibilityEventHandler);
|
|
287
282
|
}
|
|
288
283
|
}
|
|
284
|
+
static async clone(container, loadProps, createParamOverrides) {
|
|
285
|
+
return this.load(loadProps, Object.assign(Object.assign({}, container.createProps), createParamOverrides));
|
|
286
|
+
}
|
|
289
287
|
/**
|
|
290
288
|
* Load an existing container.
|
|
291
289
|
* @internal
|
|
292
290
|
*/
|
|
293
|
-
static async load(
|
|
294
|
-
const
|
|
295
|
-
|
|
296
|
-
resolvedUrl: loadOptions.resolvedUrl,
|
|
297
|
-
canReconnect: loadOptions.canReconnect,
|
|
298
|
-
serializedContainerState: pendingLocalState,
|
|
299
|
-
}, protocolHandlerBuilder);
|
|
291
|
+
static async load(loadProps, createProps) {
|
|
292
|
+
const { version, pendingLocalState, loadMode, resolvedUrl } = loadProps;
|
|
293
|
+
const container = new Container(createProps, loadProps);
|
|
300
294
|
return PerformanceEvent.timedExecAsync(container.mc.logger, { eventName: "Load" }, async (event) => new Promise((resolve, reject) => {
|
|
301
|
-
var _a, _b;
|
|
302
|
-
const version = loadOptions.version;
|
|
303
295
|
const defaultMode = { opsBeforeReturn: "cached" };
|
|
304
296
|
// if we have pendingLocalState, anything we cached is not useful and we shouldn't wait for connection
|
|
305
297
|
// to return container, so ignore this value and use undefined for opsBeforeReturn
|
|
306
298
|
const mode = pendingLocalState
|
|
307
|
-
? Object.assign(Object.assign({}, (
|
|
299
|
+
? Object.assign(Object.assign({}, (loadMode !== null && loadMode !== void 0 ? loadMode : defaultMode)), { opsBeforeReturn: undefined }) : loadMode !== null && loadMode !== void 0 ? loadMode : defaultMode;
|
|
308
300
|
const onClosed = (err) => {
|
|
309
301
|
// pre-0.58 error message: containerClosedWithoutErrorDuringLoad
|
|
310
302
|
reject(err !== null && err !== void 0 ? err : new GenericError("Container closed without error during load"));
|
|
311
303
|
};
|
|
312
304
|
container.on("closed", onClosed);
|
|
313
305
|
container
|
|
314
|
-
.load(version, mode, pendingLocalState)
|
|
306
|
+
.load(version, mode, resolvedUrl, pendingLocalState)
|
|
315
307
|
.finally(() => {
|
|
316
308
|
container.removeListener("closed", onClosed);
|
|
317
309
|
})
|
|
318
310
|
.then((props) => {
|
|
319
|
-
event.end(Object.assign(Object.assign({}, props),
|
|
311
|
+
event.end(Object.assign(Object.assign({}, props), loadMode));
|
|
320
312
|
resolve(container);
|
|
321
313
|
}, (error) => {
|
|
322
314
|
const err = normalizeError(error);
|
|
@@ -331,8 +323,8 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
331
323
|
/**
|
|
332
324
|
* Create a new container in a detached state.
|
|
333
325
|
*/
|
|
334
|
-
static async createDetached(
|
|
335
|
-
const container = new Container(
|
|
326
|
+
static async createDetached(createProps, codeDetails) {
|
|
327
|
+
const container = new Container(createProps);
|
|
336
328
|
return PerformanceEvent.timedExecAsync(container.mc.logger, { eventName: "CreateDetached" }, async (_event) => {
|
|
337
329
|
await container.createDetached(codeDetails);
|
|
338
330
|
return container;
|
|
@@ -342,8 +334,8 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
342
334
|
* Create a new container in a detached state that is initialized with a
|
|
343
335
|
* snapshot from a previous detached container.
|
|
344
336
|
*/
|
|
345
|
-
static async rehydrateDetachedFromSnapshot(
|
|
346
|
-
const container = new Container(
|
|
337
|
+
static async rehydrateDetachedFromSnapshot(createProps, snapshot) {
|
|
338
|
+
const container = new Container(createProps);
|
|
347
339
|
return PerformanceEvent.timedExecAsync(container.mc.logger, { eventName: "RehydrateDetachedFromSnapshot" }, async (_event) => {
|
|
348
340
|
const deserializedSummary = JSON.parse(snapshot);
|
|
349
341
|
await container.rehydrateDetachedFromSnapshot(deserializedSummary);
|
|
@@ -387,7 +379,19 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
387
379
|
return this;
|
|
388
380
|
}
|
|
389
381
|
get resolvedUrl() {
|
|
390
|
-
|
|
382
|
+
var _a;
|
|
383
|
+
/**
|
|
384
|
+
* All attached containers will have a document service,
|
|
385
|
+
* this is required, as attached containers are attached to
|
|
386
|
+
* a service. Detached containers will neither have a document
|
|
387
|
+
* service or a resolved url as they only exist locally.
|
|
388
|
+
* in order to create a document service a resolved url must
|
|
389
|
+
* first be obtained, this is how the container is identified.
|
|
390
|
+
* Because of this, the document service's resolved url
|
|
391
|
+
* is always the same as the containers, as we had to
|
|
392
|
+
* obtain the resolved url, and then create the service from it.
|
|
393
|
+
*/
|
|
394
|
+
return (_a = this.service) === null || _a === void 0 ? void 0 : _a.resolvedUrl;
|
|
391
395
|
}
|
|
392
396
|
get loadedFromVersion() {
|
|
393
397
|
return this._loadedFromVersion;
|
|
@@ -474,16 +478,16 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
474
478
|
return this._dirtyContainer;
|
|
475
479
|
}
|
|
476
480
|
get serviceFactory() {
|
|
477
|
-
return this.
|
|
481
|
+
return this.createProps.documentServiceFactory;
|
|
478
482
|
}
|
|
479
483
|
get urlResolver() {
|
|
480
|
-
return this.
|
|
484
|
+
return this.createProps.urlResolver;
|
|
481
485
|
}
|
|
482
486
|
get scope() {
|
|
483
|
-
return this.
|
|
487
|
+
return this.createProps.scope;
|
|
484
488
|
}
|
|
485
489
|
get codeLoader() {
|
|
486
|
-
return this.
|
|
490
|
+
return this.createProps.codeLoader;
|
|
487
491
|
}
|
|
488
492
|
/**
|
|
489
493
|
* {@inheritDoc @fluidframework/container-definitions#IContainer.entryPoint}
|
|
@@ -540,7 +544,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
540
544
|
assert(this._lifecycleState === "closed" || this._lifecycleState === "disposed", 0x314 /* Container properly closed */);
|
|
541
545
|
}
|
|
542
546
|
closeCore(error) {
|
|
543
|
-
var _a
|
|
547
|
+
var _a;
|
|
544
548
|
assert(!this.closed, 0x315 /* re-entrancy */);
|
|
545
549
|
try {
|
|
546
550
|
// Ensure that we raise all key events even if one of these throws
|
|
@@ -558,12 +562,6 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
558
562
|
this._lifecycleState = "closing";
|
|
559
563
|
(_a = this._protocolHandler) === null || _a === void 0 ? void 0 : _a.close();
|
|
560
564
|
this.connectionStateHandler.dispose();
|
|
561
|
-
(_b = this._context) === null || _b === void 0 ? void 0 : _b.dispose(error !== undefined ? new Error(error.message) : undefined);
|
|
562
|
-
this.storageAdapter.dispose();
|
|
563
|
-
// Notify storage about critical errors. They may be due to disconnect between client & server knowledge
|
|
564
|
-
// about file, like file being overwritten in storage, but client having stale local cache.
|
|
565
|
-
// Driver need to ensure all caches are cleared on critical errors
|
|
566
|
-
(_c = this.service) === null || _c === void 0 ? void 0 : _c.dispose(error);
|
|
567
565
|
}
|
|
568
566
|
catch (exception) {
|
|
569
567
|
this.mc.logger.sendErrorEvent({ eventName: "ContainerCloseException" }, exception);
|
|
@@ -652,8 +650,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
652
650
|
const appSummary = this.context.createSummary();
|
|
653
651
|
const protocolSummary = this.captureProtocolSummary();
|
|
654
652
|
const combinedSummary = combineAppAndProtocolSummary(appSummary, protocolSummary);
|
|
655
|
-
if (this.
|
|
656
|
-
this.loader.services.detachedBlobStorage.size > 0) {
|
|
653
|
+
if (this.createProps.detachedBlobStorage && this.createProps.detachedBlobStorage.size > 0) {
|
|
657
654
|
combinedSummary.tree[".hasAttachmentBlobs"] = {
|
|
658
655
|
type: SummaryType.Blob,
|
|
659
656
|
content: "true",
|
|
@@ -672,8 +669,8 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
672
669
|
assert(this._attachState === AttachState.Detached && !this.attachStarted, 0x205 /* "attach() called more than once" */);
|
|
673
670
|
this.attachStarted = true;
|
|
674
671
|
// If attachment blobs were uploaded in detached state we will go through a different attach flow
|
|
675
|
-
const hasAttachmentBlobs = this.
|
|
676
|
-
this.
|
|
672
|
+
const hasAttachmentBlobs = this.createProps.detachedBlobStorage !== undefined &&
|
|
673
|
+
this.createProps.detachedBlobStorage.size > 0;
|
|
677
674
|
try {
|
|
678
675
|
assert(this.deltaManager.inbound.length === 0, 0x0d6 /* "Inbound queue should be empty when attaching" */);
|
|
679
676
|
let summary;
|
|
@@ -697,31 +694,28 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
697
694
|
}
|
|
698
695
|
}
|
|
699
696
|
// Actually go and create the resolved document
|
|
700
|
-
const createNewResolvedUrl = await this.urlResolver.resolve(request);
|
|
701
|
-
ensureFluidResolvedUrl(createNewResolvedUrl);
|
|
702
697
|
if (this.service === undefined) {
|
|
703
|
-
|
|
698
|
+
const createNewResolvedUrl = await this.urlResolver.resolve(request);
|
|
699
|
+
assert(this.client.details.type !== summarizerClientType &&
|
|
700
|
+
createNewResolvedUrl !== undefined, 0x2c4 /* "client should not be summarizer before container is created" */);
|
|
704
701
|
this.service = await runWithRetry(async () => this.serviceFactory.createContainer(summary, createNewResolvedUrl, this.subLogger, false), "containerAttach", this.mc.logger, {
|
|
705
702
|
cancel: this.closeSignal,
|
|
706
703
|
});
|
|
707
704
|
}
|
|
708
|
-
const resolvedUrl = this.service.resolvedUrl;
|
|
709
|
-
ensureFluidResolvedUrl(resolvedUrl);
|
|
710
|
-
this._resolvedUrl = resolvedUrl;
|
|
711
705
|
await this.storageAdapter.connectToService(this.service);
|
|
712
706
|
if (hasAttachmentBlobs) {
|
|
713
707
|
// upload blobs to storage
|
|
714
|
-
assert(!!this.
|
|
708
|
+
assert(!!this.createProps.detachedBlobStorage, 0x24e /* "assertion for type narrowing" */);
|
|
715
709
|
// build a table mapping IDs assigned locally to IDs assigned by storage and pass it to runtime to
|
|
716
710
|
// support blob handles that only know about the local IDs
|
|
717
711
|
const redirectTable = new Map();
|
|
718
712
|
// if new blobs are added while uploading, upload them too
|
|
719
|
-
while (redirectTable.size < this.
|
|
720
|
-
const newIds = this.
|
|
713
|
+
while (redirectTable.size < this.createProps.detachedBlobStorage.size) {
|
|
714
|
+
const newIds = this.createProps.detachedBlobStorage
|
|
721
715
|
.getBlobIds()
|
|
722
716
|
.filter((id) => !redirectTable.has(id));
|
|
723
717
|
for (const id of newIds) {
|
|
724
|
-
const blob = await this.
|
|
718
|
+
const blob = await this.createProps.detachedBlobStorage.readBlob(id);
|
|
725
719
|
const response = await this.storageAdapter.createBlob(blob);
|
|
726
720
|
redirectTable.set(id, response.id);
|
|
727
721
|
}
|
|
@@ -756,12 +750,8 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
756
750
|
catch (error) {
|
|
757
751
|
// add resolved URL on error object so that host has the ability to find this document and delete it
|
|
758
752
|
const newError = normalizeError(error);
|
|
759
|
-
|
|
760
|
-
if (isFluidResolvedUrl(resolvedUrl)) {
|
|
761
|
-
newError.addTelemetryProperties({ resolvedUrl: resolvedUrl.url });
|
|
762
|
-
}
|
|
753
|
+
newError.addTelemetryProperties({ resolvedUrl: (_a = this.resolvedUrl) === null || _a === void 0 ? void 0 : _a.url });
|
|
763
754
|
this.close(newError);
|
|
764
|
-
(_a = this.dispose) === null || _a === void 0 ? void 0 : _a.call(this, newError);
|
|
765
755
|
throw newError;
|
|
766
756
|
}
|
|
767
757
|
}, { start: true, end: true, cancel: "generic" });
|
|
@@ -856,7 +846,6 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
856
846
|
.catch(() => false);
|
|
857
847
|
}
|
|
858
848
|
async processCodeProposal() {
|
|
859
|
-
var _a;
|
|
860
849
|
const codeDetails = this.getCodeDetailsFromQuorum();
|
|
861
850
|
await Promise.all([
|
|
862
851
|
this.deltaManager.inbound.pause(),
|
|
@@ -870,7 +859,6 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
870
859
|
// pre-0.58 error message: existingContextDoesNotSatisfyIncomingProposal
|
|
871
860
|
const error = new GenericError("Existing context does not satisfy incoming proposal");
|
|
872
861
|
this.close(error);
|
|
873
|
-
(_a = this.dispose) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
|
874
862
|
}
|
|
875
863
|
async getVersion(version) {
|
|
876
864
|
const versions = await this.storageAdapter.getVersions(version, 1);
|
|
@@ -894,12 +882,9 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
894
882
|
*
|
|
895
883
|
* @param specifiedVersion - Version SHA to load snapshot. If not specified, will fetch the latest snapshot.
|
|
896
884
|
*/
|
|
897
|
-
async load(specifiedVersion, loadMode, pendingLocalState) {
|
|
885
|
+
async load(specifiedVersion, loadMode, resolvedUrl, pendingLocalState) {
|
|
898
886
|
var _a;
|
|
899
|
-
|
|
900
|
-
throw new Error("Attempting to load without a resolved url");
|
|
901
|
-
}
|
|
902
|
-
this.service = await this.serviceFactory.createDocumentService(this._resolvedUrl, this.subLogger, this.client.details.type === summarizerClientType);
|
|
887
|
+
this.service = await this.serviceFactory.createDocumentService(resolvedUrl, this.subLogger, this.client.details.type === summarizerClientType);
|
|
903
888
|
// Ideally we always connect as "read" by default.
|
|
904
889
|
// Currently that works with SPO & r11s, because we get "write" connection when connecting to non-existing file.
|
|
905
890
|
// We should not rely on it by (one of them will address the issue, but we need to address both)
|
|
@@ -925,9 +910,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
925
910
|
else {
|
|
926
911
|
// if we have pendingLocalState we can load without storage; don't wait for connection
|
|
927
912
|
this.storageAdapter.connectToService(this.service).catch((error) => {
|
|
928
|
-
var _a;
|
|
929
913
|
this.close(error);
|
|
930
|
-
(_a = this.dispose) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
|
931
914
|
});
|
|
932
915
|
}
|
|
933
916
|
this._attachState = AttachState.Attached;
|
|
@@ -1053,8 +1036,8 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1053
1036
|
}
|
|
1054
1037
|
async rehydrateDetachedFromSnapshot(detachedContainerSnapshot) {
|
|
1055
1038
|
if (detachedContainerSnapshot.tree[".hasAttachmentBlobs"] !== undefined) {
|
|
1056
|
-
assert(!!this.
|
|
1057
|
-
this.
|
|
1039
|
+
assert(!!this.createProps.detachedBlobStorage &&
|
|
1040
|
+
this.createProps.detachedBlobStorage.size > 0, 0x250 /* "serialized container with attachment blobs must be rehydrated with detached blob storage" */);
|
|
1058
1041
|
delete detachedContainerSnapshot.tree[".hasAttachmentBlobs"];
|
|
1059
1042
|
}
|
|
1060
1043
|
const snapshotTree = getSnapshotTreeFromSerializedContainer(detachedContainerSnapshot);
|
|
@@ -1108,7 +1091,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1108
1091
|
}
|
|
1109
1092
|
initializeProtocolState(attributes, quorumSnapshot) {
|
|
1110
1093
|
var _a;
|
|
1111
|
-
const protocolHandlerBuilder = (_a = this.protocolHandlerBuilder) !== null && _a !== void 0 ? _a : ((...args) => new ProtocolHandler(...args, new Audience()));
|
|
1094
|
+
const protocolHandlerBuilder = (_a = this.createProps.protocolHandlerBuilder) !== null && _a !== void 0 ? _a : ((...args) => new ProtocolHandler(...args, new Audience()));
|
|
1112
1095
|
const protocol = protocolHandlerBuilder(attributes, quorumSnapshot, (key, value) => this.submitMessage(MessageType.Propose, JSON.stringify({ key, value })));
|
|
1113
1096
|
const protocolLogger = ChildLogger.create(this.subLogger, "ProtocolHandler");
|
|
1114
1097
|
protocol.quorum.on("error", (error) => {
|
|
@@ -1129,10 +1112,8 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1129
1112
|
});
|
|
1130
1113
|
}
|
|
1131
1114
|
this.processCodeProposal().catch((error) => {
|
|
1132
|
-
var _a;
|
|
1133
1115
|
const normalizedError = normalizeError(error);
|
|
1134
1116
|
this.close(normalizedError);
|
|
1135
|
-
(_a = this.dispose) === null || _a === void 0 ? void 0 : _a.call(this, normalizedError);
|
|
1136
1117
|
throw error;
|
|
1137
1118
|
});
|
|
1138
1119
|
}
|
|
@@ -1216,11 +1197,11 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1216
1197
|
assert(this.connectionMode === details.mode, 0x4b7 /* mismatch */);
|
|
1217
1198
|
this.connectionStateHandler.receivedConnectEvent(details);
|
|
1218
1199
|
});
|
|
1219
|
-
deltaManager.on("disconnect", (reason) => {
|
|
1200
|
+
deltaManager.on("disconnect", (reason, error) => {
|
|
1220
1201
|
var _a;
|
|
1221
1202
|
(_a = this.collabWindowTracker) === null || _a === void 0 ? void 0 : _a.stopSequenceNumberUpdate();
|
|
1222
1203
|
if (!this.closed) {
|
|
1223
|
-
this.connectionStateHandler.receivedDisconnectEvent(reason);
|
|
1204
|
+
this.connectionStateHandler.receivedDisconnectEvent(reason, error);
|
|
1224
1205
|
}
|
|
1225
1206
|
});
|
|
1226
1207
|
deltaManager.on("throttled", (warning) => {
|
|
@@ -1252,7 +1233,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1252
1233
|
},
|
|
1253
1234
|
}, prefetchType);
|
|
1254
1235
|
}
|
|
1255
|
-
logConnectionStateChangeTelemetry(value, oldState, reason) {
|
|
1236
|
+
logConnectionStateChangeTelemetry(value, oldState, reason, error) {
|
|
1256
1237
|
var _a;
|
|
1257
1238
|
// Log actual event
|
|
1258
1239
|
const time = performance.now();
|
|
@@ -1285,7 +1266,9 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1285
1266
|
durationFromDisconnected,
|
|
1286
1267
|
reason,
|
|
1287
1268
|
connectionInitiationReason, pendingClientId: this.connectionStateHandler.pendingClientId, clientId: this.clientId, autoReconnect,
|
|
1288
|
-
opsBehind, online: OnlineStatus[isOnline()], lastVisible: this.lastVisible !== undefined
|
|
1269
|
+
opsBehind, online: OnlineStatus[isOnline()], lastVisible: this.lastVisible !== undefined
|
|
1270
|
+
? performance.now() - this.lastVisible
|
|
1271
|
+
: undefined, checkpointSequenceNumber, quorumSize: (_a = this._protocolHandler) === null || _a === void 0 ? void 0 : _a.quorum.getMembers().size }, this._deltaManager.connectionProps), error);
|
|
1289
1272
|
if (value === ConnectionState.Connected) {
|
|
1290
1273
|
this.firstConnection = false;
|
|
1291
1274
|
}
|
|
@@ -1320,7 +1303,6 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1320
1303
|
}
|
|
1321
1304
|
// back-compat: ADO #1385: Remove in the future, summary op should come through submitSummaryMessage()
|
|
1322
1305
|
submitContainerMessage(type, contents, batch, metadata) {
|
|
1323
|
-
var _a;
|
|
1324
1306
|
switch (type) {
|
|
1325
1307
|
case MessageType.Operation:
|
|
1326
1308
|
return this.submitMessage(type, JSON.stringify(contents), batch, metadata);
|
|
@@ -1329,7 +1311,6 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1329
1311
|
default: {
|
|
1330
1312
|
const newError = new GenericError("invalidContainerSubmitOpType", undefined /* error */, { messageType: type });
|
|
1331
1313
|
this.close(newError);
|
|
1332
|
-
(_a = this.dispose) === null || _a === void 0 ? void 0 : _a.call(this, newError);
|
|
1333
1314
|
return -1;
|
|
1334
1315
|
}
|
|
1335
1316
|
}
|
|
@@ -1438,8 +1419,9 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1438
1419
|
assert(((_a = this._context) === null || _a === void 0 ? void 0 : _a.disposed) !== false, 0x0dd /* "Existing context not disposed" */);
|
|
1439
1420
|
// The relative loader will proxy requests to '/' to the loader itself assuming no non-cache flags
|
|
1440
1421
|
// are set. Global requests will still go directly to the loader
|
|
1441
|
-
const
|
|
1442
|
-
|
|
1422
|
+
const maybeLoader = this.scope;
|
|
1423
|
+
const loader = new RelativeLoader(this, maybeLoader.ILoader);
|
|
1424
|
+
this._context = await ContainerContext.createOrLoad(this, this.scope, this.codeLoader, codeDetails, snapshot, new DeltaManagerProxy(this._deltaManager), new QuorumProxy(this.protocolHandler.quorum), loader, (type, contents, batch, metadata) => this.submitContainerMessage(type, contents, batch, metadata), (summaryOp, referenceSequenceNumber) => this.submitSummaryMessage(summaryOp, referenceSequenceNumber), (batch, referenceSequenceNumber) => this.submitBatch(batch, referenceSequenceNumber), (message) => this.submitSignal(message), (error) => this.dispose(error), (error) => this.close(error), Container.version, (dirty) => this.updateDirtyContainerState(dirty), existing, pendingLocalState);
|
|
1443
1425
|
this.emit("contextChanged", codeDetails);
|
|
1444
1426
|
}
|
|
1445
1427
|
updateDirtyContainerState(dirty) {
|