diff --git a/src/routes/hooks.server.ts b/src/hooks.server.ts similarity index 100% rename from src/routes/hooks.server.ts rename to src/hooks.server.ts diff --git a/src/routes/+page.server.ts b/src/routes/+page.server.ts new file mode 100644 index 0000000..ff67b68 --- /dev/null +++ b/src/routes/+page.server.ts @@ -0,0 +1,10 @@ +import type { PageServerLoad } from './$types' + +export const load: PageServerLoad = async ({ locals: { supabase } }) => { + const { data: countries } = await supabase + .from('countries') + .select('name') + .limit(5) + .order('name') + return { countries: countries ?? [] } +} diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 550ea6e..2c6d28b 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,8 +1,22 @@ -

- Hello world! -

- + +
+

+ Supavelte! +

+
+ + Authenticate + + + Private + +
+ +
diff --git a/src/routes/api/auth/confirm/+server.ts b/src/routes/api/auth/confirm/+server.ts new file mode 100644 index 0000000..d6f1a5b --- /dev/null +++ b/src/routes/api/auth/confirm/+server.ts @@ -0,0 +1,30 @@ +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") ?? "/" + + /** + * 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") + return redirect(303, redirectTo) + } + } + + redirectTo.pathname = "/auth/error" + return redirect(303, redirectTo) +} diff --git a/src/routes/auth/+layout.svelte b/src/routes/auth/+layout.svelte new file mode 100644 index 0000000..1f6b19e --- /dev/null +++ b/src/routes/auth/+layout.svelte @@ -0,0 +1,6 @@ +
+ +
+ diff --git a/src/routes/auth/+page.server.ts b/src/routes/auth/+page.server.ts new file mode 100644 index 0000000..81fdfe4 --- /dev/null +++ b/src/routes/auth/+page.server.ts @@ -0,0 +1,32 @@ +import { redirect } from "@sveltejs/kit" + +import type { Actions } from './$types' + +export const actions: Actions = { + signup: async ({ request, locals: { supabase } }) => { + const formData = await request.formData() + const email = formData.get("email") as string + const password = formData.get("password") as string + + const { error } = await supabase.auth.signUp({ email, password }) + if (error) { + console.error(error) + return redirect(303, "/auth/error") + } else { + return redirect(303, "/") + } + }, + login: async ({ request, locals: { supabase } }) => { + const formData = await request.formData() + const email = formData.get("email") as string + const password = formData.get("password") as string + + const { error } = await supabase.auth.signInWithPassword({ email, password }) + if (error) { + console.error(error) + return redirect(303, "/auth/error") + } else { + return redirect(303, "/private") + } + } +} diff --git a/src/routes/auth/+page.svelte b/src/routes/auth/+page.svelte new file mode 100644 index 0000000..8a36e36 --- /dev/null +++ b/src/routes/auth/+page.svelte @@ -0,0 +1,35 @@ +
+
+ + +
+ +
+
+ diff --git a/src/routes/auth/error/+page.svelte b/src/routes/auth/error/+page.svelte new file mode 100644 index 0000000..5e995de --- /dev/null +++ b/src/routes/auth/error/+page.svelte @@ -0,0 +1 @@ +

Login error

diff --git a/src/routes/private/+layout.server.ts b/src/routes/private/+layout.server.ts new file mode 100644 index 0000000..2b66aa3 --- /dev/null +++ b/src/routes/private/+layout.server.ts @@ -0,0 +1,5 @@ +/** + * This file is necessary to ensure protection of all routes in the `private` + * directory. It makes the routes in this directory _dynamic_ routes, which + * send a server request, and thus trigger `hooks.server.ts`. + **/ diff --git a/src/routes/private/+layout.svelte b/src/routes/private/+layout.svelte new file mode 100644 index 0000000..20f131d --- /dev/null +++ b/src/routes/private/+layout.svelte @@ -0,0 +1,21 @@ + + +
+ + +
+
+ +
diff --git a/src/routes/private/+page.server.ts b/src/routes/private/+page.server.ts new file mode 100644 index 0000000..00f29b4 --- /dev/null +++ b/src/routes/private/+page.server.ts @@ -0,0 +1,10 @@ +import type { PageServerLoad } from "./$types" + +export const load: PageServerLoad = async ({ depends, locals: { supabase } }) => { + depends("supabase:db:notes") + const { data: notes } = await supabase + .from("notes") + .select("id,note") + .order("id") + return { notes: notes ?? [] } +} diff --git a/src/routes/private/+page.svelte b/src/routes/private/+page.svelte new file mode 100644 index 0000000..120a1a0 --- /dev/null +++ b/src/routes/private/+page.svelte @@ -0,0 +1,40 @@ + + +

Private page for user: {user?.email}

+

Notes

+ +
+ +