code: async function session(ctx, next) {
      ctx.sessionStore = store
      if (ctx.session || ctx._session) {
        return next()
      }
      const result = await getSession(ctx)
      if (!result) {
        return next()
      }
  
      addCommonAPI(ctx)
  
      ctx._session = result.session
  
      // more flexible
      Object.defineProperty(ctx, 'session', {
        get() {
          return this._session
        },
        set(sess) {
          this._session = sess
        }
      })
  
      ctx.regenerateSession = async function regenerateSession() {
        debug('regenerating session')
        if (!result.isNew) {
          // destroy the old session
          debug('destroying previous session')
          await store.destroy(ctx.sessionId)
        }
  
        ctx.session = generateSession()
        ctx.sessionId = genSid.call(ctx, 24)
        sessionIdStore.reset.call(ctx)
  
        debug('created new session: %s', ctx.sessionId)
        result.isNew = true
      }
  
      // make sure `refreshSession` always called
      let firstError = null
      try {
        await next()
      } catch (err) {
        debug('next logic error: %s', err.message)
        firstError = err
      }
      // can't use finally because `refreshSession` is async
      try {
        await refreshSession(ctx, ctx.session, result.originalHash, result.isNew)
      } catch (err) {
        debug('refresh session error: %s', err.message)
        if (firstError) ctx.app.emit('error', err, ctx)
        firstError = firstError || err
      }
      if (firstError) throw firstError
    }
docs: common session middleware
  each request will generate a new session
  
  ```
  let session = this.session
  ```