Merge branch 'master' of github.com:supabase/supabase

This commit is contained in:
Terry Sutton committed 2024-12-03 14:33:48 -03:30
commit b65fa37ec3
34 files changed
+537 -435

No files matched your search

@@ -32,6 +32,10 @@ const formatTOCHeader = (content: string) => {
begin = false
res.push(`</code>`)
}
} else if (x === '<') {
res.push('&lt')
} else if (x === '>') {
res.push('&gt')
} else {
res.push(x)
}
+42
View File
@@ -586,12 +586,53 @@ parameters:
tags: ['storage']
required: false
default: '"50MiB"'
description: |
The maximum file size allowed for all buckets in the project.
links:
- name: 'Storage server configuration'
link: 'https://supabase.com/docs/guides/self-hosting/storage/config'
- id: 'storage.buckets.bucket_name.public'
title: 'storage.buckets.<bucket_name>.public'
tags: ['storage']
required: false
default: 'false'
description: |
Enable public access to the bucket.
links:
- name: 'Storage server configuration'
link: 'https://supabase.com/docs/guides/self-hosting/storage/config'
- id: 'storage.buckets.bucket_name.file_size_limit'
title: 'storage.buckets.<bucket_name>.file_size_limit'
tags: ['storage']
required: false
description: |
The maximum file size allowed (e.g. "5MB", "500KB").
links:
- name: 'Storage server configuration'
link: 'https://supabase.com/docs/guides/self-hosting/storage/config'
- id: 'storage.buckets.bucket_name.allowed_mime_types'
title: 'storage.buckets.<bucket_name>.allowed_mime_types'
tags: ['storage']
required: false
description: |
The list of allowed MIME types for objects in the bucket.
links:
- name: 'Storage server configuration'
link: 'https://supabase.com/docs/guides/self-hosting/storage/config'
- id: 'storage.buckets.bucket_name.objects_path'
title: 'storage.buckets.<bucket_name>.objects_path'
tags: ['storage']
required: false
description: |
The local directory to upload objects to the bucket.
links:
- name: 'Storage server configuration'
link: 'https://supabase.com/docs/guides/self-hosting/storage/config'
- id: 'auth.enabled'
title: 'auth.enabled'
tags: ['auth']
@@ -1176,6 +1217,7 @@ parameters:
required: false
description: |
Specify the Deno import map file to use for the Function.
When not specified, defaults to `supabase/functions/<function_name>/deno.json`.
Note that the `--import-map` flag overrides this configuration.
links:
@@ -10,6 +10,7 @@ tags:
- supabase-engineering
date: '2024-12-01'
toc_depth: 3
launchweek: '13'
---
# OrioleDB Public Alpha
@@ -12,6 +12,7 @@ tags:
- postgres
date: '2024-12-02'
toc_depth: 3
launchweek: '13'
---
Today we are releasing Supabase Assistant v2 in the Dashboard - a global assistant with several new abilities:
@@ -0,0 +1,276 @@
---
title: 'Supabase Edge Functions: Introducing Background Tasks, Ephemeral Storage, and WebSockets'
description: Edge functions can be used for workloads outside the request-response lifecycle
author: laktek,nyannyacha
image: launch-week-13/day-2-functions-background-tasks/og.jpg
thumb: launch-week-13/day-2-functions-background-tasks/thumb.jpg
categories:
- product
tags:
- functions
- launch-week
date: '2024-12-03'
toc_depth: 3
launchweek: '13'
---
We are excited to announce three long-awaited features: Background Tasks, Ephemeral File Storage, and WebSockets.
Starting today, you can use these features in any project. Let's explore what exciting things you can build with them.
<div className="video-container">
<iframe
className="w-full"
src="https://www.youtube-nocookie.com/embed/envrsJ8VfAU"
title="Introducing Background Tasks, Ephemeral Storage, and WebSockets"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; gyroscope; picture-in-picture; web-share"
allowfullscreen
/>
</div>
## Background Tasks
Sometimes you need a backend logic to do more than respond to a request. For example, you might want to process a batch of files and upload the results to Supabase Storage. Or read multiple entries from a database table and generate embeddings for each entry.
With the introduction of background tasks, executing these long-running workloads with Edge Functions is super easy.
We've introduced a new method called `EdgeRuntime.waitUntil` , which accepts a promise. This ensures that the function isn't terminated until the promise is resolved.
Free projects can run background tasks for a maximum of 150 seconds (2m 30s). If you are on a paid plan, this limit increases to 400 seconds (6m 40s). We plan to introduce more flexible limits in the coming months.
You can subscribe to notifications when the function is about to be shut down by listening to `beforeunload` event. Read the guide for more details on [how to use background tasks](/docs/guides/functions/background-tasks).
## Ephemeral Storage
Edge Function invocations now have access to ephemeral storage. This is useful for background tasks, as it allows you to read and write files in the `/tmp` directory to store intermediate results.
Check the guide on how to access [ephemeral storage](/docs/guides/functions/ephemeral-storage).
### Example: Extracting a zip file and uploading its content to Supabase Storage
Let's look at a real-world example using Background Tasks and Ephemeral Storage.
Imagine you're building a Photo Album app. You want your users to upload photos as a zip file. You would extract them in an Edge Function and upload them to storage.
One of the most straightforward ways to implement is using streams:
```jsx
import { ZipReaderStream } from 'https://deno.land/x/zipjs/index.js'
import { createClient } from 'jsr:@supabase/supabase-js@2'
const supabase = createClient(
Deno.env.get('SUPABASE_URL'),
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')
)
Deno.serve(async (req) => {
const uploadId = crypto.randomUUID()
const { error } = await supabase.storage.createBucket(uploadId, {
public: false,
})
for await (const entry of await req.body.pipeThrough(new ZipReaderStream())) {
// write file to Supabase Storage
const { error } = await supabase.storage
.from(uploadId)
.upload(entry.filename, entry.readable, {})
console.log('uploaded', entry.filename)
}
return new Response(
JSON.stringify({
uploadId,
}),
{
headers: {
'content-type': 'application/json',
},
}
)
})
```
If you test out the streaming version, it will run into memory limit errors when you try to upload zip files over 100MB. This is because the streaming version has to keep every file in a zip archive in memory.
We can modify it instead to write the zip file to a temporary file. Then, use a background task to extract and upload it to Supabase Storage. This way, we only read parts of the zip file to the memory.
```jsx
import { BlobWriter, ZipReader, ZipReaderStream } from 'https://deno.land/x/zipjs/index.js'
import { createClient } from 'jsr:@supabase/supabase-js@2'
const supabase = createClient(
Deno.env.get('SUPABASE_URL'),
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')
)
let numFilesUploaded = 0
async function processZipFile(uploadId, filepath) {
const file = await Deno.open(filepath, { read: true })
const zipReader = new ZipReader(file.readable)
const entries = await zipReader.getEntries()
await supabase.storage.createBucket(uploadId, {
public: false,
})
await Promise.all(
entries.map(async (entry) => {
// read file entry
const blobWriter = new BlobWriter()
const blob = await entry.getData(blobWriter)
if (entry.directory) {
return
}
// write file to Supabase Storage
await supabase.storage.from(uploadId).upload(entry.filename, blob, {})
numFilesUploaded += 1
console.log('uploaded', entry.filename)
})
)
await zipReader.close()
}
// you can add a `beforeunload` event listener to be notified
// when Function Worker is about to terminate.
// use this to do any logging, save states.
globalThis.addEventListener('beforeunload', (ev) => {
console.log('function about to terminate: ', ev.detail.reason)
console.log('number of files uploaded: ', numFilesUploaded)
})
async function writeZipFile(filepath, stream) {
await Deno.writeFile(filepath, stream)
}
Deno.serve(async (req) => {
const uploadId = crypto.randomUUID()
await writeZipFile('/tmp/' + uploadId, req.body)
// process zip file in a background task
// calling EdgeRuntime.waitUntil() would ensure
// function worker wouldn't exit until the promise is completed.
EdgeRuntime.waitUntil(processZipFile(uploadId, '/tmp/' + uploadId))
return new Response(
JSON.stringify({
uploadId,
}),
{
headers: {
'content-type': 'application/json',
},
}
)
})
```
## WebSockets
Edge Functions now support establishing both inbound (server) and outbound (client) WebSocket connections. This enables a variety of new use cases.
### Example: Building an authenticated relay to OpenAI Realtime API
OpenAI recently introduced a [Realtime API](https://openai.com/index/introducing-the-realtime-api/), which uses WebSockets. This is tricky to implement purely client-side because you'd need to expose your OpenAI key publicly. OpenAI [recommends](https://platform.openai.com/docs/guides/realtime/overview?text-generation-quickstart-example=audio) building a server to authenticate requests.
With our new support for WebSockets, you can easily do this in Edge Functions without standing up any infrastructure. Additionally, you can use [Supabase Auth](https://supabase.com/docs/guides/auth) to authenticate users and protect your OpenAI usage from being abused.
```jsx
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 WebSocket connection to 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
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)
})
```
## Performance and stability
In the past few months, we have made many [performance, stability,](https://supabase.com/blog/edge-functions-faster-smaller) and [DX improvements](https://github.com/orgs/supabase/discussions/30307) to Edge Functions. While these improvements often aren't visible to the end-users, they are the foundation of the new features we are announcing today.
## What's next?
We have a very exciting roadmap planned for 2025. One of the main priorities is to provide customizable compute limits (memory, CPU, and execution duration). We will soon announce an update on it.
Stay tuned for the upcoming launches this week. You will see how all these upcoming pieces fit like Lego bricks to make your developer life easy.
+3 -3
View File
@@ -25,9 +25,9 @@ const Hero = () => {
<div className="flex flex-col items-center">
<div className="z-40 w-full flex justify-center -mt-4 lg:-mt-12 mb-8">
<AnnouncementBadge
url="/launch-week#day-1"
badge="Launch Week 13"
announcement="Day 1: AI Assistant v2"
url="/launch-week#day-2"
badge="LW13: Day 2"
announcement="Background Tasks and WebSockets"
/>
</div>
<h1 className="text-foreground text-4xl sm:text-5xl sm:leading-none lg:text-7xl">
@@ -9,7 +9,7 @@ const LW11Summary = () => {
<div className="w-full border bg-alternative-200 flex flex-col rounded-lg text-foreground-lighter mt-12">
<div className="w-full p-4 flex justify-between items-center">
<Link
href="/launch-week"
href="/launch-week/12"
className="flex items-center text-foreground font-medium gap-1.5 leading-none uppercase text-xs opacity-80 transition-opacity hover:opacity-100"
>
Launch Week
@@ -79,7 +79,7 @@ const LWXStickyNav: FC = () => {
<li>
<Link
href="#build-stage"
className="p-1 transition-colors hover:text-foreground pointer-events-auto"
className="p-1 transition-colors hover:text-foreground pointer-events-auto lw-sticky-nav"
>
Build <span className="hidden sm:inline">Stage</span>
</Link>
@@ -0,0 +1,77 @@
import React from 'react'
import Link from 'next/link'
import { buildDays, mainDays } from './data'
const LW13Summary = () => {
const days = mainDays()
return (
<div className="w-full border bg-alternative-200 flex flex-col rounded-lg text-foreground-lighter mt-12">
<div className="w-full p-4 flex justify-between items-center">
<Link
href="/launch-week"
className="flex items-center text-foreground font-medium gap-1.5 leading-none uppercase text-xs opacity-80 transition-opacity hover:opacity-100"
>
Launch Week
<span className="font-mono">13</span>
</Link>
<div className="font-mono uppercase tracking-wide text-xs">2-6 December 24</div>
</div>
<div className="pb-4 border-t p-4">
<ul className="flex flex-col gap-2">
{days.map(
(day, i: number) =>
day.shipped && (
<ol key={day.id}>
<Link href={day.blog} className="group flex py-1 gap-2 hover:text-foreground">
<span className="shrink-0 text-sm font-mono uppercase leading-6">
Day {i + 1} -
</span>
<span className="leading-6">{day.title}</span>
</Link>
</ol>
)
)}
</ul>
</div>
<div className="w-[calc(100%+2px)] bg-surface-100 flex flex-col gap-2 -m-px border rounded-lg">
<div className="p-4">
<div className="font-mono uppercase text-xs text-foreground tracking-wide">
Build Stage
</div>
<ul className="flex flex-col gap-2 mt-4">
{buildDays.map(
(day, i: number) =>
day.is_shipped && (
<ol key={day.id}>
<Link
href={day.links[0].url}
className="relative flex items-center justify-between group w-full py-1 hover:text-foreground"
>
<span className="relative">
<span className="font-mono uppercase mr-2">
{i + 1 < 10 ? '0' : ''}
{i + 1} -
</span>
{day.title}
</span>
</Link>
</ol>
)
)}
<ol className="border-t pt-4 mt-2">
<Link
href="/events?category=meetup"
className="relative flex items-center justify-between group w-full py-1 hover:text-foreground"
>
Community Meetups
</Link>
</ol>
</ul>
</div>
</div>
</div>
)
}
export default LW13Summary
@@ -25,11 +25,15 @@ export interface AdventLink {
export const days: AdventDay[] = [
{
title: 'OrioleDB Public Alpha',
description: 'Postgres storage extension with better performance over default Heap storage',
description: 'Launching OrioleDB Public Alpha',
id: 'orioledb',
is_shipped: true,
links: [
{ url: 'https://supabase.com/blog/orioledb-launch', label: 'Blog post', target: '_blank' },
{
url: '/blog/orioledb-launch',
label: 'Blog post',
target: '_blank',
},
],
icon: (
<svg
@@ -62,7 +62,7 @@ const days: (isDark?: boolean) => WeekDayProps[] = (isDark = true) => [
d: 1,
dd: 'Mon',
shipped: true,
isToday: true,
isToday: false,
blog: '/blog/supabase-ai-assistant-v2',
hasCountdown: false,
date: '2 December',
@@ -76,7 +76,7 @@ const days: (isDark?: boolean) => WeekDayProps[] = (isDark = true) => [
},
{
type: 'xSpace',
href: 'https://twitter.com/i/spaces/1OyKAZyeQyWGb ',
href: 'https://twitter.com/i/spaces/1OyKAZyeQyWGb',
},
],
steps: [
@@ -99,25 +99,43 @@ const days: (isDark?: boolean) => WeekDayProps[] = (isDark = true) => [
id: 'day-2',
d: 2,
dd: 'Tue',
shipped: false,
isToday: false,
hasCountdown: true,
blog: '',
shipped: true,
isToday: true,
hasCountdown: false,
blog: '/blog/edge-functions-background-tasks-websockets',
date: '3 December',
published_at: '2024-12-03T08:00:00.000-07:00',
title: '',
description: null,
title: 'Supabase Functions: Background Tasks and WebSockets',
description: (
<>
Supabase Functions: <br className="hidden sm:block" /> Background Tasks and WebSockets
</>
),
links: [
// {
// type: 'video',
// href: '',
// },
{
type: 'video',
href: 'envrsJ8VfAU',
},
{
type: 'xSpace',
href: 'https://twitter.com/i/spaces/1yoJMyjzVWRJQ',
},
],
steps: [],
steps: [
{
title: '',
bg_layers: [
{
img: '/images/launchweek/13/releases/d2/d2-functions-background-tasks-dark.png',
mobileImg:
'/images/launchweek/13/releases/d2/d2-functions-background-tasks-mobile-dark.png',
imgLight: '/images/launchweek/13/releases/d2/d2-functions-background-tasks-light.png',
mobileImgLight:
'/images/launchweek/13/releases/d2/d2-functions-background-tasks-mobile-light.png',
},
],
},
],
},
{
id: 'day-3',
@@ -125,7 +143,7 @@ const days: (isDark?: boolean) => WeekDayProps[] = (isDark = true) => [
dd: 'Wed',
shipped: false,
isToday: false,
hasCountdown: false,
hasCountdown: true,
blog: '',
date: '4 December',
published_at: '2024-12-04T08:00:00.000-07:00',
@@ -150,8 +150,8 @@ const ThreeTicketCanvas: React.FC<{
bumpMap: IS_SECRET ? goldTexture : IS_PLATINUM ? metalTexture : undefined,
metalnessMap: IS_SECRET ? goldTexture : metalTexture,
// roughnessMap: IS_SECRET ? goldTexture : metalTexture,
metalness: IS_SECRET ? 0.8 : IS_PLATINUM ? 0.8 : isDarkTheme ? 0.2 : 0.9,
roughness: IS_SECRET ? 0.12 : IS_PLATINUM ? 0.12 : isDarkTheme ? 0.2 : 0.5,
metalness: IS_SECRET ? 0.8 : IS_PLATINUM ? 1.0 : isDarkTheme ? 0.2 : 0.9,
roughness: IS_SECRET ? 0.12 : IS_PLATINUM ? 0.22 : isDarkTheme ? 0.2 : 0.5,
bumpScale: IS_SECRET ? 0.02 : IS_PLATINUM ? 0.0045 : undefined,
})
@@ -293,7 +293,7 @@ const ThreeTicketCanvas: React.FC<{
scene.add(ambientLight)
const spotLight = new THREE.SpotLight(0xffffff, isDarkTheme ? 0.8 : 0.2)
spotLight.position.z = ticketGroup.position.z + 4
spotLight.position.z = ticketGroup.position.z + 8
spotLight.position.x = ticketGroup.position.x + 10
spotLight.angle = (Math.PI / 2) * 0.5
spotLight.castShadow = true
@@ -29,7 +29,7 @@ export default function TicketCopy() {
}, 2000)
})
}}
className="font-mono w-full flex-grow px-2 lg:px-3.5 !pr-1 py-1 rounded-md bg-alternative-200 border flex gap-2 relative text-foreground-light hover:text-foreground text-xs pointer-events-auto justify-between items-center hover:border-stronger transition-all"
className="font-mono w-full flex-grow px-2 lg:px-3.5 !pr-1 py-1 rounded-md bg-alternative-200 border flex gap-2 relative text-foreground-light hover:text-foreground text-xs pointer-events-auto justify-between items-center hover:border-stronger transition-all max-w-[80vw]"
>
<span className="truncate">{displayUrl}</span>
<div className="w-6 min-w-6 h-6 flex items-center justify-center flex-shrink-0 border border-strong rounded bg-muted hover:bg-selection hover:border-stronger">
@@ -109,7 +109,7 @@ const TicketingFlow = () => {
initial={initial}
animate={animate}
exit={exit}
className="w-full max-w-5xl mx-auto lg:min-h-[400px] lg:pl-12 h-full flex flex-col lg:flex-row items-center lg:justify-start gap-8 md:gap-10 lg:gap-32 text-foreground text-center md:text-left"
className="w-full max-w-5xl mx-auto lg:min-h-[400px] xl:pl-8 h-full flex flex-col lg:flex-row items-center lg:justify-start gap-8 md:gap-10 lg:gap-32 text-foreground text-center md:text-left"
>
<div className="order-first lg:h-full w-full max-w-md xl:max-w-2xl gap-8 flex flex-col items-center justify-center lg:items-start lg:justify-center text-center lg:text-left">
<div className="flex flex-col gap-1 max-w-md">
+3
View File
@@ -19,6 +19,7 @@ import ShareArticleActions from '~/components/Blog/ShareArticleActions'
import CTABanner from '~/components/CTABanner'
import LW11Summary from '~/components/LaunchWeek/11/LW11Summary'
import LW12Summary from '~/components/LaunchWeek/12/LWSummary'
import LW13Summary from '~/components/LaunchWeek/13/Releases/LWSummary'
import BlogLinks from '~/components/LaunchWeek/7/BlogLinks'
import LWXSummary from '~/components/LaunchWeek/X/LWXSummary'
import DefaultLayout from '~/components/Layouts/Default'
@@ -129,6 +130,7 @@ function BlogPostPage(props: InferGetStaticPropsType<typeof getStaticProps>) {
const isLaunchWeekX = props.blog.launchweek?.toString().toLocaleLowerCase() === 'x'
const isGAWeek = props.blog.launchweek?.toString().toLocaleLowerCase() === '11'
const isLaunchWeek12 = props.blog.launchweek?.toString().toLocaleLowerCase() === '12'
const isLaunchWeek13 = props.blog.launchweek?.toString().toLocaleLowerCase() === '13'
const author = authorArray
.map((authorId) => {
@@ -341,6 +343,7 @@ function BlogPostPage(props: InferGetStaticPropsType<typeof getStaticProps>) {
{isLaunchWeekX && <LWXSummary />}
{isGAWeek && <LW11Summary />}
{isLaunchWeek12 && <LW12Summary />}
{isLaunchWeek13 && <LW13Summary />}
<div className="block lg:hidden py-8">
<div className="text-foreground-lighter text-sm">Share this article</div>
<ShareArticleActions title={props.blog.title} slug={props.blog.slug} />
Binary file not shown.

Before

Width:  |  Height:  |  Size: 143 KiB

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

+8 -8
View File
@@ -5,22 +5,22 @@
<link>https://supabase.com</link>
<description>Latest news from Supabase</description>
<language>en</language>
<lastBuildDate>Mon, 02 Dec 2024 00:00:00 -0700</lastBuildDate>
<lastBuildDate>Tue, 03 Dec 2024 00:00:00 -0700</lastBuildDate>
<atom:link href="https://supabase.com/rss.xml" rel="self" type="application/rss+xml"/>
<item>
<guid>https://supabase.com/blog/edge-functions-background-tasks-websockets</guid>
<title>Supabase Edge Functions: Introducing Background Tasks, Ephemeral Storage, and WebSockets</title>
<link>https://supabase.com/blog/edge-functions-background-tasks-websockets</link>
<description>Edge functions can be used for workloads outside the request-response lifecycle</description>
<pubDate>Tue, 03 Dec 2024 00:00:00 -0700</pubDate>
</item>
<item>
<guid>https://supabase.com/blog/supabase-ai-assistant-v2</guid>
<title>Supabase AI Assistant v2</title>
<link>https://supabase.com/blog/supabase-ai-assistant-v2</link>
<description>An evolution of how we approach AI within the Supabase dashboard</description>
<pubDate>Mon, 02 Dec 2024 00:00:00 -0700</pubDate>
</item>
<item>
<guid>https://supabase.com/blog/supabase-assistant</guid>
<title>Supabase AI Assistant v2</title>
<link>https://supabase.com/blog/supabase-assistant</link>
<description>An evolution of how we approach AI within the Supabase dashboard</description>
<pubDate>Mon, 02 Dec 2024 00:00:00 -0700</pubDate>
</item>
<item>
<guid>https://supabase.com/blog/orioledb-launch</guid>
<title>OrioleDB Public Alpha</title>
@@ -15,14 +15,9 @@ shadow_port = 54320
# server_version;` on the remote database to check.
major_version = 15
[db.pooler]
[db.seed]
# If enabled, seeds the database after migrations during a db reset.
enabled = false
# Port to use for the local connection pooler.
port = 54329
# Specifies when a server connection can be reused by other clients.
# Configure one of the supported pooler modes: `transaction`, `session`.
pool_mode = "transaction"
# How many server connections to allow per user/database pair.
default_pool_size = 20
# Maximum number of client connections allowed.
max_client_conn = 100
# Specifies an ordered list of seed files to load during db reset.
# Supports glob patterns relative to supabase directory. For example:
# sql_paths = ['./seeds/*.sql', '../project-src/seeds/*-load-testing.sql']
+1 -1
View File
@@ -14,7 +14,7 @@ This demo consists of three parts:
- Link your project: `supabase link`
- Deploy Edge Functions: `supabase functions deploy`
- Enable Database Webhooks in your [project dashboard](https://supabase.com/dashboard/project/_/database/hooks)
- Update project config to [enable webhooks](https://supabase.com/docs/guides/local-development/cli/config#experimental.webhooks.enabled): `supabase config push`
- Navigate to the [database-webhook](./supabase/migrations/20240410041607_database-webhook.sql) migration file and insert your `generate-embedding` function details.
- Push up the database schema `supabase db push`
+22 -133
View File
@@ -7,9 +7,9 @@ enabled = true
# Port to use for the API URL.
port = 54321
# Schemas to expose in your API. Tables, views and stored procedures in this schema will get API
# endpoints. public and storage are always included.
schemas = ["public", "storage", "graphql_public"]
# Extra schemas to add to the search_path of every request. public is always included.
# endpoints. `public` is always included.
schemas = ["public", "graphql_public"]
# Extra schemas to add to the search_path of every request. `public` is always included.
extra_search_path = ["public", "extensions"]
# The maximum number of rows returns from a view, table, or stored procedure. Limits payload size
# for accidental or malicious requests.
@@ -24,140 +24,29 @@ shadow_port = 54320
# server_version;` on the remote database to check.
major_version = 15
[db.pooler]
enabled = false
# Port to use for the local connection pooler.
port = 54329
# Specifies when a server connection can be reused by other clients.
# Configure one of the supported pooler modes: `transaction`, `session`.
pool_mode = "transaction"
# How many server connections to allow per user/database pair.
default_pool_size = 20
# Maximum number of client connections allowed.
max_client_conn = 100
[realtime]
[db.seed]
# If enabled, seeds the database after migrations during a db reset.
enabled = true
# Bind realtime via either IPv4 or IPv6. (default: IPv6)
# ip_version = "IPv6"
# The maximum length in bytes of HTTP request headers. (default: 4096)
# max_header_length = 4096
# Specifies an ordered list of seed files to load during db reset.
# Supports glob patterns relative to supabase directory, ie. './seeds/*.sql'
sql_paths = ['./seed.sql']
[studio]
[functions.generate-embedding]
enabled = true
# Port to use for Supabase Studio.
port = 54323
# External URL of the API server that frontend connects to.
api_url = "http://127.0.0.1"
# OpenAI API Key to use for Supabase AI in the Supabase Studio.
openai_api_key = "env(OPENAI_API_KEY)"
# verify_jwt = true
# import_map = "./functions/generate-embedding/deno.json"
# Uncomment to specify a custom file path to the entrypoint.
# Supported file extensions are: .ts, .js, .mjs, .jsx, .tsx
# entrypoint = "./functions/generate-embedding/index.ts"
# Email testing server. Emails sent with the local dev setup are not actually sent - rather, they
# are monitored, and you can view the emails that would have been sent from the web interface.
[inbucket]
[functions.search]
enabled = true
# Port to use for the email testing server web interface.
port = 54324
# Uncomment to expose additional ports for testing user applications that send emails.
# smtp_port = 54325
# pop3_port = 54326
[storage]
enabled = true
# The maximum file size allowed (e.g. "5MB", "500KB").
file_size_limit = "50MiB"
[auth]
enabled = true
# The base URL of your website. Used as an allow-list for redirects and for constructing URLs used
# in emails.
site_url = "http://127.0.0.1:3000"
# A list of *exact* URLs that auth providers are permitted to redirect to post authentication.
additional_redirect_urls = ["https://127.0.0.1:3000"]
# How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 (1 week).
jwt_expiry = 3600
# If disabled, the refresh token will never expire.
enable_refresh_token_rotation = true
# Allows refresh tokens to be reused after expiry, up to the specified interval in seconds.
# Requires enable_refresh_token_rotation = true.
refresh_token_reuse_interval = 10
# Allow/disallow new user signups to your project.
enable_signup = true
# Allow/disallow anonymous sign-ins to your project.
enable_anonymous_sign_ins = false
# Allow/disallow testing manual linking of accounts
enable_manual_linking = false
[auth.email]
# Allow/disallow new user signups via email to your project.
enable_signup = true
# If enabled, a user will be required to confirm any email change on both the old, and new email
# addresses. If disabled, only the new email is required to confirm.
double_confirm_changes = true
# If enabled, users need to confirm their email address before signing in.
enable_confirmations = false
# Uncomment to customize email template
# [auth.email.template.invite]
# subject = "You have been invited"
# content_path = "./supabase/templates/invite.html"
[auth.sms]
# Allow/disallow new user signups via SMS to your project.
enable_signup = true
# If enabled, users need to confirm their phone number before signing in.
enable_confirmations = false
# Template for sending OTP to users
template = "Your code is {{ .Code }} ."
# Use pre-defined map of phone number to OTP for testing.
[auth.sms.test_otp]
# 4152127777 = "123456"
# This hook runs before a token is issued and allows you to add additional claims based on the authentication method used.
[auth.hook.custom_access_token]
# enabled = true
# uri = "pg-functions://<database>/<schema>/<hook_name>"
# Configure one of the supported SMS providers: `twilio`, `twilio_verify`, `messagebird`, `textlocal`, `vonage`.
[auth.sms.twilio]
enabled = false
account_sid = ""
message_service_sid = ""
# DO NOT commit your Twilio auth token to git. Use environment variable substitution instead:
auth_token = "env(SUPABASE_AUTH_SMS_TWILIO_AUTH_TOKEN)"
# Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`,
# `discord`, `facebook`, `github`, `gitlab`, `google`, `keycloak`, `linkedin_oidc`, `notion`, `twitch`,
# `twitter`, `slack`, `spotify`, `workos`, `zoom`.
[auth.external.apple]
enabled = false
client_id = ""
# DO NOT commit your OAuth provider secret to git. Use environment variable substitution instead:
secret = "env(SUPABASE_AUTH_EXTERNAL_APPLE_SECRET)"
# Overrides the default auth redirectUrl.
redirect_uri = ""
# Overrides the default auth provider URL. Used to support self-hosted gitlab, single-tenant Azure,
# or any other third-party OIDC providers.
url = ""
[analytics]
enabled = false
port = 54327
vector_port = 54328
# Configure one of the supported backends: `postgres`, `bigquery`.
backend = "postgres"
# verify_jwt = true
# import_map = "./functions/search/deno.json"
# Uncomment to specify a custom file path to the entrypoint.
# Supported file extensions are: .ts, .js, .mjs, .jsx, .tsx
# entrypoint = "./functions/search/index.ts"
# Experimental features may be deprecated any time
[experimental]
# Configures Postgres storage engine to use OrioleDB (S3)
orioledb_version = ""
# Configures S3 bucket URL, eg. <bucket_name>.s3-<region>.amazonaws.com
s3_host = "env(S3_HOST)"
# Configures S3 bucket region, eg. us-east-1
s3_region = "env(S3_REGION)"
# Configures AWS_ACCESS_KEY_ID for S3 bucket
s3_access_key = "env(S3_ACCESS_KEY)"
# Configures AWS_SECRET_ACCESS_KEY for S3 bucket
s3_secret_key = "env(S3_SECRET_KEY)"
[experimental.webhooks]
enabled = true
@@ -0,0 +1,4 @@
# Supabase
.branches
.temp
.env
+12 -71
View File
@@ -1,82 +1,23 @@
# A string used to distinguish different Supabase projects on the same host. Defaults to the working
# directory name when running `supabase init`.
project_id = "image_search"
# A string used to distinguish different Supabase projects on the same host. Defaults to the
# working directory name when running `supabase init`.
project_id = "aws_bedrock_image_search"
[api]
# Port to use for the API URL.
port = 54321
# Schemas to expose in your API. Tables, views and stored procedures in this schema will get API
# endpoints. public and storage are always included.
schemas = ["public", "storage", "graphql_public"]
# Extra schemas to add to the search_path of every request. public is always included.
extra_search_path = ["public", "extensions"]
# The maximum number of rows returns from a view, table, or stored procedure. Limits payload size
# for accidental or malicious requests.
max_rows = 1000
# Disable data API since we are not using the PostgREST client in this example.
enabled = false
[db]
# Port to use for the local database URL.
port = 54322
# Port used by db diff command to initialize the shadow database.
shadow_port = 54320
# The database major version to use. This has to be the same as your remote database's. Run `SHOW
# server_version;` on the remote database to check.
major_version = 15
[studio]
# Port to use for Supabase Studio.
port = 54323
# Email testing server. Emails sent with the local dev setup are not actually sent - rather, they
# are monitored, and you can view the emails that would have been sent from the web interface.
[inbucket]
# Port to use for the email testing server web interface.
port = 54324
smtp_port = 54325
pop3_port = 54326
[storage]
# The maximum file size allowed (e.g. "5MB", "500KB").
file_size_limit = "50MiB"
[auth]
# The base URL of your website. Used as an allow-list for redirects and for constructing URLs used
# in emails.
site_url = "http://localhost:3000"
# A list of *exact* URLs that auth providers are permitted to redirect to post authentication.
additional_redirect_urls = ["https://localhost:3000"]
# How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 seconds (one
# week).
jwt_expiry = 3600
# Allow/disallow new user signups to your project.
enable_signup = true
[auth.email]
# Allow/disallow new user signups via email to your project.
enable_signup = true
# If enabled, a user will be required to confirm any email change on both the old, and new email
# addresses. If disabled, only the new email is required to confirm.
double_confirm_changes = true
# If enabled, users need to confirm their email address before signing in.
enable_confirmations = false
# Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`,
# `discord`, `facebook`, `github`, `gitlab`, `google`, `keycloak`, `linkedin`, `notion`, `twitch`,
# `twitter`, `slack`, `spotify`, `workos`, `zoom`.
[auth.external.apple]
[db.seed]
# If enabled, seeds the database after migrations during a db reset.
enabled = false
client_id = ""
secret = ""
# Overrides the default auth redirectUrl.
redirect_uri = ""
# Overrides the default auth provider URL. Used to support self-hosted gitlab, single-tenant Azure,
# or any other third-party OIDC providers.
url = ""
[analytics]
enabled = false
port = 54327
vector_port = 54328
# Setup BigQuery project to enable log viewer on local development stack.
# See: https://logflare.app/guides/bigquery-setup
gcp_project_id = ""
gcp_project_number = ""
gcp_jwt_path = "supabase/gcloud.json"
# Specifies an ordered list of seed files to load during db reset.
# Supports glob patterns relative to supabase directory. For example:
# sql_paths = ['./seeds/*.sql', '../project-src/seeds/*-load-testing.sql']
Whitespace-only changes.
+25 -180
View File
@@ -1,21 +1,9 @@
# A string used to distinguish different Supabase projects on the same host. Defaults to the
# working directory name when running `supabase init`.
project_id = "llamafile-edge"
project_id = "aws_bedrock_image_search"
[api]
enabled = true
# Port to use for the API URL.
port = 54321
# Schemas to expose in your API. Tables, views and stored procedures in this schema will get API
# endpoints. `public` is always included.
schemas = ["public", "graphql_public"]
# Extra schemas to add to the search_path of every request. `public` is always included.
extra_search_path = ["public", "extensions"]
# The maximum number of rows returns from a view, table, or stored procedure. Limits payload size
# for accidental or malicious requests.
max_rows = 1000
[api.tls]
# Disable data API since we are not using the PostgREST client in this example.
enabled = false
[db]
@@ -27,176 +15,33 @@ shadow_port = 54320
# server_version;` on the remote database to check.
major_version = 15
[db.pooler]
[db.seed]
# If enabled, seeds the database after migrations during a db reset.
enabled = false
# Port to use for the local connection pooler.
port = 54329
# Specifies when a server connection can be reused by other clients.
# Configure one of the supported pooler modes: `transaction`, `session`.
pool_mode = "transaction"
# How many server connections to allow per user/database pair.
default_pool_size = 20
# Maximum number of client connections allowed.
max_client_conn = 100
# Specifies an ordered list of seed files to load during db reset.
# Supports glob patterns relative to supabase directory. For example:
# sql_paths = ['./seeds/*.sql', '../project-src/seeds/*-load-testing.sql']
[realtime]
[functions.llamafile]
enabled = true
# Bind realtime via either IPv4 or IPv6. (default: IPv4)
# ip_version = "IPv6"
# The maximum length in bytes of HTTP request headers. (default: 4096)
# max_header_length = 4096
# verify_jwt = true
# import_map = "./functions/llamafile/deno.json"
# Uncomment to specify a custom file path to the entrypoint.
# Supported file extensions are: .ts, .js, .mjs, .jsx, .tsx
# entrypoint = "./functions/llamafile/index.ts"
[studio]
[functions.llamafile-stream]
enabled = true
# Port to use for Supabase Studio.
port = 54323
# External URL of the API server that frontend connects to.
api_url = "http://127.0.0.1"
# OpenAI API Key to use for Supabase AI in the Supabase Studio.
openai_api_key = "env(OPENAI_API_KEY)"
# verify_jwt = true
# import_map = "./functions/llamafile-stream/deno.json"
# Uncomment to specify a custom file path to the entrypoint.
# Supported file extensions are: .ts, .js, .mjs, .jsx, .tsx
# entrypoint = "./functions/llamafile-stream/index.ts"
# Email testing server. Emails sent with the local dev setup are not actually sent - rather, they
# are monitored, and you can view the emails that would have been sent from the web interface.
[inbucket]
[functions.openai-sdk]
enabled = true
# Port to use for the email testing server web interface.
port = 54324
# Uncomment to expose additional ports for testing user applications that send emails.
# smtp_port = 54325
# pop3_port = 54326
[storage]
enabled = true
# The maximum file size allowed (e.g. "5MB", "500KB").
file_size_limit = "50MiB"
[storage.image_transformation]
enabled = true
# Uncomment to configure local storage buckets
# [storage.buckets.images]
# public = false
# file_size_limit = "50MiB"
# allowed_mime_types = ["image/png", "image/jpeg"]
[auth]
enabled = true
# The base URL of your website. Used as an allow-list for redirects and for constructing URLs used
# in emails.
site_url = "http://127.0.0.1:3000"
# A list of *exact* URLs that auth providers are permitted to redirect to post authentication.
additional_redirect_urls = ["https://127.0.0.1:3000"]
# How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 (1 week).
jwt_expiry = 3600
# If disabled, the refresh token will never expire.
enable_refresh_token_rotation = true
# Allows refresh tokens to be reused after expiry, up to the specified interval in seconds.
# Requires enable_refresh_token_rotation = true.
refresh_token_reuse_interval = 10
# Allow/disallow new user signups to your project.
enable_signup = true
# Allow/disallow anonymous sign-ins to your project.
enable_anonymous_sign_ins = false
# Allow/disallow testing manual linking of accounts
enable_manual_linking = false
[auth.email]
# Allow/disallow new user signups via email to your project.
enable_signup = true
# If enabled, a user will be required to confirm any email change on both the old, and new email
# addresses. If disabled, only the new email is required to confirm.
double_confirm_changes = true
# If enabled, users need to confirm their email address before signing in.
enable_confirmations = false
# Controls the minimum amount of time that must pass before sending another signup confirmation or password reset email.
max_frequency = "1s"
# Use a production-ready SMTP server
# [auth.email.smtp]
# host = "smtp.sendgrid.net"
# port = 587
# user = "apikey"
# pass = "env(SENDGRID_API_KEY)"
# admin_email = "admin@email.com"
# sender_name = "Admin"
# Uncomment to customize email template
# [auth.email.template.invite]
# subject = "You have been invited"
# content_path = "./supabase/templates/invite.html"
[auth.sms]
# Allow/disallow new user signups via SMS to your project.
enable_signup = true
# If enabled, users need to confirm their phone number before signing in.
enable_confirmations = false
# Template for sending OTP to users
template = "Your code is {{ .Code }} ."
# Controls the minimum amount of time that must pass before sending another sms otp.
max_frequency = "5s"
# Use pre-defined map of phone number to OTP for testing.
# [auth.sms.test_otp]
# 4152127777 = "123456"
# Configure logged in session timeouts.
# [auth.sessions]
# Force log out after the specified duration.
# timebox = "24h"
# Force log out if the user has been inactive longer than the specified duration.
# inactivity_timeout = "8h"
# This hook runs before a token is issued and allows you to add additional claims based on the authentication method used.
# [auth.hook.custom_access_token]
# enabled = true
# uri = "pg-functions://<database>/<schema>/<hook_name>"
# Configure one of the supported SMS providers: `twilio`, `twilio_verify`, `messagebird`, `textlocal`, `vonage`.
[auth.sms.twilio]
enabled = false
account_sid = ""
message_service_sid = ""
# DO NOT commit your Twilio auth token to git. Use environment variable substitution instead:
auth_token = "env(SUPABASE_AUTH_SMS_TWILIO_AUTH_TOKEN)"
# Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`,
# `discord`, `facebook`, `github`, `gitlab`, `google`, `keycloak`, `linkedin_oidc`, `notion`, `twitch`,
# `twitter`, `slack`, `spotify`, `workos`, `zoom`.
[auth.external.apple]
enabled = false
client_id = ""
# DO NOT commit your OAuth provider secret to git. Use environment variable substitution instead:
secret = "env(SUPABASE_AUTH_EXTERNAL_APPLE_SECRET)"
# Overrides the default auth redirectUrl.
redirect_uri = ""
# Overrides the default auth provider URL. Used to support self-hosted gitlab, single-tenant Azure,
# or any other third-party OIDC providers.
url = ""
# If enabled, the nonce check will be skipped. Required for local sign in with Google auth.
skip_nonce_check = false
[edge_runtime]
enabled = true
# Configure one of the supported request policies: `oneshot`, `per_worker`.
# Use `oneshot` for hot reload, or `per_worker` for load testing.
policy = "oneshot"
inspector_port = 8083
[analytics]
enabled = true
port = 54327
# Configure one of the supported backends: `postgres`, `bigquery`.
backend = "postgres"
# Experimental features may be deprecated any time
[experimental]
# Configures Postgres storage engine to use OrioleDB (S3)
orioledb_version = ""
# Configures S3 bucket URL, eg. <bucket_name>.s3-<region>.amazonaws.com
s3_host = "env(S3_HOST)"
# Configures S3 bucket region, eg. us-east-1
s3_region = "env(S3_REGION)"
# Configures AWS_ACCESS_KEY_ID for S3 bucket
s3_access_key = "env(S3_ACCESS_KEY)"
# Configures AWS_SECRET_ACCESS_KEY for S3 bucket
s3_secret_key = "env(S3_SECRET_KEY)"
# verify_jwt = true
# import_map = "./functions/openai-sdk/deno.json"
# Uncomment to specify a custom file path to the entrypoint.
# Supported file extensions are: .ts, .js, .mjs, .jsx, .tsx
# entrypoint = "./functions/openai-sdk/index.ts"
Whitespace-only changes.
@@ -44,10 +44,10 @@ const PromoToast = () => {
)}
>
<div className="relative z-10 text-foreground-lighter leading-3 flex flex-col font-mono uppercase tracking-wide w-full text-xs">
Launch Week 13: Day 1
{announcement.text}
</div>
<div className="relative z-10 text-foreground uppercase flex flex-col text-xl w-full font-mono -mt-1">
AI Assistant v2
<div className="relative z-10 text-foreground flex flex-col text-xl w-full -mt-1">
Supabase Functions — Background Tasks and WebSockets
</div>
<div className="relative z-10 flex items-center space-x-2 mt-2">
@@ -36,7 +36,9 @@ export function LW13CountdownBanner() {
)}
>
<p className="flex gap-1.5 items-center">{announcement.text}</p>
<div className="hidden sm:block text-foreground-lighter">AI Assistant v2</div>
<div className="hidden sm:block text-foreground-lighter">
Supabase Functions: Background Tasks and WebSockets
</div>
<Button size="tiny" type="default" className="px-2 !leading-none text-xs" asChild>
<Link href={announcement.link}>{announcement.cta}</Link>
</Button>
@@ -1,7 +1,7 @@
{
"show": true,
"text": "Launch Week 13: Day 1",
"text": "Launch Week 13: Day 2",
"launchDate": "2024-12-02T07:00:00.000-08:00",
"link": "/launch-week#day-1",
"link": "/launch-week#day-2",
"cta": "Learn more"
}