{"version":3,"file":"index.cjs","names":["DEP_BRAND","ProxyCache","emptyPathSet","ALL_PATHS","DEP_BRAND"],"sources":["../src/BlocProvider.tsx","../src/buildTrackedProxy.ts","../src/useBloc.ts","../src/config.ts"],"sourcesContent":["import {\n  createContext,\n  useContext,\n  useMemo,\n  type ReactElement,\n  type ReactNode,\n} from 'react';\nimport type { ExtractArgs, StateContainerConstructor } from '@blac/core';\n\n/**\n * Internal context value: a Map from bloc constructor to the args object\n * provided by the nearest BlocProvider for that bloc class.\n *\n * Stored as a WeakMap-keyed record so nested providers for different blocs\n * compose without clobbering each other.\n */\ntype ProvidedArgsMap = Map<StateContainerConstructor, unknown>;\n\nconst ProvidedArgsContext = createContext<ProvidedArgsMap>(new Map());\n\n/**\n * Props for {@link BlocProvider}.\n */\nexport interface BlocProviderProps<T extends StateContainerConstructor> {\n  /**\n   * The bloc class whose args are being provided to descendants.\n   */\n  bloc: T;\n  /**\n   * Args that descendant `useBloc(bloc)` calls will resolve to when no\n   * own `args` are given.\n   */\n  args: ExtractArgs<T>;\n  children: ReactNode;\n}\n\n/**\n * Provides args to descendant `useBloc` calls for a specific bloc class via\n * React context.\n *\n * Descendants calling `useBloc(Bloc)` without their own `args` resolve to the\n * args supplied here. Own `args` on the `useBloc` call always win.\n *\n * Multiple `BlocProvider` wrappers for different bloc classes compose: each\n * provider merges its entry into the inherited map, so nested providers for\n * different blocs do not interfere.\n *\n * @example\n * ```tsx\n * <BlocProvider bloc={UserBloc} args={{ userId: 'alice' }}>\n *   <UserProfile />\n * </BlocProvider>\n * ```\n *\n * @example Per-mount private instance\n * ```tsx\n * const id = useId();\n * <BlocProvider bloc={CartBloc} args={{ _id: id }}>\n *   <CartWidget />\n * </BlocProvider>\n * ```\n */\nexport function BlocProvider<T extends StateContainerConstructor>({\n  bloc,\n  args,\n  children,\n}: BlocProviderProps<T>): ReactElement {\n  const parentMap = useContext(ProvidedArgsContext);\n\n  // Merge our entry into a new Map so sibling/parent providers for other blocs\n  // are preserved. Memoised on (parentMap, bloc, args) identity.\n  const mergedMap = useMemo(() => {\n    const next = new Map(parentMap);\n    next.set(bloc, args);\n    return next;\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [parentMap, bloc, args]);\n\n  return (\n    <ProvidedArgsContext.Provider value={mergedMap}>\n      {children}\n    </ProvidedArgsContext.Provider>\n  );\n}\n\n/**\n * Returns the args provided by the nearest {@link BlocProvider} for the given\n * bloc class, or `undefined` when called outside a matching provider.\n *\n * Used by `useBloc` to inherit provider args when no own `args` are given.\n */\nexport function useProvidedArgs<T extends StateContainerConstructor>(\n  BlocClass: T,\n): ExtractArgs<T> | undefined {\n  const map = useContext(ProvidedArgsContext);\n  return map.get(BlocClass) as ExtractArgs<T> | undefined;\n}\n","import { DEP_BRAND } from '@blac/core';\n\n/**\n * Build a per-consumer proxy pair for a bloc instance.\n *\n * Returns two proxies:\n * - `proxy` — the stable outer proxy returned to the consumer. Getter\n *   properties are invoked with `thisProxy` as `this` so that `this.state`\n *   reads inside getters are redirected to the current render's tracking\n *   proxy. Non-getter properties fall through to the live instance.\n * - `thisProxy` — the inner `this`-proxy used as the receiver for getter\n *   calls. Intercepts `state` to return `trackedStateRef.current` when a\n *   tracking context is active; otherwise falls through to the live value.\n *   When `onDepHandle` is supplied, a read off `this` whose value carries the\n *   `DEP_BRAND` symbol (i.e. a `depend()` handle) is routed through\n *   `onDepHandle`, which returns a per-consumer wrapper whose `.track()` opts\n *   the consumer into cross-bloc reactivity. Core stays decoupled — detection\n *   is purely by the `DEP_BRAND` symbol.\n *\n * Both allocations happen exactly once per bloc acquisition (inside `useMemo`)\n * so the proxies are stable across renders.\n *\n * @param onDepHandle - Optional callback invoked when a getter reads a branded\n *   dep handle off `this`. Receives the original handle and returns the value\n *   to expose in its place (the session-bound wrapper). The callback is\n *   responsible for caching wrappers per handle to avoid re-allocation.\n */\nexport function buildTrackedProxy<T extends object>(\n  instance: T,\n  trackedStateRef: { current: unknown },\n  onDepHandle?: (handle: object) => unknown,\n): { proxy: T; thisProxy: T } {\n  // Build a map of getter descriptors from the prototype chain (excluding\n  // Object.prototype). This is computed once per bloc acquisition so that\n  // the proxy's get trap is O(1) per property access. Both string- and\n  // symbol-keyed getters are collected. Arrow-function class properties\n  // (own, bound in the constructor) are not getters and pass through\n  // unmodified.\n  const getterDescs = new Map<string | symbol, PropertyDescriptor>();\n  let proto = Object.getPrototypeOf(instance);\n  while (proto && proto !== Object.prototype) {\n    const keys: (string | symbol)[] = [\n      ...Object.getOwnPropertyNames(proto),\n      ...Object.getOwnPropertySymbols(proto),\n    ];\n    for (const key of keys) {\n      const desc = Object.getOwnPropertyDescriptor(proto, key);\n      if (desc?.get && !getterDescs.has(key)) getterDescs.set(key, desc);\n    }\n    proto = Object.getPrototypeOf(proto);\n  }\n\n  // `this`-proxy for getter invocations, allocated ONCE per acquisition (the\n  // trap closes over the stable `trackedStateRef`, so it never needs to be\n  // rebuilt per access). Redirects `this.state` to the current render's\n  // tracking proxy so getter reads during JSX record paths; outside render\n  // `trackedStateRef.current` is null and it falls through to live state.\n  // The receiver `r` (this proxy) is threaded through Reflect.get so chained\n  // getter calls (getters reading other getters) stay in tracked context.\n  const thisProxy = new Proxy(instance as object, {\n    get(t, k, r) {\n      if (k === 'state') return trackedStateRef.current ?? Reflect.get(t, k, r);\n      const value = Reflect.get(t, k, r);\n      // A branded dep handle read off `this` (e.g. `this.price`) is routed\n      // through onDepHandle so the consumer's session can wrap `.track()`.\n      if (\n        onDepHandle !== undefined &&\n        (typeof value === 'function' || typeof value === 'object') &&\n        value !== null &&\n        (value as Record<symbol, unknown>)[DEP_BRAND] !== undefined\n      ) {\n        return onDepHandle(value as object);\n      }\n      return value;\n    },\n  });\n\n  // Stable proxy: one allocation per bloc acquisition. Non-getter access is\n  // a single Map lookup + Reflect.get — no prototype walk on the hot path.\n  const proxy = new Proxy(instance as object, {\n    get(target, key, receiver) {\n      const desc = getterDescs.get(key);\n      if (desc?.get) return desc.get.call(thisProxy);\n      return Reflect.get(target, key, receiver);\n    },\n  }) as T;\n\n  return { proxy, thisProxy: thisProxy as T };\n}\n","import {\n  useEffect,\n  useLayoutEffect,\n  useMemo,\n  useReducer,\n  useRef,\n  type RefObject,\n} from 'react';\nimport {\n  DEP_BRAND,\n  getRegistry,\n  isIsolatedClass,\n  resolveInstanceKey,\n  type ExtractArgs,\n  type ExtractState,\n  type InstanceState,\n  type StateContainer,\n  type StateContainerConstructor,\n} from '@blac/core';\nimport {\n  ALL_PATHS,\n  emptyPathSet,\n  pathSetEquals,\n  trackRender,\n  PathInterner,\n  ProxyCache,\n  type PathSet,\n} from '@dirtytalk/structural';\nimport { useProvidedArgs } from './BlocProvider';\nimport { buildTrackedProxy } from './buildTrackedProxy';\nimport type { ComponentRef, UseBlocOptions, UseBlocReturn } from './types';\n\nlet nextConsumerId = 0;\n\n// Sentinel that can never `Object.is`-equal a real args value (including\n// `undefined`). Used to lazily seed args-key refs so the structural key is\n// computed only when the guard actually runs, never on every render.\nconst ARGS_UNSET: unique symbol = Symbol('blac.argsKeyUnset');\n\n/**\n * `useRef` with a lazily-built initial value. `useRef(new Map())` discards its\n * argument after the first render but still EVALUATES it on every render, so\n * each such ref costs one dead allocation per render. Passing a module-level\n * factory instead makes the per-render cost a single identity read.\n *\n * The factory MUST be a stable module-level function (an inline arrow would\n * just move the per-render allocation from the value to the closure). The\n * returned `current` is non-nullable, so read sites keep their original types.\n */\nfunction useLazyRef<T>(create: () => T): { current: T } {\n  const ref = useRef<T | null>(null);\n  if (ref.current === null) {\n    ref.current = create();\n  }\n  return ref as { current: T };\n}\n\n// Stable factories for the lazy refs below — one per shape, module-level so the\n// reference passed to `useLazyRef` never changes. Each hook instance still gets\n// its OWN object: nothing here is shared between components (a shared session\n// map or ProxyCache would break per-consumer render isolation).\nconst newComponentRef = (): ComponentRef => ({});\nconst newArgsKeyEntry = (): { ref: unknown; key: string | undefined } => ({\n  ref: ARGS_UNSET,\n  key: undefined,\n});\nconst newSessionMap = (): Map<StateContainer, SessionEntry> => new Map();\nconst newDepSubsMap = (): Map<StateContainer, DepSub> => new Map();\nconst newDepWrapperCache = (): WeakMap<object, unknown> => new WeakMap();\nconst newProxyCache = (): ProxyCache => new ProxyCache();\n\n// Registry refId formats for a consumer's primary bloc and its tracked deps.\n// Centralised so the `acquire` and `release` sites can never drift apart — a\n// mismatch would leak the ref and keep the bloc alive past unmount.\nconst primaryRefId = (consumerId: string): string => `useBloc@${consumerId}`;\nconst depRefId = (consumerId: string): string => `useBloc@${consumerId}:dep`;\n\n/**\n * React hook that connects a component to a state container with automatic\n * re-render on state changes.\n *\n * Two tracking modes:\n * - **Auto-tracking** (default): the returned state value is a proxy that\n *   records read paths during render. The component re-renders when any\n *   recorded path changes. Backed by `@dirtytalk/structural`'s\n *   {@link trackRender} + the container's path-scoped `DirtyChannel`.\n * - **Manual select**: pass `options.select` to opt out of auto-tracking.\n *   The hook re-renders only when the returned array's elements change\n *   (per-index `Object.is`).\n *\n * Lifecycle:\n * - The bloc is acquired from the registry on mount and released on\n *   unmount. The instance key is derived from `options.args` (own args),\n *   then the surrounding {@link BlocProvider} context args for this bloc,\n *   then the default key (no args).\n * - `options.onMount` fires after the bloc is acquired; `options.onUnmount`\n *   fires *before* the registry releases its ref, so the bloc is still\n *   alive when the callback runs.\n *\n * Per-mount private instance:\n * ```ts\n * const id = useId();\n * const [state, bloc] = useBloc(MyBloc, { args: { _id: id } });\n * ```\n *\n * @template T - The state container constructor type (inferred from BlocClass)\n * @param BlocClass - The state container class to connect to\n * @param options - Configuration options\n * @returns Tuple of `[state, bloc, ref]`\n *\n * @example Basic usage\n * ```ts\n * const [state, bloc] = useBloc(MyBloc);\n * ```\n *\n * @example Manual select\n * ```ts\n * const [state, bloc] = useBloc(MyBloc, {\n *   select: (state) => [state.count],\n * });\n * ```\n *\n * @example Args-based shared instance\n * ```ts\n * const [state, bloc] = useBloc(UserBloc, { args: { userId: 'alice' } });\n * ```\n */\nexport function useBloc<\n  T extends StateContainerConstructor = StateContainerConstructor,\n>(\n  BlocClass: T,\n  options?: UseBlocOptions<T>,\n): UseBlocReturn<T, ExtractState<T>> {\n  type TBloc = InstanceState<T>;\n\n  const componentRef = useLazyRef(newComponentRef);\n\n  // Stable per-consumer id (for the structural container's consumer registry).\n  // Plain counter rather than `useId()` so we don't compete with internal hooks\n  // for SSR id slots.\n  const consumerIdRef = useRef<string | null>(null);\n  if (consumerIdRef.current === null) {\n    consumerIdRef.current = `useBloc-${nextConsumerId++}`;\n  }\n  const consumerId = consumerIdRef.current;\n\n  // `isolated` is sugar over args identity: it injects a per-mount id into the\n  // args used for keying. `consumerId` is already stable for this mount, so this\n  // costs no extra hook slot (a `useId()` here would cost one in EVERY consumer).\n  const isolated = options?.isolated === true || isIsolatedClass(BlocClass);\n  // Memo dep: flips when isolation is toggled at runtime (`{ isolated: cond }`)\n  // so the instance re-keys. Constant for the common case.\n  const isolationKey = isolated ? consumerId : undefined;\n\n  // Refs that always carry the latest option callbacks, so the commit effect\n  // can read them without re-keying.\n  const selectRef = useRef(options?.select);\n  selectRef.current = options?.select;\n  const isSelectMode = options?.select !== undefined;\n  const onMountRef = useRef(options?.onMount);\n  onMountRef.current = options?.onMount;\n  const onUnmountRef = useRef(options?.onUnmount);\n  onUnmountRef.current = options?.onUnmount;\n  const isolatedRef = useRef(isolated);\n  isolatedRef.current = isolated;\n\n  // ---------------------------------------------------------------------------\n  // Identity resolution\n  //\n  // Priority: own args > provider args (for this bloc class) > none.\n  //\n  // Args are user-supplied; callers commonly pass a fresh object literal each\n  // render. Memoising on `args` directly would bust every render. We compute a\n  // structural key (JSON.stringify) for the useMemo dep instead — undefined\n  // args (void-args blocs) collapse to an undefined key.\n  // ---------------------------------------------------------------------------\n  const ownArgs = (options as { args?: ExtractArgs<T> } | undefined)?.args;\n  const ownArgsRef = useRef(ownArgs);\n  ownArgsRef.current = ownArgs;\n  // Fast-path: only recompute the structural key when the args REFERENCE\n  // changes. Callers commonly pass a stable args object (e.g. memoised or\n  // module-level), so this skips a JSON.stringify call every render.\n  const ownArgsKeyRef = useLazyRef(newArgsKeyEntry);\n  if (!Object.is(ownArgsKeyRef.current.ref, ownArgs)) {\n    ownArgsKeyRef.current = {\n      ref: ownArgs,\n      key: ownArgs === undefined ? undefined : JSON.stringify(ownArgs),\n    };\n  }\n  const ownArgsKey = ownArgsKeyRef.current.key;\n\n  // Read provided args from the nearest BlocProvider for this bloc class.\n  const providerArgs = useProvidedArgs(BlocClass);\n  const providerArgsRef = useRef(providerArgs);\n  providerArgsRef.current = providerArgs;\n  // Same reference fast-path as ownArgsKey above.\n  const providerArgsKeyRef = useLazyRef(newArgsKeyEntry);\n  if (!Object.is(providerArgsKeyRef.current.ref, providerArgs)) {\n    providerArgsKeyRef.current = {\n      ref: providerArgs,\n      key:\n        providerArgs === undefined ? undefined : JSON.stringify(providerArgs),\n    };\n  }\n  const providerArgsKey = providerArgsKeyRef.current.key;\n\n  // Current render's tracking proxy. Declared before the memo so the stable\n  // ref object can be passed to buildTrackedProxy at acquisition time. The\n  // proxy trap only reads `.current` at invocation time (not during creation),\n  // so it is safe to pass on first mount even though the value is null.\n  // Populated during each auto-track render snapshot (below); cleared to null\n  // by useLayoutEffect after commit.\n  const trackedStateRef = useRef<unknown>(null);\n\n  // ---------------------------------------------------------------------------\n  // Per-consumer cross-bloc session.\n  //\n  // Each render rebuilds a map of every container this consumer is currently\n  // interested in. The PRIMARY bloc is the first uniform entry; every dep\n  // reached through `this.<handle>.track()` inside a tracked getter adds an\n  // entry. The layout-effect reconcile (below) diffs this map vs the previous\n  // render to subscribe new deps and release dropped ones. The session lives in\n  // this hook's refs only — there is no global ambient state, so sibling\n  // renders never cross-contaminate.\n  // ---------------------------------------------------------------------------\n  const sessionRef = useLazyRef(newSessionMap);\n  // Channel subscriptions for DEP containers (the primary keeps its own\n  // dedicated effect). container -> { unsubscribe, interestRef, refId held }.\n  const depSubsRef = useLazyRef(newDepSubsMap);\n  // Per-handle wrapper cache, allocated once per bloc acquisition (in the memo)\n  // so wrappers are stable across renders. handle -> session-bound wrapper.\n  const depWrapperCacheRef = useLazyRef(newDepWrapperCache);\n  const proxyCacheRef = useLazyRef(newProxyCache);\n  // Snapshot of the last FULL reconcile's shape, used by the layout-effect\n  // below to short-circuit when nothing actually changed. `null` means \"no\n  // prior full run to compare against\" (first commit, or the previous commit\n  // was in select-mode) — always forces a full reconcile in that case.\n  const lastReconcileRef = useRef<ReconcileSignature | null>(null);\n\n  // Rebind nonce: bumped by the ownership layout-effect when the instance the\n  // render captured was disposed + recreated out from under us. This happens on\n  // a same-commit ownership handoff of a shared (non-keepAlive) key — the sole\n  // prior owner's effect cleanup releases refs→0 and SYNCHRONOUSLY disposes the\n  // instance before this consumer's layout setup re-acquires (creating a fresh\n  // one) — and equivalently under StrictMode's setup→cleanup→setup double-invoke\n  // for a lone owner. Threaded into the memo deps so bumping it re-ensures `bloc`\n  // against the LIVE registry entry instead of the disposed instance.\n  const [rebindNonce, bumpRebind] = useReducer((x: number) => x + 1, 0);\n  // The live instance actually owned (ref held) by the ownership layout-effect,\n  // read by its cleanup so onUnmount always fires with the owned instance.\n  const ownedBlocRef = useRef<TBloc | null>(null);\n\n  const { bloc, instanceKey, trackedBloc } = useMemo<{\n    bloc: TBloc;\n    instanceKey: string;\n    trackedBloc: TBloc;\n  }>(() => {\n    // Own args win over provider args; provider args win over no args.\n    const baseArgs =\n      ownArgsRef.current !== undefined\n        ? ownArgsRef.current\n        : providerArgsRef.current;\n    // Isolation MERGES with resolved args rather than losing to them (plan Q2=B):\n    // a class-level `static isolated` must not be silently cancelled by a call\n    // site that happens to pass args.\n    // The cast is the point of the documented behavior note: the injected\n    // `_blacIsolated` key is NOT part of the bloc's declared `Args` type, but it\n    // does reach `init(args)` — exactly as the `{ args: { _id: useId() } }`\n    // idiom this replaces always did.\n    const effectiveArgs = isolatedRef.current\n      ? (withIsolation(baseArgs, consumerId) as ExtractArgs<T>)\n      : baseArgs;\n\n    const resolvedKey = resolveInstanceKey(BlocClass, effectiveArgs);\n    const registry = getRegistry();\n    // Render only ENSUREs the instance exists (no ref). Ownership is claimed in\n    // the layout effect below, so an abandoned/uncommitted render can never\n    // leak a ref and a memo re-run can never double-count one (R3/R4).\n    const instance = registry.acquire(BlocClass, resolvedKey, {\n      canCreate: true,\n      countRef: false,\n      args: effectiveArgs,\n    }) as TBloc;\n\n    // Build a session-bound wrapper for a dep handle the first time a getter\n    // reads it off `this`; cache per handle so the wrapper identity is stable.\n    // `onDepHandle` is threaded into each dep's tracked proxy too, so a nested\n    // `this.<otherHandle>.track()` inside a dep's getter records into the SAME\n    // consumer session — that is what makes deep chains (A→B→C) reactive.\n    const onDepHandle = (handle: object): unknown => {\n      const cache = depWrapperCacheRef.current;\n      const cached = cache.get(handle);\n      if (cached !== undefined) return cached;\n      const wrapper = makeDepWrapper(\n        handle as DepHandleLike,\n        consumerId,\n        trackedStateRef,\n        sessionRef,\n        onDepHandle,\n      );\n      cache.set(handle, wrapper);\n      return wrapper;\n    };\n\n    const { proxy } = buildTrackedProxy(\n      instance as object,\n      trackedStateRef,\n      onDepHandle,\n    );\n\n    return {\n      bloc: instance,\n      instanceKey: resolvedKey,\n      trackedBloc: proxy as TBloc,\n    };\n    // oxlint-disable-next-line react-hooks/exhaustive-deps\n  }, [BlocClass, ownArgsKey, providerArgsKey, isolationKey, rebindNonce]);\n\n  // ---------------------------------------------------------------------------\n  // Channel subscription\n  //\n  // We talk directly to `bloc.channel` — the StructuralContainer's path-scoped\n  // DirtyChannel. Subscribing with a dynamic interest function lets us narrow\n  // wakeups per consumer, so a component only re-renders when a path it\n  // actually read changes (rather than on every state change).\n  // ---------------------------------------------------------------------------\n  const [, force] = useReducer((x: number) => x + 1, 0);\n  const pathRef = useLazyRef(emptyPathSet);\n  // Expanded interest: leaf paths PLUS *ancestor-watch* ids for their parents,\n  // so that when `patch` atomically replaces a parent (e.g. the array 'items')\n  // and the consumer tracked a child (e.g. 'items.length'), the intersection\n  // still fires — while a structural pulse-up of a plain-object parent (e.g.\n  // 'user' when a sibling 'user.name' changed) does NOT, because pulse-up marks\n  // are normal ids and ancestor-watch ids only intersect their own lane.\n  // Updated in useLayoutEffect after each render once pathRef.current is\n  // populated.\n  const expandedInterestRef = useLazyRef(emptyPathSet);\n  // For select-mode: cache the last selected array so we can compare against\n  // the next one before forcing a re-render.\n  const lastSelectionRef = useRef<unknown[] | null>(null);\n  // Render-time raw-state snapshot, seeded each render (below) and read by the\n  // subscription effect to close the mount gap (R2): an emit landing between the\n  // render read and the passive subscribe would otherwise be lost.\n  const renderStateRef = useRef<unknown>(undefined);\n  // Bloc identity from the previous render, so select-mode can reset its cached\n  // selection when the underlying instance changes (re-key).\n  const prevBlocRef = useRef<unknown>(null);\n\n  useEffect(() => {\n    // Subscribe via the channel directly. For auto-track we re-register the\n    // current path interest on each commit (below); for select-mode we use\n    // ALL_PATHS and compare selections in the callback.\n    //\n    // Self-healing note: this effect can run once against a pre-rebind (possibly\n    // disposed) `bloc` before the ownership layout-effect's nonce bump triggers a\n    // re-render that swaps `bloc` to the live instance (the memo dep array\n    // includes `rebindNonce`). That's benign — `channel.subscribe` and\n    // `unregisterConsumer` are plain Map operations that don't check disposal\n    // state and never throw on a disposed container — so this effect's cleanup\n    // runs cleanly and the re-render re-subscribes against the live instance.\n    const channel = (bloc as unknown as StateContainer).channel;\n\n    if (isSelectMode) {\n      const unsub = channel.subscribe(\n        () => ALL_PATHS,\n        () => {\n          const select = selectRef.current;\n          if (!select) {\n            force();\n            return;\n          }\n          const next = select(\n            (bloc as unknown as StateContainer).state as ExtractState<T>,\n            bloc as InstanceState<T>,\n          );\n          const prev = lastSelectionRef.current;\n          if (prev !== null && shallowArrayEqual(prev, next)) return;\n          lastSelectionRef.current = next;\n          force();\n        },\n      );\n      // Close the mount gap (R2): an emit between the render's selector seed and\n      // this subscribe would be lost. Recompute against LIVE state and force if\n      // the selection advanced.\n      const select = selectRef.current;\n      if (select) {\n        const next = select(\n          (bloc as unknown as StateContainer).state as ExtractState<T>,\n          bloc as InstanceState<T>,\n        );\n        const prev = lastSelectionRef.current;\n        if (prev === null || !shallowArrayEqual(prev, next)) {\n          lastSelectionRef.current = next;\n          force();\n        }\n      }\n      return unsub;\n    }\n\n    // Auto-track mode: subscribe with the expanded interest (leaf paths + their\n    // ancestors). This ensures that when `patch` marks a parent path (e.g.\n    // 'items') and the consumer tracked a child (e.g. 'items.length'), the\n    // channel intersection still fires a re-render.\n    //\n    // `expandedInterestRef.current` is updated by the useLayoutEffect below\n    // after each render, so the interest is always fresh at flush time.\n    const unsub = channel.subscribe(\n      () => expandedInterestRef.current,\n      () => force(),\n    );\n    // Register the consumer's leaf paths with the container for skeleton\n    // recomputation, so the source-side diff can skip us when our paths don't\n    // intersect the change.\n    (bloc as unknown as StateContainer).registerConsumerPaths(\n      consumerId,\n      pathRef.current,\n    );\n    // Close the mount gap (R2): if the container's state advanced between the\n    // render snapshot (renderStateRef) and this subscribe, the emit was lost —\n    // force one re-render so we don't stay stale.\n    if ((bloc as unknown as StateContainer).state !== renderStateRef.current) {\n      force();\n    }\n    return () => {\n      unsub();\n      (bloc as unknown as StateContainer).unregisterConsumer(consumerId);\n    };\n    // oxlint-disable-next-line react-hooks/exhaustive-deps\n  }, [bloc, consumerId, isSelectMode]);\n\n  // ---------------------------------------------------------------------------\n  // Ownership + mount / unmount lifecycle.\n  //\n  // The ownership ref is claimed HERE (a layout effect), not in the render/memo,\n  // so acquire and release are perfectly paired: a memo re-run can no longer\n  // double-count (R3) and an uncommitted render can no longer leak (R4). Keyed\n  // on [BlocClass, instanceKey, consumerId] — NOT `bloc` — so a genuine re-key\n  // (args change, OR a BlocClass swap) releases the old ref and acquires the new\n  // one, while a pure rebind (same class+key, instance replaced under us) does\n  // NOT re-run this effect and therefore never releases the single ref we just\n  // took (which, for a sole owner, would synchronously dispose the\n  // freshly-created instance and churn indefinitely).\n  //\n  // `BlocClass` MUST stay in the dep array even though `instanceKey` alone often\n  // determines identity: `resolveInstanceKey`/`resolveKey` collapse to the same\n  // `DEFAULT_STRUCTURAL_KEY` sentinel across DIFFERENT classes when neither has\n  // args nor a `static key` (e.g. `useBloc(cond ? AdminBloc : UserBloc)`). Without\n  // `BlocClass` here, swapping classes at that shared key would never re-run this\n  // effect: the old class's ref would leak until unmount, and the new class's\n  // instance (only `ensure`d by the render memo, countRef:false) would be held\n  // with zero ownership refs — exposed to disposal by unrelated traffic on that\n  // class+key, with no rebind path to recover it.\n  //\n  // `acquire` returns the authoritative LIVE instance for the key. If it differs\n  // from the instance the render captured (`bloc`), the render read a disposed /\n  // replaced instance (same-commit shared-key handoff, or StrictMode remount);\n  // we bump the rebind nonce so the memo re-ensures `bloc` against this live one.\n  // onMount/onUnmount fire with the owned live instance and stay co-located with\n  // acquire/release so onUnmount(bloc) runs BEFORE release(...) within one\n  // cleanup, keeping the instance alive while the callback runs.\n  // ---------------------------------------------------------------------------\n  useLayoutEffect(() => {\n    const registry = getRegistry();\n    const live = registry.acquire(BlocClass, instanceKey, {\n      canCreate: true,\n      countRef: true,\n      refId: primaryRefId(consumerId),\n    }) as TBloc;\n    ownedBlocRef.current = live;\n    onMountRef.current?.(live as InstanceType<T>);\n    // Rebind if the render captured a stale (disposed/replaced) instance so the\n    // component renders + subscribes against the live registry entry, not a\n    // disposed one. Only bumps on an actual mismatch, so it can fire at most once\n    // per handoff and never loops (the re-ensured `bloc` equals `live`, and this\n    // effect is not keyed on `bloc` so it won't re-run and re-release).\n    if (live !== bloc) {\n      bumpRebind();\n    }\n    return () => {\n      onUnmountRef.current?.((ownedBlocRef.current ?? bloc) as InstanceType<T>);\n      registry.release(BlocClass, instanceKey, false, primaryRefId(consumerId));\n    };\n    // oxlint-disable-next-line react-hooks/exhaustive-deps\n  }, [BlocClass, instanceKey, consumerId]);\n\n  // ---------------------------------------------------------------------------\n  // Snapshot\n  //\n  // - Auto-track: wrap state in trackRender, record paths into pathRef, and\n  //   re-register with the container so the skeleton picks up new interest.\n  // - Select-mode: return state directly; the subscription callback compares\n  //   selections to decide whether to re-render.\n  // ---------------------------------------------------------------------------\n  const rawState = (bloc as unknown as StateContainer).state as ExtractState<T>;\n  // Seed the render-time snapshot so the subscription effect can detect an emit\n  // that landed in the render→subscribe window (R2 mount gap).\n  renderStateRef.current = rawState;\n  // Reset the cached selection when the bloc identity changes (re-key) so the\n  // select seed below re-seeds against the NEW instance instead of comparing\n  // against a stale selection from the previous instance.\n  if (prevBlocRef.current !== bloc) {\n    prevBlocRef.current = bloc;\n    lastSelectionRef.current = null;\n  }\n  let state: ExtractState<T>;\n  if (selectRef.current !== undefined) {\n    state = rawState;\n    // Seed the last selection on the first render so we don't fire an\n    // immediate \"different from null\" wakeup on the first emit.\n    if (lastSelectionRef.current === null) {\n      lastSelectionRef.current = selectRef.current(\n        rawState,\n        bloc as InstanceState<T>,\n      );\n    }\n  } else {\n    const tracked = trackRender(\n      rawState,\n      (bloc as unknown as StateContainer).interner,\n      proxyCacheRef.current,\n    );\n    state = tracked.value as ExtractState<T>;\n    trackedStateRef.current = tracked.value;\n    pathRef.current = tracked.paths;\n    // Rebuild the per-consumer session for this render. The primary bloc is the\n    // first uniform entry; its `paths` are the SAME PathSet object the proxy\n    // mutates during JSX (so it stays live as getters record leaves). Dep\n    // entries are appended during JSX as `this.<handle>.track()` runs. Cleared\n    // here (not in the layout effect) so a render that no longer tracks a dep\n    // produces a session without it, and the reconcile drops it.\n    const session = sessionRef.current;\n    session.clear();\n    session.set(bloc as unknown as StateContainer, {\n      kind: 'primary',\n      paths: tracked.paths,\n    });\n    // Freeze this render's tracking proxy after the synchronous render+commit\n    // pass. The microtask fires only once the current task unwinds, so all\n    // render-time JSX reads still record; reads afterwards — effects, event\n    // handlers, async callbacks, devtools inspecting `state` — hit the\n    // disarmed proxy and record nothing, so this render's path set can't be\n    // polluted by work that outlives the render that owns it.\n    queueMicrotask(tracked.disarm);\n    // NOTE: registerConsumerPaths is intentionally NOT called here. The\n    // proxy hasn't been accessed yet, so `tracked.paths` is an empty Set\n    // that the proxy will mutate during JSX evaluation. Registering at\n    // this point would store an empty interest with the container and\n    // freeze the skeleton at that snapshot — subsequent emits would\n    // diff against an empty skeleton and silently drop wakeups. The\n    // useLayoutEffect below registers the populated set after render.\n  }\n\n  // After the render commits, pathRef.current is the consumer's actual leaf\n  // interest (populated by the proxy during JSX evaluation). Re-register with\n  // the container so the skeleton reflects the latest paths, and expand the\n  // interest to include ancestor paths for the channel subscription.\n  //\n  // useLayoutEffect runs before the browser paints (and before any emit\n  // triggered by another effect), so the skeleton is fresh by the time the\n  // next emit fires.\n  // oxlint-disable-next-line react-hooks/exhaustive-deps\n  useLayoutEffect(() => {\n    // Clear the render-time tracking proxy now that JSX has been evaluated and\n    // committed. Getters invoked after this point (event handlers, effects,\n    // method→getter chains) fall through to live state instead of reading this\n    // render's frozen snapshot. The render body re-seeds it next render.\n    trackedStateRef.current = null;\n    if (selectRef.current !== undefined) {\n      // Switching into (or staying in) select-mode: invalidate any prior full\n      // reconcile so a later switch back to auto-track mode never mistakes a\n      // stale signature for \"unchanged\" and skips a needed reconcile.\n      lastReconcileRef.current = null;\n      return;\n    }\n    const container = bloc as unknown as StateContainer;\n    const paths = pathRef.current;\n    const session = sessionRef.current;\n\n    // ---------------------------------------------------------------------\n    // Short-circuit: if the primary path set AND the full dep session are\n    // set-equal (paths + key/refId/args) to the last FULL reconcile, none of\n    // registerConsumerPaths/subscribe/unsubscribe/expandWithAncestors below\n    // can have anything new to do — skip the whole block. Any mismatch, or\n    // `lastReconcileRef.current === null` (first commit, or the immediately\n    // preceding commit was select-mode / uncertain), falls through to the\n    // full reconcile. Never skip on uncertainty — a missed re-subscribe would\n    // leave a stale/dropped subscription.\n    // ---------------------------------------------------------------------\n    const last = lastReconcileRef.current;\n    if (\n      last !== null &&\n      last.primaryContainer === container &&\n      pathSetEquals(last.primaryPaths, paths)\n    ) {\n      let unchanged = last.deps.size === session.size - 1;\n      if (unchanged) {\n        for (const [depContainer, entry] of session) {\n          if (entry.kind === 'primary') continue;\n          const prevEntry = last.deps.get(depContainer);\n          if (\n            prevEntry === undefined ||\n            prevEntry.key !== entry.key ||\n            prevEntry.refId !== entry.refId ||\n            !Object.is(prevEntry.args, entry.args) ||\n            !pathSetEquals(prevEntry.paths, entry.paths)\n          ) {\n            unchanged = false;\n            break;\n          }\n        }\n      }\n      if (unchanged) return;\n    }\n\n    container.registerConsumerPaths(consumerId, paths);\n    // Register the *normal* leaf paths above for the source-side skeleton, then\n    // build the channel interest as leaves + ancestor-watch ids so that an\n    // atomic `patch` replacement of a parent (e.g. the array 'items') wakes a\n    // consumer that tracked a child (e.g. 'items.length').\n    expandedInterestRef.current = expandWithAncestors(\n      paths,\n      container.interner,\n    );\n\n    // -----------------------------------------------------------------------\n    // Reconcile DEP containers (cross-bloc `.track()` interest).\n    //\n    // The primary bloc keeps its own dedicated subscription effect above; this\n    // block manages only the *dep* containers recorded in the session this\n    // render. We diff the new dep set vs the previously-subscribed set:\n    //   - new dep      -> acquire was already done in `.track()`; subscribe its\n    //                     channel + registerConsumerPaths + seed interest.\n    //   - surviving    -> refresh its interest ref (subscribe closure reads it).\n    //   - dropped      -> unsubscribe, unregisterConsumer, and release its ref.\n    // -----------------------------------------------------------------------\n    const subs = depSubsRef.current;\n\n    // Pass 1: drop containers no longer in the session.\n    for (const [depContainer, sub] of subs) {\n      if (!session.has(depContainer)) {\n        sub.unsubscribe();\n        depContainer.unregisterConsumer(consumerId);\n        getRegistry().release(sub.Type, sub.key, false, sub.refId);\n        subs.delete(depContainer);\n      }\n    }\n\n    // Pass 2: add/refresh containers in the session (skip the primary).\n    for (const [depContainer, entry] of session) {\n      if (entry.kind === 'primary') continue;\n      const interest = expandWithAncestors(entry.paths, depContainer.interner);\n      depContainer.registerConsumerPaths(consumerId, entry.paths);\n      const existing = subs.get(depContainer);\n      if (existing) {\n        existing.interestRef.current = interest;\n        continue;\n      }\n      // First commit that sees this dep: take the ownership ref HERE (not in\n      // render/`.track()`), so an uncommitted render can never leak it (R4).\n      getRegistry().acquire(entry.Type, entry.key, {\n        canCreate: true,\n        countRef: true,\n        refId: entry.refId,\n        args: entry.args,\n      });\n      const interestRef: { current: PathSet } = { current: interest };\n      const unsubscribe = depContainer.channel.subscribe(\n        () => interestRef.current,\n        () => force(),\n      );\n      subs.set(depContainer, {\n        unsubscribe,\n        interestRef,\n        Type: entry.Type,\n        key: entry.key,\n        refId: entry.refId,\n        args: entry.args,\n      });\n    }\n\n    // Capture this full reconcile's shape for the NEXT commit's short-circuit\n    // check above. `paths`/`entry.paths` are fresh Sets seeded this render\n    // (trackRender/unionPaths always allocate new Sets, never mutate one from\n    // a prior render) — safe to keep direct references without cloning.\n    const depsSignature = new Map<StateContainer, ReconcileDepSignature>();\n    for (const [depContainer, entry] of session) {\n      if (entry.kind === 'primary') continue;\n      depsSignature.set(depContainer, {\n        paths: entry.paths,\n        key: entry.key,\n        refId: entry.refId,\n        args: entry.args,\n      });\n    }\n    lastReconcileRef.current = {\n      primaryContainer: container,\n      primaryPaths: paths,\n      deps: depsSignature,\n    };\n  });\n\n  // Unmount: tear down every dep subscription + ref exactly once. Kept in its\n  // own effect (consumerId is stable for the component's lifetime, so this only\n  // runs on final unmount, not on every reconcile). depSubsRef is mutated in\n  // place by the reconcile, so the captured Map reference still holds the live\n  // set at unmount.\n  useEffect(() => {\n    // Capture the ref's Map (mutated in place across renders) so the cleanup\n    // reads the captured reference rather than depSubsRef.current directly.\n    const subs = depSubsRef.current;\n    return () => {\n      for (const [depContainer, sub] of subs) {\n        sub.unsubscribe();\n        depContainer.unregisterConsumer(consumerId);\n        getRegistry().release(sub.Type, sub.key, false, sub.refId);\n      }\n      subs.clear();\n    };\n    // `depSubsRef` is a stable ref object (its identity never changes), so\n    // listing it keeps this effect an unmount-only effect while satisfying\n    // exhaustive-deps — the lint rule can't tell `useLazyRef` returns a ref.\n  }, [consumerId, depSubsRef]);\n\n  return [\n    state,\n    trackedBloc,\n    componentRef as RefObject<ComponentRef>,\n  ] as UseBlocReturn<T, ExtractState<T>>;\n}\n\n// ---------------------------------------------------------------------------\n// Cross-bloc session types + dep-handle wrapper.\n// ---------------------------------------------------------------------------\n\n/**\n * One entry in a consumer's per-render session map. Discriminated on `kind`:\n * the primary bloc is managed by its own dedicated effect, while dep entries\n * carry the registry coordinates the reconcile needs to release their ref.\n */\ntype SessionEntry =\n  | {\n      kind: 'primary';\n      /** Tracked leaf paths recorded against the primary this render. */\n      paths: PathSet;\n    }\n  | {\n      kind: 'dep';\n      /** Tracked leaf paths recorded against this dep this render. */\n      paths: PathSet;\n      /** Constructor for registry release. */\n      Type: StateContainerConstructor;\n      /** Resolved instance key for registry release. */\n      key: string;\n      /** refId held for this dep (released on drop/unmount). */\n      refId: string;\n      /** Construction args, used by the reconcile pass to acquire the ref. */\n      args: unknown;\n    };\n\n/** A live dep-channel subscription tracked between renders for reconciliation. */\ninterface DepSub {\n  unsubscribe: () => void;\n  interestRef: { current: PathSet };\n  Type: StateContainerConstructor;\n  key: string;\n  refId: string;\n  args: unknown;\n}\n\n/**\n * Snapshot of one dep's shape from the last FULL reconcile, compared against\n * the current session entry to decide whether the dep-reconcile layout effect\n * can short-circuit (see `lastReconcileRef` in `useBloc`).\n */\ninterface ReconcileDepSignature {\n  paths: PathSet;\n  key: string;\n  refId: string;\n  args: unknown;\n}\n\n/** Snapshot of the last FULL dep-reconcile layout effect run. */\ninterface ReconcileSignature {\n  /** The primary container this signature was captured against (identity\n   * check — a rebind/re-key swaps this even if the tracked paths happen to\n   * be textually identical, and must never be mistaken for \"unchanged\"). */\n  primaryContainer: StateContainer;\n  primaryPaths: PathSet;\n  deps: Map<StateContainer, ReconcileDepSignature>;\n}\n\n/** Per-access options shared by both dep accessors. */\ninterface DepAccessOptionsLike {\n  args?: unknown;\n}\n\n/** Structural shape of a branded `depend()` handle as seen from React. */\ninterface DepHandleLike {\n  track(options?: DepAccessOptionsLike): [unknown, StateContainer];\n  untracked(options?: DepAccessOptionsLike): StateContainer;\n  readonly [DEP_BRAND]: {\n    Type: StateContainerConstructor;\n    defaultArgs?: unknown;\n  };\n}\n\n/**\n * Build the per-consumer wrapper that replaces a branded dep handle inside a\n * tracked getter's `this`. The wrapper exposes the same accessors as the core\n * handle and overrides `.track()`:\n *\n * - **Inside a render** (`trackedStateRef.current != null`): resolve (ENSURE,\n *   no ref) the dep, `trackRender` its state, merge the recorded paths into the\n *   session entry, build/reuse a tracked proxy for the dep so its OWN getters\n *   track too, and return `[trackedValue, depProxy]`. The ownership ref is taken\n *   by the layout-effect reconcile pass, not here.\n * - **Outside a render**: degrade to live `[dep.state, dep]` — matches the core\n *   base impl, safe in event handlers/effects/methods.\n *\n * `.untracked()` always returns the live instance with no subscription.\n *\n * Args resolve at call time (`options.args ?? defaultArgs`), so a single handle\n * can resolve different dep instances across calls; tracked-proxy state is\n * therefore cached per resolved instance, not per handle. Guards against a\n * container re-entering tracking within the same render (mutual A↔B deps): if\n * the dep already has a non-primary session entry this render, reuse its proxy\n * + union its paths instead of re-acquiring.\n */\nfunction makeDepWrapper(\n  handle: DepHandleLike,\n  consumerId: string,\n  trackedStateRef: { current: unknown },\n  sessionRef: { current: Map<StateContainer, SessionEntry> },\n  onDepHandle: (handle: object) => unknown,\n): DepHandleLike {\n  const brand = handle[DEP_BRAND];\n  const refId = depRefId(consumerId);\n  const registry = getRegistry();\n  // Per-resolved-instance tracked-state ref + proxy. Call-time args mean one\n  // handle can resolve several instances, so cache is keyed by the instance.\n  const perDep = new WeakMap<\n    StateContainer,\n    { ref: { current: unknown }; proxy: StateContainer }\n  >();\n  // One ProxyCache shared across every instance this handle resolves to\n  // (call-time args can resolve different dep instances across calls) — safe\n  // because ProxyCache's internal map is keyed by target object identity, so\n  // unrelated instances' objects never collide in it.\n  const proxyCache = new ProxyCache();\n  // One-entry identity cache: skip re-hashing the structural key\n  // (`resolveKey` -> `structuralKey` -> JSON.stringify) when `args` is the\n  // same reference as last call — callers almost always pass a\n  // reference-stable `args` (`options?.args ?? brand.defaultArgs`). Only the\n  // derived key is cached; `ensure` still runs every call so a\n  // disposed-and-recreated entry is always picked up.\n  let lastArgs: unknown = ARGS_UNSET;\n  let lastKey = '';\n\n  const resolve = (options?: DepAccessOptionsLike) => {\n    const args = options?.args ?? brand.defaultArgs;\n    // `ARGS_UNSET` is module-private, so no caller's `args` can equal it — the\n    // first call always misses and seeds `lastKey` before it is ever read.\n    if (!Object.is(lastArgs, args)) {\n      lastArgs = args;\n      lastKey = registry.resolveKey(brand.Type, undefined, args);\n    }\n    const key = lastKey;\n    const dep = registry.ensure(\n      brand.Type,\n      key,\n      args,\n    ) as unknown as StateContainer;\n    return { dep, key, args };\n  };\n\n  const wrapper = {\n    untracked: (options?: DepAccessOptionsLike) => resolve(options).dep,\n    track: (options?: DepAccessOptionsLike) => {\n      const { dep, key, args } = resolve(options);\n\n      // Outside a render: live values, no subscription (core base behavior).\n      if (trackedStateRef.current == null) {\n        return [dep.state, dep];\n      }\n\n      const session = sessionRef.current;\n      const existing = session.get(dep);\n\n      // Render only ENSUREs the dep instance (via `resolve()` above); it does\n      // NOT take a ref. Ownership is claimed by the layout-effect reconcile\n      // pass-2 the first commit it sees this dep, and released on drop/unmount.\n      // This keeps acquire/release paired so an uncommitted render can't leak a\n      // dep ref (R4).\n\n      const tracked = trackRender(dep.state, dep.interner, proxyCache);\n      let cache = perDep.get(dep);\n      if (cache === undefined) {\n        const ref = { current: tracked.value as unknown };\n        cache = { ref, proxy: buildTrackedProxy(dep, ref, onDepHandle).proxy };\n        perDep.set(dep, cache);\n      } else {\n        cache.ref.current = tracked.value;\n      }\n\n      if (existing !== undefined) {\n        // Re-entry this render (`.track()` twice, or a mutual cycle): union the\n        // new paths into the existing entry rather than re-acquiring.\n        existing.paths = unionPaths(existing.paths, tracked.paths);\n      } else {\n        session.set(dep, {\n          kind: 'dep',\n          paths: tracked.paths,\n          Type: brand.Type,\n          key,\n          refId,\n          args,\n        });\n      }\n\n      return [tracked.value, cache.proxy];\n    },\n  } as DepHandleLike;\n\n  Object.defineProperty(wrapper, DEP_BRAND, {\n    value: brand,\n    enumerable: false,\n    writable: false,\n    configurable: false,\n  });\n\n  return wrapper;\n}\n\n/** Union two PathSets (ALL_PATHS dominates). */\nfunction unionPaths(a: PathSet, b: PathSet): PathSet {\n  if (a === ALL_PATHS || b === ALL_PATHS) return ALL_PATHS;\n  const out = new Set<number>(a as Set<number>);\n  for (const id of b as Set<number>) out.add(id);\n  return out;\n}\n\n/**\n * Fold a per-mount isolation id into `args`. MERGES rather than replaces\n * (plan Q2=B): a class-level `static isolated` must not be silently cancelled\n * by a call site that happens to pass args. Non-object args are nested rather\n * than spread, so a primitive arg can't be destructured into index keys.\n */\nconst withIsolation = (base: unknown, id: string): object =>\n  base === undefined\n    ? { _blacIsolated: id }\n    : typeof base === 'object' && base !== null\n      ? { ...base, _blacIsolated: id }\n      : { _blacArgs: base, _blacIsolated: id };\n\nconst shallowArrayEqual = (a: unknown[], b: unknown[]): boolean => {\n  if (a === b) return true;\n  if (a.length !== b.length) return false;\n  for (let i = 0; i < a.length; i++) {\n    if (!Object.is(a[i], b[i])) return false;\n  }\n  return true;\n};\n\n/**\n * Expand a PathSet to include an *ancestor-watch* id for every ancestor of\n * every tracked leaf.\n *\n * The auto-tracker records leaf paths (e.g. `'items.length'`), but\n * `StructuralContainer.patch` can only mark the parent (`'items'`) when it\n * replaces a value atomically (arrays, `null`, primitives — it can't see\n * inside). Without expansion, a subscriber with interest `{'items.length'}`\n * would miss a `patch`-triggered atomic-replacement of `items`.\n *\n * Ancestors are added under the interner's *ancestor-watch* lane\n * (`internAncestor`), NOT as normal ids. The source emits a matching\n * ancestor-watch mark only for paths it replaces atomically — never for a\n * plain-object structural pulse-up. So `{'items.length'}` wakes when the array\n * `items` is replaced, but `{'user.email'}` does NOT wake when a sibling\n * `user.name` changes and pulses `user` up: pulse-up `user` is a normal id and\n * the ancestor-watch `user` only intersects another ancestor-watch `user`.\n *\n * Example: leaf `'a.b.c'` adds ancestor-watch ids for `'a.b'` and `'a'` (but\n * NOT the `''` root — a root change is covered by `ALL_PATHS` from the source,\n * and `''` would wake this consumer on every field change).\n */\nfunction expandWithAncestors(paths: PathSet, interner: PathInterner): PathSet {\n  if (paths === ALL_PATHS) return ALL_PATHS;\n  const leafPaths = paths as Set<number>;\n  if (leafPaths.size === 0) return paths;\n\n  const expanded = new Set<number>(leafPaths);\n  for (const id of leafPaths) {\n    const str = interner.lookup(id);\n    // Add all non-root ancestor segments as *ancestor-watch* ids: 'a.b.c' →\n    // watch 'a.b' and 'a'. These live in the interner's ancestor lane so they\n    // only intersect the source's atomic-replacement marks (`internAncestor`),\n    // never a structural pulse-up mark of the same path. That is what lets a\n    // descendant-reader (e.g. `items.length`) wake on an array/null replacement\n    // without a sibling-leaf reader (`user.email`) waking when a sibling\n    // (`user.name`) changes and pulses up through `user`.\n    let idx = str.lastIndexOf('.');\n    while (idx > 0) {\n      const ancestor = str.slice(0, idx);\n      expanded.add(interner.internAncestor(ancestor));\n      idx = ancestor.lastIndexOf('.');\n    }\n  }\n  return expanded;\n}\n","/**\n * Global configuration for `@blac/react`.\n *\n * The hook's tracking model is fixed: when `useBloc` is called without a\n * `select`, render-time auto-tracking is used (via\n * `@dirtytalk/structural`'s `trackRender`). When `select` is provided,\n * re-renders are driven by per-index `Object.is` over the returned array.\n *\n * Reserved for forwards-compatible knobs; currently empty.\n */\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface BlacReactConfig {}\n\nconst defaultConfig: BlacReactConfig = {};\n\nlet globalConfig: BlacReactConfig = { ...defaultConfig };\n\n/**\n * Configure global defaults for `@blac/react` hooks.\n *\n * @param config - Partial configuration to merge with current globals\n */\nexport function configureBlacReact(config: Partial<BlacReactConfig>): void {\n  globalConfig = { ...globalConfig, ...config };\n}\n\n/**\n * Get the current global configuration.\n * @internal\n */\nexport function getBlacReactConfig(): BlacReactConfig {\n  return globalConfig;\n}\n\n/**\n * Reset configuration to defaults (useful for testing).\n * @internal\n */\nexport function resetBlacReactConfig(): void {\n  globalConfig = { ...defaultConfig };\n}\n"],"mappings":";;;;;;AAkBA,MAAM,uBAAA,GAAA,MAAA,+BAAqD,IAAI,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CpE,SAAgB,aAAkD,EAChE,MACA,MACA,YACqC;CACrC,MAAM,aAAA,GAAA,MAAA,YAAuB,mBAAmB;CAIhD,MAAM,aAAA,GAAA,MAAA,eAA0B;EAC9B,MAAM,OAAO,IAAI,IAAI,SAAS;EAC9B,KAAK,IAAI,MAAM,IAAI;EACnB,OAAO;CAET,GAAG;EAAC;EAAW;EAAM;CAAI,CAAC;CAE1B,OACE,iBAAA,GAAA,kBAAA,KAAC,oBAAoB,UAArB;EAA8B,OAAO;EAClC;CAC2B,CAAA;AAElC;;;;;;;AAQA,SAAgB,gBACd,WAC4B;CAE5B,QAAA,GAAA,MAAA,YADuB,mBACd,EAAE,IAAI,SAAS;AAC1B;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrEA,SAAgB,kBACd,UACA,iBACA,aAC4B;CAO5B,MAAM,8BAAc,IAAI,IAAyC;CACjE,IAAI,QAAQ,OAAO,eAAe,QAAQ;CAC1C,OAAO,SAAS,UAAU,OAAO,WAAW;EAC1C,MAAM,OAA4B,CAChC,GAAG,OAAO,oBAAoB,KAAK,GACnC,GAAG,OAAO,sBAAsB,KAAK,CACvC;EACA,KAAK,MAAM,OAAO,MAAM;GACtB,MAAM,OAAO,OAAO,yBAAyB,OAAO,GAAG;GACvD,IAAI,MAAM,OAAO,CAAC,YAAY,IAAI,GAAG,GAAG,YAAY,IAAI,KAAK,IAAI;EACnE;EACA,QAAQ,OAAO,eAAe,KAAK;CACrC;CASA,MAAM,YAAY,IAAI,MAAM,UAAoB,EAC9C,IAAI,GAAG,GAAG,GAAG;EACX,IAAI,MAAM,SAAS,OAAO,gBAAgB,WAAW,QAAQ,IAAI,GAAG,GAAG,CAAC;EACxE,MAAM,QAAQ,QAAQ,IAAI,GAAG,GAAG,CAAC;EAGjC,IACE,gBAAgB,KAAA,MACf,OAAO,UAAU,cAAc,OAAO,UAAU,aACjD,UAAU,QACT,MAAkCA,WAAAA,eAAe,KAAA,GAElD,OAAO,YAAY,KAAe;EAEpC,OAAO;CACT,EACF,CAAC;CAYD,OAAO;EAAE,OAAA,IARS,MAAM,UAAoB,EAC1C,IAAI,QAAQ,KAAK,UAAU;GACzB,MAAM,OAAO,YAAY,IAAI,GAAG;GAChC,IAAI,MAAM,KAAK,OAAO,KAAK,IAAI,KAAK,SAAS;GAC7C,OAAO,QAAQ,IAAI,QAAQ,KAAK,QAAQ;EAC1C,EACF,CAEa;EAAc;CAAe;AAC5C;;;ACxDA,IAAI,iBAAiB;AAKrB,MAAM,aAA4B,OAAO,mBAAmB;;;;;;;;;;;AAY5D,SAAS,WAAc,QAAiC;CACtD,MAAM,OAAA,GAAA,MAAA,QAAuB,IAAI;CACjC,IAAI,IAAI,YAAY,MAClB,IAAI,UAAU,OAAO;CAEvB,OAAO;AACT;AAMA,MAAM,yBAAuC,CAAC;AAC9C,MAAM,yBAAoE;CACxE,KAAK;CACL,KAAK,KAAA;AACP;AACA,MAAM,sCAAyD,IAAI,IAAI;AACvE,MAAM,sCAAmD,IAAI,IAAI;AACjE,MAAM,2CAAqD,IAAI,QAAQ;AACvE,MAAM,sBAAkC,IAAIC,sBAAAA,WAAW;AAKvD,MAAM,gBAAgB,eAA+B,WAAW;AAChE,MAAM,YAAY,eAA+B,WAAW,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoDvE,SAAgB,QAGd,WACA,SACmC;CAGnC,MAAM,eAAe,WAAW,eAAe;CAK/C,MAAM,iBAAA,GAAA,MAAA,QAAsC,IAAI;CAChD,IAAI,cAAc,YAAY,MAC5B,cAAc,UAAU,WAAW;CAErC,MAAM,aAAa,cAAc;CAKjC,MAAM,WAAW,SAAS,aAAa,SAAA,GAAA,WAAA,iBAAwB,SAAS;CAGxE,MAAM,eAAe,WAAW,aAAa,KAAA;CAI7C,MAAM,aAAA,GAAA,MAAA,QAAmB,SAAS,MAAM;CACxC,UAAU,UAAU,SAAS;CAC7B,MAAM,eAAe,SAAS,WAAW,KAAA;CACzC,MAAM,cAAA,GAAA,MAAA,QAAoB,SAAS,OAAO;CAC1C,WAAW,UAAU,SAAS;CAC9B,MAAM,gBAAA,GAAA,MAAA,QAAsB,SAAS,SAAS;CAC9C,aAAa,UAAU,SAAS;CAChC,MAAM,eAAA,GAAA,MAAA,QAAqB,QAAQ;CACnC,YAAY,UAAU;CAYtB,MAAM,UAAW,SAAmD;CACpE,MAAM,cAAA,GAAA,MAAA,QAAoB,OAAO;CACjC,WAAW,UAAU;CAIrB,MAAM,gBAAgB,WAAW,eAAe;CAChD,IAAI,CAAC,OAAO,GAAG,cAAc,QAAQ,KAAK,OAAO,GAC/C,cAAc,UAAU;EACtB,KAAK;EACL,KAAK,YAAY,KAAA,IAAY,KAAA,IAAY,KAAK,UAAU,OAAO;CACjE;CAEF,MAAM,aAAa,cAAc,QAAQ;CAGzC,MAAM,eAAe,gBAAgB,SAAS;CAC9C,MAAM,mBAAA,GAAA,MAAA,QAAyB,YAAY;CAC3C,gBAAgB,UAAU;CAE1B,MAAM,qBAAqB,WAAW,eAAe;CACrD,IAAI,CAAC,OAAO,GAAG,mBAAmB,QAAQ,KAAK,YAAY,GACzD,mBAAmB,UAAU;EAC3B,KAAK;EACL,KACE,iBAAiB,KAAA,IAAY,KAAA,IAAY,KAAK,UAAU,YAAY;CACxE;CAEF,MAAM,kBAAkB,mBAAmB,QAAQ;CAQnD,MAAM,mBAAA,GAAA,MAAA,QAAkC,IAAI;CAa5C,MAAM,aAAa,WAAW,aAAa;CAG3C,MAAM,aAAa,WAAW,aAAa;CAG3C,MAAM,qBAAqB,WAAW,kBAAkB;CACxD,MAAM,gBAAgB,WAAW,aAAa;CAK9C,MAAM,oBAAA,GAAA,MAAA,QAAqD,IAAI;CAU/D,MAAM,CAAC,aAAa,eAAA,GAAA,MAAA,aAA0B,MAAc,IAAI,GAAG,CAAC;CAGpE,MAAM,gBAAA,GAAA,MAAA,QAAoC,IAAI;CAE9C,MAAM,EAAE,MAAM,aAAa,iBAAA,GAAA,MAAA,eAIlB;EAEP,MAAM,WACJ,WAAW,YAAY,KAAA,IACnB,WAAW,UACX,gBAAgB;EAQtB,MAAM,gBAAgB,YAAY,UAC7B,cAAc,UAAU,UAAU,IACnC;EAEJ,MAAM,eAAA,GAAA,WAAA,oBAAiC,WAAW,aAAa;EAK/D,MAAM,YAAA,GAAA,WAAA,aAAkB,EAAE,QAAQ,WAAW,aAAa;GACxD,WAAW;GACX,UAAU;GACV,MAAM;EACR,CAAC;EAOD,MAAM,eAAe,WAA4B;GAC/C,MAAM,QAAQ,mBAAmB;GACjC,MAAM,SAAS,MAAM,IAAI,MAAM;GAC/B,IAAI,WAAW,KAAA,GAAW,OAAO;GACjC,MAAM,UAAU,eACd,QACA,YACA,iBACA,YACA,WACF;GACA,MAAM,IAAI,QAAQ,OAAO;GACzB,OAAO;EACT;EAEA,MAAM,EAAE,UAAU,kBAChB,UACA,iBACA,WACF;EAEA,OAAO;GACL,MAAM;GACN,aAAa;GACb,aAAa;EACf;CAEF,GAAG;EAAC;EAAW;EAAY;EAAiB;EAAc;CAAW,CAAC;CAUtE,MAAM,GAAG,UAAA,GAAA,MAAA,aAAqB,MAAc,IAAI,GAAG,CAAC;CACpD,MAAM,UAAU,WAAWC,sBAAAA,YAAY;CASvC,MAAM,sBAAsB,WAAWA,sBAAAA,YAAY;CAGnD,MAAM,oBAAA,GAAA,MAAA,QAA4C,IAAI;CAItD,MAAM,kBAAA,GAAA,MAAA,QAAiC,KAAA,CAAS;CAGhD,MAAM,eAAA,GAAA,MAAA,QAA8B,IAAI;CAExC,CAAA,GAAA,MAAA,iBAAgB;EAYd,MAAM,UAAW,KAAmC;EAEpD,IAAI,cAAc;GAChB,MAAM,QAAQ,QAAQ,gBACdC,sBAAAA,iBACA;IACJ,MAAM,SAAS,UAAU;IACzB,IAAI,CAAC,QAAQ;KACX,MAAM;KACN;IACF;IACA,MAAM,OAAO,OACV,KAAmC,OACpC,IACF;IACA,MAAM,OAAO,iBAAiB;IAC9B,IAAI,SAAS,QAAQ,kBAAkB,MAAM,IAAI,GAAG;IACpD,iBAAiB,UAAU;IAC3B,MAAM;GACR,CACF;GAIA,MAAM,SAAS,UAAU;GACzB,IAAI,QAAQ;IACV,MAAM,OAAO,OACV,KAAmC,OACpC,IACF;IACA,MAAM,OAAO,iBAAiB;IAC9B,IAAI,SAAS,QAAQ,CAAC,kBAAkB,MAAM,IAAI,GAAG;KACnD,iBAAiB,UAAU;KAC3B,MAAM;IACR;GACF;GACA,OAAO;EACT;EASA,MAAM,QAAQ,QAAQ,gBACd,oBAAoB,eACpB,MAAM,CACd;EAIA,KAAoC,sBAClC,YACA,QAAQ,OACV;EAIA,IAAK,KAAmC,UAAU,eAAe,SAC/D,MAAM;EAER,aAAa;GACX,MAAM;GACN,KAAoC,mBAAmB,UAAU;EACnE;CAEF,GAAG;EAAC;EAAM;EAAY;CAAY,CAAC;CAiCnC,CAAA,GAAA,MAAA,uBAAsB;EACpB,MAAM,YAAA,GAAA,WAAA,aAAuB;EAC7B,MAAM,OAAO,SAAS,QAAQ,WAAW,aAAa;GACpD,WAAW;GACX,UAAU;GACV,OAAO,aAAa,UAAU;EAChC,CAAC;EACD,aAAa,UAAU;EACvB,WAAW,UAAU,IAAuB;EAM5C,IAAI,SAAS,MACX,WAAW;EAEb,aAAa;GACX,aAAa,UAAW,aAAa,WAAW,IAAwB;GACxE,SAAS,QAAQ,WAAW,aAAa,OAAO,aAAa,UAAU,CAAC;EAC1E;CAEF,GAAG;EAAC;EAAW;EAAa;CAAU,CAAC;CAUvC,MAAM,WAAY,KAAmC;CAGrD,eAAe,UAAU;CAIzB,IAAI,YAAY,YAAY,MAAM;EAChC,YAAY,UAAU;EACtB,iBAAiB,UAAU;CAC7B;CACA,IAAI;CACJ,IAAI,UAAU,YAAY,KAAA,GAAW;EACnC,QAAQ;EAGR,IAAI,iBAAiB,YAAY,MAC/B,iBAAiB,UAAU,UAAU,QACnC,UACA,IACF;CAEJ,OAAO;EACL,MAAM,WAAA,GAAA,sBAAA,aACJ,UACC,KAAmC,UACpC,cAAc,OAChB;EACA,QAAQ,QAAQ;EAChB,gBAAgB,UAAU,QAAQ;EAClC,QAAQ,UAAU,QAAQ;EAO1B,MAAM,UAAU,WAAW;EAC3B,QAAQ,MAAM;EACd,QAAQ,IAAI,MAAmC;GAC7C,MAAM;GACN,OAAO,QAAQ;EACjB,CAAC;EAOD,eAAe,QAAQ,MAAM;CAQ/B;CAWA,CAAA,GAAA,MAAA,uBAAsB;EAKpB,gBAAgB,UAAU;EAC1B,IAAI,UAAU,YAAY,KAAA,GAAW;GAInC,iBAAiB,UAAU;GAC3B;EACF;EACA,MAAM,YAAY;EAClB,MAAM,QAAQ,QAAQ;EACtB,MAAM,UAAU,WAAW;EAY3B,MAAM,OAAO,iBAAiB;EAC9B,IACE,SAAS,QACT,KAAK,qBAAqB,cAAA,GAAA,sBAAA,eACZ,KAAK,cAAc,KAAK,GACtC;GACA,IAAI,YAAY,KAAK,KAAK,SAAS,QAAQ,OAAO;GAClD,IAAI,WACF,KAAK,MAAM,CAAC,cAAc,UAAU,SAAS;IAC3C,IAAI,MAAM,SAAS,WAAW;IAC9B,MAAM,YAAY,KAAK,KAAK,IAAI,YAAY;IAC5C,IACE,cAAc,KAAA,KACd,UAAU,QAAQ,MAAM,OACxB,UAAU,UAAU,MAAM,SAC1B,CAAC,OAAO,GAAG,UAAU,MAAM,MAAM,IAAI,KACrC,EAAA,GAAA,sBAAA,eAAe,UAAU,OAAO,MAAM,KAAK,GAC3C;KACA,YAAY;KACZ;IACF;GACF;GAEF,IAAI,WAAW;EACjB;EAEA,UAAU,sBAAsB,YAAY,KAAK;EAKjD,oBAAoB,UAAU,oBAC5B,OACA,UAAU,QACZ;EAaA,MAAM,OAAO,WAAW;EAGxB,KAAK,MAAM,CAAC,cAAc,QAAQ,MAChC,IAAI,CAAC,QAAQ,IAAI,YAAY,GAAG;GAC9B,IAAI,YAAY;GAChB,aAAa,mBAAmB,UAAU;GAC1C,CAAA,GAAA,WAAA,aAAY,EAAE,QAAQ,IAAI,MAAM,IAAI,KAAK,OAAO,IAAI,KAAK;GACzD,KAAK,OAAO,YAAY;EAC1B;EAIF,KAAK,MAAM,CAAC,cAAc,UAAU,SAAS;GAC3C,IAAI,MAAM,SAAS,WAAW;GAC9B,MAAM,WAAW,oBAAoB,MAAM,OAAO,aAAa,QAAQ;GACvE,aAAa,sBAAsB,YAAY,MAAM,KAAK;GAC1D,MAAM,WAAW,KAAK,IAAI,YAAY;GACtC,IAAI,UAAU;IACZ,SAAS,YAAY,UAAU;IAC/B;GACF;GAGA,CAAA,GAAA,WAAA,aAAY,EAAE,QAAQ,MAAM,MAAM,MAAM,KAAK;IAC3C,WAAW;IACX,UAAU;IACV,OAAO,MAAM;IACb,MAAM,MAAM;GACd,CAAC;GACD,MAAM,cAAoC,EAAE,SAAS,SAAS;GAC9D,MAAM,cAAc,aAAa,QAAQ,gBACjC,YAAY,eACZ,MAAM,CACd;GACA,KAAK,IAAI,cAAc;IACrB;IACA;IACA,MAAM,MAAM;IACZ,KAAK,MAAM;IACX,OAAO,MAAM;IACb,MAAM,MAAM;GACd,CAAC;EACH;EAMA,MAAM,gCAAgB,IAAI,IAA2C;EACrE,KAAK,MAAM,CAAC,cAAc,UAAU,SAAS;GAC3C,IAAI,MAAM,SAAS,WAAW;GAC9B,cAAc,IAAI,cAAc;IAC9B,OAAO,MAAM;IACb,KAAK,MAAM;IACX,OAAO,MAAM;IACb,MAAM,MAAM;GACd,CAAC;EACH;EACA,iBAAiB,UAAU;GACzB,kBAAkB;GAClB,cAAc;GACd,MAAM;EACR;CACF,CAAC;CAOD,CAAA,GAAA,MAAA,iBAAgB;EAGd,MAAM,OAAO,WAAW;EACxB,aAAa;GACX,KAAK,MAAM,CAAC,cAAc,QAAQ,MAAM;IACtC,IAAI,YAAY;IAChB,aAAa,mBAAmB,UAAU;IAC1C,CAAA,GAAA,WAAA,aAAY,EAAE,QAAQ,IAAI,MAAM,IAAI,KAAK,OAAO,IAAI,KAAK;GAC3D;GACA,KAAK,MAAM;EACb;CAIF,GAAG,CAAC,YAAY,UAAU,CAAC;CAE3B,OAAO;EACL;EACA;EACA;CACF;AACF;;;;;;;;;;;;;;;;;;;;;;;AAoGA,SAAS,eACP,QACA,YACA,iBACA,YACA,aACe;CACf,MAAM,QAAQ,OAAOC,WAAAA;CACrB,MAAM,QAAQ,SAAS,UAAU;CACjC,MAAM,YAAA,GAAA,WAAA,aAAuB;CAG7B,MAAM,yBAAS,IAAI,QAGjB;CAKF,MAAM,aAAa,IAAIH,sBAAAA,WAAW;CAOlC,IAAI,WAAoB;CACxB,IAAI,UAAU;CAEd,MAAM,WAAW,YAAmC;EAClD,MAAM,OAAO,SAAS,QAAQ,MAAM;EAGpC,IAAI,CAAC,OAAO,GAAG,UAAU,IAAI,GAAG;GAC9B,WAAW;GACX,UAAU,SAAS,WAAW,MAAM,MAAM,KAAA,GAAW,IAAI;EAC3D;EACA,MAAM,MAAM;EAMZ,OAAO;GAAE,KALG,SAAS,OACnB,MAAM,MACN,KACA,IAES;GAAG;GAAK;EAAK;CAC1B;CAEA,MAAM,UAAU;EACd,YAAY,YAAmC,QAAQ,OAAO,EAAE;EAChE,QAAQ,YAAmC;GACzC,MAAM,EAAE,KAAK,KAAK,SAAS,QAAQ,OAAO;GAG1C,IAAI,gBAAgB,WAAW,MAC7B,OAAO,CAAC,IAAI,OAAO,GAAG;GAGxB,MAAM,UAAU,WAAW;GAC3B,MAAM,WAAW,QAAQ,IAAI,GAAG;GAQhC,MAAM,WAAA,GAAA,sBAAA,aAAsB,IAAI,OAAO,IAAI,UAAU,UAAU;GAC/D,IAAI,QAAQ,OAAO,IAAI,GAAG;GAC1B,IAAI,UAAU,KAAA,GAAW;IACvB,MAAM,MAAM,EAAE,SAAS,QAAQ,MAAiB;IAChD,QAAQ;KAAE;KAAK,OAAO,kBAAkB,KAAK,KAAK,WAAW,EAAE;IAAM;IACrE,OAAO,IAAI,KAAK,KAAK;GACvB,OACE,MAAM,IAAI,UAAU,QAAQ;GAG9B,IAAI,aAAa,KAAA,GAGf,SAAS,QAAQ,WAAW,SAAS,OAAO,QAAQ,KAAK;QAEzD,QAAQ,IAAI,KAAK;IACf,MAAM;IACN,OAAO,QAAQ;IACf,MAAM,MAAM;IACZ;IACA;IACA;GACF,CAAC;GAGH,OAAO,CAAC,QAAQ,OAAO,MAAM,KAAK;EACpC;CACF;CAEA,OAAO,eAAe,SAASG,WAAAA,WAAW;EACxC,OAAO;EACP,YAAY;EACZ,UAAU;EACV,cAAc;CAChB,CAAC;CAED,OAAO;AACT;;AAGA,SAAS,WAAW,GAAY,GAAqB;CACnD,IAAI,MAAMD,sBAAAA,aAAa,MAAMA,sBAAAA,WAAW,OAAOA,sBAAAA;CAC/C,MAAM,MAAM,IAAI,IAAY,CAAgB;CAC5C,KAAK,MAAM,MAAM,GAAkB,IAAI,IAAI,EAAE;CAC7C,OAAO;AACT;;;;;;;AAQA,MAAM,iBAAiB,MAAe,OACpC,SAAS,KAAA,IACL,EAAE,eAAe,GAAG,IACpB,OAAO,SAAS,YAAY,SAAS,OACnC;CAAE,GAAG;CAAM,eAAe;AAAG,IAC7B;CAAE,WAAW;CAAM,eAAe;AAAG;AAE7C,MAAM,qBAAqB,GAAc,MAA0B;CACjE,IAAI,MAAM,GAAG,OAAO;CACpB,IAAI,EAAE,WAAW,EAAE,QAAQ,OAAO;CAClC,KAAK,IAAI,IAAI,GAAG,IAAI,EAAE,QAAQ,KAC5B,IAAI,CAAC,OAAO,GAAG,EAAE,IAAI,EAAE,EAAE,GAAG,OAAO;CAErC,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;AAwBA,SAAS,oBAAoB,OAAgB,UAAiC;CAC5E,IAAI,UAAUA,sBAAAA,WAAW,OAAOA,sBAAAA;CAChC,MAAM,YAAY;CAClB,IAAI,UAAU,SAAS,GAAG,OAAO;CAEjC,MAAM,WAAW,IAAI,IAAY,SAAS;CAC1C,KAAK,MAAM,MAAM,WAAW;EAC1B,MAAM,MAAM,SAAS,OAAO,EAAE;EAQ9B,IAAI,MAAM,IAAI,YAAY,GAAG;EAC7B,OAAO,MAAM,GAAG;GACd,MAAM,WAAW,IAAI,MAAM,GAAG,GAAG;GACjC,SAAS,IAAI,SAAS,eAAe,QAAQ,CAAC;GAC9C,MAAM,SAAS,YAAY,GAAG;EAChC;CACF;CACA,OAAO;AACT;ACj+BA,IAAI,eAAgC,CAAmB;;;;;;AAOvD,SAAgB,mBAAmB,QAAwC;CACzE,eAAe;EAAE,GAAG;EAAc,GAAG;CAAO;AAC9C"}