supabase-realtime について
シェルスクリプトから Supabase Realtime を扱うためのスキルです。データベース変更、ブロードキャスト、プレゼンスの WebSocket パターンと、代替手段としての REST ポーリングを紹介します。
主な機能
- 01WebSocket 接続例
- 02テーブル変更の購読とフィルター
- 03ブロードキャストのパターン
- 04プレゼンス追跡の例
- 05REST ポーリングの代替案
活用シーン
- 01開発中のテーブル変更の監視
- 02スクリプトでのログやイベントのストリーミング
- 03Supabase Realtime 購読のテスト
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ nice-wolf-studio/ claude-code-supabase-skills --skill supabase-realtimeインストール後、Claude Code で/supabase-realtimeを入力して読み込まれたか確認します。
詳細
Supabase Realtime
概要
このスキルでは、Supabase Realtime の機能を使用する方法を説明します。Realtime では、WebSocket 接続を使用してデータベースの変更をリッスンしたり、メッセージをブロードキャストしたり、プレゼンスを追跡したりできます。
注: Realtime の操作には WebSocket のサポートが必要で、bash での実装はより複雑です。このスキルでは、利用可能なツールを使った実用的なパターンと例に焦点を当てます。
前提条件
必須の環境変数:
export SUPABASE_URL="https://your-project.supabase.co"
export SUPABASE_KEY="your-anon-or-service-role-key"
追加ツール:
- WebSocket 接続用の
websocatまたはwscat - JSON 処理用の
jq
websocat のインストール:
# macOS
brew install websocat
# Linux
wget https://github.com/vi/websocat/releases/download/v1.12.0/websocat.x86_64-unknown-linux-musl
chmod +x websocat.x86_64-unknown-linux-musl
sudo mv websocat.x86_64-unknown-linux-musl /usr/local/bin/websocat
WebSocket 接続
Supabase Realtime に接続する:
SUPABASE_URL="https://your-project.supabase.co"
SUPABASE_KEY="your-anon-key"
# Extract WebSocket URL (replace https:// with wss://)
WS_URL=$(echo "$SUPABASE_URL" | sed 's/https:/wss:/')
# Connect to realtime
websocat "${WS_URL}/realtime/v1/websocket?apikey=${SUPABASE_KEY}&vsn=1.0.0"
データベース変更のサブスクリプション
テーブルの変更をサブスクライブする
テーブルのすべての変更をリッスンする:
#!/bin/bash
SUPABASE_URL="https://your-project.supabase.co"
SUPABASE_KEY="your-anon-key"
WS_URL=$(echo "$SUPABASE_URL" | sed 's/https:/wss:/')
# Create subscription message
SUB_MESSAGE='{
"topic": "realtime:public:users",
"event": "phx_join",
"payload": {},
"ref": "1"
}'
# Connect and subscribe
echo "$SUB_MESSAGE" | websocat "${WS_URL}/realtime/v1/websocket?apikey=${SUPABASE_KEY}&vsn=1.0.0"
特定のイベントをサブスクライブする:
# Listen for INSERT events only
SUB_MESSAGE='{
"topic": "realtime:public:users",
"event": "phx_join",
"payload": {
"config": {
"postgres_changes": [
{
"event": "INSERT",
"schema": "public",
"table": "users"
}
]
}
},
"ref": "1"
}'
echo "$SUB_MESSAGE" | websocat "${WS_URL}/realtime/v1/websocket?apikey=${SUPABASE_KEY}&vsn=1.0.0"
UPDATE イベントをサブスクライブする:
SUB_MESSAGE='{
"topic": "realtime:public:products",
"event": "phx_join",
"payload": {
"config": {
"postgres_changes": [
{
"event": "UPDATE",
"schema": "public",
"table": "products"
}
]
}
},
"ref": "1"
}'
DELETE イベントをサブスクライブする:
SUB_MESSAGE='{
"topic": "realtime:public:posts",
"event": "phx_join",
"payload": {
"config": {
"postgres_changes": [
{
"event": "DELETE",
"schema": "public",
"table": "posts"
}
]
}
},
"ref": "1"
}'
すべてのイベント(*、INSERT、UPDATE、DELETE)をサブスクライブする:
SUB_MESSAGE='{
"topic": "realtime:public:orders",
"event": "phx_join",
"payload": {
"config": {
"postgres_changes": [
{
"event": "*",
"schema": "public",
"table": "orders"
}
]
}
},
"ref": "1"
}'
サブスクリプションのフィルター
フィルターに一致する変更をリッスンする:
# Only listen to changes where status = 'active'
SUB_MESSAGE='{
"topic": "realtime:public:users",
"event": "phx_join",
"payload": {
"config": {
"postgres_changes": [
{
"event": "*",
"schema": "public",
"table": "users",
"filter": "status=eq.active"
}
]
}
},
"ref": "1"
}'
ブロードキャストメッセージ
ブロードキャストメッセージを送信する
チャンネルにメッセージをブロードキャストする:
#!/bin/bash
SUPABASE_URL="https://your-project.supabase.co"
SUPABASE_KEY="your-anon-key"
WS_URL=$(echo "$SUPABASE_URL" | sed 's/https:/wss:/')
# Join channel first
JOIN_MESSAGE='{
"topic": "realtime:chat-room-1",
"event": "phx_join",
"payload": {
"config": {
"broadcast": {
"self": true
}
}
},
"ref": "1"
}'
# Broadcast message
BROADCAST_MESSAGE='{
"topic": "realtime:chat-room-1",
"event": "broadcast",
"payload": {
"type": "message",
"event": "new_message",
"payload": {
"user": "Alice",
"message": "Hello, World!"
}
},
"ref": "2"
}'
# Send messages
{
echo "$JOIN_MESSAGE"
sleep 1
echo "$BROADCAST_MESSAGE"
} | websocat "${WS_URL}/realtime/v1/websocket?apikey=${SUPABASE_KEY}&vsn=1.0.0"
ブロードキャストメッセージをリッスンする
ブロードキャストメッセージを受信する:
# Join channel and listen
JOIN_MESSAGE='{
"topic": "realtime:chat-room-1",
"event": "phx_join",
"payload": {
"config": {
"broadcast": {
"self": false
}
}
},
"ref": "1"
}'
echo "$JOIN_MESSAGE" | websocat "${WS_URL}/realtime/v1/websocket?apikey=${SUPABASE_KEY}&vsn=1.0.0"
プレゼンスの追跡
プレゼンスを追跡する
プレゼンスを有効にしてチャンネルに参加する:
PRESENCE_MESSAGE='{
"topic": "realtime:lobby",
"event": "phx_join",
"payload": {
"config": {
"presence": {
"key": "user-123"
}
}
},
"ref": "1"
}'
# Track presence state
TRACK_MESSAGE='{
"topic": "realtime:lobby",
"event": "presence",
"payload": {
"type": "presence",
"event": "track",
"payload": {
"user_id": "123",
"username": "Alice",
"status": "online"
}
},
"ref": "2"
}'
プレゼンスの追跡を停止する
プレゼンスから退出する:
UNTRACK_MESSAGE='{
"topic": "realtime:lobby",
"event": "presence",
"payload": {
"type": "presence",
"event": "untrack"
},
"ref": "3"
}'
実用的なパターン
継続的なリスナースクリプト
#!/bin/bash
# listen-to-changes.sh
SUPABASE_URL="https://your-project.supabase.co"
SUPABASE_KEY="your-anon-key"
WS_URL=$(echo "$SUPABASE_URL" | sed 's/https:/wss:/')
TABLE="users"
echo "Listening for changes on $TABLE table..."
# Subscribe to changes
SUB_MESSAGE='{
"topic": "realtime:public:'"$TABLE"'",
"event": "phx_join",
"payload": {
"config": {
"postgres_changes": [
{
"event": "*",
"schema": "public",
"table": "'"$TABLE"'"
}
]
}
},
"ref": "1"
}'
# Listen continuously
echo "$SUB_MESSAGE" | websocat "${WS_URL}/realtime/v1/websocket?apikey=${SUPABASE_KEY}&vsn=1.0.0" | \
while IFS= read -r line; do
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $line" | jq '.'
done
ハンドラーで変更を処理する
#!/bin/bash
# process-changes.sh
handle_insert() {
local record="$1"
echo "New record inserted:"
echo "$record" | jq '.payload.record'
# Your custom logic here
# Example: Send notification, update cache, etc.
}
handle_update() {
local old_record="$1"
local new_record="$2"
echo "Record updated:"
echo "Old: $(echo "$old_record" | jq -c '.')"
echo "New: $(echo "$new_record" | jq -c '.')"
}
handle_delete() {
local record="$1"
echo "Record deleted:"
echo "$record" | jq '.payload.old_record'
}
# Listen and process
websocat "${WS_URL}/realtime/v1/websocket?apikey=${SUPABASE_KEY}&vsn=1.0.0" | \
while IFS= read -r line; do
event_type=$(echo "$line" | jq -r '.payload.data.type // empty')
case "$event_type" in
"INSERT")
handle_insert "$(echo "$line" | jq '.payload.data')"
;;
"UPDATE")
handle_update \
"$(echo "$line" | jq '.payload.data.old_record')" \
"$(echo "$line" | jq '.payload.data.record')"
;;
"DELETE")
handle_delete "$(echo "$line" | jq '.payload.data')"
;;
esac
done
複数テーブルのリスナー
#!/bin/bash
# listen-multiple-tables.sh
TABLES=("users" "posts" "comments")
for table in "${TABLES[@]}"; do
(
echo "Starting listener for $table"
SUB_MESSAGE='{
"topic": "realtime:public:'"$table"'",
"event": "phx_join",
"payload": {
"config": {
"postgres_changes": [{"event": "*", "schema": "public", "table": "'"$table"'"}]
}
},
"ref": "1"
}'
echo "$SUB_MESSAGE" | websocat "${WS_URL}/realtime/v1/websocket?apikey=${SUPABASE_KEY}&vsn=1.0.0" | \
while IFS= read -r line; do
echo "[$table] $line"
done
) &
done
wait
メッセージ形式
サブスクリプションの確認
{
"event": "phx_reply",
"payload": {
"response": {
"postgres_changes": [
{
"id": "12345",
"event": "*",
"schema": "public",
"table": "users"
}
]
},
"status": "ok"
},
"ref": "1",
"topic": "realtime:public:users"
}
INSERT イベント
{
"event": "postgres_changes",
"payload": {
"data": {
"commit_timestamp": "2023-01-01T12:00:00Z",
"record": {
"id": 123,
"name": "John Doe",
"email": "[email protected]"
},
"schema": "public",
"table": "users",
"type": "INSERT"
},
"ids": [12345]
},
"topic": "realtime:public:users"
}
UPDATE イベント
{
"event": "postgres_changes",
"payload": {
"data": {
"commit_timestamp": "2023-01-01T12:00:00Z",
"old_record": {
"id": 123,
"name": "John Doe"
},
"record": {
"id": 123,
"name": "Jane Doe"
},
"schema": "public",
"table": "users",
"type": "UPDATE"
}
}
}
DELETE イベント
{
"event": "postgres_changes",
"payload": {
"data": {
"commit_timestamp": "2023-01-01T12:00:00Z",
"old_record": {
"id": 123,
"name": "John Doe"
},
"schema": "public",
"table": "users",
"type": "DELETE"
}
}
}
代替方法:REST ポーリング
WebSocket の利用が現実的でない、よりシンプルなユースケースでは、ポーリングを検討してください。
#!/bin/bash
# poll-changes.sh
source "$(dirname "${BASH_SOURCE[0]}")/../../scripts/supabase-api.sh"
LAST_TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
while true; do
# Get records created/updated since last check
new_records=$(supabase_get "/rest/v1/users?updated_at=gt.${LAST_TIMESTAMP}&order=updated_at.asc")
if [[ "$new_records" != "[]" ]]; then
echo "New changes detected:"
echo "$new_records" | jq '.'
# Update timestamp
LAST_TIMESTAMP=$(echo "$new_records" | jq -r '.[-1].updated_at')
fi
# Poll every 5 seconds
sleep 5
done
Realtime の設定
Supabase Dashboard で Realtime を有効にする:
- Database > Replication に移動します
- リッスンするテーブルのレプリケーションを有効にします
- パブリッシュするイベント(INSERT、UPDATE、DELETE)を選択します
行レベルセキュリティ: Realtime は RLS ポリシーに従います。ユーザーが受信するのは、アクセス権のある行の変更のみです。
制限事項
- WebSocket 接続には、永続的な接続管理が必要です
- WebSocket の処理に bash は適していません(本番環境では Node.js/Python を検討してください)
- 接続が切断された場合は、再接続ロジックが必要です
- Realtime には Supabase のプランに応じた接続数の制限があります
ユースケース
bash での Realtime に適している用途:
- 開発/デバッグツール
- シンプルな監視スクリプト
- ログのストリーミング
- リアルタイム機能のテスト
他の言語のほうが適している用途:
- 本番環境のチャットアプリケーション
- 複雑なプレゼンス追跡
- 複数チャンネルの連携
- 自動再接続が必要な場合
API ドキュメント
Supabase Realtime のドキュメント全文:https://supabase.com/docs/guides/realtime