import {Asset as Asset_3} from '@sanity/media-library-types'
import {AssetInstanceDocument as AssetInstanceDocument_2} from '@sanity/media-library-types'
import {ClientPerspective} from '@sanity/client'
import {ComponentType} from 'react'
import {ElementType} from 'react'
import {ReactNode} from 'react'
import {SanityClient} from '@sanity/client'

/**
 * Types of array actions that can be performed
 * @beta
 */
declare type ArrayActionName =
  /**
   * Add any item to the array at any position
   */
  | 'add'
  /**
   * Add item after an existing item
   */
  | 'addBefore'
  /**
   * Add item after an existing item
   */
  | 'addAfter'
  /**
   * Remove any item
   */
  | 'remove'
  /**
   * Duplicate item
   */
  | 'duplicate'
  /**
   * Copy item
   */
  | 'copy'

/** @public */
declare interface ArrayDefinition extends BaseSchemaDefinition {
  type: 'array'
  of: ArrayOfType[]
  initialValue?: InitialValueProperty<any, unknown[]>
  validation?: ValidationBuilder<ArrayRule<unknown[]>, unknown[]>
  options?: ArrayOptions
}

/** @public */
declare type ArrayOfEntry<T> = Omit<T, 'name' | 'hidden'> & {
  name?: string
}

/** @public */
declare type ArrayOfType<
  TType extends IntrinsicTypeName = IntrinsicTypeName,
  TAlias extends IntrinsicTypeName | undefined = undefined,
> = IntrinsicArrayOfDefinition[TType] | ArrayOfEntry<TypeAliasDefinition<string, TAlias>>

/** @public */
declare interface ArrayOptions<V = unknown> extends SearchConfiguration, BaseSchemaTypeOptions {
  list?: TitledListValue<V>[] | V[]
  layout?: 'list' | 'tags' | 'grid'
  /** @deprecated This option does not have any effect anymore */
  direction?: 'horizontal' | 'vertical'
  sortable?: boolean
  modal?: {
    type?: 'dialog' | 'popover'
    width?: number | 'auto'
  }
  /** @alpha This API may change */
  insertMenu?: InsertMenuOptions
  /**
   * A boolean flag to enable or disable tree editing for the array.
   * If there are any nested arrays, they will inherit this value.
   * @deprecated tree editing beta feature has been disabled
   */
  treeEditing?: boolean
  /**
   * A list of array actions to disable
   * Possible options are defined by {@link ArrayActionName}
   * @beta
   */
  disableActions?: ArrayActionName[]
}

/** @public */
declare interface ArrayRule<Value> extends RuleDef<ArrayRule<Value>, Value> {
  min: (length: number | FieldReference) => ArrayRule<Value>
  max: (length: number | FieldReference) => ArrayRule<Value>
  length: (length: number | FieldReference) => ArrayRule<Value>
  unique: () => ArrayRule<Value>
}

/** @public */
declare interface ArraySchemaType<V = unknown> extends BaseSchemaType {
  jsonType: 'array'
  of: (Exclude<SchemaType, ArraySchemaType> | ReferenceSchemaType)[]
  options?: ArrayOptions<V> & {
    layout?: V extends string ? 'tag' : 'grid'
  }
}

export declare interface Asset<
  AssetInstance extends AssetInstanceDocument = AssetInstanceDocument,
> {
  _id: string
  _type: SanityAsset['_type']
  title: string
  assetType: AssetInstance['_type']
  cdnAccessPolicy: SanityAsset['cdnAccessPolicy']
  currentVersion: {
    _ref: string
  }
  aspects?: unknown
  versions: AssetVersion<AssetInstance>[]
  collections: SanityAssetCollection[]
  _createdAt: string
  _updatedAt: string
  _rev: string
  url?: string
}

/** @public */
declare interface Asset_2 extends SanityDocument {
  url: string
  path: string
  assetId: string
  extension: string
  mimeType: string
  sha1hash: string
  size: number
  originalFilename?: string
  label?: string
  title?: string
  description?: string
  creditLine?: string
  source?: AssetSourceSpec
}

export declare interface AssetAspectDocument extends BaseDocument {
  _type: 'sanity.asset.aspect'
  /**
   * The asset type this aspect definition applies to
   * Undefined means that it applies to all asset types
   */
  assetType?: Asset['assetType']
  definition: FieldDefinition
  public?: boolean
}

/** @public */
declare type AssetFromSource = {
  kind: 'assetDocumentId' | 'file' | 'base64' | 'url'
  value: string | File_2
  assetDocumentProps?: ImageAsset
  mediaLibraryProps?: {
    mediaLibraryId: string
    assetId: string
    assetInstanceId: string
  }
}

export declare type AssetInstanceDocument = SanityImageAsset | SanityVideoAsset | SanityFileAsset

export declare interface AssetSelectionItem {
  asset: Asset
  assetInstanceId?: string | null
}

declare interface AssetSelectionItemWithLegacySupport extends AssetSelectionItem {
  assetId: string
  assetType: string
  assetInstanceId: string
}

/** @public */
declare interface AssetSource {
  name: string
  /** @deprecated provide `i18nKey` instead */
  title?: string
  i18nKey?: string
  component: ComponentType<AssetSourceComponentProps>
  icon?: ComponentType<EmptyProps>
  /** @beta */
  Uploader?: AssetSourceUploaderClass
}

/** @public */
declare interface AssetSourceComponentProps {
  action?: 'select' | 'upload'
  assetSource: AssetSource
  assetType?: 'file' | 'image' | 'sanity.video'
  accept: string
  selectionType: 'single'
  dialogHeaderTitle?: React.ReactNode
  selectedAssets: Asset_2[]
  onClose: () => void
  onSelect: (assetFromSource: AssetFromSource[]) => void
  schemaType?: ImageSchemaType | FileSchemaType
  /** @beta */
  uploader?: AssetSourceUploader
}

/** @public */
declare interface AssetSourceSpec {
  id: string
  name: string
  url?: string
}

/** @beta */
declare interface AssetSourceUploader {
  upload(
    files: globalThis.File[],
    options?: {
      /**
       * The schema type of the field the asset is being uploaded to.
       * May be of interest to the uploader to read file and image options.
       */
      schemaType?: SchemaType
      /**
       * The uploader may send patches directly to the field
       * Typed 'unknown' as we don't have patch definitions in sanity/types yet.
       */
      onChange?: (patch: unknown) => void
    },
  ): AssetSourceUploadFile[]
  /**
   * Abort the upload of a file
   */
  abort(file?: AssetSourceUploadFile): void
  /**
   * Get the files that are currently being uploaded
   */
  getFiles(): AssetSourceUploadFile[]
  /**
   * Subscribe to upload events from the uploader
   */
  subscribe(subscriber: (event: AssetSourceUploadEvent) => void): () => void
  /**
   * Update the status of a file. Will be emitted to subscribers.
   */
  updateFile(
    fileId: string,
    data: {
      progress?: number
      status?: string
      error?: Error
    },
  ): void
  /**
   * Reset the uploader (clear files). Should be called by the uploader when all files are done.
   */
  reset(): void
}

/** @beta */
declare type AssetSourceUploaderClass = new (...args: any[]) => AssetSourceUploader

/** @beta */
declare type AssetSourceUploadEvent =
  | AssetSourceUploadEventProgress
  | AssetSourceUploadEventStatus
  | AssetSourceUploadEventAllComplete
  | AssetSourceUploadEventError
  | AssetSourceUploadEventAbort

/**
 * Emitted when all files are done, either successfully, aborted or with errors
 * @beta */
declare type AssetSourceUploadEventAbort = {
  type: 'abort'
  /**
   * Files aborted
   */
  files: AssetSourceUploadFile[]
}

/**
 * Emitted when all files are done, either successfully, aborted or with errors
 * @beta */
declare type AssetSourceUploadEventAllComplete = {
  type: 'all-complete'
  files: AssetSourceUploadFile[]
}

/**
 * Emitted when all files are done, either successfully, aborted or with errors
 * @beta */
declare type AssetSourceUploadEventError = {
  type: 'error'
  /**
   * Files errored
   */
  files: AssetSourceUploadFile[]
}

/**
 * Emitted when a file upload is progressing
 * @beta */
declare type AssetSourceUploadEventProgress = {
  type: 'progress'
  file: AssetSourceUploadFile
  progress: number
}

/**
 * Emitted when a file upload is changing status
 * @beta */
declare type AssetSourceUploadEventStatus = {
  type: 'status'
  file: AssetSourceUploadFile
  status: AssetSourceUploadFile['status']
}

/** @beta */
declare interface AssetSourceUploadFile {
  id: string
  file: globalThis.File
  progress: number
  status: 'pending' | 'uploading' | 'complete' | 'error' | 'aborted' | 'alreadyExists'
  error?: Error
  result?: unknown
}

export declare interface AssetVersion<
  AssetInstance extends AssetInstanceDocument = AssetInstanceDocument,
