@cendarsoss/pusher-js 8.4.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (425) hide show
  1. package/.editorconfig +14 -0
  2. package/.github/ISSUE_TEMPLATE.md +11 -0
  3. package/.github/PULL_REQUEST_TEMPLATE.md +14 -0
  4. package/.github/dependabot.yml +14 -0
  5. package/.github/stale.yml +26 -0
  6. package/.github/workflows/release.yml +112 -0
  7. package/.github/workflows/release_pr.yml +43 -0
  8. package/.github/workflows/run-tests.yml +62 -0
  9. package/.gitmodules +3 -0
  10. package/.prettierrc +2 -0
  11. package/CHANGELOG.md +928 -0
  12. package/DELTA_COMPRESSION.md +365 -0
  13. package/DELTA_USAGE.md +179 -0
  14. package/IMPLEMENTATION_SUMMARY.md +261 -0
  15. package/IMPORT_GUIDE.md +638 -0
  16. package/LIBRARY_STRUCTURE_ANALYSIS.md +940 -0
  17. package/LICENCE +19 -0
  18. package/Makefile +14 -0
  19. package/README.md +709 -0
  20. package/TAG_FILTERING_CLIENT.md +471 -0
  21. package/bower.json +19 -0
  22. package/bun.lock +2695 -0
  23. package/dist/node/filter.js +252 -0
  24. package/dist/node/filter.js.map +1 -0
  25. package/dist/node/pusher.js +4434 -0
  26. package/dist/node/pusher.js.map +1 -0
  27. package/dist/web/filter.mjs +252 -0
  28. package/dist/web/filter.mjs.map +1 -0
  29. package/dist/web/pusher.mjs +5889 -0
  30. package/dist/web/pusher.mjs.map +1 -0
  31. package/examples/delta-compression-example.html +372 -0
  32. package/examples/delta-seamless-example.html +185 -0
  33. package/index.d.ts +36 -0
  34. package/integration_tests_server/index.js +176 -0
  35. package/integration_tests_server/package-lock.json +1177 -0
  36. package/integration_tests_server/package.json +15 -0
  37. package/interactive/.env +16 -0
  38. package/interactive/CONFLATION_TEST.md +73 -0
  39. package/interactive/DELTA_COMPRESSION_TESTING.md +262 -0
  40. package/interactive/bun.lock +208 -0
  41. package/interactive/package-lock.json +1075 -0
  42. package/interactive/package.json +32 -0
  43. package/interactive/public/app.js +1363 -0
  44. package/interactive/public/bundle-entry.js +14 -0
  45. package/interactive/public/conflation-test.html +508 -0
  46. package/interactive/public/conflation-test.js +785 -0
  47. package/interactive/public/delta-compression.js +1090 -0
  48. package/interactive/public/dist/bundle.js +5857 -0
  49. package/interactive/public/index.html +392 -0
  50. package/interactive/public/main.js +20 -0
  51. package/interactive/public/style.css +823 -0
  52. package/interactive/server.js +246 -0
  53. package/interactive/test-bundle.html +89 -0
  54. package/interactive/test-delta.js +146 -0
  55. package/node.js +1 -0
  56. package/package.json +94 -0
  57. package/pusher-with-encryption/index.js +1 -0
  58. package/react-native/index.d.ts +29 -0
  59. package/react-native/index.js +1 -0
  60. package/spec/config/jasmine/helpers/reporter.js +14 -0
  61. package/spec/config/jasmine/integration.json +13 -0
  62. package/spec/config/jasmine/unit.json +13 -0
  63. package/spec/config/jasmine/webpack.integration.js +33 -0
  64. package/spec/config/jasmine/webpack.unit.js +30 -0
  65. package/spec/config/karma/available_browsers.json +4957 -0
  66. package/spec/config/karma/config.ci.js +25 -0
  67. package/spec/config/karma/config.common.js +50 -0
  68. package/spec/config/karma/config.integration.js +26 -0
  69. package/spec/config/karma/config.unit.js +10 -0
  70. package/spec/config/karma/config.worker.js +34 -0
  71. package/spec/config/karma/integration.js +24 -0
  72. package/spec/config/karma/unit.js +20 -0
  73. package/spec/javascripts/helpers/mocks.js +274 -0
  74. package/spec/javascripts/helpers/node/integration.js +33 -0
  75. package/spec/javascripts/helpers/node/mock-dom-dependencies.ts +1 -0
  76. package/spec/javascripts/helpers/pusher_integration.js +1 -0
  77. package/spec/javascripts/helpers/pusher_integration_class.ts +12 -0
  78. package/spec/javascripts/helpers/timers/promises.js +9 -0
  79. package/spec/javascripts/helpers/waitsFor.js +37 -0
  80. package/spec/javascripts/helpers/web/integration.js +44 -0
  81. package/spec/javascripts/helpers/worker/mock-dom-dependencies.js +1 -0
  82. package/spec/javascripts/integration/core/cluster_config_spec.js +153 -0
  83. package/spec/javascripts/integration/core/falling_back_spec.js +195 -0
  84. package/spec/javascripts/integration/core/pusher_spec/index.js +68 -0
  85. package/spec/javascripts/integration/core/pusher_spec/test_builder.js +715 -0
  86. package/spec/javascripts/integration/core/timeout_configuration_spec.js +200 -0
  87. package/spec/javascripts/integration/core/transport_lists_spec.js +103 -0
  88. package/spec/javascripts/integration/index.node.js +12 -0
  89. package/spec/javascripts/integration/index.web.js +63 -0
  90. package/spec/javascripts/integration/index.worker.js +13 -0
  91. package/spec/javascripts/integration/web/dom/jsonp_spec.js +97 -0
  92. package/spec/javascripts/integration/web/dom/script_request_spec.js +90 -0
  93. package/spec/javascripts/polyfills/index.js +105 -0
  94. package/spec/javascripts/unit/core/channels/channel_spec.js +355 -0
  95. package/spec/javascripts/unit/core/channels/channels_spec.js +94 -0
  96. package/spec/javascripts/unit/core/channels/encrypted_channel_spec.js +343 -0
  97. package/spec/javascripts/unit/core/channels/presence_channel_spec.js +553 -0
  98. package/spec/javascripts/unit/core/channels/private_channel_spec.js +182 -0
  99. package/spec/javascripts/unit/core/config_spec.js +507 -0
  100. package/spec/javascripts/unit/core/connection/connection_manager_spec.js +656 -0
  101. package/spec/javascripts/unit/core/connection/connection_spec.js +286 -0
  102. package/spec/javascripts/unit/core/connection/handshake_spec.js +160 -0
  103. package/spec/javascripts/unit/core/connection/protocol_spec.js +420 -0
  104. package/spec/javascripts/unit/core/defaults_spec.js +26 -0
  105. package/spec/javascripts/unit/core/events_dispatcher_spec.js +385 -0
  106. package/spec/javascripts/unit/core/http/http_polling_socket_spec.js +60 -0
  107. package/spec/javascripts/unit/core/http/http_request_spec.js +185 -0
  108. package/spec/javascripts/unit/core/http/http_socket_spec.js +370 -0
  109. package/spec/javascripts/unit/core/http/http_streaming_socket_spec.js +56 -0
  110. package/spec/javascripts/unit/core/http/http_xhr_request_spec.js +164 -0
  111. package/spec/javascripts/unit/core/logger_spec.js +133 -0
  112. package/spec/javascripts/unit/core/pusher_spec.js +613 -0
  113. package/spec/javascripts/unit/core/pusher_with_encryption_spec.js +18 -0
  114. package/spec/javascripts/unit/core/strategies/best_connected_ever_strategy_spec.js +104 -0
  115. package/spec/javascripts/unit/core/strategies/delayed_strategy_spec.js +95 -0
  116. package/spec/javascripts/unit/core/strategies/first_connected_strategy_spec.js +68 -0
  117. package/spec/javascripts/unit/core/strategies/if_strategy_spec.js +165 -0
  118. package/spec/javascripts/unit/core/strategies/sequential_strategy_spec.js +213 -0
  119. package/spec/javascripts/unit/core/strategies/transport_strategy_spec.js +250 -0
  120. package/spec/javascripts/unit/core/strategies/websocket_prioritized_cached_strategy_spec.js +400 -0
  121. package/spec/javascripts/unit/core/timeline/timeline_spec.js +153 -0
  122. package/spec/javascripts/unit/core/transports/assistant_to_the_transport_manager_spec.js +223 -0
  123. package/spec/javascripts/unit/core/transports/hosts_and_ports_spec.js +85 -0
  124. package/spec/javascripts/unit/core/transports/transport_connection_spec.js +585 -0
  125. package/spec/javascripts/unit/core/transports/transport_manager_spec.js +64 -0
  126. package/spec/javascripts/unit/core/user_spec.js +303 -0
  127. package/spec/javascripts/unit/core/utils/periodic_timer_spec.js +74 -0
  128. package/spec/javascripts/unit/core/utils/timers_spec.js +157 -0
  129. package/spec/javascripts/unit/core/utils/url_store_spec.js +14 -0
  130. package/spec/javascripts/unit/core/watchlist_spec.js +48 -0
  131. package/spec/javascripts/unit/core_with_runtime/auth/channel_authorizer_spec.js +137 -0
  132. package/spec/javascripts/unit/core_with_runtime/auth/deprecated_channel_authorizer_spec.js +48 -0
  133. package/spec/javascripts/unit/core_with_runtime/auth/user_authorizer_spec.js +128 -0
  134. package/spec/javascripts/unit/core_with_runtime/readme.md +5 -0
  135. package/spec/javascripts/unit/index.node.js +11 -0
  136. package/spec/javascripts/unit/index.web.js +12 -0
  137. package/spec/javascripts/unit/index.worker.js +11 -0
  138. package/spec/javascripts/unit/isomorphic/transports/hosts_and_ports_spec.js +82 -0
  139. package/spec/javascripts/unit/isomorphic/transports/transports_spec.js +202 -0
  140. package/spec/javascripts/unit/node/timeline_sender_spec.js +83 -0
  141. package/spec/javascripts/unit/web/dom/dependency_loader_spec.js +249 -0
  142. package/spec/javascripts/unit/web/dom/jsonp_request_spec.js +130 -0
  143. package/spec/javascripts/unit/web/dom/script_receiver_factory_spec.js +68 -0
  144. package/spec/javascripts/unit/web/http/http_xdomain_request_spec.js +222 -0
  145. package/spec/javascripts/unit/web/pusher_authorizer_spec.js +64 -0
  146. package/spec/javascripts/unit/web/timeline/timeline_sender_spec.js +131 -0
  147. package/spec/javascripts/unit/web/transports/hosts_and_ports_spec.js +127 -0
  148. package/spec/javascripts/unit/web/transports/transports_spec.js +444 -0
  149. package/spec/javascripts/unit/worker/channel_authorizer_spec.js +156 -0
  150. package/spec/javascripts/unit/worker/timeline_sender_spec.js +76 -0
  151. package/src/core/auth/auth_transports.ts +18 -0
  152. package/src/core/auth/channel_authorizer.ts +64 -0
  153. package/src/core/auth/deprecated_channel_authorizer.ts +56 -0
  154. package/src/core/auth/options.ts +76 -0
  155. package/src/core/auth/user_authenticator.ts +62 -0
  156. package/src/core/base64.ts +49 -0
  157. package/src/core/channels/channel.ts +173 -0
  158. package/src/core/channels/channel_table.ts +7 -0
  159. package/src/core/channels/channels.ts +86 -0
  160. package/src/core/channels/encrypted_channel.ts +150 -0
  161. package/src/core/channels/filter.ts +342 -0
  162. package/src/core/channels/members.ts +80 -0
  163. package/src/core/channels/metadata.ts +5 -0
  164. package/src/core/channels/presence_channel.ts +113 -0
  165. package/src/core/channels/private_channel.ts +25 -0
  166. package/src/core/config.ts +189 -0
  167. package/src/core/connection/callbacks.ts +21 -0
  168. package/src/core/connection/connection.ts +160 -0
  169. package/src/core/connection/connection_manager.ts +371 -0
  170. package/src/core/connection/connection_manager_options.ts +14 -0
  171. package/src/core/connection/handshake/handshake_payload.ts +10 -0
  172. package/src/core/connection/handshake/index.ts +90 -0
  173. package/src/core/connection/protocol/action.ts +8 -0
  174. package/src/core/connection/protocol/message-types.ts +11 -0
  175. package/src/core/connection/protocol/protocol.ts +166 -0
  176. package/src/core/defaults.ts +66 -0
  177. package/src/core/delta/channel_state.ts +194 -0
  178. package/src/core/delta/decoders.ts +129 -0
  179. package/src/core/delta/index.ts +10 -0
  180. package/src/core/delta/manager.ts +504 -0
  181. package/src/core/delta/types.ts +60 -0
  182. package/src/core/errors.ts +69 -0
  183. package/src/core/events/callback.ts +6 -0
  184. package/src/core/events/callback_registry.ts +75 -0
  185. package/src/core/events/callback_table.ts +7 -0
  186. package/src/core/events/dispatcher.ts +84 -0
  187. package/src/core/http/ajax.ts +24 -0
  188. package/src/core/http/http_factory.ts +16 -0
  189. package/src/core/http/http_polling_socket.ts +24 -0
  190. package/src/core/http/http_request.ts +81 -0
  191. package/src/core/http/http_socket.ts +220 -0
  192. package/src/core/http/http_streaming_socket.ts +19 -0
  193. package/src/core/http/request_hooks.ts +9 -0
  194. package/src/core/http/socket_hooks.ts +11 -0
  195. package/src/core/http/state.ts +7 -0
  196. package/src/core/http/url_location.ts +6 -0
  197. package/src/core/logger.ts +66 -0
  198. package/src/core/options.ts +61 -0
  199. package/src/core/pusher-licence.js +7 -0
  200. package/src/core/pusher-with-encryption.js +1 -0
  201. package/src/core/pusher-with-encryption.ts +14 -0
  202. package/src/core/pusher.js +10 -0
  203. package/src/core/pusher.ts +412 -0
  204. package/src/core/reachability.ts +7 -0
  205. package/src/core/socket.ts +14 -0
  206. package/src/core/strategies/best_connected_ever_strategy.ts +81 -0
  207. package/src/core/strategies/delayed_strategy.ts +48 -0
  208. package/src/core/strategies/first_connected_strategy.ts +31 -0
  209. package/src/core/strategies/if_strategy.ts +34 -0
  210. package/src/core/strategies/sequential_strategy.ts +129 -0
  211. package/src/core/strategies/strategy.ts +8 -0
  212. package/src/core/strategies/strategy_builder.ts +67 -0
  213. package/src/core/strategies/strategy_options.ts +18 -0
  214. package/src/core/strategies/strategy_runner.ts +6 -0
  215. package/src/core/strategies/transport_strategy.ts +144 -0
  216. package/src/core/strategies/websocket_prioritized_cached_strategy.ts +157 -0
  217. package/src/core/timeline/level.ts +7 -0
  218. package/src/core/timeline/timeline.ts +90 -0
  219. package/src/core/timeline/timeline_sender.ts +33 -0
  220. package/src/core/timeline/timeline_transport.ts +11 -0
  221. package/src/core/transports/assistant_to_the_transport_manager.ts +104 -0
  222. package/src/core/transports/ping_delay_options.ts +7 -0
  223. package/src/core/transports/transport.ts +54 -0
  224. package/src/core/transports/transport_connection.ts +241 -0
  225. package/src/core/transports/transport_connection_options.ts +8 -0
  226. package/src/core/transports/transport_hooks.ts +16 -0
  227. package/src/core/transports/transport_manager.ts +52 -0
  228. package/src/core/transports/transports_table.ts +12 -0
  229. package/src/core/transports/url_scheme.ts +13 -0
  230. package/src/core/transports/url_schemes.ts +47 -0
  231. package/src/core/user.ts +186 -0
  232. package/src/core/util.ts +34 -0
  233. package/src/core/utils/collections.ts +353 -0
  234. package/src/core/utils/factory.ts +79 -0
  235. package/src/core/utils/flat_promise.ts +10 -0
  236. package/src/core/utils/timers/abstract_timer.ts +39 -0
  237. package/src/core/utils/timers/index.ts +39 -0
  238. package/src/core/utils/timers/scheduling.ts +11 -0
  239. package/src/core/utils/timers/timed_callback.ts +5 -0
  240. package/src/core/utils/url_store.ts +48 -0
  241. package/src/core/watchlist.ts +31 -0
  242. package/src/d.ts/constants/index.d.ts +5 -0
  243. package/src/d.ts/faye-websocket/faye-websocket.d.ts +21 -0
  244. package/src/d.ts/global/global.d.ts +1 -0
  245. package/src/d.ts/module/module.d.ts +12 -0
  246. package/src/d.ts/tweetnacl-util/index.d.ts +6 -0
  247. package/src/d.ts/window/events.d.ts +4 -0
  248. package/src/d.ts/window/sockjs.d.ts +3 -0
  249. package/src/d.ts/window/websocket.d.ts +4 -0
  250. package/src/d.ts/window/xmlhttprequest.d.ts +3 -0
  251. package/src/filter.ts +5 -0
  252. package/src/index.ts +8 -0
  253. package/src/runtimes/interface.ts +60 -0
  254. package/src/runtimes/isomorphic/auth/xhr_auth.ts +90 -0
  255. package/src/runtimes/isomorphic/default_strategy.ts +155 -0
  256. package/src/runtimes/isomorphic/http/http.ts +32 -0
  257. package/src/runtimes/isomorphic/http/http_xhr_request.ts +35 -0
  258. package/src/runtimes/isomorphic/runtime.ts +62 -0
  259. package/src/runtimes/isomorphic/timeline/xhr_timeline.ts +50 -0
  260. package/src/runtimes/isomorphic/transports/transport_connection_initializer.ts +19 -0
  261. package/src/runtimes/isomorphic/transports/transports.ts +83 -0
  262. package/src/runtimes/node/net_info.ts +10 -0
  263. package/src/runtimes/node/runtime.ts +68 -0
  264. package/src/runtimes/react-native/net_info.ts +42 -0
  265. package/src/runtimes/react-native/runtime.ts +65 -0
  266. package/src/runtimes/web/auth/jsonp_auth.ts +51 -0
  267. package/src/runtimes/web/browser.ts +24 -0
  268. package/src/runtimes/web/default_strategy.ts +201 -0
  269. package/src/runtimes/web/dom/dependencies.ts +16 -0
  270. package/src/runtimes/web/dom/dependency_loader.ts +93 -0
  271. package/src/runtimes/web/dom/json2.js +486 -0
  272. package/src/runtimes/web/dom/jsonp_request.ts +52 -0
  273. package/src/runtimes/web/dom/script_receiver.ts +8 -0
  274. package/src/runtimes/web/dom/script_receiver_factory.ts +57 -0
  275. package/src/runtimes/web/dom/script_request.ts +85 -0
  276. package/src/runtimes/web/http/http.ts +8 -0
  277. package/src/runtimes/web/http/http_xdomain_request.ts +37 -0
  278. package/src/runtimes/web/net_info.ts +50 -0
  279. package/src/runtimes/web/runtime.ts +174 -0
  280. package/src/runtimes/web/timeline/jsonp_timeline.ts +34 -0
  281. package/src/runtimes/web/transports/transport_connection_initializer.ts +39 -0
  282. package/src/runtimes/web/transports/transports.ts +67 -0
  283. package/src/runtimes/worker/auth/fetch_auth.ts +69 -0
  284. package/src/runtimes/worker/net_info.ts +10 -0
  285. package/src/runtimes/worker/runtime.ts +75 -0
  286. package/src/runtimes/worker/timeline/fetch_timeline.ts +39 -0
  287. package/tsconfig.json +18 -0
  288. package/types/spec/javascripts/helpers/node/mock-dom-dependencies.d.ts +1 -0
  289. package/types/spec/javascripts/helpers/pusher_integration_class.d.ts +4 -0
  290. package/types/src/core/auth/auth_transports.d.ts +9 -0
  291. package/types/src/core/auth/channel_authorizer.d.ts +3 -0
  292. package/types/src/core/auth/deprecated_channel_authorizer.d.ts +18 -0
  293. package/types/src/core/auth/options.d.ts +48 -0
  294. package/types/src/core/auth/user_authenticator.d.ts +3 -0
  295. package/types/src/core/base64.d.ts +1 -0
  296. package/types/src/core/channels/channel.d.ts +25 -0
  297. package/types/src/core/channels/channel_table.d.ts +5 -0
  298. package/types/src/core/channels/channels.d.ts +12 -0
  299. package/types/src/core/channels/encrypted_channel.d.ts +15 -0
  300. package/types/src/core/channels/filter.d.ts +33 -0
  301. package/types/src/core/channels/members.d.ts +14 -0
  302. package/types/src/core/channels/metadata.d.ts +4 -0
  303. package/types/src/core/channels/presence_channel.d.ts +13 -0
  304. package/types/src/core/channels/private_channel.d.ts +5 -0
  305. package/types/src/core/config.d.ts +31 -0
  306. package/types/src/core/connection/callbacks.d.ts +18 -0
  307. package/types/src/core/connection/connection.d.ts +16 -0
  308. package/types/src/core/connection/connection_manager.d.ts +50 -0
  309. package/types/src/core/connection/connection_manager_options.d.ts +11 -0
  310. package/types/src/core/connection/handshake/handshake_payload.d.ts +8 -0
  311. package/types/src/core/connection/handshake/index.d.ts +12 -0
  312. package/types/src/core/connection/protocol/action.d.ts +7 -0
  313. package/types/src/core/connection/protocol/message-types.d.ts +10 -0
  314. package/types/src/core/connection/protocol/protocol.d.ts +10 -0
  315. package/types/src/core/defaults.d.ts +26 -0
  316. package/types/src/core/delta/channel_state.d.ts +23 -0
  317. package/types/src/core/delta/decoders.d.ts +12 -0
  318. package/types/src/core/delta/index.d.ts +4 -0
  319. package/types/src/core/delta/manager.d.ts +27 -0
  320. package/types/src/core/delta/types.d.ts +50 -0
  321. package/types/src/core/errors.d.ts +28 -0
  322. package/types/src/core/events/callback.d.ts +5 -0
  323. package/types/src/core/events/callback_registry.d.ts +11 -0
  324. package/types/src/core/events/callback_table.d.ts +5 -0
  325. package/types/src/core/events/dispatcher.d.ts +14 -0
  326. package/types/src/core/http/ajax.d.ts +16 -0
  327. package/types/src/core/http/http_factory.d.ts +13 -0
  328. package/types/src/core/http/http_polling_socket.d.ts +3 -0
  329. package/types/src/core/http/http_request.d.ts +17 -0
  330. package/types/src/core/http/http_socket.d.ts +32 -0
  331. package/types/src/core/http/http_streaming_socket.d.ts +3 -0
  332. package/types/src/core/http/request_hooks.d.ts +6 -0
  333. package/types/src/core/http/socket_hooks.d.ts +8 -0
  334. package/types/src/core/http/state.d.ts +6 -0
  335. package/types/src/core/http/url_location.d.ts +5 -0
  336. package/types/src/core/logger.d.ts +11 -0
  337. package/types/src/core/options.d.ts +36 -0
  338. package/types/src/core/pusher-with-encryption.d.ts +5 -0
  339. package/types/src/core/pusher.d.ts +56 -0
  340. package/types/src/core/reachability.d.ts +5 -0
  341. package/types/src/core/socket.d.ts +12 -0
  342. package/types/src/core/strategies/best_connected_ever_strategy.d.ts +10 -0
  343. package/types/src/core/strategies/delayed_strategy.d.ts +15 -0
  344. package/types/src/core/strategies/first_connected_strategy.d.ts +8 -0
  345. package/types/src/core/strategies/if_strategy.d.ts +10 -0
  346. package/types/src/core/strategies/sequential_strategy.d.ts +16 -0
  347. package/types/src/core/strategies/strategy.d.ts +6 -0
  348. package/types/src/core/strategies/strategy_builder.d.ts +5 -0
  349. package/types/src/core/strategies/strategy_options.d.ts +16 -0
  350. package/types/src/core/strategies/strategy_runner.d.ts +5 -0
  351. package/types/src/core/strategies/transport_strategy.d.ts +15 -0
  352. package/types/src/core/strategies/websocket_prioritized_cached_strategy.d.ts +20 -0
  353. package/types/src/core/timeline/level.d.ts +6 -0
  354. package/types/src/core/timeline/timeline.d.ts +25 -0
  355. package/types/src/core/timeline/timeline_sender.d.ts +13 -0
  356. package/types/src/core/timeline/timeline_transport.d.ts +6 -0
  357. package/types/src/core/transports/assistant_to_the_transport_manager.d.ts +14 -0
  358. package/types/src/core/transports/ping_delay_options.d.ts +6 -0
  359. package/types/src/core/transports/transport.d.ts +8 -0
  360. package/types/src/core/transports/transport_connection.d.ts +35 -0
  361. package/types/src/core/transports/transport_connection_options.d.ts +6 -0
  362. package/types/src/core/transports/transport_hooks.d.ts +13 -0
  363. package/types/src/core/transports/transport_manager.d.ts +14 -0
  364. package/types/src/core/transports/transports_table.d.ts +10 -0
  365. package/types/src/core/transports/url_scheme.d.ts +11 -0
  366. package/types/src/core/transports/url_schemes.d.ts +4 -0
  367. package/types/src/core/user.d.ts +21 -0
  368. package/types/src/core/util.d.ts +8 -0
  369. package/types/src/core/utils/collections.d.ts +18 -0
  370. package/types/src/core/utils/factory.d.ts +29 -0
  371. package/types/src/core/utils/flat_promise.d.ts +6 -0
  372. package/types/src/core/utils/timers/abstract_timer.d.ts +10 -0
  373. package/types/src/core/utils/timers/index.d.ts +9 -0
  374. package/types/src/core/utils/timers/scheduling.d.ts +8 -0
  375. package/types/src/core/utils/timers/timed_callback.d.ts +4 -0
  376. package/types/src/core/utils/url_store.d.ts +4 -0
  377. package/types/src/core/watchlist.d.ts +8 -0
  378. package/types/src/runtimes/interface.d.ts +43 -0
  379. package/types/src/runtimes/isomorphic/auth/xhr_auth.d.ts +3 -0
  380. package/types/src/runtimes/isomorphic/default_strategy.d.ts +5 -0
  381. package/types/src/runtimes/isomorphic/http/http.d.ts +3 -0
  382. package/types/src/runtimes/isomorphic/http/http_xhr_request.d.ts +3 -0
  383. package/types/src/runtimes/isomorphic/runtime.d.ts +2 -0
  384. package/types/src/runtimes/isomorphic/timeline/xhr_timeline.d.ts +6 -0
  385. package/types/src/runtimes/isomorphic/transports/transport_connection_initializer.d.ts +1 -0
  386. package/types/src/runtimes/isomorphic/transports/transports.d.ts +5 -0
  387. package/types/src/runtimes/node/net_info.d.ts +6 -0
  388. package/types/src/runtimes/node/runtime.d.ts +3 -0
  389. package/types/src/runtimes/react-native/net_info.d.ts +8 -0
  390. package/types/src/runtimes/react-native/runtime.d.ts +3 -0
  391. package/types/src/runtimes/web/auth/jsonp_auth.d.ts +3 -0
  392. package/types/src/runtimes/web/browser.d.ts +19 -0
  393. package/types/src/runtimes/web/default_strategy.d.ts +5 -0
  394. package/types/src/runtimes/web/dom/dependencies.d.ts +4 -0
  395. package/types/src/runtimes/web/dom/dependency_loader.d.ts +10 -0
  396. package/types/src/runtimes/web/dom/jsonp_request.d.ts +10 -0
  397. package/types/src/runtimes/web/dom/script_receiver.d.ts +7 -0
  398. package/types/src/runtimes/web/dom/script_receiver_factory.d.ts +10 -0
  399. package/types/src/runtimes/web/dom/script_request.d.ts +9 -0
  400. package/types/src/runtimes/web/http/http.d.ts +2 -0
  401. package/types/src/runtimes/web/http/http_xdomain_request.d.ts +3 -0
  402. package/types/src/runtimes/web/net_info.d.ts +7 -0
  403. package/types/src/runtimes/web/runtime.d.ts +3 -0
  404. package/types/src/runtimes/web/timeline/jsonp_timeline.d.ts +6 -0
  405. package/types/src/runtimes/web/transports/transport_connection_initializer.d.ts +1 -0
  406. package/types/src/runtimes/web/transports/transports.d.ts +2 -0
  407. package/types/src/runtimes/worker/auth/fetch_auth.d.ts +3 -0
  408. package/types/src/runtimes/worker/net_info.d.ts +6 -0
  409. package/types/src/runtimes/worker/runtime.d.ts +3 -0
  410. package/types/src/runtimes/worker/timeline/fetch_timeline.d.ts +6 -0
  411. package/vite.config.js +52 -0
  412. package/vite.config.node.js +72 -0
  413. package/webpack/config.node.js +26 -0
  414. package/webpack/config.react-native.js +35 -0
  415. package/webpack/config.shared.js +50 -0
  416. package/webpack/config.web.js +36 -0
  417. package/webpack/config.worker.js +42 -0
  418. package/webpack/dev.server.js +17 -0
  419. package/webpack/hosting_config.js +6 -0
  420. package/with-encryption/index.d.ts +29 -0
  421. package/with-encryption/index.js +4 -0
  422. package/worker/index.d.ts +29 -0
  423. package/worker/index.js +1 -0
  424. package/worker/with-encryption/index.d.ts +29 -0
  425. package/worker/with-encryption/index.js +1 -0
