UNPKG

@arealtimetech/adk-js

Version:

JavaScript ADK to interact with the A Realtime Tech Platform.

392 lines (263 loc) 10.2 kB
# JavaScript ADK *The official JavaScript SDK for the [A Realtime Tech (ART)](https://www.arealtimetech.com) platform.* [Website](https://www.arealtimetech.com) · [Documentation](https://docs.arealtimetech.com) · [About ART](https://www.arealtimetech.com/about) --- ## About ART **A Realtime Tech (ART)** is a realtime application platform that powers low-latency messaging, presence, and collaborative state for modern apps. Build chat, live dashboards, multiplayer experiences, IoT control planes, and CRDT-backed shared documents on a single managed backbone without standing up your own websocket, presence, or sync infrastructure. Learn more at [arealtimetech.com](https://www.arealtimetech.com). ## About the JavaScript ADK The **JavaScript ADK (ART Development Kit)** gives your application the tools it needs to talk to ART services. It ships only the runtime needed to connect, subscribe, send, receive, and synchronise state no separate dev/prod build is required, so you can drop the same package directly into production. > **Note** installing the package is not enough on its own. The ADK must also be authenticated using credentials issued by ART (see [Configuration](#configuration) below). --- ## Installation ```bash npm install @arealtimetech/adk-js ``` --- ## Configuration The ADK supports **two ways** to provide credentials. Pick whichever fits your app. ### Option 1 — Load credentials from a JSON file (`AutoLoadCredsFromJSON`) Set `AutoLoadCredsFromJSON: true` and the ADK will automatically fetch credentials from a JSON file at the configured path. This is the simplest setup and where you can place adk-services.json in the root of the project. ```js import Adk from '@arealtimetech/adk-js'; const adk = new Adk({ Uri: "", // ART service URL AutoLoadCredsFromJSON: true, // load credentials from JSON }); adk.connect(); ``` **JSON file shape** (served at the configured config path): ```json { "Client-ID": "your-client-id", "Client-Secret": "your-client-secret", "Org-Title": "your-org", "Environment": "your-environment", "ProjectKey": "your-project-key" } ``` ### Option 2 — Set credentials programmatically (`setCredentials`) When `AutoLoadCredsFromJSON` is **off** (or omitted), you supply credentials in code via `setCredentials()`. Use this when credentials come from your own auth flow, an active user session, or any other runtime source. ```js import Adk from '@arealtimetech/adk-js'; const adk = new Adk({ Uri: "", // ART service URL }); adk.setCredentials({ ClientID: "your-client-id", ClientSecret: "your-client-secret", OrgTitle: "your-org", Environment: "your-environment", ProjectKey: "your-project-key" }); adk.connect(); ``` | Field | Type | Required | Description | | -------------- | ------ | -------- | ------------------------------------ | | `ClientID` | string | yes | Client identifier issued by ART | | `ClientSecret` | string | yes | Client secret paired with `ClientID` | | `OrgTitle` | string | yes | Your organisation / tenant title | | `Environment` | string | yes | Target environment name | | `ProjectKey` | string | yes | Project key inside the environment | --- ## Usage ### Establish and manage the connection ```js import Adk from '@arealtimetech/adk-js'; const adk = new Adk({ Uri: "", // service URL AuthToken: "", // passcode generated by your server for the user }); // Open the connection adk.connect(); // Connection lifecycle adk.on("open", async (event) => { console.log("ADK connection opened", event); }); adk.on("close", () => { console.log("ADK connection closed"); }); // Tear down adk.disconnect(); ``` ### Subscribe to a channel `subscribe()` joins a specific channel. Once subscribed, the channel is a real-time stream where you can **send**, **receive**, listen to events, and observe **user presence**. ```js const sub = await adk.subscribe("YOUR_CHANNEL_NAME"); ``` ### Track presence `fetchPresence()` returns the list of users currently active in the channel. ```js sub.fetchPresence((users) => { console.log("Active users:", users); }); ``` ### Listen to all events `listen()` is a catch-all every payload published to the channel is delivered to your callback. ```js sub.listen((data) => { console.log("Received:", data); }); ``` ### Listen to a specific event `bind()` filters by event name; the callback only fires for matching events. ```js sub.bind("EVENT", (data) => { console.log("Event received:", data); }); ``` ### Send messages `push()` publishes an event to the channel. Pass `to` to deliver only to specific users. ```js const payload = { message: "Hello!" }; sub.push("EVENT", payload, { to: ["username1", "username2"], // optional target specific users }); ``` --- ## Threads on an orchestrator-enabled channel On a channel that has orchestrator enabled, you can spin up isolated **threads** from a subscription. Each thread has its own id and only receives messages tagged with that id. ```js const sub = await adk.subscribe("YOUR_CHANNEL"); const thread = sub.thread(); console.log(thread.threadId); ``` Pass an existing id to attach to a known thread (for example, one created by the server): ```js const thread = sub.thread("thread_xxxxx"); ``` ### Listen to all events on the thread ```js thread.listen((msg) => { console.log(msg.event, msg.content); }); ``` ### Listen to a specific event ```js thread.bind("status_update", (content) => { console.log(content); }); ``` ### Send a message The `thread_id` is attached automatically. ```js await thread.push("user_input", { message: "hello" }, { to: ["username"], }); ``` ### Stop listening ```js thread.remove("status_update"); // remove all callbacks for the event thread.remove("status_update", myFn); // remove a single callback ``` ### Close the thread ```js thread.dispose(); ``` --- ## Orchestrator `adk.orchestrator(id)` connects directly to an orchestrator. The SDK subscribes to the orchestrator, so you can go straight to threads. ```js const orch = adk.orchestrator("your-orchestrator-id").connect(); const thread = await orch.thread(); thread.listen((msg) => { console.log(msg.event, msg.content); }); await thread.push("user_input", { message: "hi" }, { to: ["username"], }); ``` Reuse an existing thread by id: ```js const thread = await orch.thread("thread_xxxxx"); ``` --- ## Agent `adk.agent(id)` connects directly to an agent. The SDK subscribes to the agent's. ```js const agent = adk.agent("your-agent-id").connect(); const thread = agent.thread(); thread.listen((evt) => { console.log(evt.event, evt.content); }); // Start a run with user input const run = await thread.run("Hello agent"); // Await the final output const output = await run.done(); console.log(output); ``` Reply to a follow-up question from the agent: ```js await run.sendFeedback("yes, proceed"); ``` --- ## Shared Object Channel A **Shared Object Channel** is a real-time, collaborative data structure backed by a **CRDT**. Multiple clients can update the same JSON tree concurrently and converge to a consistent state. ```js // Subscribe like any other channel const sub = await adk.subscribe("YOUR_SO_CHANNEL_NAME"); ``` ### Reading #### Listen for live updates Listen at a **path** inside the shared object your callback receives plain JSON whenever that subtree changes. ```js // path examples: "", "user", "user.profile", "todos" const unsubscribe = await sub.query("user.profile").listen((data) => { console.log("profile updated:", data); }); // later unsubscribe(); ``` **Path rules** - `""` (empty) or `"index"` whole document - Use dot paths for objects (e.g. `user.profile.name`) - For arrays, listen at the array path (e.g. `"todos"`). Item keys are internal; per-item paths are not stable. #### Fetch once (no subscription) Retrieve the current value at a path without subscribing for ongoing updates. ```js const profile = await sub.query("user.profile").execute(); ``` ### Writing `sub.state()` returns a live proxy. Mutate it like normal JavaScript changes are batched and merged using CRDT rules. The proxy: - Auto-creates missing parent objects/arrays on write - Deletes safely (deleting a missing key is a no-op) - Emits ops optimistically (UI updates immediately) and ships a compacted batch to the server ```js // Get the live state proxy once and reuse it const state = sub.state(); /* ---------- Objects ---------- */ state.user.profile.name = "Jane Doe"; // Safe delete (no error if the key doesn't exist) delete state.settings.theme; /* ---------- Arrays ---------- */ state.todos.push({ text: "one" }, { text: "two" }); // Mutate newly added items immediately state.todos[0].text = "ONE"; // Replace item at index 1 state.todos.splice(1, 1, { text: "two-ish" }); // Pop last item (returns the removed value) const last = state.todos.pop(); /* ---------- Flushing ---------- */ // The client batches & compacts ops automatically. // Call flush() to force-send the current batch now. await sub.flush(); ``` **Array API (on any array path)** - `push(...items)` / `pop()` / `unshift(...items)` - `splice(start, deleteCount?, ...insert)` - `insertAt(index, item)` - `move(fromIndex, toIndex)` - Numeric index get/set (`state.todos[0] = {...}`) - `delete state.todos[i]` (remove at index) > **Notes** > > - You cannot create sparse indices by assignment (e.g. `todos[5] = ...` when length is 1). Use `insertAt` / `splice`. > - For newly pushed items you can mutate them immediately (optimistic local state). --- ## Documentation Full API reference and guides: **[docs.arealtimetech.com](https://docs.arealtimetech.com)** ## Learn more - **Website:** [arealtimetech.com](https://www.arealtimetech.com) - **About ART:** [arealtimetech.com/about](https://www.arealtimetech.com/about) - **Documentation:** [docs.arealtimetech.com](https://docs.arealtimetech.com) --- Made with care by [A Realtime Tech](https://www.arealtimetech.com).