> {
  _key: string
  _type: SanityAssetVersion['_type']
  title?: string
  instance: AssetInstance
}

export declare type BaseDocument = {
  _id: string
  _type: string
  _rev: string
  _createdAt: string
  _updatedAt: string
  [key: string]: any
}

/** @public */
declare interface BaseSchemaDefinition {
  name: string
  title?: string
  description?: string | React.JSX.Element
  hidden?: ConditionalProperty
  readOnly?: ConditionalProperty
  icon?: ComponentType | ReactNode
  validation?: unknown
  initialValue?: unknown
  deprecated?: DeprecatedProperty
}

/** @public */
declare interface BaseSchemaType extends Partial<DeprecationConfiguration> {
  name: string
  title?: string
  description?: string
  type?: SchemaType
  liveEdit?: boolean
  readOnly?: ConditionalProperty
  hidden?: ConditionalProperty
  icon?: ComponentType
  initialValue?: InitialValueProperty<any, any>
  validation?: SchemaValidationValue
  preview?: PreviewConfig
  /** @beta */
  components?: {
    block?: ComponentType<any>
    inlineBlock?: ComponentType<any>
    annotation?: ComponentType<any>
    diff?: ComponentType<any>
    field?: ComponentType<any>
    input?: ComponentType<any>
    item?: ComponentType<any>
    preview?: ComponentType<any>
    portableText?: {
      plugins?: ComponentType<any>
    }
  }
  /**
   * @deprecated This will be removed.
   */
  placeholder?: string
}

/**
 * `BaseOptions` applies to all type options.
 *
 *  It can be extended by interface declaration merging in plugins to provide generic options to all types and fields.
 *
 *  @public
 *  */
declare interface BaseSchemaTypeOptions {
  sanityCreate?: SanityCreateOptions
  canvasApp?: CanvasAppOptions
}

/**
 * Schema definition for text block decorators.
 *
 * @public
 * @example The default set of decorators
 * ```ts
 * {
 *   name: 'blockContent',
 *   title: 'Content',
 *   type: 'array',
 *   of: [
 *     {
 *       type: 'block',
 *       marks: {
 *         decorators: [
 *           {title: 'Strong', value: 'strong'},
 *           {title: 'Emphasis', value: 'em'},
 *           {title: 'Underline', value: 'underline'},
 *           {title: 'Strike', value: 'strike-through'},
 *           {title: 'Code', value: 'code'},
 *         ]
 *       }
 *     }
 *   ]
 * }
 * ```
 */
declare interface BlockDecoratorDefinition {
  title: string
  i18nTitleKey?: string
  value: string
  icon?: ReactNode | ComponentType
}

/**
 * Schema definition for text blocks.
 *
 * @public
 * @example the default block definition
 * ```ts
 * {
 *   name: 'blockContent',
 *   title: 'Content',
 *   type: 'array',
 *   of: [
 *     {
 *       type: 'block',
 *       marks: {
 *         decorators: [
 *           {title: 'Strong', value: 'strong'},
 *           {title: 'Emphasis', value: 'em'},
 *           {title: 'Underline', value: 'underline'},
 *           {title: 'Strike', value: 'strike-through'},
 *           {title: 'Code', value: 'code'},
 *         ],
 *         annotations: [
 *           {
 *             type: 'object',
 *             name: 'link',
 *             fields: [
 *               {
 *                 type: 'string',
 *                 name: 'href',
 *               },
 *             ],
 *           },
 *         ]
 *       },
 *       styles: [
 *         {title: 'Normal', value: 'normal'},
 *         {title: 'H1', value: 'h1'},
 *         {title: 'H2', value: 'h2'},
 *         {title: 'H3', value: 'h3'},
 *         {title: 'H4', value: 'h4'},
 *         {title: 'H5', value: 'h5'},
 *         {title: 'H6', value: 'h6'},
 *         {title: 'Quote', value: 'blockquote'}
 *       ],
 *       lists: [
 *         {title: 'Bullet', value: 'bullet'},
 *         {title: 'Number', value: 'number'},
 *       ],
 *     },
 *   ]
 * }
 * ```
 */
declare interface BlockDefinition extends BaseSchemaDefinition {
  type: 'block'
  styles?: BlockStyleDefinition[]
  lists?: BlockListDefinition[]
  marks?: BlockMarksDefinition
  of?: ArrayOfType<'object' | 'reference'>[]
  initialValue?: InitialValueProperty<any, any[]>
  options?: BlockOptions
  validation?: ValidationBuilder<BlockRule, any[]>
}

/**
 * Schema definition for a text block list style.
 *
 * @public
 * @example The defaults lists
 * ```ts
 * {
 *   name: 'blockContent',
 *   title: 'Content',
 *   type: 'array',
 *   of: [
 *     {
 *       type: 'block',
 *       lists: [
 *         {title: 'Bullet', value: 'bullet'},
 *         {title: 'Number', value: 'number'},
 *       ]
 *     }
 *   ]
 * }
 * ```
 */
declare interface BlockListDefinition {
  title: string
  i18nTitleKey?: string
  value: string
  icon?: ReactNode | ComponentType
}

/**
 * Schema definition for text block marks (decorators and annotations).
 *
 * @public */
declare interface BlockMarksDefinition {
  decorators?: BlockDecoratorDefinition[]
  annotations?: ArrayOfType<'object' | 'reference'>[]
}

/**
 * Schema options for a Block schema definition
 * @public */
declare interface BlockOptions extends BaseSchemaTypeOptions {
  /**
   * Turn on or off the builtin browser spellchecking. Default is on.
   */
  spellCheck?: boolean
  unstable_whitespaceOnPasteMode?: 'preserve' | 'normalize' | 'remove'
  /**
   * When enabled, the editor will restrict all line breaks and soft breaks,
   * forcing content to remain on a single line. This will also update
   * the styling of the editor to reflect the single-line constraint.
   *
   * Pasting content that is on multiple lines will be normalized to a single line, if possible.
   *
   * @defaultValue false
   */
  oneLine?: boolean
}

/** @public */
declare interface BlockRule extends RuleDef<BlockRule, any[]> {}

/**
 * Schema definition for a text block style.
 * A text block may have a block style like 'header', 'normal', 'lead'
 * attached to it, which is stored on the `.style` property for that block.
 *
 * @public
 * @remarks The first defined style will become the default style.´´
 * @example The default set of styles
 * ```ts
 * {
 *   name: 'blockContent',
 *   title: 'Content',
 *   type: 'array',
 *   of: [
 *     {
 *       type: 'block',
 *       styles: [
 *         {title: 'Normal', value: 'normal'},
 *         {title: 'H1', value: 'h1'},
 *         {title: 'H2', value: 'h2'},
 *         {title: 'H3', value: 'h3'},
 *         {title: 'H4', value: 'h4'},
 *         {title: 'H5', value: 'h5'},
 *         {title: 'H6', value: 'h6'},
 *         {title: 'Quote', value: 'blockquote'}
 *       ]
 *     }
 *   ]
 * }
 * ```
 * @example Example of defining a block type with custom styles and render components.
 * ```ts
 * defineArrayMember({
 *   type: 'block',
 *   styles: [
 *     {
 *       title: 'Paragraph',
 *       value: 'paragraph',
 *       component: ParagraphStyle,
 *     },
 *     {
 *       title: 'Lead',
 *       value: 'lead',
 *       component: LeadStyle,
 *     },
 *     {
 *       title: 'Heading',
 *       value: 'heading',
 *       component: HeadingStyle,
 *     },
 *   ],
 * })
 * ```
 */
declare interface BlockStyleDefinition {
  title: string
  value: string
  i18nTitleKey?: string
  icon?: ReactNode | ComponentType
}

/** @public */
declare interface BooleanDefinition extends BaseSchemaDefinition {
  type: 'boolean'
  options?: BooleanOptions
  initialValue?: InitialValueProperty<any, boolean>
  validation?: ValidationBuilder<BooleanRule, boolean>
}

/** @public */
declare interface BooleanOptions extends BaseSchemaTypeOptions {
  layout?: 'switch' | 'checkbox'
}

/** @public */
declare interface BooleanRule extends RuleDef<BooleanRule, boolean> {}

/** @public */
declare interface BooleanSchemaType extends BaseSchemaType {
  jsonType: 'boolean'
  options?: BooleanOptions
  initialValue?: InitialValueProperty<any, boolean>
}

/**
 * Options for configuring how Canvas app interfaces with the type or field.
 *
 * @public
 */
declare interface CanvasAppOptions {
  /** Set to true to exclude a type or field from appearing in Canvas */
  exclude?: boolean
  /**
   * A short description of what the type or field is used for.
   * Purpose can be used to improve how and when content mapping uses the field.
   * */
  purpose?: string
}

/** @public */
declare interface CollapseOptions {
  collapsed?: boolean
  collapsible?: boolean
  /**
   * @deprecated Use `collapsible` instead
   */
  collapsable?: boolean
}

