// rx/src/utils.ts
function deepEqual(x, y, matched) {
  if (x === y) {
    return true;
  } else if (typeof x == "object" && x != null && typeof y == "object" && y != null) {
    if (matched?.get(x)?.has(y)) return true;
    const xEntries = Object.entries(x);
    const yKeys = Object.keys(y);
    if (xEntries.length != yKeys.length) return false;
    if (!xEntries.length && x.constructor.name !== y.constructor.name) return false;
    for (const [key, val] of xEntries) {
      if (!yKeys.includes(key)) return false;
      if (!deepEqual(val, y[key], matched)) return false;
    }
    if (matched) {
      Object.freeze(y);
      if (!matched.has(x)) matched.set(x, /* @__PURE__ */ new WeakSet());
      matched.get(x).add(y);
    }
    return true;
  } else return false;
}
function deepFreeze(obj) {
  Object.freeze(obj);
  for (const value of Object.values(obj)) {
    if (value !== null && typeof value == "object") deepFreeze(value);
  }
  return obj;
}
var emptyFrozenObj = Object.freeze({});
function deepCopyFreeze(input, ref = {}, matched = /* @__PURE__ */ new Map()) {
  if (input === null || typeof input != "object") return input;
  if (input.constructor.name !== "Object" && input.constructor.name !== "Array" && typeof input.deepFreeze == "function") {
    if (!matched.has(input)) matched.set(input, /* @__PURE__ */ new WeakSet());
    matched.get(input).add(input);
    return input.deepFreeze();
  }
  if (deepEqual(input, ref, matched)) return Object.freeze(ref);
  const copy = Array.isArray(input) ? [] : {};
  const _ref = ref === null || typeof ref !== "object" ? emptyFrozenObj : ref;
  for (const [key, value] of Object.entries(input)) {
    copy[key] = deepCopyFreeze(value, _ref[key], matched);
  }
  return Object.freeze(copy);
}
async function notifyComponents(components, current) {
  if (!components) return;
  const called = [];
  for (const name of Object.keys(components)) {
    const component = components[name];
    if (Array.isArray(component)) {
      for (const c of component) called.push(c.update(current));
    } else if (typeof component == "object") {
      if (typeof component.update == "function") {
        called.push(component.update(current));
      } else if (!component.main) {
        for (const subname of Object.keys(component)) {
          if (typeof component[subname] == "object" && typeof component[subname]?.update == "function") {
            called.push(component[subname].update(current));
          }
        }
      }
    }
  }
  return Promise.all(called);
}
function copyMerge(base, ...args) {
  const target = typeof base == "string" ? fromJson(base) : base;
  for (const arg of args) {
    if (!arg) continue;
    const source = typeof base == "string" ? fromJson(toJson(arg)) : arg;
    for (const [key, value] of Object.entries(source)) {
      if (!target[key] || Array.isArray(target[key]) || typeof target[key] !== "object" || source === null || source === void 0 || source.isAtomic || target?.isAtomic || target[key]?.isAtomic) {
        target[key] = value;
      } else copyMerge(target[key], value);
    }
  }
  return target;
}
function fromJson(objStr) {
  return JSON.parse(objStr);
}
function toJson(obj = null) {
  return JSON.stringify(obj ? obj : this.state);
}
function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}
function getComponents(components, dotSepNames) {
  if (!dotSepNames) return Object.assign({}, components);
  const names = dotSepNames.split(".");
  let component = components;
  while (names.length) {
    let name = names.shift();
    if (Array.isArray(component)) name = Number(name);
    if (!names.length) component = component[name];
    else if (component[name] && component[name].components) component = component[name].components;
    else if (component[name] && component[name].getComponents) component = component[name].getComponents();
    else component = component[name];
    if (!component) break;
  }
  return component;
}

