Session
@voltage/session wraps express-session for NestJS. It provides a Session service injectable anywhere in the call stack and automatically appends the session ID to every log entry.
Installation
Section titled “Installation”yarn add @voltage/session @voltage/async-context @voltage/event-manager @voltage/logger @voltage/zod zodBasic usage
Section titled “Basic usage”register()
Section titled “register()”Pass configuration directly:
import { SessionModule } from '@voltage/session';
@Module({ imports: [ SessionModule.register({ secret: process.env.SESSION_SECRET, }), ],})export class AppModule {}registerAsync()
Section titled “registerAsync()”Use a factory when configuration comes from another provider — the typical approach when using a Redis store:
import { SessionModule } from '@voltage/session';import { RedisStore } from 'connect-redis';
SessionModule.registerAsync({ inject: [AppConfiguration, getClientToken()], useFactory: (config: AppConfiguration, client: RedisClientType) => ({ secret: config.session.secret, saveUninitialized: true, store: new RedisStore({ client, ttl: 60 * 60 * 2, prefix: 'myapp:session', }), }),}),The module is global — you do not need to import it in feature modules.
Inject Session into any service or controller:
import { Session } from '@voltage/session';
@Injectable()export class CartService { constructor(private readonly session: Session) {}
addItem(item: CartItem) { this.session.update('cart', (current = []) => [...current, item]); }
getItems(): CartItem[] { return this.session.get('cart', []); }}Session API
Section titled “Session API”get(key, fallback?) reads a value. set(key, value) writes one. update(key, updater) is the right choice when modifying existing data — the updater receives the current value and returns the new one:
// Readconst items = this.session.get('cart', []);
// Writethis.session.set('returnUrl', '/checkout');
// Updatethis.session.update('cart', (current = []) => current.filter(i => i.id !== id));The remaining methods manage the session lifecycle:
await this.session.save(); // Force-persist to storeawait this.session.delete(); // Destroy the session (use on logout)await this.session.regenerate(); // Issue a new session ID, keep data (use after login)await this.session.reload(); // Re-read from storethis.session.resetMaxAge(); // Reset the cookie expirythis.session.touch(); // Mark the session as activeSession scopes
Section titled “Session scopes”WithSessionScope() creates a namespaced base class for services that own a specific slice of session state. All data is stored under a private key so different parts of the app cannot accidentally overwrite each other:
import { WithSessionScope } from '@voltage/session';
interface CheckoutState { step: 'shipping' | 'payment' | 'review'; addressId?: string;}
@Injectable()export class CheckoutSession extends WithSessionScope<CheckoutState>('checkout', { step: 'shipping',}) { get step() { return this.data.step; }
advance(step: CheckoutState['step']) { this.data = { ...this.data, step }; }
reset() { super.reset(); }}Inject CheckoutSession like any other provider. The data property is typed to the shape you declared and initialised to defaults when the scope has not been written yet.
Logger integration
Section titled “Logger integration”The module hooks into @voltage/logger automatically. Every log entry for a request with an active session will include a sessionId field in its metadata — no configuration required.
Configuration
Section titled “Configuration”interface SessionConfiguration { /** Secret used to sign the session cookie. Use a long random string. */ secret: string; /** Session store. Defaults to in-memory — use a persistent store in production. */ store?: SessionStore; /** Force HTTPS-only cookies. Defaults to true when NODE_ENV is production. */ secure?: boolean; /** Save sessions that have not been modified. Defaults to false. */ saveUninitialized?: boolean; /** Re-save sessions to the store even if they were not modified. Defaults to false. */ resave?: boolean; /** Additional cookie options passed directly to express-session. */ cookie?: CookieOptions;}Cookies are signed and httpOnly by default. In production (NODE_ENV=production), secure is set automatically.