/** @public */
declare type ConditionalProperty = boolean | ConditionalPropertyCallback | undefined

/** @public */
declare type ConditionalPropertyCallback = (context: ConditionalPropertyCallbackContext) => boolean

/** @public */
declare interface ConditionalPropertyCallbackContext {
  document: SanityDocument | undefined
  parent: any
  value: any
  currentUser: Omit<CurrentUser, 'role'> | null
}

/** @public */
declare interface CrossDatasetReferenceDefinition extends BaseSchemaDefinition {
  type: 'crossDatasetReference'
  weak?: boolean
  to: {
    type: string
    title?: string
    icon?: ComponentType
    preview?: PreviewConfig
    /**
     * @deprecated Unused. Configuring search is no longer supported.
     */
    __experimental_search?: {
      path: string | string[]
      weight?: number
      mapWith?: string
    }[]
  }[]
  dataset: string
  studioUrl?: (document: {id: string; type?: string}) => string | null
  tokenId?: string
  options?: ReferenceOptions
  /**
   * @deprecated Cross-project references are no longer supported, only cross-dataset
   */
  projectId?: string
}

/** @public */
declare interface CurrentUser {
  id: string
  name: string
  email: string
  profileImage?: string
  provider?: string
  /** @deprecated use `roles` instead */
  role: string
  roles: Role[]
}

/** @public */
declare interface CustomValidator<T = unknown> {
  (value: T, context: ValidationContext): CustomValidatorResult | Promise<CustomValidatorResult>
  bypassConcurrencyLimit?: boolean
}

/** @public */
declare type CustomValidatorResult =
  | true
  | string
  | ValidationError
  | ValidationError[]
  | LocalizedValidationMessages

/** @public */
declare interface DateDefinition extends BaseSchemaDefinition {
  type: 'date'
  options?: DateOptions
  placeholder?: string
  validation?: ValidationBuilder<DateRule, string>
  initialValue?: InitialValueProperty<any, string>
}

/** @public */
declare interface DateOptions extends BaseSchemaTypeOptions {
  dateFormat?: string
}

/** @public */
declare interface DateRule extends RuleDef<DateRule, string> {
  /**
   * @param minDate - Minimum date (inclusive). minDate should be in ISO 8601 format.
   */
  min: (minDate: string | FieldReference) => DateRule
  /**
   * @param maxDate - Maximum date (inclusive). maxDate should be in ISO 8601 format.
   */
  max: (maxDate: string | FieldReference) => DateRule
}

/** @public */
declare interface DatetimeDefinition extends BaseSchemaDefinition {
  type: 'datetime'
  options?: DatetimeOptions
  placeholder?: string
  validation?: ValidationBuilder<DatetimeRule, string>
  initialValue?: InitialValueProperty<any, string>
}

/** @public */
declare interface DatetimeOptions extends BaseSchemaTypeOptions {
  dateFormat?: string
  timeFormat?: string
  timeStep?: number
  displayTimeZone?: string
  allowTimeZoneSwitch?: boolean
}

/** @public */
declare interface DatetimeRule extends RuleDef<DatetimeRule, string> {
  /**
   * @param minDate - Minimum date (inclusive). minDate should be in ISO 8601 format.
   */
  min: (minDate: string | FieldReference) => DatetimeRule
  /**
   * @param maxDate - Maximum date (inclusive). maxDate should be in ISO 8601 format.
   */
  max: (maxDate: string | FieldReference) => DatetimeRule
}

/** @public */
declare interface DeprecatedProperty {
  reason: string
}

/**
 * @public
 */
declare interface DeprecationConfiguration {
  deprecated: DeprecatedProperty
}

/** @public */
declare interface DocumentDefinition extends Omit<ObjectDefinition, 'type'> {
  type: 'document'
  liveEdit?: boolean
  /** @beta */
  orderings?: SortOrdering[]
  options?: DocumentOptions
  validation?: ValidationBuilder<DocumentRule, SanityDocument>
  initialValue?: InitialValueProperty<any, Record<string, unknown>>
  /** @deprecated Unused. Use the new field-level search config. */
  __experimental_search?: {
    path: string
    weight: number
    mapWith?: string
  }[]
  /** @alpha */
  __experimental_omnisearch_visibility?: boolean
  /**
   * Determines whether the large preview title is displayed in the document pane form
   * @alpha
   * */
  __experimental_formPreviewTitle?: boolean
}

/**
 * This exists only to allow for extensions using declaration-merging.
 *
 * @public
 */
declare interface DocumentOptions extends BaseSchemaTypeOptions {}

/** @public */
declare interface DocumentRule extends RuleDef<DocumentRule, SanityDocument> {}

/** @public */
declare interface EmailDefinition extends BaseSchemaDefinition {
  type: 'email'
  options?: EmailOptions
  placeholder?: string
  validation?: ValidationBuilder<EmailRule, string>
  initialValue?: InitialValueProperty<any, string>
}

/** @public */
declare interface EmailOptions extends BaseSchemaTypeOptions {}

/** @public */
declare interface EmailRule extends RuleDef<EmailRule, string> {}

/** @public */
declare interface EmptyProps {}

/** @public */
declare interface EnumListProps<V = unknown> {
  list?: Array<TitledListValue<V> | V>
  layout?: 'radio' | 'dropdown'
  direction?: 'horizontal' | 'vertical'
}

/**
 * The shape of a field definition. Note, it's recommended to use the
 * `defineField` function instead of using this type directly.
 *
 * Where `defineField` infers the exact field type,
 * FieldDefinition is a compromise union of all types a field can have.
 *
 * A field definition can be a reference to another registered top-level type
 * or a inline type definition.
 *
 * @public
 */
declare type FieldDefinition<
  TType extends IntrinsicTypeName = IntrinsicTypeName,
  TAlias extends IntrinsicTypeName | undefined = undefined,
> = (InlineFieldDefinition[TType] | TypeAliasDefinition<string, TAlias>) & FieldDefinitionBase

/** @public */
declare interface FieldDefinitionBase {
  fieldset?: string
  group?: string | string[]
}

/** @public */
declare interface FieldGroup {
  name: string
  icon?: ComponentType
  title?: string
  description?: string
  i18n?: I18nTextRecord<'title'>
  hidden?: ConditionalProperty
  default?: boolean
  fields?: ObjectField[]
}

/** @public */
declare type FieldGroupDefinition = {
  name: string
  title?: string
  hidden?: ConditionalProperty
  icon?: ComponentType
  default?: boolean
  i18n?: I18nTextRecord<'title'>
}

/**
 * Holds a reference to a different field
 * NOTE: Only use this through {@link Rule.valueOfField}
 *
 * @public
 */
declare interface FieldReference {
  type: symbol
  path: string | string[]
}

/** @public */
declare type FieldRules = {
  [fieldKey: string]: SchemaValidationValue
}

/** @public */
declare type Fieldset = SingleFieldSet | MultiFieldSet

/** @public */
declare type FieldsetDefinition = {
  name: string
  title?: string
  description?: string
  group?: string
  hidden?: ConditionalProperty
  readOnly?: ConditionalProperty
  options?: ObjectOptions
}

/** @public */
declare interface File_2 {
  [key: string]: unknown
  asset?: Reference
}

/** @public */
declare interface FileDefinition
  extends Omit<ObjectDefinition, 'type' | 'fields' | 'options' | 'groups' | 'validation'> {
  type: 'file'
  fields?: ObjectDefinition['fields']
  options?: FileOptions
  validation?: ValidationBuilder<FileRule, FileValue>
  initialValue?: InitialValueProperty<any, FileValue>
}

/** @public */
declare interface FileOptions extends ObjectOptions {
  storeOriginalFilename?: boolean
  accept?: string
  sources?: AssetSource[]
  mediaLibrary?: MediaLibraryOptions
}

/** @public */
declare interface FileRule extends RuleDef<FileRule, FileValue> {
  /**
   * Require a file field has an asset.
   *
   * @example
   * ```ts
   * defineField({
   *  name: 'file',
   *  title: 'File',
   *  type: 'file',
   *  validation: (Rule) => Rule.required().assetRequired(),
   * })
   * ```
   */
  assetRequired(): FileRule
}

/** @public */
declare interface FileSchemaType extends Omit<ObjectSchemaType, 'options'> {
  options?: FileOptions
}

export declare type FileStatus = 'pending' | 'uploading' | 'complete' | 'error' | 'alreadyExists'

/**
 * Wrapper object for the file upload with progress and status
 */
export declare interface FileUpload {
  id: string
  file: File
  status: FileStatus
  progress: number
  error?: Error
}

/** @public */
declare interface FileValue {
  asset?: Reference
  [index: string]: unknown
}

declare type Geopoint = {
  _type: 'geopoint'
  lat?: number
  lng?: number
  alt?: number
}

