text: /**
   * Phoenix Channels JavaScript client
   *
   * ## Socket Connection
   *
   * A single connection is established to the server and
   * channels are multiplexed over the connection.
   * Connect to the server using the `Socket` class:
   *
   * ```javascript
   * let socket = new Socket("/socket", {params: {userToken: "123"}})
   * socket.connect()
   * ```
   *
   * The `Socket` constructor takes the mount point of the socket,
   * the authentication params, as well as options that can be found in
   * the Socket docs, such as configuring the `LongPoll` transport, and
   * heartbeat.
   *
   * ## Channels
   *
   * Channels are isolated, concurrent processes on the server that
   * subscribe to topics and broker events between the client and server.
   * To join a channel, you must provide the topic, and channel params for
   * authorization. Here's an example chat room example where `"new_msg"`
   * events are listened for, messages are pushed to the server, and
   * the channel is joined with ok/error/timeout matches:
   *
   * ```javascript
   * let channel = socket.channel("room:123", {token: roomToken})
   * channel.on("new_msg", msg => console.log("Got message", msg) )
   * $input.onEnter( e => {
   *   channel.push("new_msg", {body: e.target.val}, 10000)
   *     .receive("ok", (msg) => console.log("created message", msg) )
   *     .receive("error", (reasons) => console.log("create failed", reasons) )
   *     .receive("timeout", () => console.log("Networking issue...") )
   * })
   *
   * channel.join()
   *   .receive("ok", ({messages}) => console.log("catching up", messages) )
   *   .receive("error", ({reason}) => console.log("failed join", reason) )
   *   .receive("timeout", () => console.log("Networking issue. Still waiting..."))
   *```
   *
   * ## Joining
   *
   * Creating a channel with `socket.channel(topic, params)`, binds the params to
   * `channel.params`, which are sent up on `channel.join()`.
   * Subsequent rejoins will send up the modified params for
   * updating authorization params, or passing up last_message_id information.
   * Successful joins receive an "ok" status, while unsuccessful joins
   * receive "error".
   *
   * With the default serializers and WebSocket transport, JSON text frames are
   * used for pushing a JSON object literal. If an `ArrayBuffer` instance is provided,
   * binary encoding will be used and the message will be sent with the binary
   * opcode.
   *
   * *Note*: binary messages are only supported on the WebSocket transport.
   *
   * ## Duplicate Join Subscriptions
   *
   * While the client may join any number of topics on any number of channels,
   * the client may only hold a single subscription for each unique topic at any
   * given time. When attempting to create a duplicate subscription,
   * the server will close the existing channel, log a warning, and
   * spawn a new channel for the topic. The client will have their
   * `channel.onClose` callbacks fired for the existing channel, and the new
   * channel join will have its receive hooks processed as normal.
   *
   * ## Pushing Messages
   *
   * From the previous example, we can see that pushing messages to the server
   * can be done with `channel.push(eventName, payload)` and we can optionally
   * receive responses from the push. Additionally, we can use
   * `receive("timeout", callback)` to abort waiting for our other `receive` hooks
   *  and take action after some period of waiting. The default timeout is 10000ms.
   *
   *
   * ## Socket Hooks
   *
   * Lifecycle events of the multiplexed connection can be hooked into via
   * `socket.onError()` and `socket.onClose()` events, ie:
   *
   * ```javascript
   * socket.onError( () => console.log("there was an error with the connection!") )
   * socket.onClose( () => console.log("the connection dropped") )
   * ```
   *
   *
   * ## Channel Hooks
   *
   * For each joined channel, you can bind to `onError` and `onClose` events
   * to monitor the channel lifecycle, ie:
   *
   * ```javascript
   * channel.onError( () => console.log("there was an error!") )
   * channel.onClose( () => console.log("the channel has gone away gracefully") )
   * ```
   *
   * ### onError hooks
   *
   * `onError` hooks are invoked if the socket connection drops, or the channel
   * crashes on the server. In either case, a channel rejoin is attempted
   * automatically in an exponential backoff manner.
   *
   * ### onClose hooks
   *
   * `onClose` hooks are invoked only in two cases. 1) the channel explicitly
   * closed on the server, or 2). The client explicitly closed, by calling
   * `channel.leave()`
   *
   *
   * ## Presence
   *
   * The `Presence` object provides features for syncing presence information
   * from the server with the client and handling presences joining and leaving.
   *
   * ### Syncing state from the server
   *
   * To sync presence state from the server, first instantiate an object and
   * pass your channel in to track lifecycle events:
   *
   * ```javascript
   * let channel = socket.channel("some:topic")
   * let presence = new Presence(channel)
   * ```
   *
   * Next, use the `presence.onSync` callback to react to state changes
   * from the server. For example, to render the list of users every time
   * the list changes, you could write:
   *
   * ```javascript
   * presence.onSync(() => {
   *   myRenderUsersFunction(presence.list())
   * })
   * ```
   *
   * ### Listing Presences
   *
   * `presence.list` is used to return a list of presence information
   * based on the local state of metadata. By default, all presence
   * metadata is returned, but a `listBy` function can be supplied to
   * allow the client to select which metadata to use for a given presence.
   * For example, you may have a user online from different devices with
   * a metadata status of "online", but they have set themselves to "away"
   * on another device. In this case, the app may choose to use the "away"
   * status for what appears on the UI. The example below defines a `listBy`
   * function which prioritizes the first metadata which was registered for
   * each user. This could be the first tab they opened, or the first device
   * they came online from:
   *
   * ```javascript
   * let listBy = (id, {metas: [first, ...rest]}) => {
   *   first.count = rest.length + 1 // count of this user's presences
   *   first.id = id
   *   return first
   * }
   * let onlineUsers = presence.list(listBy)
   * ```
   *
   * ### Handling individual presence join and leave events
   *
   * The `presence.onJoin` and `presence.onLeave` callbacks can be used to
   * react to individual presences joining and leaving the app. For example:
   *
   * ```javascript
   * let presence = new Presence(channel)
   *
   * // detect if user has joined for the 1st time or from another tab/device
   * presence.onJoin((id, current, newPres) => {
   *   if(!current){
   *     console.log("user has entered for the first time", newPres)
   *   } else {
   *     console.log("user additional presence", newPres)
   *   }
   * })
   *
   * // detect if user has left from all tabs/devices, or is still present
   * presence.onLeave((id, current, leftPres) => {
   *   if(current.metas.length === 0){
   *     console.log("user has left from all devices", leftPres)
   *   } else {
   *     console.log("user left from a device", leftPres)
   *   }
   * })
   * // receive presence data from server
   * presence.onSync(() => {
   *   displayUsers(presence.list())
   * })
   * ```
   * @module phoenix
   */
  
  import Channel from "./channel"
  import LongPoll from "./longpoll"
  import Presence from "./presence"
  import Serializer from "./serializer"
  import Socket from "./socket"
  
  export {
    Channel,
    LongPoll,
    Presence,
    Serializer,
    Socket
  }
  