Thanks to visit codestin.com
Credit goes to sdk.ably.com

Ably Specification: Features

See also:

This document outlines the complete feature set of both the REST and Realtime client libraries. It is expected that every client library developer refers to this document to ensure that their client library provides the same API and features as the existing Ably client libraries. In addition to this, it is essential that there is test coverage over all of the features described below. As an example, see the Ruby library test specification and coverage generated from the test suite.

We recommend you use the IDL and refer to other existing libraries that adhere to this spec as a reference when reviewing how the API has been implemented.

The key words “must”, “must not”, “required”, “shall”, “shall not”, “should”, “should not”, “recommended”, “may”, and “optional” (whether lowercased or uppercased) in this document are to be interpreted as described in RFC 2119 .

Please note we maintain a separate Google Sheet that keeps track of which features are implemented and matching test coverage for each client library. If you intend to work on an Ably client library, please contact us for access to this Google Sheet as it is useful as a reference and also needs to be kept up to date

Specification and Protocol Versions

Test guidelines

Client library endpoint configuration

REST client library

RestClient

Auth

Channels

RestChannel

Plugins

PluginType

VCDiffDecoder

RestPresence

Encryption

RestAnnotations

Forwards compatibility

Realtime client library features

The Ably Realtime client libraries establish and maintain a persistent connection to Ably and provide methods to publish and subscribe to messages over a low latency realtime connection.

The Realtime library is a super-set of the REST library and as such all Realtime libraries provide the functionality available in the REST library in addition to Realtime-specific features.

The threading and/or asynchronous model for each realtime library will vary by language and it is therefore up to the developer to decide on the best approach for each given client library. For example, Node.js and Ruby (EventMachine) use a similar callback single threaded evented approach that ensures all public methods are non-blocking. Java and .NET use a threaded model whereby the Connection runs in its own thread. Go makes extensive use of goroutines and channels.

RealtimeClient

Connection

Channels

RealtimeChannel

RealtimePresence

RealtimeObjects

Reserved for RealtimeObjects feature specification, see objects-features. Reserved spec points: RTO, RTLO, RTLC, RTLM

RealtimeAnnotations

EventEmitter mixin / interface

Incremental backoff and jitter

Forwards compatibility

Wrapper SDK proxy client

A wrapper SDK is an Ably-authored non-core SDK.

The core SDK provides an API for wrapper SDKs to supply Ably with analytics information that allows us track the usage of these SDKs.

State conditions and operations

Connection.state effects on realtime operations

Initialized Connecting Connected Disconnected Suspended Closing Closed Failed
connect RTN11f No-op (RTN11e) No-op (RTN11e) RTN11f, RTN11c RTN11f, RTN11c RTN11f, RTN11b RTN11f, RTN11d RTN11f, RTN11d
close No-op RTN12f RTN12a RTN12d RTN12d No-op No-op No-op
ping RTN13b RTN13c RTN13a RTN13c RTN13b RTN13b RTN13b RTN13b
RealtimeChannel attach RTL4h RTL4h See channel states table RTL4h RTL4b RTL4b RTL4b RTL4b
RealtimeChannel detach RTL5h RTL5h See channel states table RTL5h See channel states table RTL5g See channel states table RTL5g
RealtimeChannel publish RTL6c2 RTL6c2 See channel states table RTL6c2 RTL6c4 RTL6c4 RTL6c4 RTL6c4
Presence ops. RTP16b RTP16b See channel states table RTP16b RTP16c RTP16c RTP16c RTP16c

RealtimeChannel.state effects on channel operations

Initialized Attaching Attached Suspended Detaching Detached Failed
attach RTL4c RTL4h RTL4a RTL4c RTL4h RTL4c RTL4g
detach RTL5h RTL5i RTL5d RTL5j RTL5i RTL5a RTL5b
publish RTL6c2 RTL6c2 RTL6c1 RTL6c4 RTL6c4 RTL6c4 RTL6c3
Presence ops. RTP16b RTP16b RTP16a RTP16c RTP16c RTP16c RTP16c

Push notifications

Activation State Machine

Push device authentication

Push channels

LocalDevice

Types

Data types

Message

DeltaExtras

PresenceMessage

ObjectMessage

ObjectOperation

ObjectState

MapCreate

MapSet

MapRemove

CounterCreate

CounterInc

ObjectDelete

MapCreateWithObjectId

CounterCreateWithObjectId

ObjectsMapOp

ObjectsCounterOp

ObjectsMap

ObjectsCounter

ObjectsMapEntry

ObjectData

Annotation

ProtocolMessage

PaginatedResult

HttpPaginatedResponse

TokenRequest

TokenDetails

Token string

AuthDetails

Stats

ErrorInfo

ConnectionStateChange

ChannelStateChange

Capability – API not defined yet

ConnectionDetails

ChannelDetails

ChannelStatus

ChannelOccupancy

ChannelMetrics

BatchResult

BatchPublishSpec

BatchPublishSuccessResult

BatchPublishFailureResult

BatchPresenceSuccessResult

BatchPresenceFailureResult

PublishResult

UpdateDeleteResult

TokenRevocationTargetSpecifier

TokenRevocationSuccessResult

TokenRevocationFailureResult