/** @public */
declare interface GeopointDefinition extends BaseSchemaDefinition {
  type: 'geopoint'
  options?: GeopointOptions
  validation?: ValidationBuilder<GeopointRule, GeopointValue>
  initialValue?: InitialValueProperty<any, Omit<GeopointValue, '_type'>>
}

/** @public */
declare interface GeopointOptions extends BaseSchemaTypeOptions {}

/** @public */
declare interface GeopointRule extends RuleDef<GeopointRule, GeopointValue> {}

/**
 * Geographical point representing a pair of latitude and longitude coordinates,
 * stored as degrees, in the World Geodetic System 1984 (WGS 84) format. Also
 * includes an optional `alt` property representing the altitude in meters.
 *
 * @public
 */
declare interface GeopointValue {
  /**
   * Type of the object. Must be `geopoint`.
   */
  _type: 'geopoint'
  /**
   * Latitude in degrees
   */
  lat: number
  /**
   * Longitude in degrees
   */
  lng: number
  /**
   * Altitude in meters
   */
  alt?: number
}

/** @public */
declare interface GlobalDocumentReferenceDefinition extends BaseSchemaDefinition {
  type: 'globalDocumentReference'
  weak?: boolean
  to: {
    type: string
    title?: string
    icon?: ComponentType
    preview?: PreviewConfig
  }[]
  resourceType: string
  resourceId: string
  options?: ReferenceOptions
  studioUrl?: string | ((document: {id: string; type?: string}) => string | null)
}

/** @public */
declare interface HotspotOptions {
  previews?: HotspotPreview[]
}

/** @public */
declare interface HotspotPreview {
  title: string
  aspectRatio: number
}

/** @public */
declare type I18nTextRecord<K extends string> = {
  [P in K]?: {
    key: string
    ns: string
  }
}

/** @public */
declare interface ImageAsset extends Asset_2 {
  _type: 'sanity.imageAsset'
  metadata: ImageMetadata
}

/** @public */
declare interface ImageCrop {
  _type?: 'sanity.imageCrop'
  left: number
  bottom: number
  right: number
  top: number
}

/** @public */
declare interface ImageDefinition
  extends Omit<ObjectDefinition, 'type' | 'fields' | 'options' | 'groups' | 'validation'> {
  type: 'image'
  fields?: FieldDefinition[]
  options?: ImageOptions
  validation?: ValidationBuilder<ImageRule, ImageValue>
  initialValue?: InitialValueProperty<any, ImageValue>
}

/** @public */
declare interface ImageDimensions {
  _type: 'sanity.imageDimensions'
  height: number
  width: number
  aspectRatio: number
}

/** @public */
declare interface ImageHotspot {
  _type?: 'sanity.imageHotspot'
  width: number
  height: number
  x: number
  y: number
}

/** @public */
declare interface ImageMetadata {
  [key: string]: unknown
  _type: 'sanity.imageMetadata'
  dimensions: ImageDimensions
  palette?: ImagePalette
  lqip?: string
  blurHash?: string
  hasAlpha: boolean
  isOpaque: boolean
}

/** @public */
declare type ImageMetadataType = 'blurhash' | 'lqip' | 'palette' | 'exif' | 'image' | 'location'

/** @public */
declare interface ImageOptions extends FileOptions {
  metadata?: ImageMetadataType[]
  hotspot?: boolean | HotspotOptions
}

/** @public */
declare interface ImagePalette {
  _type: 'sanity.imagePalette'
  darkMuted?: ImageSwatch
  darkVibrant?: ImageSwatch
  dominant?: ImageSwatch
  lightMuted?: ImageSwatch
  lightVibrant?: ImageSwatch
  muted?: ImageSwatch
  vibrant?: ImageSwatch
}

/** @public */
declare interface ImageRule extends RuleDef<ImageRule, ImageValue> {
  /**
   * Require an image field has an asset.
   *
   * @example
   * ```ts
   * defineField({
   *  name: 'image',
   *  title: 'Image',
   *  type: 'image',
   *  validation: (Rule) => Rule.required().assetRequired(),
   * })
   * ```
   */
  assetRequired(): ImageRule
}

/** @public */
declare interface ImageSchemaType extends Omit<ObjectSchemaType, 'options'> {
  options?: ImageOptions
}

/** @public */
declare interface ImageSwatch {
  _type: 'sanity.imagePaletteSwatch'
  background: string
  foreground: string
  population: number
  title?: string
}

/** @public */
declare interface ImageValue extends FileValue {
  crop?: ImageCrop
  hotspot?: ImageHotspot
  [index: string]: unknown
}

/** @public */
declare type IndexTuple = [number | '', number | '']

/** @public */
declare type InitialValueProperty<Params, Value> =
  | Value
  | InitialValueResolver<Params, Value>
  | undefined

/** @public */
declare type InitialValueResolver<Params, Value> = (
  params: Params | undefined,
  context: InitialValueResolverContext,
) => Promise<Value> | Value

/** @public */
declare interface InitialValueResolverContext {
  projectId: string
  dataset: string
  schema: Schema
  currentUser: CurrentUser | null
  getClient: (options: {apiVersion: string}) => SanityClient
}

/** @public */
declare type InlineFieldDefinition = {
  [K in keyof IntrinsicDefinitions]: Omit<
    IntrinsicDefinitions[K],
    'initialValue' | 'validation'
  > & {
    validation?: SchemaValidationValue
    initialValue?: InitialValueProperty<any, any>
  }
}

/** @alpha This API may change */
declare interface InsertMenuOptions {
  /**
   * @defaultValue `'auto'`
   * `filter: 'auto'` automatically turns on filtering if there are more than 5
   * schema types added to the menu.
   */
  filter?: 'auto' | boolean | undefined
  groups?:
    | Array<{
        name: string
        title?: string
        of?: Array<string>
      }>
    | undefined
  /** defaultValue `true` */
  showIcons?: boolean | undefined
  /** @defaultValue `[{name: 'list'}]` */
  views?:
    | Array<
        | {
            name: 'list'
          }
        | {
            name: 'grid'
            previewImageUrl?: (schemaTypeName: string) => string | undefined
          }
      >
    | undefined
}

declare const internalGroqTypeReferenceTo: unique symbol

/** @public */
declare type IntrinsicArrayOfDefinition = {
  [K in keyof IntrinsicDefinitions]: Omit<
    ArrayOfEntry<IntrinsicDefinitions[K]>,
    'validation' | 'initialValue'
  > & {
    validation?: SchemaValidationValue
    initialValue?: InitialValueProperty<any, any>
  }
}

/**
 * `IntrinsicDefinitions` is a lookup map for "predefined" schema definitions.
 * Schema types in `IntrinsicDefinitions` will have good type-completion and type-safety in {@link defineType},
 * {@link defineField} and {@link defineArrayMember} once the `type` property is provided.
 *
 * By default, `IntrinsicDefinitions` contains all standard Sanity schema types (`array`, `string`, `number` ect),
 * but it is an interface and as such, open for extension.
 *
 * This type can be extended using declaration merging; this way new entries can be added.
 * See {@link defineType} for examples on how this can be accomplished.
 *
 * @see defineType
 *
 * @public
 */
declare interface IntrinsicDefinitions {
  array: ArrayDefinition
  block: BlockDefinition
  boolean: BooleanDefinition
  date: DateDefinition
  datetime: DatetimeDefinition
  document: DocumentDefinition
  file: FileDefinition
  geopoint: GeopointDefinition
  image: ImageDefinition
  number: NumberDefinition
  object: ObjectDefinition
  reference: ReferenceDefinition
  crossDatasetReference: CrossDatasetReferenceDefinition
  globalDocumentReference: GlobalDocumentReferenceDefinition
  slug: SlugDefinition
  string: StringDefinition
  text: TextDefinition
  url: UrlDefinition
  email: EmailDefinition
}

/**
 * A union of all intrinsic types allowed natively in the schema.
 *
 * @see IntrinsicDefinitions
 *
 * @public
 */
declare type IntrinsicTypeName = IntrinsicDefinitions[keyof IntrinsicDefinitions]['type']

/** @public */
declare type KeyedSegment = {
  _key: string
}

/**
 * Holds localized validation messages for a given field.
 *
 * @example Custom message for English (US) and Norwegian (Bokmål):
 * ```
 * {
 *   'en-US': 'Needs to start with a capital letter',
 *   'no-NB': 'Må starte med stor bokstav',
 * }
 * ```
 * @public
 */
declare interface LocalizedValidationMessages {
  [locale: string]: string
}

/** @public */
declare type MediaAssetTypes = AssetInstanceDocument_2['_type']

/** @public */
declare interface MediaLibraryFilter {
  name: string
  query: string
}

/** @public */
declare interface MediaLibraryOptions {
  filters?: MediaLibraryFilter[]
}

