@fluidframework/container-loader 2.70.0-361248 → 2.70.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 +4 -0
- package/api-report/container-loader.legacy.alpha.api.md +13 -0
- package/dist/container.d.ts +7 -4
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +92 -16
- package/dist/container.js.map +1 -1
- package/dist/containerContext.d.ts +1 -0
- package/dist/containerContext.d.ts.map +1 -1
- package/dist/containerContext.js +1 -0
- package/dist/containerContext.js.map +1 -1
- package/dist/containerStorageAdapter.d.ts +1 -8
- package/dist/containerStorageAdapter.d.ts.map +1 -1
- package/dist/containerStorageAdapter.js +0 -9
- package/dist/containerStorageAdapter.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/legacyAlpha.d.ts +1 -0
- package/dist/loaderLayerCompatState.d.ts +4 -3
- package/dist/loaderLayerCompatState.d.ts.map +1 -1
- package/dist/loaderLayerCompatState.js +4 -34
- package/dist/loaderLayerCompatState.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/pendingLocalStateStore.d.ts +84 -0
- package/dist/pendingLocalStateStore.d.ts.map +1 -0
- package/dist/pendingLocalStateStore.js +157 -0
- package/dist/pendingLocalStateStore.js.map +1 -0
- package/dist/protocol.d.ts +1 -0
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +43 -1
- package/dist/protocol.js.map +1 -1
- package/dist/utils.d.ts +1 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +0 -4
- package/dist/utils.js.map +1 -1
- package/lib/container.d.ts +7 -4
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +93 -17
- package/lib/container.js.map +1 -1
- package/lib/containerContext.d.ts +1 -0
- package/lib/containerContext.d.ts.map +1 -1
- package/lib/containerContext.js +1 -0
- package/lib/containerContext.js.map +1 -1
- package/lib/containerStorageAdapter.d.ts +1 -8
- package/lib/containerStorageAdapter.d.ts.map +1 -1
- package/lib/containerStorageAdapter.js +0 -9
- package/lib/containerStorageAdapter.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/legacyAlpha.d.ts +1 -0
- package/lib/loaderLayerCompatState.d.ts +4 -3
- package/lib/loaderLayerCompatState.d.ts.map +1 -1
- package/lib/loaderLayerCompatState.js +5 -35
- package/lib/loaderLayerCompatState.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/pendingLocalStateStore.d.ts +84 -0
- package/lib/pendingLocalStateStore.d.ts.map +1 -0
- package/lib/pendingLocalStateStore.js +153 -0
- package/lib/pendingLocalStateStore.js.map +1 -0
- package/lib/protocol.d.ts +1 -0
- package/lib/protocol.d.ts.map +1 -1
- package/lib/protocol.js +41 -0
- package/lib/protocol.js.map +1 -1
- package/lib/utils.d.ts +1 -0
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +0 -4
- package/lib/utils.js.map +1 -1
- package/package.json +11 -11
- package/src/container.ts +129 -31
- package/src/containerContext.ts +2 -0
- package/src/containerStorageAdapter.ts +1 -11
- package/src/index.ts +1 -0
- package/src/loaderLayerCompatState.ts +21 -36
- package/src/packageVersion.ts +1 -1
- package/src/pendingLocalStateStore.ts +160 -0
- package/src/protocol.ts +49 -0
- package/src/utils.ts +6 -0
package/lib/container.js
CHANGED
|
@@ -28,7 +28,7 @@ import { validateDriverCompatibility, validateRuntimeCompatibility, } from "./lo
|
|
|
28
28
|
import { createMemoryDetachedBlobStorage, tryInitializeMemoryDetachedBlobStorage, } from "./memoryBlobStorage.js";
|
|
29
29
|
import { NoopHeuristic } from "./noopHeuristic.js";
|
|
30
30
|
import { pkgVersion } from "./packageVersion.js";
|
|
31
|
-
import { ProtocolHandler, protocolHandlerShouldProcessSignal, } from "./protocol.js";
|
|
31
|
+
import { ProtocolHandler, protocolHandlerShouldProcessSignal, wrapProtocolHandlerBuilder, } from "./protocol.js";
|
|
32
32
|
import { initQuorumValuesFromCodeDetails } from "./quorum.js";
|
|
33
33
|
import { SerializedStateManager, } from "./serializedStateManager.js";
|
|
34
34
|
import { combineAppAndProtocolSummary, combineSnapshotTreeAndSnapshotBlobs, getDetachedContainerStateFromSerializedContainer, getDocumentAttributes, getProtocolSnapshotTree, getISnapshotFromSerializedContainer, runSingle, convertISnapshotToSnapshotWithBlobs, convertSnapshotInfoToSnapshot, } from "./utils.js";
|
|
@@ -208,12 +208,16 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
208
208
|
// in the order that is not possible in real life, that it may not expect.
|
|
209
209
|
// Ideally, we should supply pendingLocalState?.clientId here as well, not in constructor, but it does not matter (at least today)
|
|
210
210
|
this.connectionStateHandler.initProtocol(this.protocolHandler);
|
|
211
|
-
// Propagate current connection state through the system.
|
|
212
|
-
const readonly = this.readOnlyInfo.readonly ?? false;
|
|
213
211
|
// This call does not look like needed any more, with delaying all connection-related events past loaded phase.
|
|
214
212
|
// Yet, there could be some customer code that would break if we do not deliver it.
|
|
215
213
|
// Will be removed in further PRs with proper changeset.
|
|
216
|
-
|
|
214
|
+
const runtime = this._runtime;
|
|
215
|
+
if (runtime !== undefined &&
|
|
216
|
+
// Check for older runtime that may need this call
|
|
217
|
+
!("setConnectionStatus" in runtime) &&
|
|
218
|
+
runtime.disposed === false) {
|
|
219
|
+
runtime.setConnectionState(false /* canSendOps */, this.clientId);
|
|
220
|
+
}
|
|
217
221
|
// Deliver delayed calls to DeltaManager - we ignored "connect" events while loading.
|
|
218
222
|
const cm = this._deltaManager.connectionManager;
|
|
219
223
|
if (cm.connected) {
|
|
@@ -373,6 +377,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
373
377
|
}, error);
|
|
374
378
|
this.close(normalizeError(error));
|
|
375
379
|
});
|
|
380
|
+
this.signalAudience = new Audience();
|
|
376
381
|
/**
|
|
377
382
|
* Lifecycle state of the container, used mainly to prevent re-entrancy and telemetry
|
|
378
383
|
*
|
|
@@ -501,7 +506,8 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
501
506
|
const { canReconnect, clientDetailsOverride, urlResolver, documentServiceFactory, codeLoader, options, scope, subLogger, protocolHandlerBuilder, retryConnectionTimeoutMs, } = createProps;
|
|
502
507
|
// Validate that the Driver is compatible with this Loader.
|
|
503
508
|
const maybeDriverCompatDetails = documentServiceFactory;
|
|
504
|
-
validateDriverCompatibility(maybeDriverCompatDetails.ILayerCompatDetails, (error) => { } /* disposeFn
|
|
509
|
+
validateDriverCompatibility(maybeDriverCompatDetails.ILayerCompatDetails, (error) => { } /* disposeFn */, // There is nothing to dispose here, so just ignore the error.
|
|
510
|
+
subLogger);
|
|
505
511
|
this.connectionTransitionTimes[ConnectionState.Disconnected] = performanceNow();
|
|
506
512
|
const pendingLocalState = loadProps?.pendingLocalState;
|
|
507
513
|
this._canReconnect = canReconnect ?? true;
|
|
@@ -515,9 +521,8 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
515
521
|
// Tracking alternative ways to handle this in AB#4129.
|
|
516
522
|
this.options = { ...options };
|
|
517
523
|
this.scope = scope;
|
|
518
|
-
this.protocolHandlerBuilder =
|
|
519
|
-
|
|
520
|
-
((attributes, quorumSnapshot, sendProposal) => new ProtocolHandler(attributes, quorumSnapshot, sendProposal, new Audience(), (clientId) => this.clientsWhoShouldHaveLeft.has(clientId)));
|
|
524
|
+
this.protocolHandlerBuilder = wrapProtocolHandlerBuilder(protocolHandlerBuilder ??
|
|
525
|
+
((attributes, quorumSnapshot, sendProposal) => new ProtocolHandler(attributes, quorumSnapshot, sendProposal, new Audience(), (clientId) => this.clientsWhoShouldHaveLeft.has(clientId))), this.signalAudience);
|
|
521
526
|
// Note that we capture the createProps here so we can replicate the creation call when we want to clone.
|
|
522
527
|
this.clone = async (_loadProps, createParamOverrides) => {
|
|
523
528
|
return Container.load(_loadProps, {
|
|
@@ -1321,7 +1326,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1321
1326
|
});
|
|
1322
1327
|
deltaManager.on("readonly", (readonly) => {
|
|
1323
1328
|
if (this.loaded) {
|
|
1324
|
-
this.
|
|
1329
|
+
this.setConnectionStatus(readonly);
|
|
1325
1330
|
}
|
|
1326
1331
|
this.emit("readonly", readonly);
|
|
1327
1332
|
});
|
|
@@ -1397,7 +1402,18 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1397
1402
|
const clientId = this.connectionStateHandler.clientId;
|
|
1398
1403
|
assert(clientId !== undefined, 0x96e /* there has to be clientId */);
|
|
1399
1404
|
this.protocolHandler.audience.setCurrentClientId(clientId);
|
|
1405
|
+
this.signalAudience.setCurrentClientId(clientId);
|
|
1406
|
+
}
|
|
1407
|
+
else if (this.connectionState === ConnectionState.CatchingUp) {
|
|
1408
|
+
// Signal-based Audience does not wait for ops. So provide clientId
|
|
1409
|
+
// as soon as possible.
|
|
1410
|
+
const clientId = this.connectionStateHandler.pendingClientId;
|
|
1411
|
+
assert(clientId !== undefined, 0xc89 /* catching up without clientId */);
|
|
1412
|
+
this.signalAudience.setCurrentClientId(clientId);
|
|
1400
1413
|
}
|
|
1414
|
+
this.setConnectionStatus(
|
|
1415
|
+
/* readonly */ this.readOnlyInfo.readonly ?? false,
|
|
1416
|
+
/* onlyCallSetConnectionStateIfConnectedOrDisconnected */ true);
|
|
1401
1417
|
// We communicate only transitions to Connected & Disconnected states, skipping all other states.
|
|
1402
1418
|
// This can be changed in the future, for example we likely should add "CatchingUp" event on Container.
|
|
1403
1419
|
if (this.connectionState !== ConnectionState.Connected &&
|
|
@@ -1405,7 +1421,6 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1405
1421
|
return;
|
|
1406
1422
|
}
|
|
1407
1423
|
// Both protocol and context should not be undefined if we got so far.
|
|
1408
|
-
this.setContextConnectedState(connected, this.readOnlyInfo.readonly ?? false);
|
|
1409
1424
|
this.protocolHandler.setConnectionState(connected, this.clientId);
|
|
1410
1425
|
raiseConnectedEvent(this.mc.logger, this, connected, this.clientId, disconnectedReason?.text);
|
|
1411
1426
|
}
|
|
@@ -1537,6 +1552,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1537
1552
|
storage: this.storageAdapter,
|
|
1538
1553
|
quorum: this.protocolHandler.quorum,
|
|
1539
1554
|
audience: this.protocolHandler.audience,
|
|
1555
|
+
signalAudience: this.signalAudience,
|
|
1540
1556
|
loader,
|
|
1541
1557
|
submitFn: (type, contents, batch, metadata) => this.submitContainerMessage(type, contents, batch, metadata),
|
|
1542
1558
|
submitSummaryFn: (summaryOp, referenceSequenceNumber) => this.submitSummaryMessage(summaryOp, referenceSequenceNumber),
|
|
@@ -1560,7 +1576,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1560
1576
|
const runtime = await PerformanceEvent.timedExecAsync(this.subLogger, { eventName: "InstantiateRuntime" }, async () => runtimeFactory.instantiateRuntime(context, existing));
|
|
1561
1577
|
// Validate that the Runtime is compatible with this Loader.
|
|
1562
1578
|
const maybeRuntimeCompatDetails = runtime;
|
|
1563
|
-
validateRuntimeCompatibility(maybeRuntimeCompatDetails.ILayerCompatDetails);
|
|
1579
|
+
validateRuntimeCompatibility(maybeRuntimeCompatDetails.ILayerCompatDetails, this.mc.logger);
|
|
1564
1580
|
this._runtime = runtime;
|
|
1565
1581
|
this._lifecycleEvents.emit("runtimeInstantiated");
|
|
1566
1582
|
this._loadedCodeDetails = codeDetails;
|
|
@@ -1571,15 +1587,75 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1571
1587
|
}
|
|
1572
1588
|
}
|
|
1573
1589
|
/**
|
|
1574
|
-
*
|
|
1575
|
-
* This controls the "connected" state of the ContainerRuntime as well
|
|
1576
|
-
* @param connected - Is the container currently connected?
|
|
1590
|
+
* Send the connected status to the runtime.
|
|
1577
1591
|
* @param readonly - Is the container in readonly mode?
|
|
1592
|
+
* @param onlyCallSetConnectionStateIfConnectedOrDisconnected - If true, only
|
|
1593
|
+
* call older `setConnectionState` on the runtime if the connection state is
|
|
1594
|
+
* either Connected or Disconnected. This exists to preserve older behavior
|
|
1595
|
+
* where the runtime was only notified of these two states.
|
|
1578
1596
|
*/
|
|
1579
|
-
|
|
1597
|
+
setConnectionStatus(readonly, onlyCallSetConnectionStateIfConnectedOrDisconnected = false) {
|
|
1580
1598
|
if (this._runtime?.disposed === false && this.loaded) {
|
|
1581
|
-
this.runtime.
|
|
1582
|
-
|
|
1599
|
+
const setConnectionStatus = this.runtime.setConnectionStatus?.bind(this.runtime);
|
|
1600
|
+
if (setConnectionStatus === undefined) {
|
|
1601
|
+
if (!onlyCallSetConnectionStateIfConnectedOrDisconnected ||
|
|
1602
|
+
this.connectionState === ConnectionState.Connected ||
|
|
1603
|
+
this.connectionState === ConnectionState.Disconnected) {
|
|
1604
|
+
this.runtime.setConnectionState(this.connectionState === ConnectionState.Connected &&
|
|
1605
|
+
!readonly /* container can send ops if connected to service and not in readonly mode */, this.clientId);
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
else {
|
|
1609
|
+
const pendingClientConnectionId = this.connectionStateHandler.pendingClientId;
|
|
1610
|
+
const connectionState = this.connectionState;
|
|
1611
|
+
switch (connectionState) {
|
|
1612
|
+
case ConnectionState.EstablishingConnection: {
|
|
1613
|
+
setConnectionStatus({
|
|
1614
|
+
connectionState,
|
|
1615
|
+
canSendOps: false,
|
|
1616
|
+
readonly,
|
|
1617
|
+
});
|
|
1618
|
+
break;
|
|
1619
|
+
}
|
|
1620
|
+
case ConnectionState.CatchingUp: {
|
|
1621
|
+
// When catching up, we have a pending clientId, but it
|
|
1622
|
+
// is not usable for ops. Send clientId with canSendOps false.
|
|
1623
|
+
assert(pendingClientConnectionId !== undefined, 0xc8a /* catching up without clientId */);
|
|
1624
|
+
setConnectionStatus({
|
|
1625
|
+
connectionState,
|
|
1626
|
+
pendingClientConnectionId,
|
|
1627
|
+
canSendOps: false,
|
|
1628
|
+
readonly,
|
|
1629
|
+
});
|
|
1630
|
+
break;
|
|
1631
|
+
}
|
|
1632
|
+
case ConnectionState.Connected: {
|
|
1633
|
+
// When connected, we have an active clientId. Pass it along
|
|
1634
|
+
// with canSendOps true/false based on readonly.
|
|
1635
|
+
const clientConnectionId = this.clientId;
|
|
1636
|
+
assert(clientConnectionId !== undefined, 0xc8b /* connected without clientId */);
|
|
1637
|
+
assert(clientConnectionId === pendingClientConnectionId, 0xc8c /* connected with different clientId than pending */);
|
|
1638
|
+
setConnectionStatus({
|
|
1639
|
+
connectionState,
|
|
1640
|
+
clientConnectionId,
|
|
1641
|
+
canSendOps: !readonly,
|
|
1642
|
+
readonly,
|
|
1643
|
+
});
|
|
1644
|
+
break;
|
|
1645
|
+
}
|
|
1646
|
+
case ConnectionState.Disconnected: {
|
|
1647
|
+
setConnectionStatus({
|
|
1648
|
+
connectionState,
|
|
1649
|
+
priorPendingClientConnectionId: pendingClientConnectionId,
|
|
1650
|
+
priorConnectedClientConnectionId: this.clientId,
|
|
1651
|
+
canSendOps: false,
|
|
1652
|
+
readonly,
|
|
1653
|
+
});
|
|
1654
|
+
break;
|
|
1655
|
+
}
|
|
1656
|
+
// No default
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1583
1659
|
}
|
|
1584
1660
|
}
|
|
1585
1661
|
handleDeltaConnectionArg(deltaConnectionArg, connectionArgs) {
|