diff --git a/.github/workflows/fix-typos.yml b/.github/workflows/fix-typos.yml index faa0e01c84d..cf114552968 100644 --- a/.github/workflows/fix-typos.yml +++ b/.github/workflows/fix-typos.yml @@ -12,7 +12,7 @@ jobs: with: ref: master - uses: sobolevn/misspell-fixer-action@master - - uses: peter-evans/create-pull-request@v2.4.4 + - uses: peter-evans/create-pull-request@v4 env: ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true' with: diff --git a/apps/docs/components/Navigation/Navigation.constants.ts b/apps/docs/components/Navigation/Navigation.constants.ts index 57a10d0e4c2..c77ba490b70 100644 --- a/apps/docs/components/Navigation/Navigation.constants.ts +++ b/apps/docs/components/Navigation/Navigation.constants.ts @@ -1,3 +1,5 @@ +// [Terry] Also need to look at getPageType() in ./lib/helpers +// to set a menu to a page import SupabaseJsV1Nav from 'data/nav/supabase-js/v1' import SupabaseJsV2Nav from 'data/nav/supabase-js/v2' import SupabaseDartV0Nav from 'data/nav/supabase-dart/v0' @@ -5,6 +7,7 @@ import SupabaseDartV1Nav from 'data/nav/supabase-dart/v1' import SupabaseCLINav from 'data/nav/supabase-cli' import SupabaseAPINav from 'data/nav/supabase-api' import AuthServerNav from 'data/nav/auth-server' +import RealtimeServerNav from 'data/nav/realtime-server' import StorageServerNav from 'data/nav/storage-server' import { NavMenu, References } from './Navigation.types' @@ -178,11 +181,6 @@ export const menuItems: NavMenu = { url: undefined, items: [ { name: 'Overview', url: '/guides/database/extensions', items: [] }, - { - name: 'plv8: Javascript Language', - url: '/guides/database/extensions/plv8', - items: [], - }, { name: 'http: RESTful Client', url: '/guides/database/extensions/http', items: [] }, { name: 'pg_cron: Job Scheduling', @@ -195,6 +193,11 @@ export const menuItems: NavMenu = { items: [], }, { name: 'pgTAP: Unit Testing', url: '/guides/database/extensions/pgtap', items: [] }, + { + name: 'plv8: Javascript Language', + url: '/guides/database/extensions/plv8', + items: [], + }, { name: 'uuid-ossp: Unique Identifiers', url: '/guides/database/extensions/uuid-ossp', @@ -335,6 +338,7 @@ export const menuItems: NavMenu = { label: 'Self-hosting', items: [ { name: 'Auth Server', url: '/reference/auth', items: [] }, + { name: 'Realtime Server', url: '/reference/realtime', items: [] }, { name: 'Storage Server', url: '/reference/storage', items: [] }, ], }, @@ -346,5 +350,6 @@ export const menuItems: NavMenu = { 'reference/cli': SupabaseCLINav, 'reference/api': SupabaseAPINav, 'reference/auth': AuthServerNav, + 'reference/realtime': RealtimeServerNav, 'reference/storage': StorageServerNav, } diff --git a/apps/docs/data/footer.json b/apps/docs/data/footer.json index a856765f29e..c67c52972bc 100644 --- a/apps/docs/data/footer.json +++ b/apps/docs/data/footer.json @@ -86,7 +86,7 @@ }, { "text": "Open Source", - "url": "/oss" + "url": "/docs/oss" }, { "text": "SupaSquad", diff --git a/apps/docs/data/nav/realtime-server.ts b/apps/docs/data/nav/realtime-server.ts new file mode 100644 index 00000000000..dee6ab65b28 --- /dev/null +++ b/apps/docs/data/nav/realtime-server.ts @@ -0,0 +1,12 @@ +const Nav = [ + { + label: 'Realtime', + items: [ + { name: 'Realtime Server', url: '/reference/realtime', items: [] }, + { name: 'Configuration', url: '/reference/realtime/config', items: [] }, + { name: 'Release Notes', url: '/reference/realtime/release-notes', items: [] }, + ], + }, +] + +export default Nav diff --git a/apps/docs/data/nonGeneratedReferencePages.ts b/apps/docs/data/nonGeneratedReferencePages.ts index 73585f54f19..fd5ba84d1f5 100644 --- a/apps/docs/data/nonGeneratedReferencePages.ts +++ b/apps/docs/data/nonGeneratedReferencePages.ts @@ -21,6 +21,8 @@ const nonGeneratedReferencePages = [ 'docs/reference/auth/release-notes', 'docs/reference/storage', 'docs/reference/storage/release-notes', + 'docs/reference/realtime', + 'docs/reference/realtime/release-notes', ] export default nonGeneratedReferencePages diff --git a/apps/docs/docs/guides/api.mdx b/apps/docs/docs/guides/api.mdx index 68974f7c1da..9896a65128b 100644 --- a/apps/docs/docs/guides/api.mdx +++ b/apps/docs/docs/guides/api.mdx @@ -199,13 +199,6 @@ JS Reference: [select()](../reference/javascript/select), ### GraphQL API - - -To rebuild your GraphQL schema from the SQL schema, call `select graphql.rebuild_schema();`. -Be sure to rebuild the GraphQL schema after altering the SQL schema. - - - You can use any GraphQL client with the Supabase GraphQL API. For our GraphQL example we will use [urql](https://formidable.com/open-source/urql/docs/). =1.8.1" --save-dev ``` -Login with your Personal Access Token +Login with your Personal Access Token: ```bash npx supabase login ``` -Generate types for your project to produce the file `types/supabase.ts` +Generate types for your project to produce the `types/supabase.ts` file: ```bash npx supabase gen types typescript --project-id "$PROJECT_ID" --schema public > types/supabase.ts diff --git a/apps/docs/docs/guides/auth/auth-captcha.mdx b/apps/docs/docs/guides/auth/auth-captcha.mdx index 0990634b619..225c899d614 100644 --- a/apps/docs/docs/guides/auth/auth-captcha.mdx +++ b/apps/docs/docs/guides/auth/auth-captcha.mdx @@ -7,11 +7,9 @@ description: Add Captcha Protection to your Supabase project import Tabs from '@theme/Tabs' import TabItem from '@theme/TabItem' -## hCaptcha guide - Supabase provides you with the option of adding captcha to your sign-in, sign-up, and password reset forms. This keeps your website safe from bots and malicious scripts. Supabase authentication has support for [hCaptcha](https://www.hcaptcha.com/). -### Sign up for hCaptcha +## Sign up for hCaptcha Go to the [hCaptcha](https://www.hcaptcha.com/) website and sign up for an account. On the welcome page, copy the **Sitekey** and **Secret key**. @@ -27,7 +25,7 @@ In the Settings page, look for the **Sitekey** section and copy the key. ![sitekey_settings.png](/docs/img/guides/auth-captcha/sitekey_settings.png) -### Enable hCaptcha protection for your Supabase project +## Enable hCaptcha protection for your Supabase project Navigate to the **[Authentication](https://app.supabase.com/project/_/settings/auth)** page in the Supabase Dashboard and find the **Enable hCaptcha protection** toggle under the **Security and Protection** section. @@ -35,7 +33,7 @@ Navigate to the **[Authentication](https://app.supabase.com/project/_/settings/a Enter your hCaptcha **Secret key** and click **Save**. -### Add the hCaptcha frontend component +## Add the hCaptcha frontend component The frontend requires some changes to provide the captcha on-screen for the user. This example uses React and the hCaptcha React component, but hCaptcha can be used with any JavaScript framework. diff --git a/apps/docs/docs/guides/auth/auth-helpers/sveltekit.mdx b/apps/docs/docs/guides/auth/auth-helpers/sveltekit.mdx index f8267ea371c..7d5d25d3385 100644 --- a/apps/docs/docs/guides/auth/auth-helpers/sveltekit.mdx +++ b/apps/docs/docs/guides/auth/auth-helpers/sveltekit.mdx @@ -53,11 +53,351 @@ PUBLIC_SUPABASE_ANON_KEY=your-anon-key Start off by creating a `db.ts` file inside of the `src/lib` directory and instantiate the `supabaseClient`. ```ts title=src/lib/db.ts +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'; + +export const supabaseClient = createClient( + env.PUBLIC_SUPABASE_URL, + env.PUBLIC_SUPABASE_ANON_KEY +); +``` + +To make sure the client is initialized on the server and the client, include this file in `src/hooks.server.js` and `src/hooks.client.js`: + +```ts +import '$lib/db'; +``` + +### Synchronizing the page store + +Edit your `+layout.svelte` file and set up the client side. + +```html title=src/routes/+layout.svelte + + + +``` + +Every `PageLoad` or `LayoutLoad` using `getSupabase()` will update when `invalidate('supabase:auth')` is called. + +If some data is not updated on signin/signout you can fall back to `invalidateAll()`. + +### Send session to client + +To make the session available to the UI (pages, layouts), pass the session in the root layout server load function: + +```ts title=src/routes/+layout.server.ts +import type { LayoutServerLoad } from './$types'; +import { getServerSession } from '@supabase/auth-helpers-sveltekit'; + +export const load: LayoutServerLoad = async (event) => { + return { + session: await getServerSession(event) + }; +}; +``` + +In addition you can create a layout load function if you are using `invalidate('supabase:auth')`: + +```ts title=src/routes/+layout.ts +import type { LayoutLoad } from './$types'; +import { getSupabase } from '@supabase/auth-helpers-sveltekit'; + +export const load: LayoutLoad = async (event) => { + const { session } = await getSupabase(event); + return { session }; +}; +``` + +This results in fewer server calls as the client manages the session on its own. + +### Typings + +In order to get the most out of TypeScript and it´s intellisense, you should import our types into the `app.d.ts` type definition file that comes with your SvelteKit project. + +```ts title=src/app.d.ts + +/// + +// See https://kit.svelte.dev/docs/types#app +// for information about these interfaces +// and what to do when importing types +declare namespace App { + interface Supabase { + Database: import('./DatabaseDefinitions').Database; + SchemaName: 'public'; + } + + // interface Locals {} + interface PageData { + session: import('@supabase/supabase-js').Session | null; + } + // interface Error {} + // interface Platform {} +} +``` + +### Basic Setup + +You can now determine if a user is authenticated on the client-side by checking that the `session` object in `$page.data` is defined. + +```html title=src/routes/+page.svelte + + +{#if !$page.data.session} +

