/**
 * Router Error Handling Utilities
 *
 * Error boundary and not-found boundary handling for RSC Router.
 * Also includes the shared invokeOnError utility for error callback invocation.
 */
/**
 * Invoke the onError callback with comprehensive context.
 * Catches any errors in the callback itself to prevent masking the original error.
 *
 * This is a shared utility used by both the router and RSC handler to ensure
 * consistent error callback behavior across the codebase.
 *
 * @param onError - The onError callback to invoke (may be undefined)
 * @param error - The error that occurred
 * @param phase - The phase where the error occurred
 * @param context - Additional context about the error
 * @param logPrefix - Prefix for console.error messages (e.g., "Router" or "RSC")
 */
export function invokeOnError(onError, error, phase, context, logPrefix = "Router") {
    if (!onError)
        return;
    const errorObj = error instanceof Error ? error : new Error(String(error));
    const duration = context.requestStartTime
        ? performance.now() - context.requestStartTime
        : undefined;
    const errorContext = {
        error: errorObj,
        phase,
        request: context.request,
        url: context.url,
        pathname: context.url.pathname,
        method: context.request.method,
        routeKey: context.routeKey,
        params: context.params,
        segmentId: context.segmentId,
        segmentType: context.segmentType,
        loaderName: context.loaderName,
        middlewareId: context.middlewareId,
        actionId: context.actionId,
        env: context.env,
        duration,
        isPartial: context.isPartial,
        handledByBoundary: context.handledByBoundary,
        stack: errorObj.stack,
        metadata: context.metadata,
    };
    try {
        const result = onError(errorContext);
        // If onError returns a promise, catch any rejections
        if (result instanceof Promise) {
            result.catch((callbackError) => {
                console.error(`[${logPrefix}.onError] Callback error:`, callbackError);
            });
        }
    }
    catch (callbackError) {
        // Log but don't throw - we don't want callback errors to mask the original error
        console.error(`[${logPrefix}.onError] Callback error:`, callbackError);
    }
}
/**
 * Find the nearest error boundary by walking up the entry chain
 * Also checks sibling layouts (orphan layouts) for error boundaries
 * Returns the first fallback found, or the default error boundary if configured
 */
export function findNearestErrorBoundary(entry, defaultErrorBoundary) {
    let current = entry;
    while (current) {
        // Check if this entry has error boundaries defined
        if (current.errorBoundary && current.errorBoundary.length > 0) {
            // Return the last error boundary (most recently defined takes precedence)
            return current.errorBoundary[current.errorBoundary.length - 1];
        }
        // Check orphan layouts for error boundaries
        // Orphan layouts are siblings that render alongside the main route chain
        // They can define error boundaries that catch errors from routes in the same route group
        // Check from first to last (first sibling takes precedence as the "outer" wrapper)
        if (current.layout && current.layout.length > 0) {
            for (const orphan of current.layout) {
                if (orphan.errorBoundary && orphan.errorBoundary.length > 0) {
                    return orphan.errorBoundary[orphan.errorBoundary.length - 1];
                }
            }
        }
        current = current.parent;
    }
    // Return default error boundary if configured
    return defaultErrorBoundary || null;
}
/**
 * Find the nearest notFound boundary by walking up the entry chain
 * Returns the first fallback found, or the default notFound boundary if configured
 */
export function findNearestNotFoundBoundary(entry, defaultNotFoundBoundary) {
    let current = entry;
    while (current) {
        // Check if this entry has notFound boundaries defined
        if (current.notFoundBoundary && current.notFoundBoundary.length > 0) {
            // Return the last notFound boundary (most recently defined takes precedence)
            return current.notFoundBoundary[current.notFoundBoundary.length - 1];
        }
        current = current.parent;
    }
    // Return default notFound boundary if configured
    return defaultNotFoundBoundary || null;
}
/**
 * Create ErrorInfo from an error object
 * Sanitizes error details in production
 */
export function createErrorInfo(error, segmentId, segmentType) {
    const isDev = process.env.NODE_ENV !== "production";
    if (error instanceof Error) {
        return {
            message: isDev ? error.message : "An error occurred",
            name: error.name,
            code: error.code,
            stack: isDev ? error.stack : undefined,
            cause: isDev ? error.cause : undefined,
            segmentId,
            segmentType,
        };
    }
    // Non-Error thrown
    return {
        message: isDev ? String(error) : "An error occurred",
        name: "Error",
        segmentId,
        segmentType,
    };
}
/**
 * Create an error segment with the fallback component
 * Renders the fallback with error info and reset function
 */
export function createErrorSegment(errorInfo, fallback, entry, params) {
    // Determine the component to render
    let component;
    if (typeof fallback === "function") {
        // ErrorBoundaryHandler - call with error info
        const props = {
            error: errorInfo,
        };
        component = fallback(props);
    }
    else {
        // Static ReactNode fallback
        component = fallback;
    }
    // Error segment uses the same ID as the layout that has the error boundary
    // The error boundary content replaces the layout's outlet content
    return {
        id: entry.shortCode,
        namespace: entry.id,
        type: "error",
        index: 0,
        component,
        params,
        error: errorInfo,
    };
}
/**
 * Create NotFoundInfo from a DataNotFoundError
 */
export function createNotFoundInfo(error, segmentId, segmentType, pathname) {
    return {
        message: error.message,
        segmentId,
        segmentType,
        pathname,
    };
}
/**
 * Create a notFound segment with the fallback component
 * Renders the fallback with not found info
 */
export function createNotFoundSegment(notFoundInfo, fallback, entry, params) {
    // Determine the component to render
    let component;
    if (typeof fallback === "function") {
        // NotFoundBoundaryHandler - call with props
        const props = {
            notFound: notFoundInfo,
        };
        component = fallback(props);
    }
    else {
        // Static ReactNode fallback
        component = fallback;
    }
    return {
        id: `${entry.shortCode}.notFound`,
        namespace: entry.id,
        type: "notFound",
        index: 0,
        component,
        params,
        notFoundInfo,
    };
}
//# sourceMappingURL=error-handling.js.map