supabase-realtime

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Supabase Realtime

Supabase Realtime

Overview

概述

This skill provides guidance for working with Supabase Realtime features. Realtime allows you to listen to database changes, broadcast messages, and track presence using WebSocket connections.
Note: Realtime operations require WebSocket support, which is more complex in bash. This skill focuses on practical patterns and examples using available tools.
本技能提供了使用Supabase Realtime功能的指导。Realtime允许你通过WebSocket连接监听数据库变更、广播消息以及追踪在线状态。
注意: Realtime操作需要WebSocket支持,这在bash中实现起来较为复杂。本技能聚焦于使用现有工具的实用模式和示例。

Prerequisites

前提条件

Required environment variables:
bash
export SUPABASE_URL="https://your-project.supabase.co"
export SUPABASE_KEY="your-anon-or-service-role-key"
Additional tools:
  • websocat
    or
    wscat
    for WebSocket connections
  • jq
    for JSON processing
Install websocat:
bash
undefined
所需环境变量:
bash
export SUPABASE_URL="https://your-project.supabase.co"
export SUPABASE_KEY="your-anon-or-service-role-key"
额外工具:
  • websocat
    wscat
    用于WebSocket连接
  • jq
    用于JSON处理
安装websocat:
bash
undefined

macOS

macOS

brew install websocat
brew install websocat

Linux

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
undefined
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
undefined

WebSocket Connection

WebSocket连接

Connect to Supabase Realtime:
bash
SUPABASE_URL="https://your-project.supabase.co"
SUPABASE_KEY="your-anon-key"
连接到Supabase Realtime:
bash
SUPABASE_URL="https://your-project.supabase.co"
SUPABASE_KEY="your-anon-key"

Extract WebSocket URL (replace https:// with wss://)

提取WebSocket URL(将https://替换为wss://)

WS_URL=$(echo "$SUPABASE_URL" | sed 's/https:/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"
undefined
websocat "${WS_URL}/realtime/v1/websocket?apikey=${SUPABASE_KEY}&vsn=1.0.0"
undefined

Database Change Subscriptions

数据库变更订阅

Subscribe to Table Changes

订阅表变更

Listen to all changes on a table:
bash
#!/bin/bash

SUPABASE_URL="https://your-project.supabase.co"
SUPABASE_KEY="your-anon-key"
WS_URL=$(echo "$SUPABASE_URL" | sed 's/https:/wss:/')
监听某个表的所有变更:
bash
#!/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" }'
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"

**Subscribe to specific events:**
```bash
echo "$SUB_MESSAGE" | websocat "${WS_URL}/realtime/v1/websocket?apikey=${SUPABASE_KEY}&vsn=1.0.0"

**订阅特定事件:**
```bash

Listen for INSERT events only

仅监听INSERT事件

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"

**Subscribe to UPDATE events:**
```bash
SUB_MESSAGE='{
  "topic": "realtime:public:products",
  "event": "phx_join",
  "payload": {
    "config": {
      "postgres_changes": [
        {
          "event": "UPDATE",
          "schema": "public",
          "table": "products"
        }
      ]
    }
  },
  "ref": "1"
}'
Subscribe to DELETE events:
bash
SUB_MESSAGE='{
  "topic": "realtime:public:posts",
  "event": "phx_join",
  "payload": {
    "config": {
      "postgres_changes": [
        {
          "event": "DELETE",
          "schema": "public",
          "table": "posts"
        }
      ]
    }
  },
  "ref": "1"
}'
Subscribe to all events (*, INSERT, UPDATE, DELETE):
bash
SUB_MESSAGE='{
  "topic": "realtime:public:orders",
  "event": "phx_join",
  "payload": {
    "config": {
      "postgres_changes": [
        {
          "event": "*",
          "schema": "public",
          "table": "orders"
        }
      ]
    }
  },
  "ref": "1"
}'
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事件:**
```bash
SUB_MESSAGE='{
  "topic": "realtime:public:products",
  "event": "phx_join",
  "payload": {
    "config": {
      "postgres_changes": [
        {
          "event": "UPDATE",
          "schema": "public",
          "table": "products"
        }
      ]
    }
  },
  "ref": "1"
}'
订阅DELETE事件:
bash
SUB_MESSAGE='{
  "topic": "realtime:public:posts",
  "event": "phx_join",
  "payload": {
    "config": {
      "postgres_changes": [
        {
          "event": "DELETE",
          "schema": "public",
          "table": "posts"
        }
      ]
    }
  },
  "ref": "1"
}'
订阅所有事件(*, INSERT, UPDATE, DELETE):
bash
SUB_MESSAGE='{
  "topic": "realtime:public:orders",
  "event": "phx_join",
  "payload": {
    "config": {
      "postgres_changes": [
        {
          "event": "*",
          "schema": "public",
          "table": "orders"
        }
      ]
    }
  },
  "ref": "1"
}'

