var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
    if (value !== null && value !== void 0) {
        if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
        var dispose, inner;
        if (async) {
            if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
            dispose = value[Symbol.asyncDispose];
        }
        if (dispose === void 0) {
            if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
            dispose = value[Symbol.dispose];
            if (async) inner = dispose;
        }
        if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
        if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
        env.stack.push({ value: value, dispose: dispose, async: async });
    }
    else if (async) {
        env.stack.push({ async: true });
    }
    return value;
};
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
    return function (env) {
        function fail(e) {
            env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
            env.hasError = true;
        }
        var r, s = 0;
        function next() {
            while (r = env.stack.pop()) {
                try {
                    if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
                    if (r.dispose) {
                        var result = r.dispose.call(r.value);
                        if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
                    }
                    else s |= 1;
                }
                catch (e) {
                    fail(e);
                }
            }
            if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
            if (env.hasError) throw env.error;
        }
        return next();
    };
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
    var e = new Error(message);
    return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
});
import { createPartialUpdater } from "./partial-update.js";
import { createNavigationTransaction } from "./navigation-bridge.js";
import { mergeSegmentLoaders, needsLoaderMerge, } from "./merge-segment-loaders.js";
import { assertSegmentStructure } from "./segment-structure-assert.js";
import { startTransition, createElement } from "react";
import { NetworkError, isNetworkError } from "../errors.js";
import { NetworkErrorThrower } from "../network-error-thrower.js";
import { browserDebugLog, isBrowserDebugEnabled, startBrowserTransaction, } from "./logging.js";
// Polyfill Symbol.dispose/asyncDispose for Safari and older browsers
if (typeof Symbol.dispose === "undefined") {
    Symbol.dispose = Symbol("Symbol.dispose");
}
if (typeof Symbol.asyncDispose === "undefined") {
    Symbol.asyncDispose = Symbol("Symbol.asyncDispose");
}
/**
 * Normalize action ID - returns the ID as-is
 *
 * Server actions have IDs like "hash#actionName" or "src/actions.ts#actionName".
 * The full ID is used for tracking in the event controller. When subscribing
 * via useAction, both exact matching (full ID) and suffix matching (action name
 * only) are supported by the event controller.
 */
function normalizeActionId(actionId) {
    return actionId;
}
/**
 * Create a server action bridge for handling RSC server actions
 *
 * The bridge registers a callback with the RSC runtime that handles:
 * - Encoding action arguments
 * - Sending action requests to the server
 * - Processing responses and updating UI
 * - Managing concurrent action requests via event controller
 * - HMR resilience (refetching if segments are missing)
 *
 * @param config - Bridge configuration
 * @returns ServerActionBridge instance
 */