/** @public */
declare interface MediaValidationValue<T extends MediaAssetTypes = MediaAssetTypes> {
  /**
   * Media information
   */
  media: {
    /**
     * The Media Library Asset.
     */
    asset: Asset_3 & {
      currentVersion: Extract<
        AssetInstanceDocument_2,
        {
          _type: T
        }
      >
    }
  }
  /**
   * The field value which the media is used in.
   */
  value: unknown
}

/** @public */
declare interface MediaValidator<T extends MediaAssetTypes = MediaAssetTypes> {
  (
    value: MediaValidationValue<T>,
    context: ValidationContext,
  ): CustomValidatorResult | Promise<CustomValidatorResult>
}

/** @public */
declare interface MultiFieldSet {
  name: string
  title?: string
  description?: string
  single?: false
  group?: string | string[]
  options?: CollapseOptions & {
    columns?: number
  }
  fields: ObjectField[]
  hidden?: ConditionalProperty
  readOnly?: ConditionalProperty
}

/** @public */
declare interface NumberDefinition extends BaseSchemaDefinition {
  type: 'number'
  options?: NumberOptions
  placeholder?: string
  validation?: ValidationBuilder<NumberRule, number>
  initialValue?: InitialValueProperty<any, number>
}

/** @public */
declare interface NumberOptions extends EnumListProps<number>, BaseSchemaTypeOptions {}

/** @public */
declare interface NumberRule extends RuleDef<NumberRule, number> {
  min: (minNumber: number | FieldReference) => NumberRule
  max: (maxNumber: number | FieldReference) => NumberRule
  lessThan: (limit: number | FieldReference) => NumberRule
  greaterThan: (limit: number | FieldReference) => NumberRule
  integer: () => NumberRule
  precision: (limit: number | FieldReference) => NumberRule
  positive: () => NumberRule
  negative: () => NumberRule
}

/** @public */
declare interface NumberSchemaType extends BaseSchemaType {
  jsonType: 'number'
  options?: NumberOptions
  initialValue?: InitialValueProperty<any, number>
}

/** @public */
declare interface ObjectDefinition extends BaseSchemaDefinition {
  type: 'object'
  /**
   * Object must have at least one field. This is validated at Studio startup.
   */
  fields: FieldDefinition[]
  groups?: FieldGroupDefinition[]
  fieldsets?: FieldsetDefinition[]
  preview?: PreviewConfig
  options?: ObjectOptions
  validation?: ValidationBuilder<ObjectRule, Record<string, unknown>>
  initialValue?: InitialValueProperty<any, Record<string, unknown>>
}

/** @public */
declare interface ObjectField<T extends SchemaType = SchemaType> {
  name: string
  fieldset?: string
  group?: string | string[]
  type: ObjectFieldType<T>
}

/** @public */
declare type ObjectFieldType<T extends SchemaType = SchemaType> = T & {
  hidden?: ConditionalProperty
  readOnly?: ConditionalProperty
}

/** @public */
declare interface ObjectOptions extends BaseSchemaTypeOptions {
  collapsible?: boolean
  collapsed?: boolean
  columns?: number
  modal?: {
    type?: 'dialog' | 'popover'
    width?: number | number[] | 'auto'
  }
}

/** @public */
declare interface ObjectRule extends RuleDef<ObjectRule, Record<string, unknown>> {}

/** @public */
declare interface ObjectSchemaType extends BaseSchemaType {
  jsonType: 'object'
  fields: ObjectField[]
  groups?: FieldGroup[]
  fieldsets?: Fieldset[]
  initialValue?: InitialValueProperty<any, Record<string, unknown>>
  weak?: boolean
  /** @deprecated Unused. Use the new field-level search config. */
  __experimental_search?: {
    path: (string | number)[]
    weight: number
    mapWith?: string
  }[]
  /** @alpha */
  __experimental_omnisearch_visibility?: boolean
  /** @alpha */
  __experimental_actions?: string[]
  /** @alpha */
  __experimental_formPreviewTitle?: boolean
  /**
   * @beta
   */
  orderings?: SortOrdering[]
  options?: any
}

/** @public */
declare type Path = PathSegment[]

/** @public */
declare type PathSegment = string | number | KeyedSegment | IndexTuple

export declare type PluginPostMessage =
  | PluginPostMessageAbortUploadRequest
  | PluginPostMessageAssetSelection
  | PluginPostMessageDocumentUpdate
  | PluginPostMessagePageLoaded
  | PluginPostMessagePageUnloaded
  | PluginPostMessageTokenRequest
  | PluginPostMessageTokenResponse
  | PluginPostMessageUploadFilesProgress
  | PluginPostMessageUploadFilesRequest
  | PluginPostMessageUploadFilesResponse

export declare type PluginPostMessageAbortUploadRequest = {
  type: 'abortUploadRequest'
  files?: {
    id: string
  }[]
}

export declare type PluginPostMessageAssetSelection = {
  type: 'assetSelection'
  selection: AssetSelectionItemWithLegacySupport[]
}

/**
 * Message sent from the plugin that a document has been updated
 */
export declare type PluginPostMessageDocumentUpdate = {
  type: 'documentUpdate'
  document: {
    _id: string
    _type: string
    _rev: string
  }
}

/**
 * Message sent from a plugin page to notify the host that the page is loaded and ready to be interacted with
 */
export declare type PluginPostMessagePageLoaded = {
  type: 'pageLoaded'
  page: string
}

/**
 * Message sent from a plugin page that a page is unloaded by the user (for closing the dialog and similar)
 */
export declare type PluginPostMessagePageUnloaded = {
  type: 'pageUnloaded'
  page: string
}

export declare type PluginPostMessageTokenRequest = {
  type: 'tokenRequest'
}

export declare type PluginPostMessageTokenResponse = {
  type: 'tokenResponse'
  token: string | null
}

/**
 * Message sent from the plugin when files are uploading
 */
export declare type PluginPostMessageUploadFilesProgress = {
  type: 'uploadProgress'
  files: FileUpload[]
}

/**
 * Message sent from the plugin that the user wants to upload files
 */
export declare type PluginPostMessageUploadFilesRequest = {
  type: 'uploadRequest'
  files: {
    id: string
    file: File
  }[]
}

/**
 * Message sent from the app that the pending uploads are uploaded
 */
export declare type PluginPostMessageUploadFilesResponse = {
  type: 'uploadResponse'
  assets: AssetSelectionItemWithLegacySupport[]
}

/** @public */
declare interface PrepareViewOptions {
  /** @beta */
  ordering?: SortOrdering
}

/** @public */
declare interface PreviewConfig<
  Select extends Record<string, string> = Record<string, string>,
  PrepareValue extends Record<keyof Select, any> = Record<keyof Select, any>,
> {
  select?: Select
  prepare?: (value: PrepareValue, viewOptions?: PrepareViewOptions) => PreviewValue
}

/** @public */
declare interface PreviewValue {
  _id?: string
  _createdAt?: string
  _updatedAt?: string
  title?: string
  subtitle?: string
  description?: string
  media?: ReactNode | ElementType
  imageUrl?: string
}

/** @public */
declare interface Reference {
  _type: string
  _ref: string
  _key?: string
  _weak?: boolean
  _strengthenOnPublish?: {
    type: string
    weak?: boolean
    template?: {
      id: string
      params: Record<string, string | number | boolean>
    }
  }
}

/** @public */
declare interface ReferenceBaseOptions extends BaseSchemaTypeOptions {
  disableNew?: boolean
}

/** @public */
declare interface ReferenceDefinition extends BaseSchemaDefinition {
  type: 'reference'
  to: ReferenceTo
  weak?: boolean
  options?: ReferenceOptions
  validation?: ValidationBuilder<ReferenceRule, ReferenceValue>
  initialValue?: InitialValueProperty<any, Omit<ReferenceValue, '_type'>>
}

/** @public */
declare type ReferenceFilterOptions = ReferenceFilterResolverOptions | ReferenceFilterQueryOptions

/** @public */
declare interface ReferenceFilterQueryOptions {
  filter: string
  filterParams?: Record<string, unknown>
}

/** @public */
declare type ReferenceFilterResolver = (
  context: ReferenceFilterResolverContext,
) => ReferenceFilterSearchOptions | Promise<ReferenceFilterSearchOptions>

/** @public */
declare interface ReferenceFilterResolverContext {
  document: SanityDocument
  parent?: Record<string, unknown> | Record<string, unknown>[]
  parentPath: Path
  getClient: (options: {apiVersion: string}) => SanityClient
}

/** @public */
declare interface ReferenceFilterResolverOptions {
  filter?: ReferenceFilterResolver
  filterParams?: never
}

/** @public */
declare type ReferenceFilterSearchOptions = {
  filter?: string
  params?: Record<string, unknown>
  tag?: string
  maxFieldDepth?: number
  strategy?: SearchStrategy
  perspective?: ClientPerspective
}

