@deeblr/auth-session
v0.4.0
Published
Session Manager and session-strategy infrastructure for Deeblr Auth: memory/database strategies, device tracking, expiration, and the SessionStrategy contract custom strategies (e.g. @deeblr/auth-jwt) implement.
Readme
@deeblr/auth-session
The Session Manager and session-strategy infrastructure for Deeblr Auth.
Strategy-agnostic: session: { strategy: "memory" } vs "database" vs
"jwt" (from @deeblr/auth-jwt) is a config change, never an
application-code change.
Install
npm install @deeblr/auth-sessionMost people won't install this directly — it's used automatically when you
configure sessions on @deeblr/auth's DeeblrAuth. Install it directly
if you're building on @deeblr/auth-core yourself, or writing a custom
SessionStrategy.
Strategies
| Strategy | Storage | Notes |
|---|---|---|
| MemorySessionStrategy | In-process Map | Single instance only; lost on restart. Good for dev/tests. |
| DatabaseSessionStrategy | Your DatabaseAdapter | Uses createSession/getSession/updateSession/deleteSession/deleteSessionsForUser — all already-optional methods on DatabaseAdapter (@deeblr/auth-types). .list() requires a listSessionsForUser function, since listing efficiently is adapter-specific. |
| Custom | Anything | Implement the 6-method SessionStrategy interface. |
@deeblr/auth-jwt ships a fourth strategy, JwtSessionStrategy, which
implements this same interface using signed JWTs instead of storage — see
that package.
Usage
import { SessionManager, MemorySessionStrategy } from "@deeblr/auth-session";
import { SystemClock, InMemoryHookBus, ConsoleLogger } from "@deeblr/auth-core";
const clock = new SystemClock();
const hooks = new InMemoryHookBus(new ConsoleLogger());
const strategy = new MemorySessionStrategy(clock);
const sessions = new SessionManager({
strategy,
hooks,
clock,
ttlSeconds: 60 * 60 * 24 * 30, // 30 days
expirationStrategy: "sliding", // or "absolute" (default)
deviceTracking: true,
});
const session = await sessions.create({ userId: "user_1", userAgent, ipAddress });
await sessions.validate(session.id); // throws SessionNotFoundError if gone
await sessions.refresh(session.id); // extends expiry under "sliding"
await sessions.list("user_1");
await sessions.destroy(session.id);
await sessions.destroyAll("user_1");Or via the config-driven factory (what @deeblr/auth uses internally):
import { createSessionManager } from "@deeblr/auth-session";
const sessions = createSessionManager(
{ strategy: "database", listSessionsForUser: (id) => myAdapter.listSessionsForUser(id) },
{ adapter, clock, hooks },
);Device tracking
SessionManager.create() captures device/browser/operatingSystem
(via a small dependency-free User-Agent parser — good enough for a device
list UI, not exhaustive; swap in parseUserAgent for anything more) plus
ipAddress, userAgent, and timestamps. country/city are supported
fields but NOT populated by default — no fake IP geolocation ships here.
Pass a geoLookup function backed by whatever geo-IP provider you use.
Expiration
absolute(default):expiresAtis fixed at creation;refresh()is a validating no-op.sliding:refresh()extendsexpiresAtbyslidingTtlSeconds.
Hooks and events
auth:beforeSessionCreate, auth:afterSessionCreate,
auth:beforeSessionDestroy, auth:afterSessionDestroy (cancellable/
notification, matching core's convention), plus session.created,
session.destroyed, session.expired, session.refreshed (dot-notation
domain events) — all declaration-merged onto the same AuthHookEventMap
every other package extends.
Writing a custom strategy
import type { SessionStrategy } from "@deeblr/auth-session";
class RedisSessionStrategy implements SessionStrategy {
readonly name = "redis";
async create(input) { /* ... */ }
async get(id) { /* ... */ }
async touch(id, newExpiresAt) { /* ... */ }
async destroy(id) { /* ... */ }
async destroyAllForUser(userId) { /* ... */ }
async list(userId) { /* ... */ }
}Pass an instance directly as strategy — SessionManager never checks
instanceof anything, only the interface.
License
MIT