Filter Subscriptions

过滤订阅

Listen to changes matching a filter:
bash
undefined
监听符合过滤条件的变更:
bash
undefined

Only listen to changes where status = 'active'

仅监听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" }'
undefined
SUB_MESSAGE='{ "topic": "realtime:public:users", "event": "phx_join", "payload": { "config": { "postgres_changes": [ { "event": "*", "schema": "public", "table": "users", "filter": "status=eq.active" } ] } }, "ref": "1" }'
undefined

Broadcast Messaging

广播消息

Send Broadcast Message

发送广播消息

Broadcast a message to a channel:
bash
#!/bin/bash

SUPABASE_URL="https://your-project.supabase.co"
SUPABASE_KEY="your-anon-key"
WS_URL=$(echo "$SUPABASE_URL" | sed 's/https:/wss:/')
向频道广播消息:
bash
#!/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" }'
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" }'
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"
undefined
{ echo "$JOIN_MESSAGE" sleep 1 echo "$BROADCAST_MESSAGE" } | websocat "${WS_URL}/realtime/v1/websocket?apikey=${SUPABASE_KEY}&vsn=1.0.0"
undefined

Listen to Broadcast Messages

监听广播消息

Receive broadcast messages:
bash
undefined
接收广播消息:
bash
undefined

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"
undefined
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"
undefined

Presence Tracking

在线状态追踪

Track Presence

追踪在线状态

Join channel with presence:
bash
PRESENCE_MESSAGE='{
  "topic": "realtime:lobby",
  "event": "phx_join",
  "payload": {
    "config": {
      "presence": {
        "key": "user-123"
      }
    }
  },
  "ref": "1"
}'
加入带在线状态追踪的频道:
bash
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" }'
undefined
TRACK_MESSAGE='{ "topic": "realtime:lobby", "event": "presence", "payload": { "type": "presence", "event": "track", "payload": { "user_id": "123", "username": "Alice", "status": "online" } }, "ref": "2" }'
undefined

Untrack Presence

取消在线状态追踪

Leave presence:
bash
UNTRACK_MESSAGE='{
  "topic": "realtime:lobby",
  "event": "presence",
  "payload": {
    "type": "presence",
    "event": "untrack"
  },
  "ref": "3"
}'
退出在线状态追踪:
bash
UNTRACK_MESSAGE='{
  "topic": "realtime:lobby",
  "event": "presence",
  "payload": {
    "type": "presence",
    "event": "untrack"
  },
  "ref": "3"
}'

Practical Patterns

实用模式

Continuous Listener Script

持续监听脚本

bash
#!/bin/bash
bash
#!/bin/bash

listen-to-changes.sh

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..."
SUPABASE_URL="https://your-project.supabase.co" SUPABASE_KEY="your-anon-key" WS_URL=$(echo "$SUPABASE_URL" | sed 's/https:/wss:/') TABLE="users"
echo "正在监听$TABLE表的变更..."

Subscribe to changes

订阅变更

SUB_MESSAGE='{ "topic": "realtime:public:'"$TABLE"'", "event": "phx_join", "payload": { "config": { "postgres_changes": [ { "event": "*", "schema": "public", "table": "'"$TABLE"'" } ] } }, "ref": "1" }'
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
undefined
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
undefined

Process Changes with Handler

使用处理器处理变更

bash
#!/bin/bash
bash
#!/bin/bash