/**
 * Types are closed for extension. To add properties via declaration merging to this type,
 * redeclare and add the properties to the interfaces that make up ReferenceOptions type.
 *
 * @see ReferenceFilterOptions
 * @see ReferenceFilterResolverOptions
 * @see ReferenceBaseOptions
 *
 * @public
 */
declare type ReferenceOptions = ReferenceBaseOptions & ReferenceFilterOptions

/** @public */
declare interface ReferenceRule extends RuleDef<ReferenceRule, ReferenceValue> {}

/** @public */
declare interface ReferenceSchemaType extends Omit<ObjectSchemaType, 'options'> {
  jsonType: 'object'
  to: ObjectSchemaType[]
  weak?: boolean
  options?: ReferenceOptions
}

/** @public */
declare type ReferenceTo =
  | SchemaTypeDefinition
  | TypeReference
  | Array<SchemaTypeDefinition | TypeReference>

/** @public */
declare type ReferenceValue = Reference

/** @public */
declare interface Role {
  name: string
  title: string
  description?: string
}

/** @public */
declare interface Rule {
  /**
   * @internal
   * @deprecated internal use only
   */
  _type: RuleTypeConstraint | undefined
  /**
   * @internal
   * @deprecated internal use only
   */
  _level: 'error' | 'warning' | 'info' | undefined
  /**
   * @internal
   * @deprecated internal use only
   */
  _required: 'required' | 'optional' | undefined
  /**
   * @internal
   * @deprecated internal use only
   */
  _typeDef: SchemaType | undefined
  /**
   * @internal
   * @deprecated internal use only
   */
  _message: string | LocalizedValidationMessages | undefined
  /**
   * @internal
   * @deprecated internal use only
   */
  _rules: RuleSpec[]
  /**
   * @internal
   * @deprecated internal use only
   */
  _fieldRules: FieldRules | undefined
  /**
   * Takes in a path and returns an object with a symbol.
   *
   * When the validation lib sees this symbol, it will use the provided path to
   * get a value from the current field's parent and use that value as the input
   * to the Rule.
   *
   * The path that's given is forwarded to `lodash/get`
   *
   * ```js
   * fields: [
   * // ...
   *   {
   *     // ...
   *     name: 'highestTemperature',
   *     type: 'number',
   *     validation: (Rule) => Rule.positive().min(Rule.valueOfField('lowestTemperature')),
   *     // ...
   *   },
   * ]
   * ```
   */
  valueOfField: (path: string | string[]) => FieldReference
  error(message?: string | LocalizedValidationMessages): Rule
  warning(message?: string | LocalizedValidationMessages): Rule
  info(message?: string | LocalizedValidationMessages): Rule
  reset(): this
  isRequired(): boolean
  clone(): Rule
  cloneWithRules(rules: RuleSpec[]): Rule
  merge(rule: Rule): Rule
  type(targetType: RuleTypeConstraint | Lowercase<RuleTypeConstraint>): Rule
  all(children: Rule[]): Rule
  either(children: Rule[]): Rule
  optional(): Rule
  required(): Rule
  custom<T = unknown>(
    fn: CustomValidator<T>,
    options?: {
      bypassConcurrencyLimit?: boolean
    },
  ): Rule
  media<T extends MediaAssetTypes = MediaAssetTypes>(fn: MediaValidator<T>): Rule
  min(len: number | string | FieldReference): Rule
  max(len: number | string | FieldReference): Rule
  length(len: number | FieldReference): Rule
  valid(value: unknown | unknown[]): Rule
  integer(): Rule
  precision(limit: number | FieldReference): Rule
  positive(): Rule
  negative(): Rule
  greaterThan(num: number | FieldReference): Rule
  lessThan(num: number | FieldReference): Rule
  uppercase(): Rule
  lowercase(): Rule
  regex(
    pattern: RegExp,
    name: string,
    options: {
      name?: string
      invert?: boolean
    },
  ): Rule
  regex(
    pattern: RegExp,
    options: {
      name?: string
      invert?: boolean
    },
  ): Rule
  regex(pattern: RegExp, name: string): Rule
  regex(pattern: RegExp): Rule
  email(): Rule
  uri(options?: UriValidationOptions): Rule
  unique(): Rule
  reference(): Rule
  fields(rules: FieldRules): Rule
  assetRequired(): Rule
  validate(
    value: unknown,
    options: ValidationContext & {
      /**
       * @deprecated Internal use only
       * @internal
       */
      __internal?: {
        customValidationConcurrencyLimiter?: {
          ready: () => Promise<void>
          release: () => void
        }
      }
    },
  ): Promise<ValidationMarker[]>
}

/** @public */
declare type RuleBuilder<T extends RuleDef<T, FieldValue>, FieldValue = unknown> = T | T[]

/** @public */
declare interface RuleDef<T, FieldValue = unknown> {
  required: () => T
  custom: <LenientFieldValue extends FieldValue>(
    fn: CustomValidator<LenientFieldValue | undefined>,
  ) => T
  info: (message?: string | LocalizedValidationMessages) => T
  error: (message?: string | LocalizedValidationMessages) => T
  warning: (message?: string | LocalizedValidationMessages) => T
  valueOfField: (path: string | string[]) => FieldReference
}

/** @public */
declare type RuleSpec =
  | {
      flag: 'integer'
    }
  | {
      flag: 'email'
    }
  | {
      flag: 'unique'
    }
  | {
      flag: 'reference'
    }
  | {
      flag: 'type'
      constraint: RuleTypeConstraint
    }
  | {
      flag: 'all'
      constraint: Rule[]
    }
  | {
      flag: 'either'
      constraint: Rule[]
    }
  | {
      flag: 'presence'
      constraint: 'optional' | 'required'
    }
  | {
      flag: 'custom'
      constraint: CustomValidator
    }
  | {
      flag: 'min'
      constraint: number | string | FieldReference
    }
  | {
      flag: 'max'
      constraint: number | string | FieldReference
    }
  | {
      flag: 'length'
      constraint: number | FieldReference
    }
  | {
      flag: 'valid'
      constraint: unknown[]
    }
  | {
      flag: 'precision'
      constraint: number | FieldReference
    }
  | {
      flag: 'lessThan'
      constraint: number | FieldReference
    }
  | {
      flag: 'greaterThan'
      constraint: number | FieldReference
    }
  | {
      flag: 'stringCasing'
      constraint: 'uppercase' | 'lowercase'
    }
  | {
      flag: 'assetRequired'
      constraint: {
        assetType: 'asset' | 'image' | 'file'
      }
    }
  | {
      flag: 'media'
      constraint: MediaValidator<any>
    }
  | {
      flag: 'regex'
      constraint: {
        pattern: RegExp
        name?: string
        invert: boolean
      }
    }
  | {
      flag: 'uri'
      constraint: {
        options: {
          scheme: RegExp[]
          allowRelative: boolean
          relativeOnly: boolean
          allowCredentials: boolean
        }
      }
    }

/** @public */
declare type RuleTypeConstraint = 'Array' | 'Boolean' | 'Date' | 'Number' | 'Object' | 'String'

declare type SanityAsset = {
  _id: string
  _type: 'sanity.asset'
  _createdAt: string
  _updatedAt: string
  _rev: string
  title?: string
  aspects?: Record<string, unknown>
  currentVersion: {
    _ref: string
    _type: 'reference'
    _weak?: boolean
    [internalGroqTypeReferenceTo]?: 'sanity.asset.version'
  }
  versions: Array<
    {
      _key: string
    } & SanityAssetVersion
  >
  assetType: 'sanity.imageAsset' | 'sanity.videoAsset' | 'sanity.fileAsset'
  cdnAccessPolicy: 'public' | 'private'
  url?: string
}

declare type SanityAssetCollection = {
  _id: string
  _type: 'sanity.asset.collection'
  _createdAt: string
  _updatedAt: string
  _rev: string
  title: string
  description?: string
  assets?: Array<{
    _ref: string
    _type: 'reference'
    _weak?: boolean
    _key: string
    [internalGroqTypeReferenceTo]?: 'sanity.asset'
  }>
}

declare type SanityAssetInstanceState = string

declare type SanityAssetVersion = {
  _type: 'sanity.asset.version'
  title?: string
  instance:
    | {
        _ref: string
        _type: 'reference'
        _weak?: boolean
        [internalGroqTypeReferenceTo]?: 'sanity.imageAsset'
      }
    | {
        _ref: string
        _type: 'reference'
        _weak?: boolean
        [internalGroqTypeReferenceTo]?: 'sanity.fileAsset'
      }
    | {
        _ref: string
        _type: 'reference'
        _weak?: boolean
        [internalGroqTypeReferenceTo]?: 'sanity.videoAsset'
      }
}

/**
 * Options for configuring how Sanity Create interfaces with the type or field.
 *
 * @public
 */
declare interface SanityCreateOptions {
  /** Set to true to exclude a type or field from appearing in Sanity Create */
  exclude?: boolean
  /**
   * A short description of what the type or field is used for.
   * Purpose can be used to improve how and when content mapping uses the field.
   * */
  purpose?: string
}

