text: 'use strict';
  
  Object.defineProperty(exports, '__esModule', { value: true });
  
  var _tslib = require('./_virtual/_tslib.js');
  var types = require('./types.js');
  var State = require('./State.js');
  var actionTypes = require('./actionTypes.js');
  var actions = require('./actions.js');
  var environment = require('./environment.js');
  var utils = require('./utils.js');
  var scheduler = require('./scheduler.js');
  var Actor = require('./Actor.js');
  var stateUtils = require('./stateUtils.js');
  var registry = require('./registry.js');
  var devTools = require('./devTools.js');
  var serviceScope = require('./serviceScope.js');
  var behaviors = require('./behaviors.js');
  
  var DEFAULT_SPAWN_OPTIONS = {
    sync: false,
    autoForward: false
  };
  exports.InterpreterStatus = void 0;
  
  (function (InterpreterStatus) {
    InterpreterStatus[InterpreterStatus["NotStarted"] = 0] = "NotStarted";
    InterpreterStatus[InterpreterStatus["Running"] = 1] = "Running";
    InterpreterStatus[InterpreterStatus["Stopped"] = 2] = "Stopped";
  })(exports.InterpreterStatus || (exports.InterpreterStatus = {}));
  /** @ts-ignore [symbolObservable] creates problems for people without `skipLibCheck` who are on older versions of TS, remove this comment when we drop support for TS@<4.3 */
  
  
  var Interpreter =
  /*#__PURE__*/
  
  /** @class */
  function () {
    /**
     * Creates a new Interpreter instance (i.e., service) for the given machine with the provided options, if any.
     *
     * @param machine The machine to be interpreted
     * @param options Interpreter options
     */
    function Interpreter(machine, options) {
      var _this = this;
  
      if (options === void 0) {
        options = Interpreter.defaultOptions;
      }
  
      this.machine = machine;
      this.scheduler = new scheduler.Scheduler();
      this.delayedEventsMap = {};
      this.listeners = new Set();
      this.contextListeners = new Set();
      this.stopListeners = new Set();
      this.doneListeners = new Set();
      this.eventListeners = new Set();
      this.sendListeners = new Set();
      /**
       * Whether the service is started.
       */
  
      this.initialized = false;
      this.status = exports.InterpreterStatus.NotStarted;
      this.children = new Map();
      this.forwardTo = new Set();
      /**
       * Alias for Interpreter.prototype.start
       */
  
      this.init = this.start;
      /**
       * Sends an event to the running interpreter to trigger a transition.
       *
       * An array of events (batched) can be sent as well, which will send all
       * batched events to the running interpreter. The listeners will be
       * notified only **once** when all events are processed.
       *
       * @param event The event(s) to send
       */
  
      this.send = function (event, payload) {
        if (utils.isArray(event)) {
          _this.batch(event);
  
          return _this.state;
        }
  
        var _event = utils.toSCXMLEvent(utils.toEventObject(event, payload));
  
        if (_this.status === exports.InterpreterStatus.Stopped) {
          // do nothing
          if (!environment.IS_PRODUCTION) {
            utils.warn(false, "Event \"".concat(_event.name, "\" was sent to stopped service \"").concat(_this.machine.id, "\". This service has already reached its final state, and will not transition.\nEvent: ").concat(JSON.stringify(_event.data)));
          }
  
          return _this.state;
        }
  
        if (_this.status !== exports.InterpreterStatus.Running && !_this.options.deferEvents) {
          throw new Error("Event \"".concat(_event.name, "\" was sent to uninitialized service \"").concat(_this.machine.id // tslint:disable-next-line:max-line-length
          , "\". Make sure .start() is called for this service, or set { deferEvents: true } in the service options.\nEvent: ").concat(JSON.stringify(_event.data)));
        }
  
        _this.scheduler.schedule(function () {
          // Forward copy of event to child actors
          _this.forward(_event);
  
          var nextState = _this.nextState(_event);
  
          _this.update(nextState, _event);
        });
  
        return _this._state; // TODO: deprecate (should return void)
        // tslint:disable-next-line:semicolon
      };
  
      this.sendTo = function (event, to) {
        var isParent = _this.parent && (to === types.SpecialTargets.Parent || _this.parent.id === to);
        var target = isParent ? _this.parent : utils.isString(to) ? _this.children.get(to) || registry.registry.get(to) : utils.isActor(to) ? to : undefined;
  
        if (!target) {
          if (!isParent) {
            throw new Error("Unable to send event to child '".concat(to, "' from service '").concat(_this.id, "'."));
          } // tslint:disable-next-line:no-console
  
  
          if (!environment.IS_PRODUCTION) {
            utils.warn(false, "Service '".concat(_this.id, "' has no parent: unable to send event ").concat(event.type));
          }
  
          return;
        }
  
        if ('machine' in target) {
          // Send SCXML events to machines
          target.send(_tslib.__assign(_tslib.__assign({}, event), {
            name: event.name === actionTypes.error ? "".concat(actions.error(_this.id)) : event.name,
            origin: _this.sessionId
          }));
        } else {
          // Send normal events to other targets
          target.send(event.data);
        }
      };
  
      var resolvedOptions = _tslib.__assign(_tslib.__assign({}, Interpreter.defaultOptions), options);
  
      var clock = resolvedOptions.clock,
          logger = resolvedOptions.logger,
          parent = resolvedOptions.parent,
          id = resolvedOptions.id;
      var resolvedId = id !== undefined ? id : machine.id;
      this.id = resolvedId;
      this.logger = logger;
      this.clock = clock;
      this.parent = parent;
      this.options = resolvedOptions;
      this.scheduler = new scheduler.Scheduler({
        deferEvents: this.options.deferEvents
      });
      this.sessionId = registry.registry.bookId();
    }
  
    Object.defineProperty(Interpreter.prototype, "initialState", {
      get: function () {
        var _this = this;
  
        if (this._initialState) {
          return this._initialState;
        }
  
        return serviceScope.provide(this, function () {
          _this._initialState = _this.machine.initialState;
          return _this._initialState;
        });
      },
      enumerable: false,
      configurable: true
    });
    Object.defineProperty(Interpreter.prototype, "state", {
      get: function () {
        if (!environment.IS_PRODUCTION) {
          utils.warn(this.status !== exports.InterpreterStatus.NotStarted, "Attempted to read state from uninitialized service '".concat(this.id, "'. Make sure the service is started first."));
        }
  
        return this._state;
      },
      enumerable: false,
      configurable: true
    });
    /**
     * Executes the actions of the given state, with that state's `context` and `event`.
     *
     * @param state The state whose actions will be executed
     * @param actionsConfig The action implementations to use
     */
  
    Interpreter.prototype.execute = function (state, actionsConfig) {
      var e_1, _a;
  
      try {
        for (var _b = _tslib.__values(state.actions), _c = _b.next(); !_c.done; _c = _b.next()) {
          var action = _c.value;
          this.exec(action, state, actionsConfig);
        }
      } catch (e_1_1) {
        e_1 = {
          error: e_1_1
        };
      } finally {
        try {
          if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
        } finally {
          if (e_1) throw e_1.error;
        }
      }
    };
  
    Interpreter.prototype.update = function (state, _event) {
      var e_2, _a, e_3, _b, e_4, _c, e_5, _d;
  
      var _this = this; // Attach session ID to state
  
  
      state._sessionid = this.sessionId; // Update state
  
      this._state = state; // Execute actions
  
      if (this.options.execute) {
        this.execute(this.state);
      } // Update children
  
  
      this.children.forEach(function (child) {
        _this.state.children[child.id] = child;
      }); // Dev tools
  
      if (this.devTools) {
        this.devTools.send(_event.data, state);
      } // Execute listeners
  
  
      if (state.event) {
        try {
          for (var _e = _tslib.__values(this.eventListeners), _f = _e.next(); !_f.done; _f = _e.next()) {
            var listener = _f.value;
            listener(state.event);
          }
        } catch (e_2_1) {
          e_2 = {
            error: e_2_1
          };
        } finally {
          try {
            if (_f && !_f.done && (_a = _e.return)) _a.call(_e);
          } finally {
            if (e_2) throw e_2.error;
          }
        }
      }
  
      try {
        for (var _g = _tslib.__values(this.listeners), _h = _g.next(); !_h.done; _h = _g.next()) {
          var listener = _h.value;
          listener(state, state.event);
        }
      } catch (e_3_1) {
        e_3 = {
          error: e_3_1
        };
      } finally {
        try {
          if (_h && !_h.done && (_b = _g.return)) _b.call(_g);
        } finally {
          if (e_3) throw e_3.error;
        }
      }
  
      try {
        for (var _j = _tslib.__values(this.contextListeners), _k = _j.next(); !_k.done; _k = _j.next()) {
          var contextListener = _k.value;
          contextListener(this.state.context, this.state.history ? this.state.history.context : undefined);
        }
      } catch (e_4_1) {
        e_4 = {
          error: e_4_1
        };
      } finally {
        try {
          if (_k && !_k.done && (_c = _j.return)) _c.call(_j);
        } finally {
          if (e_4) throw e_4.error;
        }
      }
  
      var isDone = stateUtils.isInFinalState(state.configuration || [], this.machine);
  
      if (this.state.configuration && isDone) {
        // get final child state node
        var finalChildStateNode = state.configuration.find(function (sn) {
          return sn.type === 'final' && sn.parent === _this.machine;
        });
        var doneData = finalChildStateNode && finalChildStateNode.doneData ? utils.mapContext(finalChildStateNode.doneData, state.context, _event) : undefined;
  
        try {
          for (var _l = _tslib.__values(this.doneListeners), _m = _l.next(); !_m.done; _m = _l.next()) {
            var listener = _m.value;
            listener(actions.doneInvoke(this.id, doneData));
          }
        } catch (e_5_1) {
          e_5 = {
            error: e_5_1
          };
        } finally {
          try {
            if (_m && !_m.done && (_d = _l.return)) _d.call(_l);
          } finally {
            if (e_5) throw e_5.error;
          }
        }
  
        this.stop();
      }
    };
    /*
     * Adds a listener that is notified whenever a state transition happens. The listener is called with
     * the next state and the event object that caused the state transition.
     *
     * @param listener The state listener
     */
  
  
    Interpreter.prototype.onTransition = function (listener) {
      this.listeners.add(listener); // Send current state to listener
  
      if (this.status === exports.InterpreterStatus.Running) {
        listener(this.state, this.state.event);
      }
  
      return this;
    };
  
    Interpreter.prototype.subscribe = function (nextListenerOrObserver, _, // TODO: error listener
    completeListener) {
      var _this = this;
  
      if (!nextListenerOrObserver) {
        return {
          unsubscribe: function () {
            return void 0;
          }
        };
      }
  
      var listener;
      var resolvedCompleteListener = completeListener;
  
      if (typeof nextListenerOrObserver === 'function') {
        listener = nextListenerOrObserver;
      } else {
        listener = nextListenerOrObserver.next.bind(nextListenerOrObserver);
        resolvedCompleteListener = nextListenerOrObserver.complete.bind(nextListenerOrObserver);
      }
  
      this.listeners.add(listener); // Send current state to listener
  
      if (this.status === exports.InterpreterStatus.Running) {
        listener(this.state);
      }
  
      if (resolvedCompleteListener) {
        this.onDone(resolvedCompleteListener);
      }
  
      return {
        unsubscribe: function () {
          listener && _this.listeners.delete(listener);
          resolvedCompleteListener && _this.doneListeners.delete(resolvedCompleteListener);
        }
      };
    };
    /**
     * Adds an event listener that is notified whenever an event is sent to the running interpreter.
     * @param listener The event listener
     */
  
  
    Interpreter.prototype.onEvent = function (listener) {
      this.eventListeners.add(listener);
      return this;
    };
    /**
     * Adds an event listener that is notified whenever a `send` event occurs.
     * @param listener The event listener
     */
  
  
    Interpreter.prototype.onSend = function (listener) {
      this.sendListeners.add(listener);
      return this;
    };
    /**
     * Adds a context listener that is notified whenever the state context changes.
     * @param listener The context listener
     */
  
  
    Interpreter.prototype.onChange = function (listener) {
      this.contextListeners.add(listener);
      return this;
    };
    /**
     * Adds a listener that is notified when the machine is stopped.
     * @param listener The listener
     */
  
  
    Interpreter.prototype.onStop = function (listener) {
      this.stopListeners.add(listener);
      return this;
    };
    /**
     * Adds a state listener that is notified when the statechart has reached its final state.
     * @param listener The state listener
     */
  
  
    Interpreter.prototype.onDone = function (listener) {
      this.doneListeners.add(listener);
      return this;
    };
    /**
     * Removes a listener.
     * @param listener The listener to remove
     */
  
  
    Interpreter.prototype.off = function (listener) {
      this.listeners.delete(listener);
      this.eventListeners.delete(listener);
      this.sendListeners.delete(listener);
      this.stopListeners.delete(listener);
      this.doneListeners.delete(listener);
      this.contextListeners.delete(listener);
      return this;
    };
    /**
     * Starts the interpreter from the given state, or the initial state.
     * @param initialState The state to start the statechart from
     */
  
  
    Interpreter.prototype.start = function (initialState) {
      var _this = this;
  
      if (this.status === exports.InterpreterStatus.Running) {
        // Do not restart the service if it is already started
        return this;
      }
  
      registry.registry.register(this.sessionId, this);
      this.initialized = true;
      this.status = exports.InterpreterStatus.Running;
      var resolvedState = initialState === undefined ? this.initialState : serviceScope.provide(this, function () {
        return State.isStateConfig(initialState) ? _this.machine.resolveState(initialState) : _this.machine.resolveState(State.State.from(initialState, _this.machine.context));
      });
  
      if (this.options.devTools) {
        this.attachDev();
      }
  
      this.scheduler.initialize(function () {
        _this.update(resolvedState, actions.initEvent);
      });
      return this;
    };
    /**
     * Stops the interpreter and unsubscribe all listeners.
     *
     * This will also notify the `onStop` listeners.
     */
  
  
    Interpreter.prototype.stop = function () {
      var e_6, _a, e_7, _b, e_8, _c, e_9, _d, e_10, _e;
  
      var _this = this;
  
      try {
        for (var _f = _tslib.__values(this.listeners), _g = _f.next(); !_g.done; _g = _f.next()) {
          var listener = _g.value;
          this.listeners.delete(listener);
        }
      } catch (e_6_1) {
        e_6 = {
          error: e_6_1
        };
      } finally {
        try {
          if (_g && !_g.done && (_a = _f.return)) _a.call(_f);
        } finally {
          if (e_6) throw e_6.error;
        }
      }
  
      try {
        for (var _h = _tslib.__values(this.stopListeners), _j = _h.next(); !_j.done; _j = _h.next()) {
          var listener = _j.value; // call listener, then remove
  
          listener();
          this.stopListeners.delete(listener);
        }
      } catch (e_7_1) {
        e_7 = {
          error: e_7_1
        };
      } finally {
        try {
          if (_j && !_j.done && (_b = _h.return)) _b.call(_h);
        } finally {
          if (e_7) throw e_7.error;
        }
      }
  
      try {
        for (var _k = _tslib.__values(this.contextListeners), _l = _k.next(); !_l.done; _l = _k.next()) {
          var listener = _l.value;
          this.contextListeners.delete(listener);
        }
      } catch (e_8_1) {
        e_8 = {
          error: e_8_1
        };
      } finally {
        try {
          if (_l && !_l.done && (_c = _k.return)) _c.call(_k);
        } finally {
          if (e_8) throw e_8.error;
        }
      }
  
      try {
        for (var _m = _tslib.__values(this.doneListeners), _o = _m.next(); !_o.done; _o = _m.next()) {
          var listener = _o.value;
          this.doneListeners.delete(listener);
        }
      } catch (e_9_1) {
        e_9 = {
          error: e_9_1
        };
      } finally {
        try {
          if (_o && !_o.done && (_d = _m.return)) _d.call(_m);
        } finally {
          if (e_9) throw e_9.error;
        }
      }
  
      if (!this.initialized) {
        // Interpreter already stopped; do nothing
        return this;
      }
  
      _tslib.__spreadArray([], _tslib.__read(this.state.configuration), false).sort(function (a, b) {
        return b.order - a.order;
      }).forEach(function (stateNode) {
        var e_11, _a;
  
        try {
          for (var _b = _tslib.__values(stateNode.definition.exit), _c = _b.next(); !_c.done; _c = _b.next()) {
            var action = _c.value;
  
            _this.exec(action, _this.state);
          }
        } catch (e_11_1) {
          e_11 = {
            error: e_11_1
          };
        } finally {
          try {
            if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
          } finally {
            if (e_11) throw e_11.error;
          }
        }
      }); // Stop all children
  
  
      this.children.forEach(function (child) {
        if (utils.isFunction(child.stop)) {
          child.stop();
        }
      });
  
      try {
        // Cancel all delayed events
        for (var _p = _tslib.__values(Object.keys(this.delayedEventsMap)), _q = _p.next(); !_q.done; _q = _p.next()) {
          var key = _q.value;
          this.clock.clearTimeout(this.delayedEventsMap[key]);
        }
      } catch (e_10_1) {
        e_10 = {
          error: e_10_1
        };
      } finally {
        try {
          if (_q && !_q.done && (_e = _p.return)) _e.call(_p);
        } finally {
          if (e_10) throw e_10.error;
        }
      }
  
      this.scheduler.clear();
      this.initialized = false;
      this.status = exports.InterpreterStatus.Stopped;
      registry.registry.free(this.sessionId);
      return this;
    };
  
    Interpreter.prototype.batch = function (events) {
      var _this = this;
  
      if (this.status === exports.InterpreterStatus.NotStarted && this.options.deferEvents) {
        // tslint:disable-next-line:no-console
        if (!environment.IS_PRODUCTION) {
          utils.warn(false, "".concat(events.length, " event(s) were sent to uninitialized service \"").concat(this.machine.id, "\" and are deferred. Make sure .start() is called for this service.\nEvent: ").concat(JSON.stringify(event)));
        }
      } else if (this.status !== exports.InterpreterStatus.Running) {
        throw new Error( // tslint:disable-next-line:max-line-length
        "".concat(events.length, " event(s) were sent to uninitialized service \"").concat(this.machine.id, "\". Make sure .start() is called for this service, or set { deferEvents: true } in the service options."));
      }
  
      this.scheduler.schedule(function () {
        var e_12, _a;
  
        var nextState = _this.state;
        var batchChanged = false;
        var batchedActions = [];
  
        var _loop_1 = function (event_1) {
          var _event = utils.toSCXMLEvent(event_1);
  
          _this.forward(_event);
  
          nextState = serviceScope.provide(_this, function () {
            return _this.machine.transition(nextState, _event);
          });
          batchedActions.push.apply(batchedActions, _tslib.__spreadArray([], _tslib.__read(nextState.actions.map(function (a) {
            return State.bindActionToState(a, nextState);
          })), false));
          batchChanged = batchChanged || !!nextState.changed;
        };
  
        try {
          for (var events_1 = _tslib.__values(events), events_1_1 = events_1.next(); !events_1_1.done; events_1_1 = events_1.next()) {
            var event_1 = events_1_1.value;
  
            _loop_1(event_1);
          }
        } catch (e_12_1) {
          e_12 = {
            error: e_12_1
          };
        } finally {
          try {
            if (events_1_1 && !events_1_1.done && (_a = events_1.return)) _a.call(events_1);
          } finally {
            if (e_12) throw e_12.error;
          }
        }
  
        nextState.changed = batchChanged;
        nextState.actions = batchedActions;
  
        _this.update(nextState, utils.toSCXMLEvent(events[events.length - 1]));
      });
    };
    /**
     * Returns a send function bound to this interpreter instance.
     *
     * @param event The event to be sent by the sender.
     */
  
  
    Interpreter.prototype.sender = function (event) {
      return this.send.bind(this, event);
    };
    /**
     * Returns the next state given the interpreter's current state and the event.
     *
     * This is a pure method that does _not_ update the interpreter's state.
     *
     * @param event The event to determine the next state
     */
  
  
    Interpreter.prototype.nextState = function (event) {
      var _this = this;
  
      var _event = utils.toSCXMLEvent(event);
  
      if (_event.name.indexOf(actionTypes.errorPlatform) === 0 && !this.state.nextEvents.some(function (nextEvent) {
        return nextEvent.indexOf(actionTypes.errorPlatform) === 0;
      })) {
        throw _event.data.data;
      }
  
      var nextState = serviceScope.provide(this, function () {
        return _this.machine.transition(_this.state, _event);
      });
      return nextState;
    };
  
    Interpreter.prototype.forward = function (event) {
      var e_13, _a;
  
      try {
        for (var _b = _tslib.__values(this.forwardTo), _c = _b.next(); !_c.done; _c = _b.next()) {
          var id = _c.value;
          var child = this.children.get(id);
  
          if (!child) {
            throw new Error("Unable to forward event '".concat(event, "' from interpreter '").concat(this.id, "' to nonexistant child '").concat(id, "'."));
          }
  
          child.send(event);
        }
      } catch (e_13_1) {
        e_13 = {
          error: e_13_1
        };
      } finally {
        try {
          if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
        } finally {
          if (e_13) throw e_13.error;
        }
      }
    };
  
    Interpreter.prototype.defer = function (sendAction) {
      var _this = this;
  
      this.delayedEventsMap[sendAction.id] = this.clock.setTimeout(function () {
        if (sendAction.to) {
          _this.sendTo(sendAction._event, sendAction.to);
        } else {
          _this.send(sendAction._event);
        }
      }, sendAction.delay);
    };
  
    Interpreter.prototype.cancel = function (sendId) {
      this.clock.clearTimeout(this.delayedEventsMap[sendId]);
      delete this.delayedEventsMap[sendId];
    };
  
    Interpreter.prototype.exec = function (action, state, actionFunctionMap) {
      if (actionFunctionMap === void 0) {
        actionFunctionMap = this.machine.options.actions;
      }
  
      var context = state.context,
          _event = state._event;
      var actionOrExec = action.exec || actions.getActionFunction(action.type, actionFunctionMap);
      var exec = utils.isFunction(actionOrExec) ? actionOrExec : actionOrExec ? actionOrExec.exec : action.exec;
  
      if (exec) {
        try {
          return exec(context, _event.data, {
            action: action,
            state: this.state,
            _event: _event
          });
        } catch (err) {
          if (this.parent) {
            this.parent.send({
              type: 'xstate.error',
              data: err
            });
          }
  
          throw err;
        }
      }
  
      switch (action.type) {
        case actionTypes.send:
          var sendAction = action;
  
          if (typeof sendAction.delay === 'number') {
            this.defer(sendAction);
            return;
          } else {
            if (sendAction.to) {
              this.sendTo(sendAction._event, sendAction.to);
            } else {
              this.send(sendAction._event);
            }
          }
  
          break;
  
        case actionTypes.cancel:
          this.cancel(action.sendId);
          break;
  
        case actionTypes.start:
          {
            if (this.status !== exports.InterpreterStatus.Running) {
              return;
            }
  
            var activity = action.activity; // If the activity will be stopped right after it's started
            // (such as in transient states)
            // don't bother starting the activity.
  
            if (!this.state.activities[activity.id || activity.type]) {
              break;
            } // Invoked services
  
  
            if (activity.type === types.ActionTypes.Invoke) {
              var invokeSource = utils.toInvokeSource(activity.src);
              var serviceCreator = this.machine.options.services ? this.machine.options.services[invokeSource.type] : undefined;
              var id = activity.id,
                  data = activity.data;
  
              if (!environment.IS_PRODUCTION) {
                utils.warn(!('forward' in activity), // tslint:disable-next-line:max-line-length
                "`forward` property is deprecated (found in invocation of '".concat(activity.src, "' in in machine '").concat(this.machine.id, "'). ") + "Please use `autoForward` instead.");
              }
  
              var autoForward = 'autoForward' in activity ? activity.autoForward : !!activity.forward;
  
              if (!serviceCreator) {
                // tslint:disable-next-line:no-console
                if (!environment.IS_PRODUCTION) {
                  utils.warn(false, "No service found for invocation '".concat(activity.src, "' in machine '").concat(this.machine.id, "'."));
                }
  
                return;
              }
  
              var resolvedData = data ? utils.mapContext(data, context, _event) : undefined;
  
              if (typeof serviceCreator === 'string') {
                // TODO: warn
                return;
              }
  
              var source = utils.isFunction(serviceCreator) ? serviceCreator(context, _event.data, {
                data: resolvedData,
                src: invokeSource,
                meta: activity.meta
              }) : serviceCreator;
  
              if (!source) {
                // TODO: warn?
                return;
              }
  
              var options = void 0;
  
              if (utils.isMachine(source)) {
                source = resolvedData ? source.withContext(resolvedData) : source;
                options = {
                  autoForward: autoForward
                };
              }
  
              this.spawn(source, id, options);
            } else {
              this.spawnActivity(activity);
            }
  
            break;
          }
  
        case actionTypes.stop:
          {
            this.stopChild(action.activity.id);
            break;
          }
  
        case actionTypes.log:
          var label = action.label,
              value = action.value;
  
          if (label) {
            this.logger(label, value);
          } else {
            this.logger(value);
          }
  
          break;
  
        default:
          if (!environment.IS_PRODUCTION) {
            utils.warn(false, "No implementation found for action type '".concat(action.type, "'"));
          }
  
          break;
      }
  
      return undefined;
    };
  
    Interpreter.prototype.removeChild = function (childId) {
      var _a;
  
      this.children.delete(childId);
      this.forwardTo.delete(childId); // this.state might not exist at the time this is called,
      // such as when a child is added then removed while initializing the state
  
      (_a = this.state) === null || _a === void 0 ? true : delete _a.children[childId];
    };
  
    Interpreter.prototype.stopChild = function (childId) {
      var child = this.children.get(childId);
  
      if (!child) {
        return;
      }
  
      this.removeChild(childId);
  
      if (utils.isFunction(child.stop)) {
        child.stop();
      }
    };
  
    Interpreter.prototype.spawn = function (entity, name, options) {
      if (utils.isPromiseLike(entity)) {
        return this.spawnPromise(Promise.resolve(entity), name);
      } else if (utils.isFunction(entity)) {
        return this.spawnCallback(entity, name);
      } else if (Actor.isSpawnedActor(entity)) {
        return this.spawnActor(entity, name);
      } else if (utils.isObservable(entity)) {
        return this.spawnObservable(entity, name);
      } else if (utils.isMachine(entity)) {
        return this.spawnMachine(entity, _tslib.__assign(_tslib.__assign({}, options), {
          id: name
        }));
      } else if (utils.isBehavior(entity)) {
        return this.spawnBehavior(entity, name);
      } else {
        throw new Error("Unable to spawn entity \"".concat(name, "\" of type \"").concat(typeof entity, "\"."));
      }
    };
  
    Interpreter.prototype.spawnMachine = function (machine, options) {
      var _this = this;
  
      if (options === void 0) {
        options = {};
      }
  
      var childService = new Interpreter(machine, _tslib.__assign(_tslib.__assign({}, this.options), {
        parent: this,
        id: options.id || machine.id
      }));
  
      var resolvedOptions = _tslib.__assign(_tslib.__assign({}, DEFAULT_SPAWN_OPTIONS), options);
  
      if (resolvedOptions.sync) {
        childService.onTransition(function (state) {
          _this.send(actionTypes.update, {
            state: state,
            id: childService.id
          });
        });
      }
  
      var actor = childService;
      this.children.set(childService.id, actor);
  
      if (resolvedOptions.autoForward) {
        this.forwardTo.add(childService.id);
      }
  
      childService.onDone(function (doneEvent) {
        _this.removeChild(childService.id);
  
        _this.send(utils.toSCXMLEvent(doneEvent, {
          origin: childService.id
        }));
      }).start();
      return actor;
    };
  
    Interpreter.prototype.spawnBehavior = function (behavior, id) {
      var actorRef = behaviors.spawnBehavior(behavior, {
        id: id,
        parent: this
      });
      this.children.set(id, actorRef);
      return actorRef;
    };
  
    Interpreter.prototype.spawnPromise = function (promise, id) {
      var _a;
  
      var _this = this;
  
      var canceled = false;
      var resolvedData;
      promise.then(function (response) {
        if (!canceled) {
          resolvedData = response;
  
          _this.removeChild(id);
  
          _this.send(utils.toSCXMLEvent(actions.doneInvoke(id, response), {
            origin: id
          }));
        }
      }, function (errorData) {
        if (!canceled) {
          _this.removeChild(id);
  
          var errorEvent = actions.error(id, errorData);
  
          try {
            // Send "error.platform.id" to this (parent).
            _this.send(utils.toSCXMLEvent(errorEvent, {
              origin: id
            }));
          } catch (error) {
            utils.reportUnhandledExceptionOnInvocation(errorData, error, id);
  
            if (_this.devTools) {
              _this.devTools.send(errorEvent, _this.state);
            }
  
            if (_this.machine.strict) {
              // it would be better to always stop the state machine if unhandled
              // exception/promise rejection happens but because we don't want to
              // break existing code so enforce it on strict mode only especially so
              // because documentation says that onError is optional
              _this.stop();
            }
          }
        }
      });
      var actor = (_a = {
        id: id,
        send: function () {
          return void 0;
        },
        subscribe: function (next, handleError, complete) {
          var observer = utils.toObserver(next, handleError, complete);
          var unsubscribed = false;
          promise.then(function (response) {
            if (unsubscribed) {
              return;
            }
  
            observer.next(response);
  
            if (unsubscribed) {
              return;
            }
  
            observer.complete();
          }, function (err) {
            if (unsubscribed) {
              return;
            }
  
            observer.error(err);
          });
          return {
            unsubscribe: function () {
              return unsubscribed = true;
            }
          };
        },
        stop: function () {
          canceled = true;
        },
        toJSON: function () {
          return {
            id: id
          };
        },
        getSnapshot: function () {
          return resolvedData;
        }
      }, _a[utils.symbolObservable] = function () {
        return this;
      }, _a);
      this.children.set(id, actor);
      return actor;
    };
  
    Interpreter.prototype.spawnCallback = function (callback, id) {
      var _a;
  
      var _this = this;
  
      var canceled = false;
      var receivers = new Set();
      var listeners = new Set();
      var emitted;
  
      var receive = function (e) {
        emitted = e;
        listeners.forEach(function (listener) {
          return listener(e);
        });
  
        if (canceled) {
          return;
        }
  
        _this.send(utils.toSCXMLEvent(e, {
          origin: id
        }));
      };
  
      var callbackStop;
  
      try {
        callbackStop = callback(receive, function (newListener) {
          receivers.add(newListener);
        });
      } catch (err) {
        this.send(actions.error(id, err));
      }
  
      if (utils.isPromiseLike(callbackStop)) {
        // it turned out to be an async function, can't reliably check this before calling `callback`
        // because transpiled async functions are not recognizable
        return this.spawnPromise(callbackStop, id);
      }
  
      var actor = (_a = {
        id: id,
        send: function (event) {
          return receivers.forEach(function (receiver) {
            return receiver(event);
          });
        },
        subscribe: function (next) {
          var observer = utils.toObserver(next);
          listeners.add(observer.next);
          return {
            unsubscribe: function () {
              listeners.delete(observer.next);
            }
          };
        },
        stop: function () {
          canceled = true;
  
          if (utils.isFunction(callbackStop)) {
            callbackStop();
          }
        },
        toJSON: function () {
          return {
            id: id
          };
        },
        getSnapshot: function () {
          return emitted;
        }
      }, _a[utils.symbolObservable] = function () {
        return this;
      }, _a);
      this.children.set(id, actor);
      return actor;
    };
  
    Interpreter.prototype.spawnObservable = function (source, id) {
      var _a;
  
      var _this = this;
  
      var emitted;
      var subscription = source.subscribe(function (value) {
        emitted = value;
  
        _this.send(utils.toSCXMLEvent(value, {
          origin: id
        }));
      }, function (err) {
        _this.removeChild(id);
  
        _this.send(utils.toSCXMLEvent(actions.error(id, err), {
          origin: id
        }));
      }, function () {
        _this.removeChild(id);
  
        _this.send(utils.toSCXMLEvent(actions.doneInvoke(id), {
          origin: id
        }));
      });
      var actor = (_a = {
        id: id,
        send: function () {
          return void 0;
        },
        subscribe: function (next, handleError, complete) {
          return source.subscribe(next, handleError, complete);
        },
        stop: function () {
          return subscription.unsubscribe();
        },
        getSnapshot: function () {
          return emitted;
        },
        toJSON: function () {
          return {
            id: id
          };
        }
      }, _a[utils.symbolObservable] = function () {
        return this;
      }, _a);
      this.children.set(id, actor);
      return actor;
    };
  
    Interpreter.prototype.spawnActor = function (actor, name) {
      this.children.set(name, actor);
      return actor;
    };
  
    Interpreter.prototype.spawnActivity = function (activity) {
      var implementation = this.machine.options && this.machine.options.activities ? this.machine.options.activities[activity.type] : undefined;
  
      if (!implementation) {
        if (!environment.IS_PRODUCTION) {
          utils.warn(false, "No implementation found for activity '".concat(activity.type, "'"));
        } // tslint:disable-next-line:no-console
  
  
        return;
      } // Start implementation
  
  
      var dispose = implementation(this.state.context, activity);
      this.spawnEffect(activity.id, dispose);
    };
  
    Interpreter.prototype.spawnEffect = function (id, dispose) {
      var _a;
  
      this.children.set(id, (_a = {
        id: id,
        send: function () {
          return void 0;
        },
        subscribe: function () {
          return {
            unsubscribe: function () {
              return void 0;
            }
          };
        },
        stop: dispose || undefined,
        getSnapshot: function () {
          return undefined;
        },
        toJSON: function () {
          return {
            id: id
          };
        }
      }, _a[utils.symbolObservable] = function () {
        return this;
      }, _a));
    };
  
    Interpreter.prototype.attachDev = function () {
      var global = devTools.getGlobal();
  
      if (this.options.devTools && global) {
        if (global.__REDUX_DEVTOOLS_EXTENSION__) {
          var devToolsOptions = typeof this.options.devTools === 'object' ? this.options.devTools : undefined;
          this.devTools = global.__REDUX_DEVTOOLS_EXTENSION__.connect(_tslib.__assign(_tslib.__assign({
            name: this.id,
            autoPause: true,
            stateSanitizer: function (state) {
              return {
                value: state.value,
                context: state.context,
                actions: state.actions
              };
            }
          }, devToolsOptions), {
            features: _tslib.__assign({
              jump: false,
              skip: false
            }, devToolsOptions ? devToolsOptions.features : undefined)
          }), this.machine);
          this.devTools.init(this.state);
        } // add XState-specific dev tooling hook
  
  
        devTools.registerService(this);
      }
    };
  
    Interpreter.prototype.toJSON = function () {
      return {
        id: this.id
      };
    };
    /** @ts-ignore this creates problems for people without `skipLibCheck` who are on older versions of TS, remove this comment when we drop support for TS@<4.3 */
  
  
    Interpreter.prototype[utils.symbolObservable] = function () {
      return this;
    };
  
    Interpreter.prototype.getSnapshot = function () {
      if (this.status === exports.InterpreterStatus.NotStarted) {
        return this.initialState;
      }
  
      return this._state;
    };
    /**
     * The default interpreter options:
     *
     * - `clock` uses the global `setTimeout` and `clearTimeout` functions
     * - `logger` uses the global `console.log()` method
     */
  
  
    Interpreter.defaultOptions = /*#__PURE__*/function (global) {
      return {
        execute: true,
        deferEvents: true,
        clock: {
          setTimeout: function (fn, ms) {
            return setTimeout(fn, ms);
          },
          clearTimeout: function (id) {
            return clearTimeout(id);
          }
        },
        logger: global.console.log.bind(console),
        devTools: false
      };
    }(typeof self !== 'undefined' ? self : global);
  
    Interpreter.interpret = interpret;
    return Interpreter;
  }();
  
  var resolveSpawnOptions = function (nameOrOptions) {
    if (utils.isString(nameOrOptions)) {
      return _tslib.__assign(_tslib.__assign({}, DEFAULT_SPAWN_OPTIONS), {
        name: nameOrOptions
      });
    }
  
    return _tslib.__assign(_tslib.__assign(_tslib.__assign({}, DEFAULT_SPAWN_OPTIONS), {
      name: utils.uniqueId()
    }), nameOrOptions);
  };
  
  function spawn(entity, nameOrOptions) {
    var resolvedOptions = resolveSpawnOptions(nameOrOptions);
    return serviceScope.consume(function (service) {
      if (!environment.IS_PRODUCTION) {
        var isLazyEntity = utils.isMachine(entity) || utils.isFunction(entity);
        utils.warn(!!service || isLazyEntity, "Attempted to spawn an Actor (ID: \"".concat(utils.isMachine(entity) ? entity.id : 'undefined', "\") outside of a service. This will have no effect."));
      }
  
      if (service) {
        return service.spawn(entity, resolvedOptions.name, resolvedOptions);
      } else {
        return Actor.createDeferredActor(entity, resolvedOptions.name);
      }
    });
  }
  /**
   * Creates a new Interpreter instance for the given machine with the provided options, if any.
   *
   * @param machine The machine to interpret
   * @param options Interpreter options
   */
  
  function interpret(machine, options) {
    var interpreter = new Interpreter(machine, options);
    return interpreter;
  }
  
  exports.Interpreter = Interpreter;
  exports.interpret = interpret;
  exports.spawn = spawn;
  