/**
 * @license bippy
 *
 * Copyright (c) Aiden Bai, Million Software, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

// src/rdt-hook.ts
var version = "0.3.8";
var BIPPY_INSTRUMENTATION_STRING = `bippy-${version}`;
var objectDefineProperty = Object.defineProperty;
var objectHasOwnProperty = Object.prototype.hasOwnProperty;
var NO_OP = () => {
};
var checkDCE = (fn) => {
  try {
    const code = Function.prototype.toString.call(fn);
    if (code.indexOf("^_^") > -1) {
      setTimeout(() => {
        throw new Error(
          "React is running in production mode, but dead code elimination has not been applied. Read how to correctly configure React for production: https://reactjs.org/link/perf-use-production-build"
        );
      });
    }
  } catch {
  }
};
var isRealReactDevtools = (rdtHook = getRDTHook()) => {
  return "getFiberRoots" in rdtHook;
};
var isReactRefreshOverride = false;
var injectFnStr = void 0;
var isReactRefresh = (rdtHook = getRDTHook()) => {
  if (isReactRefreshOverride) return true;
  if (typeof rdtHook.inject === "function") {
    injectFnStr = rdtHook.inject.toString();
  }
  return Boolean(injectFnStr?.includes("(injected)"));
};
var onActiveListeners = /* @__PURE__ */ new Set();
var installRDTHook = (onActive) => {
  const renderers = /* @__PURE__ */ new Map();
  let i = 0;
  let rdtHook = {
    checkDCE,
    supportsFiber: true,
    supportsFlight: true,
    hasUnsupportedRendererAttached: false,
    renderers,
    onCommitFiberRoot: NO_OP,
    onCommitFiberUnmount: NO_OP,
    onPostCommitFiberRoot: NO_OP,
    inject(renderer) {
      const nextID = ++i;
      renderers.set(nextID, renderer);
      if (!rdtHook._instrumentationIsActive) {
        rdtHook._instrumentationIsActive = true;
        onActiveListeners.forEach((listener) => listener());
      }
      return nextID;
    },
    _instrumentationSource: BIPPY_INSTRUMENTATION_STRING,
    _instrumentationIsActive: false
  };
  try {
    objectDefineProperty(globalThis, "__REACT_DEVTOOLS_GLOBAL_HOOK__", {
      get() {
        return rdtHook;
      },
      set(newHook) {
        if (newHook && typeof newHook === "object") {
          const ourRenderers = rdtHook.renderers;
          rdtHook = newHook;
          if (ourRenderers.size > 0) {
            ourRenderers.forEach((renderer, id) => {
              newHook.renderers.set(id, renderer);
            });
            patchRDTHook(onActive);
          }
        }
      },
      configurable: true,
      enumerable: true
    });
    const originalWindowHasOwnProperty = window.hasOwnProperty;
    let hasRanHack = false;
    objectDefineProperty(window, "hasOwnProperty", {
      value: function() {
        try {
          if (!hasRanHack && // biome-ignore lint/style/noArguments: perf
          arguments[0] === "__REACT_DEVTOOLS_GLOBAL_HOOK__") {
            globalThis.__REACT_DEVTOOLS_GLOBAL_HOOK__ = void 0;
            hasRanHack = true;
            return -0;
          }
          return originalWindowHasOwnProperty.apply(this, arguments);
        } catch {
          return originalWindowHasOwnProperty.apply(this, arguments);
        }
      },
      configurable: true,
      writable: true
    });
  } catch {
    patchRDTHook(onActive);
  }
  return rdtHook;
};
var patchRDTHook = (onActive) => {
  if (onActive) {
    onActiveListeners.add(onActive);
  }
  try {
    const rdtHook = globalThis.__REACT_DEVTOOLS_GLOBAL_HOOK__;
    if (!rdtHook) return;
    if (!rdtHook._instrumentationSource) {
      rdtHook.checkDCE = checkDCE;
      rdtHook.supportsFiber = true;
      rdtHook.supportsFlight = true;
      rdtHook.hasUnsupportedRendererAttached = false;
      rdtHook._instrumentationSource = BIPPY_INSTRUMENTATION_STRING;
      rdtHook._instrumentationIsActive = false;
      if (rdtHook.renderers.size) {
        rdtHook._instrumentationIsActive = true;
        onActiveListeners.forEach((listener) => listener());
        return;
      }
      const prevInject = rdtHook.inject;
      if (isReactRefresh(rdtHook) && !isRealReactDevtools()) {
        isReactRefreshOverride = true;
        const nextID = rdtHook.inject({
          // @ts-expect-error this is not actually a ReactRenderer,
          scheduleRefresh() {
          }
        });
        if (nextID) {
          rdtHook._instrumentationIsActive = true;
        }
      }
      rdtHook.inject = (renderer) => {
        const id = prevInject(renderer);
        rdtHook._instrumentationIsActive = true;
        onActiveListeners.forEach((listener) => listener());
        return id;
      };
    }
    if (rdtHook.renderers.size || rdtHook._instrumentationIsActive || // depending on this to inject is unsafe, since inject could occur before and we wouldn't know
    isReactRefresh()) {
      onActive?.();
    }
  } catch {
  }
};
var hasRDTHook = () => {
  return objectHasOwnProperty.call(
    globalThis,
    "__REACT_DEVTOOLS_GLOBAL_HOOK__"
  );
};
var getRDTHook = (onActive) => {
  if (!hasRDTHook()) {
    return installRDTHook(onActive);
  }
  patchRDTHook(onActive);
  return globalThis.__REACT_DEVTOOLS_GLOBAL_HOOK__;
};
var isClientEnvironment = () => {
  return Boolean(
    typeof window !== "undefined" && (window.document?.createElement || window.navigator?.product === "ReactNative")
  );
};
var safelyInstallRDTHook = () => {
  try {
    if (isClientEnvironment()) {
      getRDTHook();
    }
  } catch {
  }
};

