@fluidframework/datastore 2.41.0-338401 → 2.41.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/.eslintrc.cjs +1 -4
- package/CHANGELOG.md +4 -0
- package/dist/channelContext.d.ts +7 -5
- package/dist/channelContext.d.ts.map +1 -1
- package/dist/channelContext.js +3 -1
- package/dist/channelContext.js.map +1 -1
- package/dist/channelDeltaConnection.d.ts +5 -5
- package/dist/channelDeltaConnection.d.ts.map +1 -1
- package/dist/channelDeltaConnection.js +7 -6
- package/dist/channelDeltaConnection.js.map +1 -1
- package/dist/channelStorageService.js +2 -2
- package/dist/channelStorageService.js.map +1 -1
- package/dist/dataStoreRuntime.d.ts.map +1 -1
- package/dist/dataStoreRuntime.js +65 -37
- package/dist/dataStoreRuntime.js.map +1 -1
- package/dist/fluidHandle.d.ts.map +1 -1
- package/dist/fluidHandle.js +6 -2
- package/dist/fluidHandle.js.map +1 -1
- package/dist/localChannelContext.d.ts +8 -6
- package/dist/localChannelContext.d.ts.map +1 -1
- package/dist/localChannelContext.js +8 -6
- package/dist/localChannelContext.js.map +1 -1
- package/dist/localChannelStorageService.d.ts.map +1 -1
- package/dist/localChannelStorageService.js +6 -4
- package/dist/localChannelStorageService.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/remoteChannelContext.d.ts +7 -5
- package/dist/remoteChannelContext.d.ts.map +1 -1
- package/dist/remoteChannelContext.js +5 -4
- package/dist/remoteChannelContext.js.map +1 -1
- package/lib/channelContext.d.ts +7 -5
- package/lib/channelContext.d.ts.map +1 -1
- package/lib/channelContext.js +3 -1
- package/lib/channelContext.js.map +1 -1
- package/lib/channelDeltaConnection.d.ts +5 -5
- package/lib/channelDeltaConnection.d.ts.map +1 -1
- package/lib/channelDeltaConnection.js +7 -6
- package/lib/channelDeltaConnection.js.map +1 -1
- package/lib/channelStorageService.js +2 -2
- package/lib/channelStorageService.js.map +1 -1
- package/lib/dataStoreRuntime.d.ts.map +1 -1
- package/lib/dataStoreRuntime.js +65 -37
- package/lib/dataStoreRuntime.js.map +1 -1
- package/lib/fluidHandle.d.ts.map +1 -1
- package/lib/fluidHandle.js +6 -2
- package/lib/fluidHandle.js.map +1 -1
- package/lib/localChannelContext.d.ts +8 -6
- package/lib/localChannelContext.d.ts.map +1 -1
- package/lib/localChannelContext.js +8 -6
- package/lib/localChannelContext.js.map +1 -1
- package/lib/localChannelStorageService.d.ts.map +1 -1
- package/lib/localChannelStorageService.js +6 -4
- package/lib/localChannelStorageService.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/remoteChannelContext.d.ts +7 -5
- package/lib/remoteChannelContext.d.ts.map +1 -1
- package/lib/remoteChannelContext.js +5 -4
- package/lib/remoteChannelContext.js.map +1 -1
- package/package.json +15 -15
- package/src/channelContext.ts +7 -5
- package/src/channelDeltaConnection.ts +19 -19
- package/src/channelStorageService.ts +3 -3
- package/src/dataStoreRuntime.ts +100 -64
- package/src/fluidHandle.ts +7 -3
- package/src/localChannelContext.ts +18 -16
- package/src/localChannelStorageService.ts +6 -4
- package/src/packageVersion.ts +1 -1
- package/src/remoteChannelContext.ts +19 -19
package/src/dataStoreRuntime.ts
CHANGED
|
@@ -201,22 +201,25 @@ export class FluidDataStoreRuntime
|
|
|
201
201
|
return this.dataStoreContext.idCompressor;
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
-
|
|
204
|
+
// TODO: the methods below should have more specific return typing, per the interfaces they are implementing.
|
|
205
|
+
// Doing so would be a breaking change.
|
|
206
|
+
|
|
207
|
+
public get IFluidHandleContext(): this {
|
|
205
208
|
return this;
|
|
206
209
|
}
|
|
207
210
|
|
|
208
|
-
public get rootRoutingContext() {
|
|
211
|
+
public get rootRoutingContext(): this {
|
|
209
212
|
return this;
|
|
210
213
|
}
|
|
211
|
-
public get channelsRoutingContext() {
|
|
214
|
+
public get channelsRoutingContext(): this {
|
|
212
215
|
return this;
|
|
213
216
|
}
|
|
214
|
-
public get objectsRoutingContext() {
|
|
217
|
+
public get objectsRoutingContext(): this {
|
|
215
218
|
return this;
|
|
216
219
|
}
|
|
217
220
|
|
|
218
221
|
private _disposed = false;
|
|
219
|
-
public get disposed() {
|
|
222
|
+
public get disposed(): boolean {
|
|
220
223
|
return this._disposed;
|
|
221
224
|
}
|
|
222
225
|
|
|
@@ -234,6 +237,8 @@ export class FluidDataStoreRuntime
|
|
|
234
237
|
|
|
235
238
|
public readonly id: string;
|
|
236
239
|
|
|
240
|
+
// TODO: use something other than `any` here (breaking change)
|
|
241
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
237
242
|
public readonly options: Record<string | number, any>;
|
|
238
243
|
public readonly deltaManagerInternal: IDeltaManager<
|
|
239
244
|
ISequencedDocumentMessage,
|
|
@@ -337,10 +342,10 @@ export class FluidDataStoreRuntime
|
|
|
337
342
|
|
|
338
343
|
// Must always receive the data store type inside of the attributes
|
|
339
344
|
if (tree?.trees !== undefined) {
|
|
340
|
-
Object.entries(tree.trees)
|
|
345
|
+
for (const [path, subtree] of Object.entries(tree.trees)) {
|
|
341
346
|
// Issue #4414
|
|
342
347
|
if (path === "_search") {
|
|
343
|
-
|
|
348
|
+
continue;
|
|
344
349
|
}
|
|
345
350
|
|
|
346
351
|
let channelContext: RemoteChannelContext | RehydratedLocalChannelContext;
|
|
@@ -353,10 +358,10 @@ export class FluidDataStoreRuntime
|
|
|
353
358
|
// data store, if the data store is loaded after the container is attached, then we missed making
|
|
354
359
|
// the channel visible. So do it now. Otherwise, add it to local channel context queue, so
|
|
355
360
|
// that it can be make it visible later with the data store.
|
|
356
|
-
if (dataStoreContext.attachState
|
|
357
|
-
channelContext.makeVisible();
|
|
358
|
-
} else {
|
|
361
|
+
if (dataStoreContext.attachState === AttachState.Detached) {
|
|
359
362
|
this.localChannelContextQueue.set(path, channelContext);
|
|
363
|
+
} else {
|
|
364
|
+
channelContext.makeVisible();
|
|
360
365
|
}
|
|
361
366
|
} else {
|
|
362
367
|
channelContext = new RemoteChannelContext(
|
|
@@ -376,7 +381,7 @@ export class FluidDataStoreRuntime
|
|
|
376
381
|
}
|
|
377
382
|
|
|
378
383
|
this.contexts.set(path, channelContext);
|
|
379
|
-
}
|
|
384
|
+
}
|
|
380
385
|
}
|
|
381
386
|
|
|
382
387
|
this.entryPoint = new FluidObjectHandle<FluidObject>(
|
|
@@ -508,7 +513,7 @@ export class FluidDataStoreRuntime
|
|
|
508
513
|
* IDs cannot start with "_" as it could result in collision of IDs with auto-assigned (by FF) short IDs.
|
|
509
514
|
* @param id - channel ID.
|
|
510
515
|
*/
|
|
511
|
-
protected validateChannelId(id: string) {
|
|
516
|
+
protected validateChannelId(id: string): void {
|
|
512
517
|
if (id.includes("/")) {
|
|
513
518
|
throw new UsageError(`Id cannot contain slashes: ${id}`);
|
|
514
519
|
}
|
|
@@ -546,10 +551,7 @@ export class FluidDataStoreRuntime
|
|
|
546
551
|
public createChannel(idArg: string | undefined, type: string): IChannel {
|
|
547
552
|
let id: string;
|
|
548
553
|
|
|
549
|
-
if (idArg
|
|
550
|
-
id = idArg;
|
|
551
|
-
this.validateChannelId(id);
|
|
552
|
-
} else {
|
|
554
|
+
if (idArg === undefined) {
|
|
553
555
|
/**
|
|
554
556
|
* Return uuid if short-ids are explicitly disabled via feature flags.
|
|
555
557
|
*/
|
|
@@ -562,18 +564,21 @@ export class FluidDataStoreRuntime
|
|
|
562
564
|
// - uuids
|
|
563
565
|
// In first two cases we will encode result as strings in more compact form, with leading underscore,
|
|
564
566
|
// to ensure no overlap with user-provided DDS names (see validateChannelId())
|
|
565
|
-
if (this.visibilityState
|
|
566
|
-
// container is detached, only one client observes content, no way to hit collisions with other clients.
|
|
567
|
-
id = encodeCompactIdToString(2 * this.contexts.size, "_");
|
|
568
|
-
} else {
|
|
567
|
+
if (this.visibilityState === VisibilityState.GloballyVisible) {
|
|
569
568
|
// Due to back-compat, we could not depend yet on generateDocumentUniqueId() being there.
|
|
570
569
|
// We can remove the need to leverage uuid() as fall-back in couple releases.
|
|
571
570
|
const res =
|
|
572
571
|
this.dataStoreContext.containerRuntime.generateDocumentUniqueId?.() ?? uuid();
|
|
573
572
|
id = typeof res === "number" ? encodeCompactIdToString(2 * res + 1, "_") : res;
|
|
573
|
+
} else {
|
|
574
|
+
// container is detached, only one client observes content, no way to hit collisions with other clients.
|
|
575
|
+
id = encodeCompactIdToString(2 * this.contexts.size, "_");
|
|
574
576
|
}
|
|
575
577
|
}
|
|
576
578
|
assert(!id.includes("/"), 0x8fc /* slash */);
|
|
579
|
+
} else {
|
|
580
|
+
id = idArg;
|
|
581
|
+
this.validateChannelId(id);
|
|
577
582
|
}
|
|
578
583
|
|
|
579
584
|
this.verifyNotClosed();
|
|
@@ -592,7 +597,7 @@ export class FluidDataStoreRuntime
|
|
|
592
597
|
return channel;
|
|
593
598
|
}
|
|
594
599
|
|
|
595
|
-
private createChannelContext(channel: IChannel) {
|
|
600
|
+
private createChannelContext(channel: IChannel): void {
|
|
596
601
|
this.notBoundedChannelContextSet.add(channel.id);
|
|
597
602
|
const context = new LocalChannelContext(
|
|
598
603
|
channel,
|
|
@@ -610,7 +615,7 @@ export class FluidDataStoreRuntime
|
|
|
610
615
|
id: string,
|
|
611
616
|
tree: ISnapshotTree,
|
|
612
617
|
flatBlobs?: Map<string, ArrayBufferLike>,
|
|
613
|
-
) {
|
|
618
|
+
): RehydratedLocalChannelContext {
|
|
614
619
|
return new RehydratedLocalChannelContext(
|
|
615
620
|
id,
|
|
616
621
|
this.sharedObjectRegistry,
|
|
@@ -672,15 +677,15 @@ export class FluidDataStoreRuntime
|
|
|
672
677
|
* visible, it will mark us globally visible. Otherwise, it will mark us globally visible when it becomes
|
|
673
678
|
* globally visible.
|
|
674
679
|
*/
|
|
675
|
-
public makeVisibleAndAttachGraph() {
|
|
680
|
+
public makeVisibleAndAttachGraph(): void {
|
|
676
681
|
if (this.visibilityState !== VisibilityState.NotVisible) {
|
|
677
682
|
return;
|
|
678
683
|
}
|
|
679
684
|
this.visibilityState = VisibilityState.LocallyVisible;
|
|
680
685
|
|
|
681
|
-
this.pendingHandlesToMakeVisible
|
|
686
|
+
for (const handle of this.pendingHandlesToMakeVisible) {
|
|
682
687
|
handle.attachGraph();
|
|
683
|
-
}
|
|
688
|
+
}
|
|
684
689
|
this.pendingHandlesToMakeVisible.clear();
|
|
685
690
|
this.dataStoreContext.makeLocallyVisible();
|
|
686
691
|
}
|
|
@@ -688,7 +693,7 @@ export class FluidDataStoreRuntime
|
|
|
688
693
|
/**
|
|
689
694
|
* This function is called when a handle to this data store is added to a visible DDS.
|
|
690
695
|
*/
|
|
691
|
-
public attachGraph() {
|
|
696
|
+
public attachGraph(): void {
|
|
692
697
|
this.makeVisibleAndAttachGraph();
|
|
693
698
|
}
|
|
694
699
|
|
|
@@ -701,7 +706,7 @@ export class FluidDataStoreRuntime
|
|
|
701
706
|
this.pendingHandlesToMakeVisible.add(toFluidHandleInternal(handle));
|
|
702
707
|
}
|
|
703
708
|
|
|
704
|
-
public setConnectionState(connected: boolean, clientId?: string) {
|
|
709
|
+
public setConnectionState(connected: boolean, clientId?: string): void {
|
|
705
710
|
this.verifyNotClosed();
|
|
706
711
|
|
|
707
712
|
for (const [, object] of this.contexts) {
|
|
@@ -745,7 +750,7 @@ export class FluidDataStoreRuntime
|
|
|
745
750
|
private createRemoteChannelContext(
|
|
746
751
|
attachMessage: IAttachMessage,
|
|
747
752
|
summarizerNodeParams: CreateChildSummarizerNodeParam,
|
|
748
|
-
) {
|
|
753
|
+
): RemoteChannelContext {
|
|
749
754
|
const flatBlobs = new Map<string, ArrayBufferLike>();
|
|
750
755
|
const snapshotTree = buildSnapshotTree(attachMessage.snapshot.entries, flatBlobs);
|
|
751
756
|
|
|
@@ -773,7 +778,7 @@ export class FluidDataStoreRuntime
|
|
|
773
778
|
* store.
|
|
774
779
|
* @param messageCollection - The collection of messages to process.
|
|
775
780
|
*/
|
|
776
|
-
private processChannelMessages(messageCollection: IRuntimeMessageCollection) {
|
|
781
|
+
private processChannelMessages(messageCollection: IRuntimeMessageCollection): void {
|
|
777
782
|
this.verifyNotClosed();
|
|
778
783
|
|
|
779
784
|
/*
|
|
@@ -783,9 +788,9 @@ export class FluidDataStoreRuntime
|
|
|
783
788
|
*/
|
|
784
789
|
let currentAddress: string | undefined;
|
|
785
790
|
let currentMessagesContent: IRuntimeMessagesContent[] = [];
|
|
786
|
-
const { messagesContent, local } = messageCollection;
|
|
791
|
+
const { messagesContent, local, envelope } = messageCollection;
|
|
787
792
|
|
|
788
|
-
const sendBunchedMessages = () => {
|
|
793
|
+
const sendBunchedMessages = (): void => {
|
|
789
794
|
// Current address will be undefined for the first message in the list.
|
|
790
795
|
if (currentAddress === undefined) {
|
|
791
796
|
return;
|
|
@@ -796,7 +801,7 @@ export class FluidDataStoreRuntime
|
|
|
796
801
|
assert(!!channelContext, 0xa6b /* Channel context not found */);
|
|
797
802
|
|
|
798
803
|
channelContext.processMessages({
|
|
799
|
-
envelope
|
|
804
|
+
envelope,
|
|
800
805
|
messagesContent: currentMessagesContent,
|
|
801
806
|
local,
|
|
802
807
|
});
|
|
@@ -823,7 +828,7 @@ export class FluidDataStoreRuntime
|
|
|
823
828
|
sendBunchedMessages();
|
|
824
829
|
}
|
|
825
830
|
|
|
826
|
-
private processAttachMessages(messageCollection: IRuntimeMessageCollection) {
|
|
831
|
+
private processAttachMessages(messageCollection: IRuntimeMessageCollection): void {
|
|
827
832
|
const { envelope, messagesContent, local } = messageCollection;
|
|
828
833
|
for (const { contents } of messagesContent) {
|
|
829
834
|
const attachMessage = contents as IAttachMessage;
|
|
@@ -871,12 +876,14 @@ export class FluidDataStoreRuntime
|
|
|
871
876
|
const { envelope, messagesContent } = messageCollection;
|
|
872
877
|
try {
|
|
873
878
|
switch (envelope.type) {
|
|
874
|
-
case DataStoreMessageType.ChannelOp:
|
|
879
|
+
case DataStoreMessageType.ChannelOp: {
|
|
875
880
|
this.processChannelMessages(messageCollection);
|
|
876
881
|
break;
|
|
877
|
-
|
|
882
|
+
}
|
|
883
|
+
case DataStoreMessageType.Attach: {
|
|
878
884
|
this.processAttachMessages(messageCollection);
|
|
879
885
|
break;
|
|
886
|
+
}
|
|
880
887
|
default:
|
|
881
888
|
}
|
|
882
889
|
} catch (error) {
|
|
@@ -892,7 +899,7 @@ export class FluidDataStoreRuntime
|
|
|
892
899
|
}
|
|
893
900
|
}
|
|
894
901
|
|
|
895
|
-
public processSignal(message: IInboundSignalMessage, local: boolean) {
|
|
902
|
+
public processSignal(message: IInboundSignalMessage, local: boolean): void {
|
|
896
903
|
this.emit("signal", message, local);
|
|
897
904
|
}
|
|
898
905
|
|
|
@@ -929,7 +936,7 @@ export class FluidDataStoreRuntime
|
|
|
929
936
|
* - Adds a node for this channel.
|
|
930
937
|
* @param builder - The builder that contains the GC nodes for this channel's children.
|
|
931
938
|
*/
|
|
932
|
-
private updateGCNodes(builder: GCDataBuilder) {
|
|
939
|
+
private updateGCNodes(builder: GCDataBuilder): void {
|
|
933
940
|
// Add a back route to self in each child's GC nodes. If any child is referenced, then its parent should
|
|
934
941
|
// be considered referenced as well.
|
|
935
942
|
builder.addRouteToAllNodes(this.absolutePath);
|
|
@@ -993,7 +1000,7 @@ export class FluidDataStoreRuntime
|
|
|
993
1000
|
* update their used routes.
|
|
994
1001
|
* @param usedRoutes - The routes that are used in all contexts in this channel.
|
|
995
1002
|
*/
|
|
996
|
-
public updateUsedRoutes(usedRoutes: string[]) {
|
|
1003
|
+
public updateUsedRoutes(usedRoutes: string[]): void {
|
|
997
1004
|
// Get a map of channel ids to routes used in it.
|
|
998
1005
|
const usedContextRoutes = unpackChildNodesUsedRoutes(usedRoutes);
|
|
999
1006
|
|
|
@@ -1132,7 +1139,13 @@ export class FluidDataStoreRuntime
|
|
|
1132
1139
|
}
|
|
1133
1140
|
}
|
|
1134
1141
|
|
|
1135
|
-
public submitMessage(
|
|
1142
|
+
public submitMessage(
|
|
1143
|
+
type: DataStoreMessageType,
|
|
1144
|
+
// TODO: use something other than `any` here (breaking change)
|
|
1145
|
+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
|
|
1146
|
+
content: any,
|
|
1147
|
+
localOpMetadata: unknown,
|
|
1148
|
+
): void {
|
|
1136
1149
|
this.submit(type, content, localOpMetadata);
|
|
1137
1150
|
}
|
|
1138
1151
|
|
|
@@ -1142,9 +1155,9 @@ export class FluidDataStoreRuntime
|
|
|
1142
1155
|
* @param content - Content of the signal. Should be a JSON serializable object or primitive.
|
|
1143
1156
|
* @param targetClientId - When specified, the signal is only sent to the provided client id.
|
|
1144
1157
|
*/
|
|
1145
|
-
public submitSignal(type: string, content: unknown, targetClientId?: string) {
|
|
1158
|
+
public submitSignal(type: string, content: unknown, targetClientId?: string): void {
|
|
1146
1159
|
this.verifyNotClosed();
|
|
1147
|
-
|
|
1160
|
+
this.dataStoreContext.submitSignal(type, content, targetClientId);
|
|
1148
1161
|
}
|
|
1149
1162
|
|
|
1150
1163
|
/**
|
|
@@ -1201,14 +1214,14 @@ export class FluidDataStoreRuntime
|
|
|
1201
1214
|
context.makeVisible();
|
|
1202
1215
|
}
|
|
1203
1216
|
|
|
1204
|
-
private submitChannelOp(address: string, contents:
|
|
1217
|
+
private submitChannelOp(address: string, contents: unknown, localOpMetadata: unknown): void {
|
|
1205
1218
|
const envelope: IEnvelope = { address, contents };
|
|
1206
1219
|
this.submit(DataStoreMessageType.ChannelOp, envelope, localOpMetadata);
|
|
1207
1220
|
}
|
|
1208
1221
|
|
|
1209
1222
|
private submit(
|
|
1210
1223
|
type: DataStoreMessageType,
|
|
1211
|
-
content:
|
|
1224
|
+
content: unknown,
|
|
1212
1225
|
localOpMetadata: unknown = undefined,
|
|
1213
1226
|
): void {
|
|
1214
1227
|
this.verifyNotClosed();
|
|
@@ -1224,10 +1237,12 @@ export class FluidDataStoreRuntime
|
|
|
1224
1237
|
*/
|
|
1225
1238
|
public reSubmit(
|
|
1226
1239
|
type: DataStoreMessageType,
|
|
1240
|
+
// TODO: use something other than `any` here (breaking change)
|
|
1241
|
+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
|
|
1227
1242
|
content: any,
|
|
1228
1243
|
localOpMetadata: unknown,
|
|
1229
1244
|
squash?: boolean,
|
|
1230
|
-
) {
|
|
1245
|
+
): void {
|
|
1231
1246
|
this.verifyNotClosed();
|
|
1232
1247
|
|
|
1233
1248
|
switch (type) {
|
|
@@ -1239,12 +1254,14 @@ export class FluidDataStoreRuntime
|
|
|
1239
1254
|
channelContext.reSubmit(envelope.contents, localOpMetadata, squash);
|
|
1240
1255
|
break;
|
|
1241
1256
|
}
|
|
1242
|
-
case DataStoreMessageType.Attach:
|
|
1257
|
+
case DataStoreMessageType.Attach: {
|
|
1243
1258
|
// For Attach messages, just submit them again.
|
|
1244
1259
|
this.submit(type, content, localOpMetadata);
|
|
1245
1260
|
break;
|
|
1246
|
-
|
|
1261
|
+
}
|
|
1262
|
+
default: {
|
|
1247
1263
|
unreachableCase(type);
|
|
1264
|
+
}
|
|
1248
1265
|
}
|
|
1249
1266
|
}
|
|
1250
1267
|
|
|
@@ -1253,7 +1270,13 @@ export class FluidDataStoreRuntime
|
|
|
1253
1270
|
* @param content - The content of the original message.
|
|
1254
1271
|
* @param localOpMetadata - The local metadata associated with the original message.
|
|
1255
1272
|
*/
|
|
1256
|
-
public rollback?(
|
|
1273
|
+
public rollback?(
|
|
1274
|
+
type: DataStoreMessageType,
|
|
1275
|
+
// TODO: use something other than `any` here (breaking change)
|
|
1276
|
+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
|
|
1277
|
+
content: any,
|
|
1278
|
+
localOpMetadata: unknown,
|
|
1279
|
+
): void {
|
|
1257
1280
|
this.verifyNotClosed();
|
|
1258
1281
|
|
|
1259
1282
|
switch (type) {
|
|
@@ -1265,15 +1288,20 @@ export class FluidDataStoreRuntime
|
|
|
1265
1288
|
channelContext.rollback(envelope.contents, localOpMetadata);
|
|
1266
1289
|
break;
|
|
1267
1290
|
}
|
|
1268
|
-
default:
|
|
1291
|
+
default: {
|
|
1269
1292
|
throw new LoggingError(`Can't rollback ${type} message`);
|
|
1293
|
+
}
|
|
1270
1294
|
}
|
|
1271
1295
|
}
|
|
1272
1296
|
|
|
1297
|
+
// TODO: use something other than `any` here
|
|
1298
|
+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
|
|
1273
1299
|
public async applyStashedOp(content: any): Promise<unknown> {
|
|
1300
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
1274
1301
|
const type = content?.type as DataStoreMessageType;
|
|
1275
1302
|
switch (type) {
|
|
1276
1303
|
case DataStoreMessageType.Attach: {
|
|
1304
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
1277
1305
|
const attachMessage = content.content as IAttachMessage;
|
|
1278
1306
|
|
|
1279
1307
|
const flatBlobs = new Map<string, ArrayBufferLike>();
|
|
@@ -1295,14 +1323,16 @@ export class FluidDataStoreRuntime
|
|
|
1295
1323
|
return;
|
|
1296
1324
|
}
|
|
1297
1325
|
case DataStoreMessageType.ChannelOp: {
|
|
1326
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
1298
1327
|
const envelope = content.content as IEnvelope;
|
|
1299
1328
|
const channelContext = this.contexts.get(envelope.address);
|
|
1300
1329
|
assert(!!channelContext, 0x184 /* "There should be a channel context for the op" */);
|
|
1301
1330
|
await channelContext.getChannel();
|
|
1302
1331
|
return channelContext.applyStashedOp(envelope.contents);
|
|
1303
1332
|
}
|
|
1304
|
-
default:
|
|
1333
|
+
default: {
|
|
1305
1334
|
unreachableCase(type);
|
|
1335
|
+
}
|
|
1306
1336
|
}
|
|
1307
1337
|
}
|
|
1308
1338
|
|
|
@@ -1311,23 +1341,25 @@ export class FluidDataStoreRuntime
|
|
|
1311
1341
|
this.dataStoreContext.setChannelDirty(address);
|
|
1312
1342
|
}
|
|
1313
1343
|
|
|
1314
|
-
private attachListener() {
|
|
1344
|
+
private attachListener(): void {
|
|
1315
1345
|
this.setMaxListeners(Number.MAX_SAFE_INTEGER);
|
|
1316
1346
|
|
|
1317
1347
|
// back-compat, to be removed in the future.
|
|
1318
1348
|
// Added in "2.0.0-rc.2.0.0" timeframe.
|
|
1349
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-explicit-any
|
|
1319
1350
|
(this.dataStoreContext as any).once?.("attaching", () => {
|
|
1320
1351
|
this.setAttachState(AttachState.Attaching);
|
|
1321
1352
|
});
|
|
1322
1353
|
|
|
1323
1354
|
// back-compat, to be removed in the future.
|
|
1324
1355
|
// Added in "2.0.0-rc.2.0.0" timeframe.
|
|
1356
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-explicit-any
|
|
1325
1357
|
(this.dataStoreContext as any).once?.("attached", () => {
|
|
1326
1358
|
this.setAttachState(AttachState.Attached);
|
|
1327
1359
|
});
|
|
1328
1360
|
}
|
|
1329
1361
|
|
|
1330
|
-
private verifyNotClosed() {
|
|
1362
|
+
private verifyNotClosed(): void {
|
|
1331
1363
|
if (this._disposed) {
|
|
1332
1364
|
throw new LoggingError("Runtime is closed");
|
|
1333
1365
|
}
|
|
@@ -1342,7 +1374,7 @@ export class FluidDataStoreRuntime
|
|
|
1342
1374
|
eventName: string,
|
|
1343
1375
|
channelId: string,
|
|
1344
1376
|
channelType: string,
|
|
1345
|
-
) {
|
|
1377
|
+
): void {
|
|
1346
1378
|
if (this.clientDetails.type !== "summarizer" || this.localChangesTelemetryCount <= 0) {
|
|
1347
1379
|
return;
|
|
1348
1380
|
}
|
|
@@ -1365,7 +1397,7 @@ export class FluidDataStoreRuntime
|
|
|
1365
1397
|
|
|
1366
1398
|
public setAttachState(attachState: AttachState.Attaching | AttachState.Attached): void {
|
|
1367
1399
|
switch (attachState) {
|
|
1368
|
-
case AttachState.Attaching:
|
|
1400
|
+
case AttachState.Attaching: {
|
|
1369
1401
|
/**
|
|
1370
1402
|
* back-compat 0.59.1000 - Ideally, attachGraph() should have already been called making the data store
|
|
1371
1403
|
* locally visible. However, before visibility state was added, this may not have been the case and data
|
|
@@ -1386,16 +1418,17 @@ export class FluidDataStoreRuntime
|
|
|
1386
1418
|
|
|
1387
1419
|
// Mark the data store globally visible and make its child channels visible as well.
|
|
1388
1420
|
this.visibilityState = VisibilityState.GloballyVisible;
|
|
1389
|
-
this.localChannelContextQueue
|
|
1421
|
+
for (const [, channel] of this.localChannelContextQueue) {
|
|
1390
1422
|
channel.makeVisible();
|
|
1391
|
-
}
|
|
1423
|
+
}
|
|
1392
1424
|
this.localChannelContextQueue.clear();
|
|
1393
1425
|
|
|
1394
1426
|
// This promise resolution will be moved to attached event once we fix the scheduler.
|
|
1395
1427
|
this.deferredAttached.resolve();
|
|
1396
1428
|
this.emit("attaching");
|
|
1397
1429
|
break;
|
|
1398
|
-
|
|
1430
|
+
}
|
|
1431
|
+
case AttachState.Attached: {
|
|
1399
1432
|
assert(
|
|
1400
1433
|
this.visibilityState === VisibilityState.GloballyVisible,
|
|
1401
1434
|
0x2d2 /* "Data store should be globally visible when its attached." */,
|
|
@@ -1403,8 +1436,10 @@ export class FluidDataStoreRuntime
|
|
|
1403
1436
|
this._attachState = AttachState.Attached;
|
|
1404
1437
|
this.emit("attached");
|
|
1405
1438
|
break;
|
|
1406
|
-
|
|
1439
|
+
}
|
|
1440
|
+
default: {
|
|
1407
1441
|
unreachableCase(attachState, "unreached");
|
|
1442
|
+
}
|
|
1408
1443
|
}
|
|
1409
1444
|
}
|
|
1410
1445
|
}
|
|
@@ -1420,9 +1455,9 @@ export class FluidDataStoreRuntime
|
|
|
1420
1455
|
export const mixinRequestHandler = (
|
|
1421
1456
|
requestHandler: (request: IRequest, runtime: FluidDataStoreRuntime) => Promise<IResponse>,
|
|
1422
1457
|
Base: typeof FluidDataStoreRuntime = FluidDataStoreRuntime,
|
|
1423
|
-
) =>
|
|
1458
|
+
): typeof FluidDataStoreRuntime =>
|
|
1424
1459
|
class RuntimeWithRequestHandler extends Base {
|
|
1425
|
-
public async request(request: IRequest) {
|
|
1460
|
+
public async request(request: IRequest): Promise<IResponse> {
|
|
1426
1461
|
const response = await super.request(request);
|
|
1427
1462
|
if (response.status === 404) {
|
|
1428
1463
|
return requestHandler(request, this);
|
|
@@ -1444,9 +1479,9 @@ export const mixinSummaryHandler = (
|
|
|
1444
1479
|
runtime: FluidDataStoreRuntime,
|
|
1445
1480
|
) => Promise<{ path: string[]; content: string } | undefined>,
|
|
1446
1481
|
Base: typeof FluidDataStoreRuntime = FluidDataStoreRuntime,
|
|
1447
|
-
) =>
|
|
1482
|
+
): typeof FluidDataStoreRuntime =>
|
|
1448
1483
|
class RuntimeWithSummarizerHandler extends Base {
|
|
1449
|
-
private addBlob(summary: ISummaryTreeWithStats, path: string[], content: string) {
|
|
1484
|
+
private addBlob(summary: ISummaryTreeWithStats, path: string[], content: string): void {
|
|
1450
1485
|
const firstName = path.shift();
|
|
1451
1486
|
if (firstName === undefined) {
|
|
1452
1487
|
throw new LoggingError("Path can't be empty");
|
|
@@ -1469,7 +1504,8 @@ export const mixinSummaryHandler = (
|
|
|
1469
1504
|
summary.summary.tree[firstName] = blob;
|
|
1470
1505
|
}
|
|
1471
1506
|
|
|
1472
|
-
async summarize(...args: any[]) {
|
|
1507
|
+
async summarize(...args: any[]): Promise<ISummaryTreeWithStats> {
|
|
1508
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
1473
1509
|
const summary = await super.summarize(...args);
|
|
1474
1510
|
|
|
1475
1511
|
try {
|
|
@@ -1477,9 +1513,9 @@ export const mixinSummaryHandler = (
|
|
|
1477
1513
|
if (content !== undefined) {
|
|
1478
1514
|
this.addBlob(summary, content.path, content.content);
|
|
1479
1515
|
}
|
|
1480
|
-
} catch (
|
|
1516
|
+
} catch (error) {
|
|
1481
1517
|
// Any error coming from app-provided handler should be marked as DataProcessingError
|
|
1482
|
-
throw DataProcessingError.wrapIfUnrecognized(
|
|
1518
|
+
throw DataProcessingError.wrapIfUnrecognized(error, "mixinSummaryHandler");
|
|
1483
1519
|
}
|
|
1484
1520
|
|
|
1485
1521
|
return summary;
|
package/src/fluidHandle.ts
CHANGED
|
@@ -77,6 +77,9 @@ export class FluidObjectHandle<
|
|
|
77
77
|
/**
|
|
78
78
|
* {@inheritDoc @fluidframework/core-interfaces#IFluidHandle.get}
|
|
79
79
|
*/
|
|
80
|
+
// TODO: Return `Promise<T>` instead of `Promise<any>`.
|
|
81
|
+
// This was clearly the intended typing of this API, but fixing it would be a breaking change.
|
|
82
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
80
83
|
public async get(): Promise<any> {
|
|
81
84
|
// Note that this return works whether we received a T or a Promise<T> for this.value in the constructor.
|
|
82
85
|
return this.value;
|
|
@@ -91,18 +94,19 @@ export class FluidObjectHandle<
|
|
|
91
94
|
}
|
|
92
95
|
|
|
93
96
|
this.locallyVisible = true;
|
|
94
|
-
this.pendingHandlesToMakeVisible
|
|
97
|
+
for (const handle of this.pendingHandlesToMakeVisible) {
|
|
95
98
|
handle.attachGraph();
|
|
96
|
-
}
|
|
99
|
+
}
|
|
97
100
|
this.pendingHandlesToMakeVisible.clear();
|
|
98
101
|
this.routeContext.attachGraph();
|
|
99
102
|
}
|
|
100
103
|
|
|
104
|
+
// eslint-disable-next-line jsdoc/require-description
|
|
101
105
|
/**
|
|
102
106
|
* @deprecated No replacement provided. Arbitrary handles may not serve as a bind source.
|
|
103
107
|
* @privateRemarks This implementation will be moved to SharedObjectHandle once this is removed.
|
|
104
108
|
*/
|
|
105
|
-
public bind(handle: IFluidHandleInternal) {
|
|
109
|
+
public bind(handle: IFluidHandleInternal): void {
|
|
106
110
|
// If this handle is visible, attach the graph of the incoming handle as well.
|
|
107
111
|
if (this.visible) {
|
|
108
112
|
handle.attachGraph();
|
|
@@ -42,7 +42,9 @@ import { ISharedObjectRegistry } from "./dataStoreRuntime.js";
|
|
|
42
42
|
*/
|
|
43
43
|
export abstract class LocalChannelContextBase implements IChannelContext {
|
|
44
44
|
private globallyVisible = false;
|
|
45
|
-
/**
|
|
45
|
+
/**
|
|
46
|
+
* Tracks the messages for this channel that are sent while it's not loaded
|
|
47
|
+
*/
|
|
46
48
|
protected pendingMessagesState: IPendingMessagesState = {
|
|
47
49
|
messageCollections: [],
|
|
48
50
|
pendingCount: 0,
|
|
@@ -57,7 +59,7 @@ export abstract class LocalChannelContextBase implements IChannelContext {
|
|
|
57
59
|
assert(!this.id.includes("/"), 0x30f /* Channel context ID cannot contain slashes */);
|
|
58
60
|
}
|
|
59
61
|
|
|
60
|
-
protected get isGloballyVisible() {
|
|
62
|
+
protected get isGloballyVisible(): boolean {
|
|
61
63
|
return this.globallyVisible;
|
|
62
64
|
}
|
|
63
65
|
|
|
@@ -72,7 +74,7 @@ export abstract class LocalChannelContextBase implements IChannelContext {
|
|
|
72
74
|
return this._channel !== undefined;
|
|
73
75
|
}
|
|
74
76
|
|
|
75
|
-
public setConnectionState(connected: boolean, clientId?: string) {
|
|
77
|
+
public setConnectionState(connected: boolean, clientId?: string): void {
|
|
76
78
|
// Connection events are ignored if the data store is not yet globallyVisible or loaded
|
|
77
79
|
if (this.globallyVisible && this.isLoaded) {
|
|
78
80
|
this.services.value.deltaConnection.setConnectionState(connected);
|
|
@@ -101,13 +103,13 @@ export abstract class LocalChannelContextBase implements IChannelContext {
|
|
|
101
103
|
);
|
|
102
104
|
const propsCopy = {
|
|
103
105
|
...messageCollection,
|
|
104
|
-
messagesContent:
|
|
106
|
+
messagesContent: [...messageCollection.messagesContent],
|
|
105
107
|
};
|
|
106
108
|
this.pendingMessagesState.messageCollections.push(propsCopy);
|
|
107
109
|
}
|
|
108
110
|
}
|
|
109
111
|
|
|
110
|
-
public reSubmit(content:
|
|
112
|
+
public reSubmit(content: unknown, localOpMetadata: unknown, squash: boolean): void {
|
|
111
113
|
assert(this.isLoaded, 0x18a /* "Channel should be loaded to resubmit ops" */);
|
|
112
114
|
assert(
|
|
113
115
|
this.globallyVisible,
|
|
@@ -115,7 +117,7 @@ export abstract class LocalChannelContextBase implements IChannelContext {
|
|
|
115
117
|
);
|
|
116
118
|
this.services.value.deltaConnection.reSubmit(content, localOpMetadata, squash);
|
|
117
119
|
}
|
|
118
|
-
public rollback(content:
|
|
120
|
+
public rollback(content: unknown, localOpMetadata: unknown): void {
|
|
119
121
|
assert(this.isLoaded, 0x2ee /* "Channel should be loaded to rollback ops" */);
|
|
120
122
|
assert(
|
|
121
123
|
this.globallyVisible,
|
|
@@ -198,7 +200,7 @@ export abstract class LocalChannelContextBase implements IChannelContext {
|
|
|
198
200
|
return channel.getGCData(fullGC);
|
|
199
201
|
}
|
|
200
202
|
|
|
201
|
-
public updateUsedRoutes(usedRoutes: string[]) {
|
|
203
|
+
public updateUsedRoutes(usedRoutes: string[]): void {
|
|
202
204
|
/**
|
|
203
205
|
* Currently, DDSes are always considered referenced and are not garbage collected.
|
|
204
206
|
* Once we have GC at DDS level, this channel context's used routes will be updated as per the passed
|
|
@@ -216,7 +218,7 @@ export class RehydratedLocalChannelContext extends LocalChannelContextBase {
|
|
|
216
218
|
dataStoreContext: IFluidDataStoreContext,
|
|
217
219
|
storageService: IDocumentStorageService,
|
|
218
220
|
logger: ITelemetryLoggerExt,
|
|
219
|
-
submitFn: (content:
|
|
221
|
+
submitFn: (content: unknown, localOpMetadata: unknown) => void,
|
|
220
222
|
dirtyFn: (address: string) => void,
|
|
221
223
|
private readonly snapshotTree: ISnapshotTree,
|
|
222
224
|
extraBlob?: Map<string, ArrayBufferLike>,
|
|
@@ -267,9 +269,9 @@ export class RehydratedLocalChannelContext extends LocalChannelContextBase {
|
|
|
267
269
|
this.services.value.deltaConnection.processMessages(messageCollection);
|
|
268
270
|
}
|
|
269
271
|
return channel;
|
|
270
|
-
} catch (
|
|
272
|
+
} catch (error) {
|
|
271
273
|
throw DataProcessingError.wrapIfUnrecognized(
|
|
272
|
-
|
|
274
|
+
error,
|
|
273
275
|
"rehydratedLocalChannelContextFailedToLoadChannel",
|
|
274
276
|
undefined,
|
|
275
277
|
);
|
|
@@ -282,7 +284,7 @@ export class RehydratedLocalChannelContext extends LocalChannelContextBase {
|
|
|
282
284
|
};
|
|
283
285
|
}
|
|
284
286
|
|
|
285
|
-
public override applyStashedOp(content) {
|
|
287
|
+
public override applyStashedOp(content: unknown): unknown {
|
|
286
288
|
return this.services.value.deltaConnection.applyStashedOp(content);
|
|
287
289
|
}
|
|
288
290
|
|
|
@@ -293,12 +295,12 @@ export class RehydratedLocalChannelContext extends LocalChannelContextBase {
|
|
|
293
295
|
let sanitize = false;
|
|
294
296
|
const blobsContents = snapshotTree.blobsContents;
|
|
295
297
|
if (blobsContents !== undefined) {
|
|
296
|
-
|
|
298
|
+
for (const [key, value] of Object.entries(blobsContents)) {
|
|
297
299
|
blobMap.set(key, value);
|
|
298
300
|
if (snapshotTree.blobs[key] !== undefined) {
|
|
299
301
|
sanitize = true;
|
|
300
302
|
}
|
|
301
|
-
}
|
|
303
|
+
}
|
|
302
304
|
}
|
|
303
305
|
for (const value of Object.values(snapshotTree.trees)) {
|
|
304
306
|
sanitize = sanitize || this.isSnapshotInOldFormatAndCollectBlobs(value, blobMap);
|
|
@@ -306,7 +308,7 @@ export class RehydratedLocalChannelContext extends LocalChannelContextBase {
|
|
|
306
308
|
return sanitize;
|
|
307
309
|
}
|
|
308
310
|
|
|
309
|
-
private sanitizeSnapshot(snapshotTree: ISnapshotTree) {
|
|
311
|
+
private sanitizeSnapshot(snapshotTree: ISnapshotTree): void {
|
|
310
312
|
const blobMapInitial = new Map(Object.entries(snapshotTree.blobs));
|
|
311
313
|
for (const [blobName, blobId] of blobMapInitial.entries()) {
|
|
312
314
|
const blobValue = blobMapInitial.get(blobId);
|
|
@@ -329,7 +331,7 @@ export class LocalChannelContext extends LocalChannelContextBase {
|
|
|
329
331
|
dataStoreContext: IFluidDataStoreContext,
|
|
330
332
|
storageService: IDocumentStorageService,
|
|
331
333
|
logger: ITelemetryLoggerExt,
|
|
332
|
-
submitFn: (content:
|
|
334
|
+
submitFn: (content: unknown, localOpMetadata: unknown) => void,
|
|
333
335
|
dirtyFn: (address: string) => void,
|
|
334
336
|
) {
|
|
335
337
|
super(
|
|
@@ -355,7 +357,7 @@ export class LocalChannelContext extends LocalChannelContextBase {
|
|
|
355
357
|
};
|
|
356
358
|
}
|
|
357
359
|
|
|
358
|
-
public applyStashedOp() {
|
|
360
|
+
public applyStashedOp(): void {
|
|
359
361
|
throw new Error("no stashed ops on local channel");
|
|
360
362
|
}
|
|
361
363
|
}
|