Socket
Socket
Sign inDemoInstall

phoenix

Package Overview
Dependencies
Maintainers
2
Versions
81
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

phoenix - npm Package Compare versions

Comparing version 1.5.12 to 1.6.0-rc.0

assets/js/phoenix/ajax.js

160

CHANGELOG.md

@@ -1,149 +0,43 @@

# Changelog for v1.5
# Changelog for v1.6
See the [upgrade guides](https://gist.github.com/chrismccord/e53e79ef8b34adf5d8122a47db44d22f) to bring your Phoenix 1.4.x apps up to speed
Phoenix v1.6 requires Elixir v1.9+.
## Phoenix.PubSub 2.0 released
## 1.6.0-rc.0 (2021-08-26)
Phoenix.PubSub 2.0 has been released with a more flexible and powerful fastlane mechanism. We use this opportunity to also move Phoenix.PubSub out of the endpoint and explicitly into your supervision tree. To update, you will need to remove or update the `{:phoenix_pubsub, "~> 1.x"}` entry in your `mix.exs` to at least `2.0`.
### Enhancements
Then once you start an application, you will get a warning about the `:pubsub` key in your endpoint being deprecated. Follow the steps in the warning and you are good to go!
* [Controller] Do not create compile-time dependency for `action_fallback`
* [Endpoint] Allow custom error response from socket handler
* [Endpoint] Do not require a pubsub server in the socket (only inside channels)
* [mix phx.gen.auth] Add `mix phx.gen.auth` generator
* [mix phx.gen.context] Support `enum` types and the `redact` option when declaring fields
* [mix phx.new] Update `mix phx.new` to require Elixir v1.11 and use the new `config/runtime.exs`
* [mix phx.new] Add description to Ecto telemetry metrics
* [mix phx.new] Use `Ecto.Adapters.SQL.Sandbox.start_owner!/2` in generators - this approach provides proper shutdown semantics for apps using LiveView and Presence
* [mix phx.new] Add `--install` and `--no-install` options to `phx.new`
* [mix phx.new] Add `--database sqlite3` option to `phx.new`
* [View] Extracted `Phoenix.View` into its own project to facilitate reuse
* [mix phx.new] Remove usage of Sass
## Guides revamped
Phoenix built-in guides have been restructured and revamped, providing a better navigation structure and more content.
### 1.5.12 (2021-08-24)
### Bug Fixes
* [Router] Ensure we properly track all Plug compile-time dependencies. This may increase compilation times during test, to address it, you may set `config :phoenix, :plug_init_mode, :runtime` in your `config/test.exs`
### 1.5.11 (2021-08-20)
### Bug Fixes
* Relax `phoenix_ecto` version for installer to fix version conflicts
### 1.5.10 (2021-08-06)
### Bug Fixes
* [Channel] Push proper close event to client on duplicate topic shutdown
* [View] Do not render root layout outside of layout formats
### JavaScript Client Enhancements
* Schedule heartbeat on reply to avoid intensive throttling
* Add new `replaceTransport` function to socket with extended `onError` API to allow simplified LongPoll fallback
* Fire each event in a separate task for the LongPoll transport to fix ordering
* Optimize presence syncing
### 1.5.9 (2021-05-10)
### JavaScript client
* Bind to `beforeunload` instead of `unload` to solve Firefox connection issues
### 1.5.8 (2021-02-23)
### Enhancements
* [Endpoint] - Add `:log_access_url` config to endpoint start
* [Router] - Include route information in router_dispatch exception for telemetry events
* [Router] - Optimize router code generation to reduce compilation dependencies
* [phx.new] - Use topbar in new apps with the --live flag
### JavaScript client
* Default channel `push` payload to empty object for backwards compatibility
### 1.5.7 (2020-11-20)
### Enhancements
* [Channel] - Add binary serialization support to default serializers
### JavaScript client
* Add binary serialization support to default serializers for ability to push `ArrayBuffer` objects as binary WebSocket frames
### 1.5.6 (2020-10-12)
### Enhancements
* [phx.new] Add --install and --no-install options to phx.new
### Bug fixes
* [phx.new] Update `phoenix_live_dashboard` requirement to fix version conflicts
### 1.5.5 (2020-09-21)
* [Controller] Return normalized paths in `current_path/1` and `current_path/2`
* [mix phx.gen.live] Fix a bug where tests with `utc_datetime` and `boolean` fields did not pass out of the box
### Enhancements
* [Phoenix.Logger] Add :conn to `[:phoenix, :router_dispatch, :exception]` events
* [Phoenix.Endpoint] Use regex to detect invalid hosts for IPv6 configurations
* [Phoenix.Controller] Don't create compile-time references when using `action_fallback` to speed up compilation
* [Phoenix.Endpoint] Expose `:connect_info` `:trace_context_headers` in websockets and long polling
### JavaScript Client Bug fixes
* Bind to `beforeunload` instead of `unload` to solve Firefox connection issues
* Fix presence onJoin including current metadata in new presence
### 1.5.4 (2020-07-21)
### Enhancements
* [Phoenix.Endpoint] Include `:conn` in `[:phoenix, :error_rendered]` event
* [Phoenix.Endpoint] Warn if the `url.host` provided for the endpoint is invalid
* [Phoenix.Router] Log when router plugs halt
* Fix warnings on Elixir v1.11
### Bug fixes
* [Phoenix.Router] Rename the `[:phoenix, :router_dispatch, :exception]` metadata from `:error` to `:reason` to match the documentation and the telemetry specification (`:error` is still emitted for compatibility but it will be fully removed on v1.6)
## 1.5.3 (2020-05-21)
### Bug fixes
* [phx.new] - Fix incompatible LiveView version for newly generated projects
## 1.5.2 (2020-05-21)
### Enhancements
* [Channel] Import `assigns: 2` on channels
* [Endpoint] Track latest static in `config(:cache_static_manifest_latest)`
* [Endpoint] Allow `:user_agent` on `connect_info`
### Bug fixes
* [Endpoint] Undeprecate `subscribe` and `unsubscribe` in the endpoint
## 1.5.1 (2020-04-23)
### Bug Fixes
* [Endpoint] Ignore the root layout on error pages unless explicitly set
## 1.5.0 (2020-04-22)
### Enhancements
* [Channel] Do not block the channel supervisor on join
* [ConnTest] Add `init_test_session` to Phoenix.ConnTest
* [Controller] Support `:disposition` option in `send_download/3`
* [Endpoint] Automatically perform connection draining when shutting down the VM
* [Endpoint] Allow named params to be used when defining socket paths
* [Endpoint] Raise if `force_ssl` has changed from compile time to runtime
* [Generator] Add `mix phx.gen.live` for LiveView CRUD generation
* [PubSub] Migrate to PubSub 2.0 with a more flexible fastlaning mechanism
* [View] Add `render_layout` which makes it easy to work with nested layouts
* [View] Raise if `assigns` argument to functions `render/3`, `render_existing/3`, `render_many/4`, `render_one/4`, `render_layout/4`, `render_to_iodata/3`, `render_to_string/4` is a struct
* [Transport] Transports can now optionally implement `handle_control/2` for handling control frames such as `:ping` and `:pong`
### Deprecations
* [ChannelTest] `use Phoenix.ChannelTest` is deprecated in favor of `import Phoenix.ChannelTest`
* [ConnTest] `use Phoenix.ConnTest` is deprecated in favor of `import Plug.Conn; import Phoenix.ConnTest`
* [Endpoint] The outdated `Phoenix.Endpoint.CowboyAdapter` for Cowboy 1 is deprecated. Please make sure `{:plug_cowboy, "~> 2.1"}` or later is listed in your `mix.exs`.
* [Endpoint] `Phoenix.Endpoint.instrument/4` is deprecated and has no effect. Use `:telemetry` instead. See `Phoenix.Logger` for more information.
* [Endpoint] The `:pubsub` key for endpoint is deprecated. Once you start your app, you will see step-by-step instructions on how to use the new PubSub config.
* [Layout] Use `<%= @inner_content %>` instead of `<%= render @view_module, @view_template, assigns %>` for rendering the child layout
* [Endpoint] Phoenix now requires Cowboy v2.7+
* [View] `@view_module` is deprecated in favor of `Phoenix.Controller.view_module/1` and `@view_template` is deprecated in favor of `Phoenix.Controller.view_template/1`
### phx.new installer
## v1.5
* Built-in support for MSSQL databases via [`Ecto.Adapters.Tds`](https://hexdocs.pm/ecto_sql/Ecto.Adapters.Tds.html)
* `Phoenix.PubSub` is now started directly in your application supervision tree
* `Phoenix.Ecto.CheckRepoStatus` is now added to new applications that use Ecto
* Automatically use `System.get_env("MIX_TEST_PARTITION")` in the database name in the test environment for built-in CI test partitioning
* Generate a `MyApp.Telemetry` module with examples of Telemetry Metrics you may want to track in your app
* Support the `--live` flag for generating apps with out-of-the-box LiveView support
* Include SCSS support by default when using webpack
### JavaScript client
* Ensure all channel event listeners are called
* Fix rejoining channels after explicit disconnect following be immediate reconnect
* Prevent duplicate join race conditions by immediately leaving duplicate channel on client
## v1.4
The CHANGELOG for v1.4 releases can be found [in the v1.4 branch](https://github.com/phoenixframework/phoenix/blob/v1.4/CHANGELOG.md).
The CHANGELOG for v1.5 releases can be found in the [v1.5 branch](https://github.com/phoenixframework/phoenix/blob/v1.5/CHANGELOG.md).
{
"name": "phoenix",
"version": "1.5.12",
"version": "1.6.0-rc.0",
"description": "The official JavaScript client for the Phoenix web framework.",
"license": "MIT",
"main": "./priv/static/phoenix.js",
"module": "./priv/static/phoenix.esm.js",
"unpkg": "./priv/static/phoenix.min.js",
"jsdelivr": "./priv/static/phoenix.min.js",
"exports": {
"import": "./priv/static/phoenix.esm.js"
},
"repository": {

@@ -16,5 +21,5 @@ "type": "git",

"package.json",
"priv/static/phoenix.js",
"assets/js/phoenix.js"
"priv/static/*",
"assets/js/phoenix/*"
]
}
}

@@ -1,1 +0,1098 @@

!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Phoenix=t():e.Phoenix=t()}(this,(function(){return function(e){var t={};function n(i){if(t[i])return t[i].exports;var o=t[i]={i:i,l:!1,exports:{}};return e[i].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(i,o,function(t){return e[t]}.bind(null,o));return i},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){(function(t){e.exports=t.Phoenix=n(2)}).call(this,n(1))},function(e,t){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t,n){"use strict";function i(e){return function(e){if(Array.isArray(e))return a(e)}(e)||function(e){if("undefined"!=typeof Symbol&&Symbol.iterator in Object(e))return Array.from(e)}(e)||s(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function o(e){return(o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function r(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){if("undefined"==typeof Symbol||!(Symbol.iterator in Object(e)))return;var n=[],i=!0,o=!1,r=void 0;try{for(var s,a=e[Symbol.iterator]();!(i=(s=a.next()).done)&&(n.push(s.value),!t||n.length!==t);i=!0);}catch(e){o=!0,r=e}finally{try{i||null==a.return||a.return()}finally{if(o)throw r}}return n}(e,t)||s(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function s(e,t){if(e){if("string"==typeof e)return a(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(n):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?a(e,t):void 0}}function a(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,i=new Array(t);n<t;n++)i[n]=e[n];return i}function c(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function u(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}function h(e,t,n){return t&&u(e.prototype,t),n&&u(e,n),e}n.r(t),n.d(t,"Channel",(function(){return _})),n.d(t,"Serializer",(function(){return H})),n.d(t,"Socket",(function(){return U})),n.d(t,"LongPoll",(function(){return D})),n.d(t,"Ajax",(function(){return M})),n.d(t,"Presence",(function(){return N}));var l="undefined"!=typeof self?self:null,f="undefined"!=typeof window?window:null,d=l||f||void 0,p=0,v=1,y=2,m=3,g="closed",k="errored",b="joined",j="joining",T="leaving",C="phx_close",R="phx_error",E="phx_join",w="phx_reply",S="phx_leave",A=[C,R,E,w,S],L="longpoll",x="websocket",O=function(e){if("function"==typeof e)return e;return function(){return e}},P=function(){function e(t,n,i,o){c(this,e),this.channel=t,this.event=n,this.payload=i||function(){return{}},this.receivedResp=null,this.timeout=o,this.timeoutTimer=null,this.recHooks=[],this.sent=!1}return h(e,[{key:"resend",value:function(e){this.timeout=e,this.reset(),this.send()}},{key:"send",value:function(){this.hasReceived("timeout")||(this.startTimeout(),this.sent=!0,this.channel.socket.push({topic:this.channel.topic,event:this.event,payload:this.payload(),ref:this.ref,join_ref:this.channel.joinRef()}))}},{key:"receive",value:function(e,t){return this.hasReceived(e)&&t(this.receivedResp.response),this.recHooks.push({status:e,callback:t}),this}},{key:"reset",value:function(){this.cancelRefEvent(),this.ref=null,this.refEvent=null,this.receivedResp=null,this.sent=!1}},{key:"matchReceive",value:function(e){var t=e.status,n=e.response;e.ref;this.recHooks.filter((function(e){return e.status===t})).forEach((function(e){return e.callback(n)}))}},{key:"cancelRefEvent",value:function(){this.refEvent&&this.channel.off(this.refEvent)}},{key:"cancelTimeout",value:function(){clearTimeout(this.timeoutTimer),this.timeoutTimer=null}},{key:"startTimeout",value:function(){var e=this;this.timeoutTimer&&this.cancelTimeout(),this.ref=this.channel.socket.makeRef(),this.refEvent=this.channel.replyEventName(this.ref),this.channel.on(this.refEvent,(function(t){e.cancelRefEvent(),e.cancelTimeout(),e.receivedResp=t,e.matchReceive(t)})),this.timeoutTimer=setTimeout((function(){e.trigger("timeout",{})}),this.timeout)}},{key:"hasReceived",value:function(e){return this.receivedResp&&this.receivedResp.status===e}},{key:"trigger",value:function(e,t){this.channel.trigger(this.refEvent,{status:e,response:t})}}]),e}(),_=function(){function e(t,n,i){var o=this;c(this,e),this.state=g,this.topic=t,this.params=O(n||{}),this.socket=i,this.bindings=[],this.bindingRef=0,this.timeout=this.socket.timeout,this.joinedOnce=!1,this.joinPush=new P(this,E,this.params,this.timeout),this.pushBuffer=[],this.stateChangeRefs=[],this.rejoinTimer=new J((function(){o.socket.isConnected()&&o.rejoin()}),this.socket.rejoinAfterMs),this.stateChangeRefs.push(this.socket.onError((function(){return o.rejoinTimer.reset()}))),this.stateChangeRefs.push(this.socket.onOpen((function(){o.rejoinTimer.reset(),o.isErrored()&&o.rejoin()}))),this.joinPush.receive("ok",(function(){o.state=b,o.rejoinTimer.reset(),o.pushBuffer.forEach((function(e){return e.send()})),o.pushBuffer=[]})),this.joinPush.receive("error",(function(){o.state=k,o.socket.isConnected()&&o.rejoinTimer.scheduleTimeout()})),this.onClose((function(){o.rejoinTimer.reset(),o.socket.hasLogger()&&o.socket.log("channel","close ".concat(o.topic," ").concat(o.joinRef())),o.state=g,o.socket.remove(o)})),this.onError((function(e){o.socket.hasLogger()&&o.socket.log("channel","error ".concat(o.topic),e),o.isJoining()&&o.joinPush.reset(),o.state=k,o.socket.isConnected()&&o.rejoinTimer.scheduleTimeout()})),this.joinPush.receive("timeout",(function(){o.socket.hasLogger()&&o.socket.log("channel","timeout ".concat(o.topic," (").concat(o.joinRef(),")"),o.joinPush.timeout),new P(o,S,O({}),o.timeout).send(),o.state=k,o.joinPush.reset(),o.socket.isConnected()&&o.rejoinTimer.scheduleTimeout()})),this.on(w,(function(e,t){o.trigger(o.replyEventName(t),e)}))}return h(e,[{key:"join",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.timeout;if(this.joinedOnce)throw new Error("tried to join multiple times. 'join' can only be called a single time per channel instance");return this.timeout=e,this.joinedOnce=!0,this.rejoin(),this.joinPush}},{key:"onClose",value:function(e){this.on(C,e)}},{key:"onError",value:function(e){return this.on(R,(function(t){return e(t)}))}},{key:"on",value:function(e,t){var n=this.bindingRef++;return this.bindings.push({event:e,ref:n,callback:t}),n}},{key:"off",value:function(e,t){this.bindings=this.bindings.filter((function(n){return!(n.event===e&&(void 0===t||t===n.ref))}))}},{key:"canPush",value:function(){return this.socket.isConnected()&&this.isJoined()}},{key:"push",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:this.timeout;if(t=t||{},!this.joinedOnce)throw new Error("tried to push '".concat(e,"' to '").concat(this.topic,"' before joining. Use channel.join() before pushing events"));var i=new P(this,e,(function(){return t}),n);return this.canPush()?i.send():(i.startTimeout(),this.pushBuffer.push(i)),i}},{key:"leave",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.timeout;this.rejoinTimer.reset(),this.joinPush.cancelTimeout(),this.state=T;var n=function(){e.socket.hasLogger()&&e.socket.log("channel","leave ".concat(e.topic)),e.trigger(C,"leave")},i=new P(this,S,O({}),t);return i.receive("ok",(function(){return n()})).receive("timeout",(function(){return n()})),i.send(),this.canPush()||i.trigger("ok",{}),i}},{key:"onMessage",value:function(e,t,n){return t}},{key:"isLifecycleEvent",value:function(e){return A.indexOf(e)>=0}},{key:"isMember",value:function(e,t,n,i){return this.topic===e&&(!i||i===this.joinRef()||!this.isLifecycleEvent(t)||(this.socket.hasLogger()&&this.socket.log("channel","dropping outdated message",{topic:e,event:t,payload:n,joinRef:i}),!1))}},{key:"joinRef",value:function(){return this.joinPush.ref}},{key:"rejoin",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.timeout;this.isLeaving()||(this.socket.leaveOpenTopic(this.topic),this.state=j,this.joinPush.resend(e))}},{key:"trigger",value:function(e,t,n,i){var o=this.onMessage(e,t,n,i);if(t&&!o)throw new Error("channel onMessage callbacks must return the payload, modified or unmodified");for(var r=this.bindings.filter((function(t){return t.event===e})),s=0;s<r.length;s++){r[s].callback(o,n,i||this.joinRef())}}},{key:"replyEventName",value:function(e){return"chan_reply_".concat(e)}},{key:"isClosed",value:function(){return this.state===g}},{key:"isErrored",value:function(){return this.state===k}},{key:"isJoined",value:function(){return this.state===b}},{key:"isJoining",value:function(){return this.state===j}},{key:"isLeaving",value:function(){return this.state===T}}]),e}(),H={HEADER_LENGTH:1,META_LENGTH:4,KINDS:{push:0,reply:1,broadcast:2},encode:function(e,t){if(e.payload.constructor===ArrayBuffer)return t(this.binaryEncode(e));var n=[e.join_ref,e.ref,e.topic,e.event,e.payload];return t(JSON.stringify(n))},decode:function(e,t){if(e.constructor===ArrayBuffer)return t(this.binaryDecode(e));var n=r(JSON.parse(e),5);return t({join_ref:n[0],ref:n[1],topic:n[2],event:n[3],payload:n[4]})},binaryEncode:function(e){var t=e.join_ref,n=e.ref,i=e.event,o=e.topic,r=e.payload,s=this.META_LENGTH+t.length+n.length+o.length+i.length,a=new ArrayBuffer(this.HEADER_LENGTH+s),c=new DataView(a),u=0;c.setUint8(u++,this.KINDS.push),c.setUint8(u++,t.length),c.setUint8(u++,n.length),c.setUint8(u++,o.length),c.setUint8(u++,i.length),Array.from(t,(function(e){return c.setUint8(u++,e.charCodeAt(0))})),Array.from(n,(function(e){return c.setUint8(u++,e.charCodeAt(0))})),Array.from(o,(function(e){return c.setUint8(u++,e.charCodeAt(0))})),Array.from(i,(function(e){return c.setUint8(u++,e.charCodeAt(0))}));var h=new Uint8Array(a.byteLength+r.byteLength);return h.set(new Uint8Array(a),0),h.set(new Uint8Array(r),a.byteLength),h.buffer},binaryDecode:function(e){var t=new DataView(e),n=t.getUint8(0),i=new TextDecoder;switch(n){case this.KINDS.push:return this.decodePush(e,t,i);case this.KINDS.reply:return this.decodeReply(e,t,i);case this.KINDS.broadcast:return this.decodeBroadcast(e,t,i)}},decodePush:function(e,t,n){var i=t.getUint8(1),o=t.getUint8(2),r=t.getUint8(3),s=this.HEADER_LENGTH+this.META_LENGTH-1,a=n.decode(e.slice(s,s+i));s+=i;var c=n.decode(e.slice(s,s+o));s+=o;var u=n.decode(e.slice(s,s+r));return s+=r,{join_ref:a,ref:null,topic:c,event:u,payload:e.slice(s,e.byteLength)}},decodeReply:function(e,t,n){var i=t.getUint8(1),o=t.getUint8(2),r=t.getUint8(3),s=t.getUint8(4),a=this.HEADER_LENGTH+this.META_LENGTH,c=n.decode(e.slice(a,a+i));a+=i;var u=n.decode(e.slice(a,a+o));a+=o;var h=n.decode(e.slice(a,a+r));a+=r;var l=n.decode(e.slice(a,a+s));a+=s;var f=e.slice(a,e.byteLength);return{join_ref:c,ref:u,topic:h,event:w,payload:{status:l,response:f}}},decodeBroadcast:function(e,t,n){var i=t.getUint8(1),o=t.getUint8(2),r=this.HEADER_LENGTH+2,s=n.decode(e.slice(r,r+i));r+=i;var a=n.decode(e.slice(r,r+o));return r+=o,{join_ref:null,ref:null,topic:s,event:a,payload:e.slice(r,e.byteLength)}}},U=function(){function e(t){var n=this,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};c(this,e),this.stateChangeCallbacks={open:[],close:[],error:[],message:[]},this.channels=[],this.sendBuffer=[],this.ref=0,this.timeout=i.timeout||1e4,this.transport=i.transport||d.WebSocket||D,this.defaultEncoder=H.encode.bind(H),this.defaultDecoder=H.decode.bind(H),this.closeWasClean=!1,this.unloaded=!1,this.binaryType=i.binaryType||"arraybuffer",this.transport!==D?(this.encode=i.encode||this.defaultEncoder,this.decode=i.decode||this.defaultDecoder):(this.encode=this.defaultEncoder,this.decode=this.defaultDecoder),f&&f.addEventListener&&f.addEventListener("beforeunload",(function(e){n.conn&&(n.unloaded=!0,n.abnormalClose("unloaded"))})),this.heartbeatIntervalMs=i.heartbeatIntervalMs||3e4,this.rejoinAfterMs=function(e){return i.rejoinAfterMs?i.rejoinAfterMs(e):[1e3,2e3,5e3][e-1]||1e4},this.reconnectAfterMs=function(e){return n.unloaded?100:i.reconnectAfterMs?i.reconnectAfterMs(e):[10,50,100,150,200,250,500,1e3,2e3][e-1]||5e3},this.logger=i.logger||null,this.longpollerTimeout=i.longpollerTimeout||2e4,this.params=O(i.params||{}),this.endPoint="".concat(t,"/").concat(x),this.vsn=i.vsn||"2.0.0",this.heartbeatTimer=null,this.pendingHeartbeatRef=null,this.reconnectTimer=new J((function(){n.teardown((function(){return n.connect()}))}),this.reconnectAfterMs)}return h(e,[{key:"protocol",value:function(){return location.protocol.match(/^https/)?"wss":"ws"}},{key:"endPointURL",value:function(){var e=M.appendParams(M.appendParams(this.endPoint,this.params()),{vsn:this.vsn});return"/"!==e.charAt(0)?e:"/"===e.charAt(1)?"".concat(this.protocol(),":").concat(e):"".concat(this.protocol(),"://").concat(location.host).concat(e)}},{key:"disconnect",value:function(e,t,n){this.closeWasClean=!0,this.reconnectTimer.reset(),this.teardown(e,t,n)}},{key:"connect",value:function(e){var t=this;e&&(console&&console.log("passing params to connect is deprecated. Instead pass :params to the Socket constructor"),this.params=O(e)),this.conn||(this.closeWasClean=!1,this.conn=new this.transport(this.endPointURL()),this.conn.binaryType=this.binaryType,this.conn.timeout=this.longpollerTimeout,this.conn.onopen=function(){return t.onConnOpen()},this.conn.onerror=function(e){return t.onConnError(e)},this.conn.onmessage=function(e){return t.onConnMessage(e)},this.conn.onclose=function(e){return t.onConnClose(e)})}},{key:"log",value:function(e,t,n){this.logger(e,t,n)}},{key:"hasLogger",value:function(){return null!==this.logger}},{key:"onOpen",value:function(e){var t=this.makeRef();return this.stateChangeCallbacks.open.push([t,e]),t}},{key:"onClose",value:function(e){var t=this.makeRef();return this.stateChangeCallbacks.close.push([t,e]),t}},{key:"onError",value:function(e){var t=this.makeRef();return this.stateChangeCallbacks.error.push([t,e]),t}},{key:"onMessage",value:function(e){var t=this.makeRef();return this.stateChangeCallbacks.message.push([t,e]),t}},{key:"onConnOpen",value:function(){this.hasLogger()&&this.log("transport","connected to ".concat(this.endPointURL())),this.unloaded=!1,this.closeWasClean=!1,this.flushSendBuffer(),this.reconnectTimer.reset(),this.resetHeartbeat(),this.stateChangeCallbacks.open.forEach((function(e){return(0,r(e,2)[1])()}))}},{key:"heartbeatTimeout",value:function(){this.pendingHeartbeatRef&&(this.pendingHeartbeatRef=null,this.hasLogger()&&this.log("transport","heartbeat timeout. Attempting to re-establish connection"),this.abnormalClose("heartbeat timeout"))}},{key:"resetHeartbeat",value:function(){var e=this;this.conn&&this.conn.skipHeartbeat||(this.pendingHeartbeatRef=null,clearTimeout(this.heartbeatTimer),setTimeout((function(){return e.sendHeartbeat()}),this.heartbeatIntervalMs))}},{key:"teardown",value:function(e,t,n){var i=this;if(!this.conn)return e&&e();this.waitForBufferDone((function(){i.conn&&(t?i.conn.close(t,n||""):i.conn.close()),i.waitForSocketClosed((function(){i.conn&&(i.conn.onclose=function(){},i.conn=null),e&&e()}))}))}},{key:"waitForBufferDone",value:function(e){var t=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1;5!==n&&this.conn&&this.conn.bufferedAmount?setTimeout((function(){t.waitForBufferDone(e,n+1)}),150*n):e()}},{key:"waitForSocketClosed",value:function(e){var t=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1;5!==n&&this.conn&&this.conn.readyState!==m?setTimeout((function(){t.waitForSocketClosed(e,n+1)}),150*n):e()}},{key:"onConnClose",value:function(e){this.hasLogger()&&this.log("transport","close",e),this.triggerChanError(),clearTimeout(this.heartbeatTimer),this.closeWasClean||this.reconnectTimer.scheduleTimeout(),this.stateChangeCallbacks.close.forEach((function(t){return(0,r(t,2)[1])(e)}))}},{key:"onConnError",value:function(e){this.hasLogger()&&this.log("transport",e),this.triggerChanError(),this.stateChangeCallbacks.error.forEach((function(t){return(0,r(t,2)[1])(e)}))}},{key:"triggerChanError",value:function(){this.channels.forEach((function(e){e.isErrored()||e.isLeaving()||e.isClosed()||e.trigger(R)}))}},{key:"connectionState",value:function(){switch(this.conn&&this.conn.readyState){case p:return"connecting";case v:return"open";case y:return"closing";default:return"closed"}}},{key:"isConnected",value:function(){return"open"===this.connectionState()}},{key:"remove",value:function(e){this.off(e.stateChangeRefs),this.channels=this.channels.filter((function(t){return t.joinRef()!==e.joinRef()}))}},{key:"off",value:function(e){for(var t in this.stateChangeCallbacks)this.stateChangeCallbacks[t]=this.stateChangeCallbacks[t].filter((function(t){var n=r(t,1)[0];return-1===e.indexOf(n)}))}},{key:"channel",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=new _(e,t,this);return this.channels.push(n),n}},{key:"push",value:function(e){var t=this;if(this.hasLogger()){var n=e.topic,i=e.event,o=e.payload,r=e.ref,s=e.join_ref;this.log("push","".concat(n," ").concat(i," (").concat(s,", ").concat(r,")"),o)}this.isConnected()?this.encode(e,(function(e){return t.conn.send(e)})):this.sendBuffer.push((function(){return t.encode(e,(function(e){return t.conn.send(e)}))}))}},{key:"makeRef",value:function(){var e=this.ref+1;return e===this.ref?this.ref=0:this.ref=e,this.ref.toString()}},{key:"sendHeartbeat",value:function(){var e=this;this.pendingHeartbeatRef&&!this.isConnected()||(this.pendingHeartbeatRef=this.makeRef(),this.push({topic:"phoenix",event:"heartbeat",payload:{},ref:this.pendingHeartbeatRef}),this.heartbeatTimer=setTimeout((function(){return e.heartbeatTimeout()}),this.heartbeatIntervalMs))}},{key:"abnormalClose",value:function(e){this.closeWasClean=!1,this.isConnected()&&this.conn.close(1e3,e)}},{key:"flushSendBuffer",value:function(){this.isConnected()&&this.sendBuffer.length>0&&(this.sendBuffer.forEach((function(e){return e()})),this.sendBuffer=[])}},{key:"onConnMessage",value:function(e){var t=this;this.decode(e.data,(function(e){var n=e.topic,i=e.event,o=e.payload,s=e.ref,a=e.join_ref;s&&s===t.pendingHeartbeatRef&&(clearTimeout(t.heartbeatTimer),t.pendingHeartbeatRef=null,setTimeout((function(){return t.sendHeartbeat()}),t.heartbeatIntervalMs)),t.hasLogger()&&t.log("receive","".concat(o.status||""," ").concat(n," ").concat(i," ").concat(s&&"("+s+")"||""),o);for(var c=0;c<t.channels.length;c++){var u=t.channels[c];u.isMember(n,i,o,a)&&u.trigger(i,o,s,a)}for(var h=0;h<t.stateChangeCallbacks.message.length;h++){(0,r(t.stateChangeCallbacks.message[h],2)[1])(e)}}))}},{key:"leaveOpenTopic",value:function(e){var t=this.channels.find((function(t){return t.topic===e&&(t.isJoined()||t.isJoining())}));t&&(this.hasLogger()&&this.log("transport",'leaving duplicate topic "'.concat(e,'"')),t.leave())}}]),e}(),D=function(){function e(t){c(this,e),this.endPoint=null,this.token=null,this.skipHeartbeat=!0,this.onopen=function(){},this.onerror=function(){},this.onmessage=function(){},this.onclose=function(){},this.pollEndpoint=this.normalizeEndpoint(t),this.readyState=p,this.poll()}return h(e,[{key:"normalizeEndpoint",value:function(e){return e.replace("ws://","http://").replace("wss://","https://").replace(new RegExp("(.*)/"+x),"$1/"+L)}},{key:"endpointURL",value:function(){return M.appendParams(this.pollEndpoint,{token:this.token})}},{key:"closeAndRetry",value:function(){this.close(),this.readyState=p}},{key:"ontimeout",value:function(){this.onerror("timeout"),this.closeAndRetry()}},{key:"poll",value:function(){var e=this;this.readyState!==v&&this.readyState!==p||M.request("GET",this.endpointURL(),"application/json",null,this.timeout,this.ontimeout.bind(this),(function(t){if(t){var n=t.status,i=t.token,o=t.messages;e.token=i}else n=0;switch(n){case 200:o.forEach((function(t){setTimeout((function(){e.onmessage({data:t})}),0)})),e.poll();break;case 204:e.poll();break;case 410:e.readyState=v,e.onopen(),e.poll();break;case 403:e.onerror(),e.close();break;case 0:case 500:e.onerror(),e.closeAndRetry();break;default:throw new Error("unhandled poll status ".concat(n))}}))}},{key:"send",value:function(e){var t=this;M.request("POST",this.endpointURL(),"application/json",e,this.timeout,this.onerror.bind(this,"timeout"),(function(e){e&&200===e.status||(t.onerror(e&&e.status),t.closeAndRetry())}))}},{key:"close",value:function(e,t){this.readyState=m,this.onclose()}}]),e}(),M=function(){function e(){c(this,e)}return h(e,null,[{key:"request",value:function(e,t,n,i,o,r,s){if(d.XDomainRequest){var a=new XDomainRequest;this.xdomainRequest(a,e,t,i,o,r,s)}else{var c=new d.XMLHttpRequest;this.xhrRequest(c,e,t,n,i,o,r,s)}}},{key:"xdomainRequest",value:function(e,t,n,i,o,r,s){var a=this;e.timeout=o,e.open(t,n),e.onload=function(){var t=a.parseJSON(e.responseText);s&&s(t)},r&&(e.ontimeout=r),e.onprogress=function(){},e.send(i)}},{key:"xhrRequest",value:function(e,t,n,i,o,r,s,a){var c=this;e.open(t,n,!0),e.timeout=r,e.setRequestHeader("Content-Type",i),e.onerror=function(){a&&a(null)},e.onreadystatechange=function(){if(e.readyState===c.states.complete&&a){var t=c.parseJSON(e.responseText);a(t)}},s&&(e.ontimeout=s),e.send(o)}},{key:"parseJSON",value:function(e){if(!e||""===e)return null;try{return JSON.parse(e)}catch(t){return console&&console.log("failed to parse JSON response",e),null}}},{key:"serialize",value:function(e,t){var n=[];for(var i in e)if(e.hasOwnProperty(i)){var r=t?"".concat(t,"[").concat(i,"]"):i,s=e[i];"object"===o(s)?n.push(this.serialize(s,r)):n.push(encodeURIComponent(r)+"="+encodeURIComponent(s))}return n.join("&")}},{key:"appendParams",value:function(e,t){if(0===Object.keys(t).length)return e;var n=e.match(/\?/)?"&":"?";return"".concat(e).concat(n).concat(this.serialize(t))}}]),e}();M.states={complete:4};var N=function(){function e(t){var n=this,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};c(this,e);var o=i.events||{state:"presence_state",diff:"presence_diff"};this.state={},this.pendingDiffs=[],this.channel=t,this.joinRef=null,this.caller={onJoin:function(){},onLeave:function(){},onSync:function(){}},this.channel.on(o.state,(function(t){var i=n.caller,o=i.onJoin,r=i.onLeave,s=i.onSync;n.joinRef=n.channel.joinRef(),n.state=e.syncState(n.state,t,o,r),n.pendingDiffs.forEach((function(t){n.state=e.syncDiff(n.state,t,o,r)})),n.pendingDiffs=[],s()})),this.channel.on(o.diff,(function(t){var i=n.caller,o=i.onJoin,r=i.onLeave,s=i.onSync;n.inPendingSyncState()?n.pendingDiffs.push(t):(n.state=e.syncDiff(n.state,t,o,r),s())}))}return h(e,[{key:"onJoin",value:function(e){this.caller.onJoin=e}},{key:"onLeave",value:function(e){this.caller.onLeave=e}},{key:"onSync",value:function(e){this.caller.onSync=e}},{key:"list",value:function(t){return e.list(this.state,t)}},{key:"inPendingSyncState",value:function(){return!this.joinRef||this.joinRef!==this.channel.joinRef()}}],[{key:"syncState",value:function(e,t,n,i){var o=this,r=this.clone(e),s={},a={};return this.map(r,(function(e,n){t[e]||(a[e]=n)})),this.map(t,(function(e,t){var n=r[e];if(n){var i=t.metas.map((function(e){return e.phx_ref})),c=n.metas.map((function(e){return e.phx_ref})),u=t.metas.filter((function(e){return c.indexOf(e.phx_ref)<0})),h=n.metas.filter((function(e){return i.indexOf(e.phx_ref)<0}));u.length>0&&(s[e]=t,s[e].metas=u),h.length>0&&(a[e]=o.clone(n),a[e].metas=h)}else s[e]=t})),this.syncDiff(r,{joins:s,leaves:a},n,i)}},{key:"syncDiff",value:function(e,t,n,o){var r=t.joins,s=t.leaves,a=this.clone(e);return n||(n=function(){}),o||(o=function(){}),this.map(r,(function(e,t){var o=a[e];if(a[e]=t,o){var r,s=a[e].metas.map((function(e){return e.phx_ref})),c=o.metas.filter((function(e){return s.indexOf(e.phx_ref)<0}));(r=a[e].metas).unshift.apply(r,i(c))}n(e,o,t)})),this.map(s,(function(e,t){var n=a[e];if(n){var i=t.metas.map((function(e){return e.phx_ref}));n.metas=n.metas.filter((function(e){return i.indexOf(e.phx_ref)<0})),o(e,n,t),0===n.metas.length&&delete a[e]}})),a}},{key:"list",value:function(e,t){return t||(t=function(e,t){return t}),this.map(e,(function(e,n){return t(e,n)}))}},{key:"map",value:function(e,t){return Object.getOwnPropertyNames(e).map((function(n){return t(n,e[n])}))}},{key:"clone",value:function(e){return JSON.parse(JSON.stringify(e))}}]),e}(),J=function(){function e(t,n){c(this,e),this.callback=t,this.timerCalc=n,this.timer=null,this.tries=0}return h(e,[{key:"reset",value:function(){this.tries=0,clearTimeout(this.timer)}},{key:"scheduleTimeout",value:function(){var e=this;clearTimeout(this.timer),this.timer=setTimeout((function(){e.tries=e.tries+1,e.callback()}),this.timerCalc(this.tries+1))}}]),e}()}])}));
var Phoenix = (() => {
var __defProp = Object.defineProperty;
var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
var __export = (target, all) => {
__markAsModule(target);
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
// js/phoenix/index.js
var phoenix_exports = {};
__export(phoenix_exports, {
Channel: () => Channel,
LongPoll: () => LongPoll,
Presence: () => Presence,
Serializer: () => serializer_default,
Socket: () => Socket
});
// js/phoenix/utils.js
var closure = (value) => {
if (typeof value === "function") {
return value;
} else {
let closure2 = function() {
return value;
};
return closure2;
}
};
// js/phoenix/constants.js
var globalSelf = typeof self !== "undefined" ? self : null;
var phxWindow = typeof window !== "undefined" ? window : null;
var global = globalSelf || phxWindow || void 0;
var DEFAULT_VSN = "2.0.0";
var SOCKET_STATES = { connecting: 0, open: 1, closing: 2, closed: 3 };
var DEFAULT_TIMEOUT = 1e4;
var WS_CLOSE_NORMAL = 1e3;
var CHANNEL_STATES = {
closed: "closed",
errored: "errored",
joined: "joined",
joining: "joining",
leaving: "leaving"
};
var CHANNEL_EVENTS = {
close: "phx_close",
error: "phx_error",
join: "phx_join",
reply: "phx_reply",
leave: "phx_leave"
};
var CHANNEL_LIFECYCLE_EVENTS = [
CHANNEL_EVENTS.close,
CHANNEL_EVENTS.error,
CHANNEL_EVENTS.join,
CHANNEL_EVENTS.reply,
CHANNEL_EVENTS.leave
];
var TRANSPORTS = {
longpoll: "longpoll",
websocket: "websocket"
};
// js/phoenix/push.js
var Push = class {
constructor(channel, event, payload, timeout) {
this.channel = channel;
this.event = event;
this.payload = payload || function() {
return {};
};
this.receivedResp = null;
this.timeout = timeout;
this.timeoutTimer = null;
this.recHooks = [];
this.sent = false;
}
resend(timeout) {
this.timeout = timeout;
this.reset();
this.send();
}
send() {
if (this.hasReceived("timeout")) {
return;
}
this.startTimeout();
this.sent = true;
this.channel.socket.push({
topic: this.channel.topic,
event: this.event,
payload: this.payload(),
ref: this.ref,
join_ref: this.channel.joinRef()
});
}
receive(status, callback) {
if (this.hasReceived(status)) {
callback(this.receivedResp.response);
}
this.recHooks.push({ status, callback });
return this;
}
reset() {
this.cancelRefEvent();
this.ref = null;
this.refEvent = null;
this.receivedResp = null;
this.sent = false;
}
matchReceive({ status, response, _ref }) {
this.recHooks.filter((h) => h.status === status).forEach((h) => h.callback(response));
}
cancelRefEvent() {
if (!this.refEvent) {
return;
}
this.channel.off(this.refEvent);
}
cancelTimeout() {
clearTimeout(this.timeoutTimer);
this.timeoutTimer = null;
}
startTimeout() {
if (this.timeoutTimer) {
this.cancelTimeout();
}
this.ref = this.channel.socket.makeRef();
this.refEvent = this.channel.replyEventName(this.ref);
this.channel.on(this.refEvent, (payload) => {
this.cancelRefEvent();
this.cancelTimeout();
this.receivedResp = payload;
this.matchReceive(payload);
});
this.timeoutTimer = setTimeout(() => {
this.trigger("timeout", {});
}, this.timeout);
}
hasReceived(status) {
return this.receivedResp && this.receivedResp.status === status;
}
trigger(status, response) {
this.channel.trigger(this.refEvent, { status, response });
}
};
// js/phoenix/timer.js
var Timer = class {
constructor(callback, timerCalc) {
this.callback = callback;
this.timerCalc = timerCalc;
this.timer = null;
this.tries = 0;
}
reset() {
this.tries = 0;
clearTimeout(this.timer);
}
scheduleTimeout() {
clearTimeout(this.timer);
this.timer = setTimeout(() => {
this.tries = this.tries + 1;
this.callback();
}, this.timerCalc(this.tries + 1));
}
};
// js/phoenix/channel.js
var Channel = class {
constructor(topic, params, socket) {
this.state = CHANNEL_STATES.closed;
this.topic = topic;
this.params = closure(params || {});
this.socket = socket;
this.bindings = [];
this.bindingRef = 0;
this.timeout = this.socket.timeout;
this.joinedOnce = false;
this.joinPush = new Push(this, CHANNEL_EVENTS.join, this.params, this.timeout);
this.pushBuffer = [];
this.stateChangeRefs = [];
this.rejoinTimer = new Timer(() => {
if (this.socket.isConnected()) {
this.rejoin();
}
}, this.socket.rejoinAfterMs);
this.stateChangeRefs.push(this.socket.onError(() => this.rejoinTimer.reset()));
this.stateChangeRefs.push(this.socket.onOpen(() => {
this.rejoinTimer.reset();
if (this.isErrored()) {
this.rejoin();
}
}));
this.joinPush.receive("ok", () => {
this.state = CHANNEL_STATES.joined;
this.rejoinTimer.reset();
this.pushBuffer.forEach((pushEvent) => pushEvent.send());
this.pushBuffer = [];
});
this.joinPush.receive("error", () => {
this.state = CHANNEL_STATES.errored;
if (this.socket.isConnected()) {
this.rejoinTimer.scheduleTimeout();
}
});
this.onClose(() => {
this.rejoinTimer.reset();
if (this.socket.hasLogger())
this.socket.log("channel", `close ${this.topic} ${this.joinRef()}`);
this.state = CHANNEL_STATES.closed;
this.socket.remove(this);
});
this.onError((reason) => {
if (this.socket.hasLogger())
this.socket.log("channel", `error ${this.topic}`, reason);
if (this.isJoining()) {
this.joinPush.reset();
}
this.state = CHANNEL_STATES.errored;
if (this.socket.isConnected()) {
this.rejoinTimer.scheduleTimeout();
}
});
this.joinPush.receive("timeout", () => {
if (this.socket.hasLogger())
this.socket.log("channel", `timeout ${this.topic} (${this.joinRef()})`, this.joinPush.timeout);
let leavePush = new Push(this, CHANNEL_EVENTS.leave, closure({}), this.timeout);
leavePush.send();
this.state = CHANNEL_STATES.errored;
this.joinPush.reset();
if (this.socket.isConnected()) {
this.rejoinTimer.scheduleTimeout();
}
});
this.on(CHANNEL_EVENTS.reply, (payload, ref) => {
this.trigger(this.replyEventName(ref), payload);
});
}
join(timeout = this.timeout) {
if (this.joinedOnce) {
throw new Error("tried to join multiple times. 'join' can only be called a single time per channel instance");
} else {
this.timeout = timeout;
this.joinedOnce = true;
this.rejoin();
return this.joinPush;
}
}
onClose(callback) {
this.on(CHANNEL_EVENTS.close, callback);
}
onError(callback) {
return this.on(CHANNEL_EVENTS.error, (reason) => callback(reason));
}
on(event, callback) {
let ref = this.bindingRef++;
this.bindings.push({ event, ref, callback });
return ref;
}
off(event, ref) {
this.bindings = this.bindings.filter((bind) => {
return !(bind.event === event && (typeof ref === "undefined" || ref === bind.ref));
});
}
canPush() {
return this.socket.isConnected() && this.isJoined();
}
push(event, payload, timeout = this.timeout) {
payload = payload || {};
if (!this.joinedOnce) {
throw new Error(`tried to push '${event}' to '${this.topic}' before joining. Use channel.join() before pushing events`);
}
let pushEvent = new Push(this, event, function() {
return payload;
}, timeout);
if (this.canPush()) {
pushEvent.send();
} else {
pushEvent.startTimeout();
this.pushBuffer.push(pushEvent);
}
return pushEvent;
}
leave(timeout = this.timeout) {
this.rejoinTimer.reset();
this.joinPush.cancelTimeout();
this.state = CHANNEL_STATES.leaving;
let onClose = () => {
if (this.socket.hasLogger())
this.socket.log("channel", `leave ${this.topic}`);
this.trigger(CHANNEL_EVENTS.close, "leave");
};
let leavePush = new Push(this, CHANNEL_EVENTS.leave, closure({}), timeout);
leavePush.receive("ok", () => onClose()).receive("timeout", () => onClose());
leavePush.send();
if (!this.canPush()) {
leavePush.trigger("ok", {});
}
return leavePush;
}
onMessage(_event, payload, _ref) {
return payload;
}
isLifecycleEvent(event) {
return CHANNEL_LIFECYCLE_EVENTS.indexOf(event) >= 0;
}
isMember(topic, event, payload, joinRef) {
if (this.topic !== topic) {
return false;
}
if (joinRef && joinRef !== this.joinRef() && this.isLifecycleEvent(event)) {
if (this.socket.hasLogger())
this.socket.log("channel", "dropping outdated message", { topic, event, payload, joinRef });
return false;
} else {
return true;
}
}
joinRef() {
return this.joinPush.ref;
}
rejoin(timeout = this.timeout) {
if (this.isLeaving()) {
return;
}
this.socket.leaveOpenTopic(this.topic);
this.state = CHANNEL_STATES.joining;
this.joinPush.resend(timeout);
}
trigger(event, payload, ref, joinRef) {
let handledPayload = this.onMessage(event, payload, ref, joinRef);
if (payload && !handledPayload) {
throw new Error("channel onMessage callbacks must return the payload, modified or unmodified");
}
let eventBindings = this.bindings.filter((bind) => bind.event === event);
for (let i = 0; i < eventBindings.length; i++) {
let bind = eventBindings[i];
bind.callback(handledPayload, ref, joinRef || this.joinRef());
}
}
replyEventName(ref) {
return `chan_reply_${ref}`;
}
isClosed() {
return this.state === CHANNEL_STATES.closed;
}
isErrored() {
return this.state === CHANNEL_STATES.errored;
}
isJoined() {
return this.state === CHANNEL_STATES.joined;
}
isJoining() {
return this.state === CHANNEL_STATES.joining;
}
isLeaving() {
return this.state === CHANNEL_STATES.leaving;
}
};
// js/phoenix/ajax.js
var Ajax = class {
constructor() {
this.states = { complete: 4 };
}
static request(method, endPoint, accept, body, timeout, ontimeout, callback) {
if (global.XDomainRequest) {
let req = new global.XDomainRequest();
this.xdomainRequest(req, method, endPoint, body, timeout, ontimeout, callback);
} else {
let req = new global.XMLHttpRequest();
this.xhrRequest(req, method, endPoint, accept, body, timeout, ontimeout, callback);
}
}
static xdomainRequest(req, method, endPoint, body, timeout, ontimeout, callback) {
req.timeout = timeout;
req.open(method, endPoint);
req.onload = () => {
let response = this.parseJSON(req.responseText);
callback && callback(response);
};
if (ontimeout) {
req.ontimeout = ontimeout;
}
req.onprogress = () => {
};
req.send(body);
}
static xhrRequest(req, method, endPoint, accept, body, timeout, ontimeout, callback) {
req.open(method, endPoint, true);
req.timeout = timeout;
req.setRequestHeader("Content-Type", accept);
req.onerror = () => {
callback && callback(null);
};
req.onreadystatechange = () => {
if (req.readyState === this.states.complete && callback) {
let response = this.parseJSON(req.responseText);
callback(response);
}
};
if (ontimeout) {
req.ontimeout = ontimeout;
}
req.send(body);
}
static parseJSON(resp) {
if (!resp || resp === "") {
return null;
}
try {
return JSON.parse(resp);
} catch (e) {
console && console.log("failed to parse JSON response", resp);
return null;
}
}
static serialize(obj, parentKey) {
let queryStr = [];
for (var key in obj) {
if (!Object.prototype.hasOwnProperty.call(obj, key)) {
continue;
}
let paramKey = parentKey ? `${parentKey}[${key}]` : key;
let paramVal = obj[key];
if (typeof paramVal === "object") {
queryStr.push(this.serialize(paramVal, paramKey));
} else {
queryStr.push(encodeURIComponent(paramKey) + "=" + encodeURIComponent(paramVal));
}
}
return queryStr.join("&");
}
static appendParams(url, params) {
if (Object.keys(params).length === 0) {
return url;
}
let prefix = url.match(/\?/) ? "&" : "?";
return `${url}${prefix}${this.serialize(params)}`;
}
};
// js/phoenix/longpoll.js
var LongPoll = class {
constructor(endPoint) {
this.endPoint = null;
this.token = null;
this.skipHeartbeat = true;
this.onopen = function() {
};
this.onerror = function() {
};
this.onmessage = function() {
};
this.onclose = function() {
};
this.pollEndpoint = this.normalizeEndpoint(endPoint);
this.readyState = SOCKET_STATES.connecting;
this.poll();
}
normalizeEndpoint(endPoint) {
return endPoint.replace("ws://", "http://").replace("wss://", "https://").replace(new RegExp("(.*)/" + TRANSPORTS.websocket), "$1/" + TRANSPORTS.longpoll);
}
endpointURL() {
return Ajax.appendParams(this.pollEndpoint, { token: this.token });
}
closeAndRetry() {
this.close();
this.readyState = SOCKET_STATES.connecting;
}
ontimeout() {
this.onerror("timeout");
this.closeAndRetry();
}
poll() {
if (!(this.readyState === SOCKET_STATES.open || this.readyState === SOCKET_STATES.connecting)) {
return;
}
Ajax.request("GET", this.endpointURL(), "application/json", null, this.timeout, this.ontimeout.bind(this), (resp) => {
if (resp) {
var { status, token, messages } = resp;
this.token = token;
} else {
status = 0;
}
switch (status) {
case 200:
messages.forEach((msg) => {
setTimeout(() => {
this.onmessage({ data: msg });
}, 0);
});
this.poll();
break;
case 204:
this.poll();
break;
case 410:
this.readyState = SOCKET_STATES.open;
this.onopen();
this.poll();
break;
case 403:
this.onerror();
this.close();
break;
case 0:
case 500:
this.onerror();
this.closeAndRetry();
break;
default:
throw new Error(`unhandled poll status ${status}`);
}
});
}
send(body) {
Ajax.request("POST", this.endpointURL(), "application/json", body, this.timeout, this.onerror.bind(this, "timeout"), (resp) => {
if (!resp || resp.status !== 200) {
this.onerror(resp && resp.status);
this.closeAndRetry();
}
});
}
close(_code, _reason) {
this.readyState = SOCKET_STATES.closed;
this.onclose();
}
};
// js/phoenix/presence.js
var Presence = class {
constructor(channel, opts = {}) {
let events = opts.events || { state: "presence_state", diff: "presence_diff" };
this.state = {};
this.pendingDiffs = [];
this.channel = channel;
this.joinRef = null;
this.caller = {
onJoin: function() {
},
onLeave: function() {
},
onSync: function() {
}
};
this.channel.on(events.state, (newState) => {
let { onJoin, onLeave, onSync } = this.caller;
this.joinRef = this.channel.joinRef();
this.state = Presence.syncState(this.state, newState, onJoin, onLeave);
this.pendingDiffs.forEach((diff) => {
this.state = Presence.syncDiff(this.state, diff, onJoin, onLeave);
});
this.pendingDiffs = [];
onSync();
});
this.channel.on(events.diff, (diff) => {
let { onJoin, onLeave, onSync } = this.caller;
if (this.inPendingSyncState()) {
this.pendingDiffs.push(diff);
} else {
this.state = Presence.syncDiff(this.state, diff, onJoin, onLeave);
onSync();
}
});
}
onJoin(callback) {
this.caller.onJoin = callback;
}
onLeave(callback) {
this.caller.onLeave = callback;
}
onSync(callback) {
this.caller.onSync = callback;
}
list(by) {
return Presence.list(this.state, by);
}
inPendingSyncState() {
return !this.joinRef || this.joinRef !== this.channel.joinRef();
}
static syncState(currentState, newState, onJoin, onLeave) {
let state = this.clone(currentState);
let joins = {};
let leaves = {};
this.map(state, (key, presence) => {
if (!newState[key]) {
leaves[key] = presence;
}
});
this.map(newState, (key, newPresence) => {
let currentPresence = state[key];
if (currentPresence) {
let newRefs = newPresence.metas.map((m) => m.phx_ref);
let curRefs = currentPresence.metas.map((m) => m.phx_ref);
let joinedMetas = newPresence.metas.filter((m) => curRefs.indexOf(m.phx_ref) < 0);
let leftMetas = currentPresence.metas.filter((m) => newRefs.indexOf(m.phx_ref) < 0);
if (joinedMetas.length > 0) {
joins[key] = newPresence;
joins[key].metas = joinedMetas;
}
if (leftMetas.length > 0) {
leaves[key] = this.clone(currentPresence);
leaves[key].metas = leftMetas;
}
} else {
joins[key] = newPresence;
}
});
return this.syncDiff(state, { joins, leaves }, onJoin, onLeave);
}
static syncDiff(state, diff, onJoin, onLeave) {
let { joins, leaves } = this.clone(diff);
if (!onJoin) {
onJoin = function() {
};
}
if (!onLeave) {
onLeave = function() {
};
}
this.map(joins, (key, newPresence) => {
let currentPresence = state[key];
state[key] = this.clone(newPresence);
if (currentPresence) {
let joinedRefs = state[key].metas.map((m) => m.phx_ref);
let curMetas = currentPresence.metas.filter((m) => joinedRefs.indexOf(m.phx_ref) < 0);
state[key].metas.unshift(...curMetas);
}
onJoin(key, currentPresence, newPresence);
});
this.map(leaves, (key, leftPresence) => {
let currentPresence = state[key];
if (!currentPresence) {
return;
}
let refsToRemove = leftPresence.metas.map((m) => m.phx_ref);
currentPresence.metas = currentPresence.metas.filter((p) => {
return refsToRemove.indexOf(p.phx_ref) < 0;
});
onLeave(key, currentPresence, leftPresence);
if (currentPresence.metas.length === 0) {
delete state[key];
}
});
return state;
}
static list(presences, chooser) {
if (!chooser) {
chooser = function(key, pres) {
return pres;
};
}
return this.map(presences, (key, presence) => {
return chooser(key, presence);
});
}
static map(obj, func) {
return Object.getOwnPropertyNames(obj).map((key) => func(key, obj[key]));
}
static clone(obj) {
return JSON.parse(JSON.stringify(obj));
}
};
// js/phoenix/serializer.js
var serializer_default = {
HEADER_LENGTH: 1,
META_LENGTH: 4,
KINDS: { push: 0, reply: 1, broadcast: 2 },
encode(msg, callback) {
if (msg.payload.constructor === ArrayBuffer) {
return callback(this.binaryEncode(msg));
} else {
let payload = [msg.join_ref, msg.ref, msg.topic, msg.event, msg.payload];
return callback(JSON.stringify(payload));
}
},
decode(rawPayload, callback) {
if (rawPayload.constructor === ArrayBuffer) {
return callback(this.binaryDecode(rawPayload));
} else {
let [join_ref, ref, topic, event, payload] = JSON.parse(rawPayload);
return callback({ join_ref, ref, topic, event, payload });
}
},
binaryEncode(message) {
let { join_ref, ref, event, topic, payload } = message;
let metaLength = this.META_LENGTH + join_ref.length + ref.length + topic.length + event.length;
let header = new ArrayBuffer(this.HEADER_LENGTH + metaLength);
let view = new DataView(header);
let offset = 0;
view.setUint8(offset++, this.KINDS.push);
view.setUint8(offset++, join_ref.length);
view.setUint8(offset++, ref.length);
view.setUint8(offset++, topic.length);
view.setUint8(offset++, event.length);
Array.from(join_ref, (char) => view.setUint8(offset++, char.charCodeAt(0)));
Array.from(ref, (char) => view.setUint8(offset++, char.charCodeAt(0)));
Array.from(topic, (char) => view.setUint8(offset++, char.charCodeAt(0)));
Array.from(event, (char) => view.setUint8(offset++, char.charCodeAt(0)));
var combined = new Uint8Array(header.byteLength + payload.byteLength);
combined.set(new Uint8Array(header), 0);
combined.set(new Uint8Array(payload), header.byteLength);
return combined.buffer;
},
binaryDecode(buffer) {
let view = new DataView(buffer);
let kind = view.getUint8(0);
let decoder = new TextDecoder();
switch (kind) {
case this.KINDS.push:
return this.decodePush(buffer, view, decoder);
case this.KINDS.reply:
return this.decodeReply(buffer, view, decoder);
case this.KINDS.broadcast:
return this.decodeBroadcast(buffer, view, decoder);
}
},
decodePush(buffer, view, decoder) {
let joinRefSize = view.getUint8(1);
let topicSize = view.getUint8(2);
let eventSize = view.getUint8(3);
let offset = this.HEADER_LENGTH + this.META_LENGTH - 1;
let joinRef = decoder.decode(buffer.slice(offset, offset + joinRefSize));
offset = offset + joinRefSize;
let topic = decoder.decode(buffer.slice(offset, offset + topicSize));
offset = offset + topicSize;
let event = decoder.decode(buffer.slice(offset, offset + eventSize));
offset = offset + eventSize;
let data = buffer.slice(offset, buffer.byteLength);
return { join_ref: joinRef, ref: null, topic, event, payload: data };
},
decodeReply(buffer, view, decoder) {
let joinRefSize = view.getUint8(1);
let refSize = view.getUint8(2);
let topicSize = view.getUint8(3);
let eventSize = view.getUint8(4);
let offset = this.HEADER_LENGTH + this.META_LENGTH;
let joinRef = decoder.decode(buffer.slice(offset, offset + joinRefSize));
offset = offset + joinRefSize;
let ref = decoder.decode(buffer.slice(offset, offset + refSize));
offset = offset + refSize;
let topic = decoder.decode(buffer.slice(offset, offset + topicSize));
offset = offset + topicSize;
let event = decoder.decode(buffer.slice(offset, offset + eventSize));
offset = offset + eventSize;
let data = buffer.slice(offset, buffer.byteLength);
let payload = { status: event, response: data };
return { join_ref: joinRef, ref, topic, event: CHANNEL_EVENTS.reply, payload };
},
decodeBroadcast(buffer, view, decoder) {
let topicSize = view.getUint8(1);
let eventSize = view.getUint8(2);
let offset = this.HEADER_LENGTH + 2;
let topic = decoder.decode(buffer.slice(offset, offset + topicSize));
offset = offset + topicSize;
let event = decoder.decode(buffer.slice(offset, offset + eventSize));
offset = offset + eventSize;
let data = buffer.slice(offset, buffer.byteLength);
return { join_ref: null, ref: null, topic, event, payload: data };
}
};
// js/phoenix/socket.js
var Socket = class {
constructor(endPoint, opts = {}) {
this.stateChangeCallbacks = { open: [], close: [], error: [], message: [] };
this.channels = [];
this.sendBuffer = [];
this.ref = 0;
this.timeout = opts.timeout || DEFAULT_TIMEOUT;
this.transport = opts.transport || global.WebSocket || LongPoll;
this.establishedConnections = 0;
this.defaultEncoder = serializer_default.encode.bind(serializer_default);
this.defaultDecoder = serializer_default.decode.bind(serializer_default);
this.closeWasClean = false;
this.binaryType = opts.binaryType || "arraybuffer";
this.connectClock = 1;
if (this.transport !== LongPoll) {
this.encode = opts.encode || this.defaultEncoder;
this.decode = opts.decode || this.defaultDecoder;
} else {
this.encode = this.defaultEncoder;
this.decode = this.defaultDecoder;
}
let awaitingConnectionOnPageShow = null;
if (phxWindow && phxWindow.addEventListener) {
phxWindow.addEventListener("pagehide", (_e) => {
if (this.conn) {
this.disconnect();
awaitingConnectionOnPageShow = this.connectClock;
}
});
phxWindow.addEventListener("pageshow", (_e) => {
if (awaitingConnectionOnPageShow === this.connectClock) {
awaitingConnectionOnPageShow = null;
this.connect();
}
});
}
this.heartbeatIntervalMs = opts.heartbeatIntervalMs || 3e4;
this.rejoinAfterMs = (tries) => {
if (opts.rejoinAfterMs) {
return opts.rejoinAfterMs(tries);
} else {
return [1e3, 2e3, 5e3][tries - 1] || 1e4;
}
};
this.reconnectAfterMs = (tries) => {
if (opts.reconnectAfterMs) {
return opts.reconnectAfterMs(tries);
} else {
return [10, 50, 100, 150, 200, 250, 500, 1e3, 2e3][tries - 1] || 5e3;
}
};
this.logger = opts.logger || null;
this.longpollerTimeout = opts.longpollerTimeout || 2e4;
this.params = closure(opts.params || {});
this.endPoint = `${endPoint}/${TRANSPORTS.websocket}`;
this.vsn = opts.vsn || DEFAULT_VSN;
this.heartbeatTimer = null;
this.pendingHeartbeatRef = null;
this.reconnectTimer = new Timer(() => {
this.teardown(() => this.connect());
}, this.reconnectAfterMs);
}
replaceTransport(newTransport) {
this.disconnect();
this.transport = newTransport;
}
protocol() {
return location.protocol.match(/^https/) ? "wss" : "ws";
}
endPointURL() {
let uri = Ajax.appendParams(Ajax.appendParams(this.endPoint, this.params()), { vsn: this.vsn });
if (uri.charAt(0) !== "/") {
return uri;
}
if (uri.charAt(1) === "/") {
return `${this.protocol()}:${uri}`;
}
return `${this.protocol()}://${location.host}${uri}`;
}
disconnect(callback, code, reason) {
this.connectClock++;
this.closeWasClean = true;
this.reconnectTimer.reset();
this.teardown(callback, code, reason);
}
connect(params) {
this.connectClock++;
if (params) {
console && console.log("passing params to connect is deprecated. Instead pass :params to the Socket constructor");
this.params = closure(params);
}
if (this.conn) {
return;
}
this.closeWasClean = false;
this.conn = new this.transport(this.endPointURL());
this.conn.binaryType = this.binaryType;
this.conn.timeout = this.longpollerTimeout;
this.conn.onopen = () => this.onConnOpen();
this.conn.onerror = (error) => this.onConnError(error);
this.conn.onmessage = (event) => this.onConnMessage(event);
this.conn.onclose = (event) => this.onConnClose(event);
}
log(kind, msg, data) {
this.logger(kind, msg, data);
}
hasLogger() {
return this.logger !== null;
}
onOpen(callback) {
let ref = this.makeRef();
this.stateChangeCallbacks.open.push([ref, callback]);
return ref;
}
onClose(callback) {
let ref = this.makeRef();
this.stateChangeCallbacks.close.push([ref, callback]);
return ref;
}
onError(callback) {
let ref = this.makeRef();
this.stateChangeCallbacks.error.push([ref, callback]);
return ref;
}
onMessage(callback) {
let ref = this.makeRef();
this.stateChangeCallbacks.message.push([ref, callback]);
return ref;
}
onConnOpen() {
if (this.hasLogger())
this.log("transport", `connected to ${this.endPointURL()}`);
this.closeWasClean = false;
this.establishedConnections++;
this.flushSendBuffer();
this.reconnectTimer.reset();
this.resetHeartbeat();
this.stateChangeCallbacks.open.forEach(([, callback]) => callback());
}
heartbeatTimeout() {
if (this.pendingHeartbeatRef) {
this.pendingHeartbeatRef = null;
if (this.hasLogger()) {
this.log("transport", "heartbeat timeout. Attempting to re-establish connection");
}
this.abnormalClose("heartbeat timeout");
}
}
resetHeartbeat() {
if (this.conn && this.conn.skipHeartbeat) {
return;
}
this.pendingHeartbeatRef = null;
clearTimeout(this.heartbeatTimer);
setTimeout(() => this.sendHeartbeat(), this.heartbeatIntervalMs);
}
teardown(callback, code, reason) {
if (!this.conn) {
return callback && callback();
}
this.waitForBufferDone(() => {
if (this.conn) {
if (code) {
this.conn.close(code, reason || "");
} else {
this.conn.close();
}
}
this.waitForSocketClosed(() => {
if (this.conn) {
this.conn.onclose = function() {
};
this.conn = null;
}
callback && callback();
});
});
}
waitForBufferDone(callback, tries = 1) {
if (tries === 5 || !this.conn || !this.conn.bufferedAmount) {
callback();
return;
}
setTimeout(() => {
this.waitForBufferDone(callback, tries + 1);
}, 150 * tries);
}
waitForSocketClosed(callback, tries = 1) {
if (tries === 5 || !this.conn || this.conn.readyState === SOCKET_STATES.closed) {
callback();
return;
}
setTimeout(() => {
this.waitForSocketClosed(callback, tries + 1);
}, 150 * tries);
}
onConnClose(event) {
if (this.hasLogger())
this.log("transport", "close", event);
this.triggerChanError();
clearTimeout(this.heartbeatTimer);
if (!this.closeWasClean) {
this.reconnectTimer.scheduleTimeout();
}
this.stateChangeCallbacks.close.forEach(([, callback]) => callback(event));
}
onConnError(error) {
if (this.hasLogger())
this.log("transport", error);
let transportBefore = this.transport;
let establishedBefore = this.establishedConnections;
this.stateChangeCallbacks.error.forEach(([, callback]) => {
callback(error, transportBefore, establishedBefore);
});
if (transportBefore === this.transport || establishedBefore > 0) {
this.triggerChanError();
}
}
triggerChanError() {
this.channels.forEach((channel) => {
if (!(channel.isErrored() || channel.isLeaving() || channel.isClosed())) {
channel.trigger(CHANNEL_EVENTS.error);
}
});
}
connectionState() {
switch (this.conn && this.conn.readyState) {
case SOCKET_STATES.connecting:
return "connecting";
case SOCKET_STATES.open:
return "open";
case SOCKET_STATES.closing:
return "closing";
default:
return "closed";
}
}
isConnected() {
return this.connectionState() === "open";
}
remove(channel) {
this.off(channel.stateChangeRefs);
this.channels = this.channels.filter((c) => c.joinRef() !== channel.joinRef());
}
off(refs) {
for (let key in this.stateChangeCallbacks) {
this.stateChangeCallbacks[key] = this.stateChangeCallbacks[key].filter(([ref]) => {
return refs.indexOf(ref) === -1;
});
}
}
channel(topic, chanParams = {}) {
let chan = new Channel(topic, chanParams, this);
this.channels.push(chan);
return chan;
}
push(data) {
if (this.hasLogger()) {
let { topic, event, payload, ref, join_ref } = data;
this.log("push", `${topic} ${event} (${join_ref}, ${ref})`, payload);
}
if (this.isConnected()) {
this.encode(data, (result) => this.conn.send(result));
} else {
this.sendBuffer.push(() => this.encode(data, (result) => this.conn.send(result)));
}
}
makeRef() {
let newRef = this.ref + 1;
if (newRef === this.ref) {
this.ref = 0;
} else {
this.ref = newRef;
}
return this.ref.toString();
}
sendHeartbeat() {
if (this.pendingHeartbeatRef && !this.isConnected()) {
return;
}
this.pendingHeartbeatRef = this.makeRef();
this.push({ topic: "phoenix", event: "heartbeat", payload: {}, ref: this.pendingHeartbeatRef });
this.heartbeatTimer = setTimeout(() => this.heartbeatTimeout(), this.heartbeatIntervalMs);
}
abnormalClose(reason) {
this.closeWasClean = false;
if (this.isConnected()) {
this.conn.close(WS_CLOSE_NORMAL, reason);
}
}
flushSendBuffer() {
if (this.isConnected() && this.sendBuffer.length > 0) {
this.sendBuffer.forEach((callback) => callback());
this.sendBuffer = [];
}
}
onConnMessage(rawMessage) {
this.decode(rawMessage.data, (msg) => {
let { topic, event, payload, ref, join_ref } = msg;
if (ref && ref === this.pendingHeartbeatRef) {
clearTimeout(this.heartbeatTimer);
this.pendingHeartbeatRef = null;
setTimeout(() => this.sendHeartbeat(), this.heartbeatIntervalMs);
}
if (this.hasLogger())
this.log("receive", `${payload.status || ""} ${topic} ${event} ${ref && "(" + ref + ")" || ""}`, payload);
for (let i = 0; i < this.channels.length; i++) {
const channel = this.channels[i];
if (!channel.isMember(topic, event, payload, join_ref)) {
continue;
}
channel.trigger(event, payload, ref, join_ref);
}
for (let i = 0; i < this.stateChangeCallbacks.message.length; i++) {
let [, callback] = this.stateChangeCallbacks.message[i];
callback(msg);
}
});
}
leaveOpenTopic(topic) {
let dupChannel = this.channels.find((c) => c.topic === topic && (c.isJoined() || c.isJoining()));
if (dupChannel) {
if (this.hasLogger())
this.log("transport", `leaving duplicate topic "${topic}"`);
dupChannel.leave();
}
}
};
return phoenix_exports;
})();
![phoenix logo](https://raw.githubusercontent.com/phoenixframework/phoenix/master/priv/static/phoenix.png)
> Peace of mind from prototype to production.
[![Build Status](https://api.travis-ci.org/phoenixframework/phoenix.svg?branch=master)](https://travis-ci.org/phoenixframework/phoenix)
[![Inline docs](http://inch-ci.org/github/phoenixframework/phoenix.svg)](http://inch-ci.org/github/phoenixframework/phoenix)
[![Build Status](https://github.com/phoenixframework/phoenix/workflows/CI/badge.svg)](https://github.com/phoenixframework/phoenix/actions?query=workflow%3ACI)

@@ -21,3 +20,3 @@ ## Getting started

We appreciate any contribution to Phoenix. Check our [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) and [CONTRIBUTING.md](CONTRIBUTING.md) guides for more information. We usually keep a list of features and bugs [in the issue tracker][4].
We appreciate any contribution to Phoenix. Check our [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) and [CONTRIBUTING.md](CONTRIBUTING.md) guides for more information. We usually keep a list of features and bugs in the [issue tracker][4].

@@ -30,6 +29,6 @@ ### Generating a Phoenix project from unreleased versions

2. Copy this repo via `git clone https://github.com/phoenixframework/phoenix` or by downloading it
3. Run the `phx.new` mix task from within the `installer` directory, for example:
3. Run the `phx.new` Mix task from within the `installer` directory, for example:
```bash
$ cd installer
$ cd phoenix/installer
$ mix phx.new dev_app --dev

@@ -79,4 +78,4 @@ ```

* [#elixir-lang][1] on [Freenode][2] IRC
* [elixir-lang slack channel][3]
* [#elixir][1] on [Libera][2] IRC
* [elixir-lang Slack channel][3]
* [Issue tracker][4]

@@ -88,4 +87,4 @@ * [Phoenix Forum (questions)][5]

[1]: https://webchat.freenode.net/?channels=#elixir-lang
[2]: http://www.freenode.net/
[1]: https://web.libera.chat/?channels=#elixir
[2]: https://libera.chat/
[3]: https://elixir-slackin.herokuapp.com/

@@ -92,0 +91,0 @@ [4]: https://github.com/phoenixframework/phoenix/issues

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc