# Navigation

Provides backend-neutral reactive navigation state and Effectful history operations.

## Signatures

```ts
export declare class Navigation extends Navigation_base {
    static readonly origin: Effect.Effect<string, never, Navigation>;
    static readonly base: Effect.Effect<string, never, Navigation>;
    static readonly currentEntry: RefSubject.Computed<{
        readonly id: string;
        readonly key: string;
        readonly url: URL;
        readonly state: unknown;
        readonly sameDocument: boolean;
    }, never, Navigation>;
    static readonly entries: RefSubject.Computed<readonly {
        readonly id: string;
        readonly key: string;
        readonly url: URL;
        readonly state: unknown;
        readonly sameDocument: boolean;
    }[], never, Navigation>;
    static readonly transition: RefSubject.Filtered<{
        readonly type: "push" | "replace" | "reload" | "traverse";
        readonly from: {
            readonly id: string;
            readonly key: string;
            readonly url: URL;
            readonly state: unknown;
            readonly sameDocument: boolean;
        };
        readonly to: {
            readonly url: URL;
            readonly state: unknown;
            readonly sameDocument: boolean;
            readonly key?: string | undefined;
        };
        readonly info?: unknown;
    }, never, Navigation>;
    static readonly canGoBack: RefSubject.Computed<boolean, never, Navigation>;
    static readonly canGoForward: RefSubject.Computed<boolean, never, Navigation>;
    static navigate<S>(url: string | URL, options: NavigationNavigateOptions & {
        readonly state: S;
    }): Effect.Effect<DestinationState<S>, NavigationError, Navigation>;
    static navigate(url: string | URL, options?: NavigationNavigateOptions): Effect.Effect<Destination, NavigationError, Navigation>;
    static readonly back: (options?: NavigationInfoOptions) => Effect.Effect<{
        readonly id: string;
        readonly key: string;
        readonly url: URL;
        readonly state: unknown;
        readonly sameDocument: boolean;
    }, NavigationError, Navigation>;
    static readonly forward: (options?: NavigationInfoOptions) => Effect.Effect<{
        readonly id: string;
        readonly key: string;
        readonly url: URL;
        readonly state: unknown;
        readonly sameDocument: boolean;
    }, NavigationError, Navigation>;
    static readonly traverseTo: (key: Destination["key"], options?: NavigationInfoOptions) => Effect.Effect<{
        readonly id: string;
        readonly key: string;
        readonly url: URL;
        readonly state: unknown;
        readonly sameDocument: boolean;
    }, NavigationError, Navigation>;
    static updateCurrentEntry<S>(options: {
        readonly state: S;
    }): Effect.Effect<DestinationState<S>, NavigationError, Navigation>;
    static updateCurrentEntry(options: {
        readonly state: unknown;
    }): Effect.Effect<Destination, NavigationError, Navigation>;
    static reload<S>(options: NavigationReloadOptions & {
        readonly state: S;
    }): Effect.Effect<DestinationState<S>, NavigationError, Navigation>;
    static reload(options?: NavigationReloadOptions): Effect.Effect<Destination, NavigationError, Navigation>;
    static readonly onBeforeNavigation: <R = never, R2 = never>(handler: BeforeNavigationHandler<R, R2>) => Effect.Effect<void, never, Navigation | Scope.Scope | R | R2>;
    static readonly onNavigation: <R = never, R2 = never>(handler: NavigationHandler<R, R2>) => Effect.Effect<void, never, Navigation | Scope.Scope | R | R2>;
}
```

## Why

Routers, renderers, and application code can depend on one service whether history comes from a
browser, SSR memory, or a test. Current entry, entries, and transition are RefSubjects so state
remains renderer-independent.

## Ownership and lifetime

A provider Layer owns the service, its backend listeners, reactive state, and handler registry.
Handler registration requires a Scope and unregisters through that scope's finalizer. Each
navigation Effect publishes a transition, runs before handlers sequentially, commits, clears the
transition, and then runs post-commit handlers. Interruption follows Effect's scoped cleanup.

## Property: back

Traverses to the preceding retained entry when one exists.

## Property: back: Why

Bounds behavior stays provider-neutral and preserves the destination's key, id, and state.

## Property: back: Ownership and lifetime

The provider computes the preceding index and owns the resulting traversal transition. At the
lower bound it returns the current Destination without creating backend work.

## Property: base

The structural base path exposed by the active provider.

## Property: base: Why

Routers can establish a stable mount root separately from the changing current URL.

## Property: base: Ownership and lifetime

`Navigation.base` reads the active service synchronously; the provider owns the stored string for its Layer lifetime.

## Property: canGoBack

Whether the retained history contains a preceding entry.

## Property: canGoBack: Why

Callers can disable back actions without duplicating provider bounds logic.

## Property: canGoBack: Ownership and lifetime

`Navigation.canGoBack` is a provider-backed RefSubject view. The provider owns its state; each consumer Scope owns and releases its observation.

## Property: canGoForward

Whether the retained history contains a following entry.

## Property: canGoForward: Why

Callers can disable forward actions after pushes truncate the forward branch.

## Property: canGoForward: Ownership and lifetime

`Navigation.canGoForward` is a provider-backed RefSubject view. The provider owns its state; each consumer Scope owns and releases its observation.

## Property: currentEntry

The reactive committed destination at the active history index.

## Property: currentEntry: Why

Readers observe committed history. A before-navigation decision can still cancel or redirect
the separate proposed transition without changing this value. A committed destination does
not imply that the selected page has finished loading data or mounting its DOM.

## Property: currentEntry: Ownership and lifetime

`Navigation.currentEntry` is a provider-backed RefSubject view. The provider owns its state; each consumer Scope owns and releases its observation.

## Property: entries

The reactive retained history entries in traversal order.

## Property: entries: Why

Back, forward, and keyed traversal need an explicit bounded history model in every provider.

## Property: entries: Ownership and lifetime

`Navigation.entries` is a provider-backed RefSubject view. The provider owns its state; each consumer Scope owns and releases its observation.

## Property: forward

Traverses to the following retained entry when one exists.

## Property: forward: Why

Bounds behavior stays provider-neutral and preserves forward-history identity.

## Property: forward: Ownership and lifetime

The provider computes the following index and owns the resulting traversal transition. At the
upper bound it returns the current Destination without creating backend work.

## Method: navigate

Starts a push or replacement transition to a URL.

## Method: navigate: Why

All backends use the same ordered guard, redirect, commit, and post-commit protocol.

## Method: navigate: Ownership and lifetime

The provider owns the proposed transition until it commits, redirects, cancels, fails, or is
interrupted. Once its backend mutation commits, later interruption cannot undo that mutation.

## Property: onBeforeNavigation

Registers a scoped pre-commit navigation handler.

## Property: onBeforeNavigation: Why

Handlers can allow, redirect, or cancel before the backend mutates history.

## Property: onBeforeNavigation: Ownership and lifetime

Registration captures the current Effect context and requires Scope. Closing that Scope unregisters the handler and releases retained references.

## Property: onNavigation

Registers a scoped post-commit navigation handler.

## Property: onNavigation: Why

Follow-up synchronization runs only after history and current-entry state agree.

## Property: onNavigation: Ownership and lifetime

Registration captures the current Effect context and requires Scope. Closing that Scope unregisters the handler and releases retained references.

## Property: origin

The absolute origin used to resolve relative destinations.

## Property: origin: Why

A single origin makes same-document classification and URL normalization consistent across providers.

## Property: origin: Ownership and lifetime

`Navigation.origin` reads the active service synchronously; the provider owns the stored string for its Layer lifetime.

## Method: reload

Reloads the current destination through the active backend.

## Method: reload: Why

Reload behavior remains explicit without pretending it is a push or keyed traversal.

## Method: reload: Ownership and lifetime

The active provider owns reload work and decides whether the platform can remain in-process.
Browser reload may leave the current JavaScript lifetime once the History API action commits.

## Property: transition

The reactive transition while navigation is pending.

## Property: transition: Why

Renderers can show pending work without treating a proposal as the committed destination.

## Property: transition: Ownership and lifetime

`Navigation.transition` is a provider-backed RefSubject view. The provider owns its state; each consumer Scope owns and releases its observation.

Use `transition.asComputed()` when pending UI must observe `Option.none()` as the transition
ends. The Filtered observation itself emits only present transitions, so it cannot signal
absence by publishing another Transition. Reading it while absent has the usual Filtered
`NoSuchElementError` behavior.

## Property: traverseTo

Traverses to a retained entry by stable key.

## Property: traverseTo: Why

A key addresses history identity even when several entries share the same URL.

## Property: traverseTo: Ownership and lifetime

The provider owns keyed lookup and the resulting backend traversal. The current key is a no-op;
an unknown key fails with `NavigationError` before any backend commit.

## Method: updateCurrentEntry

Replaces application state on the current committed entry.

## Method: updateCurrentEntry: Why

State updates should not create a new navigation position or remount the selected route.

## Method: updateCurrentEntry: Ownership and lifetime

The provider owns the replacement transition and retains the supplied state only if it commits.
The existing Destination key and history position remain current.

## Examples

```ts
import { Navigation } from "@typed/navigation/Navigation"
import * as Effect from "effect/Effect"

const goToAccount = Navigation.navigate("/account", { history: "push" })
const current = Navigation.currentEntry
```

Effect service and Scope concepts follow the Effect v4 model documented at
https://effect.website/docs/requirements-management/services/ and
https://effect.website/docs/resource-management/scope/.
