code: function Cabal (storage, key, opts) {
    if (!(this instanceof Cabal)) return new Cabal(storage, key, opts)
    if (!opts) opts = {}
    events.EventEmitter.call(this)
  
    var json = {
      encode: function (obj) {
        return Buffer.from(JSON.stringify(obj))
      },
      decode: function (buf) {
        var str = buf.toString('utf8')
        try { var obj = JSON.parse(str) } catch (err) { return {} }
        return obj
      }
    }
  
    this.maxFeeds = opts.maxFeeds
    this.key = key || null
    this.db = kappa(storage, {
      valueEncoding: json
    })
  
    // Create (if needed) and open local write feed
    var self = this
    this.feed = thunky(function (cb) {
      self.db.ready(function () {
        self.db.feed('local', function (err, feed) {
          if (!self.key) self.key = feed.key.toString('hex')
          cb(feed)
        })
      })
    })
  
    // views
  
    this.db.use('channels', createChannelView(memdb({ valueEncoding: json })))
    this.db.use('messages', createMessagesView(memdb({ valueEncoding: json })))
    this.db.use('topics', createTopicsView(memdb({ valueEncoding: json })))
    this.db.use('users', createUsersView(memdb({ valueEncoding: json })))
  
    this.messages = this.db.api.messages
    this.channels = this.db.api.channels
    this.topics = this.db.api.topics
    this.users = this.db.api.users
  }
docs: Create a new cabal. This is the object handling all
  local nickname -> mesh interactions for a single user.
  @constructor
  @param {string|function} storage - A hyperdb compatible storage function, or a string representing the local data path.
  @param {string} key - The dat link
  @param {Object} opts -