{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "admin",
  "title": "Admin",
  "description": "Static administration shell with user management, a user inspector, session controls, and the stop-impersonating action.",
  "dependencies": [
    "@better-auth-ui/core@latest",
    "@better-auth-ui/react@latest",
    "@tanstack/react-form",
    "@tanstack/react-pacer",
    "@tanstack/react-query",
    "@tanstack/react-store",
    "@tanstack/react-table",
    "better-auth",
    "cn",
    "date-fns",
    "lucide-react"
  ],
  "registryDependencies": [
    "alert-dialog",
    "avatar",
    "badge",
    "button",
    "calendar",
    "checkbox",
    "combobox",
    "dialog",
    "dropdown-menu",
    "field",
    "https://better-auth-ui.com/r/radix-nova/user-button.json",
    "input",
    "input-group",
    "popover",
    "radio-group",
    "select",
    "separator",
    "skeleton",
    "slider",
    "sonner",
    "spinner",
    "switch",
    "table",
    "tabs",
    "textarea"
  ],
  "files": [
    {
      "path": "examples/start-shadcn-example/src/components/auth/additional-field.tsx",
      "content": "\"use client\"\n\nimport {\n  type AdditionalField as AdditionalFieldConfig,\n  type AdditionalFieldFormValue,\n  getFormFieldErrors,\n  resolveInputType\n} from \"@better-auth-ui/core\"\nimport { useAuth, useCopyToClipboard } from \"@better-auth-ui/react\"\nimport { format } from \"date-fns\"\nimport { CalendarIcon, Check, ChevronDownIcon, Copy } from \"lucide-react\"\nimport { type ComponentType, useRef, useState } from \"react\"\nimport { toast } from \"sonner\"\n\nimport { buttonVariants } from \"@/components/ui/button\"\nimport { Calendar } from \"@/components/ui/calendar\"\nimport { Checkbox } from \"@/components/ui/checkbox\"\nimport {\n  Combobox,\n  ComboboxContent,\n  ComboboxEmpty,\n  ComboboxInput,\n  ComboboxItem,\n  ComboboxList\n} from \"@/components/ui/combobox\"\nimport {\n  Field,\n  FieldContent,\n  FieldError,\n  FieldLabel\n} from \"@/components/ui/field\"\nimport { Input } from \"@/components/ui/input\"\nimport {\n  InputGroup,\n  InputGroupAddon,\n  InputGroupButton,\n  InputGroupInput\n} from \"@/components/ui/input-group\"\nimport {\n  Popover,\n  PopoverContent,\n  PopoverTrigger\n} from \"@/components/ui/popover\"\nimport {\n  Select,\n  SelectContent,\n  SelectItem,\n  SelectTrigger,\n  SelectValue\n} from \"@/components/ui/select\"\nimport { Slider } from \"@/components/ui/slider\"\nimport { Switch } from \"@/components/ui/switch\"\nimport { Textarea } from \"@/components/ui/textarea\"\nimport { cn } from \"cn\"\n\nexport type AdditionalFieldProps = {\n  name: string\n  field: AdditionalFieldConfig\n  value: AdditionalFieldFormValue\n  onBlur: () => void\n  onChange: (value: AdditionalFieldFormValue) => void\n  isInvalid?: boolean\n  errors?: unknown[]\n  isPending?: boolean\n  /** Complete suffix appended to labels for fields that are not required. */\n  optionalLabel?: string\n}\n\nfunction valueToString(value: AdditionalFieldFormValue) {\n  if (value == null) return \"\"\n  return value instanceof Date ? value.toISOString() : String(value)\n}\n\n/** Convert a `defaultValue` into a `Date` for the calendar. */\nfunction toDate(value: unknown): Date | undefined {\n  if (value instanceof Date) return value\n  if (typeof value === \"string\") {\n    const parsed = new Date(value)\n    return Number.isNaN(parsed.getTime()) ? undefined : parsed\n  }\n  return undefined\n}\n\n/** Format a Date as `HH:mm:ss` for an `<input type=\"time\">`. */\nfunction formatTime(date: Date) {\n  const pad = (n: number) => n.toString().padStart(2, \"0\")\n  return `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`\n}\n\n/**\n * Icon-only copy button used as an `InputGroupAddon`. `getValue` is invoked\n * lazily on click so the button copies the input's *live* value rather than a\n * stale snapshot — important when paired with editable inputs.\n */\nfunction CopyButton({\n  getValue,\n  isDisabled\n}: {\n  getValue: () => string | undefined\n  isDisabled?: boolean\n}) {\n  const { localization } = useAuth()\n  const { copied, copy } = useCopyToClipboard({\n    onError: (error) => {\n      console.error(\"[Better Auth UI] Copy failed\", error)\n      toast.error(localization.errors.copyFailed)\n    }\n  })\n\n  async function handleCopy() {\n    const value = getValue()\n    if (!value) return\n\n    await copy(value)\n  }\n\n  return (\n    <InputGroupButton\n      aria-label={\n        copied\n          ? localization.settings.copiedToClipboard\n          : localization.settings.copyToClipboard\n      }\n      title={\n        copied\n          ? localization.settings.copiedToClipboard\n          : localization.settings.copyToClipboard\n      }\n      onClick={handleCopy}\n      disabled={isDisabled}\n    >\n      {copied ? <Check /> : <Copy />}\n    </InputGroupButton>\n  )\n}\n\n/** Renders a single additional user field via shadcn primitives. */\nexport function AdditionalField({\n  name,\n  field: configuredField,\n  value,\n  onBlur,\n  onChange,\n  isInvalid,\n  errors,\n  isPending,\n  optionalLabel\n}: AdditionalFieldProps) {\n  const field =\n    optionalLabel && !configuredField.required\n      ? {\n          ...configuredField,\n          label: (\n            <>\n              {configuredField.label}\n              {optionalLabel}\n            </>\n          )\n        }\n      : configuredField\n  const inputType = resolveInputType(field)\n  const fieldErrors = getFormFieldErrors(errors ?? [])\n\n  if (field.render) {\n    const FieldRenderer = field.render as ComponentType<AdditionalFieldProps>\n    return (\n      <FieldRenderer\n        name={name}\n        field={field}\n        value={value}\n        onBlur={onBlur}\n        onChange={onChange}\n        isInvalid={isInvalid}\n        errors={errors}\n        isPending={isPending}\n        optionalLabel={optionalLabel}\n      />\n    )\n  }\n\n  if (inputType === \"hidden\") {\n    return (\n      <input type=\"hidden\" name={name} value={valueToString(value)} readOnly />\n    )\n  }\n\n  if (inputType === \"textarea\") {\n    return (\n      <Field data-invalid={isInvalid}>\n        <FieldLabel htmlFor={name}>{field.label}</FieldLabel>\n\n        <Textarea\n          id={name}\n          name={name}\n          value={valueToString(value)}\n          onBlur={onBlur}\n          onChange={(event) => onChange(event.target.value || null)}\n          placeholder={field.placeholder}\n          required={field.required}\n          readOnly={field.readOnly}\n          disabled={isPending}\n          aria-invalid={isInvalid}\n        />\n\n        <FieldError errors={fieldErrors} />\n      </Field>\n    )\n  }\n\n  if (inputType === \"number\") {\n    const maxFractionDigits = field.formatOptions?.maximumFractionDigits\n\n    return (\n      <Field data-invalid={isInvalid}>\n        <FieldLabel htmlFor={name}>{field.label}</FieldLabel>\n\n        <Input\n          id={name}\n          name={name}\n          type=\"number\"\n          inputMode={maxFractionDigits ? \"decimal\" : \"numeric\"}\n          min={field.min}\n          max={field.max}\n          step={\n            field.step ??\n            (maxFractionDigits ? 1 / 10 ** maxFractionDigits : undefined)\n          }\n          value={typeof value === \"number\" ? value : \"\"}\n          onBlur={onBlur}\n          onChange={(event) =>\n            onChange(\n              event.target.value === \"\" ? null : event.target.valueAsNumber\n            )\n          }\n          placeholder={field.placeholder}\n          required={field.required}\n          readOnly={field.readOnly}\n          disabled={isPending}\n          aria-invalid={isInvalid}\n        />\n\n        <FieldError errors={fieldErrors} />\n      </Field>\n    )\n  }\n\n  if (inputType === \"slider\") {\n    return (\n      <SliderField\n        name={name}\n        field={field}\n        value={value}\n        onBlur={onBlur}\n        onChange={onChange}\n        isInvalid={isInvalid}\n        errors={errors}\n        isPending={isPending}\n      />\n    )\n  }\n\n  if (inputType === \"switch\") {\n    return (\n      <Field data-invalid={isInvalid} orientation=\"horizontal\">\n        <Switch\n          id={name}\n          name={name}\n          checked={value === true}\n          onBlur={onBlur}\n          onCheckedChange={onChange}\n          disabled={isPending || field.readOnly}\n          aria-invalid={isInvalid}\n        />\n\n        <FieldContent>\n          <FieldLabel htmlFor={name}>{field.label}</FieldLabel>\n        </FieldContent>\n        <FieldError errors={fieldErrors} />\n      </Field>\n    )\n  }\n\n  if (inputType === \"checkbox\") {\n    return (\n      <Field data-invalid={isInvalid} orientation=\"horizontal\">\n        <Checkbox\n          id={name}\n          name={name}\n          checked={value === true}\n          onBlur={onBlur}\n          onCheckedChange={(checked) => onChange(checked === true)}\n          required={field.required}\n          disabled={isPending || field.readOnly}\n          aria-invalid={isInvalid}\n        />\n\n        <FieldContent>\n          <FieldLabel htmlFor={name}>{field.label}</FieldLabel>\n        </FieldContent>\n        <FieldError errors={fieldErrors} />\n      </Field>\n    )\n  }\n\n  if (inputType === \"select\") {\n    return (\n      <Field data-invalid={isInvalid}>\n        <FieldLabel htmlFor={name}>{field.label}</FieldLabel>\n\n        <Select\n          name={name}\n          value={valueToString(value) || undefined}\n          onValueChange={(nextValue) => onChange(nextValue)}\n          required={field.required}\n          disabled={isPending || field.readOnly}\n        >\n          <SelectTrigger\n            id={name}\n            className=\"w-full\"\n            onBlur={onBlur}\n            aria-invalid={isInvalid}\n          >\n            <SelectValue placeholder={field.placeholder} />\n          </SelectTrigger>\n\n          <SelectContent>\n            {field.options?.map((option) => (\n              <SelectItem key={option.value} value={option.value}>\n                {option.label}\n              </SelectItem>\n            ))}\n          </SelectContent>\n        </Select>\n\n        <FieldError errors={fieldErrors} />\n      </Field>\n    )\n  }\n\n  if (inputType === \"combobox\") {\n    const selectedOption = field.options?.find(\n      (option) => option.value === valueToString(value)\n    )\n\n    return (\n      <Field data-invalid={isInvalid}>\n        <FieldLabel htmlFor={name}>{field.label}</FieldLabel>\n\n        <Combobox\n          items={field.options ?? []}\n          name={name}\n          value={selectedOption ?? null}\n          onValueChange={(option) => onChange(option?.value ?? null)}\n          required={field.required}\n          disabled={isPending || field.readOnly}\n        >\n          <ComboboxInput\n            placeholder={field.placeholder}\n            id={name}\n            onBlur={onBlur}\n            aria-invalid={isInvalid}\n          />\n\n          <ComboboxContent>\n            <ComboboxEmpty>No items found.</ComboboxEmpty>\n\n            <ComboboxList>\n              {(option) => (\n                <ComboboxItem key={option.value} value={option}>\n                  {option.label}\n                </ComboboxItem>\n              )}\n            </ComboboxList>\n          </ComboboxContent>\n        </Combobox>\n\n        <FieldError errors={fieldErrors} />\n      </Field>\n    )\n  }\n\n  if (inputType === \"date\" || inputType === \"datetime\") {\n    return (\n      <DateInput\n        name={name}\n        field={field}\n        value={value}\n        onBlur={onBlur}\n        onChange={onChange}\n        isInvalid={isInvalid}\n        errors={errors}\n        isPending={isPending}\n      />\n    )\n  }\n\n  return (\n    <InputField\n      name={name}\n      field={field}\n      value={value}\n      onBlur={onBlur}\n      onChange={onChange}\n      isInvalid={isInvalid}\n      errors={errors}\n      isPending={isPending}\n    />\n  )\n}\n\nfunction InputField({\n  name,\n  field,\n  value,\n  onBlur,\n  onChange,\n  isInvalid,\n  errors,\n  isPending\n}: AdditionalFieldProps) {\n  const inputRef = useRef<HTMLInputElement>(null)\n  const fieldErrors = getFormFieldErrors(errors ?? [])\n\n  const hasPrefix = field.prefix != null\n  const hasSuffix = field.suffix != null || field.copyable\n\n  const isNumeric = field.type === \"number\"\n  const maxFractionDigits = field.formatOptions?.maximumFractionDigits\n  const nativeInputType = isNumeric ? \"number\" : undefined\n  const nativeInputMode = isNumeric\n    ? maxFractionDigits\n      ? \"decimal\"\n      : \"numeric\"\n    : undefined\n  const nativeStep = maxFractionDigits ? 1 / 10 ** maxFractionDigits : undefined\n\n  if (hasPrefix || hasSuffix) {\n    return (\n      <Field data-invalid={isInvalid}>\n        <FieldLabel htmlFor={name}>{field.label}</FieldLabel>\n\n        <InputGroup>\n          {hasPrefix && (\n            <InputGroupAddon align=\"inline-start\">\n              {field.prefix}\n            </InputGroupAddon>\n          )}\n\n          <InputGroupInput\n            ref={inputRef}\n            id={name}\n            name={name}\n            type={nativeInputType}\n            inputMode={nativeInputMode}\n            step={nativeStep}\n            value={valueToString(value)}\n            onBlur={onBlur}\n            onChange={(event) => onChange(event.target.value || null)}\n            placeholder={field.placeholder}\n            required={field.required}\n            readOnly={field.readOnly}\n            disabled={isPending}\n            aria-invalid={isInvalid}\n          />\n\n          {field.copyable ? (\n            <InputGroupAddon align=\"inline-end\">\n              <CopyButton\n                getValue={() => inputRef.current?.value}\n                isDisabled={isPending}\n              />\n            </InputGroupAddon>\n          ) : (\n            field.suffix != null && (\n              <InputGroupAddon align=\"inline-end\">\n                {field.suffix}\n              </InputGroupAddon>\n            )\n          )}\n        </InputGroup>\n\n        <FieldError errors={fieldErrors} />\n      </Field>\n    )\n  }\n\n  return (\n    <Field data-invalid={isInvalid}>\n      <FieldLabel htmlFor={name}>{field.label}</FieldLabel>\n\n      <Input\n        id={name}\n        name={name}\n        type={nativeInputType}\n        inputMode={nativeInputMode}\n        step={nativeStep}\n        value={valueToString(value)}\n        onBlur={onBlur}\n        onChange={(event) => onChange(event.target.value || null)}\n        placeholder={field.placeholder}\n        required={field.required}\n        readOnly={field.readOnly}\n        disabled={isPending}\n        aria-invalid={isInvalid}\n      />\n\n      <FieldError errors={fieldErrors} />\n    </Field>\n  )\n}\n\n/**\n * Slider field. Radix Slider doesn't render the current value, so we render\n * it next to the label and control the state to keep the displayed value in\n * sync. The selected value is submitted via the underlying Radix `name` prop.\n */\nfunction SliderField({\n  name,\n  field,\n  value,\n  onBlur,\n  onChange,\n  isInvalid,\n  errors,\n  isPending\n}: AdditionalFieldProps) {\n  const maxFractionDigits = field.formatOptions?.maximumFractionDigits\n  const min = field.min ?? 0\n  const max = field.max ?? 100\n  const step =\n    field.step ?? (maxFractionDigits ? 1 / 10 ** maxFractionDigits : 1)\n  const numericValue = typeof value === \"number\" ? value : min\n  const fieldErrors = getFormFieldErrors(errors ?? [])\n\n  const formatter = new Intl.NumberFormat(undefined, field.formatOptions)\n\n  return (\n    <Field data-invalid={isInvalid}>\n      <div className=\"flex items-center justify-between gap-2\">\n        <FieldLabel htmlFor={name}>{field.label}</FieldLabel>\n        <span className=\"text-sm text-muted-foreground tabular-nums\">\n          {formatter.format(numericValue)}\n        </span>\n      </div>\n\n      <Slider\n        id={name}\n        name={name}\n        value={[numericValue]}\n        onBlur={onBlur}\n        onValueChange={(nextValue) =>\n          onChange((Array.isArray(nextValue) ? nextValue[0] : nextValue) ?? min)\n        }\n        min={min}\n        max={max}\n        step={step}\n        disabled={isPending || field.readOnly}\n        aria-invalid={isInvalid}\n      />\n\n      <FieldError errors={fieldErrors} />\n    </Field>\n  )\n}\n\n/**\n * Date / datetime input. Composes `Popover` + `Calendar` for the date and\n * (optionally) `<input type=\"time\">` for the time. Submits the combined ISO\n * value via a hidden `<input>` so it shows up in `FormData`.\n */\nfunction DateInput({\n  name,\n  field,\n  value,\n  onBlur,\n  onChange,\n  isInvalid,\n  errors,\n  isPending\n}: AdditionalFieldProps) {\n  const { localization } = useAuth()\n  const inputType = resolveInputType(field)\n  const isDateTime = inputType === \"datetime\"\n  const fieldErrors = getFormFieldErrors(errors ?? [])\n\n  const date = toDate(value)\n  const [time, setTime] = useState<string>(\n    isDateTime && date ? formatTime(date) : \"\"\n  )\n  const [open, setOpen] = useState(false)\n\n  // Compose the hidden form value: ISO date for \"date\", ISO datetime for\n  // \"datetime\" (date + time).\n  return (\n    <Field data-invalid={isInvalid}>\n      <FieldLabel htmlFor={`${name}-date`}>{field.label}</FieldLabel>\n\n      <div className=\"relative flex gap-2\">\n        <Popover open={open} onOpenChange={setOpen}>\n          <PopoverTrigger\n            type=\"button\"\n            id={`${name}-date`}\n            data-empty={!date}\n            aria-invalid={isInvalid}\n            aria-required={field.required}\n            onBlur={onBlur}\n            disabled={isPending || field.readOnly}\n            className={cn(\n              buttonVariants({ variant: \"outline\" }),\n              \"flex-1 justify-between font-normal\",\n              \"data-[empty=true]:text-muted-foreground\"\n            )}\n          >\n            {date ? format(date, \"PPP\") : <span>{field.placeholder}</span>}\n\n            {isDateTime ? <ChevronDownIcon /> : <CalendarIcon />}\n          </PopoverTrigger>\n\n          <PopoverContent className=\"w-auto overflow-hidden p-0\" align=\"start\">\n            <Calendar\n              mode=\"single\"\n              selected={date}\n              defaultMonth={date}\n              captionLayout=\"dropdown\"\n              onSelect={(value) => {\n                if (!value) {\n                  onChange(null)\n                } else {\n                  const nextValue = new Date(value)\n                  if (isDateTime && time.trim()) {\n                    const [hours = \"0\", minutes = \"0\", seconds = \"0\"] =\n                      time.split(\":\")\n                    nextValue.setHours(\n                      Number(hours),\n                      Number(minutes),\n                      Number(seconds),\n                      0\n                    )\n                  } else {\n                    nextValue.setHours(0, 0, 0, 0)\n                  }\n                  onChange(nextValue)\n                }\n                if (!isDateTime) setOpen(false)\n              }}\n            />\n          </PopoverContent>\n        </Popover>\n\n        {isDateTime && (\n          <Field className=\"w-32\">\n            <FieldLabel htmlFor={`${name}-time`} className=\"sr-only\">\n              {localization.settings.time}\n            </FieldLabel>\n\n            <Input\n              type=\"time\"\n              id={`${name}-time`}\n              step=\"1\"\n              value={time}\n              onChange={(event) => {\n                const nextTime = event.target.value\n                setTime(nextTime)\n                if (!date) return\n                const nextValue = new Date(date)\n                const [hours = \"0\", minutes = \"0\", seconds = \"0\"] =\n                  nextTime.split(\":\")\n                nextValue.setHours(\n                  Number(hours),\n                  Number(minutes),\n                  Number(seconds),\n                  0\n                )\n                onChange(nextValue)\n              }}\n              disabled={isPending || field.readOnly}\n              className=\"appearance-none bg-background [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none\"\n            />\n          </Field>\n        )}\n      </div>\n\n      <FieldError errors={fieldErrors} />\n    </Field>\n  )\n}\n",
      "type": "registry:component",
      "target": "@components/auth/additional-field.tsx"
    },
    {
      "path": "examples/start-shadcn-example/src/components/auth/admin/admin-table.ts",
      "content": "\"use client\"\n\nimport {\n  columnFilteringFeature,\n  createTableHook,\n  globalFilteringFeature,\n  rowPaginationFeature,\n  rowSortingFeature,\n  tableFeatures\n} from \"@tanstack/react-table\"\n\nexport const {\n  createAppColumnHelper: createAdminColumnHelper,\n  useAppTable: useAdminTable\n} = createTableHook({\n  enableMultiSort: false,\n  enableSortingRemoval: false,\n  sortDescFirst: false,\n  features: tableFeatures({\n    columnFilteringFeature,\n    globalFilteringFeature,\n    rowPaginationFeature,\n    rowSortingFeature\n  })\n})\n",
      "type": "registry:component",
      "target": "@components/auth/admin/admin-table.ts"
    },
    {
      "path": "examples/start-shadcn-example/src/components/auth/admin/admin-users.tsx",
      "content": "\"use client\"\n\nimport {\n  DEFAULT_TABLE_SEARCH_DEBOUNCE_MS,\n  fieldsWithModelValues,\n  getAdditionalFieldDefaultValues,\n  getAdditionalFieldSubmitValues,\n  getClampedTablePageIndex\n} from \"@better-auth-ui/core\"\nimport {\n  type AdminAuthClient,\n  type AdminListUsersParams,\n  type AdminUser,\n  banAdminUserOptions,\n  createAdminUserOptions,\n  impersonateAdminUserOptions,\n  isAdminTarget,\n  removeAdminUserOptions,\n  revokeAdminUserSessionOptions,\n  revokeAdminUserSessionsOptions,\n  setAdminUserPasswordOptions,\n  setAdminUserRoleOptions,\n  unbanAdminUserOptions,\n  updateAdminUserOptions\n} from \"@better-auth-ui/core/plugins/admin\"\nimport {\n  useAuth,\n  useAuthPlugin,\n  useCopyToClipboard,\n  useSession\n} from \"@better-auth-ui/react\"\nimport {\n  useAdminPermission,\n  useAdminUser,\n  useAdminUserSessions,\n  useAdminUsers\n} from \"@better-auth-ui/react/plugins/admin\"\nimport { useDebouncedValue } from \"@tanstack/react-pacer\"\nimport { keepPreviousData, useMutation } from \"@tanstack/react-query\"\nimport type { SortingState } from \"@tanstack/react-table\"\nimport type { BetterFetchError } from \"better-auth/react\"\nimport {\n  BanIcon,\n  CheckIcon,\n  ChevronLeftIcon,\n  ChevronRightIcon,\n  CopyIcon,\n  EllipsisIcon,\n  KeyRoundIcon,\n  LogInIcon,\n  Monitor,\n  SearchIcon,\n  ShieldAlertIcon,\n  Trash2Icon,\n  UserPlusIcon,\n  UserRound\n} from \"lucide-react\"\nimport { type FormEvent, useEffect, useMemo, useState } from \"react\"\nimport { UserAvatar } from \"@/components/auth/user/user-avatar\"\nimport {\n  AlertDialog,\n  AlertDialogAction,\n  AlertDialogCancel,\n  AlertDialogContent,\n  AlertDialogDescription,\n  AlertDialogFooter,\n  AlertDialogHeader,\n  AlertDialogTitle\n} from \"@/components/ui/alert-dialog\"\nimport { Badge } from \"@/components/ui/badge\"\nimport { Button } from \"@/components/ui/button\"\nimport { Checkbox } from \"@/components/ui/checkbox\"\nimport {\n  Dialog,\n  DialogContent,\n  DialogDescription,\n  DialogFooter,\n  DialogHeader,\n  DialogTitle\n} from \"@/components/ui/dialog\"\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuGroup,\n  DropdownMenuItem,\n  DropdownMenuTrigger\n} from \"@/components/ui/dropdown-menu\"\nimport {\n  Field,\n  FieldContent,\n  FieldError,\n  FieldGroup,\n  FieldLabel,\n  FieldLegend,\n  FieldSet\n} from \"@/components/ui/field\"\nimport {\n  InputGroup,\n  InputGroupAddon,\n  InputGroupInput\n} from \"@/components/ui/input-group\"\nimport { RadioGroup, RadioGroupItem } from \"@/components/ui/radio-group\"\nimport {\n  Select,\n  SelectContent,\n  SelectItem,\n  SelectTrigger,\n  SelectValue\n} from \"@/components/ui/select\"\nimport { Separator } from \"@/components/ui/separator\"\nimport { Skeleton } from \"@/components/ui/skeleton\"\nimport { Switch } from \"@/components/ui/switch\"\nimport {\n  Table,\n  TableBody,\n  TableCell,\n  TableHead,\n  TableHeader,\n  TableRow\n} from \"@/components/ui/table\"\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from \"@/components/ui/tabs\"\nimport { adminPlugin } from \"@/lib/auth/admin-plugin\"\nimport { getAuthAdditionalFieldValidators, useAuthForm } from \"../auth-form\"\nimport { useServerTableState } from \"../server-table-state\"\n\nimport { createAdminColumnHelper, useAdminTable } from \"./admin-table\"\n\ntype SearchField = \"email\" | \"name\"\ntype SearchOperator = \"contains\" | \"ends_with\" | \"starts_with\"\ntype StatusFilter = \"all\" | \"active\" | \"banned\"\ntype DangerousAction = \"ban\" | \"delete\" | \"impersonate\" | \"revokeAll\"\n\nexport type AdminUsersProps = {\n  className?: string\n  onSelectedUserIdChange?: (userId: string | undefined) => void\n  selectedUserId?: string\n}\n\nconst formatDate = (value: Date | string | undefined | null) =>\n  value\n    ? new Intl.DateTimeFormat(undefined, { dateStyle: \"medium\" }).format(\n        new Date(value)\n      )\n    : \"–\"\n\nconst asAdminRoles = (roles: string[]) => roles as (\"user\" | \"admin\")[]\n\nconst parseAdminRoles = (\n  role: string | undefined,\n  fallback: string,\n  allowMultipleRoles: boolean\n) => {\n  const roles = role\n    ?.split(\",\")\n    .map((value) => value.trim())\n    .filter(Boolean)\n  const resolved = roles?.length ? roles : [fallback]\n  return allowMultipleRoles ? resolved : resolved.slice(0, 1)\n}\n\nconst getBanDurationSeconds = (value: string) => {\n  if (!value) return undefined\n  const days = Number(value)\n  if (!Number.isSafeInteger(days) || days <= 0) return null\n  const seconds = days * 86_400\n  return Number.isSafeInteger(seconds) ? seconds : null\n}\n\nconst getAdminErrorMessage = (error: Error | null) => {\n  const authError = error as BetterFetchError | null\n  return authError?.error?.message ?? authError?.message\n}\n\nconst adminColumnHelper = createAdminColumnHelper<AdminUser>()\nconst adminColumns = adminColumnHelper.columns([\n  adminColumnHelper.accessor(\"name\", { id: \"name\" }),\n  adminColumnHelper.accessor(\"role\", {\n    id: \"role\",\n    enableSorting: false\n  }),\n  adminColumnHelper.accessor(\"banned\", {\n    id: \"status\",\n    enableSorting: false\n  }),\n  adminColumnHelper.accessor((user) => new Date(user.createdAt).getTime(), {\n    id: \"createdAt\"\n  })\n])\nconst EMPTY_USERS: AdminUser[] = []\nconst INITIAL_ADMIN_SORTING: SortingState = [{ id: \"createdAt\", desc: true }]\n\n/** Server-paginated user management with optional controlled inspector state. */\nexport function AdminUsers({\n  className,\n  onSelectedUserIdChange,\n  selectedUserId: controlledSelectedUserId\n}: AdminUsersProps) {\n  const auth = useAuth<AdminAuthClient>()\n  const config = useAuthPlugin(adminPlugin)\n  const { localization } = config\n  const [localSelectedUserId, setLocalSelectedUserId] = useState<string>()\n  const tableState = useServerTableState({\n    initialSorting: INITIAL_ADMIN_SORTING,\n    pageSize: config.pageSize\n  })\n  const { columnFilters, globalFilter, pagination, setPagination, sorting } =\n    tableState\n  const [searchField, setSearchField] = useState<SearchField>(\"email\")\n  const [searchOperator, setSearchOperator] =\n    useState<SearchOperator>(\"contains\")\n  const [createOpen, setCreateOpen] = useState(false)\n  const [debouncedSearch] = useDebouncedValue(globalFilter.trim(), {\n    wait: DEFAULT_TABLE_SEARCH_DEBOUNCE_MS\n  })\n  const status = String(\n    columnFilters.find((filter) => filter.id === \"status\")?.value ?? \"all\"\n  ) as StatusFilter\n  const primarySort = sorting[0]\n  const sortBy = primarySort?.id === \"name\" ? \"name\" : \"createdAt\"\n  const sortDirection = primarySort?.desc ? \"desc\" : \"asc\"\n  const isSelectionControlled = onSelectedUserIdChange !== undefined\n  const selectedUserId = isSelectionControlled\n    ? controlledSelectedUserId\n    : localSelectedUserId\n\n  const setSelectedUserId = (userId: string | undefined) => {\n    if (!isSelectionControlled) setLocalSelectedUserId(userId)\n    onSelectedUserIdChange?.(userId)\n  }\n\n  const params = useMemo<AdminListUsersParams>(\n    () => ({\n      limit: pagination.pageSize,\n      offset: pagination.pageIndex * pagination.pageSize,\n      searchField,\n      searchOperator,\n      searchValue: debouncedSearch || undefined,\n      sortBy,\n      sortDirection,\n      ...(status === \"all\"\n        ? {}\n        : {\n            filterField: \"banned\",\n            filterOperator: \"eq\" as const,\n            filterValue: status === \"banned\"\n          })\n    }),\n    [\n      debouncedSearch,\n      pagination.pageIndex,\n      pagination.pageSize,\n      searchField,\n      searchOperator,\n      sortBy,\n      sortDirection,\n      status\n    ]\n  )\n  const permission = useAdminPermission(auth.authClient, { user: [\"list\"] })\n  const users = useAdminUsers(auth.authClient, {\n    enabled: permission.data?.success === true,\n    params,\n    placeholderData: keepPreviousData\n  })\n  const canCreate = useAdminPermission(auth.authClient, { user: [\"create\"] })\n  const canGet = useAdminPermission(auth.authClient, { user: [\"get\"] })\n\n  const total = users.data?.total ?? 0\n\n  useEffect(() => {\n    if (!users.isSuccess) return\n    const pageIndex = getClampedTablePageIndex(\n      pagination.pageIndex,\n      pagination.pageSize,\n      total\n    )\n    if (pageIndex !== pagination.pageIndex) {\n      setPagination((current) => ({ ...current, pageIndex }))\n    }\n  }, [\n    pagination.pageIndex,\n    pagination.pageSize,\n    setPagination,\n    total,\n    users.isSuccess\n  ])\n  const table = useAdminTable(\n    {\n      atoms: tableState.atoms,\n      columns: adminColumns,\n      data: users.data?.users ?? EMPTY_USERS,\n      getRowId: (user) => user.id,\n      manualFiltering: true,\n      manualPagination: true,\n      manualSorting: true,\n      rowCount: total\n    },\n    () => null\n  )\n  const from = total ? pagination.pageIndex * pagination.pageSize + 1 : 0\n  const to = Math.min(total, (pagination.pageIndex + 1) * pagination.pageSize)\n\n  return (\n    <section className={className}>\n      <div className=\"flex flex-col gap-4\">\n        <div className=\"flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between\">\n          <div className=\"flex flex-col gap-1\">\n            <h1 className=\"text-xl font-semibold tracking-tight\">\n              {localization.users}\n            </h1>\n            <p className=\"text-sm text-muted-foreground\">\n              {localization.usersDescription}\n            </p>\n          </div>\n          {canCreate.isPending ? (\n            <Skeleton className=\"h-8 w-28\" />\n          ) : canCreate.data?.success ? (\n            <Button onClick={() => setCreateOpen(true)}>\n              <UserPlusIcon />\n              {localization.createUser}\n            </Button>\n          ) : null}\n        </div>\n\n        <div className=\"grid gap-2 sm:grid-cols-2 lg:grid-cols-[9rem_10rem_minmax(14rem,1fr)_10rem]\">\n          <Select\n            value={searchField}\n            onValueChange={(value) => {\n              setSearchField(value as SearchField)\n              table.setPageIndex(0)\n            }}\n          >\n            <SelectTrigger\n              aria-label={localization.search}\n              className=\"w-full sm:w-36\"\n            >\n              <SelectValue />\n            </SelectTrigger>\n            <SelectContent>\n              <SelectItem value=\"email\">{localization.email}</SelectItem>\n              <SelectItem value=\"name\">{localization.name}</SelectItem>\n            </SelectContent>\n          </Select>\n          <Select\n            value={searchOperator}\n            onValueChange={(value) => {\n              setSearchOperator(value as SearchOperator)\n              table.setPageIndex(0)\n            }}\n          >\n            <SelectTrigger aria-label={localization.searchOperator}>\n              <SelectValue />\n            </SelectTrigger>\n            <SelectContent>\n              <SelectItem value=\"contains\">\n                {localization.searchContains}\n              </SelectItem>\n              <SelectItem value=\"starts_with\">\n                {localization.startsWith}\n              </SelectItem>\n              <SelectItem value=\"ends_with\">{localization.endsWith}</SelectItem>\n            </SelectContent>\n          </Select>\n          <InputGroup>\n            <InputGroupAddon>\n              <SearchIcon />\n            </InputGroupAddon>\n            <InputGroupInput\n              aria-label={\n                searchField === \"email\"\n                  ? localization.searchByEmail\n                  : localization.searchByName\n              }\n              onChange={(event) => {\n                table.setGlobalFilter(event.target.value)\n              }}\n              placeholder={\n                searchField === \"email\"\n                  ? localization.searchByEmail\n                  : localization.searchByName\n              }\n              value={globalFilter}\n            />\n          </InputGroup>\n          <Select\n            value={status}\n            onValueChange={(value) => {\n              table\n                .getColumn(\"status\")\n                ?.setFilterValue(value === \"all\" ? undefined : value)\n            }}\n          >\n            <SelectTrigger\n              aria-label={localization.status}\n              className=\"w-full sm:w-36\"\n            >\n              <SelectValue />\n            </SelectTrigger>\n            <SelectContent>\n              <SelectItem value=\"all\">\n                {localization.filterAllStatuses}\n              </SelectItem>\n              <SelectItem value=\"active\">{localization.active}</SelectItem>\n              <SelectItem value=\"banned\">{localization.banned}</SelectItem>\n            </SelectContent>\n          </Select>\n        </div>\n\n        {permission.isPending ? (\n          <UserTableSkeleton />\n        ) : !permission.data?.success ? (\n          <AdminState\n            icon={<ShieldAlertIcon />}\n            title={localization.accessDenied}\n            description={localization.accessDeniedDescription}\n          />\n        ) : users.isError ? (\n          <AdminState\n            icon={<ShieldAlertIcon />}\n            title={localization.loadUsersError}\n            description={localization.loadUsersErrorDescription}\n            action={\n              <Button variant=\"outline\" onClick={() => users.refetch()}>\n                {localization.retry}\n              </Button>\n            }\n          />\n        ) : (\n          <div className=\"overflow-hidden rounded-lg border\">\n            <Table>\n              <TableHeader>\n                <TableRow>\n                  <TableHead>\n                    <SortButton\n                      onClick={table\n                        .getColumn(\"name\")\n                        ?.getToggleSortingHandler()}\n                      sorted={table.getColumn(\"name\")?.getIsSorted() ?? false}\n                    >\n                      {localization.name}\n                    </SortButton>\n                  </TableHead>\n                  <TableHead className=\"hidden md:table-cell\">\n                    {localization.role}\n                  </TableHead>\n                  <TableHead>{localization.status}</TableHead>\n                  <TableHead className=\"hidden lg:table-cell\">\n                    <SortButton\n                      onClick={table\n                        .getColumn(\"createdAt\")\n                        ?.getToggleSortingHandler()}\n                      sorted={\n                        table.getColumn(\"createdAt\")?.getIsSorted() ?? false\n                      }\n                    >\n                      {localization.created}\n                    </SortButton>\n                  </TableHead>\n                </TableRow>\n              </TableHeader>\n              <TableBody>\n                {users.isPending ? (\n                  <UserRowsSkeleton />\n                ) : table.getRowModel().rows.length ? (\n                  table.getRowModel().rows.map((row) => {\n                    const user = row.original\n                    return (\n                      <TableRow\n                        key={row.id}\n                        aria-selected={selectedUserId === user.id}\n                        className={\n                          canGet.data?.success ? \"cursor-pointer\" : undefined\n                        }\n                        onClick={\n                          canGet.data?.success\n                            ? () => setSelectedUserId(user.id)\n                            : undefined\n                        }\n                      >\n                        <TableCell>\n                          <div className=\"flex items-center gap-3\">\n                            <UserAvatar className=\"size-8\" user={user} />\n                            <div className=\"min-w-0\">\n                              {canGet.data?.success ? (\n                                <Button\n                                  className=\"h-auto min-w-0 justify-start p-0 font-medium\"\n                                  onClick={(event) => {\n                                    event.stopPropagation()\n                                    setSelectedUserId(user.id)\n                                  }}\n                                  variant=\"link\"\n                                >\n                                  <span className=\"truncate\">{user.name}</span>\n                                </Button>\n                              ) : (\n                                <span className=\"truncate\">{user.name}</span>\n                              )}\n                              <div className=\"truncate text-xs text-muted-foreground\">\n                                {user.email}\n                              </div>\n                            </div>\n                          </div>\n                        </TableCell>\n                        <TableCell className=\"hidden md:table-cell\">\n                          <Badge variant=\"outline\">\n                            {user.role ?? config.defaultRole}\n                          </Badge>\n                        </TableCell>\n                        <TableCell>\n                          <Badge\n                            variant={user.banned ? \"destructive\" : \"secondary\"}\n                          >\n                            {user.banned\n                              ? localization.banned\n                              : localization.active}\n                          </Badge>\n                        </TableCell>\n                        <TableCell className=\"hidden text-muted-foreground lg:table-cell\">\n                          {formatDate(user.createdAt)}\n                        </TableCell>\n                      </TableRow>\n                    )\n                  })\n                ) : (\n                  <TableRow>\n                    <TableCell colSpan={4} className=\"h-40 text-center\">\n                      <strong className=\"block font-medium\">\n                        {localization.noUsers}\n                      </strong>\n                      <span className=\"text-muted-foreground\">\n                        {localization.noUsersDescription}\n                      </span>\n                    </TableCell>\n                  </TableRow>\n                )}\n              </TableBody>\n            </Table>\n          </div>\n        )}\n\n        <div className=\"flex items-center justify-between gap-3 text-sm text-muted-foreground\">\n          <span>\n            {localization.usersPaginationRange\n              .replace(\"{{from}}\", String(from))\n              .replace(\"{{to}}\", String(to))\n              .replace(\"{{total}}\", String(total))}\n          </span>\n          <div className=\"flex gap-1\">\n            <Button\n              aria-label={localization.previousPage}\n              disabled={!table.getCanPreviousPage() || users.isFetching}\n              onClick={() => table.previousPage()}\n              size=\"icon-sm\"\n              variant=\"outline\"\n            >\n              <ChevronLeftIcon />\n            </Button>\n            <Button\n              aria-label={localization.nextPage}\n              disabled={!table.getCanNextPage() || users.isFetching}\n              onClick={() => table.nextPage()}\n              size=\"icon-sm\"\n              variant=\"outline\"\n            >\n              <ChevronRightIcon />\n            </Button>\n          </div>\n        </div>\n      </div>\n\n      <CreateUserDialog open={createOpen} onOpenChange={setCreateOpen} />\n      <UserInspector\n        canGetUser={canGet.data?.success === true}\n        open={Boolean(selectedUserId) && canGet.data?.success === true}\n        onOpenChange={(open) => !open && setSelectedUserId(undefined)}\n        userId={selectedUserId}\n      />\n    </section>\n  )\n}\n\nfunction SortButton({\n  children,\n  onClick,\n  sorted\n}: {\n  children: React.ReactNode\n  onClick?: (event: unknown) => void\n  sorted: false | \"asc\" | \"desc\"\n}) {\n  return (\n    <button\n      className=\"inline-flex items-center gap-1 hover:text-foreground\"\n      onClick={onClick}\n      type=\"button\"\n    >\n      {children}\n      {sorted ? (sorted === \"asc\" ? \"↑\" : \"↓\") : null}\n    </button>\n  )\n}\n\nfunction AdminState({\n  action,\n  description,\n  icon,\n  title\n}: {\n  action?: React.ReactNode\n  description: string\n  icon: React.ReactNode\n  title: string\n}) {\n  return (\n    <div className=\"flex min-h-64 flex-col items-center justify-center gap-3 rounded-lg border border-dashed p-8 text-center\">\n      <span className=\"text-muted-foreground [&>svg]:size-8\">{icon}</span>\n      <div className=\"flex flex-col gap-1\">\n        <h2 className=\"font-medium\">{title}</h2>\n        <p className=\"max-w-md text-sm text-muted-foreground\">{description}</p>\n      </div>\n      {action}\n    </div>\n  )\n}\n\nconst skeletonRowIds = [\n  \"admin-row-1\",\n  \"admin-row-2\",\n  \"admin-row-3\",\n  \"admin-row-4\",\n  \"admin-row-5\"\n]\n\nfunction UserRowsSkeleton() {\n  return skeletonRowIds.map((id) => (\n    <TableRow key={id}>\n      <TableCell>\n        <div className=\"flex items-center gap-3\">\n          <Skeleton className=\"size-8 rounded-full\" />\n          <div className=\"flex flex-col gap-1\">\n            <Skeleton className=\"h-4 w-32\" />\n            <Skeleton className=\"h-3 w-48\" />\n          </div>\n        </div>\n      </TableCell>\n      <TableCell className=\"hidden md:table-cell\">\n        <Skeleton className=\"h-5 w-16\" />\n      </TableCell>\n      <TableCell>\n        <Skeleton className=\"h-5 w-16\" />\n      </TableCell>\n      <TableCell className=\"hidden lg:table-cell\">\n        <Skeleton className=\"h-4 w-24\" />\n      </TableCell>\n    </TableRow>\n  ))\n}\n\nfunction UserTableSkeleton() {\n  return (\n    <div className=\"overflow-hidden rounded-lg border\">\n      <Table>\n        <TableBody>\n          <UserRowsSkeleton />\n        </TableBody>\n      </Table>\n    </div>\n  )\n}\n\nfunction CreateUserDialog({\n  open,\n  onOpenChange\n}: {\n  open: boolean\n  onOpenChange: (open: boolean) => void\n}) {\n  const auth = useAuth<AdminAuthClient>()\n  const config = useAuthPlugin(adminPlugin)\n  const { data: session } = useSession(auth.authClient)\n  const createUser = useMutation(\n    createAdminUserOptions(auth.authClient, session?.user.id)\n  )\n  const canSetRole = useAdminPermission(auth.authClient, {\n    user: [\"set-role\"]\n  })\n  const additionalFields = auth.additionalFields ?? []\n  const form = useAuthForm({\n    defaultValues: {\n      additionalFields: getAdditionalFieldDefaultValues(additionalFields),\n      email: \"\",\n      emailVerified: false,\n      name: \"\",\n      password: \"\",\n      roles: [config.defaultRole]\n    },\n    onSubmit: async ({ value }) => {\n      try {\n        await createUser.mutateAsync(\n          {\n            data: {\n              ...getAdditionalFieldSubmitValues(\n                additionalFields,\n                value.additionalFields\n              ),\n              emailVerified: value.emailVerified\n            },\n            email: value.email,\n            name: value.name,\n            password: value.password,\n            ...(canSetRole.data?.success\n              ? { role: asAdminRoles(value.roles) }\n              : {})\n          },\n          { onSuccess: close }\n        )\n      } catch {\n        // The mutation reports the error through its configured handler.\n      }\n    }\n  })\n\n  useEffect(() => {\n    if (!config.allowMultipleRoles)\n      form.setFieldValue(\"roles\", (current) => current.slice(0, 1))\n  }, [config.allowMultipleRoles, form.setFieldValue])\n\n  const close = () => {\n    form.reset()\n    createUser.reset()\n    onOpenChange(false)\n  }\n\n  return (\n    <Dialog\n      open={open}\n      onOpenChange={(value) => (value ? onOpenChange(true) : close())}\n    >\n      <DialogContent>\n        <form.AppForm>\n          <form.AuthFormRoot className=\"flex flex-col gap-4\">\n            <DialogHeader>\n              <DialogTitle>{config.localization.createUser}</DialogTitle>\n              <DialogDescription>\n                {config.localization.usersDescription}\n              </DialogDescription>\n            </DialogHeader>\n            <FieldGroup>\n              <form.Field name=\"name\">\n                {(field) => (\n                  <Field>\n                    <FieldLabel htmlFor=\"admin-create-name\">\n                      {config.localization.name}\n                    </FieldLabel>\n                    <InputGroup>\n                      <InputGroupInput\n                        id=\"admin-create-name\"\n                        name={field.name}\n                        onChange={(event) =>\n                          field.handleChange(event.target.value)\n                        }\n                        required\n                        value={field.state.value}\n                      />\n                    </InputGroup>\n                  </Field>\n                )}\n              </form.Field>\n              <form.Field name=\"email\">\n                {(field) => (\n                  <Field>\n                    <FieldLabel htmlFor=\"admin-create-email\">\n                      {config.localization.email}\n                    </FieldLabel>\n                    <InputGroup>\n                      <InputGroupInput\n                        autoComplete=\"off\"\n                        id=\"admin-create-email\"\n                        name={field.name}\n                        onChange={(event) =>\n                          field.handleChange(event.target.value)\n                        }\n                        required\n                        type=\"email\"\n                        value={field.state.value}\n                      />\n                    </InputGroup>\n                  </Field>\n                )}\n              </form.Field>\n              <form.Field name=\"password\">\n                {(field) => (\n                  <Field>\n                    <FieldLabel htmlFor=\"admin-create-password\">\n                      {config.localization.password}\n                    </FieldLabel>\n                    <InputGroup>\n                      <InputGroupInput\n                        autoComplete=\"new-password\"\n                        id=\"admin-create-password\"\n                        name={field.name}\n                        onChange={(event) =>\n                          field.handleChange(event.target.value)\n                        }\n                        required\n                        type=\"password\"\n                        value={field.state.value}\n                      />\n                    </InputGroup>\n                  </Field>\n                )}\n              </form.Field>\n              {canSetRole.isPending ? (\n                <Skeleton className=\"h-16 w-full\" />\n              ) : canSetRole.data?.success ? (\n                <FieldSet>\n                  <FieldLegend variant=\"label\">\n                    {config.localization.role}\n                  </FieldLegend>\n                  <form.Field name=\"roles\">\n                    {(field) =>\n                      config.allowMultipleRoles ? (\n                        <FieldGroup data-slot=\"checkbox-group\">\n                          {config.roles.map((role) => (\n                            <Field key={role} orientation=\"horizontal\">\n                              <Checkbox\n                                checked={field.state.value.includes(role)}\n                                id={`admin-create-role-${role}`}\n                                onCheckedChange={(checked) => {\n                                  const next = checked\n                                    ? [...field.state.value, role]\n                                    : field.state.value.filter(\n                                        (item) => item !== role\n                                      )\n                                  if (next.length) field.handleChange(next)\n                                }}\n                              />\n                              <FieldLabel htmlFor={`admin-create-role-${role}`}>\n                                {role}\n                              </FieldLabel>\n                            </Field>\n                          ))}\n                        </FieldGroup>\n                      ) : (\n                        <RadioGroup\n                          onValueChange={(role) => field.handleChange([role])}\n                          value={field.state.value[0] ?? \"\"}\n                        >\n                          {config.roles.map((role) => (\n                            <Field key={role} orientation=\"horizontal\">\n                              <RadioGroupItem\n                                id={`admin-create-role-${role}`}\n                                value={role}\n                              />\n                              <FieldLabel htmlFor={`admin-create-role-${role}`}>\n                                {role}\n                              </FieldLabel>\n                            </Field>\n                          ))}\n                        </RadioGroup>\n                      )\n                    }\n                  </form.Field>\n                </FieldSet>\n              ) : null}\n              <form.Field name=\"emailVerified\">\n                {(field) => (\n                  <Field orientation=\"horizontal\">\n                    <Switch\n                      checked={field.state.value}\n                      id=\"admin-create-email-verified\"\n                      onCheckedChange={field.handleChange}\n                    />\n                    <FieldContent>\n                      <FieldLabel htmlFor=\"admin-create-email-verified\">\n                        {config.localization.emailVerified}\n                      </FieldLabel>\n                    </FieldContent>\n                  </Field>\n                )}\n              </form.Field>\n              {additionalFields.map((configuredField) => (\n                <form.AppField\n                  key={configuredField.name}\n                  name={`additionalFields.${configuredField.name}`}\n                  validators={getAuthAdditionalFieldValidators(\n                    configuredField,\n                    auth.localization.auth.fieldRequired\n                  )}\n                >\n                  {(field) => (\n                    <field.AuthFormAdditionalField\n                      field={configuredField}\n                      isPending={createUser.isPending}\n                    />\n                  )}\n                </form.AppField>\n              ))}\n            </FieldGroup>\n            <FieldError>{getAdminErrorMessage(createUser.error)}</FieldError>\n            <DialogFooter>\n              <Button onClick={close} type=\"button\" variant=\"outline\">\n                {config.localization.cancel}\n              </Button>\n              <form.AuthFormSubmitButton disabled={createUser.isPending}>\n                {config.localization.createUser}\n              </form.AuthFormSubmitButton>\n            </DialogFooter>\n          </form.AuthFormRoot>\n        </form.AppForm>\n      </DialogContent>\n    </Dialog>\n  )\n}\n\nfunction UserInspector({\n  canGetUser,\n  open,\n  onOpenChange,\n  userId\n}: {\n  canGetUser: boolean\n  open: boolean\n  onOpenChange: (open: boolean) => void\n  userId?: string\n}) {\n  const auth = useAuth<AdminAuthClient>()\n  const config = useAuthPlugin(adminPlugin)\n  const contributedTabs = auth.plugins.flatMap((plugin) =>\n    (plugin.adminUserTabs ?? []).map((tab) => ({\n      ...tab,\n      value: `${plugin.id}:${tab.id}`\n    }))\n  )\n  const detail = useAdminUser(auth.authClient, userId, {\n    enabled: canGetUser\n  })\n  const user = detail.data\n  const sessionsPermission = useAdminPermission(\n    auth.authClient,\n    {\n      session: [\"list\"]\n    },\n    { enabled: Boolean(userId) }\n  )\n  const sessions = useAdminUserSessions(auth.authClient, userId, {\n    enabled: sessionsPermission.data?.success === true\n  })\n  const { data: actor } = useSession(auth.authClient)\n  const canSetRole = useAdminPermission(\n    auth.authClient,\n    {\n      user: [\"set-role\"]\n    },\n    { enabled: Boolean(userId) }\n  )\n  const canUpdate = useAdminPermission(\n    auth.authClient,\n    { user: [\"update\"] },\n    { enabled: Boolean(userId) }\n  )\n  const canSetEmail = useAdminPermission(\n    auth.authClient,\n    { user: [\"set-email\"] },\n    { enabled: Boolean(userId) }\n  )\n  const canSetPassword = useAdminPermission(\n    auth.authClient,\n    {\n      user: [\"set-password\"]\n    },\n    { enabled: Boolean(userId) }\n  )\n  const canBan = useAdminPermission(\n    auth.authClient,\n    { user: [\"ban\"] },\n    { enabled: Boolean(userId) }\n  )\n  const canImpersonate = useAdminPermission(\n    auth.authClient,\n    {\n      user: [\"impersonate\"]\n    },\n    { enabled: Boolean(userId) }\n  )\n  const targetIsAdmin = user\n    ? isAdminTarget(user, config.adminRoles, config.adminUserIds)\n    : false\n  const canImpersonateAdmins = useAdminPermission(\n    auth.authClient,\n    { user: [\"impersonate-admins\"] },\n    { enabled: Boolean(userId && targetIsAdmin) }\n  )\n  const canDelete = useAdminPermission(\n    auth.authClient,\n    { user: [\"delete\"] },\n    { enabled: Boolean(userId) }\n  )\n  const canRevoke = useAdminPermission(\n    auth.authClient,\n    {\n      session: [\"revoke\"]\n    },\n    { enabled: Boolean(userId) }\n  )\n  const {\n    copied: userIdCopied,\n    copy: copyUserId,\n    reset: resetUserIdCopy\n  } = useCopyToClipboard()\n\n  useEffect(() => {\n    if (open && userId) resetUserIdCopy()\n  }, [open, userId, resetUserIdCopy])\n\n  const [banReason, setBanReason] = useState(\"\")\n  const [banDuration, setBanDuration] = useState(\"\")\n  const banDurationSeconds = getBanDurationSeconds(banDuration)\n  const [passwordOpen, setPasswordOpen] = useState(false)\n  const [dangerousAction, setDangerousAction] = useState<DangerousAction>()\n  const isSelf = user?.id === actor?.user.id\n\n  const updateUser = useMutation(\n    updateAdminUserOptions(auth.authClient, actor?.user.id)\n  )\n\n  useEffect(() => {\n    if (user?.id) updateUser.reset()\n  }, [user?.id, updateUser.reset])\n\n  useEffect(() => {\n    if (!open) updateUser.reset()\n  }, [open, updateUser.reset])\n\n  const setRoleMutation = useMutation(\n    setAdminUserRoleOptions(auth.authClient, actor?.user.id)\n  )\n  const ban = useMutation(banAdminUserOptions(auth.authClient, actor?.user.id))\n  const unban = useMutation(\n    unbanAdminUserOptions(auth.authClient, actor?.user.id)\n  )\n  const remove = useMutation(\n    removeAdminUserOptions(auth.authClient, actor?.user.id)\n  )\n  const impersonate = useMutation(\n    impersonateAdminUserOptions(auth.authClient, actor?.user.id)\n  )\n  const revokeSession = useMutation(\n    revokeAdminUserSessionOptions(auth.authClient, actor?.user.id, userId)\n  )\n  const revokeSessions = useMutation(\n    revokeAdminUserSessionsOptions(auth.authClient, actor?.user.id, userId)\n  )\n  const configuredUserFields = useMemo(\n    () =>\n      fieldsWithModelValues(\n        auth.additionalFields ?? [],\n        user ? (user as unknown as Record<string, unknown>) : {}\n      ),\n    [auth.additionalFields, user]\n  )\n  const profileForm = useAuthForm({\n    defaultValues: {\n      additionalFields: getAdditionalFieldDefaultValues(configuredUserFields),\n      email: \"\",\n      emailVerified: false,\n      name: \"\",\n      roles: [config.defaultRole]\n    },\n    onSubmit: async ({ value }) => {\n      if (!user) return\n\n      const mutations: Promise<unknown>[] = []\n      if (canUpdate.data?.success) {\n        mutations.push(\n          updateUser.mutateAsync({\n            userId: user.id,\n            data: {\n              ...getAdditionalFieldSubmitValues(\n                configuredUserFields,\n                value.additionalFields\n              ),\n              name: value.name.trim(),\n              ...(canSetEmail.data?.success\n                ? {\n                    email: value.email.trim(),\n                    emailVerified: value.emailVerified\n                  }\n                : {})\n            }\n          })\n        )\n      }\n      if (canSetRole.data?.success && !isSelf) {\n        mutations.push(\n          setRoleMutation.mutateAsync({\n            userId: user.id,\n            role: asAdminRoles(value.roles)\n          })\n        )\n      }\n\n      try {\n        await Promise.all(mutations)\n        onOpenChange(false)\n      } catch {\n        // Mutation errors are rendered next to the form.\n      }\n    }\n  })\n\n  useEffect(() => {\n    profileForm.reset({\n      additionalFields: getAdditionalFieldDefaultValues(configuredUserFields),\n      email: user?.email ?? \"\",\n      emailVerified: user?.emailVerified ?? false,\n      name: user?.name ?? \"\",\n      roles: parseAdminRoles(\n        user?.role,\n        config.defaultRole,\n        config.allowMultipleRoles\n      )\n    })\n  }, [\n    config.allowMultipleRoles,\n    config.defaultRole,\n    configuredUserFields,\n    profileForm.reset,\n    user?.email,\n    user?.emailVerified,\n    user?.name,\n    user?.role\n  ])\n\n  const confirm = () => {\n    if (!user) return\n    if (dangerousAction === \"ban\") {\n      if (banDurationSeconds === null) return\n      ban.mutate(\n        {\n          banExpiresIn: banDurationSeconds,\n          banReason: banReason.trim() || undefined,\n          userId: user.id\n        },\n        {\n          onSuccess: () => {\n            setBanDuration(\"\")\n            setBanReason(\"\")\n            setDangerousAction(undefined)\n          }\n        }\n      )\n    }\n    if (dangerousAction === \"delete\")\n      remove.mutate(\n        { userId: user.id },\n        {\n          onSuccess: () => {\n            setDangerousAction(undefined)\n            onOpenChange(false)\n          }\n        }\n      )\n    if (dangerousAction === \"revokeAll\")\n      revokeSessions.mutate(\n        { userId: user.id },\n        { onSuccess: () => setDangerousAction(undefined) }\n      )\n    if (dangerousAction === \"impersonate\")\n      impersonate.mutate(\n        { userId: user.id },\n        {\n          onSuccess: () => {\n            setDangerousAction(undefined)\n            if (config.impersonationRedirectTo)\n              auth.navigate({ to: config.impersonationRedirectTo })\n          }\n        }\n      )\n  }\n  const closeDangerousAction = () => {\n    ban.reset()\n    remove.reset()\n    revokeSessions.reset()\n    impersonate.reset()\n    setBanDuration(\"\")\n    setBanReason(\"\")\n    setDangerousAction(undefined)\n  }\n  const dangerousMutation =\n    dangerousAction === \"ban\"\n      ? ban\n      : dangerousAction === \"delete\"\n        ? remove\n        : dangerousAction === \"revokeAll\"\n          ? revokeSessions\n          : impersonate\n  const dangerousError = getAdminErrorMessage(dangerousMutation.error)\n  const dangerLabel =\n    dangerousAction === \"ban\"\n      ? config.localization.banUser\n      : dangerousAction === \"delete\"\n        ? config.localization.deleteUser\n        : dangerousAction === \"revokeAll\"\n          ? config.localization.revokeAllSessions\n          : config.localization.impersonateUser\n\n  return (\n    <>\n      <Dialog open={open} onOpenChange={onOpenChange}>\n        <DialogContent className=\"h-[min(52rem,calc(100vh-2rem))] grid-rows-[auto_minmax(0,1fr)] gap-0 overflow-hidden p-0 sm:max-w-4xl\">\n          <DialogHeader className=\"border-b px-6 py-5 pr-14\">\n            {user ? (\n              <div className=\"flex items-center justify-between gap-4\">\n                <div className=\"flex min-w-0 items-center gap-3\">\n                  <UserAvatar className=\"size-12\" user={user} />\n                  <div className=\"min-w-0\">\n                    <DialogTitle className=\"truncate\">{user.name}</DialogTitle>\n                    <DialogDescription className=\"truncate\">\n                      {user.email}\n                    </DialogDescription>\n                  </div>\n                </div>\n                <div className=\"flex shrink-0 items-center gap-2\">\n                  <Badge variant={user.banned ? \"destructive\" : \"secondary\"}>\n                    {user.banned\n                      ? config.localization.banned\n                      : config.localization.active}\n                  </Badge>\n                  <DropdownMenu>\n                    <DropdownMenuTrigger asChild>\n                      <Button\n                        aria-label={config.localization.moreActions}\n                        size=\"icon-sm\"\n                        variant=\"ghost\"\n                      >\n                        <EllipsisIcon />\n                      </Button>\n                    </DropdownMenuTrigger>\n                    <DropdownMenuContent align=\"end\" className=\"w-48\">\n                      <DropdownMenuGroup>\n                        <DropdownMenuItem\n                          disabled={\n                            canImpersonate.isPending ||\n                            !canImpersonate.data?.success ||\n                            (targetIsAdmin &&\n                              (canImpersonateAdmins.isPending ||\n                                !canImpersonateAdmins.data?.success)) ||\n                            isSelf\n                          }\n                          onSelect={() => setDangerousAction(\"impersonate\")}\n                        >\n                          <LogInIcon />\n                          {config.localization.impersonateUser}\n                        </DropdownMenuItem>\n                      </DropdownMenuGroup>\n                    </DropdownMenuContent>\n                  </DropdownMenu>\n                </div>\n              </div>\n            ) : (\n              <>\n                <DialogTitle>{config.localization.userDetails}</DialogTitle>\n                <DialogDescription>\n                  {config.localization.usersDescription}\n                </DialogDescription>\n              </>\n            )}\n          </DialogHeader>\n          {detail.isPending ? (\n            <div className=\"flex flex-col gap-3 p-6\">\n              <Skeleton className=\"size-14 rounded-full\" />\n              <Skeleton className=\"h-5 w-40\" />\n              <Skeleton className=\"h-4 w-64\" />\n            </div>\n          ) : user ? (\n            <Tabs\n              className=\"min-h-0 gap-0 overflow-hidden\"\n              defaultValue=\"overview\"\n            >\n              <TabsList className=\"mx-6 h-11 shrink-0\" variant=\"line\">\n                <TabsTrigger value=\"overview\">\n                  <UserRound\n                    aria-hidden=\"true\"\n                    className=\"text-muted-foreground\"\n                  />\n                  {config.localization.overview}\n                </TabsTrigger>\n                <TabsTrigger\n                  disabled={\n                    sessionsPermission.isPending ||\n                    !sessionsPermission.data?.success\n                  }\n                  value=\"sessions\"\n                >\n                  <Monitor\n                    aria-hidden=\"true\"\n                    className=\"text-muted-foreground\"\n                  />\n                  {config.localization.sessions}\n                </TabsTrigger>\n                {contributedTabs.map((tab) => (\n                  <TabsTrigger key={tab.value} value={tab.value}>\n                    {tab.label}\n                  </TabsTrigger>\n                ))}\n              </TabsList>\n              <TabsContent className=\"min-h-0 overflow-hidden\" value=\"overview\">\n                <profileForm.AppForm>\n                  <profileForm.AuthFormRoot className=\"grid h-full grid-rows-[minmax(0,1fr)_auto]\">\n                    <div className=\"overflow-y-auto\">\n                      <section className=\"flex flex-col gap-5 p-6\">\n                        <h3 className=\"font-medium\">\n                          {config.localization.profileAndAccess}\n                        </h3>\n                        <FieldGroup className=\"grid gap-5 md:grid-cols-2\">\n                          <profileForm.Field name=\"name\">\n                            {(field) => (\n                              <Field>\n                                <FieldLabel htmlFor=\"admin-user-name\">\n                                  {config.localization.name}\n                                </FieldLabel>\n                                <InputGroup>\n                                  <InputGroupInput\n                                    disabled={!canUpdate.data?.success}\n                                    id=\"admin-user-name\"\n                                    name={field.name}\n                                    value={field.state.value}\n                                    onChange={(event) =>\n                                      field.handleChange(event.target.value)\n                                    }\n                                  />\n                                </InputGroup>\n                              </Field>\n                            )}\n                          </profileForm.Field>\n                          <profileForm.Field name=\"email\">\n                            {(field) => (\n                              <Field>\n                                <FieldLabel htmlFor=\"admin-user-email\">\n                                  {config.localization.email}\n                                </FieldLabel>\n                                <InputGroup>\n                                  <InputGroupInput\n                                    disabled={\n                                      !canUpdate.data?.success ||\n                                      !canSetEmail.data?.success\n                                    }\n                                    id=\"admin-user-email\"\n                                    name={field.name}\n                                    onChange={(event) =>\n                                      field.handleChange(event.target.value)\n                                    }\n                                    required\n                                    type=\"email\"\n                                    value={field.state.value}\n                                  />\n                                </InputGroup>\n                              </Field>\n                            )}\n                          </profileForm.Field>\n                          <profileForm.Field name=\"emailVerified\">\n                            {(field) => (\n                              <Field orientation=\"horizontal\">\n                                <Switch\n                                  checked={field.state.value}\n                                  disabled={\n                                    !canUpdate.data?.success ||\n                                    !canSetEmail.data?.success\n                                  }\n                                  id=\"admin-user-email-verified\"\n                                  onCheckedChange={field.handleChange}\n                                />\n                                <FieldContent>\n                                  <FieldLabel htmlFor=\"admin-user-email-verified\">\n                                    {config.localization.emailVerified}\n                                  </FieldLabel>\n                                </FieldContent>\n                              </Field>\n                            )}\n                          </profileForm.Field>\n                          <FieldSet>\n                            <FieldLegend variant=\"label\">\n                              {config.localization.role}\n                            </FieldLegend>\n                            <profileForm.Field name=\"roles\">\n                              {(field) =>\n                                config.allowMultipleRoles ? (\n                                  <FieldGroup\n                                    className=\"flex-row flex-wrap gap-4\"\n                                    data-slot=\"checkbox-group\"\n                                  >\n                                    {config.roles.map((item) => (\n                                      <Field\n                                        key={item}\n                                        orientation=\"horizontal\"\n                                      >\n                                        <Checkbox\n                                          checked={field.state.value.includes(\n                                            item\n                                          )}\n                                          disabled={\n                                            isSelf || !canSetRole.data?.success\n                                          }\n                                          id={`admin-user-role-${item}`}\n                                          onCheckedChange={(checked) => {\n                                            const next = checked\n                                              ? [...field.state.value, item]\n                                              : field.state.value.filter(\n                                                  (role) => role !== item\n                                                )\n                                            if (next.length)\n                                              field.handleChange(next)\n                                          }}\n                                        />\n                                        <FieldLabel\n                                          htmlFor={`admin-user-role-${item}`}\n                                        >\n                                          {item}\n                                        </FieldLabel>\n                                      </Field>\n                                    ))}\n                                  </FieldGroup>\n                                ) : (\n                                  <RadioGroup\n                                    className=\"flex-row flex-wrap gap-4\"\n                                    disabled={\n                                      isSelf || !canSetRole.data?.success\n                                    }\n                                    onValueChange={(role) =>\n                                      field.handleChange([role])\n                                    }\n                                    value={field.state.value[0] ?? \"\"}\n                                  >\n                                    {config.roles.map((item) => (\n                                      <Field\n                                        key={item}\n                                        orientation=\"horizontal\"\n                                      >\n                                        <RadioGroupItem\n                                          id={`admin-user-role-${item}`}\n                                          value={item}\n                                        />\n                                        <FieldLabel\n                                          htmlFor={`admin-user-role-${item}`}\n                                        >\n                                          {item}\n                                        </FieldLabel>\n                                      </Field>\n                                    ))}\n                                  </RadioGroup>\n                                )\n                              }\n                            </profileForm.Field>\n                          </FieldSet>\n                          {configuredUserFields.map((configuredField) => (\n                            <profileForm.AppField\n                              key={configuredField.name}\n                              name={`additionalFields.${configuredField.name}`}\n                              validators={getAuthAdditionalFieldValidators(\n                                configuredField,\n                                auth.localization.auth.fieldRequired\n                              )}\n                            >\n                              {(field) => (\n                                <field.AuthFormAdditionalField\n                                  field={configuredField}\n                                  isPending={\n                                    updateUser.isPending ||\n                                    !canUpdate.data?.success\n                                  }\n                                />\n                              )}\n                            </profileForm.AppField>\n                          ))}\n                        </FieldGroup>\n                        <FieldError>\n                          {getAdminErrorMessage(updateUser.error) ??\n                            getAdminErrorMessage(setRoleMutation.error)}\n                        </FieldError>\n                      </section>\n                      <Separator />\n                      <section className=\"flex flex-col gap-4 p-6\">\n                        <h3 className=\"font-medium\">\n                          {config.localization.accountInformation}\n                        </h3>\n                        <dl className=\"grid gap-x-8 gap-y-4 text-sm sm:grid-cols-2\">\n                          <div className=\"flex flex-col gap-1\">\n                            <dt className=\"text-muted-foreground\">\n                              {config.localization.userId}\n                            </dt>\n                            <dd className=\"flex min-w-0 items-center gap-1\">\n                              <code className=\"truncate text-xs\">\n                                {user.id}\n                              </code>\n                              <Button\n                                aria-label={\n                                  userIdCopied\n                                    ? auth.localization.settings\n                                        .copiedToClipboard\n                                    : config.localization.copyUserId\n                                }\n                                onClick={() => copyUserId(user.id)}\n                                size=\"icon-xs\"\n                                type=\"button\"\n                                variant=\"ghost\"\n                              >\n                                {userIdCopied ? <CheckIcon /> : <CopyIcon />}\n                              </Button>\n                            </dd>\n                          </div>\n                          <div className=\"flex flex-col gap-1\">\n                            <dt className=\"text-muted-foreground\">\n                              {config.localization.created}\n                            </dt>\n                            <dd>{formatDate(user.createdAt)}</dd>\n                          </div>\n                          <div className=\"flex flex-col gap-1\">\n                            <dt className=\"text-muted-foreground\">\n                              {config.localization.status}\n                            </dt>\n                            <dd>\n                              <Badge\n                                variant={\n                                  user.banned ? \"destructive\" : \"secondary\"\n                                }\n                              >\n                                {user.banned\n                                  ? config.localization.banned\n                                  : config.localization.active}\n                              </Badge>\n                            </dd>\n                          </div>\n                          {user.banned && user.banReason ? (\n                            <div className=\"flex flex-col gap-1\">\n                              <dt className=\"text-muted-foreground\">\n                                {config.localization.banReason}\n                              </dt>\n                              <dd>{user.banReason}</dd>\n                            </div>\n                          ) : null}\n                          {user.banned && user.banExpires ? (\n                            <div className=\"flex flex-col gap-1\">\n                              <dt className=\"text-muted-foreground\">\n                                {config.localization.banExpires}\n                              </dt>\n                              <dd>{formatDate(user.banExpires)}</dd>\n                            </div>\n                          ) : null}\n                        </dl>\n                      </section>\n                      <Separator />\n                      <section className=\"flex flex-col gap-4 p-6\">\n                        <h3 className=\"font-medium\">\n                          {config.localization.security}\n                        </h3>\n                        <div>\n                          <Button\n                            disabled={\n                              canSetPassword.isPending ||\n                              !canSetPassword.data?.success\n                            }\n                            onClick={() => setPasswordOpen(true)}\n                            type=\"button\"\n                            variant=\"outline\"\n                          >\n                            <KeyRoundIcon />\n                            {config.localization.setPassword}\n                          </Button>\n                        </div>\n                      </section>\n                      <Separator />\n                      <section className=\"flex flex-col gap-4 p-6\">\n                        <h3 className=\"font-medium\">\n                          {config.localization.dangerZone}\n                        </h3>\n                        <div className=\"flex flex-wrap gap-2\">\n                          <Button\n                            disabled={\n                              canBan.isPending ||\n                              !canBan.data?.success ||\n                              isSelf\n                            }\n                            onClick={() =>\n                              user.banned\n                                ? unban.mutate({ userId: user.id })\n                                : setDangerousAction(\"ban\")\n                            }\n                            type=\"button\"\n                            variant=\"outline\"\n                          >\n                            <BanIcon />\n                            {user.banned\n                              ? config.localization.unbanUser\n                              : config.localization.banUser}\n                          </Button>\n                          <Button\n                            disabled={\n                              canDelete.isPending ||\n                              !canDelete.data?.success ||\n                              isSelf\n                            }\n                            onClick={() => setDangerousAction(\"delete\")}\n                            type=\"button\"\n                            variant=\"destructive\"\n                          >\n                            <Trash2Icon />\n                            {config.localization.deleteUser}\n                          </Button>\n                        </div>\n                        {unban.error ? (\n                          <FieldError>\n                            {getAdminErrorMessage(unban.error)}\n                          </FieldError>\n                        ) : null}\n                      </section>\n                    </div>\n                    <div className=\"flex flex-col-reverse gap-2 border-t bg-muted/50 px-6 py-4 sm:flex-row sm:justify-end\">\n                      <Button\n                        onClick={() => onOpenChange(false)}\n                        type=\"button\"\n                        variant=\"outline\"\n                      >\n                        {config.localization.cancel}\n                      </Button>\n                      <profileForm.Subscribe\n                        selector={(state) => [\n                          state.values.name,\n                          state.values.email\n                        ]}\n                      >\n                        {([name, email]) => (\n                          <profileForm.AuthFormSubmitButton\n                            disabled={\n                              !name.trim() ||\n                              !email.trim() ||\n                              updateUser.isPending ||\n                              setRoleMutation.isPending ||\n                              canUpdate.isPending ||\n                              canSetRole.isPending ||\n                              (!canUpdate.data?.success &&\n                                (!canSetRole.data?.success || isSelf))\n                            }\n                          >\n                            {config.localization.saveChanges}\n                          </profileForm.AuthFormSubmitButton>\n                        )}\n                      </profileForm.Subscribe>\n                    </div>\n                  </profileForm.AuthFormRoot>\n                </profileForm.AppForm>\n              </TabsContent>\n              <TabsContent\n                className=\"min-h-0 overflow-y-auto p-6\"\n                value=\"sessions\"\n              >\n                <div className=\"flex flex-col gap-3\">\n                  {sessionsPermission.isPending || sessions.isPending ? (\n                    skeletonRowIds\n                      .slice(0, 3)\n                      .map((id) => (\n                        <Skeleton\n                          className=\"h-20 w-full\"\n                          key={`session-${id}`}\n                        />\n                      ))\n                  ) : !sessionsPermission.data?.success ? (\n                    <p className=\"text-sm text-muted-foreground\">\n                      {config.localization.accessDeniedDescription}\n                    </p>\n                  ) : sessions.data?.sessions.length ? (\n                    <>\n                      <Button\n                        className=\"self-end\"\n                        disabled={\n                          canRevoke.isPending ||\n                          !canRevoke.data?.success ||\n                          isSelf\n                        }\n                        onClick={() => setDangerousAction(\"revokeAll\")}\n                        variant=\"outline\"\n                      >\n                        {config.localization.revokeAllSessions}\n                      </Button>\n                      {sessions.data.sessions.map((item) => (\n                        <div\n                          className=\"flex items-start justify-between gap-3 rounded-lg border p-3\"\n                          key={item.id}\n                        >\n                          <div className=\"min-w-0 text-sm\">\n                            <div className=\"truncate font-medium\">\n                              {item.userAgent || config.localization.sessions}\n                            </div>\n                            <div className=\"text-xs text-muted-foreground\">\n                              {formatDate(item.createdAt)} ·{\" \"}\n                              {formatDate(item.expiresAt)}\n                            </div>\n                            {config.showIpAddress && item.ipAddress ? (\n                              <div className=\"mt-1 font-mono text-xs text-muted-foreground\">\n                                {item.ipAddress}\n                              </div>\n                            ) : null}\n                          </div>\n                          <Button\n                            aria-label={config.localization.revoke}\n                            disabled={\n                              revokeSession.isPending ||\n                              canRevoke.isPending ||\n                              !canRevoke.data?.success ||\n                              isSelf\n                            }\n                            onClick={() =>\n                              revokeSession.mutate({ sessionToken: item.token })\n                            }\n                            size=\"icon-sm\"\n                            variant=\"ghost\"\n                          >\n                            <Trash2Icon />\n                          </Button>\n                        </div>\n                      ))}\n                    </>\n                  ) : (\n                    <p className=\"py-8 text-center text-sm text-muted-foreground\">\n                      {config.localization.noSessions}\n                    </p>\n                  )}\n                </div>\n              </TabsContent>\n              {contributedTabs.map((tab) => {\n                const ContributedTab = tab.component\n                return (\n                  <TabsContent\n                    className=\"min-h-0 overflow-y-auto p-6\"\n                    key={tab.value}\n                    value={tab.value}\n                  >\n                    <ContributedTab userId={user.id} />\n                  </TabsContent>\n                )\n              })}\n            </Tabs>\n          ) : (\n            <AdminState\n              icon={<ShieldAlertIcon />}\n              title={config.localization.loadUsersError}\n              description={config.localization.loadUsersErrorDescription}\n            />\n          )}\n        </DialogContent>\n      </Dialog>\n      <PasswordDialog\n        open={passwordOpen}\n        onOpenChange={setPasswordOpen}\n        userId={user?.id}\n      />\n      <AlertDialog\n        open={Boolean(dangerousAction)}\n        onOpenChange={(value) => !value && closeDangerousAction()}\n      >\n        <AlertDialogContent>\n          <AlertDialogHeader>\n            <AlertDialogTitle>{dangerLabel}</AlertDialogTitle>\n            <AlertDialogDescription>{user?.email}</AlertDialogDescription>\n          </AlertDialogHeader>\n          {dangerousAction === \"ban\" ? (\n            <FieldGroup>\n              <Field>\n                <FieldLabel htmlFor=\"admin-ban-reason\">\n                  {config.localization.banReason}\n                </FieldLabel>\n                <InputGroup>\n                  <InputGroupInput\n                    id=\"admin-ban-reason\"\n                    onChange={(event) => setBanReason(event.target.value)}\n                    value={banReason}\n                  />\n                </InputGroup>\n              </Field>\n              <Field>\n                <FieldLabel htmlFor=\"admin-ban-duration\">\n                  {config.localization.banDuration}\n                </FieldLabel>\n                <InputGroup>\n                  <InputGroupInput\n                    id=\"admin-ban-duration\"\n                    min=\"1\"\n                    onChange={(event) => setBanDuration(event.target.value)}\n                    step=\"1\"\n                    type=\"number\"\n                    value={banDuration}\n                  />\n                </InputGroup>\n                <p className=\"text-xs text-muted-foreground\">\n                  {config.localization.banDurationDescription}\n                </p>\n              </Field>\n            </FieldGroup>\n          ) : null}\n          {dangerousError ? <FieldError>{dangerousError}</FieldError> : null}\n          <AlertDialogFooter>\n            <AlertDialogCancel>{config.localization.cancel}</AlertDialogCancel>\n            <AlertDialogAction\n              disabled={\n                isSelf ||\n                dangerousMutation.isPending ||\n                (dangerousAction === \"ban\" && banDurationSeconds === null)\n              }\n              onClick={(event) => {\n                event.preventDefault()\n                confirm()\n              }}\n              variant={dangerousAction === \"delete\" ? \"destructive\" : \"default\"}\n            >\n              {dangerLabel}\n            </AlertDialogAction>\n          </AlertDialogFooter>\n        </AlertDialogContent>\n      </AlertDialog>\n    </>\n  )\n}\n\nfunction PasswordDialog({\n  open,\n  onOpenChange,\n  userId\n}: {\n  open: boolean\n  onOpenChange: (open: boolean) => void\n  userId?: string\n}) {\n  const auth = useAuth<AdminAuthClient>()\n  const config = useAuthPlugin(adminPlugin)\n  const [password, setPassword] = useState(\"\")\n  const [errorMessage, setErrorMessage] = useState<string>()\n  const mutation = useMutation(\n    setAdminUserPasswordOptions(auth.authClient, () => {\n      setTimeout(() => mutation.reset(), 0)\n    })\n  )\n  const close = () => {\n    setPassword(\"\")\n    setErrorMessage(undefined)\n    mutation.reset()\n    onOpenChange(false)\n  }\n  const submit = (event: FormEvent) => {\n    event.preventDefault()\n    setErrorMessage(undefined)\n    if (userId)\n      mutation.mutate(\n        { userId, newPassword: password },\n        {\n          onError: (error) => setErrorMessage(getAdminErrorMessage(error)),\n          onSuccess: close\n        }\n      )\n  }\n  return (\n    <Dialog\n      open={open}\n      onOpenChange={(value) => (value ? onOpenChange(true) : close())}\n    >\n      <DialogContent>\n        <form className=\"flex flex-col gap-4\" onSubmit={submit}>\n          <DialogHeader>\n            <DialogTitle>{config.localization.setPassword}</DialogTitle>\n            <DialogDescription>\n              {config.localization.userDetails}\n            </DialogDescription>\n          </DialogHeader>\n          <Field data-invalid={Boolean(errorMessage)}>\n            <FieldLabel htmlFor=\"admin-new-password\">\n              {config.localization.password}\n            </FieldLabel>\n            <InputGroup>\n              <InputGroupInput\n                aria-invalid={Boolean(errorMessage)}\n                autoComplete=\"new-password\"\n                id=\"admin-new-password\"\n                onChange={(event) => setPassword(event.target.value)}\n                required\n                type=\"password\"\n                value={password}\n              />\n            </InputGroup>\n            <FieldError>{errorMessage}</FieldError>\n          </Field>\n          <DialogFooter>\n            <Button onClick={close} type=\"button\" variant=\"outline\">\n              {config.localization.cancel}\n            </Button>\n            <Button disabled={!password || mutation.isPending} type=\"submit\">\n              {config.localization.setPassword}\n            </Button>\n          </DialogFooter>\n        </form>\n      </DialogContent>\n    </Dialog>\n  )\n}\n",
      "type": "registry:component",
      "target": "@components/auth/admin/admin-users.tsx"
    },
    {
      "path": "examples/start-shadcn-example/src/components/auth/admin/admin.tsx",
      "content": "\"use client\"\n\nimport type { AdminView } from \"@better-auth-ui/core\"\nimport { useAuth, useAuthenticate, useAuthPlugin } from \"@better-auth-ui/react\"\nimport { ShieldAlertIcon, UsersIcon } from \"lucide-react\"\n\nimport { Button } from \"@/components/ui/button\"\nimport { adminPlugin } from \"@/lib/auth/admin-plugin\"\nimport { cn } from \"cn\"\n\nimport { AdminUsers } from \"./admin-users\"\n\nexport type AdminProps = {\n  className?: string\n  hideNav?: boolean\n  path?: string\n  view?: AdminView | string\n}\n\n/** Render a finite, static administration route and plugin-contributed tabs. */\nexport function Admin({ className, hideNav, path, view }: AdminProps) {\n  const { authClient, basePaths, plugins, viewPaths } = useAuth()\n  const { localization } = useAuthPlugin(adminPlugin)\n  useAuthenticate(authClient)\n\n  if (!view && !path) {\n    throw new Error(\"[Better Auth UI] Either `view` or `path` must be provided\")\n  }\n\n  const contributedTabs = plugins.flatMap((plugin) => plugin.adminTabs ?? [])\n  const currentView =\n    view ??\n    (viewPaths.admin.users === path ? \"users\" : undefined) ??\n    contributedTabs.find((tab) => tab.path === path)?.id\n  const contributedView = contributedTabs.find((tab) => tab.id === currentView)\n\n  return (\n    <div className={cn(\"flex w-full flex-col gap-6\", className)}>\n      {!hideNav && (\n        <nav aria-label={localization.admin} className=\"flex gap-1 border-b\">\n          <Button\n            aria-current={currentView === \"users\" ? \"page\" : undefined}\n            asChild\n            className=\"rounded-b-none\"\n            variant={currentView === \"users\" ? \"secondary\" : \"ghost\"}\n          >\n            <a href={`${basePaths.admin}/${viewPaths.admin.users}`}>\n              <UsersIcon />\n              {localization.users}\n            </a>\n          </Button>\n\n          {contributedTabs.map((tab) => (\n            <Button\n              key={`${tab.id}-${tab.path}`}\n              aria-current={currentView === tab.id ? \"page\" : undefined}\n              asChild\n              className=\"rounded-b-none\"\n              variant={currentView === tab.id ? \"secondary\" : \"ghost\"}\n            >\n              <a href={`${basePaths.admin}/${tab.path}`}>{tab.label}</a>\n            </Button>\n          ))}\n        </nav>\n      )}\n\n      {currentView === \"users\" ? (\n        <AdminUsers />\n      ) : contributedView ? (\n        <contributedView.component />\n      ) : (\n        <div className=\"flex min-h-64 flex-col items-center justify-center gap-3 rounded-lg border border-dashed p-8 text-center\">\n          <ShieldAlertIcon className=\"size-8 text-muted-foreground\" />\n          <div className=\"flex flex-col gap-1\">\n            <h2 className=\"font-medium\">{localization.unknownView}</h2>\n            <p className=\"max-w-md text-sm text-muted-foreground\">\n              {localization.unknownViewDescription} &quot;{path ?? view}&quot;\n            </p>\n          </div>\n        </div>\n      )}\n    </div>\n  )\n}\n",
      "type": "registry:component",
      "target": "@components/auth/admin/admin.tsx"
    },
    {
      "path": "examples/start-shadcn-example/src/components/auth/admin/stop-impersonating.tsx",
      "content": "\"use client\"\n\nimport {\n  type AdminAuthClient,\n  isImpersonatingSession\n} from \"@better-auth-ui/core/plugins/admin\"\nimport { useAuth, useAuthPlugin, useSession } from \"@better-auth-ui/react\"\nimport { useStopImpersonating } from \"@better-auth-ui/react/plugins/admin\"\nimport { UserRoundCheck } from \"lucide-react\"\n\nimport { DropdownMenuItem } from \"@/components/ui/dropdown-menu\"\nimport { Spinner } from \"@/components/ui/spinner\"\nimport { adminPlugin } from \"@/lib/auth/admin-plugin\"\n\nexport type StopImpersonatingProps = {\n  className?: string\n}\n\n/**\n * Restore the administrator's session when the current session is\n * impersonating another user.\n */\nexport function StopImpersonating({ className }: StopImpersonatingProps) {\n  const { authClient } = useAuth()\n  const { localization } = useAuthPlugin(adminPlugin)\n  const { data: session } = useSession(authClient)\n  const stopImpersonating = useStopImpersonating(authClient as AdminAuthClient)\n\n  if (!isImpersonatingSession(session)) {\n    return null\n  }\n\n  return (\n    <DropdownMenuItem\n      className={className}\n      disabled={stopImpersonating.isPending}\n      onClick={() => stopImpersonating.mutate(undefined)}\n    >\n      {stopImpersonating.isPending ? (\n        <Spinner />\n      ) : (\n        <UserRoundCheck className=\"text-muted-foreground\" />\n      )}\n\n      {localization.stopImpersonating}\n    </DropdownMenuItem>\n  )\n}\n",
      "type": "registry:component",
      "target": "@components/auth/admin/stop-impersonating.tsx"
    },
    {
      "path": "examples/start-shadcn-example/src/components/auth/auth-form.tsx",
      "content": "\"use client\"\n\nimport {\n  type AdditionalField as AdditionalFieldConfig,\n  type AdditionalFieldFormValue,\n  DEFAULT_ADDITIONAL_FIELD_VALIDATION_DEBOUNCE_MS,\n  getFormFieldErrors,\n  normalizeAuthFormServerError,\n  validateAdditionalFieldRequired,\n  validateAdditionalFieldValue\n} from \"@better-auth-ui/core\"\nimport {\n  type AnyFormApi,\n  createFormHook,\n  createFormHookContexts\n} from \"@tanstack/react-form\"\nimport {\n  type ComponentProps,\n  type FormEvent,\n  type ReactNode,\n  useRef\n} from \"react\"\n\nimport { Button } from \"@/components/ui/button\"\nimport {\n  Field,\n  FieldDescription,\n  FieldError,\n  FieldLabel\n} from \"@/components/ui/field\"\nimport { Input } from \"@/components/ui/input\"\nimport { Spinner } from \"@/components/ui/spinner\"\nimport { AdditionalField, type AdditionalFieldProps } from \"./additional-field\"\n\nconst { fieldContext, formContext, useFieldContext, useFormContext } =\n  createFormHookContexts()\n\nconst DEFAULT_AUTH_FORM_SERVER_ERROR = \"Unable to submit this form. Try again.\"\n\nexport function focusFirstInvalidAuthFormControl(form: HTMLFormElement) {\n  requestAnimationFrame(() => {\n    form\n      .querySelector<HTMLElement>(\n        '[aria-invalid=\"true\"]:not([disabled]), :invalid:not([disabled])'\n      )\n      ?.focus()\n  })\n}\n\nfunction AuthFormFieldError() {\n  const field = useFieldContext<unknown>()\n  const isInvalid = field.state.meta.isTouched && !field.state.meta.isValid\n\n  if (!isInvalid) return null\n\n  const errors = getFormFieldErrors(field.state.meta.errors)\n\n  return errors.length > 0 ? <FieldError errors={errors} /> : null\n}\n\nfunction AuthFormServerError() {\n  const form = useFormContext()\n\n  return (\n    <form.Subscribe selector={(state) => state.errorMap.onServer}>\n      {(error) => {\n        const formError =\n          error && typeof error === \"object\" && \"form\" in error\n            ? error.form\n            : error\n        const errors = getFormFieldErrors(formError ? [formError] : [])\n        return errors.length > 0 ? <FieldError errors={errors} /> : null\n      }}\n    </form.Subscribe>\n  )\n}\n\nexport function setAuthFormServerError(\n  form: AnyFormApi,\n  error: unknown,\n  fallbackMessage: string\n) {\n  const normalized = normalizeAuthFormServerError(error, fallbackMessage)\n  form.setErrorMap({\n    onServer: {\n      fields: normalized.fields ?? {},\n      form: normalized.form\n    }\n  })\n}\n\nexport function clearAuthFormServerError(form: AnyFormApi) {\n  form.setErrorMap({ onServer: { fields: {} } })\n}\n\nexport function clearAuthFormFieldServerError(\n  form: AnyFormApi,\n  fieldName: string\n) {\n  form.setErrorMap({ onServer: undefined })\n  if (!fieldName) return\n\n  const fieldMeta = form.getFieldMeta(fieldName as never)\n  if (!fieldMeta?.errorMap.onServer) return\n\n  form.setFieldMeta(fieldName as never, (current = fieldMeta) => ({\n    ...current,\n    errorMap: { ...current.errorMap, onServer: undefined },\n    errorSourceMap: { ...current.errorSourceMap, onServer: undefined }\n  }))\n}\n\nexport async function runAuthFormAction(\n  form: AnyFormApi,\n  action: () => Promise<unknown>,\n  serverErrorMessage = DEFAULT_AUTH_FORM_SERVER_ERROR\n) {\n  clearAuthFormServerError(form)\n  try {\n    await action()\n    return true\n  } catch (error) {\n    if (!form.state.errorMap.onServer) {\n      setAuthFormServerError(form, error, serverErrorMessage)\n    }\n    return false\n  }\n}\n\nexport async function submitAuthForm(\n  form: AnyFormApi,\n  serverErrorMessage = DEFAULT_AUTH_FORM_SERVER_ERROR\n) {\n  clearAuthFormServerError(form)\n  try {\n    await form.handleSubmit()\n    return form.state.isValid\n  } catch (error) {\n    if (!form.state.errorMap.onServer) {\n      setAuthFormServerError(form, error, serverErrorMessage)\n    }\n    return false\n  }\n}\n\ntype AuthFormRootProps = Omit<ComponentProps<\"form\">, \"onSubmit\"> & {\n  onBeforeSubmit?: () => void\n  serverErrorMessage?: string\n}\n\nfunction AuthFormRoot({\n  children,\n  onBeforeSubmit,\n  onInput,\n  serverErrorMessage = DEFAULT_AUTH_FORM_SERVER_ERROR,\n  ...props\n}: AuthFormRootProps) {\n  const form = useFormContext()\n  const submittingRef = useRef(false)\n\n  async function submit(event: FormEvent<HTMLFormElement>) {\n    event.preventDefault()\n    if (submittingRef.current || form.state.isSubmitting) return\n\n    const formElement = event.currentTarget\n    onBeforeSubmit?.()\n    submittingRef.current = true\n    try {\n      const isValid = await submitAuthForm(form, serverErrorMessage)\n      if (!isValid) focusFirstInvalidAuthFormControl(formElement)\n    } finally {\n      submittingRef.current = false\n    }\n  }\n\n  return (\n    <form\n      {...props}\n      onInvalid={(event) =>\n        focusFirstInvalidAuthFormControl(event.currentTarget)\n      }\n      onInput={(event) => {\n        const target = event.target\n        const fieldName =\n          target instanceof HTMLInputElement ||\n          target instanceof HTMLSelectElement ||\n          target instanceof HTMLTextAreaElement\n            ? target.name\n            : \"\"\n        clearAuthFormFieldServerError(form, fieldName)\n        onInput?.(event)\n      }}\n      onSubmit={submit}\n    >\n      {children}\n    </form>\n  )\n}\n\ntype AuthFormTextFieldProps = Omit<\n  ComponentProps<typeof Input>,\n  \"name\" | \"onBlur\" | \"onChange\" | \"value\"\n> & {\n  description?: ReactNode\n  label: ReactNode\n}\n\nfunction AuthFormTextField({\n  description,\n  id,\n  label,\n  ...props\n}: AuthFormTextFieldProps) {\n  const field = useFieldContext<string>()\n  const form = useFormContext()\n  const isInvalid = isAuthFormFieldInvalid(field.state.meta)\n  const inputId = id ?? field.name\n\n  return (\n    <Field data-invalid={isInvalid}>\n      <FieldLabel htmlFor={inputId}>{label}</FieldLabel>\n      <Input\n        {...props}\n        aria-busy={field.state.meta.isValidating || undefined}\n        aria-invalid={isInvalid}\n        id={inputId}\n        name={field.name}\n        onBlur={field.handleBlur}\n        onChange={(event) => {\n          clearAuthFormFieldServerError(form, field.name)\n          field.handleChange(event.target.value)\n        }}\n        value={field.state.value}\n      />\n      {description ? <FieldDescription>{description}</FieldDescription> : null}\n      <AuthFormFieldError />\n    </Field>\n  )\n}\n\nfunction AuthFormSubmitButton({\n  children,\n  disabled,\n  isPending,\n  ...props\n}: ComponentProps<typeof Button> & { isPending?: boolean }) {\n  const form = useFormContext()\n\n  return (\n    <form.Subscribe\n      selector={(state) => [state.isSubmitting, state.isValidating] as const}\n    >\n      {([isSubmitting, isValidating]) => (\n        <Button\n          {...props}\n          aria-busy={isPending || isSubmitting || undefined}\n          aria-disabled={\n            disabled || isPending || isSubmitting || isValidating || undefined\n          }\n          disabled={disabled || isPending || isSubmitting || isValidating}\n          type=\"submit\"\n        >\n          {isPending || isSubmitting ? (\n            <Spinner data-icon=\"inline-start\" />\n          ) : null}\n          {children}\n        </Button>\n      )}\n    </form.Subscribe>\n  )\n}\n\ntype AuthFormAdditionalFieldProps = Omit<\n  AdditionalFieldProps,\n  \"errors\" | \"isInvalid\" | \"name\" | \"onBlur\" | \"onChange\" | \"value\"\n>\n\nfunction AuthFormAdditionalField(props: AuthFormAdditionalFieldProps) {\n  const field = useFieldContext<AdditionalFieldFormValue>()\n  const form = useFormContext()\n  const isInvalid = isAuthFormFieldInvalid(field.state.meta)\n\n  return (\n    <AdditionalField\n      {...props}\n      errors={\n        isInvalid ? getFormFieldErrors(field.state.meta.errors) : undefined\n      }\n      isInvalid={isInvalid}\n      name={field.name}\n      onBlur={field.handleBlur}\n      onChange={(value) => {\n        clearAuthFormFieldServerError(form, field.name)\n        field.handleChange(value)\n      }}\n      value={field.state.value}\n    />\n  )\n}\n\nexport const {\n  useAppForm: useAuthForm,\n  withFieldGroup: withAuthFieldGroup,\n  withForm: withAuthForm\n} = createFormHook({\n  fieldComponents: {\n    AuthFormAdditionalField,\n    AuthFormFieldError,\n    AuthFormTextField\n  },\n  fieldContext,\n  formComponents: {\n    AuthFormRoot,\n    AuthFormServerError,\n    AuthFormSubmitButton\n  },\n  formContext\n})\n\nexport function isAuthFormFieldInvalid({\n  isTouched,\n  isValid\n}: {\n  isTouched: boolean\n  isValid: boolean\n}) {\n  return isTouched && !isValid\n}\n\nexport function getAuthAdditionalFieldValidators(\n  field: AdditionalFieldConfig,\n  requiredMessage: string\n) {\n  return {\n    onChange: ({ value }: { value: AdditionalFieldFormValue }) =>\n      validateAdditionalFieldRequired(field, value, requiredMessage),\n    onChangeAsync: field.validate\n      ? ({ value }: { value: AdditionalFieldFormValue }) =>\n          validateAdditionalFieldValue(field, value)\n      : undefined,\n    onChangeAsyncDebounceMs: field.validate\n      ? (field.validateDebounceMs ??\n        DEFAULT_ADDITIONAL_FIELD_VALIDATION_DEBOUNCE_MS)\n      : undefined\n  }\n}\n",
      "type": "registry:component",
      "target": "@components/auth/auth-form.tsx"
    },
    {
      "path": "examples/start-shadcn-example/src/components/auth/server-table-state.ts",
      "content": "\"use client\"\n\nimport { useCreateAtom, useSelector } from \"@tanstack/react-store\"\nimport {\n  type ColumnFiltersState,\n  functionalUpdate,\n  type PaginationState,\n  type SortingState,\n  type Updater\n} from \"@tanstack/react-table\"\nimport { useCallback, useEffect, useMemo } from \"react\"\n\nexport function useServerTableState({\n  initialSorting = [],\n  pageSize\n}: {\n  initialSorting?: SortingState\n  pageSize: number\n}) {\n  const columnFiltersAtom = useCreateAtom<ColumnFiltersState>([])\n  const globalFilterAtom = useCreateAtom(\"\")\n  const paginationAtom = useCreateAtom<PaginationState>({\n    pageIndex: 0,\n    pageSize\n  })\n  const sortingAtom = useCreateAtom<SortingState>(initialSorting)\n  const columnFilters = useSelector(columnFiltersAtom)\n  const globalFilter = useSelector(globalFilterAtom)\n  const pagination = useSelector(paginationAtom)\n  const sorting = useSelector(sortingAtom)\n  const atoms = useMemo(\n    () => ({\n      columnFilters: columnFiltersAtom,\n      globalFilter: globalFilterAtom,\n      pagination: paginationAtom,\n      sorting: sortingAtom\n    }),\n    [columnFiltersAtom, globalFilterAtom, paginationAtom, sortingAtom]\n  )\n\n  useEffect(() => {\n    const resetPage = () => {\n      const current = paginationAtom.get()\n      if (current.pageIndex !== 0) {\n        paginationAtom.set({ ...current, pageIndex: 0 })\n      }\n    }\n    const subscriptions = [\n      columnFiltersAtom.subscribe(resetPage),\n      globalFilterAtom.subscribe(resetPage),\n      sortingAtom.subscribe(resetPage)\n    ]\n\n    return () => {\n      for (const subscription of subscriptions) subscription.unsubscribe()\n    }\n  }, [columnFiltersAtom, globalFilterAtom, paginationAtom, sortingAtom])\n\n  const setPagination = useCallback(\n    (updater: Updater<PaginationState>) => {\n      paginationAtom.set((current) => functionalUpdate(updater, current))\n    },\n    [paginationAtom]\n  )\n\n  return {\n    atoms,\n    columnFilters,\n    globalFilter,\n    pagination,\n    setPagination,\n    sorting\n  }\n}\n",
      "type": "registry:component",
      "target": "@components/auth/server-table-state.ts"
    },
    {
      "path": "examples/start-shadcn-example/src/components/auth/user/user-avatar.tsx",
      "content": "\"use client\"\n\nimport type { UsernameAuthClient } from \"@better-auth-ui/core/plugins/username\"\nimport { useAuth, useSession } from \"@better-auth-ui/react\"\nimport type { User } from \"better-auth\"\nimport { User2 } from \"lucide-react\"\nimport type { ReactNode } from \"react\"\n\nimport { Avatar, AvatarFallback, AvatarImage } from \"@/components/ui/avatar\"\nimport { Skeleton } from \"@/components/ui/skeleton\"\nimport { cn } from \"cn\"\n\nexport type UserAvatarProps = {\n  className?: string\n  fallback?: ReactNode\n  isPending?: boolean\n  /** @remarks `User` */\n  user?: User & { username?: string | null; displayUsername?: string | null }\n}\n\n/**\n * Display a user's avatar using session information or an explicit user prop.\n *\n * Renders a circular avatar that shows the user's image when available, a fallback node if provided, or the user's first two initials; while the session is loading (or when `isPending` is true) and no `user` prop is supplied, renders a skeleton placeholder.\n *\n * @param className - Additional CSS classes applied to the avatar container\n * @param user - Optional user object to display instead of the session user\n * @param isPending - When true, treat the component as loading and show the skeleton if no `user` is provided\n * @param fallback - Node to render inside the avatar fallback area before initials or the default icon\n * @returns The avatar element to render (JSX)\n */\nexport function UserAvatar({\n  className,\n  user,\n  isPending,\n  fallback\n}: UserAvatarProps) {\n  const { authClient } = useAuth<UsernameAuthClient>()\n  const { data: session, isPending: sessionPending } = useSession(authClient, {\n    enabled: !user && !isPending\n  })\n\n  if ((isPending || sessionPending) && !user) {\n    return <Skeleton className={cn(\"size-8 rounded-full\", className)} />\n  }\n\n  const resolvedUser = user ?? session?.user\n\n  const initials = (\n    resolvedUser?.username ||\n    resolvedUser?.name ||\n    resolvedUser?.email\n  )\n    ?.slice(0, 2)\n    .toUpperCase()\n\n  return (\n    <Avatar\n      className={cn(\n        \"size-8 bg-muted text-foreground text-sm rounded-full\",\n        className\n      )}\n    >\n      <AvatarImage\n        src={resolvedUser?.image ?? undefined}\n        alt={\n          resolvedUser?.displayUsername ||\n          resolvedUser?.name ||\n          resolvedUser?.email\n        }\n      />\n\n      <AvatarFallback className=\"text-muted-foreground!\">\n        {fallback || initials || <User2 className=\"size-4\" />}\n      </AvatarFallback>\n    </Avatar>\n  )\n}\n",
      "type": "registry:component",
      "target": "@components/auth/user/user-avatar.tsx"
    },
    {
      "path": "examples/start-shadcn-example/src/lib/auth/admin-plugin.ts",
      "content": "import { createAuthPlugin } from \"@better-auth-ui/core\"\nimport {\n  type AdminPluginOptions,\n  adminPlugin as coreAdminPlugin\n} from \"@better-auth-ui/core/plugins/admin\"\n\nimport { StopImpersonating } from \"@/components/auth/admin/stop-impersonating\"\n\nexport const adminPlugin = createAuthPlugin(\n  coreAdminPlugin.id,\n  (options: AdminPluginOptions = {}) => ({\n    ...coreAdminPlugin(options),\n    userMenuItems: [StopImpersonating]\n  })\n)\n",
      "type": "registry:lib",
      "target": "@lib/auth/admin-plugin.ts"
    },
    {
      "path": "examples/start-shadcn-example/src/lib/auth/auth-plugin.ts",
      "content": "import type {\n  AuthPluginComponents,\n  AuthPlugin as AuthPluginPrimitive\n} from \"@better-auth-ui/react\"\n\ndeclare module \"@better-auth-ui/core\" {\n  /** Widens `useAuth().plugins` to the shadcn-typed `AuthPlugin`. */\n  interface AuthPluginRegister {\n    shadcn: AuthPlugin\n  }\n}\n\n/** Props the shadcn `<Auth>` router spreads onto plugin-contributed auth views. */\nexport type AuthViewProps = {\n  className?: string\n  socialLayout?: \"auto\" | \"horizontal\" | \"vertical\" | \"grid\"\n  socialPosition?: \"top\" | \"bottom\"\n}\n\n/** Props the shadcn `<Settings>` router spreads onto plugin-contributed settings views. */\nexport type SettingsViewProps = {\n  className?: string\n}\n\n/** Shadcn plugin type. Plugin authors import this from `@/lib/auth/auth-plugin`. */\nexport type AuthPlugin = AuthPluginPrimitive<\n  AuthPluginComponents,\n  AuthViewProps,\n  SettingsViewProps\n>\n",
      "type": "registry:lib",
      "target": "@lib/auth/auth-plugin.ts"
    }
  ],
  "type": "registry:component"
}