fix: merge conflict pkg lock

This commit is contained in:
kemal committed 2025-08-26 14:36:54 +01:00
commit b4628688fd
721 files changed
+17972 -10895

No files matched your search

+4 -1
View File
@@ -45,6 +45,7 @@ jobs:
sparse-checkout: |
apps/docs
apps/www/.env.local.example
examples
supabase
- uses: pnpm/action-setup@v4
@@ -63,7 +64,9 @@ jobs:
- name: Update embeddings
working-directory: ./apps/docs
if: ${{ !inputs.refresh }}
run: pnpm run embeddings
run: |
pnpm run codegen:examples
pnpm run embeddings
- name: Refresh embeddings
working-directory: ./apps/docs
+1 -1
View File
@@ -203,7 +203,7 @@ Some things to consider:
## Community channels
If you get stuck somewhere or have any questions, join our [Discord Community Server](https://discord.supabase.com/) or the [Github Discussions](https://github.com/supabase/supabase/discussions). We are here to help!
If you get stuck somewhere or have any questions, join our [Discord Community Server](https://discord.supabase.com/) or the [GitHub Discussions](https://github.com/supabase/supabase/discussions). We are here to help!
## Contributors
+4 -4
View File
@@ -1,12 +1,12 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@import './../../../packages/ui/build/css/source/global.css';
@import './../../../packages/ui/build/css/themes/dark.css';
@import './../../../packages/ui/build/css/themes/classic-dark.css';
@import './../../../packages/ui/build/css/themes/light.css';
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--chart-1: 12 76% 61%;
@@ -4,7 +4,9 @@ import { type OpenAIClientInterface } from '~/lib/openAi'
import { ApiError } from '../../utils'
import { POST } from '../route'
const contentEmbeddingMock = vi.fn().mockImplementation(async () => Result.ok([0.1, 0.2, 0.3]))
const contentEmbeddingMock = vi
.fn()
.mockImplementation(async () => Result.ok({ embedding: [0.1, 0.2, 0.3], tokenCount: 10 }))
const openAIMock: OpenAIClientInterface = {
createContentEmbedding: contentEmbeddingMock,
}
+11 -1
View File
@@ -64,6 +64,16 @@ export class NoDataError<Details extends ObjectOrNever = never> extends ApiError
}
}
export class FileNotFoundError<Details extends ObjectOrNever = never> extends Error {
constructor(
message: string,
error: Error,
public details?: Details
) {
super(`FileNotFound: ${message}`, { cause: error })
}
}
export class MultiError<ErrorType = unknown, Details extends ObjectOrNever = never> extends Error {
constructor(
message: string,
@@ -79,7 +89,7 @@ export class MultiError<ErrorType = unknown, Details extends ObjectOrNever = nev
appendError(message: string, error: ErrorType): this {
this.message = `${this.message}\n\t${message}`
;((this.cause ?? (this.cause = [])) as Array<ErrorType>).push(error)
;((this.cause ??= []) as Array<ErrorType>).push(error)
return this
}
}
+17 -13
View File
@@ -150,7 +150,7 @@ export const GET: APIRoute = async ({ request, cookies, redirect }) => {
if (code) {
const supabase = createServerClient(
import.meta.env.PUBLIC_SUPABASE_URL,
import.meta.env.PUBLIC_SUPABASE_ANON_KEY,
import.meta.env.PUBLIC_SUPABASE_PUBLISHABLE_KEY,
{
cookies: {
getAll() {
@@ -194,18 +194,22 @@ export async function loader({ request }: LoaderFunctionArgs) {
const headers = new Headers()
if (code) {
const supabase = createServerClient(process.env.SUPABASE_URL!, process.env.SUPABASE_ANON_KEY!, {
cookies: {
getAll() {
return parseCookieHeader(request.headers.get('Cookie') ?? '')
const supabase = createServerClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_PUBLISHABLE_KEY!,
{
cookies: {
getAll() {
return parseCookieHeader(request.headers.get('Cookie') ?? '')
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) =>
headers.append('Set-Cookie', serializeCookieHeader(name, value, options))
)
},
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) =>
headers.append('Set-Cookie', serializeCookieHeader(name, value, options))
)
},
},
})
}
)
const { error } = await supabase.auth.exchangeCodeForSession(code)
@@ -233,7 +237,7 @@ app.get("/auth/callback", async function (req, res) {
if (code) {
const supabase = createServerClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_ANON_KEY, {
process.env.SUPABASE_PUBLISHABLE_KEY, {
cookies: {
getAll() {
return parseCookieHeader(context.req.headers.cookie ?? '')
@@ -283,7 +283,7 @@ With our database set up, we need to process and store all `.mdx` files in the `
```bash
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_ANON_KEY=
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=
SUPABASE_SERVICE_ROLE_KEY=
# Get your key at https://platform.openai.com/account/api-keys
@@ -470,8 +470,8 @@ const handleConfirm = React.useCallback(
const eventSource = new SSE(`api/vector-search`, {
headers: {
apikey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY ?? '',
Authorization: `Bearer ${process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY}`,
apikey: process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY ?? '',
Authorization: `Bearer ${process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY}`,
'Content-Type': 'application/json',
},
payload: JSON.stringify({ query }),
+1 -1
View File
@@ -136,7 +136,7 @@ Rotating a secret key (`sb_secret_...`) is easy and painless. Use the [API Keys]
If you are still using the JWT-based `service_role` key, there are two options.
1. **Strongly recommended:** Replace the `service_role` key with a new secret key instead. Follow the guide from above as if you are rotating an existing secret key.
2. [Rotate your project's JWT secret.](/dashboard/project/_/settings/api) This operation is only recommended if you suspect that the JWT secret has leaked itself. Consider switching your `anon` JWT-based key to the publishable key, and all `service_role` JWT-based keys to secret keys. Only then rotate the JWT secret. Check the FAQ below if you use the JWT-based keys in mobile, desktop or CLI applications!
2. [Rotate your project's JWT secret.](/dashboard/project/_/settings/jwt) This operation is only recommended if you suspect that the JWT secret has leaked itself. Consider switching your `anon` JWT-based key to the publishable key, and all `service_role` JWT-based keys to secret keys. Only then rotate the JWT secret. Check the FAQ below if you use the JWT-based keys in mobile, desktop or CLI applications!
## Known limitations and compatibility differences
@@ -32,11 +32,15 @@ import fetchRetry from 'fetch-retry'
const fetchWithRetry = fetchRetry(fetch)
// Create a Supabase client instance with the custom fetch
const supabase = createClient('https://your-supabase-url.supabase.co', 'your-anon-key', {
global: {
fetch: fetchWithRetry,
},
})
const supabase = createClient(
'https://your-supabase-url.supabase.co',
'sb_publishable_... or anon key',
{
global: {
fetch: fetchWithRetry,
},
}
)
```
## 3. Configure retry options
@@ -72,7 +72,7 @@ Both of these routes require the `anon` key to be passed through an `apikey` hea
You can interact with your API directly via HTTP requests, or you can use the client libraries which we provide.
Let's see how to make a request to the `todos` table which we created in the first step,
using the API URL (`SUPABASE_URL`) and Key (`SUPABASE_ANON_KEY`) we provided:
using the API URL (`SUPABASE_URL`) and Key (`SUPABASE_PUBLISHABLE_KEY`) we provided:
<Tabs
scrollable
@@ -86,7 +86,7 @@ using the API URL (`SUPABASE_URL`) and Key (`SUPABASE_ANON_KEY`) we provided:
```javascript
// Initialize the JS client
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY)
const supabase = createClient(SUPABASE_URL, SUPABASE_PUBLISHABLE_KEY)
// Make a request
const { data: todos, error } = await supabase.from('todos').select('*')
@@ -98,8 +98,8 @@ const { data: todos, error } = await supabase.from('todos').select('*')
```bash
# Append /rest/v1/ to your URL, and then use the table name as the route
curl '<SUPABASE_URL>/rest/v1/todos' \
-H "apikey: <SUPABASE_ANON_KEY>" \
-H "Authorization: Bearer <SUPABASE_ANON_KEY>"
-H "apikey: <SUPABASE_PUBLISHABLE_KEY>" \
-H "Authorization: Bearer <SUPABASE_PUBLISHABLE_KEY>"
```
</TabPanel>
@@ -95,7 +95,10 @@ You can supply the type definitions to `supabase-js` like so:
import { createClient } from '@supabase/supabase-js'
import { Database } from './database.types'
const supabase = createClient<Database>(process.env.SUPABASE_URL, process.env.SUPABASE_ANON_KEY)
const supabase = createClient<Database>(
process.env.SUPABASE_URL,
process.env.SUPABASE_PUBLISHABLE_KEY
)
```
## Helper types for tables and joins
@@ -45,7 +45,9 @@ Now you can access these schemas from data APIs:
```js
// Initialize the JS client
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, { db: { schema: 'myschema' } })
const supabase = createClient(SUPABASE_URL, SUPABASE_PUBLISHABLE_KEY, {
db: { schema: 'myschema' },
})
// Make a request
const { data: todos, error } = await supabase.from('todos').select('*')
@@ -81,14 +83,14 @@ final data = await supabase.schema('myschema').from('todos').select();
# for GET or HEAD request use Accept-Profile
curl '<SUPABASE_URL>/rest/v1/todos' \
-H "apikey: <SUPABASE_ANON_KEY>" \
-H "Authorization: Bearer <SUPABASE_ANON_KEY>" \
-H "apikey: <SUPABASE_PUBLISHABLE_KEY>" \
-H "Authorization: Bearer <SUPABASE_PUBLISHABLE_KEY>" \
-H "Accept-Profile: myschema"
# for POST, PATCH, PUT and DELETE Request use Content-Profile
curl -X POST '<SUPABASE_URL>/rest/v1/todos' \
-H "apikey: <SUPABASE_ANON_KEY>" \
-H "Authorization: Bearer <SUPABASE_ANON_KEY>" \
-H "apikey: <SUPABASE_PUBLISHABLE_KEY>" \
-H "Authorization: Bearer <SUPABASE_PUBLISHABLE_KEY>" \
-H "Content-Type: application/json" \
-H "Content-Profile: myschema" \
-d '{"column_name": "value"}'
@@ -57,7 +57,7 @@ Call the [`signInAnonymously()`](/docs/reference/javascript/auth-signinanonymous
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project.supabase.co', 'your-anon-key')
const supabase = createClient('https://your-project.supabase.co', 'sb_publishable_... or anon key')
// ---cut---
const { data, error } = await supabase.auth.signInAnonymously()
@@ -121,7 +121,7 @@ You can use the [`updateUser()`](/docs/reference/javascript/auth-updateuser) met
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project.supabase.co', 'your-anon-key')
const supabase = createClient('https://your-project.supabase.co', 'sb_publishable_... or anon key')
// ---cut---
const { data: updateEmailData, error: updateEmailError } = await supabase.auth.updateUser({
@@ -205,7 +205,7 @@ You can use the [`linkIdentity()`](/docs/reference/javascript/auth-linkidentity)
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project.supabase.co', 'your-anon-key')
const supabase = createClient('https://your-project.supabase.co', 'sb_publishable_... or anon key')
// ---cut---
const { data, error } = await supabase.auth.linkIdentity({ provider: 'google' })
@@ -107,7 +107,10 @@ When the user clicks on the link, the request will hit `https://api.example.com/
```ts
import { createClient, type EmailOtpType } from '@supabase/supabase-js'
const supabase = createClient('https://your-project-id.supabase.co', 'your-anon-key')
const supabase = createClient(
'https://your-project-id.supabase.co',
'sb_publishable_... or anon key'
)
// ---cut---
const { token_hash, type } = Object.fromEntries(new URLSearchParams(window.location.search))
@@ -27,7 +27,7 @@ import 'package:supabase_auth_ui/supabase_auth_ui.dart';
void main() async {
await Supabase.initialize(
url: dotenv.get('SUPABASE_URL'),
anonKey: dotenv.get('SUPABASE_ANON_KEY'),
anonKey: dotenv.get('SUPABASE_PUBLISHABLE_KEY'),
);
runApp(const MyApp());
@@ -57,7 +57,7 @@ Retrieve your project URL and anon key in your project's [API settings](https://
```bash .env.local
NEXT_PUBLIC_SUPABASE_URL=your-supabase-url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=your-supabase-publishable-key
```
## Basic setup
@@ -55,7 +55,7 @@ Retrieve your project's URL and anon key from your [API settings](https://supaba
```bash .env.local
NEXT_PUBLIC_SUPABASE_URL=your-supabase-url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=your-supabase-publishable-key
```
## Managing session with middleware
@@ -1172,7 +1172,7 @@ import { createClient } from '@supabase/supabase-js'
export default async function Page() {
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY
)
const { data } = await supabase.from('todos').select()
@@ -1192,7 +1192,7 @@ import type { Database } from '@/lib/database.types'
export default async function Page() {
const supabase = createClient<Database>(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!
)
const { data } = await supabase.from('todos').select()
@@ -1229,7 +1229,7 @@ export async function POST(request) {
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY
)
const { data } = await supabase.from('todos').insert({ title }).select()
@@ -1252,7 +1252,7 @@ export async function POST(request: Request) {
const supabase = createClient<Database>(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!
)
const { data } = await supabase.from('todos').insert({ title }).select()
@@ -59,7 +59,7 @@ Retrieve your project URL and anon key in your project's [API settings](https://
```bash .env
SUPABASE_URL=YOUR_SUPABASE_URL
SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
SUPABASE_PUBLISHABLE_KEY=YOUR_SUPABASE_PUBLISHABLE_KEY
```
### Code Exchange route
@@ -89,7 +89,7 @@ export const loader = async ({ request }) => {
if (code) {
const supabaseClient = createServerClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_ANON_KEY,
process.env.SUPABASE_PUBLISHABLE_KEY,
{ request, response }
)
await supabaseClient.auth.exchangeCodeForSession(code)
@@ -122,7 +122,7 @@ export const loader = async ({ request }: LoaderFunctionArgs) => {
if (code) {
const supabaseClient = createServerClient<Database>(
process.env.SUPABASE_URL!,
process.env.SUPABASE_ANON_KEY!,
process.env.SUPABASE_PUBLISHABLE_KEY!,
{ request, response }
)
await supabaseClient.auth.exchangeCodeForSession(code)
@@ -145,7 +145,7 @@ The Supabase client can now be used server-side - in loaders and actions - by ca
### Loader
Loader functions run on the server immediately before the component is rendered. They respond to all GET requests on a route. You can create an authenticated Supabase client by calling the `createServerClient` function and passing it your `SUPABASE_URL`, `SUPABASE_ANON_KEY`, and a `Request` and `Response`.
Loader functions run on the server immediately before the component is rendered. They respond to all GET requests on a route. You can create an authenticated Supabase client by calling the `createServerClient` function and passing it your `SUPABASE_URL`, `SUPABASE_PUBLISHABLE_KEY`, and a `Request` and `Response`.
<Tabs
scrollable
@@ -167,7 +167,7 @@ export const loader = async ({ request }) => {
const supabaseClient = createServerClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_ANON_KEY,
process.env.SUPABASE_PUBLISHABLE_KEY,
{ request, response }
)
@@ -203,7 +203,7 @@ export const loader = async ({ request }: LoaderFunctionArgs) => {
const response = new Response()
const supabaseClient = createServerClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_ANON_KEY!,
process.env.SUPABASE_PUBLISHABLE_KEY!,
{ request, response }
)
@@ -229,7 +229,7 @@ Supabase will set cookie headers to manage the user's auth session, therefore, t
### Action
Action functions run on the server and respond to HTTP requests to a route, other than GET - POST, PUT, PATCH, DELETE etc. You can create an authenticated Supabase client by calling the `createServerClient` function and passing it your `SUPABASE_URL`, `SUPABASE_ANON_KEY`, and a `Request` and `Response`.
Action functions run on the server and respond to HTTP requests to a route, other than GET - POST, PUT, PATCH, DELETE etc. You can create an authenticated Supabase client by calling the `createServerClient` function and passing it your `SUPABASE_URL`, `SUPABASE_PUBLISHABLE_KEY`, and a `Request` and `Response`.
<Tabs
scrollable
@@ -249,7 +249,7 @@ export const action = async ({ request }) => {
const supabaseClient = createServerClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_ANON_KEY,
process.env.SUPABASE_PUBLISHABLE_KEY,
{ request, response }
)
@@ -284,7 +284,7 @@ export const action = async ({ request }: ActionFunctionArgs) => {
const supabaseClient = createServerClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_ANON_KEY!,
process.env.SUPABASE_PUBLISHABLE_KEY!,
{ request, response }
)
@@ -355,7 +355,7 @@ Since our environment variables are not available client-side, we need to plumb
export const loader = () => {
const env = {
SUPABASE_URL: process.env.SUPABASE_URL,
SUPABASE_ANON_KEY: process.env.SUPABASE_ANON_KEY,
SUPABASE_PUBLISHABLE_KEY: process.env.SUPABASE_PUBLISHABLE_KEY,
}
return json({ env })
@@ -377,7 +377,9 @@ const { env } = useLoaderData()
We then want to instantiate a single instance of a Supabase browser client, to be used across our client-side components.
```jsx app/root.jsx
const [supabase] = useState(() => createBrowserClient(env.SUPABASE_URL, env.SUPABASE_ANON_KEY))
const [supabase] = useState(() =>
createBrowserClient(env.SUPABASE_URL, env.SUPABASE_PUBLISHABLE_KEY)
)
```
And then we can share this instance across our application with Outlet Context.
@@ -393,7 +395,7 @@ And then we can share this instance across our application with Outlet Context.
export const loader = ({}: LoaderFunctionArgs) => {
const env = {
SUPABASE_URL: process.env.SUPABASE_URL!,
SUPABASE_ANON_KEY: process.env.SUPABASE_ANON_KEY!,
SUPABASE_PUBLISHABLE_KEY: process.env.SUPABASE_PUBLISHABLE_KEY!,
}
return json({ env })
@@ -416,7 +418,7 @@ We then want to instantiate a single instance of a Supabase browser client, to b
```tsx app/root.tsx
const [supabase] = useState(() =>
createBrowserClient<Database>(env.SUPABASE_URL, env.SUPABASE_ANON_KEY)
createBrowserClient<Database>(env.SUPABASE_URL, env.SUPABASE_PUBLISHABLE_KEY)
)
```
@@ -453,15 +455,19 @@ Let's pipe that through from our loader.
export const loader = async ({ request }) => {
const env = {
SUPABASE_URL: process.env.SUPABASE_URL,
SUPABASE_ANON_KEY: process.env.SUPABASE_ANON_KEY,
SUPABASE_PUBLISHABLE_KEY: process.env.SUPABASE_PUBLISHABLE_KEY,
}
const response = new Response()
const supabase = createServerClient(process.env.SUPABASE_URL, process.env.SUPABASE_ANON_KEY, {
request,
response,
})
const supabase = createServerClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_PUBLISHABLE_KEY,
{
request,
response,
}
)
const {
data: { session },
@@ -487,15 +493,19 @@ export const loader = async ({ request }) => {
export const loader = async ({ request }: LoaderFunctionArgs) => {
const env = {
SUPABASE_URL: process.env.SUPABASE_URL!,
SUPABASE_ANON_KEY: process.env.SUPABASE_ANON_KEY!,
SUPABASE_PUBLISHABLE_KEY: process.env.SUPABASE_PUBLISHABLE_KEY!,
}
const response = new Response()
const supabase = createServerClient(process.env.SUPABASE_URL!, process.env.SUPABASE_ANON_KEY!, {
request,
response,
})
const supabase = createServerClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_PUBLISHABLE_KEY!,
{
request,
response,
}
)
const {
data: { session },
@@ -533,7 +543,9 @@ And then use the revalidator, inside the `onAuthStateChange` hook.
const { env, session } = useLoaderData()
const { revalidate } = useRevalidator()
const [supabase] = useState(() => createBrowserClient(env.SUPABASE_URL, env.SUPABASE_ANON_KEY))
const [supabase] = useState(() =>
createBrowserClient(env.SUPABASE_URL, env.SUPABASE_PUBLISHABLE_KEY)
)
const serverAccessToken = session?.access_token
@@ -562,7 +574,7 @@ const { env, session } = useLoaderData<typeof loader>()
const { revalidate } = useRevalidator()
const [supabase] = useState(() =>
createBrowserClient<Database>(env.SUPABASE_URL, env.SUPABASE_ANON_KEY)
createBrowserClient<Database>(env.SUPABASE_URL, env.SUPABASE_PUBLISHABLE_KEY)
)
const serverAccessToken = session?.access_token
@@ -703,10 +715,14 @@ import { useEffect, useState } from 'react'
export const loader = async ({ request }) => {
const response = new Response()
const supabase = createServerClient(process.env.SUPABASE_URL, process.env.SUPABASE_ANON_KEY, {
request,
response,
})
const supabase = createServerClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_PUBLISHABLE_KEY,
{
request,
response,
}
)
const { data } = await supabase.from('posts').select()
@@ -760,7 +776,7 @@ export const loader = async ({ request }: LoaderFunctionArgs) => {
const response = new Response()
const supabase = createServerClient<Database>(
process.env.SUPABASE_URL!,
process.env.SUPABASE_ANON_KEY!,
process.env.SUPABASE_PUBLISHABLE_KEY!,
{
request,
response,
@@ -45,7 +45,7 @@ Retrieve your project's URL and anon key from your [API settings](https://supaba
```bash .env.local
# Find these in your Supabase project settings https://supabase.com/dashboard/project/_/settings/api
PUBLIC_SUPABASE_URL=https://your-project.supabase.co
PUBLIC_SUPABASE_ANON_KEY=your-anon-key
PUBLIC_SUPABASE_PUBLISHABLE_KEY=sb_publishable_... or anon key
```
### Creating a Supabase client
@@ -65,13 +65,13 @@ Create a new `hooks.server.js` file in the root of your project and populate wit
```js src/hooks.server.js
// src/hooks.server.js
import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public'
import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_PUBLISHABLE_KEY } from '$env/static/public'
import { createSupabaseServerClient } from '@supabase/auth-helpers-sveltekit'
export const handle = async ({ event, resolve }) => {
event.locals.supabase = createSupabaseServerClient({
supabaseUrl: PUBLIC_SUPABASE_URL,
supabaseKey: PUBLIC_SUPABASE_ANON_KEY,
supabaseKey: PUBLIC_SUPABASE_PUBLISHABLE_KEY,
event,
})
@@ -111,14 +111,14 @@ Create a new `hooks.server.ts` file in the root of your project and populate wit
```ts src/hooks.server.ts
// src/hooks.server.ts
import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public'
import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_PUBLISHABLE_KEY } from '$env/static/public'
import { createSupabaseServerClient } from '@supabase/auth-helpers-sveltekit'
import type { Handle } from '@sveltejs/kit'
export const handle: Handle = async ({ event, resolve }) => {
event.locals.supabase = createSupabaseServerClient({
supabaseUrl: PUBLIC_SUPABASE_URL,
supabaseKey: PUBLIC_SUPABASE_ANON_KEY,
supabaseKey: PUBLIC_SUPABASE_PUBLISHABLE_KEY,
event,
})
@@ -307,7 +307,7 @@ To utilize Supabase in shared load functions and within pages, it is essential t
```ts src/routes/+layout.js
// src/routes/+layout.js
import { PUBLIC_SUPABASE_ANON_KEY, PUBLIC_SUPABASE_URL } from '$env/static/public'
import { PUBLIC_SUPABASE_PUBLISHABLE_KEY, PUBLIC_SUPABASE_URL } from '$env/static/public'
import { createSupabaseLoadClient } from '@supabase/auth-helpers-sveltekit'
export const load = async ({ fetch, data, depends }) => {
@@ -315,7 +315,7 @@ export const load = async ({ fetch, data, depends }) => {
const supabase = createSupabaseLoadClient({
supabaseUrl: PUBLIC_SUPABASE_URL,
supabaseKey: PUBLIC_SUPABASE_ANON_KEY,
supabaseKey: PUBLIC_SUPABASE_PUBLISHABLE_KEY,
event: { fetch },
serverSession: data.session,
})
@@ -339,7 +339,7 @@ export const load = async ({ fetch, data, depends }) => {
```ts src/routes/+layout.ts
// src/routes/+layout.ts
import { PUBLIC_SUPABASE_ANON_KEY, PUBLIC_SUPABASE_URL } from '$env/static/public'
import { PUBLIC_SUPABASE_PUBLISHABLE_KEY, PUBLIC_SUPABASE_URL } from '$env/static/public'
import { createSupabaseLoadClient } from '@supabase/auth-helpers-sveltekit'
import type { Database } from '../DatabaseDefinitions'
@@ -348,7 +348,7 @@ export const load = async ({ fetch, data, depends }) => {
const supabase = createSupabaseLoadClient<Database>({
supabaseUrl: PUBLIC_SUPABASE_URL,
supabaseKey: PUBLIC_SUPABASE_ANON_KEY,
supabaseKey: PUBLIC_SUPABASE_PUBLISHABLE_KEY,
event: { fetch },
serverSession: data.session,
})
@@ -648,7 +648,7 @@ Edit your `/src/hooks.server.js` with the below:
```js src/hooks.server.js
// src/hooks.server.js
import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public'
import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_PUBLISHABLE_KEY } from '$env/static/public'
import { createSupabaseServerClient } from '@supabase/auth-helpers-sveltekit'
import { redirect, error } from '@sveltejs/kit'
import { sequence } from '@sveltejs/kit/hooks'
@@ -656,7 +656,7 @@ import { sequence } from '@sveltejs/kit/hooks'
async function supabase({ event, resolve }) {
event.locals.supabase = createSupabaseServerClient({
supabaseUrl: PUBLIC_SUPABASE_URL,
supabaseKey: PUBLIC_SUPABASE_ANON_KEY,
supabaseKey: PUBLIC_SUPABASE_PUBLISHABLE_KEY,
event,
})
@@ -717,14 +717,14 @@ export const handle = sequence(supabase, authorization)
```ts src/hooks.server.ts
// src/hooks.server.ts
import { type Handle, redirect, error } from '@sveltejs/kit'
import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public'
import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_PUBLISHABLE_KEY } from '$env/static/public'
import { createSupabaseServerClient } from '@supabase/auth-helpers-sveltekit'
import { sequence } from '@sveltejs/kit/hooks'
async function supabase({ event, resolve }) {
event.locals.supabase = createSupabaseServerClient({
supabaseUrl: PUBLIC_SUPABASE_URL,
supabaseKey: PUBLIC_SUPABASE_ANON_KEY,
supabaseKey: PUBLIC_SUPABASE_PUBLISHABLE_KEY,
event,
})
@@ -932,9 +932,12 @@ import { createClient } from '@supabase/auth-helpers-sveltekit'
import { env } from '$env/dynamic/public'
// or use the static env
// import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public';
// import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_PUBLISHABLE_KEY } from '$env/static/public';
export const supabaseClient = createClient(env.PUBLIC_SUPABASE_URL, env.PUBLIC_SUPABASE_ANON_KEY)
export const supabaseClient = createClient(
env.PUBLIC_SUPABASE_URL,
env.PUBLIC_SUPABASE_PUBLISHABLE_KEY
)
```
</TabPanel>
@@ -942,14 +945,14 @@ export const supabaseClient = createClient(env.PUBLIC_SUPABASE_URL, env.PUBLIC_S
```js src/hooks.server.ts
// src/hooks.server.ts
import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public'
import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_PUBLISHABLE_KEY } from '$env/static/public'
import { createSupabaseServerClient } from '@supabase/auth-helpers-sveltekit'
import type { Handle } from '@sveltejs/kit'
export const handle: Handle = async ({ event, resolve }) => {
event.locals.supabase = createSupabaseServerClient({
supabaseUrl: PUBLIC_SUPABASE_URL,
supabaseKey: PUBLIC_SUPABASE_ANON_KEY,
supabaseKey: PUBLIC_SUPABASE_PUBLISHABLE_KEY,
event,
})
@@ -1024,7 +1027,7 @@ In order to use the Supabase library in your client code you will need to setup
```ts src/routes/+layout.ts
// src/routes/+layout.ts
import { invalidate } from '$app/navigation'
import { PUBLIC_SUPABASE_ANON_KEY, PUBLIC_SUPABASE_URL } from '$env/static/public'
import { PUBLIC_SUPABASE_PUBLISHABLE_KEY, PUBLIC_SUPABASE_URL } from '$env/static/public'
import { createSupabaseLoadClient } from '@supabase/auth-helpers-sveltekit'
import type { LayoutLoad } from './$types'
import type { Database } from '../DatabaseDefinitions'
@@ -1034,7 +1037,7 @@ export const load: LayoutLoad = async ({ fetch, data, depends }) => {
const supabase = createSupabaseLoadClient<Database>({
supabaseUrl: PUBLIC_SUPABASE_URL,
supabaseKey: PUBLIC_SUPABASE_ANON_KEY,
supabaseKey: PUBLIC_SUPABASE_PUBLISHABLE_KEY,
event: { fetch },
serverSession: data.session,
})
@@ -1295,12 +1298,16 @@ import { dev } from '$app/environment'
import { env } from '$env/dynamic/public'
// or use the static env
// import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public';
// import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_PUBLISHABLE_KEY } from '$env/static/public';
export const supabaseClient = createClient(env.PUBLIC_SUPABASE_URL, env.PUBLIC_SUPABASE_ANON_KEY, {
persistSession: false,
autoRefreshToken: false,
})
export const supabaseClient = createClient(
env.PUBLIC_SUPABASE_URL,
env.PUBLIC_SUPABASE_PUBLISHABLE_KEY,
{
persistSession: false,
autoRefreshToken: false,
}
)
setupSupabaseHelpers({
supabaseClient,
@@ -1318,9 +1325,12 @@ import { createClient } from '@supabase/auth-helpers-sveltekit'
import { env } from '$env/dynamic/public'
// or use the static env
// import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public';
// import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_PUBLISHABLE_KEY } from '$env/static/public';
export const supabaseClient = createClient(env.PUBLIC_SUPABASE_URL, env.PUBLIC_SUPABASE_ANON_KEY)
export const supabaseClient = createClient(
env.PUBLIC_SUPABASE_URL,
env.PUBLIC_SUPABASE_PUBLISHABLE_KEY
)
```
</TabPanel>
@@ -1646,7 +1656,7 @@ import { createSupabaseClient } from '@supabase/auth-helpers-sveltekit';
const { supabaseClient } = createSupabaseClient(
import.meta.env.VITE_SUPABASE_URL as string,
import.meta.env.VITE_SUPABASE_ANON_KEY as string
import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY as string
);
export { supabaseClient };
@@ -1662,12 +1672,16 @@ import { dev } from '$app/environment'
import { env } from '$env/dynamic/public'
// or use the static env
// import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public';
// import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_PUBLISHABLE_KEY } from '$env/static/public';
export const supabaseClient = createClient(env.PUBLIC_SUPABASE_URL, env.PUBLIC_SUPABASE_ANON_KEY, {
persistSession: false,
autoRefreshToken: false,
})
export const supabaseClient = createClient(
env.PUBLIC_SUPABASE_URL,
env.PUBLIC_SUPABASE_PUBLISHABLE_KEY,
{
persistSession: false,
autoRefreshToken: false,
}
)
setupSupabaseHelpers({
supabaseClient,
+4 -1
View File
@@ -82,7 +82,10 @@ When a user unenrolls a factor, call `supabase.auth.mfa.unenroll()` with the ID
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project-id.supabase.co', 'your-anon-key')
const supabase = createClient(
'https://your-project-id.supabase.co',
'sb_publishable_... or anon key'
)
// ---cut---
supabase.auth.mfa.unenroll({ factorId: 'd30fd651-184e-4748-a928-0a4b9be1d429' })
@@ -195,7 +195,7 @@ To initiate a sign-in request from your application's user interface (i.e. the S
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('<your-project-url>', '<your-anon-key>')
const supabase = createClient('<your-project-url>', '<sb_publishable_... or anon key>')
// ---cut---
supabase.auth.signInWithSSO({
@@ -436,7 +436,7 @@ Yes, also referred to as [cross-origin authentication within the same site](http
```ts
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project.supabase.co', 'your-anon-key')
const supabase = createClient('https://your-project.supabase.co', 'sb_publishable_... or anon key')
// ---cut---
const { data, error } = await supabase.auth.signInWithSSO({
+11 -7
View File
@@ -93,11 +93,15 @@ If you wish to send a JWT from a Third-Party Auth provider, or one you made your
```typescript
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://<supabase-project>.supabase.co', 'SUPABASE_ANON_KEY', {
accessToken: async () => {
return '<your JWT here>'
},
})
const supabase = createClient(
'https://<supabase-project>.supabase.co',
'SUPABASE_PUBLISHABLE_KEY',
{
accessToken: async () => {
return '<your JWT here>'
},
}
)
```
</TabPanel>
@@ -124,7 +128,7 @@ import Supabase
let supabase = SupabaseClient(
supabaseURL: URL(string: "https://<supabase-project>.supabase.co")!,
supabaseKey: "SUPABASE_ANON_KEY",
supabaseKey: "SUPABASE_PUBLISHABLE_KEY",
options: SupabaseClientOptions(
auth: SupabaseClientOptions.AuthOptions(
accessToken: {
@@ -142,7 +146,7 @@ let supabase = SupabaseClient(
```kotlin
val supabase = createSupabaseClient(
"https://<supabase-project>.supabase.co",
"SUPABASE_ANON_KEY"
"SUPABASE_PUBLISHABLE_KEY"
) {
accessToken = {
"<your JWT here>"
@@ -102,7 +102,7 @@ With Deep Linking, you can configure this redirect to open a specific page. This
return (
<>
<Button onPress={performOAuth} title="Sign in with Github" />
<Button onPress={performOAuth} title="Sign in with GitHub" />
<Button onPress={sendMagicLink} title="Send Magic Link" />
</>
);
+35 -27
View File
@@ -57,7 +57,7 @@ If you don't specify a redirect URL, the user is automatically redirected to you
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project.supabase.co', 'your-anon-key')
const supabase = createClient('https://your-project.supabase.co', 'sb_publishable_... or anon key')
// ---cut---
async function signUpNewUser() {
@@ -266,7 +266,7 @@ export const GET: APIRoute = async ({ request, cookies, redirect }) => {
if (token_hash && type) {
const supabase = createServerClient(
import.meta.env.PUBLIC_SUPABASE_URL,
import.meta.env.PUBLIC_SUPABASE_ANON_KEY,
import.meta.env.PUBLIC_SUPABASE_PUBLISHABLE_KEY,
{
cookies: {
getAll() {
@@ -313,16 +313,20 @@ export async function loader({ request }: LoaderFunctionArgs) {
const headers = new Headers()
if (token_hash && type) {
const supabase = createServerClient(process.env.SUPABASE_URL!, process.env.SUPABASE_ANON_KEY!, {
cookies: {
getAll() {
return parseCookieHeader(request.headers.get('Cookie') ?? '')
const supabase = createServerClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_PUBLISHABLE_KEY!,
{
cookies: {
getAll() {
return parseCookieHeader(request.headers.get('Cookie') ?? '')
},
setAll(key, value, options) {
headers.append('Set-Cookie', serializeCookieHeader(key, value, options))
},
},
setAll(key, value, options) {
headers.append('Set-Cookie', serializeCookieHeader(key, value, options))
},
},
})
}
)
const { error } = await supabase.auth.verifyOtp({
type,
@@ -390,7 +394,7 @@ If you don't specify a redirect URL, the user is automatically redirected to you
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project.supabase.co', 'your-anon-key')
const supabase = createClient('https://your-project.supabase.co', 'sb_publishable_... or anon key')
// ---cut---
async function signUpNewUser() {
@@ -477,7 +481,7 @@ When your user signs in, call [`signInWithPassword()`](/docs/reference/javascrip
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project.supabase.co', 'your-anon-key')
const supabase = createClient('https://your-project.supabase.co', 'sb_publishable_... or anon key')
// ---cut---
async function signInWithEmail() {
@@ -570,7 +574,7 @@ Collect the user's email address and request a password reset email. Specify the
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project.supabase.co', 'your-anon-key')
const supabase = createClient('https://your-project.supabase.co', 'sb_publishable_... or anon key')
// ---cut---
await supabase.auth.resetPasswordForEmail('valid.email@supabase.io', {
@@ -749,7 +753,7 @@ export const GET: APIRoute = async ({ request, cookies, redirect }) => {
if (token_hash && type) {
const supabase = createServerClient(
import.meta.env.PUBLIC_SUPABASE_URL,
import.meta.env.PUBLIC_SUPABASE_ANON_KEY,
import.meta.env.PUBLIC_SUPABASE_PUBLISHABLE_KEY,
{
cookies: {
getAll() {
@@ -796,16 +800,20 @@ export async function loader({ request }: LoaderFunctionArgs) {
const headers = new Headers()
if (token_hash && type) {
const supabase = createServerClient(process.env.SUPABASE_URL!, process.env.SUPABASE_ANON_KEY!, {
cookies: {
getAll() {
return parseCookieHeader(request.headers.get('Cookie') ?? '')
const supabase = createServerClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_PUBLISHABLE_KEY!,
{
cookies: {
getAll() {
return parseCookieHeader(request.headers.get('Cookie') ?? '')
},
setAll(key, value, options) {
headers.append('Set-Cookie', serializeCookieHeader(key, value, options))
},
},
setAll(key, value, options) {
headers.append('Set-Cookie', serializeCookieHeader(key, value, options))
},
},
})
}
)
const { error } = await supabase.auth.verifyOtp({
type,
@@ -1004,7 +1012,7 @@ To sign up the user, call [`signUp()`](/docs/reference/javascript/auth-signup) w
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project.supabase.co', 'your-anon-key')
const supabase = createClient('https://your-project.supabase.co', 'sb_publishable_... or anon key')
// ---cut---
const { data, error } = await supabase.auth.signUp({
@@ -1074,7 +1082,7 @@ You should present a form to the user so they can input the 6 digit pin, then se
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project.supabase.co', 'your-anon-key')
const supabase = createClient('https://your-project.supabase.co', 'sb_publishable_... or anon key')
// ---cut---
const {
@@ -1158,7 +1166,7 @@ Call the function to sign in with the user's phone number and password:
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project.supabase.co', 'your-anon-key')
const supabase = createClient('https://your-project.supabase.co', 'sb_publishable_... or anon key')
// ---cut---
const { data, error } = await supabase.auth.signInWithPassword({
@@ -60,7 +60,7 @@ hideToc: true
```text name=.env.local
NEXT_PUBLIC_SUPABASE_URL=your-project-url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=sb_publishable_... or anon key
```
</StepHikeCompact.Code>
@@ -77,7 +77,7 @@ hideToc: true
import { createClient, processLock } from '@supabase/supabase-js'
const supabaseUrl = YOUR_REACT_NATIVE_SUPABASE_URL
const supabaseAnonKey = YOUR_REACT_NATIVE_SUPABASE_ANON_KEY
const supabaseAnonKey = YOUR_REACT_NATIVE_SUPABASE_PUBLISHABLE_KEY
export const supabase = createClient(supabaseUrl, supabaseAnonKey, {
auth: {
@@ -78,7 +78,7 @@ hideToc: true
import { Auth } from '@supabase/auth-ui-react'
import { ThemeSupa } from '@supabase/auth-ui-shared'
const supabase = createClient('https://<project>.supabase.co', '<your-anon-key>')
const supabase = createClient('https://<project>.supabase.co', '<sb_publishable_... or anon key>')
export default function App() {
const [session, setSession] = useState(null)
@@ -50,7 +50,7 @@ In your environment variables file, set your Supabase URL and Supabase Anon Key:
```bash .env.local
NEXT_PUBLIC_SUPABASE_URL=your_supabase_project_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=sb_publishable_... or anon keyY
```
</TabPanel>
@@ -58,7 +58,7 @@ NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
```bash .env.local
PUBLIC_SUPABASE_URL=your_supabase_project_url
PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
PUBLIC_SUPABASE_PUBLISHABLE_KEY=sb_publishable_... or anon keyY
```
</TabPanel>
@@ -66,7 +66,7 @@ PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
```bash .env
PUBLIC_SUPABASE_URL=your_supabase_project_url
PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
PUBLIC_SUPABASE_PUBLISHABLE_KEY=sb_publishable_... or anon keyY
```
</TabPanel>
@@ -74,7 +74,7 @@ PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
```bash .env
SUPABASE_URL=your_supabase_project_url
SUPABASE_ANON_KEY=your_supabase_anon_key
SUPABASE_PUBLISHABLE_KEY=sb_publishable_... or anon keyY
```
</TabPanel>
@@ -90,7 +90,7 @@ SUPABASE_ANON_KEY=your_supabase_anon_key
```bash .env
SUPABASE_URL=your_supabase_project_url
SUPABASE_ANON_KEY=your_supabase_anon_key
SUPABASE_PUBLISHABLE_KEY=sb_publishable_... or anon keyY
```
Install [dotenv](https://www.npmjs.com/package/dotenv):
@@ -134,7 +134,7 @@ pnpm add dotenv
```bash .env
SUPABASE_URL=your_supabase_project_url
SUPABASE_ANON_KEY=your_supabase_anon_key
SUPABASE_PUBLISHABLE_KEY=sb_publishable_... or anon keyY
```
</TabPanel>
@@ -172,7 +172,7 @@ import { createBrowserClient } from '@supabase/ssr'
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!
)
}
```
@@ -190,7 +190,7 @@ export async function createClient() {
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,
{
cookies: {
getAll() {
@@ -252,7 +252,7 @@ export async function updateSession(request: NextRequest) {
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,
{
cookies: {
getAll() {
@@ -324,12 +324,12 @@ export async function updateSession(request: NextRequest) {
<TabPanel id="hooks" label="Hooks">
```ts hooks.server.ts
import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public'
import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_PUBLISHABLE_KEY } from '$env/static/public'
import { createServerClient } from '@supabase/ssr'
import type { Handle } from '@sveltejs/kit'
export const handle: Handle = async ({ event, resolve }) => {
event.locals.supabase = createServerClient(PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY, {
event.locals.supabase = createServerClient(PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_PUBLISHABLE_KEY, {
cookies: {
getAll() {
return event.cookies.getAll()
@@ -388,7 +388,7 @@ export const handle: Handle = async ({ event, resolve }) => {
Page components can get access to the Supabase client from the `data` object due to this load function.
```ts +layout.ts
import { PUBLIC_SUPABASE_ANON_KEY, PUBLIC_SUPABASE_URL } from '$env/static/public'
import { PUBLIC_SUPABASE_PUBLISHABLE_KEY, PUBLIC_SUPABASE_URL } from '$env/static/public'
import type { LayoutLoad } from './$types'
import { createBrowserClient, createServerClient, isBrowser } from '@supabase/ssr'
@@ -396,12 +396,12 @@ export const load: LayoutLoad = async ({ fetch, data, depends }) => {
depends('supabase:auth')
const supabase = isBrowser()
? createBrowserClient(PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY, {
? createBrowserClient(PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_PUBLISHABLE_KEY, {
global: {
fetch,
},
})
: createServerClient(PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY, {
: createServerClient(PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_PUBLISHABLE_KEY, {
global: {
fetch,
},
@@ -475,7 +475,7 @@ import { createServerClient, parseCookieHeader } from "@supabase/ssr";
const supabase = createServerClient(
import.meta.env.PUBLIC_SUPABASE_URL,
import.meta.env.PUBLIC_SUPABASE_ANON_KEY,
import.meta.env.PUBLIC_SUPABASE_PUBLISHABLE_KEY,
{
cookies: {
getAll() {
@@ -501,7 +501,7 @@ const supabase = createServerClient(
const supabase = createBrowserClient(
import.meta.env.PUBLIC_SUPABASE_URL,
import.meta.env.PUBLIC_SUPABASE_ANON_KEY
import.meta.env.PUBLIC_SUPABASE_PUBLISHABLE_KEY
);
</script>
```
@@ -517,7 +517,7 @@ import type { APIContext } from "astro";
export async function GET(context: APIContext) {
const supabase = createServerClient(
import.meta.env.PUBLIC_SUPABASE_URL,
import.meta.env.PUBLIC_SUPABASE_ANON_KEY,
import.meta.env.PUBLIC_SUPABASE_PUBLISHABLE_KEY,
{
cookies: {
getAll() {
@@ -546,7 +546,7 @@ import { defineMiddleware } from 'astro:middleware'
export const onRequest = defineMiddleware(async (context, next) => {
const supabase = createServerClient(
import.meta.env.PUBLIC_SUPABASE_URL,
import.meta.env.PUBLIC_SUPABASE_ANON_KEY,
import.meta.env.PUBLIC_SUPABASE_PUBLISHABLE_KEY,
{
cookies: {
getAll() {
@@ -587,18 +587,22 @@ import { createServerClient, parseCookieHeader, serializeCookieHeader } from '@s
export async function loader({ request }: LoaderFunctionArgs) {
const headers = new Headers()
const supabase = createServerClient(process.env.SUPABASE_URL!, process.env.SUPABASE_ANON_KEY!, {
cookies: {
getAll() {
return parseCookieHeader(request.headers.get('Cookie') ?? '')
const supabase = createServerClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_PUBLISHABLE_KEY!,
{
cookies: {
getAll() {
return parseCookieHeader(request.headers.get('Cookie') ?? '')
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) =>
headers.append('Set-Cookie', serializeCookieHeader(name, value, options))
)
},
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) =>
headers.append('Set-Cookie', serializeCookieHeader(name, value, options))
)
},
},
})
}
)
return new Response('...', {
headers,
@@ -617,18 +621,22 @@ import { createServerClient, parseCookieHeader, serializeCookieHeader } from '@s
export async function action({ request }: ActionFunctionArgs) {
const headers = new Headers()
const supabase = createServerClient(process.env.SUPABASE_URL!, process.env.SUPABASE_ANON_KEY!, {
cookies: {
getAll() {
return parseCookieHeader(request.headers.get('Cookie') ?? '')
const supabase = createServerClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_PUBLISHABLE_KEY!,
{
cookies: {
getAll() {
return parseCookieHeader(request.headers.get('Cookie') ?? '')
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) =>
headers.append('Set-Cookie', serializeCookieHeader(name, value, options))
)
},
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) =>
headers.append('Set-Cookie', serializeCookieHeader(name, value, options))
)
},
},
})
}
)
return new Response('...', {
headers,
@@ -649,7 +657,7 @@ export async function loader({}: LoaderFunctionArgs) {
return {
env: {
SUPABASE_URL: process.env.SUPABASE_URL!,
SUPABASE_ANON_KEY: process.env.SUPABASE_ANON_KEY!,
SUPABASE_PUBLISHABLE_KEY: process.env.SUPABASE_PUBLISHABLE_KEY!,
},
};
}
@@ -657,7 +665,7 @@ export async function loader({}: LoaderFunctionArgs) {
export default function Index() {
const { env } = useLoaderData<typeof loader>();
const supabase = createBrowserClient(env.SUPABASE_URL, env.SUPABASE_ANON_KEY);
const supabase = createBrowserClient(env.SUPABASE_URL, env.SUPABASE_PUBLISHABLE_KEY);
return ...
}
@@ -782,7 +790,7 @@ export default function Index() {
const { createServerClient, parseCookieHeader, serializeCookieHeader } = require('@supabase/ssr')
exports.createClient = (context) => {
return createServerClient(process.env.SUPABASE_URL, process.env.SUPABASE_ANON_KEY, {
return createServerClient(process.env.SUPABASE_URL, process.env.SUPABASE_PUBLISHABLE_KEY, {
cookies: {
getAll() {
return parseCookieHeader(context.req.headers.cookie ?? '')
@@ -853,21 +861,21 @@ export const getSupabase = (c: Context) => {
type SupabaseEnv = {
SUPABASE_URL: string
SUPABASE_ANON_KEY: string
SUPABASE_PUBLISHABLE_KEY: string
}
export const supabaseMiddleware = (): MiddlewareHandler => {
return async (c, next) => {
const supabaseEnv = env<SupabaseEnv>(c)
const supabaseUrl = supabaseEnv.SUPABASE_URL
const supabaseAnonKey = supabaseEnv.SUPABASE_ANON_KEY
const supabaseAnonKey = supabaseEnv.SUPABASE_PUBLISHABLE_KEY
if (!supabaseUrl) {
throw new Error('SUPABASE_URL missing!')
}
if (!supabaseAnonKey) {
throw new Error('SUPABASE_ANON_KEY missing!')
throw new Error('SUPABASE_PUBLISHABLE_KEY missing!')
}
const supabase = createServerClient(supabaseUrl, supabaseAnonKey, {
@@ -36,7 +36,7 @@ npm install @supabase/supabase-js @supabase/ssr
Create a `.env.local` file in your project root directory.
Fill in your `NEXT_PUBLIC_SUPABASE_URL` and `NEXT_PUBLIC_SUPABASE_ANON_KEY`:
Fill in your `NEXT_PUBLIC_SUPABASE_URL` and `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY`:
<ProjectConfigVariables variable="url" />
<ProjectConfigVariables variable="anonKey" />
@@ -49,7 +49,7 @@ Fill in your `NEXT_PUBLIC_SUPABASE_URL` and `NEXT_PUBLIC_SUPABASE_ANON_KEY`:
```txt name=.env.local
NEXT_PUBLIC_SUPABASE_URL=<your_supabase_project_url>
NEXT_PUBLIC_SUPABASE_ANON_KEY=<your_supabase_anon_key>
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=<sb_publishable_... or anon keyY>
```
</$CodeTabs>
@@ -120,7 +120,7 @@ import { createBrowserClient } from '@supabase/ssr'
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!
)
}
```
@@ -134,7 +134,7 @@ export async function createClient() {
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,
{
cookies: {
getAll() {
@@ -232,7 +232,7 @@ export async function updateSession(request: NextRequest) {
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,
{
cookies: {
getAll() {
@@ -264,7 +264,8 @@ export async function updateSession(request: NextRequest) {
if (
!user &&
!request.nextUrl.pathname.startsWith('/login') &&
!request.nextUrl.pathname.startsWith('/auth')
!request.nextUrl.pathname.startsWith('/auth') &&
!request.nextUrl.pathname.startsWith('/error')
) {
// no user, potentially respond by redirecting the user to the login page
const url = request.nextUrl.clone()
@@ -556,7 +557,7 @@ npm install @supabase/supabase-js @supabase/ssr
Create a `.env.local` file in your project root directory.
Fill in your `NEXT_PUBLIC_SUPABASE_URL` and `NEXT_PUBLIC_SUPABASE_ANON_KEY`:
Fill in your `NEXT_PUBLIC_SUPABASE_URL` and `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY`:
<ProjectConfigVariables variable="url" />
<ProjectConfigVariables variable="anonKey" />
@@ -567,7 +568,7 @@ Fill in your `NEXT_PUBLIC_SUPABASE_URL` and `NEXT_PUBLIC_SUPABASE_ANON_KEY`:
```txt name=.env.local
NEXT_PUBLIC_SUPABASE_URL=<your_supabase_project_url>
NEXT_PUBLIC_SUPABASE_ANON_KEY=<your_supabase_anon_key>
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=<sb_publishable_... or anon keyY>
```
</StepHikeCompact.Code>
@@ -639,7 +640,7 @@ import { createServerClient, serializeCookieHeader } from '@supabase/ssr'
export function createClient({ req, res }: GetServerSidePropsContext) {
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,
{
cookies: {
getAll() {
@@ -667,7 +668,7 @@ import { createClient as createClientPrimitive } from '@supabase/supabase-js'
export function createClient() {
const supabase = createClientPrimitive(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!
)
return supabase
@@ -680,7 +681,7 @@ import { createBrowserClient } from '@supabase/ssr'
export function createClient() {
const supabase = createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!
)
return supabase
@@ -694,7 +695,7 @@ import { type NextApiRequest, type NextApiResponse } from 'next'
export default function createClient(req: NextApiRequest, res: NextApiResponse) {
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,
{
cookies: {
getAll() {
@@ -31,7 +31,7 @@ npm install @supabase/supabase-js @supabase/ssr
Create a `.env.local` file in your project root directory.
Fill in your `PUBLIC_SUPABASE_URL` and `PUBLIC_SUPABASE_ANON_KEY`:
Fill in your `PUBLIC_SUPABASE_URL` and `PUBLIC_SUPABASE_PUBLISHABLE_KEY`:
<ProjectConfigVariables variable="url" />
<ProjectConfigVariables variable="anonKey" />
@@ -44,7 +44,7 @@ Fill in your `PUBLIC_SUPABASE_URL` and `PUBLIC_SUPABASE_ANON_KEY`:
```txt name=.env.local
PUBLIC_SUPABASE_URL=<your_supabase_project_url>
PUBLIC_SUPABASE_ANON_KEY=<your_supabase_anon_key>
PUBLIC_SUPABASE_PUBLISHABLE_KEY=<sb_publishable_... or anon keyY>
```
</$CodeTabs>
@@ -74,7 +74,7 @@ import { createServerClient } from '@supabase/ssr'
import { type Handle, redirect } from '@sveltejs/kit'
import { sequence } from '@sveltejs/kit/hooks'
import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public'
import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_PUBLISHABLE_KEY } from '$env/static/public'
const supabase: Handle = async ({ event, resolve }) => {
/**
@@ -82,7 +82,7 @@ const supabase: Handle = async ({ event, resolve }) => {
*
* The Supabase client gets the Auth token from the request cookies.
*/
event.locals.supabase = createServerClient(PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY, {
event.locals.supabase = createServerClient(PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_PUBLISHABLE_KEY, {
cookies: {
getAll: () => event.cookies.getAll(),
/**
@@ -215,7 +215,7 @@ Create a Supabase client in your root `+layout.ts`. This client can be used to a
```ts name=src/routes/+layout.ts
import { createBrowserClient, createServerClient, isBrowser } from '@supabase/ssr'
import { PUBLIC_SUPABASE_ANON_KEY, PUBLIC_SUPABASE_URL } from '$env/static/public'
import { PUBLIC_SUPABASE_PUBLISHABLE_KEY, PUBLIC_SUPABASE_URL } from '$env/static/public'
import type { LayoutLoad } from './$types'
export const load: LayoutLoad = async ({ data, depends, fetch }) => {
@@ -226,12 +226,12 @@ export const load: LayoutLoad = async ({ data, depends, fetch }) => {
depends('supabase:auth')
const supabase = isBrowser()
? createBrowserClient(PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY, {
? createBrowserClient(PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_PUBLISHABLE_KEY, {
global: {
fetch,
},
})
: createServerClient(PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY, {
: createServerClient(PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_PUBLISHABLE_KEY, {
global: {
fetch,
},
+1 -1
View File
@@ -130,7 +130,7 @@ Because of this, the Supabase JavaScript libraries provide only limited support.
```typescript
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('SUPABASE_URL', 'SUPABASE_ANON_KEY', {
const supabase = createClient('SUPABASE_URL', 'SUPABASE_PUBLISHABLE_KEY', {
auth: {
storage: {
getItem: () => {
@@ -63,7 +63,7 @@ Putting it all together, your client library initialization may look like this:
import { createClient } from '@supabase/supabase-js'
// ---cut---
const supabase = createClient('https://xyzcompany.supabase.co', 'public-anon-key', {
const supabase = createClient('https://xyzcompany.supabase.co', 'publishable-or-anon-key', {
// ...
auth: {
// ...
+8 -2
View File
@@ -18,7 +18,10 @@ Call the sign out method from the client library. It removes the active session
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project-id.supabase.co', 'your-anon-key')
const supabase = createClient(
'https://your-project-id.supabase.co',
'sb_publishable_... or anon key'
)
// ---cut---
async function signOut() {
@@ -82,7 +85,10 @@ You can invoke these by providing the `scope` option:
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project-id.supabase.co', 'your-anon-key')
const supabase = createClient(
'https://your-project-id.supabase.co',
'sb_publishable_... or anon key'
)
// ---cut---
// defaults to the global scope
@@ -43,7 +43,7 @@ When developing with Expo, you can test Sign in with Apple via the Expo Go app,
```ts
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project.supabase.co', 'your-anon-key')
const supabase = createClient('https://your-project.supabase.co', 'sb_publishable_... or anon key')
// ---cut---
supabase.auth.signInWithOAuth({
@@ -150,7 +150,7 @@ When your user signs in, call [`signInWithOAuth()`](/docs/reference/javascript/a
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project.supabase.co', 'your-anon-key')
const supabase = createClient('https://your-project.supabase.co', 'sb_publishable_... or anon key')
// ---cut---
async function signInWithAzure() {
@@ -210,7 +210,7 @@ When your user signs out, call [signOut()](/docs/reference/javascript/auth-signo
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project.supabase.co', 'your-anon-key')
const supabase = createClient('https://your-project.supabase.co', 'sb_publishable_... or anon key')
// ---cut---
async function signOut() {
@@ -258,7 +258,7 @@ Azure OAuth2.0 doesn't return the `provider_refresh_token` by default. If you ne
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project.supabase.co', 'your-anon-key')
const supabase = createClient('https://your-project.supabase.co', 'sb_publishable_... or anon key')
// ---cut---
async function signInWithAzure() {
@@ -61,7 +61,10 @@ When your user signs in, call [`signInWithOAuth()`](/docs/reference/javascript/a
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project-id.supabase.co', 'your-anon-key')
const supabase = createClient(
'https://your-project-id.supabase.co',
'sb_publishable_... or anon key'
)
// ---cut---
async function signInWithBitbucket() {
@@ -116,7 +119,10 @@ When your user signs out, call [signOut()](/docs/reference/javascript/auth-signo
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project-id.supabase.co', 'your-anon-key')
const supabase = createClient(
'https://your-project-id.supabase.co',
'sb_publishable_... or anon key'
)
// ---cut---
async function signOut() {
@@ -78,7 +78,10 @@ When your user signs in, call [`signInWithOAuth()`](/docs/reference/javascript/a
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project-id.supabase.co', 'your-anon-key')
const supabase = createClient(
'https://your-project-id.supabase.co',
'sb_publishable_... or anon key'
)
// ---cut---
async function signInWithDiscord() {
@@ -135,7 +138,10 @@ When your user signs out, call [signOut()](/docs/reference/javascript/auth-signo
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project-id.supabase.co', 'your-anon-key')
const supabase = createClient(
'https://your-project-id.supabase.co',
'sb_publishable_... or anon key'
)
// ---cut---
async function signOut() {
@@ -95,7 +95,7 @@ When your user signs in, call [`signInWithOAuth()`](/docs/reference/javascript/a
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project.supabase.co', 'your-anon-key')
const supabase = createClient('https://your-project.supabase.co', 'sb_publishable_... or anon key')
// ---cut---
async function signInWithFacebook() {
@@ -170,7 +170,7 @@ When your user signs out, call [signOut()](/docs/reference/javascript/auth-signo
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project.supabase.co', 'your-anon-key')
const supabase = createClient('https://your-project.supabase.co', 'sb_publishable_... or anon key')
// ---cut---
async function signOut() {
@@ -61,7 +61,7 @@ When your user signs in, call [`signInWithOAuth()`](/docs/reference/javascript/a
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('<your-project-url>', '<your-anon-key>')
const supabase = createClient('<your-project-url>', '<sb_publishable_... or anon key>')
// ---cut---
async function signInWithFigma() {
@@ -116,7 +116,7 @@ When your user signs out, call [signOut()](/docs/reference/javascript/auth-signo
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('<your-project-url>', '<your-anon-key>')
const supabase = createClient('<your-project-url>', '<sb_publishable_... or anon key>')
// ---cut---
async function signOut() {
@@ -73,7 +73,10 @@ When your user signs in, call [`signInWithOAuth()`](/docs/reference/javascript/a
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project-id.supabase.co', 'your-anon-key')
const supabase = createClient(
'https://your-project-id.supabase.co',
'sb_publishable_... or anon key'
)
// ---cut---
async function signInWithGithub() {
@@ -116,7 +119,7 @@ func signInWithGithub() async throws {
</TabPanel>
<TabPanel id="kotlin" label="Kotlin">
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Github` as the `Provider`:
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with [`Github`](https://github.com/supabase-community/supabase-kt/blob/master/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/providers/Providers.kt#L16-L20) as the `Provider`:
```kotlin
suspend fun signInWithGithub() {
@@ -142,7 +145,10 @@ When your user signs out, call [signOut()](/docs/reference/javascript/auth-signo
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project-id.supabase.co', 'your-anon-key')
const supabase = createClient(
'https://your-project-id.supabase.co',
'sb_publishable_... or anon key'
)
// ---cut---
async function signOut() {
@@ -58,7 +58,10 @@ When your user signs in, call [`signInWithOAuth()`](/docs/reference/javascript/a
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project-id.supabase.co', 'your-anon-key')
const supabase = createClient(
'https://your-project-id.supabase.co',
'sb_publishable_... or anon key'
)
// ---cut---
async function signInWithGitLab() {
@@ -113,7 +116,10 @@ When your user signs out, call [signOut()](/docs/reference/javascript/auth-signo
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project-id.supabase.co', 'your-anon-key')
const supabase = createClient(
'https://your-project-id.supabase.co',
'sb_publishable_... or anon key'
)
// ---cut---
async function signOut() {
@@ -270,7 +270,7 @@ Google does not send out a refresh token by default, so you will need to pass pa
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project.supabase.co', 'your-anon-key')
const supabase = createClient('https://your-project.supabase.co', 'sb_publishable_... or anon key')
// ---cut---
const { data, error } = await supabase.auth.signInWithOAuth({
@@ -397,7 +397,7 @@ const OneTapComponent = () => {
const supabase = createClient()
const router = useRouter()
const initializeGoogleOneTap = () => {
const initializeGoogleOneTap = async () => {
console.log('Initializing Google One Tap')
const [nonce, hashedNonce] = await generateNonce()
console.log('Nonce: ', nonce, hashedNonce)
@@ -801,4 +801,5 @@ chrome.identity.launchWebAuthFlow(
By default, the Google consent screen shows the root domain of the callback URL, where Google will send the authentication response. With Supabase Auth, it is your Supabase project's domain `(https://<your-project-ref>.supabase.co)`.
If that is not preferable, you can use a [Custom Domain](https://supabase.com/docs/guides/platform/custom-domains) with your Supabase project. You can use it as your project's domain when creating the Supabase client in your application and initiating the authentication flow. It will then show up in the Google consent screen. If you want your app name and the logo on the consent screen, [you must submit your app to Google for verification](https://support.google.com/cloud/answer/10311615).
You can change this domain in the settings for your Google app. Go to Google App Platform, click on Branding, and then set your application home page, privacy policy, and terms of use. You can also add your logo.
Next, go to Audience and click publish. Google will need to verify the app, which usually takes around 24 hours.
@@ -85,7 +85,7 @@ When your user signs in, call [`signInWithOAuth()`](/docs/reference/javascript/a
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('<your-project-url>', '<your-anon-key>')
const supabase = createClient('<your-project-url>', '<sb_publishable_... or anon key>')
// ---cut---
async function signInWithKakao() {
@@ -76,7 +76,7 @@ When your user signs in, call [`signInWithOAuth()`](/docs/reference/javascript/a
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('<your-project-url>', '<your-anon-key>')
const supabase = createClient('<your-project-url>', '<sb_publishable_... or anon key>')
// ---cut---
async function signInWithKeycloak() {
@@ -158,7 +158,7 @@ When your user signs out, call [signOut()](/docs/reference/kotlin/auth-signout)
```kotlin
import { createClient } from '@supabase/supabase-js';
const supabase = createClient('<your-project-url>', '<your-anon-key>');
const supabase = createClient('<your-project-url>', '<sb_publishable_... or anon key>');
// ---cut---
suspend fun signOut() {
@@ -81,7 +81,7 @@ When your user signs in, call [`signInWithOAuth()`](/docs/reference/javascript/a
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('<your-project-url>', '<your-anon-key>')
const supabase = createClient('<your-project-url>', '<sb_publishable_... or anon key>')
// ---cut---
async function signInWithLinkedIn() {
@@ -136,7 +136,7 @@ When your user signs out, call [signOut()](/docs/reference/javascript/auth-signo
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('<your-project-url>', '<your-anon-key>')
const supabase = createClient('<your-project-url>', '<sb_publishable_... or anon key>')
// ---cut---
async function signOut() {
@@ -61,7 +61,7 @@ When your user signs in, call [`signInWithOAuth()`](/docs/reference/javascript/a
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('<your-project-url>', '<your-anon-key>')
const supabase = createClient('<your-project-url>', '<sb_publishable_... or anon key>')
// ---cut---
async function signInWithNotion() {
@@ -116,7 +116,7 @@ When your user signs out, call [signOut()](/docs/reference/javascript/auth-signo
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('<your-project-url>', '<your-anon-key>')
const supabase = createClient('<your-project-url>', '<sb_publishable_... or anon key>')
// ---cut---
async function signOut() {
@@ -97,7 +97,7 @@ When your user signs in, call [`signInWithOAuth()`](/docs/reference/javascript/a
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('<your-project-url>', '<your-anon-key>')
const supabase = createClient('<your-project-url>', '<sb_publishable_... or anon key>')
// ---cut---
async function signInWithSlack() {
@@ -152,7 +152,7 @@ When your user signs out, call [signOut()](/docs/reference/javascript/auth-signo
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('<your-project-url>', '<your-anon-key>')
const supabase = createClient('<your-project-url>', '<sb_publishable_... or anon key>')
// ---cut---
async function signOut() {
@@ -91,7 +91,7 @@ When your user signs in, call [`signInWithOAuth()`](/docs/reference/javascript/a
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('<your-project-url>', '<your-anon-key>')
const supabase = createClient('<your-project-url>', '<sb_publishable_... or anon key>')
// ---cut---
async function signInWithSpotify() {
@@ -146,7 +146,7 @@ When your user signs out, call [signOut()](/docs/reference/javascript/auth-signo
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('<your-project-url>', '<your-anon-key>')
const supabase = createClient('<your-project-url>', '<sb_publishable_... or anon key>')
// ---cut---
async function signOut() {
@@ -76,7 +76,7 @@ When your user signs in, call [`signInWithOAuth()`](/docs/reference/javascript/a
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('<your-project-url>', '<your-anon-key>')
const supabase = createClient('<your-project-url>', '<sb_publishable_... or anon key>')
// ---cut---
async function signInWithTwitch() {
@@ -131,7 +131,7 @@ When your user signs out, call [signOut()](/docs/reference/javascript/auth-signo
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('<your-project-url>', '<your-anon-key>')
const supabase = createClient('<your-project-url>', '<sb_publishable_... or anon key>')
// ---cut---
async function signOut() {
@@ -85,7 +85,10 @@ When your user signs in, call [`signInWithOAuth()`](/docs/reference/javascript/a
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project-id.supabase.co', 'your-anon-key')
const supabase = createClient(
'https://your-project-id.supabase.co',
'sb_publishable_... or anon key'
)
// ---cut---
async function signInWithTwitter() {
@@ -140,7 +143,10 @@ When your user signs out, call [signOut()](/docs/reference/javascript/auth-signo
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://your-project-id.supabase.co', 'your-anon-key')
const supabase = createClient(
'https://your-project-id.supabase.co',
'sb_publishable_... or anon key'
)
// ---cut---
async function signOut() {
@@ -73,7 +73,7 @@ When a user signs in, call `signInWithOAuth` with `workos` as the provider.
```javascript
import { createClient } from '@supabase/supabase-js';
const supabase = createClient('<your-project-url>', '<your-anon-key>');
const supabase = createClient('<your-project-url>', '<sb_publishable_... or anon key>');
const redirect = (url: string) => {}
// ---cut---
@@ -92,7 +92,7 @@ When your user signs in, call [`signInWithOAuth()`](/docs/reference/javascript/a
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('<your-project-url>', '<your-anon-key>')
const supabase = createClient('<your-project-url>', '<sb_publishable_... or anon key>')
// ---cut---
async function signInWithZoom() {
@@ -147,7 +147,7 @@ When your user signs out, call [signOut()](/docs/reference/javascript/auth-signo
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('<your-project-url>', '<your-anon-key>')
const supabase = createClient('<your-project-url>', '<sb_publishable_... or anon key>')
// ---cut---
async function signOut() {
+15 -11
View File
@@ -31,16 +31,20 @@ const auth0 = new Auth0Client({
},
})
const supabase = createClient('https://<supabase-project>.supabase.co', 'SUPABASE_ANON_KEY', {
accessToken: async () => {
const accessToken = await auth0.getTokenSilently()
const supabase = createClient(
'https://<supabase-project>.supabase.co',
'SUPABASE_PUBLISHABLE_KEY',
{
accessToken: async () => {
const accessToken = await auth0.getTokenSilently()
// Alternatively you can use (await auth0.getIdTokenClaims()).__raw to
// use an ID token instead.
// Alternatively you can use (await auth0.getIdTokenClaims()).__raw to
// use an ID token instead.
return accessToken
},
})
return accessToken
},
}
)
```
</TabPanel>
@@ -57,7 +61,7 @@ extension CredentialsManager {
let supabase = SupabaseClient(
supabaseURL: URL(string: "https://<supabase-project>.supabase.co")!,
supabaseKey: "SUPABASE_ANON_KEY",
supabaseKey: "SUPABASE_PUBLISHABLE_KEY",
options: SupabaseClientOptions(
auth: SupabaseClientOptions.AuthOptions(
accessToken: {
@@ -81,7 +85,7 @@ Future<void> main() async {
final auth0 = Auth0('AUTH0_DOMAIN', 'AUTH0_CLIENT_ID');
await Supabase.initialize(
url: 'https://<supabase-project>.supabase.co',
anonKey: 'SUPABASE_ANON_KEY',
anonKey: 'SUPABASE_PUBLISHABLE_KEY',
accessToken: () async {
final credentials = await auth0.credentialsManager.credentials();
return credentials.accessToken;
@@ -100,7 +104,7 @@ import com.auth0.android.result.Credentials
val supabase = createSupabaseClient(
"https://<supabase-project>.supabase.co",
"SUPABASE_ANON_KEY"
"SUPABASE_PUBLISHABLE_KEY"
) {
accessToken = {
val credentials: Credentials = ...; // Get credentials from Auth0
+14 -10
View File
@@ -22,14 +22,18 @@ Amazon Cognito User Pools (via AWS Amplify or on its own) can be used as a third
```typescript
import { fetchAuthSession, Hub } from 'aws-amplify/auth'
const supabase = createClient('https://<supabase-project>.supabase.co', 'SUPABASE_ANON_KEY', {
accessToken: async () => {
const tokens = await fetchAuthSession()
const supabase = createClient(
'https://<supabase-project>.supabase.co',
'SUPABASE_PUBLISHABLE_KEY',
{
accessToken: async () => {
const tokens = await fetchAuthSession()
// Alternatively you can use tokens?.idToken instead.
return tokens?.accessToken
},
})
// Alternatively you can use tokens?.idToken instead.
return tokens?.accessToken
},
}
)
// if you're using Realtime you also need to set up a listener for Cognito auth changes
Hub.listen('auth', () => {
@@ -49,7 +53,7 @@ struct UnexpectedAuthSessionError: Error {}
let supabase = SupabaseClient(
supabaseURL: URL(string: "https://<supabase-project>.supabase.co")!,
supabaseKey: "SUPABASE_ANON_KEY",
supabaseKey: "SUPABASE_PUBLISHABLE_KEY",
options: SupabaseClientOptions(
auth: SupabaseClientOptions.AuthOptions(
accessToken: {
@@ -80,7 +84,7 @@ import 'package:supabase_flutter/supabase_flutter.dart';
Future<void> main() async {
await Supabase.initialize(
url: 'https://<supabase-project>.supabase.co',
anonKey: 'SUPABASE_ANON_KEY',
anonKey: 'SUPABASE_PUBLISHABLE_KEY',
accessToken: () async {
final session = await Amplify.Auth.fetchAuthSession();
final cognitoSession = session as CognitoAuthSession;
@@ -102,7 +106,7 @@ import com.amplifyframework.core.Amplify
val supabase = createSupabaseClient(
"https://<supabase-project>.supabase.co",
"SUPABASE_ANON_KEY"
"SUPABASE_PUBLISHABLE_KEY"
) {
accessToken = {
getAccessToken()
+1 -1
View File
@@ -54,7 +54,7 @@ import 'package:supabase_flutter/supabase_flutter.dart';
await Supabase.initialize(
url: 'SUPABASE_URL',
anonKey: 'SUPABASE_ANON_KEY',
anonKey: 'SUPABASE_PUBLISHABLE_KEY',
accessToken: () async {
final token = await ClerkAuth.of(context).sessionToken();
return token.jwt;
+12 -8
View File
@@ -25,11 +25,15 @@ Creating a client for the Web is as easy as passing the `accessToken` async func
```typescript
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://<supabase-project>.supabase.co', 'SUPABASE_ANON_KEY', {
accessToken: async () => {
return (await firebase.auth().currentUser?.getIdToken(/* forceRefresh */ false)) ?? null
},
})
const supabase = createClient(
'https://<supabase-project>.supabase.co',
'SUPABASE_PUBLISHABLE_KEY',
{
accessToken: async () => {
return (await firebase.auth().currentUser?.getIdToken(/* forceRefresh */ false)) ?? null
},
}
)
```
Make sure the all users in your application have the `role: 'authenticated'` [custom claim](https://firebase.google.com/docs/auth/admin/custom-claims) set. If you're using the `onCreate` Cloud Function to add this custom claim to newly signed up users, you will need to call `getIdToken(/* forceRefresh */ true)` immediately after sign up as the `onCreate` function does not run synchronously.
@@ -66,7 +70,7 @@ struct MissingFirebaseTokenError: Error {}
let supabase = SupabaseClient(
supabaseURL: URL(string: "https://<supabase-project>.supabase.co")!,
supabaseKey: "SUPABASE_ANON_KEY",
supabaseKey: "SUPABASE_PUBLISHABLE_KEY",
options: SupabaseClientOptions(
auth: SupabaseClientOptions.AuthOptions(
accessToken: {
@@ -93,7 +97,7 @@ import com.google.firebase.ktx.Firebase
val supabase = createSupabaseClient(
"https://<supabase-project>.supabase.co",
"SUPABASE_ANON_KEY"
"SUPABASE_PUBLISHABLE_KEY"
) {
accessToken = {
Firebase.auth.currentUser?.getIdToken(false)?.await()?.token
@@ -113,7 +117,7 @@ import dev.gitlive.firebase.auth.auth
val supabase = createSupabaseClient(
"https://<supabase-project>.supabase.co",
"SUPABASE_ANON_KEY"
"SUPABASE_PUBLISHABLE_KEY"
) {
accessToken = {
Firebase.auth.currentUser?.getIdToken(false)
+9 -5
View File
@@ -26,11 +26,15 @@ const authkit = await createAuthKitClient('WORKOS_CLIENT_ID', {
apiHostname: '<WORKOS_AUTH_DOMAIN>',
})
const supabase = createClient('https://<supabase-project>.supabase.co', 'SUPABASE_ANON_KEY', {
accessToken: async () => {
return authkit.getAccessToken()
},
})
const supabase = createClient(
'https://<supabase-project>.supabase.co',
'SUPABASE_PUBLISHABLE_KEY',
{
accessToken: async () => {
return authkit.getAccessToken()
},
}
)
```
</TabPanel>
@@ -60,6 +60,10 @@ If a new version of an extension becomes available on Supabase, you need to init
### Full list of extensions
Supabase is pre-configured with over 50 extensions. You can also install your own SQL extensions directly in the database through our SQL editor.
Supabase is pre-configured with over 50 extensions and you can install additional extensions through the [database.dev](https://database.dev/) package manager.
You can install pure SQL extensions directly in the database using the SQL editor or any Postgres client.
If you would like to request an extension, add (or upvote) it in the [GitHub Discussion](https://github.com/orgs/supabase/discussions/33754).
<Extensions />
@@ -92,7 +92,7 @@ This approach has several benefits:
1. **On-demand:** analytical data is immediately available within your application with no additional infrastructure.
1. **Always in sync:** since the data is queried directly from the remote server, it's always up-to-date.
1. **Integrated:** large datasets are available within your application, and can be joined with your operational/transactional data.
1. **Save on bandwidth:** only extract/load what you need.
1. **Save on egress:** only extract/load what you need.
### Batch ETL with Wrappers
@@ -425,7 +425,7 @@ $$;
create policy "rls_test_select"
on test_table
to authenticated
using ( private.has_good_role() );
using ( (select private.has_good_role()) );
```
<Admonition type="caution">
@@ -34,6 +34,19 @@ supabase --experimental branches create --persistent
# Do you want to create a branch named develop? [Y/n]
```
<Admonition type="tip">
To retrieve the project ID for an existing branch, use the `branches list` command:
```bash
supabase --experimental branches list
```
This will display a table showing all your branches with their corresponding project ID.
Use the value from the `BRANCH PROJECT ID` column as your `project_id` in the remote configuration.
</Admonition>
### Configuration merging
When merging a PR into a persistent branch, the Supabase integration:
@@ -186,6 +199,19 @@ max_rows = 500
pool_size = 25
```
<Admonition type="tip">
To retrieve the project ID for an existing branch, use the `branches list` command:
```bash
supabase --experimental branches list
```
This will display a table showing all your branches with their corresponding project ID.
Use the value from the `BRANCH PROJECT ID` column as your `project_id` in the remote configuration.
</Admonition>
### Feature branch configuration
For feature branches that need specific settings:
@@ -200,6 +226,19 @@ client_id = "env(GOOGLE_CLIENT_ID)"
secret = "env(GOOGLE_CLIENT_SECRET)"
```
<Admonition type="tip">
To retrieve the project ID for an existing branch, use the `branches list` command:
```bash
supabase --experimental branches list
```
This will display a table showing all your branches with their corresponding project ID.
Use the value from the `BRANCH PROJECT ID` column as your `project_id` in the remote configuration.
</Admonition>
## Next steps
- Explore [branching integrations](/docs/guides/deployment/branching/integrations)
@@ -58,8 +58,6 @@ When reviewing a merge request you may see a notice at the top of the page askin
There are a few limitations you should be aware of before deciding to use branching without git.
- Custom roles created through the dashboard are not captured on branch creation
- Only public schema changes are supported right now
- Extensions are not included in the diff process
- Branches can only be merged to main; merging between preview branches is not supported
- If your branch is out of date, you can pull in latest changes from main, but keep in mind that all functions will be overwritten
- Deleting functions must be done manually on main branch
+1 -1
View File
@@ -94,7 +94,7 @@ Check out the [Edge Function Examples](https://github.com/supabase/supabase/tree
href: '/guides/functions/connect-to-postgres',
},
{
name: 'Github Actions',
name: 'GitHub Actions',
description: `Deploying Edge Functions with GitHub Actions.`,
href: '/guides/functions/examples/github-actions',
},
+1 -1
View File
@@ -25,7 +25,7 @@ import { createClient } from 'npm:@supabase/supabase-js@2'
Deno.serve(async (req: Request) => {
const supabaseClient = createClient(
Deno.env.get('SUPABASE_URL') ?? '',
Deno.env.get('SUPABASE_ANON_KEY') ?? '',
Deno.env.get('SUPABASE_PUBLISHABLE_KEY') ?? '',
// Create client with Auth context of the user that called the function.
// This way your row-level-security (RLS) policies are applied.
{
@@ -22,7 +22,7 @@ Deno.serve(async (req) => {
try {
const supabase = createClient(
Deno.env.get('SUPABASE_URL') ?? '',
Deno.env.get('SUPABASE_ANON_KEY') ?? '',
Deno.env.get('SUPABASE_PUBLISHABLE_KEY') ?? '',
{ global: { headers: { Authorization: req.headers.get('Authorization')! } } }
)
@@ -103,7 +103,7 @@ curl --request POST 'https://<project_id>.supabase.co/functions/v1/hello-world'
import { createClient } from '@supabase/supabase-js'
// Create a single supabase client for interacting with your database
const supabase = createClient('https://xyzcompany.supabase.co', 'public-anon-key')
const supabase = createClient('https://xyzcompany.supabase.co', 'publishable-or-anon-key')
const { data, error } = await supabase.functions.invoke('hello-world', {
body: { name: 'Functions' },
@@ -114,7 +114,7 @@ const { data, error } = await supabase.functions.invoke('hello-world', {
<Admonition type="note">
Note that the `SUPABASE_ANON_KEY` is different in development and production. To get your production anon key, you can find it in your Supabase dashboard under Settings > API.
Note that the `SUPABASE_PUBLISHABLE_KEY` is different in development and production. To get your production anon key, you can find it in your Supabase dashboard under Settings > API.
</Admonition>
@@ -115,7 +115,7 @@ Open a new terminal and test your function with curl:
<Admonition type="tip">
**Need your `SUPABASE_ANON_KEY`?**
**Need your `SUPABASE_PUBLISHABLE_KEY`?**
Run `supabase status` to see your local anon key and other credentials.
@@ -123,7 +123,7 @@ Run `supabase status` to see your local anon key and other credentials.
```bash
curl -i --location --request POST 'http://localhost:54321/functions/v1/hello-world' \
--header 'Authorization: Bearer SUPABASE_ANON_KEY' \
--header 'Authorization: Bearer SUPABASE_PUBLISHABLE_KEY' \
--header 'Content-Type: application/json' \
--data '{"name":"Functions"}'
```
@@ -229,7 +229,7 @@ Now, you should have your Edge Function deployed and running globally at `https:
```bash
curl --request POST 'https://[YOUR_PROJECT_ID].supabase.co/functions/v1/hello-world' \
--header 'Authorization: Bearer SUPABASE_ANON_KEY' \
--header 'Authorization: Bearer SUPABASE_PUBLISHABLE_KEY' \
--header 'Content-Type: application/json' \
--data '{"name":"Production"}'
```
@@ -242,7 +242,7 @@ curl --request POST 'https://[YOUR_PROJECT_ID].supabase.co/functions/v1/hello-wo
<Admonition type="note" label="Production vs Development Keys">
The `SUPABASE_ANON_KEY` is different in development and production. To get your production anon key, you can find it in your Supabase dashboard under **Settings > API**.
The `SUPABASE_PUBLISHABLE_KEY` is different in development and production. To get your production anon key, you can find it in your Supabase dashboard under **Settings > API**.
</Admonition>
@@ -31,7 +31,7 @@ Store `project_url` and `anon_key` in Supabase Vault:
```sql
select vault.create_secret('https://project-ref.supabase.co', 'project_url');
select vault.create_secret('YOUR_SUPABASE_ANON_KEY', 'anon_key');
select vault.create_secret('YOUR_SUPABASE_PUBLISHABLE_KEY', 'publishable_key');
```
Make a POST request to a Supabase Edge Function every minute:
@@ -10,7 +10,7 @@ subtitle: 'Manage sensitive data securely across environments.'
Edge Functions have access to these secrets by default:
- `SUPABASE_URL`: The API gateway for your Supabase project
- `SUPABASE_ANON_KEY`: The `anon` key for your Supabase API. This is safe to use in a browser when you have Row Level Security enabled
- `SUPABASE_PUBLISHABLE_KEY`: The `publishable` key for your Supabase API. This is safe to use in a browser when you have Row Level Security enabled
- `SUPABASE_SERVICE_ROLE_KEY`: The `service_role` key for your Supabase API. This is safe to use in Edge Functions, but it should NEVER be used in a browser. This key will bypass Row Level Security
- `SUPABASE_DB_URL`: The URL for your Postgres database. You can use this to connect directly to your database
@@ -32,7 +32,7 @@ import { createClient } from 'npm:@supabase/supabase-js@2'
// For user-facing operations (respects RLS)
const supabase = createClient(
Deno.env.get('SUPABASE_URL')!,
Deno.env.get('SUPABASE_ANON_KEY')!
Deno.env.get('SUPABASE_PUBLISHABLE_KEY')!
)
// For admin operations (bypasses RLS)
@@ -48,7 +48,7 @@ import 'jsr:@std/dotenv/load'
// Set up the configuration for the Supabase client
const supabaseUrl = Deno.env.get('SUPABASE_URL') ?? ''
const supabaseKey = Deno.env.get('SUPABASE_ANON_KEY') ?? ''
const supabaseKey = Deno.env.get('SUPABASE_PUBLISHABLE_KEY') ?? ''
const options = {
auth: {
autoRefreshToken: false,
@@ -146,8 +146,8 @@ To locally test and debug Edge Functions, you can utilize the Supabase CLI. Let'
touch .env
# adds the SUPABASE_URL secret
echo "SUPABASE_URL=http://localhost:54321" >> .env
# adds the SUPABASE_ANON_KEY secret
echo "SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0" >> .env
# adds the SUPABASE_PUBLISHABLE_KEY secret
echo "SUPABASE_PUBLISHABLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0" >> .env
# Alternatively, you can open it in your editor:
open .env
```
@@ -32,7 +32,7 @@ Here are some basic examples of setting up WebSocket servers using Deno and Node
Deno.serve((req) => {
const upgrade = req.headers.get('upgrade') || ''
if (upgrade.toLowerCase() != 'WebSocket') {
if (upgrade.toLowerCase() != 'websocket') {
return new Response("request isn't trying to upgrade to WebSocket.", { status: 400 })
}
@@ -72,7 +72,7 @@ hideToc: true
await Supabase.initialize(
url: 'YOUR_SUPABASE_URL',
anonKey: 'YOUR_SUPABASE_ANON_KEY',
anonKey: 'YOUR_SUPABASE_PUBLISHABLE_KEY',
);
runApp(MyApp());
}
@@ -53,7 +53,7 @@ hideToc: true
let supabase = SupabaseClient(
supabaseURL: URL(string: "YOUR_SUPABASE_URL")!,
supabaseKey: "YOUR_SUPABASE_ANON_KEY"
supabaseKey: "YOUR_SUPABASE_PUBLISHABLE_KEY"
)
```
@@ -50,7 +50,7 @@ hideToc: true
```text name=.env.local
NEXT_PUBLIC_SUPABASE_URL=<SUBSTITUTE_SUPABASE_URL>
NEXT_PUBLIC_SUPABASE_ANON_KEY=<SUBSTITUTE_SUPABASE_ANON_KEY>
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=<SUBSTITUTE_SUPABASE_PUBLISHABLE_KEY>
```
</$CodeTabs>
@@ -59,12 +59,12 @@ hideToc: true
</StepHikeCompact.Step>
<StepHikeCompact.Step step={4}>
<StepHikeCompact.Details title="Query Supabase data from Next.js">
<StepHikeCompact.Step step={4}>
<StepHikeCompact.Details title="Create Supabase client">
Create a new file at `app/instruments/page.tsx` and populate with the following.
Create a new file at `utils/supabase/server.ts` and populate with the following.
This will select all the rows from the `instruments` table in Supabase and render them on the page.
This creates a Supabase client, using the credentials from the `env.local` file.
</StepHikeCompact.Details>
@@ -72,17 +72,6 @@ hideToc: true
<$CodeTabs>
```ts name=app/instruments/page.tsx
import { createClient } from '@/utils/supabase/server';
export default async function Instruments() {
const supabase = await createClient();
const { data: instruments } = await supabase.from("instruments").select();
return <pre>{JSON.stringify(instruments, null, 2)}</pre>
}
```
```ts name=utils/supabase/server.ts
import { createServerClient } from '@supabase/ssr'
import { cookies } from 'next/headers'
@@ -92,7 +81,7 @@ hideToc: true
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,
{
cookies: {
getAll() {
@@ -122,6 +111,36 @@ hideToc: true
</StepHikeCompact.Step>
<StepHikeCompact.Step step={5}>
<StepHikeCompact.Details title="Query Supabase data from Next.js">
Create a new file at `app/instruments/page.tsx` and populate with the following.
This selects all the rows from the `instruments` table in Supabase and render them on the page.
</StepHikeCompact.Details>
<StepHikeCompact.Code>
<$CodeTabs>
```ts name=app/instruments/page.tsx
import { createClient } from '@/utils/supabase/server';
export default async function Instruments() {
const supabase = await createClient();
const { data: instruments } = await supabase.from("instruments").select();
return <pre>{JSON.stringify(instruments, null, 2)}</pre>
}
```
</$CodeTabs>
</StepHikeCompact.Code>
</StepHikeCompact.Step>
<StepHikeCompact.Step step={6}>
<StepHikeCompact.Details title="Start the app">
Run the development server, go to http://localhost:3000/instruments in a browser and you should see the list of instruments.
@@ -66,7 +66,7 @@ hideToc: true
```text name=.env.local
SUPABASE_URL=<SUBSTITUTE_SUPABASE_URL>
SUPABASE_ANON_KEY=<SUBSTITUTE_SUPABASE_ANON_KEY>
SUPABASE_PUBLISHABLE_KEY=<SUBSTITUTE_SUPABASE_PUBLISHABLE_KEY>
```
```ts name=nuxt.config.tsx
@@ -74,7 +74,7 @@ hideToc: true
runtimeConfig: {
public: {
supabaseUrl: process.env.SUPABASE_URL,
supabaseAnonKey: process.env.SUPABASE_ANON_KEY,
supabaseAnonKey: process.env.SUPABASE_PUBLISHABLE_KEY,
},
},
});
@@ -66,7 +66,7 @@ hideToc: true
```text name=.env.local
VITE_SUPABASE_URL=<SUBSTITUTE_SUPABASE_URL>
VITE_SUPABASE_ANON_KEY=<SUBSTITUTE_SUPABASE_ANON_KEY>
VITE_SUPABASE_PUBLISHABLE_KEY=<SUBSTITUTE_SUPABASE_PUBLISHABLE_KEY>
```
</$CodeTabs>
@@ -87,7 +87,7 @@ hideToc: true
import { useEffect, useState } from "react";
import { createClient } from "@supabase/supabase-js";
const supabase = createClient(import.meta.env.VITE_SUPABASE_URL, import.meta.env.VITE_SUPABASE_ANON_KEY);
const supabase = createClient(import.meta.env.VITE_SUPABASE_URL, import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY);
function App() {
const [instruments, setInstruments] = useState([]);
@@ -66,7 +66,7 @@ hideToc: true
```text name=.env.local
VITE_SUPABASE_URL=<SUBSTITUTE_SUPABASE_URL>
VITE_SUPABASE_ANON_KEY=<SUBSTITUTE_SUPABASE_ANON_KEY>
VITE_SUPABASE_PUBLISHABLE_KEY=<SUBSTITUTE_SUPABASE_PUBLISHABLE_KEY>
```
</$CodeTabs>
@@ -90,7 +90,7 @@ hideToc: true
import { createClient } from "@supabase/supabase-js";
import { createResource, For } from "solid-js";
const supabase = createClient('https://<project>.supabase.co', '<your-anon-key>');
const supabase = createClient('https://<project>.supabase.co', '<sb_publishable_... or anon key>');
async function getInstruments() {
const { data } = await supabase.from("instruments").select();
@@ -67,7 +67,7 @@ hideToc: true
```text name=.env
VITE_PUBLIC_SUPABASE_URL=<SUBSTITUTE_SUPABASE_URL>
VITE_PUBLIC_SUPABASE_ANON_KEY=<SUBSTITUTE_SUPABASE_ANON_KEY>
VITE_PUBLIC_SUPABASE_PUBLISHABLE_KEY=<SUBSTITUTE_SUPABASE_PUBLISHABLE_KEY>
```
</$CodeTabs>
@@ -89,16 +89,16 @@ hideToc: true
```js name=src/lib/supabaseClient.js
import { createClient } from '@supabase/supabase-js';
import { VITE_PUBLIC_SUPABASE_URL, VITE_PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public';
import { VITE_PUBLIC_SUPABASE_URL, VITE_PUBLIC_SUPABASE_PUBLISHABLE_KEY } from '$env/static/public';
export const supabase = createClient(VITE_PUBLIC_SUPABASE_URL, VITE_PUBLIC_SUPABASE_ANON_KEY)
export const supabase = createClient(VITE_PUBLIC_SUPABASE_URL, VITE_PUBLIC_SUPABASE_PUBLISHABLE_KEY)
```
```ts name=src/lib/supabaseClient.ts
import { createClient } from '@supabase/supabase-js';
import { VITE_PUBLIC_SUPABASE_URL, VITE_PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public';
import { VITE_PUBLIC_SUPABASE_URL, VITE_PUBLIC_SUPABASE_PUBLISHABLE_KEY } from '$env/static/public';
export const supabase = createClient(VITE_PUBLIC_SUPABASE_URL, VITE_PUBLIC_SUPABASE_ANON_KEY)
export const supabase = createClient(VITE_PUBLIC_SUPABASE_URL, VITE_PUBLIC_SUPABASE_PUBLISHABLE_KEY)
```
</$CodeTabs>
@@ -66,7 +66,7 @@ hideToc: true
```text name=.env.local
VITE_SUPABASE_URL=<SUBSTITUTE_SUPABASE_URL>
VITE_SUPABASE_ANON_KEY=<SUBSTITUTE_SUPABASE_ANON_KEY>
VITE_SUPABASE_PUBLISHABLE_KEY=<SUBSTITUTE_SUPABASE_PUBLISHABLE_KEY>
```
</$CodeTabs>
@@ -88,7 +88,7 @@ hideToc: true
import { createClient } from '@supabase/supabase-js'
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY
export const supabase = createClient(supabaseUrl, supabaseAnonKey)
```
@@ -58,7 +58,7 @@ These variables are safe to expose in your Expo app since Supabase has
import { createClient } from '@supabase/supabase-js'
const supabaseUrl = YOUR_REACT_NATIVE_SUPABASE_URL
const supabaseAnonKey = YOUR_REACT_NATIVE_SUPABASE_ANON_KEY
const supabaseAnonKey = YOUR_REACT_NATIVE_SUPABASE_PUBLISHABLE_KEY
export const supabase = createClient(supabaseUrl, supabaseAnonKey, {
auth: {
@@ -150,7 +150,7 @@ These variables are safe to expose in your Expo app since Supabase has
}
const supabaseUrl = YOUR_REACT_NATIVE_SUPABASE_URL
const supabaseAnonKey = YOUR_REACT_NATIVE_SUPABASE_ANON_KEY
const supabaseAnonKey = YOUR_REACT_NATIVE_SUPABASE_PUBLISHABLE_KEY
const supabase = createClient(supabaseUrl, supabaseAnonKey, {
auth: {
@@ -155,7 +155,7 @@ import 'package:supabase_flutter/supabase_flutter.dart';
Future<void> main() async {
await Supabase.initialize(
url: 'YOUR_SUPABASE_URL',
anonKey: 'YOUR_SUPABASE_ANON_KEY',
anonKey: 'YOUR_SUPABASE_PUBLISHABLE_KEY',
);
runApp(const MyApp());
}
@@ -474,7 +474,7 @@ import 'package:supabase_quickstart/pages/login_page.dart';
Future<void> main() async {
await Supabase.initialize(
url: 'YOUR_SUPABASE_URL',
anonKey: 'YOUR_SUPABASE_ANON_KEY',
anonKey: 'YOUR_SUPABASE_PUBLISHABLE_KEY',
);
runApp(const MyApp());
}
@@ -43,7 +43,7 @@ All we need are the API URL and the `anon` key that you copied [earlier](#get-th
```bash name=.env
VITE_SUPABASE_URL=YOUR_SUPABASE_URL
VITE_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
VITE_SUPABASE_PUBLISHABLE_KEY=YOUR_SUPABASE_PUBLISHABLE_KEY
```
</$CodeTabs>
@@ -57,7 +57,7 @@ on the browser, and that's completely fine since we have [Row Level Security](/d
import { createClient } from '@supabase/supabase-js'
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL || ''
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY || ''
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY || ''
export const supabase = createClient(supabaseUrl, supabaseAnonKey)
```
@@ -43,7 +43,7 @@ All we need are the API URL and the `anon` key that you copied [earlier](#get-th
```bash name=.env
VITE_SUPABASE_URL=YOUR_SUPABASE_URL
VITE_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
VITE_SUPABASE_PUBLISHABLE_KEY=YOUR_SUPABASE_PUBLISHABLE_KEY
```
</$CodeTabs>
@@ -56,7 +56,7 @@ Now that we have the API credentials in place, let's create a helper file to ini
import { createClient } from '@supabase/supabase-js';
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL as string;
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY as string;
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY as string;
export const supabase = createClient(supabaseUrl, supabaseAnonKey);
```
@@ -36,7 +36,7 @@ Create or edit the `local.properties` file at the root (same level as `build.gra
> **Note**: Do not commit this file to your source control, for example, by adding it to your `.gitignore` file!
```kotlin
SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
SUPABASE_PUBLISHABLE_KEY=YOUR_SUPABASE_PUBLISHABLE_KEY
SUPABASE_URL=YOUR_SUPABASE_URL
```
@@ -56,7 +56,7 @@ defaultConfig {
// Set value part
Properties properties = new Properties()
properties.load(project.rootProject.file("local.properties").newDataInputStream())
buildConfigField("String", "SUPABASE_ANON_KEY", "\"${properties.getProperty("SUPABASE_ANON_KEY")}\"")
buildConfigField("String", "SUPABASE_PUBLISHABLE_KEY", "\"${properties.getProperty("SUPABASE_PUBLISHABLE_KEY")}\"")
buildConfigField("String", "SECRET", "\"${properties.getProperty("SECRET")}\"")
buildConfigField("String", "SUPABASE_URL", "\"${properties.getProperty("SUPABASE_URL")}\"")
}
@@ -68,7 +68,7 @@ Read the value from `BuildConfig`:
```kotlin
val url = BuildConfig.SUPABASE_URL
val apiKey = BuildConfig.SUPABASE_ANON_KEY
val apiKey = BuildConfig.SUPABASE_PUBLISHABLE_KEY
```
### Set up Supabase dependencies
@@ -152,7 +152,7 @@ object SupabaseModule {
fun provideSupabaseClient(): SupabaseClient {
return createSupabaseClient(
supabaseUrl = BuildConfig.SUPABASE_URL,
supabaseKey = BuildConfig.SUPABASE_ANON_KEY
supabaseKey = BuildConfig.SUPABASE_PUBLISHABLE_KEY
) {
install(Postgrest)
install(Auth) {
@@ -58,7 +58,7 @@ Save the environment variables in a `.env.local` file at the root of the project
```bash .env.local
NEXT_PUBLIC_SUPABASE_URL=YOUR_SUPABASE_URL
NEXT_PUBLIC_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=YOUR_SUPABASE_PUBLISHABLE_KEY
```
### App styling (optional)
@@ -108,7 +108,7 @@ export function createClient() {
// Create a supabase client on the browser with project's credentials
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY
)
}
```
@@ -124,7 +124,7 @@ export async function createClient() {
// which could be used to maintain user's session
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY,
{
cookies: {
getAll() {
@@ -244,7 +244,7 @@ export async function updateSession(request) {
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY,
{
cookies: {
getAll() {
@@ -42,7 +42,7 @@ All we need are the API URL and the `anon` key that you copied [earlier](#get-th
```bash name=.env
SUPABASE_URL="YOUR_SUPABASE_URL"
SUPABASE_KEY="YOUR_SUPABASE_ANON_KEY"
SUPABASE_KEY="YOUR_SUPABASE_PUBLISHABLE_KEY"
```
</$CodeTabs>
@@ -42,7 +42,7 @@ All we need are the API URL and the `anon` key that you copied [earlier](#get-th
```bash name=.env
VITE_SUPABASE_URL=YOUR_SUPABASE_URL
VITE_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
VITE_SUPABASE_PUBLISHABLE_KEY=YOUR_SUPABASE_PUBLISHABLE_KEY
```
</$CodeTabs>
@@ -58,7 +58,7 @@ Create and edit `src/supabaseClient.js`:
import { createClient } from '@supabase/supabase-js'
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY
export const supabase = createClient(supabaseUrl, supabaseAnonKey)
```
@@ -109,7 +109,7 @@ We need the `API URL` as well as the `anon` and `jwt_secret` keys that you copie
```bash name=.env
SUPABASE_URL=YOUR_SUPABASE_URL
SUPABASE_KEY=YOUR_SUPABASE_ANON_KEY
SUPABASE_KEY=YOUR_SUPABASE_PUBLISHABLE_KEY
SUPABASE_JWT_SECRET=YOUR_SUPABASE_JWT_SECRET
```
@@ -73,7 +73,7 @@ We'll update it with environment variables managed by Vite:
import { createClient } from '@refinedev/supabase'
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY
export const supabaseClient = createClient(supabaseUrl, supabaseAnonKey, {
db: {
@@ -91,7 +91,7 @@ And then, we want to save the environment variables in a `.env.local` file. All
```bash .env.local
VITE_SUPABASE_URL=YOUR_SUPABASE_URL
VITE_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
VITE_SUPABASE_PUBLISHABLE_KEY=YOUR_SUPABASE_PUBLISHABLE_KEY
```
The `supabaseClient` will be used in fetch calls to Supabase endpoints from our app. As we'll see below, the client is instrumental in implementing authentication using Refine's auth provider methods and CRUD actions with appropriate data provider methods.
@@ -41,7 +41,7 @@ All we need are the API URL and the `anon` key that you copied [earlier](#get-th
```bash name=.env
VITE_SUPABASE_URL=YOUR_SUPABASE_URL
VITE_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
VITE_SUPABASE_PUBLISHABLE_KEY=YOUR_SUPABASE_PUBLISHABLE_KEY
```
</$CodeTabs>
@@ -55,7 +55,7 @@ on the browser, and that's completely fine since we have [Row Level Security](/d
import { createClient } from '@supabase/supabase-js'
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY
export const supabase = createClient(supabaseUrl, supabaseAnonKey)
```
@@ -42,7 +42,7 @@ All you need are the API URL and the `anon` key that you copied [earlier](#get-t
```bash name=.env
VITE_SUPABASE_URL=YOUR_SUPABASE_URL
VITE_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
VITE_SUPABASE_PUBLISHABLE_KEY=YOUR_SUPABASE_PUBLISHABLE_KEY
```
</$CodeTabs>
@@ -17,14 +17,14 @@ If you get stuck while working through this guide, refer to the [full example on
## Building the app
Let's start building the Svelte app from scratch.
Start building the Svelte app from scratch.
### Initialize a Svelte app
We can use the [SvelteKit Skeleton Project](https://kit.svelte.dev/docs) to initialize an app called `supabase-sveltekit` (for this tutorial we will be using TypeScript):
Use the [SvelteKit Skeleton Project](https://svelte.dev/docs/kit) to initialize an app called `supabase-sveltekit` (for this tutorial, select "SvelteKit minimal" and use TypeScript):
```bash
npm create svelte@latest supabase-sveltekit
npx sv create supabase-sveltekit
cd supabase-sveltekit
npm install
```
@@ -35,120 +35,58 @@ Then install the Supabase client library: [supabase-js](https://github.com/supab
npm install @supabase/supabase-js
```
And finally we want to save the environment variables in a `.env`.
All we need are the `SUPABASE_URL` and the `SUPABASE_KEY` key that you copied [earlier](#get-the-api-keys).
And finally, save the environment variables in a `.env` file.
All you need are the `PUBLIC_SUPABASE_URL` and the `PUBLIC_SUPABASE_ANON_KEY` key that you copied [earlier](#get-the-api-keys).
<$CodeTabs>
```bash name=.env
PUBLIC_SUPABASE_URL="YOUR_SUPABASE_URL"
PUBLIC_SUPABASE_ANON_KEY="YOUR_SUPABASE_KEY"
PUBLIC_SUPABASE_PUBLISHABLE_KEY="YOUR_SUPABASE_PUBLISHABLE_KEY"
```
</$CodeTabs>
Optionally, add `src/styles.css` with the [CSS from the example](https://raw.githubusercontent.com/supabase/supabase/master/examples/user-management/sveltekit-user-management/src/styles.css).
### App styling (optional)
An optional step is to update the CSS file `src/styles.css` to make the app look nice.
You can find the full contents of this file [in the example repository](https://raw.githubusercontent.com/supabase/supabase/master/examples/user-management/sveltekit-user-management/src/styles.css).
### Creating a Supabase client for SSR
The `ssr` package configures Supabase to use Cookies, which is required for server-side languages and frameworks.
The `ssr` package configures Supabase to use Cookies, which are required for server-side languages and frameworks.
Install the Supabase packages:
Install the SSR package:
```bash
npm install @supabase/ssr @supabase/supabase-js
npm install @supabase/ssr
```
Creating a Supabase client with the `ssr` package automatically configures it to use Cookies. This means your user's session is available throughout the entire SvelteKit stack - page, layout, server, hooks.
Creating a Supabase client with the `ssr` package automatically configures it to use Cookies. This means the user's session is available throughout the entire SvelteKit stack - page, layout, server, and hooks.
Add the code below to your `src/hooks.server.ts` to initialize the client on the server:
Add the code below to a `src/hooks.server.ts` file to initialize the client on the server:
<$CodeTabs>
```ts name=src/hooks.server.ts
// src/hooks.server.ts
import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public'
import { createServerClient } from '@supabase/ssr'
import type { Handle } from '@sveltejs/kit'
export const handle: Handle = async ({ event, resolve }) => {
event.locals.supabase = createServerClient(PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY, {
cookies: {
getAll: () => event.cookies.getAll(),
/**
* SvelteKit's cookies API requires `path` to be explicitly set in
* the cookie options. Setting `path` to `/` replicates previous/
* standard behavior.
*/
setAll: (cookiesToSet) => {
cookiesToSet.forEach(({ name, value, options }) => {
event.cookies.set(name, value, { ...options, path: '/' })
})
},
},
})
/**
* Unlike `supabase.auth.getSession()`, which returns the session _without_
* validating the JWT, this function also calls `getUser()` to validate the
* JWT before returning the session.
*/
event.locals.safeGetSession = async () => {
const {
data: { session },
} = await event.locals.supabase.auth.getSession()
if (!session) {
return { session: null, user: null }
}
const {
data: { user },
error,
} = await event.locals.supabase.auth.getUser()
if (error) {
// JWT validation has failed
return { session: null, user: null }
}
return { session, user }
}
return resolve(event, {
filterSerializedResponseHeaders(name) {
return name === 'content-range' || name === 'x-supabase-api-version'
},
})
}
```
<$CodeSample
path="/user-management/sveltekit-user-management/src/hooks.server.ts"
lines={[[1, -1]]}
meta="name=src/hooks.server.ts"
/>
</$CodeTabs>
<$Partial path="get_session_warning.mdx" />
If you are using TypeScript the compiler might complain about `event.locals.supabase` and `event.locals.safeGetSession`, this can be fixed by updating your `src/app.d.ts` with the content below:
{/* TODO: Change when adding JS autoconversion */}
As this tutorial uses TypeScript the compiler complains about `event.locals.supabase` and `event.locals.safeGetSession`, you can fix this by updating the `src/app.d.ts` with the content below:
<$CodeTabs>
```ts name=src/app.d.ts
// src/app.d.ts
import { SupabaseClient, Session } from '@supabase/supabase-js'
declare global {
namespace App {
interface Locals {
supabase: SupabaseClient
safeGetSession(): Promise<{ session: Session | null; user: User | null }>
}
interface PageData {
session: Session | null
user: User | null
}
// interface Error {}
// interface Platform {}
}
}
```
<$CodeSample
path="/user-management/sveltekit-user-management/src/app.d.ts"
lines={[[1, -1]]}
meta="name=src/app.d.ts"
/>
</$CodeTabs>
@@ -156,26 +94,17 @@ Create a new `src/routes/+layout.server.ts` file to handle the session on the se
<$CodeTabs>
```ts name=src/routes/+layout.server.ts
// src/routes/+layout.server.ts
import type { LayoutServerLoad } from './$types'
export const load: LayoutServerLoad = async ({ locals: { safeGetSession }, cookies }) => {
const { session, user } = await safeGetSession()
return {
session,
user,
cookies: cookies.getAll(),
}
}
```
<$CodeSample
path="/user-management/sveltekit-user-management/src/routes/+layout.server.ts"
lines={[[1, -1]]}
meta="name=src/routes/+layout.server.ts"
/>
</$CodeTabs>
<Admonition type="tip">
Start your dev server (`npm run dev`) in order to generate the `./$types` files we are referencing in our project.
Start the dev server (`npm run dev`) to generate the `./$types` files we are referencing in our project.
</Admonition>
@@ -183,202 +112,49 @@ Create a new `src/routes/+layout.ts` file to handle the session and the `supabas
<$CodeTabs>
```ts name=src/routes/+layout.ts
// src/routes/+layout.ts
import { createBrowserClient, createServerClient, isBrowser } from '@supabase/ssr'
import { PUBLIC_SUPABASE_ANON_KEY, PUBLIC_SUPABASE_URL } from '$env/static/public'
import type { LayoutLoad } from './$types'
export const load: LayoutLoad = async ({ fetch, data, depends }) => {
depends('supabase:auth')
const supabase = isBrowser()
? createBrowserClient(PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY, {
global: {
fetch,
},
})
: createServerClient(PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY, {
global: {
fetch,
},
cookies: {
getAll() {
return data.cookies
},
},
})
/**
* It's fine to use `getSession` here, because on the client, `getSession` is
* safe, and on the server, it reads `session` from the `LayoutData`, which
* safely checked the session using `safeGetSession`.
*/
const {
data: { session },
} = await supabase.auth.getSession()
return { supabase, session }
}
```
<$CodeSample
path="/user-management/sveltekit-user-management/src/routes/+layout.ts"
lines={[[1, -1]]}
meta="name=src/routes/+layout.ts"
/>
</$CodeTabs>
Update your `src/routes/+layout.svelte`:
Create `src/routes/+layout.svelte`:
<$CodeTabs>
```svelte name=src/routes/+layout.svelte
<!-- src/routes/+layout.svelte -->
<script lang="ts">
import '../styles.css'
import { invalidate } from '$app/navigation'
import { onMount } from 'svelte'
export let data
let { supabase, session } = data
$: ({ supabase, session } = data)
onMount(() => {
const { data } = supabase.auth.onAuthStateChange((event, newSession) => {
if (newSession?.expires_at !== session?.expires_at) {
invalidate('supabase:auth')
}
})
return () => data.subscription.unsubscribe()
})
</script>
<svelte:head>
<title>User Management</title>
</svelte:head>
<div class="container" style="padding: 50px 0 100px 0">
<slot />
</div>
```
<$CodeSample
path="/user-management/sveltekit-user-management/src/routes/+layout.svelte"
lines={[[1, -1]]}
meta="name=src/routes/+layout.svelte"
/>
</$CodeTabs>
## Set up a login page
Create a magic link login/signup page for your application:
Create a magic link login/signup page for your application by updating the `routes/+page.svelte` file:
<$CodeTabs>
```svelte name=src/routes/+page.svelte
<!-- src/routes/+page.svelte -->
<script lang="ts">
import { enhance } from '$app/forms'
import type { ActionData, SubmitFunction } from './$types.js'
export let form: ActionData;
let loading = false
const handleSubmit: SubmitFunction = () => {
loading = true
return async ({ update }) => {
update()
loading = false
}
}
</script>
<svelte:head>
<title>User Management</title>
</svelte:head>
<form class="row flex flex-center" method="POST" use:enhance={handleSubmit}>
<div class="col-6 form-widget">
<h1 class="header">Supabase + SvelteKit</h1>
<p class="description">Sign in via magic link with your email below</p>
{#if form?.message !== undefined}
<div class="success {form?.success ? '' : 'fail'}">
{form?.message}
</div>
{/if}
<div>
<label for="email">Email address</label>
<input
id="email"
name="email"
class="inputField"
type="email"
placeholder="Your email"
value={form?.email ?? ''}
/>
</div>
{#if form?.errors?.email}
<span class="flex items-center text-sm error">
{form?.errors?.email}
</span>
{/if}
<div>
<button class="button primary block">
{ loading ? 'Loading' : 'Send magic link' }
</button>
</div>
</div>
</form>
```
<$CodeSample
path="/user-management/sveltekit-user-management/src/routes/+page.svelte"
lines={[[1, -1]]}
meta="name=src/routes/+page.svelte"
/>
</$CodeTabs>
Create a `src/routes/+page.server.ts` file that will handle our magic link form when submitted.
Create a `src/routes/+page.server.ts` file that handles the magic link form when submitted.
<$CodeTabs>
```ts name=src/routes/+page.server.ts
// src/routes/+page.server.ts
import { fail, redirect } from '@sveltejs/kit'
import type { Actions, PageServerLoad } from './$types'
export const load: PageServerLoad = async ({ url, locals: { safeGetSession } }) => {
const { session } = await safeGetSession()
// if the user is already logged in return them to the account page
if (session) {
redirect(303, '/account')
}
return { url: url.origin }
}
export const actions: Actions = {
default: async (event) => {
const {
url,
request,
locals: { supabase },
} = event
const formData = await request.formData()
const email = formData.get('email') as string
const validEmail = /^[\w-\.+]+@([\w-]+\.)+[\w-]{2,8}$/.test(email)
if (!validEmail) {
return fail(400, { errors: { email: 'Please enter a valid email address' }, email })
}
const { error } = await supabase.auth.signInWithOtp({ email })
if (error) {
return fail(400, {
success: false,
email,
message: `There was an issue, Please contact support.`,
})
}
return {
success: true,
message: 'Please check your email for a magic link to log into the website.',
}
},
}
```
<$CodeSample
path="/user-management/sveltekit-user-management/src/routes/+page.server.ts"
lines={[[1, -1]]}
meta="name=src/routes/+page.server.ts"
/>
</$CodeTabs>
@@ -388,239 +164,77 @@ Change the email template to support a server-side authentication flow.
Before we proceed, let's change the email template to support sending a token hash:
- Go to the [Auth templates](/dashboard/project/_/auth/templates) page in your dashboard.
- Select `Confirm signup` template.
- Go to the [**Auth** > **Emails**](/dashboard/project/_/auth/templates) page in the project dashboard.
- Select the **Confirm signup** template.
- Change `{{ .ConfirmationURL }}` to `{{ .SiteURL }}/auth/confirm?token_hash={{ .TokenHash }}&type=email`.
- Repeat the previous step for `Magic link` template.
- Repeat the previous step for **Magic link** template.
<Admonition type="tip">
Did you know? You could also customize emails sent out to new users, including the email's looks, content, and query parameters. Check out the [settings of your project](/dashboard/project/_/auth/templates).
**Did you know?** You can also customize emails sent out to new users, including the email's looks, content, and query parameters. Check out the [settings of your project](/dashboard/project/_/auth/templates).
</Admonition>
### Confirmation endpoint
As we are working in a server-side rendering (SSR) environment, it is necessary to create a server endpoint responsible for exchanging the `token_hash` for a session.
As this is a server-side rendering (SSR) environment, you need to create a server endpoint responsible for exchanging the `token_hash` for a session.
In the following code snippet, we perform the following steps:
The following code snippet performs the following steps:
- Retrieve the `token_hash` sent back from the Supabase Auth server using the `token_hash` query parameter.
- Exchange this `token_hash` for a session, which we store in storage (in this case, cookies).
- Finally, the user is redirected to the `account` page or the `error` page.
- Retrieves the `token_hash` sent back from the Supabase Auth server using the `token_hash` query parameter.
- Exchanges this `token_hash` for a session, which you store in storage (in this case, cookies).
- Finally, redirect the user to the `account` page or the `error` page.
<$CodeTabs>
```ts name=src/routes/auth/confirm/+server.ts
// src/routes/auth/confirm/+server.ts
import type { EmailOtpType } from '@supabase/supabase-js'
import { redirect } from '@sveltejs/kit'
import type { RequestHandler } from './$types'
export const GET: RequestHandler = async ({ url, locals: { supabase } }) => {
const token_hash = url.searchParams.get('token_hash')
const type = url.searchParams.get('type') as EmailOtpType | null
const next = url.searchParams.get('next') ?? '/account'
/**
* Clean up the redirect URL by deleting the Auth flow parameters.
*
* `next` is preserved for now, because it's needed in the error case.
*/
const redirectTo = new URL(url)
redirectTo.pathname = next
redirectTo.searchParams.delete('token_hash')
redirectTo.searchParams.delete('type')
if (token_hash && type) {
const { error } = await supabase.auth.verifyOtp({ type, token_hash })
if (!error) {
redirectTo.searchParams.delete('next')
redirect(303, redirectTo)
}
}
redirectTo.pathname = '/auth/error'
redirect(303, redirectTo)
}
```
<$CodeSample
path="/user-management/sveltekit-user-management/src/routes/auth/confirm/+server.ts"
lines={[[1, -1]]}
meta="name=src/routes/auth/confirm/+server.ts"
/>
</$CodeTabs>
### Authentication error page
If there is an error with confirming the token you will be redirect to this error page.
If there is an error with confirming the token, redirect the user to an error page.
<$CodeTabs>
```svelte name=src/routes/auth/error/+page.svelte
<p>Login error</p>
```
<$CodeSample
path="/user-management/sveltekit-user-management/src/routes/auth/error/+page.svelte"
lines={[[1, -1]]}
meta="name=src/routes/auth/error/+page.svelte"
/>
</$CodeTabs>
### Account page
After a user is signed in, they need to be able to edit their profile details and manage their account.
After a user signs in, they need to be able to edit their profile details page.
Create a new `src/routes/account/+page.svelte` file with the content below.
<$CodeTabs>
```svelte name=src/routes/account/+page.svelte
<!-- src/routes/account/+page.svelte -->
<script lang="ts">
import { enhance } from '$app/forms';
import type { SubmitFunction } from '@sveltejs/kit';
export let data
export let form
let { session, supabase, profile } = data
$: ({ session, supabase, profile } = data)
let profileForm: HTMLFormElement
let loading = false
let fullName: string = profile?.full_name ?? ''
let username: string = profile?.username ?? ''
let website: string = profile?.website ?? ''
let avatarUrl: string = profile?.avatar_url ?? ''
const handleSubmit: SubmitFunction = () => {
loading = true
return async () => {
loading = false
}
}
const handleSignOut: SubmitFunction = () => {
loading = true
return async ({ update }) => {
loading = false
update()
}
}
</script>
<div class="form-widget">
<form
class="form-widget"
method="post"
action="?/update"
use:enhance={handleSubmit}
bind:this={profileForm}
>
<div>
<label for="email">Email</label>
<input id="email" type="text" value={session.user.email} disabled />
</div>
<div>
<label for="fullName">Full Name</label>
<input id="fullName" name="fullName" type="text" value={form?.fullName ?? fullName} />
</div>
<div>
<label for="username">Username</label>
<input id="username" name="username" type="text" value={form?.username ?? username} />
</div>
<div>
<label for="website">Website</label>
<input id="website" name="website" type="url" value={form?.website ?? website} />
</div>
<div>
<input
type="submit"
class="button block primary"
value={loading ? 'Loading...' : 'Update'}
disabled={loading}
/>
</div>
</form>
<form method="post" action="?/signout" use:enhance={handleSignOut}>
<div>
<button class="button block" disabled={loading}>Sign Out</button>
</div>
</form>
</div>
```
<$CodeSample
path="/user-management/sveltekit-user-management/src/routes/account/+page.svelte"
lines={[[1, 3],[6,12],[15,38],[47,-1]]}
meta="name=src/routes/account/+page.svelte"
/>
</$CodeTabs>
Now create the associated `src/routes/account/+page.server.ts` file that will handle loading our data from the server through the `load` function
and handle all our form actions through the `actions` object.
Now, create the associated `src/routes/account/+page.server.ts` file that handles loading data from the server through the `load` function
and handle all form actions through the `actions` object.
```ts name=src/routes/account/+page.server.ts
import { fail, redirect } from '@sveltejs/kit'
import type { Actions, PageServerLoad } from './$types'
export const load: PageServerLoad = async ({ locals: { supabase, safeGetSession } }) => {
const { session } = await safeGetSession()
if (!session) {
redirect(303, '/')
}
const { data: profile } = await supabase
.from('profiles')
.select(`username, full_name, website, avatar_url`)
.eq('id', session.user.id)
.single()
return { session, profile }
}
export const actions: Actions = {
update: async ({ request, locals: { supabase, safeGetSession } }) => {
const formData = await request.formData()
const fullName = formData.get('fullName') as string
const username = formData.get('username') as string
const website = formData.get('website') as string
const avatarUrl = formData.get('avatarUrl') as string
const { session } = await safeGetSession()
const { error } = await supabase.from('profiles').upsert({
id: session?.user.id,
full_name: fullName,
username,
website,
avatar_url: avatarUrl,
updated_at: new Date(),
})
if (error) {
return fail(500, {
fullName,
username,
website,
avatarUrl,
})
}
return {
fullName,
username,
website,
avatarUrl,
}
},
signout: async ({ locals: { supabase, safeGetSession } }) => {
const { session } = await safeGetSession()
if (session) {
await supabase.auth.signOut()
redirect(303, '/')
}
},
}
```
<$CodeSample
path="/user-management/sveltekit-user-management/src/routes/+page.server.ts"
lines={[[1, -1]]}
meta="name=src/routes/+page.server.ts"
/>
### Launch!
Now that we have all the pages in place, run this in a terminal window:
With all the pages in place, run this command in a terminal:
```bash
npm run dev
@@ -636,144 +250,29 @@ Every Supabase project is configured with [Storage](/docs/guides/storage) for ma
### Create an upload widget
Let's create an avatar for the user so that they can upload a profile photo. We can start by creating a new component called `Avatar.svelte` in the `src/routes/account` directory:
Create an avatar for the user so that they can upload a profile photo. Start by creating a new component called `Avatar.svelte` in the `src/routes/account` directory:
<$CodeTabs>
```svelte name=src/routes/account/Avatar.svelte
<!-- src/routes/account/Avatar.svelte -->
<script lang="ts">
import type { SupabaseClient } from '@supabase/supabase-js'
import { createEventDispatcher } from 'svelte'
export let size = 10
export let url: string
export let supabase: SupabaseClient
let avatarUrl: string | null = null
let uploading = false
let files: FileList
const dispatch = createEventDispatcher()
const downloadImage = async (path: string) => {
try {
const { data, error } = await supabase.storage.from('avatars').download(path)
if (error) {
throw error
}
const url = URL.createObjectURL(data)
avatarUrl = url
} catch (error) {
if (error instanceof Error) {
console.log('Error downloading image: ', error.message)
}
}
}
const uploadAvatar = async () => {
try {
uploading = true
if (!files || files.length === 0) {
throw new Error('You must select an image to upload.')
}
const file = files[0]
const fileExt = file.name.split('.').pop()
const filePath = `${Math.random()}.${fileExt}`
const { error } = await supabase.storage.from('avatars').upload(filePath, file)
if (error) {
throw error
}
url = filePath
setTimeout(() => {
dispatch('upload')
}, 100)
} catch (error) {
if (error instanceof Error) {
alert(error.message)
}
} finally {
uploading = false
}
}
$: if (url) downloadImage(url)
</script>
<div>
{#if avatarUrl}
<img
src={avatarUrl}
alt={avatarUrl ? 'Avatar' : 'No image'}
class="avatar image"
style="height: {size}em; width: {size}em;"
/>
{:else}
<div class="avatar no-image" style="height: {size}em; width: {size}em;" />
{/if}
<input type="hidden" name="avatarUrl" value={url} />
<div style="width: {size}em;">
<label class="button primary block" for="single">
{uploading ? 'Uploading ...' : 'Upload'}
</label>
<input
style="visibility: hidden; position:absolute;"
type="file"
id="single"
accept="image/*"
bind:files
on:change={uploadAvatar}
disabled={uploading}
/>
</div>
</div>
```
<$CodeSample
path="/user-management/sveltekit-user-management/src/routes/account/Avatar.svelte"
lines={[[1, -1]]}
meta="name=src/routes/account/Avatar.svelte"
/>
</$CodeTabs>
### Add the new widget
And then we can add the widget to the Account page:
Add the widget to the Account page:
<$CodeTabs>
```svelte name=src/routes/account/+page.svelte
<!-- src/routes/account/+page.svelte -->
<script lang="ts">
// Import the new component
import Avatar from './Avatar.svelte'
</script>
<div class="form-widget">
<form
class="form-widget"
method="post"
action="?/update"
use:enhance={handleSubmit}
bind:this={profileForm}
>
<!-- Add to body -->
<Avatar
{supabase}
bind:url={avatarUrl}
size={10}
on:upload={() => {
profileForm.requestSubmit();
}}
/>
<!-- Other form elements -->
</form>
</div>
```
<$CodeSample
path="/user-management/sveltekit-user-management/src/routes/account/+page.svelte"
lines={[[1, 1], [4,4], [31,31],[39,46],[82,82]]}
meta="name=src/routes/account/+page.svelte"
/>
</$CodeTabs>
@@ -40,7 +40,7 @@ import Supabase
let supabase = SupabaseClient(
supabaseURL: URL(string: "YOUR_SUPABASE_URL")!,
supabaseKey: "YOUR_SUPABASE_ANON_KEY"
supabaseKey: "YOUR_SUPABASE_PUBLISHABLE_KEY"
)
```
@@ -47,7 +47,7 @@ All we need are the API URL and the `anon` key that you copied [earlier](#get-th
```bash name=.env
VITE_SUPABASE_URL=YOUR_SUPABASE_URL
VITE_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
VITE_SUPABASE_PUBLISHABLE_KEY=YOUR_SUPABASE_PUBLISHABLE_KEY
```
</$CodeTabs>
@@ -61,7 +61,7 @@ on the browser, and that's completely fine since we have [Row Level Security](/d
import { createClient } from '@supabase/supabase-js'
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY
export const supabase = createClient(supabaseUrl, supabaseAnonKey)
```
@@ -47,10 +47,10 @@ POSTGRES_HOST
POSTGRES_PASSWORD
POSTGRES_DATABASE
SUPABASE_SERVICE_ROLE_KEY
SUPABASE_ANON_KEY
SUPABASE_PUBLISHABLE_KEY
SUPABASE_URL
SUPABASE_JWT_SECRET
NEXT_PUBLIC_SUPABASE_ANON_KEY
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY
NEXT_PUBLIC_SUPABASE_URL
```
@@ -141,7 +141,7 @@ describe('Todos RLS', () => {
const USER_1_ID = crypto.randomUUID()
const USER_2_ID = crypto.randomUUID()
const supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_ANON_KEY!)
const supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_PUBLISHABLE_KEY!)
beforeAll(async () => {
// Setup test data specific to this test suite
@@ -64,9 +64,11 @@ If you upgrade your project to a larger instance for 10 hours and then downgrade
Read more about [Compute usage](/docs/guides/platform/manage-your-usage/compute).
#### What is unified egress and how is it billed?
#### What is egress and how is it billed?
Unified egress refers to the total egress quota available to each organization. This quota can be utilized for various purposes such as Storage, Realtime, Auth, Functions, Supavisor, Log Drains and Database. Each plan includes a specific egress quota, and any additional usage beyond that quota is billed accordingly.
Egress refers to the total bandwidth (network traffic) quota available to each organization. This quota can be utilized for various purposes such as Storage, Realtime, Auth, Functions, Supavisor, Log Drains and Database. Each plan includes a specific egress quota, and any additional usage beyond that quota is billed accordingly.
We differentiate between cached (served via our CDN from cache hits) and uncached egress and give quotas for each type and have varying pricing (cached egress is cheaper).
Read more about [Egress usage](/docs/guides/platform/manage-your-usage/egress).
@@ -128,7 +130,7 @@ The Fair Use Policy is generally applied to all projects of the restricted organ
To remove restrictions, you will need to address the issue that caused the restriction. This could be reducing your usage, paying overdue invoices, updating your payment method, or any other issue that caused the restriction. Once the issue is resolved, the restriction will be lifted.
Restrictions due to usage limits are lifted with the next billing cycle as your quota refills at the beginning of each cycle. You can see when your current billing cycle ends on the [billing page](https://supabase.com/dashboard/org/_/billing) under "Upcoming Invoice". If your organization is on the Free Plan, you can also lift restrictions immediately by [upgrading](https://supabase.com/dashboard/org/_/billing?panel=subscriptionPlan) to Pro.
Restrictions due to usage limits are lifted with the next billing cycle as your quota refills at the beginning of each cycle. You can see when your current billing cycle ends on the [billing page](https://supabase.com/dashboard/org/_/billing) under "Upcoming Invoice". You can also lift restrictions immediately by [upgrading](https://supabase.com/dashboard/org/_/billing?panel=subscriptionPlan) to Pro (if on Free Plan) or by [disabling spend cap](https://supabase.com/dashboard/org/_/billing?panel=costControl) (if on Pro Plan with spend cap enabled).
## Reports and invoices
@@ -124,7 +124,7 @@ If you wish to use the new domain in client code, change the URL used in your Su
import { createClient } from '@supabase/supabase-js'
// Use a custom domain as the supabase URL
const supabase = createClient('https://api.example.com', 'public-anon-key')
const supabase = createClient('https://api.example.com', 'publishable-or-anon-key')
```
Similarly, your Edge Functions will now be available at `https://api.example.com/functions/v1/your_function_name`, and your Storage objects at `https://api.example.com/storage/v1/object/public/your_file_path.ext`.
@@ -202,7 +202,7 @@ If you wish to use the new domain in client code, you can set it up like so:
import { createClient } from '@supabase/supabase-js'
// Use a custom domain as the supabase URL
const supabase = createClient('https://my-example-brand.supabase.co', 'public-anon-key')
const supabase = createClient('https://my-example-brand.supabase.co', 'publishable-or-anon-key')
```
When using [Sign in with Twitter](/docs/guides/auth/social-login/auth-twitter) make sure your frontend code is using the subdomain only.
@@ -55,25 +55,29 @@ Data pushed to the connected log drain.
**Example:** You set up a log drain, each log sent to the log drain is considered egress. You can toggle the GZIP option to reduce egress, in case your provider supports it.
### Cached Egress
Cached and uncached egress have independent quotas and independent pricing. Cached egress is egress that is served from our CDN via cache hits. Cached egress is typically incurred for storage through our [Smart CDN](/docs/guides/storage/cdn/smart-cdn).
## How charges are calculated
Egress is charged by gigabyte. Charges apply only for usage exceeding your subscription plan's quota. This quota is called the Unified Egress Quota because it can be used across all services (Database, Auth, Storage etc.).
### Usage on your invoice
Usage is shown as "Egress GB" on your invoice.
Usage is shown as "Egress GB" and "Cached Egress GB" on your invoice.
## Pricing
<Price price="0.09" /> per GB per month. You are only charged for usage exceeding your subscription plan's
quota.
<Price price="0.09" /> per GB per month for uncached egress, <Price price="0.03" /> per GB per month
for cached egress. You are only charged for usage exceeding your subscription plan's quota.
| Plan | Unified Egress Quota | Over-Usage per month |
| ---------- | -------------------- | ----------------------------- |
| Free | 5 GB | - |
| Pro | 250 GB | <Price price="0.09" /> per GB |
| Team | 250 GB | <Price price="0.09" /> per GB |
| Enterprise | Custom | Custom |
| Plan | Egress Quota (Uncached / Cached) | Over-Usage per month (Uncached / Cached) |
| ---------- | -------------------------------- | ------------------------------------------------------------- |
| Free | 5 GB / 5 GB | - |
| Pro | 250 GB / 250 GB | <Price price="0.09" /> per GB / <Price price="0.03" /> per GB |
| Team | 250 GB / 250 GB | <Price price="0.09" /> per GB / <Price price="0.03" /> per GB |
| Enterprise | Custom | Custom |
## Billing examples
@@ -86,22 +90,24 @@ The organization's Egress usage is within the quota, so no charges for Egress ap
| Pro Plan | 1 | <Price price="25" /> |
| Compute Hours Micro | 744 hours | <Price price="10" /> |
| Egress | 200 GB | <Price price="0" /> |
| Cached Egress | 230 GB | <Price price="0" /> |
| **Subtotal** | | **<Price price="35" />** |
| Compute Credits | | -<Price price="10" /> |
| **Total** | | **<Price price="25" />** |
### Exceeding quota
The organization's Egress usage exceeds the quota by 50 GB, incurring charges for this additional usage.
The organization's Egress usage exceeds the uncached egress quota by 50 GB and the cached egress quota by 550 GB, incurring charges for this additional usage.
| Line Item | Units | Costs |
| ------------------- | --------- | -------------------------- |
| Pro Plan | 1 | <Price price="25" /> |
| Compute Hours Micro | 744 hours | <Price price="10" /> |
| Egress | 300 GB | <Price price="4.5" /> |
| **Subtotal** | | **<Price price="39.5" />** |
| Cached Egress | 800 GB | <Price price="16.5" /> |
| **Subtotal** | | **<Price price="47.5" />** |
| Compute Credits | | -<Price price="10" /> |
| **Total** | | **<Price price="29.5" />** |
| **Total** | | **<Price price="37.5" />** |
## View usage
@@ -118,7 +124,7 @@ You can view Egress usage on the [organization's usage page](https://supabase.co
zoomable
/>
In the Total Egress section, you can see the usage for the selected time period. Hover over a specific date to view a breakdown by service.
In the Total Egress section, you can see the usage for the selected time period. Hover over a specific date to view a breakdown by service. Note that this includes the cached egress.
<Image
alt="Unified Egress"
@@ -128,6 +134,16 @@ In the Total Egress section, you can see the usage for the selected time period.
}}
/>
Separately, you can see the cached egress right below:
<Image
alt="Unified Egress"
src={{
light: '/docs/img/guides/platform/cached-egress--light.png',
dark: '/docs/img/guides/platform/cached-egress.png',
}}
/>
### Custom report
1. On the [reports page](https://supabase.com/dashboard/project/_/reports), click **New custom report** in the left navigation menu
@@ -144,7 +160,7 @@ In the Total Egress section, you can see the usage for the selected time period.
## Debug usage
To better understand your Egress usage, identify what’s driving the most traffic. Check the most frequent database queries, or analyze the most requested API paths to pinpoint high-bandwidth endpoints.
To better understand your Egress usage, identify what’s driving the most traffic. Check the most frequent database queries, or analyze the most requested API paths to pinpoint high-egress endpoints.
### Frequent database queries
@@ -164,6 +164,7 @@ In projects using Postgres 17, the following extensions are deprecated:
- `plls`
- `plv8`
- `timescaledb`
- `pgjwt`
Existing projects on lower versions of Postgres are not impacted, and the extensions will continue to be supported on projects using Postgres 15, until the end of life of Postgres 15 on the Supabase platform.
Loaded 100 of 721 files, more files were not shown because too many files have changed in this diff. Show more