// src/core.ts
var FunctionComponentTag = 0;
var ClassComponentTag = 1;
var HostRootTag = 3;
var HostTextTag = 6;
var FragmentTag = 7;
var ContextConsumerTag = 9;
var ForwardRefTag = 11;
var SuspenseComponentTag = 13;
var MemoComponentTag = 14;
var SimpleMemoComponentTag = 15;
var DehydratedSuspenseComponentTag = 18;
var OffscreenComponentTag = 22;
var LegacyHiddenComponentTag = 23;
var CONCURRENT_MODE_NUMBER = 60111;
var CONCURRENT_MODE_SYMBOL_STRING = "Symbol(react.concurrent_mode)";
var DEPRECATED_ASYNC_MODE_SYMBOL_STRING = "Symbol(react.async_mode)";
var PerformedWork = 1;
var isCompositeFiber = (fiber) => {
  switch (fiber.tag) {
    case FunctionComponentTag:
    case ClassComponentTag:
    case SimpleMemoComponentTag:
    case MemoComponentTag:
    case ForwardRefTag:
      return true;
    default:
      return false;
  }
};
var traverseContexts = (fiber, selector) => {
  try {
    const nextDependencies = fiber.dependencies;
    const prevDependencies = fiber.alternate?.dependencies;
    if (!nextDependencies || !prevDependencies) return false;
    if (typeof nextDependencies !== "object" || !("firstContext" in nextDependencies) || typeof prevDependencies !== "object" || !("firstContext" in prevDependencies)) {
      return false;
    }
    let nextContext = nextDependencies.firstContext;
    let prevContext = prevDependencies.firstContext;
    while (nextContext && typeof nextContext === "object" && "memoizedValue" in nextContext || prevContext && typeof prevContext === "object" && "memoizedValue" in prevContext) {
      if (selector(nextContext, prevContext) === true) return true;
      nextContext = nextContext?.next;
      prevContext = prevContext?.next;
    }
  } catch {
  }
  return false;
};
var traverseState = (fiber, selector) => {
  try {
    let nextState = fiber.memoizedState;
    let prevState = fiber.alternate?.memoizedState;
    while (nextState || prevState) {
      if (selector(nextState, prevState) === true) return true;
      nextState = nextState?.next;
      prevState = prevState?.next;
    }
  } catch {
  }
  return false;
};
var traverseProps = (fiber, selector) => {
  try {
    const nextProps = fiber.memoizedProps;
    const prevProps = fiber.alternate?.memoizedProps || {};
    const allKeys = /* @__PURE__ */ new Set([
      ...Object.keys(prevProps),
      ...Object.keys(nextProps)
    ]);
    for (const propName of allKeys) {
      const prevValue = prevProps?.[propName];
      const nextValue = nextProps?.[propName];
      if (selector(propName, nextValue, prevValue) === true) return true;
    }
  } catch {
  }
  return false;
};
var didFiberRender = (fiber) => {
  const nextProps = fiber.memoizedProps;
  const prevProps = fiber.alternate?.memoizedProps || {};
  const flags = fiber.flags ?? fiber.effectTag ?? 0;
  switch (fiber.tag) {
    case ClassComponentTag:
    case FunctionComponentTag:
    case ContextConsumerTag:
    case ForwardRefTag:
    case MemoComponentTag:
    case SimpleMemoComponentTag: {
      return (flags & PerformedWork) === PerformedWork;
    }
    default:
      if (!fiber.alternate) return true;
      return prevProps !== nextProps || fiber.alternate.memoizedState !== fiber.memoizedState || fiber.alternate.ref !== fiber.ref;
  }
};
var shouldFilterFiber = (fiber) => {
  switch (fiber.tag) {
    case DehydratedSuspenseComponentTag:
      return true;
    case HostTextTag:
    case FragmentTag:
    case LegacyHiddenComponentTag:
    case OffscreenComponentTag:
      return true;
    case HostRootTag:
      return false;
    default: {
      const symbolOrNumber = typeof fiber.type === "object" && fiber.type !== null ? fiber.type.$$typeof : fiber.type;
      const typeSymbol = typeof symbolOrNumber === "symbol" ? symbolOrNumber.toString() : symbolOrNumber;
      switch (typeSymbol) {
        case CONCURRENT_MODE_NUMBER:
        case CONCURRENT_MODE_SYMBOL_STRING:
        case DEPRECATED_ASYNC_MODE_SYMBOL_STRING:
          return true;
        default:
          return false;
      }
    }
  }
};
var getType = (type) => {
  const currentType = type;
  if (typeof currentType === "function") {
    return currentType;
  }
  if (typeof currentType === "object" && currentType) {
    return getType(
      currentType.type || currentType.render
    );
  }
  return null;
};
var getDisplayName = (type) => {
  const currentType = type;
  if (typeof currentType === "string") {
    return currentType;
  }
  if (typeof currentType !== "function" && !(typeof currentType === "object" && currentType)) {
    return null;
  }
  const name = currentType.displayName || currentType.name || null;
  if (name) return name;
  const unwrappedType = getType(currentType);
  if (!unwrappedType) return null;
  return unwrappedType.displayName || unwrappedType.name || null;
};
var detectReactBuildType = (renderer) => {
  try {
    if (typeof renderer.version === "string" && renderer.bundleType > 0) {
      return "development";
    }
  } catch {
  }
  return "production";
};
var fiberId = 0;
var fiberIdMap = /* @__PURE__ */ new WeakMap();
var setFiberId = (fiber, id = fiberId++) => {
  fiberIdMap.set(fiber, id);
};
var getFiberId = (fiber) => {
  let id = fiberIdMap.get(fiber);
  if (!id && fiber.alternate) {
    id = fiberIdMap.get(fiber.alternate);
  }
  if (!id) {
    id = fiberId++;
    setFiberId(fiber, id);
  }
  return id;
};
var mountFiberRecursively = (onRender, firstChild, traverseSiblings) => {
  let fiber = firstChild;
  while (fiber != null) {
    if (!fiberIdMap.has(fiber)) {
      getFiberId(fiber);
    }
    const shouldIncludeInTree = !shouldFilterFiber(fiber);
    if (shouldIncludeInTree && didFiberRender(fiber)) {
      onRender(fiber, "mount");
    }
    if (fiber.tag === SuspenseComponentTag) {
      const isTimedOut = fiber.memoizedState !== null;
      if (isTimedOut) {
        const primaryChildFragment = fiber.child;
        const fallbackChildFragment = primaryChildFragment ? primaryChildFragment.sibling : null;
        if (fallbackChildFragment) {
          const fallbackChild = fallbackChildFragment.child;
          if (fallbackChild !== null) {
            mountFiberRecursively(onRender, fallbackChild, false);
          }
        }
      } else {
        let primaryChild = null;
        if (fiber.child !== null) {
          primaryChild = fiber.child.child;
        }
        if (primaryChild !== null) {
          mountFiberRecursively(onRender, primaryChild, false);
        }
      }
    } else if (fiber.child != null) {
      mountFiberRecursively(onRender, fiber.child, true);
    }
    fiber = traverseSiblings ? fiber.sibling : null;
  }
};
var updateFiberRecursively = (onRender, nextFiber, prevFiber, parentFiber) => {
  if (!fiberIdMap.has(nextFiber)) {
    getFiberId(nextFiber);
  }
  if (!prevFiber) return;
  if (!fiberIdMap.has(prevFiber)) {
    getFiberId(prevFiber);
  }
  const isSuspense = nextFiber.tag === SuspenseComponentTag;
  const shouldIncludeInTree = !shouldFilterFiber(nextFiber);
  if (shouldIncludeInTree && didFiberRender(nextFiber)) {
    onRender(nextFiber, "update");
  }
  const prevDidTimeout = isSuspense && prevFiber.memoizedState !== null;
  const nextDidTimeOut = isSuspense && nextFiber.memoizedState !== null;
  if (prevDidTimeout && nextDidTimeOut) {
    const nextFallbackChildSet = nextFiber.child?.sibling ?? null;
    const prevFallbackChildSet = prevFiber.child?.sibling ?? null;
    if (nextFallbackChildSet !== null && prevFallbackChildSet !== null) {
      updateFiberRecursively(
        onRender,
        nextFallbackChildSet,
        prevFallbackChildSet);
    }
  } else if (prevDidTimeout && !nextDidTimeOut) {
    const nextPrimaryChildSet = nextFiber.child;
    if (nextPrimaryChildSet !== null) {
      mountFiberRecursively(onRender, nextPrimaryChildSet, true);
    }
  } else if (!prevDidTimeout && nextDidTimeOut) {
    unmountFiberChildrenRecursively(onRender, prevFiber);
    const nextFallbackChildSet = nextFiber.child?.sibling ?? null;
    if (nextFallbackChildSet !== null) {
      mountFiberRecursively(onRender, nextFallbackChildSet, true);
    }
  } else if (nextFiber.child !== prevFiber.child) {
    let nextChild = nextFiber.child;
    while (nextChild) {
      if (nextChild.alternate) {
        const prevChild = nextChild.alternate;
        updateFiberRecursively(
          onRender,
          nextChild,
          prevChild);
      } else {
        mountFiberRecursively(onRender, nextChild, false);
      }
      nextChild = nextChild.sibling;
    }
  }
};
var unmountFiber = (onRender, fiber) => {
  const isRoot = fiber.tag === HostRootTag;
  if (isRoot || !shouldFilterFiber(fiber)) {
    onRender(fiber, "unmount");
  }
};
var unmountFiberChildrenRecursively = (onRender, fiber) => {
  const isTimedOutSuspense = fiber.tag === SuspenseComponentTag && fiber.memoizedState !== null;
  let child = fiber.child;
  if (isTimedOutSuspense) {
    const primaryChildFragment = fiber.child;
    const fallbackChildFragment = primaryChildFragment?.sibling ?? null;
    child = fallbackChildFragment?.child ?? null;
  }
  while (child !== null) {
    if (child.return !== null) {
      unmountFiber(onRender, child);
      unmountFiberChildrenRecursively(onRender, child);
    }
    child = child.sibling;
  }
};
var commitId = 0;
var rootInstanceMap = /* @__PURE__ */ new WeakMap();
var traverseRenderedFibers = (root, onRender) => {
  const fiber = "current" in root ? root.current : root;
  let rootInstance = rootInstanceMap.get(root);
  if (!rootInstance) {
    rootInstance = { prevFiber: null, id: commitId++ };
    rootInstanceMap.set(root, rootInstance);
  }
  const { prevFiber } = rootInstance;
  if (!fiber) {
    unmountFiber(onRender, fiber);
  } else if (prevFiber !== null) {
    const wasMounted = prevFiber && prevFiber.memoizedState != null && prevFiber.memoizedState.element != null && // A dehydrated root is not considered mounted
    prevFiber.memoizedState.isDehydrated !== true;
    const isMounted = fiber.memoizedState != null && fiber.memoizedState.element != null && // A dehydrated root is not considered mounted
    fiber.memoizedState.isDehydrated !== true;
    if (!wasMounted && isMounted) {
      mountFiberRecursively(onRender, fiber, false);
    } else if (wasMounted && isMounted) {
      updateFiberRecursively(onRender, fiber, fiber.alternate);
    } else if (wasMounted && !isMounted) {
      unmountFiber(onRender, fiber);
    }
  } else {
    mountFiberRecursively(onRender, fiber, true);
  }
  rootInstance.prevFiber = fiber;
};
var instrument = (options) => {
  return getRDTHook(() => {
    const rdtHook = getRDTHook();
    options.onActive?.();
    rdtHook._instrumentationSource = options.name ?? BIPPY_INSTRUMENTATION_STRING;
    const prevOnCommitFiberRoot = rdtHook.onCommitFiberRoot;
    if (options.onCommitFiberRoot) {
      rdtHook.onCommitFiberRoot = (rendererID, root, priority) => {
        if (prevOnCommitFiberRoot)
          prevOnCommitFiberRoot(rendererID, root, priority);
        options.onCommitFiberRoot?.(rendererID, root, priority);
      };
    }
    const prevOnCommitFiberUnmount = rdtHook.onCommitFiberUnmount;
    if (options.onCommitFiberUnmount) {
      rdtHook.onCommitFiberUnmount = (rendererID, root) => {
        if (prevOnCommitFiberUnmount)
          prevOnCommitFiberUnmount(rendererID, root);
        options.onCommitFiberUnmount?.(rendererID, root);
      };
    }
    const prevOnPostCommitFiberRoot = rdtHook.onPostCommitFiberRoot;
    if (options.onPostCommitFiberRoot) {
      rdtHook.onPostCommitFiberRoot = (rendererID, root) => {
        if (prevOnPostCommitFiberRoot)
          prevOnPostCommitFiberRoot(rendererID, root);
        options.onPostCommitFiberRoot?.(rendererID, root);
      };
    }
  });
};
var INSTALL_ERROR = new Error();
var _fiberRoots = /* @__PURE__ */ new Set();
var secure = (options, secureOptions = {}) => {
  const onActive = options.onActive;
  const isRDTHookInstalled = hasRDTHook();
  const isUsingRealReactDevtools = isRealReactDevtools();
  const isUsingReactRefresh = isReactRefresh();
  let timeout;
  let isProduction = secureOptions.isProduction ?? false;
  options.onActive = () => {
    clearTimeout(timeout);
    let isSecure = true;
    try {
      const rdtHook = getRDTHook();
      for (const renderer of rdtHook.renderers.values()) {
        const [majorVersion] = renderer.version.split(".");
        if (Number(majorVersion) < (secureOptions.minReactMajorVersion ?? 17)) {
          isSecure = false;
        }
        const buildType = detectReactBuildType(renderer);
        if (buildType !== "development") {
          isProduction = true;
          if (!secureOptions.dangerouslyRunInProduction) {
            isSecure = false;
          }
        }
      }
    } catch (err) {
      secureOptions.onError?.(err);
    }
    if (!isSecure) {
      options.onCommitFiberRoot = void 0;
      options.onCommitFiberUnmount = void 0;
      options.onPostCommitFiberRoot = void 0;
      options.onActive = void 0;
      return;
    }
    onActive?.();
    try {
      const onCommitFiberRoot2 = options.onCommitFiberRoot;
      if (onCommitFiberRoot2) {
        options.onCommitFiberRoot = (rendererID, root, priority) => {
          if (!_fiberRoots.has(root)) {
            _fiberRoots.add(root);
          }
          try {
            onCommitFiberRoot2(rendererID, root, priority);
          } catch (err) {
            secureOptions.onError?.(err);
          }
        };
      }
      const onCommitFiberUnmount = options.onCommitFiberUnmount;
      if (onCommitFiberUnmount) {
        options.onCommitFiberUnmount = (rendererID, root) => {
          try {
            onCommitFiberUnmount(rendererID, root);
          } catch (err) {
            secureOptions.onError?.(err);
          }
        };
      }
      const onPostCommitFiberRoot = options.onPostCommitFiberRoot;
      if (onPostCommitFiberRoot) {
        options.onPostCommitFiberRoot = (rendererID, root) => {
          try {
            onPostCommitFiberRoot(rendererID, root);
          } catch (err) {
            secureOptions.onError?.(err);
          }
        };
      }
    } catch (err) {
      secureOptions.onError?.(err);
    }
  };
  if (!isRDTHookInstalled && !isUsingRealReactDevtools && !isUsingReactRefresh) {
    timeout = setTimeout(() => {
      if (!isProduction) {
        secureOptions.onError?.(INSTALL_ERROR);
      }
      stop();
    }, secureOptions.installCheckTimeout ?? 100);
  }
  return options;
};

/**
 * @license bippy
 *
 * Copyright (c) Aiden Bai, Million Software, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

// src/index.ts
safelyInstallRDTHook();

instrument(
  secure({
    onCommitFiberRoot(rendererID, root) {
      traverseRenderedFibers(root, (fiber) => {
        if (!isCompositeFiber(fiber)) return;
        const displayName = getDisplayName(fiber);
        if (!displayName) return;
        const changes = [];
        traverseProps(fiber, (propName, next, prev) => {
          if (next !== prev) {
            changes.push({
              name: `prop ${propName}`,
              prev,
              next
            });
          }
        });
        let contextId = 0;
        traverseContexts(fiber, (next, prev) => {
          if (next !== prev) {
            changes.push({
              name: `context ${contextId}`,
              prev,
              next,
              contextId
            });
          }
          contextId++;
        });
        let stateId = 0;
        traverseState(fiber, (value, prevValue) => {
          if (value !== prevValue) {
            changes.push({
              name: `state ${stateId}`,
              prev: prevValue,
              next: value
            });
          }
          stateId++;
        });
      });
    }
  })
);
//# sourceMappingURL=devtool-0RYEUQbh.js.map