// rx/src/Bus.ts
var Bus = class {
  constructor(api, eventTypes, callbacks) {
    this.name = api.type + (api.id === void 0 || api.id === null ? "" : "#" + api.id);
    this.eventTypes = eventTypes;
    this.events = {};
    this.defaultArg = api;
    if (callbacks) {
      for (const [eventType, callback] of Object.entries(callbacks)) {
        this.on(eventType, callback);
      }
    }
  }
  on(eventType, callback, opts = {}) {
    const type = eventType.split(".").shift();
    if (!this.eventTypes.includes(type)) {
      throw `Unknown bus event '${type}' for component ${this.name}`;
    } else if (!callback) {
      delete this.events[eventType];
    } else if (typeof callback == "function") {
      if (eventType in this.events && !eventType.includes(".")) {
        console.log(`Warning: replacing ${this.name} ${eventType} callback - use event.name?`);
      }
      this.events[eventType] = opts.wait ? (arg) => setTimeout(() => callback(arg), opts.wait) : callback;
    } else {
      throw `invalid callback for ${this.name} eventType=${eventType}`;
    }
    return this;
  }
  emit(eventType, arg = null, wait = 0, error = null) {
    setTimeout(() => {
      for (const type of Object.keys(this.events)) {
        if (eventType == "postRender" && type.startsWith("firstRender")) {
          this.events[type](arg || this.defaultArg, error);
          delete this.events[type];
        }
        if (type == eventType || type.startsWith(eventType + ".")) {
          this.events[type](arg || this.defaultArg, error);
          if (eventType == "postInit") delete this.events[type];
        }
      }
    }, wait);
    return this;
  }
  destroy() {
    for (const key in this.events) {
      delete this.events[key];
    }
  }
};