process-changes.sh

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' }
handle_insert() { local record="$1" echo "插入新记录:" echo "$record" | jq '.payload.record'
# 此处添加自定义逻辑
# 示例:发送通知、更新缓存等
}
handle_update() { local old_record="$1" local new_record="$2" echo "记录已更新:" echo "旧记录:$(echo "$old_record" | jq -c '.')" echo "新记录:$(echo "$new_record" | jq -c '.')" }
handle_delete() { local record="$1" echo "记录已删除:" 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
undefined
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
undefined

Multi-Table Listener

多表监听脚本

bash
#!/bin/bash
bash
#!/bin/bash

listen-multiple-tables.sh

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
undefined
TABLES=("users" "posts" "comments")
for table in "${TABLES[@]}"; do ( echo "开始监听$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
undefined

Message Format

消息格式

Subscription Confirmation

订阅确认

json
{
  "event": "phx_reply",
  "payload": {
    "response": {
      "postgres_changes": [
        {
          "id": "12345",
          "event": "*",
          "schema": "public",
          "table": "users"
        }
      ]
    },
    "status": "ok"
  },
  "ref": "1",
  "topic": "realtime:public:users"
}
json
{
  "event": "phx_reply",
  "payload": {
    "response": {
      "postgres_changes": [
        {
          "id": "12345",
          "event": "*",
          "schema": "public",
          "table": "users"
        }
      ]
    },
    "status": "ok"
  },
  "ref": "1",
  "topic": "realtime:public:users"
}

INSERT Event

INSERT事件

json
{
  "event": "postgres_changes",
  "payload": {
    "data": {
      "commit_timestamp": "2023-01-01T12:00:00Z",
      "record": {
        "id": 123,
        "name": "John Doe",
        "email": "john@example.com"
      },
      "schema": "public",
      "table": "users",
      "type": "INSERT"
    },
    "ids": [12345]
  },
  "topic": "realtime:public:users"
}
json
{
  "event": "postgres_changes",
  "payload": {
    "data": {
      "commit_timestamp": "2023-01-01T12:00:00Z",
      "record": {
        "id": 123,
        "name": "John Doe",
        "email": "john@example.com"
      },
      "schema": "public",
      "table": "users",
      "type": "INSERT"
    },
    "ids": [12345]
  },
  "topic": "realtime:public:users"
}

UPDATE Event

UPDATE事件

json
{
  "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"
    }
  }
}
json
{
  "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

DELETE事件

json
{
  "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"
    }
  }
}
json
{
  "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"
    }
  }
}

Alternative: REST Polling

替代方案:REST轮询

For simpler use cases where WebSockets are impractical, consider polling:
bash
#!/bin/bash
对于WebSocket不适用的简单场景,可以考虑轮询:
bash
#!/bin/bash

poll-changes.sh

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
undefined
source "$(dirname "${BASH_SOURCE[0]}")/../../scripts/supabase-api.sh"
LAST_TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
while true; do # 获取自上次检查以来创建/更新的记录 new_records=$(supabase_get "/rest/v1/users?updated_at=gt.${LAST_TIMESTAMP}&order=updated_at.asc")
if [[ "$new_records" != "[]" ]]; then
    echo "检测到新变更:"
    echo "$new_records" | jq '.'

    # 更新时间戳
    LAST_TIMESTAMP=$(echo "$new_records" | jq -r '.[-1].updated_at')
fi

# 每5秒轮询一次
sleep 5
done
undefined

Realtime Configuration

Realtime配置

Enable Realtime in Supabase Dashboard:
  1. Go to Database > Replication
  2. Enable replication for tables you want to listen to
  3. Choose which events to publish (INSERT, UPDATE, DELETE)
Row Level Security: Realtime respects RLS policies. Users only receive changes for rows they have access to.
在Supabase控制台中启用Realtime:
  1. 进入数据库 > 复制
  2. 为需要监听的表启用复制功能
  3. 选择要发布的事件(INSERT、UPDATE、DELETE)
行级安全性: Realtime会遵循RLS策略。用户只会收到他们有权访问的行的变更。

Limitations

限制

  • WebSocket connections require persistent connection management
  • Bash is not ideal for WebSocket handling (consider Node.js/Python for production)
  • Connection drops require reconnection logic
  • Realtime is subject to connection limits based on your Supabase plan
  • WebSocket连接需要持久连接管理
  • Bash并非处理WebSocket的理想选择(生产环境建议使用Node.js/Python)
  • 连接断开需要重连逻辑
  • Realtime的连接数量受限于你的Supabase套餐

Use Cases

使用场景

Good for Realtime in bash:
  • Development/debugging tools
  • Simple monitoring scripts
  • Log streaming
  • Testing realtime functionality
Better in other languages:
  • Production chat applications
  • Complex presence tracking
  • Multi-channel coordination
  • Auto-reconnection requirements
适合在bash中使用Realtime的场景:
  • 开发/调试工具
  • 简单监控脚本
  • 日志流
  • 测试实时功能
更适合其他语言的场景:
  • 生产环境聊天应用
  • 复杂在线状态追踪
  • 多频道协调
  • 自动重连需求

API Documentation

API文档

Full Supabase Realtime documentation: https://supabase.com/docs/guides/realtime
完整的Supabase Realtime文档:https://supabase.com/docs/guides/realtime