export function createServerActionBridge(config) {
    const { store, client, eventController, deps, onUpdate, renderSegments, version } = config;
    let isRegistered = false;
    const fetchPartialUpdate = createPartialUpdater({
        store,
        client,
        onUpdate,
        renderSegments,
        version,
    });
    /**
     * Server action callback handler
     */
    async function handleServerAction(id, args) {
        const env_1 = { stack: [], error: void 0, hasError: false };
        try {
            const tx = isBrowserDebugEnabled()
                ? startBrowserTransaction("action")
                : null;
            // Normalize action ID to just the function name for store tracking
            const locationKey = window.history.state?.key;
            const actionId = normalizeActionId(id);
            if (tx) {
                browserDebugLog(tx, "action start", { id, actionId, argsCount: args.length });
            }
            // Start action in event controller - handles lifecycle tracking
            const handle = __addDisposableResource(env_1, eventController.startAction(actionId, args), false);
            const segmentState = store.getSegmentState();
            if (tx) {
                browserDebugLog(tx, "action args prepared");
            }
            // Mark cache as stale immediately when action starts
            // This ensures SWR pattern kicks in if user navigates away during action
            store.markCacheAsStaleAndBroadcast();
            // Create temporary references for serialization
            const temporaryReferences = deps.createTemporaryReferenceSet();
            // Capture URL pathname at action start to detect navigation during action
            // Must use window.location (not store.path) because intercepts change URL
            // without changing store.path (e.g., /kanban -> /kanban/card/1)
            const actionStartPathname = window.location.pathname;
            // Build action request URL with current segments
            const url = new URL(window.location.href);
            url.searchParams.set("_rsc_action", id);
            url.searchParams.set("_rsc_segments", segmentState.currentSegmentIds.join(","));
            // Add version param for version mismatch detection
            if (version) {
                url.searchParams.set("_rsc_v", version);
            }
            // Encode arguments
            const encodedBody = await deps.encodeReply(args, { temporaryReferences });
            if (tx) {
                browserDebugLog(tx, "sending action request", {
                    url: url.href,
                    bodyType: typeof encodedBody,
                    isFormData: encodedBody instanceof FormData,
                    segmentCount: segmentState.currentSegmentIds.length,
                });
            }
            // Track when the stream completes
            let resolveStreamComplete;
            const streamComplete = new Promise((resolve) => {
                resolveStreamComplete = resolve;
            });
            // Get intercept source URL if in intercept context
            const interceptSourceUrl = store.getInterceptSourceUrl();
            // Track streaming token - will be set when response arrives
            let streamingToken = null;
            // Send action request with stream tracking
            const responsePromise = fetch(url, {
                method: "POST",
                headers: {
                    "rsc-action": id,
                    "X-RSC-Router-Client-Path": segmentState.currentUrl,
                    ...(tx && { "X-RSC-Router-Request-Id": tx.requestId }),
                    // Send intercept source URL so server can maintain intercept context
                    ...(interceptSourceUrl && {
                        "X-RSC-Router-Intercept-Source": interceptSourceUrl,
                    }),
                },
                body: encodedBody,
            }).then(async (response) => {
                // Check for version mismatch - server wants us to reload
                const reloadUrl = response.headers.get("X-RSC-Reload");
                if (reloadUrl) {
                    if (tx) {
                        browserDebugLog(tx, "version mismatch on action, reloading", { reloadUrl });
                    }
                    window.location.href = reloadUrl;
                    // Return a never-resolving promise to prevent further processing
                    return new Promise(() => { });
                }
                // Start streaming immediately when response arrives
                if (!handle.signal.aborted) {
                    streamingToken = handle.startStreaming();
                }
                if (!response.body) {
                    // No body means stream is already complete
                    streamingToken?.end();
                    resolveStreamComplete();
                    return response;
                }
                // Tee the stream: one for RSC runtime, one for tracking completion
                const [rscStream, trackingStream] = response.body.tee();
                // Consume the tracking stream to detect when it closes
                (async () => {
                    const reader = trackingStream.getReader();
                    try {
                        while (true) {
                            const { done } = await reader.read();
                            if (done)
                                break;
                        }
                    }
                    finally {
                        reader.releaseLock();
                        if (tx) {
                            browserDebugLog(tx, "stream complete");
                        }
                        streamingToken?.end();
                        resolveStreamComplete();
                    }
                })().catch((error) => {
                    console.error("[STREAMING] Error reading tracking stream:", error);
                    streamingToken?.end();
                });
                // Return response with the RSC stream
                return new Response(rscStream, {
                    headers: response.headers,
                    status: response.status,
                    statusText: response.statusText,
                });
            });
            // Deserialize response (MUST use same temporaryReferences)
            let payload;
            try {
                payload = await deps.createFromFetch(responsePromise, {
                    temporaryReferences,
                });
            }
            catch (error) {
                // Clean up streaming token on error (may be null if fetch failed before .then() ran)
                // The token is assigned in .then() callback which runs before this catch block,
                // but TypeScript doesn't track cross-async assignments, so use type assertion
                streamingToken?.end();
                // resolveStreamComplete is assigned in the Promise constructor so it's safe to call
                resolveStreamComplete();
                // Convert network-level errors to NetworkError for proper handling
                if (isNetworkError(error)) {
                    const networkError = new NetworkError("Unable to connect to server. Please check your connection.", {
                        cause: error,
                        url: url.toString(),
                        operation: "action",
                    });
                    // Mark action as failed
                    handle.fail(networkError);
                    // Emit the network error so the root error boundary can catch it
                    // NetworkErrorThrower throws during render to trigger the error boundary
                    startTransition(() => {
                        onUpdate({
                            root: createElement(NetworkErrorThrower, { error: networkError }),
                            metadata: {
                                pathname: segmentState.currentUrl,
                                segments: [],
                                isError: true,
                            },
                        });
                    });
                    throw networkError;
                }
                throw error;
            }
            if (tx) {
                browserDebugLog(tx, "action response received", {
                    isPartial: payload.metadata?.isPartial,
                    isError: payload.metadata?.isError,
                    matchedCount: payload.metadata?.matched?.length ?? 0,
                    diffCount: payload.metadata?.diff?.length ?? 0,
                });
            }
            // Process response
            const { metadata, returnValue } = payload;
            const { matched, diff, segments, isPartial, isError } = metadata || {};
            // Log action result
            if (returnValue) {
                console.log(`[Browser] Action result:`, returnValue);
                if (!returnValue.ok) {
                    console.error(`[Browser] Action failed:`, returnValue.data);
                }
            }
            // Handle error responses with error boundary UI
            if (isError && isPartial && segments && diff) {
                console.log(`[Browser] Processing error boundary response`);
                // Abort all other pending action requests - error takes precedence
                // This prevents other actions from completing and overwriting the error UI
                eventController.abortAllActions();
                // Clear concurrent action tracking - no consolidation needed when showing error
                handle.clearConsolidation();
                // Get current page's cached segments
                const currentKey = store.getHistoryKey();
                const cached = store.getCachedSegments(currentKey);
                const cachedSegments = cached?.segments || [];
                // Create lookup for error segment from server
                const errorSegmentMap = new Map();
                segments.forEach((s) => errorSegmentMap.set(s.id, s));
                // For error responses, use ALL cached segments but replace the errored one
                // This preserves sibling layouts that aren't in the parent chain
                const fullSegments = cachedSegments.map((cached) => {
                    // Replace the error segment with the one from server
                    const fromServer = errorSegmentMap.get(cached.id);
                    if (fromServer)
                        return fromServer;
                    return cached;
                });
                // INTERCEPT HANDLING: Separate intercept segments for explicit injection
                const isInterceptSegment = (s) => s.namespace?.startsWith("intercept:") ||
                    (s.type === "parallel" && s.id.includes(".@"));
                const interceptSegments = fullSegments.filter(isInterceptSegment);
                const mainSegments = fullSegments.filter((s) => !isInterceptSegment(s));
                // Render the full tree with error segment merged with parent layouts
                const errorRenderOptions = {
                    isAction: true,
                    interceptSegments: interceptSegments.length > 0 ? interceptSegments : undefined,
                };
                const errorTree = await renderSegments(mainSegments, errorRenderOptions);
                // Update UI with error boundary
                startTransition(() => {
                    onUpdate({ root: errorTree, metadata: metadata });
                });
                console.log(`[Browser] Error boundary UI rendered`);
                // Update segment tracking to exclude error segment IDs
                const errorSegmentIds = new Set(diff);
                const segmentIdsAfterError = segmentState.currentSegmentIds.filter((id) => !errorSegmentIds.has(id));
                // Update store state
                store.setSegmentIds(segmentIdsAfterError);
                const currentHandleData = eventController.getHandleState().data;
                store.cacheSegmentsForHistory(currentKey, fullSegments, currentHandleData);
                console.log(`[Browser] Segment IDs updated (excluding error segments):`, segmentIdsAfterError);
                // Throw the error so the action promise rejects
                if (returnValue && !returnValue.ok) {
                    handle.fail(returnValue.data);
                    throw returnValue.data;
                }
                // No error in returnValue (shouldn't happen with isError: true)
                handle.complete(undefined);
                return undefined;
            }
            if (isPartial) {
                console.log(`[Browser] Processing partial update`);
                console.log(`[Browser] Server sent ${segments?.length || 0} segments in diff:`, diff);
                console.log(`[Browser] Server expects client to have:`, matched);
                // Record revalidated segments for concurrent action tracking
                if (diff) {
                    handle.recordRevalidatedSegments(diff);
                }
                // Get current page's cached segments for merging
                const currentKey = store.getHistoryKey();
                const cached = store.getCachedSegments(currentKey);
                const cachedSegments = cached?.segments || [];
                const currentSegmentMap = new Map();
                cachedSegments.forEach((s) => currentSegmentMap.set(s.id, s));
                // Create lookup for new segments from server
                const newSegmentMap = new Map();
                (segments || []).forEach((s) => newSegmentMap.set(s.id, s));
                if (!matched) {
                    throw new Error("No matched segments in response");
                }
                // Rebuild from matched: merge server segments with cached, or use cached as fallback
                const fullSegments = matched
                    .map((segId) => {
                    const fromServer = newSegmentMap.get(segId);
                    const fromCache = currentSegmentMap.get(segId);
                    if (fromServer) {
                        // Server returned this segment - check if we need to merge partial loaders
                        if (needsLoaderMerge(fromServer, fromCache)) {
                            return mergeSegmentLoaders(fromServer, fromCache);
                        }
                        const cached = currentSegmentMap.get(segId); // Re-fetch to avoid type narrowing issues
                        // Dev-mode assertion: warn if tree structure would change
                        if (cached) {
                            assertSegmentStructure(cached, fromServer, "action-bridge");
                        }
                        // Preserve cached structural properties to maintain consistent React tree.
                        // Changing these between renders alters the element nesting
                        // (with/without RouteContentWrapper, MountContextProvider, etc.),
                        // causing React to remount components and destroy useActionState.
                        if (cached) {
                            let merged = fromServer;
                            // When server returns component: null for a layout segment, it means
                            // "this segment doesn't need re-rendering" - preserve the cached component
                            // to maintain the outlet chain and prevent React tree changes
                            if (fromServer.component === null &&
                                fromServer.type === "layout" &&
                                cached.component != null) {
                                merged = { ...merged, component: cached.component };
                            }
                            // loading: SSR may set loading=false for skipSSR routes, but actions
                            // resolve loading=<skeleton> (isSSR=false). Preserve cached value.
                            if (cached.loading !== undefined &&
                                fromServer.loading !== cached.loading) {
                                merged = { ...merged, loading: cached.loading };
                            }
                            // mountPath: SSR segments may lack mountPath while action-revalidated
                            // segments include it (from include() scope). The conditional
                            // MountContextProvider wrapper in renderSegments changes tree depth.
                            if (fromServer.mountPath !== cached.mountPath) {
                                merged = { ...merged, mountPath: cached.mountPath };
                            }
                            return merged;
                        }
                        return fromServer;
                    }
                    // Fall back to current page's cached segments
                    if (!fromCache) {
                        console.error(`[Browser] MISSING SEGMENT: ${segId} not in cache!`);
                    }
                    return fromCache;
                })
                    .filter(Boolean);
                const returnData = returnValue?.data;
                console.log(`[Browser] Action complete - UI updated (after action state committed)`);
                if (returnValue && !returnValue.ok) {
                    handle.fail(returnValue.data);
                    throw returnValue.data;
                }
                // Check if user navigated away during the action
                const currentPathname = window.location.pathname;
                const currentLocationKey = window.history.state?.key;
                const userNavigatedAway = currentPathname !== actionStartPathname ||
                    currentLocationKey !== locationKey;
                if (userNavigatedAway) {
                    const env_2 = { stack: [], error: void 0, hasError: false };
                    try {
                        console.log(`[Browser] User navigated away during action (${actionStartPathname} -> ${currentPathname})`);
                        // Clear concurrent action tracking - don't consolidate for old route's segments
                        handle.clearConsolidation();
                        // Check if the history key changed (different cache entry)
                        // This happens when navigating between intercept and non-intercept routes
                        if (currentLocationKey !== locationKey) {
                            console.log(`[Browser] History key changed (${locationKey} -> ${currentLocationKey}), triggering background revalidation`);
                            // The action completed on the server, but the user navigated to a different route.
                            // The navigation fetch may have gotten stale data (before action committed).
                            // Trigger a background revalidation of the CURRENT route to get fresh data.
                            // User navigated to a different history entry.
                            // Check if we should do background revalidation:
                            // - YES if user is on a non-intercept route (safe to revalidate)
                            // - NO if user is on an intercept route (would lose background segments)
                            const currentInterceptSource = store.getInterceptSourceUrl();
                            if (currentInterceptSource) {
                                // User is on an intercept route - skip revalidation to preserve background
                                console.log(`[Browser] Skipping background revalidation - user on intercept route`);
                            }
                            else {
                                // User is on a non-intercept route - safe to revalidate
                                console.log(`[Browser] History key changed, triggering background revalidation`);
                                store.markCacheAsStaleAndBroadcast();
                                const navTx = createNavigationTransaction(store, eventController, window.location.href, { replace: true, skipLoadingState: true });
                                fetchPartialUpdate(window.location.href, [], false, navTx.handle.signal, navTx.with({
                                    url: window.location.href,
                                    storeOnly: true,
                                }), {
                                    isAction: true,
                                }).then(() => {
                                    console.log(`[Browser] Background revalidation complete`);
                                }).catch((error) => {
                                    if (error instanceof DOMException &&
                                        error.name === "AbortError") {
                                        console.log("[Browser] Background revalidation aborted");
                                        return;
                                    }
                                    if (error instanceof NetworkError || isNetworkError(error)) {
                                        console.warn("[Browser] Background revalidation network error (action):", error.message);
                                        return;
                                    }
                                    console.error("[Browser] Background revalidation failed:", error);
                                }).finally(() => {
                                    navTx[Symbol.dispose]();
                                });
                            }
                            handle.complete(returnData);
                            return returnData;
                        }
                        // Same history key but different pathname (e.g., same-page navigation)
                        // Safe to refetch current route
                        console.log(`[Browser] Same history key, refetching current route`);
                        store.markCacheAsStaleAndBroadcast();
                        const navTx = __addDisposableResource(env_2, createNavigationTransaction(store, eventController, window.location.href, { replace: true, skipLoadingState: true }), false);
                        // Preserve intercept context
                        const currentInterceptSource = store.getInterceptSourceUrl();
                        await fetchPartialUpdate(window.location.href, [], // Empty array = refetch all segments for current route
                        false, navTx.handle.signal, navTx.with({
                            url: window.location.href,
                            storeOnly: true,
                            intercept: !!currentInterceptSource,
                            interceptSourceUrl: currentInterceptSource ?? undefined,
                        }), {
                            isAction: true,
                            interceptSourceUrl: currentInterceptSource ?? undefined,
                        });
                        console.log(`[Browser] Refetch after navigation complete`);
                        handle.complete(returnData);
                        return returnData;
                    }
                    catch (e_1) {
                        env_2.error = e_1;
                        env_2.hasError = true;
                    }
                    finally {
                        __disposeResources(env_2);
                    }
                }
                // HMR resilience check - only runs if user DIDN'T navigate away
                if (fullSegments.length < matched.length) {
                    const env_3 = { stack: [], error: void 0, hasError: false };
                    try {
                        console.warn(`[Browser] Missing segments after action (HMR detected), refetching...`);
                        const navTx = __addDisposableResource(env_3, createNavigationTransaction(store, eventController, window.location.href, { replace: true, skipLoadingState: true }), false);
                        await fetchPartialUpdate(window.location.href, [], false, navTx.handle.signal, navTx.with({
                            url: window.location.href,
                            storeOnly: true,
                            intercept: !!interceptSourceUrl,
                            interceptSourceUrl: interceptSourceUrl ?? undefined,
                        }), {
                            isAction: true,
                            interceptSourceUrl: interceptSourceUrl ?? undefined,
                        });
                        console.log(`[Browser] Refetch complete (HMR), now returning action result`);
                        // Broadcast to other tabs
                        store.broadcastCacheInvalidation();
                        handle.complete(returnData);
                        return returnData;
                    }
                    catch (e_2) {
                        env_3.error = e_2;
                        env_3.hasError = true;
                    }
                    finally {
                        __disposeResources(env_3);
                    }
                }
                // Check if we need a consolidation fetch due to concurrent actions
                const consolidationSegments = handle.getConsolidationSegments();
                if (consolidationSegments && consolidationSegments.length > 0) {
                    const env_4 = { stack: [], error: void 0, hasError: false };
                    try {
                        // This is the last concurrent action - do consolidation fetch
                        console.log(`[Browser] Concurrent actions detected - consolidation fetch needed for:`, consolidationSegments);
                        // Calculate segments to send (exclude the ones we want fresh)
                        const currentSegmentIds = store.getSegmentState().currentSegmentIds;
                        const segmentsToSend = currentSegmentIds.filter((id) => !consolidationSegments.includes(id));
                        console.log(`[Browser] Sending segments (excluding revalidated):`, segmentsToSend);
                        // Clear consolidation tracking before fetch
                        handle.clearConsolidation();
                        const navTx = __addDisposableResource(env_4, createNavigationTransaction(store, eventController, window.location.href, { replace: true, skipLoadingState: true }), false);
                        console.warn("Fetch partial", id);
                        await fetchPartialUpdate(window.location.href, segmentsToSend, false, navTx.handle.signal, navTx.with({
                            url: window.location.href,
                            storeOnly: true,
                            intercept: !!interceptSourceUrl,
                            interceptSourceUrl: interceptSourceUrl ?? undefined,
                        }), {
                            isAction: true,
                            interceptSourceUrl: interceptSourceUrl ?? undefined,
                        });
                        console.log(`[Browser] Consolidation fetch complete`);
                        // Broadcast to other tabs
                        store.broadcastCacheInvalidation();
                        console.log(`[Browser] Consolidate/Reconcile - Returning to React:`, returnData);
                        handle.complete(returnData);
                        return returnData;
                    }
                    catch (e_3) {
                        env_4.error = e_3;
                        env_4.hasError = true;
                    }
                    finally {
                        __disposeResources(env_4);
                    }
                }
                // Check if there are OTHER actions still fetching (waiting for server response)
                // Exclude the current action since we already have our response
                // We don't need to wait for streaming to complete - just for the response to arrive
                const otherFetchingActions = [...eventController.getInflightActions().values()].filter((a) => a.phase === "fetching" && a.id !== handle.id);
                if (otherFetchingActions.length > 0) {
                    console.log(`[Browser] Skipping UI update - ${otherFetchingActions.length} other action(s) still fetching`);
                    console.log(`[Browser] Multi actions - Returning to React (no cache clear):`, returnData);
                    // Only update store if history key hasn't changed (user didn't navigate away)
                    const currentKeyNow = store.getHistoryKey();
                    if (currentKeyNow === currentKey) {
                        store.setSegmentIds(matched);
                        const currentHandleData = eventController.getHandleState().data;
                        store.cacheSegmentsForHistory(currentKey, fullSegments, currentHandleData);
                    }
                    else {
                        console.log(`[Browser] History key changed during multi-action (${currentKey} -> ${currentKeyNow}), skipping cache update`);
                    }
                    handle.complete(returnData);
                    return returnData;
                }
                // No concurrent actions - normal flow with single action
                // INTERCEPT HANDLING: Separate intercept segments for explicit injection
                const isInterceptSegment = (s) => s.namespace?.startsWith("intercept:") ||
                    (s.type === "parallel" && s.id.includes(".@"));
                const interceptSegments = fullSegments.filter(isInterceptSegment);
                const mainSegments = fullSegments.filter((s) => !isInterceptSegment(s));
                // Prepare new tree (await loader data resolution)
                const renderOptions = {
                    isAction: true,
                    interceptSegments: interceptSegments.length > 0 ? interceptSegments : undefined,
                };
                const newTree = await renderSegments(mainSegments, renderOptions);
                // Re-check if user navigated away (could happen during async wait)
                const currentPathnameNow = window.location.pathname;
                if (currentPathnameNow !== actionStartPathname) {
                    console.log(`[Browser] User navigated during UI update scheduling, skipping`);
                    handle.complete(returnData);
                    return returnData;
                }
                // Verify the store's current key still matches what we captured at action start
                // If they differ, user navigated away and we should NOT cache under the old key
                const currentKeyNow = store.getHistoryKey();
                if (currentKeyNow !== currentKey) {
                    console.log(`[Browser] History key changed during action (${currentKey} -> ${currentKeyNow}), skipping cache update`);
                    handle.complete(returnData);
                    return returnData;
                }
                startTransition(() => {
                    onUpdate({ root: newTree, metadata: metadata });
                });
                // Update store state
                store.setSegmentIds(matched);
                const currentHandleData = eventController.getHandleState().data;
                store.cacheSegmentsForHistory(currentKey, fullSegments, currentHandleData);
                store.markCacheAsStaleAndBroadcast();
                console.log(`[Browser] Normal - Returning to React:`, returnData);
                handle.complete(returnData);
                return returnData;
            }
            else {
                // Full update not supported for actions
                throw new Error(`[Browser] Full update after action is not supported yet`);
            }
        }
        catch (e_4) {
            env_1.error = e_4;
            env_1.hasError = true;
        }
        finally {
            __disposeResources(env_1);
        }
    }
    return {
        /**
         * Register the server action callback with the RSC runtime
         */
        register() {
            if (isRegistered) {
                console.warn("[Browser] Server action bridge already registered");
                return;
            }
            deps.setServerCallback(handleServerAction);
            isRegistered = true;
            console.log("[Browser] Server action callback registered");
        },
        /**
         * Unregister the server action callback
         */
        unregister() {
            if (!isRegistered) {
                return;
            }
            isRegistered = false;
            console.log("[Browser] Server action bridge unregistered");
        },
    };
}
export { createServerActionBridge as default };
//# sourceMappingURL=server-action-bridge.js.map