npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

fa-session-redis

v0.0.3

Published

Redis session store for farrow-auth-session with support for both redis and ioredis clients

Readme

fa-session-redis

Redis session store for farrow-auth-session with support for both redis and ioredis clients.

中文文档

Features

  • 🔄 Universal Redis Support - Works with both redis and ioredis clients through function overloads and normalized adapter
  • 🎯 Type-Safe - Full TypeScript support with function overloads for compile-time type checking
  • Performance - Efficient session management with configurable TTL strategies
  • 🔒 Secure - Server-side session storage with ULID-based session IDs
  • 🎨 Flexible - Multiple session expiration strategies (rolling, renewing, fixed)

Installation

npm install fa-session-redis farrow-auth-session

# Install one of the Redis clients
npm install redis
# or
npm install ioredis

Quick Start

import { Http, Response } from 'farrow-http';
import { ObjectType, String } from 'farrow-schema';
import { createSession, createSessionCtx, cookieSessionParser } from 'farrow-auth-session';
import { createRedisSessionStore } from 'fa-session-redis';
import Redis from 'ioredis';

// Create Redis client
const redis = new Redis();

// Define user data type
type UserData = {
  userId?: string;
  username?: string;
  role?: string;
};

// Create session context
const sessionUserDataCtx = createSessionCtx<UserData>({});

// Create Redis session store
const redisStore = createRedisSessionStore<UserData>(redis, {
  prefix: 'session',
  ttl: 86400, // 24 hours in seconds
  rolling: true, // Reset expiration on each access
});

// Setup session middleware
const sessionMiddleware = createSession({
  sessionUserDataCtx,
  sessionParser: cookieSessionParser(),
  sessionStore: redisStore,
  autoSave: true,
  autoCreateOnMissing: true,
});

// Define request schema
class LoginRequest extends ObjectType {
  username = String;
  password = String;
}

// Create HTTP app
const app = Http();
app.use(sessionMiddleware);

// Login endpoint
app.post('/login', { body: LoginRequest }).use(async (request) => {
  const { username, password } = request.body;
  
  // Your authentication logic here
  sessionUserDataCtx.set({
    userId: 'user-123',
    username: username,
  });
  
  return Response.json({ success: true });
});

// Protected endpoint
app.get('/profile').use(() => {
  const userData = sessionUserDataCtx.get();
  
  if (!userData?.userId) {
    return Response.status(401).json({ error: 'Not authenticated' });
  }
  
  return Response.json(userData);
});

// Logout endpoint
app.post('/logout').use(async () => {
  await sessionUserDataCtx.destroy();
  return Response.json({ success: true });
});

app.listen(3000);

Redis Client Examples

The function overloads provide compile-time type safety for different Redis clients:

With ioredis

import Redis from 'ioredis';
import { createRedisSessionStore } from 'fa-session-redis';

const redis = new Redis({
  host: 'localhost',
  port: 6379,
  db: 0,
});

// TypeScript automatically infers the correct overload
const store = createRedisSessionStore(redis, {
  prefix: 'app-session',
  ttl: 3600,
});

With node-redis

import { createClient } from 'redis';
import { createRedisSessionStore } from 'fa-session-redis';

const redis = createClient({
  url: 'redis://localhost:6379'
});

await redis.connect();

// TypeScript automatically infers the correct overload
const store = createRedisSessionStore(redis, {
  prefix: 'app-session',
  ttl: 3600,
});

Type Safety

// ✅ This works - valid Redis client
const validStore = createRedisSessionStore(redisClient, options);

// ❌ This fails at compile time - not a Redis client
const invalidStore = createRedisSessionStore({}, options);
// Error: Argument of type '{}' is not assignable to parameter of type 'IoRedisLike | NodeRedisLike | RedisLikeClient'

Configuration Options

createRedisSessionStore(client, options)

Creates a Redis-backed session store for farrow-auth-session. This function uses TypeScript function overloads to provide compile-time type safety for different Redis client types.

Function Overloads

// For ioredis clients
function createRedisSessionStore<UserData>(
  client: IoRedisLike,
  options?: RedisSessionStoreOptions<UserData>
): SessionStore<UserData, string>;

// For node-redis clients  
function createRedisSessionStore<UserData>(
  client: NodeRedisLike,
  options?: RedisSessionStoreOptions<UserData>
): SessionStore<UserData, string>;

// For generic Redis clients
function createRedisSessionStore<UserData>(
  client: RedisLikeClient,
  options?: RedisSessionStoreOptions<UserData>
): SessionStore<UserData, string>;

Parameters

  • client - Redis client instance (from redis, ioredis, or compatible package)
  • options - Configuration options (optional)

Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | prefix | string | 'session' | Redis key prefix for sessions | | ttl | number \| false | 86400 | Session TTL in seconds. Set to false to disable expiration | | rolling | boolean | false | Reset expiration on each access | | renew | boolean | false | Renew session when close to expiry | | renewBefore | number | 600 | Seconds before expiry to trigger renewal (when renew is true) | | genSessionId | () => string | () => ulid() | Custom session ID generator | | defaultData | () => UserData | () => ({}) | Initial session data creator |

Session Expiration Strategies

Rolling Sessions

const redisStore = createRedisSessionStore(redis, {
  ttl: 1800, // 30 minutes
  rolling: true,
});

Renewing Sessions

const redisStore = createRedisSessionStore(redis, {
  ttl: 3600, // 1 hour
  renew: true,
  renewBefore: 600, // Renew 10 minutes before expiry
});

Fixed Sessions

const redisStore = createRedisSessionStore(redis, {
  ttl: 28800, // 8 hours
  rolling: false,
  renew: false,
});

No Expiration

const redisStore = createRedisSessionStore(redis, {
  ttl: false, // No expiration in Redis
});

API Reference

createRedisSessionStore<UserData>(client, options)

Creates a Redis-backed session store implementing the SessionStore interface from farrow-auth-session.

Returns: SessionStore<UserData, string>

createNormalizedRedisClient(client)

Creates a normalized Redis client that provides a consistent API regardless of the underlying Redis client library.

Returns: NormalizedRedisClient

Type Definitions

// Configuration options for Redis session store
interface RedisSessionStoreOptions<UserData> {
  prefix?: string;
  ttl?: number | false;
  rolling?: boolean;
  renew?: boolean;
  renewBefore?: number;
  genSessionId?: () => string;
  defaultData?: () => UserData;
}

// Interface for ioredis-like clients
interface IoRedisLike {
  get(key: string): Promise<string | null>;
  set(key: string, value: string): Promise<string>;
  setex(key: string, seconds: number, value: string): Promise<string>;
  del(...keys: string[]): Promise<number>;
  expire(key: string, seconds: number): Promise<number>;
  ttl(key: string): Promise<number>;
  mget(...keys: string[]): Promise<(string | null)[]>;
  scan(cursor: number | string, ...args: any[]): Promise<[string, string[]]>;
}

// Interface for node-redis-like clients
interface NodeRedisLike {
  get(key: string): Promise<string | null>;
  set(key: string, value: string): Promise<string>;
  setEx(key: string, seconds: number, value: string): Promise<string>;
  del(keyOrKeys: string | string[]): Promise<number>;
  expire(key: string, seconds: number): Promise<boolean>;
  ttl(key: string): Promise<number>;
  mGet(keys: string[]): Promise<(string | null)[]>;
  scanIterator(options: { MATCH?: string; COUNT?: number }): AsyncIterable<string>;
}

// Generic Redis client interface (fallback)
interface RedisLikeClient {
  get(key: string): Promise<string | null>;
  set(key: string, value: string): Promise<string | 'OK' | null>;
  del(key: string | string[]): Promise<number>;
  expire(key: string, seconds: number): Promise<number | boolean>;
  mGet?(keys: string[]): Promise<(string | null)[]>;
  mget?(keys: string[]): Promise<(string | null)[]>;
  scan?(cursor: number | string, ...args: any[]): Promise<[string, string[]]>;
  scanIterator?(options: { MATCH?: string; COUNT?: number }): AsyncIterable<string>;
}

// Internal normalized client interface
interface NormalizedRedisClient {
  get(key: string): Promise<string | null>;
  set(key: string, value: string): Promise<boolean>;
  setex(key: string, seconds: number, value: string): Promise<boolean>;
  del(keyOrKeys: string | string[]): Promise<number>;
  expire(key: string, seconds: number): Promise<boolean>;
  ttl(key: string): Promise<number>;
  mget(keys: string[]): Promise<(string | null)[]>;
  scanIterator(match: string, count: number): AsyncIterable<string>;
}

License

MIT