This library provides an easy way to start, serve and modify server sessions.
Install with:
npm i -D sveltekit-server-session
src/app.d.ts
file and define your session key under interface Locals
.// See https://kit.svelte.dev/docs/types#app
import type { Session } from 'sveltekit-server-session';
// for information about these interfaces
declare global {
namespace App {
// interface Error {}
interface Locals {
// Add type hints to "locals".
session: Session;
}
// interface PageData {}
// interface PageState {}
// interface Platform {}
}
}
export {};
This will give you proper type hints when you access your locals
property.src/hooks.server.js
and start the session in your handle
function.// src/hooks.server.js
import { session } from 'sveltekit-server-session';
/**
* @type {import("@sveltejs/kit").Handle}
*/
export async function handle({ event, resolve }) {
// Start the session.
const [ sessionLocal, error ] = await session.start({
cookies: event.cookies,
})
// Check for errors.
if (error) {
return new Response(error.message, { status: 500 })
}
// Save session to `locals`.
event.locals.session = sessionLocal
// Resolve the sveltekit response.
const response = await resolve(event)
// Adding required headers to the response.
for (const [key, value] of sessionLocal.response().headers) {
response.headers.set(key, value)
}
return response
}
This will make sure every api request has access to the session.// src/routes/session/quote/update/+server.js
export async function PUT({ locals, request }) {
// Get the session data and response function.
const { data, response } = locals.session
// Update the "quote".
data.set('quote', await request.text())
// Respond with the new "quote".
return response(data.get('quote'))
}
// src/routes/+page.server.svelte
/**
* @type {import("./$types").PageServerLoad}
*/
export function load({ locals }) {
// Get the session data.
const { data } = locals.session
if (!data.has('quote')) {
// Set a default "quote".
data.set('quote', 'initial quote')
}
return {
// Load the "quote" into the page.
quote: data.get('quote'),
}
}
<!-- src/routes/+page.svelte -->
<script>
// Load session data.
/** @type {import('./$types').PageData} */
export let data
let sending = false
async function set() {
sending = true
// Update the session.
await fetch('/session/quote/update', { method: 'PUT', body: data.quote })
sending = false
}
</script>
<textarea bind:value={data.quote}></textarea>
<br />
<button disabled={sending} on:mouseup={set}>
<span>Save</span>
</button>
Every single session related operation like validation, creation, update, deletion and so on, is described by SessionInterface
.
You can use session.setOperations()
to overwrite these operations by providing your own SessionInterface
implementation
session.setOperations({
async exists(id) {
return ok(map.has(id))
},
async isValid(id) {
const session = map.get(id)
if (!session) {
return ok(false)
}
return ok(session.getRemainingSeconds() > 0)
},
async has(id) {
return ok(map.has(id))
},
async get(id) {
return ok(map.get(id))
},
async set(id, session) {
map.set(id, session)
return ok()
},
async delete(id) {
map.delete(id)
return ok()
},
})
This is a simple in memory session implementation, but the sky is the limit, you could even fetch and persist sessions to a remote database.
SvelteKit comes with preload features baked in, however this feature may cause some inconsistent behavior when dealing with sessions.
Consider the following use case,
Which is obviously wrong.
To fix this you need to disable preloading.
Navigate to your src/app.html
file and disable preloading by settings data-sveltekit-preload-data
to false
on your body
element.
<!DOCTYPE html/>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="false"> <!-- Here. -->
<div>%sveltekit.body%</div>
</body>
</html>
You could technically disable preloading for specific cases and avoid the issue in that way, but at some point your whole application will be filled with links that point to some page that depends on the server session.
It's just simply not worth the headache.
[!NOTE] Obviously you can still enable preload for resources like assets by manually adding the
data-sveltekit-preload-data="hover"
attribute to specific elements in your page.
You can find a complete example leveraging the recommended usage here.
[!NOTE] Remember to run your SvelteKit server dev at least once to properly generate your glue types.
[!NOTE] Sessions are only directly available under
*.server.js
and*.server.ts
files.
Sessions are meant to be private data, so they will never be directly available under universal files like+page.js
, for example.