Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
051ba03
Rename entry point: `channel.objects.getRoot()` -> `channel.object.ge…
VeskeR Feb 24, 2026
a416411
PathObject and Instance API - access and mutation methods (no subscri…
VeskeR Feb 24, 2026
dd11843
LiveMap and LiveCounter creation via value types
VeskeR Feb 24, 2026
f59e8f9
Subscriptions for PathObject and Instance
VeskeR Feb 24, 2026
7d2e7ea
Mark `LiveObjectUpdate` as internal in IDL
lawrence-forooghian May 20, 2026
157fddd
Use arrays, not iterators, for PathObject and Instance getters
lawrence-forooghian May 20, 2026
da192dd
Use explicit delegation for PathObject and Instance methods
lawrence-forooghian May 20, 2026
dea8cf0
Use "evaluate"/"evaluation" instead of "consume"/"consumption" for va…
lawrence-forooghian May 20, 2026
466892d
Fix missing "is" in SUB2a
lawrence-forooghian May 20, 2026
09cf185
Clarify InstanceSubscriptionEvent.object wording
lawrence-forooghian May 20, 2026
ed71a2f
Make LiveMap/LiveCounter/LiveObject fully internal in IDL
lawrence-forooghian May 21, 2026
2b64b35
Reword RTO23d to use PathObject's path/root property names
lawrence-forooghian May 21, 2026
ffbcb65
Drop "public" modifier from RTLO4b and RTLO4c
lawrence-forooghian May 21, 2026
9cc1bc8
Drop RTPO21 and RTINS18 (`subscribeIterator` spec points)
lawrence-forooghian May 21, 2026
99334f4
Specify public-facing types for subscription event message field
lawrence-forooghian May 21, 2026
dd25afd
Propagate source ObjectMessage on LiveObjectUpdate
lawrence-forooghian May 21, 2026
2eb4f81
Unify dispatch and surface ObjectMessage to subscribers
lawrence-forooghian May 21, 2026
9e8ce98
Restructure path-based subscription dispatch
lawrence-forooghian May 21, 2026
5832222
remove RTO24d
lawrence-forooghian May 22, 2026
037de99
Remove unsubscribe(listener) from LiveObject/PathObject/Instance
lawrence-forooghian May 22, 2026
535eaee
Specify that Subscription#unsubscribe is idempotent
lawrence-forooghian May 22, 2026
294b7b1
Add internal *ValueType backing fields to the IDL
lawrence-forooghian May 22, 2026
32e2351
Add placeholder RTLO3f for parentReferences
lawrence-forooghian May 22, 2026
c83ce63
Add `getFullPaths` from PR #480 (unreviewed)
lawrence-forooghian May 22, 2026
d524ec4
Replace "outermost" with "final element" in *_CREATE references
lawrence-forooghian May 22, 2026
a12ba53
Mark PAOM2c `connectionId` as optional
lawrence-forooghian May 22, 2026
807d3c5
Make PAOM3's operation precondition explicit
lawrence-forooghian May 22, 2026
3edaf71
Mark PAOM2a `id` and PAOM2d `timestamp` as optional
lawrence-forooghian May 22, 2026
4a8e293
Align LiveObject tombstone behaviour with ably-js
lawrence-forooghian May 24, 2026
103f5b9
Pull parentReferences maintenance rules from PR #480
lawrence-forooghian May 24, 2026
a5bde95
Lowercase RFC 2119 keywords in clauses imported from PR #480
lawrence-forooghian May 24, 2026
084d7d1
Add argument types to addParentReference/removeParentReference IDL
lawrence-forooghian May 24, 2026
cc093b5
Add getFullPaths to the LiveObject IDL
lawrence-forooghian May 24, 2026
7132962
Tighten parent-presence wording in RTLO4g/RTLO4h
lawrence-forooghian May 24, 2026
aae86c3
Simplify RTO5c10
lawrence-forooghian May 24, 2026
1e56ade
Rework RTLO4e9 tombstone children walk
lawrence-forooghian May 24, 2026
4ec119b
Tidy RTLM7 parent-reference clauses
lawrence-forooghian May 24, 2026
4dc800d
Tighten parent-ref cleanup clauses to a single parallel form
lawrence-forooghian May 24, 2026
f399e44
Restructure parent-ref cleanup clauses around the data modification
lawrence-forooghian May 24, 2026
de3574f
Rework RTLO4f around an explicit graph-theoretic definition
lawrence-forooghian May 24, 2026
69ae754
Centralise PathObject/Instance access checks in RTO25/RTO26
lawrence-forooghian May 25, 2026
d2fe1bd
Add UTS test specs for LiveObjects path-based API (~330 tests)
paddybyers May 13, 2026
828b8e1
Delegate proxy port assignment to uts-proxy in all test specs
paddybyers May 14, 2026
97d02db
Update UTS test specs to match LiveObjects path-based API spec (a397e34)
paddybyers May 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ Historically, before the above guidance was established - in particular around _
This left us open to the problem that client library references to spec items could end up semantically invalid if that spec point was re-used later.
For example, if `XXX1a` and `XXX1c` exist but `XXX1b` doesn’t because it was removed in the past (prior to this guidance being established), then we should introduce `XXX1d` for the new spec item rather than re-using `XXX1b`.

## Public-API namespacing for name clashes

Most spec types are public API by default (the IDL marks the exceptions with `internal`). When a public-API type would have the same natural name as an existing internal/wire concept, the first preference is to rename the internal concept so the public type can take the unqualified name. Where no good rename exists for the internal concept, or where renaming it would cause excessive churn or inconsistency across the spec, the spec instead qualifies the public type with a `PublicAPI::` namespace prefix (e.g. `PublicAPI::ObjectMessage`).

This is purely a spec-side disambiguation: SDKs should expose the type to users under its unqualified name (here, `ObjectMessage`). Where an SDK's language uses a single flat namespace and cannot have two types with that name, the canonical/wire concept may be renamed internally (e.g. `WireObjectMessage`) to free up the public name.

The `PublicAPI::` prefix is only introduced when there is an actual clash; the bare name remains the canonical reference everywhere else.

## SDK API docstrings

The `api-docstrings.md` file is a set of language-agnostic reference API commentaries for SDK developers to use when adding docstring comments to Ably SDKs. For new fields, this file should be modified in the same PR that makes the spec changes for those fields.
Expand Down
34 changes: 22 additions & 12 deletions specifications/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -377,15 +377,15 @@ Support for the deprecated client options `environment`, `restHost`, `realtimeHo
- `(PC2)` No generic plugin interface is specified, and therefore there is no common API exposed by all plugins. However, for type-safety, the opaque interface `Plugin` should be used in strongly-typed languages as the type of the `ClientOptions.plugins` collection as per [TO3o](#TO3o).
- `(PC3)` A plugin provided with the `PluginType` enum key value of `vcdiff` should be capable of decoding "vcdiff"-encoded messages. It must implement the `VCDiffDecoder` interface and the client library must be able to use it by casting it to this interface.
- `(PC3a)` The base argument of the `VCDiffDecoder.decode` method should receive the stored base payload of the last message on a channel as specified by [RTL19](#RTL19). If the base payload is a string it should be encoded to binary using UTF-8 before being passed as base argument of the `VCDiffDecoder.decode` method.
- `(PC5)` A plugin provided with the `PluginType` enum key value of `Objects` should provide the [RealtimeObjects](../objects-features#RTO1) feature functionality for realtime channels ([RTL27](#RTL27)). The plugin object itself is not expected to provide a public API. The type of the plugin object, and how it enables the Objects feature for a realtime channel, are left for individual implementations to decide.
- `(PC5)` A plugin provided with the `PluginType` enum key value of `LiveObjects` should provide the [RealtimeObject](../objects-features#RTO23) feature functionality for realtime channels ([RTL27](#RTL27)). The plugin object itself is not expected to provide a public API. The type of the plugin object, and how it enables the Objects feature for a realtime channel, are left for individual implementations to decide.
- `(PC4)` A client library is allowed to accept plugins other than those specified in this specification, through the use of additional `ClientOptions.plugins` keys defined by that library. The library is responsible for defining the interface of these plugins, and for making sure that these keys do not clash with the keys defined in this specification.

### PluginType {#plugin-type}

- `(PT1)` `PluginType` is an enum describing the different types of plugins that the library supports. See the `ClientOptions#plugins` property ([TO3o](#TO3o)).
- `(PT2)` `PluginType` takes one of the following values:
- `(PT2a)` `vcdiff` -- see [PC3](#PC3).
- `(PT2b)` `Objects` -- see [PC5](#PC5).
- `(PT2b)` `LiveObjects` -- see [PC5](#PC5).

### VCDiffDecoder {#vcdiff-decoder}

Expand Down Expand Up @@ -673,7 +673,7 @@ The threading and/or asynchronous model for each realtime library will vary by l
### RealtimeChannel {#realtime-channel}

- `(RTL23)` `RealtimeChannel#name` attribute is a string containing the channel's name
- `(RTL1)` As soon as a `RealtimeChannel` becomes attached, all incoming messages, presence messages and object messages (where 'incoming' is defined as 'received from Ably over the realtime transport') are processed and emitted where applicable. `PRESENCE` and `SYNC` messages are passed to the `RealtimePresence` object ensuring it maintains a map of current members on a channel in realtime. `OBJECT` and `OBJECT_SYNC` messages are passed to the `RealtimeObjects` object ensuring it maintains an up-to-date representation of objects on a channel in realtime
- `(RTL1)` As soon as a `RealtimeChannel` becomes attached, all incoming messages, presence messages and object messages (where 'incoming' is defined as 'received from Ably over the realtime transport') are processed and emitted where applicable. `PRESENCE` and `SYNC` messages are passed to the `RealtimePresence` object ensuring it maintains a map of current members on a channel in realtime. `OBJECT` and `OBJECT_SYNC` messages are passed to the `RealtimeObject` object ensuring it maintains an up-to-date representation of objects on a channel in realtime
- `(RTL2)` The `RealtimeChannel` implements `EventEmitter` and emits `ChannelEvent` events, where a `ChannelEvent` is either a `ChannelState` or `UPDATE`, and a `ChannelState` is either `INITIALIZED`, `ATTACHING`, `ATTACHED`, `DETACHING`, `DETACHED`, `SUSPENDED` and `FAILED`
- `(RTL2a)` It emits a `ChannelState` `ChannelEvent` for every channel state change
- `(RTL2g)` It emits an `UPDATE` `ChannelEvent` for changes to channel conditions for which the `ChannelState` (e.g. `ATTACHED`) does not change, unless explicitly prevented by a more specific condition (see [RTL12](#RTL12)). (The library must never emit a `ChannelState` `ChannelEvent` for a state equal to the previous state)
Expand Down Expand Up @@ -767,9 +767,9 @@ The threading and/or asynchronous model for each realtime library will vary by l
- `(RTL8b)` Unsubscribe with a name argument and a listener argument unsubscribes the provided listener if previously subscribed with a name-specific subscription
- `(RTL9)` `RealtimeChannel#presence` attribute:
- `(RTL9a)` Returns the `RealtimePresence` object for this channel
- `(RTL27)` `RealtimeChannel#objects` attribute:
- `(RTL27a)` Returns the `RealtimeObjects` object for this channel [RTO1](../objects-features#RTO1)
- `(RTL27b)` It is a programmer error to access this property without first providing the `Objects` plugin ([PC5](#PC5)) in the client options. This programmer error should be handled in an idiomatic fashion; if this means accessing the property should throw an error, then the error should be an `ErrorInfo` with `statusCode` 400 and `code` 40019.
- `(RTL27)` `RealtimeChannel#object` attribute:
- `(RTL27a)` Returns the `RealtimeObject` object for this channel [RTO23](../objects-features#RTO23)
- `(RTL27b)` It is a programmer error to access this property without first providing the `LiveObjects` plugin ([PC5](#PC5)) in the client options. This programmer error should be handled in an idiomatic fashion; if this means accessing the property should throw an error, then the error should be an `ErrorInfo` with `statusCode` 400 and `code` 40019.
- `(RTL10)` `RealtimeChannel#history` function:
- `(RTL10a)` Supports all the same params as `RestChannel#history`
- `(RTL10b)` Additionally supports the param `untilAttach`, which if true, will only retrieve messages prior to the moment that the channel was attached or emitted an `UPDATE` indicating loss of continuity. This bound is specified by passing the querystring param `fromSerial` with the `RealtimeChannel#properties.attachSerial` assigned to the channel in the `ATTACHED` `ProtocolMessage` (see [RTL15a](#RTL15a)). If the `untilAttach` param is specified when the channel is not attached, it results in an error
Expand Down Expand Up @@ -937,9 +937,9 @@ The threading and/or asynchronous model for each realtime library will vary by l
- `(RTP15e)` 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
- `(RTP15f)` If the client is identified and has a valid `clientId`, and the `clientId` argument does not match the client's `clientId`, then it should indicate an error. The connection and channel remain available for further operations

### RealtimeObjects {#realtime-objects}
### RealtimeObject {#realtime-objects}

Reserved for `RealtimeObjects` feature specification, see [objects-features](../objects-features). Reserved spec points: `RTO`, `RTLO`, `RTLC`, `RTLM`
Reserved for `RealtimeObject` feature specification, see [objects-features](../objects-features). Reserved spec points: `RTO`, `RTLO`, `RTLC`, `RTLM`, `RTPO`, `RTINS`, `RTLCV`, `RTLMV`

### RealtimeAnnotations {#realtime-annotations}

Expand Down Expand Up @@ -1333,13 +1333,13 @@ The core SDK provides an API for wrapper SDKs to supply Ably with analytics info
- `(OOP4g)` The size is the sum of the sizes of the map create, `mapSet`, `mapRemove`, counter create, and `counterInc` components
- `(OOP4h)` The size of the map create component is:
- `(OOP4h1)` If `mapCreate` is present, it is equal to the size of `mapCreate` calculated per [MCR3](#MCR3)
- `(OOP4h2)` Else if `mapCreateWithObjectId` is present, it is equal to the size of the `MapCreate` retained in [RTO11f18](objects-features#RTO11f18), calculated per [MCR3](#MCR3)
- `(OOP4h2)` Else if `mapCreateWithObjectId` is present, it is equal to the size of the `MapCreate` retained in [RTLMV4j5](objects-features#RTLMV4j5), calculated per [MCR3](#MCR3)
- `(OOP4h3)` Otherwise it is zero
- `(OOP4i)` The size of the `mapSet` property is calculated per [MST3](#MST3)
- `(OOP4j)` The size of the `mapRemove` property is calculated per [MRM3](#MRM3)
- `(OOP4k)` The size of the counter create component is:
- `(OOP4k1)` If `counterCreate` is present, it is equal to the size of `counterCreate` calculated per [CCR3](#CCR3)
- `(OOP4k2)` Else if `counterCreateWithObjectId` is present, it is equal to the size of the `CounterCreate` retained in [RTO12f16](objects-features#RTO12f16), calculated per [CCR3](#CCR3)
- `(OOP4k2)` Else if `counterCreateWithObjectId` is present, it is equal to the size of the `CounterCreate` retained in [RTLCV4g5](objects-features#RTLCV4g5), calculated per [CCR3](#CCR3)
- `(OOP4k3)` Otherwise it is zero
- `(OOP4l)` The size of the `counterInc` property is calculated per [CIN3](#CIN3)
- `(OOP4f)` The size of a `null` or omitted property is zero
Expand Down Expand Up @@ -1872,6 +1872,13 @@ The core SDK provides an API for wrapper SDKs to supply Ably with analytics info
- `(REX2b1)` Should be written in reverse domain name notation
- `(REX2b2)` Types beginning with `com.ably.` are reserved

#### Subscription

- `(SUB1)` A `Subscription` represents a registration for receiving events from a subscribe operation
- `(SUB2)` The `Subscription` object has the following method:
- `(SUB2a)` `unsubscribe` - deregisters the listener that was registered by the corresponding `subscribe` call. Once `unsubscribe` is called, the listener must not be called for any subsequent events
- `(SUB2b)` Calling `unsubscribe` more than once is a no-op

### Option types {#options}

#### ClientOptions
Expand Down Expand Up @@ -2260,7 +2267,7 @@ Each type, method, and attribute is labelled with the name of one or more clause
state: ChannelState // RTL2b
whenState(ChannelState, (ChannelStateChange?) ->) // RTL25
presence: RealtimePresence // RTL9
objects: RealtimeObjects // RTL27
object: RealtimeObject // RTL27
properties: ChannelProperties // RTL15
// Only on platforms that support receiving push notifications:
push: PushChannel // RSH7
Expand Down Expand Up @@ -2840,7 +2847,7 @@ Each type, method, and attribute is labelled with the name of one or more clause

enum PluginType // PT*
"vcdiff" // PT2a
"Objects" // PT2b
"LiveObjects" // PT2b

class VCDiffDecoder // VD*
decode([byte] delta, [byte] base) -> [byte] // VD2a, PC3a
Expand Down Expand Up @@ -2926,6 +2933,9 @@ Each type, method, and attribute is labelled with the name of one or more clause
description: string? // TM2s4
metadata: Dict<string, string>? //TM2s5

interface Subscription: // SUB*
unsubscribe() // SUB2a

## Old specs

Use the version navigation to view older versions. References to diffs for each version are maintained below:
Expand Down
Loading