@fluidframework/presence 2.20.0 → 2.21.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.
@@ -1 +1 @@
1
- {"version":3,"file":"latestValueManager.d.ts","sourceRoot":"","sources":["../src/latestValueManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAElE,OAAO,KAAK,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAI1F,OAAO,KAAK,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACpF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAIpD,OAAO,KAAK,EACX,gBAAgB,EAChB,gBAAgB,EAChB,MAAM,mDAAmD,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wDAAwD,CAAC;AAC5F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uDAAuD,CAAC;AAElG;;;GAGG;AACH,MAAM,WAAW,wBAAwB,CAAC,CAAC;IAC1C;;;;OAIG;IACH,OAAO,EAAE,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;CACpD;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC;IACpC;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,CAAC;IAEzD;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IAErC;;;;;OAKG;IACH,IAAI,KAAK,IAAI,oBAAoB,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;IACrE,IAAI,KAAK,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,EAAE;IAE5D;;OAEG;IACH,YAAY,IAAI,gBAAgB,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3D;;OAEG;IACH,OAAO,IAAI,cAAc,EAAE,CAAC;IAC5B;;OAEG;IACH,WAAW,CAAC,MAAM,EAAE,cAAc,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;CACxD;AAoFD;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,SAAS,MAAM,GAAG,MAAM,EACnE,YAAY,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,GAAG,MAAM,EAChE,QAAQ,CAAC,EAAE,wBAAwB,GACjC,aAAa,CAAC,cAAc,CAC9B,GAAG,EACH,aAAa,CAAC,kBAAkB,CAAC,CAAC,CAAC,EACnC,kBAAkB,CAAC,CAAC,CAAC,CACrB,CAwBA"}
1
+ {"version":3,"file":"latestValueManager.d.ts","sourceRoot":"","sources":["../src/latestValueManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAGlE,OAAO,KAAK,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAI1F,OAAO,KAAK,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACpF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAIpD,OAAO,KAAK,EACX,gBAAgB,EAChB,gBAAgB,EAChB,MAAM,mDAAmD,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wDAAwD,CAAC;AAC5F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uDAAuD,CAAC;AAElG;;;GAGG;AACH,MAAM,WAAW,wBAAwB,CAAC,CAAC;IAC1C;;;;OAIG;IACH,OAAO,EAAE,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;CACpD;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC;IACpC;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,CAAC;IAEzD;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IAErC;;;;;OAKG;IACH,IAAI,KAAK,IAAI,oBAAoB,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;IACrE,IAAI,KAAK,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,EAAE;IAE5D;;OAEG;IACH,YAAY,IAAI,gBAAgB,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3D;;OAEG;IACH,OAAO,IAAI,cAAc,EAAE,CAAC;IAC5B;;OAEG;IACH,WAAW,CAAC,MAAM,EAAE,cAAc,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;CACxD;AAoFD;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,SAAS,MAAM,GAAG,MAAM,EACnE,YAAY,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,GAAG,MAAM,EAChE,QAAQ,CAAC,EAAE,wBAAwB,GACjC,aAAa,CAAC,cAAc,CAC9B,GAAG,EACH,aAAa,CAAC,kBAAkB,CAAC,CAAC,CAAC,EACnC,kBAAkB,CAAC,CAAC,CAAC,CACrB,CAwBA"}
@@ -6,6 +6,7 @@
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.Latest = void 0;
8
8
  const client_utils_1 = require("@fluid-internal/client-utils");
9
+ const internal_1 = require("@fluidframework/core-utils/internal");
9
10
  const broadcastControls_js_1 = require("./broadcastControls.js");
10
11
  const internalUtils_js_1 = require("./internalUtils.js");
11
12
  const stateDatastore_js_1 = require("./stateDatastore.js");
@@ -84,7 +85,7 @@ function Latest(initialValue, controls) {
84
85
  const value = {
85
86
  rev: 0,
86
87
  timestamp: Date.now(),
87
- value: { ...initialValue },
88
+ value: (0, internal_1.shallowCloneObject)(initialValue),
88
89
  };
89
90
  const factory = (key, datastoreHandle) => ({
90
91
  initialData: { value, allowableUpdateLatencyMs: controls?.allowableUpdateLatencyMs },
@@ -1 +1 @@
1
- {"version":3,"file":"latestValueManager.js","sourceRoot":"","sources":["../src/latestValueManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { createEmitter } from \"@fluid-internal/client-utils\";\nimport type { Listenable } from \"@fluidframework/core-interfaces\";\n\nimport type { BroadcastControls, BroadcastControlSettings } from \"./broadcastControls.js\";\nimport { OptionalBroadcastControl } from \"./broadcastControls.js\";\nimport type { ValueManager } from \"./internalTypes.js\";\nimport { objectEntries } from \"./internalUtils.js\";\nimport type { LatestValueClientData, LatestValueData } from \"./latestValueTypes.js\";\nimport type { ISessionClient } from \"./presence.js\";\nimport { datastoreFromHandle, type StateDatastore } from \"./stateDatastore.js\";\nimport { brandIVM } from \"./valueManager.js\";\n\nimport type {\n\tJsonDeserialized,\n\tJsonSerializable,\n} from \"@fluidframework/presence/internal/core-interfaces\";\nimport type { InternalTypes } from \"@fluidframework/presence/internal/exposedInternalTypes\";\nimport type { InternalUtilityTypes } from \"@fluidframework/presence/internal/exposedUtilityTypes\";\n\n/**\n * @sealed\n * @alpha\n */\nexport interface LatestValueManagerEvents<T> {\n\t/**\n\t * Raised when remote client's value is updated, which may be the same value.\n\t *\n\t * @eventProperty\n\t */\n\tupdated: (update: LatestValueClientData<T>) => void;\n}\n\n/**\n * Value manager that provides the latest known value from this client to others and read access to their values.\n * All participant clients must provide a value.\n *\n * @remarks Create using {@link Latest} registered to {@link PresenceStates}.\n *\n * @sealed\n * @alpha\n */\nexport interface LatestValueManager<T> {\n\t/**\n\t * Events for Latest value manager.\n\t */\n\treadonly events: Listenable<LatestValueManagerEvents<T>>;\n\n\t/**\n\t * Controls for management of sending updates.\n\t */\n\treadonly controls: BroadcastControls;\n\n\t/**\n\t * Current state for this client.\n\t * State for this client that will be transmitted to all other connected clients.\n\t * @remarks Manager assumes ownership of the value and its references. Make a deep clone before\n\t * setting, if needed. No comparison is done to detect changes; all sets are transmitted.\n\t */\n\tget local(): InternalUtilityTypes.FullyReadonly<JsonDeserialized<T>>;\n\tset local(value: JsonSerializable<T> & JsonDeserialized<T>);\n\n\t/**\n\t * Iterable access to remote clients' values.\n\t */\n\tclientValues(): IterableIterator<LatestValueClientData<T>>;\n\t/**\n\t * Array of known clients.\n\t */\n\tclients(): ISessionClient[];\n\t/**\n\t * Access to a specific client's value.\n\t */\n\tclientValue(client: ISessionClient): LatestValueData<T>;\n}\n\nclass LatestValueManagerImpl<T, Key extends string>\n\timplements\n\t\tLatestValueManager<T>,\n\t\tRequired<ValueManager<T, InternalTypes.ValueRequiredState<T>>>\n{\n\tpublic readonly events = createEmitter<LatestValueManagerEvents<T>>();\n\tpublic readonly controls: OptionalBroadcastControl;\n\n\tpublic constructor(\n\t\tprivate readonly key: Key,\n\t\tprivate readonly datastore: StateDatastore<Key, InternalTypes.ValueRequiredState<T>>,\n\t\tpublic readonly value: InternalTypes.ValueRequiredState<T>,\n\t\tcontrolSettings: BroadcastControlSettings | undefined,\n\t) {\n\t\tthis.controls = new OptionalBroadcastControl(controlSettings);\n\t}\n\n\tpublic get local(): InternalUtilityTypes.FullyReadonly<JsonDeserialized<T>> {\n\t\treturn this.value.value;\n\t}\n\n\tpublic set local(value: JsonSerializable<T> & JsonDeserialized<T>) {\n\t\tthis.value.rev += 1;\n\t\tthis.value.timestamp = Date.now();\n\t\tthis.value.value = value;\n\t\tthis.datastore.localUpdate(this.key, this.value, {\n\t\t\tallowableUpdateLatencyMs: this.controls.allowableUpdateLatencyMs,\n\t\t});\n\t}\n\n\tpublic *clientValues(): IterableIterator<LatestValueClientData<T>> {\n\t\tconst allKnownStates = this.datastore.knownValues(this.key);\n\t\tfor (const [clientSessionId, value] of objectEntries(allKnownStates.states)) {\n\t\t\tif (clientSessionId !== allKnownStates.self) {\n\t\t\t\tyield {\n\t\t\t\t\tclient: this.datastore.lookupClient(clientSessionId),\n\t\t\t\t\tvalue: value.value,\n\t\t\t\t\tmetadata: { revision: value.rev, timestamp: value.timestamp },\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic clients(): ISessionClient[] {\n\t\tconst allKnownStates = this.datastore.knownValues(this.key);\n\t\treturn Object.keys(allKnownStates.states)\n\t\t\t.filter((clientSessionId) => clientSessionId !== allKnownStates.self)\n\t\t\t.map((clientSessionId) => this.datastore.lookupClient(clientSessionId));\n\t}\n\n\tpublic clientValue(client: ISessionClient): LatestValueData<T> {\n\t\tconst allKnownStates = this.datastore.knownValues(this.key);\n\t\tconst clientState = allKnownStates.states[client.sessionId];\n\t\tif (clientState === undefined) {\n\t\t\tthrow new Error(\"No entry for clientId\");\n\t\t}\n\t\treturn {\n\t\t\tvalue: clientState.value,\n\t\t\tmetadata: { revision: clientState.rev, timestamp: Date.now() },\n\t\t};\n\t}\n\n\tpublic update(\n\t\tclient: ISessionClient,\n\t\t_received: number,\n\t\tvalue: InternalTypes.ValueRequiredState<T>,\n\t): void {\n\t\tconst allKnownStates = this.datastore.knownValues(this.key);\n\t\tconst clientSessionId = client.sessionId;\n\t\tconst currentState = allKnownStates.states[clientSessionId];\n\t\tif (currentState !== undefined && currentState.rev >= value.rev) {\n\t\t\treturn;\n\t\t}\n\t\tthis.datastore.update(this.key, clientSessionId, value);\n\t\tthis.events.emit(\"updated\", {\n\t\t\tclient,\n\t\t\tvalue: value.value,\n\t\t\tmetadata: { revision: value.rev, timestamp: value.timestamp },\n\t\t});\n\t}\n}\n\n/**\n * Factory for creating a {@link LatestValueManager}.\n *\n * @alpha\n */\nexport function Latest<T extends object, Key extends string = string>(\n\tinitialValue: JsonSerializable<T> & JsonDeserialized<T> & object,\n\tcontrols?: BroadcastControlSettings,\n): InternalTypes.ManagerFactory<\n\tKey,\n\tInternalTypes.ValueRequiredState<T>,\n\tLatestValueManager<T>\n> {\n\t// LatestValueManager takes ownership of initialValue but makes a shallow\n\t// copy for basic protection.\n\tconst value: InternalTypes.ValueRequiredState<T> = {\n\t\trev: 0,\n\t\ttimestamp: Date.now(),\n\t\tvalue: { ...initialValue },\n\t};\n\tconst factory = (\n\t\tkey: Key,\n\t\tdatastoreHandle: InternalTypes.StateDatastoreHandle<\n\t\t\tKey,\n\t\t\tInternalTypes.ValueRequiredState<T>\n\t\t>,\n\t): {\n\t\tinitialData: { value: typeof value; allowableUpdateLatencyMs: number | undefined };\n\t\tmanager: InternalTypes.StateValue<LatestValueManager<T>>;\n\t} => ({\n\t\tinitialData: { value, allowableUpdateLatencyMs: controls?.allowableUpdateLatencyMs },\n\t\tmanager: brandIVM<LatestValueManagerImpl<T, Key>, T, InternalTypes.ValueRequiredState<T>>(\n\t\t\tnew LatestValueManagerImpl(key, datastoreFromHandle(datastoreHandle), value, controls),\n\t\t),\n\t});\n\treturn Object.assign(factory, { instanceBase: LatestValueManagerImpl });\n}\n"]}
1
+ {"version":3,"file":"latestValueManager.js","sourceRoot":"","sources":["../src/latestValueManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { createEmitter } from \"@fluid-internal/client-utils\";\nimport type { Listenable } from \"@fluidframework/core-interfaces\";\nimport { shallowCloneObject } from \"@fluidframework/core-utils/internal\";\n\nimport type { BroadcastControls, BroadcastControlSettings } from \"./broadcastControls.js\";\nimport { OptionalBroadcastControl } from \"./broadcastControls.js\";\nimport type { ValueManager } from \"./internalTypes.js\";\nimport { objectEntries } from \"./internalUtils.js\";\nimport type { LatestValueClientData, LatestValueData } from \"./latestValueTypes.js\";\nimport type { ISessionClient } from \"./presence.js\";\nimport { datastoreFromHandle, type StateDatastore } from \"./stateDatastore.js\";\nimport { brandIVM } from \"./valueManager.js\";\n\nimport type {\n\tJsonDeserialized,\n\tJsonSerializable,\n} from \"@fluidframework/presence/internal/core-interfaces\";\nimport type { InternalTypes } from \"@fluidframework/presence/internal/exposedInternalTypes\";\nimport type { InternalUtilityTypes } from \"@fluidframework/presence/internal/exposedUtilityTypes\";\n\n/**\n * @sealed\n * @alpha\n */\nexport interface LatestValueManagerEvents<T> {\n\t/**\n\t * Raised when remote client's value is updated, which may be the same value.\n\t *\n\t * @eventProperty\n\t */\n\tupdated: (update: LatestValueClientData<T>) => void;\n}\n\n/**\n * Value manager that provides the latest known value from this client to others and read access to their values.\n * All participant clients must provide a value.\n *\n * @remarks Create using {@link Latest} registered to {@link PresenceStates}.\n *\n * @sealed\n * @alpha\n */\nexport interface LatestValueManager<T> {\n\t/**\n\t * Events for Latest value manager.\n\t */\n\treadonly events: Listenable<LatestValueManagerEvents<T>>;\n\n\t/**\n\t * Controls for management of sending updates.\n\t */\n\treadonly controls: BroadcastControls;\n\n\t/**\n\t * Current state for this client.\n\t * State for this client that will be transmitted to all other connected clients.\n\t * @remarks Manager assumes ownership of the value and its references. Make a deep clone before\n\t * setting, if needed. No comparison is done to detect changes; all sets are transmitted.\n\t */\n\tget local(): InternalUtilityTypes.FullyReadonly<JsonDeserialized<T>>;\n\tset local(value: JsonSerializable<T> & JsonDeserialized<T>);\n\n\t/**\n\t * Iterable access to remote clients' values.\n\t */\n\tclientValues(): IterableIterator<LatestValueClientData<T>>;\n\t/**\n\t * Array of known clients.\n\t */\n\tclients(): ISessionClient[];\n\t/**\n\t * Access to a specific client's value.\n\t */\n\tclientValue(client: ISessionClient): LatestValueData<T>;\n}\n\nclass LatestValueManagerImpl<T, Key extends string>\n\timplements\n\t\tLatestValueManager<T>,\n\t\tRequired<ValueManager<T, InternalTypes.ValueRequiredState<T>>>\n{\n\tpublic readonly events = createEmitter<LatestValueManagerEvents<T>>();\n\tpublic readonly controls: OptionalBroadcastControl;\n\n\tpublic constructor(\n\t\tprivate readonly key: Key,\n\t\tprivate readonly datastore: StateDatastore<Key, InternalTypes.ValueRequiredState<T>>,\n\t\tpublic readonly value: InternalTypes.ValueRequiredState<T>,\n\t\tcontrolSettings: BroadcastControlSettings | undefined,\n\t) {\n\t\tthis.controls = new OptionalBroadcastControl(controlSettings);\n\t}\n\n\tpublic get local(): InternalUtilityTypes.FullyReadonly<JsonDeserialized<T>> {\n\t\treturn this.value.value;\n\t}\n\n\tpublic set local(value: JsonSerializable<T> & JsonDeserialized<T>) {\n\t\tthis.value.rev += 1;\n\t\tthis.value.timestamp = Date.now();\n\t\tthis.value.value = value;\n\t\tthis.datastore.localUpdate(this.key, this.value, {\n\t\t\tallowableUpdateLatencyMs: this.controls.allowableUpdateLatencyMs,\n\t\t});\n\t}\n\n\tpublic *clientValues(): IterableIterator<LatestValueClientData<T>> {\n\t\tconst allKnownStates = this.datastore.knownValues(this.key);\n\t\tfor (const [clientSessionId, value] of objectEntries(allKnownStates.states)) {\n\t\t\tif (clientSessionId !== allKnownStates.self) {\n\t\t\t\tyield {\n\t\t\t\t\tclient: this.datastore.lookupClient(clientSessionId),\n\t\t\t\t\tvalue: value.value,\n\t\t\t\t\tmetadata: { revision: value.rev, timestamp: value.timestamp },\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic clients(): ISessionClient[] {\n\t\tconst allKnownStates = this.datastore.knownValues(this.key);\n\t\treturn Object.keys(allKnownStates.states)\n\t\t\t.filter((clientSessionId) => clientSessionId !== allKnownStates.self)\n\t\t\t.map((clientSessionId) => this.datastore.lookupClient(clientSessionId));\n\t}\n\n\tpublic clientValue(client: ISessionClient): LatestValueData<T> {\n\t\tconst allKnownStates = this.datastore.knownValues(this.key);\n\t\tconst clientState = allKnownStates.states[client.sessionId];\n\t\tif (clientState === undefined) {\n\t\t\tthrow new Error(\"No entry for clientId\");\n\t\t}\n\t\treturn {\n\t\t\tvalue: clientState.value,\n\t\t\tmetadata: { revision: clientState.rev, timestamp: Date.now() },\n\t\t};\n\t}\n\n\tpublic update(\n\t\tclient: ISessionClient,\n\t\t_received: number,\n\t\tvalue: InternalTypes.ValueRequiredState<T>,\n\t): void {\n\t\tconst allKnownStates = this.datastore.knownValues(this.key);\n\t\tconst clientSessionId = client.sessionId;\n\t\tconst currentState = allKnownStates.states[clientSessionId];\n\t\tif (currentState !== undefined && currentState.rev >= value.rev) {\n\t\t\treturn;\n\t\t}\n\t\tthis.datastore.update(this.key, clientSessionId, value);\n\t\tthis.events.emit(\"updated\", {\n\t\t\tclient,\n\t\t\tvalue: value.value,\n\t\t\tmetadata: { revision: value.rev, timestamp: value.timestamp },\n\t\t});\n\t}\n}\n\n/**\n * Factory for creating a {@link LatestValueManager}.\n *\n * @alpha\n */\nexport function Latest<T extends object, Key extends string = string>(\n\tinitialValue: JsonSerializable<T> & JsonDeserialized<T> & object,\n\tcontrols?: BroadcastControlSettings,\n): InternalTypes.ManagerFactory<\n\tKey,\n\tInternalTypes.ValueRequiredState<T>,\n\tLatestValueManager<T>\n> {\n\t// LatestValueManager takes ownership of initialValue but makes a shallow\n\t// copy for basic protection.\n\tconst value: InternalTypes.ValueRequiredState<T> = {\n\t\trev: 0,\n\t\ttimestamp: Date.now(),\n\t\tvalue: shallowCloneObject(initialValue),\n\t};\n\tconst factory = (\n\t\tkey: Key,\n\t\tdatastoreHandle: InternalTypes.StateDatastoreHandle<\n\t\t\tKey,\n\t\t\tInternalTypes.ValueRequiredState<T>\n\t\t>,\n\t): {\n\t\tinitialData: { value: typeof value; allowableUpdateLatencyMs: number | undefined };\n\t\tmanager: InternalTypes.StateValue<LatestValueManager<T>>;\n\t} => ({\n\t\tinitialData: { value, allowableUpdateLatencyMs: controls?.allowableUpdateLatencyMs },\n\t\tmanager: brandIVM<LatestValueManagerImpl<T, Key>, T, InternalTypes.ValueRequiredState<T>>(\n\t\t\tnew LatestValueManagerImpl(key, datastoreFromHandle(datastoreHandle), value, controls),\n\t\t),\n\t});\n\treturn Object.assign(factory, { instanceBase: LatestValueManagerImpl });\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"latestValueManager.d.ts","sourceRoot":"","sources":["../src/latestValueManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAElE,OAAO,KAAK,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAI1F,OAAO,KAAK,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACpF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAIpD,OAAO,KAAK,EACX,gBAAgB,EAChB,gBAAgB,EAChB,MAAM,mDAAmD,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wDAAwD,CAAC;AAC5F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uDAAuD,CAAC;AAElG;;;GAGG;AACH,MAAM,WAAW,wBAAwB,CAAC,CAAC;IAC1C;;;;OAIG;IACH,OAAO,EAAE,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;CACpD;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC;IACpC;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,CAAC;IAEzD;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IAErC;;;;;OAKG;IACH,IAAI,KAAK,IAAI,oBAAoB,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;IACrE,IAAI,KAAK,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,EAAE;IAE5D;;OAEG;IACH,YAAY,IAAI,gBAAgB,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3D;;OAEG;IACH,OAAO,IAAI,cAAc,EAAE,CAAC;IAC5B;;OAEG;IACH,WAAW,CAAC,MAAM,EAAE,cAAc,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;CACxD;AAoFD;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,SAAS,MAAM,GAAG,MAAM,EACnE,YAAY,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,GAAG,MAAM,EAChE,QAAQ,CAAC,EAAE,wBAAwB,GACjC,aAAa,CAAC,cAAc,CAC9B,GAAG,EACH,aAAa,CAAC,kBAAkB,CAAC,CAAC,CAAC,EACnC,kBAAkB,CAAC,CAAC,CAAC,CACrB,CAwBA"}
1
+ {"version":3,"file":"latestValueManager.d.ts","sourceRoot":"","sources":["../src/latestValueManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAGlE,OAAO,KAAK,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAI1F,OAAO,KAAK,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACpF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAIpD,OAAO,KAAK,EACX,gBAAgB,EAChB,gBAAgB,EAChB,MAAM,mDAAmD,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wDAAwD,CAAC;AAC5F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uDAAuD,CAAC;AAElG;;;GAGG;AACH,MAAM,WAAW,wBAAwB,CAAC,CAAC;IAC1C;;;;OAIG;IACH,OAAO,EAAE,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;CACpD;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC;IACpC;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,CAAC;IAEzD;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IAErC;;;;;OAKG;IACH,IAAI,KAAK,IAAI,oBAAoB,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;IACrE,IAAI,KAAK,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,EAAE;IAE5D;;OAEG;IACH,YAAY,IAAI,gBAAgB,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3D;;OAEG;IACH,OAAO,IAAI,cAAc,EAAE,CAAC;IAC5B;;OAEG;IACH,WAAW,CAAC,MAAM,EAAE,cAAc,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;CACxD;AAoFD;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,SAAS,MAAM,GAAG,MAAM,EACnE,YAAY,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,GAAG,MAAM,EAChE,QAAQ,CAAC,EAAE,wBAAwB,GACjC,aAAa,CAAC,cAAc,CAC9B,GAAG,EACH,aAAa,CAAC,kBAAkB,CAAC,CAAC,CAAC,EACnC,kBAAkB,CAAC,CAAC,CAAC,CACrB,CAwBA"}
@@ -3,6 +3,7 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
  import { createEmitter } from "@fluid-internal/client-utils";
6
+ import { shallowCloneObject } from "@fluidframework/core-utils/internal";
6
7
  import { OptionalBroadcastControl } from "./broadcastControls.js";
7
8
  import { objectEntries } from "./internalUtils.js";
8
9
  import { datastoreFromHandle } from "./stateDatastore.js";
@@ -81,7 +82,7 @@ export function Latest(initialValue, controls) {
81
82
  const value = {
82
83
  rev: 0,
83
84
  timestamp: Date.now(),
84
- value: { ...initialValue },
85
+ value: shallowCloneObject(initialValue),
85
86
  };
86
87
  const factory = (key, datastoreHandle) => ({
87
88
  initialData: { value, allowableUpdateLatencyMs: controls?.allowableUpdateLatencyMs },
@@ -1 +1 @@
1
- {"version":3,"file":"latestValueManager.js","sourceRoot":"","sources":["../src/latestValueManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { createEmitter } from \"@fluid-internal/client-utils\";\nimport type { Listenable } from \"@fluidframework/core-interfaces\";\n\nimport type { BroadcastControls, BroadcastControlSettings } from \"./broadcastControls.js\";\nimport { OptionalBroadcastControl } from \"./broadcastControls.js\";\nimport type { ValueManager } from \"./internalTypes.js\";\nimport { objectEntries } from \"./internalUtils.js\";\nimport type { LatestValueClientData, LatestValueData } from \"./latestValueTypes.js\";\nimport type { ISessionClient } from \"./presence.js\";\nimport { datastoreFromHandle, type StateDatastore } from \"./stateDatastore.js\";\nimport { brandIVM } from \"./valueManager.js\";\n\nimport type {\n\tJsonDeserialized,\n\tJsonSerializable,\n} from \"@fluidframework/presence/internal/core-interfaces\";\nimport type { InternalTypes } from \"@fluidframework/presence/internal/exposedInternalTypes\";\nimport type { InternalUtilityTypes } from \"@fluidframework/presence/internal/exposedUtilityTypes\";\n\n/**\n * @sealed\n * @alpha\n */\nexport interface LatestValueManagerEvents<T> {\n\t/**\n\t * Raised when remote client's value is updated, which may be the same value.\n\t *\n\t * @eventProperty\n\t */\n\tupdated: (update: LatestValueClientData<T>) => void;\n}\n\n/**\n * Value manager that provides the latest known value from this client to others and read access to their values.\n * All participant clients must provide a value.\n *\n * @remarks Create using {@link Latest} registered to {@link PresenceStates}.\n *\n * @sealed\n * @alpha\n */\nexport interface LatestValueManager<T> {\n\t/**\n\t * Events for Latest value manager.\n\t */\n\treadonly events: Listenable<LatestValueManagerEvents<T>>;\n\n\t/**\n\t * Controls for management of sending updates.\n\t */\n\treadonly controls: BroadcastControls;\n\n\t/**\n\t * Current state for this client.\n\t * State for this client that will be transmitted to all other connected clients.\n\t * @remarks Manager assumes ownership of the value and its references. Make a deep clone before\n\t * setting, if needed. No comparison is done to detect changes; all sets are transmitted.\n\t */\n\tget local(): InternalUtilityTypes.FullyReadonly<JsonDeserialized<T>>;\n\tset local(value: JsonSerializable<T> & JsonDeserialized<T>);\n\n\t/**\n\t * Iterable access to remote clients' values.\n\t */\n\tclientValues(): IterableIterator<LatestValueClientData<T>>;\n\t/**\n\t * Array of known clients.\n\t */\n\tclients(): ISessionClient[];\n\t/**\n\t * Access to a specific client's value.\n\t */\n\tclientValue(client: ISessionClient): LatestValueData<T>;\n}\n\nclass LatestValueManagerImpl<T, Key extends string>\n\timplements\n\t\tLatestValueManager<T>,\n\t\tRequired<ValueManager<T, InternalTypes.ValueRequiredState<T>>>\n{\n\tpublic readonly events = createEmitter<LatestValueManagerEvents<T>>();\n\tpublic readonly controls: OptionalBroadcastControl;\n\n\tpublic constructor(\n\t\tprivate readonly key: Key,\n\t\tprivate readonly datastore: StateDatastore<Key, InternalTypes.ValueRequiredState<T>>,\n\t\tpublic readonly value: InternalTypes.ValueRequiredState<T>,\n\t\tcontrolSettings: BroadcastControlSettings | undefined,\n\t) {\n\t\tthis.controls = new OptionalBroadcastControl(controlSettings);\n\t}\n\n\tpublic get local(): InternalUtilityTypes.FullyReadonly<JsonDeserialized<T>> {\n\t\treturn this.value.value;\n\t}\n\n\tpublic set local(value: JsonSerializable<T> & JsonDeserialized<T>) {\n\t\tthis.value.rev += 1;\n\t\tthis.value.timestamp = Date.now();\n\t\tthis.value.value = value;\n\t\tthis.datastore.localUpdate(this.key, this.value, {\n\t\t\tallowableUpdateLatencyMs: this.controls.allowableUpdateLatencyMs,\n\t\t});\n\t}\n\n\tpublic *clientValues(): IterableIterator<LatestValueClientData<T>> {\n\t\tconst allKnownStates = this.datastore.knownValues(this.key);\n\t\tfor (const [clientSessionId, value] of objectEntries(allKnownStates.states)) {\n\t\t\tif (clientSessionId !== allKnownStates.self) {\n\t\t\t\tyield {\n\t\t\t\t\tclient: this.datastore.lookupClient(clientSessionId),\n\t\t\t\t\tvalue: value.value,\n\t\t\t\t\tmetadata: { revision: value.rev, timestamp: value.timestamp },\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic clients(): ISessionClient[] {\n\t\tconst allKnownStates = this.datastore.knownValues(this.key);\n\t\treturn Object.keys(allKnownStates.states)\n\t\t\t.filter((clientSessionId) => clientSessionId !== allKnownStates.self)\n\t\t\t.map((clientSessionId) => this.datastore.lookupClient(clientSessionId));\n\t}\n\n\tpublic clientValue(client: ISessionClient): LatestValueData<T> {\n\t\tconst allKnownStates = this.datastore.knownValues(this.key);\n\t\tconst clientState = allKnownStates.states[client.sessionId];\n\t\tif (clientState === undefined) {\n\t\t\tthrow new Error(\"No entry for clientId\");\n\t\t}\n\t\treturn {\n\t\t\tvalue: clientState.value,\n\t\t\tmetadata: { revision: clientState.rev, timestamp: Date.now() },\n\t\t};\n\t}\n\n\tpublic update(\n\t\tclient: ISessionClient,\n\t\t_received: number,\n\t\tvalue: InternalTypes.ValueRequiredState<T>,\n\t): void {\n\t\tconst allKnownStates = this.datastore.knownValues(this.key);\n\t\tconst clientSessionId = client.sessionId;\n\t\tconst currentState = allKnownStates.states[clientSessionId];\n\t\tif (currentState !== undefined && currentState.rev >= value.rev) {\n\t\t\treturn;\n\t\t}\n\t\tthis.datastore.update(this.key, clientSessionId, value);\n\t\tthis.events.emit(\"updated\", {\n\t\t\tclient,\n\t\t\tvalue: value.value,\n\t\t\tmetadata: { revision: value.rev, timestamp: value.timestamp },\n\t\t});\n\t}\n}\n\n/**\n * Factory for creating a {@link LatestValueManager}.\n *\n * @alpha\n */\nexport function Latest<T extends object, Key extends string = string>(\n\tinitialValue: JsonSerializable<T> & JsonDeserialized<T> & object,\n\tcontrols?: BroadcastControlSettings,\n): InternalTypes.ManagerFactory<\n\tKey,\n\tInternalTypes.ValueRequiredState<T>,\n\tLatestValueManager<T>\n> {\n\t// LatestValueManager takes ownership of initialValue but makes a shallow\n\t// copy for basic protection.\n\tconst value: InternalTypes.ValueRequiredState<T> = {\n\t\trev: 0,\n\t\ttimestamp: Date.now(),\n\t\tvalue: { ...initialValue },\n\t};\n\tconst factory = (\n\t\tkey: Key,\n\t\tdatastoreHandle: InternalTypes.StateDatastoreHandle<\n\t\t\tKey,\n\t\t\tInternalTypes.ValueRequiredState<T>\n\t\t>,\n\t): {\n\t\tinitialData: { value: typeof value; allowableUpdateLatencyMs: number | undefined };\n\t\tmanager: InternalTypes.StateValue<LatestValueManager<T>>;\n\t} => ({\n\t\tinitialData: { value, allowableUpdateLatencyMs: controls?.allowableUpdateLatencyMs },\n\t\tmanager: brandIVM<LatestValueManagerImpl<T, Key>, T, InternalTypes.ValueRequiredState<T>>(\n\t\t\tnew LatestValueManagerImpl(key, datastoreFromHandle(datastoreHandle), value, controls),\n\t\t),\n\t});\n\treturn Object.assign(factory, { instanceBase: LatestValueManagerImpl });\n}\n"]}
1
+ {"version":3,"file":"latestValueManager.js","sourceRoot":"","sources":["../src/latestValueManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { createEmitter } from \"@fluid-internal/client-utils\";\nimport type { Listenable } from \"@fluidframework/core-interfaces\";\nimport { shallowCloneObject } from \"@fluidframework/core-utils/internal\";\n\nimport type { BroadcastControls, BroadcastControlSettings } from \"./broadcastControls.js\";\nimport { OptionalBroadcastControl } from \"./broadcastControls.js\";\nimport type { ValueManager } from \"./internalTypes.js\";\nimport { objectEntries } from \"./internalUtils.js\";\nimport type { LatestValueClientData, LatestValueData } from \"./latestValueTypes.js\";\nimport type { ISessionClient } from \"./presence.js\";\nimport { datastoreFromHandle, type StateDatastore } from \"./stateDatastore.js\";\nimport { brandIVM } from \"./valueManager.js\";\n\nimport type {\n\tJsonDeserialized,\n\tJsonSerializable,\n} from \"@fluidframework/presence/internal/core-interfaces\";\nimport type { InternalTypes } from \"@fluidframework/presence/internal/exposedInternalTypes\";\nimport type { InternalUtilityTypes } from \"@fluidframework/presence/internal/exposedUtilityTypes\";\n\n/**\n * @sealed\n * @alpha\n */\nexport interface LatestValueManagerEvents<T> {\n\t/**\n\t * Raised when remote client's value is updated, which may be the same value.\n\t *\n\t * @eventProperty\n\t */\n\tupdated: (update: LatestValueClientData<T>) => void;\n}\n\n/**\n * Value manager that provides the latest known value from this client to others and read access to their values.\n * All participant clients must provide a value.\n *\n * @remarks Create using {@link Latest} registered to {@link PresenceStates}.\n *\n * @sealed\n * @alpha\n */\nexport interface LatestValueManager<T> {\n\t/**\n\t * Events for Latest value manager.\n\t */\n\treadonly events: Listenable<LatestValueManagerEvents<T>>;\n\n\t/**\n\t * Controls for management of sending updates.\n\t */\n\treadonly controls: BroadcastControls;\n\n\t/**\n\t * Current state for this client.\n\t * State for this client that will be transmitted to all other connected clients.\n\t * @remarks Manager assumes ownership of the value and its references. Make a deep clone before\n\t * setting, if needed. No comparison is done to detect changes; all sets are transmitted.\n\t */\n\tget local(): InternalUtilityTypes.FullyReadonly<JsonDeserialized<T>>;\n\tset local(value: JsonSerializable<T> & JsonDeserialized<T>);\n\n\t/**\n\t * Iterable access to remote clients' values.\n\t */\n\tclientValues(): IterableIterator<LatestValueClientData<T>>;\n\t/**\n\t * Array of known clients.\n\t */\n\tclients(): ISessionClient[];\n\t/**\n\t * Access to a specific client's value.\n\t */\n\tclientValue(client: ISessionClient): LatestValueData<T>;\n}\n\nclass LatestValueManagerImpl<T, Key extends string>\n\timplements\n\t\tLatestValueManager<T>,\n\t\tRequired<ValueManager<T, InternalTypes.ValueRequiredState<T>>>\n{\n\tpublic readonly events = createEmitter<LatestValueManagerEvents<T>>();\n\tpublic readonly controls: OptionalBroadcastControl;\n\n\tpublic constructor(\n\t\tprivate readonly key: Key,\n\t\tprivate readonly datastore: StateDatastore<Key, InternalTypes.ValueRequiredState<T>>,\n\t\tpublic readonly value: InternalTypes.ValueRequiredState<T>,\n\t\tcontrolSettings: BroadcastControlSettings | undefined,\n\t) {\n\t\tthis.controls = new OptionalBroadcastControl(controlSettings);\n\t}\n\n\tpublic get local(): InternalUtilityTypes.FullyReadonly<JsonDeserialized<T>> {\n\t\treturn this.value.value;\n\t}\n\n\tpublic set local(value: JsonSerializable<T> & JsonDeserialized<T>) {\n\t\tthis.value.rev += 1;\n\t\tthis.value.timestamp = Date.now();\n\t\tthis.value.value = value;\n\t\tthis.datastore.localUpdate(this.key, this.value, {\n\t\t\tallowableUpdateLatencyMs: this.controls.allowableUpdateLatencyMs,\n\t\t});\n\t}\n\n\tpublic *clientValues(): IterableIterator<LatestValueClientData<T>> {\n\t\tconst allKnownStates = this.datastore.knownValues(this.key);\n\t\tfor (const [clientSessionId, value] of objectEntries(allKnownStates.states)) {\n\t\t\tif (clientSessionId !== allKnownStates.self) {\n\t\t\t\tyield {\n\t\t\t\t\tclient: this.datastore.lookupClient(clientSessionId),\n\t\t\t\t\tvalue: value.value,\n\t\t\t\t\tmetadata: { revision: value.rev, timestamp: value.timestamp },\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic clients(): ISessionClient[] {\n\t\tconst allKnownStates = this.datastore.knownValues(this.key);\n\t\treturn Object.keys(allKnownStates.states)\n\t\t\t.filter((clientSessionId) => clientSessionId !== allKnownStates.self)\n\t\t\t.map((clientSessionId) => this.datastore.lookupClient(clientSessionId));\n\t}\n\n\tpublic clientValue(client: ISessionClient): LatestValueData<T> {\n\t\tconst allKnownStates = this.datastore.knownValues(this.key);\n\t\tconst clientState = allKnownStates.states[client.sessionId];\n\t\tif (clientState === undefined) {\n\t\t\tthrow new Error(\"No entry for clientId\");\n\t\t}\n\t\treturn {\n\t\t\tvalue: clientState.value,\n\t\t\tmetadata: { revision: clientState.rev, timestamp: Date.now() },\n\t\t};\n\t}\n\n\tpublic update(\n\t\tclient: ISessionClient,\n\t\t_received: number,\n\t\tvalue: InternalTypes.ValueRequiredState<T>,\n\t): void {\n\t\tconst allKnownStates = this.datastore.knownValues(this.key);\n\t\tconst clientSessionId = client.sessionId;\n\t\tconst currentState = allKnownStates.states[clientSessionId];\n\t\tif (currentState !== undefined && currentState.rev >= value.rev) {\n\t\t\treturn;\n\t\t}\n\t\tthis.datastore.update(this.key, clientSessionId, value);\n\t\tthis.events.emit(\"updated\", {\n\t\t\tclient,\n\t\t\tvalue: value.value,\n\t\t\tmetadata: { revision: value.rev, timestamp: value.timestamp },\n\t\t});\n\t}\n}\n\n/**\n * Factory for creating a {@link LatestValueManager}.\n *\n * @alpha\n */\nexport function Latest<T extends object, Key extends string = string>(\n\tinitialValue: JsonSerializable<T> & JsonDeserialized<T> & object,\n\tcontrols?: BroadcastControlSettings,\n): InternalTypes.ManagerFactory<\n\tKey,\n\tInternalTypes.ValueRequiredState<T>,\n\tLatestValueManager<T>\n> {\n\t// LatestValueManager takes ownership of initialValue but makes a shallow\n\t// copy for basic protection.\n\tconst value: InternalTypes.ValueRequiredState<T> = {\n\t\trev: 0,\n\t\ttimestamp: Date.now(),\n\t\tvalue: shallowCloneObject(initialValue),\n\t};\n\tconst factory = (\n\t\tkey: Key,\n\t\tdatastoreHandle: InternalTypes.StateDatastoreHandle<\n\t\t\tKey,\n\t\t\tInternalTypes.ValueRequiredState<T>\n\t\t>,\n\t): {\n\t\tinitialData: { value: typeof value; allowableUpdateLatencyMs: number | undefined };\n\t\tmanager: InternalTypes.StateValue<LatestValueManager<T>>;\n\t} => ({\n\t\tinitialData: { value, allowableUpdateLatencyMs: controls?.allowableUpdateLatencyMs },\n\t\tmanager: brandIVM<LatestValueManagerImpl<T, Key>, T, InternalTypes.ValueRequiredState<T>>(\n\t\t\tnew LatestValueManagerImpl(key, datastoreFromHandle(datastoreHandle), value, controls),\n\t\t),\n\t});\n\treturn Object.assign(factory, { instanceBase: LatestValueManagerImpl });\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/presence",
3
- "version": "2.20.0",
3
+ "version": "2.21.0",
4
4
  "description": "A component for lightweight data sharing within a single session",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -69,20 +69,20 @@
69
69
  "temp-directory": "nyc/.nyc_output"
70
70
  },
71
71
  "dependencies": {
72
- "@fluid-internal/client-utils": "~2.20.0",
73
- "@fluidframework/container-definitions": "~2.20.0",
74
- "@fluidframework/container-loader": "~2.20.0",
75
- "@fluidframework/container-runtime-definitions": "~2.20.0",
76
- "@fluidframework/core-interfaces": "~2.20.0",
77
- "@fluidframework/core-utils": "~2.20.0",
78
- "@fluidframework/datastore": "~2.20.0",
79
- "@fluidframework/datastore-definitions": "~2.20.0",
80
- "@fluidframework/fluid-static": "~2.20.0",
81
- "@fluidframework/id-compressor": "~2.20.0",
82
- "@fluidframework/runtime-definitions": "~2.20.0",
83
- "@fluidframework/runtime-utils": "~2.20.0",
84
- "@fluidframework/shared-object-base": "~2.20.0",
85
- "@fluidframework/telemetry-utils": "~2.20.0"
72
+ "@fluid-internal/client-utils": "~2.21.0",
73
+ "@fluidframework/container-definitions": "~2.21.0",
74
+ "@fluidframework/container-loader": "~2.21.0",
75
+ "@fluidframework/container-runtime-definitions": "~2.21.0",
76
+ "@fluidframework/core-interfaces": "~2.21.0",
77
+ "@fluidframework/core-utils": "~2.21.0",
78
+ "@fluidframework/datastore": "~2.21.0",
79
+ "@fluidframework/datastore-definitions": "~2.21.0",
80
+ "@fluidframework/fluid-static": "~2.21.0",
81
+ "@fluidframework/id-compressor": "~2.21.0",
82
+ "@fluidframework/runtime-definitions": "~2.21.0",
83
+ "@fluidframework/runtime-utils": "~2.21.0",
84
+ "@fluidframework/shared-object-base": "~2.21.0",
85
+ "@fluidframework/telemetry-utils": "~2.21.0"
86
86
  },
87
87
  "devDependencies": {
88
88
  "@arethetypeswrong/cli": "^0.17.1",
@@ -90,10 +90,10 @@
90
90
  "@fluid-tools/build-cli": "^0.51.0",
91
91
  "@fluidframework/build-common": "^2.0.3",
92
92
  "@fluidframework/build-tools": "^0.51.0",
93
- "@fluidframework/driver-definitions": "~2.20.0",
94
- "@fluidframework/eslint-config-fluid": "^5.6.0",
95
- "@fluidframework/test-runtime-utils": "~2.20.0",
96
- "@fluidframework/test-utils": "~2.20.0",
93
+ "@fluidframework/driver-definitions": "~2.21.0",
94
+ "@fluidframework/eslint-config-fluid": "^5.7.3",
95
+ "@fluidframework/test-runtime-utils": "~2.21.0",
96
+ "@fluidframework/test-utils": "~2.21.0",
97
97
  "@microsoft/api-extractor": "7.47.8",
98
98
  "@types/mocha": "^10.0.10",
99
99
  "@types/node": "^18.19.0",