mirror of
https://github.com/LukeHagar/website.git
synced 2025-12-10 12:57:49 +00:00
fix: svelte
This commit is contained in:
@@ -30,8 +30,8 @@ create-svelte version 3.2.0
|
||||
◇ Add type checking with TypeScript?
|
||||
│ Yes, using JavaScript with JSDoc comments
|
||||
│
|
||||
◇ Select additional options (use arrow keys/space bar)
|
||||
│ Add ESLint for code linting
|
||||
◇ Select additional options
|
||||
│ None
|
||||
│
|
||||
└ Your project is ready!
|
||||
```
|
||||
|
||||
@@ -27,38 +27,38 @@ import { PUBLIC_APPWRITE_ENDPOINT, PUBLIC_APPWRITE_PROJECT } from '$env/static/p
|
||||
export const SESSION_COOKIE = 'my-custom-session';
|
||||
|
||||
export function createAdminClient() {
|
||||
const client = new Client()
|
||||
.setEndpoint(PUBLIC_APPWRITE_ENDPOINT)
|
||||
.setProject(PUBLIC_APPWRITE_PROJECT)
|
||||
.setKey(APPWRITE_KEY); // Set the Appwrite API key!
|
||||
const client = new Client()
|
||||
.setEndpoint(PUBLIC_APPWRITE_ENDPOINT)
|
||||
.setProject(PUBLIC_APPWRITE_PROJECT)
|
||||
.setKey(APPWRITE_KEY); // Set the Appwrite API key!
|
||||
|
||||
// Return the services we want to use.
|
||||
return {
|
||||
get account() {
|
||||
return new Account(client);
|
||||
}
|
||||
};
|
||||
// Return the services we want to use.
|
||||
return {
|
||||
get account() {
|
||||
return new Account(client);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function createSessionClient(event) {
|
||||
const client = new Client()
|
||||
.setEndpoint(PUBLIC_APPWRITE_ENDPOINT)
|
||||
.setProject(PUBLIC_APPWRITE_PROJECT);
|
||||
const client = new Client()
|
||||
.setEndpoint(PUBLIC_APPWRITE_ENDPOINT)
|
||||
.setProject(PUBLIC_APPWRITE_PROJECT);
|
||||
|
||||
// Extract our custom domain's session cookie from the request
|
||||
const session = event.cookies.get(SESSION_COOKIE);
|
||||
if (!session) {
|
||||
throw new Error('Session cookie not found');
|
||||
}
|
||||
|
||||
client.setSession(session);
|
||||
// Extract our custom domain's session cookie from the request
|
||||
const session = event.cookies.get(SESSION_COOKIE);
|
||||
if (!session) {
|
||||
throw new Error('Session cookie not found');
|
||||
}
|
||||
|
||||
client.setSession(session);
|
||||
|
||||
// Return the services we want to use.
|
||||
return {
|
||||
get account() {
|
||||
return new Account(client);
|
||||
}
|
||||
};
|
||||
// Return the services we want to use.
|
||||
return {
|
||||
get account() {
|
||||
return new Account(client);
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -7,43 +7,42 @@ step: 4
|
||||
|
||||
SvelteKit hooks which are functions that run on the server before a page is displayed to the user. SvelteKit locals are a way to store data that is specific to the current request. We can use this to store the user's account data, so that it is available to all pages.
|
||||
|
||||
Create a new file in the `src/hooks` directory called `server.js`:
|
||||
Create a new file in the `src` directory called `hooks.server.js`:
|
||||
|
||||
```js
|
||||
// src/hooks.server.js
|
||||
import { createSessionClient } from '$lib/server/appwrite';
|
||||
|
||||
export async function handle({ event, resolve }) {
|
||||
try {
|
||||
// Use our helper function to create the Appwrite client.
|
||||
const { account } = createSessionClient(event);
|
||||
|
||||
// Store the current logged in user in locals,
|
||||
// for easy access in our other routes.
|
||||
event.locals.user = await account.get();
|
||||
} catch {}
|
||||
|
||||
// Continue with the request.
|
||||
return resolve(event);
|
||||
try {
|
||||
// Use our helper function to create the Appwrite client.
|
||||
const { account } = createSessionClient(event);
|
||||
// Store the current logged in user in locals,
|
||||
// for easy access in our other routes.
|
||||
event.locals.user = await account.get();
|
||||
} catch {}
|
||||
|
||||
// Continue with the request.
|
||||
return resolve(event);
|
||||
}
|
||||
```
|
||||
|
||||
To ensure the `locals` object is typed correctly, we can add a type definition for it in the `env.d.ts` file:
|
||||
|
||||
```ts
|
||||
import type { Models } from 'node-appwrite';
|
||||
import type { AppwriteService } from '$lib/server/appwrite';
|
||||
import type { Models } from "node-appwrite";
|
||||
|
||||
// See https://kit.svelte.dev/docs/types#app
|
||||
// for information about these interfaces
|
||||
declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
interface Locals {
|
||||
user: Models.User<Preferences> | undefined;
|
||||
}
|
||||
// interface PageData {}
|
||||
// interface Platform {}
|
||||
}
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
interface Locals {
|
||||
user: Models.User<Models.Preferences> | undefined;
|
||||
}
|
||||
// interface PageData {}
|
||||
// interface Platform {}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
@@ -55,15 +54,15 @@ Now, use the `locals` object in the home page to redirect based on the user's lo
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
|
||||
export async function load({ locals }) {
|
||||
// Access our user from locals.
|
||||
if (!locals.user) {
|
||||
// If no user is logged in, redirect to the sign up page.
|
||||
throw redirect(301, '/signup');
|
||||
}
|
||||
|
||||
// If the user is logged in, redirect to the account page.
|
||||
throw redirect(301, '/account');
|
||||
// Access our user from locals.
|
||||
if (!locals.user) {
|
||||
// If no user is logged in, redirect to the sign up page.
|
||||
throw redirect(301, '/signup');
|
||||
}
|
||||
|
||||
// If the user is logged in, redirect to the account page.
|
||||
throw redirect(301, '/account');
|
||||
}
|
||||
```
|
||||
|
||||
When a user visits the home page, they will be redirected to the sign up page if they are not logged in, or to the account page if they are logged in.
|
||||
When a user visits the home page, they will be redirected to the sign up page if they are not logged in, or to the account page if they are logged in.
|
||||
|
||||
@@ -9,42 +9,49 @@ We can now implement our sign up page. Create a `+page.svelte` file in the `src/
|
||||
|
||||
```svelte
|
||||
<!-- src/routes/signup/+page.svelte -->
|
||||
<form method="post">
|
||||
<input id="email" placeholder="Email" type="email" />
|
||||
<input id="password" placeholder="Password" type="password" />
|
||||
<button type="submit">Sign up</button>
|
||||
<form action="?/signup" method="post">
|
||||
<input id="email" name="email" placeholder="Email" type="email" />
|
||||
<input id="password" name="password" placeholder="Password" type="password" />
|
||||
<input id="name" name="name" placeholder="Name" type="text" />
|
||||
<button type="submit">Sign up</button>
|
||||
</form>
|
||||
|
||||
```
|
||||
|
||||
This is an HTML form with an email and password input. When the form is submitted, we want to send the email and password to Appwrite to authenticate the user. To use SvelteKit form actions we create a `+page.server.js` file in the same directory:
|
||||
|
||||
```javascript
|
||||
import { SESSION_COOKIE, createAdminClient } from '$lib/server/appwrite.js';
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
// src/routes/signup/+page.server.js
|
||||
|
||||
import { SESSION_COOKIE, createAdminClient } from "$lib/server/appwrite.js";
|
||||
import { redirect } from "@sveltejs/kit";
|
||||
import { ID } from "node-appwrite";
|
||||
|
||||
export const actions = {
|
||||
default: async (event) => {
|
||||
// Extract the form data.
|
||||
const form = await event.request.formData();
|
||||
const email = form.get('email') as string;
|
||||
const password = form.get('password') as string;
|
||||
signup: async ({ request, cookies }) => {
|
||||
// Extract the form data.
|
||||
const form = await request.formData();
|
||||
const email = form.get("email");
|
||||
const password = form.get("password");
|
||||
const name = form.get("name");
|
||||
|
||||
// Create the Appwrite client.
|
||||
const { account } = createAdminClient();
|
||||
// Create the Appwrite client.
|
||||
const { account } = createAdminClient();
|
||||
|
||||
// Create the session using the client
|
||||
const session = await account.createEmailPasswordSession(email, password);
|
||||
// Create the session using the client
|
||||
await account.create(ID.unique(), email, password, name);
|
||||
const session = await account.createEmailPasswordSession(email, password);
|
||||
|
||||
// Set the session cookie with the secret
|
||||
event.cookies.set(SESSION_COOKIE, session.secret, {
|
||||
sameSite: 'strict',
|
||||
expires: new Date(session.expire),
|
||||
secure: true,
|
||||
path: '/'
|
||||
});
|
||||
// Set the session cookie with the secret
|
||||
cookies.set(SESSION_COOKIE, session.secret, {
|
||||
sameSite: "strict",
|
||||
expires: new Date(session.expire),
|
||||
secure: true,
|
||||
path: "/",
|
||||
});
|
||||
|
||||
// Redirect to the account page.
|
||||
throw redirect(301, '/account');
|
||||
}
|
||||
// Redirect to the account page.
|
||||
throw redirect(301, "/account");
|
||||
},
|
||||
};
|
||||
```
|
||||
@@ -9,32 +9,33 @@ Now the end-user is able to sign up, we can create the account page. This page w
|
||||
|
||||
```js
|
||||
// src/routes/account/+page.server.js
|
||||
import { SESSION_COOKIE, createSessionClient } from '$lib/server/appwrite.js';
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
|
||||
import { SESSION_COOKIE, createSessionClient } from "$lib/server/appwrite.js";
|
||||
import { redirect } from "@sveltejs/kit";
|
||||
|
||||
export async function load({ locals }) {
|
||||
// Logged out users can't access this page.
|
||||
if (!locals.user) throw redirect(301, '/signup');
|
||||
// Logged out users can't access this page.
|
||||
if (!locals.user) throw redirect(301, "/signup");
|
||||
|
||||
// Pass the stored user local to the page.
|
||||
return {
|
||||
user: locals.user
|
||||
};
|
||||
// Pass the stored user local to the page.
|
||||
return {
|
||||
user: locals.user,
|
||||
};
|
||||
}
|
||||
|
||||
// Define our log out endpoint/server action.
|
||||
export const actions = {
|
||||
default: async (event) => {
|
||||
// Create the Appwrite client.
|
||||
const { account } = createSessionClient(event);
|
||||
default: async (event) => {
|
||||
// Create the Appwrite client.
|
||||
const { account } = createSessionClient(event);
|
||||
|
||||
// Delete the session on Appwrite, and delete the session cookie.
|
||||
await account.deleteSession('current');
|
||||
event.cookies.delete(SESSION_COOKIE);
|
||||
// Delete the session on Appwrite, and delete the session cookie.
|
||||
await account.deleteSession("current");
|
||||
event.cookies.delete(SESSION_COOKIE, { path: "/" });
|
||||
|
||||
// Redirect to the sign up page.
|
||||
throw redirect(301, '/signup');
|
||||
}
|
||||
// Redirect to the sign up page.
|
||||
throw redirect(301, "/signup");
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
@@ -42,24 +43,24 @@ Create a new file in the `src/routes/account` directory called `+page.svelte` an
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
export let data;
|
||||
export let data;
|
||||
|
||||
const { user } = data
|
||||
const { user } = data
|
||||
</script>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Email:</strong> {user.email}
|
||||
</li>
|
||||
<li>
|
||||
<strong>Name:</strong> {user.name}
|
||||
</li>
|
||||
<li>
|
||||
<strong>ID: </strong> {user.$id}
|
||||
</li>
|
||||
<li>
|
||||
<strong>Email:</strong> {user.email}
|
||||
</li>
|
||||
<li>
|
||||
<strong>Name:</strong> {user.name}
|
||||
</li>
|
||||
<li>
|
||||
<strong>ID: </strong> {user.$id}
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<form action="/account" method="post">
|
||||
<button type="submit">Log out</button>
|
||||
<form method="post">
|
||||
<button type="submit">Log out</button>
|
||||
</form>
|
||||
```
|
||||
```
|
||||
|
||||
@@ -14,7 +14,7 @@ To redirect, add a button to our sign up page that redirects the user to the OAu
|
||||
|
||||
<!-- ... existing sign up form -->
|
||||
|
||||
<form action="/oauth" method="post">
|
||||
<form action="?/oauth" method="post">
|
||||
<button type="submit">Sign up with GitHub</button>
|
||||
</form>
|
||||
```
|
||||
@@ -24,28 +24,25 @@ Add a new server route to handle the redirect.
|
||||
```js
|
||||
// src/routes/signup/+page.server.js
|
||||
|
||||
// ... existing imports
|
||||
|
||||
|
||||
import { SESSION_COOKIE, createAdminClient } from '$lib/server/appwrite';
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import { OAuthProvider } from 'node-appwrite';
|
||||
import { SESSION_COOKIE, createAdminClient } from "$lib/server/appwrite.js";
|
||||
import { redirect } from "@sveltejs/kit";
|
||||
import { ID, OAuthProvider } from "node-appwrite";
|
||||
|
||||
export const actions = {
|
||||
// ... existing actions
|
||||
// ... existing email sign up action
|
||||
oauth: async (event) => {
|
||||
const { account } = createAdminClient();
|
||||
|
||||
oauth2: async (event) => {
|
||||
const { account } = createAdminClient();
|
||||
const redirectUrl = await account.createOAuth2Token(
|
||||
OAuthProvider.Github,
|
||||
`${event.url.origin}/oauth`,
|
||||
`${event.url.origin}/signup`
|
||||
);
|
||||
|
||||
const redirectURL = account.createOAuth2Token(
|
||||
OAuthProvider.Github,
|
||||
`${event.url.origin}/oauth`,
|
||||
`${event.url.origin}/signup`
|
||||
);
|
||||
|
||||
throw redirect(url);
|
||||
}
|
||||
throw redirect(301, redirectUrl);
|
||||
},
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
The `createOAuth2Token` method redirects the user to the OAuth provider, and then the OAuth provider redirects the user back to the `/oauth` route with the `userId` and `secret` URL query parameters.
|
||||
@@ -55,28 +52,34 @@ Handle the callback and create a session for the user. Create a new server route
|
||||
```js
|
||||
// src/routes/oauth/+server.js
|
||||
|
||||
import { SESSION_COOKIE, createAdminClient } from '$lib/server/appwrite';
|
||||
import { SESSION_COOKIE, createAdminClient } from "$lib/server/appwrite";
|
||||
|
||||
export async function GET(event) {
|
||||
// We should have a `userId` and `secret` query parameters in the URL
|
||||
const userId = event.url.searchParams.get('userId') as string;
|
||||
const secret = event.url.searchParams.get('secret') as string;
|
||||
// We should have a `userId` and `secret` query parameters in the URL
|
||||
const userId = event.url.searchParams.get("userId");
|
||||
const secret = event.url.searchParams.get("secret");
|
||||
|
||||
// Exchange the token `userId` and `secret` for a session
|
||||
const { account } = createAdminClient();
|
||||
const session = await account.createSession(userId, secret);
|
||||
if (!userId || !secret) {
|
||||
return new Response("Missing `userId` or `secret` query parameters", {
|
||||
status: 400,
|
||||
});
|
||||
}
|
||||
|
||||
// Redirect to the account page, and set the session cookie
|
||||
const headers = new Headers({
|
||||
location: '/account',
|
||||
'set-cookie': event.cookies.serialize(SESSION_COOKIE, session.secret, {
|
||||
sameSite: 'strict',
|
||||
expires: new Date(session.expire),
|
||||
secure: true,
|
||||
path: '/'
|
||||
})
|
||||
});
|
||||
// Exchange the token `userId` and `secret` for a session
|
||||
const { account } = createAdminClient();
|
||||
const session = await account.createSession(userId, secret);
|
||||
|
||||
return new Response(null, { status: 302, headers });
|
||||
// Redirect to the account page, and set the session cookie
|
||||
const headers = new Headers({
|
||||
location: "/account",
|
||||
"set-cookie": event.cookies.serialize(SESSION_COOKIE, session.secret, {
|
||||
sameSite: "strict",
|
||||
expires: new Date(session.expire),
|
||||
secure: true,
|
||||
path: "/",
|
||||
}),
|
||||
});
|
||||
|
||||
return new Response(null, { status: 302, headers });
|
||||
}
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user