<|start_filename|>package.json<|end_filename|>
{
  "name": "y-websockets-client",
  "version": "9.0.0-4",
  "description": "Websockets connector for Yjs (browser/node client)",
  "main": "./y-websockets-client.node.js",
  "browser": "./y-websockets-client.js",
  "module": "./src/y-websockets-client.js",
  "scripts": {
    "test": "npm run lint",
    "dist": "rollup -c rollup.browser.js && rollup -c rollup.node.js",
    "lint": "standard",
    "watch": "concurrently 'rollup -wc rollup.browser.js' 'rollup -wc rollup.node.js'",
    "postversion": "npm run dist",
    "postpublish": "tag-dist-files --overwrite-existing-tag"
  },
  "files": [
    "y-websockets-client.*",
    "src/*"
  ],
  "standard": {
    "ignore": [
      "y-websockets-client.js",
      "y-websockets-client.node.js"
    ]
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/y-js/y-websockets-client.git"
  },
  "keywords": [
    "Yjs",
    "OT",
    "Collaboration",
    "Synchronization",
    "ShareJS",
    "Coweb",
    "Concurrency"
  ],
  "author": "<NAME> <<EMAIL>>",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/y-js/y-websockets-client/issues"
  },
  "homepage": "http://y-js.org",
  "dependencies": {
    "socket.io-client": "^2.0.3"
  },
  "devDependencies": {
    "babel-plugin-external-helpers": "^6.22.0",
    "babel-preset-latest": "^6.24.1",
    "concurrently": "^3.4.0",
    "rollup-plugin-babel": "^2.7.1",
    "rollup-plugin-commonjs": "^8.0.2",
    "rollup-plugin-multi-entry": "^2.0.1",
    "rollup-plugin-node-resolve": "^3.0.0",
    "rollup-plugin-uglify": "^1.0.2",
    "rollup-watch": "^3.2.2",
    "standard": "^10.0.2",
    "tag-dist-files": "^0.1.6"
  },
  "peerDependencies": {
    "yjs": "^13.0.0-8"
  }
}


<|start_filename|>src/y-websockets-client.js<|end_filename|>
import io from 'socket.io-client'

export default function extend (Y) {
  class Connector extends Y.AbstractConnector {
    constructor (y, options) {
      if (options === undefined) {
        throw new Error('Options must not be undefined!')
      }
      options.role = 'slave'
      options.preferUntransformed = true
      options.generateUserId = options.generateUserId || false
      if (options.initSync !== false) { options.initSync = true }
      super(y, options)
      this._sentSync = false
      this.options = options
      options.url = options.url || 'https://yjs.dbis.rwth-aachen.de:5072'
      var socket = options.socket || io(options.url, options.options)
      this.socket = socket
      var self = this

      this._onConnect = function () {
        if (options.initSync) {
          if (options.room == null) {
            throw new Error('You must define a room name!')
          }
          self._sentSync = true
          // only sync with server when connect = true
          socket.emit('joinRoom', options.room)
          self.userJoined('server', 'master')
          self.connections.get('server').syncStep2.promise.then(() => {
            // set user id when synced with server
            self.setUserId(Y.utils.generateUserId())
          })
        }
        socket.on('yjsEvent', self._onYjsEvent)
        socket.on('disconnect', self._onDisconnect)
      }

      socket.on('connect', this._onConnect)
      if (socket.connected) {
        this._onConnect()
      } else {
        socket.connect()
      }

      this._onYjsEvent = function (buffer) {
        let decoder = new Y.utils.BinaryDecoder(buffer)
        let roomname = decoder.readVarString()
        if (roomname === options.room) {
          self.receiveMessage('server', buffer)
        }
      }

      this._onDisconnect = function (peer) {
        Y.AbstractConnector.prototype.disconnect.call(self)
      }
    }

    /*
     * Call this if you set options.initSync = false. Yjs will sync with the server after calling this method.
     */
    initSync (opts) {
      if (!this.options.initSync) {
        this.options.initSync = true
        if (opts.room != null) {
          this.options.room = opts.room
        }
      }
      if (this.socket.connected) {
        this._onConnect()
      }
    }

    disconnect () {
      this.socket.emit('leaveRoom', this.options.room)
      if (!this.options.socket) {
        this.socket.disconnect()
      }
      super.disconnect()
    }
    destroy () {
      this.disconnect()
      this.socket.off('disconnect', this._onDisconnect)
      this.socket.off('yjsEvent', this._onYjsEvent)
      this.socket.off('connect', this._onConnect)
      if (!this.options.socket) {
        this.socket.destroy()
      }
      this.socket = null
    }
    reconnect () {
      this.socket.connect()
      super.reconnect()
    }
    send (uid, message) {
      if (this._sentSync) {
        super.send(uid, message)
        this.socket.emit('yjsEvent', message)
      }
    }
    broadcast (message) {
      if (this._sentSync) {
        super.broadcast(message)
        this.socket.emit('yjsEvent', message)
      }
    }
    whenRemoteResponsive () {
      return new Promise(resolve => {
        this.socket.emit('yjsResponsive', this.options.room, resolve)
      })
    }
    isDisconnected () {
      return this.socket.disconnected
    }
  }
  Connector.io = io
  Y['websockets-client'] = Connector
  // Y.extend('websockets-client', Connector)
}

if (typeof Y !== 'undefined') {
  extend(Y) // eslint-disable-line
}
