Skip to content

Commit 1c5e13e

Browse files
Apply LiveObjects operations on ACK
Based on [1] at c3a4917. Implementation and tests are Claude-generated from the spec; I've largely resisted the temptation to tweak things that aren't quite how I'd write them but which are still correct. The only behaviour here that's not in the spec is to also apply-on-ACK for batch operations (the batch API isn't in the spec yet). TODO: - test for batch [1] ably/specification#419
1 parent adda1cf commit 1c5e13e

7 files changed

Lines changed: 219 additions & 91 deletions

File tree

liveobjects.d.ts

Lines changed: 44 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -839,9 +839,9 @@ interface BatchContextLiveMapOperations<T extends Record<string, Value> = Record
839839
*
840840
* If the underlying instance at runtime is not a map, this method throws an error.
841841
*
842-
* This does not modify the underlying data of the map. Instead, the change is applied when
843-
* the published operation is echoed back to the client and applied to the object.
844-
* To get notified when object gets updated, use {@link PathObjectBase.subscribe | PathObject.subscribe} or {@link InstanceBase.subscribe | Instance.subscribe}, as appropriate.
842+
* This does not modify the underlying data of the map. Instead, when the batch function returns, the
843+
* batched operations are sent to Ably. Once accepted, they are applied locally before the
844+
* promise returned by {@link BatchOperations.batch | batch()} resolves.
845845
*
846846
* @param key - The key to set the value for.
847847
* @param value - The value to assign to the key.
@@ -855,9 +855,9 @@ interface BatchContextLiveMapOperations<T extends Record<string, Value> = Record
855855
*
856856
* If the underlying instance at runtime is not a map, this method throws an error.
857857
*
858-
* This does not modify the underlying data of the map. Instead, the change is applied when
859-
* the published operation is echoed back to the client and applied to the object.
860-
* To get notified when object gets updated, use {@link PathObjectBase.subscribe | PathObject.subscribe} or {@link InstanceBase.subscribe | Instance.subscribe}, as appropriate.
858+
* This does not modify the underlying data of the map. Instead, when the batch function returns, the
859+
* batched operations are sent to Ably. Once accepted, they are applied locally before the
860+
* promise returned by {@link BatchOperations.batch | batch()} resolves.
861861
*
862862
* @param key - The key to remove.
863863
*/
@@ -875,9 +875,9 @@ interface BatchContextLiveCounterOperations {
875875
*
876876
* If the underlying instance at runtime is not a counter, this method throws an error.
877877
*
878-
* This does not modify the underlying data of the counter. Instead, the change is applied when
879-
* the published operation is echoed back to the client and applied to the object.
880-
* To get notified when object gets updated, use {@link PathObjectBase.subscribe | PathObject.subscribe} or {@link InstanceBase.subscribe | Instance.subscribe}, as appropriate.
878+
* This does not modify the underlying data of the counter. Instead, when the batch function returns, the
879+
* batched operations are sent to Ably. Once accepted, they are applied locally before the
880+
* promise returned by {@link BatchOperations.batch | batch()} resolves.
881881
*
882882
* @param amount - The amount by which to increase the counter value. If not provided, defaults to 1.
883883
*/
@@ -904,9 +904,9 @@ interface BatchContextAnyOperations {
904904
*
905905
* If the underlying instance at runtime is not a map, this method throws an error.
906906
*
907-
* This does not modify the underlying data of the map. Instead, the change is applied when
908-
* the published operation is echoed back to the client and applied to the object.
909-
* To get notified when object gets updated, use {@link PathObjectBase.subscribe | PathObject.subscribe} or {@link InstanceBase.subscribe | Instance.subscribe}, as appropriate.
907+
* This does not modify the underlying data of the map. Instead, when the batch function returns, the
908+
* batched operations are sent to Ably. Once accepted, they are applied locally before the
909+
* promise returned by {@link BatchOperations.batch | batch()} resolves.
910910
*
911911
* @param key - The key to set the value for.
912912
* @param value - The value to assign to the key.
@@ -920,9 +920,9 @@ interface BatchContextAnyOperations {
920920
*
921921
* If the underlying instance at runtime is not a map, this method throws an error.
922922
*
923-
* This does not modify the underlying data of the map. Instead, the change is applied when
924-
* the published operation is echoed back to the client and applied to the object.
925-
* To get notified when object gets updated, use {@link PathObjectBase.subscribe | PathObject.subscribe} or {@link InstanceBase.subscribe | Instance.subscribe}, as appropriate.
923+
* This does not modify the underlying data of the map. Instead, when the batch function returns, the
924+
* batched operations are sent to Ably. Once accepted, they are applied locally before the
925+
* promise returned by {@link BatchOperations.batch | batch()} resolves.
926926
*
927927
* @param key - The key to remove.
928928
*/
@@ -937,9 +937,9 @@ interface BatchContextAnyOperations {
937937
*
938938
* If the underlying instance at runtime is not a counter, this method throws an error.
939939
*
940-
* This does not modify the underlying data of the counter. Instead, the change is applied when
941-
* the published operation is echoed back to the client and applied to the object.
942-
* To get notified when object gets updated, use {@link PathObjectBase.subscribe | PathObject.subscribe} or {@link InstanceBase.subscribe | Instance.subscribe}, as appropriate.
940+
* This does not modify the underlying data of the counter. Instead, when the batch function returns, the
941+
* batched operations are sent to Ably. Once accepted, they are applied locally before the
942+
* promise returned by {@link BatchOperations.batch | batch()} resolves.
943943
*
944944
* @param amount - The amount by which to increase the counter value. If not provided, defaults to 1.
945945
*/
@@ -967,11 +967,11 @@ interface BatchOperations<T extends LiveObject> {
967967
* Batching enables you to group multiple operations together and send them to the Ably service in a single channel message.
968968
* As a result, other clients will receive the changes in a single channel message once the batch function has completed.
969969
*
970-
* The objects' data is not modified inside the batch function. Instead, the objects will be updated
971-
* when the batched operations are applied by the Ably service and echoed back to the client.
970+
* The objects' data is not modified inside the batch function. The batched operations are sent to Ably
971+
* and, once accepted, applied locally. The returned promise resolves after all operations have been applied.
972972
*
973973
* @param fn - A synchronous function that receives a {@link BatchContext} used to group operations together.
974-
* @returns A promise which resolves upon success of the batch operation and rejects with an {@link ErrorInfo} object upon its failure.
974+
* @returns A promise which resolves after all batched operations have been accepted by Ably and applied locally, or rejects with an {@link ErrorInfo} object upon failure.
975975
*/
976976
batch(fn: BatchFunction<T>): Promise<void>;
977977
}
@@ -989,13 +989,12 @@ interface LiveMapOperations<T extends Record<string, Value> = Record<string, Val
989989
* or if called via {@link LiveMapPathObject} and the map instance at the specified path cannot
990990
* be resolved at the time of the call, this method throws an error.
991991
*
992-
* This does not modify the underlying data of the map. Instead, the change is applied when
993-
* the published operation is echoed back to the client and applied to the object.
994-
* To get notified when object gets updated, use {@link PathObjectBase.subscribe | PathObject.subscribe} or {@link InstanceBase.subscribe | Instance.subscribe}, as appropriate.
992+
* The operation is sent to Ably and, once accepted, applied locally. The returned promise resolves
993+
* after the operation has been applied.
995994
*
996995
* @param key - The key to set the value for.
997996
* @param value - The value to assign to the key.
998-
* @returns A promise which resolves upon success of the operation and rejects with an {@link ErrorInfo} object upon its failure.
997+
* @returns A promise which resolves after the operation has been accepted by Ably and applied locally, or rejects with an {@link ErrorInfo} object upon failure.
999998
*/
1000999
set<K extends keyof T & string>(key: K, value: T[K]): Promise<void>;
10011000

@@ -1007,12 +1006,11 @@ interface LiveMapOperations<T extends Record<string, Value> = Record<string, Val
10071006
* or if called via {@link LiveMapPathObject} and the map instance at the specified path cannot
10081007
* be resolved at the time of the call, this method throws an error.
10091008
*
1010-
* This does not modify the underlying data of the map. Instead, the change is applied when
1011-
* the published operation is echoed back to the client and applied to the object.
1012-
* To get notified when object gets updated, use {@link PathObjectBase.subscribe | PathObject.subscribe} or {@link InstanceBase.subscribe | Instance.subscribe}, as appropriate.
1009+
* The operation is sent to Ably and, once accepted, applied locally. The returned promise resolves
1010+
* after the operation has been applied.
10131011
*
10141012
* @param key - The key to remove.
1015-
* @returns A promise which resolves upon success of the operation and rejects with an {@link ErrorInfo} object upon its failure.
1013+
* @returns A promise which resolves after the operation has been accepted by Ably and applied locally, or rejects with an {@link ErrorInfo} object upon failure.
10161014
*/
10171015
remove(key: keyof T & string): Promise<void>;
10181016
}
@@ -1029,20 +1027,19 @@ interface LiveCounterOperations extends BatchOperations<LiveCounter> {
10291027
* or if called via {@link LiveCounterPathObject} and the counter instance at the specified path cannot
10301028
* be resolved at the time of the call, this method throws an error.
10311029
*
1032-
* This does not modify the underlying data of the counter. Instead, the change is applied when
1033-
* the published operation is echoed back to the client and applied to the object.
1034-
* To get notified when object gets updated, use {@link PathObjectBase.subscribe | PathObject.subscribe} or {@link InstanceBase.subscribe | Instance.subscribe}, as appropriate.
1030+
* The operation is sent to Ably and, once accepted, applied locally. The returned promise resolves
1031+
* after the operation has been applied.
10351032
*
10361033
* @param amount - The amount by which to increase the counter value. If not provided, defaults to 1.
1037-
* @returns A promise which resolves upon success of the operation and rejects with an {@link ErrorInfo} object upon its failure.
1034+
* @returns A promise which resolves after the operation has been accepted by Ably and applied locally, or rejects with an {@link ErrorInfo} object upon failure.
10381035
*/
10391036
increment(amount?: number): Promise<void>;
10401037

10411038
/**
10421039
* An alias for calling {@link LiveCounterOperations.increment | increment(-amount)}
10431040
*
10441041
* @param amount - The amount by which to decrease the counter value. If not provided, defaults to 1.
1045-
* @returns A promise which resolves upon success of the operation and rejects with an {@link ErrorInfo} object upon its failure.
1042+
* @returns A promise which resolves after the operation has been accepted by Ably and applied locally, or rejects with an {@link ErrorInfo} object upon failure.
10461043
*/
10471044
decrement(amount?: number): Promise<void>;
10481045
}
@@ -1061,11 +1058,11 @@ interface AnyOperations {
10611058
* Batching enables you to group multiple operations together and send them to the Ably service in a single channel message.
10621059
* As a result, other clients will receive the changes in a single channel message once the batch function has completed.
10631060
*
1064-
* The objects' data is not modified inside the batch function. Instead, the objects will be updated
1065-
* when the batched operations are applied by the Ably service and echoed back to the client.
1061+
* The objects' data is not modified inside the batch function. The batched operations are sent to Ably
1062+
* and, once accepted, applied locally. The returned promise resolves after all operations have been applied.
10661063
*
10671064
* @param fn - A synchronous function that receives a {@link BatchContext} used to group operations together.
1068-
* @returns A promise which resolves upon success of the batch operation and rejects with an {@link ErrorInfo} object upon its failure.
1065+
* @returns A promise which resolves after all batched operations have been accepted by Ably and applied locally, or rejects with an {@link ErrorInfo} object upon failure.
10691066
*/
10701067
batch<T extends LiveObject = LiveObject>(fn: BatchFunction<T>): Promise<void>;
10711068

@@ -1079,13 +1076,12 @@ interface AnyOperations {
10791076
* or if called via {@link AnyPathObject} and the map instance at the specified path cannot
10801077
* be resolved at the time of the call, this method throws an error.
10811078
*
1082-
* This does not modify the underlying data of the map. Instead, the change is applied when
1083-
* the published operation is echoed back to the client and applied to the object.
1084-
* To get notified when object gets updated, use {@link PathObjectBase.subscribe | PathObject.subscribe} or {@link InstanceBase.subscribe | Instance.subscribe}, as appropriate.
1079+
* The operation is sent to Ably and, once accepted, applied locally. The returned promise resolves
1080+
* after the operation has been applied.
10851081
*
10861082
* @param key - The key to set the value for.
10871083
* @param value - The value to assign to the key.
1088-
* @returns A promise which resolves upon success of the operation and rejects with an {@link ErrorInfo} object upon its failure.
1084+
* @returns A promise which resolves after the operation has been accepted by Ably and applied locally, or rejects with an {@link ErrorInfo} object upon failure.
10891085
*/
10901086
set<T extends Record<string, Value> = Record<string, Value>>(key: keyof T & string, value: T[keyof T]): Promise<void>;
10911087

@@ -1097,12 +1093,11 @@ interface AnyOperations {
10971093
* or if called via {@link AnyPathObject} and the map instance at the specified path cannot
10981094
* be resolved at the time of the call, this method throws an error.
10991095
*
1100-
* This does not modify the underlying data of the map. Instead, the change is applied when
1101-
* the published operation is echoed back to the client and applied to the object.
1102-
* To get notified when object gets updated, use {@link PathObjectBase.subscribe | PathObject.subscribe} or {@link InstanceBase.subscribe | Instance.subscribe}, as appropriate.
1096+
* The operation is sent to Ably and, once accepted, applied locally. The returned promise resolves
1097+
* after the operation has been applied.
11031098
*
11041099
* @param key - The key to remove.
1105-
* @returns A promise which resolves upon success of the operation and rejects with an {@link ErrorInfo} object upon its failure.
1100+
* @returns A promise which resolves after the operation has been accepted by Ably and applied locally, or rejects with an {@link ErrorInfo} object upon failure.
11061101
*/
11071102
remove<T extends Record<string, Value> = Record<string, Value>>(key: keyof T & string): Promise<void>;
11081103

@@ -1116,20 +1111,19 @@ interface AnyOperations {
11161111
* or if called via {@link AnyPathObject} and the counter instance at the specified path cannot
11171112
* be resolved at the time of the call, this method throws an error.
11181113
*
1119-
* This does not modify the underlying data of the counter. Instead, the change is applied when
1120-
* the published operation is echoed back to the client and applied to the object.
1121-
* To get notified when object gets updated, use {@link PathObjectBase.subscribe | PathObject.subscribe} or {@link InstanceBase.subscribe | Instance.subscribe}, as appropriate.
1114+
* The operation is sent to Ably and, once accepted, applied locally. The returned promise resolves
1115+
* after the operation has been applied.
11221116
*
11231117
* @param amount - The amount by which to increase the counter value. If not provided, defaults to 1.
1124-
* @returns A promise which resolves upon success of the operation and rejects with an {@link ErrorInfo} object upon its failure.
1118+
* @returns A promise which resolves after the operation has been accepted by Ably and applied locally, or rejects with an {@link ErrorInfo} object upon failure.
11251119
*/
11261120
increment(amount?: number): Promise<void>;
11271121

11281122
/**
11291123
* An alias for calling {@link AnyOperations.increment | increment(-amount)}
11301124
*
11311125
* @param amount - The amount by which to decrease the counter value. If not provided, defaults to 1.
1132-
* @returns A promise which resolves upon success of the operation and rejects with an {@link ErrorInfo} object upon its failure.
1126+
* @returns A promise which resolves after the operation has been accepted by Ably and applied locally, or rejects with an {@link ErrorInfo} object upon failure.
11331127
*/
11341128
decrement(amount?: number): Promise<void>;
11351129
}

src/common/lib/client/realtimechannel.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -520,13 +520,13 @@ class RealtimeChannel extends EventEmitter {
520520
await this.sendMessage(msg);
521521
}
522522

523-
async sendState(objectMessages: WireObjectMessage[]): Promise<void> {
523+
async sendState(objectMessages: WireObjectMessage[]): Promise<API.PublishResult | undefined> {
524524
const msg = protocolMessageFromValues({
525525
action: actions.OBJECT,
526526
channel: this.name,
527527
state: objectMessages,
528528
});
529-
await this.sendMessage(msg);
529+
return this.sendMessage(msg);
530530
}
531531

532532
// Access to this method is synchronised by ConnectionManager#processChannelMessage, in order to synchronise access to the state stored in _decodingContext.

0 commit comments

Comments
 (0)