@supabase/auth-helpers-sveltekit
Advanced tools
Comparing version 0.7.1 to 0.7.2-next.0
@@ -5,8 +5,10 @@ // See https://kit.svelte.dev/docs/types#app | ||
declare namespace App { | ||
interface Locals { | ||
session: import('./').SupabaseSession; | ||
interface Supabase { | ||
Database: any; | ||
SchemaName: 'public'; | ||
} | ||
// interface Locals {} | ||
interface PageData { | ||
session: import('./').SupabaseSession; | ||
session: import('@supabase/supabase-js').Session | null; | ||
} | ||
@@ -13,0 +15,0 @@ // interface Error {} |
@@ -1,6 +0,3 @@ | ||
import type { Config, SetupOptions } from './types.js'; | ||
/** | ||
* Setup the global client configuration | ||
*/ | ||
export declare function setupSupabaseHelpers({ supabaseClient, tokenRefreshMargin, endpointPrefix, cookieOptions, getSessionFromPageData, getSessionFromLocals, setSessionToLocals }: SetupOptions): void; | ||
import type { Config } from './types'; | ||
export declare function setConfig(value: Config): void; | ||
export declare function getConfig(): Config; |
@@ -1,30 +0,7 @@ | ||
import { ENDPOINT_PREFIX, TOKEN_REFRESH_MARGIN, COOKIE_OPTIONS } from './constants.js'; | ||
let config; | ||
/** | ||
* Setup the global client configuration | ||
*/ | ||
export function setupSupabaseHelpers({ supabaseClient, tokenRefreshMargin = TOKEN_REFRESH_MARGIN, endpointPrefix = ENDPOINT_PREFIX, cookieOptions = {}, getSessionFromPageData = (data) => data.session, getSessionFromLocals = (locals) => locals.session, setSessionToLocals = (locals, session) => (locals.session = session) }) { | ||
if (config) | ||
throw new Error('`setupSupabaseHelpers` called multiple times'); | ||
if (!supabaseClient) { | ||
throw new Error('You need to pass the your supabase instance to `setupSupabaseHelpers`'); | ||
} | ||
config = { | ||
supabaseClient, | ||
tokenRefreshMargin, | ||
endpointPrefix, | ||
cookieOptions: { | ||
...COOKIE_OPTIONS, | ||
...cookieOptions | ||
}, | ||
getSessionFromPageData, | ||
getSessionFromLocals, | ||
setSessionToLocals | ||
}; | ||
export function setConfig(value) { | ||
config = value; | ||
} | ||
export function getConfig() { | ||
if (!config) { | ||
throw new Error('Not initialized, make sure to call `setupSupabaseHelpers({ supabaseClient })`'); | ||
} | ||
return config; | ||
} |
@@ -1,3 +0,2 @@ | ||
import type { CookieOptions } from './types.js'; | ||
export { TOKEN_REFRESH_MARGIN, ENDPOINT_PREFIX } from '@supabase/auth-helpers-shared'; | ||
export declare const COOKIE_OPTIONS: Required<CookieOptions>; | ||
export declare const PKG_NAME = "@supabase/auth-helpers-sveltekit"; | ||
export declare const PKG_VERSION = "0.7.2-next.0"; |
@@ -1,6 +0,2 @@ | ||
import { COOKIE_OPTIONS as SHARED_COOKIE_OPTIONS } from '@supabase/auth-helpers-shared'; | ||
export { TOKEN_REFRESH_MARGIN, ENDPOINT_PREFIX } from '@supabase/auth-helpers-shared'; | ||
export const COOKIE_OPTIONS = { | ||
...SHARED_COOKIE_OPTIONS, | ||
secure: true | ||
}; | ||
export const PKG_NAME = '@supabase/auth-helpers-sveltekit'; | ||
export const PKG_VERSION = '0.7.2-next.0'; |
@@ -1,5 +0,4 @@ | ||
export { setupSupabaseHelpers } from './config.js'; | ||
export { startSupabaseSessionSync } from './client.js'; | ||
export { supabaseServerClient } from './utils/supabaseServerClient.js'; | ||
export { withAuth } from './utils/withAuth.js'; | ||
export type { SupabaseSession, CookieOptions, Config, SetupOptions } from './types'; | ||
export type { ExtendedEvent, Config } from './types'; | ||
export { getSupabase } from './utils/getSupabase'; | ||
export { getServerSession } from './utils/getServerSession'; | ||
export { createClient } from './createClient'; |
@@ -1,4 +0,3 @@ | ||
export { setupSupabaseHelpers } from './config.js'; | ||
export { startSupabaseSessionSync } from './client.js'; | ||
export { supabaseServerClient } from './utils/supabaseServerClient.js'; | ||
export { withAuth } from './utils/withAuth.js'; | ||
export { getSupabase } from './utils/getSupabase'; | ||
export { getServerSession } from './utils/getServerSession'; | ||
export { createClient } from './createClient'; |
@@ -1,30 +0,14 @@ | ||
import type { SupabaseClient, User } from '@supabase/supabase-js'; | ||
import type { CookieOptions as SharedCookieOptions, ErrorPayload } from '@supabase/auth-helpers-shared'; | ||
export interface CookieOptions extends SharedCookieOptions { | ||
secure?: boolean; | ||
} | ||
export declare type SupabaseSession = { | ||
user: User; | ||
accessToken: string; | ||
error?: undefined; | ||
} | { | ||
user?: undefined; | ||
accessToken?: undefined; | ||
error?: ErrorPayload; | ||
}; | ||
import type { CookieOptions } from '@supabase/auth-helpers-shared'; | ||
import type { Session, SupabaseClient, SupabaseClientOptions } from '@supabase/supabase-js'; | ||
export declare type TypedSupabaseClient = SupabaseClient<App.Supabase['Database'], App.Supabase['SchemaName']>; | ||
export interface ExtendedEvent { | ||
getSupabaseClient(): SupabaseClient; | ||
session: SupabaseSession; | ||
session: Session | null; | ||
supabaseClient: TypedSupabaseClient; | ||
} | ||
export interface SetupOptions { | ||
supabaseClient: SupabaseClient; | ||
tokenRefreshMargin?: number; | ||
endpointPrefix?: string; | ||
cookieOptions?: CookieOptions; | ||
getSessionFromPageData?: (data: App.PageData) => SupabaseSession; | ||
getSessionFromLocals?: (locals: App.Locals) => SupabaseSession; | ||
setSessionToLocals?: (locals: App.Locals, session: SupabaseSession) => void; | ||
export interface Config { | ||
globalInstance: TypedSupabaseClient; | ||
supabaseUrl: string; | ||
supabaseKey: string; | ||
options: SupabaseClientOptions<App.Supabase['SchemaName']>; | ||
cookieOptions: CookieOptions; | ||
} | ||
export interface Config extends Omit<Required<SetupOptions>, 'cookieOptions'> { | ||
cookieOptions: Required<CookieOptions>; | ||
} |
{ | ||
"name": "@supabase/auth-helpers-sveltekit", | ||
"version": "0.7.1", | ||
"version": "0.7.2-next.0", | ||
"description": "A collection of framework specific Auth utilities for working with Supabase.", | ||
@@ -15,14 +15,4 @@ "type": "module", | ||
".": "./dist/index.js", | ||
"./server": "./dist/server/index.js" | ||
"./": "./dist/index.js" | ||
}, | ||
"typesVersions": { | ||
"*": { | ||
"server": [ | ||
"./dist/server/index.d.ts" | ||
], | ||
"./": [ | ||
"./dist/index.d.ts" | ||
] | ||
} | ||
}, | ||
"files": [ | ||
@@ -48,4 +38,4 @@ "dist" | ||
"devDependencies": { | ||
"@supabase/supabase-js": "^1.35.3", | ||
"@sveltejs/kit": "1.0.0-next.499", | ||
"@supabase/supabase-js": "2.0.0-rc.10", | ||
"@sveltejs/kit": "1.0.0-next.504", | ||
"@sveltejs/package": "1.0.0-next.5", | ||
@@ -61,13 +51,14 @@ "del-cli": "^5.0.0", | ||
"dependencies": { | ||
"@supabase/auth-helpers-shared": "0.1.4" | ||
"@supabase/auth-helpers-shared": "0.2.0-next.3" | ||
}, | ||
"peerDependencies": { | ||
"@supabase/supabase-js": "^1.35.3" | ||
"@supabase/supabase-js": "2.0.0-rc.10" | ||
}, | ||
"scripts": { | ||
"build": "svelte-kit sync && svelte-package && pnpm del:dup", | ||
"build": "pnpm make:constants && svelte-kit sync && svelte-package && pnpm del:dup", | ||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", | ||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", | ||
"del:dup": "del-cli dist/package.json dist/CHANGELOG.md dist/README.md" | ||
"del:dup": "del-cli dist/package.json dist/CHANGELOG.md dist/README.md", | ||
"make:constants": "node ./scripts/make_constants.cjs > src/constants.ts" | ||
} | ||
} |
262
README.md
@@ -41,5 +41,3 @@ # @supabase/auth-helpers-sveltekit (BETA) | ||
// src/lib/db.ts | ||
import { createClient } from '@supabase/supabase-js'; | ||
import { setupSupabaseHelpers } from '@supabase/auth-helpers-sveltekit'; | ||
import { dev } from '$app/environment'; | ||
import { createClient } from '@supabase/auth-helpers-sveltekit'; | ||
import { env } from '$env/dynamic/public'; | ||
@@ -49,17 +47,15 @@ // or use the static env | ||
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_ANON_KEY | ||
); | ||
``` | ||
setupSupabaseHelpers({ | ||
supabaseClient, | ||
cookieOptions: { | ||
secure: !dev | ||
} | ||
}); | ||
To make sure the client is initialized on the server and the client we include this file in `src/hooks.server.js` and `src/hooks.client.js`: | ||
```ts | ||
import '$lib/db'; | ||
``` | ||
### Initialize the client | ||
### Synchronizing the page store | ||
@@ -70,13 +66,17 @@ Edit your `+layout.svelte` file and set up the client side. | ||
<!-- src/routes/+layout.svelte --> | ||
<script lang="ts"> | ||
// we need to make sure the supabase instance is initialized on the client | ||
import '$lib/db'; | ||
import { startSupabaseSessionSync } from '@supabase/auth-helpers-sveltekit'; | ||
<script> | ||
import { supabaseClient } from '$lib/db'; | ||
import { invalidateAll } from '$app/navigation'; | ||
import { page } from '$app/stores'; | ||
import { onMount } from 'svelte'; | ||
// this sets up automatic token refreshing | ||
startSupabaseSessionSync({ | ||
page, | ||
handleRefresh: () => invalidateAll() | ||
onMount(() => { | ||
const { | ||
data: { subscription } | ||
} = supabaseClient.auth.onAuthStateChange(() => { | ||
invalidate('supabase:auth'); | ||
}); | ||
return () => { | ||
subscription.unsubscribe(); | ||
}; | ||
}); | ||
@@ -88,39 +88,9 @@ </script> | ||
### Hooks setup | ||
Every `PageLoad` or `LayoutLoad` wrapped with `withAuth` will update when `invalidate('supabase:auth')` is called. | ||
Our `hooks.ts` file is where the heavy lifting of this library happens: | ||
If some data is not updated on signin/signout you can fall back to `invalidateAll()`. | ||
```ts | ||
// src/hooks.server.ts | ||
// we need to 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'; | ||
export const handle = auth(); | ||
// use the sequence helper if you have additional Handle methods | ||
import { sequence } from '@sveltejs/kit/hooks'; | ||
export const handle = sequence(auth(), yourHandler); | ||
``` | ||
There are three handle methods available: | ||
- `callback()`: | ||
This will create 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 will parse 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 (pages, layouts) we need to pass the session in the root layout load function: | ||
In order to make the session available to the UI (pages, layouts) we need to pass the session in the root layout server load function: | ||
@@ -130,6 +100,7 @@ ```ts | ||
import type { LayoutServerLoad } from './$types'; | ||
import { getServerSession } from '@supabase/auth-helpers-sveltekit'; | ||
export const load: LayoutServerLoad = async ({ locals }) => { | ||
export const load: LayoutServerLoad = async (event) => { | ||
return { | ||
session: locals.session | ||
session: await getServerSession(event) | ||
}; | ||
@@ -139,2 +110,16 @@ }; | ||
In addition you can create a layout load function if you are using `invalidate('supabase:auth')`: | ||
```ts | ||
// src/routes/+layout.ts | ||
import type { LayoutLoad } from './$types'; | ||
import { withAuth } from '@supabase/auth-helpers-sveltekit'; | ||
export const load: LayoutLoad = withAuth(async ({ session }) => { | ||
return { session }; | ||
}); | ||
``` | ||
This results in less server calls as the client manages the session on it´s own. | ||
### Typings | ||
@@ -153,7 +138,10 @@ | ||
declare namespace App { | ||
interface Locals { | ||
session: import('@supabase/auth-helpers-sveltekit').SupabaseSession; | ||
interface Supabase { | ||
Database: import('./DatabaseDefinitions').Database; | ||
SchemaName: 'public'; | ||
} | ||
// interface Locals {} | ||
interface PageData { | ||
session: import('@supabase/auth-helpers-sveltekit').SupabaseSession; | ||
session: import('@supabase/supabase-js').Session | null; | ||
} | ||
@@ -167,3 +155,3 @@ // interface Error {} | ||
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. | ||
You can now determine if a user is authenticated on the client-side by checking that the `session` object in `$page.data` is defined. | ||
@@ -176,7 +164,7 @@ ```html | ||
{#if !$page.data.session.user} | ||
<h1>I am not logged in</h1> | ||
{#if !$page.data.session} | ||
<h1>I am not logged in</h1> | ||
{:else} | ||
<h1>Welcome {$page.data.session.user.email}</h1> | ||
<p>I am logged in!</p> | ||
<h1>Welcome {$page.data.session.user.email}</h1> | ||
<p>I am logged in!</p> | ||
{/if} | ||
@@ -187,3 +175,3 @@ ``` | ||
For [row level security](https://supabase.com/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`: | ||
For [row level security](https://supabase.com/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`: | ||
@@ -201,3 +189,3 @@ ```html | ||
$: if ($page.data.session.user) { | ||
$: if ($page.data.session) { | ||
loadData(); | ||
@@ -207,5 +195,5 @@ } | ||
{#if $page.data.session.user} | ||
<p>client-side data fetching with RLS</p> | ||
<pre>{JSON.stringify(loadedData, null, 2)}</pre> | ||
{#if $page.data.session} | ||
<p>client-side data fetching with RLS</p> | ||
<pre>{JSON.stringify(loadedData, null, 2)}</pre> | ||
{/if} | ||
@@ -229,3 +217,3 @@ ``` | ||
For [row level security](https://supabase.com/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()`: | ||
For [row level security](https://supabase.com/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 `supabaseClient`: | ||
@@ -238,13 +226,8 @@ ```ts | ||
interface TestTable { | ||
id: string; | ||
created_at: string; | ||
} | ||
export const load: PageLoad = withAuth(async ({ getSupabaseClient, session }) => { | ||
if (!session.user) { | ||
export const load: PageLoad = withAuth(async ({ supabaseClient, session }) => { | ||
if (!session) { | ||
throw redirect(303, '/'); | ||
} | ||
const { data: tableData } = await getSupabaseClient() | ||
.from<TestTable>('test') | ||
const { data: tableData } = await supabaseClient | ||
.from('test') | ||
.select('*'); | ||
@@ -259,18 +242,2 @@ | ||
**Caution:** | ||
Always use the instance returned by `getSupabaseClient()` directly! | ||
```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 | ||
@@ -286,13 +253,8 @@ | ||
interface TestTable { | ||
id: string; | ||
created_at: string; | ||
} | ||
export const GET: RequestHandler = withAuth(async ({ session, getSupabaseClient }) => { | ||
if (!session.user) { | ||
export const GET: RequestHandler = withAuth(async ({ session, supabaseClient }) => { | ||
if (!session) { | ||
throw redirect(303, '/'); | ||
} | ||
const { data } = await getSupabaseClient() | ||
.from<TestTable>('test') | ||
const { data } = await supabaseClient | ||
.from('test') | ||
.select('*'); | ||
@@ -317,4 +279,4 @@ | ||
export const actions: Actions = { | ||
createPost: withAuth(async ({ session, getSupabaseClient, request }) => { | ||
if (!session.user) { | ||
createPost: withAuth(async ({ session, supabaseClient, request }) => { | ||
if (!session) { | ||
// the user is not signed in | ||
@@ -327,3 +289,3 @@ throw error(403, { message: 'Unauthorized' }); | ||
const { error: createPostError, data: newPost } = await getSupabaseClient() | ||
const { error: createPostError, data: newPost } = await supabaseClient | ||
.from('posts') | ||
@@ -348,12 +310,9 @@ .insert({ content }); | ||
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'; | ||
import { withAuth } from '@supabase/auth-helpers-sveltekit'; | ||
export const actions: Actions = { | ||
async signin({ request, cookies, url }) { | ||
signin: withAuth(async ({ request, cookies, url, supabaseClient }) => { | ||
const formData = await request.formData(); | ||
@@ -364,3 +323,4 @@ | ||
const { data, error } = await supabaseClient.auth.signIn({ email, password }, | ||
const { error } = await supabaseClient.auth.signIn( | ||
{ email, password }, | ||
{ | ||
@@ -371,11 +331,11 @@ redirectTo: `${url.origin}/logging-in` | ||
if (error || !data) { | ||
if (error?.status === 400) { | ||
return invalid(400, { | ||
error: 'Invalid credentials', | ||
values: { | ||
} | ||
}); | ||
} | ||
if (error?.status === 400) { | ||
return invalid(400, { | ||
error: 'Invalid credentials', | ||
values: { | ||
} | ||
}); | ||
} | ||
if (error) { | ||
return invalid(500, { | ||
@@ -388,56 +348,10 @@ error: 'Server error. Try again later.', | ||
} | ||
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); | ||
signout: withAuth(async ({ supabaseClient }) => { | ||
await supabaseClient.auth.signOut(); | ||
throw redirect(303, '/'); | ||
} | ||
}) | ||
}; | ||
``` | ||
## Custom session namespace | ||
If you wan´t to use something else than `locals.session` and `$page.data.session` you can do so by updating the types and creating three helper functions: | ||
```ts | ||
// src/app.d.ts | ||
declare namespace App { | ||
interface Locals { | ||
mySupabaseSession: import('@supabase/auth-helpers-sveltekit').SupabaseSession; | ||
} | ||
interface PageData { | ||
mySupabaseSession: import('@supabase/auth-helpers-sveltekit').SupabaseSession; | ||
} | ||
} | ||
// src/hooks.server.ts | ||
setupSupabaseServer({ | ||
supabaseClient, | ||
cookieOptions: { | ||
secure: !dev | ||
}, | ||
// --- change location within locals --- | ||
getSessionFromLocals: (locals) => locals.mySupabaseSession, | ||
setSessionToLocals: (locals, session) => (locals.mySupabaseSession = session) | ||
}); | ||
// src/lib/db.ts | ||
setupSupabaseClient({ | ||
supabaseClient, | ||
// --- change location within pageData --- | ||
getSessionFromPageData: (data) => data.mySupabaseSession | ||
}); | ||
``` |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
1
19869
22
209
336
+ Added@supabase/auth-helpers-shared@0.2.0-next.3(transitive)
+ Added@supabase/functions-js@2.4.4(transitive)
+ Added@supabase/gotrue-js@2.68.0(transitive)
+ Added@supabase/node-fetch@2.6.15(transitive)
+ Added@supabase/postgrest-js@1.18.1(transitive)
+ Added@supabase/realtime-js@2.11.3(transitive)
+ Added@supabase/storage-js@2.7.1(transitive)
+ Added@supabase/supabase-js@2.0.0-rc.10(transitive)
+ Added@types/node@22.13.4(transitive)
+ Added@types/ws@8.5.14(transitive)
+ Addedundici-types@6.20.0(transitive)
+ Addedws@8.18.0(transitive)
- Removed@supabase/auth-helpers-shared@0.1.4(transitive)
- Removed@supabase/functions-js@1.3.4(transitive)
- Removed@supabase/gotrue-js@1.24.0(transitive)
- Removed@supabase/postgrest-js@0.37.4(transitive)
- Removed@supabase/realtime-js@1.7.5(transitive)
- Removed@supabase/storage-js@1.7.3(transitive)
- Removed@supabase/supabase-js@1.35.7(transitive)
- Removedbufferutil@4.0.9(transitive)
- Removedd@1.0.2(transitive)
- Removeddebug@2.6.9(transitive)
- Removedes5-ext@0.10.64(transitive)
- Removedes6-iterator@2.0.3(transitive)
- Removedes6-symbol@3.1.4(transitive)
- Removedesniff@2.0.1(transitive)
- Removedevent-emitter@0.3.5(transitive)
- Removedext@1.7.0(transitive)
- Removedis-typedarray@1.0.0(transitive)
- Removedjose@4.15.9(transitive)
- Removedms@2.0.0(transitive)
- Removednext-tick@1.1.0(transitive)
- Removednode-gyp-build@4.8.4(transitive)
- Removedtype@2.7.3(transitive)
- Removedtypedarray-to-buffer@3.1.5(transitive)
- Removedutf-8-validate@5.0.10(transitive)
- Removedwebsocket@1.0.35(transitive)
- Removedyaeti@0.0.6(transitive)