Skip to content

Commit 0fa37b5

Browse files
committed
Update liveobjects examples to use Path-based API
Updates our examples for AIT-31
1 parent 65cf5f7 commit 0fa37b5

7 files changed

Lines changed: 152 additions & 160 deletions

File tree

examples/liveobjects-live-counter/javascript/README.md

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,27 @@
11
# Synchronize numeric values with LiveCounter
22

3-
Enable clients to update and synchronize numerical values in an application in realtime.
3+
Enable clients to update and synchronize numeric values in an application in realtime.
44

5-
LiveCounter is a synchronized numerical counter that supports increment and decrement operations. It ensures that all updates are correctly applied and synchronized across users in realtime, preventing inconsistencies when multiple users modify the counter value simultaneously.
5+
[`LiveCounter`](/docs/liveobjects/counter) is a synchronized numeric counter that supports increment and decrement operations. It ensures that all updates are correctly applied and synchronized across users in realtime, preventing inconsistencies when multiple users modify the counter value simultaneously.
66

7-
LiveCounter is useful for tracking values that need to be updated dynamically, such as votes, reaction counts, live leaderboards, game stats, or other numeric data points.
7+
`LiveCounter` is useful for tracking values that need to be updated dynamically, such as votes, reaction counts, live leaderboards, game stats, or other numeric data points.
88

9-
LiveCounter is implemented using [Ably LiveObjects](/docs/liveobjects). LiveObjects, as a feature of [Ably Pub/Sub](/docs/channels), contains a set of purpose-built APIs that abstract away the complexities of managing shared state between clients in an application. It is built on top of Ably's core platform, and so it provides the same performance guarantees and scaling potential.
9+
`LiveCounter` is a feature of [LiveObjects](/docs/liveobjects), which provides a serverless, durable, and scalable way to create, update, and subscribe to shared state across large numbers of connected clients at any scale. LiveObjects is built on [channels](/docs/channels) and provides the same [performance guarantees and scaling potential](/docs/platform/architecture).
1010

1111
## Resources
1212

13-
Use the following methods to interact with a LiveCounter in your application:
13+
Use the following methods to interact with a `LiveCounter` in your application:
1414

