import { NamedInputEvent, ValidationConfig, Validator } from 'laravel-precognition'; import type { HttpCancelledError, HttpNetworkError, HttpResponseError } from './httpErrors'; import { Response } from './response'; export type HttpRequestHeaders = Record; export type HttpResponseHeaders = Record; export interface HttpProgressEvent { progress: number | undefined; loaded: number; total: number | undefined; percentage?: number; } export interface HttpRequestConfig { method: Method; url: string; data?: unknown; params?: Record; headers?: HttpRequestHeaders; signal?: AbortSignal; onUploadProgress?: (event: HttpProgressEvent) => void; } export interface HttpResponse { status: number; data: string; headers: HttpResponseHeaders; } export interface HttpClient { request(config: HttpRequestConfig): Promise; } export interface HttpClientOptions { xsrfCookieName?: string; xsrfHeaderName?: string; } export type HttpRequestHandler = (config: HttpRequestConfig) => HttpRequestConfig | Promise; export type HttpResponseHandler = (response: HttpResponse) => HttpResponse | Promise; export type HttpErrorHandler = (error: HttpResponseError | HttpNetworkError | HttpCancelledError) => void | Promise; export interface PageFlashData { [key: string]: unknown; } export type DefaultInertiaConfig = { errorValueType: string; flashDataType: PageFlashData; sharedPageProps: PageProps; layoutProps: Record; namedLayoutProps: Record>; }; /** * Designed to allow overriding of some core types using TypeScript * interface declaration merging. * * @see {@link DefaultInertiaConfig} for keys to override * @example * ```ts * // global.d.ts * import '@inertiajs/core' * * declare module '@inertiajs/core' { * export interface InertiaConfig { * errorValueType: string[] * flashDataType: { * toast?: { type: 'success' | 'error', message: string } * } * sharedPageProps: { * auth: { user: User | null } * } * layoutProps: { * title: string * showSidebar: boolean * } * namedLayoutProps: { * app: { title: string; theme: string } * content: { padding: string; maxWidth: string } * } * } * } * ``` */ export interface InertiaConfig { } export type InertiaConfigFor = Key extends keyof InertiaConfig ? InertiaConfig[Key] : DefaultInertiaConfig[Key]; export type ErrorValue = InertiaConfigFor<'errorValueType'>; export type FlashData = InertiaConfigFor<'flashDataType'>; export type SharedPageProps = InertiaConfigFor<'sharedPageProps'>; export type LayoutProps = InertiaConfigFor<'layoutProps'>; export type NamedLayoutProps = InertiaConfigFor<'namedLayoutProps'>; export type Errors = Record; export type ErrorBag = Record; export type FormDataConvertibleValue = Blob | FormDataEntryValue | Date | boolean | number | null | undefined; export type FormDataConvertible = Array | { [key: string]: FormDataConvertible; } | FormDataConvertibleValue; export type FormDataType = { [K in keyof T]: T[K] extends infer U ? U extends FormDataConvertibleValue ? U : U extends (...args: unknown[]) => unknown ? never : U extends object | Array ? FormDataType : never : never; }; /** * Uses `0 extends 1 & T` to detect `any` type and prevent infinite recursion. */ export type FormDataKeys = T extends Function | FormDataConvertibleValue ? never : T extends unknown[] ? ArrayFormDataKeys : T extends object ? ObjectFormDataKeys : never; /** * Helper type for array form data keys */ type ArrayFormDataKeys = number extends T['length'] ? `${number}` | (0 extends 1 & T[number] ? never : T[number] extends FormDataConvertibleValue ? never : `${number}.${FormDataKeys}`) : Extract | { [Key in Extract]: 0 extends 1 & T[Key] ? never : T[Key] extends FormDataConvertibleValue ? never : `${Key & string}.${FormDataKeys}`; }[Extract]; /** * Helper type for object form data keys */ type ObjectFormDataKeys = string extends keyof T ? string : Extract | { [Key in Extract]: 0 extends 1 & T[Key] ? never : T[Key] extends FormDataConvertibleValue ? never : T[Key] extends any[] ? `${Key}.${FormDataKeys & string}` : T[Key] extends Record ? `${Key}.${FormDataKeys & string}` : Exclude extends any[] ? never : Exclude extends Record ? `${Key}.${FormDataKeys> & string}` : never; }[Extract]; type PartialFormDataErrors = { [K in string extends keyof T ? string : Extract, string>]?: ErrorValue; }; export type FormDataErrors = PartialFormDataErrors & { [K in keyof PartialFormDataErrors]: NonNullable[K]>; }; export type FormDataValues> = K extends `${infer P}.${infer Rest}` ? T extends unknown[] ? P extends `${infer I extends number}` ? Rest extends FormDataKeys ? FormDataValues : never : never : P extends keyof T ? Rest extends FormDataKeys ? FormDataValues : never : never : K extends keyof T ? T[K] : T extends unknown[] ? T[K & number] : never; export type FormDataError = Partial, ErrorValue>>; export type Method = 'get' | 'post' | 'put' | 'patch' | 'delete'; export type RequestPayload = Record | FormData; export interface PageProps { [key: string]: unknown; } export type ScrollProp = { pageName: string; previousPage: number | string | null; nextPage: number | string | null; currentPage: number | string | null; reset: boolean; }; export interface Page { component: string; props: PageProps & SharedProps & { errors: Errors & ErrorBag; deferred?: Record; }; url: string; version: string | null; clearHistory?: boolean; preserveFragment?: boolean; encryptHistory?: boolean; deferredProps?: Record>; initialDeferredProps?: Record>; mergeProps?: string[]; prependProps?: string[]; deepMergeProps?: string[]; matchPropsOn?: string[]; sharedProps?: string[]; scrollProps?: Record; flash: FlashData; onceProps?: Record; /** @internal */ rememberedState: Record; /** @internal */ optimisticUpdatedAt?: Record; } export type ScrollRegion = { top: number; left: number; }; export interface ClientSideVisitOptions { component?: Page['component']; url?: Page['url']; props?: ((props: TProps, onceProps: Partial) => PageProps) | PageProps; flash?: ((flash: FlashData) => PageFlashData) | PageFlashData; clearHistory?: Page['clearHistory']; encryptHistory?: Page['encryptHistory']; preserveScroll?: VisitOptions['preserveScroll']; preserveState?: VisitOptions['preserveState']; errorBag?: string | null; viewTransition?: VisitOptions['viewTransition']; onError?: (errors: Errors) => void; onFinish?: (visit: ClientSideVisitOptions) => void; onFlash?: (flash: FlashData) => void; onSuccess?: (page: Page) => void; } export type PageResolver = (name: string, page?: Page) => Component; export type PageHandler = ({ component, page, preserveState, }: { component: ComponentType; page: Page; preserveState: boolean; }) => Promise; export type PreserveStateOption = boolean | 'errors' | ((page: Page) => boolean); export type QueryStringArrayFormatOption = 'indices' | 'brackets'; export type Progress = HttpProgressEvent; export type LocationVisit = { preserveScroll: boolean; }; export type CancelToken = { cancel: VoidFunction; }; export type CancelTokenCallback = (cancelToken: CancelToken) => void; export type OptimisticCallback['props']> = (props: TProps) => Partial | void; export type Visit = { method: Method; data: T; replace: boolean; preserveScroll: PreserveStateOption; preserveState: PreserveStateOption; only: Array; except: Array; headers: Record; errorBag: string | null; forceFormData: boolean; queryStringArrayFormat: QueryStringArrayFormatOption; async: boolean; showProgress: boolean; prefetch: boolean; fresh: boolean; reset: string[]; preserveUrl: boolean; preserveErrors: boolean; invalidateCacheTags: string | string[]; viewTransition: boolean | ((viewTransition: ViewTransition) => void); optimistic?: OptimisticCallback; component: string | null; pageProps: Record | ((currentProps: PageProps, sharedProps: Partial) => Record) | null; }; export type GlobalEventsMap = { before: { parameters: [PendingVisit]; details: { visit: PendingVisit; }; result: boolean | void; }; start: { parameters: [PendingVisit]; details: { visit: PendingVisit; }; result: void; }; progress: { parameters: [Progress | undefined]; details: { progress: Progress | undefined; }; result: void; }; finish: { parameters: [ActiveVisit]; details: { visit: ActiveVisit; }; result: void; }; cancel: { parameters: []; details: {}; result: void; }; beforeUpdate: { parameters: [Page]; details: { page: Page; }; result: void; }; navigate: { parameters: [Page]; details: { page: Page; }; result: void; }; success: { parameters: [Page]; details: { page: Page; }; result: void; }; error: { parameters: [Errors]; details: { errors: Errors; }; result: void; }; httpException: { parameters: [HttpResponse]; details: { response: HttpResponse; }; result: boolean | void; }; networkError: { parameters: [Error]; details: { error: Error; }; result: boolean | void; }; prefetched: { parameters: [HttpResponse, ActiveVisit]; details: { response: HttpResponse; fetchedAt: number; visit: ActiveVisit; }; result: void; }; prefetching: { parameters: [ActiveVisit]; details: { visit: ActiveVisit; }; result: void; }; flash: { parameters: [Page['flash']]; details: { flash: Page['flash']; }; result: void; }; }; export type PageEvent = 'newComponent' | 'firstLoad'; export type GlobalEventNames = keyof GlobalEventsMap; export type GlobalEvent, T extends RequestPayload = RequestPayload> = CustomEvent>; export type GlobalEventParameters, T extends RequestPayload = RequestPayload> = GlobalEventsMap[TEventName]['parameters']; export type GlobalEventResult, T extends RequestPayload = RequestPayload> = GlobalEventsMap[TEventName]['result']; export type GlobalEventDetails, T extends RequestPayload = RequestPayload> = GlobalEventsMap[TEventName]['details']; export type GlobalEventTrigger, T extends RequestPayload = RequestPayload> = (...params: GlobalEventParameters) => GlobalEventResult; export type GlobalEventCallback, T extends RequestPayload = RequestPayload> = (...params: GlobalEventParameters) => GlobalEventResult; export type InternalEvent = 'missingHistoryItem' | 'loadDeferredProps' | 'historyQuotaExceeded'; export type VisitCallbacks = { onCancelToken: CancelTokenCallback; onBefore: GlobalEventCallback<'before', T>; onBeforeUpdate: GlobalEventCallback<'beforeUpdate', T>; onStart: GlobalEventCallback<'start', T>; onProgress: GlobalEventCallback<'progress', T>; onFinish: GlobalEventCallback<'finish', T>; onCancel: GlobalEventCallback<'cancel', T>; onSuccess: GlobalEventCallback<'success', T>; onError: GlobalEventCallback<'error', T>; onHttpException: GlobalEventCallback<'httpException', T>; onNetworkError: GlobalEventCallback<'networkError', T>; onFlash: GlobalEventCallback<'flash', T>; onPrefetched: GlobalEventCallback<'prefetched', T>; onPrefetching: GlobalEventCallback<'prefetching', T>; }; export type VisitOptions = Partial & VisitCallbacks>; export type ReloadOptions = Omit, 'preserveScroll' | 'preserveState'>; export type PollOptions = { keepAlive?: boolean; autoStart?: boolean; }; export type VisitHelperOptions = Omit, 'method' | 'data'>; export type RouterInitParams = { initialPage: Page; resolveComponent: PageResolver; swapComponent: PageHandler; onFlash?: (flash: Page['flash']) => void; }; export type PendingVisitOptions = { url: URL; completed: boolean; cancelled: boolean; interrupted: boolean; }; export type PendingVisit = Visit & PendingVisitOptions; export type ActiveVisit = PendingVisit & Required, 'optimistic'>>; export type InternalActiveVisit = ActiveVisit & { onPrefetchResponse?: (response: Response) => void; onPrefetchError?: (error: Error) => void; deferredProps?: boolean; }; export type VisitId = unknown; export type Component = unknown; type FirstLevelOptional = { [K in keyof T]?: T[K] extends object ? { [P in keyof T[K]]?: T[K][P]; } : T[K]; }; type PagesOption = string | { path: string; extension?: string | string[]; lazy?: boolean; transform?: (name: string, page: Page) => string; }; export type ProgressOptions = { delay?: number; color?: string; includeCSS?: boolean; showSpinner?: boolean; popover?: boolean | null; }; interface BaseCreateInertiaAppOptions { resolve: TComponentResolver; pages?: PagesOption; layout?: (name: string, page: Page) => unknown; setup: (options: TSetupOptions) => TSetupReturn; title?: HeadManagerTitleCallback; defaults?: FirstLevelOptional; /** HTTP client or options to use for requests. Defaults to XhrHttpClient. */ http?: HttpClient | HttpClientOptions; } export interface CreateInertiaAppOptionsForCSR extends BaseCreateInertiaAppOptions { id?: string; page?: Page; progress?: ProgressOptions | false; render?: undefined; } export interface CreateInertiaAppOptionsForSSR extends BaseCreateInertiaAppOptions { id?: undefined; page: Page; progress?: undefined; render: unknown; } export type InertiaAppSSRResponse = { head: string[]; body: string; }; export type InertiaAppResponse = Promise; export type HeadManagerTitleCallback = (title: string) => string; export interface CreateInertiaAppOptions { id?: string; resolve?: TComponentResolver; pages?: PagesOption; layout?: (name: string, page: Page) => unknown; setup?: (options: TSetupOptions) => TSetupReturn; title?: HeadManagerTitleCallback; progress?: ProgressOptions | false; defaults?: FirstLevelOptional; /** HTTP client or options to use for requests. Defaults to XhrHttpClient. */ http?: HttpClient | HttpClientOptions; } export type HeadManagerOnUpdateCallback = (elements: string[]) => void; export type HeadManager = { forceUpdate: () => void; createProvider: () => { reconnect: () => void; update: HeadManagerOnUpdateCallback; disconnect: () => void; }; }; export type LinkPrefetchOption = 'mount' | 'hover' | 'click'; export type TimeUnit = 'ms' | 's' | 'm' | 'h' | 'd'; export type CacheForOption = number | `${number}${TimeUnit}` | string; export type PrefetchOptions = { cacheFor: CacheForOption | CacheForOption[]; cacheTags: string | string[]; }; export type InertiaAppConfig = { form: { recentlySuccessfulDuration: number; forceIndicesArrayFormatInFormData: boolean; withAllErrors: boolean; }; prefetch: { cacheFor: CacheForOption | CacheForOption[]; hoverDelay: number; }; visitOptions?: (href: string, options: VisitOptions) => VisitOptions; }; export interface LinkComponentBaseProps extends Partial, 'component' | 'data' | 'method' | 'replace' | 'preserveScroll' | 'preserveState' | 'preserveUrl' | 'only' | 'except' | 'headers' | 'queryStringArrayFormat' | 'async' | 'viewTransition'> & VisitCallbacks & { href: string | UrlMethodPair; instant: boolean; pageProps: Record | ((currentProps: PageProps, sharedProps: Partial) => Record) | null; prefetch: boolean | LinkPrefetchOption | LinkPrefetchOption[]; cacheFor: CacheForOption | CacheForOption[]; cacheTags: string | string[]; }> { } type PrefetchObject = { params: ActiveVisit; response: Promise; }; export type InFlightPrefetch = PrefetchObject & { staleTimestamp: null; inFlight: true; }; export type PrefetchCancellationToken = { isCancelled: boolean; cancel: () => void; }; export type PrefetchedResponse = PrefetchObject & { staleTimestamp: number; timestamp: number; expiresAt: number; singleUse: boolean; inFlight: false; tags: string[]; }; export type PrefetchRemovalTimer = { params: ActiveVisit; timer: number; }; export type ProgressSettings = { minimum: number; easing: string; speed: number; trickle: boolean; trickleSpeed: number; showSpinner: boolean; barSelector: string; spinnerSelector: string; parent: string; template: string; includeCSS: boolean; color: string; popover: boolean | null; }; export type UrlMethodPair = { url: string; method: Method; component?: string | Record; }; export type UseFormTransformCallback = (data: TForm) => object; export type UseFormWithPrecognitionArguments = [Method | (() => Method), string | (() => string)] | [UrlMethodPair | (() => UrlMethodPair)]; type UseFormInertiaArguments = [] | [data: TForm | (() => TForm)] | [rememberKey: string, data: TForm | (() => TForm)]; type UseFormPrecognitionArguments = [urlMethodPair: UrlMethodPair | (() => UrlMethodPair), data: TForm | (() => TForm)] | [method: Method | (() => Method), url: string | (() => string), data: TForm | (() => TForm)]; export type UseFormArguments = UseFormInertiaArguments | UseFormPrecognitionArguments; export type UseFormSubmitOptions = Omit; export type UseFormSubmitArguments = [Method, string, UseFormSubmitOptions?] | [UrlMethodPair, UseFormSubmitOptions?] | [UseFormSubmitOptions?]; export type UseHttpSubmitArguments = [Method, string, UseHttpSubmitOptions?] | [UrlMethodPair, UseHttpSubmitOptions?] | [UseHttpSubmitOptions?]; export type FormComponentOptions = Pick; export type FormComponentOptimisticCallback['props'], TForm = Record> = (props: TProps, formData: TForm) => Partial | void; export type FormComponentProps> = Partial & Omit> & { method?: Method | Uppercase; action?: string | UrlMethodPair; component?: string; instant?: boolean; transform?: (data: TForm) => Record; optimistic?: FormComponentOptimisticCallback['props'], TForm>; options?: FormComponentOptions; onSubmitComplete?: (props: FormComponentOnSubmitCompleteArguments) => void; disableWhileProcessing?: boolean; resetOnSuccess?: boolean | NoInfer>[]; resetOnError?: boolean | NoInfer>[]; setDefaultsOnSuccess?: boolean; validateFiles?: boolean; validationTimeout?: number; withAllErrors?: boolean | null; }; export type FormComponentMethods> = { clearErrors: >(...fields: K[]) => void; resetAndClearErrors: >(...fields: K[]) => void; setError: { >(field: K, value: ErrorValue): void; (errors: FormDataErrors): void; }; reset: >(...fields: K[]) => void; submit: () => void; defaults: () => void; getData: () => TForm; getFormData: () => FormData; valid: >(field: K) => boolean; invalid: >(field: K) => boolean; validate: >(field?: K | NamedInputEvent | ValidationConfig, config?: ValidationConfig) => void; touch: >(...fields: K[]) => void; touched: >(field?: K) => boolean; validator: () => Validator; }; export type FormComponentOnSubmitCompleteArguments> = Pick, 'reset' | 'defaults'>; export type FormComponentState> = { errors: FormDataErrors; hasErrors: boolean; processing: boolean; progress: Progress | null; wasSuccessful: boolean; recentlySuccessful: boolean; isDirty: boolean; validating: boolean; }; export type FormComponentSlotProps> = FormComponentMethods & FormComponentState; export type FormComponentRef> = FormComponentSlotProps; export interface UseInfiniteScrollOptions { getPropName: () => string; inReverseMode: () => boolean; shouldFetchNext: () => boolean; shouldFetchPrevious: () => boolean; shouldPreserveUrl: () => boolean; getReloadOptions?: () => ReloadOptions; getTriggerMargin: () => number; getStartElement: () => HTMLElement; getEndElement: () => HTMLElement; getItemsElement: () => HTMLElement; getScrollableParent: () => HTMLElement | null; onBeforePreviousRequest: () => void; onBeforeNextRequest: () => void; onCompletePreviousRequest: () => void; onCompleteNextRequest: () => void; onDataReset?: () => void; } export interface UseInfiniteScrollDataManager { getLastLoadedPage: () => number | string | null; getPageName: () => string; getRequestCount: () => number; hasPrevious: () => boolean; hasNext: () => boolean; fetchNext: (reloadOptions?: ReloadOptions) => void; fetchPrevious: (reloadOptions?: ReloadOptions) => void; removeEventListener: () => void; } export interface UseInfiniteScrollElementManager { setupObservers: () => void; enableTriggers: () => void; disableTriggers: () => void; refreshTriggers: () => void; flushAll: () => void; processManuallyAddedElements: () => void; processServerLoadedElements: (loadedPage: string | number | null) => void; } export interface UseInfiniteScrollProps { dataManager: UseInfiniteScrollDataManager; elementManager: UseInfiniteScrollElementManager; flush: () => void; } export interface InfiniteScrollSlotProps { loading: boolean; loadingPrevious: boolean; loadingNext: boolean; } export interface InfiniteScrollActionSlotProps { loading: boolean; loadingPrevious: boolean; loadingNext: boolean; fetch: () => void; autoMode: boolean; manualMode: boolean; hasMore: boolean; hasPrevious: boolean; hasNext: boolean; } export interface InfiniteScrollRef { fetchNext: (reloadOptions?: ReloadOptions) => void; fetchPrevious: (reloadOptions?: ReloadOptions) => void; hasPrevious: () => boolean; hasNext: () => boolean; } export interface InfiniteScrollComponentBaseProps { data: string; buffer?: number; as?: string; manual?: boolean; manualAfter?: number; preserveUrl?: boolean; reverse?: boolean; autoScroll?: boolean; onlyNext?: boolean; onlyPrevious?: boolean; } export type UseHttpOptions = { onBefore?: () => boolean | void; onStart?: () => void; onProgress?: (progress: HttpProgressEvent) => void; onSuccess?: (response: TResponse, httpResponse: HttpResponse) => void; onError?: (errors: Errors) => void; onHttpException?: (response: HttpResponse) => boolean | void; onNetworkError?: (error: Error) => boolean | void; onFinish?: () => void; onCancel?: () => void; onCancelToken?: (cancelToken: CancelToken) => void; }; export type UseHttpSubmitOptions = UseHttpOptions & { headers?: HttpRequestHeaders; optimistic?: (currentData: TForm) => Partial | void; }; declare global { interface DocumentEventMap { 'inertia:before': GlobalEvent<'before'>; 'inertia:start': GlobalEvent<'start'>; 'inertia:progress': GlobalEvent<'progress'>; 'inertia:success': GlobalEvent<'success'>; 'inertia:error': GlobalEvent<'error'>; 'inertia:httpException': GlobalEvent<'httpException'>; 'inertia:networkError': GlobalEvent<'networkError'>; 'inertia:finish': GlobalEvent<'finish'>; 'inertia:beforeUpdate': GlobalEvent<'beforeUpdate'>; 'inertia:navigate': GlobalEvent<'navigate'>; 'inertia:flash': GlobalEvent<'flash'>; } } export {};