constructor ({ type, name = '', debug }) {
    this.portName = type
    this.#type = type

    if (type === 'content') {
      /**
       * There can be multiple instances of the same content script
       * but for different tabs, so we need to differentiate them.
       *
       * Generating an easy to handle id for the content script.
       */
      this.portName = `${ type }@${ name }-${ getRandomId(10_000) }`
    }

    this.#banner = `[QBex|${ this.portName }]`
    this.#debug = debug === true

    if (type !== 'background') {
      this.on('@quasar:ports', ({ payload }) => {
        this.portList = payload.portList
        if (payload.removed !== void 0) {
          this.#cleanupPort(payload.removed)
        }
      })

      return
    }

    /**
     * Else we're the background script
     */

    this.isConnected = true
    const onPacket = this.#onPacket.bind(this)

    runtime.onConnect.addListener(port => {
      // if it's not a bridge port on the other end,
      // then ignore it
      if (portNameRE.test(port.name) === false) return

      if (this.portMap[ port.name ] !== void 0) {
        this.warn(
          `Connection with "${ port.name }" already exists.`
          + ' Disconnecting the previous one and connecting the new one.'
        )
        this.portMap[ port.name ].disconnect()
        this.#cleanupPort(port.name)
      }

      this.portMap[ port.name ] = port

      port.onMessage.addListener(onPacket)
      port.onDisconnect.addListener(() => {
        port.onMessage.removeListener(onPacket)
        this.#cleanupPort(port.name)
        this.log(`Closed connection with ${ port.name }.`)
        this.#onPortChange({ removed: port.name })
      })

      this.log(`Opened connection with ${ port.name }.`)
      this.#onPortChange({ added: port.name })
    })
  }
@param {{ type: 'background' | 'content' | 'app', name?: string, debug?: boolean }} options