MessageFilter

ReferenceExtras

Option types

ClientOptions

TokenParams

AuthOptions

ChannelOptions

DeriveOptions

CipherParams

CipherParamOptions

WrapperSDKProxyOptions

Push notifications

PushChannelSubscription

DeviceDetails

DevicePushDetails

Client library introspection

ClientInformation

Client Library defaults

The following default values are configured for the client library:

Interface Definition

The following bespoke IDL (Interface Definition Language) describes the types and classes present in the REST and Realtime client libraries.

Please note the following conventions:

Each type, method, and attribute is labelled with the name of one or more clauses from the preceding feature spec. An asterisk is used as a wildcard to mean all clauses with a given prefix.

class RestClient: // RSC*
  constructor(keyOrTokenStr: String) // RSC1
  constructor(ClientOptions) // RSC1
  auth: Auth // RSC5
  push: Push // RSC21
  device() => io LocalDevice // RSH8
  channels: Channels<RestChannel> // RSN1
  request(
    String method,
    String path,
    Int version,
    Dict<String, String> params?,
    JsonObject | JsonArray body?,
    Dict<String, String> headers?
  ) => io HttpPaginatedResponse // RSC19
  stats(
    start: Time api-default epoch(), // RSC6b1
    end: Time api-default now(), // RSC6b1
    direction: .Backwards | .Forwards api-default .Backwards, // RSC6b2
    limit: int api-default 100, // RSC6b3
    unit: .Minute | .Hour | .Day | .Month api-default .Minute // RSC6b4
  ) => io PaginatedResult<Stats> // RSC6a
  time() => io Time // RSC16
  batchPublish(BatchPublishSpec) => io BatchResult<BatchPublishSuccessResult | BatchPublishFailureResult> // RSC22
  batchPublish(BatchPublishSpec[]) => io BatchResult<BatchPublishSuccessResult | BatchPublishFailureResult>[] // RSC22
  batchPresence(string[]) => io BatchResult<BatchPresenceSuccessResult | BatchPresenceFailureResult> // RSC24
  createWrapperSDKProxy(WrapperSDKProxyOptions) => RestClientInterface // RSC26

interface RestClientInterface // WP*
  // This is an interface that has the same instance methods as RestClient, except for createWrapperSDKProxy.

class RealtimeClient: // RTC*
  constructor(keyOrTokenStr: String) // RTC12
  constructor(ClientOptions) // RTC12
  auth: Auth // RTC4
  push: Push // RTC13
  device() => io LocalDevice // RSH8
  channels: Channels<RealtimeChannel> // RTC3, RTS1
  clientId: String? // RTC17
  connection: Connection // RTC2
  request(
    String method,
    String path,
    Dict<String, String> params?,
    JsonObject | JsonArray body?,
    Dict<String, String> headers?
  ) => io HttpPaginatedResponse // RTC9
  stats(
    start: Time api-default epoch(),
    end: Time api-default now(),
    direction: .Backwards | .Forwards api-default .Backwards,
    limit: int api-default 100,
    unit: .Minute | .Hour | .Day | .Month api-default .Minute
  ) => io PaginatedResult<Stats> // Same as RestClient.stats, RTC5
  close() // RTC16
  connect() // RTC15
  time() => io Time // RTC6
  batchPublish(BatchPublishSpec) => io BatchResult<BatchPublishSuccessResult | BatchPublishFailureResult> // RSC22
  batchPublish(BatchPublishSpec[]) => io BatchResult<BatchPublishSuccessResult | BatchPublishFailureResult>[] // RSC22
  batchPresence(string[]) => io BatchResult<BatchPresenceSuccessResult | BatchPresenceFailureResult> // RSC24
  createWrapperSDKProxy(WrapperSDKProxyOptions) => RealtimeClientInterface // RTC14

interface RealtimeClientInterface // WP*
  // This is an interface that has the same instance methods as RealtimeClient, except for createWrapperSDKProxy.

class ClientOptions: // TO*
  embeds AuthOptions // This is not currently documented in the spec and needs to be – see https://github.com/ably/docs/issues/1476
  autoConnect: Bool default true // RTC1b, TO3e
  clientId: String? // RSC17, RSA15, TO3a
  defaultTokenParams: TokenParams? // TO3j11
  echoMessages: Bool default true // RTC1a, TO3h
  environment: String? // RSC15e, TO3k1
  endpoint: String? // RSC15e, TO3k8
  logHandler: // platform specific - TO3c
  logLevel: // platform specific - TO3b
  logExceptionReportingUrl: String default "[library specific]" // TO3m (deprecated)
  port: Int default 80 // TO3k4
  queueMessages: Bool default true // RTP16b, TO3g
  restHost: String default "main.realtime.ably.net" // RSC12, TO3k2
  realtimeHost: String default "main.realtime.ably.net" // RTC1d, TO3k3
  fallbackHosts: String[] default nil // RSC15b, RSC15a, TO3k6
  fallbackHostsUseDefault: Bool default false // TO3k7 (deprecated)
  recover: String? // RTC1c, TO3i
  tls: Bool default true // RSC18, TO3d
  tlsPort: Int default 443 // TO3k5
  useBinaryProtocol: Bool default true // TO3f
  transportParams: [String: Stringifiable]? // TO3q, RTC1f
  addRequestIds: Bool default false // TO3p
  // configurable retry and failure defaults
  disconnectedRetryTimeout: Duration default 15s // TO3l1
  suspendedRetryTimeout: Duration default 30s // RTN14e, TO3l2
  channelRetryTimeout: Duration default 15s // RTL13b, TO3l7
  httpOpenTimeout: Duration default 4s // TO3l3
  httpRequestTimeout: Duration default 10s // TO3l4
  realtimeRequestTimeout: Duration default 10s // TO3l11
  httpMaxRetryCount: Int default 3 // TO3l5
  httpMaxRetryDuration: Duration default 15s // TO3l6
  maxMessageSize: Int default 65536 // TO3l8
  maxFrameSize: Int default 524288 // TO3l9
  fallbackRetryTimeout: Duration default 600s // TO3l10
  plugins: Dict<PluginType, Plugin> // TO3o
  idempotentRestPublishing: bool default true // RSL1k1, RTL6a1, TO3n
  agents: [String: String?]? // RSC7d6 - interface only offered by some libraries
  connectivityCheckUrl: String default "https://internet-up.ably-realtime.com/is-the-internet-up.txt" // REC3

