@~lyre/guest
v0.1.0
Published
Anonymous-visitor tracking for SvelteKit + Drizzle + Postgres. UUID cookie, pluggable GeoIP, merge-on-signup. Lets you attribute pre-signup activity (assessments, chats) to the authenticated user once they create an account.
Maintainers
Readme
@lyre/guest
Anonymous-visitor tracking for SvelteKit + Drizzle + Postgres. Mints a guest_uuid cookie on first visit, writes a guests row with the request context (IP, user-agent, referrer, language), and exposes a mergeGuestIntoUser helper you call from your auth signIn / signUp hooks so the pre-auth history (assessment answers, advisor chats, etc.) is attributed to the user once they create an account.
Install
pnpm add @lyre/guest drizzle-ormQuick start
// 1. include the schema in your Drizzle client
import { guests } from '@lyre/guest/schema';
// re-export from your schema barrel
// 2. wire the hook into your SvelteKit chain
// src/hooks.server.ts
import { sequence } from '@sveltejs/kit/hooks';
import { createGuestHook } from '@lyre/guest';
import { db } from '$lib/server/db';
const handleGuest = createGuestHook({
db,
// Optional: pluggable GeoIP resolver. Leave undefined and geo fields stay null.
geoIpResolver: async (ip) => {
// call your maxmind / ipapi / ipinfo client; return null on failure
return null;
}
});
export const handle = sequence(handleParaglide, handleGuest, handleAuth);In your sign-in / sign-up actions, attach the guest history to the new user:
import { mergeGuestIntoUser, readGuestUuid } from '@lyre/guest';
const guestUuid = readGuestUuid({ cookies: event.cookies, headers: event.request.headers });
if (guestUuid && session?.user?.id) {
await mergeGuestIntoUser(db, { guestUuid, userId: session.user.id });
}What's in event.locals.guest
After the hook runs, every request has the resolved Guest row available:
event.locals.guest = {
id, uuid, userId, // identity
ip, userAgent, referrer, currentUrl, previousUrl, // request context
country, countryCode, region, city, postalCode, // optional geo (if resolver set)
latitude, longitude, timezone, currencyCode,
language,
createdAt, updatedAt
};Design
- No dummy user rows. Unlike some patterns,
@lyre/guestdoes NOT create a placeholder User record for every visitor. Identity belongs to your auth system; this package only stores anonymous history. - Pluggable GeoIP. The package ships no provider — you choose maxmind, ipapi, ipinfo, etc. Failure is non-blocking; geo fields stay null.
- Throttled writes. Repeat-visit updates (
current_url,previous_url) are throttled to one write per minute per visitor by default; tunable viathrottleMs.
License
MIT
