Space
A space is a virtual area of your application in which realtime collaboration between users can take place. You can have any number of virtual spaces within an application, with a single space being anything from a web page, a sheet within a spreadsheet, an individual slide in a slideshow, or the entire slideshow itself.
The following features can be implemented within a space:
The space
namespace consists of a state object that represents the realtime status of all members in a given virtual space. This includes a list of which members are currently online or have recently left and each member’s location within the application. The position of members’ cursors are excluded from the space state due to their high frequency of updates. In the beta release, which UI components members have locked are also excluded from the space state.
Space state can be subscribed to in the space
namespace. Alternatively, subscription listeners can be registered for individual features, such as avatar stack events and member location updates. These individual subscription listeners are intended to provide flexibility when implementing collaborative features. Individual listeners are client-side filtered events, so irrespective of whether you choose to subscribe to the space state or individual listeners, each event only counts as a single message.
To subscribe to any events in a space, you first need to create or retrieve a space.
Create or retrieve a space
A space
object is a reference to a single space and is uniquely identified by its unicode string name. A space is created, or an existing space is retrieved from the spaces
collection using the get()
method.
The following restrictions apply to space names:
- Avoid starting names with
[
or:
- Ensure names aren’t empty
- Exclude whitespace and wildcards, such as
*
- Use the correct case, whether it be uppercase or lowercase
The following is an example of creating a space:
const space = await spaces.get('board-presentation');
CopyCopied!
If a name is not specified when creating or retrieving a space, the request will fail with the error code 10100
.
Enter a space
Entering a space will register a client as a member and emit an enter
event to all subscribers. Use the enter()
method to enter a space.
Being entered into a space is required for members to:
- Update their profile data.
- Set their location.
- Set their cursor position.
The following is an example of entering a space:
await space.enter();
CopyCopied!
If a member has not entered a space and attempts an operation that requires them to be entered then the request will fail with the error code 101001
.
Leave a space
Leaving a space will emit a leave
event to all subscribers.
The following is an example of explicitly leaving a space:
await space.leave();
CopyCopied!
Members will implicitly leave a space after 15 seconds if they abruptly disconnect. If experiencing network disruption, and they reconnect within 15 seconds, then they will remain part of the space and no leave
event will be emitted.
Profile data
Profile data can be set when entering a space. It is optional data that can be used to associate information with a member, such as a preferred username, or profile picture that can be subsequently displayed in their avatar. Profile data can be any arbitrary JSON-serializable object.
Profile data is returned in the payload of all space events.
The following is an example of setting profile data when entering a space:
await space.enter({
username: 'Claire Oranges',
avatar: 'https://slides-internal.com/users/coranges.png',
});
CopyCopied!
Update profile data
Profile data can be updated at any point after entering a space by calling updateProfileData()
. This will emit an updateProfile
event. If a client hasn’t yet entered the space, updateProfileData()
will instead enter the space, with the profile data, and emit an enter
event.
The following is an example of updating profile data:
space.updateProfileData({
username: 'Claire Lemons',
avatar: 'https://slides-internal.com/users/clemons.png',
});
CopyCopied!
A function can be passed to updateProfileData()
in order to update a field based on the existing profile data:
space.updateProfileData(currentProfile => {
return { ...currentProfile, username: 'Clara Lemons' }
});
CopyCopied!
Subscribe to space state
Subscribe to space state updates by registering a listener. Use the subscribe()
method on the space
object to receive updates.
The following events will trigger a space event:
- A member enters the space
- A member leaves the space
- A member is removed from the space state after the offlineTimeout period has elapsed
- A member updates their profile data
- A member sets a new location
Space state contains a single object called members
. Any events that trigger a change in space state will always return the current state of the space as an array of member
objects.
The following is an example of subscribing to space events:
space.subscribe('update', (spaceState) => {
console.log(spaceState.members);
});
CopyCopied!
The following is an example payload of a space event.
[
{
"clientId": "clemons#142",
"connectionId": "hd9743gjDc",
"isConnected": false,
"lastEvent": {
"name": "leave",
"timestamp": 1677595689759
},
"location": null,
"profileData": {
"username": "Claire Lemons",
"avatar": "https://slides-internal.com/users/clemons.png"
}
},
{
"clientId": "amint#5",
"connectionId": "hg35a4fgjAs",
"isConnected": true,
"lastEvent": {
"name": "enter",
"timestamp": 173459567340
},
"location": null,
"profileData": {
"username": "Arit Mint",
"avatar": "https://slides-internal.com/users/amint.png"
}
},
...
]
CopyCopied!
The following are the properties of an individual member
within a space event payload:
Property | Description | Type |
---|---|---|
clientId | The client identifier for the member. | String |
connectionId | The unique identifier of the member’s connection. | String |
isConnected | Whether the member is connected to Ably or not. | Boolean |
profileData | The optional profile data associated with the member. | Object |
location | The current location of the member. | Object |
lastEvent.name | The most recent event emitted by the member. | String |
lastEvent.timestamp | The timestamp of the most recently emitted event. | Number |
Unsubscribe from space events
Unsubscribe from space events to remove previously registered listeners.
The following is an example of removing a listener:
space.unsubscribe('update', listener);
CopyCopied!
Retrieve space state
The current state of the space can be retrieved in a one-off call. This will return an array of all member
objects currently in the space. This is a local call and retrieves the membership of the space retained in memory by the SDK.
The following is an example of retrieving the current space state. Ths includes members that have recently left the space, but have not yet been removed:
const spaceState = await space.getState();
CopyCopied!
Advanced properties
The following sections are only relevant if you want to further customize a space, or understand more about the Spaces SDK. They aren’t required to get up and running with the basics.
Space options
An additional set of optional properties may be passed when creating or retrieving a space to customize the behavior of different features.
The following properties can be customized:
Property | Description | Type |
---|---|---|
offlineTimeout | Number of milliseconds after a member loses connection or closes their browser window to wait before they are removed from the member list. The default is 120,000ms (2 minutes). | Number |
cursors | A cursor options object for customizing live cursor behavior. | Object |
cursors.outboundBatchInterval | The interval, in milliseconds, at which a batch of cursor positions are published. This is multiplied by the number of members in a space, minus 1. The default value is 100ms. | Number |
cursors.paginationLimit | The number of pages searched from history for the last published cursor position. The default is 5. | Number |
The following is an example of customizing the space options when calling spaces.get()
:
const space = await spaces.get('board-presentation', {
offlineTimeout: 180_000,
cursors: { paginationLimit: 10 }
});
CopyCopied!
Space foundations
The Spaces SDK is built upon existing Ably functionality available in Ably’s Core SDKs. Understanding which core features are used to provide the abstractions in the Spaces SDK enables you to manage space state and build additional functionality into your application.
A space is created as an Ably channel. Members attach to the channel and join its presence set when they enter the space. Avatar stacks, member locations and component locking are all handled on this channel.
To manage the state of the space, you can monitor the state of the underlying channel. The channel object can be accessed through space.channel
.
The following is an example of registering a listener to wait for a channel to become attached:
space.channel.on('attached', (stateChange) => {
console.log(stateChange)
});
CopyCopied!