class AuthOptions: // AO*
  authCallback: ((TokenParams) -> io (String | TokenDetails | TokenRequest | JsonObject))? // RSA4a, RSA4, TO3j5, AO2b
  authHeaders: [String: Stringifiable]? // RSA8c3, TO3j8, AO2e
  authMethod: .GET | .POST default .GET // RSA8c, TO3j7, AO2d
  authParams: [String: Stringifiable]? // RSA8c3, RSA8c1, TO3j9, AO2f
  authUrl: String? // RSA4a, RSA4, RSA8c, TO3j6, AO2c
  key: String? // RSA11, RSA14, TO3j1, AO2a
  queryTime: Bool default false // RSA9d, TO3j10, AO2g
  token: String? | TokenDetails? | TokenRequest? // RSA4a, RSA4, TO3j2, AO2h
  tokenDetails: TokenDetails? // RSA4a, RSA4, TO3j3, AO2i
  useTokenAuth: Bool? // RSA4, RSA14, TO3j4, AO2j

class TokenParams: // TK*
  capability: String api-default '{"*":["*"]}' // RSA9f, TK2b
  clientId: String? // TK2c
  nonce: String? // RSA9c, Tk2e
  timestamp: Time? // RSA9d, TK2d
  ttl: Duration api-default 60min // RSA9e, TK2a

class Auth: // RSA*
  clientId: String? // RSA7, RSC17, RSA12
  authorize(TokenParams?, AuthOptions?) => io TokenDetails // RSA10
  createTokenRequest(TokenParams?, AuthOptions?) => io TokenRequest // RSA9
  requestToken(TokenParams?, AuthOptions?) => io TokenDetails // RSA8
  tokenDetails: TokenDetails? // RSA16
  revokeTokens(TokenRevocationTargetSpecifier[], issuedBefore Time?, allowReauthMargin boolean?) => io BatchResult<TokenRevocationSuccessResult | TokenRevocationFailureResult> // RSA17

class TokenDetails: // TD*
  +fromJson(String | JsonObject) -> TokenDetails // TD7
  capability: String // TD5
  clientId: String? // TD6
  expires: Time // TD3
  issued: Time // TD4
  token: String // TD2

class TokenRequest: // TE*
  +fromJson(String | JsonObject) -> TokenRequest // TE6
  capability: String // TE3
  clientId: String? // TE2
  keyName: String // TE2
  mac: String // TE2
  nonce: String // TE2
  timestamp: Time? // TE5
  ttl: Duration? api-default 60min // TE4

class Channels<ChannelType>: // RSN*, RTS*
  exists(String) -> Bool // RSN2, RTS2
  get(String) -> ChannelType // RSN3, RTS3
  get(String, ChannelOptions) -> ChannelType // RSN3c, RTS3c
  iterate() -> Iterator<ChannelType> // RSN2, RTS2
  release(String) // RSN4, RTS4

class RestChannel: // RSL*
  name: String // RSL9
  presence: RestPresence // RSL3
  history(
    start: Time, // RSL2b1
    end: Time api-default now(), // RSL2b1
    direction: .Backwards | .Forwards api-default .Backwards, // RSL2b2
    limit: int api-default 100 // RSL2b3
  ) => io PaginatedResult<Message> // RSL2
  status() => ChannelDetails // RSL8
  publish(Message, params?: Dict<String, Stringifiable>) => io PublishResult // RSL1
  publish([Message], params?: Dict<String, Stringifiable>) => io PublishResult // RSL1
  publish(name: String?, data: Data?) => io PublishResult // RSL1
  setOptions(options: ChannelOptions) => io // RSL7 - note asynchronous return value for
    // compatibility with RealtimeChannel#setOptions; not required for REST-only libraries
  getMessage(serial: String) => io Message // RSL11
  updateMessage(Message, operation?: MessageOperation, params?: Dict<String, Stringifiable>) => io UpdateDeleteResult // RSL12
  deleteMessage(Message, operation?: MessageOperation, params?: Dict<String, Stringifiable>) => io UpdateDeleteResult // RSL13
  getMessageVersions(serial: String, params?: Dict<String, Stringifiable>) => io PaginatedResult<Message> // RSL14
  appendMessage(Message, operation?: MessageOperation, params?: Dict<String, Stringifiable>) => io UpdateDeleteResult // RSL15

  // Only on platforms that support receiving push notifications:
  push: PushChannel // RSH7

