From f53ddb450f5fd9cec21ed72cd7e6082f88ef8f60 Mon Sep 17 00:00:00 2001 From: Andrew Bulat Date: Tue, 10 Mar 2026 12:13:22 +0000 Subject: [PATCH] Add LiveObjects REST SDK usage docs Largely based on the existing usage doc for the REST API [1]. Added REST SDK docs as a separate page for two reasons: 1. There is no language selector for the shell/curl/HTTP "language", nor do I think it would look or feel nice UX-wise. It would only exist for this single page and may not be obvious to readers that they can switch it at the top to see SDK/API docs. 2. The SDK docs differ in many minor details throughout, and it would be a nightmare to maintain different versions on the same page using if-lang blocks. Where large sections are unchanged (like the procedure to generate the client-generated object ID), the doc references the corresponding REST API section instead of duplicating it. Resolves AIT-319 [1] https://ably.com/docs/liveobjects/rest-api-usage --- src/data/nav/liveobjects.ts | 4 + src/pages/docs/api/rest-sdk/channels.mdx | 6 + src/pages/docs/liveobjects/rest-api-usage.mdx | 6 +- src/pages/docs/liveobjects/rest-sdk-usage.mdx | 937 ++++++++++++++++++ 4 files changed, 950 insertions(+), 3 deletions(-) create mode 100644 src/pages/docs/liveobjects/rest-sdk-usage.mdx diff --git a/src/data/nav/liveobjects.ts b/src/data/nav/liveobjects.ts index 11e38a69e2..87732773d5 100644 --- a/src/data/nav/liveobjects.ts +++ b/src/data/nav/liveobjects.ts @@ -98,6 +98,10 @@ export default { name: 'Object storage', link: '/docs/liveobjects/storage', }, + { + name: 'Using the REST SDK', + link: '/docs/liveobjects/rest-sdk-usage', + }, { name: 'Using the REST API', link: '/docs/liveobjects/rest-api-usage', diff --git a/src/pages/docs/api/rest-sdk/channels.mdx b/src/pages/docs/api/rest-sdk/channels.mdx index c9863086d1..713b2b9526 100644 --- a/src/pages/docs/api/rest-sdk/channels.mdx +++ b/src/pages/docs/api/rest-sdk/channels.mdx @@ -82,6 +82,12 @@ Provides access to the [REST Presence](/docs/presence-occupancy/presence) object Provides access to the [PushChannel](/docs/api/realtime-sdk/push#push-channel) object for this channel which can be used to access members present on the channel, or participate in presence. + +#### object + +Provides access to the [RestObject](/docs/liveobjects/rest-sdk-usage) for this channel which can be used to read and modify LiveObjects on a channel using the REST SDK. + + ### Channel Methods #### publishPublish diff --git a/src/pages/docs/liveobjects/rest-api-usage.mdx b/src/pages/docs/liveobjects/rest-api-usage.mdx index 6a7c997148..1cf72680c1 100644 --- a/src/pages/docs/liveobjects/rest-api-usage.mdx +++ b/src/pages/docs/liveobjects/rest-api-usage.mdx @@ -632,7 +632,7 @@ There are additional operations for creating objects with client-generated IDs: { "objectId": "map:Qj2kkvprTybCY5mkNMcm31hhNKZCDWqcz45LjYvCABs@1769079911168", "mapCreateWithObjectId": { - "initialValue": "{\"entries\":{\"name\":{\"data\":{\"string\":\"Alice\"}},\"age\":{\"data\":{\"number\":30}}}}", + "initialValue": "{\"semantics\":0,\"entries\":{\"name\":{\"data\":{\"string\":\"Alice\"}},\"age\":{\"data\":{\"number\":30}}}}", "nonce": "random-nonce-abc123" } } @@ -677,7 +677,7 @@ For example: -d '{ "objectId": "map:Qj2kkvprTybCY5mkNMcm31hhNKZCDWqcz45LjYvCABs@1769079911168", "mapCreateWithObjectId": { - "initialValue": "{\"entries\":{\"name\":{\"data\":{\"string\":\"Alice\"}},\"age\":{\"data\":{\"number\":30}}}}", + "initialValue": "{\"semantics\":0,\"entries\":{\"name\":{\"data\":{\"string\":\"Alice\"}},\"age\":{\"data\":{\"number\":30}}}}", "nonce": "random-nonce-abc123" } }' @@ -697,7 +697,7 @@ Create a map and immediately link it to root in a single atomic operation: { "objectId": "map:Qj2kkvprTybCY5mkNMcm31hhNKZCDWqcz45LjYvCABs@1769079911168", "mapCreateWithObjectId": { - "initialValue": "{\"entries\":{\"name\":{\"data\":{\"string\":\"Alice\"}}}}", + "initialValue": "{\"semantics\":0,\"entries\":{\"name\":{\"data\":{\"string\":\"Alice\"}}}}", "nonce": "nonce-1" } }, diff --git a/src/pages/docs/liveobjects/rest-sdk-usage.mdx b/src/pages/docs/liveobjects/rest-sdk-usage.mdx new file mode 100644 index 0000000000..66d8cda94d --- /dev/null +++ b/src/pages/docs/liveobjects/rest-sdk-usage.mdx @@ -0,0 +1,937 @@ +--- +title: Using the REST SDK +meta_description: "Learn how to work with Ably LiveObjects using the REST SDK" +--- + + + +LiveObjects provides a JavaScript REST SDK that enables you to directly work with objects without using a realtime connection. + +## Setup + +Create an [`Ably.Rest`](/docs/api/rest-sdk) client instance with the `LiveObjects` plugin: + + +```javascript +import { LiveObjects } from 'ably/liveobjects'; + +const rest = new Ably.Rest({ plugins: { LiveObjects }, /* other ClientOptions */ }); +``` + + +The LiveObjects REST SDK is then available on a channel via `channel.object`: + + +```javascript +const channel = rest.channels.get('my-channel'); +channel.object // LiveObjects REST SDK +``` + + +## Authentication + +Authentication is configured when instantiating the REST client. Pass an API key or use [token authentication](/docs/auth/token) via the [`ClientOptions`](/docs/api/rest-sdk#client-options). See the [REST SDK authentication](/docs/api/rest-sdk/authentication) documentation for details. + +To use LiveObjects, an API key must have at least the `object-subscribe` capability. With only this capability, clients will have read-only access, preventing them from publishing operations. + +In order to create or update objects, make sure your API key includes both `object-subscribe` and `object-publish` [capabilities](/docs/auth/capabilities) to allow full read and write access. + +## Fetch objects + +### Use `channel.object.get` + +`get(GetObjectParams params?): Promise` + +Reads object data from the channel. Uses the channel's root object as the entrypoint when no `objectId` is provided. Makes a request to the [`GET /channels/{channelId}/object`](/docs/liveobjects/rest-api-usage#fetch-channel-object) REST API endpoint. The return type depends on the `compact` parameter: when `compact` is `true` (default), returns a JSON value; when `compact` is `false`, returns a [`RestLiveObject`](#rest-live-object). + +| Parameter | Description | Type | +|-----------|-------------|------| +| params | An optional object containing the query parameters | [`GetObjectParams`](#get-object-params) | + +Objects can be fetched in two formats: + +| Format | Parameter | Description | +|--------|----------------|-------------| +| **Compact** (default) | `compact: true` | Values-only representation without metadata. Ideal for reading data values. | +| **Non-compact** | `compact: false` | Full structure including object IDs and type metadata. Useful for debugging. | + +**Compact format** returns the logical structure of your data as a JSON object. [LiveMap](/docs/liveobjects/map) instances appear as JSON objects with their entries, and [LiveCounter](/docs/liveobjects/counter) instances appear as numbers. + +**Non-compact format** includes additional [metadata](/docs/liveobjects/concepts/objects#metadata) for each object: +- Object IDs for each instance +- Object type metadata (map semantics, counter values) +- Complete object hierarchy + +### Fetch the channel object + +Fetch the entire channel object: + + +```javascript +const data = await channel.object.get(); +``` + + +Example compact result: + + +```json +{ + "votes": { + "down": 5, + "up": 10 + } +} +``` + + +This example shows a `LiveMap` stored on the "votes" key of the channel object, which contains two `LiveCounter` instances on the "down" and "up" keys. + +Set `compact: false` to include object metadata: + + +```javascript +const data = await channel.object.get({ compact: false }); +``` + + + +```json +{ + "objectId": "root", + "map": { + "semantics": "lww", + "entries": { + "votes": { + "data": { + "objectId": "map:qZXBk8xaGqf4kwLSlR7Tj0Eqhd48WDFfb3gTAbj194k@1760448597692", + "map": { + "semantics": "lww", + "entries": { + "down": { + "data": { + "objectId": "counter:Yj1F_aEX3T2rRkTkra7Aifmlr8PxUWSR3kO3MzxtQto@1760448653393", + "counter": { + "data": { + "number": 5 + } + } + } + }, + "up": { + "data": { + "objectId": "counter:ibxddWpDjH8R3cvXWWacfe4IVd3DxT_oqkAafhaS68s@1760448646413", + "counter": { + "data": { + "number": 10 + } + } + } + } + } + } + } + } + } + } +} +``` + + +### Fetch by path + +Return a subset of the channel object by specifying the `path` parameter. For example, to return only the `votes` `LiveMap` instance from the channel object: + + +```javascript +const data = await channel.object.get({ path: 'votes' }); +``` + + +Example result: + + +```json +{ + "down": 5, + "up": 10 +} +``` + + +### Fetch by object ID + +Fetch a specific [object instance](/docs/liveobjects/concepts/instance) by specifying its `objectId`: + + +```javascript +const data = await channel.object.get({ + objectId: 'map:qZXBk8xaGqf4kwLSlR7Tj0Eqhd48WDFfb3gTAbj194k@1760448597692' +}); +``` + + +Example compact result: + + +```json +{ + "down": 5, + "up": 10 +} +``` + + +Set `compact: false` to include object metadata: + + +```javascript +const data = await channel.object.get({ + objectId: 'map:qZXBk8xaGqf4kwLSlR7Tj0Eqhd48WDFfb3gTAbj194k@1760448597692', + compact: false +}); +``` + + + +```json +{ + "objectId": "map:qZXBk8xaGqf4kwLSlR7Tj0Eqhd48WDFfb3gTAbj194k@1760448597692", + "map": { + "semantics": "lww", + "entries": { + "down": { + "data": { + "objectId": "counter:Yj1F_aEX3T2rRkTkra7Aifmlr8PxUWSR3kO3MzxtQto@1760448653393", + "counter": { + "data": { + "number": 5 + } + } + } + }, + "up": { + "data": { + "objectId": "counter:ibxddWpDjH8R3cvXWWacfe4IVd3DxT_oqkAafhaS68s@1760448646413", + "counter": { + "data": { + "number": 10 + } + } + } + } + } + } +} +``` + + +You can also specify a `path` parameter alongside `objectId`. The path is evaluated relative to the specified object instance: + + +```javascript +const data = await channel.object.get({ + objectId: 'map:qZXBk8xaGqf4kwLSlR7Tj0Eqhd48WDFfb3gTAbj194k@1760448597692', + path: 'down' +}); +``` + + + +```json +5 +``` + + +## Publish operations + +### Use `channel.object.publish` + +`publish(RestObjectOperation operation): Promise` + +`publish(RestObjectOperation[] operations): Promise` + +Publishes one or more operations to modify objects on the channel. Makes a request to the [`POST /channels/{channelId}/object`](/docs/liveobjects/rest-api-usage#publishing-operations) REST API endpoint. When an array is provided, all operations are published as an atomic [batch](#batch-operations). + +| Parameter | Description | Type | +|-----------|-------------|------| +| operation | The operation or array of operations to publish | [`RestObjectOperation`](#rest-object-operation) or [`RestObjectOperation[]`](#rest-object-operation) | + +Returns a [`RestObjectPublishResult`](#rest-object-publish-result) containing the message ID and affected object IDs. + +Each operation includes: +1. A reference to an object using either `objectId` or `path`. Create operations (`mapCreate`, `counterCreate`) can omit both to create a [standalone object](#create-standalone). +2. An **operation-specific field** (`mapSet`, `counterInc`, etc.) containing the operation parameters + +Operations can target objects using `objectId`, `path`, or neither (for create operations that create [standalone objects](#create-standalone)): +- `objectId` (string): The unique identifier of the object instance to create or update +- `path` (string): The path to the object instance within the channel object + +Use dot-separated notation for paths (for example `votes.up`), relative to the channel object. An empty path `""` refers to the channel object itself. Paths can contain wildcards (`*`) to target multiple objects. + + + + + +### Available operations + +LiveObjects supports the following operations: + +| Operation | Description | +| --------- | ----------- | +| `mapSet` | Sets a key/value pair in a `LiveMap`. | +| `mapRemove` | Removes a key from a `LiveMap`. | +| `counterInc` | Increments or decrements a `LiveCounter`. | +| `mapCreate` | Creates a new `LiveMap` instance. | +| `counterCreate` | Creates a new `LiveCounter` instance. | +| `mapCreateWithObjectId` | Creates a new `LiveMap` with a [client-generated ID](#client-generated-ids). | +| `counterCreateWithObjectId` | Creates a new `LiveCounter` with a [client-generated ID](#client-generated-ids). | + +To create an object, see [Create objects](#create-objects). + +Each operation has specific required and optional fields: + +#### mapSet + + +```javascript +await channel.object.publish({ + path: 'user', + mapSet: { + key: 'username', + value: { string: 'alice' } + } +}); +``` + + +Map values can be any of the supported [data value types](#data-values), including references to other objects. + +#### mapRemove + + +```javascript +await channel.object.publish({ + path: 'user', + mapRemove: { + key: 'username' + } +}); +``` + + +#### counterInc + + +```javascript +await channel.object.publish({ + path: 'votes.up', + counterInc: { + number: 5 + } +}); +``` + + + + +#### mapCreate + +Optionally omit the `path` or `objectId` fields when creating an object with `mapCreate`. +For the object to be [reachable](/docs/liveobjects/concepts/objects#reachability) in the state tree, assign it to a key in a `LiveMap` that is reachable from the channel object. + + +```javascript +await channel.object.publish({ + path: 'posts.post1', + mapCreate: { + semantics: 'lww', + entries: { + title: { data: { string: 'LiveObjects is awesome' } }, + createdAt: { data: { number: 1745835181122 } }, + isPublished: { data: { boolean: true } } + } + } +}); +``` + + +#### counterCreate + +Optionally omit the `path` or `objectId` fields when creating an object with `counterCreate`. +For the object to be [reachable](/docs/liveobjects/concepts/objects#reachability) in the state tree, assign it to a key in a `LiveMap` that is reachable from the channel object. + + +```javascript +await channel.object.publish({ + path: 'visits', + counterCreate: { + count: 0 + } +}); +``` + + +### Update by object ID + +To perform operations on a specific object instance, provide its `objectId` in the operation: + + +```javascript +const result = await channel.object.publish({ + objectId: 'counter:iVji62_MW_j4dShuJbr2fmsP2D8MyCs6tFqON9-xAkc@1745828645269', + counterInc: { + number: 1 + } +}); +``` + + +### Update by path + +Path operations target objects based on their location in the channel object. + +Paths are expressed relative to the structure of the object as defined by the [compact](#fetch-channel-object) view of the channel object. + +The following example increments the `LiveCounter` instance stored at the `up` key on the `votes` `LiveMap` object: + + +```javascript +const result = await channel.object.publish({ + path: 'votes.up', + counterInc: { + number: 1 + } +}); +``` + + +### Publish result + +The result includes the ID of the published operation message, the channel and a list of object IDs that were affected by the operation: + + +```json +{ + "messageId": "TJPWHhMTrF:0", + "channel": "my-channel", + "objectIds": ["counter:iVji62_MW_j4dShuJbr2fmsP2D8MyCs6tFqON9-xAkc@1745828645269"] +} +``` + + +### Path operations + +Path operations provide flexibility when targeting objects. + +#### Path wildcards + +Use wildcards in paths to target multiple objects at once. To increment all `LiveCounter` instances in the `votes` `LiveMap` instance: + + +```javascript +const result = await channel.object.publish({ + path: 'votes.*', + counterInc: { + number: 1 + } +}); +``` + + +The result includes the IDs of each of the affected object instances: + + +```json +{ + "messageId": "0Q1w-LpA11:0", + "channel": "my-channel", + "objectIds": [ + "counter:iVji62_MW_j4dShuJbr2fmsP2D8MyCs6tFqON9-xAkc@1745828645269", + "counter:JbZYiHnw0ORAyzzLSQahVik31iBDL_ehJNpTEF3qwg8@1745828651669" + ] +} +``` + + +Wildcards match exactly one level in the channel object and can appear at the end or middle of paths. For example, given the following compact view of the channel object: + + +```json +{ + "posts": { + "post1": { + "votes": { + "down": 5, + "up": 10 + } + }, + "post2": { + "votes": { + "down": 5, + "up": 10 + } + } + } +} +``` + + +The following example increments the upvote `LiveCounter` instances for all posts in the `posts` `LiveMap` instance: + + +```javascript +const result = await channel.object.publish({ + path: 'posts.*.votes.up', + counterInc: { + number: 1 + } +}); +``` + + +#### Escape special characters + +If your `LiveMap` keys contain periods, escape them with a backslash. The following example increments the upvote `LiveCounter` instance for a post with the key `post.123`: + + +```javascript +const result = await channel.object.publish({ + path: 'posts.post\\.123.votes.up', + counterInc: { + number: 1 + } +}); +``` + + +### Remove objects + +Remove an object from the channel using `mapRemove` to delete the key referencing it: + + +```javascript +await channel.object.publish({ + objectId: 'root', + mapRemove: { + key: 'posts' + } +}); +``` + + +Map keys can be removed by issuing a `mapRemove` operation targeting either an `objectId` or a `path`. + +If no other references to the object exist, it becomes unreachable and is eligible for [garbage collection](#object-reachability). + + + +## Create objects + +Use `mapCreate` and `counterCreate` operations to create new LiveObjects [instances](/docs/liveobjects/concepts/instance). + +### Create objects with paths + +The simplest way to create an object is to specify a `path` where it should be created. The server automatically creates the object and assigns it to that path in a single atomic operation. + +The following example creates a new `LiveMap` instance and assigns it to the `posts` `LiveMap` instance on the channel object under the key `post1`: + + +```javascript +const result = await channel.object.publish({ + path: 'posts.post1', + mapCreate: { + semantics: 'lww', + entries: { + title: { data: { string: 'LiveObjects is awesome' } }, + createdAt: { data: { number: 1745835181122 } }, + isPublished: { data: { boolean: true } } + } + } +}); +``` + + +When using `path` with a create operation, the server constructs two operations published as a [batch](#batch-operations): + +1. A `mapCreate` or `counterCreate` operation to create the new object +2. A `mapSet` operation to assign the new object to the parent `LiveMap` at the specified path + +This ensures the new object is immediately [reachable](#object-reachability) from the root. + +The result will include the object IDs of all objects affected by the resulting set of operations. +The newly created object's ID will be the first item in the list: + + +```json +{ + "messageId": "mkfjWU2jju:0", + "channel": "my-channel", + "objectIds": [ + "map:cRCKx-eev7Tl66jGfl1SkZh_uEMo6F5jyV0B7mUn4Zs@1745835549101", + "map:a_oQqPYUGxi95_Cn0pWcsoeBlHZZtVW5xKIw0hnJCZs@1745835547258" + ] +} +``` + + +### Create standalone objects + +Create objects without immediately assigning them by omitting both `objectId` and `path` from the create operation. + + +```javascript +const result = await channel.object.publish({ + mapCreate: { + semantics: 'lww', + entries: { + name: { data: { string: 'Alice' } } + } + } +}); +``` + + +The result includes the generated object ID: + + +```json +{ + "messageId": "TJPWHhMTrF:0", + "channel": "my-channel", + "objectIds": ["map:abc123def456...@1745835549101"] +} +``` + + + + +### Client-generated object IDs + +Client-generated object IDs enable atomic batch operations with cross-references between newly created objects. See the [REST API documentation](/docs/liveobjects/rest-api-usage#client-generated-ids) for details on how to generate object IDs. + +#### Publish with client-generated IDs + +Use `mapCreateWithObjectId` or `counterCreateWithObjectId` to create an object with a pre-computed ID: + + +```javascript +const result = await channel.object.publish({ + objectId: 'map:Qj2kkvprTybCY5mkNMcm31hhNKZCDWqcz45LjYvCABs@1769079911168', + mapCreateWithObjectId: { + initialValue: '{"semantics":0,"entries":{"name":{"data":{"string":"Alice"}},"age":{"data":{"number":30}}}}', + nonce: 'random-nonce-abc123' + } +}); +``` + + +#### Atomic batch with cross-references + +Create a map and immediately link it to root in a single atomic batch: + + +```javascript +const result = await channel.object.publish([ + { + objectId: 'map:Qj2kkvprTybCY5mkNMcm31hhNKZCDWqcz45LjYvCABs@1769079911168', + mapCreateWithObjectId: { + initialValue: '{"semantics":0,"entries":{"name":{"data":{"string":"Alice"}}}}', + nonce: 'nonce-1' + } + }, + { + objectId: 'root', + mapSet: { + key: 'alice', + value: { objectId: 'map:Qj2kkvprTybCY5mkNMcm31hhNKZCDWqcz45LjYvCABs@1769079911168' } + } + } +]); +``` + + +Both operations execute atomically. The second operation references the object created in the first because you pre-computed the ID. + + + +## Cyclic references + +For both the full object and the compact formats, cyclic references in the channel object are included as a reference to the object ID rather than including the same object instance in the result more than once. + +For example, if you create a cycle in the channel object by adding a reference to the channel object in the `votes` `LiveMap` instance with the following operation: + + +```javascript +await channel.object.publish({ + objectId: 'map:qZXBk8xaGqf4kwLSlR7Tj0Eqhd48WDFfb3gTAbj194k@1760448597692', + mapSet: { + key: 'myRoot', + value: { objectId: 'root' } + } +}); +``` + + +The result will handle the cyclic reference by including the `myRoot` key as a reference to the object ID of the channel object: + + +```javascript +const data = await channel.object.get(); +``` + + + +```json +{ + "votes": { + "down": 5, + "up": 10, + "myRoot": { + "objectId": "root" + } + } +} +``` + + +## Object reachability and garbage collection + +Objects that are not reachable from the channel object are automatically garbage collected. See the [REST API documentation](/docs/liveobjects/rest-api-usage#object-reachability) and [reachability and object lifecycle](/docs/liveobjects/concepts/objects#reachability) for details. + +## Batch operations + +Group multiple operations into a single call by passing an array of operations to `publish()`. All operations are published as a single message and processed as a single atomic unit. Learn more about [batch operations](/docs/liveobjects/batch). + +The following example increments two distinct `LiveCounter` instances in a single batch operation: + + +```javascript +await channel.object.publish([ + { + objectId: 'counter:iVji62_MW_j4dShuJbr2fmsP2D8MyCs6tFqON9-xAkc@1745828645269', + counterInc: { + number: 1 + } + }, + { + objectId: 'counter:JbZYiHnw0ORAyzzLSQahVik31iBDL_ehJNpTEF3qwg8@1745828651669', + counterInc: { + number: 1 + } + } +]); +``` + + +## Idempotent operations + +Publish operations idempotently by specifying an `id` for the operation, using the same approach as [idempotent message publishing](/docs/api/liveobjects-rest#idempotent-publish): + + +```javascript +await channel.object.publish({ + id: 'my-idempotency-key', + objectId: 'counter:iVji62_MW_j4dShuJbr2fmsP2D8MyCs6tFqON9-xAkc@1745828645269', + counterInc: { + number: 1 + } +}); +``` + + +For batch operations, use the format `:` where the index is the zero-based index of the operation in the array: + + +```javascript +await channel.object.publish([ + { + id: 'my-idempotency-key:0', + objectId: 'counter:iVji62_MW_j4dShuJbr2fmsP2D8MyCs6tFqON9-xAkc@1745828645269', + counterInc: { + number: 1 + } + }, + { + id: 'my-idempotency-key:1', + objectId: 'counter:JbZYiHnw0ORAyzzLSQahVik31iBDL_ehJNpTEF3qwg8@1745828651669', + counterInc: { + number: 1 + } + } +]); +``` + + +## Data values reference + +When working with objects via the REST SDK, [primitive types](/docs/liveobjects/concepts/objects#primitive-types) and [object references](/docs/liveobjects/concepts/objects#composability) are represented as typed value objects. + +The key in the value object indicates the type of the value. Examples of data value formats: + + +```javascript +{ number: 42 } +{ string: 'LiveObjects is awesome' } +{ boolean: true } +{ bytes: new Uint8Array([76, 105, 118, 101]) } +{ objectId: 'counter:JbZYiHnw0ORAyzzLSQahVik31iBDL_ehJNpTEF3qwg8@1745828651669' } +{ json: { someKey: 'someValue' } } +``` + + + + +## Related types + +### GetObjectParams + +Parameters for the [`get()`](#get) method: + +| Property | Description | Type | +|----------|-------------|------| +| objectId | The unique identifier of the [object instance](/docs/liveobjects/concepts/instance) to fetch. If omitted, fetches from the channel's root object | `String` (optional) | +| path | A dot-separated path to return a subset of the object. Evaluated relative to the root or the specified `objectId` | `String` (optional) | +| compact | When `true` (default), returns a values-only representation. When `false`, includes object IDs and type metadata | `Boolean` (optional) | + +### RestObjectOperation + +An operation passed to the [`publish()`](#publish) method. Each operation contains an optional `id` for [idempotent publishing](#idempotent-operations), an optional target (`objectId` or `path`), and exactly one operation-specific field containing the operation parameters: + +| Property | Description | Type | +|----------|-------------|------| +| id | Identifier for [idempotent publishing](#idempotent-operations) | `String` (optional) | +| objectId | The unique identifier of the [object instance](/docs/liveobjects/concepts/instance) to target | `String` (optional) | +| path | The dot-separated path to the object instance within the channel object. Evaluated relative to the root | `String` (optional) | +| mapSet | Parameters for setting a key to a value in a `LiveMap` | [`MapSet`](#map-set) (optional) | +| mapRemove | Parameters for removing a key from a `LiveMap` | [`MapRemove`](#map-remove) (optional) | +| counterInc | Parameters for incrementing a `LiveCounter` | [`CounterInc`](#counter-inc) (optional) | +| mapCreate | Parameters for creating a new `LiveMap` | [`MapCreate`](#map-create) (optional) | +| counterCreate | Parameters for creating a new `LiveCounter` | [`CounterCreate`](#counter-create) (optional) | +| mapCreateWithObjectId | Parameters for creating a new `LiveMap` with a [client-generated ID](#client-generated-ids) | [`CreateWithObjectId`](#create-with-object-id) (optional) | +| counterCreateWithObjectId | Parameters for creating a new `LiveCounter` with a [client-generated ID](#client-generated-ids) | [`CreateWithObjectId`](#create-with-object-id) (optional) | + +### MapSet + +| Property | Description | Type | +|----------|-------------|------| +| key | The key to set | `String` | +| value | The value to assign to the key | [`ObjectData`](#object-data) | + +### MapRemove + +| Property | Description | Type | +|----------|-------------|------| +| key | The key to remove | `String` | + +### CounterInc + +| Property | Description | Type | +|----------|-------------|------| +| number | The amount to increment by. Use a negative value to decrement | `Number` | + +### MapCreate + +| Property | Description | Type | +|----------|-------------|------| +| semantics | The conflict-resolution semantics for the map. One of: `'lww'` | `String` | +| entries | Initial key-value pairs, keyed by string | `Record` | + +### CounterCreate + +| Property | Description | Type | +|----------|-------------|------| +| count | The initial value of the counter | `Number` | + +### RestDataMapEntry + +| Property | Description | Type | +|----------|-------------|------| +| data | The value for this entry | [`ObjectData`](#object-data) | + +### CreateWithObjectId + +Used by `mapCreateWithObjectId` and `counterCreateWithObjectId`: + +| Property | Description | Type | +|----------|-------------|------| +| initialValue | JSON-encoded string of the object data, matching the format from the corresponding create operation | `String` | +| nonce | Random string used to generate the object ID | `String` | + +### RestLiveObject + +Returned by [`get()`](#get) when `compact` is `false`. An expanded representation that includes object metadata. Can be a [`RestLiveMap`](#rest-live-map), [`RestLiveCounter`](#rest-live-counter), or a generic object with an `objectId` property. + +#### RestLiveMap + +| Property | Description | Type | +|----------|-------------|------| +| objectId | The ID of the map object | `String` | +| map | The map data | [`RestLiveMapValue`](#rest-live-map-value) | + +#### RestLiveMapValue + +| Property | Description | Type | +|----------|-------------|------| +| semantics | The conflict-resolution semantics. One of: `'lww'` | `String` | +| entries | The map entries, indexed by key. Each entry is either a [`RestDataMapEntry`](#rest-data-map-entry) (leaf value) or a [`RestLiveObjectMapEntry`](#rest-live-object-map-entry) (nested object) | `Record` | + +#### RestLiveObjectMapEntry + +| Property | Description | Type | +|----------|-------------|------| +| data | A nested object | [`RestLiveObject`](#rest-live-object) | + +#### RestLiveCounter + +| Property | Description | Type | +|----------|-------------|------| +| objectId | The ID of the counter object | `String` | +| counter | The counter data | [`RestLiveCounterValue`](#rest-live-counter-value) | + +#### RestLiveCounterValue + +| Property | Description | Type | +|----------|-------------|------| +| data | Holds the counter value | `{ number: Number }` | + +### ObjectData + +Represents a leaf data value for an object. Either a primitive value or a reference to another object. Exactly one property is set, indicating the type: + +| Property | Description | Type | +|----------|-------------|------| +| string | A string value | `String` | +| number | A numeric value | `Number` | +| boolean | A boolean value | `Boolean` | +| bytes | A binary value | `ArrayBuffer``Buffer` | +| json | A JSON value (array or object) | `Array` / `Object` | +| objectId | A reference to another object by its ID | `String` | + +### RestObjectPublishResult + +Result returned by the [`publish()`](#publish) method: + +| Property | Description | Type | +|----------|-------------|------| +| messageId | The ID of the message containing the published operations | `String` | +| channel | The name of the channel the operations were published to | `String` | +| objectIds | Array of object IDs affected by the operations. May include multiple IDs for wildcard paths and batch operations | `String[]` |