15-
- [`objects.getRoot()`](/docs/liveobjects/concepts/objects#root-object): retrieves the root object that serves as the starting point for storing and organizing objects on a channel.
16-
- [`objects.createCounter()`](/docs/liveobjects/counter#create): creates a new LiveCounter instance.
17-
- [`liveCounter.value()`](/docs/liveobjects/counter#value): returns the current value of a counter.
18-
- [`liveCounter.increment()`](/docs/liveobjects/counter#update): sends the operation message to the Ably system to increase the counter value.
19-
- [`liveCounter.decrement()`](/docs/liveobjects/counter#update): sends the operation message to the Ably system to decrease the counter value.
20-
- [`liveCounter.subscribe()`](/docs/liveobjects/counter#subscribe-data): subscribes to LiveCounter updates by registering a listener.
15+
- [`channel.object.get()`](/docs/liveobjects/concepts/path-object): retrieve a [`PathObject`](/docs/liveobjects/concepts/path-object) reference to the [channel object](/docs/liveobjects/concepts/objects#channel-object). Use this `PathObject` to update and subscribe to data via:
16+
- [`get(key)`](/docs/liveobjects/concepts/path-object#navigate): navigate to child paths within the `PathObject`, such as entries in a [`LiveMap`](/docs/liveobjects/map).
17+
- [`set(key, value)`](/docs/liveobjects/concepts/path-object#update): assign data, such as a `LiveCounter` instance, to the specified key on a `LiveMap`.
18+
- [`value()`](/docs/liveobjects/concepts/path-object#read-values): read the current value of the `LiveCounter` instance at the specified path.
19+
- [`increment()`](/docs/liveobjects/counter#increment): send an [operation](/docs/liveobjects/concepts/operations) to increment the `LiveCounter` at the specified path.
20+
- [`subscribe()`](/docs/liveobjects/concepts/path-object#subscribe): subscribe to updates at the specified path by registering a listener.
21+
- [`batch()`](/docs/liveobjects/concepts/path-object#batch-multiple-updates): group multiple operations into a single message for atomic updates.
22+
- [`LiveCounter.create()`](/docs/liveobjects/counter#create): create a new `LiveCounter` instance.
2123

22-
Find out more about [LiveCounter](/docs/liveobjects/counter).
24+
Find out more about [PathObject](/docs/liveobjects/concepts/path-object) and [LiveCounter](/docs/liveobjects/counter).
2325

2426
## Getting started
2527

examples/liveobjects-live-counter/javascript/src/ably.config.d.ts

Lines changed: 0 additions & 12 deletions
This file was deleted.

examples/liveobjects-live-counter/javascript/src/script.ts

Lines changed: 39 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1-
import { DefaultRoot, LiveCounter, LiveMap, Realtime } from 'ably';
2-
import Objects from 'ably/objects';
1+
import { Realtime } from 'ably';
2+
import { LiveCounter, LiveMap, LiveObjects, type PathObject } from 'ably/liveobjects';
33
import { nanoid } from 'nanoid';
44
import { config } from './config';
55
import './styles.css';
66

7-
export enum Color {
7+
type ColorCounters = {
8+
[Color.red]: LiveCounter;
9+
[Color.green]: LiveCounter;
10+
[Color.blue]: LiveCounter;
11+
};
12+
13+
enum Color {
814
red = 'red',
915
green = 'green',
1016
blue = 'blue',
@@ -13,75 +19,63 @@ export enum Color {
1319
const client = new Realtime({
1420
clientId: nanoid(),
1521
key: config.ABLY_KEY,
16-
plugins: { Objects },
22+
plugins: { LiveObjects },
1723
});
1824

1925
const channelName = config.CHANNEL_NAME || 'objects-live-counter';
20-
const channel = client.channels.get(channelName, { modes: ['OBJECT_PUBLISH', 'OBJECT_SUBSCRIBE'] });
26+
const channel = client.channels.get(channelName, { modes: ['object_publish', 'object_subscribe'] });
2127

22-
const colorCountDivs: Record<Color, HTMLElement> = {
23-
red: document.getElementById('count-red')!,
24-
green: document.getElementById('count-green')!,
25-
blue: document.getElementById('count-blue')!,
28+
const colorCountDivs: Record<Color, HTMLElement | null> = {
29+
red: document.getElementById('count-red'),
30+
green: document.getElementById('count-green'),
31+
blue: document.getElementById('count-blue'),
2632
};
27-
const countersReset = document.getElementById('reset')!;
33+
const countersReset = document.getElementById('reset');
2834

2935
async function main() {
30-
await channel.attach();
31-
32-
const objects = channel.objects;
33-
const root = await objects.getRoot();
36+
const countersObject = await channel.object.get<ColorCounters>();
3437

35-
await initCounters(root);
36-
addEventListenersToButtons(root);
38+
await initCounters(countersObject);
39+
addEventListenersToButtons(countersObject);
3740
}
3841

39-
async function initCounters(root: LiveMap<DefaultRoot>) {
40-
// subscribe to root to get notified when counter objects get changed on the root.
41-
// for example, when we reset all counters
42-
root.subscribe(({ update }) => {
43-
Object.entries(update).forEach(([keyName, change]) => {
44-
if (change === 'removed') {
45-
return;
46-
}
47-
48-
if (Object.values(Color).includes(keyName as Color)) {
49-
// key pointing to a counter object got updated, resubscribe to a counter
50-
const color = keyName as Color;
51-
subscribeToCounterUpdates(color, root.get(color)!);
52-
}
53-
});
54-
});
55-
42+
async function initCounters(counters: PathObject<LiveMap<ColorCounters>>) {
5643
await Promise.all(
5744
Object.values(Color).map(async (color) => {
58-
if (root.get(color)) {
59-
subscribeToCounterUpdates(color, root.get(color)!);
60-
return;
61-
}
45+
subscribeToCounterUpdates(color, counters.get(color));
6246

63-
await root.set(color, await channel.objects.createCounter());
47+
// Initialize counter if it doesn't exist
48+
if (counters.get(color).value() === undefined) {
49+
await counters.set(color, LiveCounter.create());
50+
}
6451
}),
6552
);
6653
}
6754

68-
function subscribeToCounterUpdates(color: Color, counter: LiveCounter) {
55+
function subscribeToCounterUpdates(color: Color, counter: PathObject<LiveCounter>) {
6956
counter.subscribe(() => {
70-
colorCountDivs[color].innerHTML = counter.value().toString();
57+
if (colorCountDivs[color]) {
58+
colorCountDivs[color].innerHTML = counter.value()?.toString() ?? '0';
59+
}
7160
});
72-
colorCountDivs[color].innerHTML = counter.value().toString();
61+
if (colorCountDivs[color]) {
62+
colorCountDivs[color].innerHTML = counter.value()?.toString() ?? '0';
63+
}
7364
}
7465

75-
function addEventListenersToButtons(root: LiveMap<DefaultRoot>) {
66+
function addEventListenersToButtons(counters: PathObject<LiveMap<ColorCounters>>) {
7667
document.querySelectorAll('.vote-button').forEach((button) => {
7768
const color = button.getAttribute('data-color') as Color;
7869
button.addEventListener('click', () => {
79-
root.get(color)?.increment(1);
70+
counters.get(color).increment(1);
8071
});
8172
});
8273

83-
countersReset.addEventListener('click', () => {
84-
Object.values(Color).forEach(async (color) => root.set(color, await channel.objects.createCounter()));
74+
countersReset?.addEventListener('click', () => {
75+
// Use batch to reset all counters atomically
76+
counters.batch((ctx) => {
77+
Object.values(Color).forEach((color) => ctx.set(color, LiveCounter.create()));
78+
});
8579
});
8680
}
8781

examples/liveobjects-live-map/javascript/README.md

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,27 @@
22

33
Enable clients to update and synchronize key/value data in an application in realtime.
44

5-
LiveMap is a key/value data structure that synchronizes its state across users in realtime. It enables you to store primitive values, such as numbers, strings, booleans and buffers, as well as other objects, enabling you to build complex, hierarchical object structure.
5+
[`LiveMap`](/docs/liveobjects/map) is a key/value data structure that synchronizes its state across users in realtime. It enables you to store primitive values, such as numbers, strings, booleans, binary data, JSON-serializable objects or arrays and other live [object types](/docs/liveobjects/concepts/objects#object-types), enabling you to build complex, hierarchical channel objects.
66

7-
LiveMap can be used to store both predefined and dynamic datasets that need to be updated in realtime. They are ideal for scenarios such as collaborative task management, live leaderboards, multiplayer game state, shared settings, or live dashboards.
7+
`LiveMap` can be used to store both predefined and dynamic datasets that need to be updated in realtime. It is ideal for scenarios such as collaborative task management, live leaderboards, multiplayer game state, shared settings, or live dashboards.
88

9-
LiveMap is implemented using [Ably LiveObjects](/docs/liveobjects). LiveObjects, as a feature of [Ably Pub/Sub](/docs/channels), contains a set of purpose-built APIs that abstract away the complexities of managing shared state between clients in an application. It is built on top of Ably's core platform, and so it provides the same performance guarantees and scaling potential.
9+
`LiveMap` is a feature of [LiveObjects](/docs/liveobjects), which provides a serverless, durable, and scalable way to create, update, and subscribe to shared state across large numbers of connected clients at any scale. LiveObjects is built on [channels](/docs/channels) and provides the same [performance guarantees and scaling potential](/docs/platform/architecture).
1010

1111
## Resources
1212

13-
Use the following methods to interact with a LiveMap in your application:
13+
Use the following methods to interact with a `LiveMap` in your application:
1414

15-
- [`objects.getRoot()`](/docs/liveobjects/concepts/objects#root-object): retrieves the root object that serves as the starting point for storing and organizing objects on a channel.
16-
- [`objects.createMap()`](/docs/liveobjects/map#create): creates a new LiveMap instance.
17-
- [`liveMap.get(key)`](/docs/liveobjects/map#get): returns the current value associated with a given key in the map.
18-
- [`liveMap.set(key, value)`](/docs/liveobjects/map#set): sends the operation message to the Ably system to assign a value to a key in the map.
19-
- [`liveMap.remove(key)`](/docs/liveobjects/map#remove): sends the operation message to the Ably system to remove a key from the map.
20-
- [`liveMap.subscribe()`](/docs/liveobjects/map#subscribe-data): subscribes to LiveMap updates by registering a listener.
15+
- [`channel.object.get()`](/docs/liveobjects/concepts/path-object): retrieve a [`PathObject`](/docs/liveobjects/concepts/path-object) reference to the [channel object](/docs/liveobjects/concepts/objects#channel-object). Use this `PathObject` to update and subscribe to data via:
16+
- [`get(key)`](/docs/liveobjects/concepts/path-object#navigate): navigate to child paths within the `PathObject`, such as entries in a `LiveMap`.
17+
- [`set(key, value)`](/docs/liveobjects/concepts/path-object#update): assign a value to a key in the `LiveMap`.
18+
- [`remove(key)`](/docs/liveobjects/concepts/path-object#delete): send an [operation](/docs/liveobjects/concepts/operations) to remove a key from the `LiveMap`.
19+
- [`value()`](/docs/liveobjects/concepts/path-object#read-values): read the current value at the specified path.
20+
- [`entries()`](/docs/liveobjects/concepts/path-object#iterate): iterate over key-value pairs in the `LiveMap`.
21+
- [`subscribe()`](/docs/liveobjects/concepts/path-object#subscribe): subscribe to updates at the specified path by registering a listener.
22+
- [`batch()`](/docs/liveobjects/concepts/path-object#batch-multiple-updates): group multiple operations into a single message for atomic updates.
23+
- [`LiveMap.create()`](/docs/liveobjects/map#create): create a new `LiveMap` instance.
2124

22-
Find out more about [LiveMap](/docs/liveobjects/map).
25+
Find out more about [PathObject](/docs/liveobjects/concepts/path-object) and [LiveMap](/docs/liveobjects/map).
2326

2427
## Getting started
2528

examples/liveobjects-live-map/javascript/src/ably.config.d.ts

Lines changed: 0 additions & 11 deletions
This file was deleted.

0 commit comments

Comments
 (0)