class RealtimeChannel: // RTL*
  embeds EventEmitter<ChannelEvent, ChannelStateChange?> // RTL2, RTL2a, RTL2d
  name: String // RTL23
  errorReason: ErrorInfo? // RTL24
  state: ChannelState // RTL2b
  whenState(ChannelState, (ChannelStateChange?) ->) // RTL25
  presence: RealtimePresence // RTL9
  objects: RealtimeObjects // RTL27
  properties: ChannelProperties // RTL15
  // Only on platforms that support receiving push notifications:
  push: PushChannel // RSH7
  modes: readonly [ChannelMode] // RTL4m
  params: readonly Dict<String, String> // RTL4k1
  attach() => io ChannelStateChange? // RTL4
  detach() => io // RTL5
  history(
    start: Time, // RTL10a
    end: Time api-default now(), // RTL10a
    direction: .Backwards | .Forwards api-default .Backwards, // RTL10a
    limit: int api-default 100, // RTL10a
    untilAttach: Bool default false // RTL10b
  ) => io PaginatedResult<Message> // RTL10
  publish(Message, params?: Dict<String, Stringifiable>) => io PublishResult // RTL6, RTL6i
  publish([Message], params?: Dict<String, Stringifiable>) => io PublishResult // RTL6, RTL6i
  publish(name: String?, data: Data?) => io PublishResult // RTL6, RTL6i
  subscribe((Message) ->) => io ChannelStateChange? // RTL7, RTL7a
  subscribe(String, (Message) ->) => io ChannelStateChange? // RTL7, RTL7b
  subscribe(MessageFilter, (Message) ->) io ChannelStateChange? // RTL22
  unsubscribe() // RTL8, RTL8c
  unsubscribe((Message) ->) // RTL8, RTL8a
  unsubscribe(String, (Message) ->) // RTL8, RTL8b
  unsubscribe(MessageFilter, (Message) ->) // RTL22
  setOptions(options: ChannelOptions) => io // RTL16
  getMessage(serial: String) => io Message // RTL28
  updateMessage(Message, operation?: MessageOperation, params?: Dict<String, Stringifiable>) => io UpdateDeleteResult // RTL29
  deleteMessage(Message, operation?: MessageOperation, params?: Dict<String, Stringifiable>) => io UpdateDeleteResult // RTL30
  getMessageVersions(serial: String, params?: Dict<String, Stringifiable>) => io PaginatedResult<Message> // RTL31
  appendMessage(Message, operation?: MessageOperation, params?: Dict<String, Stringifiable>) => io UpdateDeleteResult // RTL32

class MessageFilter: // MFI*
  isRef: bool // MFI2a
  refTimeserial: string // MFI2b
  refType: string // MFI2c
  name: string // MFI2d

class ChannelProperties: // CP*
  attachSerial: String? // CP2a
  channelSerial: String? // CP2b

// Only on platforms that support receiving push notifications:
class PushChannel: // RSH7
  subscribeDevice() => io // RSH7a
  subscribeClient() => io // RSH7b
  unsubscribeDevice() => io // RSH7c
  unsubscribeClient() => io // RSH7d
  listSubscriptions(params?: Dict<String, String>) => io PaginatedResult<PushChannelSubscription> // RSH7e

enum ChannelState: // RTL2
  INITIALIZED
  ATTACHING
  ATTACHED
  DETACHING
  DETACHED
  SUSPENDED
  FAILED

enum ChannelEvent: // RTL2
  embeds ChannelState
  UPDATE // RTL2g

enum ChannelMode: // TB2d
  PRESENCE
  PUBLISH
  SUBSCRIBE
  MESSAGE_SUBSCRIBE
  PRESENCE_SUBSCRIBE
  OBJECT_SUBSCRIBE
  OBJECT_PUBLISH

class ChannelStateChange: // TH*
  current: ChannelState // TH2, RTL2a, RTL2b
  event: ChannelEvent // TH5
  previous: ChannelState // TH2, RTL2a, RTL2b
  reason: ErrorInfo? // TH3
  resumed: Boolean // RTL2f, TH4
  hasBacklog: Boolean // RTL2i, TH6

class ChannelOptions: // TB*
  +withCipherKey(key: Binary | String)? -> ChannelOptions // TB3
  cipher: (CipherParams | CipherParamOptions)? // RSL5a, TB2b
  params?: Dict<String, String> // TB2c
  modes?: [ChannelMode] // TB2d
  attachOnSubscribe: Bool default true // TB4

class MessageOperation: // MOP*
  clientId?: String // MOP2a
  description?: String // MOP2b
  metadata?: Dict<String, String> // MOP2c

class DeriveOptions: // DO*
  filter: String // DO2a (The filter string is a valid JMESPath String Expression)