I am not logged in

+{:else} +

Welcome {$page.data.session.user.email}

+

I am logged in!

+{/if} +``` + +## Client-side data fetching with RLS + +For [row level security](/docs/learn/auth-deep-dive/auth-row-level-security) to work properly when fetching data client-side, you need to make sure to import the `{ supabaseClient }` from `$lib/db` and only run your query once the session is defined client-side in `$page.data`: + +```html + + +{#if $page.data.session} +

client-side data fetching with RLS

+
{JSON.stringify(loadedData, null, 2)}
+{/if} +``` + +## Server-side data fetching with RLS + +```html title=src/routes/profile/+page.svelte + + +
Protected content for {user.email}
+
{JSON.stringify(tableData, null, 2)}
+
{JSON.stringify(user, null, 2)}
+``` + +For [row level security](/docs/learn/auth-deep-dive/auth-row-level-security) to work in a server environment, you need to use the `getSupabase` helper to check if the user is authenticated. The helper requires the `event` and returns `session` and `supabaseClient`: + +```ts title=src/routes/profile/+page.ts +import type { PageLoad } from './$types'; +import { getSupabase } from '@supabase/auth-helpers-sveltekit'; +import { redirect } from '@sveltejs/kit'; + +export const load: PageLoad = async (event) => { + const { session, supabaseClient } = await getSupabase(event); + if (!session) { + throw redirect(303, '/'); + } + const { data: tableData } = await supabaseClient.from('test').select('*'); + + return { + user: session.user, + tableData + }; +}; +``` + +## Protecting API routes + +Wrap an API Route to check that the user has a valid session. If they're not logged in the session is `null`. + +```ts title=src/routes/api/protected-route/+server.ts +import type { RequestHandler } from './$types'; +import { getSupabase } from '@supabase/auth-helpers-sveltekit'; +import { json, redirect } from '@sveltejs/kit'; + +export const GET: RequestHandler = async (event) => { + const { session, supabaseClient } = await getSupabase(event); + if (!session) { + throw redirect(303, '/'); + } + const { data } = await supabaseClient.from('test').select('*'); + + return json({ data }); +}; +``` + +If you visit `/api/protected-route` without a valid session cookie, you will get a 303 response. + +## Protecting Actions + +Wrap an Action to check that the user has a valid session. If they're not logged in the session is `null`. + +```ts title=src/routes/posts/+page.server.ts +import type { Actions } from './$types'; +import { getSupabase } from '@supabase/auth-helpers-sveltekit'; +import { error, invalid } from '@sveltejs/kit'; + +export const actions: Actions = { + createPost: async (event) => { + const { request } = event; + const { session, supabaseClient } = await getSupabase(event); + if (!session) { + // the user is not signed in + throw error(403, { message: 'Unauthorized' }); + } + // we are save, let the user create the post + const formData = await request.formData(); + const content = formData.get('content'); + + const { error: createPostError, data: newPost } = await supabaseClient + .from('posts') + .insert({ content }); + + if (createPostError) { + return invalid(500, { + supabaseErrorMessage: createPostError.message + }); + } + return { + newPost + }; + } +}; +``` + +If you try to submit a form with the action `?/createPost` without a valid session cookie, you will get a 403 error response. + +## Saving and deleting the session + +```ts +import type { Actions } from './$types'; +import { invalid, redirect } from '@sveltejs/kit'; +import { getSupabase } from '@supabase/auth-helpers-sveltekit'; + +export const actions: Actions = { + signin: async (event) => { + const { request, cookies, url } = event; + const { session, supabaseClient } = await getSupabase(event); + const formData = await request.formData(); + + const email = formData.get('email') as string; + const password = formData.get('password') as string; + + const { error } = await supabaseClient.auth.signInWithPassword({ + email, + password + }); + + if (error) { + if (error instanceof AuthApiError && error.status === 400) { + return invalid(400, { + error: 'Invalid credentials.', + values: { + email + } + }); + } + return invalid(500, { + error: 'Server error. Try again later.', + values: { + email + } + }); + } + + throw redirect(303, '/dashboard'); + }, + + signout: async (event) => { + const { supabaseClient } = await getSupabase(event); + await supabaseClient.auth.signOut(); + throw redirect(303, '/'); + } +}; +``` + +## Protecting multiple routes + +To avoid writing the same auth logic in every single route you can use the handle hook to +protect multiple routes at once. + +```ts title=src/hooks.server.ts +import type { RequestHandler } from './$types'; +import { getSupabase } from '@supabase/auth-helpers-sveltekit'; +import { redirect, error } from '@sveltejs/kit'; + +export const handle: Handle = async ({ event, resolve }) => { + // protect requests to all routes that start with /protected-routes + if (event.url.pathname.startsWith('/protected-routes')) { + const { session, supabaseClient } = await getSupabase(event); + + if (!session) { + throw redirect(303, '/'); + } + } + + // protect POST requests to all routes that start with /protected-posts + if ( + event.url.pathname.startsWith('/protected-posts') && + event.request.method === 'POST' + ) { + const { session, supabaseClient } = await getSupabase(event); + + if (!session) { + throw error(303, '/'); + } + } + + return resolve(event); +}; +``` + +## Migrate from 0.7.x to 0.8 {#migration} + +### Set up the Supabase client {#migration-set-up-supabase-client} + + + + +```js title=src/lib/db.ts import { createClient } from '@supabase/supabase-js' import { setupSupabaseHelpers } from '@supabase/auth-helpers-sveltekit' 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'; export const supabaseClient = createClient(env.PUBLIC_SUPABASE_URL, env.PUBLIC_SUPABASE_ANON_KEY, { @@ -73,9 +413,34 @@ setupSupabaseHelpers({ }) ``` -### Initialize the client + + -Edit your `+layout.svelte` file and set up the client-side. +```js title=src/lib/db.ts +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'; + +export const supabaseClient = createClient( + env.PUBLIC_SUPABASE_URL, + env.PUBLIC_SUPABASE_ANON_KEY +); +``` + + + + +### Initialize the client {#migration-initialize-client} + + + ```html title=src/routes/+layout.svelte + + +``` + + + + +### Set up hooks {#migration-set-up-hooks} + + + ```ts title=src/hooks.server.ts // make sure the supabase instance is initialized on the server @@ -106,39 +505,45 @@ import { dev } from '$app/environment' import { auth } from '@supabase/auth-helpers-sveltekit/server' export const handle = auth() +``` -// use the sequence helper if you have additional Handle methods +**Optional** _if using additional handle methods_ + +```ts title=src/hooks.server.ts +// make sure the supabase instance is initialized on the server +import '$lib/db' +import { dev } from '$app/environment' +import { auth } from '@supabase/auth-helpers-sveltekit/server' import { sequence } from '@sveltejs/kit/hooks' export const handle = sequence(auth(), yourHandler) ``` -There are three handle methods available: + + -- `callback()`: - This creates a handler for `/api/auth/callback`. The `client` forwards the session details here every time `onAuthStateChange` fires on the client-side. This is needed to set up the cookies for your application so that SSR works seamlessly. -- `session()`: - This parses the session from the cookie and populate it in locals -- `auth()`: - a shorthand for `sequence(callback(), session())` that uses both handlers - -### Send session to client - -In order to make the session available to the UI (e.g., pages and layouts), pass the session in the root layout load function: - -```ts title=src/routes/+layout.server.ts -import type { LayoutServerLoad } from './$types' - -export const load: LayoutServerLoad = async ({ locals }) => { - return { - session: locals.session, - } -} +```ts title=src/hooks.server.ts +// make sure the supabase instance is initialized on the server +import '$lib/db' ``` -### Typings +```ts title=src/hooks.client.ts +// make sure the supabase instance is initialized on the client +import '$lib/db' +``` -In order to get the most out of TypeScript and IntelliSense, import the types into the `app.d.ts` type definition file that comes with your SvelteKit project. + + + +### Typings {#migration-typings} + + + ```ts title=src/app.d.ts /// @@ -150,95 +555,91 @@ declare namespace App { interface Locals { session: import('@supabase/auth-helpers-sveltekit').SupabaseSession } + interface PageData { session: import('@supabase/auth-helpers-sveltekit').SupabaseSession } + + // interface Error {} + // interface Platform {} +} +``` + + + + +```ts title=src/app.d.ts +/// + +// See https://kit.svelte.dev/docs/types#app +// for information about these interfaces +// and what to do when importing types +declare namespace App { + interface Supabase { + Database: import('./DatabaseDefinitions').Database; + SchemaName: 'public'; + } + + // interface Locals {} + interface PageData { + session: import('@supabase/auth-helpers-sveltekit').SupabaseSession; + } // interface Error {} // interface Platform {} } ``` -### Signing out + + -This library has provided a method to delete the session cookie. +### withPageAuth {#migration-with-page-auth} -Create a server only page with an action to delete the cookie + + -```ts title=src/routes/logout/+page.server.ts -import { deleteSession } from '@supabase/auth-helpers-sveltekit/server' -import { redirect } from '@sveltejs/kit' -import type { Actions } from './$types' - -export const actions: Actions = { - async default({ cookies }) { - deleteSession(cookies) - throw redirect(303, '/') - }, -} -``` - -Then make a **POST** request with a form to the server only page above. - -```html +```html title=src/routes/protected-route/+page.svelte -
- -
+
Protected content for {user.email}
+

server-side fetched data with RLS:

+
{JSON.stringify(tableData, null, 2)}
+

user:

+
{JSON.stringify(user, null, 2)}
``` -### Basic setup +```ts title=src/routes/protected-route/+page.ts +import { withAuth } from '@supabase/auth-helpers-sveltekit' +import { redirect } from '@sveltejs/kit' +import type { PageLoad } from './$types' -You can now determine if a user is authenticated on the client-side by checking that the `user` object in `$page.data.session` is defined. - -```html title=src/routes/+page.svelte - - -{#if !$page.data.session.user} -

I am not logged in

-{:else} -

Welcome {$page.data.session.user.email}

-

I am logged in!

-{/if} -``` - -## Client-side data fetching with RLS - -For [row level security](/docs/learn/auth-deep-dive/auth-row-level-security) to work properly when fetching data client-side, you need to make sure to import the `{ supabaseClient }` from `$lib/db` and only run your query once the user is defined client-side in `$page.data.session`: - -```html - - -{#if $page.data.session.user} -

client-side data fetching with RLS

-
{JSON.stringify(loadedData, null, 2)}
-{/if} + const { data: tableData } = await getSupabaseClient().from('test').select('*') + return { tableData, user: session.user } +}) ``` -## Server-side data fetching with RLS +
+ -```html title=src/routes/profile/+page.svelte +```html title=src/routes/protected-route/+page.svelte
Protected content for {user.email}
@@ -246,52 +647,38 @@ For [row level security](/docs/learn/auth-deep-dive/auth-row-level-security) to
{JSON.stringify(user, null, 2)}
``` -For [row level security](/docs/learn/auth-deep-dive/auth-row-level-security) to work in a server environment, you need to use the `withAuth` helper to check if the user is authenticated. The helper extends the event with `session` and `getSupabaseClient()`: - -```ts title=src/routes/profile/+page.ts +```ts title=src/routes/protected-route/+page.ts +// src/routes/profile/+page.ts import type { PageLoad } from './$types'; -import { withAuth } from '@supabase/auth-helpers-sveltekit'; +import { getSupabase } from '@supabase/auth-helpers-sveltekit'; import { redirect } from '@sveltejs/kit'; -interface TestTable { - id: string; - created_at: string; -} - -export const load: PageLoad = withAuth(async ({ getSupabaseClient, session }) => { - if (!session.user) { +export const load: PageLoad = async (event) => { + const { session, supabaseClient } = await getSupabase(event); + if (!session) { throw redirect(303, '/'); } - const { data: tableData } = await getSupabaseClient() - .from('test') - .select('*'); + const { data: tableData } = await supabaseClient.from('test').select('*'); return { user: session.user, tableData }; -); +}; ``` -**Caution:** +
+
-Always use the instance returned by `getSupabaseClient()` directly! +### withApiAuth {#migration-with-api-auth} -```ts -// Bad -const supabaseClient = getSupabaseClient() - -await supabaseClient.from('table1').select() -await supabaseClient.from('table2').select() - -// Good -await getSupabaseClient().from('table1').select() -await getSupabaseClient().from('table2').select() -``` - -## Protecting API routes - -Wrap an API Route to check that the user has a valid session. If they're not logged in the session is `null`. + + ```ts title=src/routes/api/protected-route/+server.ts import type { RequestHandler } from './$types'; @@ -307,148 +694,38 @@ export const GET: RequestHandler = withAuth(async ({ session, getSupabaseClient if (!session.user) { throw redirect(303, '/'); } + const { data } = await getSupabaseClient() .from('test') .select('*'); return json({ data }); -); +}); ``` -If you visit `/api/protected-route` without a valid session cookie, you will get a 303 response. + + -## Protecting Actions +```ts title=src/routes/api/protected-route/+server.ts +import type { RequestHandler } from './$types'; +import { getSupabase } from '@supabase/auth-helpers-sveltekit'; +import { json, redirect } from '@sveltejs/kit'; -Wrap an Action to check that the user has a valid session. If they're not logged in, the session is `null`. - -```ts title=src/routes/posts/+page.server.ts -import type { Actions } from './$types' -import { withAuth } from '@supabase/auth-helpers-sveltekit' -import { error, invalid } from '@sveltejs/kit' - -export const actions: Actions = { - createPost: withAuth(async ({ session, getSupabaseClient, request }) => { - if (!session.user) { - // the user is not signed in - throw error(403, { message: 'Unauthorized' }) - } - // we are save, let the user create the post - const formData = await request.formData() - const content = formData.get('content') - - const { error: createPostError, data: newPost } = await getSupabaseClient() - .from('posts') - .insert({ content }) - - if (createPostError) { - return invalid(500, { - supabaseErrorMessage: createPostError.message, - }) - } - return { - newPost, - } - }), -} -``` - -If you try to submit a form with the action `?/createPost` without a valid session cookie, you will get a 403 error response. - -## Saving and deleting the session - -Use `saveSession` to save the session cookies: - -```ts -import type { Actions } from './$types' -import { supabaseClient } from '$lib/db' -import { invalid, redirect } from '@sveltejs/kit' -import { saveSession } from '@supabase/auth-helpers-sveltekit/server' - -export const actions: Actions = { - async signin({ request, cookies, url }) { - const formData = await request.formData() - - const email = formData.get('email') as string - const password = formData.get('password') as string - - const { data, error } = await supabaseClient.auth.api.signInWithEmail(email, password, { - redirectTo: `${url.origin}/logging-in`, - }) - - if (error || !data) { - if (error?.status === 400) { - return invalid(400, { - error: 'Invalid credentials', - values: { - email, - }, - }) - } - return invalid(500, { - error: 'Server error. Try again later.', - values: { - email, - }, - }) - } - - saveSession(cookies, data) - throw redirect(303, '/dashboard') - }, -} -``` - -Use `deleteSession` to delete the session cookies: - -```ts -import type { Actions } from './$types' -import { deleteSession } from '@supabase/auth-helpers-sveltekit/server' -import { redirect } from '@sveltejs/kit' - -export const actions: Actions = { - async logout({ cookies }) { - deleteSession(cookies) - throw redirect(303, '/') - }, -} -``` - -## Custom session namespace - -If you want to use something other than `locals.session` and `$page.data.session`, update the types and create three helper functions: - -```ts title=src/app.d.ts -declare namespace App { - interface Locals { - mySupabaseSession: import('@supabase/auth-helpers-sveltekit').SupabaseSession +export const GET: RequestHandler = async (event) => { + const { session, supabaseClient } = await getSupabase(event); + if (!session) { + throw redirect(303, '/'); } - interface PageData { - mySupabaseSession: import('@supabase/auth-helpers-sveltekit').SupabaseSession - } -} + const { data } = await supabaseClient.from('test').select('*'); + + return json({ data }); +}; ``` -```ts title=src/hooks.server.ts -setupSupabaseServer({ - supabaseClient, - cookieOptions: { - secure: !dev, - }, - // --- change location within locals --- - getSessionFromLocals: (locals) => locals.mySupabaseSession, - setSessionToLocals: (locals, session) => (locals.mySupabaseSession = session), -}) -``` + + -```ts title=src/lib/db.ts -setupSupabaseClient({ - supabaseClient, - // --- change location within pageData --- - getSessionFromPageData: (data) => data.mySupabaseSession, -}) -``` - -## Migrate from 0.6.11 and below to 0.7.0 {#migration} +## Migrate from 0.6.11 and below to 0.7.0 {#migration-0-7} There are numerous breaking changes in the latest 0.7.0 version of this library. @@ -456,7 +733,7 @@ There are numerous breaking changes in the latest 0.7.0 version of this library. The environment variable prefix is now `PUBLIC_` instead of `VITE_` (e.g., `VITE_SUPABASE_URL` is now `PUBLIC_SUPABASE_URL`). -### Set up the Supabase client {#migration-set-up-supabase-client} +### Set up the Supabase client {#migration-set-up-supabase-client-0-7} - + ```js title=src/lib/db.ts import { createClient } from '@supabase/supabase-js' @@ -505,7 +782,7 @@ setupSupabaseHelpers({ -### Initialize the client {#migration-initialize-client} +### Initialize the client {#migration-initialize-client-0-7} - + The `@supabase/auth-helpers-svelte` library is no longer required as the `@supabase/auth-helpers-sveltekit` library handles all the client-side code. @@ -553,7 +830,7 @@ The `@supabase/auth-helpers-svelte` library is no longer required as the `@supab -### Set up hooks {#migration-set-up-hooks} +### Set up hooks {#migration-set-up-hooks-0-7} { ``` - + ```ts title=src/hooks.server.ts // make sure the supabase instance is initialized on the server @@ -607,7 +884,7 @@ export const handle = sequence(auth(), yourHandler) -### Typings {#migration-typings} +### Typings {#migration-typings-0-7} - + ```ts title=src/app.d.ts /// @@ -688,7 +965,7 @@ declare namespace App { ``` - + ```html title=src/routes/+page.svelte