Skip to content

Service API ​

Inject the service with the SESSION_SERVICE token; pass your payload shape as the generic:

typescript
constructor(
  @Inject(SESSION_SERVICE) private readonly sessions: ISessionService<AppSession>,
) {}

Introspection ​

getSession(sessionId) ​

Returns ISessionInfo<T> | null — the parsed middleware payload plus plugin metadata. Reading a session enforces the absolute lifetime cap (a capped-out session is destroyed and reported as null).

typescript
const info = await sessions.getSession(req.sessionID);
// info.data      -> your payload (typed T)
// info.metadata  -> { userId?, ip?, userAgent?, createdAt, lastSeenAt, expiresAt } | null

getSessionsByUser(userId) ​

The device page: every live session of a user, with metadata.

typescript
import { Controller, Get, Inject, Req } from '@nestjs/common';
import { SESSION_SERVICE } from '@nestjs-redisx/session';
import type { ISessionService } from '@nestjs-redisx/session';

import { AppSession } from './types';

interface SessionRequest {
  sessionID: string;
  session: { passport?: { user?: string } };
}

@Controller('account')
export class DevicePageController {
  constructor(@Inject(SESSION_SERVICE) private readonly sessions: ISessionService<AppSession>) {}

  // GitHub-style "Sessions" page: every device with IP, browser, and activity.
  @Get('sessions')
  async devicePage(@Req() req: SessionRequest) {
    const userId = req.session.passport?.user;
    const devices = await this.sessions.getSessionsByUser(userId!);

    return devices.map((device) => ({
      id: device.id,
      current: device.id === req.sessionID,
      ip: device.metadata?.ip,
      userAgent: device.metadata?.userAgent,
      signedInAt: device.metadata?.createdAt,
      lastActiveAt: device.metadata?.lastSeenAt,
    }));
  }
}

count() / countByUser(userId) ​

Live totals from the global / per-user index. Expired entries are swept by score before counting, so numbers stay accurate as sessions expire naturally.

Revocation ​

revoke(sessionId) ​

Terminates one session; returns true when a session existed. The owner's next request is treated as unauthenticated.

revokeAll(userId) ​

Password change / compromise response — terminates every session of the user; returns the number revoked.

revokeAllExcept(userId, currentSessionId) ​

The real product button: "log out everywhere else". A naked revokeAll logs out the clicker too.

typescript
import { Injectable, Inject } from '@nestjs/common';
import { SESSION_SERVICE } from '@nestjs-redisx/session';
import type { ISessionService } from '@nestjs-redisx/session';

@Injectable()
export class SessionSecurityService {
  constructor(@Inject(SESSION_SERVICE) private readonly sessions: ISessionService) {}

  // The "log out everywhere else" button: keeps the clicking device signed in.
  logoutOtherDevices(userId: string, currentSessionId: string): Promise<number> {
    return this.sessions.revokeAllExcept(userId, currentSessionId);
  }

  // Password change / account compromise: terminate everything.
  async onPasswordChanged(userId: string): Promise<number> {
    return this.sessions.revokeAll(userId);
  }

  // Support/admin: terminate one specific session by ID.
  async revokeSingle(sessionId: string): Promise<boolean> {
    return this.sessions.revoke(sessionId);
  }

  // Live counters for dashboards.
  async stats(userId: string): Promise<{ total: number; forUser: number }> {
    return {
      total: await this.sessions.count(),
      forUser: await this.sessions.countByUser(userId),
    };
  }
}

Activity ​

recordActivity(sessionId, { ip?, userAgent? }) ​

Stamps request-scoped attributes onto the session metadata and refreshes lastSeenAt. No-op for missing sessions. See Store Adapters — Activity Stamping for the middleware one-liner.

Errors ​

All errors extend SessionError (which extends RedisXError):

ErrorCodeWhen
SessionStoreErrorSESSION_STORE_ERRORRedis/Lua failure in any store operation
InvalidSessionConfigErrorSESSION_CONFIG_INVALIDInvalid plugin options (thrown at bootstrap)
SessionLimitExceededErrorSESSION_LIMIT_EXCEEDEDSeat limit hit under the reject policy
SessionMiddlewareMissingErrorSESSION_MIDDLEWARE_MISSINGtoExpressStore() without express-session installed
SessionSerializationErrorSESSION_SERIALIZATION_FAILEDPayload not JSON-serializable

Released under the MIT License.