class ChannelDetails: // CHD*
  channelId: String // CHD2a
  status: ChannelStatus // CHD2b

class ChannelStatus: // CHS*
  isActive: Boolean // CHS2a
  occupancy: ChannelOccupancy // CHS2b

class ChannelOccupancy: // CHO*
  metrics: ChannelMetrics // CHO2a

class ChannelMetrics: // CHM*
  connections: Int // CHM2a
  presenceConnections: Int // CHM2b
  presenceMembers: Int // CHM2c
  presenceSubscribers: Int // CHM2d
  publishers: Int // CHM2e
  subscribers: Int // CHM2f
  objectPublishers: Int // CHM2g
  objectSubscribers: Int // CHM2h

class CipherParams: // TZ*
  algorithm: String default "AES" // TZ2a
  key: Binary // TZ2d
  keyLength: Int // TZ2b
  mode: String default "CBC" // TZ2c

class CipherParamOptions: // CO* (may be implemented as a hashmap or a class depending on language)
  algorithm?: String // CO2a
  key: Binary | String // CO2b
  keyLength?: Int // CO2c
  mode?: String // CO2d

class Crypto: // RSE*
  +getDefaultParams(CipherParamOptions) -> CipherParams // RSE1
  +generateRandomKey(keyLength: Int?) => io Binary // RSE2

class RestPresence: // RSP*
  get(
    limit: int api-default 100, // RSP3a
    clientId: String?, // RSP3a2
    connectionId: String?, // RSP3a3
  ) => io PaginatedResult<PresenceMessage> // RSP3
  history(
    start: Time, // RSP4b1
    end: Time api-default now(), // RSP4b1
    direction: .Backwards | .Forwards api-default .Backwards, // RSP4b2
    limit: int api-default 100, // RSP4b3
  ) => io PaginatedResult<PresenceMessage> // RSP4

class RealtimePresence: // RTP*
  syncComplete: Bool // RTP13
  get(
    waitForSync: Bool default true, // RTP11c1
    clientId: String?, // RTP11c2
    connectionId: String?, // RTP11c3
  ) => io [PresenceMessage] // RTP11
  history(
    start: Time, // RTP12a
    end: Time, // RTP12a
    direction: .Backwards | .Forwards api-default .Backwards, // RTP12a
    limit: int api-default 100, // RTP12a
  ) => io PaginatedResult<PresenceMessage> // RTP12
  subscribe((PresenceMessage) ->) => io ChannelStateChange? // RTP6a
  subscribe(PresenceAction | [PresenceAction], (PresenceMessage) ->) => io ChannelStateChange? // RTP6b
  unsubscribe() // RTP7c
  unsubscribe((PresenceMessage) ->) // RTP7a
  unsubscribe(PresenceAction, (PresenceMessage) ->) // RTP7b
  // presence state modifiers
  enter(Data?, extras?: JsonObject) => io // RTP8
  update(Data?, extras?: JsonObject) => io // RTP9
  leave(Data?, extras?: JsonObject) => io // RTP10
  enterClient(clientId: String, Data?, extras?: JsonObject) => io // RTP4, RTP14, RTP15
  updateClient(clientId: String, Data?, extras?: JsonObject) => io // RTP15
  leaveClient(clientId: String, Data?, extras?: JsonObject) => io // RTP15

class RestAnnotations: // RSAN*
  publish(messageSerial: String | Message, annotation: Partial<Annotation>) => io // RSAN1
  delete(messageSerial: String | Message, annotation: Partial<Annotation>) => io // RSAN2
  get(
    messageSerial: String | Message,
    params?: Dict<String, Stringifiable>
  ) => io PaginatedResult<Annotation> // RSAN3

class RealtimeAnnotations: // RTAN*
  publish(messageSerial: String | Message, annotation: Annotation) => io // RTAN1
  delete(messageSerial: String | Message, annotation: Annotation) => io // RTAN2
  get(
    messageSerial: String | Message,
    params?: Dict<String, Stringifiable>
  ) => io PaginatedResult<Annotation> // RTAN3
  subscribe((Annotation) ->) => io ChannelStateChange? // RTAN4
  subscribe(String | [String], (Annotation) ->) => io ChannelStateChange? // RTAN4
  unsubscribe() // RTAN5
  unsubscribe((Annotation) ->) // RTAN5
  unsubscribe(String, (Annotation) ->) // RTAN5

enum PresenceAction: // TP2
  ABSENT // TP2
  PRESENT // TP2
  ENTER // TP2
  LEAVE // TP2
  UPDATE // TP2

enum MessageAction: // TM5
  MESSAGE_CREATE // TM5
  MESSAGE_UPDATE // TM5
  MESSAGE_DELETE // TM5
  META // TM5
  MESSAGE_SUMMARY // TM5
  MESSAGE_APPEND // TM5

enum ObjectOperationAction: // OOP2, internal
  MAP_CREATE // OOP2
  MAP_SET // OOP2
  MAP_REMOVE // OOP2
  COUNTER_CREATE // OOP2
  COUNTER_INC // OOP2
  OBJECT_DELETE // OOP2

enum ObjectsMapSemantics: // OMP2, internal
  LWW // OMP2

