| title | Objects Features | |||
|---|---|---|---|---|
| section | client-lib-development-guide | |||
| index | 65 | |||
| jump_to |
|
This document outlines the feature specification for the Objects feature of the Realtime system. It is currently under development and stored separately from the main specification to simplify the initial implementation of the feature in other SDKs. Once completed, it will be moved to the main features spec.
Objects feature enables clients to store shared data as “objects” on a channel. When an object is updated, changes are automatically propagated to all subscribed clients in realtime, ensuring each client always sees the latest state.
(RTO1)RealtimeObjects#getRootfunction:(RTO1a)Requires theOBJECT_SUBSCRIBEchannel mode to be granted per RTO2(RTO1b)If the channel is in theDETACHEDorFAILEDstate, the library should throw anErrorInfoerror withstatusCode400 andcode90001(RTO1c)Waits for the objects sync sequence to complete and for RTO5c to finish(RTO1d)Returns the object with idrootfrom the internalObjectsPoolas aLiveMap
(RTO2)Certain object operations may require a specific channel mode to be set on a channel in order to be performed. If a specific channel mode is required by an operation, then:(RTO2a)If the channel is in theATTACHEDstate, the presence of the required channel mode is checked against the set of channel modes granted by the server per RTL4m :(RTO2a1)If the channel mode is in the set, the operation is allowed(RTO2a2)If the channel mode is missing, unless otherwise specified by the operation, the library should throw anErrorInfoerror withstatusCode400 andcode40024, indicating that the operation cannot be performed without the required channel mode
(RTO2b)Otherwise, a best-effort attempt is made, and the channel mode is checked against the set of channel modes requested by the user per TB2d :(RTO2b1)If the channel mode is in the set, the operation is allowed(RTO2b2)If the channel mode is missing, unless otherwise specified by the operation, the library should throw anErrorInfoerror withstatusCode400 andcode40024, indicating that the operation cannot be performed without the required channel mode
(RTO3)An internalObjectsPoolshould be used to maintain the list of objects present on a channel(RTO4)When a channelATTACHEDProtocolMessageis received, theProtocolMessagemay contain aHAS_OBJECTSbit flag indicating that it will perform an objects sync, see TR3 . Note that this does not imply that objects are definitely present on the channel, only that there may be; theOBJECT_SYNCmessage may be empty(RTO4a)If theHAS_OBJECTSflag is 1, the server will shortly perform anOBJECT_SYNCsequence as described in RTO5(RTO4b)If theHAS_OBJECTSflag is 0 or there is noflagsfield, the sync sequence must be considered complete immediately, and the client library must perform the following actions in order:(RTO4b1)All objects except the one with idrootmust be removed from the internalObjectsPool(RTO4b2)The data for theLiveMapwith idrootmust be cleared by setting it to a zero-value per RTLM4. Note that the client SDK must not create a newLiveMapinstance with idroot; it must only clear the internal data of the existingLiveMapwith idroot(RTO4b3)TheSyncObjectsPoollist must be cleared(RTO4b5)TheBufferedObjectOperationslist must be cleared(RTO4b4)Perform the actions for objects sync completion as described in RTO5c
(RTO5)The realtime system reserves the right to initiate an objects sync of the objects on a channel at any point once a channel is attached. A server initiated objects sync provides Ably with a means to send a complete list of objects present on the channel at any point(RTO5d)If anOBJECT_SYNCProtocolMessageis received andObjectMessage.objectis null or omitted, the client library should skip processing thatProtocolMessage(RTO5a)When anOBJECT_SYNCProtocolMessageis received with achannelattribute matching the channel name, the client library must parse thechannelSerialattribute:(RTO5a1)ThechannelSerialis used as the sync cursor and is a two-part identifier:<sequence id>:<cursor value>(RTO5a2)If a new sequence id is sent from Ably, the client library must treat it as the start of a new objects sync sequence, and any previous in-flight sync must be discarded:(RTO5a2a)TheSyncObjectsPoollist must be cleared(RTO5a2b)TheBufferedObjectOperationslist must be cleared
(RTO5a3)If the sequence id matches the previously received sequence id, the client library should continue the sync process(RTO5a4)The objects sync sequence for that sequence identifier is considered complete once the cursor is empty; that is when thechannelSeriallooks like<sequence id>:(RTO5a5)AnOBJECT_SYNCmay also be sent with nochannelSerialattribute. In this case, the sync data is entirely contained within theProtocolMessage
(RTO5b)During the sync sequence, theObjectMessage.objectvalues from incomingOBJECT_SYNCProtocolMessagesmust be temporarily stored in the internalSyncObjectsPoollist(RTO5c)When the objects sync has completed, the client library must perform the following actions in order:(RTO5c1)For eachObjectStatein theSyncObjectsPoollist:(RTO5c1a)If an object withObjectState.objectIdexists in the internalObjectsPool:(RTO5c1b)If an object withObjectState.objectIddoes not exist in the internalObjectsPool:(RTO5c1b1)Create a newLiveObjectusing the data fromObjectStateand add it to the internalObjectsPool:(RTO5c1b1a)IfObjectState.counteris present, create a zero-valueLiveCounter(per RTLC4), set its privateobjectIdequal toObjectState.objectIdand replace its internal data using the currentObjectStateper RTLC6(RTO5c1b1b)IfObjectState.mapis present, create a zero-valueLiveMap(per RTLM4), set its privateobjectIdequal toObjectState.objectId, set its privatesemanticsequal toObjectState.map.semanticsand replace its internal data using the currentObjectStateper RTLM6(RTO5c1b1c)Otherwise, log a warning that an unsupported object state message has been received, and discard the currentObjectStatewithout taking any action
(RTO5c2)Remove any objects from the internalObjectsPoolfor which @objectId@s were not received during the sync sequence(RTO5c2a)The object with IDrootmust not be removed fromObjectsPool, as per RTO3b
(RTO5c6)ObjectMessagesstored in theBufferedObjectOperationslist are applied as described in RTO9(RTO5c3)Clear any stored sync sequence identifiers and cursor values(RTO5c4)TheSyncObjectsPoolmust be cleared(RTO5c5)TheBufferedObjectOperationslist must be cleared
(RTO6)Certain object operations may require creating a zero-value object if one does not already exist in the internalObjectsPoolfor the givenobjectId. This can be done as follows:(RTO6a)If an object withobjectIdexists inObjectsPool, do not create a new object(RTO6b)The expected type of the object can be inferred from the providedobjectId:(RTO6b1)Split theobjectId(formatted astype:hash@timestamp) on the separator:and parse the first part as the type string(RTO6b2)If the parsed type ismap, create a zero-valueLiveMapper RTLM4 in theObjectsPool(RTO6b3)If the parsed type iscounter, create a zero-valueLiveCounterper RTLC4 in theObjectsPool
(RTO7)The client library may receiveOBJECTProtocolMessagesin realtime over the channel concurrently withOBJECT_SYNCProtocolMessagesduring the object sync sequence (RTO5). Some of the incomingOBJECTmessages may have already been applied to the objects described in the sync sequence, while others may not. Therefore, the client must bufferOBJECTmessages during the sync sequence so that it can determine which of them should be applied to the objects once the sync is complete. See RTO8(RTO7a)An internalBufferedObjectOperationsshould be used to store the bufferedObjectMessages, as described in RTO8a.BufferedObjectOperationsis an array ofObjectMessageinstances(RTO7a1)This array is empty uponRealtimeObjectsinitialization
(RTO8)When the library receives aProtocolMessagewith an action ofOBJECT, each member of theProtocolMessage.statearray (decoded intoObjectMessageobjects) is passed to theRealtimeObjectsinstance per RTL1. EachObjectMessagefromOBJECTProtocolMessage(also referred to as anOBJECTmessage) describes an operation to be applied to an object on a channel and must be handled as follows:(RTO8a)If an object sync sequence is currently in progress, add theObjectMessagesto the internalBufferedObjectOperationsarray(RTO8b)Otherwise, apply theObjectMessagesas described in RTO9
(RTO9)OBJECTmessages can be applied toRealtimeObjectsin the following way:(RTO9a)For eachObjectMessagein the provided list:(RTO9a1)IfObjectMessage.operationis null or omitted, log a warning indicating that an unsupported object operation message has been received, and discard the currentObjectMessagewithout taking any action(RTO9a2)TheObjectMessage.operation.actionfield (seeObjectOperationAction) determines the type of operation to apply:(RTO9a2a)IfObjectMessage.operation.actionis one of the following:MAP_CREATE,MAP_SET,MAP_REMOVE,COUNTER_CREATE,COUNTER_INC, orOBJECT_DELETE, then:(RTO9a2a1)If it does not already exist, create a zero-valueLiveObjectin the internalObjectsPoolper RTO6 using theobjectIdfromObjectMessage.operation.objectId(RTO9a2a2)Get theLiveObjectinstance from the internalObjectsPoolusing theobjectIdfromObjectMessage.operation.objectId(RTO9a2a3)Apply theObjectMessage.operationto theLiveObject; see RTLC7, RTLM15
(RTO9a2b)Otherwise, log a warning that an object operation message with an unsupported action has been received, and discard the currentObjectMessagewithout taking any action
(RTLO1)TheLiveObjectrepresents the common interface and includes shared functionality for concrete object types(RTLO2)The client library may choose to implementLiveObjectas an abstract class(RTLO3)LiveObjectproperties:(RTLO3a)protectedobjectIdstring – an Object ID for this object(RTLO3a1)Must be provided and set in the constructor
(RTLO3b)protectedsiteTimeserialsDict<String, String>– a map of serials keyed by siteCode, representing the last operations applied to this object(RTLO3b1)Set to an empty map when theLiveObjectis initialized, so that any future operation can be applied to this object
(RTLO3c)protectedcreateOperationIsMergedboolean – a flag indicating whether the correspondingMAP_CREATEorCOUNTER_CREATEoperation has been applied to thisLiveObjectinstance(RTLO3c1)Set tofalsewhen theLiveObjectis initialized
(RTLO4)LiveObjectmethods:(RTLO4a)protectedcanApplyOperation– a convenience method used to determine whether theObjectMessage.operationshould be applied to this object based on a serial value:(RTLO4a1)Expects the following arguments:(RTLO4a1a)ObjectMessage
(RTLO4a2)Returns a boolean indicating whether the operation should be applied to this object(RTLO4a3)BothObjectMessage.serialandObjectMessage.siteCodemust be non-empty strings. Otherwise, log a warning that the object operation message has invalid serial values. The client library must not apply this operation to the object(RTLO4a4)Get thesiteSerialvalue stored for thisLiveObjectin thesiteTimeserialsmap using the keyObjectMessage.siteCode(RTLO4a5)If thesiteSerialfor thisLiveObjectis null or an empty string, return true(RTLO4a6)If thesiteSerialfor thisLiveObjectis not an empty string, return true ifObjectMessage.serialis greater thansiteSerialwhen compared lexicographically
(RTLC1)TheLiveCounterextendsLiveObject(RTLC2)Represents the counter object type for Object IDs of typecounter(RTLC3)Holds a 64-bit floating-point number as a privatedata(RTLC4)The zero-valueLiveCounteris aLiveCounterwithdataset to 0(RTLC5)LiveCounter#valuefunction:(RTLC5a)Requires theOBJECT_SUBSCRIBEchannel mode to be granted per RTO2(RTLC5b)If the channel is in theDETACHEDorFAILEDstate, the library should throw anErrorInfoerror withstatusCode400 andcode90001(RTLC5c)Returns the currentdatavalue
(RTLC6)@LiveCounter@’s internaldatacan be replaced with the providedObjectStatein the following way:(RTLC6a)Replace the privatesiteTimeserialsof theLiveCounterwith the value fromObjectState.siteTimeserials(RTLC6b)Set the private flagcreateOperationIsMergedtofalse(RTLC6c)Setdatato the value ofObjectState.counter.count, or to 0 if it does not exist(RTLC6d)IfObjectState.createOpis present, merge the initial value into theLiveCounteras described in RTLC10, passing in theObjectState.createOpinstance
(RTLC7)AnObjectOperationfromObjectMessage.operationcan be applied to aLiveCounterin the following way:(RTLC7a)A client library may choose to implement this logic as a convenience method namedapplyOperation, which accepts anObjectMessageinstance with an existingObjectMessage.operationobject, withObjectMessage.operation.objectIdmatching the Object ID of thisLiveCounter. ThisObjectMessagerepresents the operation to be applied to thisLiveCounter(RTLC7b)IfObjectMessage.operationcannot be applied based on the result ofLiveObject.canApplyOperation, log a debug or trace message indicating that the operation cannot be applied because its serial value is not newer than the object’s, and discard theObjectMessagewithout taking any action(RTLC7c)Set the entry in the privatesiteTimeserialsmap at the keyObjectMessage.siteCodeto equalObjectMessage.serial(RTLC7d)TheObjectMessage.operation.actionfield (seeObjectOperationAction) determines the type of operation to apply:(RTLC7d1)IfObjectMessage.operation.actionis set toCOUNTER_CREATE, apply the operation as described in RTLC8, passing inObjectMessage.operation(RTLC7d2)IfObjectMessage.operation.actionis set toCOUNTER_INC, apply the operation as described in RTLC9, passing inObjectMessage.operation.counterOp(RTLC7d3)Otherwise, log a warning that an object operation message with an unsupported action has been received, and discard the currentObjectMessagewithout taking any action
(RTLC8)ACOUNTER_CREATEoperation can be applied to aLiveCounterin the following way:(RTLC8a)Expects the following arguments:(RTLC8a1)ObjectOperation
(RTLC8b)If the private flagcreateOperationIsMergedistrue, log a debug or trace message indicating that the operation will not be applied because aCOUNTER_CREATEoperation has already been applied to thisLiveCounter, and discard the operation without taking any further action(RTLC8c)Otherwise merge the initial value into theLiveCounteras described in RTLC10, passing in theObjectOperationinstance
(RTLC9)ACOUNTER_INCoperation can be applied to aLiveCounterin the following way:(RTLC9a)Expects the following arguments:(RTLC9a1)ObjectsCounterOp
(RTLC9b)AddObjectsCounterOp.amounttodata, if it exists
(RTLC10)The initial value fromObjectOperation.countercan be merged into thisLiveCounterin the following way:(RTLC10a)AddObjectOperation.counter.counttodata, if it exists(RTLC10b)Set the private flagcreateOperationIsMergedtotrue
(RTLM1)TheLiveMapextendsLiveObject(RTLM2)Represents the map object type for Object IDs of typemap(RTLM3)Holds aDict<String, ObjectsMapEntry>as a privatedatamap(RTLM4)The zero-valueLiveMapis aLiveMapwithdataset to an empty map(RTLM5)LiveMap#getfunction:(RTLM5a)Accepts a key of type String(RTLM5b)Requires theOBJECT_SUBSCRIBEchannel mode to be granted per RTO2(RTLM5c)If the channel is in theDETACHEDorFAILEDstate, the library should throw anErrorInfoerror withstatusCode400 andcode90001(RTLM5d)Returns the value from the currentdataat the specified key, as follows:(RTLM5d1)If noObjectsMapEntryexists at the key, return undefined/null(RTLM5d2)If anObjectsMapEntryexists at the key:(RTLM5d2a)IfObjectsMapEntry.tombstoneistrue, return undefined/null(RTLM5d2b)IfObjectsMapEntry.data.booleanexists, return it(RTLM5d2c)IfObjectsMapEntry.data.bytesexists, return it(RTLM5d2d)IfObjectsMapEntry.data.numberexists, return it(RTLM5d2e)IfObjectsMapEntry.data.stringexists, return it(RTLM5d2f)IfObjectsMapEntry.data.objectIdexists, get the object stored at thatobjectIdfrom the internalObjectsPool:(RTLM5d2f1)If an object with idobjectIddoes not exist, return undefined/null(RTLM5d2f2)If an object with idobjectIdexists, return it
(RTLM5d2g)Otherwise, return undefined/null
(RTLM10)LiveMap#size:(RTLM10a)A method or property, depending on what is more idiomatic for the platform to use for a Map/Dictionary interface. For example, in JavaScript, this is a property similar toMap.sizefor the nativeMapclass(RTLM10b)Requires theOBJECT_SUBSCRIBEchannel mode to be granted per RTO2(RTLM10c)If the channel is in theDETACHEDorFAILEDstate, the library should throw anErrorInfoerror withstatusCode400 andcode90001(RTLM10d)Returns the number of non-tombstoned entries (per RTLM14) in the internaldatamap
(RTLM11)LiveMap#entries:(RTLM11a)A method or property, depending on what is more idiomatic for the platform to use for a Map/Dictionary interface. For example, in JavaScript, this is a method similar toMap.entries()for the nativeMapclass(RTLM11b)Requires theOBJECT_SUBSCRIBEchannel mode to be granted per RTO2(RTLM11c)If the channel is in theDETACHEDorFAILEDstate, the library should throw anErrorInfoerror withstatusCode400 andcode90001(RTLM11d)Returns key-value pairs from the internaldatamap:(RTLM11d1)Pairs with tombstoned entries (per RTLM14) are not returned(RTLM11d3)ObjectsMapEntryvalues are mapped to user-facing values following the same procedure as in RTLM5d2(RTLM11d3a)Note that if RTLM5d2 results in anObjectsMapEntrybeing mapped to an undefined/null value, the corresponding key-value pair is still returned by thisLiveMap#entriescall
(RTLM11d2)The return type is idiomatic for the platform’s analogous Map/Dictionary interface operation. For example, in JavaScript, it returns a map iterator object like the one returned byMap.entries()method for the nativeMapclass
(RTLM12)LiveMap#keys:(RTLM12a)A method or property, depending on what is more idiomatic for the platform to use for a Map/Dictionary interface. For example, in JavaScript, this is a method similar toMap.keys()for the nativeMapclass(RTLM12b)The implementation is identical toLiveMap#entries, except that it returns only the keys from the internaldatamap
(RTLM13)LiveMap#values:(RTLM13a)A method or property, depending on what is more idiomatic for the platform to use for a Map/Dictionary interface. For example, in JavaScript, this is a method similar toMap.values()for the nativeMapclass(RTLM13b)The implementation is identical toLiveMap#entries, except that it returns only the values from the internaldatamap
(RTLM14)AnObjectsMapEntryin the internaldatamap can be checked for being tombstoned using the convenience method:(RTLM14a)The method returns true ifObjectsMapEntry.tombstoneis true(RTLM14b)Otherwise, it returns false
(RTLM6)LiveMapinternaldatacan be replaced with the providedObjectStatein the following way:(RTLM6a)Replace the privatesiteTimeserialsof theLiveMapwith the value fromObjectState.siteTimeserials(RTLM6b)Set the private flagcreateOperationIsMergedtofalse(RTLM6c)SetdatatoObjectState.map.entries, or to an empty map if it does not exist(RTLM6d)IfObjectState.createOpis present, merge the initial value into theLiveMapas described in RTLM17, passing in theObjectState.createOpinstance
(RTLM15)AnObjectOperationfromObjectMessage.operationcan be applied to aLiveMapin the following way:(RTLM15a)A client library may choose to implement this logic as a convenience method namedapplyOperation, which accepts anObjectMessageinstance with an existingObjectMessage.operationobject, withObjectMessage.operation.objectIdmatching the Object ID of thisLiveMap. ThisObjectMessagerepresents the operation to be applied to thisLiveMap(RTLM15b)IfObjectMessage.operationcannot be applied based on the result ofLiveObject.canApplyOperation, log a debug or trace message indicating that the operation cannot be applied because its serial value is not newer than the object’s, and discard theObjectMessagewithout taking any action(RTLM15c)Set the entry in the privatesiteTimeserialsmap at the keyObjectMessage.siteCodeto equalObjectMessage.serial(RTLM15d)TheObjectMessage.operation.actionfield (seeObjectOperationAction) determines the type of operation to apply:(RTLM15d1)IfObjectMessage.operation.actionis set toMAP_CREATE, apply the operation as described in RTLM16, passing inObjectMessage.operation(RTLM15d2)IfObjectMessage.operation.actionis set toMAP_SET, apply the operation as described in RTLM7, passing inObjectMessage.operation.mapOpandObjectMessage.serial(RTLM15d3)IfObjectMessage.operation.actionis set toMAP_REMOVE, apply the operation as described in RTLM8, passing inObjectMessage.operation.mapOpandObjectMessage.serial(RTLM15d4)Otherwise, log a warning that an object operation message with an unsupported action has been received, and discard the currentObjectMessagewithout taking any action
(RTLM16)AMAP_CREATEoperation can be applied to aLiveMapin the following way:(RTLM16a)Expects the following argument:(RTLM16a1)ObjectOperation
(RTLM16b)If the private flagcreateOperationIsMergedistrue, log a debug or trace message indicating that the operation will not be applied because aMAP_CREATEoperation has already been applied to thisLiveMap, and discard the operation without taking any further action(RTLM16c)If the privatesemanticsfield does not matchObjectOperation.map.semantics, log a warning that the operation cannot be applied due to mismatched semantics, and discard the operation without taking any further action(RTLM16d)Otherwise merge the initial value into theLiveMapas described in RTLM17, passing in theObjectOperationinstance
(RTLM7)AMAP_SEToperation for a key can be applied to aLiveMapin the following way:(RTLM7d)Expects the following arguments:(RTLM7d1)ObjectsMapOp(RTLM7d2)serialstring – operation’s serial value
(RTLM7a)If anObjectsMapEntryexists in the privatedatafor the specified key:(RTLM7a1)If the operation cannot be applied to the existing entry as per RTLM9, discard the operation without taking any action(RTLM7a2)Otherwise, apply the operation to the existing entry:(RTLM7a2a)SetObjectsMapEntry.datato theObjectDatafrom the operation(RTLM7a2b)SetObjectsMapEntry.timeserialto the providedserial(RTLM7a2c)SetObjectsMapEntry.tombstonetofalse
(RTLM7b)If an entry does not exist in the privatedatafor the specified key:(RTLM7b1)Create a newObjectsMapEntryindatafor the specified key, withObjectsMapEntry.dataset to the providedObjectDataandObjectsMapEntry.timeserialset toserial(RTLM7b2)SetObjectsMapEntry.tombstonefor the new entry tofalse
(RTLM7c)If the operation has a non-emptyObjectData.objectIdattribute:(RTLM7c1)Create a zero-valueLiveObjectfor thisObjectData.objectIdin the internalObjectsPoolper RTO6
(RTLM8)MAP_REMOVEoperation for a key can be applied to aLiveMapin the following way:(RTLM8c)Expects the following arguments:(RTLM8c1)ObjectsMapOp(RTLM8c2)serialstring – operation’s serial value
(RTLM8a)If anObjectsMapEntryexists in the privatedatafor the specified key:(RTLM8a1)If the operation cannot be applied to the existing entry as per RTLM9, discard the operation without taking any action(RTLM8a2)Otherwise, apply the operation to the existing entry:(RTLM8a2a)SetObjectsMapEntry.datato undefined/null(RTLM8a2b)SetObjectsMapEntry.timeserialto the providedserial(RTLM8a2c)SetObjectsMapEntry.tombstonetotrue
(RTLM8b)If an entry does not exist in the privatedatafor the specified key:(RTLM8b1)Create a newObjectsMapEntryindatafor the specified key, withObjectsMapEntry.dataset to undefined/null andObjectsMapEntry.timeserialset to the providedserial(RTLM8b2)SetObjectsMapEntry.tombstonefor the new entry totrue
(RTLM9)Whether a map operation can be applied to a map entry is determined as follows:(RTLM9a)For aLiveMapwithsemanticsset toObjectsMapSemantics.LWW(Last-Write-Wins CRDT semantics), the operation must only be applied if its serial is strictly greater (“after”) than the entry’s serial when compared lexicographically(RTLM9b)If both the entry serial and the operation serial are null or empty strings, they are treated as the “earliest possible” serials and considered “equal”, so the operation must not be applied(RTLM9c)If only the entry serial exists and is not an empty string, the missing operation serial is considered lower than the existing entry serial, so the operation must not be applied(RTLM9d)If only the operation serial exists and is not an empty string, it is considered greater than the missing entry serial, so the operation can be applied(RTLM9e)If both serials exist and are not empty strings, compare them lexicographically and allow operation to be applied only if the operation’s serial is greater than the entry’s serial
(RTLM17)The initial value fromObjectOperation.mapcan be merged into thisLiveMapin the following way:(RTLM17a)For each key–@ObjectsMapEntry@ pair inObjectOperation.map.entries:(RTLM17a1)IfObjectsMapEntry.tombstoneisfalseor omitted, apply theMAP_SEToperation to the current key as described in RTLM7, passing inObjectsMapEntry.dataand the current key asObjectsMapOp, andObjectsMapEntry.timeserialasserial(RTLM17a2)IfObjectsMapEntry.tombstoneistrue, apply theMAP_REMOVEoperation to the current key as described in RTLM8, passing in the current key asObjectsMapOp, andObjectsMapEntry.timeserialasserial
(RTLM17b)Set the private flagcreateOperationIsMergedtotrue
Describes types for RealtimeObjects.
Types and their properties/methods are public and exposed to users by default. An internal label may be used to indicate that a type or its property/method must not be exposed to users and is intended for internal SDK use only.
class RealtimeObjects: // RTO* getRoot() => io LiveMap // RTO1 class LiveObject: // RTLO* objectId: String // RTLO3a, internal siteTimeserials: Dict<String, String> // RTLO3b, internal createOperationIsMerged: Boolean // RTLO3c, internal canApplyOperation(ObjectMessage) -> Boolean // RTLO4a, internal class LiveCounter extends LiveObject: // RTLC*, RTLC1 value() -> Number // RTLC5 class LiveMap extends LiveObject: // RTLM*, RTLM1 get(key: String) -> (Boolean | Binary | Number | String | JsonArray | JsonObject | LiveCounter | LiveMap)? // RTLM5 size() -> Number // RTLM10 entries() -> [String, (Boolean | Binary | Number | String | JsonArray | JsonObject | LiveCounter | LiveMap)?][] // RTLM11 keys() -> String[] // RTLM12 values() -> (Boolean | Binary | Number | String | JsonArray | JsonObject | LiveCounter | LiveMap)?[] // RTLM13