From e157409db7dc1e13f89cb8eaf4d34a334b427155 Mon Sep 17 00:00:00 2001 From: Andrew Bulat Date: Tue, 12 May 2026 17:00:14 -0300 Subject: [PATCH 1/3] Implicit attach on `channel.objects.getRoot()` call As already implemented in JS in 9bde15e. Co-Authored-By: Lawrence Forooghian --- specifications/objects-features.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/specifications/objects-features.md b/specifications/objects-features.md index 5a1e64db9..170031112 100644 --- a/specifications/objects-features.md +++ b/specifications/objects-features.md @@ -12,7 +12,9 @@ Objects feature enables clients to store shared data as "objects" on a channel. - `(RTO1)` `RealtimeObjects#getRoot` function: - `(RTO1a)` Requires the `OBJECT_SUBSCRIBE` channel mode to be granted per [RTO2](#RTO2) - - `(RTO1b)` If the channel is in the `DETACHED` or `FAILED` state, the library should throw an `ErrorInfo` error with `statusCode` 400 and `code` 90001 + - `(RTO1b)` This clause has been replaced by [RTO1e](#RTO1e) and [RTO1f](#RTO1f). + - `(RTO1e)` If the channel is in the `INITIALIZED`, `DETACHED`, `DETACHING`, or `ATTACHING` state, implicitly attach the `RealtimeChannel` and wait for the attach to complete + - `(RTO1f)` If the channel is in the `FAILED` state, the library should throw an `ErrorInfo` error with `statusCode` 400 and `code` 90001, indicating that the channel operation failed due to the current channel state - `(RTO1c)` If the [RTO17](#RTO17) sync state is not `SYNCED`, waits for the sync state to transition to `SYNCED` - `(RTO1d)` Returns the object with id `root` from the internal `ObjectsPool` as a `LiveMap` - `(RTO11)` `RealtimeObjects#createMap` function: From 2c9b91be50700e1978d87fe6e9845df1174c71af Mon Sep 17 00:00:00 2001 From: sacOO7 Date: Tue, 19 May 2026 15:43:21 +0530 Subject: [PATCH 2/3] Updated spec for implicit attach as per review comments --- specifications/objects-features.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/specifications/objects-features.md b/specifications/objects-features.md index 170031112..24a6c6052 100644 --- a/specifications/objects-features.md +++ b/specifications/objects-features.md @@ -12,9 +12,12 @@ Objects feature enables clients to store shared data as "objects" on a channel. - `(RTO1)` `RealtimeObjects#getRoot` function: - `(RTO1a)` Requires the `OBJECT_SUBSCRIBE` channel mode to be granted per [RTO2](#RTO2) - - `(RTO1b)` This clause has been replaced by [RTO1e](#RTO1e) and [RTO1f](#RTO1f). - - `(RTO1e)` If the channel is in the `INITIALIZED`, `DETACHED`, `DETACHING`, or `ATTACHING` state, implicitly attach the `RealtimeChannel` and wait for the attach to complete - - `(RTO1f)` If the channel is in the `FAILED` state, the library should throw an `ErrorInfo` error with `statusCode` 400 and `code` 90001, indicating that the channel operation failed due to the current channel state + - `(RTO1b)` This clause has been replaced by [RTO1e](#RTO1e). + - `(RTO1e)` Performs the *ensure-attached* procedure to make sure the underlying `RealtimeChannel` is in the `ATTACHED` state before proceeding. + - `(RTO1e1)` If the channel is in the `INITIALIZED`, `DETACHED`, `DETACHING`, or `ATTACHING` state, implicitly attach the `RealtimeChannel` and wait for the attach to complete + - `(RTO1e1a)` If the implicit attach fails (for example, the channel transitions to the non-attached state), the call MUST reject with the same `ErrorInfo` that caused the attach to fail + - `(RTO1e2)` If the channel is in the `FAILED` state, the library MUST throw an `ErrorInfo` error with `statusCode` 400 and `code` 90001, indicating that the channel operation failed due to the current channel state + - `(RTO1e3)` If the channel is in the `ATTACHED` or `SUSPENDED` state, proceed without attaching. A `SUSPENDED` channel is intentionally not re-attached so that any locally-held object state remains readable while the connection and channel state is being re-established. - `(RTO1c)` If the [RTO17](#RTO17) sync state is not `SYNCED`, waits for the sync state to transition to `SYNCED` - `(RTO1d)` Returns the object with id `root` from the internal `ObjectsPool` as a `LiveMap` - `(RTO11)` `RealtimeObjects#createMap` function: From 582f2e2286a3ce3b94bbdef88fdc9ef4ee944550 Mon Sep 17 00:00:00 2001 From: sacOO7 Date: Thu, 21 May 2026 00:58:09 +0530 Subject: [PATCH 3/3] Addressed review feedback, added separate spec point for `ensure-active-channel` procedure to avoid spec duplication --- specifications/features.md | 8 +++++++- specifications/objects-features.md | 8 ++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/specifications/features.md b/specifications/features.md index e30f80ef1..34863d52b 100644 --- a/specifications/features.md +++ b/specifications/features.md @@ -820,6 +820,11 @@ The threading and/or asynchronous model for each realtime library will vary by l - `(RTL32e)` Any params provided in the third argument must be sent in the `TR4q` `ProtocolMessage.params` field, as a `Dict` (that is, with the values of the provided dict stringified per `RTC1f`) - `(RTL32c)` The SDK must not mutate the user-supplied `Message` object. - `(RTL32d)` On success, returns an `UpdateDeleteResult` object containing the version serial of the published update, obtained from the first element of the `serials` array of the [TR4s](#TR4s) `res` field of the `ACK`. Indicates an error if the operation was not successful. +- `(RTL33)` *Ensure-active-channel* internal procedure. When invoked, the SDK MUST inspect the current state of the `RealtimeChannel` (see [RTL2](#RTL2)) and proceed as follows: + - `(RTL33a)` If the channel is in the `ATTACHED` or `SUSPENDED` state, the procedure completes immediately without performing any attach. + - `(RTL33b)` If the channel is in the `INITIALIZED`, `DETACHED`, `DETACHING`, or `ATTACHING` state, perform an implicit attach per [RTL4](#RTL4) and wait for it to complete + - `(RTL33b1)` If the implicit attach fails (for example, the channel transitions to the `FAILED` state, or the underlying attach is otherwise rejected), the procedure MUST reject with the same `ErrorInfo` that caused the attach to fail + - `(RTL33c)` If the channel is in the `FAILED` state, the procedure MUST throw an `ErrorInfo` with `statusCode` 400 and `code` 90001, indicating that the channel operation failed due to the current channel state ### RealtimePresence {#realtime-presence} @@ -913,8 +918,9 @@ The threading and/or asynchronous model for each realtime library will vary by l - `(RTP10e)` In all other ways, this method is identical to `RealtimePresence#enter` and should have matching tests - `(RTP11)` `RealtimePresence#get` function: - `(RTP11a)` Returns the list of current members on the channel in a callback. By default, will wait for the `SYNC` to be completed, see [RTP11c1](#RTP11c1) - - `(RTP11b)` Implicitly attaches the `RealtimeChannel` if the channel is in the `INITIALIZED` state. However, if the channel is in or enters the `DETACHED` or `FAILED` state before the operation succeeds, it will result in an error + - `(RTP11b)` This clause has been replaced by [RTP11e](#RTP11e) - `(RTP11d)` If the `RealtimeChannel` is in the `SUSPENDED` state then the `get` function will by default, or if `waitForSync` is set to `true`, result in an error with `code` `91005` and a `message` stating that the presence state is out of sync due to the channel being in a `SUSPENDED` state. If however the `get` function is called with `waitForSync` set to `false`, then it immediately returns the members currently stored in the `PresenceMap` giving developers access to the members that were present at the time the channel became `SUSPENDED` + - `(RTP11e)` Perform the *ensure-active-channel* procedure ([RTL33](#RTL33)) on the underlying `RealtimeChannel`. Note that [RTP11d](#RTP11d) takes precedence over current spec point [RTP11e](#RTP11e) - `(RTP11c)` An optional set of params can be provided: - `(RTP11c1)` `waitForSync` (default `true`). When `true`, method will wait until `SYNC` is complete before returning a list of members. When `false`, known set of presence members is returned immediately, which may be incomplete if the `SYNC` is not finished - `(RTP11c2)` `clientId` filters members by the provided `clientId` diff --git a/specifications/objects-features.md b/specifications/objects-features.md index 24a6c6052..1510468b4 100644 --- a/specifications/objects-features.md +++ b/specifications/objects-features.md @@ -12,12 +12,8 @@ Objects feature enables clients to store shared data as "objects" on a channel. - `(RTO1)` `RealtimeObjects#getRoot` function: - `(RTO1a)` Requires the `OBJECT_SUBSCRIBE` channel mode to be granted per [RTO2](#RTO2) - - `(RTO1b)` This clause has been replaced by [RTO1e](#RTO1e). - - `(RTO1e)` Performs the *ensure-attached* procedure to make sure the underlying `RealtimeChannel` is in the `ATTACHED` state before proceeding. - - `(RTO1e1)` If the channel is in the `INITIALIZED`, `DETACHED`, `DETACHING`, or `ATTACHING` state, implicitly attach the `RealtimeChannel` and wait for the attach to complete - - `(RTO1e1a)` If the implicit attach fails (for example, the channel transitions to the non-attached state), the call MUST reject with the same `ErrorInfo` that caused the attach to fail - - `(RTO1e2)` If the channel is in the `FAILED` state, the library MUST throw an `ErrorInfo` error with `statusCode` 400 and `code` 90001, indicating that the channel operation failed due to the current channel state - - `(RTO1e3)` If the channel is in the `ATTACHED` or `SUSPENDED` state, proceed without attaching. A `SUSPENDED` channel is intentionally not re-attached so that any locally-held object state remains readable while the connection and channel state is being re-established. + - `(RTO1b)` This clause has been replaced by [RTO1e](#RTO1e) + - `(RTO1e)` Perform the *ensure-active-channel* procedure ([RTL33](../features#RTL33)) on the underlying `RealtimeChannel`. - `(RTO1c)` If the [RTO17](#RTO17) sync state is not `SYNCED`, waits for the sync state to transition to `SYNCED` - `(RTO1d)` Returns the object with id `root` from the internal `ObjectsPool` as a `LiveMap` - `(RTO11)` `RealtimeObjects#createMap` function: