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 🙏

© 2024 – Pkg Stats / Ryan Hefner

koa-imsession

v1.0.3

Published

Pretty simple and performance koa session middleware using immutability

Downloads

21

Readme

koa-imsession

npm build status npm download

Pretty simple and performance session middleware for koa using immutability.

Installation

$ npm install koa-imsession

API

Set session (e.g. login)

ctx.session = { id: 1, state: 'pending' }

Update session

Session data is immutable. Set the session to a new object.

const oldSession = ctx.session
ctx.session = { ...oldSession, state: 'activated' }

Destroy session (e.g. logout)

ctx.session = false // the `Set-Cookie` header will be sent to remove the cookie

Manually regenerate session ID (e.g. renew session)

ctx.session = true // a new session ID is generated and the existing session data is preserved

For session auto-renewal see Redis session store and session auto-renewal.

Examples

View counter

import { imsession } from 'koa-imsession'
import Koa from 'koa'

const app = new Koa()

/**
 * All options are optional, except the `store` MUST be set to a custom store
 * (eg. Redis) on production.
 */
const options = {
  name: 'connsid',     // the name of the session ID cookie, default value is `connsid`
  // idResolver,       // session ID resolver which gets/sets/generates the session ID
  // store,            // session store, default value is a `MemoryStore` instance for development
  cookie: {            // cookie options, see https://github.com/pillarjs/cookies
    maxAge: 86400_000, // default value is 1 day
  },
}

app.use(imsession(options))

app.use(ctx => {
  const views = ctx.session?.views ?? 0
  ctx.session = { views: views + 1 } // immutable object
  ctx.body = 'views: ' + ctx.session.views
})

app.listen(3000)

Redis session store and session auto-renewal

The builtin MemoryStore is used by default for development and testing purpose only. A custom session store must be set on production environment.

import type { SessionStore, SessionData } from 'koa-imsession'
import { TTL_MS } from 'koa-imsession'
import redis from './redis.js' // github.com/redis/ioredis

/**
 * A Redis session store.
 */
export class RedisSessionStore<T extends SessionData> implements SessionStore<T> {
  /**
   * Returns session data and TTL_MS.
   */
  async get(sessionId: string): Promise<T | undefined> {
    const tx = redis.multi()
    tx.get(sessionId) // value
    tx.ttl(sessionId) // ttl in seconds
    const results = await tx.exec()
    if (!results) return

    const [[, value], [, ttl]] = results
    if (!value) return

    const sessionData = JSON.parse(value as string)
    if (ttl as number > 0) {
      // AUTO RENEWAL happens here!!!

      // Set the `TTL_MS` symbol property, koa-imsession will check whether it
      // is less than cookie's `maxAge/3`, if true the session will be renewed
      // automatically.
      sessionData[TTL_MS] = (ttl as number) * 1000
    }

    return sessionData
  }

  async set(sessionId: string, sessionData: T, ttlMs: number): Promise<void> {
    const data = JSON.stringify(sessionData)
    await redis.set(sessionId, data, 'PX', ttlMs)
  }

  async destroy(sessionId: string): Promise<void> {
    await redis.del(sessionId)
  }
}

Custom SessionIdResolver

You may want to get the Bearer access token from the Authorization header.

import type Cookies from 'cookies'
import type Koa from 'koa'
import { SessionIdResolver as CookieSessionIdResolver } from 'koa-imsession'

export class SessionIdResolver extends CookieSessionIdResolver {
  constructor({ name, cookie }: { name: string; cookie?: Cookies.SetOption }) {
    super({ name, cookie })
  }

  // Overrides `get` method to get the access token from header first.
  get(ctx: Koa.Context): string | undefined {
    return getAccessTokenFromHeader(ctx) ?? super.get(ctx)
  }
}

/**
 * Gets access token from header.
 */
function getAccessTokenFromHeader(ctx: Koa.Context): string | undefined {
  const authorization = ctx.get('Authorization')
  if (!authorization) return

  // Syntax: Bearer 1*SP b64token
  const [scheme, accessToken] = authorization.split(' ', 2)
  if (scheme.toLowerCase() === 'bearer')
    return accessToken
}