@fluidframework/map 2.41.0 → 2.43.0-343119
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/dist/directory.d.ts +2 -16
- package/dist/directory.d.ts.map +1 -1
- package/dist/directory.js +23 -39
- package/dist/directory.js.map +1 -1
- package/dist/localValues.d.ts +10 -58
- package/dist/localValues.d.ts.map +1 -1
- package/dist/localValues.js +29 -83
- package/dist/localValues.js.map +1 -1
- package/dist/map.d.ts.map +1 -1
- package/dist/map.js +4 -4
- package/dist/map.js.map +1 -1
- package/dist/mapKernel.d.ts +5 -22
- package/dist/mapKernel.d.ts.map +1 -1
- package/dist/mapKernel.js +14 -57
- package/dist/mapKernel.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/lib/directory.d.ts +2 -16
- package/lib/directory.d.ts.map +1 -1
- package/lib/directory.js +24 -40
- package/lib/directory.js.map +1 -1
- package/lib/localValues.d.ts +10 -58
- package/lib/localValues.d.ts.map +1 -1
- package/lib/localValues.js +26 -79
- package/lib/localValues.js.map +1 -1
- package/lib/map.d.ts.map +1 -1
- package/lib/map.js +4 -4
- package/lib/map.js.map +1 -1
- package/lib/mapKernel.d.ts +5 -22
- package/lib/mapKernel.d.ts.map +1 -1
- package/lib/mapKernel.js +15 -58
- package/lib/mapKernel.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/package.json +18 -18
- package/src/directory.ts +32 -60
- package/src/localValues.ts +33 -106
- package/src/map.ts +7 -5
- package/src/mapKernel.ts +24 -74
- package/src/packageVersion.ts +1 -1
package/src/localValues.ts
CHANGED
|
@@ -19,125 +19,52 @@ import type { ISerializableValue, ISerializedValue } from "./internalInterfaces.
|
|
|
19
19
|
* A local value to be stored in a container type Distributed Data Store (DDS).
|
|
20
20
|
*/
|
|
21
21
|
export interface ILocalValue {
|
|
22
|
-
/**
|
|
23
|
-
* Type indicator of the value stored within.
|
|
24
|
-
*/
|
|
25
|
-
readonly type: string;
|
|
26
|
-
|
|
27
22
|
/**
|
|
28
23
|
* The in-memory value stored within.
|
|
29
24
|
*/
|
|
30
|
-
|
|
31
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
32
|
-
readonly value: any;
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Retrieve the serialized form of the value stored within.
|
|
36
|
-
* @param serializer - Data store runtime's serializer
|
|
37
|
-
* @param bind - Container type's handle
|
|
38
|
-
* @returns The serialized form of the contained value
|
|
39
|
-
*/
|
|
40
|
-
makeSerialized(serializer: IFluidSerializer, bind: IFluidHandle): ISerializedValue;
|
|
25
|
+
readonly value: unknown;
|
|
41
26
|
}
|
|
42
27
|
|
|
43
28
|
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* @param localValue - The value to serialize.
|
|
47
|
-
* @param serializer - Data store runtime's serializer.
|
|
48
|
-
* @param bind - Container type's handle.
|
|
49
|
-
*
|
|
50
|
-
* @see {@link ILocalValue.makeSerialized}
|
|
29
|
+
* Convert a value to its serialized form, i.e. to be used in ops and summaries.
|
|
51
30
|
*/
|
|
52
|
-
export
|
|
53
|
-
|
|
31
|
+
export const serializeValue = (
|
|
32
|
+
value: unknown,
|
|
54
33
|
serializer: IFluidSerializer,
|
|
55
34
|
bind: IFluidHandle,
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
35
|
+
): ISerializedValue => {
|
|
36
|
+
const serializedValue = serializeHandles(value, serializer, bind);
|
|
37
|
+
|
|
59
38
|
return {
|
|
60
|
-
type:
|
|
61
|
-
|
|
62
|
-
value: value.value && JSON.parse(value.value),
|
|
39
|
+
type: ValueType[ValueType.Plain],
|
|
40
|
+
value: serializedValue,
|
|
63
41
|
};
|
|
64
|
-
}
|
|
42
|
+
};
|
|
65
43
|
|
|
66
44
|
/**
|
|
67
|
-
*
|
|
45
|
+
* Very old versions of Fluid permitted a different type of stored value, which represented a
|
|
46
|
+
* SharedObject held directly. This functionality has since been replaced with handles.
|
|
47
|
+
*
|
|
48
|
+
* If the passed serializable is one of these old values, this function will mutate it to a modern
|
|
49
|
+
* value with a handle. Otherwise it does nothing.
|
|
50
|
+
* @param serializable - The serializable value to potentially convert.
|
|
68
51
|
*/
|
|
69
|
-
export
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* {@inheritDoc ILocalValue.makeSerialized}
|
|
85
|
-
*/
|
|
86
|
-
public makeSerialized(serializer: IFluidSerializer, bind: IFluidHandle): ISerializedValue {
|
|
87
|
-
// Stringify to convert to the serialized handle values - and then parse in order to create
|
|
88
|
-
// a POJO for the op
|
|
89
|
-
const value = serializeHandles(this.value, serializer, bind);
|
|
90
|
-
|
|
91
|
-
return {
|
|
92
|
-
type: this.type,
|
|
93
|
-
value,
|
|
52
|
+
export const migrateIfSharedSerializable = (
|
|
53
|
+
// eslint-disable-next-line import/no-deprecated
|
|
54
|
+
serializable: ISerializableValue,
|
|
55
|
+
serializer: IFluidSerializer,
|
|
56
|
+
bind: IFluidHandle,
|
|
57
|
+
): void => {
|
|
58
|
+
// Migrate from old shared value to handles
|
|
59
|
+
if (serializable.type === ValueType[ValueType.Shared]) {
|
|
60
|
+
serializable.type = ValueType[ValueType.Plain];
|
|
61
|
+
const handle: ISerializedHandle = {
|
|
62
|
+
type: "__fluid_handle__",
|
|
63
|
+
url: serializable.value as string,
|
|
94
64
|
};
|
|
65
|
+
// NOTE: here we require the use of `parseHandles` because the roundtrip
|
|
66
|
+
// through a string is necessary to resolve the absolute path of
|
|
67
|
+
// legacy handles (`ValueType.Shared`)
|
|
68
|
+
serializable.value = serializer.encode(parseHandles(handle, serializer), bind);
|
|
95
69
|
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Enables a container type {@link https://fluidframework.com/docs/build/dds/ | DDS} to produce and store local
|
|
100
|
-
* values with minimal awareness of how those objects are stored, serialized, and deserialized.
|
|
101
|
-
*/
|
|
102
|
-
export class LocalValueMaker {
|
|
103
|
-
/**
|
|
104
|
-
* Create a new LocalValueMaker.
|
|
105
|
-
*/
|
|
106
|
-
public constructor() {}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Create a new local value from an incoming serialized value.
|
|
110
|
-
* @param serializable - The serializable value to make local
|
|
111
|
-
*/
|
|
112
|
-
public fromSerializable(
|
|
113
|
-
// eslint-disable-next-line import/no-deprecated
|
|
114
|
-
serializable: ISerializableValue,
|
|
115
|
-
serializer: IFluidSerializer,
|
|
116
|
-
bind: IFluidHandle,
|
|
117
|
-
): ILocalValue {
|
|
118
|
-
// Migrate from old shared value to handles
|
|
119
|
-
if (serializable.type === ValueType[ValueType.Shared]) {
|
|
120
|
-
serializable.type = ValueType[ValueType.Plain];
|
|
121
|
-
const handle: ISerializedHandle = {
|
|
122
|
-
type: "__fluid_handle__",
|
|
123
|
-
url: serializable.value as string,
|
|
124
|
-
};
|
|
125
|
-
// NOTE: here we require the use of `parseHandles` because the roundtrip
|
|
126
|
-
// through a string is necessary to resolve the absolute path of
|
|
127
|
-
// legacy handles (`ValueType.Shared`)
|
|
128
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
129
|
-
serializable.value = serializer.encode(parseHandles(handle, serializer), bind);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return new PlainLocalValue(serializable.value);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Create a new local value containing a given plain object.
|
|
137
|
-
* @param value - The value to store
|
|
138
|
-
* @returns An ILocalValue containing the value
|
|
139
|
-
*/
|
|
140
|
-
public fromInMemory(value: unknown): ILocalValue {
|
|
141
|
-
return new PlainLocalValue(value);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
70
|
+
};
|
package/src/map.ts
CHANGED
|
@@ -253,12 +253,14 @@ export class SharedMap extends SharedObject<ISharedMapEvents> implements IShared
|
|
|
253
253
|
const newFormat = json as IMapSerializationFormat;
|
|
254
254
|
if (Array.isArray(newFormat.blobs)) {
|
|
255
255
|
this.kernel.populateFromSerializable(newFormat.content);
|
|
256
|
-
await Promise.all(
|
|
257
|
-
newFormat.blobs.map(async (
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
}),
|
|
256
|
+
const blobContents = await Promise.all(
|
|
257
|
+
newFormat.blobs.map(async (blobName) =>
|
|
258
|
+
readAndParse<IMapDataObjectSerializable>(storage, blobName),
|
|
259
|
+
),
|
|
261
260
|
);
|
|
261
|
+
for (const blobContent of blobContents) {
|
|
262
|
+
this.kernel.populateFromSerializable(blobContent);
|
|
263
|
+
}
|
|
262
264
|
} else {
|
|
263
265
|
this.kernel.populateFromSerializable(json as IMapDataObjectSerializable);
|
|
264
266
|
}
|
package/src/mapKernel.ts
CHANGED
|
@@ -21,7 +21,11 @@ import type {
|
|
|
21
21
|
ISerializableValue,
|
|
22
22
|
ISerializedValue,
|
|
23
23
|
} from "./internalInterfaces.js";
|
|
24
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
type ILocalValue,
|
|
26
|
+
serializeValue,
|
|
27
|
+
migrateIfSharedSerializable,
|
|
28
|
+
} from "./localValues.js";
|
|
25
29
|
|
|
26
30
|
/**
|
|
27
31
|
* Defines the means to process and submit a given op on a map.
|
|
@@ -154,18 +158,13 @@ export class MapKernel {
|
|
|
154
158
|
/**
|
|
155
159
|
* This is used to assign a unique id to every outgoing operation and helps in tracking unack'd ops.
|
|
156
160
|
*/
|
|
157
|
-
private
|
|
161
|
+
private nextPendingMessageId: number = 0;
|
|
158
162
|
|
|
159
163
|
/**
|
|
160
164
|
* The pending ids of any clears that have been performed locally but not yet ack'd from the server
|
|
161
165
|
*/
|
|
162
166
|
private readonly pendingClearMessageIds: number[] = [];
|
|
163
167
|
|
|
164
|
-
/**
|
|
165
|
-
* Object to create encapsulations of the values stored in the map.
|
|
166
|
-
*/
|
|
167
|
-
private readonly localValueMaker: LocalValueMaker;
|
|
168
|
-
|
|
169
168
|
/**
|
|
170
169
|
* Create a new shared map kernel.
|
|
171
170
|
* @param serializer - The serializer to serialize / parse handles
|
|
@@ -182,7 +181,6 @@ export class MapKernel {
|
|
|
182
181
|
private readonly isAttached: () => boolean,
|
|
183
182
|
private readonly eventEmitter: TypedEventEmitter<ISharedMapEvents>,
|
|
184
183
|
) {
|
|
185
|
-
this.localValueMaker = new LocalValueMaker();
|
|
186
184
|
this.messageHandlers = this.getMessageHandlers();
|
|
187
185
|
}
|
|
188
186
|
|
|
@@ -198,9 +196,7 @@ export class MapKernel {
|
|
|
198
196
|
* Get an iterator over the entries in this map.
|
|
199
197
|
* @returns The iterator
|
|
200
198
|
*/
|
|
201
|
-
|
|
202
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
203
|
-
public entries(): IterableIterator<[string, any]> {
|
|
199
|
+
public entries(): IterableIterator<[string, unknown]> {
|
|
204
200
|
const localEntriesIterator = this.data.entries();
|
|
205
201
|
const iterator = {
|
|
206
202
|
next(): IteratorResult<[string, unknown]> {
|
|
@@ -221,9 +217,7 @@ export class MapKernel {
|
|
|
221
217
|
* Get an iterator over the values in this map.
|
|
222
218
|
* @returns The iterator
|
|
223
219
|
*/
|
|
224
|
-
|
|
225
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
226
|
-
public values(): IterableIterator<any> {
|
|
220
|
+
public values(): IterableIterator<unknown> {
|
|
227
221
|
const localValuesIterator = this.data.values();
|
|
228
222
|
const iterator = {
|
|
229
223
|
next(): IteratorResult<unknown> {
|
|
@@ -231,7 +225,7 @@ export class MapKernel {
|
|
|
231
225
|
return nextVal.done
|
|
232
226
|
? { value: undefined, done: true }
|
|
233
227
|
: // Unpack the stored value
|
|
234
|
-
{ value: nextVal.value.value
|
|
228
|
+
{ value: nextVal.value.value, done: false };
|
|
235
229
|
},
|
|
236
230
|
[Symbol.iterator](): IterableIterator<unknown> {
|
|
237
231
|
return this;
|
|
@@ -244,9 +238,7 @@ export class MapKernel {
|
|
|
244
238
|
* Get an iterator over the entries in this map.
|
|
245
239
|
* @returns The iterator
|
|
246
240
|
*/
|
|
247
|
-
|
|
248
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
249
|
-
public [Symbol.iterator](): IterableIterator<[string, any]> {
|
|
241
|
+
public [Symbol.iterator](): IterableIterator<[string, unknown]> {
|
|
250
242
|
return this.entries();
|
|
251
243
|
}
|
|
252
244
|
|
|
@@ -266,9 +258,7 @@ export class MapKernel {
|
|
|
266
258
|
/**
|
|
267
259
|
* {@inheritDoc ISharedMap.get}
|
|
268
260
|
*/
|
|
269
|
-
|
|
270
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
271
|
-
public get<T = any>(key: string): T | undefined {
|
|
261
|
+
public get<T = unknown>(key: string): T | undefined {
|
|
272
262
|
const localValue = this.data.get(key);
|
|
273
263
|
return localValue === undefined ? undefined : (localValue.value as T);
|
|
274
264
|
}
|
|
@@ -291,11 +281,8 @@ export class MapKernel {
|
|
|
291
281
|
throw new Error("Undefined and null keys are not supported");
|
|
292
282
|
}
|
|
293
283
|
|
|
294
|
-
// Create a local value and serialize it.
|
|
295
|
-
const localValue = this.localValueMaker.fromInMemory(value);
|
|
296
|
-
|
|
297
284
|
// Set the value locally.
|
|
298
|
-
const previousValue = this.setCore(key,
|
|
285
|
+
const previousValue = this.setCore(key, { value }, true);
|
|
299
286
|
|
|
300
287
|
// If we are not attached, don't submit the op.
|
|
301
288
|
if (!this.isAttached()) {
|
|
@@ -305,7 +292,7 @@ export class MapKernel {
|
|
|
305
292
|
const op: IMapSetOperation = {
|
|
306
293
|
key,
|
|
307
294
|
type: "set",
|
|
308
|
-
value: { type:
|
|
295
|
+
value: { type: ValueType[ValueType.Plain], value },
|
|
309
296
|
};
|
|
310
297
|
this.submitMapKeyMessage(op, previousValue);
|
|
311
298
|
}
|
|
@@ -362,23 +349,11 @@ export class MapKernel {
|
|
|
362
349
|
* @returns A JSON string containing serialized map data
|
|
363
350
|
*/
|
|
364
351
|
public getSerializedStorage(serializer: IFluidSerializer): IMapDataObjectSerialized {
|
|
365
|
-
const
|
|
352
|
+
const serializedMapData: IMapDataObjectSerialized = {};
|
|
366
353
|
for (const [key, localValue] of this.data.entries()) {
|
|
367
|
-
|
|
354
|
+
serializedMapData[key] = serializeValue(localValue.value, serializer, this.handle);
|
|
368
355
|
}
|
|
369
|
-
return
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
public getSerializableStorage(serializer: IFluidSerializer): IMapDataObjectSerializable {
|
|
373
|
-
const serializableMapData: IMapDataObjectSerializable = {};
|
|
374
|
-
for (const [key, localValue] of this.data.entries()) {
|
|
375
|
-
serializableMapData[key] = makeSerializable(localValue, serializer, this.handle);
|
|
376
|
-
}
|
|
377
|
-
return serializableMapData;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
public serialize(serializer: IFluidSerializer): string {
|
|
381
|
-
return JSON.stringify(this.getSerializableStorage(serializer));
|
|
356
|
+
return serializedMapData;
|
|
382
357
|
}
|
|
383
358
|
|
|
384
359
|
/**
|
|
@@ -389,12 +364,8 @@ export class MapKernel {
|
|
|
389
364
|
for (const [key, serializable] of Object.entries(
|
|
390
365
|
this.serializer.decode(json) as IMapDataObjectSerializable,
|
|
391
366
|
)) {
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
value: this.makeLocal(key, serializable),
|
|
395
|
-
};
|
|
396
|
-
|
|
397
|
-
this.data.set(localValue.key, localValue.value);
|
|
367
|
+
migrateIfSharedSerializable(serializable, this.serializer, this.handle);
|
|
368
|
+
this.data.set(key, { value: serializable.value });
|
|
398
369
|
}
|
|
399
370
|
}
|
|
400
371
|
|
|
@@ -426,7 +397,8 @@ export class MapKernel {
|
|
|
426
397
|
break;
|
|
427
398
|
}
|
|
428
399
|
case "set": {
|
|
429
|
-
|
|
400
|
+
migrateIfSharedSerializable(op.value, this.serializer, this.handle);
|
|
401
|
+
this.set(op.key, op.value.value);
|
|
430
402
|
break;
|
|
431
403
|
}
|
|
432
404
|
default: {
|
|
@@ -578,28 +550,6 @@ export class MapKernel {
|
|
|
578
550
|
}
|
|
579
551
|
}
|
|
580
552
|
|
|
581
|
-
/**
|
|
582
|
-
* The remote ISerializableValue we're receiving (either as a result of a load or an incoming set op) will
|
|
583
|
-
* have the information we need to create a real object, but will not be the real object yet. For example,
|
|
584
|
-
* we might know it's a map and the map's ID but not have the actual map or its data yet. makeLocal's
|
|
585
|
-
* job is to convert that information into a real object for local usage.
|
|
586
|
-
* @param key - The key that the caller intends to store the local value into (used for ops later). But
|
|
587
|
-
* doesn't actually store the local value into that key. So better not lie!
|
|
588
|
-
* @param serializable - The remote information that we can convert into a real object
|
|
589
|
-
* @returns The local value that was produced
|
|
590
|
-
*/
|
|
591
|
-
// eslint-disable-next-line import/no-deprecated
|
|
592
|
-
private makeLocal(key: string, serializable: ISerializableValue): ILocalValue {
|
|
593
|
-
if (
|
|
594
|
-
serializable.type === ValueType[ValueType.Plain] ||
|
|
595
|
-
serializable.type === ValueType[ValueType.Shared]
|
|
596
|
-
) {
|
|
597
|
-
return this.localValueMaker.fromSerializable(serializable, this.serializer, this.handle);
|
|
598
|
-
} else {
|
|
599
|
-
throw new Error("Unknown local value type");
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
|
|
603
553
|
/**
|
|
604
554
|
* If our local operations that have not yet been ack'd will eventually overwrite an incoming operation, we should
|
|
605
555
|
* not process the incoming operation.
|
|
@@ -710,8 +660,8 @@ export class MapKernel {
|
|
|
710
660
|
}
|
|
711
661
|
|
|
712
662
|
// needProcessKeyOperation should have returned false if local is true
|
|
713
|
-
|
|
714
|
-
this.setCore(op.key,
|
|
663
|
+
migrateIfSharedSerializable(op.value, this.serializer, this.handle);
|
|
664
|
+
this.setCore(op.key, { value: op.value.value }, local);
|
|
715
665
|
},
|
|
716
666
|
submit: (op: IMapSetOperation, localOpMetadata: MapKeyLocalOpMetadata) => {
|
|
717
667
|
this.resubmitMapKeyMessage(op, localOpMetadata);
|
|
@@ -722,7 +672,7 @@ export class MapKernel {
|
|
|
722
672
|
}
|
|
723
673
|
|
|
724
674
|
private getMapClearMessageId(): number {
|
|
725
|
-
const pendingMessageId =
|
|
675
|
+
const pendingMessageId = this.nextPendingMessageId++;
|
|
726
676
|
this.pendingClearMessageIds.push(pendingMessageId);
|
|
727
677
|
return pendingMessageId;
|
|
728
678
|
}
|
|
@@ -740,7 +690,7 @@ export class MapKernel {
|
|
|
740
690
|
}
|
|
741
691
|
|
|
742
692
|
private getMapKeyMessageId(op: IMapKeyOperation): number {
|
|
743
|
-
const pendingMessageId =
|
|
693
|
+
const pendingMessageId = this.nextPendingMessageId++;
|
|
744
694
|
const pendingMessageIds = this.pendingKeys.get(op.key);
|
|
745
695
|
if (pendingMessageIds === undefined) {
|
|
746
696
|
this.pendingKeys.set(op.key, [pendingMessageId]);
|
package/src/packageVersion.ts
CHANGED