import type { ReactElement, ReactNode, Component, ComponentType } from 'react';
import type { PipeableStream } from 'react-dom/server';
import type { Readable } from 'stream';
/**
 * Don't import Redux just for the type definitions
 * See https://github.com/shakacode/react_on_rails/issues/1321
 * and https://redux.js.org/api/store for the actual API.
 * @see {import('redux').Store}
 */
type Store = {
    getState(): unknown;
};
type ReactComponent = ComponentType<any> | string;
export type RailsContext = {
    componentRegistryTimeout: number;
    railsEnv: string;
    inMailer: boolean;
    i18nLocale: string;
    i18nDefaultLocale: string;
    rorVersion: string;
    rorPro: boolean;
    rorProVersion?: string;
    href: string;
    location: string;
    scheme: string;
    host: string;
    port: number | null;
    pathname: string;
    search: string | null;
    httpAcceptLanguage: string;
    rscPayloadGenerationUrlPath?: string;
} & ({
    serverSide: false;
} | {
    serverSide: true;
    serverSideRSCPayloadParameters?: unknown;
    reactClientManifestFileName?: string;
    reactServerClientManifestFileName?: string;
    getRSCPayloadStream: (componentName: string, props: unknown) => Promise<NodeJS.ReadableStream>;
});
export type RailsContextWithServerComponentMetadata = RailsContext & {
    serverSide: true;
    serverSideRSCPayloadParameters?: unknown;
    reactClientManifestFileName: string;
    reactServerClientManifestFileName: string;
};
export type RailsContextWithServerStreamingCapabilities = RailsContextWithServerComponentMetadata & {
    getRSCPayloadStream: (componentName: string, props: unknown) => Promise<NodeJS.ReadableStream>;
    addPostSSRHook: (hook: () => void) => void;
};
export declare const assertRailsContextWithServerComponentMetadata: (context: RailsContext | undefined) => asserts context is RailsContextWithServerComponentMetadata;
export declare const assertRailsContextWithServerStreamingCapabilities: (context: RailsContext | undefined) => asserts context is RailsContextWithServerStreamingCapabilities;
type AuthenticityHeaders = Record<string, string> & {
    'X-CSRF-Token': string | null;
    'X-Requested-With': string;
};
type StoreGenerator = (props: Record<string, unknown>, railsContext: RailsContext) => Store;
type ServerRenderHashRenderedHtml = {
    componentHtml: string;
    [key: string]: string;
};
interface ServerRenderResult {
    renderedHtml?: string | ServerRenderHashRenderedHtml;
    redirectLocation?: {
        pathname: string;
        search: string;
    };
    routeError?: Error;
    error?: Error;
}
type CreateReactOutputSyncResult = ServerRenderResult | ReactElement;
type CreateReactOutputAsyncResult = Promise<string | ServerRenderHashRenderedHtml | ReactElement>;
type CreateReactOutputResult = CreateReactOutputSyncResult | CreateReactOutputAsyncResult;
type RenderFunctionSyncResult = ReactComponent | ServerRenderResult;
type RenderFunctionAsyncResult = Promise<string | ServerRenderHashRenderedHtml | ReactComponent>;
type RenderFunctionResult = RenderFunctionSyncResult | RenderFunctionAsyncResult;
type StreamableComponentResult = ReactElement | Promise<ReactElement | string>;
/**
 * Render-functions are used to create dynamic React components or server-rendered HTML with side effects.
 * They receive two arguments: props and railsContext.
 *
 * @param props - The component props passed to the render function
 * @param railsContext - The Rails context object containing environment information
 * @returns A string, React component, React element, or a Promise resolving to a string
 *
 * @remarks
 * To distinguish a render function from a React Function Component:
 * 1. Ensure it accepts two parameters (props and railsContext), even if railsContext is unused, or
 * 2. Set the `renderFunction` property to `true` on the function object.
 *
 * If neither condition is met, it will be treated as a React Function Component,
 * and ReactDOMServer will attempt to render it.
 *
 * @example
 * // Option 1: Two-parameter function
 * const renderFunction = (props, railsContext) => { ... };
 *
 * // Option 2: Using renderFunction property
 * const anotherRenderFunction = (props) => { ... };
 * anotherRenderFunction.renderFunction = true;
 */
