Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 12 additions & 89 deletions apps/docs/content/guides/functions/websockets.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ subtitle: 'How to handle WebSocket connections in Edge Functions'

Edge Functions supports hosting WebSocket servers that can facilitate bi-directional communications with browser clients.

You can also establish outgoing WebSocket client connections to another server from Edge Functions (e.g., [OpenAI Realtime API](https://platform.openai.com/docs/guides/realtime/overview)).
You can also establish outgoing WebSocket client connections to another server from Edge Functions (e.g., [OpenAI Realtime API](https://platform.openai.com/docs/guides/realtime/overview)). You can find an example OpenAI Realtime Relay Server implementation on the [supabase-community GitHub account](https://github.com/supabase-community/openai-realtime-console?tab=readme-ov-file#using-supabase-edge-functions-as-a-relay-server).

### Writing a WebSocket server

Expand Down Expand Up @@ -92,94 +92,17 @@ server.listen(8080);

You can also establish an outbound WebSocket connection to another server from an Edge Function.

Combining it with incoming WebSocket servers, it's possible to use Edge Functions as a WebSocket proxy.

Here is an example of proxying messages to OpenAI Realtime API.

We use [Supabase Auth](/docs/guides/functions/auth#fetching-the-user) to authenticate the user who is sending the messages.

```ts
import { createClient } from 'jsr:@supabase/supabase-js@2'

const supabase = createClient(
Deno.env.get('SUPABASE_URL'),
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')
)
const OPENAI_API_KEY = Deno.env.get('OPENAI_API_KEY')

Deno.serve(async (req) => {
const upgrade = req.headers.get('upgrade') || ''

if (upgrade.toLowerCase() != 'websocket') {
return new Response("request isn't trying to upgrade to websocket.")
}

// WebSocket browser clients does not support sending custom headers.
// We have to use the URL query params to provide user's JWT.
// Please be aware query params may be logged in some logging systems.
const url = new URL(req.url)
const jwt = url.searchParams.get('jwt')
if (!jwt) {
console.error('Auth token not provided')
return new Response('Auth token not provided', { status: 403 })
}
const { error, data } = await supabase.auth.getUser(jwt)
if (error) {
console.error(error)
return new Response('Invalid token provided', { status: 403 })
}
if (!data.user) {
console.error('user is not authenticated')
return new Response('User is not authenticated', { status: 403 })
}

const { socket, response } = Deno.upgradeWebSocket(req)

socket.onopen = () => {
// initiate an outbound WS connection with OpenAI
const url = 'wss://api.openai.com/v1/realtime?model=gpt-4o-realtime-preview-2024-10-01'

// openai-insecure-api-key isn't a problem since this code runs in an Edge Function (not client browser)
const openaiWS = new WebSocket(url, [
'realtime',
`openai-insecure-api-key.${OPENAI_API_KEY}`,
'openai-beta.realtime-v1',
])

openaiWS.onopen = () => {
console.log('Connected to OpenAI server.')

socket.onmessage = (e) => {
console.log('socket message:', e.data)
// only send the message if openAI ws is open
if (openaiWS.readyState === 1) {
openaiWS.send(e.data)
} else {
socket.send(
JSON.stringify({
type: 'error',
msg: 'openAI connection not ready',
})
)
}
}
}

openaiWS.onmessage = (e) => {
console.log(e.data)
socket.send(e.data)
}

openaiWS.onerror = (e) => console.log('OpenAI error: ', e.message)
openaiWS.onclose = (e) => console.log('OpenAI session closed')
}

socket.onerror = (e) => console.log('socket errored:', e.message)
socket.onclose = () => console.log('socket closed')

return response // 101 (Switching Protocols)
})
```
Combining it with incoming WebSocket servers, it's possible to use Edge Functions as a WebSocket proxy, for example as a [relay server](https://github.com/supabase-community/openai-realtime-console?tab=readme-ov-file#using-supabase-edge-functions-as-a-relay-server) for the [OpenAI Realtime API](https://platform.openai.com/docs/guides/realtime/overview).

<$CodeSample
external={true}
org="supabase-community"
repo="openai-realtime-console"
commit="0f93657a71670704fbf77c48cf54d6c9eb956698"
path="/supabase/functions/relay/index.ts"
meta="supabase/functions/relay/index.ts"
lines={[[1, 3], [5, -1]]}
/>

### Authentication

Expand Down
2 changes: 1 addition & 1 deletion apps/docs/features/directives/CodeSample.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import { z, type SafeParseError } from 'zod'
import { fetchWithNextOptions } from '~/features/helpers.fetch'
import { EXAMPLES_DIRECTORY } from '~/lib/docs'

const ALLOW_LISTED_GITHUB_ORGS = ['supabase'] as [string, ...string[]]
const ALLOW_LISTED_GITHUB_ORGS = ['supabase', 'supabase-community'] as [string, ...string[]]

const linesSchema = z.array(z.tuple([z.coerce.number(), z.coerce.number()]))
const linesValidator = z
Expand Down
1 change: 1 addition & 0 deletions apps/docs/public/humans.txt
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ Terry Sutton
Thomas E
Thor Schaeff
Tom Ashley
Tom G
Tyler Hillery
Tyler Fontaine
Tyler Shukert
Expand Down
116 changes: 29 additions & 87 deletions apps/docs/spec/cli_v1_commands.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
clispec: '001'
info:
id: cli
version: 1.226.3
version: 2.0.0
title: Supabase CLI
language: sh
source: https://github.com/supabase/cli
Expand Down Expand Up @@ -3538,10 +3538,6 @@ commands:
name: --persistent
description: Switch between ephemeral and persistent branch.
default_value: 'false'
- id: reset-on-push
name: --reset-on-push
description: Reset the preview branch on git push.
default_value: 'false'
- id: status
name: --status <string>
description: Override the current branch status.
Expand Down Expand Up @@ -3661,101 +3657,47 @@ commands:
description: Select a region to deploy the branch database.
default_value: ''
accepted_values:
- id: ams
name: ams
type: string
- id: arn
name: arn
type: string
- id: bog
name: bog
type: string
- id: bos
name: bos
type: string
- id: cdg
name: cdg
type: string
- id: den
name: den
type: string
- id: dfw
name: dfw
type: string
- id: ewr
name: ewr
type: string
- id: fra
name: fra
type: string
- id: gdl
name: gdl
type: string
- id: gig
name: gig
type: string
- id: gru
name: gru
type: string
- id: hkg
name: hkg
type: string
- id: iad
name: iad
type: string
- id: jnb
name: jnb
type: string
- id: lax
name: lax
type: string
- id: lhr
name: lhr
type: string
- id: maa
name: maa
type: string
- id: mad
name: mad
- id: ap-northeast-1
name: ap-northeast-1
type: string
- id: mia
name: mia
- id: ap-northeast-2
name: ap-northeast-2
type: string
- id: nrt
name: nrt
- id: ap-south-1
name: ap-south-1
type: string
- id: ord
name: ord
- id: ap-southeast-1
name: ap-southeast-1
type: string
- id: otp
name: otp
- id: ap-southeast-2
name: ap-southeast-2
type: string
- id: qro
name: qro
- id: ca-central-1
name: ca-central-1
type: string
- id: scl
name: scl
- id: eu-central-1
name: eu-central-1
type: string
- id: sea
name: sea
- id: eu-west-1
name: eu-west-1
type: string
- id: sin
name: sin
- id: eu-west-2
name: eu-west-2
type: string
- id: sjc
name: sjc
- id: eu-west-3
name: eu-west-3
type: string
- id: syd
name: syd
- id: sa-east-1
name: sa-east-1
type: string
- id: waw
name: waw
- id: us-east-1
name: us-east-1
type: string
- id: yul
name: yul
- id: us-west-1
name: us-west-1
type: string
- id: yyz
name: yyz
- id: us-west-2
name: us-west-2
type: string
- id: size
name: --size <string>
Expand Down
Loading
Loading