Skip to content

Commit

Permalink
Added SessionProvider on sveltekit
Browse files Browse the repository at this point in the history
  • Loading branch information
Neo-Ciber94 committed Sep 26, 2023
1 parent 9dff45b commit e7f14f4
Show file tree
Hide file tree
Showing 11 changed files with 209 additions and 101 deletions.
2 changes: 1 addition & 1 deletion examples/sveltekit-mal-auth/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "vite dev",
"dev": "vite dev --port 5175",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
Expand Down
10 changes: 8 additions & 2 deletions examples/sveltekit-mal-auth/src/app.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@
// for information about these interfaces
declare global {
namespace App {
interface Locals {
session?: {
user: User,
accessToken: string;
} | null;
}

// interface Error {}
// interface Locals {}
// interface PageData {}
// interface Platform {}
}
}

export {};
export { };
22 changes: 16 additions & 6 deletions examples/sveltekit-mal-auth/src/hooks.server.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
import type { Handle } from "@sveltejs/kit";
import { createMyAnimeListHandler } from "@animelist/auth-sveltekit/server";
import { getServerSession } from "@animelist/auth/common";
import { MALClient } from "@animelist/client";

const handler = createMyAnimeListHandler({
callbacks: {
onSession(session) {
console.log(session.user);
const handler = createMyAnimeListHandler();

export const handle: Handle = async ({ event, resolve }) => {
const session = await getServerSession(event.cookies);

if (session) {
const { accessToken } = session;
const client = new MALClient({ accessToken });

try {
const user = await client.getMyUserInfo({});
event.locals.session = { user, accessToken };
} catch (err) {
console.error(err);
}
}
});

export const handle: Handle = ({ event, resolve }) => {
if (event.url.pathname.startsWith("/api/myanimelist")) {
return handler({ event, resolve });
}
Expand Down
6 changes: 6 additions & 0 deletions examples/sveltekit-mal-auth/src/routes/+layout.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { LayoutServerLoad } from "./$types";


export const load: LayoutServerLoad = async ({ locals }) => {
return { session: locals.session }
};
9 changes: 9 additions & 0 deletions examples/sveltekit-mal-auth/src/routes/+layout.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<script lang="ts">
import { SessionProvider } from '@animelist/auth-sveltekit/client';
// import type { LayoutServerData } from './$types';
</script>


<SessionProvider>
<slot />
</SessionProvider>
5 changes: 0 additions & 5 deletions examples/sveltekit-mal-auth/src/routes/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
<script>
import { signIn, signOut } from '@animelist/auth/client';
import { session } from '@animelist/auth-sveltekit/client';
import { onMount } from 'svelte';
onMount(async () => {
await session.initialize();
});
</script>

{#if $session.loading}
Expand Down
11 changes: 10 additions & 1 deletion packages/animelist-auth-sveltekit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"entrypoints": "tsx entrypoints.script.mts",
"build:types": "tsc --emitDeclarationOnly",
"build:lib": "tsx esbuild.mts",
"build": "rimraf dist && pnpm build:types && pnpm build:lib && pnpm entrypoints"
"build:svelte": "svelte-package -i src/client -o dist/client",
"build": "rimraf dist && pnpm build:types && pnpm build:lib && pnpm run build:svelte && rimraf .svelte-kit && pnpm entrypoints"
},
"keywords": [],
"author": "",
Expand All @@ -22,9 +23,14 @@
"@sveltejs/kit": "^1.25.0"
},
"devDependencies": {
"@sveltejs/package": "^2.2.2",
"eslint": "^8.49.0",
"svelte": "^4.0.5",
"typescript": "^5.2.2"
},
"peerDependencies": {
"svelte": "^4.0.5"
},
"publishConfig": {
"access": "public"
},
Expand All @@ -34,6 +40,9 @@
"import": "./dist/client/index.mjs",
"default": "./dist/client/index.mjs"
},
"./client/SessionProvider.svelte": {
"svelte": "./dist/client/SessionProvider.svelte"
},
"./server": {
"import": "./dist/server/index.mjs",
"default": "./dist/server/index.mjs"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<script lang="ts">
import { Session } from "@animelist/auth/client";
import { session as sessionStore, INITIALIZE_SESSION } from "./session";
export let session: Session | null | undefined = undefined;
// Initialize the session store
sessionStore[INITIALIZE_SESSION](session).catch(console.error);
</script>

<slot {session} />
3 changes: 2 additions & 1 deletion packages/animelist-auth-sveltekit/src/client/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from "./session";
export * from "./session";
export { default as SessionProvider } from "./SessionProvider.svelte";
172 changes: 87 additions & 85 deletions packages/animelist-auth-sveltekit/src/client/session.ts
Original file line number Diff line number Diff line change
@@ -1,107 +1,109 @@
// import { dev } from "$app/environment";
import { type User } from "@animelist/core";
import { getSession } from "@animelist/auth/client";
import { get, writable } from "svelte/store";
import { type Session, getSession } from "@animelist/auth/client";
import { get, writable, derived } from "svelte/store";

let initialized = false;
/**
* @internal
*/
export const INITIALIZE_SESSION = Symbol("INITIALIZE_SESSION");

const DAY_MILLIS = 1000 * 60 * 60 * 24;

export type SessionState = {
user: User | null;
accessToken: string | null;
session: Session | null,
loading: boolean;
}

const sessionStore = writable<SessionState>({
user: null,
accessToken: null,
loading: false
});

type InitializeSession = Omit<SessionState, 'loading'>;

function setUserSession(session: InitializeSession | null) {
if (session) {
initialized = true;
sessionStore.set({
loading: false,
accessToken: session.accessToken,
user: session.user
})
} else {
initialized = false;
sessionStore.set({
loading: false,
accessToken: null,
user: null
});
}
}
function createSession() {
const baseSessionStore = writable<SessionState>({
session: null,
loading: false
});

async function fetchUserSession() {
if (typeof window === 'undefined') {
return;
}
async function fetchUserSession() {
if (typeof window === 'undefined') {
return null;
}

initialized = true;
try {
// fetch the current user session
const session = await getSession();

try {
// Set state to loading
const currentSession = get(sessionStore);
sessionStore.set({
loading: true,
accessToken: currentSession.accessToken,
user: currentSession.user
});
if (session == null) {
baseSessionStore.set({ loading: false, session });
return null;
}

// fetch the current user session
const session = await getSession();
baseSessionStore.set({ session, loading: false });

if (session == null) {
return sessionStore.set({ loading: false, accessToken: null, user: null });
}
// We use 1 day as a threshold because we don't expect an user to stay 24 hours
// without any interaction. in most cases this is not reached because the default session is 7 days
const expiresAt = new Date(session.expiresAt);

// if (dev) {
// console.log("🍥 User session loaded: ", JSON.stringify(session, null, 2));
// }
if (expiresAt.getTime() < DAY_MILLIS) {
window.setTimeout(
fetchUserSession,
expiresAt.getTime()
);
}

// Currently the expiration of the access token is 31 days, which is really long,
// so we don't have reason to refresh it, each time the user log in a new token will be created.
const { accessToken, user } = session;
sessionStore.set({ user, accessToken, loading: false })
}
catch (err) {
console.error(err);
initialized = false;
sessionStore.set({ user: null, accessToken: null, loading: false })
}
}
return session;
}
catch (err) {
console.error(err);
baseSessionStore.set({ session: null, loading: false });
}

async function initialize(session?: InitializeSession | null) {
if (session && initialized) {
return;
return null;
}

if (session !== undefined) {
setUserSession(session);
}
else {
await fetchUserSession();
async function initialize(session?: Session | null) {
if (session === undefined) {
// Set state to loading
baseSessionStore.update(s => ({ ...s, loading: true }));

// Fetch the current session
await fetchUserSession();
} else {
baseSessionStore.set({
session,
loading: false
})
}
}
}

function destroy() {
sessionStore.set({
accessToken: null,
loading: false,
user: null,
const sessionStore = derived(baseSessionStore, ($store) => {
return {
/**
* Returns the current user.
*/
get user() {
return $store?.session?.user || null;
},

/**
* Returns the current user access token.
*/
get accessToken() {
return $store?.session?.accessToken || null
},

...$store
}
})
}

export const session = {
initialize,
destroy,
subscribe: sessionStore.subscribe,
get current() {
return get(sessionStore);
return {
subscribe: sessionStore.subscribe,

/**
* Returns `true` if the user is authenticated.
*/
get isAuthenticated() {
return get(baseSessionStore).session != null
},

// @internal
[INITIALIZE_SESSION]: initialize
}
}

export const session = createSession();
Loading

0 comments on commit e7f14f4

Please sign in to comment.