/** @public */
declare interface SanityDocument {
  _id: string
  _type: string
  _createdAt: string
  _updatedAt: string
  _rev: string
  [key: string]: unknown
}

declare type SanityFileAsset = {
  _id: string
  _type: 'sanity.fileAsset'
  _createdAt: string
  _updatedAt: string
  _rev: string
  title?: string
  description?: Array<{
    children?: Array<{
      marks?: Array<string>
      text?: string
      _type: 'span'
      _key: string
    }>
    style?: 'normal' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'blockquote'
    listItem?: 'bullet' | 'number'
    markDefs?: Array<{
      href?: string
      _type: 'link'
      _key: string
    }>
    level?: number
    _type: 'block'
    _key: string
  }>
  state: SanityAssetInstanceState
  sha1hash?: string
  mimeType?: string
  originalFilename?: string
  size?: number
  uploadId?: string
  path: string
  extension?: string
  url: string
}

declare type SanityImageAsset = {
  _id: string
  _type: 'sanity.imageAsset'
  _createdAt: string
  _updatedAt: string
  _rev: string
  altText?: string
  state: SanityAssetInstanceState
  sha1hash?: string
  mimeType?: string
  originalFilename?: string
  size?: number
  uploadId?: string
  path?: string
  extension?: string
  url: string
  metadata: SanityImageMetadata
}

declare type SanityImageDimensions = {
  _type: 'sanity.imageDimensions'
  height: number
  width: number
  aspectRatio: number
}

declare type SanityImageExifMetadata = {
  _type: 'sanity.imageExifMetadata'
  ApertureValue?: number
  BrightnessValue?: number
  DateTimeDigitized?: string
  DateTimeOriginal?: string
  ExposureBiasValue?: number
  ExposureMode?: number
  ExposureProgram?: number
  ExposureTime?: number
  FNumber?: number
  Flash?: number
  FocalLength?: number
  FocalLengthIn35mmFormat?: number
  ISO?: number
  LensModel?: string
  WhiteBalance?: number
  GPSLatitude?: number
  GPSLongitude?: number
  GPSAltitude?: number
  Copyright?: string
  Artist?: string
}

declare type SanityImageExifTags = {
  _type: 'sanity.imageExifTags'
  Make?: string
  Model?: string
  Orientation?: number
  XResolution?: number
  YResolution?: number
  ResolutionUnit?: number
  Software?: string
  ModifyDate?: string
  ExifOffset?: number
  GPSInfo?: number
}

declare type SanityImageMetadata = {
  _type: 'sanity.imageMetadata'
  location?: Geopoint
  dimensions: SanityImageDimensions
  exif?: SanityImageExifMetadata
  image?: SanityImageExifTags
  palette: SanityImagePalette
  lqip: string
  blurHash: string
  hasAlpha: boolean
  isOpaque: boolean
}

declare type SanityImagePalette = {
  _type: 'sanity.imagePalette'
  darkMuted?: SanityImagePaletteSwatch
  lightVibrant?: SanityImagePaletteSwatch
  darkVibrant?: SanityImagePaletteSwatch
  vibrant?: SanityImagePaletteSwatch
  dominant?: SanityImagePaletteSwatch
  lightMuted?: SanityImagePaletteSwatch
  muted?: SanityImagePaletteSwatch
}

declare type SanityImagePaletteSwatch = {
  _type: 'sanity.imagePaletteSwatch'
  background?: string
  foreground?: string
  population?: number
  title?: string
}

declare type SanitySystem = {
  _type: 'sanity.system'
  createdBy?: string
}

export declare type SanityVideoAsset = {
  _id: string
  _type: 'sanity.videoAsset'
  _createdAt: string
  _updatedAt: string
  _rev: string
  title?: string
  description?: Array<{
    children?: Array<{
      marks?: Array<string>
      text?: string
      _type: 'span'
      _key: string
    }>
    style?: 'normal' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'blockquote'
    listItem?: 'bullet' | 'number'
    markDefs?: Array<{
      href?: string
      _type: 'link'
      _key: string
    }>
    level?: number
    _type: 'block'
    _key: string
  }>
  state: SanityAssetInstanceState
  sha1hash?: string
  mimeType?: string
  originalFilename?: string
  size?: number
  uploadId?: string
  path?: string
  url?: string
  extension?: string
  source?: {
    id?: string
    name?: string
    url?: string
  }
  metadata: SanityVideoMetadata
}

declare type SanityVideoMetadata = {
  _type: 'sanity.videoMetadata'
  aspectRatio?: string
  duration?: number
  framerate?: number
  playbacks?: Array<
    {
      _key: string
    } & SanityVideoMetadataPlayback
  >
}

declare type SanityVideoMetadataPlayback = {
  _type: 'sanity.videoMetadata.playback'
  _id: string
  name?: string
  policy: string
}

/** @public */
declare interface Schema {
  /** @internal */
  _original?: {
    name: string
    types: SchemaTypeDefinition[]
  }
  /** @internal */
  _registry: {
    [typeName: string]: any
  }
  /** @internal */
  _validation?: SchemaValidationProblemGroup[]
  name: string
  get: (name: string) => SchemaType | undefined
  has: (name: string) => boolean
  getTypeNames: () => string[]
  /**
   * Returns the types which were explicitly defined in this schema,
   * as opposed to the types which were inherited from the parent.
   */
  getLocalTypeNames: () => string[]
  /**
   * Returns the parent schema.
   */
  parent?: Schema
}

/**
 * Note: you probably want `SchemaTypeDefinition` instead
 * @see SchemaTypeDefinition
 *
 * @public
 */
declare type SchemaType =
  | ArraySchemaType
  | BooleanSchemaType
  | FileSchemaType
  | NumberSchemaType
  | ObjectSchemaType
  | StringSchemaType
  | ReferenceSchemaType

/**
 * Represents a Sanity schema type definition with an optional type parameter.
 *
 * It's recommend to use the `defineType` helper instead of this type by
 * itself.
 *
 * @see defineType
 *
 * @public
 */
declare type SchemaTypeDefinition<TType extends IntrinsicTypeName = IntrinsicTypeName> =
  | IntrinsicDefinitions[IntrinsicTypeName]
  | TypeAliasDefinition<string, TType>

/** @public */
declare interface SchemaValidationError {
  helpId?: string
  message: string
  severity: 'error'
}

/** @internal */
declare type SchemaValidationProblem = SchemaValidationError | SchemaValidationWarning

/** @internal */
declare interface SchemaValidationProblemGroup {
  path: SchemaValidationProblemPath
  problems: SchemaValidationProblem[]
}

/** @internal */
declare type SchemaValidationProblemPath = Array<
  | {
      kind: 'type'
      type: string
      name?: string
    }
  | {
      kind: 'property'
      name: string
    }
>

/**
 * Represents the possible values of a schema type's `validation` field.
 *
 * If the schema has not been run through `inferFromSchema` from
 * `sanity/validation` then value could be a function.
 *
 * `inferFromSchema` mutates the schema converts this value to an array of
 * `Rule` instances.
 *
 * @privateRemarks
 *
 * Usage of the schema inside the studio will almost always be from the compiled
 * `createSchema` function. In this case, you can cast the value or throw to
 * narrow the type. E.g.:
 *
 * ```ts
 * if (typeof type.validation === 'function') {
 *   throw new Error(
 *     `Schema type "${type.name}"'s \`validation\` was not run though \`inferFromSchema\``
 *   )
 * }
 * ```
 *
 * @public
 */
declare type SchemaValidationValue =
  | false
  | undefined
  | Rule
  | SchemaValidationValue[]
  | ((rule: Rule) => SchemaValidationValue)

/** @internal */
declare interface SchemaValidationWarning {
  helpId?: string
  message: string
  severity: 'warning'
}

/** @public */
declare interface SearchConfiguration {
  search?: {
    /**
     * Defines a search weight for this field to prioritize its importance
     * during search operations in the Studio. This setting allows the specified
     * field to be ranked higher in search results compared to other fields.
     *
     * By default, all fields are assigned a weight of 1. However, if a field is
     * chosen as the `title` in the preview configuration's `select` option, it
     * will automatically receive a default weight of 10. Similarly, if selected
     * as the `subtitle`, the default weight is 5. Fields marked as
     * `hidden: true` (no function) are assigned a weight of 0 by default.
     *
     * Note: Search weight configuration is currently supported only for fields
     * of type string or portable text arrays.
     */
    weight?: number
  }
}

/**
 * @public
 */
declare const searchStrategies: readonly ['groqLegacy', 'groq2024']

/**
 * @public
 */
declare type SearchStrategy = (typeof searchStrategies)[number]

/** @public */
declare interface SingleFieldSet {
  single: true
  field: ObjectField
  hidden?: ConditionalProperty
  readOnly?: ConditionalProperty
  group?: string | string[]
}