enum AnnotationAction: // TAN2b
  ANNOTATION_CREATE
  ANNOTATION_DELETE

class ConnectionDetails: // CD*, internal
  clientId: String? // RSA12a, CD2a
  connectionKey: String // RTN15e, CD2b
  connectionStateTtl: Duration // CD2f, RTN14e, DF1a
  maxFrameSize: Int // CD2d
  maxInboundRate: Int // CD2e
  maxMessageSize: Int // CD2c
  serverId: String // CD2g
  maxIdleInterval: Duration // CD2h
  objectsGCGracePeriod: Int // CD2i
  siteCode: String // CD2j

class Message: // TM*
  constructor(name: String?, data: Data?) // TM4
  constructor(name: String?, data: Data?, clientId: String?) // TM4
  +fromEncoded(JsonObject, ChannelOptions?) -> Message // TM3
  +fromEncodedArray(JsonArray, ChannelOptions?) -> [Message] // TM3
  +summaryDistinctV1(JsonObject) -> Dict<string, SummaryClientIdList>// TM7b1
  +summaryUniqueV1(JsonObject) -> Dict<string, SummaryClientIdList> // TM7b2
  +summaryMultipleV1(JsonObject) -> Dict<string, SummaryClientIdCounts> // TM7b3
  +summaryFlagV1(JsonObject) -> SummaryClientIdList // TM7b4
  +summaryTotalV1(JsonObject) -> SummaryTotal // TM7b5
  clientId: String? // TM2b
  connectionId: String? // TM2c
  connectionKey: String? // TM2h
  data: Data? // TM2d
  encoding: String? // TM2e
  extras: JsonObject? // TM2i
  id: String // TM2a
  name: String? // TM2g
  timestamp: Time // TM2f
  action: MessageAction // TM2j
  serial: string? // TM2r
  version: MessageVersion // TM2s
  annotations: MessageAnnotations // TM2u

class PresenceMessage // TP*
  +fromEncoded(JsonObject, ChannelOptions?) -> PresenceMessage // TP4
  +fromEncodedArray(JsonArray, ChannelOptions?) -> [PresenceMessage] // TP4
  action: PresenceAction // TP3b
  clientId: String // TP3c
  connectionId: String // TP3d
  data: Data? // TP3e
  encoding: String? // TP3f
  extras: JsonObject? // TP3i
  id: String // TP3a
  timestamp: Time // TP3g
  memberKey() -> String // TP3h

class ObjectMessage // OM*, internal
  id: String // OM2a
  clientId: String // OM2b
  connectionId: String // OM2c
  extras: JsonObject? // OM2d
  timestamp: Time // OM2e
  operation: ObjectOperation? // OM2f
  object: ObjectState? // OM2g
  serial: String // OM2h
  serialTimestamp: Time? // OM2j
  siteCode: String // OM2i

class ObjectOperation // OOP*, internal
  action: ObjectOperationAction // OOP3a
  objectId: String // OOP3b
  mapCreate: MapCreate? // OOP3j
  mapSet: MapSet? // OOP3k
  mapRemove: MapRemove? // OOP3l
  counterCreate: CounterCreate? // OOP3m
  counterInc: CounterInc? // OOP3n
  objectDelete: ObjectDelete? // OOP3o
  mapCreateWithObjectId: MapCreateWithObjectId? // OOP3p
  counterCreateWithObjectId: CounterCreateWithObjectId? // OOP3q

class ObjectState // OST*, internal
  objectId: String // OST2a
  siteTimeserials: Dict<String, String> // OST2b
  tombstone: Boolean // OST2c
  createOp: ObjectOperation? // OST2d
  map: ObjectsMap? // OST2e
  counter: ObjectsCounter? // OST2f

class MapCreate // MCR*, internal
  semantics: ObjectsMapSemantics // MCR2a
  entries: Dict<String, ObjectsMapEntry> // MCR2b

class MapSet // MST*, internal
  key: String // MST2a
  value: ObjectData // MST2b

class MapRemove // MRM*, internal
  key: String // MRM2a

class CounterCreate // CCR*, internal
  count: Number // CCR2a

class CounterInc // CIN*, internal
  number: Number // CIN2a

class ObjectDelete // ODE*, internal

class MapCreateWithObjectId // MCRO*, internal
  initialValue: String // MCRO2a
  nonce: String // MCRO2b

class CounterCreateWithObjectId // CCRO*, internal
  initialValue: String // CCRO2a
  nonce: String // CCRO2b

class ObjectsMap // OMP*, internal
  semantics: ObjectsMapSemantics // OMP3a
  entries: Dict<String, ObjectsMapEntry>? // OMP3b

class ObjectsCounter // OCN*, internal
  count: Number? // OCN2a

class ObjectsMapEntry // OME*, internal
  tombstone: Boolean? // OME2a
  timeserial: String? // OME2b
  serialTimestamp: Time? // OME2d
  data: ObjectData? // OME2c

class ObjectData // OD*, internal
  objectId: String? // OD2a
  encoding: String? // OD2b
  boolean: Boolean? // OD2c
  bytes: Binary? | String? // OD2d
  number: Number? // OD2e
  string: String? // OD2f

