svelte-kit-cookie-session icon indicating copy to clipboard operation
svelte-kit-cookie-session copied to clipboard

Synchronize sessions (Server -> Client)

Open pixelmund opened this issue 1 year ago • 6 comments

This PR implements syncing sessions between the server and client.

You'll have to set the session store yourself, but this can be easily done.

This works best with the enhance action from kit!

/// lib/form.ts
import { session } from "$app/stores";

export function enhance(){
	...
	async function handle_submit(e) {
		...
		if (response.ok) {
			if (response.headers.has('x-svelte-kit-cookie-session-needs-sync')) {
				const sessionData = await fetch('/__session.json').then((r) => (r.ok ? r.json() : null));
				if (sessionData) {
					session.set(sessionData);
				}
			}
			...
		}
		...
	}
}

pixelmund avatar Jul 15 '22 12:07 pixelmund

The cast to any is a little unfortunate but it's something I'd be willing to add by hand if there was no other option - maybe some documentation for the signature is enough for now?

edit: Spoke too soon :( my session store does not seem to be getting the new value when i call sync. I trimmed down my example so now I have a function that logs my users in that looks roughly like the following. After navigating to /routeA, my session does not contain the new data.

export async function authorizeUser(variables: {}) {
	// trigger the mutation to authorize the user
	var sessionData = await logIn({ variables })

	// update the session with the result
	await fetch('/auth/token', {
		method: 'POST',
		headers: {
			'Content-Type': 'application/json'
		},
		body: JSON.stringify(sessionData)
	})

	await (session as any).sync()

	goto('/routeA')
}

Here's the endpoint:

export async function POST({ request, locals }) {
	// save the tokens in the local session
	locals.session.set(await request.json())

	return {}
}

AlecAivazis avatar Jul 22 '22 20:07 AlecAivazis

The cast to any is a little unfortunate but it's something I'd be willing to add by hand if there was no other option - maybe some documentation for the signature is enough for now?

edit: Spoke too soon :( my session store does not seem to be getting the new value when i call sync. I trimmed down my example so now I have a function that logs my users in that looks roughly like the following. After navigating to /routeA, my session does not contain the new data.

export async function authorizeUser(variables: {}) {
	// trigger the mutation to authorize the user
	var sessionData = await logIn({ variables })

	// update the session with the result
	await fetch('/auth/token', {
		method: 'POST',
		headers: {
			'Content-Type': 'application/json'
		},
		body: JSON.stringify(sessionData)
	})

	await (session as any).sync()

	goto('/routeA')
}

Here's the endpoint:

export async function POST({ request, locals }) {
	// save the tokens in the local session
	locals.session.set(await request.json())

	return {}
}

Oh no! Can you see a request to /__session.json when calling sync or have some kind of error in the console?

pixelmund avatar Jul 23 '22 04:07 pixelmund

Ahh i think you have to await locals.session.set() in your endpoint! Since switching to webcrypto those methods are async.

pixelmund avatar Jul 23 '22 04:07 pixelmund

Oh yep! That was it 👍

AlecAivazis avatar Jul 24 '22 00:07 AlecAivazis

I am now running into a new error when calling session.sync(): Cannot set session store before subscribing. I haven't been able to dig into it much yet but i figured I would share while I do that in case you have any ideas

AlecAivazis avatar Jul 24 '22 01:07 AlecAivazis

You'll have to use the session store somewhere in your application via $session. This error would also appear if you'd use the unmodified version and session.set or session.update. The set and update methods are getting available after the first subscription. Don't know the exact reason behind it.

pixelmund avatar Jul 24 '22 07:07 pixelmund