interface RenderFunction {
    (props?: any, railsContext?: RailsContext, domNodeId?: string): RenderFunctionResult;
    renderFunction?: true;
}
type ReactComponentOrRenderFunction = ReactComponent | RenderFunction;
type PipeableOrReadableStream = PipeableStream | NodeJS.ReadableStream;
export type { ReactComponentOrRenderFunction, ReactComponent, AuthenticityHeaders, RenderFunction, RenderFunctionResult, Store, StoreGenerator, CreateReactOutputResult, ServerRenderResult, ServerRenderHashRenderedHtml, CreateReactOutputSyncResult, CreateReactOutputAsyncResult, RenderFunctionSyncResult, RenderFunctionAsyncResult, StreamableComponentResult, PipeableOrReadableStream, };
export interface RegisteredComponent {
    name: string;
    component: ReactComponentOrRenderFunction;
    /**
     * Indicates if the registered component is a RenderFunction
     * @see RenderFunction for more details on its behavior and usage.
     */
    renderFunction: boolean;
    isRenderer: boolean;
}
export type ItemRegistrationCallback<T> = (component: T) => void;
interface Params {
    props?: Record<string, unknown>;
    railsContext?: RailsContext;
    domNodeId?: string;
    trace?: boolean;
}
export interface RenderParams extends Params {
    name: string;
    throwJsErrors: boolean;
    renderingReturnsPromises: boolean;
}
export interface RSCRenderParams extends Omit<RenderParams, 'railsContext'> {
    railsContext: RailsContextWithServerStreamingCapabilities;
}
export interface CreateParams extends Params {
    componentObj: RegisteredComponent;
    shouldHydrate?: boolean;
}
export interface ErrorOptions {
    e: Error & {
        fileName?: string;
        lineNumber?: string;
    };
    name?: string;
    jsCode?: string;
    serverSide: boolean;
}
export type RenderingError = Pick<Error, 'message' | 'stack'>;
export type FinalHtmlResult = string | ServerRenderHashRenderedHtml;
export interface RenderResult {
    html: FinalHtmlResult | null;
    consoleReplayScript: string;
    hasErrors: boolean;
    renderingError?: RenderingError;
    isShellReady?: boolean;
}
export interface RSCPayloadChunk extends RenderResult {
    html: string;
}
export interface Root {
    render(children: ReactNode): void;
    unmount(): void;
}
export type RenderReturnType = void | Element | Component | Root;
export interface ReactOnRailsOptions {
    /** Gives you debugging messages on Turbolinks events. */
    traceTurbolinks?: boolean;
    /** Turbo (the successor of Turbolinks) events will be registered, if set to true. */
    turbo?: boolean;
    /** Enable debug mode for detailed logging of React on Rails operations. */
    debugMode?: boolean;
    /** Log component registration details including timing and size information. */
    logComponentRegistration?: boolean;
}
export interface ReactOnRails {
    /**
     * Main entry point to using the react-on-rails npm package. This is how Rails will be able to
     * find you components for rendering.
     * @param components keys are component names, values are components
     */
    register(components: Record<string, ReactComponentOrRenderFunction>): void;
    /** @deprecated Use registerStoreGenerators instead */
    registerStore(stores: Record<string, StoreGenerator>): void;
    /**
     * Allows registration of store generators to be used by multiple React components on one Rails
     * view. Store generators are functions that take one arg, props, and return a store. Note that
     * the `setStore` API is different in that it's the actual store hydrated with props.
     * @param storeGenerators keys are store names, values are the store generators
     */
    registerStoreGenerators(storeGenerators: Record<string, StoreGenerator>): void;
    /**
     * Allows retrieval of the store by name. This store will be hydrated by any Rails form props.
     * @param name
     * @param [throwIfMissing=true] When false, this function will return undefined if
     *        there is no store with the given name.
     * @returns Redux Store, possibly hydrated
     */
    getStore(name: string, throwIfMissing?: boolean): Store | undefined;
    /**
     * Get a store by name, or wait for it to be registered.
     */
    getOrWaitForStore(name: string): Promise<Store>;
    /**
     * Get a store generator by name, or wait for it to be registered.
     */
    getOrWaitForStoreGenerator(name: string): Promise<StoreGenerator>;
    /**
     * Set options for ReactOnRails, typically before you call `ReactOnRails.register`.
     * @see {ReactOnRailsOptions}
     */
    setOptions(newOptions: Partial<ReactOnRailsOptions>): void;
    /**
     * Renders or hydrates the React element passed. In case React version is >=18 will use the root API.
     * @param domNode
     * @param reactElement
     * @param hydrate if true will perform hydration, if false will render
     * @returns {Root|ReactComponent|ReactElement|null}
     */
    reactHydrateOrRender(domNode: Element, reactElement: ReactElement, hydrate: boolean): RenderReturnType;
    /**
     * Allow directly calling the page loaded script in case the default events that trigger React
     * rendering are not sufficient, such as when loading JavaScript asynchronously with TurboLinks.
     * More details can be found here:
     * https://github.com/shakacode/react_on_rails/blob/master/docs/additional-reading/turbolinks.md
     */
    reactOnRailsPageLoaded(): Promise<void>;
    reactOnRailsComponentLoaded(domId: string): Promise<void>;
    reactOnRailsStoreLoaded(storeName: string): Promise<void>;
    /**
     * Returns CSRF authenticity token inserted by Rails csrf_meta_tags
     * @returns String or null
     */
    authenticityToken(): string | null;
    /**
     * Returns headers with CSRF authenticity token and XMLHttpRequest
     * @param otherHeaders Other headers
     */
    authenticityHeaders(otherHeaders: Record<string, string>): AuthenticityHeaders;
}
export type RSCPayloadStreamInfo = {
    stream: NodeJS.ReadableStream;
    props: unknown;
    componentName: string;
};
export type RSCPayloadCallback = (streamInfo: RSCPayloadStreamInfo) => void;
/** Contains the parts of the `ReactOnRails` API intended for internal use only. */
export interface ReactOnRailsInternal extends ReactOnRails {
    /**
     * Retrieve an option by key.
     * @param key
     * @returns option value
     */
    option<K extends keyof ReactOnRailsOptions>(key: K): ReactOnRailsOptions[K];
    /**
     * Allows retrieval of the store generator by name. This is used internally by ReactOnRails after
     * a Rails form loads to prepare stores.
     * @param name
     * @returns Redux Store generator function
     */
    getStoreGenerator(name: string): StoreGenerator;
    /**
     * Allows saving the store populated by Rails form props. Used internally by ReactOnRails.
     */
    setStore(name: string, store: Store): void;
    /**
     * Clears `hydratedStores` to avoid accidental usage of wrong store hydrated in a previous/parallel
     * request.
     */
    clearHydratedStores(): void;
    /**
     * @example
     * ```js
     * ReactOnRails.render("HelloWorldApp", {name: "Stranger"}, "app");
     * ```
     *
     * Does this:
     * ```js
     * ReactDOM.render(
     *   React.createElement(HelloWorldApp, {name: "Stranger"}),
     *   document.getElementById("app")
     * );
     * ```
     * under React 16/17 and
     * ```js
     * const root = ReactDOMClient.createRoot(document.getElementById("app"));
     * root.render(React.createElement(HelloWorldApp, {name: "Stranger"}));
     * return root;
     * ```
     * under React 18+.
     *
     * @param name Name of your registered component
     * @param props Props to pass to your component
     * @param domNodeId HTML ID of the node the component will be rendered at
     * @param [hydrate=false] Pass truthy to update server rendered HTML. Default is falsy
     * @returns {Root|ReactComponent|ReactElement} Under React 18+: the created React root
     *   (see "What is a root?" in https://github.com/reactwg/react-18/discussions/5).
     *   Under React 16/17: Reference to your component's backing instance or `null` for stateless components.
     */
    render(name: string, props: Record<string, string>, domNodeId: string, hydrate?: boolean): RenderReturnType;
    /**
     * Get the component that you registered
     * @returns {name, component, renderFunction, isRenderer}
     */
    getComponent(name: string): RegisteredComponent;
    /**
     * Get the component that you registered, or wait for it to be registered
     * @returns {name, component, renderFunction, isRenderer}
     */
    getOrWaitForComponent(name: string): Promise<RegisteredComponent>;
    /**
     * Used by server rendering by Rails
     */
    serverRenderReactComponent(options: RenderParams): null | string | Promise<RenderResult>;
    /**
     * Used by server rendering by Rails
     */
    streamServerRenderedReactComponent(options: RenderParams): Readable;
    /**
     * Generates RSC payload, used by Rails
     */
    serverRenderRSCReactComponent(options: RSCRenderParams): Readable;
    /**
     * Used by Rails to catch errors in rendering
     */
    handleError(options: ErrorOptions): string | undefined;
    /**
     * Used by Rails server rendering to replay console messages.
     * Returns the console replay script wrapped in script tags.
     */
    buildConsoleReplay(): string;
    /**
     * Returns the console replay JavaScript code without wrapping it in script tags.
     * Useful when you need to add CSP nonce or other attributes to the script tag.
     */
    getConsoleReplayScript(): string;
    /**
     * Get a Map containing all registered components. Useful for debugging.
     */
    registeredComponents(): Map<string, RegisteredComponent>;
    /**
     * Get a Map containing all registered store generators. Useful for debugging.
     */
    storeGenerators(): Map<string, StoreGenerator>;
    /**
     * Get a Map containing all hydrated stores. Useful for debugging.
     */
    stores(): Map<string, Store>;
    /**
     * Reset options to default.
     */
    resetOptions(): void;
    /**
     * Current options.
     */
    options: ReactOnRailsOptions;
    /**
     * Indicates if the RSC bundle is being used.
     */
    isRSCBundle: boolean;
}
export type RenderStateHtml = FinalHtmlResult | Promise<FinalHtmlResult>;
export type RenderState = {
    result: null | RenderStateHtml;
    hasErrors: boolean;
    error?: RenderingError;
};
export type StreamRenderState = Omit<RenderState, 'result'> & {
    result: null | Readable;
    isShellReady: boolean;
};
export type RenderOptions = {
    componentName: string;
    domNodeId?: string;
    trace?: boolean;
    renderingReturnsPromises: boolean;
};
//# sourceMappingURL=index.d.ts.map