(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
  typeof define === 'function' && define.amd ? define(['exports'], factory) :
  (global = global || self, factory(global.ReactQueryBroadcastQueryClientExperimental = {}));
}(this, (function (exports) { 'use strict';

  /**
   * returns true if the given object is a promise
   */
  function isPromise(obj) {
    if (obj && typeof obj.then === 'function') {
      return true;
    } else {
      return false;
    }
  }
  function sleep(time) {
    if (!time) time = 0;
    return new Promise(function (res) {
      return setTimeout(res, time);
    });
  }
  function randomInt(min, max) {
    return Math.floor(Math.random() * (max - min + 1) + min);
  }
  /**
   * https://stackoverflow.com/a/8084248
   */

  function randomToken() {
    return Math.random().toString(36).substring(2);
  }
  var lastMs = 0;
  var additional = 0;
  /**
   * returns the current time in micro-seconds,
   * WARNING: This is a pseudo-function
   * Performance.now is not reliable in webworkers, so we just make sure to never return the same time.
   * This is enough in browsers, and this function will not be used in nodejs.
   * The main reason for this hack is to ensure that BroadcastChannel behaves equal to production when it is used in fast-running unit tests.
   */

  function microSeconds() {
    var ms = new Date().getTime();

    if (ms === lastMs) {
      additional++;
      return ms * 1000 + additional;
    } else {
      lastMs = ms;
      additional = 0;
      return ms * 1000;
    }
  }
  /**
   * copied from the 'detect-node' npm module
   * We cannot use the module directly because it causes problems with rollup
   * @link https://github.com/iliakan/detect-node/blob/master/index.js
   */

  var isNode = Object.prototype.toString.call(typeof process !== 'undefined' ? process : 0) === '[object process]';

  var microSeconds$1 = microSeconds;
  var type = 'native';
  function create(channelName) {
    var state = {
      messagesCallback: null,
      bc: new BroadcastChannel(channelName),
      subFns: [] // subscriberFunctions

    };

    state.bc.onmessage = function (msg) {
      if (state.messagesCallback) {
        state.messagesCallback(msg.data);
      }
    };

    return state;
  }
  function close(channelState) {
    channelState.bc.close();
    channelState.subFns = [];
  }
  function postMessage(channelState, messageJson) {
    channelState.bc.postMessage(messageJson, false);
  }
  function onMessage(channelState, fn) {
    channelState.messagesCallback = fn;
  }
  function canBeUsed() {
    /**
     * in the electron-renderer, isNode will be true even if we are in browser-context
     * so we also check if window is undefined
     */
    if (isNode && typeof window === 'undefined') return false;

    if (typeof BroadcastChannel === 'function') {
      if (BroadcastChannel._pubkey) {
        throw new Error('BroadcastChannel: Do not overwrite window.BroadcastChannel with this module, this is not a polyfill');
      }

      return true;
    } else return false;
  }
  function averageResponseTime() {
    return 150;
  }
  var NativeMethod = {
    create: create,
    close: close,
    onMessage: onMessage,
    postMessage: postMessage,
    canBeUsed: canBeUsed,
    type: type,
    averageResponseTime: averageResponseTime,
    microSeconds: microSeconds$1
  };

  /**
   * this is a set which automatically forgets
   * a given entry when a new entry is set and the ttl
   * of the old one is over
   * @constructor
   */
  var ObliviousSet = function ObliviousSet(ttl) {
    var set = new Set();
    var timeMap = new Map();
    this.has = set.has.bind(set);

    this.add = function (value) {
      timeMap.set(value, now());
      set.add(value);

      _removeTooOldValues();
    };

    this.clear = function () {
      set.clear();
      timeMap.clear();
    };

    function _removeTooOldValues() {
      var olderThen = now() - ttl;
      var iterator = set[Symbol.iterator]();

      while (true) {
        var value = iterator.next().value;
        if (!value) return; // no more elements

        var time = timeMap.get(value);

        if (time < olderThen) {
          timeMap["delete"](value);
          set["delete"](value);
        } else {
          // we reached a value that is not old enough
          return;
        }
      }
    }
  };

  function now() {
    return new Date().getTime();
  }

  function fillOptionsWithDefaults() {
    var originalOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
    var options = JSON.parse(JSON.stringify(originalOptions)); // main

    if (typeof options.webWorkerSupport === 'undefined') options.webWorkerSupport = true; // indexed-db

    if (!options.idb) options.idb = {}; //  after this time the messages get deleted

    if (!options.idb.ttl) options.idb.ttl = 1000 * 45;
    if (!options.idb.fallbackInterval) options.idb.fallbackInterval = 150; //  handles abrupt db onclose events.

    if (originalOptions.idb && typeof originalOptions.idb.onclose === 'function') options.idb.onclose = originalOptions.idb.onclose; // localstorage

    if (!options.localstorage) options.localstorage = {};
    if (!options.localstorage.removeTimeout) options.localstorage.removeTimeout = 1000 * 60; // custom methods

    if (originalOptions.methods) options.methods = originalOptions.methods; // node

    if (!options.node) options.node = {};
    if (!options.node.ttl) options.node.ttl = 1000 * 60 * 2; // 2 minutes;

    if (typeof options.node.useFastPath === 'undefined') options.node.useFastPath = true;
    return options;
  }

  /**
   * this method uses indexeddb to store the messages
   * There is currently no observerAPI for idb
   * @link https://github.com/w3c/IndexedDB/issues/51
   */
  var microSeconds$2 = microSeconds;
  var DB_PREFIX = 'pubkey.broadcast-channel-0-';
  var OBJECT_STORE_ID = 'messages';
  var type$1 = 'idb';
  function getIdb() {
    if (typeof indexedDB !== 'undefined') return indexedDB;

    if (typeof window !== 'undefined') {
      if (typeof window.mozIndexedDB !== 'undefined') return window.mozIndexedDB;
      if (typeof window.webkitIndexedDB !== 'undefined') return window.webkitIndexedDB;
      if (typeof window.msIndexedDB !== 'undefined') return window.msIndexedDB;
    }

    return false;
  }
  function createDatabase(channelName) {
    var IndexedDB = getIdb(); // create table

    var dbName = DB_PREFIX + channelName;
    var openRequest = IndexedDB.open(dbName, 1);

    openRequest.onupgradeneeded = function (ev) {
      var db = ev.target.result;
      db.createObjectStore(OBJECT_STORE_ID, {
        keyPath: 'id',
        autoIncrement: true
      });
    };

    var dbPromise = new Promise(function (res, rej) {
      openRequest.onerror = function (ev) {
        return rej(ev);
      };

      openRequest.onsuccess = function () {
        res(openRequest.result);
      };
    });
    return dbPromise;
  }
  /**
   * writes the new message to the database
   * so other readers can find it
   */

  function writeMessage(db, readerUuid, messageJson) {
    var time = new Date().getTime();
    var writeObject = {
      uuid: readerUuid,
      time: time,
      data: messageJson
    };
    var transaction = db.transaction([OBJECT_STORE_ID], 'readwrite');
    return new Promise(function (res, rej) {
      transaction.oncomplete = function () {
        return res();
      };

      transaction.onerror = function (ev) {
        return rej(ev);
      };

      var objectStore = transaction.objectStore(OBJECT_STORE_ID);
      objectStore.add(writeObject);
    });
  }
  function getMessagesHigherThan(db, lastCursorId) {
    var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);
    var ret = [];

    function openCursor() {
      // Occasionally Safari will fail on IDBKeyRange.bound, this
      // catches that error, having it open the cursor to the first
      // item. When it gets data it will advance to the desired key.
      try {
        var keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity);
        return objectStore.openCursor(keyRangeValue);
      } catch (e) {
        return objectStore.openCursor();
      }
    }

    return new Promise(function (res) {
      openCursor().onsuccess = function (ev) {
        var cursor = ev.target.result;

        if (cursor) {
          if (cursor.value.id < lastCursorId + 1) {
            cursor["continue"](lastCursorId + 1);
          } else {
            ret.push(cursor.value);
            cursor["continue"]();
          }
        } else {
          res(ret);
        }
      };
    });
  }
  function removeMessageById(db, id) {
    var request = db.transaction([OBJECT_STORE_ID], 'readwrite').objectStore(OBJECT_STORE_ID)["delete"](id);
    return new Promise(function (res) {
      request.onsuccess = function () {
        return res();
      };
    });
  }
  function getOldMessages(db, ttl) {
    var olderThen = new Date().getTime() - ttl;
    var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);
    var ret = [];
    return new Promise(function (res) {
      objectStore.openCursor().onsuccess = function (ev) {
        var cursor = ev.target.result;

        if (cursor) {
          var msgObk = cursor.value;

          if (msgObk.time < olderThen) {
            ret.push(msgObk); //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);

            cursor["continue"]();
          } else {
            // no more old messages,
            res(ret);
            return;
          }
        } else {
          res(ret);
        }
      };
    });
  }
  function cleanOldMessages(db, ttl) {
    return getOldMessages(db, ttl).then(function (tooOld) {
      return Promise.all(tooOld.map(function (msgObj) {
        return removeMessageById(db, msgObj.id);
      }));
    });
  }
  function create$1(channelName, options) {
    options = fillOptionsWithDefaults(options);
    return createDatabase(channelName).then(function (db) {
      var state = {
        closed: false,
        lastCursorId: 0,
        channelName: channelName,
        options: options,
        uuid: randomToken(),

        /**
         * emittedMessagesIds
         * contains all messages that have been emitted before
         * @type {ObliviousSet}
         */
        eMIs: new ObliviousSet(options.idb.ttl * 2),
        // ensures we do not read messages in parrallel
        writeBlockPromise: Promise.resolve(),
        messagesCallback: null,
        readQueuePromises: [],
        db: db
      };
      /**
       * Handle abrupt closes that do not originate from db.close().
       * This could happen, for example, if the underlying storage is
       * removed or if the user clears the database in the browser's
       * history preferences.
       */

      db.onclose = function () {
        state.closed = true;
        if (options.idb.onclose) options.idb.onclose();
      };
      /**
       * if service-workers are used,
       * we have no 'storage'-event if they post a message,
       * therefore we also have to set an interval
       */


      _readLoop(state);

      return state;
    });
  }

  function _readLoop(state) {
    if (state.closed) return;
    readNewMessages(state).then(function () {
      return sleep(state.options.idb.fallbackInterval);
    }).then(function () {
      return _readLoop(state);
    });
  }

  function _filterMessage(msgObj, state) {
    if (msgObj.uuid === state.uuid) return false; // send by own

    if (state.eMIs.has(msgObj.id)) return false; // already emitted

    if (msgObj.data.time < state.messagesCallbackTime) return false; // older then onMessageCallback

    return true;
  }
  /**
   * reads all new messages from the database and emits them
   */


  function readNewMessages(state) {
    // channel already closed
    if (state.closed) return Promise.resolve(); // if no one is listening, we do not need to scan for new messages

    if (!state.messagesCallback) return Promise.resolve();
    return getMessagesHigherThan(state.db, state.lastCursorId).then(function (newerMessages) {
      var useMessages = newerMessages
      /**
       * there is a bug in iOS where the msgObj can be undefined some times
       * so we filter them out
       * @link https://github.com/pubkey/broadcast-channel/issues/19
       */
      .filter(function (msgObj) {
        return !!msgObj;
      }).map(function (msgObj) {
        if (msgObj.id > state.lastCursorId) {
          state.lastCursorId = msgObj.id;
        }

        return msgObj;
      }).filter(function (msgObj) {
        return _filterMessage(msgObj, state);
      }).sort(function (msgObjA, msgObjB) {
        return msgObjA.time - msgObjB.time;
      }); // sort by time

      useMessages.forEach(function (msgObj) {
        if (state.messagesCallback) {
          state.eMIs.add(msgObj.id);
          state.messagesCallback(msgObj.data);
        }
      });
      return Promise.resolve();
    });
  }

  function close$1(channelState) {
    channelState.closed = true;
    channelState.db.close();
  }
  function postMessage$1(channelState, messageJson) {
    channelState.writeBlockPromise = channelState.writeBlockPromise.then(function () {
      return writeMessage(channelState.db, channelState.uuid, messageJson);
    }).then(function () {
      if (randomInt(0, 10) === 0) {
        /* await (do not await) */
        cleanOldMessages(channelState.db, channelState.options.idb.ttl);
      }
    });
    return channelState.writeBlockPromise;
  }
  function onMessage$1(channelState, fn, time) {
    channelState.messagesCallbackTime = time;
    channelState.messagesCallback = fn;
    readNewMessages(channelState);
  }
  function canBeUsed$1() {
    if (isNode) return false;
    var idb = getIdb();
    if (!idb) return false;
    return true;
  }
  function averageResponseTime$1(options) {
    return options.idb.fallbackInterval * 2;
  }
  var IndexeDbMethod = {
    create: create$1,
    close: close$1,
    onMessage: onMessage$1,
    postMessage: postMessage$1,
    canBeUsed: canBeUsed$1,
    type: type$1,
    averageResponseTime: averageResponseTime$1,
    microSeconds: microSeconds$2
  };

  /**
   * A localStorage-only method which uses localstorage and its 'storage'-event
   * This does not work inside of webworkers because they have no access to locastorage
   * This is basically implemented to support IE9 or your grandmothers toaster.
   * @link https://caniuse.com/#feat=namevalue-storage
   * @link https://caniuse.com/#feat=indexeddb
   */
  var microSeconds$3 = microSeconds;
  var KEY_PREFIX = 'pubkey.broadcastChannel-';
  var type$2 = 'localstorage';
  /**
   * copied from crosstab
   * @link https://github.com/tejacques/crosstab/blob/master/src/crosstab.js#L32
   */

  function getLocalStorage() {
    var localStorage;
    if (typeof window === 'undefined') return null;

    try {
      localStorage = window.localStorage;
      localStorage = window['ie8-eventlistener/storage'] || window.localStorage;
    } catch (e) {// New versions of Firefox throw a Security exception
      // if cookies are disabled. See
      // https://bugzilla.mozilla.org/show_bug.cgi?id=1028153
    }

    return localStorage;
  }
  function storageKey(channelName) {
    return KEY_PREFIX + channelName;
  }
  /**
  * writes the new message to the storage
  * and fires the storage-event so other readers can find it
  */

  function postMessage$2(channelState, messageJson) {
    return new Promise(function (res) {
      sleep().then(function () {
        var key = storageKey(channelState.channelName);
        var writeObj = {
          token: randomToken(),
          time: new Date().getTime(),
          data: messageJson,
          uuid: channelState.uuid
        };
        var value = JSON.stringify(writeObj);
        getLocalStorage().setItem(key, value);
        /**
         * StorageEvent does not fire the 'storage' event
         * in the window that changes the state of the local storage.
         * So we fire it manually
         */

        var ev = document.createEvent('Event');
        ev.initEvent('storage', true, true);
        ev.key = key;
        ev.newValue = value;
        window.dispatchEvent(ev);
        res();
      });
    });
  }
  function addStorageEventListener(channelName, fn) {
    var key = storageKey(channelName);

    var listener = function listener(ev) {
      if (ev.key === key) {
        fn(JSON.parse(ev.newValue));
      }
    };

    window.addEventListener('storage', listener);
    return listener;
  }
  function removeStorageEventListener(listener) {
    window.removeEventListener('storage', listener);
  }
  function create$2(channelName, options) {
    options = fillOptionsWithDefaults(options);

    if (!canBeUsed$2()) {
      throw new Error('BroadcastChannel: localstorage cannot be used');
    }

    var uuid = randomToken();
    /**
     * eMIs
     * contains all messages that have been emitted before
     * @type {ObliviousSet}
     */

    var eMIs = new ObliviousSet(options.localstorage.removeTimeout);
    var state = {
      channelName: channelName,
      uuid: uuid,
      eMIs: eMIs // emittedMessagesIds

    };
    state.listener = addStorageEventListener(channelName, function (msgObj) {
      if (!state.messagesCallback) return; // no listener

      if (msgObj.uuid === uuid) return; // own message

      if (!msgObj.token || eMIs.has(msgObj.token)) return; // already emitted

      if (msgObj.data.time && msgObj.data.time < state.messagesCallbackTime) return; // too old

      eMIs.add(msgObj.token);
      state.messagesCallback(msgObj.data);
    });
    return state;
  }
  function close$2(channelState) {
    removeStorageEventListener(channelState.listener);
  }
  function onMessage$2(channelState, fn, time) {
    channelState.messagesCallbackTime = time;
    channelState.messagesCallback = fn;
  }
  function canBeUsed$2() {
    if (isNode) return false;
    var ls = getLocalStorage();
    if (!ls) return false;

    try {
      var key = '__broadcastchannel_check';
      ls.setItem(key, 'works');
      ls.removeItem(key);
    } catch (e) {
      // Safari 10 in private mode will not allow write access to local
      // storage and fail with a QuotaExceededError. See
      // https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API#Private_Browsing_Incognito_modes
      return false;
    }

    return true;
  }
  function averageResponseTime$2() {
    var defaultTime = 120;
    var userAgent = navigator.userAgent.toLowerCase();

    if (userAgent.includes('safari') && !userAgent.includes('chrome')) {
      // safari is much slower so this time is higher
      return defaultTime * 2;
    }

    return defaultTime;
  }
  var LocalstorageMethod = {
    create: create$2,
    close: close$2,
    onMessage: onMessage$2,
    postMessage: postMessage$2,
    canBeUsed: canBeUsed$2,
    type: type$2,
    averageResponseTime: averageResponseTime$2,
    microSeconds: microSeconds$3
  };

  var microSeconds$4 = microSeconds;
  var type$3 = 'simulate';
  var SIMULATE_CHANNELS = new Set();
  function create$3(channelName) {
    var state = {
      name: channelName,
      messagesCallback: null
    };
    SIMULATE_CHANNELS.add(state);
    return state;
  }
  function close$3(channelState) {
    SIMULATE_CHANNELS["delete"](channelState);
  }
  function postMessage$3(channelState, messageJson) {
    return new Promise(function (res) {
      return setTimeout(function () {
        var channelArray = Array.from(SIMULATE_CHANNELS);
        channelArray.filter(function (channel) {
          return channel.name === channelState.name;
        }).filter(function (channel) {
          return channel !== channelState;
        }).filter(function (channel) {
          return !!channel.messagesCallback;
        }).forEach(function (channel) {
          return channel.messagesCallback(messageJson);
        });
        res();
      }, 5);
    });
  }
  function onMessage$3(channelState, fn) {
    channelState.messagesCallback = fn;
  }
  function canBeUsed$3() {
    return true;
  }
  function averageResponseTime$3() {
    return 5;
  }
  var SimulateMethod = {
    create: create$3,
    close: close$3,
    onMessage: onMessage$3,
    postMessage: postMessage$3,
    canBeUsed: canBeUsed$3,
    type: type$3,
    averageResponseTime: averageResponseTime$3,
    microSeconds: microSeconds$4
  };

  var METHODS = [NativeMethod, // fastest
  IndexeDbMethod, LocalstorageMethod];
  /**
   * The NodeMethod is loaded lazy
   * so it will not get bundled in browser-builds
   */

  if (isNode) {
    /**
     * we use the non-transpiled code for nodejs
     * because it runs faster
     */
    var NodeMethod = require('../../src/methods/' + // use this hack so that browserify and others
    // do not import the node-method by default
    // when bundling.
    'node.js');
    /**
     * this will be false for webpackbuilds
     * which will shim the node-method with an empty object {}
     */


    if (typeof NodeMethod.canBeUsed === 'function') {
      METHODS.push(NodeMethod);
    }
  }

  function chooseMethod(options) {
    var chooseMethods = [].concat(options.methods, METHODS).filter(Boolean); // directly chosen

    if (options.type) {
      if (options.type === 'simulate') {
        // only use simulate-method if directly chosen
        return SimulateMethod;
      }

      var ret = chooseMethods.find(function (m) {
        return m.type === options.type;
      });
      if (!ret) throw new Error('method-type ' + options.type + ' not found');else return ret;
    }
    /**
     * if no webworker support is needed,
     * remove idb from the list so that localstorage is been chosen
     */


    if (!options.webWorkerSupport && !isNode) {
      chooseMethods = chooseMethods.filter(function (m) {
        return m.type !== 'idb';
      });
    }

    var useMethod = chooseMethods.find(function (method) {
      return method.canBeUsed();
    });
    if (!useMethod) throw new Error('No useable methode found:' + JSON.stringify(METHODS.map(function (m) {
      return m.type;
    })));else return useMethod;
  }

  var BroadcastChannel$1 = function BroadcastChannel(name, options) {
    this.name = name;

    this.options = fillOptionsWithDefaults(options);
    this.method = chooseMethod(this.options); // isListening

    this._iL = false;
    /**
     * _onMessageListener
     * setting onmessage twice,
     * will overwrite the first listener
     */

    this._onML = null;
    /**
     * _addEventListeners
     */

    this._addEL = {
      message: [],
      internal: []
    };
    /**
     * _beforeClose
     * array of promises that will be awaited
     * before the channel is closed
     */

    this._befC = [];
    /**
     * _preparePromise
     */

    this._prepP = null;

    _prepareChannel(this);
  }; // STATICS

  /**
   * used to identify if someone overwrites
   * window.BroadcastChannel with this
   * See methods/native.js
   */

  BroadcastChannel$1._pubkey = true;

  BroadcastChannel$1.prototype = {
    postMessage: function postMessage(msg) {
      if (this.closed) {
        throw new Error('BroadcastChannel.postMessage(): ' + 'Cannot post message after channel has closed');
      }

      return _post(this, 'message', msg);
    },
    postInternal: function postInternal(msg) {
      return _post(this, 'internal', msg);
    },

    set onmessage(fn) {
      var time = this.method.microSeconds();
      var listenObj = {
        time: time,
        fn: fn
      };

      _removeListenerObject(this, 'message', this._onML);

      if (fn && typeof fn === 'function') {
        this._onML = listenObj;

        _addListenerObject(this, 'message', listenObj);
      } else {
        this._onML = null;
      }
    },

    addEventListener: function addEventListener(type, fn) {
      var time = this.method.microSeconds();
      var listenObj = {
        time: time,
        fn: fn
      };

      _addListenerObject(this, type, listenObj);
    },
    removeEventListener: function removeEventListener(type, fn) {
      var obj = this._addEL[type].find(function (obj) {
        return obj.fn === fn;
      });

      _removeListenerObject(this, type, obj);
    },
    close: function close() {
      var _this = this;

      if (this.closed) return;
      this.closed = true;
      var awaitPrepare = this._prepP ? this._prepP : Promise.resolve();
      this._onML = null;
      this._addEL.message = [];
      return awaitPrepare.then(function () {
        return Promise.all(_this._befC.map(function (fn) {
          return fn();
        }));
      }).then(function () {
        return _this.method.close(_this._state);
      });
    },

    get type() {
      return this.method.type;
    }

  };

  function _post(broadcastChannel, type, msg) {
    var time = broadcastChannel.method.microSeconds();
    var msgObj = {
      time: time,
      type: type,
      data: msg
    };
    var awaitPrepare = broadcastChannel._prepP ? broadcastChannel._prepP : Promise.resolve();
    return awaitPrepare.then(function () {
      return broadcastChannel.method.postMessage(broadcastChannel._state, msgObj);
    });
  }

  function _prepareChannel(channel) {
    var maybePromise = channel.method.create(channel.name, channel.options);

    if (isPromise(maybePromise)) {
      channel._prepP = maybePromise;
      maybePromise.then(function (s) {
        // used in tests to simulate slow runtime

        /*if (channel.options.prepareDelay) {
             await new Promise(res => setTimeout(res, this.options.prepareDelay));
        }*/
        channel._state = s;
      });
    } else {
      channel._state = maybePromise;
    }
  }

  function _hasMessageListeners(channel) {
    if (channel._addEL.message.length > 0) return true;
    if (channel._addEL.internal.length > 0) return true;
    return false;
  }

  function _addListenerObject(channel, type, obj) {
    channel._addEL[type].push(obj);

    _startListening(channel);
  }

  function _removeListenerObject(channel, type, obj) {
    channel._addEL[type] = channel._addEL[type].filter(function (o) {
      return o !== obj;
    });

    _stopListening(channel);
  }

  function _startListening(channel) {
    if (!channel._iL && _hasMessageListeners(channel)) {
      // someone is listening, start subscribing
      var listenerFn = function listenerFn(msgObj) {
        channel._addEL[msgObj.type].forEach(function (obj) {
          if (msgObj.time >= obj.time) {
            obj.fn(msgObj.data);
          }
        });
      };

      var time = channel.method.microSeconds();

      if (channel._prepP) {
        channel._prepP.then(function () {
          channel._iL = true;
          channel.method.onMessage(channel._state, listenerFn, time);
        });
      } else {
        channel._iL = true;
        channel.method.onMessage(channel._state, listenerFn, time);
      }
    }
  }

  function _stopListening(channel) {
    if (channel._iL && !_hasMessageListeners(channel)) {
      // noone is listening, stop subscribing
      channel._iL = false;
      var time = channel.method.microSeconds();
      channel.method.onMessage(channel._state, null, time);
    }
  }

  function broadcastQueryClient(_ref) {
    var queryClient = _ref.queryClient,
        _ref$broadcastChannel = _ref.broadcastChannel,
        broadcastChannel = _ref$broadcastChannel === void 0 ? 'react-query' : _ref$broadcastChannel;
    var transaction = false;

    var tx = function tx(cb) {
      transaction = true;
      cb();
      transaction = false;
    };

    var channel = new BroadcastChannel$1(broadcastChannel, {
      webWorkerSupport: false
    });
    var queryCache = queryClient.getQueryCache();
    queryClient.getQueryCache().subscribe(function (queryEvent) {
      var _queryEvent$action;

      if (transaction || !(queryEvent == null ? void 0 : queryEvent.query)) {
        return;
      }

      var _queryEvent$query = queryEvent.query,
          queryHash = _queryEvent$query.queryHash,
          queryKey = _queryEvent$query.queryKey,
          state = _queryEvent$query.state;

      if (queryEvent.type === 'queryUpdated' && ((_queryEvent$action = queryEvent.action) == null ? void 0 : _queryEvent$action.type) === 'success') {
        channel.postMessage({
          type: 'queryUpdated',
          queryHash: queryHash,
          queryKey: queryKey,
          state: state
        });
      }

      if (queryEvent.type === 'queryRemoved') {
        channel.postMessage({
          type: 'queryRemoved',
          queryHash: queryHash,
          queryKey: queryKey
        });
      }
    });

    channel.onmessage = function (action) {
      if (!(action == null ? void 0 : action.type)) {
        return;
      }

      tx(function () {
        var type = action.type,
            queryHash = action.queryHash,
            queryKey = action.queryKey,
            state = action.state;

        if (type === 'queryUpdated') {
          var query = queryCache.get(queryHash);

          if (query) {
            query.setState(state);
            return;
          }

          queryCache.build(queryClient, {
            queryKey: queryKey,
            queryHash: queryHash
          }, state);
        } else if (type === 'queryRemoved') {
          var _query = queryCache.get(queryHash);

          if (_query) {
            queryCache.remove(_query);
          }
        }
      });
    };
  }

  exports.broadcastQueryClient = broadcastQueryClient;

  Object.defineProperty(exports, '__esModule', { value: true });

})));
//# sourceMappingURL=broadcastQueryClient-experimental.development.js.map
