@fluidframework/container-loader 0.59.2000-63294 → 0.59.3000-66610
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/.eslintrc.js +0 -1
- package/README.md +4 -4
- package/dist/collabWindowTracker.js +5 -5
- package/dist/collabWindowTracker.js.map +1 -1
- package/dist/connectionManager.d.ts.map +1 -1
- package/dist/connectionManager.js +32 -32
- package/dist/connectionManager.js.map +1 -1
- package/dist/connectionStateHandler.js +9 -9
- package/dist/connectionStateHandler.js.map +1 -1
- package/dist/container.d.ts +2 -1
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +76 -71
- package/dist/container.js.map +1 -1
- package/dist/containerContext.js +2 -2
- package/dist/containerContext.js.map +1 -1
- package/dist/containerStorageAdapter.d.ts.map +1 -1
- package/dist/containerStorageAdapter.js.map +1 -1
- package/dist/contracts.js +1 -1
- package/dist/contracts.js.map +1 -1
- package/dist/deltaManager.d.ts.map +1 -1
- package/dist/deltaManager.js +27 -27
- package/dist/deltaManager.js.map +1 -1
- package/dist/deltaQueue.d.ts.map +1 -1
- package/dist/deltaQueue.js +1 -1
- package/dist/deltaQueue.js.map +1 -1
- package/dist/loader.d.ts +2 -0
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +9 -9
- 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/protocolTreeDocumentStorageService.d.ts +2 -2
- package/dist/protocolTreeDocumentStorageService.d.ts.map +1 -1
- package/dist/protocolTreeDocumentStorageService.js +1 -1
- package/dist/protocolTreeDocumentStorageService.js.map +1 -1
- package/dist/quorum.d.ts +4 -1
- package/dist/quorum.d.ts.map +1 -1
- package/dist/quorum.js +25 -6
- package/dist/quorum.js.map +1 -1
- package/dist/retriableDocumentStorageService.js +2 -2
- package/dist/retriableDocumentStorageService.js.map +1 -1
- package/dist/utils.d.ts +1 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +11 -7
- package/dist/utils.js.map +1 -1
- package/lib/connectionManager.d.ts.map +1 -1
- package/lib/connectionManager.js.map +1 -1
- package/lib/connectionStateHandler.js +2 -2
- package/lib/connectionStateHandler.js.map +1 -1
- package/lib/container.d.ts +2 -1
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +28 -23
- package/lib/container.js.map +1 -1
- package/lib/containerContext.js.map +1 -1
- package/lib/containerStorageAdapter.d.ts.map +1 -1
- package/lib/containerStorageAdapter.js.map +1 -1
- package/lib/contracts.js.map +1 -1
- package/lib/deltaManager.d.ts.map +1 -1
- package/lib/deltaManager.js.map +1 -1
- package/lib/deltaQueue.d.ts.map +1 -1
- package/lib/deltaQueue.js.map +1 -1
- package/lib/loader.d.ts +2 -0
- package/lib/loader.d.ts.map +1 -1
- 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/protocolTreeDocumentStorageService.d.ts +2 -2
- package/lib/protocolTreeDocumentStorageService.d.ts.map +1 -1
- package/lib/quorum.d.ts +4 -1
- package/lib/quorum.d.ts.map +1 -1
- package/lib/quorum.js +18 -1
- package/lib/quorum.js.map +1 -1
- package/lib/utils.d.ts +1 -0
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +3 -0
- package/lib/utils.js.map +1 -1
- package/package.json +12 -11
- package/src/connectionManager.ts +2 -3
- package/src/connectionStateHandler.ts +6 -6
- package/src/container.ts +55 -49
- package/src/containerStorageAdapter.ts +4 -4
- package/src/contracts.ts +8 -8
- package/src/deltaManager.ts +5 -8
- package/src/deltaQueue.ts +2 -4
- package/src/loader.ts +5 -3
- package/src/packageVersion.ts +1 -1
- package/src/quorum.ts +26 -1
- package/src/utils.ts +6 -2
package/src/container.ts
CHANGED
|
@@ -89,6 +89,7 @@ import {
|
|
|
89
89
|
normalizeError,
|
|
90
90
|
MonitoringContext,
|
|
91
91
|
loggerToMonitoringContext,
|
|
92
|
+
wrapError,
|
|
92
93
|
} from "@fluidframework/telemetry-utils";
|
|
93
94
|
import { Audience } from "./audience";
|
|
94
95
|
import { ContainerContext } from "./containerContext";
|
|
@@ -101,8 +102,8 @@ import { ConnectionStateHandler, ILocalSequencedClient } from "./connectionState
|
|
|
101
102
|
import { RetriableDocumentStorageService } from "./retriableDocumentStorageService";
|
|
102
103
|
import { ProtocolTreeStorageService } from "./protocolTreeDocumentStorageService";
|
|
103
104
|
import { BlobOnlyStorage, ContainerStorageAdapter } from "./containerStorageAdapter";
|
|
104
|
-
import { getSnapshotTreeFromSerializedContainer } from "./utils";
|
|
105
|
-
import { QuorumProxy } from "./quorum";
|
|
105
|
+
import { getProtocolSnapshotTree, getSnapshotTreeFromSerializedContainer } from "./utils";
|
|
106
|
+
import { initQuorumValuesFromCodeDetails, getCodeDetailsFromQuorumValues, QuorumProxy } from "./quorum";
|
|
106
107
|
import { CollabWindowTracker } from "./collabWindowTracker";
|
|
107
108
|
import { ConnectionManager } from "./connectionManager";
|
|
108
109
|
|
|
@@ -166,17 +167,27 @@ export enum ConnectionState {
|
|
|
166
167
|
* @returns true: container is up to date, it processed all the ops that were know at the time of first connection
|
|
167
168
|
* false: storage does not provide indication of how far the client is. Container processed
|
|
168
169
|
* all the ops known to it, but it maybe still behind.
|
|
170
|
+
* @throws an error beginning with `"Container closed"` if the container is closed before it catches up.
|
|
169
171
|
*/
|
|
170
172
|
export async function waitContainerToCatchUp(container: IContainer) {
|
|
171
173
|
// Make sure we stop waiting if container is closed.
|
|
172
174
|
if (container.closed) {
|
|
173
|
-
throw new
|
|
175
|
+
throw new UsageError("waitContainerToCatchUp: Container closed");
|
|
174
176
|
}
|
|
175
177
|
|
|
176
178
|
return new Promise<boolean>((resolve, reject) => {
|
|
177
179
|
const deltaManager = container.deltaManager;
|
|
178
180
|
|
|
179
|
-
|
|
181
|
+
const closedCallback = (err?: ICriticalContainerError | undefined) => {
|
|
182
|
+
container.off("closed", closedCallback);
|
|
183
|
+
const baseMessage = "Container closed while waiting to catch up";
|
|
184
|
+
reject(
|
|
185
|
+
err !== undefined
|
|
186
|
+
? wrapError(err, (innerMessage) => new GenericError(`${baseMessage}: ${innerMessage}`))
|
|
187
|
+
: new GenericError(baseMessage),
|
|
188
|
+
);
|
|
189
|
+
};
|
|
190
|
+
container.on("closed", closedCallback);
|
|
180
191
|
|
|
181
192
|
const waitForOps = () => {
|
|
182
193
|
assert(container.connectionState !== ConnectionState.Disconnected,
|
|
@@ -187,11 +198,13 @@ export async function waitContainerToCatchUp(container: IContainer) {
|
|
|
187
198
|
assert(deltaManager.lastSequenceNumber <= connectionOpSeqNumber,
|
|
188
199
|
0x266 /* "lastKnownSeqNumber should never be below last processed sequence number" */);
|
|
189
200
|
if (deltaManager.lastSequenceNumber === connectionOpSeqNumber) {
|
|
201
|
+
container.off("closed", closedCallback);
|
|
190
202
|
resolve(hasCheckpointSequenceNumber);
|
|
191
203
|
return;
|
|
192
204
|
}
|
|
193
205
|
const callbackOps = (message: ISequencedDocumentMessage) => {
|
|
194
206
|
if (connectionOpSeqNumber <= message.sequenceNumber) {
|
|
207
|
+
container.off("closed", closedCallback);
|
|
195
208
|
resolve(hasCheckpointSequenceNumber);
|
|
196
209
|
deltaManager.off("op", callbackOps);
|
|
197
210
|
}
|
|
@@ -517,11 +530,11 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
517
530
|
return this._dirtyContainer;
|
|
518
531
|
}
|
|
519
532
|
|
|
520
|
-
private get serviceFactory() {return this.loader.services.documentServiceFactory;}
|
|
521
|
-
private get urlResolver() {return this.loader.services.urlResolver;}
|
|
533
|
+
private get serviceFactory() { return this.loader.services.documentServiceFactory; }
|
|
534
|
+
private get urlResolver() { return this.loader.services.urlResolver; }
|
|
522
535
|
public readonly options: ILoaderOptions;
|
|
523
|
-
private get scope() { return this.loader.services.scope;}
|
|
524
|
-
private get codeLoader() { return this.loader.services.codeLoader;}
|
|
536
|
+
private get scope() { return this.loader.services.scope; }
|
|
537
|
+
private get codeLoader() { return this.loader.services.codeLoader; }
|
|
525
538
|
|
|
526
539
|
constructor(
|
|
527
540
|
private readonly loader: Loader,
|
|
@@ -726,7 +739,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
726
739
|
// Driver need to ensure all caches are cleared on critical errors
|
|
727
740
|
this.service?.dispose(error);
|
|
728
741
|
} catch (exception) {
|
|
729
|
-
this.mc.logger.sendErrorEvent({ eventName: "ContainerCloseException"}, exception);
|
|
742
|
+
this.mc.logger.sendErrorEvent({ eventName: "ContainerCloseException" }, exception);
|
|
730
743
|
}
|
|
731
744
|
|
|
732
745
|
this.mc.logger.sendTelemetryEvent(
|
|
@@ -885,7 +898,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
885
898
|
if (!this.closed) {
|
|
886
899
|
this.resumeInternal({ fetchOpsFromStorage: false, reason: "createDetached" });
|
|
887
900
|
}
|
|
888
|
-
} catch(error) {
|
|
901
|
+
} catch (error) {
|
|
889
902
|
// add resolved URL on error object so that host has the ability to find this document and delete it
|
|
890
903
|
const newError = normalizeError(error);
|
|
891
904
|
const resolvedUrl = this.resolvedUrl;
|
|
@@ -956,11 +969,9 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
956
969
|
public connect() {
|
|
957
970
|
if (this.closed) {
|
|
958
971
|
throw new UsageError(`The Container is closed and cannot be connected`);
|
|
959
|
-
}
|
|
960
|
-
else if (this._attachState !== AttachState.Attached) {
|
|
972
|
+
} else if (this._attachState !== AttachState.Attached) {
|
|
961
973
|
throw new UsageError(`The Container is not attached and cannot be connected`);
|
|
962
|
-
}
|
|
963
|
-
else if (!this.connected) {
|
|
974
|
+
} else if (!this.connected) {
|
|
964
975
|
// Note: no need to fetch ops as we do it preemptively as part of DeltaManager.attachOpHandler().
|
|
965
976
|
// If there is gap, we will learn about it once connected, but the gap should be small (if any),
|
|
966
977
|
// assuming that connect() is called quickly after initial container boot.
|
|
@@ -984,8 +995,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
984
995
|
public disconnect() {
|
|
985
996
|
if (this.closed) {
|
|
986
997
|
throw new UsageError(`The Container is closed and cannot be disconnected`);
|
|
987
|
-
}
|
|
988
|
-
else {
|
|
998
|
+
} else {
|
|
989
999
|
this.disconnectInternal();
|
|
990
1000
|
}
|
|
991
1001
|
}
|
|
@@ -1053,8 +1063,8 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1053
1063
|
}
|
|
1054
1064
|
|
|
1055
1065
|
return this.protocolHandler.quorum.propose("code", codeDetails)
|
|
1056
|
-
.then(()=>true)
|
|
1057
|
-
.catch(()=>false);
|
|
1066
|
+
.then(() => true)
|
|
1067
|
+
.catch(() => false);
|
|
1058
1068
|
}
|
|
1059
1069
|
|
|
1060
1070
|
private async processCodeProposal(): Promise<void> {
|
|
@@ -1166,7 +1176,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1166
1176
|
// ...load in the existing quorum
|
|
1167
1177
|
// Initialize the protocol handler
|
|
1168
1178
|
this._protocolHandler =
|
|
1169
|
-
await this.
|
|
1179
|
+
await this.initializeProtocolStateFromSnapshot(attributes, this.storageService, snapshot);
|
|
1170
1180
|
|
|
1171
1181
|
const codeDetails = this.getCodeDetailsFromQuorum();
|
|
1172
1182
|
await this.instantiateContext(
|
|
@@ -1233,27 +1243,16 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1233
1243
|
minimumSequenceNumber: 0,
|
|
1234
1244
|
};
|
|
1235
1245
|
|
|
1236
|
-
// Seed the base quorum to be an empty list with a code quorum set
|
|
1237
|
-
const committedCodeProposal: ICommittedProposal = {
|
|
1238
|
-
key: "code",
|
|
1239
|
-
value: source,
|
|
1240
|
-
approvalSequenceNumber: 0,
|
|
1241
|
-
commitSequenceNumber: 0,
|
|
1242
|
-
sequenceNumber: 0,
|
|
1243
|
-
};
|
|
1244
|
-
|
|
1245
|
-
const members: [string, ISequencedClient][] = [];
|
|
1246
|
-
const proposals: [number, ISequencedProposal, string[]][] = [];
|
|
1247
|
-
const values: [string, ICommittedProposal][] = [["code", committedCodeProposal]];
|
|
1248
|
-
|
|
1249
1246
|
await this.attachDeltaManagerOpHandler(attributes);
|
|
1250
1247
|
|
|
1251
1248
|
// Need to just seed the source data in the code quorum. Quorum itself is empty
|
|
1249
|
+
const qValues = initQuorumValuesFromCodeDetails(source);
|
|
1252
1250
|
this._protocolHandler = await this.initializeProtocolState(
|
|
1253
1251
|
attributes,
|
|
1254
|
-
members
|
|
1255
|
-
proposals
|
|
1256
|
-
|
|
1252
|
+
[], // members
|
|
1253
|
+
[], // proposals
|
|
1254
|
+
qValues,
|
|
1255
|
+
);
|
|
1257
1256
|
|
|
1258
1257
|
// The load context - given we seeded the quorum - will be great
|
|
1259
1258
|
await this.instantiateContextDetached(
|
|
@@ -1275,13 +1274,22 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1275
1274
|
const snapshotTree = getSnapshotTreeFromSerializedContainer(detachedContainerSnapshot);
|
|
1276
1275
|
this._storage.loadSnapshotForRehydratingContainer(snapshotTree);
|
|
1277
1276
|
const attributes = await this.getDocumentAttributes(this._storage, snapshotTree);
|
|
1278
|
-
|
|
1277
|
+
|
|
1279
1278
|
await this.attachDeltaManagerOpHandler(attributes);
|
|
1280
1279
|
|
|
1281
|
-
// ...load in the existing quorum
|
|
1282
1280
|
// Initialize the protocol handler
|
|
1281
|
+
const baseTree = getProtocolSnapshotTree(snapshotTree);
|
|
1282
|
+
const qValues = await readAndParse<[string, ICommittedProposal][]>(
|
|
1283
|
+
this._storage,
|
|
1284
|
+
baseTree.blobs.quorumValues,
|
|
1285
|
+
);
|
|
1286
|
+
const codeDetails = getCodeDetailsFromQuorumValues(qValues);
|
|
1283
1287
|
this._protocolHandler =
|
|
1284
|
-
await this.
|
|
1288
|
+
await this.initializeProtocolState(
|
|
1289
|
+
attributes,
|
|
1290
|
+
[], // members
|
|
1291
|
+
[], // proposals
|
|
1292
|
+
codeDetails !== undefined ? initQuorumValuesFromCodeDetails(codeDetails) : []);
|
|
1285
1293
|
|
|
1286
1294
|
await this.instantiateContextDetached(
|
|
1287
1295
|
true, // existing
|
|
@@ -1304,10 +1312,10 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1304
1312
|
this._storageService =
|
|
1305
1313
|
new RetriableDocumentStorageService(storageService, this.mc.logger);
|
|
1306
1314
|
|
|
1307
|
-
if(this.options.summarizeProtocolTree === true) {
|
|
1308
|
-
this.mc.logger.sendTelemetryEvent({eventName:"summarizeProtocolTreeEnabled"});
|
|
1315
|
+
if (this.options.summarizeProtocolTree === true) {
|
|
1316
|
+
this.mc.logger.sendTelemetryEvent({ eventName: "summarizeProtocolTreeEnabled" });
|
|
1309
1317
|
this._storageService =
|
|
1310
|
-
new ProtocolTreeStorageService(this._storageService, ()=>this.captureProtocolSummary());
|
|
1318
|
+
new ProtocolTreeStorageService(this._storageService, () => this.captureProtocolSummary());
|
|
1311
1319
|
}
|
|
1312
1320
|
|
|
1313
1321
|
// ensure we did not lose that policy in the process of wrapping
|
|
@@ -1342,7 +1350,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1342
1350
|
return attributes;
|
|
1343
1351
|
}
|
|
1344
1352
|
|
|
1345
|
-
private async
|
|
1353
|
+
private async initializeProtocolStateFromSnapshot(
|
|
1346
1354
|
attributes: IDocumentAttributes,
|
|
1347
1355
|
storage: IDocumentStorageService,
|
|
1348
1356
|
snapshot: ISnapshotTree | undefined,
|
|
@@ -1352,7 +1360,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1352
1360
|
let values: [string, any][] = [];
|
|
1353
1361
|
|
|
1354
1362
|
if (snapshot !== undefined) {
|
|
1355
|
-
const baseTree =
|
|
1363
|
+
const baseTree = getProtocolSnapshotTree(snapshot);
|
|
1356
1364
|
[members, proposals, values] = await Promise.all([
|
|
1357
1365
|
readAndParse<[string, ISequencedClient][]>(storage, baseTree.blobs.quorumMembers),
|
|
1358
1366
|
readAndParse<[number, ISequencedProposal, string[]][]>(storage, baseTree.blobs.quorumProposals),
|
|
@@ -1561,8 +1569,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1561
1569
|
|
|
1562
1570
|
private async attachDeltaManagerOpHandler(
|
|
1563
1571
|
attributes: IDocumentAttributes,
|
|
1564
|
-
prefetchType?: "cached" | "all" | "none")
|
|
1565
|
-
{
|
|
1572
|
+
prefetchType?: "cached" | "all" | "none") {
|
|
1566
1573
|
return this._deltaManager.attachOpHandler(
|
|
1567
1574
|
attributes.minimumSequenceNumber,
|
|
1568
1575
|
attributes.sequenceNumber,
|
|
@@ -1668,7 +1675,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1668
1675
|
// this can be removed once all clients send
|
|
1669
1676
|
// protocol tree by default
|
|
1670
1677
|
const summary = contents as ISummaryContent;
|
|
1671
|
-
if(summary.details === undefined) {
|
|
1678
|
+
if (summary.details === undefined) {
|
|
1672
1679
|
summary.details = {};
|
|
1673
1680
|
}
|
|
1674
1681
|
summary.details.includesProtocolTree =
|
|
@@ -1740,7 +1747,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1740
1747
|
private processSignal(message: ISignalMessage) {
|
|
1741
1748
|
// No clientId indicates a system signal message.
|
|
1742
1749
|
if (message.clientId === null) {
|
|
1743
|
-
const innerContent = message.content as { content: any; type: string };
|
|
1750
|
+
const innerContent = message.content as { content: any; type: string; };
|
|
1744
1751
|
if (innerContent.type === MessageType.ClientJoin) {
|
|
1745
1752
|
const newClient = innerContent.content as ISignalClient;
|
|
1746
1753
|
this._audience.addMember(newClient.clientId, newClient.client);
|
|
@@ -1760,8 +1767,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1760
1767
|
* @returns The snapshot requested, or the latest snapshot if no version was specified, plus version ID
|
|
1761
1768
|
*/
|
|
1762
1769
|
private async fetchSnapshotTree(specifiedVersion: string | undefined):
|
|
1763
|
-
Promise<{snapshot?: ISnapshotTree; versionId?: string}>
|
|
1764
|
-
{
|
|
1770
|
+
Promise<{ snapshot?: ISnapshotTree; versionId?: string; }> {
|
|
1765
1771
|
const version = await this.getVersion(specifiedVersion ?? null);
|
|
1766
1772
|
|
|
1767
1773
|
if (version === undefined && specifiedVersion !== undefined) {
|
|
@@ -25,7 +25,7 @@ import { ISnapshotTreeWithBlobContents } from "./utils";
|
|
|
25
25
|
* container attach state.
|
|
26
26
|
*/
|
|
27
27
|
export class ContainerStorageAdapter implements IDocumentStorageService {
|
|
28
|
-
private readonly blobContents: {[id: string]: ArrayBufferLike} = {};
|
|
28
|
+
private readonly blobContents: { [id: string]: ArrayBufferLike; } = {};
|
|
29
29
|
constructor(private readonly storageGetter: () => IDocumentStorageService) {}
|
|
30
30
|
|
|
31
31
|
public loadSnapshotForRehydratingContainer(snapshotTree: ISnapshotTreeWithBlobContents) {
|
|
@@ -33,10 +33,10 @@ export class ContainerStorageAdapter implements IDocumentStorageService {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
private getBlobContents(snapshotTree: ISnapshotTreeWithBlobContents) {
|
|
36
|
-
for(const [id, value] of Object.entries(snapshotTree.blobsContents)) {
|
|
36
|
+
for (const [id, value] of Object.entries(snapshotTree.blobsContents)) {
|
|
37
37
|
this.blobContents[id] = value;
|
|
38
38
|
}
|
|
39
|
-
for(const [_, tree] of Object.entries(snapshotTree.trees)) {
|
|
39
|
+
for (const [_, tree] of Object.entries(snapshotTree.trees)) {
|
|
40
40
|
this.getBlobContents(tree);
|
|
41
41
|
}
|
|
42
42
|
}
|
|
@@ -46,7 +46,7 @@ export class ContainerStorageAdapter implements IDocumentStorageService {
|
|
|
46
46
|
// and storage is always present in >=0.41.
|
|
47
47
|
try {
|
|
48
48
|
return this.storageGetter().policies;
|
|
49
|
-
} catch(e) {}
|
|
49
|
+
} catch (e) {}
|
|
50
50
|
return undefined;
|
|
51
51
|
}
|
|
52
52
|
|
package/src/contracts.ts
CHANGED
|
@@ -112,13 +112,13 @@ export interface IConnectionManagerFactoryArgs {
|
|
|
112
112
|
* Called by connection manager for each incomming op. Some ops maybe delivered before
|
|
113
113
|
* connectHandler is called (initial ops on socket connection)
|
|
114
114
|
*/
|
|
115
|
-
readonly incomingOpHandler: (messages: ISequencedDocumentMessage[], reason: string) => void
|
|
115
|
+
readonly incomingOpHandler: (messages: ISequencedDocumentMessage[], reason: string) => void;
|
|
116
116
|
|
|
117
117
|
/**
|
|
118
118
|
* Called by connection manager for each incoming signals.
|
|
119
119
|
* Maybe called before connectHandler is called (initial signals on socket connection)
|
|
120
120
|
*/
|
|
121
|
-
readonly signalHandler: (message: ISignalMessage) => void
|
|
121
|
+
readonly signalHandler: (message: ISignalMessage) => void;
|
|
122
122
|
|
|
123
123
|
/**
|
|
124
124
|
* Called when connection manager experiences delay in connecting to relay service.
|
|
@@ -126,28 +126,28 @@ export interface IConnectionManagerFactoryArgs {
|
|
|
126
126
|
* Can be called many times while not connected.
|
|
127
127
|
* Situation is considered resolved when connection is established and connectHandler is called.
|
|
128
128
|
*/
|
|
129
|
-
readonly reconnectionDelayHandler: (delayMs: number, error: unknown) => void
|
|
129
|
+
readonly reconnectionDelayHandler: (delayMs: number, error: unknown) => void;
|
|
130
130
|
|
|
131
131
|
/**
|
|
132
132
|
* Called by connection manager whwnever critical error happens and container should be closed.
|
|
133
133
|
* Expects dispose() call in respose to this call.
|
|
134
134
|
*/
|
|
135
|
-
readonly closeHandler: (error?: any) => void
|
|
135
|
+
readonly closeHandler: (error?: any) => void;
|
|
136
136
|
|
|
137
137
|
/**
|
|
138
138
|
* Called whenever connection to relay service is lost.
|
|
139
139
|
*/
|
|
140
|
-
readonly disconnectHandler: (reason: string) => void
|
|
140
|
+
readonly disconnectHandler: (reason: string) => void;
|
|
141
141
|
|
|
142
142
|
/**
|
|
143
143
|
* Called whenever new connection to rely service is established
|
|
144
144
|
*/
|
|
145
|
-
readonly connectHandler: (connection: IConnectionDetails) => void
|
|
145
|
+
readonly connectHandler: (connection: IConnectionDetails) => void;
|
|
146
146
|
|
|
147
147
|
/**
|
|
148
148
|
* Called whenever ping/pong messages are roundtripped on connection.
|
|
149
149
|
*/
|
|
150
|
-
readonly pongHandler: (latency: number) => void
|
|
150
|
+
readonly pongHandler: (latency: number) => void;
|
|
151
151
|
|
|
152
152
|
/**
|
|
153
153
|
* Called whenever connection type changes from writable to read-only or vice versa.
|
|
@@ -156,7 +156,7 @@ export interface IConnectionManagerFactoryArgs {
|
|
|
156
156
|
* This should not be confused with "read" / "write"connection mode which is internal
|
|
157
157
|
* optimization.
|
|
158
158
|
*/
|
|
159
|
-
readonly readonlyChangeHandler: (readonly?: boolean) => void
|
|
159
|
+
readonly readonlyChangeHandler: (readonly?: boolean) => void;
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
/**
|
package/src/deltaManager.ts
CHANGED
|
@@ -77,8 +77,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
77
77
|
extends TypedEventEmitter<IDeltaManagerInternalEvents>
|
|
78
78
|
implements
|
|
79
79
|
IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>,
|
|
80
|
-
IEventProvider<IDeltaManagerInternalEvents>
|
|
81
|
-
{
|
|
80
|
+
IEventProvider<IDeltaManagerInternalEvents> {
|
|
82
81
|
public readonly connectionManager: TConnectionManager;
|
|
83
82
|
|
|
84
83
|
public get active(): boolean { return this._active(); }
|
|
@@ -268,7 +267,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
268
267
|
) {
|
|
269
268
|
super();
|
|
270
269
|
const props: IConnectionManagerFactoryArgs = {
|
|
271
|
-
incomingOpHandler:(messages: ISequencedDocumentMessage[], reason: string) =>
|
|
270
|
+
incomingOpHandler: (messages: ISequencedDocumentMessage[], reason: string) =>
|
|
272
271
|
this.enqueueMessages(messages, reason),
|
|
273
272
|
signalHandler: (message: ISignalMessage) => this._inboundSignal.push(message),
|
|
274
273
|
reconnectionDelayHandler: (delayMs: number, error: unknown) =>
|
|
@@ -440,8 +439,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
440
439
|
from: number, // inclusive
|
|
441
440
|
to: number | undefined, // exclusive
|
|
442
441
|
callback: (messages: ISequencedDocumentMessage[]) => void,
|
|
443
|
-
cacheOnly: boolean)
|
|
444
|
-
{
|
|
442
|
+
cacheOnly: boolean) {
|
|
445
443
|
const docService = this.serviceProvider();
|
|
446
444
|
if (docService === undefined) {
|
|
447
445
|
throw new Error("Delta manager is not attached");
|
|
@@ -820,8 +818,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
820
818
|
private async fetchMissingDeltasCore(
|
|
821
819
|
reason: string,
|
|
822
820
|
cacheOnly: boolean,
|
|
823
|
-
to?: number)
|
|
824
|
-
{
|
|
821
|
+
to?: number) {
|
|
825
822
|
// Exit out early if we're already fetching deltas
|
|
826
823
|
if (this.fetchReason !== undefined) {
|
|
827
824
|
return;
|
|
@@ -865,7 +862,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
865
862
|
},
|
|
866
863
|
cacheOnly);
|
|
867
864
|
} catch (error) {
|
|
868
|
-
this.logger.sendErrorEvent({eventName: "GetDeltas_Exception"}, error);
|
|
865
|
+
this.logger.sendErrorEvent({ eventName: "GetDeltas_Exception" }, error);
|
|
869
866
|
this.close(normalizeError(error));
|
|
870
867
|
} finally {
|
|
871
868
|
this.refreshDelayInfo(this.deltaStorageDelayId);
|
package/src/deltaQueue.ts
CHANGED
|
@@ -7,16 +7,14 @@ import { IDeltaQueue, IDeltaQueueEvents } from "@fluidframework/container-defini
|
|
|
7
7
|
import { assert, performance, Deferred, TypedEventEmitter } from "@fluidframework/common-utils";
|
|
8
8
|
import Deque from "double-ended-queue";
|
|
9
9
|
|
|
10
|
-
export interface IDeltaQueueWriter<T>
|
|
11
|
-
{
|
|
10
|
+
export interface IDeltaQueueWriter<T> {
|
|
12
11
|
push(task: T): void;
|
|
13
12
|
clear(): void;
|
|
14
13
|
}
|
|
15
14
|
|
|
16
15
|
export class DeltaQueue<T>
|
|
17
16
|
extends TypedEventEmitter<IDeltaQueueEvents<T>>
|
|
18
|
-
implements IDeltaQueue<T>, IDeltaQueueWriter<T>
|
|
19
|
-
{
|
|
17
|
+
implements IDeltaQueue<T>, IDeltaQueueWriter<T> {
|
|
20
18
|
private isDisposed: boolean = false;
|
|
21
19
|
private readonly q = new Deque<T>();
|
|
22
20
|
|
package/src/loader.ts
CHANGED
|
@@ -80,7 +80,7 @@ export class RelativeLoader implements ILoader {
|
|
|
80
80
|
{
|
|
81
81
|
canReconnect: request.headers?.[LoaderHeader.reconnect],
|
|
82
82
|
clientDetailsOverride: request.headers?.[LoaderHeader.clientDetails],
|
|
83
|
-
resolvedUrl: {...resolvedUrl},
|
|
83
|
+
resolvedUrl: { ...resolvedUrl },
|
|
84
84
|
version: request.headers?.[LoaderHeader.version] ?? undefined,
|
|
85
85
|
loadMode: request.headers?.[LoaderHeader.loadMode],
|
|
86
86
|
},
|
|
@@ -129,7 +129,7 @@ function createCachedResolver(resolver: IUrlResolver) {
|
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
export interface ILoaderOptions extends ILoaderOptions1{
|
|
132
|
-
summarizeProtocolTree?: boolean
|
|
132
|
+
summarizeProtocolTree?: boolean;
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
/**
|
|
@@ -203,6 +203,7 @@ export interface ILoaderProps {
|
|
|
203
203
|
/**
|
|
204
204
|
* Proxy loader factories for loading containers via proxy in other contexts,
|
|
205
205
|
* like web workers, or worker threads.
|
|
206
|
+
* @deprecated Not recommended for general use and will be removed in an upcoming release.
|
|
206
207
|
*/
|
|
207
208
|
readonly proxyLoaderFactories?: Map<string, IProxyLoaderFactory>;
|
|
208
209
|
|
|
@@ -259,6 +260,7 @@ export interface ILoaderServices {
|
|
|
259
260
|
/**
|
|
260
261
|
* Proxy loader factories for loading containers via proxy in other contexts,
|
|
261
262
|
* like web workers, or worker threads.
|
|
263
|
+
* @deprecated Not recommended for general use and will be removed in an upcoming release.
|
|
262
264
|
*/
|
|
263
265
|
readonly proxyLoaderFactories: Map<string, IProxyLoaderFactory>;
|
|
264
266
|
|
|
@@ -393,7 +395,7 @@ export class Loader implements IHostLoader {
|
|
|
393
395
|
private async resolveCore(
|
|
394
396
|
request: IRequest,
|
|
395
397
|
pendingLocalState?: IPendingLocalState,
|
|
396
|
-
): Promise<{ container: Container; parsed: IParsedUrl }> {
|
|
398
|
+
): Promise<{ container: Container; parsed: IParsedUrl; }> {
|
|
397
399
|
const resolvedAsFluid = await this.services.urlResolver.resolve(request);
|
|
398
400
|
ensureFluidResolvedUrl(resolvedAsFluid);
|
|
399
401
|
|
package/src/packageVersion.ts
CHANGED
package/src/quorum.ts
CHANGED
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
import { EventForwarder, doIfNotDisposed } from "@fluidframework/common-utils";
|
|
5
|
+
import { assert, EventForwarder, doIfNotDisposed } from "@fluidframework/common-utils";
|
|
6
|
+
import { IFluidCodeDetails } from "@fluidframework/core-interfaces";
|
|
6
7
|
import {
|
|
8
|
+
ICommittedProposal,
|
|
7
9
|
IQuorum,
|
|
8
10
|
IQuorumEvents,
|
|
9
11
|
ISequencedClient,
|
|
@@ -32,3 +34,26 @@ export class QuorumProxy extends EventForwarder<IQuorumEvents> implements IQuoru
|
|
|
32
34
|
this.getMember = doIfNotDisposed(this, quorum.getMember.bind(quorum));
|
|
33
35
|
}
|
|
34
36
|
}
|
|
37
|
+
|
|
38
|
+
export function getCodeDetailsFromQuorumValues(
|
|
39
|
+
quorumValues: [string, ICommittedProposal][],
|
|
40
|
+
): IFluidCodeDetails {
|
|
41
|
+
const qValuesMap = new Map(quorumValues);
|
|
42
|
+
const proposal = qValuesMap.get("code");
|
|
43
|
+
assert(proposal !== undefined, 0x2dc /* "Cannot find code proposal" */);
|
|
44
|
+
return proposal?.value as IFluidCodeDetails;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function initQuorumValuesFromCodeDetails(
|
|
48
|
+
source: IFluidCodeDetails,
|
|
49
|
+
): [string, ICommittedProposal][] {
|
|
50
|
+
// Seed the base quorum to be an empty list with a code quorum set
|
|
51
|
+
const committedCodeProposal: ICommittedProposal = {
|
|
52
|
+
key: "code",
|
|
53
|
+
value: source,
|
|
54
|
+
approvalSequenceNumber: 0,
|
|
55
|
+
commitSequenceNumber: 0,
|
|
56
|
+
sequenceNumber: 0,
|
|
57
|
+
};
|
|
58
|
+
return [["code", committedCodeProposal]];
|
|
59
|
+
}
|
package/src/utils.ts
CHANGED
|
@@ -16,8 +16,8 @@ import { ISummaryTree, ISnapshotTree, SummaryType } from "@fluidframework/protoc
|
|
|
16
16
|
// This is used when we rehydrate a container from the snapshot. Here we put the blob contents
|
|
17
17
|
// in separate property: blobContents.
|
|
18
18
|
export interface ISnapshotTreeWithBlobContents extends ISnapshotTree {
|
|
19
|
-
blobsContents: {[path: string]: ArrayBufferLike}
|
|
20
|
-
trees: {[path: string]: ISnapshotTreeWithBlobContents}
|
|
19
|
+
blobsContents: { [path: string]: ArrayBufferLike; };
|
|
20
|
+
trees: { [path: string]: ISnapshotTreeWithBlobContents; };
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export interface IParsedUrl {
|
|
@@ -130,3 +130,7 @@ export const getSnapshotTreeFromSerializedContainer = (detachedContainerSnapshot
|
|
|
130
130
|
);
|
|
131
131
|
return snapshotTreeWithBlobContents;
|
|
132
132
|
};
|
|
133
|
+
|
|
134
|
+
export function getProtocolSnapshotTree(snapshot: ISnapshotTree): ISnapshotTree {
|
|
135
|
+
return ".protocol" in snapshot.trees ? snapshot.trees[".protocol"] : snapshot;
|
|
136
|
+
}
|