@@ -0,0 +1,4434 @@
1
+ "use strict";
2
+ const utf8 = require("@stablelib/utf8");
3
+ const base64 = require("@stablelib/base64");
4
+ const fayeWebsocket = require("faye-websocket");
5
+ const xmlhttprequest = require("xmlhttprequest");
6
+ const crypto = require("crypto");
7
+ const fossilDelta = require("fossil-delta");
8
+ const vcdiffDecoder = require("@ably/vcdiff-decoder");
9
+ function encode(s) {
10
+ return btoa(utob(s));
11
+ }
12
+ var fromCharCode = String.fromCharCode;
13
+ var b64chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
14
+ var cb_utob = function(c) {
15
+ var cc = c.charCodeAt(0);
16
+ return cc < 128 ? c : cc < 2048 ? fromCharCode(192 | cc >>> 6) + fromCharCode(128 | cc & 63) : fromCharCode(224 | cc >>> 12 & 15) + fromCharCode(128 | cc >>> 6 & 63) + fromCharCode(128 | cc & 63);
17
+ };
18
+ var utob = function(u) {
19
+ return u.replace(/[^\x00-\x7F]/g, cb_utob);
20
+ };
21
+ var cb_encode = function(ccc) {
22
+ var padlen = [0, 2, 1][ccc.length % 3];
23
+ var ord = ccc.charCodeAt(0) << 16 | (ccc.length > 1 ? ccc.charCodeAt(1) : 0) << 8 | (ccc.length > 2 ? ccc.charCodeAt(2) : 0);
24
+ var chars = [
25
+ b64chars.charAt(ord >>> 18),
26
+ b64chars.charAt(ord >>> 12 & 63),
27
+ padlen >= 2 ? "=" : b64chars.charAt(ord >>> 6 & 63),
28
+ padlen >= 1 ? "=" : b64chars.charAt(ord & 63)
29
+ ];
30
+ return chars.join("");
31
+ };
32
+ var btoa = global.btoa || function(b) {
33
+ return b.replace(/[\s\S]{1,3}/g, cb_encode);
34
+ };
35
+ class Timer {
36
+ constructor(set, clear, delay, callback) {
37
+ this.clear = clear;
38
+ this.timer = set(() => {
39
+ if (this.timer) {
40
+ this.timer = callback(this.timer);
41
+ }
42
+ }, delay);
43
+ }
44
+ /** Returns whether the timer is still running.
45
+ *
46
+ * @return {Boolean}
47
+ */
48
+ isRunning() {
49
+ return this.timer !== null;
50
+ }
51
+ /** Aborts a timer when it's running. */
52
+ ensureAborted() {
53
+ if (this.timer) {
54
+ this.clear(this.timer);
55
+ this.timer = null;
56
+ }
57
+ }
58
+ }
59
+ function clearTimeout(timer) {
60
+ global.clearTimeout(timer);
61
+ }
62
+ function clearInterval(timer) {
63
+ global.clearInterval(timer);
64
+ }
65
+ class OneOffTimer extends Timer {
66
+ constructor(delay, callback) {
67
+ super(setTimeout, clearTimeout, delay, function(timer) {
68
+ callback();
69
+ return null;
70
+ });
71
+ }
72
+ }
73
+ class PeriodicTimer extends Timer {
74
+ constructor(delay, callback) {
75
+ super(setInterval, clearInterval, delay, function(timer) {
76
+ callback();
77
+ return timer;
78
+ });
79
+ }
80
+ }
81
+ var Util = {
82
+ now() {
83
+ if (Date.now) {
84
+ return Date.now();
85
+ } else {
86
+ return (/* @__PURE__ */ new Date()).valueOf();
87
+ }
88
+ },
89
+ defer(callback) {
90
+ return new OneOffTimer(0, callback);
91
+ },
92
+ /** Builds a function that will proxy a method call to its first argument.
93
+ *
94
+ * Allows partial application of arguments, so additional arguments are
95
+ * prepended to the argument list.
96
+ *
97
+ * @param {String} name method name
98
+ * @return {Function} proxy function
99
+ */
100
+ method(name, ...args) {
101
+ var boundArguments = Array.prototype.slice.call(arguments, 1);
102
+ return function(object) {
103
+ return object[name].apply(object, boundArguments.concat(arguments));
104
+ };
105
+ }
106
+ };
107
+ function extend(target, ...sources) {
108
+ for (var i = 0; i < sources.length; i++) {
109
+ var extensions = sources[i];
110
+ for (var property in extensions) {
111
+ if (extensions[property] && extensions[property].constructor && extensions[property].constructor === Object) {
112
+ target[property] = extend(target[property] || {}, extensions[property]);
113
+ } else {
114
+ target[property] = extensions[property];
115
+ }
116
+ }
117
+ }
118
+ return target;
119
+ }
120
+ function stringify() {
121
+ var m = ["Pusher"];
122
+ for (var i = 0; i < arguments.length; i++) {
123
+ if (typeof arguments[i] === "string") {
124
+ m.push(arguments[i]);
125
+ } else {
126
+ m.push(safeJSONStringify(arguments[i]));
127
+ }
128
+ }
129
+ return m.join(" : ");
130
+ }
131
+ function arrayIndexOf(array, item) {
132
+ var nativeIndexOf = Array.prototype.indexOf;
133
+ if (array === null) {
134
+ return -1;
135
+ }
136
+ if (nativeIndexOf && array.indexOf === nativeIndexOf) {
137
+ return array.indexOf(item);
138
+ }
139
+ for (var i = 0, l = array.length; i < l; i++) {
140
+ if (array[i] === item) {
141
+ return i;
142
+ }
143
+ }
144
+ return -1;
145
+ }
146
+ function objectApply(object, f) {
147
+ for (var key in object) {
148
+ if (Object.prototype.hasOwnProperty.call(object, key)) {
149
+ f(object[key], key, object);
150
+ }
151
+ }
152
+ }
153
+ function keys(object) {
154
+ var keys2 = [];
155
+ objectApply(object, function(_, key) {
156
+ keys2.push(key);
157
+ });
158
+ return keys2;
159
+ }
160
+ function values(object) {
161
+ var values2 = [];
162
+ objectApply(object, function(value) {
163
+ values2.push(value);
164
+ });
165
+ return values2;
166
+ }
167
+ function apply(array, f, context) {
168
+ for (var i = 0; i < array.length; i++) {
169
+ f.call(context || global, array[i], i, array);
170
+ }
171
+ }
172
+ function map(array, f) {
173
+ var result = [];
174
+ for (var i = 0; i < array.length; i++) {
175
+ result.push(f(array[i], i, array, result));
176
+ }
177
+ return result;
178
+ }
179
+ function mapObject(object, f) {
180
+ var result = {};
181
+ objectApply(object, function(value, key) {
182
+ result[key] = f(value);
183
+ });
184
+ return result;
185
+ }
186
+ function filter(array, test) {
187
+ test = test || function(value) {
188
+ return !!value;
189
+ };
190
+ var result = [];
191
+ for (var i = 0; i < array.length; i++) {
192
+ if (test(array[i], i, array, result)) {
193
+ result.push(array[i]);
194
+ }
195
+ }
196
+ return result;
197
+ }
198
+ function filterObject(object, test) {
199
+ var result = {};
200
+ objectApply(object, function(value, key) {
201
+ if (test && test(value, key, object, result) || Boolean(value)) {
202
+ result[key] = value;
203
+ }
204
+ });
205
+ return result;
206
+ }
207
+ function flatten(object) {
208
+ var result = [];
209
+ objectApply(object, function(value, key) {
210
+ result.push([key, value]);
211
+ });
212
+ return result;
213
+ }
214
+ function any(array, test) {
215
+ for (var i = 0; i < array.length; i++) {
216
+ if (test(array[i], i, array)) {
217
+ return true;
218
+ }
219
+ }
220
+ return false;
221
+ }
222
+ function all(array, test) {
223
+ for (var i = 0; i < array.length; i++) {
224
+ if (!test(array[i], i, array)) {
225
+ return false;
226
+ }
227
+ }
228
+ return true;
229
+ }
230
+ function encodeParamsObject(data) {
231
+ return mapObject(data, function(value) {
232
+ if (typeof value === "object") {
233
+ value = safeJSONStringify(value);
234
+ }
235
+ return encodeURIComponent(encode(value.toString()));
236
+ });
237
+ }
238
+ function buildQueryString(data) {
239
+ var params = filterObject(data, function(value) {
240
+ return value !== void 0;
241
+ });
242
+ var query = map(
243
+ flatten(encodeParamsObject(params)),
244
+ Util.method("join", "=")
245
+ ).join("&");
246
+ return query;
247
+ }
248
+ function decycleObject(object) {
249
+ var objects = [], paths = [];
250
+ return (function derez(value, path) {
251
+ var i, name, nu;
252
+ switch (typeof value) {
253
+ case "object":
254
+ if (!value) {
255
+ return null;
256
+ }
257
+ for (i = 0; i < objects.length; i += 1) {
258
+ if (objects[i] === value) {
259
+ return { $ref: paths[i] };
260
+ }
261
+ }
262
+ objects.push(value);
263
+ paths.push(path);
264
+ if (Object.prototype.toString.apply(value) === "[object Array]") {
265
+ nu = [];
266
+ for (i = 0; i < value.length; i += 1) {
267
+ nu[i] = derez(value[i], path + "[" + i + "]");
268
+ }
269
+ } else {
270
+ nu = {};
271
+ for (name in value) {
272
+ if (Object.prototype.hasOwnProperty.call(value, name)) {
273
+ nu[name] = derez(
274
+ value[name],
275
+ path + "[" + JSON.stringify(name) + "]"
276
+ );
277
+ }
278
+ }
279
+ }
280
+ return nu;
281
+ case "number":
282
+ case "string":
283
+ case "boolean":
284
+ return value;
285
+ }
286
+ })(object, "$");
287
+ }
288
+ function safeJSONStringify(source) {
289
+ try {
290
+ return JSON.stringify(source);
291
+ } catch (e) {
292
+ return JSON.stringify(decycleObject(source));
293
+ }
294
+ }
295
+ var Defaults = {
296
+ VERSION: "8.4.0",
297
+ PROTOCOL: 7,
298
+ wsPort: 80,
299
+ wssPort: 443,
300
+ wsPath: "",
301
+ // DEPRECATED: SockJS fallback parameters
302
+ httpHost: "sockjs.pusher.com",
303
+ httpPort: 80,
304
+ httpsPort: 443,
305
+ httpPath: "/pusher",
306
+ // DEPRECATED: Stats
307
+ stats_host: "stats.pusher.com",
308
+ // DEPRECATED: Other settings
309
+ authEndpoint: "/pusher/auth",
310
+ authTransport: "ajax",
311
+ activityTimeout: 12e4,
312
+ pongTimeout: 3e4,
313
+ unavailableTimeout: 1e4,
314
+ userAuthentication: {
315
+ endpoint: "/pusher/user-auth",
316
+ transport: "ajax"
317
+ },
318
+ channelAuthorization: {
319
+ endpoint: "/pusher/auth",
320
+ transport: "ajax"
321
+ }
322
+ };
323
+ function getGenericURL(baseScheme, params, path) {
324
+ var scheme = baseScheme + (params.useTLS ? "s" : "");
325
+ var host = params.useTLS ? params.hostTLS : params.hostNonTLS;
326
+ return scheme + "://" + host + path;
327
+ }
328
+ function getGenericPath(key, queryString) {
329
+ var path = "/app/" + key;
330
+ var query = "?protocol=" + Defaults.PROTOCOL + "&client=js&version=" + Defaults.VERSION + (queryString ? "&" + queryString : "");
331
+ return path + query;
332
+ }
333
+ var ws = {
334
+ getInitial: function(key, params) {
335
+ var path = (params.httpPath || "") + getGenericPath(key, "flash=false");
336
+ return getGenericURL("ws", params, path);
337
+ }
338
+ };
339
+ var http = {
340
+ getInitial: function(key, params) {
341
+ var path = (params.httpPath || "/pusher") + getGenericPath(key);
342
+ return getGenericURL("http", params, path);
343
+ }
344
+ };
345
+ class CallbackRegistry {
346
+ constructor() {
347
+ this._callbacks = {};
348
+ }
349
+ get(name) {
350
+ return this._callbacks[prefix(name)];
351
+ }
352
+ add(name, callback, context) {
353
+ var prefixedEventName = prefix(name);
354
+ this._callbacks[prefixedEventName] = this._callbacks[prefixedEventName] || [];
355
+ this._callbacks[prefixedEventName].push({
356
+ fn: callback,
357
+ context
358
+ });
359
+ }
360
+ remove(name, callback, context) {
361
+ if (!name && !callback && !context) {
362
+ this._callbacks = {};
363
+ return;
364
+ }
365
+ var names = name ? [prefix(name)] : keys(this._callbacks);
366
+ if (callback || context) {
367
+ this.removeCallback(names, callback, context);
368
+ } else {
369
+ this.removeAllCallbacks(names);
370
+ }
371
+ }
372
+ removeCallback(names, callback, context) {
373
+ apply(
374
+ names,
375
+ function(name) {
376
+ this._callbacks[name] = filter(
377
+ this._callbacks[name] || [],
378
+ function(binding) {
379
+ return callback && callback !== binding.fn || context && context !== binding.context;
380
+ }
381
+ );
382
+ if (this._callbacks[name].length === 0) {
383
+ delete this._callbacks[name];
384
+ }
385
+ },
386
+ this
387
+ );
388
+ }
389
+ removeAllCallbacks(names) {
390
+ apply(
391
+ names,
392
+ function(name) {
393
+ delete this._callbacks[name];
394
+ },
395
+ this
396
+ );
397
+ }
398
+ }
399
+ function prefix(name) {
400
+ return "_" + name;
401
+ }
402
+ class Dispatcher {
403
+ constructor(failThrough) {
404
+ this.callbacks = new CallbackRegistry();
405
+ this.global_callbacks = [];
406
+ this.failThrough = failThrough;
407
+ }
408
+ bind(eventName, callback, context) {
409
+ this.callbacks.add(eventName, callback, context);
410
+ return this;
411
+ }
412
+ bind_global(callback) {
413
+ this.global_callbacks.push(callback);
414
+ return this;
415
+ }
416
+ unbind(eventName, callback, context) {
417
+ this.callbacks.remove(eventName, callback, context);
418
+ return this;
419
+ }
420
+ unbind_global(callback) {
421
+ if (!callback) {
422
+ this.global_callbacks = [];
423
+ return this;
424
+ }
425
+ this.global_callbacks = filter(
426
+ this.global_callbacks || [],
427
+ (c) => c !== callback
428
+ );
429
+ return this;
430
+ }
431
+ unbind_all() {
432
+ this.unbind();
433
+ this.unbind_global();
434
+ return this;
435
+ }
436
+ emit(eventName, data, metadata) {
437
+ for (var i = 0; i < this.global_callbacks.length; i++) {
438
+ this.global_callbacks[i](eventName, data);
439
+ }
440
+ var callbacks = this.callbacks.get(eventName);
441
+ var args = [];
442
+ if (metadata) {
443
+ args.push(data, metadata);
444
+ } else if (data) {
445
+ args.push(data);
446
+ }
447
+ if (callbacks && callbacks.length > 0) {
448
+ for (var i = 0; i < callbacks.length; i++) {
449
+ callbacks[i].fn.apply(callbacks[i].context || global, args);
450
+ }
451
+ } else if (this.failThrough) {
452
+ this.failThrough(eventName, data);
453
+ }
454
+ return this;
455
+ }
456
+ }
457
+ let config = {
458
+ logToConsole: false
459
+ };
460
+ function setLoggerConfig(newConfig) {
461
+ config = { ...config, ...newConfig };
462
+ }
463
+ class Logger {
464
+ constructor() {
465
+ this.globalLog = (message) => {
466
+ if (global.console && global.console.log) {
467
+ global.console.log(message);
468
+ }
469
+ };
470
+ }
471
+ debug(...args) {
472
+ this.log(this.globalLog, args);
473
+ }
474
+ warn(...args) {
475
+ this.log(this.globalLogWarn, args);
476
+ }
477
+ error(...args) {
478
+ this.log(this.globalLogError, args);
479
+ }
480
+ globalLogWarn(message) {
481
+ if (global.console && global.console.warn) {
482
+ global.console.warn(message);
483
+ } else {
484
+ this.globalLog(message);
485
+ }
486
+ }
487
+ globalLogError(message) {
488
+ if (global.console && global.console.error) {
489
+ global.console.error(message);
490
+ } else {
491
+ this.globalLogWarn(message);
492
+ }
493
+ }
494
+ log(defaultLoggingFunction, ...args) {
495
+ var message = stringify.apply(this, arguments);
496
+ if (config.log) {
497
+ config.log(message);
498
+ } else if (config.logToConsole) {
499
+ const log = defaultLoggingFunction.bind(this);
500
+ log(message);
501
+ }
502
+ }
503
+ }
504
+ const Logger$1 = new Logger();
505
+ class TransportConnection extends Dispatcher {
506
+ constructor(hooks2, name, priority, key, options) {
507
+ super();
508
+ this.initialize = NodeJS.transportConnectionInitializer;
509
+ this.hooks = hooks2;
510
+ this.name = name;
511
+ this.priority = priority;
512
+ this.key = key;
513
+ this.options = options;
514
+ this.state = "new";
515
+ this.timeline = options.timeline;
516
+ this.activityTimeout = options.activityTimeout;
517
+ this.id = this.timeline.generateUniqueID();
518
+ }
519
+ /** Checks whether the transport handles activity checks by itself.
520
+ *
521
+ * @return {Boolean}
522
+ */
523
+ handlesActivityChecks() {
524
+ return Boolean(this.hooks.handlesActivityChecks);
525
+ }
526
+ /** Checks whether the transport supports the ping/pong API.
527
+ *
528
+ * @return {Boolean}
529
+ */
530
+ supportsPing() {
531
+ return Boolean(this.hooks.supportsPing);
532
+ }
533
+ /** Tries to establish a connection.
534
+ *
535
+ * @returns {Boolean} false if transport is in invalid state
536
+ */
537
+ connect() {
538
+ if (this.socket || this.state !== "initialized") {
539
+ return false;
540
+ }
541
+ var url = this.hooks.urls.getInitial(this.key, this.options);
542
+ try {
543
+ this.socket = this.hooks.getSocket(url, this.options);
544
+ } catch (e) {
545
+ Util.defer(() => {
546
+ this.onError(e);
547
+ this.changeState("closed");
548
+ });
549
+ return false;
550
+ }
551
+ this.bindListeners();
552
+ Logger$1.debug("Connecting", { transport: this.name, url });
553
+ this.changeState("connecting");
554
+ return true;
555
+ }
556
+ /** Closes the connection.
557
+ *
558
+ * @return {Boolean} true if there was a connection to close
559
+ */
560
+ close() {
561
+ if (this.socket) {
562
+ this.socket.close();
563
+ return true;
564
+ } else {
565
+ return false;
566
+ }
567
+ }
568
+ /** Sends data over the open connection.
569
+ *
570
+ * @param {String} data
571
+ * @return {Boolean} true only when in the "open" state
572
+ */
573
+ send(data) {
574
+ if (this.state === "open") {
575
+ Util.defer(() => {
576
+ if (this.socket) {
577
+ this.socket.send(data);
578
+ }
579
+ });
580
+ return true;
581
+ } else {
582
+ return false;
583
+ }
584
+ }
585
+ /** Sends a ping if the connection is open and transport supports it. */
586
+ ping() {
587
+ if (this.state === "open" && this.supportsPing()) {
588
+ this.socket.ping();
589
+ }
590
+ }
591
+ onOpen() {
592
+ if (this.hooks.beforeOpen) {
593
+ this.hooks.beforeOpen(
594
+ this.socket,
595
+ this.hooks.urls.getPath(this.key, this.options)
596
+ );
597
+ }
598
+ this.changeState("open");
599
+ this.socket.onopen = void 0;
600
+ }
601
+ onError(error) {
602
+ this.emit("error", { type: "WebSocketError", error });
603
+ this.timeline.error(this.buildTimelineMessage({ error: error.toString() }));
604
+ }
605
+ onClose(closeEvent) {
606
+ if (closeEvent) {
607
+ this.changeState("closed", {
608
+ code: closeEvent.code,
609
+ reason: closeEvent.reason,
610
+ wasClean: closeEvent.wasClean
611
+ });
612
+ } else {
613
+ this.changeState("closed");
614
+ }
615
+ this.unbindListeners();
616
+ this.socket = void 0;
617
+ }
618
+ onMessage(message) {
619
+ this.emit("message", message);
620
+ }
621
+ onActivity() {
622
+ this.emit("activity");
623
+ }
624
+ bindListeners() {
625
+ this.socket.onopen = () => {
626
+ this.onOpen();
627
+ };
628
+ this.socket.onerror = (error) => {
629
+ this.onError(error);
630
+ };
631
+ this.socket.onclose = (closeEvent) => {
632
+ this.onClose(closeEvent);
633
+ };
634
+ this.socket.onmessage = (message) => {
635
+ this.onMessage(message);
636
+ };
637
+ if (this.supportsPing()) {
638
+ this.socket.onactivity = () => {
639
+ this.onActivity();
640
+ };
641
+ }
642
+ }
643
+ unbindListeners() {
644
+ if (this.socket) {
645
+ this.socket.onopen = void 0;
646
+ this.socket.onerror = void 0;
647
+ this.socket.onclose = void 0;
648
+ this.socket.onmessage = void 0;
649
+ if (this.supportsPing()) {
650
+ this.socket.onactivity = void 0;
651
+ }
652
+ }
653
+ }
654
+ changeState(state, params) {
655
+ this.state = state;
656
+ this.timeline.info(
657
+ this.buildTimelineMessage({
658
+ state,
659
+ params
660
+ })
661
+ );
662
+ this.emit(state, params);
663
+ }
664
+ buildTimelineMessage(message) {
665
+ return extend({ cid: this.id }, message);
666
+ }
667
+ }
668
+ class Transport {
669
+ constructor(hooks2) {
670
+ this.hooks = hooks2;
671
+ }
672
+ /** Returns whether the transport is supported in the environment.
673
+ *
674
+ * @param {Object} envronment te environment details (encryption, settings)
675
+ * @returns {Boolean} true when the transport is supported
676
+ */
677
+ isSupported(environment) {
678
+ return this.hooks.isSupported(environment);
679
+ }
680
+ /** Creates a transport connection.
681
+ *
682
+ * @param {String} name
683
+ * @param {Number} priority
684
+ * @param {String} key the application key
685
+ * @param {Object} options
686
+ * @returns {TransportConnection}
687
+ */
688
+ createConnection(name, priority, key, options) {
689
+ return new TransportConnection(this.hooks, name, priority, key, options);
690
+ }
691
+ }
692
+ var WSTransport = new Transport({
693
+ urls: ws,
694
+ handlesActivityChecks: false,
695
+ supportsPing: false,
696
+ isInitialized: function() {
697
+ return Boolean(NodeJS.getWebSocketAPI());
698
+ },
699
+ isSupported: function() {
700
+ return Boolean(NodeJS.getWebSocketAPI());
701
+ },
702
+ getSocket: function(url) {
703
+ return NodeJS.createWebSocket(url);
704
+ }
705
+ });
706
+ var httpConfiguration = {
707
+ urls: http,
708
+ handlesActivityChecks: false,
709
+ supportsPing: true,
710
+ isInitialized: function() {
711
+ return true;
712
+ }
713
+ };
714
+ var streamingConfiguration = extend(
715
+ {
716
+ getSocket: function(url) {
717
+ return NodeJS.HTTPFactory.createStreamingSocket(url);
718
+ }
719
+ },
720
+ httpConfiguration
721
+ );
722
+ var pollingConfiguration = extend(
723
+ {
724
+ getSocket: function(url) {
725
+ return NodeJS.HTTPFactory.createPollingSocket(url);
726
+ }
727
+ },
728
+ httpConfiguration
729
+ );
730
+ var xhrConfiguration = {
731
+ isSupported: function() {
732
+ return NodeJS.isXHRSupported();
733
+ }
734
+ };
735
+ var XHRStreamingTransport = new Transport(
736
+ extend({}, streamingConfiguration, xhrConfiguration)
737
+ );
738
+ var XHRPollingTransport = new Transport(
739
+ extend({}, pollingConfiguration, xhrConfiguration)
740
+ );
741
+ var Transports$2 = {
742
+ ws: WSTransport,
743
+ xhr_streaming: XHRStreamingTransport,
744
+ xhr_polling: XHRPollingTransport
745
+ };
746
+ class AssistantToTheTransportManager {
747
+ constructor(manager, transport, options) {
748
+ this.manager = manager;
749
+ this.transport = transport;
750
+ this.minPingDelay = options.minPingDelay;
751
+ this.maxPingDelay = options.maxPingDelay;
752
+ this.pingDelay = void 0;
753
+ }
754
+ /** Creates a transport connection.
755
+ *
756
+ * This function has the same API as Transport#createConnection.
757
+ *
758
+ * @param {String} name
759
+ * @param {Number} priority
760
+ * @param {String} key the application key
761
+ * @param {Object} options
762
+ * @returns {TransportConnection}
763
+ */
764
+ createConnection(name, priority, key, options) {
765
+ options = extend({}, options, {
766
+ activityTimeout: this.pingDelay
767
+ });
768
+ var connection = this.transport.createConnection(
769
+ name,
770
+ priority,
771
+ key,
772
+ options
773
+ );
774
+ var openTimestamp = null;
775
+ var onOpen = function() {
776
+ connection.unbind("open", onOpen);
777
+ connection.bind("closed", onClosed);
778
+ openTimestamp = Util.now();
779
+ };
780
+ var onClosed = (closeEvent) => {
781
+ connection.unbind("closed", onClosed);
782
+ if (closeEvent.code === 1002 || closeEvent.code === 1003) {
783
+ this.manager.reportDeath();
784
+ } else if (!closeEvent.wasClean && openTimestamp) {
785
+ var lifespan = Util.now() - openTimestamp;
786
+ if (lifespan < 2 * this.maxPingDelay) {
787
+ this.manager.reportDeath();
788
+ this.pingDelay = Math.max(lifespan / 2, this.minPingDelay);
789
+ }
790
+ }
791
+ };
792
+ connection.bind("open", onOpen);
793
+ return connection;
794
+ }
795
+ /** Returns whether the transport is supported in the environment.
796
+ *
797
+ * This function has the same API as Transport#isSupported. Might return false
798
+ * when the manager decides to kill the transport.
799
+ *
800
+ * @param {Object} environment the environment details (encryption, settings)
801
+ * @returns {Boolean} true when the transport is supported
802
+ */
803
+ isSupported(environment) {
804
+ return this.manager.isAlive() && this.transport.isSupported(environment);
805
+ }
806
+ }
807
+ const Protocol = {
808
+ /**
809
+ * Decodes a message in a Pusher format.
810
+ *
811
+ * The MessageEvent we receive from the transport should contain a pusher event
812
+ * (https://pusher.com/docs/pusher_protocol#events) serialized as JSON in the
813
+ * data field
814
+ *
815
+ * The pusher event may contain a data field too, and it may also be
816
+ * serialised as JSON
817
+ *
818
+ * Throws errors when messages are not parse'able.
819
+ *
820
+ * @param {MessageEvent} messageEvent
821
+ * @return {PusherEvent}
822
+ */
823
+ decodeMessage: function(messageEvent) {
824
+ try {
825
+ var messageData = JSON.parse(messageEvent.data);
826
+ var pusherEventData = messageData.data;
827
+ if (typeof pusherEventData === "string") {
828
+ try {
829
+ pusherEventData = JSON.parse(messageData.data);
830
+ } catch (e) {
831
+ }
832
+ }
833
+ var pusherEvent = {
834
+ event: messageData.event,
835
+ channel: messageData.channel,
836
+ data: pusherEventData,
837
+ rawMessage: messageEvent.data
838
+ // Preserve raw message for delta compression
839
+ };
840
+ if (messageData.user_id) {
841
+ pusherEvent.user_id = messageData.user_id;
842
+ }
843
+ const sequence = messageData.__delta_seq ?? messageData.sequence;
844
+ const conflationKey = messageData.__conflation_key ?? messageData.conflation_key;
845
+ if (typeof sequence === "number") {
846
+ pusherEvent.sequence = sequence;
847
+ }
848
+ if (conflationKey !== void 0) {
849
+ pusherEvent.conflation_key = conflationKey;
850
+ }
851
+ return pusherEvent;
852
+ } catch (e) {
853
+ throw { type: "MessageParseError", error: e, data: messageEvent.data };
854
+ }
855
+ },
856
+ /**
857
+ * Encodes a message to be sent.
858
+ *
859
+ * @param {PusherEvent} event
860
+ * @return {String}
861
+ */
862
+ encodeMessage: function(event) {
863
+ return JSON.stringify(event);
864
+ },
865
+ /**
866
+ * Processes a handshake message and returns appropriate actions.
867
+ *
868
+ * Returns an object with an 'action' and other action-specific properties.
869
+ *
870
+ * There are three outcomes when calling this function. First is a successful
871
+ * connection attempt, when pusher:connection_established is received, which
872
+ * results in a 'connected' action with an 'id' property. When passed a
873
+ * pusher:error event, it returns a result with action appropriate to the
874
+ * close code and an error. Otherwise, it raises an exception.
875
+ *
876
+ * @param {String} message
877
+ * @result Object
878
+ */
879
+ processHandshake: function(messageEvent) {
880
+ var message = Protocol.decodeMessage(messageEvent);
881
+ if (message.event === "pusher:connection_established") {
882
+ if (!message.data.activity_timeout) {
883
+ throw "No activity timeout specified in handshake";
884
+ }
885
+ return {
886
+ action: "connected",
887
+ id: message.data.socket_id,
888
+ activityTimeout: message.data.activity_timeout * 1e3
889
+ };
890
+ } else if (message.event === "pusher:error") {
891
+ return {
892
+ action: this.getCloseAction(message.data),
893
+ error: this.getCloseError(message.data)
894
+ };
895
+ } else {
896
+ throw "Invalid handshake";
897
+ }
898
+ },
899
+ /**
900
+ * Dispatches the close event and returns an appropriate action name.
901
+ *
902
+ * See:
903
+ * 1. https://developer.mozilla.org/en-US/docs/WebSockets/WebSockets_reference/CloseEvent
904
+ * 2. http://pusher.com/docs/pusher_protocol
905
+ *
906
+ * @param {CloseEvent} closeEvent
907
+ * @return {String} close action name
908
+ */
909
+ getCloseAction: function(closeEvent) {
910
+ if (closeEvent.code < 4e3) {
911
+ if (closeEvent.code >= 1002 && closeEvent.code <= 1004) {
912
+ return "backoff";
913
+ } else {
914
+ return null;
915
+ }
916
+ } else if (closeEvent.code === 4e3) {
917
+ return "tls_only";
918
+ } else if (closeEvent.code < 4100) {
919
+ return "refused";
920
+ } else if (closeEvent.code < 4200) {
921
+ return "backoff";
922
+ } else if (closeEvent.code < 4300) {
923
+ return "retry";
924
+ } else {
925
+ return "refused";
926
+ }
927
+ },
928
+ /**
929
+ * Returns an error or null basing on the close event.
930
+ *
931
+ * Null is returned when connection was closed cleanly. Otherwise, an object
932
+ * with error details is returned.
933
+ *
934
+ * @param {CloseEvent} closeEvent
935
+ * @return {Object} error object
936
+ */
937
+ getCloseError: function(closeEvent) {
938
+ if (closeEvent.code !== 1e3 && closeEvent.code !== 1001) {
939
+ return {
940
+ type: "PusherError",
941
+ data: {
942
+ code: closeEvent.code,
943
+ message: closeEvent.reason || closeEvent.message
944
+ }
945
+ };
946
+ } else {
947
+ return null;
948
+ }
949
+ }
950
+ };
951
+ class Connection extends Dispatcher {
952
+ constructor(id, transport) {
953
+ super();
954
+ this.id = id;
955
+ this.transport = transport;
956
+ this.activityTimeout = transport.activityTimeout;
957
+ this.bindListeners();
958
+ }
959
+ /** Returns whether used transport handles activity checks by itself
960
+ *
961
+ * @returns {Boolean} true if activity checks are handled by the transport
962
+ */
963
+ handlesActivityChecks() {
964
+ return this.transport.handlesActivityChecks();
965
+ }
966
+ /** Sends raw data.
967
+ *
968
+ * @param {String} data
969
+ */
970
+ send(data) {
971
+ return this.transport.send(data);
972
+ }
973
+ /** Sends an event.
974
+ *
975
+ * @param {String} name
976
+ * @param {String} data
977
+ * @param {String} [channel]
978
+ * @returns {Boolean} whether message was sent or not
979
+ */
980
+ send_event(name, data, channel) {
981
+ var event = { event: name, data };
982
+ if (channel) {
983
+ event.channel = channel;
984
+ }
985
+ Logger$1.debug("Event sent", event);
986
+ return this.send(Protocol.encodeMessage(event));
987
+ }
988
+ /** Sends a ping message to the server.
989
+ *
990
+ * Basing on the underlying transport, it might send either transport's
991
+ * protocol-specific ping or pusher:ping event.
992
+ */
993
+ ping() {
994
+ if (this.transport.supportsPing()) {
995
+ this.transport.ping();
996
+ } else {
997
+ this.send_event("pusher:ping", {});
998
+ }
999
+ }
1000
+ /** Closes the connection. */
1001
+ close() {
1002
+ this.transport.close();
1003
+ }
1004
+ bindListeners() {
1005
+ var listeners = {
1006
+ message: (messageEvent) => {
1007
+ var pusherEvent;
1008
+ try {
1009
+ pusherEvent = Protocol.decodeMessage(messageEvent);
1010
+ } catch (e) {
1011
+ this.emit("error", {
1012
+ type: "MessageParseError",
1013
+ error: e,
1014
+ data: messageEvent.data
1015
+ });
1016
+ }
1017
+ if (pusherEvent !== void 0) {
1018
+ Logger$1.debug("Event recd", pusherEvent);
1019
+ switch (pusherEvent.event) {
1020
+ case "pusher:error":
1021
+ this.emit("error", {
1022
+ type: "PusherError",
1023
+ data: pusherEvent.data
1024
+ });
1025
+ break;
1026
+ case "pusher:ping":
1027
+ this.emit("ping");
1028
+ break;
1029
+ case "pusher:pong":
1030
+ this.emit("pong");
1031
+ break;
1032
+ }
1033
+ this.emit("message", pusherEvent);
1034
+ }
1035
+ },
1036
+ activity: () => {
1037
+ this.emit("activity");
1038
+ },
1039
+ error: (error) => {
1040
+ this.emit("error", error);
1041
+ },
1042
+ closed: (closeEvent) => {
1043
+ unbindListeners();
1044
+ if (closeEvent && closeEvent.code) {
1045
+ this.handleCloseEvent(closeEvent);
1046
+ }
1047
+ this.transport = null;
1048
+ this.emit("closed");
1049
+ }
1050
+ };
1051
+ var unbindListeners = () => {
1052
+ objectApply(listeners, (listener, event) => {
1053
+ this.transport.unbind(event, listener);
1054
+ });
1055
+ };
1056
+ objectApply(listeners, (listener, event) => {
1057
+ this.transport.bind(event, listener);
1058
+ });
1059
+ }
1060
+ handleCloseEvent(closeEvent) {
1061
+ var action = Protocol.getCloseAction(closeEvent);
1062
+ var error = Protocol.getCloseError(closeEvent);
1063
+ if (error) {
1064
+ this.emit("error", error);
1065
+ }
1066
+ if (action) {
1067
+ this.emit(action, { action, error });
1068
+ }
1069
+ }
1070
+ }
1071
+ class Handshake {
1072
+ constructor(transport, callback) {
1073
+ this.transport = transport;
1074
+ this.callback = callback;
1075
+ this.bindListeners();
1076
+ }
1077
+ close() {
1078
+ this.unbindListeners();
1079
+ this.transport.close();
1080
+ }
1081
+ bindListeners() {
1082
+ this.onMessage = (m) => {
1083
+ this.unbindListeners();
1084
+ var result;
1085
+ try {
1086
+ result = Protocol.processHandshake(m);
1087
+ } catch (e) {
1088
+ this.finish("error", { error: e });
1089
+ this.transport.close();
1090
+ return;
1091
+ }
1092
+ if (result.action === "connected") {
1093
+ this.finish("connected", {
1094
+ connection: new Connection(result.id, this.transport),
1095
+ activityTimeout: result.activityTimeout
1096
+ });
1097
+ } else {
1098
+ this.finish(result.action, { error: result.error });
1099
+ this.transport.close();
1100
+ }
1101
+ };
1102
+ this.onClosed = (closeEvent) => {
1103
+ this.unbindListeners();
1104
+ var action = Protocol.getCloseAction(closeEvent) || "backoff";
1105
+ var error = Protocol.getCloseError(closeEvent);
1106
+ this.finish(action, { error });
1107
+ };
1108
+ this.transport.bind("message", this.onMessage);
1109
+ this.transport.bind("closed", this.onClosed);
1110
+ }
1111
+ unbindListeners() {
1112
+ this.transport.unbind("message", this.onMessage);
1113
+ this.transport.unbind("closed", this.onClosed);
1114
+ }
1115
+ finish(action, params) {
1116
+ this.callback(
1117
+ extend({ transport: this.transport, action }, params)
1118
+ );
1119
+ }
1120
+ }
1121
+ class TimelineSender {
1122
+ constructor(timeline, options) {
1123
+ this.timeline = timeline;
1124
+ this.options = options || {};
1125
+ }
1126
+ send(useTLS, callback) {
1127
+ if (this.timeline.isEmpty()) {
1128
+ return;
1129
+ }
1130
+ this.timeline.send(
1131
+ NodeJS.TimelineTransport.getAgent(this, useTLS),
1132
+ callback
1133
+ );
1134
+ }
1135
+ }
1136
+ class BadEventName extends Error {
1137
+ constructor(msg) {
1138
+ super(msg);
1139
+ Object.setPrototypeOf(this, new.target.prototype);
1140
+ }
1141
+ }
1142
+ class BadChannelName extends Error {
1143
+ constructor(msg) {
1144
+ super(msg);
1145
+ Object.setPrototypeOf(this, new.target.prototype);
1146
+ }
1147
+ }
1148
+ class TransportPriorityTooLow extends Error {
1149
+ constructor(msg) {
1150
+ super(msg);
1151
+ Object.setPrototypeOf(this, new.target.prototype);
1152
+ }
1153
+ }
1154
+ class TransportClosed extends Error {
1155
+ constructor(msg) {
1156
+ super(msg);
1157
+ Object.setPrototypeOf(this, new.target.prototype);
1158
+ }
1159
+ }
1160
+ class UnsupportedFeature extends Error {
1161
+ constructor(msg) {
1162
+ super(msg);
1163
+ Object.setPrototypeOf(this, new.target.prototype);
1164
+ }
1165
+ }
1166
+ class UnsupportedTransport extends Error {
1167
+ constructor(msg) {
1168
+ super(msg);
1169
+ Object.setPrototypeOf(this, new.target.prototype);
1170
+ }
1171
+ }
1172
+ let UnsupportedStrategy$1 = class UnsupportedStrategy extends Error {
1173
+ constructor(msg) {
1174
+ super(msg);
1175
+ Object.setPrototypeOf(this, new.target.prototype);
1176
+ }
1177
+ };
1178
+ class HTTPAuthError extends Error {
1179
+ constructor(status, msg) {
1180
+ super(msg);
1181
+ this.status = status;
1182
+ Object.setPrototypeOf(this, new.target.prototype);
1183
+ }
1184
+ }
1185
+ const urlStore = {
1186
+ baseUrl: "https://pusher.com",
1187
+ urls: {
1188
+ authenticationEndpoint: {
1189
+ path: "/docs/channels/server_api/authenticating_users"
1190
+ },
1191
+ authorizationEndpoint: {
1192
+ path: "/docs/channels/server_api/authorizing-users/"
1193
+ },
1194
+ javascriptQuickStart: {
1195
+ path: "/docs/javascript_quick_start"
1196
+ },
1197
+ triggeringClientEvents: {
1198
+ path: "/docs/client_api_guide/client_events#trigger-events"
1199
+ },
1200
+ encryptedChannelSupport: {
1201
+ fullUrl: "https://github.com/pusher/pusher-js/tree/cc491015371a4bde5743d1c87a0fbac0feb53195#encrypted-channel-support"
1202
+ }
1203
+ }
1204
+ };
1205
+ const buildLogSuffix = function(key) {
1206
+ const urlPrefix = "See:";
1207
+ const urlObj = urlStore.urls[key];
1208
+ if (!urlObj) return "";
1209
+ let url;
1210
+ if (urlObj.fullUrl) {
1211
+ url = urlObj.fullUrl;
1212
+ } else if (urlObj.path) {
1213
+ url = urlStore.baseUrl + urlObj.path;
1214
+ }
1215
+ if (!url) return "";
1216
+ return `${urlPrefix} ${url}`;
1217
+ };
1218
+ const UrlStore = { buildLogSuffix };
1219
+ class Channel extends Dispatcher {
1220
+ constructor(name, pusher) {
1221
+ super(function(event, data) {
1222
+ Logger$1.debug("No callbacks on " + name + " for " + event);
1223
+ });
1224
+ this.name = name;
1225
+ this.pusher = pusher;
1226
+ this.subscribed = false;
1227
+ this.subscriptionPending = false;
1228
+ this.subscriptionCancelled = false;
1229
+ this.tagsFilter = null;
1230
+ }
1231
+ /** Skips authorization, since public channels don't require it.
1232
+ *
1233
+ * @param {Function} callback
1234
+ */
1235
+ authorize(socketId, callback) {
1236
+ return callback(null, { auth: "" });
1237
+ }
1238
+ /** Triggers an event */
1239
+ trigger(event, data) {
1240
+ if (event.indexOf("client-") !== 0) {
1241
+ throw new BadEventName(
1242
+ "Event '" + event + "' does not start with 'client-'"
1243
+ );
1244
+ }
1245
+ if (!this.subscribed) {
1246
+ var suffix = UrlStore.buildLogSuffix("triggeringClientEvents");
1247
+ Logger$1.warn(
1248
+ `Client event triggered before channel 'subscription_succeeded' event . ${suffix}`
1249
+ );
1250
+ }
1251
+ return this.pusher.send_event(event, data, this.name);
1252
+ }
1253
+ /** Signals disconnection to the channel. For internal use only. */
1254
+ disconnect() {
1255
+ this.subscribed = false;
1256
+ this.subscriptionPending = false;
1257
+ }
1258
+ /** Handles a PusherEvent. For internal use only.
1259
+ *
1260
+ * @param {PusherEvent} event
1261
+ */
1262
+ handleEvent(event) {
1263
+ var eventName = event.event;
1264
+ var data = event.data;
1265
+ if (eventName === "pusher_internal:subscription_succeeded") {
1266
+ this.handleSubscriptionSucceededEvent(event);
1267
+ } else if (eventName === "pusher_internal:subscription_count") {
1268
+ this.handleSubscriptionCountEvent(event);
1269
+ } else if (eventName.indexOf("pusher_internal:") !== 0) {
1270
+ var metadata = {};
1271
+ this.emit(eventName, data, metadata);
1272
+ }
1273
+ }
1274
+ handleSubscriptionSucceededEvent(event) {
1275
+ this.subscriptionPending = false;
1276
+ this.subscribed = true;
1277
+ if (this.subscriptionCancelled) {
1278
+ this.pusher.unsubscribe(this.name);
1279
+ } else {
1280
+ this.emit("pusher:subscription_succeeded", event.data);
1281
+ }
1282
+ }
1283
+ handleSubscriptionCountEvent(event) {
1284
+ if (event.data.subscription_count) {
1285
+ this.subscriptionCount = event.data.subscription_count;
1286
+ }
1287
+ this.emit("pusher:subscription_count", event.data);
1288
+ }
1289
+ /** Sends a subscription request. For internal use only. */
1290
+ subscribe() {
1291
+ if (this.subscribed) {
1292
+ return;
1293
+ }
1294
+ this.subscriptionPending = true;
1295
+ this.subscriptionCancelled = false;
1296
+ this.authorize(
1297
+ this.pusher.connection.socket_id,
1298
+ (error, data) => {
1299
+ if (error) {
1300
+ this.subscriptionPending = false;
1301
+ Logger$1.error(error.toString());
1302
+ this.emit(
1303
+ "pusher:subscription_error",
1304
+ Object.assign(
1305
+ {},
1306
+ {
1307
+ type: "AuthError",
1308
+ error: error.message
1309
+ },
1310
+ error instanceof HTTPAuthError ? { status: error.status } : {}
1311
+ )
1312
+ );
1313
+ } else {
1314
+ const subscribeData = {
1315
+ auth: data.auth,
1316
+ channel_data: data.channel_data,
1317
+ channel: this.name
1318
+ };
1319
+ if (this.tagsFilter) {
1320
+ subscribeData.tags_filter = this.tagsFilter;
1321
+ }
1322
+ this.pusher.send_event("pusher:subscribe", subscribeData);
1323
+ }
1324
+ }
1325
+ );
1326
+ }
1327
+ /** Sends an unsubscription request. For internal use only. */
1328
+ unsubscribe() {
1329
+ this.subscribed = false;
1330
+ this.pusher.send_event("pusher:unsubscribe", {
1331
+ channel: this.name
1332
+ });
1333
+ }
1334
+ /** Cancels an in progress subscription. For internal use only. */
1335
+ cancelSubscription() {
1336
+ this.subscriptionCancelled = true;
1337
+ }
1338
+ /** Reinstates an in progress subscripiton. For internal use only. */
1339
+ reinstateSubscription() {
1340
+ this.subscriptionCancelled = false;
1341
+ }
1342
+ }
1343
+ class PrivateChannel extends Channel {
1344
+ /** Authorizes the connection to use the channel.
1345
+ *
1346
+ * @param {String} socketId
1347
+ * @param {Function} callback
1348
+ */
1349
+ authorize(socketId, callback) {
1350
+ return this.pusher.config.channelAuthorizer(
1351
+ {
1352
+ channelName: this.name,
1353
+ socketId
1354
+ },
1355
+ callback
1356
+ );
1357
+ }
1358
+ }
1359
+ class Members {
1360
+ constructor() {
1361
+ this.reset();
1362
+ }
1363
+ /** Returns member's info for given id.
1364
+ *
1365
+ * Resulting object containts two fields - id and info.
1366
+ *
1367
+ * @param {Number} id
1368
+ * @return {Object} member's info or null
1369
+ */
1370
+ get(id) {
1371
+ if (Object.prototype.hasOwnProperty.call(this.members, id)) {
1372
+ return {
1373
+ id,
1374
+ info: this.members[id]
1375
+ };
1376
+ } else {
1377
+ return null;
1378
+ }
1379
+ }
1380
+ /** Calls back for each member in unspecified order.
1381
+ *
1382
+ * @param {Function} callback
1383
+ */
1384
+ each(callback) {
1385
+ objectApply(this.members, (member, id) => {
1386
+ callback(this.get(id));
1387
+ });
1388
+ }
1389
+ /** Updates the id for connected member. For internal use only. */
1390
+ setMyID(id) {
1391
+ this.myID = id;
1392
+ }
1393
+ /** Handles subscription data. For internal use only. */
1394
+ onSubscription(subscriptionData) {
1395
+ this.members = subscriptionData.presence.hash;
1396
+ this.count = subscriptionData.presence.count;
1397
+ this.me = this.get(this.myID);
1398
+ }
1399
+ /** Adds a new member to the collection. For internal use only. */
1400
+ addMember(memberData) {
1401
+ if (this.get(memberData.user_id) === null) {
1402
+ this.count++;
1403
+ }
1404
+ this.members[memberData.user_id] = memberData.user_info;
1405
+ return this.get(memberData.user_id);
1406
+ }
1407
+ /** Adds a member from the collection. For internal use only. */
1408
+ removeMember(memberData) {
1409
+ var member = this.get(memberData.user_id);
1410
+ if (member) {
1411
+ delete this.members[memberData.user_id];
1412
+ this.count--;
1413
+ }
1414
+ return member;
1415
+ }
1416
+ /** Resets the collection to the initial state. For internal use only. */
1417
+ reset() {
1418
+ this.members = {};
1419
+ this.count = 0;
1420
+ this.myID = null;
1421
+ this.me = null;
1422
+ }
1423
+ }
1424
+ class PresenceChannel extends PrivateChannel {
1425
+ /** Adds presence channel functionality to private channels.
1426
+ *
1427
+ * @param {String} name
1428
+ * @param {Pusher} pusher
1429
+ */
1430
+ constructor(name, pusher) {
1431
+ super(name, pusher);
1432
+ this.members = new Members();
1433
+ }
1434
+ /** Authorizes the connection as a member of the channel.
1435
+ *
1436
+ * @param {String} socketId
1437
+ * @param {Function} callback
1438
+ */
1439
+ authorize(socketId, callback) {
1440
+ super.authorize(socketId, async (error, authData) => {
1441
+ if (!error) {
1442
+ authData = authData;
1443
+ if (authData.channel_data != null) {
1444
+ var channelData = JSON.parse(authData.channel_data);
1445
+ this.members.setMyID(channelData.user_id);
1446
+ } else {
1447
+ await this.pusher.user.signinDonePromise;
1448
+ if (this.pusher.user.user_data != null) {
1449
+ this.members.setMyID(this.pusher.user.user_data.id);
1450
+ } else {
1451
+ let suffix = UrlStore.buildLogSuffix("authorizationEndpoint");
1452
+ Logger$1.error(
1453
+ `Invalid auth response for channel '${this.name}', expected 'channel_data' field. ${suffix}, or the user should be signed in.`
1454
+ );
1455
+ callback("Invalid auth response");
1456
+ return;
1457
+ }
1458
+ }
1459
+ }
1460
+ callback(error, authData);
1461
+ });
1462
+ }
1463
+ /** Handles presence and subscription events. For internal use only.
1464
+ *
1465
+ * @param {PusherEvent} event
1466
+ */
1467
+ handleEvent(event) {
1468
+ var eventName = event.event;
1469
+ if (eventName.indexOf("pusher_internal:") === 0) {
1470
+ this.handleInternalEvent(event);
1471
+ } else {
1472
+ var data = event.data;
1473
+ var metadata = {};
1474
+ if (event.user_id) {
1475
+ metadata.user_id = event.user_id;
1476
+ }
1477
+ this.emit(eventName, data, metadata);
1478
+ }
1479
+ }
1480
+ handleInternalEvent(event) {
1481
+ var eventName = event.event;
1482
+ var data = event.data;
1483
+ switch (eventName) {
1484
+ case "pusher_internal:subscription_succeeded":
1485
+ this.handleSubscriptionSucceededEvent(event);
1486
+ break;
1487
+ case "pusher_internal:subscription_count":
1488
+ this.handleSubscriptionCountEvent(event);
1489
+ break;
1490
+ case "pusher_internal:member_added":
1491
+ var addedMember = this.members.addMember(data);
1492
+ this.emit("pusher:member_added", addedMember);
1493
+ break;
1494
+ case "pusher_internal:member_removed":
1495
+ var removedMember = this.members.removeMember(data);
1496
+ if (removedMember) {
1497
+ this.emit("pusher:member_removed", removedMember);
1498
+ }
1499
+ break;
1500
+ }
1501
+ }
1502
+ handleSubscriptionSucceededEvent(event) {
1503
+ this.subscriptionPending = false;
1504
+ this.subscribed = true;
1505
+ if (this.subscriptionCancelled) {
1506
+ this.pusher.unsubscribe(this.name);
1507
+ } else {
1508
+ this.members.onSubscription(event.data);
1509
+ this.emit("pusher:subscription_succeeded", this.members);
1510
+ }
1511
+ }
1512
+ /** Resets the channel state, including members map. For internal use only. */
1513
+ disconnect() {
1514
+ this.members.reset();
1515
+ super.disconnect();
1516
+ }
1517
+ }
1518
+ class EncryptedChannel extends PrivateChannel {
1519
+ constructor(name, pusher, nacl2) {
1520
+ super(name, pusher);
1521
+ this.key = null;
1522
+ this.nacl = nacl2;
1523
+ }
1524
+ /** Authorizes the connection to use the channel.
1525
+ *
1526
+ * @param {String} socketId
1527
+ * @param {Function} callback
1528
+ */
1529
+ authorize(socketId, callback) {
1530
+ super.authorize(
1531
+ socketId,
1532
+ (error, authData) => {
1533
+ if (error) {
1534
+ callback(error, authData);
1535
+ return;
1536
+ }
1537
+ let sharedSecret = authData["shared_secret"];
1538
+ if (!sharedSecret) {
1539
+ callback(
1540
+ new Error(
1541
+ `No shared_secret key in auth payload for encrypted channel: ${this.name}`
1542
+ ),
1543
+ null
1544
+ );
1545
+ return;
1546
+ }
1547
+ this.key = base64.decode(sharedSecret);
1548
+ delete authData["shared_secret"];
1549
+ callback(null, authData);
1550
+ }
1551
+ );
1552
+ }
1553
+ trigger(event, data) {
1554
+ throw new UnsupportedFeature(
1555
+ "Client events are not currently supported for encrypted channels"
1556
+ );
1557
+ }
1558
+ /** Handles an event. For internal use only.
1559
+ *
1560
+ * @param {PusherEvent} event
1561
+ */
1562
+ handleEvent(event) {
1563
+ var eventName = event.event;
1564
+ var data = event.data;
1565
+ if (eventName.indexOf("pusher_internal:") === 0 || eventName.indexOf("pusher:") === 0) {
1566
+ super.handleEvent(event);
1567
+ return;
1568
+ }
1569
+ this.handleEncryptedEvent(eventName, data);
1570
+ }
1571
+ handleEncryptedEvent(event, data) {
1572
+ if (!this.key) {
1573
+ Logger$1.debug(
1574
+ "Received encrypted event before key has been retrieved from the authEndpoint"
1575
+ );
1576
+ return;
1577
+ }
1578
+ if (!data.ciphertext || !data.nonce) {
1579
+ Logger$1.error(
1580
+ "Unexpected format for encrypted event, expected object with `ciphertext` and `nonce` fields, got: " + data
1581
+ );
1582
+ return;
1583
+ }
1584
+ let cipherText = base64.decode(data.ciphertext);
1585
+ if (cipherText.length < this.nacl.secretbox.overheadLength) {
1586
+ Logger$1.error(
1587
+ `Expected encrypted event ciphertext length to be ${this.nacl.secretbox.overheadLength}, got: ${cipherText.length}`
1588
+ );
1589
+ return;
1590
+ }
1591
+ let nonce = base64.decode(data.nonce);
1592
+ if (nonce.length < this.nacl.secretbox.nonceLength) {
1593
+ Logger$1.error(
1594
+ `Expected encrypted event nonce length to be ${this.nacl.secretbox.nonceLength}, got: ${nonce.length}`
1595
+ );
1596
+ return;
1597
+ }
1598
+ let bytes = this.nacl.secretbox.open(cipherText, nonce, this.key);
1599
+ if (bytes === null) {
1600
+ Logger$1.debug(
1601
+ "Failed to decrypt an event, probably because it was encrypted with a different key. Fetching a new key from the authEndpoint..."
1602
+ );
1603
+ this.authorize(this.pusher.connection.socket_id, (error, authData) => {
1604
+ if (error) {
1605
+ Logger$1.error(
1606
+ `Failed to make a request to the authEndpoint: ${authData}. Unable to fetch new key, so dropping encrypted event`
1607
+ );
1608
+ return;
1609
+ }
1610
+ bytes = this.nacl.secretbox.open(cipherText, nonce, this.key);
1611
+ if (bytes === null) {
1612
+ Logger$1.error(
1613
+ `Failed to decrypt event with new key. Dropping encrypted event`
1614
+ );
1615
+ return;
1616
+ }
1617
+ this.emit(event, this.getDataToEmit(bytes));
1618
+ return;
1619
+ });
1620
+ return;
1621
+ }
1622
+ this.emit(event, this.getDataToEmit(bytes));
1623
+ }
1624
+ // Try and parse the decrypted bytes as JSON. If we can't parse it, just
1625
+ // return the utf-8 string
1626
+ getDataToEmit(bytes) {
1627
+ let raw = utf8.decode(bytes);
1628
+ try {
1629
+ return JSON.parse(raw);
1630
+ } catch {
1631
+ return raw;
1632
+ }
1633
+ }
1634
+ }
1635
+ class ConnectionManager extends Dispatcher {
1636
+ constructor(key, options) {
1637
+ super();
1638
+ this.state = "initialized";
1639
+ this.connection = null;
1640
+ this.key = key;
1641
+ this.options = options;
1642
+ this.timeline = this.options.timeline;
1643
+ this.usingTLS = this.options.useTLS;
1644
+ this.errorCallbacks = this.buildErrorCallbacks();
1645
+ this.connectionCallbacks = this.buildConnectionCallbacks(
1646
+ this.errorCallbacks
1647
+ );
1648
+ this.handshakeCallbacks = this.buildHandshakeCallbacks(this.errorCallbacks);
1649
+ var Network2 = NodeJS.getNetwork();
1650
+ Network2.bind("online", () => {
1651
+ this.timeline.info({ netinfo: "online" });
1652
+ if (this.state === "connecting" || this.state === "unavailable") {
1653
+ this.retryIn(0);
1654
+ }
1655
+ });
1656
+ Network2.bind("offline", () => {
1657
+ this.timeline.info({ netinfo: "offline" });
1658
+ if (this.connection) {
1659
+ this.sendActivityCheck();
1660
+ }
1661
+ });
1662
+ this.updateStrategy();
1663
+ }
1664
+ /** Establishes a connection to Pusher.
1665
+ *
1666
+ * Does nothing when connection is already established. See top-level doc
1667
+ * to find events emitted on connection attempts.
1668
+ */
1669
+ connect() {
1670
+ if (this.connection || this.runner) {
1671
+ return;
1672
+ }
1673
+ if (!this.strategy.isSupported()) {
1674
+ this.updateState("failed");
1675
+ return;
1676
+ }
1677
+ this.updateState("connecting");
1678
+ this.startConnecting();
1679
+ this.setUnavailableTimer();
1680
+ }
1681
+ /** Sends raw data.
1682
+ *
1683
+ * @param {String} data
1684
+ */
1685
+ send(data) {
1686
+ if (this.connection) {
1687
+ return this.connection.send(data);
1688
+ } else {
1689
+ return false;
1690
+ }
1691
+ }
1692
+ /** Sends an event.
1693
+ *
1694
+ * @param {String} name
1695
+ * @param {String} data
1696
+ * @param {String} [channel]
1697
+ * @returns {Boolean} whether message was sent or not
1698
+ */
1699
+ send_event(name, data, channel) {
1700
+ if (this.connection) {
1701
+ return this.connection.send_event(name, data, channel);
1702
+ } else {
1703
+ return false;
1704
+ }
1705
+ }
1706
+ /** Closes the connection. */
1707
+ disconnect() {
1708
+ this.disconnectInternally();
1709
+ this.updateState("disconnected");
1710
+ }
1711
+ isUsingTLS() {
1712
+ return this.usingTLS;
1713
+ }
1714
+ startConnecting() {
1715
+ var callback = (error, handshake) => {
1716
+ if (error) {
1717
+ this.runner = this.strategy.connect(0, callback);
1718
+ } else {
1719
+ if (handshake.action === "error") {
1720
+ this.emit("error", {
1721
+ type: "HandshakeError",
1722
+ error: handshake.error
1723
+ });
1724
+ this.timeline.error({ handshakeError: handshake.error });
1725
+ } else {
1726
+ this.abortConnecting();
1727
+ this.handshakeCallbacks[handshake.action](handshake);
1728
+ }
1729
+ }
1730
+ };
1731
+ this.runner = this.strategy.connect(0, callback);
1732
+ }
1733
+ abortConnecting() {
1734
+ if (this.runner) {
1735
+ this.runner.abort();
1736
+ this.runner = null;
1737
+ }
1738
+ }
1739
+ disconnectInternally() {
1740
+ this.abortConnecting();
1741
+ this.clearRetryTimer();
1742
+ this.clearUnavailableTimer();
1743
+ if (this.connection) {
1744
+ var connection = this.abandonConnection();
1745
+ connection.close();
1746
+ }
1747
+ }
1748
+ updateStrategy() {
1749
+ this.strategy = this.options.getStrategy({
1750
+ key: this.key,
1751
+ timeline: this.timeline,
1752
+ useTLS: this.usingTLS
1753
+ });
1754
+ }
1755
+ retryIn(delay) {
1756
+ this.timeline.info({ action: "retry", delay });
1757
+ if (delay > 0) {
1758
+ this.emit("connecting_in", Math.round(delay / 1e3));
1759
+ }
1760
+ this.retryTimer = new OneOffTimer(delay || 0, () => {
1761
+ this.disconnectInternally();
1762
+ this.connect();
1763
+ });
1764
+ }
1765
+ clearRetryTimer() {
1766
+ if (this.retryTimer) {
1767
+ this.retryTimer.ensureAborted();
1768
+ this.retryTimer = null;
1769
+ }
1770
+ }
1771
+ setUnavailableTimer() {
1772
+ this.unavailableTimer = new OneOffTimer(this.options.unavailableTimeout, () => {
1773
+ this.updateState("unavailable");
1774
+ });
1775
+ }
1776
+ clearUnavailableTimer() {
1777
+ if (this.unavailableTimer) {
1778
+ this.unavailableTimer.ensureAborted();
1779
+ }
1780
+ }
1781
+ sendActivityCheck() {
1782
+ this.stopActivityCheck();
1783
+ this.connection.ping();
1784
+ this.activityTimer = new OneOffTimer(this.options.pongTimeout, () => {
1785
+ this.timeline.error({ pong_timed_out: this.options.pongTimeout });
1786
+ this.retryIn(0);
1787
+ });
1788
+ }
1789
+ resetActivityCheck() {
1790
+ this.stopActivityCheck();
1791
+ if (this.connection && !this.connection.handlesActivityChecks()) {
1792
+ this.activityTimer = new OneOffTimer(this.activityTimeout, () => {
1793
+ this.sendActivityCheck();
1794
+ });
1795
+ }
1796
+ }
1797
+ stopActivityCheck() {
1798
+ if (this.activityTimer) {
1799
+ this.activityTimer.ensureAborted();
1800
+ }
1801
+ }
1802
+ buildConnectionCallbacks(errorCallbacks) {
1803
+ return extend({}, errorCallbacks, {
1804
+ message: (message) => {
1805
+ this.resetActivityCheck();
1806
+ this.emit("message", message);
1807
+ },
1808
+ ping: () => {
1809
+ this.send_event("pusher:pong", {});
1810
+ },
1811
+ activity: () => {
1812
+ this.resetActivityCheck();
1813
+ },
1814
+ error: (error) => {
1815
+ this.emit("error", error);
1816
+ },
1817
+ closed: () => {
1818
+ this.abandonConnection();
1819
+ if (this.shouldRetry()) {
1820
+ this.retryIn(1e3);
1821
+ }
1822
+ }
1823
+ });
1824
+ }
1825
+ buildHandshakeCallbacks(errorCallbacks) {
1826
+ return extend({}, errorCallbacks, {
1827
+ connected: (handshake) => {
1828
+ this.activityTimeout = Math.min(
1829
+ this.options.activityTimeout,
1830
+ handshake.activityTimeout,
1831
+ handshake.connection.activityTimeout || Infinity
1832
+ );
1833
+ this.clearUnavailableTimer();
1834
+ this.setConnection(handshake.connection);
1835
+ this.socket_id = this.connection.id;
1836
+ this.updateState("connected", { socket_id: this.socket_id });
1837
+ }
1838
+ });
1839
+ }
1840
+ buildErrorCallbacks() {
1841
+ let withErrorEmitted = (callback) => {
1842
+ return (result) => {
1843
+ if (result.error) {
1844
+ this.emit("error", { type: "WebSocketError", error: result.error });
1845
+ }
1846
+ callback(result);
1847
+ };
1848
+ };
1849
+ return {
1850
+ tls_only: withErrorEmitted(() => {
1851
+ this.usingTLS = true;
1852
+ this.updateStrategy();
1853
+ this.retryIn(0);
1854
+ }),
1855
+ refused: withErrorEmitted(() => {
1856
+ this.disconnect();
1857
+ }),
1858
+ backoff: withErrorEmitted(() => {
1859
+ this.retryIn(1e3);
1860
+ }),
1861
+ retry: withErrorEmitted(() => {
1862
+ this.retryIn(0);
1863
+ })
1864
+ };
1865
+ }
1866
+ setConnection(connection) {
1867
+ this.connection = connection;
1868
+ for (var event in this.connectionCallbacks) {
1869
+ this.connection.bind(event, this.connectionCallbacks[event]);
1870
+ }
1871
+ this.resetActivityCheck();
1872
+ }
1873
+ abandonConnection() {
1874
+ if (!this.connection) {
1875
+ return;
1876
+ }
1877
+ this.stopActivityCheck();
1878
+ for (var event in this.connectionCallbacks) {
1879
+ this.connection.unbind(event, this.connectionCallbacks[event]);
1880
+ }
1881
+ var connection = this.connection;
1882
+ this.connection = null;
1883
+ return connection;
1884
+ }
1885
+ updateState(newState, data) {
1886
+ var previousState = this.state;
1887
+ this.state = newState;
1888
+ if (previousState !== newState) {
1889
+ var newStateDescription = newState;
1890
+ if (newStateDescription === "connected") {
1891
+ newStateDescription += " with new socket ID " + data.socket_id;
1892
+ }
1893
+ Logger$1.debug(
1894
+ "State changed",
1895
+ previousState + " -> " + newStateDescription
1896
+ );
1897
+ this.timeline.info({ state: newState, params: data });
1898
+ this.emit("state_change", { previous: previousState, current: newState });
1899
+ this.emit(newState, data);
1900
+ }
1901
+ }
1902
+ shouldRetry() {
1903
+ return this.state === "connecting" || this.state === "connected";
1904
+ }
1905
+ }
1906
+ class Channels {
1907
+ constructor() {
1908
+ this.channels = {};
1909
+ }
1910
+ /** Creates or retrieves an existing channel by its name.
1911
+ *
1912
+ * @param {String} name
1913
+ * @param {Pusher} pusher
1914
+ * @return {Channel}
1915
+ */
1916
+ add(name, pusher) {
1917
+ if (!this.channels[name]) {
1918
+ this.channels[name] = createChannel(name, pusher);
1919
+ }
1920
+ return this.channels[name];
1921
+ }
1922
+ /** Returns a list of all channels
1923
+ *
1924
+ * @return {Array}
1925
+ */
1926
+ all() {
1927
+ return values(this.channels);
1928
+ }
1929
+ /** Finds a channel by its name.
1930
+ *
1931
+ * @param {String} name
1932
+ * @return {Channel} channel or null if it doesn't exist
1933
+ */
1934
+ find(name) {
1935
+ return this.channels[name];
1936
+ }
1937
+ /** Removes a channel from the map.
1938
+ *
1939
+ * @param {String} name
1940
+ */
1941
+ remove(name) {
1942
+ var channel = this.channels[name];
1943
+ delete this.channels[name];
1944
+ return channel;
1945
+ }
1946
+ /** Proxies disconnection signal to all channels. */
1947
+ disconnect() {
1948
+ objectApply(this.channels, function(channel) {
1949
+ channel.disconnect();
1950
+ });
1951
+ }
1952
+ }
1953
+ function createChannel(name, pusher) {
1954
+ if (name.indexOf("private-encrypted-") === 0) {
1955
+ if (pusher.config.nacl) {
1956
+ return Factory.createEncryptedChannel(name, pusher, pusher.config.nacl);
1957
+ }
1958
+ let errMsg = "Tried to subscribe to a private-encrypted- channel but no nacl implementation available";
1959
+ let suffix = UrlStore.buildLogSuffix("encryptedChannelSupport");
1960
+ throw new UnsupportedFeature(`${errMsg}. ${suffix}`);
1961
+ } else if (name.indexOf("private-") === 0) {
1962
+ return Factory.createPrivateChannel(name, pusher);
1963
+ } else if (name.indexOf("presence-") === 0) {
1964
+ return Factory.createPresenceChannel(name, pusher);
1965
+ } else if (name.indexOf("#") === 0) {
1966
+ throw new BadChannelName(
1967
+ 'Cannot create a channel with name "' + name + '".'
1968
+ );
1969
+ } else {
1970
+ return Factory.createChannel(name, pusher);
1971
+ }
1972
+ }
1973
+ var Factory = {
1974
+ createChannels() {
1975
+ return new Channels();
1976
+ },
1977
+ createConnectionManager(key, options) {
1978
+ return new ConnectionManager(key, options);
1979
+ },
1980
+ createChannel(name, pusher) {
1981
+ return new Channel(name, pusher);
1982
+ },
1983
+ createPrivateChannel(name, pusher) {
1984
+ return new PrivateChannel(name, pusher);
1985
+ },
1986
+ createPresenceChannel(name, pusher) {
1987
+ return new PresenceChannel(name, pusher);
1988
+ },
1989
+ createEncryptedChannel(name, pusher, nacl2) {
1990
+ return new EncryptedChannel(name, pusher, nacl2);
1991
+ },
1992
+ createTimelineSender(timeline, options) {
1993
+ return new TimelineSender(timeline, options);
1994
+ },
1995
+ createHandshake(transport, callback) {
1996
+ return new Handshake(transport, callback);
1997
+ },
1998
+ createAssistantToTheTransportManager(manager, transport, options) {
1999
+ return new AssistantToTheTransportManager(manager, transport, options);
2000
+ }
2001
+ };
2002
+ class TransportManager {
2003
+ constructor(options) {
2004
+ this.options = options || {};
2005
+ this.livesLeft = this.options.lives || Infinity;
2006
+ }
2007
+ /** Creates a assistant for the transport.
2008
+ *
2009
+ * @param {Transport} transport
2010
+ * @returns {AssistantToTheTransportManager}
2011
+ */
2012
+ getAssistant(transport) {
2013
+ return Factory.createAssistantToTheTransportManager(this, transport, {
2014
+ minPingDelay: this.options.minPingDelay,
2015
+ maxPingDelay: this.options.maxPingDelay
2016
+ });
2017
+ }
2018
+ /** Returns whether the transport has any lives left.
2019
+ *
2020
+ * @returns {Boolean}
2021
+ */
2022
+ isAlive() {
2023
+ return this.livesLeft > 0;
2024
+ }
2025
+ /** Takes one life from the transport. */
2026
+ reportDeath() {
2027
+ this.livesLeft -= 1;
2028
+ }
2029
+ }
2030
+ class SequentialStrategy {
2031
+ constructor(strategies, options) {
2032
+ this.strategies = strategies;
2033
+ this.loop = Boolean(options.loop);
2034
+ this.failFast = Boolean(options.failFast);
2035
+ this.timeout = options.timeout;
2036
+ this.timeoutLimit = options.timeoutLimit;
2037
+ }
2038
+ isSupported() {
2039
+ return any(this.strategies, Util.method("isSupported"));
2040
+ }
2041
+ connect(minPriority, callback) {
2042
+ var strategies = this.strategies;
2043
+ var current = 0;
2044
+ var timeout = this.timeout;
2045
+ var runner = null;
2046
+ var tryNextStrategy = (error, handshake) => {
2047
+ if (handshake) {
2048
+ callback(null, handshake);
2049
+ } else {
2050
+ current = current + 1;
2051
+ if (this.loop) {
2052
+ current = current % strategies.length;
2053
+ }
2054
+ if (current < strategies.length) {
2055
+ if (timeout) {
2056
+ timeout = timeout * 2;
2057
+ if (this.timeoutLimit) {
2058
+ timeout = Math.min(timeout, this.timeoutLimit);
2059
+ }
2060
+ }
2061
+ runner = this.tryStrategy(
2062
+ strategies[current],
2063
+ minPriority,
2064
+ { timeout, failFast: this.failFast },
2065
+ tryNextStrategy
2066
+ );
2067
+ } else {
2068
+ callback(true);
2069
+ }
2070
+ }
2071
+ };
2072
+ runner = this.tryStrategy(
2073
+ strategies[current],
2074
+ minPriority,
2075
+ { timeout, failFast: this.failFast },
2076
+ tryNextStrategy
2077
+ );
2078
+ return {
2079
+ abort: function() {
2080
+ runner.abort();
2081
+ },
2082
+ forceMinPriority: function(p) {
2083
+ minPriority = p;
2084
+ if (runner) {
2085
+ runner.forceMinPriority(p);
2086
+ }
2087
+ }
2088
+ };
2089
+ }
2090
+ tryStrategy(strategy, minPriority, options, callback) {
2091
+ var timer = null;
2092
+ var runner = null;
2093
+ if (options.timeout > 0) {
2094
+ timer = new OneOffTimer(options.timeout, function() {
2095
+ runner.abort();
2096
+ callback(true);
2097
+ });
2098
+ }
2099
+ runner = strategy.connect(minPriority, function(error, handshake) {
2100
+ if (error && timer && timer.isRunning() && !options.failFast) {
2101
+ return;
2102
+ }
2103
+ if (timer) {
2104
+ timer.ensureAborted();
2105
+ }
2106
+ callback(error, handshake);
2107
+ });
2108
+ return {
2109
+ abort: function() {
2110
+ if (timer) {
2111
+ timer.ensureAborted();
2112
+ }
2113
+ runner.abort();
2114
+ },
2115
+ forceMinPriority: function(p) {
2116
+ runner.forceMinPriority(p);
2117
+ }
2118
+ };
2119
+ }
2120
+ }
2121
+ class BestConnectedEverStrategy {
2122
+ constructor(strategies) {
2123
+ this.strategies = strategies;
2124
+ }
2125
+ isSupported() {
2126
+ return any(this.strategies, Util.method("isSupported"));
2127
+ }
2128
+ connect(minPriority, callback) {
2129
+ return connect(this.strategies, minPriority, function(i, runners) {
2130
+ return function(error, handshake) {
2131
+ runners[i].error = error;
2132
+ if (error) {
2133
+ if (allRunnersFailed(runners)) {
2134
+ callback(true);
2135
+ }
2136
+ return;
2137
+ }
2138
+ apply(runners, function(runner) {
2139
+ runner.forceMinPriority(handshake.transport.priority);
2140
+ });
2141
+ callback(null, handshake);
2142
+ };
2143
+ });
2144
+ }
2145
+ }
2146
+ function connect(strategies, minPriority, callbackBuilder) {
2147
+ var runners = map(strategies, function(strategy, i, _, rs) {
2148
+ return strategy.connect(minPriority, callbackBuilder(i, rs));
2149
+ });
2150
+ return {
2151
+ abort: function() {
2152
+ apply(runners, abortRunner);
2153
+ },
2154
+ forceMinPriority: function(p) {
2155
+ apply(runners, function(runner) {
2156
+ runner.forceMinPriority(p);
2157
+ });
2158
+ }
2159
+ };
2160
+ }
2161
+ function allRunnersFailed(runners) {
2162
+ return all(runners, function(runner) {
2163
+ return Boolean(runner.error);
2164
+ });
2165
+ }
2166
+ function abortRunner(runner) {
2167
+ if (!runner.error && !runner.aborted) {
2168
+ runner.abort();
2169
+ runner.aborted = true;
2170
+ }
2171
+ }
2172
+ class WebSocketPrioritizedCachedStrategy {
2173
+ constructor(strategy, transports, options) {
2174
+ this.strategy = strategy;
2175
+ this.transports = transports;
2176
+ this.ttl = options.ttl || 1800 * 1e3;
2177
+ this.usingTLS = options.useTLS;
2178
+ this.timeline = options.timeline;
2179
+ }
2180
+ isSupported() {
2181
+ return this.strategy.isSupported();
2182
+ }
2183
+ connect(minPriority, callback) {
2184
+ var usingTLS = this.usingTLS;
2185
+ var info = fetchTransportCache(usingTLS);
2186
+ var cacheSkipCount = info && info.cacheSkipCount ? info.cacheSkipCount : 0;
2187
+ var strategies = [this.strategy];
2188
+ if (info && info.timestamp + this.ttl >= Util.now()) {
2189
+ var transport = this.transports[info.transport];
2190
+ if (transport) {
2191
+ if (["ws", "wss"].includes(info.transport) || cacheSkipCount > 3) {
2192
+ this.timeline.info({
2193
+ cached: true,
2194
+ transport: info.transport,
2195
+ latency: info.latency
2196
+ });
2197
+ strategies.push(
2198
+ new SequentialStrategy([transport], {
2199
+ timeout: info.latency * 2 + 1e3,
2200
+ failFast: true
2201
+ })
2202
+ );
2203
+ } else {
2204
+ cacheSkipCount++;
2205
+ }
2206
+ }
2207
+ }
2208
+ var startTimestamp = Util.now();
2209
+ var runner = strategies.pop().connect(minPriority, function cb(error, handshake) {
2210
+ if (error) {
2211
+ flushTransportCache(usingTLS);
2212
+ if (strategies.length > 0) {
2213
+ startTimestamp = Util.now();
2214
+ runner = strategies.pop().connect(minPriority, cb);
2215
+ } else {
2216
+ callback(error);
2217
+ }
2218
+ } else {
2219
+ storeTransportCache(
2220
+ usingTLS,
2221
+ handshake.transport.name,
2222
+ Util.now() - startTimestamp,
2223
+ cacheSkipCount
2224
+ );
2225
+ callback(null, handshake);
2226
+ }
2227
+ });
2228
+ return {
2229
+ abort: function() {
2230
+ runner.abort();
2231
+ },
2232
+ forceMinPriority: function(p) {
2233
+ minPriority = p;
2234
+ if (runner) {
2235
+ runner.forceMinPriority(p);
2236
+ }
2237
+ }
2238
+ };
2239
+ }
2240
+ }
2241
+ function getTransportCacheKey(usingTLS) {
2242
+ return "pusherTransport" + (usingTLS ? "TLS" : "NonTLS");
2243
+ }
2244
+ function fetchTransportCache(usingTLS) {
2245
+ var storage = NodeJS.getLocalStorage();
2246
+ if (storage) {
2247
+ try {
2248
+ var serializedCache = storage[getTransportCacheKey(usingTLS)];
2249
+ if (serializedCache) {
2250
+ return JSON.parse(serializedCache);
2251
+ }
2252
+ } catch (e) {
2253
+ flushTransportCache(usingTLS);
2254
+ }
2255
+ }
2256
+ return null;
2257
+ }
2258
+ function storeTransportCache(usingTLS, transport, latency, cacheSkipCount) {
2259
+ var storage = NodeJS.getLocalStorage();
2260
+ if (storage) {
2261
+ try {
2262
+ storage[getTransportCacheKey(usingTLS)] = safeJSONStringify({
2263
+ timestamp: Util.now(),
2264
+ transport,
2265
+ latency,
2266
+ cacheSkipCount
2267
+ });
2268
+ } catch (e) {
2269
+ }
2270
+ }
2271
+ }
2272
+ function flushTransportCache(usingTLS) {
2273
+ var storage = NodeJS.getLocalStorage();
2274
+ if (storage) {
2275
+ try {
2276
+ delete storage[getTransportCacheKey(usingTLS)];
2277
+ } catch (e) {
2278
+ }
2279
+ }
2280
+ }
2281
+ class DelayedStrategy {
2282
+ constructor(strategy, { delay: number }) {
2283
+ this.strategy = strategy;
2284
+ this.options = { delay: number };
2285
+ }
2286
+ isSupported() {
2287
+ return this.strategy.isSupported();
2288
+ }
2289
+ connect(minPriority, callback) {
2290
+ var strategy = this.strategy;
2291
+ var runner;
2292
+ var timer = new OneOffTimer(this.options.delay, function() {
2293
+ runner = strategy.connect(minPriority, callback);
2294
+ });
2295
+ return {
2296
+ abort: function() {
2297
+ timer.ensureAborted();
2298
+ if (runner) {
2299
+ runner.abort();
2300
+ }
2301
+ },
2302
+ forceMinPriority: function(p) {
2303
+ minPriority = p;
2304
+ if (runner) {
2305
+ runner.forceMinPriority(p);
2306
+ }
2307
+ }
2308
+ };
2309
+ }
2310
+ }
2311
+ class IfStrategy {
2312
+ constructor(test, trueBranch, falseBranch) {
2313
+ this.test = test;
2314
+ this.trueBranch = trueBranch;
2315
+ this.falseBranch = falseBranch;
2316
+ }
2317
+ isSupported() {
2318
+ var branch = this.test() ? this.trueBranch : this.falseBranch;
2319
+ return branch.isSupported();
2320
+ }
2321
+ connect(minPriority, callback) {
2322
+ var branch = this.test() ? this.trueBranch : this.falseBranch;
2323
+ return branch.connect(minPriority, callback);
2324
+ }
2325
+ }
2326
+ class FirstConnectedStrategy {
2327
+ constructor(strategy) {
2328
+ this.strategy = strategy;
2329
+ }
2330
+ isSupported() {
2331
+ return this.strategy.isSupported();
2332
+ }
2333
+ connect(minPriority, callback) {
2334
+ var runner = this.strategy.connect(
2335
+ minPriority,
2336
+ function(error, handshake) {
2337
+ if (handshake) {
2338
+ runner.abort();
2339
+ }
2340
+ callback(error, handshake);
2341
+ }
2342
+ );
2343
+ return runner;
2344
+ }
2345
+ }
2346
+ function testSupportsStrategy(strategy) {
2347
+ return function() {
2348
+ return strategy.isSupported();
2349
+ };
2350
+ }
2351
+ var getDefaultStrategy$1 = function(config2, baseOptions, defineTransport2) {
2352
+ var definedTransports = {};
2353
+ function defineTransportStrategy(name, type, priority, options, manager) {
2354
+ var transport = defineTransport2(
2355
+ config2,
2356
+ name,
2357
+ type,
2358
+ priority,
2359
+ options,
2360
+ manager
2361
+ );
2362
+ definedTransports[name] = transport;
2363
+ return transport;
2364
+ }
2365
+ var ws_options = Object.assign({}, baseOptions, {
2366
+ hostNonTLS: config2.wsHost + ":" + config2.wsPort,
2367
+ hostTLS: config2.wsHost + ":" + config2.wssPort,
2368
+ httpPath: config2.wsPath
2369
+ });
2370
+ var wss_options = extend({}, ws_options, {
2371
+ useTLS: true
2372
+ });
2373
+ var http_options = Object.assign({}, baseOptions, {
2374
+ hostNonTLS: config2.httpHost + ":" + config2.httpPort,
2375
+ hostTLS: config2.httpHost + ":" + config2.httpsPort,
2376
+ httpPath: config2.httpPath
2377
+ });
2378
+ var timeouts = {
2379
+ loop: true,
2380
+ timeout: 15e3,
2381
+ timeoutLimit: 6e4
2382
+ };
2383
+ var ws_manager = new TransportManager({
2384
+ minPingDelay: 1e4,
2385
+ maxPingDelay: config2.activityTimeout
2386
+ });
2387
+ var streaming_manager = new TransportManager({
2388
+ lives: 2,
2389
+ minPingDelay: 1e4,
2390
+ maxPingDelay: config2.activityTimeout
2391
+ });
2392
+ var ws_transport = defineTransportStrategy(
2393
+ "ws",
2394
+ "ws",
2395
+ 3,
2396
+ ws_options,
2397
+ ws_manager
2398
+ );
2399
+ var wss_transport = defineTransportStrategy(
2400
+ "wss",
2401
+ "ws",
2402
+ 3,
2403
+ wss_options,
2404
+ ws_manager
2405
+ );
2406
+ var xhr_streaming_transport = defineTransportStrategy(
2407
+ "xhr_streaming",
2408
+ "xhr_streaming",
2409
+ 1,
2410
+ http_options,
2411
+ streaming_manager
2412
+ );
2413
+ var xhr_polling_transport = defineTransportStrategy(
2414
+ "xhr_polling",
2415
+ "xhr_polling",
2416
+ 1,
2417
+ http_options
2418
+ );
2419
+ var ws_loop = new SequentialStrategy([ws_transport], timeouts);
2420
+ var wss_loop = new SequentialStrategy([wss_transport], timeouts);
2421
+ var streaming_loop = new SequentialStrategy(
2422
+ [xhr_streaming_transport],
2423
+ timeouts
2424
+ );
2425
+ var polling_loop = new SequentialStrategy([xhr_polling_transport], timeouts);
2426
+ var http_loop = new SequentialStrategy(
2427
+ [
2428
+ new IfStrategy(
2429
+ testSupportsStrategy(streaming_loop),
2430
+ new BestConnectedEverStrategy([
2431
+ streaming_loop,
2432
+ new DelayedStrategy(polling_loop, { delay: 4e3 })
2433
+ ]),
2434
+ polling_loop
2435
+ )
2436
+ ],
2437
+ timeouts
2438
+ );
2439
+ var wsStrategy;
2440
+ if (baseOptions.useTLS) {
2441
+ wsStrategy = new BestConnectedEverStrategy([
2442
+ ws_loop,
2443
+ new DelayedStrategy(http_loop, { delay: 2e3 })
2444
+ ]);
2445
+ } else {
2446
+ wsStrategy = new BestConnectedEverStrategy([
2447
+ ws_loop,
2448
+ new DelayedStrategy(wss_loop, { delay: 2e3 }),
2449
+ new DelayedStrategy(http_loop, { delay: 5e3 })
2450
+ ]);
2451
+ }
2452
+ return new WebSocketPrioritizedCachedStrategy(
2453
+ new FirstConnectedStrategy(
2454
+ new IfStrategy(testSupportsStrategy(ws_transport), wsStrategy, http_loop)
2455
+ ),
2456
+ definedTransports,
2457
+ {
2458
+ ttl: 18e5,
2459
+ timeline: baseOptions.timeline,
2460
+ useTLS: baseOptions.useTLS
2461
+ }
2462
+ );
2463
+ };
2464
+ function transportConnectionInitializer$1() {
2465
+ var self = this;
2466
+ self.timeline.info(
2467
+ self.buildTimelineMessage({
2468
+ transport: self.name + (self.options.useTLS ? "s" : "")
2469
+ })
2470
+ );
2471
+ if (self.hooks.isInitialized()) {
2472
+ self.changeState("initialized");
2473
+ } else {
2474
+ self.onClose();
2475
+ }
2476
+ }
2477
+ const MAX_BUFFER_LENGTH = 256 * 1024;
2478
+ class HTTPRequest extends Dispatcher {
2479
+ constructor(hooks2, method, url) {
2480
+ super();
2481
+ this.hooks = hooks2;
2482
+ this.method = method;
2483
+ this.url = url;
2484
+ }
2485
+ start(payload) {
2486
+ this.position = 0;
2487
+ this.xhr = this.hooks.getRequest(this);
2488
+ this.unloader = () => {
2489
+ this.close();
2490
+ };
2491
+ NodeJS.addUnloadListener(this.unloader);
2492
+ this.xhr.open(this.method, this.url, true);
2493
+ if (this.xhr.setRequestHeader) {
2494
+ this.xhr.setRequestHeader("Content-Type", "application/json");
2495
+ }
2496
+ this.xhr.send(payload);
2497
+ }
2498
+ close() {
2499
+ if (this.unloader) {
2500
+ NodeJS.removeUnloadListener(this.unloader);
2501
+ this.unloader = null;
2502
+ }
2503
+ if (this.xhr) {
2504
+ this.hooks.abortRequest(this.xhr);
2505
+ this.xhr = null;
2506
+ }
2507
+ }
2508
+ onChunk(status, data) {
2509
+ while (true) {
2510
+ var chunk = this.advanceBuffer(data);
2511
+ if (chunk) {
2512
+ this.emit("chunk", { status, data: chunk });
2513
+ } else {
2514
+ break;
2515
+ }
2516
+ }
2517
+ if (this.isBufferTooLong(data)) {
2518
+ this.emit("buffer_too_long");
2519
+ }
2520
+ }
2521
+ advanceBuffer(buffer) {
2522
+ var unreadData = buffer.slice(this.position);
2523
+ var endOfLinePosition = unreadData.indexOf("\n");
2524
+ if (endOfLinePosition !== -1) {
2525
+ this.position += endOfLinePosition + 1;
2526
+ return unreadData.slice(0, endOfLinePosition);
2527
+ } else {
2528
+ return null;
2529
+ }
2530
+ }
2531
+ isBufferTooLong(buffer) {
2532
+ return this.position === buffer.length && buffer.length > MAX_BUFFER_LENGTH;
2533
+ }
2534
+ }
2535
+ var State = /* @__PURE__ */ ((State2) => {
2536
+ State2[State2["CONNECTING"] = 0] = "CONNECTING";
2537
+ State2[State2["OPEN"] = 1] = "OPEN";
2538
+ State2[State2["CLOSED"] = 3] = "CLOSED";
2539
+ return State2;
2540
+ })(State || {});
2541
+ var autoIncrement = 1;
2542
+ class HTTPSocket {
2543
+ constructor(hooks2, url) {
2544
+ this.hooks = hooks2;
2545
+ this.session = randomNumber(1e3) + "/" + randomString(8);
2546
+ this.location = getLocation(url);
2547
+ this.readyState = State.CONNECTING;
2548
+ this.openStream();
2549
+ }
2550
+ send(payload) {
2551
+ return this.sendRaw(JSON.stringify([payload]));
2552
+ }
2553
+ ping() {
2554
+ this.hooks.sendHeartbeat(this);
2555
+ }
2556
+ close(code, reason) {
2557
+ this.onClose(code, reason, true);
2558
+ }
2559
+ /** For internal use only */
2560
+ sendRaw(payload) {
2561
+ if (this.readyState === State.OPEN) {
2562
+ try {
2563
+ NodeJS.createSocketRequest(
2564
+ "POST",
2565
+ getUniqueURL(getSendURL(this.location, this.session))
2566
+ ).start(payload);
2567
+ return true;
2568
+ } catch (e) {
2569
+ return false;
2570
+ }
2571
+ } else {
2572
+ return false;
2573
+ }
2574
+ }
2575
+ /** For internal use only */
2576
+ reconnect() {
2577
+ this.closeStream();
2578
+ this.openStream();
2579
+ }
2580
+ /** For internal use only */
2581
+ onClose(code, reason, wasClean) {
2582
+ this.closeStream();
2583
+ this.readyState = State.CLOSED;
2584
+ if (this.onclose) {
2585
+ this.onclose({
2586
+ code,
2587
+ reason,
2588
+ wasClean
2589
+ });
2590
+ }
2591
+ }
2592
+ onChunk(chunk) {
2593
+ if (chunk.status !== 200) {
2594
+ return;
2595
+ }
2596
+ if (this.readyState === State.OPEN) {
2597
+ this.onActivity();
2598
+ }
2599
+ var payload;
2600
+ var type = chunk.data.slice(0, 1);
2601
+ switch (type) {
2602
+ case "o":
2603
+ payload = JSON.parse(chunk.data.slice(1) || "{}");
2604
+ this.onOpen(payload);
2605
+ break;
2606
+ case "a":
2607
+ payload = JSON.parse(chunk.data.slice(1) || "[]");
2608
+ for (var i = 0; i < payload.length; i++) {
2609
+ this.onEvent(payload[i]);
2610
+ }
2611
+ break;
2612
+ case "m":
2613
+ payload = JSON.parse(chunk.data.slice(1) || "null");
2614
+ this.onEvent(payload);
2615
+ break;
2616
+ case "h":
2617
+ this.hooks.onHeartbeat(this);
2618
+ break;
2619
+ case "c":
2620
+ payload = JSON.parse(chunk.data.slice(1) || "[]");
2621
+ this.onClose(payload[0], payload[1], true);
2622
+ break;
2623
+ }
2624
+ }
2625
+ onOpen(options) {
2626
+ if (this.readyState === State.CONNECTING) {
2627
+ if (options && options.hostname) {
2628
+ this.location.base = replaceHost(this.location.base, options.hostname);
2629
+ }
2630
+ this.readyState = State.OPEN;
2631
+ if (this.onopen) {
2632
+ this.onopen();
2633
+ }
2634
+ } else {
2635
+ this.onClose(1006, "Server lost session", true);
2636
+ }
2637
+ }
2638
+ onEvent(event) {
2639
+ if (this.readyState === State.OPEN && this.onmessage) {
2640
+ this.onmessage({ data: event });
2641
+ }
2642
+ }
2643
+ onActivity() {
2644
+ if (this.onactivity) {
2645
+ this.onactivity();
2646
+ }
2647
+ }
2648
+ onError(error) {
2649
+ if (this.onerror) {
2650
+ this.onerror(error);
2651
+ }
2652
+ }
2653
+ openStream() {
2654
+ this.stream = NodeJS.createSocketRequest(
2655
+ "POST",
2656
+ getUniqueURL(this.hooks.getReceiveURL(this.location, this.session))
2657
+ );
2658
+ this.stream.bind("chunk", (chunk) => {
2659
+ this.onChunk(chunk);
2660
+ });
2661
+ this.stream.bind("finished", (status) => {
2662
+ this.hooks.onFinished(this, status);
2663
+ });
2664
+ this.stream.bind("buffer_too_long", () => {
2665
+ this.reconnect();
2666
+ });
2667
+ try {
2668
+ this.stream.start();
2669
+ } catch (error) {
2670
+ Util.defer(() => {
2671
+ this.onError(error);
2672
+ this.onClose(1006, "Could not start streaming", false);
2673
+ });
2674
+ }
2675
+ }
2676
+ closeStream() {
2677
+ if (this.stream) {
2678
+ this.stream.unbind_all();
2679
+ this.stream.close();
2680
+ this.stream = null;
2681
+ }
2682
+ }
2683
+ }
2684
+ function getLocation(url) {
2685
+ var parts = /([^\?]*)\/*(\??.*)/.exec(url);
2686
+ return {
2687
+ base: parts[1],
2688
+ queryString: parts[2]
2689
+ };
2690
+ }
2691
+ function getSendURL(url, session) {
2692
+ return url.base + "/" + session + "/xhr_send";
2693
+ }
2694
+ function getUniqueURL(url) {
2695
+ var separator = url.indexOf("?") === -1 ? "?" : "&";
2696
+ return url + separator + "t=" + +/* @__PURE__ */ new Date() + "&n=" + autoIncrement++;
2697
+ }
2698
+ function replaceHost(url, hostname) {
2699
+ var urlParts = /(https?:\/\/)([^\/:]+)((\/|:)?.*)/.exec(url);
2700
+ return urlParts[1] + hostname + urlParts[3];
2701
+ }
2702
+ function randomNumber(max) {
2703
+ return NodeJS.randomInt(max);
2704
+ }
2705
+ function randomString(length) {
2706
+ var result = [];
2707
+ for (var i = 0; i < length; i++) {
2708
+ result.push(randomNumber(32).toString(32));
2709
+ }
2710
+ return result.join("");
2711
+ }
2712
+ var hooks$2 = {
2713
+ getReceiveURL: function(url, session) {
2714
+ return url.base + "/" + session + "/xhr_streaming" + url.queryString;
2715
+ },
2716
+ onHeartbeat: function(socket) {
2717
+ socket.sendRaw("[]");
2718
+ },
2719
+ sendHeartbeat: function(socket) {
2720
+ socket.sendRaw("[]");
2721
+ },
2722
+ onFinished: function(socket, status) {
2723
+ socket.onClose(1006, "Connection interrupted (" + status + ")", false);
2724
+ }
2725
+ };
2726
+ var hooks$1 = {
2727
+ getReceiveURL: function(url, session) {
2728
+ return url.base + "/" + session + "/xhr" + url.queryString;
2729
+ },
2730
+ onHeartbeat: function() {
2731
+ },
2732
+ sendHeartbeat: function(socket) {
2733
+ socket.sendRaw("[]");
2734
+ },
2735
+ onFinished: function(socket, status) {
2736
+ if (status === 200) {
2737
+ socket.reconnect();
2738
+ } else {
2739
+ socket.onClose(1006, "Connection interrupted (" + status + ")", false);
2740
+ }
2741
+ }
2742
+ };
2743
+ var hooks = {
2744
+ getRequest: function(socket) {
2745
+ var Constructor = NodeJS.getXHRAPI();
2746
+ var xhr2 = new Constructor();
2747
+ xhr2.onreadystatechange = xhr2.onprogress = function() {
2748
+ switch (xhr2.readyState) {
2749
+ case 3:
2750
+ if (xhr2.responseText && xhr2.responseText.length > 0) {
2751
+ socket.onChunk(xhr2.status, xhr2.responseText);
2752
+ }
2753
+ break;
2754
+ case 4:
2755
+ if (xhr2.responseText && xhr2.responseText.length > 0) {
2756
+ socket.onChunk(xhr2.status, xhr2.responseText);
2757
+ }
2758
+ socket.emit("finished", xhr2.status);
2759
+ socket.close();
2760
+ break;
2761
+ }
2762
+ };
2763
+ return xhr2;
2764
+ },
2765
+ abortRequest: function(xhr2) {
2766
+ xhr2.onreadystatechange = null;
2767
+ xhr2.abort();
2768
+ }
2769
+ };
2770
+ var HTTP = {
2771
+ createStreamingSocket(url) {
2772
+ return this.createSocket(hooks$2, url);
2773
+ },
2774
+ createPollingSocket(url) {
2775
+ return this.createSocket(hooks$1, url);
2776
+ },
2777
+ createSocket(hooks2, url) {
2778
+ return new HTTPSocket(hooks2, url);
2779
+ },
2780
+ createXHR(method, url) {
2781
+ return this.createRequest(hooks, method, url);
2782
+ },
2783
+ createRequest(hooks2, method, url) {
2784
+ return new HTTPRequest(hooks2, method, url);
2785
+ }
2786
+ };
2787
+ var Isomorphic = {
2788
+ getDefaultStrategy: getDefaultStrategy$1,
2789
+ Transports: Transports$2,
2790
+ transportConnectionInitializer: transportConnectionInitializer$1,
2791
+ HTTPFactory: HTTP,
2792
+ setup(PusherClass) {
2793
+ PusherClass.ready();
2794
+ },
2795
+ getLocalStorage() {
2796
+ return void 0;
2797
+ },
2798
+ getClientFeatures() {
2799
+ return keys(
2800
+ filterObject({ ws: Transports$2.ws }, function(t) {
2801
+ return t.isSupported({});
2802
+ })
2803
+ );
2804
+ },
2805
+ getProtocol() {
2806
+ return "http:";
2807
+ },
2808
+ isXHRSupported() {
2809
+ return true;
2810
+ },
2811
+ createSocketRequest(method, url) {
2812
+ if (this.isXHRSupported()) {
2813
+ return this.HTTPFactory.createXHR(method, url);
2814
+ } else {
2815
+ throw "Cross-origin HTTP requests are not supported";
2816
+ }
2817
+ },
2818
+ createXHR() {
2819
+ var Constructor = this.getXHRAPI();
2820
+ return new Constructor();
2821
+ },
2822
+ createWebSocket(url) {
2823
+ var Constructor = this.getWebSocketAPI();
2824
+ return new Constructor(url);
2825
+ },
2826
+ addUnloadListener(listener) {
2827
+ },
2828
+ removeUnloadListener(listener) {
2829
+ }
2830
+ };
2831
+ class NetInfo extends Dispatcher {
2832
+ isOnline() {
2833
+ return true;
2834
+ }
2835
+ }
2836
+ var Network = new NetInfo();
2837
+ var AuthRequestType = /* @__PURE__ */ ((AuthRequestType2) => {
2838
+ AuthRequestType2["UserAuthentication"] = "user-authentication";
2839
+ AuthRequestType2["ChannelAuthorization"] = "channel-authorization";
2840
+ return AuthRequestType2;
2841
+ })(AuthRequestType || {});
2842
+ const ajax = function(context, query, authOptions, authRequestType, callback) {
2843
+ const xhr2 = NodeJS.createXHR();
2844
+ xhr2.open("POST", authOptions.endpoint, true);
2845
+ xhr2.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
2846
+ for (var headerName in authOptions.headers) {
2847
+ xhr2.setRequestHeader(headerName, authOptions.headers[headerName]);
2848
+ }
2849
+ if (authOptions.headersProvider != null) {
2850
+ let dynamicHeaders = authOptions.headersProvider();
2851
+ for (var headerName in dynamicHeaders) {
2852
+ xhr2.setRequestHeader(headerName, dynamicHeaders[headerName]);
2853
+ }
2854
+ }
2855
+ xhr2.onreadystatechange = function() {
2856
+ if (xhr2.readyState === 4) {
2857
+ if (xhr2.status === 200) {
2858
+ let data;
2859
+ let parsed = false;
2860
+ try {
2861
+ data = JSON.parse(xhr2.responseText);
2862
+ parsed = true;
2863
+ } catch (e) {
2864
+ callback(
2865
+ new HTTPAuthError(
2866
+ 200,
2867
+ `JSON returned from ${authRequestType.toString()} endpoint was invalid, yet status code was 200. Data was: ${xhr2.responseText}`
2868
+ ),
2869
+ null
2870
+ );
2871
+ }
2872
+ if (parsed) {
2873
+ callback(null, data);
2874
+ }
2875
+ } else {
2876
+ let suffix = "";
2877
+ switch (authRequestType) {
2878
+ case AuthRequestType.UserAuthentication:
2879
+ suffix = UrlStore.buildLogSuffix("authenticationEndpoint");
2880
+ break;
2881
+ case AuthRequestType.ChannelAuthorization:
2882
+ suffix = `Clients must be authorized to join private or presence channels. ${UrlStore.buildLogSuffix(
2883
+ "authorizationEndpoint"
2884
+ )}`;
2885
+ break;
2886
+ }
2887
+ callback(
2888
+ new HTTPAuthError(
2889
+ xhr2.status,
2890
+ `Unable to retrieve auth string from ${authRequestType.toString()} endpoint - received status: ${xhr2.status} from ${authOptions.endpoint}. ${suffix}`
2891
+ ),
2892
+ null
2893
+ );
2894
+ }
2895
+ }
2896
+ };
2897
+ xhr2.send(query);
2898
+ return xhr2;
2899
+ };
2900
+ var getAgent = function(sender, useTLS) {
2901
+ return function(data, callback) {
2902
+ var scheme = "http" + (useTLS ? "s" : "") + "://";
2903
+ var url = scheme + (sender.host || sender.options.host) + sender.options.path;
2904
+ var query = buildQueryString(data);
2905
+ url += "/2?" + query;
2906
+ var xhr2 = NodeJS.createXHR();
2907
+ xhr2.open("GET", url, true);
2908
+ xhr2.onreadystatechange = function() {
2909
+ if (xhr2.readyState === 4) {
2910
+ let { status, responseText } = xhr2;
2911
+ if (status !== 200) {
2912
+ Logger$1.debug(
2913
+ `TimelineSender Error: received ${status} from stats.pusher.com`
2914
+ );
2915
+ return;
2916
+ }
2917
+ try {
2918
+ var { host } = JSON.parse(responseText);
2919
+ } catch (e) {
2920
+ Logger$1.debug(`TimelineSenderError: invalid response ${responseText}`);
2921
+ }
2922
+ if (host) {
2923
+ sender.host = host;
2924
+ }
2925
+ }
2926
+ };
2927
+ xhr2.send();
2928
+ };
2929
+ };
2930
+ var xhr = {
2931
+ name: "xhr",
2932
+ getAgent
2933
+ };
2934
+ const {
2935
+ getDefaultStrategy,
2936
+ Transports: Transports$1,
2937
+ setup,
2938
+ getProtocol,
2939
+ isXHRSupported,
2940
+ getLocalStorage,
2941
+ createXHR,
2942
+ createWebSocket,
2943
+ addUnloadListener,
2944
+ removeUnloadListener,
2945
+ transportConnectionInitializer,
2946
+ createSocketRequest,
2947
+ HTTPFactory
2948
+ } = Isomorphic;
2949
+ const NodeJS = {
2950
+ getDefaultStrategy,
2951
+ Transports: Transports$1,
2952
+ setup,
2953
+ getProtocol,
2954
+ isXHRSupported,
2955
+ createSocketRequest,
2956
+ getLocalStorage,
2957
+ createXHR,
2958
+ createWebSocket,
2959
+ addUnloadListener,
2960
+ removeUnloadListener,
2961
+ transportConnectionInitializer,
2962
+ HTTPFactory,
2963
+ TimelineTransport: xhr,
2964
+ getAuthorizers() {
2965
+ return { ajax };
2966
+ },
2967
+ getWebSocketAPI() {
2968
+ return fayeWebsocket.Client;
2969
+ },
2970
+ getXHRAPI() {
2971
+ return xmlhttprequest.XMLHttpRequest;
2972
+ },
2973
+ getNetwork() {
2974
+ return Network;
2975
+ },
2976
+ randomInt(max) {
2977
+ return crypto.randomInt(max);
2978
+ }
2979
+ };
2980
+ var TimelineLevel = /* @__PURE__ */ ((TimelineLevel2) => {
2981
+ TimelineLevel2[TimelineLevel2["ERROR"] = 3] = "ERROR";
2982
+ TimelineLevel2[TimelineLevel2["INFO"] = 6] = "INFO";
2983
+ TimelineLevel2[TimelineLevel2["DEBUG"] = 7] = "DEBUG";
2984
+ return TimelineLevel2;
2985
+ })(TimelineLevel || {});
2986
+ class Timeline {
2987
+ constructor(key, session, options) {
2988
+ this.key = key;
2989
+ this.session = session;
2990
+ this.events = [];
2991
+ this.options = options || {};
2992
+ this.sent = 0;
2993
+ this.uniqueID = 0;
2994
+ }
2995
+ log(level, event) {
2996
+ if (level <= this.options.level) {
2997
+ this.events.push(
2998
+ extend({}, event, { timestamp: Util.now() })
2999
+ );
3000
+ if (this.options.limit && this.events.length > this.options.limit) {
3001
+ this.events.shift();
3002
+ }
3003
+ }
3004
+ }
3005
+ error(event) {
3006
+ this.log(TimelineLevel.ERROR, event);
3007
+ }
3008
+ info(event) {
3009
+ this.log(TimelineLevel.INFO, event);
3010
+ }
3011
+ debug(event) {
3012
+ this.log(TimelineLevel.DEBUG, event);
3013
+ }
3014
+ isEmpty() {
3015
+ return this.events.length === 0;
3016
+ }
3017
+ send(sendfn, callback) {
3018
+ var data = extend(
3019
+ {
3020
+ session: this.session,
3021
+ bundle: this.sent + 1,
3022
+ key: this.key,
3023
+ lib: "js",
3024
+ version: this.options.version,
3025
+ cluster: this.options.cluster,
3026
+ features: this.options.features,
3027
+ timeline: this.events
3028
+ },
3029
+ this.options.params
3030
+ );
3031
+ this.events = [];
3032
+ sendfn(data, (error, result) => {
3033
+ if (!error) {
3034
+ this.sent++;
3035
+ }
3036
+ if (callback) {
3037
+ callback(error, result);
3038
+ }
3039
+ });
3040
+ return true;
3041
+ }
3042
+ generateUniqueID() {
3043
+ this.uniqueID++;
3044
+ return this.uniqueID;
3045
+ }
3046
+ }
3047
+ class TransportStrategy {
3048
+ constructor(name, priority, transport, options) {
3049
+ this.name = name;
3050
+ this.priority = priority;
3051
+ this.transport = transport;
3052
+ this.options = options || {};
3053
+ }
3054
+ /** Returns whether the transport is supported in the browser.
3055
+ *
3056
+ * @returns {Boolean}
3057
+ */
3058
+ isSupported() {
3059
+ return this.transport.isSupported({
3060
+ useTLS: this.options.useTLS
3061
+ });
3062
+ }
3063
+ /** Launches a connection attempt and returns a strategy runner.
3064
+ *
3065
+ * @param {Function} callback
3066
+ * @return {Object} strategy runner
3067
+ */
3068
+ connect(minPriority, callback) {
3069
+ if (!this.isSupported()) {
3070
+ return failAttempt(new UnsupportedStrategy$1(), callback);
3071
+ } else if (this.priority < minPriority) {
3072
+ return failAttempt(new TransportPriorityTooLow(), callback);
3073
+ }
3074
+ var connected = false;
3075
+ var transport = this.transport.createConnection(
3076
+ this.name,
3077
+ this.priority,
3078
+ this.options.key,
3079
+ this.options
3080
+ );
3081
+ var handshake = null;
3082
+ var onInitialized = function() {
3083
+ transport.unbind("initialized", onInitialized);
3084
+ transport.connect();
3085
+ };
3086
+ var onOpen = function() {
3087
+ handshake = Factory.createHandshake(transport, function(result) {
3088
+ connected = true;
3089
+ unbindListeners();
3090
+ callback(null, result);
3091
+ });
3092
+ };
3093
+ var onError = function(error) {
3094
+ unbindListeners();
3095
+ callback(error);
3096
+ };
3097
+ var onClosed = function() {
3098
+ unbindListeners();
3099
+ var serializedTransport;
3100
+ serializedTransport = safeJSONStringify(transport);
3101
+ callback(new TransportClosed(serializedTransport));
3102
+ };
3103
+ var unbindListeners = function() {
3104
+ transport.unbind("initialized", onInitialized);
3105
+ transport.unbind("open", onOpen);
3106
+ transport.unbind("error", onError);
3107
+ transport.unbind("closed", onClosed);
3108
+ };
3109
+ transport.bind("initialized", onInitialized);
3110
+ transport.bind("open", onOpen);
3111
+ transport.bind("error", onError);
3112
+ transport.bind("closed", onClosed);
3113
+ transport.initialize();
3114
+ return {
3115
+ abort: () => {
3116
+ if (connected) {
3117
+ return;
3118
+ }
3119
+ unbindListeners();
3120
+ if (handshake) {
3121
+ handshake.close();
3122
+ } else {
3123
+ transport.close();
3124
+ }
3125
+ },
3126
+ forceMinPriority: (p) => {
3127
+ if (connected) {
3128
+ return;
3129
+ }
3130
+ if (this.priority < p) {
3131
+ if (handshake) {
3132
+ handshake.close();
3133
+ } else {
3134
+ transport.close();
3135
+ }
3136
+ }
3137
+ }
3138
+ };
3139
+ }
3140
+ }
3141
+ function failAttempt(error, callback) {
3142
+ Util.defer(function() {
3143
+ callback(error);
3144
+ });
3145
+ return {
3146
+ abort: function() {
3147
+ },
3148
+ forceMinPriority: function() {
3149
+ }
3150
+ };
3151
+ }
3152
+ const { Transports } = NodeJS;
3153
+ var defineTransport = function(config2, name, type, priority, options, manager) {
3154
+ var transportClass = Transports[type];
3155
+ if (!transportClass) {
3156
+ throw new UnsupportedTransport(type);
3157
+ }
3158
+ var enabled = (!config2.enabledTransports || arrayIndexOf(config2.enabledTransports, name) !== -1) && (!config2.disabledTransports || arrayIndexOf(config2.disabledTransports, name) === -1);
3159
+ var transport;
3160
+ if (enabled) {
3161
+ options = Object.assign(
3162
+ { ignoreNullOrigin: config2.ignoreNullOrigin },
3163
+ options
3164
+ );
3165
+ transport = new TransportStrategy(
3166
+ name,
3167
+ priority,
3168
+ manager ? manager.getAssistant(transportClass) : transportClass,
3169
+ options
3170
+ );
3171
+ } else {
3172
+ transport = UnsupportedStrategy2;
3173
+ }
3174
+ return transport;
3175
+ };
3176
+ var UnsupportedStrategy2 = {
3177
+ isSupported: function() {
3178
+ return false;
3179
+ },
3180
+ connect: function(_, callback) {
3181
+ var deferred = Util.defer(function() {
3182
+ callback(new UnsupportedStrategy$1());
3183
+ });
3184
+ return {
3185
+ abort: function() {
3186
+ deferred.ensureAborted();
3187
+ },
3188
+ forceMinPriority: function() {
3189
+ }
3190
+ };
3191
+ }
3192
+ };
3193
+ function validateOptions(options) {
3194
+ if (options == null) {
3195
+ throw "You must pass an options object";
3196
+ }
3197
+ if (options.cluster == null) {
3198
+ throw "Options object must provide a cluster";
3199
+ }
3200
+ if ("disableStats" in options) {
3201
+ Logger$1.warn(
3202
+ "The disableStats option is deprecated in favor of enableStats"
3203
+ );
3204
+ }
3205
+ }
3206
+ const composeChannelQuery$1 = (params, authOptions) => {
3207
+ var query = "socket_id=" + encodeURIComponent(params.socketId);
3208
+ for (var key in authOptions.params) {
3209
+ query += "&" + encodeURIComponent(key) + "=" + encodeURIComponent(authOptions.params[key]);
3210
+ }
3211
+ if (authOptions.paramsProvider != null) {
3212
+ let dynamicParams = authOptions.paramsProvider();
3213
+ for (var key in dynamicParams) {
3214
+ query += "&" + encodeURIComponent(key) + "=" + encodeURIComponent(dynamicParams[key]);
3215
+ }
3216
+ }
3217
+ return query;
3218
+ };
3219
+ const UserAuthenticator = (authOptions) => {
3220
+ if (typeof NodeJS.getAuthorizers()[authOptions.transport] === "undefined") {
3221
+ throw `'${authOptions.transport}' is not a recognized auth transport`;
3222
+ }
3223
+ return (params, callback) => {
3224
+ const query = composeChannelQuery$1(params, authOptions);
3225
+ NodeJS.getAuthorizers()[authOptions.transport](
3226
+ NodeJS,
3227
+ query,
3228
+ authOptions,
3229
+ AuthRequestType.UserAuthentication,
3230
+ callback
3231
+ );
3232
+ };
3233
+ };
3234
+ const composeChannelQuery = (params, authOptions) => {
3235
+ var query = "socket_id=" + encodeURIComponent(params.socketId);
3236
+ query += "&channel_name=" + encodeURIComponent(params.channelName);
3237
+ for (var key in authOptions.params) {
3238
+ query += "&" + encodeURIComponent(key) + "=" + encodeURIComponent(authOptions.params[key]);
3239
+ }
3240
+ if (authOptions.paramsProvider != null) {
3241
+ let dynamicParams = authOptions.paramsProvider();
3242
+ for (var key in dynamicParams) {
3243
+ query += "&" + encodeURIComponent(key) + "=" + encodeURIComponent(dynamicParams[key]);
3244
+ }
3245
+ }
3246
+ return query;
3247
+ };
3248
+ const ChannelAuthorizer = (authOptions) => {
3249
+ if (typeof NodeJS.getAuthorizers()[authOptions.transport] === "undefined") {
3250
+ throw `'${authOptions.transport}' is not a recognized auth transport`;
3251
+ }
3252
+ return (params, callback) => {
3253
+ const query = composeChannelQuery(params, authOptions);
3254
+ NodeJS.getAuthorizers()[authOptions.transport](
3255
+ NodeJS,
3256
+ query,
3257
+ authOptions,
3258
+ AuthRequestType.ChannelAuthorization,
3259
+ callback
3260
+ );
3261
+ };
3262
+ };
3263
+ const ChannelAuthorizerProxy = (pusher, authOptions, channelAuthorizerGenerator) => {
3264
+ const deprecatedAuthorizerOptions = {
3265
+ authTransport: authOptions.transport,
3266
+ authEndpoint: authOptions.endpoint,
3267
+ auth: {
3268
+ params: authOptions.params,
3269
+ headers: authOptions.headers
3270
+ }
3271
+ };
3272
+ return (params, callback) => {
3273
+ const channel = pusher.channel(params.channelName);
3274
+ const channelAuthorizer = channelAuthorizerGenerator(channel, deprecatedAuthorizerOptions);
3275
+ channelAuthorizer.authorize(params.socketId, callback);
3276
+ };
3277
+ };
3278
+ function getConfig(opts, pusher) {
3279
+ let config2 = {
3280
+ activityTimeout: opts.activityTimeout || Defaults.activityTimeout,
3281
+ cluster: opts.cluster,
3282
+ httpPath: opts.httpPath || Defaults.httpPath,
3283
+ httpPort: opts.httpPort || Defaults.httpPort,
3284
+ httpsPort: opts.httpsPort || Defaults.httpsPort,
3285
+ pongTimeout: opts.pongTimeout || Defaults.pongTimeout,
3286
+ statsHost: opts.statsHost || Defaults.stats_host,
3287
+ unavailableTimeout: opts.unavailableTimeout || Defaults.unavailableTimeout,
3288
+ wsPath: opts.wsPath || Defaults.wsPath,
3289
+ wsPort: opts.wsPort || Defaults.wsPort,
3290
+ wssPort: opts.wssPort || Defaults.wssPort,
3291
+ enableStats: getEnableStatsConfig(opts),
3292
+ httpHost: getHttpHost(opts),
3293
+ useTLS: shouldUseTLS(opts),
3294
+ wsHost: getWebsocketHost(opts),
3295
+ userAuthenticator: buildUserAuthenticator(opts),
3296
+ channelAuthorizer: buildChannelAuthorizer(opts, pusher)
3297
+ };
3298
+ if ("disabledTransports" in opts)
3299
+ config2.disabledTransports = opts.disabledTransports;
3300
+ if ("enabledTransports" in opts)
3301
+ config2.enabledTransports = opts.enabledTransports;
3302
+ if ("ignoreNullOrigin" in opts)
3303
+ config2.ignoreNullOrigin = opts.ignoreNullOrigin;
3304
+ if ("timelineParams" in opts) config2.timelineParams = opts.timelineParams;
3305
+ if ("nacl" in opts) {
3306
+ config2.nacl = opts.nacl;
3307
+ }
3308
+ return config2;
3309
+ }
3310
+ function getHttpHost(opts) {
3311
+ if (opts.httpHost) {
3312
+ return opts.httpHost;
3313
+ }
3314
+ if (opts.cluster) {
3315
+ return `sockjs-${opts.cluster}.pusher.com`;
3316
+ }
3317
+ return Defaults.httpHost;
3318
+ }
3319
+ function getWebsocketHost(opts) {
3320
+ if (opts.wsHost) {
3321
+ return opts.wsHost;
3322
+ }
3323
+ return getWebsocketHostFromCluster(opts.cluster);
3324
+ }
3325
+ function getWebsocketHostFromCluster(cluster) {
3326
+ return `ws-${cluster}.pusher.com`;
3327
+ }
3328
+ function shouldUseTLS(opts) {
3329
+ if (NodeJS.getProtocol() === "https:") {
3330
+ return true;
3331
+ } else if (opts.forceTLS === false) {
3332
+ return false;
3333
+ }
3334
+ return true;
3335
+ }
3336
+ function getEnableStatsConfig(opts) {
3337
+ if ("enableStats" in opts) {
3338
+ return opts.enableStats;
3339
+ }
3340
+ if ("disableStats" in opts) {
3341
+ return !opts.disableStats;
3342
+ }
3343
+ return false;
3344
+ }
3345
+ function buildUserAuthenticator(opts) {
3346
+ const userAuthentication = {
3347
+ ...Defaults.userAuthentication,
3348
+ ...opts.userAuthentication
3349
+ };
3350
+ if ("customHandler" in userAuthentication && userAuthentication["customHandler"] != null) {
3351
+ return userAuthentication["customHandler"];
3352
+ }
3353
+ return UserAuthenticator(userAuthentication);
3354
+ }
3355
+ function buildChannelAuth(opts, pusher) {
3356
+ let channelAuthorization;
3357
+ if ("channelAuthorization" in opts) {
3358
+ channelAuthorization = {
3359
+ ...Defaults.channelAuthorization,
3360
+ ...opts.channelAuthorization
3361
+ };
3362
+ } else {
3363
+ channelAuthorization = {
3364
+ transport: opts.authTransport || Defaults.authTransport,
3365
+ endpoint: opts.authEndpoint || Defaults.authEndpoint
3366
+ };
3367
+ if ("auth" in opts) {
3368
+ if ("params" in opts.auth) channelAuthorization.params = opts.auth.params;
3369
+ if ("headers" in opts.auth)
3370
+ channelAuthorization.headers = opts.auth.headers;
3371
+ }
3372
+ if ("authorizer" in opts)
3373
+ channelAuthorization.customHandler = ChannelAuthorizerProxy(
3374
+ pusher,
3375
+ channelAuthorization,
3376
+ opts.authorizer
3377
+ );
3378
+ }
3379
+ return channelAuthorization;
3380
+ }
3381
+ function buildChannelAuthorizer(opts, pusher) {
3382
+ const channelAuthorization = buildChannelAuth(opts, pusher);
3383
+ if ("customHandler" in channelAuthorization && channelAuthorization["customHandler"] != null) {
3384
+ return channelAuthorization["customHandler"];
3385
+ }
3386
+ return ChannelAuthorizer(channelAuthorization);
3387
+ }
3388
+ class WatchlistFacade extends Dispatcher {
3389
+ constructor(pusher) {
3390
+ super(function(eventName, data) {
3391
+ Logger$1.debug(`No callbacks on watchlist events for ${eventName}`);
3392
+ });
3393
+ this.pusher = pusher;
3394
+ this.bindWatchlistInternalEvent();
3395
+ }
3396
+ handleEvent(pusherEvent) {
3397
+ pusherEvent.data.events.forEach((watchlistEvent) => {
3398
+ this.emit(watchlistEvent.name, watchlistEvent);
3399
+ });
3400
+ }
3401
+ bindWatchlistInternalEvent() {
3402
+ this.pusher.connection.bind("message", (pusherEvent) => {
3403
+ var eventName = pusherEvent.event;
3404
+ if (eventName === "pusher_internal:watchlist_events") {
3405
+ this.handleEvent(pusherEvent);
3406
+ }
3407
+ });
3408
+ }
3409
+ }
3410
+ function flatPromise() {
3411
+ let resolve, reject;
3412
+ const promise = new Promise((res, rej) => {
3413
+ resolve = res;
3414
+ reject = rej;
3415
+ });
3416
+ return { promise, resolve, reject };
3417
+ }
3418
+ class UserFacade extends Dispatcher {
3419
+ constructor(pusher) {
3420
+ super(function(eventName, data) {
3421
+ Logger$1.debug("No callbacks on user for " + eventName);
3422
+ });
3423
+ this.signin_requested = false;
3424
+ this.user_data = null;
3425
+ this.serverToUserChannel = null;
3426
+ this.signinDonePromise = null;
3427
+ this._signinDoneResolve = null;
3428
+ this._onAuthorize = (err, authData) => {
3429
+ if (err) {
3430
+ Logger$1.warn(`Error during signin: ${err}`);
3431
+ this._cleanup();
3432
+ return;
3433
+ }
3434
+ this.pusher.send_event("pusher:signin", {
3435
+ auth: authData.auth,
3436
+ user_data: authData.user_data
3437
+ });
3438
+ };
3439
+ this.pusher = pusher;
3440
+ this.pusher.connection.bind("state_change", ({ previous, current }) => {
3441
+ if (previous !== "connected" && current === "connected") {
3442
+ this._signin();
3443
+ }
3444
+ if (previous === "connected" && current !== "connected") {
3445
+ this._cleanup();
3446
+ this._newSigninPromiseIfNeeded();
3447
+ }
3448
+ });
3449
+ this.watchlist = new WatchlistFacade(pusher);
3450
+ this.pusher.connection.bind("message", (event) => {
3451
+ var eventName = event.event;
3452
+ if (eventName === "pusher:signin_success") {
3453
+ this._onSigninSuccess(event.data);
3454
+ }
3455
+ if (this.serverToUserChannel && this.serverToUserChannel.name === event.channel) {
3456
+ this.serverToUserChannel.handleEvent(event);
3457
+ }
3458
+ });
3459
+ }
3460
+ signin() {
3461
+ if (this.signin_requested) {
3462
+ return;
3463
+ }
3464
+ this.signin_requested = true;
3465
+ this._signin();
3466
+ }
3467
+ _signin() {
3468
+ if (!this.signin_requested) {
3469
+ return;
3470
+ }
3471
+ this._newSigninPromiseIfNeeded();
3472
+ if (this.pusher.connection.state !== "connected") {
3473
+ return;
3474
+ }
3475
+ this.pusher.config.userAuthenticator(
3476
+ {
3477
+ socketId: this.pusher.connection.socket_id
3478
+ },
3479
+ this._onAuthorize
3480
+ );
3481
+ }
3482
+ _onSigninSuccess(data) {
3483
+ try {
3484
+ this.user_data = JSON.parse(data.user_data);
3485
+ } catch (e) {
3486
+ Logger$1.error(`Failed parsing user data after signin: ${data.user_data}`);
3487
+ this._cleanup();
3488
+ return;
3489
+ }
3490
+ if (typeof this.user_data.id !== "string" || this.user_data.id === "") {
3491
+ Logger$1.error(
3492
+ `user_data doesn't contain an id. user_data: ${this.user_data}`
3493
+ );
3494
+ this._cleanup();
3495
+ return;
3496
+ }
3497
+ this._signinDoneResolve();
3498
+ this._subscribeChannels();
3499
+ }
3500
+ _subscribeChannels() {
3501
+ const ensure_subscribed = (channel) => {
3502
+ if (channel.subscriptionPending && channel.subscriptionCancelled) {
3503
+ channel.reinstateSubscription();
3504
+ } else if (!channel.subscriptionPending && this.pusher.connection.state === "connected") {
3505
+ channel.subscribe();
3506
+ }
3507
+ };
3508
+ this.serverToUserChannel = new Channel(
3509
+ `#server-to-user-${this.user_data.id}`,
3510
+ this.pusher
3511
+ );
3512
+ this.serverToUserChannel.bind_global((eventName, data) => {
3513
+ if (eventName.indexOf("pusher_internal:") === 0 || eventName.indexOf("pusher:") === 0) {
3514
+ return;
3515
+ }
3516
+ this.emit(eventName, data);
3517
+ });
3518
+ ensure_subscribed(this.serverToUserChannel);
3519
+ }
3520
+ _cleanup() {
3521
+ this.user_data = null;
3522
+ if (this.serverToUserChannel) {
3523
+ this.serverToUserChannel.unbind_all();
3524
+ this.serverToUserChannel.disconnect();
3525
+ this.serverToUserChannel = null;
3526
+ }
3527
+ if (this.signin_requested) {
3528
+ this._signinDoneResolve();
3529
+ }
3530
+ }
3531
+ _newSigninPromiseIfNeeded() {
3532
+ if (!this.signin_requested) {
3533
+ return;
3534
+ }
3535
+ if (this.signinDonePromise && !this.signinDonePromise.done) {
3536
+ return;
3537
+ }
3538
+ const { promise, resolve } = flatPromise();
3539
+ promise.done = false;
3540
+ const setDone = () => {
3541
+ promise.done = true;
3542
+ };
3543
+ promise.then(setDone).catch(setDone);
3544
+ this.signinDonePromise = promise;
3545
+ this._signinDoneResolve = resolve;
3546
+ }
3547
+ }
3548
+ class ChannelState {
3549
+ constructor(channelName) {
3550
+ this.channelName = channelName;
3551
+ this.conflationKey = null;
3552
+ this.maxMessagesPerKey = 10;
3553
+ this.conflationCaches = /* @__PURE__ */ new Map();
3554
+ this.baseMessage = null;
3555
+ this.baseSequence = null;
3556
+ this.lastSequence = null;
3557
+ this.deltaCount = 0;
3558
+ this.fullMessageCount = 0;
3559
+ }
3560
+ /**
3561
+ * Initialize cache from server sync
3562
+ */
3563
+ initializeFromCacheSync(data) {
3564
+ this.conflationKey = data.conflation_key || null;
3565
+ this.maxMessagesPerKey = data.max_messages_per_key || 10;
3566
+ this.conflationCaches.clear();
3567
+ if (data.states) {
3568
+ for (const [key, messages] of Object.entries(data.states)) {
3569
+ const cache = messages.map((msg) => ({
3570
+ content: msg.content,
3571
+ sequence: msg.seq
3572
+ }));
3573
+ this.conflationCaches.set(key, cache);
3574
+ }
3575
+ }
3576
+ }
3577
+ /**
3578
+ * Set new base message (legacy - for non-conflation channels)
3579
+ */
3580
+ setBase(message, sequence) {
3581
+ this.baseMessage = message;
3582
+ this.baseSequence = sequence;
3583
+ this.lastSequence = sequence;
3584
+ }
3585
+ /**
3586
+ * Get base message for a conflation key at specific index
3587
+ * Note: baseIndex is the sequence number, not array index
3588
+ */
3589
+ getBaseMessage(conflationKeyValue, baseIndex) {
3590
+ if (!this.conflationKey) {
3591
+ return this.baseMessage;
3592
+ }
3593
+ const key = conflationKeyValue || "";
3594
+ const cache = this.conflationCaches.get(key);
3595
+ if (!cache || baseIndex === void 0) {
3596
+ console.error("[ChannelState] No cache or baseIndex undefined", {
3597
+ hasCache: !!cache,
3598
+ baseIndex,
3599
+ key,
3600
+ allCacheKeys: Array.from(this.conflationCaches.keys())
3601
+ });
3602
+ return null;
3603
+ }
3604
+ const message = cache.find((msg) => msg.sequence === baseIndex);
3605
+ if (!message) {
3606
+ console.error("[ChannelState] Could not find message with sequence", {
3607
+ searchingFor: baseIndex,
3608
+ cacheSize: cache.length,
3609
+ cacheSequences: cache.map((m) => m.sequence),
3610
+ key: conflationKeyValue
3611
+ });
3612
+ return null;
3613
+ }
3614
+ return message.content;
3615
+ }
3616
+ /**
3617
+ * Add or update message in conflation cache
3618
+ */
3619
+ updateConflationCache(conflationKeyValue, message, sequence) {
3620
+ const key = conflationKeyValue || "";
3621
+ let cache = this.conflationCaches.get(key);
3622
+ if (!cache) {
3623
+ cache = [];
3624
+ this.conflationCaches.set(key, cache);
3625
+ }
3626
+ if (cache.length > 0) {
3627
+ const lastCacheItem = cache[cache.length - 1];
3628
+ if (sequence <= lastCacheItem.sequence) {
3629
+ cache.length = 0;
3630
+ }
3631
+ }
3632
+ cache.push({ content: message, sequence });
3633
+ while (cache.length > this.maxMessagesPerKey) {
3634
+ cache.shift();
3635
+ }
3636
+ }
3637
+ /**
3638
+ * Check if we have a valid base
3639
+ */
3640
+ hasBase() {
3641
+ if (this.conflationKey) {
3642
+ return this.conflationCaches.size > 0;
3643
+ }
3644
+ return this.baseMessage !== null && this.baseSequence !== null;
3645
+ }
3646
+ /**
3647
+ * Validate sequence number
3648
+ */
3649
+ isValidSequence(sequence) {
3650
+ if (this.lastSequence === null) {
3651
+ return true;
3652
+ }
3653
+ return sequence > this.lastSequence;
3654
+ }
3655
+ /**
3656
+ * Update sequence after processing a message
3657
+ */
3658
+ updateSequence(sequence) {
3659
+ this.lastSequence = sequence;
3660
+ }
3661
+ /**
3662
+ * Record delta received
3663
+ */
3664
+ recordDelta() {
3665
+ this.deltaCount++;
3666
+ }
3667
+ /**
3668
+ * Record full message received
3669
+ */
3670
+ recordFullMessage() {
3671
+ this.fullMessageCount++;
3672
+ }
3673
+ /**
3674
+ * Get statistics
3675
+ */
3676
+ getStats() {
3677
+ return {
3678
+ channelName: this.channelName,
3679
+ conflationKey: this.conflationKey,
3680
+ conflationGroupCount: this.conflationCaches.size,
3681
+ deltaCount: this.deltaCount,
3682
+ fullMessageCount: this.fullMessageCount,
3683
+ totalMessages: this.deltaCount + this.fullMessageCount
3684
+ };
3685
+ }
3686
+ }
3687
+ const fossilDeltaGlobal = typeof window !== "undefined" ? window.fossilDelta : void 0;
3688
+ const vcdiffGlobal = typeof window !== "undefined" ? window.vcdiff : void 0;
3689
+ function base64ToBytes(base642) {
3690
+ const binaryString = atob(base642);
3691
+ const bytes = new Uint8Array(binaryString.length);
3692
+ for (let i = 0; i < binaryString.length; i++) {
3693
+ bytes[i] = binaryString.charCodeAt(i);
3694
+ }
3695
+ return bytes;
3696
+ }
3697
+ function bytesToString(bytes) {
3698
+ if (Array.isArray(bytes) || !(bytes instanceof Uint8Array)) {
3699
+ bytes = new Uint8Array(bytes);
3700
+ }
3701
+ return new TextDecoder().decode(bytes);
3702
+ }
3703
+ function stringToBytes(str) {
3704
+ return new TextEncoder().encode(str);
3705
+ }
3706
+ class FossilDeltaDecoder {
3707
+ static isAvailable() {
3708
+ return typeof fossilDelta.applyDelta !== "undefined" || typeof fossilDeltaGlobal !== "undefined" && fossilDeltaGlobal.apply;
3709
+ }
3710
+ static apply(base, delta) {
3711
+ if (!this.isAvailable()) {
3712
+ throw new Error("Fossil Delta library not loaded");
3713
+ }
3714
+ const baseBytes = typeof base === "string" ? stringToBytes(base) : base;
3715
+ const deltaBytes = typeof delta === "string" ? stringToBytes(delta) : delta;
3716
+ try {
3717
+ let result;
3718
+ if (typeof fossilDelta.applyDelta !== "undefined") {
3719
+ result = fossilDelta.applyDelta(baseBytes, deltaBytes);
3720
+ } else if (fossilDeltaGlobal && fossilDeltaGlobal.apply) {
3721
+ result = fossilDeltaGlobal.apply(baseBytes, deltaBytes);
3722
+ } else {
3723
+ throw new Error("No fossil-delta implementation found");
3724
+ }
3725
+ return bytesToString(result);
3726
+ } catch (error) {
3727
+ throw new Error(
3728
+ `Fossil delta decode failed: ${error.message} (base=${baseBytes.length}B delta=${deltaBytes.length}B)`
3729
+ );
3730
+ }
3731
+ }
3732
+ }
3733
+ class Xdelta3Decoder {
3734
+ static isAvailable() {
3735
+ return typeof vcdiffDecoder.decode !== "undefined" || typeof vcdiffGlobal !== "undefined" && vcdiffGlobal.decode;
3736
+ }
3737
+ static apply(base, delta) {
3738
+ if (!this.isAvailable()) {
3739
+ throw new Error("Xdelta3/VCDIFF library not loaded");
3740
+ }
3741
+ const baseBytes = typeof base === "string" ? stringToBytes(base) : base;
3742
+ const deltaBytes = typeof delta === "string" ? stringToBytes(delta) : delta;
3743
+ try {
3744
+ let result;
3745
+ if (typeof vcdiffDecoder.decode !== "undefined") {
3746
+ result = vcdiffDecoder.decode(deltaBytes, baseBytes);
3747
+ } else if (vcdiffGlobal && vcdiffGlobal.decode) {
3748
+ result = vcdiffGlobal.decode(deltaBytes, baseBytes);
3749
+ } else {
3750
+ throw new Error("No VCDIFF decoder implementation found");
3751
+ }
3752
+ return bytesToString(result);
3753
+ } catch (error) {
3754
+ throw new Error(
3755
+ `Xdelta3 decode failed: ${error.message} (base=${baseBytes.length}B delta=${deltaBytes.length}B)`
3756
+ );
3757
+ }
3758
+ }
3759
+ }
3760
+ class DeltaCompressionManager {
3761
+ constructor(options = {}, sendEventCallback) {
3762
+ this.options = {
3763
+ enabled: options.enabled !== false,
3764
+ algorithms: options.algorithms || ["fossil", "xdelta3"],
3765
+ debug: options.debug || false,
3766
+ onStats: options.onStats || null,
3767
+ onError: options.onError || null
3768
+ };
3769
+ this.enabled = false;
3770
+ this.channelStates = /* @__PURE__ */ new Map();
3771
+ this.stats = {
3772
+ totalMessages: 0,
3773
+ deltaMessages: 0,
3774
+ fullMessages: 0,
3775
+ totalBytesWithoutCompression: 0,
3776
+ totalBytesWithCompression: 0,
3777
+ errors: 0
3778
+ };
3779
+ this.sendEventCallback = sendEventCallback;
3780
+ this.availableAlgorithms = this.detectAvailableAlgorithms();
3781
+ if (this.availableAlgorithms.length === 0) {
3782
+ Logger$1.warn(
3783
+ "[DeltaCompression] No delta algorithms available. Please include fossil-delta or vcdiff-decoder libraries."
3784
+ );
3785
+ }
3786
+ }
3787
+ /**
3788
+ * Detect which algorithm libraries are loaded
3789
+ */
3790
+ detectAvailableAlgorithms() {
3791
+ const available = [];
3792
+ if (FossilDeltaDecoder.isAvailable()) {
3793
+ available.push("fossil");
3794
+ this.log("Fossil Delta decoder available");
3795
+ }
3796
+ if (Xdelta3Decoder.isAvailable()) {
3797
+ available.push("xdelta3");
3798
+ this.log("Xdelta3 decoder available");
3799
+ }
3800
+ return available;
3801
+ }
3802
+ /**
3803
+ * Enable delta compression
3804
+ */
3805
+ enable() {
3806
+ if (this.enabled || !this.options.enabled) {
3807
+ return;
3808
+ }
3809
+ if (this.availableAlgorithms.length === 0) {
3810
+ this.log("No delta algorithms available, cannot enable");
3811
+ return;
3812
+ }
3813
+ const supportedAlgorithms = this.availableAlgorithms.filter(
3814
+ (algo) => this.options.algorithms.includes(algo)
3815
+ );
3816
+ if (supportedAlgorithms.length === 0) {
3817
+ this.log("No mutually supported algorithms");
3818
+ return;
3819
+ }
3820
+ this.log("Sending enable request", supportedAlgorithms);
3821
+ this.sendEventCallback("pusher:enable_delta_compression", {
3822
+ algorithms: supportedAlgorithms
3823
+ });
3824
+ }
3825
+ /**
3826
+ * Disable delta compression
3827
+ * Note: We intentionally do NOT clear channelStates here.
3828
+ * This allows state to be preserved across enable/disable cycles,
3829
+ * which is important for reconnection scenarios and user toggling.
3830
+ * Use clearChannelState() if you need to explicitly clear state.
3831
+ */
3832
+ disable() {
3833
+ this.enabled = false;
3834
+ }
3835
+ /**
3836
+ * Handle delta compression enabled confirmation
3837
+ */
3838
+ handleEnabled(data) {
3839
+ this.enabled = data.enabled || true;
3840
+ this.log("Delta compression enabled", data);
3841
+ }
3842
+ /**
3843
+ * Handle cache sync message (conflation keys)
3844
+ */
3845
+ handleCacheSync(channel, data) {
3846
+ this.log("Received cache sync", {
3847
+ channel,
3848
+ conflationKey: data.conflation_key,
3849
+ groupCount: Object.keys(data.states || {}).length
3850
+ });
3851
+ let channelState = this.channelStates.get(channel);
3852
+ if (!channelState) {
3853
+ channelState = new ChannelState(channel);
3854
+ this.channelStates.set(channel, channelState);
3855
+ }
3856
+ channelState.initializeFromCacheSync(data);
3857
+ this.log("Cache initialized", channelState.getStats());
3858
+ }
3859
+ /**
3860
+ * Handle delta-compressed message
3861
+ */
3862
+ handleDeltaMessage(channel, deltaData) {
3863
+ let deltaBytes = null;
3864
+ try {
3865
+ const event = deltaData.event;
3866
+ const delta = deltaData.delta;
3867
+ const sequence = deltaData.seq;
3868
+ const algorithm = deltaData.algorithm || "fossil";
3869
+ const conflationKey = deltaData.conflation_key;
3870
+ const baseIndex = deltaData.base_index;
3871
+ this.log("Received delta message", {
3872
+ channel,
3873
+ event,
3874
+ sequence,
3875
+ algorithm,
3876
+ conflationKey,
3877
+ baseIndex,
3878
+ deltaSize: delta.length
3879
+ });
3880
+ let channelState = this.channelStates.get(channel);
3881
+ if (!channelState) {
3882
+ this.log(`Ignoring delta for unsubscribed channel: ${channel}`);
3883
+ return null;
3884
+ }
3885
+ let baseMessage;
3886
+ if (channelState.conflationKey) {
3887
+ baseMessage = channelState.getBaseMessage(conflationKey, baseIndex);
3888
+ if (!baseMessage) {
3889
+ this.error(
3890
+ `No base message for channel ${channel}, key ${conflationKey}, index ${baseIndex}`
3891
+ );
3892
+ if (this.options.debug) {
3893
+ this.log("Current conflation cache snapshot", {
3894
+ channel,
3895
+ conflationKey: channelState.conflationKey,
3896
+ cacheSizes: Array.from(
3897
+ channelState.conflationCaches.entries()
3898
+ ).map(([key, cache]) => ({ key, size: cache.length }))
3899
+ });
3900
+ }
3901
+ this.requestResync(channel);
3902
+ return null;
3903
+ }
3904
+ } else {
3905
+ baseMessage = channelState.baseMessage;
3906
+ if (!baseMessage) {
3907
+ this.error(`No base message for channel ${channel}`);
3908
+ if (this.options.debug) {
3909
+ this.log("Channel state missing base", {
3910
+ channel,
3911
+ lastSequence: channelState.lastSequence
3912
+ });
3913
+ }
3914
+ this.requestResync(channel);
3915
+ return null;
3916
+ }
3917
+ }
3918
+ deltaBytes = base64ToBytes(delta);
3919
+ let reconstructedMessage;
3920
+ try {
3921
+ if (algorithm === "fossil") {
3922
+ reconstructedMessage = FossilDeltaDecoder.apply(
3923
+ baseMessage,
3924
+ deltaBytes
3925
+ );
3926
+ } else if (algorithm === "xdelta3") {
3927
+ reconstructedMessage = Xdelta3Decoder.apply(baseMessage, deltaBytes);
3928
+ } else {
3929
+ throw Error(`Unknown algorithm: ${algorithm}`);
3930
+ }
3931
+ } catch (decodeError) {
3932
+ throw decodeError;
3933
+ }
3934
+ if (channelState.conflationKey) {
3935
+ channelState.updateConflationCache(
3936
+ conflationKey,
3937
+ reconstructedMessage,
3938
+ sequence
3939
+ );
3940
+ } else {
3941
+ channelState.setBase(reconstructedMessage, sequence);
3942
+ }
3943
+ channelState.updateSequence(sequence);
3944
+ channelState.recordDelta();
3945
+ this.stats.totalMessages++;
3946
+ this.stats.deltaMessages++;
3947
+ this.stats.totalBytesWithCompression += deltaBytes.length;
3948
+ this.stats.totalBytesWithoutCompression += reconstructedMessage.length;
3949
+ this.updateStats();
3950
+ this.log("Delta applied successfully", {
3951
+ channel,
3952
+ event,
3953
+ conflationKey,
3954
+ originalSize: reconstructedMessage.length,
3955
+ deltaSize: deltaBytes.length,
3956
+ compressionRatio: (deltaBytes.length / reconstructedMessage.length * 100).toFixed(1) + "%"
3957
+ });
3958
+ try {
3959
+ const parsedMessage = JSON.parse(reconstructedMessage);
3960
+ return {
3961
+ event,
3962
+ channel,
3963
+ data: parsedMessage.data || parsedMessage
3964
+ };
3965
+ } catch (e) {
3966
+ return {
3967
+ event,
3968
+ channel,
3969
+ data: reconstructedMessage
3970
+ };
3971
+ }
3972
+ } catch (error) {
3973
+ this.error("Delta decode failed", {
3974
+ channel,
3975
+ event: deltaData.event,
3976
+ sequence: deltaData.seq,
3977
+ algorithm: deltaData.algorithm,
3978
+ conflationKey: deltaData.conflation_key,
3979
+ baseIndex: deltaData.base_index,
3980
+ deltaSize: deltaData.delta?.length,
3981
+ decodedDeltaBytes: deltaBytes ? deltaBytes.length : "n/a",
3982
+ message: error.message
3983
+ });
3984
+ this.stats.errors++;
3985
+ return null;
3986
+ }
3987
+ }
3988
+ /**
3989
+ * Handle regular (full) message with delta sequence markers
3990
+ */
3991
+ handleFullMessage(channel, rawMessage, sequence, conflationKey) {
3992
+ if (!sequence && sequence !== 0) {
3993
+ try {
3994
+ const parsed = JSON.parse(rawMessage);
3995
+ const candidate = typeof parsed.data === "string" ? JSON.parse(parsed.data).__delta_seq ?? parsed.__delta_seq : parsed.data?.__delta_seq ?? parsed.__delta_seq;
3996
+ if (candidate === 0 || candidate) {
3997
+ sequence = candidate;
3998
+ } else {
3999
+ this.log("handleFullMessage missing sequence, skipping", {
4000
+ channel,
4001
+ hasSequence: false
4002
+ });
4003
+ return;
4004
+ }
4005
+ } catch (e) {
4006
+ this.log("handleFullMessage missing sequence and parse failed", {
4007
+ channel,
4008
+ hasSequence: false
4009
+ });
4010
+ return;
4011
+ }
4012
+ }
4013
+ const messageSize = rawMessage.length;
4014
+ let channelState = this.channelStates.get(channel);
4015
+ if (!channelState) {
4016
+ channelState = new ChannelState(channel);
4017
+ this.channelStates.set(channel, channelState);
4018
+ }
4019
+ const finalConflationKey = conflationKey;
4020
+ if (finalConflationKey !== void 0 && !channelState.conflationKey) {
4021
+ channelState.conflationKey = "enabled";
4022
+ }
4023
+ if (channelState.conflationKey && finalConflationKey !== void 0) {
4024
+ channelState.updateConflationCache(
4025
+ finalConflationKey,
4026
+ rawMessage,
4027
+ // Store raw message directly
4028
+ sequence
4029
+ );
4030
+ this.log("Stored full message (conflation)", {
4031
+ channel,
4032
+ conflationKey: finalConflationKey,
4033
+ sequence,
4034
+ size: messageSize
4035
+ });
4036
+ } else {
4037
+ channelState.setBase(rawMessage, sequence);
4038
+ this.log("Stored full message", {
4039
+ channel,
4040
+ sequence,
4041
+ size: messageSize
4042
+ });
4043
+ }
4044
+ channelState.recordFullMessage();
4045
+ this.stats.totalMessages++;
4046
+ this.stats.fullMessages++;
4047
+ this.stats.totalBytesWithoutCompression += messageSize;
4048
+ this.stats.totalBytesWithCompression += messageSize;
4049
+ this.updateStats();
4050
+ }
4051
+ /**
4052
+ * Request resync for a channel
4053
+ */
4054
+ requestResync(channel) {
4055
+ this.log("Requesting resync for channel", channel);
4056
+ this.sendEventCallback("pusher:delta_sync_error", { channel });
4057
+ this.channelStates.delete(channel);
4058
+ }
4059
+ /**
4060
+ * Update and emit stats
4061
+ */
4062
+ updateStats() {
4063
+ if (this.options.onStats) {
4064
+ this.options.onStats(this.getStats());
4065
+ }
4066
+ }
4067
+ /**
4068
+ * Get current statistics
4069
+ */
4070
+ getStats() {
4071
+ const bandwidthSaved = this.stats.totalBytesWithoutCompression - this.stats.totalBytesWithCompression;
4072
+ const bandwidthSavedPercent = this.stats.totalBytesWithoutCompression > 0 ? bandwidthSaved / this.stats.totalBytesWithoutCompression * 100 : 0;
4073
+ const channelStats = Array.from(this.channelStates.values()).map(
4074
+ (state) => state.getStats()
4075
+ );
4076
+ return {
4077
+ ...this.stats,
4078
+ bandwidthSaved,
4079
+ bandwidthSavedPercent,
4080
+ channelCount: this.channelStates.size,
4081
+ channels: channelStats
4082
+ };
4083
+ }
4084
+ /**
4085
+ * Reset statistics
4086
+ */
4087
+ resetStats() {
4088
+ this.stats = {
4089
+ totalMessages: 0,
4090
+ deltaMessages: 0,
4091
+ fullMessages: 0,
4092
+ totalBytesWithoutCompression: 0,
4093
+ totalBytesWithCompression: 0,
4094
+ errors: 0
4095
+ };
4096
+ this.updateStats();
4097
+ }
4098
+ /**
4099
+ * Clear channel state
4100
+ */
4101
+ clearChannelState(channel) {
4102
+ if (channel) {
4103
+ this.channelStates.delete(channel);
4104
+ } else {
4105
+ this.channelStates.clear();
4106
+ }
4107
+ }
4108
+ /**
4109
+ * Check if delta compression is enabled
4110
+ */
4111
+ isEnabled() {
4112
+ return this.enabled;
4113
+ }
4114
+ /**
4115
+ * Get available algorithms
4116
+ */
4117
+ getAvailableAlgorithms() {
4118
+ return this.availableAlgorithms;
4119
+ }
4120
+ /**
4121
+ * Log message (if debug enabled)
4122
+ */
4123
+ log(...args) {
4124
+ if (this.options.debug) {
4125
+ Logger$1.debug("[DeltaCompression]", ...args);
4126
+ }
4127
+ }
4128
+ /**
4129
+ * Log error
4130
+ */
4131
+ error(...args) {
4132
+ Logger$1.error("[DeltaCompression]", ...args);
4133
+ if (this.options.onError) {
4134
+ this.options.onError(args);
4135
+ }
4136
+ }
4137
+ }
4138
+ class Pusher {
4139
+ static {
4140
+ this.instances = [];
4141
+ }
4142
+ static {
4143
+ this.isReady = false;
4144
+ }
4145
+ static {
4146
+ this._logToConsole = false;
4147
+ }
4148
+ static get logToConsole() {
4149
+ return this._logToConsole;
4150
+ }
4151
+ static set logToConsole(value) {
4152
+ this._logToConsole = value;
4153
+ setLoggerConfig({ logToConsole: value, log: this._log });
4154
+ }
4155
+ static get log() {
4156
+ return this._log;
4157
+ }
4158
+ static set log(fn) {
4159
+ this._log = fn;
4160
+ setLoggerConfig({ logToConsole: this._logToConsole, log: fn });
4161
+ }
4162
+ static {
4163
+ this.Runtime = NodeJS;
4164
+ }
4165
+ static {
4166
+ this.ScriptReceivers = NodeJS.ScriptReceivers;
4167
+ }
4168
+ static {
4169
+ this.DependenciesReceivers = NodeJS.DependenciesReceivers;
4170
+ }
4171
+ static {
4172
+ this.auth_callbacks = NodeJS.auth_callbacks;
4173
+ }
4174
+ static ready() {
4175
+ Pusher.isReady = true;
4176
+ for (var i = 0, l = Pusher.instances.length; i < l; i++) {
4177
+ Pusher.instances[i].connect();
4178
+ }
4179
+ }
4180
+ static getClientFeatures() {
4181
+ return keys(
4182
+ filterObject({ ws: NodeJS.Transports.ws }, function(t) {
4183
+ return t.isSupported({});
4184
+ })
4185
+ );
4186
+ }
4187
+ constructor(app_key, options) {
4188
+ checkAppKey(app_key);
4189
+ validateOptions(options);
4190
+ this.key = app_key;
4191
+ this.config = getConfig(options, this);
4192
+ this.channels = Factory.createChannels();
4193
+ this.global_emitter = new Dispatcher();
4194
+ this.sessionID = NodeJS.randomInt(1e9);
4195
+ this.timeline = new Timeline(this.key, this.sessionID, {
4196
+ cluster: this.config.cluster,
4197
+ features: Pusher.getClientFeatures(),
4198
+ params: this.config.timelineParams || {},
4199
+ limit: 50,
4200
+ level: TimelineLevel.INFO,
4201
+ version: Defaults.VERSION
4202
+ });
4203
+ if (this.config.enableStats) {
4204
+ this.timelineSender = Factory.createTimelineSender(this.timeline, {
4205
+ host: this.config.statsHost,
4206
+ path: "/timeline/v2/" + NodeJS.TimelineTransport.name
4207
+ });
4208
+ }
4209
+ var getStrategy = (options2) => {
4210
+ return NodeJS.getDefaultStrategy(this.config, options2, defineTransport);
4211
+ };
4212
+ this.connection = Factory.createConnectionManager(this.key, {
4213
+ getStrategy,
4214
+ timeline: this.timeline,
4215
+ activityTimeout: this.config.activityTimeout,
4216
+ pongTimeout: this.config.pongTimeout,
4217
+ unavailableTimeout: this.config.unavailableTimeout,
4218
+ useTLS: Boolean(this.config.useTLS)
4219
+ });
4220
+ if (options.deltaCompression !== void 0) {
4221
+ this.deltaCompression = new DeltaCompressionManager(
4222
+ options.deltaCompression || {},
4223
+ (event, data) => this.send_event(event, data)
4224
+ );
4225
+ }
4226
+ this.connection.bind("connected", () => {
4227
+ this.subscribeAll();
4228
+ if (this.timelineSender) {
4229
+ this.timelineSender.send(this.connection.isUsingTLS());
4230
+ }
4231
+ if (this.deltaCompression && options.deltaCompression?.enabled === true) {
4232
+ this.deltaCompression.enable();
4233
+ }
4234
+ });
4235
+ this.connection.bind("message", (event) => {
4236
+ var eventName = event.event;
4237
+ var internal = eventName.indexOf("pusher_internal:") === 0;
4238
+ if (this.deltaCompression) {
4239
+ if (eventName === "pusher:delta_compression_enabled") {
4240
+ this.deltaCompression.handleEnabled(event.data);
4241
+ } else if (eventName === "pusher:delta_cache_sync" && event.channel) {
4242
+ this.deltaCompression.handleCacheSync(event.channel, event.data);
4243
+ return;
4244
+ } else if (eventName === "pusher:delta" && event.channel) {
4245
+ var channel = this.channel(event.channel);
4246
+ if (!channel) {
4247
+ return;
4248
+ }
4249
+ const reconstructedEvent = this.deltaCompression.handleDeltaMessage(
4250
+ event.channel,
4251
+ event.data
4252
+ );
4253
+ if (reconstructedEvent) {
4254
+ if (channel) {
4255
+ channel.handleEvent(reconstructedEvent);
4256
+ }
4257
+ this.global_emitter.emit(
4258
+ reconstructedEvent.event,
4259
+ reconstructedEvent.data
4260
+ );
4261
+ }
4262
+ return;
4263
+ }
4264
+ }
4265
+ if (event.channel) {
4266
+ var channel = this.channel(event.channel);
4267
+ if (channel) {
4268
+ channel.handleEvent(event);
4269
+ }
4270
+ if (this.deltaCompression && event.event && !event.event.startsWith("pusher:") && !event.event.startsWith("pusher_internal:")) {
4271
+ let sequence;
4272
+ if (typeof event.sequence === "number") {
4273
+ sequence = event.sequence;
4274
+ }
4275
+ let conflationKey;
4276
+ if (typeof event.conflation_key === "string") {
4277
+ conflationKey = event.conflation_key;
4278
+ }
4279
+ let fullMessage = event.rawMessage || "";
4280
+ if (fullMessage && sequence !== void 0) {
4281
+ fullMessage = fullMessage.replace(/,"__delta_seq":\d+/g, "");
4282
+ fullMessage = fullMessage.replace(/"__delta_seq":\d+,/g, "");
4283
+ fullMessage = fullMessage.replace(
4284
+ /,"__conflation_key":"[^"]*"/g,
4285
+ ""
4286
+ );
4287
+ fullMessage = fullMessage.replace(
4288
+ /"__conflation_key":"[^"]*",/g,
4289
+ ""
4290
+ );
4291
+ }
4292
+ this.deltaCompression.handleFullMessage(
4293
+ event.channel,
4294
+ fullMessage,
4295
+ sequence,
4296
+ conflationKey
4297
+ );
4298
+ }
4299
+ }
4300
+ if (!internal) {
4301
+ this.global_emitter.emit(event.event, event.data);
4302
+ }
4303
+ });
4304
+ this.connection.bind("connecting", () => {
4305
+ this.channels.disconnect();
4306
+ });
4307
+ this.connection.bind("disconnected", () => {
4308
+ this.channels.disconnect();
4309
+ });
4310
+ this.connection.bind("error", (err) => {
4311
+ Logger$1.warn(err);
4312
+ });
4313
+ Pusher.instances.push(this);
4314
+ this.timeline.info({ instances: Pusher.instances.length });
4315
+ this.user = new UserFacade(this);
4316
+ if (Pusher.isReady) {
4317
+ this.connect();
4318
+ }
4319
+ }
4320
+ channel(name) {
4321
+ return this.channels.find(name);
4322
+ }
4323
+ allChannels() {
4324
+ return this.channels.all();
4325
+ }
4326
+ connect() {
4327
+ this.connection.connect();
4328
+ if (this.timelineSender) {
4329
+ if (!this.timelineSenderTimer) {
4330
+ var usingTLS = this.connection.isUsingTLS();
4331
+ var timelineSender = this.timelineSender;
4332
+ this.timelineSenderTimer = new PeriodicTimer(6e4, function() {
4333
+ timelineSender.send(usingTLS);
4334
+ });
4335
+ }
4336
+ }
4337
+ }
4338
+ disconnect() {
4339
+ this.connection.disconnect();
4340
+ if (this.timelineSenderTimer) {
4341
+ this.timelineSenderTimer.ensureAborted();
4342
+ this.timelineSenderTimer = null;
4343
+ }
4344
+ }
4345
+ bind(event_name, callback, context) {
4346
+ this.global_emitter.bind(event_name, callback, context);
4347
+ return this;
4348
+ }
4349
+ unbind(event_name, callback, context) {
4350
+ this.global_emitter.unbind(event_name, callback, context);
4351
+ return this;
4352
+ }
4353
+ bind_global(callback) {
4354
+ this.global_emitter.bind_global(callback);
4355
+ return this;
4356
+ }
4357
+ unbind_global(callback) {
4358
+ this.global_emitter.unbind_global(callback);
4359
+ return this;
4360
+ }
4361
+ unbind_all(callback) {
4362
+ this.global_emitter.unbind_all();
4363
+ return this;
4364
+ }
4365
+ subscribeAll() {
4366
+ var channelName;
4367
+ for (channelName in this.channels.channels) {
4368
+ if (this.channels.channels.hasOwnProperty(channelName)) {
4369
+ this.subscribe(channelName);
4370
+ }
4371
+ }
4372
+ }
4373
+ subscribe(channel_name, tagsFilter) {
4374
+ var channel = this.channels.add(channel_name, this);
4375
+ if (tagsFilter) {
4376
+ channel.tagsFilter = tagsFilter;
4377
+ }
4378
+ if (channel.subscriptionPending && channel.subscriptionCancelled) {
4379
+ channel.reinstateSubscription();
4380
+ } else if (!channel.subscriptionPending && this.connection.state === "connected") {
4381
+ channel.subscribe();
4382
+ }
4383
+ return channel;
4384
+ }
4385
+ unsubscribe(channel_name) {
4386
+ var channel = this.channels.find(channel_name);
4387
+ if (channel && channel.subscriptionPending) {
4388
+ channel.cancelSubscription();
4389
+ } else {
4390
+ channel = this.channels.remove(channel_name);
4391
+ if (channel && channel.subscribed) {
4392
+ channel.unsubscribe();
4393
+ }
4394
+ }
4395
+ if (this.deltaCompression) {
4396
+ this.deltaCompression.clearChannelState(channel_name);
4397
+ }
4398
+ }
4399
+ send_event(event_name, data, channel) {
4400
+ return this.connection.send_event(event_name, data, channel);
4401
+ }
4402
+ shouldUseTLS() {
4403
+ return this.config.useTLS;
4404
+ }
4405
+ signin() {
4406
+ this.user.signin();
4407
+ }
4408
+ /**
4409
+ * Get delta compression statistics
4410
+ * @returns {DeltaStats} Statistics about delta compression bandwidth savings
4411
+ */
4412
+ getDeltaStats() {
4413
+ if (!this.deltaCompression) {
4414
+ return null;
4415
+ }
4416
+ return this.deltaCompression.getStats();
4417
+ }
4418
+ /**
4419
+ * Reset delta compression statistics
4420
+ */
4421
+ resetDeltaStats() {
4422
+ if (this.deltaCompression) {
4423
+ this.deltaCompression.resetStats();
4424
+ }
4425
+ }
4426
+ }
4427
+ function checkAppKey(key) {
4428
+ if (key === null || key === void 0) {
4429
+ throw "You must pass your app key when you instantiate Pusher.";
4430
+ }
4431
+ }
4432
+ NodeJS.setup(Pusher);
4433
+ module.exports = Pusher;
4434
+ //# sourceMappingURL=pusher.js.map