diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index fe66ea7fb32..b5d3188a5b3 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -14,7 +14,7 @@ To ensure a positive and inclusive environment, please read our [code of conduc
If you find a bug, please create an Issue and we’ll triage it.
-- Please search [existing Issues](https://github.com/supabase/supabase) before creating a new one.
+- Please search [existing Issues](https://github.com/supabase/supabase/issues) before creating a new one.
- Please include a clear description of the problem along with steps to reproduce it. Exact steps with screenshots and urls really help here.
## Pull Requests
@@ -23,7 +23,7 @@ We actively welcome your Pull Requests! A couple of things to keep in mind befor
- If you’re fixing an Issue, make sure someone else hasn’t already created a PR fixing the same issue. Likewise, make sure to link your PR to the related Issue(s).
- We will always try to accept the first viable PR that resolves the Issue.
-- If you're new, we encourage you to take a look at issues tagged with [good first issue](https://github.com/supabase/supabase/pulls?q=is%3Aopen+is%3Apr+label%3A%22good+first+issue%22).
+- If you're new, we encourage you to take a look at issues tagged with [good first issue](https://github.com/supabase/supabase/labels/good%20first%20issue).
- If you’re submitting a new feature, make sure you have opened a [Discussion](https://github.com/orgs/supabase/discussions/new/choose) to discuss the new feature before opening a PR. We’d love to accept your hard work, but unfortunately if a feature hasn’t gone through a proper design process, your PR will be closed.
- Please use the PR message template and provide detailed context for quicker review. PRs without clear problem statements will be closed.
diff --git a/README.md b/README.md
index a3cd29f08a3..d63f425b65d 100644
--- a/README.md
+++ b/README.md
@@ -111,6 +111,15 @@ Our approach for client libraries is modular. Each sub-library is a standalone i
diff --git a/apps/database-new/package.json b/apps/database-new/package.json
index ea879606f3d..d7ed811868e 100644
--- a/apps/database-new/package.json
+++ b/apps/database-new/package.json
@@ -19,10 +19,10 @@
"common": "*",
"config": "*",
"dayjs": "^1.11.10",
- "eslint-config-next": "^14.1.4",
+ "eslint-config-next": "^14.2.0",
"lodash": "^4.17.21",
"lucide-react": "^0.338.0",
- "next": "^14.1.4",
+ "next": "^14.2.0",
"openai": "^4.20.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/apps/docs/components/Feedback/Feedback.tsx b/apps/docs/components/Feedback/Feedback.tsx
index 0359b20e360..4694e338e20 100644
--- a/apps/docs/components/Feedback/Feedback.tsx
+++ b/apps/docs/components/Feedback/Feedback.tsx
@@ -16,6 +16,7 @@ import { Button, cn } from 'ui'
import { useSendFeedbackMutation } from '~/lib/fetch/feedback'
import { useSendTelemetryEvent } from '~/lib/telemetry'
import { FeedbackModal, type FeedbackFields } from './FeedbackModal'
+import { getSanitizedTabParams } from './Feedback.utils'
const FeedbackButton = forwardRef<
HTMLButtonElement,
@@ -89,7 +90,7 @@ function Feedback() {
vote: response,
page: pathname,
metadata: {
- query: Object.fromEntries(new URLSearchParams(window.location.search).entries()),
+ query: getSanitizedTabParams(),
},
})
if (error) console.error(error)
diff --git a/apps/docs/components/Feedback/Feedback.utils.ts b/apps/docs/components/Feedback/Feedback.utils.ts
new file mode 100644
index 00000000000..bc3683490f0
--- /dev/null
+++ b/apps/docs/components/Feedback/Feedback.utils.ts
@@ -0,0 +1,16 @@
+import { pick } from 'lodash'
+
+/**
+ * Gets the tab selection state from the URL search params.
+ *
+ * Sanitizes by including only those search params that are explicitly marked
+ * as query groups.
+ */
+const getSanitizedTabParams = () => {
+ const searchParams = new URLSearchParams(window.location.search)
+ const queryGroups = searchParams.getAll('queryGroups')
+
+ return pick(Object.fromEntries(searchParams.entries()), queryGroups)
+}
+
+export { getSanitizedTabParams }
diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts
index b80ebbd89e3..bf1e5bda20e 100644
--- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts
+++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts
@@ -112,6 +112,12 @@ export const HOMEPAGE_MENU_ITEMS: HomepageMenuItems = [
href: '/reference/dart/introduction',
level: 'reference_dart',
},
+ {
+ label: 'Swift',
+ icon: 'reference-swift',
+ href: '/reference/swift/introduction',
+ level: 'reference_swift',
+ },
{
label: 'Python',
icon: 'reference-python',
@@ -126,13 +132,6 @@ export const HOMEPAGE_MENU_ITEMS: HomepageMenuItems = [
level: 'reference_csharp',
community: true,
},
- {
- label: 'Swift',
- icon: 'reference-swift',
- href: '/reference/swift/introduction',
- level: 'reference_swift',
- community: true,
- },
{
label: 'Kotlin',
icon: 'reference-kotlin',
@@ -1140,6 +1139,10 @@ export const functions: NavMenuConstant = {
name: 'Handling Routing in Functions',
url: '/guides/functions/routing',
},
+ {
+ name: 'Running AI Models',
+ url: '/guides/functions/ai-models',
+ },
{
name: 'Regional invocations',
url: '/guides/functions/regional-invocation',
@@ -1188,6 +1191,10 @@ export const functions: NavMenuConstant = {
name: 'Generating OG images ',
url: '/guides/functions/examples/og-image',
},
+ {
+ name: 'Semantic AI Search',
+ url: '/guides/functions/examples/semantic-search',
+ },
{
name: 'CAPTCHA support with Cloudflare Turnstile',
url: '/guides/functions/examples/cloudflare-turnstile',
diff --git a/apps/docs/content/guides/ai/quickstarts/generate-text-embeddings.mdx b/apps/docs/content/guides/ai/quickstarts/generate-text-embeddings.mdx
index 840fd114122..816b5ccaf2e 100644
--- a/apps/docs/content/guides/ai/quickstarts/generate-text-embeddings.mdx
+++ b/apps/docs/content/guides/ai/quickstarts/generate-text-embeddings.mdx
@@ -1,15 +1,11 @@
---
id: 'ai-generating-embeddings'
title: 'Generate Embeddings'
-subtitle: 'Generate text embeddings using Edge Functions + Transformer.js.'
+subtitle: 'Generate text embeddings using Edge Functions.'
breadcrumb: 'AI Quickstarts'
---
-This guide will walk you through how to generate high quality text embeddings in [Edge Functions](/docs/guides/functions) using Transformers.js. Inference is performed directly in Edge Functions using open source Hugging Face models, so no external API is required.
-
-## What is Transformers.js?
-
-[Transformers.js](https://huggingface.co/docs/transformers.js/index) is a library that allows you to perform inference using the JavaScript runtime. You can run Hugging Face embedding models through Transformers.js directly in Supabase [Edge Functions](/docs/guides/functions).
+This guide will walk you through how to generate high quality text embeddings in [Edge Functions](/docs/guides/functions) using its built-in AI inference API, so no external API is required.
## Build the Edge Function
@@ -60,89 +56,45 @@ Let's build an Edge Function that will accept an input string and generate an em
-
+
- Let's modify the Edge Function to import the Transformers.js client and configure it for the Deno runtime.
+ Let's create a new inference session to be used in the lifetime of this function. Multiple requests can use the same inference session.
- ```ts ./supabase/functions/embed/index.ts
- import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'
- import { env, pipeline } from 'https://cdn.jsdelivr.net/npm/@xenova/transformers@2.5.0'
-
- // Configuration for Deno runtime
- env.useBrowserCache = false;
- env.allowLocalModels = false;
- ```
+ Currently, only the `gte-small` (https://huggingface.co/Supabase/gte-small) text embedding model is supported in Supabase's Edge Runtime.
+
+ ```ts ./supabase/functions/embed/index.ts
+ const session = new Supabase.ai.Session('gte-small');
+ ```
+
+
-
-
- Next let's construct the `pipe()` function we'll use to generate the embeddings. We use the Transformer.js `pipeline()` function to create this.
-
-
-
-
-
- ```ts ./supabase/functions/embed/index.ts
- const pipe = await pipeline(
- 'feature-extraction',
- 'Supabase/gte-small',
- );
- ```
-
-
-
-
-
- Note the two arguments we pass to `pipeline()`:
-
- 1. The first argument specifies the type of [inference task](https://huggingface.co/docs/transformers.js/index#tasks) to perform. `feature-extraction` is used for embedding generation.
- 2. The second argument specifies which Hugging Face model to use for the embedding generation. Supabase officially supports models available on the [Supabase org](https://huggingface.co/Supabase).
-
-
-
- We intentially construct the pipeline before the `serve()` function. This allows us to reuse the pre-loaded model in future warm-start requests, significantly speeding up future queries. Note that you'll only notice this speedup after deploying your function to Supabase - requests in local development will always be a cold-start.
-
-
-
-
-
-
-
-
-
- Modify our `serve()` request handler to accept an `input` string from the POST request JSON body.
+ Modify our request handler to accept an `input` string from the POST request JSON body.
- Finally let's generate the embedding by:
-
- 1. Calling `pipe()` to perform the embedding generation
- 2. Extracting the embedding from the output as a number array
- 3. Returning it as a JSON response
+ Then generate the embedding by calling `session.run(input)`.
```ts ./supabase/functions/embed/index.ts
- serve(async (req) => {
+ Deno.serve(async (req) => {
// Extract input string from JSON body
const { input } = await req.json();
// Generate the embedding from the user input
- const output = await pipe(input, {
- pooling: 'mean',
+ const embedding = await session.run(input, {
+ mean_pool: true,
normalize: true,
});
- // Extract the embedding output
- const embedding = Array.from(output.data);
-
// Return the embedding
return new Response(
JSON.stringify({ embedding }),
@@ -155,16 +107,16 @@ Let's build an Edge Function that will accept an input string and generate an em
- Note the two options we pass to `pipe()`:
+ Note the two options we pass to `session.run()`:
- - `pooling`: The first option sets `pooling` to `mean`. Pooling referes to how token-level embedding representations are compressed into a single sentence embedding that reflects the meaning of the entire sentence. Average pooling is the most common type of pooling for sentence embeddings and is the method supported by Transformers.js.
- - `normalize`: The second option tells Transformers.js to normalize the embedding vector so that it can be used with distance measures like dot product. A normalized vector means its length (magnitude) is 1 - also referred to as a unit vector. A vector is normalized by dividing each element by the vector's length (magnitude), which maintains its direction but changes its length to 1.
+ - `mean_pool`: The first option sets `pooling` to `mean`. Pooling referes to how token-level embedding representations are compressed into a single sentence embedding that reflects the meaning of the entire sentence. Average pooling is the most common type of pooling for sentence embeddings.
+ - `normalize`: The second option tells to normalize the embedding vector so that it can be used with distance measures like dot product. A normalized vector means its length (magnitude) is 1 - also referred to as a unit vector. A vector is normalized by dividing each element by the vector's length (magnitude), which maintains its direction but changes its length to 1.
-
+
diff --git a/apps/docs/content/guides/ai/semantic-search.mdx b/apps/docs/content/guides/ai/semantic-search.mdx
index a9a219f7213..44744441840 100644
--- a/apps/docs/content/guides/ai/semantic-search.mdx
+++ b/apps/docs/content/guides/ai/semantic-search.mdx
@@ -26,7 +26,7 @@ Embeddings are generated using a language model, and embeddings are compared to
## Embedding models
-There are many embedding models available today. Some can be accessed through third-party APIs like [OpenAI](https://platform.openai.com/docs/guides/embeddings), where you send your text in the request and receive an embedding vector in the response. Others can run locally on your own compute, such as through Transformers.js for JavaScript implementations. For more information on local implementation, see [Generate embeddings](/docs/guides/ai/quickstarts/generate-text-embeddings).
+There are many embedding models available today. Supabase Edge Functions has [built in support](/docs/guides/functions/examples/semantic-search) for the `gte-small` model. Others can be accessed through third-party APIs like [OpenAI](https://platform.openai.com/docs/guides/embeddings), where you send your text in the request and receive an embedding vector in the response. Others can run locally on your own compute, such as through Transformers.js for JavaScript implementations. For more information on local implementation, see [Generate embeddings](/docs/guides/ai/quickstarts/generate-text-embeddings).
It's crucial to remember that when using embedding models with semantic search, you must use the same model for all embedding comparisons. Comparing embeddings created by different models will yield meaningless results.
diff --git a/apps/docs/content/guides/api/rest/client-libs.mdx b/apps/docs/content/guides/api/rest/client-libs.mdx
index f14d2f49bbd..15f03b0d442 100644
--- a/apps/docs/content/guides/api/rest/client-libs.mdx
+++ b/apps/docs/content/guides/api/rest/client-libs.mdx
@@ -13,6 +13,7 @@ Supabase provides client libraries for the REST and Realtime APIs. Some librarie
| --------------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
| Javascript/Typescript | [supabase-js](https://github.com/supabase/supabase-js) | [Docs](https://supabase.com/docs/reference/javascript/introduction) |
| Dart/Flutter | [supabase-flutter](https://github.com/supabase/supabase-flutter/tree/main/packages/supabase_flutter) | [Docs](https://supabase.com/docs/reference/dart/introduction) |
+| Swift | [supabase-swift](https://github.com/supabase/supabase-swift) | [Docs](https://supabase.com/docs/reference/swift/introduction) |
## Community libraries
@@ -23,5 +24,4 @@ Supabase provides client libraries for the REST and Realtime APIs. Some librarie
| Kotlin | [supabase-kt](https://github.com/supabase-community/supabase-kt) | [Docs](https://supabase.com/docs/reference/kotlin/introduction) |
| Python | [supabase-py](https://github.com/supabase-community/supabase-py) | [Docs](https://supabase.com/docs/reference/python/initializing) |
| Ruby | [supabase-rb](https://github.com/supabase-community/supabase-rb) | |
-| Swift | [supabase-swift](https://github.com/supabase-community/supabase-swift) | [Docs](https://supabase.com/docs/reference/swift/introduction) |
| Godot Engine (GDScript) | [supabase-gdscript](https://github.com/supabase-community/godot-engine.supabase) | |
diff --git a/apps/docs/content/guides/auth/auth-anonymous.mdx b/apps/docs/content/guides/auth/auth-anonymous.mdx
index bd85f55c619..4a3b4aa0ad9 100644
--- a/apps/docs/content/guides/auth/auth-anonymous.mdx
+++ b/apps/docs/content/guides/auth/auth-anonymous.mdx
@@ -4,13 +4,7 @@ title: 'Anonymous Sign-Ins'
subtitle: 'Create and use anonymous users to authenticate with Supabase'
---
-Enable Anonymous Sign-In to build apps which provide users an authenticated experience without requiring users to enter an email address, password, use an OAuth provider or provide any other PII (Personally Identifiable Information). Later, when ready, they can attach an authentication method to their account.
-
-It's most useful for:
-
-- E-commerce applications, such as shopping carts before check-out
-- Full-feature demos without collecting personal information
-- Temporary or throw-away accounts
+[Enable Anonymous Sign-Ins](/dashboard/project/_/settings/auth) to build apps which provide users an authenticated experience without requiring users to enter an email address, password, use an OAuth provider or provide any other PII (Personally Identifiable Information). Later, when ready, the user can link an authentication method to their account.
@@ -22,7 +16,11 @@ This is different from the `anon` API key which does not create a user and can b
-To get started, [enable anonymous sign-ins](/dashboard/project/_/settings/auth) for your Supabase Project.
+Anonymous sign-ins can be used to build:
+
+- E-commerce applications, such as shopping carts before check-out
+- Full-feature demos without collecting personal information
+- Temporary or throw-away accounts
@@ -87,7 +85,7 @@ supabase.auth.signInAnonymously()
## Convert an anonymous user to a permanent user
-Converting an anonymous user to a permanent user requires linking an identity to the user.
+Converting an anonymous user to a permanent user requires [linking an identity](/docs/guides/auth/auth-identity-linking#manual-linking-beta) to the user. This requires you to [enable manual linking](/dashboard/project/_/settings/auth) in your Supabase project.
### Link an Email / Phone identity
@@ -100,10 +98,16 @@ Converting an anonymous user to a permanent user requires linking an identity to
>
-You can use the [`updateUser()`](/docs/reference/javascript/auth-updateuser) method to link an email or phone identity to the anonymous user.
+You can use the [`updateUser()`](/docs/reference/javascript/auth-updateuser) method to link an email or phone identity to the anonymous user. To add a password for the anonymous user, the user's email or phone number needs to be verified first.
```js
const { data, error } = await supabase.auth.updateUser({ email: 'example@email.com' })
+
+// verify the user's email by clicking on the email change link
+// or entering the 6-digit OTP sent to the email address
+
+// once the user has been verified, update the password
+const { data, error } = await supabase.auth.updateUser({ password: 'password' })
```
@@ -129,10 +133,10 @@ try await supabase.auth.updateUser(
-You can use the [`modifyUser()`](/docs/reference/kotlin/auth-updateuser) method to link an email or phone identity to the anonymous user.
+You can use the [`updateUser()`](/docs/reference/kotlin/auth-updateuser) method to link an email or phone identity to the anonymous user.
```kotlin
-supabase.auth.modifyUser {
+supabase.auth.updateUser {
email = "example@email.com"
}
```
@@ -233,7 +237,7 @@ where is_anonymous is true and created_at < now() - interval '30 days';
## Resources
-- [Supabase Account - Free Plan OK](https://supabase.com)
+- [Supabase - Get started for free](https://supabase.com)
- [Supabase JS Client](https://github.com/supabase/supabase-js)
- [Supabase Flutter Client](https://github.com/supabase/supabase-flutter)
- [Supabase Kotlin Client](https://github.com/supabase-community/supabase-kt)
diff --git a/apps/docs/content/guides/auth/auth-email.mdx b/apps/docs/content/guides/auth/auth-email.mdx
index ab2636abfe6..6491a642830 100644
--- a/apps/docs/content/guides/auth/auth-email.mdx
+++ b/apps/docs/content/guides/auth/auth-email.mdx
@@ -207,7 +207,7 @@ suspend fun logout() {
## Resources
-- [Supabase Account - Free Plan OK](https://supabase.com)
+- [Supabase - Get started for free](https://supabase.com)
- [Supabase JS Client](https://github.com/supabase/supabase-js)
- [Supabase Flutter Client](https://github.com/supabase/supabase-flutter)
- [Supabase Kotlin Client](https://github.com/supabase-community/supabase-kt)
diff --git a/apps/docs/content/guides/auth/concepts/redirect-urls.mdx b/apps/docs/content/guides/auth/concepts/redirect-urls.mdx
index 3f9f3aab8ad..665b94f13a0 100644
--- a/apps/docs/content/guides/auth/concepts/redirect-urls.mdx
+++ b/apps/docs/content/guides/auth/concepts/redirect-urls.mdx
@@ -76,6 +76,22 @@ const { data, error } = await supabase.auth.signInWithOAuth({
})
```
+## Email templates when using `redirectTo`
+
+When using a `redirectTo` option, you may need to replace the `{{ .SiteURL }}` with `{{ .RedirectTo }}` in your email templates. See the [Email Templates guide](/docs/guides/auth/auth-email-templates) for more information.
+
+For example, change the following:
+
+```html
+
+Confirm your mail
+
+
+Confirm your mail
+```
+
## Mobile deep linking URIs
For mobile applications you can use deep linking URIs. For example, for your `SITE_URL` you can specify something like `com.supabase://login-callback/` and for additional redirect URLs something like `com.supabase.staging://login-callback/` if needed.
diff --git a/apps/docs/content/guides/auth/passwordless-login/auth-email-otp.mdx b/apps/docs/content/guides/auth/passwordless-login/auth-email-otp.mdx
index 2605da556fc..9dc8599500a 100644
--- a/apps/docs/content/guides/auth/passwordless-login/auth-email-otp.mdx
+++ b/apps/docs/content/guides/auth/passwordless-login/auth-email-otp.mdx
@@ -157,7 +157,7 @@ If successful the user will now be logged in and you should receive a valid sess
## Resources
-- [Supabase Account - Free Plan OK](https://supabase.com)
+- [Supabase - Get started for free](https://supabase.com)
- [Phone SMS & WhatsApp OTP](/docs/guides/auth/phone-login)
- [Supabase JS Client](https://github.com/supabase/supabase-js)
- [Supabase Flutter Client](https://github.com/supabase/supabase-flutter)
diff --git a/apps/docs/content/guides/auth/passwordless-login/auth-magic-link.mdx b/apps/docs/content/guides/auth/passwordless-login/auth-magic-link.mdx
index 001cab6c545..ed62d006f12 100644
--- a/apps/docs/content/guides/auth/passwordless-login/auth-magic-link.mdx
+++ b/apps/docs/content/guides/auth/passwordless-login/auth-magic-link.mdx
@@ -158,6 +158,6 @@ suspend fun logout() {
## Resources
-- [Supabase Account - Free Plan OK](https://supabase.com)
+- [Supabase - Get started for free](https://supabase.com)
- [Supabase JS Client](https://github.com/supabase/supabase-js)
- [Supabase Flutter Client](https://github.com/supabase/supabase-flutter)
diff --git a/apps/docs/content/guides/auth/passwords.mdx b/apps/docs/content/guides/auth/passwords.mdx
index eb6a54ff65e..7ed8a1471ff 100644
--- a/apps/docs/content/guides/auth/passwords.mdx
+++ b/apps/docs/content/guides/auth/passwords.mdx
@@ -149,10 +149,10 @@ try await supabase.auth.updateUser(user: UserAttributes(password: newPassword))
-To update the password, call the [`.modifyUser`](/docs/reference/kotlin/auth-updateuser) method with the new password.
+To update the password, call the [`.updateUser`](/docs/reference/kotlin/auth-updateuser) method with the new password.
```kotlin
-supabase.gotrue.modifyUser {
+supabase.auth.updateUser {
password = "new_password"
}
```
diff --git a/apps/docs/content/guides/auth/server-side/oauth-with-pkce-flow-for-ssr.mdx b/apps/docs/content/guides/auth/server-side/oauth-with-pkce-flow-for-ssr.mdx
index 1b8ca766dfc..40af43d1fde 100644
--- a/apps/docs/content/guides/auth/server-side/oauth-with-pkce-flow-for-ssr.mdx
+++ b/apps/docs/content/guides/auth/server-side/oauth-with-pkce-flow-for-ssr.mdx
@@ -237,7 +237,7 @@ In the server, you need to handle the redirect to the OAuth provider's authentic
const { data, error } = await supabase.auth.signInWithOAuth({
provider,
options: {
- redirectTo: '/auth/callback',
+ redirectTo: 'http://example.com/auth/callback',
},
})
diff --git a/apps/docs/content/guides/auth/social-login/auth-bitbucket.mdx b/apps/docs/content/guides/auth/social-login/auth-bitbucket.mdx
index 1cdde00d182..5b41ce54404 100644
--- a/apps/docs/content/guides/auth/social-login/auth-bitbucket.mdx
+++ b/apps/docs/content/guides/auth/social-login/auth-bitbucket.mdx
@@ -112,6 +112,6 @@ suspend fun signOut() {
## Resources
-- [Supabase Account - Free Plan OK](https://supabase.com)
+- [Supabase - Get started for free](https://supabase.com)
- [Supabase JS Client](https://github.com/supabase/supabase-js)
- [Bitbucket Account](https://bitbucket.org)
diff --git a/apps/docs/content/guides/auth/social-login/auth-discord.mdx b/apps/docs/content/guides/auth/social-login/auth-discord.mdx
index 1c15e17249e..2154fd37eb8 100644
--- a/apps/docs/content/guides/auth/social-login/auth-discord.mdx
+++ b/apps/docs/content/guides/auth/social-login/auth-discord.mdx
@@ -113,7 +113,7 @@ suspend fun signOut() {
## Resources
-- [Supabase Account - Free Plan OK](https://supabase.com)
+- [Supabase - Get started for free](https://supabase.com)
- [Supabase JS Client](https://github.com/supabase/supabase-js)
- [Discord Account](https://discord.com)
- [Discord Developer Portal](https://discord.com/developers)
diff --git a/apps/docs/content/guides/auth/social-login/auth-facebook.mdx b/apps/docs/content/guides/auth/social-login/auth-facebook.mdx
index b195edf22d2..f15eb331425 100644
--- a/apps/docs/content/guides/auth/social-login/auth-facebook.mdx
+++ b/apps/docs/content/guides/auth/social-login/auth-facebook.mdx
@@ -131,6 +131,6 @@ You can read more about App Review [here](https://developers.facebook.com/docs/a
## Resources
-- [Supabase Account - Free Plan OK](https://supabase.com)
+- [Supabase - Get started for free](https://supabase.com)
- [Supabase JS Client](https://github.com/supabase/supabase-js)
- [Facebook Developers Dashboard](https://developers.facebook.com/)
diff --git a/apps/docs/content/guides/auth/social-login/auth-figma.mdx b/apps/docs/content/guides/auth/social-login/auth-figma.mdx
index 0db6671df23..1f982fb668c 100644
--- a/apps/docs/content/guides/auth/social-login/auth-figma.mdx
+++ b/apps/docs/content/guides/auth/social-login/auth-figma.mdx
@@ -112,6 +112,6 @@ suspend fun signOut() {
## Resources
-- [Supabase Account - Free Plan OK](https://supabase.com)
+- [Supabase - Get started for free](https://supabase.com)
- [Supabase JS Client](https://github.com/supabase/supabase-js)
- [Figma Developers page](https://www.figma.com/developers)
diff --git a/apps/docs/content/guides/auth/social-login/auth-github.mdx b/apps/docs/content/guides/auth/social-login/auth-github.mdx
index c0ffc5e8f04..0a2883ac3d8 100644
--- a/apps/docs/content/guides/auth/social-login/auth-github.mdx
+++ b/apps/docs/content/guides/auth/social-login/auth-github.mdx
@@ -123,6 +123,6 @@ suspend fun signOut() {
## Resources
-- [Supabase Account - Free Plan OK](https://supabase.com)
+- [Supabase - Get started for free](https://supabase.com)
- [Supabase JS Client](https://github.com/supabase/supabase-js)
- [GitHub Developer Settings](https://github.com/settings/developers)
diff --git a/apps/docs/content/guides/auth/social-login/auth-gitlab.mdx b/apps/docs/content/guides/auth/social-login/auth-gitlab.mdx
index 6dd71afa9be..3ffcfd43354 100644
--- a/apps/docs/content/guides/auth/social-login/auth-gitlab.mdx
+++ b/apps/docs/content/guides/auth/social-login/auth-gitlab.mdx
@@ -109,6 +109,6 @@ suspend fun signOut() {
## Resources
-- [Supabase Account - Free Plan OK](https://supabase.com)
+- [Supabase - Get started for free](https://supabase.com)
- [Supabase JS Client](https://github.com/supabase/supabase-js)
- [GitLab Account](https://gitlab.com)
diff --git a/apps/docs/content/guides/auth/social-login/auth-linkedin.mdx b/apps/docs/content/guides/auth/social-login/auth-linkedin.mdx
index f6ed6125535..865e7ba6ee5 100644
--- a/apps/docs/content/guides/auth/social-login/auth-linkedin.mdx
+++ b/apps/docs/content/guides/auth/social-login/auth-linkedin.mdx
@@ -135,6 +135,6 @@ Do reach out to support if you have any concerns around this change.
## Resources
-- [Supabase Account - Free Plan OK](https://supabase.com)
+- [Supabase - Get started for free](https://supabase.com)
- [Supabase JS Client](https://github.com/supabase/supabase-js)
- [LinkedIn Developer Dashboard](https://api.LinkedIn.com/apps)
diff --git a/apps/docs/content/guides/auth/social-login/auth-notion.mdx b/apps/docs/content/guides/auth/social-login/auth-notion.mdx
index 0c414ab4fdb..9b7a079155d 100644
--- a/apps/docs/content/guides/auth/social-login/auth-notion.mdx
+++ b/apps/docs/content/guides/auth/social-login/auth-notion.mdx
@@ -112,7 +112,7 @@ suspend fun signOut() {
## Resources
-- [Supabase Account - Free Plan OK](https://supabase.com)
+- [Supabase - Get started for free](https://supabase.com)
- [Supabase JS Client](https://github.com/supabase/supabase-js)
- [Notion Account](https://notion.so)
- [Notion Developer Portal](https://www.notion.so/my-integrations)
diff --git a/apps/docs/content/guides/auth/social-login/auth-slack.mdx b/apps/docs/content/guides/auth/social-login/auth-slack.mdx
index 238b394b9d3..e1022ee7562 100644
--- a/apps/docs/content/guides/auth/social-login/auth-slack.mdx
+++ b/apps/docs/content/guides/auth/social-login/auth-slack.mdx
@@ -130,6 +130,6 @@ suspend fun signOut() {
## Resources
-- [Supabase Account - Free Plan OK](https://supabase.com)
+- [Supabase - Get started for free](https://supabase.com)
- [Supabase JS Client](https://github.com/supabase/supabase-js)
- [Slack Developer Dashboard](https://api.slack.com/apps)
diff --git a/apps/docs/content/guides/auth/social-login/auth-spotify.mdx b/apps/docs/content/guides/auth/social-login/auth-spotify.mdx
index c74d07bb473..071cf0f8b52 100644
--- a/apps/docs/content/guides/auth/social-login/auth-spotify.mdx
+++ b/apps/docs/content/guides/auth/social-login/auth-spotify.mdx
@@ -124,6 +124,6 @@ suspend fun signOut() {
## Resources
-- [Supabase Account - Free Plan OK](https://supabase.com)
+- [Supabase - Get started for free](https://supabase.com)
- [Supabase JS Client](https://github.com/supabase/supabase-js)
- [Spotify Developer Dashboard](https://developer.spotify.com/dashboard/)
diff --git a/apps/docs/content/guides/auth/social-login/auth-twitch.mdx b/apps/docs/content/guides/auth/social-login/auth-twitch.mdx
index 405477b5da4..a968201c747 100644
--- a/apps/docs/content/guides/auth/social-login/auth-twitch.mdx
+++ b/apps/docs/content/guides/auth/social-login/auth-twitch.mdx
@@ -127,7 +127,7 @@ suspend fun signOut() {
## Resources
-- [Supabase Account - Free Plan OK](https://supabase.com)
+- [Supabase - Get started for free](https://supabase.com)
- [Supabase JS Client](https://github.com/supabase/supabase-js)
- [Twitch Account](https://twitch.tv)
- [Twitch Developer Console](https://dev.twitch.tv/console)
diff --git a/apps/docs/content/guides/auth/social-login/auth-twitter.mdx b/apps/docs/content/guides/auth/social-login/auth-twitter.mdx
index 749029d3c9f..67721da5d8b 100644
--- a/apps/docs/content/guides/auth/social-login/auth-twitter.mdx
+++ b/apps/docs/content/guides/auth/social-login/auth-twitter.mdx
@@ -118,6 +118,6 @@ suspend fun signOut() {
## Resources
-- [Supabase Account - Free Plan OK](https://supabase.com)
+- [Supabase - Get started for free](https://supabase.com)
- [Supabase JS Client](https://github.com/supabase/supabase-js)
- [Twitter Developer Dashboard](https://developer.twitter.com/en/portal/dashboard)
diff --git a/apps/docs/content/guides/auth/social-login/auth-zoom.mdx b/apps/docs/content/guides/auth/social-login/auth-zoom.mdx
index 37d6d07a8e8..ef4bf5e2d7d 100644
--- a/apps/docs/content/guides/auth/social-login/auth-zoom.mdx
+++ b/apps/docs/content/guides/auth/social-login/auth-zoom.mdx
@@ -125,6 +125,6 @@ suspend fun signOut() {
## Resources
-- [Supabase Account - Free Plan OK](https://supabase.com)
+- [Supabase - Get started for free](https://supabase.com)
- [Supabase JS Client](https://github.com/supabase/supabase-js)
- [Zoom App Marketplace](https://marketplace.zoom.us/)
diff --git a/apps/docs/content/guides/database/arrays.mdx b/apps/docs/content/guides/database/arrays.mdx
index eb405bd293f..a7579573c17 100644
--- a/apps/docs/content/guides/database/arrays.mdx
+++ b/apps/docs/content/guides/database/arrays.mdx
@@ -210,5 +210,5 @@ returns:
## Resources
- [Supabase JS Client](https://github.com/supabase/supabase-js)
-- [Supabase Account - Free Plan OK](https://supabase.com)
+- [Supabase - Get started for free](https://supabase.com)
- [PostgreSQL Arrays](https://www.postgresql.org/docs/15/arrays.html)
diff --git a/apps/docs/content/guides/database/extensions/index_advisor.mdx b/apps/docs/content/guides/database/extensions/index_advisor.mdx
index 417db6a2f11..ebb1bace03b 100644
--- a/apps/docs/content/guides/database/extensions/index_advisor.mdx
+++ b/apps/docs/content/guides/database/extensions/index_advisor.mdx
@@ -4,7 +4,20 @@ title: 'index_advisor: query optimization'
description: 'Automatically optimize SQL queries'
---
-[Index advisor](https://database.dev/olirice/index_advisor) is a Postgres extension for recommending indexes to improve query performance.
+[Index advisor](https://github.com/supabase/index_advisor) is a Postgres extension for recommending indexes to improve query performance.
+
+Features:
+
+- Supports generic parameters e.g. `$1`, `$2`
+- Supports materialized views
+- Identifies tables/columns obfuscated by views
+- Skips duplicate indexes
+
+index_advisor is accessible directly through Supabase Studio by navigating to the [Query Performance Report](/dashboard/project/*/database/query-performance) and selecting a query and then the "indexes" tab.
+
+
+
+Alternatively, you can use index_advisor directly via SQL.
For example:
@@ -20,25 +33,12 @@ from
(1 row)
```
-Features:
-
-- Supports generic parameters e.g. `$1`, `$2`
-- Supports materialized views
-- Identifies tables/columns obfuscated by views
-- Skips duplicate indexes
-
## Installation
-index_advisor is a trusted language extension, which means it is directly installable by users from the [database.dev](https://database.dev/) SQL package repository.
-
-To get started, enable the dbdev client by executing the [setup SQL script](https://database.dev/installer).
-
-Then, install index_advisor by running
+To get started, enable index_advisor by running
```sql
-select dbdev.install('olirice-index_advisor');
-create extension if not exists hypopg;
-create extension "olirice-index_advisor";
+create extension index_advisor;
```
## API
@@ -152,5 +152,4 @@ from
## Resources
-- dbdev [`index_advisor`](https://database.dev/olirice/index_advisor) docs
-- dbdev [Github Repository](https://github.com/supabase/dbdev)
+- [`index_advisor`](https://github.com/supabase/index_advisor) repo
diff --git a/apps/docs/content/guides/database/postgres/indexes.mdx b/apps/docs/content/guides/database/postgres/indexes.mdx
index 12071e0c64c..584c1d292f9 100644
--- a/apps/docs/content/guides/database/postgres/indexes.mdx
+++ b/apps/docs/content/guides/database/postgres/indexes.mdx
@@ -104,3 +104,27 @@ reindex table concurrently persons;
```
Take note that `reindex` can be used inside a transaction, but `reindex [index/table] concurrently` cannot.
+
+## Index Advisor
+
+Indexes can improve query performance of your tables as they grow. The Supabase Dashboard offers an Index Advisor, which suggests potential indexes to add to your tables.
+
+For more information on the Index Advisor and its suggestions, see the [`index_advisor` extension](/docs/guides/database/extensions/index_advisor).
+
+To use the Dashboard Index Advisor:
+
+1. Go to the [Query Performance](/dashboard/project/_/database/query-performance) page.
+1. Click on a query to bring up the Details side panel.
+1. Select the Indexes tab.
+1. Enable Index Advisor if prompted.
+
+### Understanding Index Advisor results
+
+The Indexes tab shows the existing indexes used in the selected query. Note that indexes suggested in the "New Index Recommendations" section may not be used when you create them. Postgres' query planner may intentionally ignore an available index if it determines that the query will be faster without. For example, on a small table, a sequential scan might be faster than an index scan. In that case, the planner will switch to using the index as the table size grows, helping to future proof the query.
+
+If additional indexes might improve your query, the Index Advisor shows the suggested indexes with the estimated improvement in startup and total costs:
+
+- Startup cost is the cost to fetch the first row
+- Total cost is the cost to fetch all the rows
+
+Costs are in arbitrary units, where a single sequential page read costs 1.0 units.
diff --git a/apps/docs/content/guides/database/postgres/row-level-security.mdx b/apps/docs/content/guides/database/postgres/row-level-security.mdx
index 2475ed67604..cfd1e218542 100644
--- a/apps/docs/content/guides/database/postgres/row-level-security.mdx
+++ b/apps/docs/content/guides/database/postgres/row-level-security.mdx
@@ -362,7 +362,7 @@ Always use the Role of inside your policies, specified by the `TO` operator. For
```sql
create policy "rls_test_select" on rls_test
-using ( (select auth.uid()) = user_id );
+using ( auth.uid() = user_id );
```
Use:
diff --git a/apps/docs/content/guides/database/sql-to-api.mdx b/apps/docs/content/guides/database/sql-to-api.mdx
index 65550a1c67e..76140737c95 100644
--- a/apps/docs/content/guides/database/sql-to-api.mdx
+++ b/apps/docs/content/guides/database/sql-to-api.mdx
@@ -77,7 +77,7 @@ const { count, error } = await supabase
## Resources
-- [Supabase Account - Free Plan OK](https://supabase.com)
+- [Supabase - Get started for free](https://supabase.com)
- [Postgrest Operators](https://postgrest.org/en/stable/api.html#operators)
- [Supabase API: JavaScript select](/docs/reference/javascript/select)
- [Supabase API: JavaScript modifiers](/docs/reference/javascript/using-modifiers)
diff --git a/apps/docs/content/guides/functions/ai-models.mdx b/apps/docs/content/guides/functions/ai-models.mdx
new file mode 100644
index 00000000000..e895bb5568e
--- /dev/null
+++ b/apps/docs/content/guides/functions/ai-models.mdx
@@ -0,0 +1,171 @@
+---
+id: 'function-ai-models'
+title: 'Running AI Models'
+description: 'How to run AI models in Edge Functions.'
+subtitle: 'How to run AI models in Edge Functions.'
+---
+
+[Supabase Edge Runtime](https://github.com/supabase/edge-runtime) has a built-in API for running AI models. You can use this API to generate embeddings, build conversational workflows, and do other AI related tasks in your Edge Functions.
+
+## Setup
+
+There are no external dependencies or packages to install to enable the API.
+
+You can create a new inference session by doing:
+
+```ts
+const model = new Supabase.ai.Session('model-name')
+```
+
+
+
+To get type hints and checks for the API we recommend adding this triple-slash directive to the start of the Edge Function code: `/// `
+
+
+
+## Running a model inference
+
+Once the session is instantiated, you can call it with inputs to perform inferences. Depending on the model you run, you may need to provide different options (discussed below).
+
+```ts
+const output = await model.run(input, options)
+```
+
+## How to generate text embeddings
+
+Now let's see how to write an Edge Function using the `Supabase.ai` API to generate text embeddings. Currently, `Supabase.ai` API only supports the [gte-small](https://huggingface.co/Supabase/gte-small) model.
+
+
+
+`gte-small` model exclusively caters to English texts, and any lengthy texts will be truncated to a maximum of 512 tokens. While you can provide inputs longer than 512 tokens, truncation may affect the accuracy.
+
+
+
+```ts
+const model = new Supabase.ai.Session('gte-small')
+
+Deno.serve(async (req: Request) => {
+ const params = new URL(req.url).searchParams
+ const input = params.get('input')
+ const output = await model.run(input, { mean_pool: true, normalize: true })
+ return new Response(JSON.stringify(output), {
+ headers: {
+ 'Content-Type': 'application/json',
+ Connection: 'keep-alive',
+ },
+ })
+})
+```
+
+## Using Large Language Models
+
+Inference via larger models is supported via [Ollama](https://ollama.com/). In the first iteration, the `llama2` and `mistral` models are supported and you would need to manage the Ollama server yourself.
+
+
+
+### Running locally
+
+1. Install Ollama and pull the Mistral model
+
+ ```
+ ollama pull mistral
+ ```
+
+1. Run the Ollama server locally
+
+ ```
+ ollama serve
+ ```
+
+1. Set a function secret called AI_INFERENCE_API_HOST to point to the Ollama server
+
+ ```
+ echo "AI_INFERENCE_API_HOST=http://host.docker.internal:11434/api/generate" >> supabase/functions/.env
+ ```
+
+1. Create a new function with the following code
+
+ ```
+ supabase functions new ollama-test
+ ```
+
+ ```ts
+ ///
+ const session = new Supabase.ai.Session('mistral')
+
+ Deno.serve(async (req: Request) => {
+ const params = new URL(req.url).searchParams
+ const prompt = params.get('prompt') ?? ''
+
+ // Get the output as a stream
+ const output = await session.run(prompt, { stream: true })
+
+ const headers = new Headers({
+ 'Content-Type': 'text/event-stream',
+ Connection: 'keep-alive',
+ })
+
+ // Create a stream
+ const stream = new ReadableStream({
+ async start(controller) {
+ const encoder = new TextEncoder()
+
+ try {
+ for await (const chunk of output) {
+ controller.enqueue(encoder.encode(chunk.response ?? ''))
+ }
+ } catch (err) {
+ console.error('Stream error:', err)
+ } finally {
+ controller.close()
+ }
+ },
+ })
+
+ // Return the stream to the user
+ return new Response(stream, {
+ headers,
+ })
+ })
+ ```
+
+1. Execute the function
+
+ ```
+ curl --get "http://localhost:54321/functions/v1/ollama-test" \
+ --data-urlencode "prompt=write a short rap song about Supabase, the Postgres Developer platform, as sung by Nicki Minaj" \
+ -H "Authorization: $ANON_KEY"
+ ```
+
+### Deploying to production
+
+Once the function is working locally, it's time to deploy to production.
+
+1. Deploy a Ollama server and set a function secret called `AI_INFERENCE_API_HOST` to point to the deployed Ollama server
+
+ ```
+ supabase secrets set AI_INFERENCE_API_HOST=https://path-to-your-ollama-server/
+ ```
+
+2. Deploy the Supabase function
+
+ ```
+ supabase functions deploy ollama-test
+ ```
+
+3. Execute the function
+
+ ```
+ curl --get "https://project-ref.supabase.co/functions/v1/ollama-test" \
+ --data-urlencode "prompt=write a short rap song about Supabase, the Postgres Developer platform, as sung by Nicki Minaj" \
+ -H "Authorization: $ANON_KEY"
+ ```
+
+As demonstrated in the video above, running Ollama locally is typically slower than running it in on a server with dedicated GPUs. We are collaborating with the Ollama team to improve local performance.
+
+In the future, a hosted Ollama API, will be provided as part of the Supabase platform. Supabase will scale and manage the API and GPUs for you. To sign up for early access, fill up [this form](https://forms.supabase.com/supabase.ai-llm-early-access).
diff --git a/apps/docs/content/guides/functions/examples/semantic-search.mdx b/apps/docs/content/guides/functions/examples/semantic-search.mdx
new file mode 100644
index 00000000000..b42077dd395
--- /dev/null
+++ b/apps/docs/content/guides/functions/examples/semantic-search.mdx
@@ -0,0 +1,129 @@
+---
+id: 'function-ai-models'
+title: 'Semantic Search'
+description: 'Semantic Search with pgvector and Supabase Edge Functions'
+subtitle: 'Semantic Search with pgvector and Supabase Edge Functions'
+tocVideo: 'w4Rr_1whU-U'
+---
+
+[Semantic search](/docs/guides/ai/semantic-search) interprets the meaning behind user queries rather than exact [keywords](/docs/guides/ai/keyword-search). It uses machine learning to capture the intent and context behind the query, handling language nuances like synonyms, phrasing variations, and word relationships.
+
+Since Supabase Edge Runtime [v1.36.0](https://github.com/supabase/edge-runtime/releases/tag/v1.36.0) you can run the [`gte-small` model](https://huggingface.co/Supabase/gte-small) natively within Supabase Edge Functions without any external dependencies! This allows you to easily generate text embeddings without calling any external APIs!
+
+In this tutorial you're implementing three parts:
+
+1. A [`generate-embedding`](https://github.com/supabase/supabase/tree/master/examples/ai/edge-functions/supabase/functions/generate-embedding/index.ts) database webhook edge function which generates embeddings when a content row is added (or updated) in the [`public.embeddings`](https://github.com/supabase/supabase/tree/master/examples/ai/edge-functions/supabase/migrations/20240408072601_embeddings.sql) table.
+2. A [`query_embeddings` Postgres function](https://github.com/supabase/supabase/tree/master/examples/ai/edge-functions/supabase/migrations/20240410031515_vector-search.sql) which allows us to perform similarity search from an egde function via [Remote Procedure Call (RPC)](https://supabase.com/docs/guides/database/functions?language=js).
+3. A [`search` edge function](https://github.com/supabase/supabase/tree/master/examples/ai/edge-functions/supabase/functions/search/index.ts) which generates the embedding for the search term, performs the similarity search via RPC function call, and returns the result.
+
+You can find the complete example code on [GitHub](https://github.com/supabase/supabase/tree/master/examples/ai/edge-functions)
+
+### Create the database table and webhook
+
+Given the [following table definition](https://github.com/supabase/supabase/blob/master/examples/ai/edge-functions/supabase/migrations/20240408072601_embeddings.sql):
+
+```sql
+create extension if not exists vector with schema extensions;
+
+create table embeddings (
+ id bigint primary key generated always as identity,
+ content text not null,
+ embedding vector (384)
+);
+alter table embeddings enable row level security;
+
+create index on embeddings using hnsw (embedding vector_ip_ops);
+```
+
+You can deploy the [following edge function](https://github.com/supabase/supabase/blob/master/examples/ai/edge-functions/supabase/functions/generate-embedding/index.ts) as a [database webhook](/docs/guides/database/webhooks) to generate the embeddings for any text content inserted into the table:
+
+```tsx
+const model = new Supabase.ai.Session('gte-small')
+
+Deno.serve(async (req) => {
+ const payload: WebhookPayload = await req.json()
+ const { content, id } = payload.record
+
+ // Generate embedding.
+ const embedding = await model.run(content, {
+ mean_pool: true,
+ normalize: true,
+ })
+
+ // Store in database.
+ const { error } = await supabase
+ .from('embeddings')
+ .update({ embedding: JSON.stringify(embedding) })
+ .eq('id', id)
+ if (error) console.warn(error.message)
+
+ return new Response('ok')
+})
+```
+
+## Create a Postgres Function and RPC
+
+With the embeddings now stored in your Postgres database table, you can query them from Supabase Edge Functions by utilizing [Remote Procedure Calls (RPC)](/docs/guides/database/functions?language=js).
+
+Given the [following Postgres Function](https://github.com/supabase/supabase/blob/master/examples/ai/edge-functions/supabase/migrations/20240410031515_vector-search.sql):
+
+```sql
+-- Matches document sections using vector similarity search on embeddings
+--
+-- Returns a setof embeddings so that we can use PostgREST resource embeddings (joins with other tables)
+-- Additional filtering like limits can be chained to this function call
+create or replace function query_embeddings(embedding vector(384), match_threshold float)
+returns setof embeddings
+language plpgsql
+as $$
+begin
+ return query
+ select *
+ from embeddings
+
+ -- The inner product is negative, so we negate match_threshold
+ where embeddings.embedding <#> embedding < -match_threshold
+
+ -- Our embeddings are normalized to length 1, so cosine similarity
+ -- and inner product will produce the same query results.
+ -- Using inner product which can be computed faster.
+ --
+ -- For the different distance functions, see https://github.com/pgvector/pgvector
+ order by embeddings.embedding <#> embedding;
+end;
+$$;
+```
+
+## Query vectors in Supabase Edge Functions
+
+You can use `supabase-js` to first generate the embedding for the search term and then invoke the Postgres function to find the relevant results from your stored embeddings, right from your [Supabase Edge Function](https://github.com/supabase/supabase/blob/master/examples/ai/edge-functions/supabase/functions/search/index.ts):
+
+```tsx
+const model = new Supabase.ai.Session('gte-small')
+
+Deno.serve(async (req) => {
+ const { search } = await req.json()
+ if (!search) return new Response('Please provide a search param!')
+ // Generate embedding for search term.
+ const embedding = await model.run(search, {
+ mean_pool: true,
+ normalize: true,
+ })
+
+ // Query embeddings.
+ const { data: result, error } = await supabase
+ .rpc('query_embeddings', {
+ embedding,
+ match_threshold: 0.8,
+ })
+ .select('content')
+ .limit(3)
+ if (error) {
+ return Response.json(error)
+ }
+
+ return Response.json({ search, result })
+})
+```
+
+That's it, you now have AI powered semantic search set up without any external dependencies! Just you, pgvector, and Supabase Edge Functions!
diff --git a/apps/docs/content/guides/functions/regional-invocation.mdx b/apps/docs/content/guides/functions/regional-invocation.mdx
index f5daa3f19f4..423d0127dda 100644
--- a/apps/docs/content/guides/functions/regional-invocation.mdx
+++ b/apps/docs/content/guides/functions/regional-invocation.mdx
@@ -66,6 +66,20 @@ These are the currently supported region values you can provide for `x-region` h
- `us-west-1`
- `us-west-2`
+## Using the client library
+
+You can also specify the region when invoking a Function using the Supabase client library:
+
+```js
+const { createClient, FunctionRegion } = require('@supabase/supabase-js')
+const { data: ret, error } = await supabase.functions.invoke('my-function-name', {
+ headers: { 'Content-Type': 'application/json' },
+ method: 'GET',
+ body: {},
+ region: FunctionRegion.UsEast1,
+})
+```
+
## Handling regional outages
If you explicitly specify the region via `x-region` header, requests **will NOT** be automatically re-routed to another region and you should consider temporarily changing regions during the outage.
diff --git a/apps/docs/content/guides/functions/routing.mdx b/apps/docs/content/guides/functions/routing.mdx
index ab5496f0c41..193505e5c16 100644
--- a/apps/docs/content/guides/functions/routing.mdx
+++ b/apps/docs/content/guides/functions/routing.mdx
@@ -58,7 +58,7 @@ You can deploy the function to Supabase via:
supabase functions deploy hello-world
```
-Once the function is deployed, you can try to call the two ednpoints using cURL (or Postman).
+Once the function is deployed, you can try to call the two endpoints using cURL (or Postman).
```bash
# https://supabase.com/docs/guides/functions/deploy#invoking-remote-functions
diff --git a/apps/docs/content/guides/getting-started/architecture.mdx b/apps/docs/content/guides/getting-started/architecture.mdx
index 943f13b702d..531cce08e21 100644
--- a/apps/docs/content/guides/getting-started/architecture.mdx
+++ b/apps/docs/content/guides/getting-started/architecture.mdx
@@ -145,7 +145,7 @@ Less, but better.
To avoid lock-in, we make it easy to migrate in and out. Our cloud offering is compatible with our self-hosted product.
We use existing standards to increase portability (like `pg_dump` and CSV files). If a new standard emerges which competes with a "Supabase" approach, we will deprecate the approach in favor of the standard.
-This forces us compete on experience. We aim to be the best Postgres hosting service.
+This forces us to compete on user experience. We aim to be the best Postgres hosting service.
### Play the long game
diff --git a/apps/docs/content/guides/getting-started/features.mdx b/apps/docs/content/guides/getting-started/features.mdx
index e7127c000ea..d9896c29346 100644
--- a/apps/docs/content/guides/getting-started/features.mdx
+++ b/apps/docs/content/guides/getting-started/features.mdx
@@ -12,51 +12,89 @@ This is a non-exhaustive list of features that Supabase provides for every proje
Every project is a full Postgres database. [Docs](/docs/guides/database).
-### Database extensions
+### Vector database
-Every database comes with a full set of Postgres extensions. [Docs](/docs/guides/database/extensions).
+Store vector embeddings right next to the rest of your data. [Docs](/docs/guides/ai).
-### Database functions
+### Auto-generated Rest API via PostgREST
-Create custom database functions which you can call from the browser. [Docs](/docs/guides/database/functions).
+RESTful APIs are auto-generated from your database, without a single line of code. [Docs](/docs/guides/api#rest-api-overview).
-### Database triggers
+### Auto-generated GraphQL API via pg_graphql
-Attach triggers to your tables to handle database changes. [Docs](/docs/guides/auth/managing-user-data#using-triggers).
+Fast GraphQL APIs using our custom Postgres GraphQL extension. [Docs](/docs/guides/graphql/api).
### Database webhooks
-Send database changes to any external service using Webhooks. [Link](https://supabase.com/blog/supabase-functions-updates#database-webhooks-alpha).
-
-### Database backups
-
-Projects are backed up daily with the option to upgrade to Point in Time recovery.
-
-### Search
-
-Build search functionality using Postgres Full Text Search. [Docs](/docs/guides/database/full-text-search).
+Send database changes to any external service using Webhooks. [Docs](/docs/guides/database/webhooks).
### Secrets and encryption
-Encrypt sensitive data and store secrets using our Postgres extension, Supabase Vault. [Link](https://supabase.com/blog/supabase-vault).
+Encrypt sensitive data and store secrets using our Postgres extension, Supabase Vault. [Docs](/docs/guides/database/vault).
-### Database migrations
+## Platform
-Develop locally and push your changes to your production database using migrations. [Docs](/docs/guides/getting-started/local-development#database-migrations)
+### Database backups
+
+Projects are backed up daily with the option to upgrade to Point in Time recovery. [Docs](/docs/guides/platform/backups).
+
+### Custom domains
+
+White-label the Supabase APIs to create a branded experience for your users. [Docs](/docs/guides/platform/custom-domains).
+
+### Network restrictions
+
+Restrict IP ranges that can connect to your database. [Docs](/docs/guides/platform/network-restrictions).
+
+### SSL enforcement
+
+Enforce Postgres clients to connect via SSL. [Docs](/docs/guides/platform/ssl-enforcement).
+
+### Branching
+
+Use Supabase Branches to test and preview changes. [Docs](/docs/guides/platform/branching).
+
+### Terraform provider
+
+Manage Supabase infrastructure via Terraform, an Infrastructure as Code tool. [Docs](/docs/guides/platform/terraform).
+
+### Read replicas
+
+Deploy read-only databases across multiple regions, for lower latency and better resource management. [Docs](/docs/guides/platform/read-replicas).
+
+### Fly Postgres
+
+Launch the Supabase stack on Fly.io edge network. [Docs](/docs/guides/platform/fly-postgres).
+
+## Studio
+
+### Studio Single Sign On
+
+Login to the Supabase dashboard via SSO. [Docs](/docs/guides/platform/sso).
+## Realtime
+
+### Postgres changes
+
+Receive your database changes through websockets. [Docs](/docs/guides/realtime/postgres-changes).
+
+### Broadcast
+
+Send messages between connected users through websockets. [Docs](/docs/guides/realtime/broadcast).
+
+### Presence
+
+Synchronize shared state across your users, including online status and typing indicators. [Docs](/docs/guides/realtime/presence).
+
## Auth
-### Email & password logins
+### Email login
Build email logins for your application or website. [Docs](/docs/guides/auth/auth-email).
-### Magic links
-
-Build passwordless logins for your application or website.[Docs](/docs/guides/auth/auth-magic-link).
-
-### Social logins
+### Social login
Provide social logins - everything from Apple, to GitHub, to Slack. [Docs](/docs/guides/auth/social-login).
@@ -64,46 +102,21 @@ Provide social logins - everything from Apple, to GitHub, to Slack. [Docs](/docs
Provide phone logins using a third-party SMS provider. [Docs](/docs/guides/auth/phone-login).
-### Row Level Security
+### Passwordless login
+
+Build passwordless logins via magic links for your application or website.[Docs](/docs/guides/auth/auth-magic-link).
+
+### Authorization via Row Level Security
Control the data each user can access with Postgres Policies. [Docs](/docs/guides/auth/row-level-security).
-### Server-side Auth helpers
+### Captcha protection
-Helpers for implementing user authentication in popular frameworks like [Next.js](/docs/guides/auth/auth-helpers/nextjs) and [SvelteKit](/docs/guides/auth/auth-helpers/sveltekit)
+Add Captcha to your sign-in, sign-up, and password reset forms. [Docs](/docs/guides/auth/auth-captcha).
-### Auth UI kit
+### Server-side Auth
-Build login and registration pages with custom themes. [Docs](/docs/guides/auth/auth-helpers/auth-ui).
-
-
-
-## APIs & client libraries
-
-### Auto-generated REST API
-
-RESTful APIs are auto-generated from your database, without a single line of code. [Docs](/docs/guides/api#rest-api-overview).
-
-### Auto-generated GraphQL API
-
-Fast GraphQL APIs using our custom Postgres GraphQL extension. [Docs](/docs/guides/graphql/api).
-
-### Realtime database changes
-
-Receive your database changes through websockets. [Docs](/docs/guides/realtime/postgres-changes).
-
-### User broadcasting
-
-Send messages between connected users through websockets. [Docs](/docs/guides/realtime/broadcast).
-
-### User presence
-
-Synchronize shared state across your users, including online status and typing indicators. [Docs](/docs/guides/realtime/presence).
-
-### Client libraries
-
-Official client libraries for [JavaScript](/docs/reference/javascript/) and [Dart](/docs/reference/dart).
-Unofficial libraries [supported by the community](https://github.com/supabase-community#client-libraries).
+Helpers for implementing user authentication in popular server-side languages and frameworks like Next.js, SvelteKit and Remix. [Docs](/docs/guides/auth/server-side/overview).
@@ -113,19 +126,21 @@ Unofficial libraries [supported by the community](https://github.com/supabase-co
Supabase Storage makes it simple to store and serve files. [Docs](/docs/guides/storage).
-### Resumable uploads
-
-Upload large files easily using resumable uploads. [Docs](/docs/guides/storage/uploads/resumable-uploads).
-
-### Storage CDN
+### Content Delivery Network
Cache large files using the Supabase CDN. [Docs](/docs/guides/storage/cdn/fundamentals).
+### Smart Content Delivery Network
+
+Automatically revalidate assets at the edge via the Smart CDN. [Docs](/docs/guides/storage/cdn/smart-cdn).
+
### Image transformations
Transform images on the fly. [Docs](/docs/guides/storage/serving/image-transformations).
-
+### Resumable uploads
+
+Upload large files using resumable uploads. [Docs](/docs/guides/storage/uploads/resumable-uploads).
## Edge Functions
@@ -133,7 +148,13 @@ Transform images on the fly. [Docs](/docs/guides/storage/serving/image-transform
Globally distributed TypeScript functions to execute custom business logic. [Docs](/docs/guides/functions).
-
+### Regional invocations
+
+Execute an Edge Function in a region close to your database. [Docs](/docs/guides/functions/regional-invocation).
+
+### NPM compatibility
+
+Edge functions natively support NPM modules and Node built-in APIs. [Link](https://supabase.com/blog/edge-functions-node-npm).
## Project management
@@ -145,42 +166,75 @@ Use our CLI to develop your project locally and deploy to the Supabase Platform.
Manage your projects programmatically. [Docs](/docs/reference/api).
-
+## Client libraries
+
+Official client libraries for [JavaScript](/docs/reference/javascript/start), [Flutter](docs/reference/dart/initializing) and [Swift](/docs/reference/swift/introduction).
+Unofficial libraries are supported by the community.
## Feature status
-Both Postgres and the Supabase Platform are production-ready. Some tools we offer on top of Postgres are still under development.
+Supabase Features are in 4 different states - Private Alpha, Public Alpha, Beta and Generally Available.
-| Product | Feature | Stage | Available on self-hosted |
-| -------------------------- | ---------------------- | ------ | ------------------------------------------- |
-| Database | Postgres | `GA` | ✅ |
-| Database | Triggers | `GA` | ✅ |
-| Database | Functions | `GA` | ✅ |
-| Database | Extensions | `GA` | ✅ |
-| Database | Full Text Search | `GA` | ✅ |
-| Database | Webhooks | `GA` | ✅ |
-| Database | Point-in-Time Recovery | `GA` | 🚧 [wal-g](https://github.com/wal-g/wal-g) |
-| Database | Vault | `beta` | ✅ |
-| Studio | | `GA` | ✅ |
-| Realtime | Postgres Changes | `GA` | ✅ |
-| Realtime | Broadcast | `beta` | ✅ |
-| Realtime | Presence | `beta` | ✅ |
-| Storage | | `GA` | ✅ |
-| Storage | S3 Backend | `GA` | ✅ |
-| Storage | CDN | `GA` | 🚧 [Cloudflare](https://www.cloudflare.com) |
-| Storage | Smart CDN | `beta` | 🚧 [Cloudflare](https://www.cloudflare.com) |
-| Storage | Image Transformations | `GA` | ✅ |
-| Storage | Resumable Uploads | `beta` | ✅ |
-| Edge Functions | | `beta` | ✅ |
-| Auth | OAuth Providers | `GA` | ✅ |
-| Auth | Passwordless | `GA` | ✅ |
-| Auth | Next.js Auth Helpers | `beta` | ✅ |
-| Auth | SvelteKit Auth Helpers | `beta` | ✅ |
-| Auth | Remix Auth Helpers | `beta` | ✅ |
-| CLI | | `beta` | ✅ Works with self-hosted |
-| Management API | | `beta` | N/A |
-| Client Library: JavaScript | | `GA` | N/A |
-| Client Library: Dart | | `beta` | N/A |
+### Private Alpha
+
+Features are initially launched as a private alpha to gather feedback from the community. To join our early access program, send an email to product-ops@supabase.io.
+
+### Public Alpha
+
+he alpha stage indicates that the API might change in the future, not that the service isn’t stable. Even though the [uptime Service Level Agreement](https://supabase.com/sla) does not cover products in Alpha, we do our best to have the service as stable as possible.
+
+### Beta
+
+Features in Beta are tested by an external penetration tester for security issues. The API is guaranteed to be stable and there is a strict communication process for breaking changes.
+
+### Generally Available
+
+In addition to the Beta requirements, features in GA are covered by the [uptime SLA](https://supabase.com/sla).
+
+| Product | Feature | Stage | Available on self-hosted |
+| -------------- | -------------------------- | --------------- | ------------------------------------------- |
+| Database | Postgres | `GA` | ✅ |
+| Database | Vector Database | `GA` | ✅ |
+| Database | Auto-generated Rest API | `GA` | ✅ |
+| Database | Auto-generated GraphQL API | `GA` | ✅ |
+| Database | Webhooks | `beta` | ✅ |
+| Database | Vault | `public alpha` | ✅ |
+| Platform | | `GA` | ✅ |
+| Platform | Point-in-Time Recovery | `GA` | 🚧 [wal-g](https://github.com/wal-g/wal-g) |
+| Platform | Custom Domains | `GA` | N/A |
+| Platform | Network Restrictions | `beta` | N/A |
+| Platform | SSL enforcement | `beta` | N/A |
+| Platform | Branching | `public alpha` | N/A |
+| Platform | Terraform Provider | `public alpha` | N/A |
+| Platform | Read Replicas | `private alpha` | N/A |
+| Platform | Fly Postgres | `private alpha` | N/A |
+| Studio | | `GA` | ✅ |
+| Studio | SSO | `GA` | ✅ |
+| Realtime | Postgres Changes | `GA` | ✅ |
+| Realtime | Broadcast | `GA` | ✅ |
+| Realtime | Presence | `GA` | ✅ |
+| Storage | | `GA` | ✅ |
+| Storage | CDN | `GA` | 🚧 [Cloudflare](https://www.cloudflare.com) |
+| Storage | Smart CDN | `GA` | 🚧 [Cloudflare](https://www.cloudflare.com) |
+| Storage | Image Transformations | `GA` | ✅ |
+| Storage | Resumable Uploads | `GA` | ✅ |
+| Edge Functions | | `beta` | ✅ |
+| Edge Functions | Regional Invocations | `beta` | ✅ |
+| Edge Functions | NPM compatibility | `beta` | ✅ |
+| Auth | | `GA` | ✅ |
+| Auth | Email login | `GA` | ✅ |
+| Auth | Social login | `GA` | ✅ |
+| Auth | Phone login | `GA` | ✅ |
+| Auth | Passwordless login | `GA` | ✅ |
+| Auth | SSO with SAML | `GA` | ✅ |
+| Auth | Authorization via RLS | `GA` | ✅ |
+| Auth | Captcha protection | `GA` | ✅ |
+| Auth | Server-side Auth | `beta` | ✅ |
+| CLI | | `GA` | ✅ Works with self-hosted |
+| Management API | | `GA` | N/A |
+| Client Library | JavaScript | `GA` | N/A |
+| Client Library | Flutter | `beta` | N/A |
+| Client Library | Swift | `beta` | N/A |
- ✅ = Fully Available
- 🚧 = Available, but requires external tools or configuration
diff --git a/apps/docs/content/guides/getting-started/tutorials/with-sveltekit.mdx b/apps/docs/content/guides/getting-started/tutorials/with-sveltekit.mdx
index 567778326da..649a87dd98b 100644
--- a/apps/docs/content/guides/getting-started/tutorials/with-sveltekit.mdx
+++ b/apps/docs/content/guides/getting-started/tutorials/with-sveltekit.mdx
@@ -143,14 +143,14 @@ Create a new `src/routes/+layout.server.ts` file to handle the session on the se
// src/routes/+layout.server.ts
import type { LayoutServerLoad } from './$types'
-export const load: LayoutServerLoad = async ({ locals: { safeGetSession } }) => {
+export const load = (async ({ locals: { safeGetSession } }) => {
const { session, user } = await safeGetSession()
return {
session,
user,
}
-}
+}) satisfies LayoutServerLoad
```
> Start your dev server (`npm run dev`) in order to generate the `./$types` files we are referencing in our project.
@@ -163,7 +163,7 @@ import { PUBLIC_SUPABASE_ANON_KEY, PUBLIC_SUPABASE_URL } from '$env/static/publi
import type { LayoutLoad } from './$types'
import { createBrowserClient, isBrowser, parse } from '@supabase/ssr'
-export const load: LayoutLoad = async ({ fetch, data, depends }) => {
+export const load = (async ({ fetch, data, depends }) => {
depends('supabase:auth')
const supabase = createBrowserClient(PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY, {
@@ -192,7 +192,7 @@ export const load: LayoutLoad = async ({ fetch, data, depends }) => {
} = await supabase.auth.getSession()
return { supabase, session }
-}
+}) satisfies LayoutLoad
```
Update your `src/routes/+layout.svelte`:
diff --git a/apps/docs/content/guides/getting-started/tutorials/with-swift.mdx b/apps/docs/content/guides/getting-started/tutorials/with-swift.mdx
index 6c110b51b6e..e26045321ce 100644
--- a/apps/docs/content/guides/getting-started/tutorials/with-swift.mdx
+++ b/apps/docs/content/guides/getting-started/tutorials/with-swift.mdx
@@ -23,9 +23,9 @@ Let's start building the SwiftUI app from scratch.
Open Xcode and create a new SwiftUI project.
-Add the [supabase-swift](https://github.com/supabase-community/supabase-swift) dependency.
+Add the [supabase-swift](https://github.com/supabase/supabase-swift) dependency.
-Add the `https://github.com/supabase-community/supabase-swift` package to your app. For instructions, see the [Apple tutorial on adding package dependencies](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app).
+Add the `https://github.com/supabase/supabase-swift` package to your app. For instructions, see the [Apple tutorial on adding package dependencies](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app).
Create a helper file to initialize the Supabase client.
You need the API URL and the `anon` key that you copied [earlier](#get-the-api-keys).
diff --git a/apps/docs/content/guides/platform/read-replicas.mdx b/apps/docs/content/guides/platform/read-replicas.mdx
index 82511dc83a3..bd91e0545ac 100644
--- a/apps/docs/content/guides/platform/read-replicas.mdx
+++ b/apps/docs/content/guides/platform/read-replicas.mdx
@@ -1,16 +1,17 @@
---
title: 'Read Replicas'
-description: 'Deploy additional read-only databases in multiple regions for your project.'
-subtitle: 'Deploy additional read-only databases in multiple regions for your project'
+description: 'Deploy read-only databases across multiple regions, for lower latency.'
+subtitle: 'Deploy read-only databases across multiple regions, for lower latency and better resource management.'
---
-
+Read Replicas are additional databases that are kept in sync with your Primary database. You can read your data from a Read Replica, which helps with:
-[Request early access](https://forms.supabase.com/read-replica) and you'll be notified once Read Replicas are available to your organization.
-
-
+- **Load balancing:** Read Replicas reduce load on the Primary database. For example, you can use a Read Replica for complex analytical queries and reserve the Primary for user-facing create, update, and delete operations.
+- **Improved latency:** For projects with a global user base, additional databases can be deployed closer to users to reduce latency.
+- **Redundancy:** Read Replicas provide data redundancy.
+
-Read Replicas are Postgres databases that are continuously synced to a Supabase project's Primary database. You can both read from and write to a Primary database, but you can _only_ read from a Read Replica, such as using `select` statements.
+## About Read Replicas
+
+The database you start with when launching a Supabase project is your Primary database. Read Replicas are kept in sync with the Primary through a process called "replication." Replication is asynchronous to ensure that transactions on the Primary aren't blocked. There is a delay between an update on the Primary and the time that a Read Replica receives the change. This delay is called "replication lag."
+
+You can only read data from a Read Replica. This is in contrast to a Primary database, where you can both read and write:
| | select | insert | update | delete |
| ------------ | ------ | ------ | ------ | ------ |
| Primary | ✅ | ✅ | ✅ | ✅ |
| Read Replica | ✅ | - | - | - |
-A database is spun up automatically with every Supabase project. This database is the Primary database. You can choose to add Read Replicas to your project and those Replicas will receive and synchronize data from the Primary database.
-
-Replication is asynchronous and happens in the background so transactions on the Primary aren't blocked. The time delay between writing data to the Primary and the Read Replica receiving the change is replication lag.
-
-Read Replicas have many applications:
-
-- They reduce read load on the Primary database.
- - For example, you can use a Read Replica for complex analytical queries and reserve the Primary for user-facing create, update, and delete operations.
-- For projects that need to cover a global audience, additional databases can be deployed closer to users in any of our twelve supported regions to reduce latency.
-- Read Replicas provide data redundancy.
-
## Prerequisites
-A project needs to satisfy these requirements to deploy a Read Replica:
+
+
+Read replicas are available to projects created on the Teams and Enterprise plans after 2024 March 20. They will be progressively rolled out to older projects, and eventually available on the Pro plan.
+
+If your project doesn't meet these criteria, you can join the [early access queue](https://forms.supabase.com/read-replica).
+
+
+
+Projects must meet these requirements to use Read Replicas:
1. Running on AWS.
- Support for projects on Fly.io is coming.
1. Running on at least a [Small compute add-on](/docs/guides/platform/compute-add-ons).
- - Read Replicas are currently placed on the same compute instance as the database to make sure they can keep up with the Primary's activities.
-1. Running on Postgres 15.
- - For projects running on older versions of PostgreSQL, you will need to [upgrade to the latest platform version](/docs/guides/platform/migrating-and-upgrading-projects#pgupgrade).
+ - Read Replicas are started on the same compute instance as the Primary to keep up with changes.
+1. Running on Postgres 15+.
+ - For projects running on older versions of Postgres, you will need to [upgrade to the latest platform version](/docs/guides/platform/migrating-and-upgrading-projects#pgupgrade).
1. Using [physical backups](/docs/guides/platform/backups#point-in-time-recovery)
- Physical backups are automatically enabled if using [PITR](/docs/guides/platform/backups#point-in-time-recovery)
- If you're not using PITR, you'll be able to switch to physical backups as part of the Read Replica setup process. Note that physical backups can't be downloaded from the dashboard in the way logical backups can.
## Getting started
-Read Replicas can be managed from the [infrastructure settings page](https://supabase.com/dashboard/project/_/settings/infrastructure). For now, each project can only deploy up to two Read Replicas and all Read Replicas inherit the compute size of their Primary database.
+To add a Read Replica, go to the [Infrastructure Settings page](/dashboard/project/_/settings/infrastructure) in your dashboard. Each project can deploy up to two Read Replicas and all Read Replicas inherit the compute size of their Primary database.
+
+## Features
Read Replicas offer the following features:
### Dedicated endpoints
-Each Read Replica has its own dedicated database and API endpoints. The database endpoint can be found in your [dashboard database settings](https://supabase.com/dashboard/project/_/settings/database) under **Connection info**. The API endpoint can be found in [dashboard API settings](https://supabase.com/dashboard/project/_/settings/api) under **Project URL**.
+Each Read Replica has its own dedicated database and API endpoints.
-A Read Replica's API endpoint only supports `GET` requests to the [REST API](https://supabase.com/docs/guides/api). Requests towards other Supabase products, such as Auth, Storage, and Realtime, are not able to utilize a Read Replica nor its API endpoint for now. We are working on adding Read Replica support for them.
+- Find the database endpoint on the [Database Settings page](/dashboard/project/_/settings/database) under **Connection Info**
+- Find the API endpoint on the [API Settings page](/dashboard/project/_/settings/api) under **Project URL**
-### Dedicated connection pool
+Read Replicas only support `GET` requests and the [REST API](/docs/guides/api). Requests to other Supabase products, such as Auth, Storage, and Realtime, aren't able to use a Read Replica or its API endpoint. Support for more products will be added in the future.
-A connection pool through Supavisor is also available for each Read Replica. Its unique connection string can be found in your [dashboard database settings](https://supabase.com/dashboard/project/_/settings/database) under **Connection string**.
+## Dedicated connection pool
+
+A connection pool through Supavisor is also available for each Read Replica. Find the connection string on the [Database Settings page](/dashboard/project/_/settings/database) under **Connection String**.
+
+## API load balancer
+
+A load balancer is deployed to balance requests between your Primary database and Read Replicas. Find its endpoint on the [API Settings page](/dashboard/project/_/settings/api).
+
+The load balancer uses a round-robin strategy to route `GET` requests to all available API endpoints, including the Primary database. Non-`GET` requests can also be sent through this endpoint, and will be routed to the Primary database. Read-only Postgres functions can be called using a [`GET` request](https://github.com/supabase/supabase-js/blob/v2.42.3/src/SupabaseClient.ts#L176-L177) as well.
+
+If you remove all Read Replicas from your project, the load balancer and its endpoint are removed as well. Make sure to redirect requests back to your Primary database before removal.
### Querying through the SQL editor
+In the SQL editor, you can choose if you want to run the query on a particular Read Replica.
+
+
-In the SQL editor, you can choose if you want to run the query on the Primary or one of the Replicas.
+### Metrics
-### API load balancer
+Observability and metrics for Read Replicas are not currently available in the Supabase Dashboard.
-When Read Replicas are deployed, an API load balancer becomes available for the project. An endpoint for it is provisioned and can be found [here](https://supabase.com/dashboard/project/_/settings/api).
-
-The load balancer uses a round-robin strategy to route `GET` requests to any of the API endpoints available, including that of the Primary database. Non-`GET` requests can also be sent through this endpoint. They are immediately redirected to the Primary database.
-
-Similar to the Read Replica API endpoints, only requests to the REST API are available for now. Support for other Supabase products will become available once Read Replica support has been completed for them.
-
-When a project no longer has any Read Replicas, the load balancer and its endpoint are brought down as well.
+If you're ingesting your [project's metrics](/docs/guides/platform/metrics#accessing-the-metrics-endpoint) into your own environment, you can update [your scraping setup](https://github.com/supabase/supabase-grafana?tab=readme-ov-file#read-replica-support) to additionally ingest metrics from your Read Replicas.
### Centralized configuration management
-All settings made through the dashboard will be propagated across all databases of a project. This ensures that no Read Replica get out of sync with its Primary database or with other Read Replicas.
+All settings configured through the dashboard will be propagated across all databases of a project. This ensures that no Read Replica get out of sync with the Primary database or with other Read Replicas.
-## How are Read Replicas made?
+## Operations blocked by Read Replicas
+
+### Project upgrades and data restorations
+
+The following procedures require all Read Replicas for a project to be brought down before they can be performed:
+
+1. [Project upgrades](/docs/guides/platform/migrating-and-upgrading-projects#pgupgrade)
+1. [Data restorations](/docs/guides/platform/backups#pitr-restoration-process)
+
+These operations need to be completed before Read Replicas can be re-deployed.
+
+## About replication
We use a hybrid approach to replicate data from a Primary to its Read Replicas, combining the native methods of streaming replication and file-based log shipping.
@@ -135,14 +158,3 @@ In this replication method, the Primary continuously buffers WAL changes to a lo
We bring these two methods together to achieve quick, stable, and reliable replication. Each method addresses the limitations of the other. Streaming replication minimizes replication lag, while file-based log shipping provides a fallback. For file-based log shipping, we use our existing Point In Time Recovery (PITR) infrastructure. We regularly archive files from the Primary using [WAL-G](https://github.com/wal-g/wal-g), an open source archival and restoration tool, and ship the WAL files to S3.
We combine it with streaming replication to reduce replication lag. Once WAL-G files have been synced from S3, Read Replicas connect to the Primary and stream the WAL directly.
-
-## Operations blocked by Read Replicas
-
-### Project upgrades and data restorations
-
-The following procedures require all Read Replicas for a project to be brought down before they can be performed:
-
-1. [Project upgrades](/docs/guides/platform/migrating-and-upgrading-projects#pgupgrade)
-1. [Data restorations](/docs/guides/platform/backups#pitr-restoration-process)
-
-These operations need to be completed before Read Replicas can be re-deployed.
diff --git a/apps/docs/docs/ref/api/api.mdx b/apps/docs/docs/ref/api/api.mdx
index d543ed53351..18e09385605 100644
--- a/apps/docs/docs/ref/api/api.mdx
+++ b/apps/docs/docs/ref/api/api.mdx
@@ -14,7 +14,7 @@ The Management API is in `beta`. It is usable in it's current state, but it's li
## Authentication
-All API requests require a Supabase Personal token to be included in the Authorization header: `Authorization Bearer `.
To generate or manage your API token, visit your [account](https://supabase.com/dashboard/account/tokens) page.
Your API tokens carry the same privileges as your user account, so be sure to keep it secret.
diff --git a/apps/docs/docs/ref/swift/installing.mdx b/apps/docs/docs/ref/swift/installing.mdx
new file mode 100644
index 00000000000..cbc57f06a7b
--- /dev/null
+++ b/apps/docs/docs/ref/swift/installing.mdx
@@ -0,0 +1,63 @@
+---
+id: installing
+title: 'Installing'
+slug: installing
+custom_edit_url: https://github.com/supabase/supabase/edit/master/web/spec/supabase.yml
+---
+
+### Install using Swift Package Manager
+
+
+
+
+ You can install Supabase package using Swift Package Manager.
+
+ The package exposes multiple libraries, you can choose between adding all of them using Supabase, or some of:
+
+ - `Auth`
+ - `Realtime`
+ - `Postgrest`
+ - `Functions`
+ - `Storage`
+
+
+
+
+
+
+
+
+ ```swift
+ let package = Package(
+ ...
+ dependencies: [
+ ...
+ .package(
+ url: "https://github.com/supabase/supabase-swift.git",
+ from: "2.0.0"
+ ),
+ ],
+ targets: [
+ .target(
+ name: "YourTargetName",
+ dependencies: [
+ .product(
+ name: "Supabase", // Auth, Realtime, Postgrest, Functions, or Storage
+ package: "supabase-swift"
+ ),
+ ]
+ )
+ ]
+ )
+ ```
+
+
+
+
+
+
diff --git a/apps/docs/docs/ref/swift/introduction.mdx b/apps/docs/docs/ref/swift/introduction.mdx
index 07f405736fe..dadc4490275 100644
--- a/apps/docs/docs/ref/swift/introduction.mdx
+++ b/apps/docs/docs/ref/swift/introduction.mdx
@@ -8,25 +8,13 @@ hideTitle: true
Swift Client Library
-
- @supabase-community/supabase-swift
-
+
@supabase/supabase-swift
{/* prettier-ignore */}
- This reference documents every object and method available in Supabase's Swift library, [supabase-swift](https://github.com/supabase-community/supabase-swift). You can use supabase-swift to interact with your Postgres database, listen to database changes, invoke Deno Edge Functions, build login and user management functionality, and manage large files.
-
- We also provide a [supabase](https://pub.dev/packages/supabase) package for non-Swift projects.
-
-
-
-{/* prettier-ignore */}
-
-The Swift client library is created and maintained by the Supabase community, and is not an official library. Please be tolerant of areas where the library is still being developed, and — as with all the libraries — feel free to contribute wherever you find issues.
-
-Huge thanks to official maintainers, [Guilherme](https://github.com/grdsdev) and [Maail](https://github.com/maail).
+ This reference documents every object and method available in Supabase's Swift library, [supabase-swift](https://github.com/supabase/supabase-swift). You can use supabase-swift to interact with your Postgres database, listen to database changes, invoke Deno Edge Functions, build login and user management functionality, and manage large files.
diff --git a/apps/docs/hooks/useHash.ts b/apps/docs/hooks/useHash.ts
index 3c6f9567dab..29824c1742b 100644
--- a/apps/docs/hooks/useHash.ts
+++ b/apps/docs/hooks/useHash.ts
@@ -1,12 +1,17 @@
import { useState, useCallback, useEffect } from 'react'
const useHash = () => {
- const [hash, setHash] = useState(() =>
- typeof window !== 'undefined' ? window.location.hash.split('#')[1] : undefined
- )
+ const [hash, setHash] = useState(() => {
+ if (typeof window !== 'undefined') {
+ const url = new URL(window.location.href)
+ return url.hash.substring(1) // Removes the leading '#'
+ }
+ return undefined
+ })
const hashChangeHandler = useCallback(() => {
- setHash(window.location.hash.split('#')[1])
+ const url = new URL(window.location.href)
+ setHash(url.hash.substring(1))
}, [])
useEffect(() => {
@@ -18,7 +23,9 @@ const useHash = () => {
const updateHash = useCallback(
(newHash) => {
- if (newHash !== hash) window.location.hash = newHash
+ if (newHash !== hash) {
+ window.location.hash = newHash
+ }
},
[hash]
)
diff --git a/apps/docs/package.json b/apps/docs/package.json
index 428e3dc80ba..5b6df117e78 100644
--- a/apps/docs/package.json
+++ b/apps/docs/package.json
@@ -22,8 +22,8 @@
"@code-hike/mdx": "^0.9.0",
"@mdx-js/loader": "^2.1.5",
"@mdx-js/react": "^2.3.0",
- "@next/bundle-analyzer": "^14.1.4",
- "@next/mdx": "^14.1.4",
+ "@next/bundle-analyzer": "^14.2.0",
+ "@next/mdx": "^14.2.0",
"@octokit/auth-app": "^6.0.3",
"@octokit/core": "^5.1.0",
"@octokit/graphql": "^7.0.2",
@@ -54,7 +54,7 @@
"mdx-mermaid": "2.0.0-rc3",
"mermaid": "^10.0.2",
"micromark-extension-mdxjs": "^1.0.0",
- "next": "^14.1.4",
+ "next": "^14.2.0",
"next-mdx-remote": "^4.4.1",
"next-plugin-yaml": "^1.0.1",
"next-seo": "^6.5.0",
diff --git a/apps/docs/public/img/index_advisor_studio.png b/apps/docs/public/img/index_advisor_studio.png
new file mode 100644
index 00000000000..f23f4e0adee
Binary files /dev/null and b/apps/docs/public/img/index_advisor_studio.png differ
diff --git a/apps/docs/spec/cli_v1_commands.yaml b/apps/docs/spec/cli_v1_commands.yaml
index aa603aaa103..5fe46e5b5d8 100644
--- a/apps/docs/spec/cli_v1_commands.yaml
+++ b/apps/docs/spec/cli_v1_commands.yaml
@@ -1,7 +1,7 @@
clispec: '001'
info:
id: cli
- version: 1.151.1
+ version: 1.157.2
title: Supabase CLI
language: sh
source: https://github.com/supabase/cli
@@ -10,6 +10,8 @@ info:
description: |
Supabase CLI provides you with tools to develop your application locally, and deploy your application to the Supabase platform.
tags:
+ - id: quick-start
+ title: Quick Start
- id: local-dev
title: Local Development
- id: management-api
@@ -1349,19 +1351,21 @@ commands:
If your local and remote migration history goes out of sync, you can repair the remote history by marking specific migrations as `--status applied` or `--status reverted`. Marking as `reverted` will delete an existing record from the migration history table while marking as `applied` will insert a new record.
- For example, your migration history table may look like this after running `db pull` for the first time.
+ For example, your migration history may look like the table below, with missing entries in either local or remote.
```bash
$ supabase migration list
LOCAL │ REMOTE │ TIME (UTC)
─────────────────┼────────────────┼──────────────────────
- 20230103054303 │ 20230103054303 │ 2023-01-03 05:43:03
+ │ 20230103054303 │ 2023-01-03 05:43:03
+ 20230103054315 │ │ 2023-01-03 05:43:15
```
To reset your migration history to a clean state, first delete your local migration file.
```bash
- $ rm supabase/migrations/20230103054303_remote_commit.sql
+ $ rm supabase/migrations/20230103054315_remote_commit.sql
+
$ supabase migration list
LOCAL │ REMOTE │ TIME (UTC)
─────────────────┼────────────────┼──────────────────────
@@ -1372,13 +1376,30 @@ commands:
```bash
$ supabase migration repair 20230103054303 --status reverted
- Repaired migration history: 20230103054303 => reverted
+ Connecting to remote database...
+ Repaired migration history: [20220810154537] => reverted
+ Finished supabase migration repair.
+
$ supabase migration list
LOCAL │ REMOTE │ TIME (UTC)
─────────────────┼────────────────┼──────────────────────
```
Now you can run `db pull` again to dump the remote schema as a local migration file.
+
+ ```bash
+ $ supabase db pull
+ Connecting to remote database...
+ Schema written to supabase/migrations/20240414044403_remote_schema.sql
+ Update remote migration history table? [Y/n]
+ Repaired migration history: [20240414044403] => applied
+ Finished supabase db pull.
+
+ $ supabase migration list
+ LOCAL │ REMOTE │ TIME (UTC)
+ ─────────────────┼────────────────┼──────────────────────
+ 20240414044403 │ 20240414044403 │ 2024-04-14 04:44:03
+ ```
examples:
- id: basic-usage
name: Mark a migration as reverted
@@ -1541,9 +1562,8 @@ commands:
flags:
- id: name
name: --name
- description: |
- Name that will be used to store token in your settings, defaults to built-in token name generator
- default_value: ''
+ description: Name that will be used to store token in your settings
+ default_value: built-in token name generator
- id: no-browser
name: --no-browser
description: Do not open browser automatically
@@ -2320,9 +2340,13 @@ commands:
usage: supabase init [flags]
subcommands: []
flags:
+ - id: force
+ name: --force
+ description: Overwrite existing supabase/config.toml.
+ default_value: 'false'
- id: use-orioledb
name: --use-orioledb
- description: Use OrioleDB storage engine for Postgres
+ description: Use OrioleDB storage engine for Postgres.
default_value: 'false'
- id: with-intellij-settings
name: --with-intellij-settings
@@ -2828,6 +2852,39 @@ commands:
Optionally, a new row can be inserted into the migration history table to reflect the current state of the remote database.
If no entries exist in the migration history table, `pg_dump` will be used to capture all contents of the remote schemas you have created. Otherwise, this command will only diff schema changes against the remote database, similar to running `db diff --linked`.
+ examples:
+ - id: basic-usage
+ name: Basic usage
+ code: supabase db pull
+ response: |
+ Connecting to remote database...
+ Schema written to supabase/migrations/20240414044403_remote_schema.sql
+ Update remote migration history table? [Y/n]
+ Repaired migration history: [20240414044403] => applied
+ Finished supabase db pull.
+ The auth and storage schemas are excluded. Run supabase db pull --schema auth,storage again to diff them.
+ - id: local-studio
+ name: Local studio
+ code: supabase db pull --local
+ response: |
+ Connecting to local database...
+ Setting up initial schema....
+ Creating custom roles supabase/roles.sql...
+ Applying migration 20240414044403_remote_schema.sql...
+ No schema changes found
+ The auth and storage schemas are excluded. Run supabase db pull --schema auth,storage again to diff them.
+ exit status 1
+ - id: custom-schemas
+ name: Custom schemas
+ code: supabase db pull --schema auth,storage
+ response: |
+ Connecting to remote database...
+ Setting up initial schema....
+ Creating custom roles supabase/roles.sql...
+ Applying migration 20240414044403_remote_schema.sql...
+ No schema changes found
+ Try rerunning the command with --debug to troubleshoot the error.
+ exit status 1
tags: []
links: []
usage: supabase db pull [migration name] [flags]
@@ -3437,3 +3494,16 @@ commands:
description: enable experimental features
required: true
default_value: 'false'
+ - id: supabase-bootstrap
+ title: supabase bootstrap
+ summary: Bootstrap a Supabase project from a starter template
+ tags:
+ - quick-start
+ links: []
+ usage: supabase bootstrap [template] [flags]
+ subcommands: []
+ flags:
+ - id: password
+ name: -p, --password
+ description: Password to your remote Postgres database.
+ default_value: ''
diff --git a/apps/docs/spec/common-client-libs-sections.json b/apps/docs/spec/common-client-libs-sections.json
index 5ee520ce08a..6a44fb3c877 100644
--- a/apps/docs/spec/common-client-libs-sections.json
+++ b/apps/docs/spec/common-client-libs-sections.json
@@ -33,6 +33,7 @@
"reference_python_v2",
"reference_csharp_v0",
"reference_swift_v1",
+ "reference_swift_v2",
"reference_kotlin_v1",
"reference_kotlin_v2"
]
@@ -48,6 +49,7 @@
"reference_python_v2",
"reference_csharp_v0",
"reference_swift_v1",
+ "reference_swift_v2",
"reference_kotlin_v1",
"reference_kotlin_v2"
]
@@ -986,6 +988,7 @@
"reference_python_v2",
"reference_csharp_v0",
"reference_swift_v1",
+ "reference_swift_v2",
"reference_kotlin_v1",
"reference_kotlin_v2"
],
diff --git a/apps/docs/spec/supabase_js_v2.yml b/apps/docs/spec/supabase_js_v2.yml
index d9d829db21a..53e7e8cf7fa 100644
--- a/apps/docs/spec/supabase_js_v2.yml
+++ b/apps/docs/spec/supabase_js_v2.yml
@@ -568,7 +568,7 @@ functions:
notes: |
- Requires either an email or phone number.
- This method is used for passwordless sign-ins where a OTP is sent to the user's email or phone number.
- - If the user doesn't exist, `signInWithOtp()` will signup the user instead. To restrict this behaviour, you can set `shouldCreateUser` in `SignInWithPasswordlessCredentials.options` to `false`.
+ - If the user doesn't exist, `signInWithOtp()` will signup the user instead. To restrict this behavior, you can set `shouldCreateUser` in `SignInWithPasswordlessCredentials.options` to `false`.
- If you're using an email, you can configure whether you want the user to receive a magiclink or a OTP.
- If you're using phone, you can configure whether you want the user to receive a OTP.
- The magic link's destination URL is determined by the [`SITE_URL`](/docs/guides/auth/concepts/redirect-urls).
@@ -4925,7 +4925,7 @@ functions:
notes: |
- Requires an Authorization header.
- Invoke params generally match the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) spec.
- - When you pass in a body to your function, we automatically attach the Content-Type header for `Blob`, `ArrayBuffer`, `File`, `FormData` and `String`. If it doesn't match any of these types we assume the payload is `json`, serialise it and attach the `Content-Type` header as `application/json`. You can override this behaviour by passing in a `Content-Type` header of your own.
+ - When you pass in a body to your function, we automatically attach the Content-Type header for `Blob`, `ArrayBuffer`, `File`, `FormData` and `String`. If it doesn't match any of these types we assume the payload is `json`, serialize it and attach the `Content-Type` header as `application/json`. You can override this behavior by passing in a `Content-Type` header of your own.
- Responses are automatically parsed as `json`, `blob` and `form-data` depending on the `Content-Type` header sent by your function. Responses are parsed as `text` by default.
examples:
- id: basic-invocation
@@ -4991,6 +4991,36 @@ functions:
method: 'DELETE'
})
```
+ - id: regional-invocation
+ name: Invoking a Function in the UsEast1 region
+ description: |
+ Here are the available regions:
+ - `FunctionRegion.Any`
+ - `FunctionRegion.ApNortheast1`
+ - `FunctionRegion.ApNortheast2`
+ - `FunctionRegion.ApSouth1`
+ - `FunctionRegion.ApSoutheast1`
+ - `FunctionRegion.ApSoutheast2`
+ - `FunctionRegion.CaCentral1`
+ - `FunctionRegion.EuCentral1`
+ - `FunctionRegion.EuWest1`
+ - `FunctionRegion.EuWest2`
+ - `FunctionRegion.EuWest3`
+ - `FunctionRegion.SaEast1`
+ - `FunctionRegion.UsEast1`
+ - `FunctionRegion.UsWest1`
+ - `FunctionRegion.UsWest2`
+ isSpotlight: true
+ code: |
+ ```js
+ import { createClient, FunctionRegion } from '@supabase/supabase-js'
+
+ const { data, error } = await supabase.functions.invoke('hello', {
+ body: { foo: 'bar' },
+ region: FunctionRegion.UsEast1
+ })
+ ```
+
- id: calling-with-get-verb
name: Calling with GET HTTP verb
description: |
diff --git a/apps/docs/spec/supabase_kt_v2.yml b/apps/docs/spec/supabase_kt_v2.yml
index a613cd2cbd6..3d0a1b44996 100644
--- a/apps/docs/spec/supabase_kt_v2.yml
+++ b/apps/docs/spec/supabase_kt_v2.yml
@@ -57,7 +57,7 @@ functions:
scheme = "deeplink scheme"
// On Android only, you can set OAuth and SSO logins to open in a custom tab, rather than an external browser:
- defaultExternalAuthAction = ExternalAuthAction.CUSTOM_TABS //defaults to EXTERNAL_BROWSER
+ defaultExternalAuthAction = ExternalAuthAction.CustomTabs() //defaults to ExternalAuthAction.ExternalBrowser
}
```
4. **Call platform specific function on startup** \
@@ -684,10 +684,10 @@ functions:
isOptional: true # Not directly `optional`, as there are two overloads one with and one without `parameters`.
type: T
description: Parameters to pass to the function. T can be any serializable type.
- - name: head
+ - name: method
isOptional: true
- type: Boolean
- description: If true, delete will delete the selected data.
+ type: RpcMethod
+ description: The HTTP method to use. Defaults to `RpcMethod.POST`
- name: request
isOptional: true
type: PostgrestRequestBuilder.() -> Unit
@@ -3317,7 +3317,7 @@ functions:
title: 'reauthenticate()'
$ref: '@supabase/gotrue-js.GoTrueClient.reauthenticate'
notes: |
- - This method is used together with `modifyUser()` when a user's password needs to be updated.
+ - This method is used together with `updateUser()` when a user's password needs to be updated.
- This method will send a nonce to the user's email. If the user doesn't have a confirmed email address, the method will send the nonce to the user's confirmed phone number instead.
examples:
- id: send-reauthentication-nonce
@@ -3422,11 +3422,11 @@ functions:
val user = supabase.auth.retrieveUser("JWT")
```
- id: update-user
- title: 'modifyUser()'
+ title: 'updateUser()'
$ref: '@supabase/gotrue-js.GoTrueClient.updateUser'
notes: |
Modifies the user data.
- - In order to use the `modifyUser()` method, the user needs to be signed in first.
+ - In order to use the `updateUser()` method, the user needs to be signed in first.
- By default, email updates sends a confirmation link to both the user's current and new email.
To only send a confirmation link to the user's new email, disable **Secure email change** in your project's [email auth provider settings](https://supabase.com/dashboard/project/_/auth/providers).
params:
@@ -3469,7 +3469,7 @@ functions:
isSpotlight: false
code: |
```kotlin
- val user = supabase.auth.modifyUser {
+ val user = supabase.auth.updateUser {
email = "newEmail@email.com"
}
```
@@ -3478,7 +3478,7 @@ functions:
isSpotlight: false
code: |
```kotlin
- val user = supabase.auth.modifyUser {
+ val user = supabase.auth.updateUser {
password = "secretPassword"
}
```
@@ -3487,7 +3487,7 @@ functions:
isSpotlight: true
code: |
```kotlin
- val user = supabase.auth.modifyUser {
+ val user = supabase.auth.updateUser {
data {
put("name", "John")
}
@@ -3681,11 +3681,11 @@ functions:
Sends a password reset request to the given email address.
- The password reset flow consist of 2 broad steps: (i) Allow the user to login via the password reset link; (ii) Update the user's password.
- The `resetPasswordForEmail()` only sends a password reset link to the user's email.
- To update the user's password, see [`modifyUser()`](/docs/reference/kotlin/auth-updateuser).
+ To update the user's password, see [`updateUser()`](/docs/reference/kotlin/auth-updateuser).
- The user gets redirected back to your app, assuming you setup [OTP handling](/docs/reference/kotlin/initializing)
- - After the user has been redirected successfully, prompt them for a new password and call `modifyUser()`:
+ - After the user has been redirected successfully, prompt them for a new password and call `updateUser()`:
```kotlin
- supabase.auth.modifyUser {
+ supabase.auth.updateUser {
password = "1234567"
}
```
diff --git a/apps/docs/spec/supabase_swift_v2.yml b/apps/docs/spec/supabase_swift_v2.yml
index 5cfd133983b..43fd69fb404 100644
--- a/apps/docs/spec/supabase_swift_v2.yml
+++ b/apps/docs/spec/supabase_swift_v2.yml
@@ -92,7 +92,7 @@ functions:
- To fetch the currently logged-in user, refer to [`getUser()`](/docs/reference/swift/get-user).
examples:
- id: sign-up
- name: Sign up
+ name: Sign up with email and password
isSpotlight: true
code: |
```swift
@@ -101,6 +101,30 @@ functions:
password: "example-password"
)
```
+ - id: sign-up-phone
+ name: Sign up with a phone number and password (SMS)
+ isSpotlight: true
+ code: |
+ ```swift
+ try await supabase.auth.signUp(
+ phone: "123456789",
+ password: "example-password",
+ channel: "sms"
+ )
+ ```
+ - id: sign-up-phone-whatsapp
+ name: Sign up with a phone number and password (whatsapp)
+ isSpotlight: true
+ description: |
+ The user will be sent a WhatsApp message which contains a OTP. By default, a given user can only request a OTP once every 60 seconds. Note that a user will need to have a valid WhatsApp account that is linked to Twilio in order to use this feature.
+ code: |
+ ```swift
+ try await supabase.auth.signUp(
+ phone: "123456789",
+ password: "example-password",
+ channel: "whatsapp"
+ )
+ ```
- id: sign-up-with-additional-user-metadata
name: Sign up with additional user metadata
isSpotlight: false
@@ -120,6 +144,7 @@ functions:
- id: sign-up-with-redirect
name: Sign up with a redirect URL
description: |
+ - You can provide a default redirect URL when initializing the client.
- See [redirect URLs and wildcards](/docs/guides/auth/overview#redirect-urls-and-wildcards) to add additional redirect URLs to your project.
code: |
```swift
@@ -129,6 +154,69 @@ functions:
redirectTo: URL(string: "https://example.com/welcome")!
)
```
+ - id: on-auth-state-change
+ title: "onAuthStateChange()"
+ notes: |
+ - Subscribes to important events occurring on the user's session.
+ - Emitted events:
+ - `INITIAL_SESSION`
+ - Emitted right after the Supabase client is constructed and the initial session from storage is loaded.
+ - `SIGNED_IN`
+ - Emitted each time a user session is confirmed or re-established, including on user sign in.
+ - Avoid making assumptions as to when this event is fired, this may occur even when the user is already signed in. Instead, check the user object attached to the event to see if a new user has signed in and update your application's UI.
+ - `SIGNED_OUT`
+ - Emitted when the user signs out. This can be after:
+ - A call to `supabase.auth.signOut()`.
+ - After the user's session has expired for any reason:
+ - User has signed out on another device.
+ - The session has reached its timebox limit or inactivity timeout.
+ - User has signed in on another device with single session per user enabled.
+ - Check the [User Sessions](/docs/guides/auth/sessions) docs for more information.
+ - Use this to clean up any local storage your application has associated with the user.
+ - `TOKEN_REFRESHED`
+ - Emitted each time a new access and refresh token are fetched for the signed in user.
+ - It's best practice and highly recommended to extract the access token (JWT) and store it in memory for further use in your application.
+ - Avoid frequent calls to `supabase.auth.session` for the same purpose.
+ - There is a background process that keeps track of when the session should be refreshed so you will always receive valid tokens by listening to this event.
+ - The frequency of this event is related to the JWT expiry limit configured on your project.
+ - `USER_UPDATED`
+ - Emitted each time the `supabase.auth.update(user:)` method finishes successfully. Listen to it to update your application's UI based on new profile information.
+ - `PASSWORD_RECOVERY`
+ - Emitted instead of the `SIGNED_IN` event when the user lands on a page that includes a password recovery link in the URL.
+ - Use it to show a UI to the user where they can [reset their password](/docs/guides/auth/passwords#resetting-a-users-password-forgot-password).
+
+ examples:
+ - id: listen-to-auth-changes
+ name: Listen to auth changes
+ isSpotlight: true
+ code: |
+ ```swift
+
+ // Using AsyncStream
+ for await (event, session) in await supabase.auth.authStateChanges {
+ print(event, session)
+ }
+
+ // Using Closure
+ let subscription = await supabase.auth.onAuthStateChange { event, session in
+ print(event, session)
+ }
+
+ // call remove() to remove subscription
+ subscription.remove()
+ ```
+ description: |
+ - When using closure based, remember to call `remove()` on the returned subscription.
+ - When using AsyncStream, it automatically removes the subscription when AsyncStream is canceled, or finishes.
+ - id: list-to-a-specific-event
+ name: Listen to a specific event
+ code: |
+ ```swift
+ for await (_, session) in await supabase.auth.authStateChanges
+ .filter({ $0.event == .signedIn }) {
+ // handle signIn event.
+ }
+ ```
- id: sign-in-anonymously
title: "signInAnonymously()"
notes: |
@@ -187,14 +275,14 @@ functions:
- id: sign-in-with-otp
title: "signInWithOTP()"
notes: |
+ - Requires either an email or phone number.
- This method is used for passwordless sign-ins where a OTP is sent to the user's email or phone number.
- - If the user doesn't exist, `signInWithOTP()` will signup the user instead. To restrict this behavior, you can set `shouldCreateUser` to `false`.
+ - If the user doesn't exist, `signInWithOTP()` will signup the user instead. To restrict this behavior, you can set `shouldCreateUser` to `false``.
- If you're using an email, you can configure whether you want the user to receive a magiclink or a OTP.
- If you're using phone, you can configure whether you want the user to receive a OTP.
- The magic link's destination URL is determined by the [`SITE_URL`](/docs/guides/auth/concepts/redirect-urls).
- See [redirect URLs and wildcards](/docs/guides/auth#redirect-urls-and-wildcards) to add additional redirect URLs to your project.
- Magic links and OTPs share the same implementation. To send users a one-time code instead of a magic link, [modify the magic link email template](/dashboard/project/_/auth/templates) to include `{{ .Token }}` instead of `{{ .ConfirmationURL }}`.
- - When using magic links, specify a `redirectTo` that matches a configured url scheme in your iOS app, so Supabase can correctly redirect back to your app.
- See our [Twilio Phone Auth Guide](/docs/guides/auth/phone-login/twilio) for details about configuring WhatsApp sign in.
examples:
- id: sign-in-with-email
@@ -216,13 +304,55 @@ functions:
```swift
try await supabase.auth.signInWithOTP(phone: "+13334445555")
```
+ - id: sign-in-with-whatsapp-otp
+ name: Sign in with WhatsApp OTP
+ isSpotlight: false
+ description: The user will be sent a WhatsApp message which contains a OTP. By default, a given user can only request a OTP once every 60 seconds. Note that a user will need to have a valid WhatsApp account that is linked to Twilio in order to use this feature.
+ code: |
+ ```swift
+ try await supabase.auth.signInWithOTP(
+ phone: "+13334445555",
+ channel: "whatsapp"
+ )
+ ```
- id: sign-in-with-oauth
- title: "getOAuthSignInURL()"
+ title: "signInWithOAuth()"
notes: |
- This method is used for signing in using a third-party provider.
- Supabase supports many different [third-party providers](https://supabase.com/docs/guides/auth#providers).
examples:
- - id: sign-in-using-a-third-party-provider
+ - id: sign-in-using-ASWebAuthenticationSession
+ name: Sign in with OAuth using ASWebAuthenticationSession
+ isSpotlight: true
+ description: |
+ - Use `configure` parameter to customize the `ASWebAuthenticationSession`
+ code: |
+ ```swift
+ let session = try await supabase.auth.signInWithOAuth(
+ provider: .github
+ ) { (session: ASWebAuthenticationSession) in
+ // customize session
+ }
+ ```
+
+ - id: sign-in-using-generic-flow
+ name: Sign in with OAuth and customize flow
+ isSpotlight: true
+ description: |
+ - Use `launchFlow` parameter to customize the flow.
+ code: |
+ ```swift
+ let session = try await supabase.auth.signInWithOAuth(
+ provider: .github
+ ) { url in
+ // use url to start OAuth flow
+ // and return a result url that contains the OAuth token.
+ // ...
+ return resultURL
+ }
+ ```
+
+ - id: sign-in-using-manual-implementation
name: Sign in using a third-party provider
isSpotlight: true
description: |
@@ -231,7 +361,7 @@ functions:
- When using `ASWebAuthenticationSession` or any other implementation, use the returning URL as input to `session(from:)` method.
code: |
```swift
- let url = try await supabase.auth.getOAuthSignInURL(provider: .github)
+ let url = try await supabase.auth.getOAuthSignInURL(provider: .github, redirectTo: URL(string: "my-app-scheme://"))
let session = ASWebAuthenticationSession(url: url, callbackURLScheme: "my-app-scheme") { url, error in
guard let url else { return }
@@ -246,21 +376,6 @@ functions:
session.start()
```
- - id: sign-in-using-a-third-party-provider-with-redirect
- name: Sign in using a third-party provider with redirect
- isSpotlight: false
- description: |
- - When the third-party provider successfully authenticates the user, the provider redirects the user to the URL specified in the `redirectTo` parameter. This parameter defaults to the [`SITE_URL`](/docs/guides/auth/concepts/redirect-urls). It does not redirect the user immediately after invoking this method.
- - See [redirect URLs and wildcards](/docs/guides/auth/overview#redirect-urls-and-wildcards) to add additional redirect URLs to your project.
- - getOAuthSignInURL() provides the URL which needs to be opened in a SFSafariViewController instance.
- - The redirectTo URL needs to be setup correctly in your project under Authentication -> URL Configuration -> Redirect URLs.
- code: |
- ```swift
- let url = try await supabase.auth.getOAuthSignInURL(
- provider: .google,
- redirectTo: URL(string: "https://example.com/welcome")!
- )
- ```
- id: sign-in-with-scopes
name: Sign in with scopes
isSpotlight: false
@@ -269,7 +384,7 @@ functions:
You may also need to specify the scopes in the provider's OAuth app settings, depending on the provider. The list of scopes will be documented by the third-party provider you are using and specifying scopes will enable you to use the OAuth provider token to call additional APIs supported by the third-party provider to get more information.
code: |
```swift
- let url = try await supabase.auth.getOAuthSignInURL(
+ let url = try await supabase.auth.signInWithOAuth(
provider: .github,
scopes: "repo gist notifications"
)
@@ -290,6 +405,45 @@ functions:
)
)
```
+ - id: sign-in-with-sso
+ title: 'signInWithSSO()'
+ notes: |
+ - Before you can call this method you need to [establish a connection](/docs/guides/auth/sso/auth-sso-saml#managing-saml-20-connections) to an identity provider. Use the [CLI commands](/docs/reference/cli/supabase-sso) to do this.
+ - If you've associated an email domain to the identity provider, you can use the `domain` property to start a sign-in flow.
+ - In case you need to use a different way to start the authentication flow with an identity provider, you can use the `providerId` property. For example:
+ - Mapping specific user email addresses with an identity provider.
+ - Using different hints to identity the identity provider to be used by the user, like a company-specific page, IP address or other tracking information.
+ examples:
+ - id: sign-in-with-domain
+ name: Sign in with email domain
+ isSpotlight: true
+ code: |
+ ```swift
+ // You can extract the user's email domain and use it to trigger the
+ // authentication flow with the correct identity provider.
+
+ let url = try await await supabase.auth.signInWithSSO{
+ domain: "company.com"
+ }
+
+ // Open the URL using your preferred method to complete sign-in process.
+ UIApplication.shared.open(url)
+ ```
+ - id: sign-in-with-provider-uuid
+ name: Sign in with provider UUID
+ isSpotlight: true
+ code: |
+ ```swift
+ // Useful when you need to map a user's sign in request according
+ // to different rules that can't use email domains.
+
+ let url = try await supabase.auth.signInWithSSO{
+ providerId: "21648a9d-8d5a-4555-a9d1-d6375dc14e92"
+ }
+
+ // Open the URL using your preferred method to complete sign-in process.
+ UIApplication.shared.open(url)
+ ```
- id: sign-out
title: "signOut()"
notes: |
@@ -410,6 +564,30 @@ functions:
```swift
let identities = try await supabase.auth.userIdentities()
```
+ - id: unlink-identity
+ title: 'unlinkIdentity()'
+ notes: |
+ - The **Enable Manual Linking** option must be enabled from your [project's authentication settings](/dashboard/project/_/settings/auth).
+ - The user needs to be signed in to call `unlinkIdentity()`.
+ - The user must have at least 2 identities in order to unlink an identity.
+ - The identity to be unlinked must belong to the user.
+ examples:
+ - id: unlink-identity
+ name: Unlink an identity
+ isSpotlight: true
+ code: |
+ ```swift
+ // retrieve all identites linked to a user
+ let identities = try await supabase.auth.userIdentities()
+
+ // find the google identity
+ let googleIdentity = identities.first {
+ $0.provider == .google
+ }
+
+ // unlink the google identity
+ try await supabase.auth.unlinkIdentity(googleIdentity)
+ ```
- id: send-password-reauthentication
title: "reauthenticate()"
notes: |
@@ -512,29 +690,7 @@ functions:
```swift
let session = try await supabase.auth.refreshSession(refreshToken: "custom-refresh-token")
```
- - id: on-auth-state-change
- title: "authStateChanges"
- notes: |
- - Types of auth events: `INITIAL_SESSION`, `SIGNED_IN`, `SIGNED_OUT`, `TOKEN_REFRESHED`, `USER_UPDATED`, `PASSWORD_RECOVERY`, `MFA_CHALLENGE_VERIFIED`
- - The `INITIAL_SESSION` can be used to allow you to invoke the callback function when `authStateChanges` is first called.
- examples:
- - id: listen-to-auth-changes
- name: Listen to auth changes
- isSpotlight: true
- code: |
- ```swift
- for await (event, session) in await supabase.auth.authStateChanges {
- print(event, session)
- }
- ```
- - id: list-to-a-specific-event
- name: Listen to a specific event
- code: |
- ```swift
- for await (_, session) in await supabase.auth.authStateChanges.filter({ $0.event == .signedIn }) {
- // handle signIn event.
- }
- ```
+
- id: exchange-code-for-session
title: "exchangeCodeForSession()"
notes: |
@@ -679,6 +835,41 @@ functions:
```swift
let factors = try await supabase.auth.mfa.listFactors()
```
+ - id: admin-api
+ title: 'Overview'
+ notes: |
+ - Any method under the `supabase.auth.admin` namespace requires a `service_role` key.
+ - These methods are considered admin methods and should be called on a trusted server. Never expose your `service_role` key in the browser.
+ examples:
+ - id: create-auth-admin-client
+ name: Create server-side auth client
+ isSpotlight: true
+ code: |
+ ```swift
+ import Supabase
+
+ let supabase = SupabaseClient(
+ supabaseURL: supabaseURL,
+ supabaseKey: serviceRoleKey
+ )
+
+ // Access auth admin api
+ let adminAuthClient = supabase.auth.admin
+ ```
+ - id: delete-user
+ title: 'deleteUser()'
+ notes: |
+ - The `deleteUser()` method requires the user's ID, which maps to the `auth.users.id` column.
+ examples:
+ - id: removes-a-user
+ name: Removes a user
+ isSpotlight: true
+ code: |
+ ```swift
+ try await supabase.auth.admin.deleteUser(
+ id: "715ed5db-f090-4b8c-a067-640ecee36aa0"
+ )
+ ```
- id: select
title: "Fetch data: select()"
notes: |
@@ -2899,133 +3090,140 @@ functions:
isSpotlight: true
code: |
```swift
- let channel = supabase
- .realtime
- .channel("room1")
+ let channel = await supabase.channel("room1")
- channel
- .on("broadcast", filter: ChannelFilter(event: "cursor-pos")) { message in
- print("Cursor position received!", message.payload)
- }
- .subscribe { status, error in
- if status == .subscribed {
- Task {
- await channel.send(
- type: .broadcast,
- event: "cursor-pos",
- payload: ["x": Double.random(in: 0...1), "y": Double.random(in: 0...1)]
- )
- }
- }
+ let broadcastStream = await channel.broadcastStream(event: "cursor-pos")
+
+ await channel.subscribe()
+
+ Task {
+ for await message in broadcastMessage {
+ print("Cursor position received", message.payload)
}
+ }
+
+ Task {
+ await channel.broadcast(
+ event: "cursor-pos",
+ message: [
+ "x": .double(.random(in: 0...1)),
+ "y": .double(.random(in: 0...1))
+ ]
+ )
+ }
```
- - id: listen-to-presence-sync
- name: Listen to presence sync
- isSpotlight: true
+
+ - id: listen-to-presence-updates
+ name: Listen to presence updates
code: |
```swift
- let channel = supabase.realtime.channel("room1")
- channel
- .on("presence", filter: ChannelFilter(event: "sync")) { _ in
- print("Synced presence state: ", channel.presenceState())
+ struct PresenceState: Codable {
+ let username: String
+ }
+
+ let channel = await supabase.channel("channelId")
+
+ let presenceChange = await channel.presenceChange()
+
+ await channel.subscribe()
+
+ Task {
+ for await presence in presenceChange {
+ let joins = try presence.decodeJoins(as: PresenceState.self)
+ let leaves = try presence.decodeLeaves(as: PresenceState.self)
}
- .subscribe { status, error in
- if status == .subscribed {
- Task {
- await channel.track(["online_at": Date().ISO8601Format()])
- }
- }
- }
- ```
- - id: listen-to-presence-join
- name: Listen to presence join
- isSpotlight: true
- code: |
- ```swift
- let channel = supabase.realtime.channel("room1")
- channel
- .on("presence", filter: ChannelFilter(event: "join")) { message in
- print("Newly joined presences: ", message.payload)
- }
- .subscribe { status, error in
- if status == .subscribed {
- Task {
- await channel.track(["online_at": Date().ISO8601Format()])
- }
- }
- }
- ```
- - id: listen-to-presence-leave
- name: Listen to presence leave
- isSpotlight: true
- code: |
- ```swift
- let channel = supabase.realtime.channel("room1")
- channel
- .on("presence", filter: ChannelFilter(event: "leave")) { message in
- print("Newly left presences: ", message.payload)
- }
- .subscribe { status, error in
- if status == .subscribed {
- Task {
- await channel.track(["online_at": Date().ISO8601Format()])
- await channel.untrack()
- }
- }
- }
- ```
+ }
+
+ // Send your own state
+ Task {
+ try await channel.track(PresenceState(username: "John"))
+ }
+
- id: listen-to-all-database-changes
name: Listen to all database changes
- isSpotlight: true
code: |
```swift
- supabase.realtime
- .channel("room1")
- .on("postgres_changes", filter: ChannelFilter(event: "*", schema: "*")) { message in
- print("Change received!", message.payload)
+ let channel = await supabase.channel("channelId")
+
+ let changeStream = await channel.postgresChange(AnyAction.self, schema: "public")
+
+ await channel.subscribe()
+
+ for await change in changeStream {
+ switch change {
+ case .delete(let action): print("Deleted: \(action.oldRecord)")
+ case .insert(let action): print("Inserted: \(action.record)")
+ case .select(let action): print("Selected: \(action.record)")
+ case .update(let action): print("Updated": \(action.oldRecord) with \(action.record)")
}
- .subscribe()
+ }
```
- id: listen-to-a-specific-table
name: Listen to a specific table
code: |
```swift
- supabase.realtime
- .channel("room1")
- .on("postgres_changes", filter: ChannelFilter(event: "*", schema: "public", table: "countries")) { message in
- print("Change received!", message.payload)
+ let channel = await supabase.channel("channelId")
+
+ let changeStream = await channel.postgresChange(
+ AnyAction.self,
+ schema: "public",
+ table: "users"
+ )
+
+ await channel.subscribe()
+
+ for await change in changeStream {
+ switch change {
+ case .delete(let action): print("Deleted: \(action.oldRecord)")
+ case .insert(let action): print("Inserted: \(action.record)")
+ case .select(let action): print("Selected: \(action.record)")
+ case .update(let action): print("Updated": \(action.oldRecord) with \(action.record)")
}
- .subscribe()
+ }
```
- id: listen-to-inserts
name: Listen to inserts
code: |
```swift
- supabase.realtime
- .channel("room1")
- .on("postgres_changes", filter: ChannelFilter(event: "INSERT", schema: "public", table: "countries")) { message in
- print("Change received!", message.payload)
- }
- .subscribe()
+ let channel = await supabase.channel("channelId")
+
+ let insertions = await channel.postgresChange(
+ InsertAction.self,
+ schema: "public",
+ table: "users"
+ )
+
+ await channel.subscribe()
+
+ for await insert in insertions {
+ print("Inserted: \(insert.record)")
+ }
```
- id: listen-to-updates
name: Listen to updates
description: |
By default, Supabase will send only the updated record. If you want to receive the previous values as well you can
- enable full replication for the table you are listening to:
+ enable full replication for the table you are listening too:
```sql
alter table "your_table" replica identity full;
```
code: |
```swift
- supabase.realtime
- .channel("room1")
- .on("postgres_changes", filter: ChannelFilter(event: "UPDATE", schema: "public", table: "countries")) { message in
- print("Change received!", message.payload)
- }
- .subscribe()
- ```
+ let channel = await supabase.channel("channelId")
+
+ let updates = await channel.postgresChange(
+ UpdateAction.self,
+ schema: "public",
+ table: "users"
+ )
+
+ await channel.subscribe()
+
+ for await update in updates {
+ print("Updated: \(update.oldRecord) with \(update.record)")
+ }
+ ```
- id: listen-to-deletes
name: Listen to deletes
description: |
@@ -3037,131 +3235,96 @@ functions:
```
code: |
```swift
- supabase.realtime
- .channel("room1")
- .on("postgres_changes", filter: ChannelFilter(event: "DELETE", schema: "public", table: "countries")) { message in
- print("Change received!", message.payload)
- }
- .subscribe()
- ```
- - id: listen-to-multiple-events
- name: Listen to multiple events
- description: You can chain listeners if you want to listen to multiple events for each table.
- code: |
- ```swift
- supabase.realtime
- .channel("room1")
- .on("postgres_changes", filter: ChannelFilter(event: "INSERT", schema: "public", table: "countries"), handler: handleRecordInserted)
- .on("postgres_changes", filter: ChannelFilter(event: "DELETE", schema: "public", table: "countries"), handler: handleRecordDeleted)
- .subscribe()
+ let channel = await supabase.channel("channelId")
- func handleRecordInserted(_ message: Message) {
- // handle message
- }
+ let deletions = await channel.postgresChange(
+ DeleteAction.self,
+ schema: "public",
+ table: "users"
+ )
- func handleRecordDeleted(_ message: Message) {
- // handle message
+ await channel.subscribe()
+
+ for await deletion in deletions {
+ print("Deleted: \(deletion.oldRecord)")
}
```
- id: listening-to-row-level-changes
name: Listen to row level changes
- description: You can listen to individual rows using the format `{table}:{col}=eq.{val}` - where `{col}` is the column name, and `{val}` is the value which you want to match.
- notes: |
- - ``eq`` filter works with all database types as under the hood, it's casting both the filter value and the database value to the correct type and then comparing them.
code: |
```swift
- supabase.realtime
- .channel("room1")
- .on(
- "postgres_changes",
- filter: ChannelFilter(
- event: "INSERT",
- schema: "public",
- table: "countries",
- filter: "id=eq.200"
- ),
- handler: handleRecordInserted
- )
- .subscribe()
+ let channel = await supabase.channel("channelId")
- func handleRecordInserted(_ message: Message) {
- // handle message
- }
- ```
- - id: broadcast-message
- title: broadcastMessage()
- description: |
- Broadcast a message to all connected clients to a channel.
- notes: |
- - When using REST you don't need to subscribe to the channel
- examples:
- - id: send-a-message
- name: Send a message via websocket
- isSpotlight: true
- code: |
- ```swift
- supabase.realtime
- .channel("room1")
- .subscribe { status, error in
- if status == .subscribed {
- Task {
- await channel.send(
- type: "broadcast",
- event: "cursor-pos",
- payload: ["x": Double.random(in: 0...1), "y": Double.random(in: 0...1)]
- )
- }
- }
- }
- ```
- - id: send-a-message-via-rest
- name: Send a message via REST
- isSpotlight: true
- code: |
- ```swift
- await supabase.realtime
- .channel("room1")
- .send(
- type: "broadcast",
- event: "cursor-pos",
- payload: ["x": Double.random(in: 0...1), "y": Double.random(in: 0...1)]
- )
- ```
- - id: get-channels
- title: channels
- examples:
- - id: get-all-channels
- name: Get all channels
- isSpotlight: true
- code: |
- ```swift
- let channels = supabase.realtime.channels
+ let deletions = await channel.postgresChange(
+ DeleteAction.self,
+ schema: "public",
+ table: "users",
+ filter: "id=eq.1"
+ )
+
+ await channel.subscribe()
+
+ for await deletion in deletions {
+ print("Deleted: \(deletion.oldRecord)")
+ }
```
- id: remove-channel
- title: removeChannel()
+ description: |
+ Unsubscribes and removes Realtime channel from Realtime client.
+ title: "removeChannel()"
notes: |
- - Removing a channel is a great way to maintain the performance of your project's Realtime service as well as your database if you're listening to Postgres changes. Supabase will automatically handle cleanup 30 seconds after a client is disconnected, but unused channels may cause degradation as more clients are simultaneously subscribed.
+ - Removing a channel is a great way to maintain the performance of your project's Realtime service as well as your database if you're listening to Postgres changes.
+ - Supabase will automatically handle cleanup 30 seconds after a client is disconnected, but unused channels may cause degradation as more clients are simultaneously subscribed.
+ - If you removed all channels, the client automatically disconnects from the Realtime websocket. This can be disabled in the Realtime config by setting `disconnectOnNoSubscriptions` to false.
examples:
- id: removes-a-channel
- name: Removes a channel
+ name: Remove a channel
isSpotlight: true
code: |
```swift
- supabase.realtime.remove(myChannel)
- ```
+ let channel = await supabase.channel("channelId")
+ //...
+ await supabase.removeChannel(channel)
+ ```
+ - id: unsubscribe-channel
+ name: Unsubscribe from a channel
+ isSpotlight: true
+ code: |
+ ```swift
+ let channel = await supabase.channel("channelId")
+
+ //...
+ await channel.unsubscribe()
+ ```
- id: remove-all-channels
title: removeAllChannels()
+ $ref: "@supabase/supabase-js.index.SupabaseClient.removeAllChannels"
notes: |
+ Unsubscribes and removes all Realtime channels from Realtime client.
- Removing channels is a great way to maintain the performance of your project's Realtime service as well as your database if you're listening to Postgres changes. Supabase will automatically handle cleanup 30 seconds after a client is disconnected, but unused channels may cause degradation as more clients are simultaneously subscribed.
+ - If you removed all channels, the client automatically disconnects from the Realtime websocket. This can be disabled in the Realtime config by setting `disconnectOnNoSubscriptions` to false.
examples:
- id: remove-all-channels
name: Remove all channels
isSpotlight: true
code: |
```swift
- supabase.realtime.removeAllChannels()
+ await supabase.removeAllChannels()
+ ```
+ - id: get-channels
+ title: getChannels()
+ $ref: "@supabase/supabase-js.index.SupabaseClient.getChannels"
+ notes: |
+ Returns all Realtime channels.
+ examples:
+ - id: get-all-channels
+ name: Get all channels
+ isSpotlight: true
+ code: |
+ ```swift
+ let channels = await supabase.channels
```
- id: list-buckets
diff --git a/apps/studio/components/interfaces/Account/Preferences/AccountDeletion.tsx b/apps/studio/components/interfaces/Account/Preferences/AccountDeletion.tsx
new file mode 100644
index 00000000000..69eeb340a98
--- /dev/null
+++ b/apps/studio/components/interfaces/Account/Preferences/AccountDeletion.tsx
@@ -0,0 +1,27 @@
+import Panel from 'components/ui/Panel'
+import { AlertDescription_Shadcn_, AlertTitle_Shadcn_, Alert_Shadcn_ } from 'ui'
+import { CriticalIcon } from 'ui-patterns/Icons/StatusIcons'
+import { DeleteAccountButton } from './DeleteAccountButton'
+
+export const AccountDeletion = () => {
+ return (
+ <>
+
+
+
+
+ Request for account deletion
+
+ Deleting your account is permanent and cannot be undone. Your data will be deleted
+ within 30 days, except we may retain some metadata and logs for longer where required
+ or permitted by law.
+
+
+
+
+
+
+
+ >
+ )
+}
diff --git a/apps/studio/components/interfaces/Account/Preferences/DeleteAccountButton.tsx b/apps/studio/components/interfaces/Account/Preferences/DeleteAccountButton.tsx
new file mode 100644
index 00000000000..abe01bb2986
--- /dev/null
+++ b/apps/studio/components/interfaces/Account/Preferences/DeleteAccountButton.tsx
@@ -0,0 +1,173 @@
+import { zodResolver } from '@hookform/resolvers/zod'
+import { SupportCategories } from '@supabase/shared-types/out/constants'
+import { useEffect, useState } from 'react'
+import { useForm } from 'react-hook-form'
+import toast from 'react-hot-toast'
+import * as z from 'zod'
+
+import { useSendSupportTicketMutation } from 'data/feedback/support-ticket-send'
+import { useOrganizationsQuery } from 'data/organizations/organizations-query'
+import { useProfile } from 'lib/profile'
+import {
+ Button,
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogHeader,
+ DialogSection,
+ DialogSectionSeparator,
+ DialogTitle,
+ DialogTrigger,
+ FormControl_Shadcn_,
+ FormField_Shadcn_,
+ FormItem_Shadcn_,
+ FormLabel_Shadcn_,
+ Form_Shadcn_,
+ Input_Shadcn_,
+} from 'ui'
+
+export const DeleteAccountButton = () => {
+ const { profile } = useProfile()
+ const [isOpen, setIsOpen] = useState(false)
+ const { data: organizations, isSuccess } = useOrganizationsQuery()
+
+ const accountEmail = profile?.primary_email
+ const FormSchema = z.object({ account: z.string() })
+ const form = useForm>({
+ mode: 'onBlur',
+ reValidateMode: 'onBlur',
+ resolver: zodResolver(FormSchema),
+ defaultValues: { account: '' },
+ })
+ const { account } = form.watch()
+
+ const { mutate: submitSupportTicket, isLoading } = useSendSupportTicketMutation({
+ onSuccess: () => {
+ setIsOpen(false)
+ toast.success(
+ 'Successfully submitted account deletion request - we will reach out to you via email once the request is completed!',
+ { duration: 8000 }
+ )
+ },
+ onError: (error) => {
+ toast.error(`Failed to submit account deletion request: ${error}`)
+ },
+ })
+
+ const onConfirmDelete = async () => {
+ if (!accountEmail) return console.error('Account information is required')
+
+ const payload = {
+ subject: 'Account Deletion Request',
+ message: 'I want to delete my account.',
+ category: SupportCategories.PROBLEM,
+ severity: 'Low',
+ allowSupportAccess: false,
+ verified: true,
+ projectRef: 'no-project',
+ }
+
+ submitSupportTicket(payload)
+ }
+
+ useEffect(() => {
+ if (isOpen && form !== undefined) form.reset({ account: '' })
+ }, [form, isOpen])
+
+ return (
+
+ )
+}
diff --git a/apps/studio/components/interfaces/Auth/Policies/AIPolicyEditorPanel/LockedQuerySection.tsx b/apps/studio/components/interfaces/Auth/Policies/AIPolicyEditorPanel/LockedQuerySection.tsx
index 02dd1daac6b..224a8499203 100644
--- a/apps/studio/components/interfaces/Auth/Policies/AIPolicyEditorPanel/LockedQuerySection.tsx
+++ b/apps/studio/components/interfaces/Auth/Policies/AIPolicyEditorPanel/LockedQuerySection.tsx
@@ -3,11 +3,11 @@ import { Lock } from 'lucide-react'
import { useRouter } from 'next/router'
import { useParams } from 'common'
-import { useTableEditorStateSnapshot } from 'state/table-editor'
import { Button } from 'ui'
import { generateAlterPolicyQuery, generateCreatePolicyQuery } from './AIPolicyEditorPanel.utils'
interface LockedCreateQuerySection {
+ schema: string
selectedPolicy?: PostgresPolicy
formFields: { name: string; table: string; behavior: string; command: string; roles: string }
editorOneRef: any
@@ -15,6 +15,7 @@ interface LockedCreateQuerySection {
}
export const LockedCreateQuerySection = ({
+ schema,
selectedPolicy,
formFields,
editorOneRef,
@@ -22,7 +23,6 @@ export const LockedCreateQuerySection = ({
}: LockedCreateQuerySection) => {
const router = useRouter()
const { ref } = useParams()
- const state = useTableEditorStateSnapshot()
const isEditing = selectedPolicy !== undefined
const { name, table, behavior, command, roles } = formFields
@@ -44,7 +44,7 @@ export const LockedCreateQuerySection = ({
const query = isEditing
? generateCreatePolicyQuery({
name,
- schema: state.selectedSchemaName,
+ schema,
table,
behavior,
command,
@@ -58,7 +58,7 @@ export const LockedCreateQuerySection = ({
: generateAlterPolicyQuery({
name: '',
newName: name,
- schema: state.selectedSchemaName,
+ schema,
table,
command,
roles: roles.length === 0 ? 'public' : roles,
@@ -84,7 +84,7 @@ export const LockedCreateQuerySection = ({
2
- on "{state.selectedSchemaName}"."
+ on "{schema}"."
{table}"