using-ably について
Using Ablyは、Ablyのリアルタイムメッセージング、コラボレーション、チャット、AIストリーミングを使うアプリを開発・変更する開発者向けのスキルです。最新の公式ドキュメントの確認、適切な製品とSDKの選択、よくある統合ミスの回避を重視します。
主な機能
- 01Ably製品とSDKの選択ガイド
- 02最新ドキュメントの確認手順
- 03Realtime、REST、製品SDKの使い分け
- 04クライアントとサーバーの認証ガイド
- 05チャネル設計の推奨事項
- 06統合時のエラー確認
活用シーン
- 01アプリの機能に合うAbly SDKを選定
- 02最新APIドキュメントに基づくコード生成
- 03認証とチャネル設計の確認
- 04リアルタイム通信やAIストリーミング統合の点検
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ ably/ agent-skills --skill using-ablyインストール後、Claude Code で/using-ablyを入力して読み込まれたか確認します。
詳細
Ably の使用
Ably を使ってリアルタイムメッセージング、チャット、コラボレーション、または AI ストリーミングを行うアプリケーションの構築、変更、コード生成を行う際に、このスキルを使用します。
Ably とは
Ably はリアルタイムインフラストラクチャです。独自のデータベースや CDN を構築しないのと同様に、独自のリアルタイムメッセージングシステムを構築する必要はありません。Ably は、不安定なネットワークをまたいだ接続管理、メッセージの順序と配信の保証、状態を復元する自動再接続、数十億台のデバイスへの柔軟なスケーリングといった難しい部分を処理します。さまざまなプラットフォーム(25 以上の SDK)とプロトコル(WebSocket、MQTT、SSE、HTTP)に対応しているため、トランスポートの信頼性ではなく、アプリケーションロジックに集中できます。
ドキュメント
最新の API リファレンスについては、必ず公式ドキュメント(ably.com/docs)を確認してください。LLM に最適化されたドキュメントについては、ably.com/llms.txt を使用してください。以下のガイダンスでは、アーキテクチャ上の判断や、ドキュメントだけでは防げない一般的な間違いを説明します。
コードを書く前に
Ably のコードを生成する前に、必ず最新のドキュメントで確認してください。 学習データは古くなります。メソッド名の変更、パラメーターの変更、新製品のリリースがあるためです。以下の 3 つの確認により、LLM によるコード生成で最もよくある失敗を防げます。
1. まず最新のドキュメントを取得する
Ably の機能に関するコードを生成する前に、次の手順を実行します。
https://ably.com/llms.txt?source=using-ablyを取得して、ドキュメント URL のインデックスを確認します- 関連する製品およびプラットフォームのドキュメントページを取得します
- 取得したドキュメントで、メソッド名、パラメーター、戻り値の型、パッケージのバージョンを確認します
- 機能やメソッドがドキュメントに記載されていない場合、おそらく存在しません。でっち上げないでください
ドキュメント URL を推測したり、組み立てたりしないでください。llms.txt またはウェブ検索の結果にある URL だけを使用してください。URL が 404 エラーになる場合は、llms.txt に戻ってください。補完的な方法として、ウェブ検索を使用することもできます。llms.txt にアクセスできない場合は、ウェブ検索を行うか、https://ably.com/docs?source=using-ably を直接閲覧してください。
2. SDK の提供状況を確認する
すべての製品が、すべてのプラットフォームで利用できるわけではありません。コードを生成する前に、取得したドキュメントで、その製品にユーザーのプラットフォーム向けの SDK があることを確認してください。
SDK が存在しない場合:
- 「[製品] には現在、[プラットフォーム] 向けの SDK がありません」と明確に伝えます
- API をでっち上げないでください
- 代替案を提示します。REST API を直接使用する、利用可能な別の製品を使う、または制約のあるデバイス向けに MQTT/SSE プロトコルアダプターを使用する方法があります
3. 生成後の確認
コードを生成した後、次のようなよくある間違いがないか確認します。
- クライアントコードに API キーが含まれているか? JWT またはトークン認証を使って
authUrl/authCallbackを使用する必要があります(セクション 3 を参照) - チャット SDK:購読前に
attach()を呼び出しているか? メッセージが気づかれずに失われるのを防ぐため、先に購読してください(セクション 7 を参照) - React:クリーンアップなしでコンポーネント内に Ably クライアントを作成しているか? 外部で一度だけ作成してプロバイダー経由で渡すか、適切なクリーンアップを行う
useEffectを使用してください(セクション 8 を参照) - サーバーサイド:REST で十分な場合に Realtime SDK を使用しているか? パブリッシュ、トークン生成、履歴には、原則として
Ably.Restを使用してください(セクション 2 を参照) - アンマウント/終了時に接続をクリーンアップしているか?
realtime.close()を呼び出してください(セクション 5 を参照) - 組み込みの動作を再実装しているか? タイピングインジケーター用のカスタムデバウンス、カーソル用のカスタムスロットリング、LiveObjects 用のカスタム競合解決を追加しないでください(セクション 9 を参照)
- AI Transport:チャネルルールが有効になっているか? 名前空間に
mutableMessagesが必要です。有効でないと、ストリーミングはエラー93002で失敗します(セクション 2 を参照)
1. 製品と SDK の構成を理解する
Ably は単一の SDK ではなく、複数の製品を提供するプラットフォームです。製品や SDK の選択を誤ることは、統合時に最もよくある間違いです。
プロダクトレイヤー:何を構築しますか?
| プロダクト | ユースケース | SDK |
|---|---|---|
| Pub/Sub | コアメッセージング:ライブダッシュボード、通知、IoT、イベントストリーミング | ably(Realtime または REST) |
| AI Transport | LLM トークンのストリーミング、複数エージェントの連携、再開可能な AI セッション | @ably/ai-transport |
| LiveObjects | 共有可能な可変状態:カウンター、キーと値のマップ、共同編集データ | ably + LiveObjects プラグイン |
| LiveSync | データベースからフロントエンドへの同期(PostgreSQL の変更ストリーム) | @ably-labs/models + ADBC コネクター |
| Chat | チャットルーム、入力中インジケーター、リアクション、メッセージ履歴、モデレーション | @ably/chat |
| Spaces | 共同作業用カーソル、アバターのスタック、メンバーの位置情報、コンポーネントのロック | @ably/spaces |
SDK アーキテクチャ:2 つのレイヤー
レイヤー 1 — コア SDK(Pub/Sub、LiveObjects、LiveSync で直接使用):
| SDK | 使用する場面 | 接続 |
|---|---|---|
Ably.Realtime | クライアントがメッセージ、プレゼンス、または状態の変更をサブスクライブする必要がある | 永続的な WebSocket |
Ably.Rest | サーバー側での公開のみ、トークン生成、履歴のクエリ | ステートレス HTTP |
これらが基盤となります。LiveObjects と LiveSync はコアの Realtime SDK を基盤として構築されています。LiveObjects はクライアントオプションに渡すプラグインで、LiveSync は Models SDK を介して使用します。
レイヤー 2 — プロダクト SDK(特定のユースケース向けの高レベルな抽象化):
| SDK | 目的 |
|---|---|
@ably/chat | ルーム、入力中インジケーター、リアクション、メッセージ履歴、モデレーション |
@ably/spaces | カーソル、アバターのスタック、メンバーの位置情報、コンポーネントのロック |
@ably/ai-transport | AI エージェントの出力をストリーミングするためのセッション、実行、ステップ。分岐と履歴に対応した会話ツリー |
これらのプロダクト SDK はコアの Realtime SDK に依存します。作成時に Ably.Realtime インスタンスを渡します。基盤となる Realtime の知識(認証、チャンネル、プレゼンス)は引き続き適用されます。
選択の指針
Q: Is this server-side or client-side?
├── Server-side:
│ ├── Publishing, token generation, history → Use Ably.Rest (stateless HTTP)
│ ├── Streaming AI agent output → Use @ably/ai-transport agent session (over Realtime)
│ └── Need persistent connection (subscribing) → Use Ably.Realtime
└── Client-side → Use Ably.Realtime, then:
├── Building chat? → Use @ably/chat (pass Realtime instance)
├── Building collaboration? → Use @ably/spaces (pass Realtime instance)
├── Consuming AI agent output? → Use @ably/ai-transport client session
├── Need shared state? → Use LiveObjects plugin with Realtime
├── Syncing database? → Use @ably-labs/models with ADBC connector
└── Otherwise → Use Ably.Realtime directly (Pub/Sub)
サーバー側の経験則: サーバー操作では、デフォルトで Ably.Rest を使用します。永続的な接続が本当に必要な場合に限り、サーバーで Ably.Realtime を使用してください。たとえば、AI エージェントがクライアントにトークンをストリーミングする場合や、バックエンドサービスがイベントをサブスクライブする場合です。
よくある間違い
// WRONG: Using REST SDK then polling for messages
const rest = new Ably.Rest({ key: '...' });
setInterval(async () => {
const history = await rest.channels.get('updates').history();
}, 1000);
// RIGHT: Using Realtime SDK to subscribe
const realtime = new Ably.Realtime({ key: '...' });
realtime.channels.get('updates').subscribe((msg) => {
console.log('Received:', msg.data);
});
// WRONG: Using raw Pub/Sub for chat when Chat SDK exists
const channel = realtime.channels.get('chat-room');
channel.subscribe((msg) => { /* manually handling typing, reactions, history... */ });
// RIGHT: Using Chat SDK which handles all chat patterns
import { ChatClient } from '@ably/chat';
const chat = new ChatClient(realtime);
const room = await chat.rooms.get('my-room');
room.messages.subscribe((msg) => console.log(msg.text));
await room.typing.keystroke(); // built-in typing indicators
2. 最新の SDK パターンを使用する(v2.x)
Ably の JavaScript SDK v2.x は async/await を使用します。コールバック形式の 1.x パターンは絶対に生成しないでください。
// WRONG: Old 1.x callback pattern (deprecated)
const channel = realtime.channels.get('updates');
channel.subscribe('event', function(message) {
console.log(message.data);
});
channel.publish('event', { text: 'hello' }, function(err) {
if (err) console.error(err);
});
// RIGHT: Modern 2.x async/await pattern
const channel = realtime.channels.get('updates');
channel.subscribe('event', (message) => {
console.log(message.data);
});
await channel.publish('event', { text: 'hello' });
インポートと初期化 — シンプルに保つ:
// RIGHT: Standard ESM import
import Ably from 'ably';
const realtime = new Ably.Realtime({ key: 'your-key' });
const rest = new Ably.Rest({ key: 'your-key' });
// RIGHT: Chat SDK import
import { ChatClient } from '@ably/chat';
// WRONG: Don't invent type-based initialization
const options: Ably.Types.ClientOptions = { ... }; // unnecessary
ESM/CommonJS のインポートエラーが発生した場合は、tsconfig.json の "moduleResolution": "bundler" または "node16" が設定されていること、また 'ably'(サブパスではありません)からインポートしていることを確認してください。複数のインポート方法を試さず、利用環境に応じてSDK の READMEを確認してください。
サーバー側:REST SDK をデフォルトで使用します。 永続的な接続が必要な場合に限り、サーバーで Ably.Realtime を使用してください。
// WRONG: Realtime SDK on server just to publish
const realtime = new Ably.Realtime({ key: '...' }); // opens WebSocket unnecessarily
await realtime.channels.get('events').publish('update', data);
// RIGHT: REST SDK for server-side publish
const rest = new Ably.Rest({ key: '...' }); // stateless HTTP
await rest.channels.get('events').publish('update', data);
// WRONG: Hand-rolling token streaming onto a raw channel
const channel = realtime.channels.get('conversations:123');
const { serials: [msgSerial] } = await channel.publish({ name: 'response', data: '' });
for await (const event of llmStream) {
channel.appendMessage({ serial: msgSerial, data: event.text }); // reinvents AI Transport
}
// RIGHT: Use AI Transport — it owns the run/step lifecycle, cancellation, and history
import { createAgentSession } from '@ably/ai-transport/vercel';
const session = createAgentSession({ client: realtime, channelName: 'conversations:123' });
await session.connect();
// Then open a run and pipe your model stream into a step. Verify the run/step API
// against ably.com/docs/ai-transport/api/javascript/core/agent-session?source=using-ably
AI Transport にはチャンネルルールが必要です。 AI Transport で使用するすべての名前空間に、Message annotations, updates, deletes, and appends ルール(mutableMessages: true)が必要です。ストリーミングでは 1 つのメッセージにトークンを追加するため、このルールがないと追加がエラー 93002 で拒否されます。これは AI Transport で最もよくある失敗で、最初の追加時にのみ発生するため、アシスタントのメッセージが空、または最初のトークンしか含まれていないという症状になります。ダッシュボードで有効にするか、ably apps rules create "conversations" --mutable-messages を実行してください。チャンネルルールを参照してください。
3. 認証
API キーはサーバー側専用です。クライアントに絶対に公開しないでください。
API キーは有効期限がありません。漏えいした場合、キーを再生成するまで攻撃者が無期限にアクセスできます。
推奨:JWT 認証
JWT は、クライアント側アプリケーションに推奨される認証方法です。
Ably トークンより JWT が適している理由:
- Ably サーバーとの往復通信が不要です。バックエンドで JWT を直接作成して署名できます
- 既存の認証システムと統合できます。すでに利用している標準的な JWT ライブラリを使用できます
- トークンごとに権限を定義できます。API キーに設定された権限に制限されません
- あらゆる環境で動作します。Ably SDK がない環境(MQTT、組み込みデバイスなど)にも対応します
JWT クレーム:
kid(ヘッダー):Ably API キー名(例:xVLyHw.abcdef)iat:発行時のタイムスタンプ(秒)exp:有効期限のタイムスタンプ(秒)x-ably-capability:チャンネル権限を表す JSON 文字列x-ably-clientId(任意):プレゼンス用のクライアント ID
// Server-side: Create JWT for client
import jwt from 'jsonwebtoken';
app.post('/api/ably-auth', (req, res) => {
const apiKey = process.env.ABLY_API_KEY; // 'appId.keyId:keySecret'
const [keyName, keySecret] = apiKey.split(':');
const token = jwt.sign(
{
'x-ably-capability': JSON.stringify({
'room:*': ['subscribe', 'publish', 'presence'],
[`notifications:${req.user.id}`]: ['subscribe'],
}),
'x-ably-clientId': req.user.id,
},
keySecret,
{
expiresIn: '1h',
keyid: keyName,
}
);
res.json(token);
});
// Client-side: Use JWT with Ably
const realtime = new Ably.Realtime({
authUrl: '/api/ably-auth',
authMethod: 'POST',
});
代替手段:Ably Token Requests
ほとんどの用途では JWT が推奨されますが、権限リストが JWT のサイズ制限を超える場合(JWT は HTTP ヘッダー内に収まる必要があり、上限は約 8KB)、または JWT はクライアント側でデコードできるため、権限を機密に保つ必要がある場合は、Ably トークンが適していることがあります。その代わり、Ably トークンの統合はより複雑で、チャンネルスコープのクレームや接続ごとのレート制限など、JWT のすべての機能には対応していません。
// Ably's native token system (requires round-trip to Ably servers from backend)
app.post('/api/ably-token', (req, res) => {
const client = new Ably.Rest({ key: process.env.ABLY_API_KEY });
client.auth.createTokenRequest({
clientId: req.user.id,
capability: { 'room:*': ['subscribe', 'publish'] },
}).then(tokenRequest => res.json(tokenRequest));
});
ルール
- サーバー側:API キーを使用できます(
{ key: 'appId.keyId:keySecret' }) - クライアント側:必ず
authUrlまたはauthCallbackを使用してください。API キーを埋め込んだり、静的なtokenを直接渡したりしないでください(有効期限が切れても自動更新されません) - プレゼンス機能が必要な場合は
clientIdを設定してください。プレゼンスには必須です - 各クライアントがアクセスできるチャンネルと操作を制限するには、権限を使用してください
4. チャンネル設計
チャンネルはメッセージをトピックごとに分けます。後から変更するのは難しいため、早い段階で適切な命名規則を決めてください。
ルール:
- 階層の区切り文字として
:を使用します:chat:room-123、orders:user-456 - チャンネル名では大文字と小文字が区別されます
- メッセージごとにチャンネルを作成しないでください。チャンネルは長期間使用するトピックです
- ダッシュボードのルールを使用して、チャンネルのグループに設定(永続化、プッシュ通知など)を適用します
一般的なパターン:
chat:room-{roomId} # Chat rooms
notifications:user-{userId} # Per-user notifications
cursors:doc-{docId} # Collaborative editing
events:{eventType} # Event streaming
conversations:{sessionId} # AI Transport sessions
ルールと権限は、最初のコロンまでの名前空間に文字どおり一致します。そのため、conversation(単数形)は conversations:* に一致しません。表記を一つに決め、チャンネル名、チャンネルルール、トークンの権限で統一してください。
5. 接続管理
Realtime SDK は再接続を自動的に管理します。これを妨げないでください。
ルール:
- 手動で再接続しないでください。一時的な障害には SDK が指数バックオフで対処します
- 接続状態の変化を監視して UI を更新します:
realtime.connection.on('connected', () => { /* online */ });
realtime.connection.on('disconnected', () => { /* temporarily offline */ });
realtime.connection.on('suspended', () => { /* offline for extended period */ });
- 処理が終わったら
realtime.close()を呼び出してください(コンポーネントのアンマウント、ページのアンロードなど) - 切断中に公開されたメッセージは、再接続時に受信されます(2 分間の復旧期間内)
- 生の Pub/Sub では、再接続したクライアントがアタッチ時に最近のメッセージを受信できるよう、チャンネルの
rewindを使用します:
const channel = realtime.channels.get('updates:123', {
params: { rewind: '2m' } // Replay last 2 minutes on attach
});
- AI Transport では、
rewindを使う必要はありません。クライアントセッションは履歴を読み込む前にサブスクライブし、view.loadOlder()で過去にさかのぼるため、履歴とライブストリームが欠落も重複もなくつながります
6. プレゼンス
プレゼンスは、どのクライアントがチャンネルに参加しているかを追跡します。「オンラインのユーザー」機能に使用します。
ルール:
- 認証時に
clientIdを設定してください。プレゼンスには必須です - 参加するときは
channel.presence.enter()、データを更新するときはchannel.presence.update()、退出するときはchannel.presence.leave()を呼び出します - 現在のメンバーを取得するには
channel.presence.get()、変更を受信するにはchannel.presence.subscribe()を使用します - クライアントが正常に切断されなかった場合、Ably は約 15 秒後にそのクライアントを削除します(即時ではありません)
- 高頻度データ(カーソル位置、入力座標など)にプレゼンスを使用しないでください。代わりにチャンネルを使用します。プレゼンスは低頻度の状態(オンライン/オフライン、ユーザーのステータスなど)向けです
- Chat では、生のチャンネルプレゼンスではなく
room.presenceを使用します - Spaces では、
space.enter()/useMembers()フックを使用します。Spaces にはカーソル位置専用のcursorsAPI があります
7. Chat SDK:重要なライフサイクル
@ably/chat を使用する場合、よくある間違いは次のとおりです。
必ず attach() を呼び出す前にサブスクライブしてください。 先にサブスクライブせずにアタッチすると、メッセージが気付かないうちに失われます。これは最も厄介な種類のバグです。
const room = await chat.rooms.get('my-room');
// WRONG: Attach without subscribing first — messages silently lost
await room.attach();
room.messages.subscribe((msg) => console.log(msg.text)); // may miss messages during attach
// RIGHT: Subscribe first, then attach
room.messages.subscribe((msg) => console.log(msg.text));
await room.attach();
実際の API を使用してください。 Chat SDK には、スレッド機能、既読通知、ファイル添付機能、room.messages.broadcast() はありません。メッセージの送信には room.messages.send() を使用してください。
Chat と Pub/Sub のパターンを混在させないでください。 @ably/chat を使用する場合は、生の channel.subscribe()/channel.publish() ではなく、room.messages、room.typing、room.reactions を使用してください。
再実装する必要のない組み込み機能:
- タイピングインジケーターの頻度制御は SDK によって自動的に処理されます
- ルームのリアクション配信は SDK によって処理されます
- メッセージの順序付けと履歴のページネーションは組み込み機能です
8. React との統合
Ably は各製品向けに React フックを提供しています。
| 製品 | パッケージ | 主なフック |
|---|---|---|
| Pub/Sub | ably/react | useChannel、usePresence、useConnectionStateListener |
| Chat | @ably/chat/react | useMessages、useTyping、usePresence、useRoomReactions |
| Spaces | @ably/spaces/react | useMembers、useCursors、useLocations、useLocks |
重要なルール:レンダリングのたびに新しい Ably クライアントを作成しないでください。 作成するたびに新しい WebSocket 接続が確立され、メモリリークの原因になります。
// WRONG: Creates new connection every render — memory leak
function Chat() {
const ably = new Ably.Realtime({ authUrl: '/api/ably-auth' });
// ...
}
// RIGHT: Create client once, pass via provider
const ably = new Ably.Realtime({ authUrl: '/api/ably-auth' });
function App() {
return (
<AblyProvider client={ably}>
<ChannelProvider channelName="chat:room-1">
<Chat />
</ChannelProvider>
</AblyProvider>
);
}
// ALSO RIGHT: Create in useEffect with proper cleanup
function App() {
const [client, setClient] = useState(null);
useEffect(() => {
const ably = new Ably.Realtime({ authUrl: '/api/ably-auth' });
setClient(ably);
return () => ably.close();
}, []);
// ...
}
9. Spaces と LiveObjects:組み込み機能
Spaces(@ably/spaces)を使用する場合:
- カーソル位置のバッチ処理は組み込み機能です。独自のスロットリングを実装しないでください
space.locationsによるメンバーの位置追跡は組み込み機能です- コンポーネントのロックは
space.locksによって競合を自動的に処理します
LiveObjects を使用する場合:
- 使用できるデータ構造は Maps と Counters のみです(カスタムオブジェクト型はありません)
- 競合解決は組み込み機能です。独自に実装しないでください
- 再接続後の状態復旧は自動的に行われます
- シンプルさを優先する場合は、インスタンス API よりパスベースの API を使用してください
10. LiveSync:データベースからフロントエンドへ
LiveSync はデータベースをフロントエンドに接続します:Database → ADBC Connector → Ably Channels → Models SDK → Frontend。
主な制約: PostgreSQL では論理レプリケーションが必要です(14 以降。WAL レベルの変更には再起動が必要です)。MongoDB ではレプリカセットが必要です(スタンドアロン構成は不可)。Database Connector は、イングレスルールを設定すると、チャネルのマッピングを自動的に処理します。
LiveSync の最新ドキュメントを必ず取得してください。 ably.com/docs/livesync を参照してください。データベースの権限とコネクターの設定は、バージョンによって異なります。
11. 本番環境チェックリスト
本番環境に移行する前に、次の点を確認してください。
- クライアントコードに API キーがない —
authUrl/authCallbackを介した JWT 認証またはトークン認証を使用してください - ケイパビリティの範囲が限定されている — クライアントに
{"*":["*"]}を付与せず、特定のチャネルと操作に限定してください - 接続のクリーンアップ — 接続リークを防ぐため、アンマウント時/アンロード時に
realtime.close()を呼び出してください - エラー処理 —
connection.on('failed')をリッスンし、認証エラーを適切に処理してください - チャネルのデタッチ — 不要になったチャネルからデタッチしてください(
channel.detach()) - メッセージサイズ — メッセージのサイズはデフォルトで 64KB に制限されています。この制限に達する場合は、ペイロードを分割するか、メッセージの設計を見直してください
- 冪等なパブリッシュ — 厳密に 1 回の配信が重要な場合は、一意のメッセージ ID を設定してください
-
echoMessages: false— パブリッシャーが自身のメッセージを受信する必要がない場合は設定してください(帯域幅とコストを削減できます) - レート制限 — Ably にはレート制限があります(例:チャネルあたり毎秒 50 メッセージ、接続あたり 200 チャネル)。制限に達する場合は、パブリッシュ頻度とチャネルへのファンアウトを確認してください。制限に関するドキュメントを参照してください
エラー処理
Ably のエラーコードは大まかな場合があります(例:40000、50000)。コードだけでなく、必ずエラーのメッセージ本文を確認してください。各エラーコードのヘルプページは https://help.ably.io/error/{code} にあります。
12. クイックリファレンス
製品ドキュメント: Pub/Sub | Chat | Spaces | LiveObjects | LiveSync | AI Transport
プラットフォーム SDK: JavaScript、React、Python、Ruby、Java、Kotlin、Swift、.NET、Go、PHP、Flutter — ably.com/docs/sdks
Ably CLI: npm install -g @ably/cli でインストールすると、テストメッセージのパブリッシュ、チャンネルのサブスクライブ、セットアップの確認ができます。ably --help を実行して、コマンドを確認してください。
API リファレンスについては、ably.com/docs をご覧ください。