/** @public */
declare interface SlugDefinition extends BaseSchemaDefinition {
  type: 'slug'
  options?: SlugOptions
  validation?: ValidationBuilder<SlugRule, SlugValue>
  initialValue?: InitialValueProperty<any, Omit<SlugValue, '_type'>>
}

/** @public */
declare type SlugifierFn = (
  source: string,
  schemaType: SlugSchemaType,
  context: SlugSourceContext,
) => string | Promise<string>

/** @public */
declare type SlugIsUniqueValidator = (
  slug: string,
  context: SlugValidationContext,
) => boolean | Promise<boolean>

/** @public */
declare interface SlugOptions extends SearchConfiguration, BaseSchemaTypeOptions {
  source?: string | Path | SlugSourceFn
  maxLength?: number
  slugify?: SlugifierFn
  isUnique?: SlugIsUniqueValidator
  disableArrayWarning?: boolean
}

/** @public */
declare type SlugParent = Record<string, unknown> | Record<string, unknown>[]

/** @public */
declare interface SlugRule extends RuleDef<SlugRule, SlugValue> {}

/** @public */
declare interface SlugSchemaType extends ObjectSchemaType {
  jsonType: 'object'
  options?: SlugOptions
}

/** @public */
declare interface SlugSourceContext {
  parentPath: Path
  parent: SlugParent
  projectId: string
  dataset: string
  schema: Schema
  currentUser: CurrentUser | null
  getClient: (options: {apiVersion: string}) => SanityClient
}

/** @public */
declare type SlugSourceFn = (
  document: SanityDocument,
  context: SlugSourceContext,
) => string | Promise<string>

/** @public */
declare interface SlugValidationContext extends ValidationContext {
  parent: SlugParent
  type: SlugSchemaType
  defaultIsUnique: SlugIsUniqueValidator
}

/** @public */
declare interface SlugValue {
  _type: 'slug'
  current?: string
}

/** @beta */
declare type SortOrdering = {
  title: string
  i18n?: I18nTextRecord<'title'>
  name: string
  by: SortOrderingItem[]
}

/** @beta */
declare interface SortOrderingItem {
  field: string
  direction: 'asc' | 'desc'
}

/** @public */
declare interface StringDefinition extends BaseSchemaDefinition {
  type: 'string'
  options?: StringOptions
  placeholder?: string
  validation?: ValidationBuilder<StringRule, string>
  initialValue?: InitialValueProperty<any, string>
}

/** @public */
declare interface StringOptions
  extends EnumListProps<string>,
    SearchConfiguration,
    BaseSchemaTypeOptions {}

/** @public */
declare interface StringRule extends RuleDef<StringRule, string> {
  min: (minNumber: number | FieldReference) => StringRule
  max: (maxNumber: number | FieldReference) => StringRule
  length: (exactLength: number | FieldReference) => StringRule
  uppercase: () => StringRule
  lowercase: () => StringRule
  regex(
    pattern: RegExp,
    name: string,
    options: {
      name?: string
      invert?: boolean
    },
  ): StringRule
  regex(
    pattern: RegExp,
    options: {
      name?: string
      invert?: boolean
    },
  ): StringRule
  regex(pattern: RegExp, name: string): StringRule
  regex(pattern: RegExp): StringRule
  email(): StringRule
}

/**
 * This is used for string, text, date and datetime.
 * This interface represent the compiled version at runtime, when accessed through Schema.
 *
 * @public
 */
declare interface StringSchemaType extends BaseSchemaType {
  jsonType: 'string'
  options?: StringOptions & TextOptions & DateOptions & DatetimeOptions
  initialValue?: InitialValueProperty<any, string>
}

/** @public */
declare interface TextDefinition extends BaseSchemaDefinition {
  type: 'text'
  rows?: number
  options?: TextOptions
  placeholder?: string
  validation?: ValidationBuilder<TextRule, string>
  initialValue?: InitialValueProperty<any, string>
}

/** @public */
declare interface TextOptions extends StringOptions {}

/** @public */
declare interface TextRule extends StringRule {}

/** @public */
declare interface TitledListValue<V = unknown> {
  _key?: string
  title: string
  value?: V
}

/**
 * Represents a type definition that is an alias/extension of an existing type
 * in your schema. Creating a type alias will re-register that existing type
 * under a different name. You can also override the default type options with
 * a type alias definition.
 *
 * @public
 */
declare interface TypeAliasDefinition<
  TType extends string,
  TAlias extends IntrinsicTypeName | undefined,
> extends BaseSchemaDefinition {
  type: TType
  options?: TAlias extends IntrinsicTypeName ? IntrinsicDefinitions[TAlias]['options'] : unknown
  validation?: SchemaValidationValue
  initialValue?: InitialValueProperty<any, any>
  preview?: PreviewConfig
  components?: {
    annotation?: ComponentType<any>
    block?: ComponentType<any>
    inlineBlock?: ComponentType<any>
    diff?: ComponentType<any>
    field?: ComponentType<any>
    input?: ComponentType<any>
    item?: ComponentType<any>
    preview?: ComponentType<any>
  }
}

/**
 * Represents a reference to another type registered top-level in your schema.
 *
 * @public
 */
declare interface TypeReference {
  type: string
  name?: string
  icon?: ComponentType | ReactNode
  options?: {
    [key: string]: unknown
  }
}

export declare type UploadSession = {
  _id: string
  _type: 'sanity.asset.upload-session'
  _createdAt: string
  _updatedAt: string
  _rev: string
  title: string
  assets?: Array<{
    _ref: string
    _type: 'reference'
    _weak?: boolean
    _key: string
    [internalGroqTypeReferenceTo]?: 'sanity.asset'
  }>
  _system?: SanitySystem
}

/** @public */
declare interface UriValidationOptions {
  scheme?: (string | RegExp) | Array<string | RegExp>
  allowRelative?: boolean
  relativeOnly?: boolean
  allowCredentials?: boolean
}

/** @public */
declare interface UrlDefinition extends BaseSchemaDefinition {
  type: 'url'
  options?: UrlOptions
  placeholder?: string
  validation?: ValidationBuilder<UrlRule, string>
  initialValue?: InitialValueProperty<any, string>
}

/** @public */
declare interface UrlOptions extends BaseSchemaTypeOptions {}

/** @public */
declare interface UrlRule extends RuleDef<UrlRule, string> {
  uri(options: UriValidationOptions): UrlRule
}

/** @public */
declare type ValidationBuilder<T extends RuleDef<T, FieldValue>, FieldValue = unknown> = (
  rule: T,
) => RuleBuilder<T, FieldValue>

/**
 * A context object passed around during validation. This includes the
 * `Rule.custom` context.
 *
 * e.g.
 *
 * ```js
 * Rule.custom((_, validationContext) => {
 *   // ...
 * })`
 * ```
 *
 * @public
 */
declare interface ValidationContext {
  getClient: (options: {apiVersion: string}) => SanityClient
  schema: Schema
  parent?: unknown
  type?: SchemaType
  document?: SanityDocument
  path?: Path
  getDocumentExists?: (options: {id: string}) => Promise<boolean>
  environment: 'cli' | 'studio'
}

/**
 * The shape that can be returned from a custom validator to be converted into
 * a validation marker by the validation logic. Inside of a custom validator,
 * you can return an array of these in order to specify multiple paths within
 * an object or array.
 *
 * @public
 */
declare interface ValidationError {
  /**
   * The message describing why the value is not valid. This message will be
   * included in the validation markers after validation has finished running.
   */
  message: string
  /**
   * If writing a custom validator, you can return validation messages to
   * specific path inside of the current value (object or array) by populating
   * this `path` prop.
   *
   * NOTE: This path is relative to the current value and _not_ relative to
   * the document.
   */
  path?: Path
  /**
   * Same as `path` but allows more than one value. If provided, the same
   * message will create two markers from each path with the same message
   * provided.
   *
   * @deprecated prefer `path`
   */
  paths?: Path[]
  /**
   * @deprecated Unused. Was used to store the results from `.either()` /`.all()`
   */
  children?: ValidationMarker[]
  /**
   * @deprecated Unused. Was used to signal if this error came from an `.either()`/`.all()`.
   */
  operation?: 'AND' | 'OR'
  /**
   * @deprecated Unused. Was relevant when validation error was used as a class.
   */
  cloneWithMessage?(message: string): ValidationError
}

/** @public */
declare interface ValidationMarker {
  level: 'error' | 'warning' | 'info'
  /**
   * The validation message for this marker. E.g. "Must be greater than 0"
   */
  message: string
  /**
   * @deprecated use `message` instead
   */
  item?: ValidationError
  /**
   * The sanity path _relative to the root of the current document_ to this
   * marker.
   *
   * NOTE: Sanity paths may contain keyed segments (i.e. `{_key: string}`) that
   * are not compatible with deep getters like lodash/get
   */
  path: Path
}

export {}