// rx/src/AppApi.ts
var AppApi = class _AppApi {
  constructor(opts, __Class__) {
    this.type = "app";
    // only in debugmode
    this.#middlewares = [];
    this.#abortController = new AbortController();
    /** trackedAbortContrlsBySignal is used by trackAbortCtrlBySignal() */
    this.#trackedAbortContrlsBySignal = /* @__PURE__ */ new WeakMap();
    this.#componentsByType = {};
    const self = new __Class__(opts);
    self.opts = opts;
    if (!self.id) self.id = opts.id || self.opts?.id;
    if (!self.type) self.type = __Class__.type;
    self.api = this;
    this.#App = self;
    this.id = self.id;
    this.type = self.type || __Class__.type;
    this.opts = opts;
    if (self.debug || self.opts && self.opts.debug) this.Inner = self;
    if (!self.eventTypes) self.eventTypes = ["preDispatch", "postInit", "postRender", "firstRender", "error"];
    if (self.customEvents) self.eventTypes.push(...self.customEvents);
    self.bus = new Bus(this, self.eventTypes, opts.callbacks);
    this.#latestActionSequenceId = 0;
  }
  #App;
  #middlewares;
  #latestActionSequenceId;
  #abortController;
  #trackedAbortContrlsBySignal;
  #componentsByType;
  static getInitFxn(__Class__) {
    return async (opts) => {
      const api = new _AppApi(opts, __Class__);
      await api.init();
      return api;
    };
  }
  async init() {
    if (this.#App.preApiFreeze) await this.#App.preApiFreeze(this);
    if (typeof this.#App.init === "function") await this.#App.init();
    if (this.#App.bus) this.#App.bus.emit("postInit");
  }
  async dispatch(action) {
    const self = this.#App;
    self.bus.emit("preDispatch");
    if (this.#abortController)
      this.#abortController.abort("stale sequenceId");
    this.#abortController = new AbortController();
    try {
      if (this.#middlewares.length) {
        for (const fxn of this.#middlewares.slice()) {
          const result = await fxn(action);
          if (result) {
            if (result.cancel) return;
            if (result.error) throw result.error;
            if (result.deactivate) {
              this.#middlewares.splice(this.#middlewares.indexOf(fxn), 1);
            }
          }
        }
      }
      if (action) self.state = await self.store.write(action);
      this.#latestActionSequenceId = action?.sequenceId;
      if (self.main) await self.main();
      const current = { action, appState: self.state };
      await notifyComponents(current.action?._notificationRoot_ || self.components, current);
    } catch (e) {
      if (this.isAbortError(e) || e && typeof e == "object" && e.level === "warn") {
        self.bus.emit("postRender");
        console.warn(String(e));
        return;
      }
      if (self.wasDestroyed) return;
      if (self.bus && this.#latestActionSequenceId == action?.sequenceId) self.bus.emit("error");
      if (self.printError) self.printError(e);
      else console.log(e);
    }
    if (self.bus && this.#latestActionSequenceId == action?.sequenceId) self.bus.emit("postRender");
  }
  // action: RxAction
  async save(action) {
    const self = this.#App;
    if (self.wasDestroyed) return;
    self.state = await self.store.write(action);
    if (this.#componentsByType.recover) {
      for (const id in this.#componentsByType.recover) {
        const api = this.#componentsByType.recover[id];
        if (api.replaceLastState) api.replaceLastState(self.state);
      }
    }
  }
  getState() {
    return this.#App.state;
  }
  // fxn: RxAction => void
  middle(fxn) {
    if (typeof fxn !== "function") throw `a middleware must be a function`;
    if (this.#middlewares.includes(fxn)) throw `the function is already in the #middlewares array`;
    this.#middlewares.push(fxn);
    return this;
  }
  // must not expose this.bus directly since that
  // will also expose bus.emit() which should only
  // be triggered by this component
  on(eventType, callback) {
    const self = this.#App;
    if (!self.eventTypes) throw `no eventTypes[] for ${self.type} component`;
    self.bus.on(eventType, callback);
    return this;
  }
  getComponents(dotSepNames = "") {
    return getComponents(this.#App.components, dotSepNames);
  }
  register(api) {
    if (!this.#componentsByType[api.type]) this.#componentsByType[api.type] = {};
    this.#componentsByType[api.type][api.id] = api;
  }
  deregister(api) {
    if (this.#componentsByType[api.type]?.[api.id]) delete this.#componentsByType[api.type][api.id];
  }
  getAbortSignal() {
    if (!this.#abortController) this.#abortController = new AbortController();
    return this.#abortController?.signal;
  }
  triggerAbort(reason = "", signal) {
    if (reason) console.info(`triggerAbort()`, reason);
    if (signal) {
      if (signal.aborted) return;
      if (this.#abortController && signal === this.#abortController?.signal) this.#abortController.abort();
      else {
        const abortCtrl = this.#trackedAbortContrlsBySignal.get(signal);
        if (abortCtrl) abortCtrl.abort();
      }
      return;
    }
    const self = this.#App;
    if (this.#abortController) {
      this.#abortController.abort("stale sequenceId");
    }
    for (const name of Object.keys(self.components)) {
      const component = self.components[name];
      if (!component) continue;
      if (Array.isArray(component)) {
        for (const c of component) c.triggerAbort?.();
      } else if (!component || typeof component !== "object") {
        continue;
      } else if (typeof component.triggerAbort == "function") {
        component.triggerAbort();
      } else if (!component.main) {
        for (const subname of Object.keys(component)) {
          if (typeof component[subname].triggerAbort === "function") {
            component[subname].triggerAbort();
          }
        }
      }
    }
  }
  trackAbortCtrlBySignal(abortCtrl) {
    this.#trackedAbortContrlsBySignal.set(abortCtrl.signal, abortCtrl);
  }
  getSequenceId() {
    return this.#latestActionSequenceId;
  }
  isStaleSequenceId(sequenceId) {
    return sequenceId != this.#latestActionSequenceId;
  }
  isAbortError(e) {
    if (e instanceof DOMException) return e.name === "AbortError";
    if (typeof e == "string") return e.includes("stale sequenceId") || e.includes("AbortError");
    return false;
  }
  destroy() {
    this.#abortController?.abort();
    const self = this.#App;
    for (const key in self.components) {
      const component = self.components[key];
      if (typeof component.destroy == "function") {
        component.destroy();
      } else if (component.holder) {
        component.holder.selectAll("*").remove();
      }
      delete self.components[key];
    }
    if (typeof self.destroy == "function") self.destroy();
    if (self.dom) {
      if (self.dom.holder) self.dom.holder.selectAll("*").remove();
      for (const key in self.dom) {
        delete self.dom[key];
      }
    }
    if (self.bus) self.bus.destroy();
    delete self.store;
    if (self.api) delete self.api;
    self.wasDestroyed = true;
  }
  printError(e) {
    if (this.#App.printError) this.#App.printError(e);
    else alert(e);
  }
};

// rx/src/StoreApi.ts
var StoreApi = class _StoreApi {
  #Store;
  // only in debugmode
  #frozenStateCopy = Object.freeze({});
  static getInitFxn(__Class__) {
    return async (opts) => {
      const api = new _StoreApi(opts, __Class__);
      await api.init();
      return api;
    };
  }
  constructor(_opts, __Class__) {
    const opts = this.#validateOpts(_opts, __Class__);
    const self = new __Class__(opts, this);
    self.opts = Object.assign(self.opts || {}, opts);
    if (!self.state) self.state = self.copyMerge(structuredClone(self.defaultState), opts.state || {});
    if (!self.id) self.id = opts.id || self.opts?.id;
    if (!self.type) self.type = __Class__.type;
    self.api = this;
    this.#Store = self;
    this.id = self.id;
    this.type = self.type || __Class__.type;
    if (self.debug || self.opts?.debug) this.Inner = self;
  }
  #validateOpts(opts, __Class__) {
    const optKeys = Object.keys(opts);
    if (!optKeys.includes("app")) throw `missing opts.app`;
    if (!optKeys.includes("debug")) opts.debug = opts.app.debug ?? opts.app.opts?.debug ?? false;
    return opts;
  }
  async init() {
    if (this.#Store.init) await this.#Store.init();
    if (this.#Store.validateState) this.#Store.validateState();
    Object.freeze(this);
  }
  async write(action) {
    const self = this.#Store;
    action.sequenceId = this.#Store.sequenceId++;
    const actions = self.constructor.prototype.actions;
    if (!actions) {
      throw `no store actions specified`;
    }
    if (!Object.keys(actions).includes(action.type)) {
      throw `Action=${action.type} must be declared in an "actions" property of a class.`;
    }
    if (typeof actions[action.type] !== "function") {
      throw `invalid action type=${action.type}`;
    }
    await actions[action.type].call(self, action);
    self.state._scope_ = action._scope_;
    if (!self.opts.debounceInterval) return this.copyState();
    self.numPromisedWrites += 1;
    let decrement = -1;
    return new Promise((resolve) => {
      const interval = setInterval(() => {
        self.numPromisedWrites += decrement;
        decrement = 0;
        if (self.numPromisedWrites > 0) return;
        clearInterval(interval);
        resolve(this.copyState());
      }, self.opts.debounceInterval);
    });
  }
  async copyState() {
    this.#frozenStateCopy = deepCopyFreeze(this.#Store.state, this.#frozenStateCopy);
    return this.#frozenStateCopy;
  }
};

// rx/src/ComponentApi.ts
var ComponentApi = class _ComponentApi {
  #Component;
  // only in debugmode
  #latestActionSequenceId;
  #abortController = new AbortController();
  #abortControllers;
  // TODO: may use #incompleteUpdate property, if the shared app abortController signal is used
  // #incompleteUpdate: boolean = true
  #bus;
  #errdiv;
  static getInitFxn(__Class__) {
    return async (opts) => {
      const api = new _ComponentApi(opts, __Class__);
      await api.init();
      return api;
    };
  }
  constructor(_opts, __Class__) {
    const opts = this.#validateOpts(_opts, __Class__);
    const self = new __Class__(opts, this);
    self.opts = Object.assign(self.opts || {}, opts);
    if (!self.id) self.id = opts.id || self.opts?.id;
    if (!self.type) self.type = __Class__.type;
    self.app = opts.app;
    self.api = this;
    this.#Component = self;
    this.id = self.id;
    this.type = self.type || __Class__.type;
    if (self.debug || self.opts && self.opts.debug) this.Inner = self;
    if (!self.eventTypes) self.eventTypes = ["preDispatch", "postInit", "postRender", "firstRender", "error"];
    if (self.customEvents) self.eventTypes.push(...self.customEvents);
    self.bus = new Bus(this, self.eventTypes, opts.callbacks);
    this.#latestActionSequenceId = 0;
    this.#abortControllers = /* @__PURE__ */ new Set();
  }
  #validateOpts(opts, __Class__) {
    const optKeys = Object.keys(opts);
    if (!optKeys.includes("app")) throw `missing opts.app`;
    if (!optKeys.includes("debug")) opts.debug = opts.app.debug ?? opts.app.opts?.debug ?? false;
    if (__Class__.type && opts.app.opts?.[__Class__.type]) {
      copyMerge(opts, opts.app.opts[__Class__.type]);
    }
    return opts;
  }
  async init() {
    const self = this.#Component;
    if (self.preApiFreeze) await self.preApiFreeze(this);
    Object.freeze(this);
    if (self.init) await self.init(this.#Component.app.getState());
    if (self.state && !self.hasStatePreMain) {
      delete self.state;
      console.warn(
        `${self.type}: rx deleted this.state after init()to avoid confusing behavior, such as the component not rendering initially because this.state would not have changed between init() and the first time main() is called. To skip this warning and retain this.state after init(), set this.hasStatePreMain = true in the ${self.type} constructor.`
      );
    }
    self.bus.emit("postInit");
  }
  // current: {action: RxAction, appState}
  async update(current) {
    const self = this.#Component;
    if (
      /*!this.#incompleteUpdate &&*/
      current.action && self.reactsTo && !self.reactsTo(current.action)
    ) return;
    const componentState = self.getState ? self.getState(current.appState) : current.appState;
    if (!componentState) return;
    let detectedErrDisplay = "none";
    if (!this.#errdiv) this.#errdiv = self.dom?.errdiv || self.dom?.error;
    if (this.#errdiv) {
      detectedErrDisplay = this.#errdiv.style("display");
      this.#errdiv.style("display", "none").html?.("");
    }
    if (!current.action || detectedErrDisplay !== "none" || !deepEqual(componentState, self.state)) {
      if (current.action) this.#latestActionSequenceId = current.action.sequenceId;
      if (this.#abortController) {
        this.#abortController.abort("stale sequenceId");
      }
      this.#abortController = new AbortController();
      const preMainProps = self.opts.debug && self.opts.preMain?.(this, self);
      if (self.mainArg == "state") {
        try {
          await self.main(componentState);
        } catch (e) {
          if (self.app.isAbortError(e)) return;
          if (self.printError) self.printError(e);
          if (self.bus) self.bus.emit("error");
          if (!self.printError) throw e;
        }
      } else {
        self.state = componentState;
        if (self.main) {
          try {
            await self.main();
          } catch (e) {
            if (self.app.isAbortError(e)) return;
            if (self.printError) self.printError(e);
            if (self.bus) self.bus.emit("error");
            if (!self.printError) throw e;
          }
        }
      }
      if (preMainProps) self.opts.postMain?.(this, self, preMainProps);
    }
    try {
      await notifyComponents(self.components, current);
      if (self.bus && (!current.action || current.action.sequenceId === this.#latestActionSequenceId))
        self.bus.emit("postRender");
      return this;
    } catch (e) {
      if (self.printError) self.printError(e);
      else if (self.dom?.errdiv) throw { message: e.message || e.error || e, errdiv: self.dom?.errdiv };
      else throw e;
    }
  }
  getComponents(dotSepNames = "") {
    return getComponents(this.#Component.components, dotSepNames);
  }
  // must not expose self.bus directly since that
  // will also expose bus.emit() which should only
  // be triggered by this component
  on(eventType, callback) {
    const self = this.#Component;
    if (!self.eventTypes) throw `no eventTypes[] for ${self.type} component`;
    self.bus.on(eventType, callback);
    return this;
  }
  // getComponents(dotSepNames = '') {
  // 	return getComponents(self.components, dotSepNames)
  // }
  //
  // !!! detectStale() has been deprecated !!!
  // TODO: Replace all detectStale() usage with vocabApi.getAbortSignal()
  //
  // When an async function takes a while to resolve, such as for server requests,
  // a subsequent action may trigger another request before the first one resolves,
  // in that case should ignore the stale response/result from the async function.
  // This is an api function so that code that has access to this component api
  // can also tie-in a function call to the fresheness of the component action.
  //
  async detectStale(asyncFxn, opts = {}) {
    const abortControllers = this.#abortControllers;
    try {
      const actionSequenceId = this.#latestActionSequenceId;
      const promises = [];
      let i, promResolve;
      if (opts.abortCtrl) {
        abortControllers.add(opts.abortCtrl);
        promises.push(
          new Promise((resolve, reject) => {
            promResolve = resolve;
            i = setInterval(() => {
              if (actionSequenceId !== this.#latestActionSequenceId) {
                clearInterval(i);
                try {
                  opts.abortCtrl?.abort();
                  throw `stale sequenceId`;
                } catch (e) {
                  reject(e);
                }
              }
            }, opts.wait || 100);
          })
        );
      }
      promises.push(asyncFxn());
      const result = await Promise.race(promises);
      if (i) clearInterval(i);
      if (promResolve) promResolve();
      if (opts.abortCtrl && abortControllers.has(opts.abortCtrl)) abortControllers.delete(opts.abortCtrl);
      if (this.#latestActionSequenceId !== actionSequenceId) {
        console.warn("aborted state update, the returned data corresponds to a stale action.sequenceId");
        if (opts.abortCtrl) opts.abortCtrl.abort();
        return [result, true];
      }
      return [result];
    } catch (e) {
      if (typeof e == "string" && e.includes("sequenceId")) console.warn(e);
      throw e;
    }
  }
  getAbortSignal() {
    if (!this.#abortController) this.#abortController = new AbortController();
    return this.#abortController.signal;
  }
  triggerAbort(reason = "") {
    if (reason) console.info(`triggerAbort()`, reason);
    if (this.#abortController) {
      this.#abortController.abort("stale sequenceId");
    }
    for (const c of this.#abortControllers.values()) {
      try {
        c.abort();
        this.#abortControllers.delete(c);
      } catch (e) {
        console.warn("unable to cancel fetch: ", e);
        this.#abortControllers.delete(c);
      }
    }
    const self = this.#Component;
    if (!self.components) return;
    for (const name of Object.keys(self.components)) {
      const component = self.components[name];
      if (Array.isArray(component)) {
        for (const c of component) c.triggerAbort?.();
      } else if (!component || typeof component !== "object") {
        continue;
      } else if (typeof component.triggerAbort === "function") {
        component.triggerAbort();
      } else if (!component.main) {
        for (const subname of Object.keys(component)) {
          if (typeof component[subname].triggerAbort === "function") {
            component[subname].triggerAbort();
          }
        }
      }
    }
  }
  getSequenceId() {
    return this.#latestActionSequenceId;
  }
  isStaleSequenceId(sequenceId) {
    return sequenceId != this.#latestActionSequenceId;
  }
  destroy() {
    this.triggerAbort();
    const self = this.#Component;
    self.app.deregister(self.api);
    for (const key in self.components) {
      const component = self.components[key];
      if (typeof component.destroy == "function") {
        component.destroy();
      } else if (component.holder) {
        component.holder.selectAll("*").remove();
      }
      delete self.components[key];
    }
    if (typeof self.destroy == "function") self.destroy();
    if (self.dom) {
      if (self.dom.holder) self.dom.holder.selectAll("*").remove();
      for (const key in self.dom) {
        if (typeof self.dom[key]?.remove == "function") self.dom[key].remove();
        delete self.dom[key];
      }
    }
    if (self.bus) self.bus.destroy();
    if (self.api) delete self.api;
  }
  // defaults for optional preApiFreeze addons
  replaceLastState(_) {
  }
  getChartImages() {
    return this.#Component.getChartImages ? this.#Component.getChartImages() : null;
  }
};

// rx/src/wrappers.ts
function getInitFxn(_Class_) {
  return (opts) => {
    const self = new _Class_(opts);
    if (!self.opts) self.opts = opts;
    if (self.bus) self.bus.emit("postInit");
    if (!self.api) return Object.freeze(self);
    if (self.init) throw `legacy getInitFxn() does not accept a class with an init() method`;
    if (self.debug || self.opts?.debug) self.api.Inner = self;
    return Object.freeze(self.api);
  };
}
function getAppInit(_Class_) {
  if (_Class_.type) return AppApi.getInitFxn(_Class_);
  throw `A rx app class must declare a static type='app'.`;
}
function getStoreInit(_Class_) {
  if (_Class_.type) return StoreApi.getInitFxn(_Class_);
  throw `A rx store class must declare a static type='store'.`;
}
function getCompInit(_Class_) {
  if (_Class_.type) return ComponentApi.getInitFxn(_Class_);
  throw `A rx component class must declare a static type.`;
}
async function multiInit(initPromises) {
  const components = {};
  await Promise.all(Object.values(initPromises));
  for (const name in initPromises) {
    components[name] = await initPromises[name];
  }
  return components;
}

// rx/src/StoreBase.ts
var StoreBase = class {
  constructor(opts) {
    this.type = "store";
    // dom: any
    // config: any
    /** use for assigning unique IDs where needed
     * may be used later to simplify getting component state by type and id */
    this.prevGeneratedId = 0;
    // the action.sequenceId can be used by a chart/app
    // to identify the state that corresponds to an async step
    // like a server data request, so that a really late-arriving data
    // can be rejected if the state that was associated with that requested
    // is already stale/superseded by a subsequent state update
    this.sequenceId = 0;
    this.numPromisedWrites = 0;
    this.opts = this.validateOpts(opts);
    this.app = this.opts.app;
    this.id = opts.id;
  }
  validateOpts(o = {}) {
    return o;
  }
  fromJson(objStr) {
    return JSON.parse(objStr);
  }
  toJson(obj = null) {
    return JSON.stringify(obj ? obj : this.state);
  }
  deepFreeze(obj) {
    Object.freeze(obj);
    for (const value of Object.values(obj)) {
      if (value !== null && typeof value == "object") this.deepFreeze(value);
    }
  }
  copyMerge(base, ...args) {
    const target = typeof base == "string" ? this.fromJson(base) : base;
    for (const arg of args) {
      if (arg) {
        const source = typeof base == "string" ? this.fromJson(this.toJson(arg)) : arg;
        for (const key in source) {
          if (!target[key] || Array.isArray(target[key]) || typeof target[key] !== "object" || source === null || source === void 0 || source.isAtomic || target?.isAtomic || target[key]?.isAtomic)
            target[key] = source[key];
          else this.copyMerge(target[key], source[key]);
        }
      }
    }
    return target;
  }
};

export {
  Bus,
  deepEqual,
  deepFreeze,
  copyMerge,
  sleep,
  AppApi,
  StoreApi,
  StoreBase,
  getInitFxn,
  getAppInit,
  getStoreInit,
  getCompInit,
  multiInit
};
//# sourceMappingURL=chunk-M3J4MINX.js.map
