@fluidframework/container-loader 0.51.3 → 0.53.0-46105
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/dist/connectionStateHandler.d.ts +1 -0
- package/dist/connectionStateHandler.d.ts.map +1 -1
- package/dist/connectionStateHandler.js +11 -3
- package/dist/connectionStateHandler.js.map +1 -1
- package/dist/container.d.ts +15 -23
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +125 -140
- package/dist/container.js.map +1 -1
- package/dist/containerContext.d.ts +5 -4
- package/dist/containerContext.d.ts.map +1 -1
- package/dist/containerContext.js +4 -0
- package/dist/containerContext.js.map +1 -1
- package/dist/deltaManager.d.ts +0 -7
- package/dist/deltaManager.d.ts.map +1 -1
- package/dist/deltaManager.js +38 -50
- package/dist/deltaManager.js.map +1 -1
- package/dist/deltaQueue.d.ts +5 -1
- package/dist/deltaQueue.d.ts.map +1 -1
- package/dist/deltaQueue.js.map +1 -1
- package/dist/loader.d.ts +8 -3
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +6 -1
- package/dist/loader.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.d.ts.map +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/utils.js +6 -5
- package/dist/utils.js.map +1 -1
- package/lib/connectionStateHandler.d.ts +1 -0
- package/lib/connectionStateHandler.d.ts.map +1 -1
- package/lib/connectionStateHandler.js +11 -3
- package/lib/connectionStateHandler.js.map +1 -1
- package/lib/container.d.ts +15 -23
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +127 -142
- package/lib/container.js.map +1 -1
- package/lib/containerContext.d.ts +5 -4
- package/lib/containerContext.d.ts.map +1 -1
- package/lib/containerContext.js +4 -0
- package/lib/containerContext.js.map +1 -1
- package/lib/deltaManager.d.ts +0 -7
- package/lib/deltaManager.d.ts.map +1 -1
- package/lib/deltaManager.js +38 -50
- package/lib/deltaManager.js.map +1 -1
- package/lib/deltaQueue.d.ts +5 -1
- package/lib/deltaQueue.d.ts.map +1 -1
- package/lib/deltaQueue.js.map +1 -1
- package/lib/loader.d.ts +8 -3
- package/lib/loader.d.ts.map +1 -1
- package/lib/loader.js +6 -1
- package/lib/loader.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.d.ts.map +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/utils.js +6 -5
- package/lib/utils.js.map +1 -1
- package/package.json +11 -11
- package/src/connectionStateHandler.ts +14 -4
- package/src/container.ts +150 -160
- package/src/containerContext.ts +8 -3
- package/src/deltaManager.ts +50 -56
- package/src/deltaQueue.ts +10 -1
- package/src/loader.ts +33 -24
- package/src/packageVersion.ts +1 -1
package/src/container.ts
CHANGED
|
@@ -51,7 +51,7 @@ import {
|
|
|
51
51
|
ensureFluidResolvedUrl,
|
|
52
52
|
combineAppAndProtocolSummary,
|
|
53
53
|
runWithRetry,
|
|
54
|
-
|
|
54
|
+
isFluidResolvedUrl,
|
|
55
55
|
} from "@fluidframework/driver-utils";
|
|
56
56
|
import {
|
|
57
57
|
isSystemMessage,
|
|
@@ -175,7 +175,7 @@ export async function waitContainerToCatchUp(container: Container) {
|
|
|
175
175
|
throw new Error("Container is closed");
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
-
return new Promise<boolean>((
|
|
178
|
+
return new Promise<boolean>((resolve, reject) => {
|
|
179
179
|
const deltaManager = container.deltaManager;
|
|
180
180
|
|
|
181
181
|
container.on("closed", reject);
|
|
@@ -189,12 +189,12 @@ export async function waitContainerToCatchUp(container: Container) {
|
|
|
189
189
|
assert(deltaManager.lastSequenceNumber <= connectionOpSeqNumber,
|
|
190
190
|
0x266 /* "lastKnownSeqNumber should never be below last processed sequence number" */);
|
|
191
191
|
if (deltaManager.lastSequenceNumber === connectionOpSeqNumber) {
|
|
192
|
-
|
|
192
|
+
resolve(hasCheckpointSequenceNumber);
|
|
193
193
|
return;
|
|
194
194
|
}
|
|
195
195
|
const callbackOps = (message: ISequencedDocumentMessage) => {
|
|
196
196
|
if (connectionOpSeqNumber <= message.sequenceNumber) {
|
|
197
|
-
|
|
197
|
+
resolve(hasCheckpointSequenceNumber);
|
|
198
198
|
deltaManager.off("op", callbackOps);
|
|
199
199
|
}
|
|
200
200
|
};
|
|
@@ -279,7 +279,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
279
279
|
onClosed(err);
|
|
280
280
|
});
|
|
281
281
|
}),
|
|
282
|
-
{ start: true, end: true, cancel: "
|
|
282
|
+
{ start: true, end: true, cancel: "generic" },
|
|
283
283
|
);
|
|
284
284
|
}
|
|
285
285
|
|
|
@@ -293,9 +293,16 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
293
293
|
const container = new Container(
|
|
294
294
|
loader,
|
|
295
295
|
{});
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
296
|
+
|
|
297
|
+
return PerformanceEvent.timedExecAsync(
|
|
298
|
+
container.logger,
|
|
299
|
+
{ eventName: "CreateDetached" },
|
|
300
|
+
async (_event) => {
|
|
301
|
+
container._lifecycleState = "loading";
|
|
302
|
+
await container.createDetached(codeDetails);
|
|
303
|
+
return container;
|
|
304
|
+
},
|
|
305
|
+
{ start: true, end: true, cancel: "generic" });
|
|
299
306
|
}
|
|
300
307
|
|
|
301
308
|
/**
|
|
@@ -309,10 +316,16 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
309
316
|
const container = new Container(
|
|
310
317
|
loader,
|
|
311
318
|
{});
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
319
|
+
return PerformanceEvent.timedExecAsync(
|
|
320
|
+
container.logger,
|
|
321
|
+
{ eventName: "RehydrateDetachedFromSnapshot" },
|
|
322
|
+
async (_event) => {
|
|
323
|
+
const deserializedSummary = JSON.parse(snapshot) as ISummaryTree;
|
|
324
|
+
container._lifecycleState = "loading";
|
|
325
|
+
await container.rehydrateDetachedFromSnapshot(deserializedSummary);
|
|
326
|
+
return container;
|
|
327
|
+
},
|
|
328
|
+
{ start: true, end: true, cancel: "generic" });
|
|
316
329
|
}
|
|
317
330
|
|
|
318
331
|
public subLogger: TelemetryLogger;
|
|
@@ -412,33 +425,6 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
412
425
|
return this._loadedFromVersion;
|
|
413
426
|
}
|
|
414
427
|
|
|
415
|
-
/**
|
|
416
|
-
* Tells if container is in read-only mode.
|
|
417
|
-
* Data stores should listen for "readonly" notifications and disallow user making changes to data stores.
|
|
418
|
-
* Readonly state can be because of no storage write permission,
|
|
419
|
-
* or due to host forcing readonly mode for container.
|
|
420
|
-
*
|
|
421
|
-
* We do not differentiate here between no write access to storage vs. host disallowing changes to container -
|
|
422
|
-
* in all cases container runtime and data stores should respect readonly state and not allow local changes.
|
|
423
|
-
*
|
|
424
|
-
* It is undefined if we have not yet established websocket connection
|
|
425
|
-
* and do not know if user has write access to a file.
|
|
426
|
-
* @deprecated - use readOnlyInfo
|
|
427
|
-
*/
|
|
428
|
-
public get readonly() {
|
|
429
|
-
return this._deltaManager.readonly;
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
/**
|
|
433
|
-
* Tells if user has no write permissions for file in storage
|
|
434
|
-
* It is undefined if we have not yet established websocket connection
|
|
435
|
-
* and do not know if user has write access to a file.
|
|
436
|
-
* @deprecated - use readOnlyInfo
|
|
437
|
-
*/
|
|
438
|
-
public get readonlyPermissions() {
|
|
439
|
-
return this._deltaManager.readonlyPermissions;
|
|
440
|
-
}
|
|
441
|
-
|
|
442
428
|
public get readOnlyInfo(): ReadOnlyInfo {
|
|
443
429
|
return this._deltaManager.readOnlyInfo;
|
|
444
430
|
}
|
|
@@ -495,16 +481,32 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
495
481
|
}
|
|
496
482
|
|
|
497
483
|
/**
|
|
498
|
-
*
|
|
484
|
+
* The current code details for the container's runtime
|
|
485
|
+
* @deprecated use getSpecifiedCodeDetails for the code details currently specified for this container, or
|
|
486
|
+
* getLoadedCodeDetails for the code details that the container's context was loaded with.
|
|
487
|
+
* To be removed after getSpecifiedCodeDetails and getLoadedCodeDetails become ubiquitous.
|
|
499
488
|
*/
|
|
500
|
-
public get chaincodePackage(): IFluidCodeDetails | undefined {
|
|
501
|
-
return this.codeDetails;
|
|
502
|
-
}
|
|
503
|
-
|
|
504
489
|
public get codeDetails(): IFluidCodeDetails | undefined {
|
|
505
490
|
return this._context?.codeDetails ?? this.getCodeDetailsFromQuorum();
|
|
506
491
|
}
|
|
507
492
|
|
|
493
|
+
/**
|
|
494
|
+
* Get the code details that are currently specified for the container.
|
|
495
|
+
* @returns The current code details if any are specified, undefined if none are specified.
|
|
496
|
+
*/
|
|
497
|
+
public getSpecifiedCodeDetails(): IFluidCodeDetails | undefined {
|
|
498
|
+
return this.getCodeDetailsFromQuorum();
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Get the code details that were used to load the container.
|
|
503
|
+
* @returns The code details that were used to load the container if it is loaded, undefined if it is not yet
|
|
504
|
+
* loaded.
|
|
505
|
+
*/
|
|
506
|
+
public getLoadedCodeDetails(): IFluidCodeDetails | undefined {
|
|
507
|
+
return this._context?.codeDetails;
|
|
508
|
+
}
|
|
509
|
+
|
|
508
510
|
/**
|
|
509
511
|
* Retrieves the audience associated with the document
|
|
510
512
|
*/
|
|
@@ -560,7 +562,6 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
560
562
|
{
|
|
561
563
|
all: {
|
|
562
564
|
clientType, // Differentiating summarizer container from main container
|
|
563
|
-
loaderVersion: pkgVersion,
|
|
564
565
|
containerId: uuid(),
|
|
565
566
|
docId: () => this.id,
|
|
566
567
|
containerAttachState: () => this._attachState,
|
|
@@ -656,22 +657,22 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
656
657
|
switch (event) {
|
|
657
658
|
case dirtyContainerEvent:
|
|
658
659
|
if (this._dirtyContainer) {
|
|
659
|
-
listener(
|
|
660
|
+
listener();
|
|
660
661
|
}
|
|
661
662
|
break;
|
|
662
663
|
case savedContainerEvent:
|
|
663
664
|
if (!this._dirtyContainer) {
|
|
664
|
-
listener(
|
|
665
|
+
listener();
|
|
665
666
|
}
|
|
666
667
|
break;
|
|
667
668
|
case connectedEventName:
|
|
668
669
|
if (this.connected) {
|
|
669
|
-
listener(
|
|
670
|
+
listener(this.clientId);
|
|
670
671
|
}
|
|
671
672
|
break;
|
|
672
673
|
case disconnectedEventName:
|
|
673
674
|
if (!this.connected) {
|
|
674
|
-
listener(
|
|
675
|
+
listener();
|
|
675
676
|
}
|
|
676
677
|
break;
|
|
677
678
|
default:
|
|
@@ -703,6 +704,8 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
703
704
|
|
|
704
705
|
this._protocolHandler?.close();
|
|
705
706
|
|
|
707
|
+
this.connectionStateHandler.dispose();
|
|
708
|
+
|
|
706
709
|
this._context?.dispose(error !== undefined ? new Error(error.message) : undefined);
|
|
707
710
|
|
|
708
711
|
assert(this.connectionState === ConnectionState.Disconnected,
|
|
@@ -770,114 +773,113 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
770
773
|
}
|
|
771
774
|
|
|
772
775
|
public async attach(request: IRequest): Promise<void> {
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
+
await PerformanceEvent.timedExecAsync(this.logger, { eventName: "Attach" }, async () => {
|
|
777
|
+
if (this._lifecycleState !== "loaded") {
|
|
778
|
+
throw new UsageError(`containerNotValidForAttach [${this._lifecycleState}]`);
|
|
779
|
+
}
|
|
776
780
|
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
+
// If container is already attached or attach is in progress, throw an error.
|
|
782
|
+
assert(this._attachState === AttachState.Detached && !this.attachStarted,
|
|
783
|
+
0x205 /* "attach() called more than once" */);
|
|
784
|
+
this.attachStarted = true;
|
|
781
785
|
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
786
|
+
// If attachment blobs were uploaded in detached state we will go through a different attach flow
|
|
787
|
+
const hasAttachmentBlobs = this.loader.services.detachedBlobStorage !== undefined
|
|
788
|
+
&& this.loader.services.detachedBlobStorage.size > 0;
|
|
785
789
|
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
790
|
+
try {
|
|
791
|
+
assert(this.deltaManager.inbound.length === 0,
|
|
792
|
+
0x0d6 /* "Inbound queue should be empty when attaching" */);
|
|
793
|
+
|
|
794
|
+
let summary: ISummaryTree;
|
|
795
|
+
if (!hasAttachmentBlobs) {
|
|
796
|
+
// Get the document state post attach - possibly can just call attach but we need to change the
|
|
797
|
+
// semantics around what the attach means as far as async code goes.
|
|
798
|
+
const appSummary: ISummaryTree = this.context.createSummary();
|
|
799
|
+
const protocolSummary = this.captureProtocolSummary();
|
|
800
|
+
summary = combineAppAndProtocolSummary(appSummary, protocolSummary);
|
|
801
|
+
|
|
802
|
+
// Set the state as attaching as we are starting the process of attaching container.
|
|
803
|
+
// This should be fired after taking the summary because it is the place where we are
|
|
804
|
+
// starting to attach the container to storage.
|
|
805
|
+
// Also, this should only be fired in detached container.
|
|
806
|
+
this._attachState = AttachState.Attaching;
|
|
807
|
+
this.context.notifyAttaching();
|
|
808
|
+
}
|
|
804
809
|
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
}
|
|
820
|
-
const resolvedUrl = this.service.resolvedUrl;
|
|
821
|
-
ensureFluidResolvedUrl(resolvedUrl);
|
|
822
|
-
this._resolvedUrl = resolvedUrl;
|
|
823
|
-
await this.connectStorageService();
|
|
824
|
-
|
|
825
|
-
if (hasAttachmentBlobs) {
|
|
826
|
-
// upload blobs to storage
|
|
827
|
-
assert(!!this.loader.services.detachedBlobStorage, 0x24e /* "assertion for type narrowing" */);
|
|
828
|
-
|
|
829
|
-
// build a table mapping IDs assigned locally to IDs assigned by storage and pass it to runtime to
|
|
830
|
-
// support blob handles that only know about the local IDs
|
|
831
|
-
const redirectTable = new Map<string, string>();
|
|
832
|
-
// if new blobs are added while uploading, upload them too
|
|
833
|
-
while (redirectTable.size < this.loader.services.detachedBlobStorage.size) {
|
|
834
|
-
const newIds = this.loader.services.detachedBlobStorage.getBlobIds().filter(
|
|
835
|
-
(id) => !redirectTable.has(id));
|
|
836
|
-
for (const id of newIds) {
|
|
837
|
-
const blob = await this.loader.services.detachedBlobStorage.readBlob(id);
|
|
838
|
-
const response = await this.storageService.createBlob(blob);
|
|
839
|
-
redirectTable.set(id, response.id);
|
|
840
|
-
}
|
|
810
|
+
// Actually go and create the resolved document
|
|
811
|
+
const createNewResolvedUrl = await this.urlResolver.resolve(request);
|
|
812
|
+
ensureFluidResolvedUrl(createNewResolvedUrl);
|
|
813
|
+
if (this.service === undefined) {
|
|
814
|
+
this.service = await runWithRetry(
|
|
815
|
+
async () => this.serviceFactory.createContainer(
|
|
816
|
+
summary,
|
|
817
|
+
createNewResolvedUrl,
|
|
818
|
+
this.subLogger,
|
|
819
|
+
),
|
|
820
|
+
"containerAttach",
|
|
821
|
+
this.logger,
|
|
822
|
+
{}, // progress
|
|
823
|
+
);
|
|
841
824
|
}
|
|
825
|
+
const resolvedUrl = this.service.resolvedUrl;
|
|
826
|
+
ensureFluidResolvedUrl(resolvedUrl);
|
|
827
|
+
this._resolvedUrl = resolvedUrl;
|
|
828
|
+
await this.connectStorageService();
|
|
829
|
+
|
|
830
|
+
if (hasAttachmentBlobs) {
|
|
831
|
+
// upload blobs to storage
|
|
832
|
+
assert(!!this.loader.services.detachedBlobStorage, 0x24e /* "assertion for type narrowing" */);
|
|
833
|
+
|
|
834
|
+
// build a table mapping IDs assigned locally to IDs assigned by storage and pass it to runtime to
|
|
835
|
+
// support blob handles that only know about the local IDs
|
|
836
|
+
const redirectTable = new Map<string, string>();
|
|
837
|
+
// if new blobs are added while uploading, upload them too
|
|
838
|
+
while (redirectTable.size < this.loader.services.detachedBlobStorage.size) {
|
|
839
|
+
const newIds = this.loader.services.detachedBlobStorage.getBlobIds().filter(
|
|
840
|
+
(id) => !redirectTable.has(id));
|
|
841
|
+
for (const id of newIds) {
|
|
842
|
+
const blob = await this.loader.services.detachedBlobStorage.readBlob(id);
|
|
843
|
+
const response = await this.storageService.createBlob(blob);
|
|
844
|
+
redirectTable.set(id, response.id);
|
|
845
|
+
}
|
|
846
|
+
}
|
|
842
847
|
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
848
|
+
// take summary and upload
|
|
849
|
+
const appSummary: ISummaryTree = this.context.createSummary(redirectTable);
|
|
850
|
+
const protocolSummary = this.captureProtocolSummary();
|
|
851
|
+
summary = combineAppAndProtocolSummary(appSummary, protocolSummary);
|
|
847
852
|
|
|
848
|
-
|
|
849
|
-
|
|
853
|
+
this._attachState = AttachState.Attaching;
|
|
854
|
+
this.context.notifyAttaching();
|
|
850
855
|
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
856
|
+
await this.storageService.uploadSummaryWithContext(summary, {
|
|
857
|
+
referenceSequenceNumber: 0,
|
|
858
|
+
ackHandle: undefined,
|
|
859
|
+
proposalHandle: undefined,
|
|
860
|
+
});
|
|
861
|
+
}
|
|
857
862
|
|
|
858
|
-
|
|
859
|
-
|
|
863
|
+
this._attachState = AttachState.Attached;
|
|
864
|
+
this.emit("attached");
|
|
860
865
|
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
newError.addTelemetryProperties({ resolvedUrl: resolvedUrl.url });
|
|
866
|
+
// Propagate current connection state through the system.
|
|
867
|
+
this.propagateConnectionState();
|
|
868
|
+
if (!this.closed) {
|
|
869
|
+
this.resumeInternal({ fetchOpsFromStorage: false, reason: "createDetached" });
|
|
870
|
+
}
|
|
871
|
+
} catch(error) {
|
|
872
|
+
// add resolved URL on error object so that host has the ability to find this document and delete it
|
|
873
|
+
const newError = normalizeError(error);
|
|
874
|
+
const resolvedUrl = this.resolvedUrl;
|
|
875
|
+
if (isFluidResolvedUrl(resolvedUrl)) {
|
|
876
|
+
newError.addTelemetryProperties({ resolvedUrl: resolvedUrl.url });
|
|
877
|
+
}
|
|
878
|
+
this.close(newError);
|
|
879
|
+
throw newError;
|
|
876
880
|
}
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
throw newError;
|
|
880
|
-
}
|
|
881
|
+
},
|
|
882
|
+
{ start: true, end: true, cancel: "generic" });
|
|
881
883
|
}
|
|
882
884
|
|
|
883
885
|
public async request(path: IRequest): Promise<IResponse> {
|
|
@@ -1269,7 +1271,6 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1269
1271
|
|
|
1270
1272
|
private async createDetached(source: IFluidCodeDetails) {
|
|
1271
1273
|
const attributes: IDocumentAttributes = {
|
|
1272
|
-
branch: "",
|
|
1273
1274
|
sequenceNumber: detachedContainerRefSeqNumber,
|
|
1274
1275
|
term: 1,
|
|
1275
1276
|
minimumSequenceNumber: 0,
|
|
@@ -1362,7 +1363,6 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1362
1363
|
): Promise<IDocumentAttributes> {
|
|
1363
1364
|
if (tree === undefined) {
|
|
1364
1365
|
return {
|
|
1365
|
-
branch: this.id,
|
|
1366
1366
|
minimumSequenceNumber: 0,
|
|
1367
1367
|
sequenceNumber: 0,
|
|
1368
1368
|
term: 1,
|
|
@@ -1472,7 +1472,6 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1472
1472
|
|
|
1473
1473
|
// Save attributes for the document
|
|
1474
1474
|
const documentAttributes: IDocumentAttributes = {
|
|
1475
|
-
branch: this.id,
|
|
1476
1475
|
minimumSequenceNumber: this.protocolHandler.minimumSequenceNumber,
|
|
1477
1476
|
sequenceNumber: this.protocolHandler.sequenceNumber,
|
|
1478
1477
|
term: this.protocolHandler.term,
|
|
@@ -1527,7 +1526,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1527
1526
|
if (this.clientDetailsOverride !== undefined) {
|
|
1528
1527
|
merge(client.details, this.clientDetailsOverride);
|
|
1529
1528
|
}
|
|
1530
|
-
|
|
1529
|
+
client.details.environment = [client.details.environment, ` loaderVersion:${pkgVersion}`].join(";");
|
|
1531
1530
|
return client;
|
|
1532
1531
|
}
|
|
1533
1532
|
|
|
@@ -1538,17 +1537,8 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1538
1537
|
* If it's not true, runtime is not in position to send ops.
|
|
1539
1538
|
*/
|
|
1540
1539
|
private activeConnection() {
|
|
1541
|
-
|
|
1540
|
+
return this.connectionState === ConnectionState.Connected &&
|
|
1542
1541
|
this._deltaManager.connectionMode === "write";
|
|
1543
|
-
|
|
1544
|
-
// Check for presence of current client in quorum for "write" connections - inactive clients
|
|
1545
|
-
// would get leave op after some long timeout (5 min) and that should automatically transition
|
|
1546
|
-
// state to "read" mode.
|
|
1547
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1548
|
-
assert(!active || this.getQuorum().getMember(this.clientId!) !== undefined,
|
|
1549
|
-
0x276 /* "active connection not present in quorum" */);
|
|
1550
|
-
|
|
1551
|
-
return active;
|
|
1552
1542
|
}
|
|
1553
1543
|
|
|
1554
1544
|
private createDeltaManager() {
|
package/src/containerContext.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
IFluidCodeDetails,
|
|
13
13
|
IFluidCodeDetailsComparer,
|
|
14
14
|
IProvideFluidCodeDetailsComparer,
|
|
15
|
+
FluidObject,
|
|
15
16
|
} from "@fluidframework/core-interfaces";
|
|
16
17
|
import {
|
|
17
18
|
IAudience,
|
|
@@ -51,7 +52,7 @@ const PackageNotFactoryError = "Code package does not implement IRuntimeFactory"
|
|
|
51
52
|
export class ContainerContext implements IContainerContext {
|
|
52
53
|
public static async createOrLoad(
|
|
53
54
|
container: Container,
|
|
54
|
-
scope:
|
|
55
|
+
scope: FluidObject,
|
|
55
56
|
codeLoader: ICodeDetailsLoader | ICodeLoader,
|
|
56
57
|
codeDetails: IFluidCodeDetails,
|
|
57
58
|
baseSnapshot: ISnapshotTree | undefined,
|
|
@@ -166,7 +167,7 @@ export class ContainerContext implements IContainerContext {
|
|
|
166
167
|
|
|
167
168
|
constructor(
|
|
168
169
|
private readonly container: Container,
|
|
169
|
-
public readonly scope: IFluidObject,
|
|
170
|
+
public readonly scope: IFluidObject & FluidObject,
|
|
170
171
|
private readonly codeLoader: ICodeDetailsLoader | ICodeLoader,
|
|
171
172
|
private readonly _codeDetails: IFluidCodeDetails,
|
|
172
173
|
private readonly _baseSnapshot: ISnapshotTree | undefined,
|
|
@@ -190,6 +191,10 @@ export class ContainerContext implements IContainerContext {
|
|
|
190
191
|
this.attachListener();
|
|
191
192
|
}
|
|
192
193
|
|
|
194
|
+
public getSpecifiedCodeDetails(): IFluidCodeDetails | undefined {
|
|
195
|
+
return (this.quorum.get("code") ?? this.quorum.get("code2")) as IFluidCodeDetails | undefined;
|
|
196
|
+
}
|
|
197
|
+
|
|
193
198
|
public dispose(error?: Error): void {
|
|
194
199
|
if (this._disposed) {
|
|
195
200
|
return;
|
|
@@ -299,7 +304,7 @@ export class ContainerContext implements IContainerContext {
|
|
|
299
304
|
// #region private
|
|
300
305
|
|
|
301
306
|
private async getRuntimeFactory(): Promise<IRuntimeFactory> {
|
|
302
|
-
const fluidExport:
|
|
307
|
+
const fluidExport: FluidObject<IProvideRuntimeFactory> | undefined =
|
|
303
308
|
(await this._fluidModuleP).module?.fluidExport;
|
|
304
309
|
const runtimeFactory = fluidExport?.IRuntimeFactory;
|
|
305
310
|
if (runtimeFactory === undefined) {
|