class Annotation // TAN*
  +fromEncoded(JsonObject, ChannelOptions?) -> Annotation // TAN3
  +fromEncodedArray(JsonArray, ChannelOptions?) -> [Annotation] // TAN3
  id: String // TAN2a
  action: AnnotationAction // TAN2b
  clientId: String? // TAN2c
  name: String? // TAN2d
  count: Int? // TAN2e
  data: Data? // TAN2f
  encoding: String? // TAN2g
  timestamp: Time // TAN2h
  serial: String // TAN2i
  messageSerial: String // TAN2j
  type: String // TAN2k
  extras: JsonObject? // TAN2l

class ProtocolMessage: // internal
  action: ProtocolMessageAction // TR2, TR4a
  auth: AuthDetails? //
  channel: String? // TR4b
  channelSerial: String? // TR4c
  connectionDetails: ConnectionDetails? // RSA7b3, RTN19, TR4o
  connectionId: String? // RTN15c1, TR4d
  count: Int? // TR4g
  error: ErrorInfo? // RTN15c2, TR4h
  flags: Int? // TR4i; bitfield containing zero or more boolean flags specified in TR3
  id: String? // TR4b
  messages: [Message]? // TR4k
  msgSerial: Int? // RTN7b, TR4j
  presence: [PresenceMessage]? // TR4l
  timestamp: Time? // TR4m
  params: Dict<String, String>? // TR4q, RTL4k
  state: [ObjectMessage]? // TR4r
  res: [PublishResult]? // TR4s

enum ProtocolMessageAction: // internal
  HEARTBEAT // TR2
  ACK // TR2
  NACK // TR2
  CONNECT // TR2
  CONNECTED // TR2
  DISCONNECT // TR2
  DISCONNECTED // TR2
  CLOSE // TR2
  CLOSED // TR2
  ERROR // TR2
  ATTACH // TR2
  ATTACHED // TR2
  DETACH // TR2
  DETACHED // TR2
  PRESENCE // TR2
  MESSAGE // TR2
  SYNC // TR2
  AUTH // TR2
  ACTIVATE // TR2
  OBJECT // TR2
  OBJECT_SYNC // TR2

class AuthDetails: // AD*
  accessToken: String // AD2, RTC8a

class Connection: // RTN*
  embeds EventEmitter<ConnectionEvent, ConnectionStateChange> // RTN4a, RTN4e
  errorReason: ErrorInfo? // RTN25
  id: String? // RTN8
  key: String? // RTN9
  createRecoveryKey(): String? // RTN16g
  state: ConnectionState // RTN4d
  whenState(ConnectionState, (ConnectionStateChange?) ->) // RTN26
  close() // RTN12
  connect() // RTC1b, RTN3, RTN11
  ping() => io Duration // RTN13

enum ConnectionState: // RTN4
  INITIALIZED
  CONNECTING
  CONNECTED
  DISCONNECTED
  SUSPENDED
  CLOSING
  CLOSED
  FAILED

enum ConnectionEvent: // RTN4
  embeds ConnectionState
  UPDATE // RTN4h

class ConnectionStateChange: // TA*
  current: ConnectionState // TA2
  event: ConnectionEvent // TA5
  previous: ConnectionState // TA2
  reason: ErrorInfo? // RTN4f, TA3
  retryIn: Duration? // RTN14d, TA2

class Stats: // TS12
  intervalId: String // TS12a
  intervalTime: Time // TS12p (calculated client-side)
  unit: Stats.IntervalGranularity // TS12c
  inProgress: String? // TS12q
  entries: Dict<String, Int> // TS12r
  schema: String // TS12s
  appId: String // TS12t

enum StatsIntervalGranularity: // TS12c
  MINUTE
  HOUR
  DAY
  MONTH

class DeviceDetails: // PCD*
  id: String // PCD2
  clientId: String? // PCD3
  formFactor: DeviceFormFactor // PCD4
  metadata: JsonObject // PCD5
  platform: DevicePlatform // PCD6
  push: DevicePushDetails // PCD7

class DevicePushDetails: // PCP*
  errorReason: ErrorInfo? // PCP2
  recipient: JsonObject // PCP3
  state: .Active | .Failing | .Failed // PCP4

class LocalDevice extends DeviceDetails: // RSH8*
  deviceIdentityToken: String? // RSH8k1
  deviceSecret: String // RSH8k2

class Push: RSH1, RSH2
  admin: PushAdmin // RSH1

  // Only on platforms that support receiving push notifications:

  activate(
    registerCallback: ((ErrorInfo?, DeviceDetails?) -> io String)?,
    // Only on platforms that, after first set, can update later its push
    // device details:
    updateFailedCallback: ((ErrorInfo) ->), // Deprecated, see RSH3e3a and RSH3e3d
    updatedCallback: ((ErrorInfo?) ->)?
  ) => io ErrorInfo? // RSH2a
  deactivate(
    deregisterCallback: ((ErrorInfo?, deviceId: String?) -> io)?
  ) => io ErrorInfo? // RSH2b

class PushAdmin: // RSH1
  publish(recipient: JsonObject, data: JsonObject) => io // RSH1a
  deviceRegistrations: PushDeviceRegistrations // RSH1b
  channelSubscriptions: PushChannelSubscriptions // RSH1c

