{
  "version": 3,
  "sources": ["../../../src/use-waitable/use-waitable.ts"],
  "sourcesContent": ["import { useMemo, useRef } from 'react';\nimport type { EmptyObject, ReadonlyBinding } from 'react-bindings';\nimport {\n  areEqual,\n  pickLimiterOptions,\n  useBinding,\n  useBindingEffect,\n  useCallbackRef,\n  useDerivedBinding,\n  useLimiter,\n  useTransientDerivedBinding\n} from 'react-bindings';\n\nimport { isSpecialLoggingEnabledFor } from '../config/logging.mjs';\nimport { useIsMountedRef } from '../internal-hooks/use-is-mounted-ref.mjs';\nimport { normalizeAsArray } from '../internal-utils/array-like.mjs';\nimport { getTypedKeys } from '../internal-utils/get-typed-keys.mjs';\nimport type { ResetType } from '../waitable/types/reset';\nimport type { Waitable } from '../waitable/types/waitable';\nimport type { WrappedResult } from '../waitable/types/wrapped-result.mjs';\nimport { areAnyBindingsFalsey } from './internal/are-any-bindings-falsey.mjs';\nimport { areAnyBindingsTruthy } from './internal/are-any-bindings-truthy.mjs';\nimport { doSpecialLoggingForLockedWaitable, doSpecialLoggingForUnlockedWaitable } from './internal/special-logging.mjs';\nimport { updateWaitableBindingsWithDefaultValueProducer } from './internal/update-waitable-bindings-with-default-value-producer.mjs';\nimport { updateWaitableBindingsWithPrimaryFunction } from './internal/update-waitable-bindings-with-primary-function.mjs';\nimport { updateWaitableBindingsWithPrimaryFunctionForDefaultValue } from './internal/update-waitable-bindings-with-primary-function-for-default-value.mjs';\nimport { waitForBindingValues } from './internal/wait-for-binding-values.mjs';\nimport type { UseWaitableArgs } from './types/args';\nimport type { WaitablePrimaryFunction } from './types/primary-function';\n\nconst emptyBindingsArray = Object.freeze([]) as unknown as Array<ReadonlyBinding | undefined>;\n\n/**\n * Creates a waitable associated with a primary function that is given responsibility for updating the success and/or failure states of the\n * waitable.\n *\n * The primary function receives callbacks for setting the success and failure states of the waitable.  These can be called any number of\n * times.  However, the primary function itself will only be called once if a reset isn't issued on the waitable.  The waitable is\n * considered busy until the function itself is complete -- though it's allowed that the `setSuccess` and `setFailure` functions can be\n * called even after the primary function is complete.  If a reset occurs, any calls to previously created `setSuccess`/`setFailure`\n * callbacks are ignored.\n *\n * If a primary function throws, the waitable will no longer be busy, but the state won't otherwise change and the primary function won't\n * automatically be rerun.\n *\n * During default value generation, if an error occurs, either thrown or via `setFailure` if using `defaultValue='use-primary-function'` or\n * `defaultValue='use-primary-function-if-unlocked'`, `reset('soft')` is automatically called so the primary function can be run again as\n * applicable.\n */\nexport const useWaitable = <SuccessT, FailureT = any, ExtraFieldsT extends object = EmptyObject>(\n  primaryFunc: WaitablePrimaryFunction<SuccessT, FailureT>,\n  args: UseWaitableArgs<SuccessT, FailureT, ExtraFieldsT>\n): Waitable<SuccessT, FailureT> & ExtraFieldsT => {\n  const {\n    id,\n    deps,\n    addFields,\n    areErrorsEqual = areEqual,\n    detectErrorChanges = true,\n    areValuesEqual = areEqual,\n    detectValueChanges = true,\n    lockedUntil: lockedUntilBindings,\n    lockedWhile: lockedWhileBindings,\n    hardResetBindings,\n    softResetBindings,\n    defaultValue,\n    onFailure,\n    onReset,\n    onSuccess\n  } = args;\n\n  const limiterOptions = pickLimiterOptions(args);\n\n  const isMounted = useIsMountedRef();\n\n  /** The success value store */\n  const value = useBinding<SuccessT | undefined>(() => undefined, {\n    id: `${id}_value`,\n    areEqual: areValuesEqual,\n    detectChanges: detectValueChanges\n  });\n  /** The error value store */\n  const error = useBinding<FailureT | undefined>(() => undefined, {\n    id: `${id}_error`,\n    areEqual: areErrorsEqual,\n    detectChanges: detectErrorChanges\n  });\n\n  const force = useBinding<WrappedResult<SuccessT, FailureT> | undefined>(() => undefined, { id: `${id}_force` });\n  useBindingEffect(\n    force,\n    (force) => {\n      if (force === undefined) {\n        reset('hard');\n      } else {\n        updateWaitableBindingsWithPrimaryFunction({\n          id,\n          primaryFunc: ({ setSuccess, setFailure }) => {\n            if (force.ok) {\n              setSuccess(force.value);\n            } else {\n              setFailure(force.value);\n            }\n          },\n          isBusy,\n          error,\n          value,\n          alreadyRanFunc,\n          resetCount,\n          onFailure,\n          onSuccess\n        });\n      }\n    },\n    { limitType: 'none' }\n  );\n\n  /** If true, the primary function has already been started and won't run again */\n  const alreadyRanFunc = useRef(false);\n  /** If true, the waitable is busy running the primary function and hasn't received at least the initial result */\n  const isBusy = useBinding(() => false, { id: 'isBusy', detectChanges: true });\n\n  /**\n   * If true, either the `value` or `error` binding have defined values.\n   *\n   * This is a transient derived binding because we want it to have an up-to-date value, even when unmounted (since default value updates to\n   * value, for example, can happen asynchronously while unmounted).\n   */\n  const isComplete = useTransientDerivedBinding(\n    { error, value },\n    ({ error, value }): boolean => value !== undefined || error !== undefined,\n    { id: `${id}_isComplete` }\n  );\n\n  /** If true, the last time the primary function was attempted to be run, this waitable was locked */\n  const lastExecAttemptWasLocked = useRef(false);\n  /** If any of these bindings are falsey, this waitable is locked */\n  const lockedUntil = lockedUntilBindings !== undefined ? normalizeAsArray(lockedUntilBindings) : emptyBindingsArray;\n  /** If any of these bindings are true, this waitable is locked */\n  const lockedWhile = lockedWhileBindings !== undefined ? normalizeAsArray(lockedWhileBindings) : emptyBindingsArray;\n\n  /** Incremented on each reset */\n  const resetCount = useBinding<number>(() => 0, { id: 'resetCount', detectChanges: true });\n\n  /** The limiter used for scheduling the execution of the primary function */\n  const limiter = useLimiter({ id, cancelOnUnmount: true, ...limiterOptions });\n  const scheduleIfNeeded = useCallbackRef(() => limiter.limit(execPrimaryFuncIfNeeded));\n\n  /**\n   * Updates either using the primary function or the specified default value producer function.\n   *\n   * If no default value setting is given, this just sets the `error` and `value` bindings to undefined.\n   */\n  const updateWithDefaultValue = useCallbackRef(() => {\n    if (defaultValue === 'use-primary-function') {\n      return updateWaitableBindingsWithPrimaryFunctionForDefaultValue({\n        primaryFunc,\n        isBusy,\n        error,\n        value,\n        alreadyRanFunc,\n        resetCount,\n        softReset,\n        onSuccess\n      });\n    } else if (defaultValue === 'use-primary-function-if-unlocked') {\n      if (!isLocked.get()) {\n        return updateWaitableBindingsWithPrimaryFunctionForDefaultValue({\n          primaryFunc,\n          isBusy,\n          error,\n          value,\n          alreadyRanFunc,\n          resetCount,\n          softReset,\n          onSuccess\n        });\n      } else {\n        return updateWaitableBindingsWithDefaultValueProducer({ areValuesEqual, defaultValue: undefined, error, value });\n      }\n    } else {\n      return updateWaitableBindingsWithDefaultValueProducer({ areValuesEqual, defaultValue, error, value });\n    }\n  });\n\n  const reset: Waitable<SuccessT, FailureT>['reset'] = useCallbackRef((resetType: ResetType) => {\n    alreadyRanFunc.current = false;\n    isBusy.set(false);\n    lastExecAttemptWasLocked.current = false;\n\n    resetCount.set(resetCount.get() + 1);\n\n    switch (resetType) {\n      case 'hard':\n        updateWithDefaultValue();\n        break;\n      case 'soft':\n        // For soft reset, we always clear the error\n        if (error.get() !== undefined) {\n          error.set(undefined);\n        }\n        break;\n    }\n\n    onReset?.(resetType);\n\n    scheduleIfNeeded();\n  });\n\n  const hardReset = useCallbackRef(() => reset('hard'));\n  const softReset = useCallbackRef(() => reset('soft'));\n\n  const wait: Waitable<SuccessT, FailureT>['wait'] = useCallbackRef((options) =>\n    waitForBindingValues({ error, resetCount, value, ...options })\n  );\n\n  /** If true, this waitable is locked */\n  const isLocked = useDerivedBinding(\n    [...lockedUntil, ...lockedWhile],\n    (): boolean => areAnyBindingsFalsey(lockedUntil) || areAnyBindingsTruthy(lockedWhile),\n    { id: `${id}_locked`, limitType: 'none' }\n  );\n\n  /** If true, this waitable is locked and it doesn't already have a value */\n  const isLockedWithoutValue = useDerivedBinding({ isLocked, value }, ({ isLocked, value }): boolean => isLocked && value === undefined, {\n    id: `${id}_isLockedWithoutValue`,\n    limitType: 'none',\n    deps\n  });\n\n  /**\n   * Checks if the primary function is ready to be executed and then runs it if needed.\n   *\n   * The primary function can be run if all of:\n   *\n   * - is mounted (can be ignored via the `ignoreIsMounted` flag)\n   * - hasn't already been run\n   * - isn't locked\n   */\n  const execPrimaryFuncIfNeeded = useCallbackRef(() => {\n    if (alreadyRanFunc.current || !(isMounted.current ?? false)) {\n      return;\n    }\n\n    if (isLocked.get()) {\n      if (!lastExecAttemptWasLocked.current && isSpecialLoggingEnabledFor('waitable-locking-warnings')) {\n        doSpecialLoggingForLockedWaitable({ id, lockedUntil, lockedWhile });\n      }\n      lastExecAttemptWasLocked.current = true;\n\n      return;\n    }\n\n    if (lastExecAttemptWasLocked.current && isSpecialLoggingEnabledFor('waitable-locking-warnings')) {\n      doSpecialLoggingForUnlockedWaitable({ id, lockedUntil, lockedWhile });\n    }\n    lastExecAttemptWasLocked.current = false;\n\n    updateWaitableBindingsWithPrimaryFunction({\n      id,\n      primaryFunc,\n      isBusy,\n      error,\n      value,\n      alreadyRanFunc,\n      resetCount,\n      onFailure,\n      onSuccess\n    });\n  });\n\n  // If becomes unlocked, schedule\n  useBindingEffect(\n    { isLocked },\n    ({ isLocked }) => {\n      if (!isLocked) {\n        scheduleIfNeeded();\n      }\n    },\n    { triggerOnMount: true }\n  );\n\n  // Listening for changes to the hard and soft reset bindings.  Deps changes are also treated like hard bindings resets\n  useBindingEffect(hardResetBindings, hardReset, { id: `${id}_hardResetBindings`, deps, limitType: 'none' });\n  useBindingEffect(softResetBindings, softReset, { id: `${id}_softResetBindings`, limitType: 'none' });\n\n  // If this is the first render, initializing the default value\n  const isFirstRender = useRef(true);\n  if (isFirstRender.current) {\n    isFirstRender.current = false;\n\n    updateWithDefaultValue();\n  }\n\n  // If already mounted, scheduling right away if needed\n  if (isMounted.current ?? false) {\n    scheduleIfNeeded();\n  }\n\n  const output = useMemo<Waitable<SuccessT, FailureT>>(\n    (): Waitable<SuccessT, FailureT> => ({\n      isWaitable: true,\n      id,\n      value,\n      error,\n      force,\n      isBusy,\n      isComplete,\n      isLocked,\n      isLockedWithoutValue,\n      reset,\n      wait\n    }),\n    [error, force, id, isBusy, isComplete, isLocked, isLockedWithoutValue, reset, value, wait]\n  ) as Waitable<SuccessT, FailureT> & ExtraFieldsT;\n  const extraFields = addFields?.(output);\n  if (extraFields !== undefined) {\n    for (const key of getTypedKeys(extraFields)) {\n      output[key] = extraFields[key] as (typeof output)[typeof key];\n    }\n  }\n\n  return output;\n};\n"],
  "mappings": "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",
  "names": ["force", "error", "value", "isLocked"]
}
