(function (global, factory) {
  if (typeof define === "function" && define.amd) {
    define(["exports", "lodash/toPairs", "socket.io-client", "rxjs", "rxjs/operators", "../internals/actions"], factory);
  } else if (typeof exports !== "undefined") {
    factory(exports, require("lodash/toPairs"), require("socket.io-client"), require("rxjs"), require("rxjs/operators"), require("../internals/actions"));
  } else {
    var mod = {
      exports: {}
    };
    factory(mod.exports, global.toPairs, global.socket, global.rxjs, global.operators, global.actions);
    global.io = mod.exports;
  }
})(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : this, function (_exports, _toPairs, _socket, _rxjs, _operators, actions) {
  "use strict";

  Object.defineProperty(_exports, "__esModule", {
    value: true
  });
  _exports.default = _exports.testExports = void 0;
  _toPairs = _interopRequireDefault(_toPairs);
  _socket = _interopRequireDefault(_socket);
  actions = _interopRequireWildcard(actions);

  function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }

  function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }

  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

  const defaultOptions = {
    forceNew: true,
    reconnection: true,
    timeout: 10000,
    autoConnect: true,
    path: '/',
    query: {},
    json: true,
    upgrade: true
  };
  const eventHandlerMap = {
    connect: () => actions.connect(),
    connect_error: error => actions.connectError({
      error
    }),
    connect_timeout: timeout => actions.connectTimeout({
      timeout
    }),
    disconnect: reason => actions.disconnect({
      reason
    }),
    reconnect: attemptNumber => actions.reconnect({
      attemptNumber
    }),
    reconnecting: attemptNumber => actions.reconnecting({
      attemptNumber
    }),
    reconnect_error: error => actions.reconnectError({
      error
    }),
    reconnect_failed: attemptNumber => actions.reconnectFailed({
      attemptNumber
    }),
    ping: () => actions.ping(),
    pong: latency => actions.pong({
      latency
    })
  };

  function socketEventReducer(client, obs) {
    return (acc, [eventName, handler]) => client.on(eventName, (...args) => obs.next(handler(...args)));
  }

  function createTopicEmitter(obs, _actions = actions) {
    return topic => message => obs.next(_actions.newMessage({
      topic,
      message
    }));
  }

  function handleTopic(client, obs, emitToTopic) {
    return topic => client.on(topic, emitToTopic(topic));
  }

  function createObservableFromSocket(client, topics, _actions = actions, _eventHandlerMap = eventHandlerMap) {
    const topicBlacklist = Object.keys(_eventHandlerMap);

    if (topicBlacklist.find(key => topics.indexOf(key) > -1)) {
      return (0, _rxjs.throwError)(new Error(`These topics are reserved and cannot be subscribed to: ${topicBlacklist}`));
    }

    return new _rxjs.Observable(obs => {
      obs.next(_actions.createClient({
        client
      }));
      (0, _toPairs.default)(_eventHandlerMap).reduce(socketEventReducer(client, obs), undefined);
      const emitToTopic = createTopicEmitter(obs);
      topics.map(handleTopic(client, obs, emitToTopic));
      client.on('error', error => obs.error(error));
    });
  }

  const io = function io({
    url,
    topics = ['message'],
    socketOptions = {},
    stop$ = (0, _rxjs.of)(),
    _socketIO = _socket.default,
    _createObservableFromSocket = createObservableFromSocket
  }) {
    if (!url) return (0, _rxjs.throwError)(new Error('io creator requires a url<String>'));

    const client = _socketIO(url, { ...defaultOptions,
      ...socketOptions
    });

    const action$ = _createObservableFromSocket(client, topics);

    return action$.pipe((0, _operators.map)(action => [client, action]), (0, _operators.takeUntil)(stop$.pipe((0, _operators.tap)(() => client.disconnect()))), (0, _operators.shareReplay)(1));
  };

  const testExports = {
    createObservableFromSocket,
    createTopicEmitter,
    handleTopic,
    socketEventReducer
  };
  _exports.testExports = testExports;
  var _default = io;
  _exports.default = _default;
});
//# sourceMappingURL=io.js.map