class PushDeviceRegistrations: // RSH1b
  get(deviceId: String) => io DeviceDetails // RSH1b1
  list(params: Dict<String, String>) => io PaginatedResult<DeviceDetails> // RSH1b2
  save(DeviceDetails) => io DeviceDetails // RSH1b3
  remove(deviceId: String) => io // RSH1b4
  removeWhere(params: Dict<String, String>) => io // RSH1b5

class PushChannelSubscriptions: // RSH1c
  list(params: Dict<String, String>) => io PaginatedResult<PushChannelSubscription> // RSH1c1
  listChannels(params: Dict<String, String>?) => io PaginatedResult<String> // RSH1c2
  save(PushChannelSubscription) => io PushChannelSubscription // RSH1c3
  remove(PushChannelSubscription) => io // RSH1c4
  removeWhere(params: Dict<String, String>) => io // RSH1c5

enum DevicePlatform: // PCD6
  "android"
  "ios"
  "browser"

enum DeviceFormFactor: // PCD4
  "phone"
  "tablet"
  "desktop"
  "tv"
  "watch"
  "car"
  "embedded"
  "other"

class PushChannelSubscription: // PCS*
  +forDevice(channel: String, deviceId: String) => PushChannelSubscription // PSC5
  +forClientId(channel: String, clientId: String) => PushChannelSubscription // PSC5
  deviceId: String? // PCS2
  clientId: String? // PCS3
  channel: String // PCS4

class ErrorInfo: // TI*
  code: Int // TI1
  href: String? // TI1, TI4
  message: String // TI1
  cause: ErrorInfo? // TI1
  statusCode: Int // TI1
  requestId: String? // TI1, RSC7c
  detail: Dict<String, String>? // TI1, TI6

class EventEmitter<Event, Data>: // RTE*
  on((Data...) ->) // RTE3
  on(Event, (Data...) ->) // RTE3
  once((Data...) ->) // RTE4
  once(Event, (Data...) ->) // RTE4
  off() // RTE5
  off((Data...) ->) // RTE5
  off(Event, (Data...) ->) // RTE5
  emit(Event, Data...)  // internal, RTE6

class PaginatedResult<T>: // TG*
  items: [T] // TG3
  first() => io PaginatedResult<T> // TG5
  hasNext() -> Bool // TG6
  isLast() -> Bool // TG7
  next() => io PaginatedResult<T>? // TG4

class HttpPaginatedResponse // HP*
  embeds PaginatedResult<JsonObject>
  items: [JsonObject] // HP3
  statusCode: Int // HP4
  success: Bool // HP5
  errorCode: Int // HP6
  errorMessage: String // HP7
  headers: Dict<String, String> // HP8

class Plugin // PC2
  // Empty class/interface. Plugins are not expected to share any common interface.
  // An opaque base interface type for plugins is defined for type-safety in statically-typed languages.

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

class VCDiffDecoder // VD*
  decode([byte] delta, [byte] base) -> [byte] // VD2a, PC3a

class DeltaExtras // DE*
  from: String // DE2a
  format: String // DE2b

class ReferenceExtras: // REX*
  timeserial: String // REX2a
  type: String //REX2b

class ClientInformation: // CR*
  +agents: Dict<String, String?> // CR2
  +agentIdentifier(additionalAgents: Dict<String, String?>?) => String // CR3; interface only offered by some libraries

class BatchResult<T>
  successCount: number // BAR2a
  failureCount: number // BAR2b
  results: [T] // BAR2c

class BatchPublishSpec:
  channels: [String] // BSP2a
  messages: [Message] //BSP2b

class BatchPublishSuccessResult:
  channel: string // BPR2a
  messageId: string // BPR2b
  serials: [String?] // BPR2c

class BatchPublishFailureResult:
  channel: string // BPF2a
  error: ErrorInfo // BPF2c

class BatchPresenceSuccessResult:
  channel: string // BGR2a
  presence: [PresenceMessage] // BGR2b

class BatchPresenceFailureResult
  channel: string // BGF2a
  error: ErrorInfo // BGF2b

class PublishResult:
  serials: [String?] // PBR2a

class UpdateDeleteResult:
  versionSerial: String? // UDR2a

class TokenRevocationTargetSpecifier:
  type: string // TRT2a
  value: string // TRT2b

class TokenRevocationSuccessResult:
  target: string // TRS2a
  appliesAt: Time // TRS2b
  issuedBefore: Time // TRS2c

class TokenRevocationFailureResult:
  target: string // TRF2a
  error: ErrorInfo // TRF2b

class WrapperSDKProxyOptions:
  agents: [String: String?]? // WPO2a

class SummaryClientIdList:
  total: number // TM7c1a
  clientIds: [string] // TM7c1b

class SummaryClientIdCounts:
  total: number // TM7d1a
  clientIds: Dict<string, number> // TM7d1b

class SummaryTotal:
  total: number // TM7e1a

class MessageAnnotations:
  summary: Dict<string, JsonObject>? // TM8a

class MessageVersion:
  serial: string? // TM2s1
  timestamp: number? // TM2s2
  clientId: string? // TM2s3
  description: string? // TM2s4
  metadata: Dict<string, string>? //TM2s5

Old specs

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