Home / Function/ useRealtimeMessages() — supabase Function Reference

useRealtimeMessages() — supabase Function Reference

Architecture documentation for the useRealtimeMessages() function in useRealtimeMessages.ts from the supabase codebase.

Entity Profile

Dependency Diagram

graph TD
  c8fd8f5d_3794_25bb_3a1b_7311d9193c3d["useRealtimeMessages()"]
  97dac308_a02e_eb43_e60c_49554d27e205["RealtimeInspector()"]
  97dac308_a02e_eb43_e60c_49554d27e205 -->|calls| c8fd8f5d_3794_25bb_3a1b_7311d9193c3d
  style c8fd8f5d_3794_25bb_3a1b_7311d9193c3d fill:#6366f1,stroke:#818cf8,color:#fff

Relationship Graph

Source Code

apps/studio/components/interfaces/Realtime/Inspector/useRealtimeMessages.ts lines 57–241

export const useRealtimeMessages = (
  config: RealtimeConfig,
  setRealtimeConfig: Dispatch<SetStateAction<RealtimeConfig>>
) => {
  const {
    enabled,
    channelName,
    projectRef,
    logLevel,
    token,
    schema,
    table,
    isChannelPrivate,
    filter,
    bearer,
    enablePresence,
    enableDbChanges,
    enableBroadcast,
  } = config

  const { data: settings } = useProjectSettingsV2Query({ projectRef: projectRef })

  const protocol = settings?.app_config?.protocol ?? 'https'
  const endpoint = settings?.app_config?.endpoint
  // the default host is prod until the correct one comes through an API call.
  const host = settings ? `${protocol}://${endpoint}` : `https://${projectRef}.supabase.co`

  const realtimeUrl = `${host}/realtime/v1`.replace(/^http/i, 'ws')

  const [logData, dispatch] = useReducer(reducer, [] as LogData[])
  const pushMessage = (messageType: string, metadata: any) => {
    dispatch({ type: 'add', payload: { messageType, metadata } })
  }

  // Instantiate our client with the Realtime server and params to connect with
  let [client, setClient] = useState<RealtimeClient>()
  let [channel, setChannel] = useState<RealtimeChannel | undefined>()

  const roleImpersonationState = useRoleImpersonationStateSnapshot()

  useEffect(() => {
    if (!enabled) {
      return
    }

    const options = {
      vsn: '2.0.0',
      headers: DEFAULT_HEADERS,
      params: { apikey: token, log_level: logLevel },
    }
    const realtimeClient = new RealtimeClient(realtimeUrl, options)

    if (bearer) {
      realtimeClient.setAuth(bearer)
    }

    setClient(realtimeClient)
    return () => {
      realtimeClient.disconnect()
      setClient(undefined)
    }
  }, [enabled, bearer, host, logLevel, token])

  useEffect(() => {
    if (!client) {
      return
    }
    dispatch({ type: 'clear' })
    const newChannel = client?.channel(channelName, {
      config: { broadcast: { self: true }, private: isChannelPrivate },
    })
    // Hack to confirm Postgres is subscribed
    // Need to add 'extension' key in the 'payload'
    newChannel.on('system' as any, {} as any, (payload: any) => {
      pushMessage('SYSTEM', payload)
    })

    if (enableBroadcast) {
      // Listen for all (`*`) `broadcast` messages
      // The message name can by anything
      // Match on specific message names to filter for only those types of messages and do something with them
      newChannel.on('broadcast', { event: '*' }, (payload) => pushMessage('BROADCAST', payload))
    }

    // Listen for all (`*`) `presence` messages
    if (enablePresence) {
      newChannel.on('presence' as any, { event: '*' }, (payload) => {
        pushMessage('PRESENCE', payload)
      })
    }

    if (enableDbChanges) {
      let postgres_changes_opts: any = {
        event: '*',
        schema: schema,
        table: table,
        filter: undefined,
      }
      if (filter !== '') {
        postgres_changes_opts.filter = filter
      }
      newChannel.on('postgres_changes' as any, postgres_changes_opts, (payload: any) => {
        let ts = performance.now() + performance.timeOrigin
        let payload_ts = Date.parse(payload.commit_timestamp)
        let latency = ts - payload_ts
        pushMessage('POSTGRES', { ...payload, latency })
      })
    }

    // Finally, subscribe to the Channel we just setup
    newChannel.subscribe(async (status, err) => {
      if (status === 'SUBSCRIBED') {
        // Let LiveView know we connected so we can update the button text
        // pushMessageTo('#conn_info', 'broadcast_subscribed', { host: host })

        const role = roleImpersonationState.role?.role
        const computedRole =
          role === undefined
            ? 'service_role_'
            : role === 'anon'
              ? 'anon_role_'
              : role === 'authenticated'
                ? 'authenticated_role_'
                : 'user_name_'

        if (enablePresence) {
          const name = computedRole + Math.floor(Math.random() * 100)
          newChannel.send({
            type: 'presence',
            event: 'TRACK',
            payload: { name: name, t: performance.now() },
          })
        }
      } else if (status === 'CHANNEL_ERROR') {
        if (err?.message) {
          toast.error(`Failed to connect with the following error: ${err.message}`)
        } else {
          toast.error(`Failed to connect. Please check your RLS policies and try again.`)
        }

        newChannel.unsubscribe()
        setChannel(undefined)
        setRealtimeConfig({ ...config, channelName: '', enabled: false })
      }
    })

    setChannel(newChannel)
    return () => {
      newChannel.unsubscribe()
      setChannel(undefined)
    }
  }, [
    client,
    channelName,
    enableBroadcast,
    enableDbChanges,
    enablePresence,
    filter,
    host,
    schema,
    table,
  ])

  const sendMessage = useCallback(
    async (message: string, payload: any, callback: () => void) => {
      if (channel) {
        const res = await channel.send({
          type: 'broadcast',
          event: message,
          payload,
        })
        if (res === 'error') {
          toast.error('Failed to broadcast message')
        } else {
          toast.success('Successfully broadcasted message')
          callback()
        }
      } else {
        toast.error('Failed to broadcast message: channel has not been set')
      }
    },
    [channel]
  )
  return { logData, sendMessage }
}

Subdomains

Frequently Asked Questions

What does useRealtimeMessages() do?
useRealtimeMessages() is a function in the supabase codebase.
What calls useRealtimeMessages()?
useRealtimeMessages() is called by 1 function(s): RealtimeInspector.

Analyze Your Own Codebase

Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.

Try Supermodel Free