Skip to content

Apply Brouter improvements (#12559)#12560

Open
msynk wants to merge 21 commits into
bitfoundation:developfrom
msynk:12559-brouter-improvements
Open

Apply Brouter improvements (#12559)#12560
msynk wants to merge 21 commits into
bitfoundation:developfrom
msynk:12559-brouter-improvements

Conversation

@msynk

@msynk msynk commented Jul 3, 2026

Copy link
Copy Markdown
Member

closes #12559

  1. Leave guards — per-route "unsaved changes" blocking that cancels before the URL ever moves.
  2. External-nav confirmation — browser beforeunload dialog, always-on or toggled at runtime.
  3. Awaitable navigationNavigateAsync tells you if it succeeded, was cancelled, redirected, not found, failed, or superseded.
  4. History entry state — attach a payload to a history entry and read it back across Back/Forward.
  5. Functional query updates — change one query param, keep the rest.
  6. Redirect-loop safety — guard redirects to the current target mean "continue," never a loop.
  7. Error boundaries — nearest ErrorContent renders failures in place, with retry.
  8. .NET 10 NotFound interopNavigationManager.NotFound() support and real HTTP 404s under static SSR.
  9. Revalidation — re-run the current page's loaders after a mutation, no navigation.
  10. SWR loader cacheStaleTime makes Back/Forward instant; stale data renders now, refreshes in background.
  11. Link preloading — hover/viewport/render triggers warm the destination's loaders before the click.
  12. Deferred data<BrouterAwait> streams slow data in after the page reveals.
  13. AOT-safe persistence — plug a source-generated JSON context into the prerender state bridge.
  14. Pathless group routes — shared guard/loader/layout for children without adding URL segments.
  15. Named outlets — one route fills multiple layout regions via BrouterView.
  16. Keep-alive routes — component state survives navigating away and back.
  17. Lazy route loading — load route assemblies on demand, matched within the same navigation.
  18. View transitions — animated page changes via the browser's View Transitions API.
  19. Bit.Brouter.Generators — compile-time-safe URL builders generated from your route declarations.

Plus: 4 pre-existing bugs fixed, 77 tests added (205 total), a demo for every feature, full README coverage.

Summary by CodeRabbit

  • New Features

    • Introduced the new <Broute> route component, including improved route/query parameter binding (by name), container-scoped custom constraints, named outlets, keep-alive behavior, and discovery-based @page matching.
    • Expanded navigation with relative links, awaitable navigation outcomes, history entry state, query updates, and scroll/focus handling (including Back/Forward restoration).
    • Added loader capabilities: caching with stale-while-revalidate, revalidation, deferred/streamed rendering, prerender-state restoration, and richer loader-driven error boundaries.
    • Added view transitions support and compile-time-safe route URL generation.
  • Bug Fixes

    • Improved matching/guard/render invalidation behavior, including strict trailing-slash handling and more reliable authorization/render updates.
  • Documentation

    • Updated routing documentation and examples to use <Broute>.

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

No new commits to review since the last review.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0f3ac50a-988c-414c-a6b1-a9f54e370d65

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR renames the route component to Broute, adds registry-backed constraints and assembly discovery, refactors navigation into preventive and commit phases, adds scroll/focus effects, and updates demos, tests, docs, build wiring, and benchmarks.

Changes

Broute routing, constraints, discovery, and navigation

Layer / File(s) Summary
Broute types and template binding
src/Brouter/Bit.Brouter/Broute.cs, src/Brouter/Bit.Brouter/BrouterOutlet.cs, src/Brouter/Bit.Brouter/BrouterNavigationContext.cs, src/Brouter/Bit.Brouter/BrouterRouteRenderer.cs, src/Brouter/Bit.Brouter/BrouterRouteData.cs, src/Brouter/Bit.Brouter/BrouterView.cs, src/Brouter/Bit.Brouter/BrouterAwait.cs, src/Brouter/Bit.Brouter/BrouterErrorContext.cs, src/Brouter/Bit.Brouter/BrouterLocation.cs, src/Brouter/Bit.Brouter/BrouterQueryBuilder.cs, src/Brouter/Bit.Brouter/BrouterLoaderCache.cs, src/Brouter/Bit.Brouter/BrouterNavigationOutcome.cs, src/Brouter/Bit.Brouter/IBrouter.cs
BrouterRoute is renamed to Broute, nested route wiring uses Broute types, template parameter names are cached, typed route data/meta wrappers are cascaded, named views and deferred fragments are updated, and navigation/query/loader APIs add history state, outcomes, and cache helpers.
Constraint registry and route discovery
src/Brouter/Bit.Brouter/BrouterConstraints.cs, src/Brouter/Bit.Brouter/BrouterConstraintRegistry.cs, src/Brouter/Bit.Brouter/BrouterRouteConstraint.cs, src/Brouter/Bit.Brouter/BrouterTemplateParser.cs, src/Brouter/Bit.Brouter/BrouterTemplateSegment.cs, src/Brouter/Bit.Brouter/BrouterOptions.cs, src/Brouter/Bit.Brouter/BrouterScrollPositionStorage.cs, src/Brouter/Bit.Brouter/BrouteScanner.cs, src/Brouter/Bit.Brouter/BroutePrerenderState.cs, src/Brouter/Bit.Brouter/BrouterRelativeUrl.cs, src/Brouter/Bit.Brouter/BrouterNavigationType.cs, src/Brouter/Bit.Brouter/BrouterNavigationOutcome.cs, src/Brouter/Bit.Brouter/BrouterStaleReloadMode.cs
Constraint registration moves to a per-container registry, template parsing threads the registry into constraint resolution, routable components can be discovered from assemblies, prerender loader results can be captured and restored, relative navigation is resolved by segment math, and navigation/scroll options are exposed as enums and settings.
Matching, navigation pipeline, and prerender persistence
src/Brouter/Bit.Brouter/Brouter.cs, src/Brouter/Bit.Brouter/BrouterService.cs, src/Brouter/Bit.Brouter/BrouterLink.cs, src/Brouter/Bit.Brouter/Scripts/bit-brouter.ts
Route selection, preventive navigation handling, loader staging, prerender restoration, relative URL handling, navigation type classification, link interception/preload wiring, and scroll/focus effects are rewritten around Broute and the new navigation flow.
Build and packaging support
src/Brouter/Bit.Brouter/Bit.Brouter.csproj, src/Brouter/Bit.Brouter/package.json, src/Brouter/Bit.Brouter/tsconfig.json, .gitignore
The project adds TypeScript/JavaScript build wiring, static asset publishing, package metadata, and ignore rules for generated JavaScript.

Estimated code review effort: 5 (Critical) | ~120 minutes

Demo app, docs, tests, generators, and benchmarks

Layer / File(s) Summary
Demo app and README
src/Brouter/InteralDemos/Core/AppRouter.razor, src/Brouter/InteralDemos/Core/DemoState.cs, src/Brouter/InteralDemos/Core/Extensions/IServiceCollectionExtensions.cs, src/Brouter/InteralDemos/Core/Pages/DiscoveredPage.razor, src/Brouter/InteralDemos/Core/Shared/Header.razor, src/Brouter/README.md
The demo router, shared state, service setup, discovered page, header links, and README examples are updated for Broute, discovery, navigation outcomes, scroll/focus behavior, loader caching, deferred data, and constraints.
Route-host Razor components
src/Brouter/Tests/Bit.Brouter.Tests/GuardHost.razor, LinkHost.razor, LoaderHost.razor, NamedRouteHost.razor, OptionalParamHost.razor, QueryHost.razor, SimpleHomeHost.razor, SpecificityHost.razor, ConstraintHost.razor, DiscoveryOverrideHost.razor, MultiReplaceLinkHost.razor, NestedIndexHost.razor, RenderInvalidationHost.razor, SequentialLoadersHost.razor, SwapRouteHost.razor, TypedDataHost.razor, TypedValueReader.razor, ValueReader.razor, DiscoveryHost.razor, NavigationEffectsHost.razor, NavigationTypeHost.razor, PreventiveGuardHost.razor, RelativeLinkHost.razor, RelativeRedirectHost.razor, AmbiguousRoutesHost.razor, CacheHost.razor, CachedView.razor, ChildDataView.razor, DeferredHost.razor, ErrorContentHost.razor, GroupRouteHost.razor, HistoryStateHost.razor, KeepAliveHost.razor, LeaveGuardHost.razor, NamedOutletHost.razor, NavigateAsyncHost.razor, NotFoundInteropHost.razor, OnNavigateHost.razor, ParallelLoadersHost.razor, RevalidateHost.razor, StatefulCounter.razor
Existing test hosts are updated to Broute, and new host components are added for discovery, ambiguity, loader ordering, navigation effects, relative navigation, render invalidation, caching, keep-alive, named outlets, history state, revalidation, error boundaries, and other route scenarios.
Behavior and integration tests
src/Brouter/Tests/Bit.Brouter.Tests/BrouterTests.cs, AmbiguousRouteTests.cs, BrouterLinkTests.cs, ConstraintIntegrationTests.cs, ConstraintRegistryTests.cs, DiscoveryAndPersistenceTests.cs, GuardAndLoaderTests.cs, NavigationEffectsTests.cs, NavigationTypeTests.cs, RelativeNavigationTests.cs, RenderInvalidationTests.cs, ResolveUrlTests.cs, RouteDataCascadeTests.cs, DeferredDataTests.cs, ErrorContentTests.cs, GroupRouteTests.cs, HistoryStateTests.cs, KeepAliveTests.cs, LeaveGuardTests.cs, LoaderCacheTests.cs, NamedOutletTests.cs, NavigateAsyncTests.cs, NotFoundInteropTests.cs, OnNavigateAsyncTests.cs, QueryBuilderTests.cs, RevalidateTests.cs, ViewTransitionTests.cs
Test suites cover trailing slash behavior, ambiguity rejection, constraints, discovery, navigation type, relative URLs, guard flow, render invalidation, loader ordering, URL/query resolution, scroll effects, route data wrapping, deferred data, error boundaries, group routes, history state, keep-alive, leave guards, loader caching, named outlets, awaited navigation outcomes, not-found interop, on-navigate assembly loading, revalidation, and view transitions.
Generators, benchmarks, and support projects
src/Brouter/Bit.Brouter.Generators/Bit.Brouter.Generators.csproj, src/Brouter/Bit.Brouter.Generators/BrouterRoutesGenerator.cs, src/Brouter/Bit.Brouter.Generators/IsExternalInit.cs, src/Brouter/Bit.Brouter.Generators/RouteModel.cs, src/Brouter/Bit.Brouter.Generators/RouteTemplateParser.cs, src/Brouter/Bit.Brouter.Generators/AnalyzerReleases.Shipped.md, src/Brouter/Bit.Brouter.Generators/AnalyzerReleases.Unshipped.md, src/Brouter/Tests/Bit.Brouter.Generators.Tests/Bit.Brouter.Generators.Tests.csproj, src/Brouter/Tests/Bit.Brouter.Generators.Tests/BrouterRoutesGeneratorTests.cs, src/Brouter/Tests/Bit.Brouter.Generators.Tests/GeneratorTestHarness.cs, src/Brouter/Bit.Brouter.slnx, src/Brouter/Tests/Bit.Brouter.Benchmarks/Bit.Brouter.Benchmarks.csproj, src/Brouter/Tests/Bit.Brouter.Benchmarks/BenchmarkComponents.cs, src/Brouter/Tests/Bit.Brouter.Benchmarks/Harness.cs, src/Brouter/Tests/Bit.Brouter.Benchmarks/Program.cs, src/Brouter/Tests/Bit.Brouter.Benchmarks/README.md
Adds the Roslyn route generator and its tests, analyzer release metadata, benchmark harness and console runner, and solution/project wiring for the new generator and benchmark projects.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant NavigationManager
  participant Brouter
  participant Broute
  participant BrouterService
  participant BitBrouterJS

  NavigationManager->>Brouter: OnLocationChanging(to)
  Brouter->>Broute: InvokeGuardsAsync(ctx)
  alt cancel or redirect
    Broute-->>Brouter: ctx.Cancel() / ctx.Redirect(url)
    Brouter->>Brouter: NavigateInternal(prevented target)
  else approve
    Broute-->>Brouter: guard completes
  end
  Brouter->>Brouter: ProcessNavigationAsync(decisionAlreadyMade, navType)
  Brouter->>BrouterService: ApplyNavigationEffectsAsync / SaveScrollPositionAsync
  BrouterService->>BitBrouterJS: applyNavigationEffects(...) / saveScrollPosition(...)
Loading

Poem

I hopped through routes with twitch and cheer,
Broute is here, and guards are clear.
Fragments scroll and focus too,
Relative paths know what to do.
A rabbit grin and carrot glow —
this routey world now nicely flows.

Estimated code review effort: 5 (Critical) | ~120 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Linked Issues check ❓ Inconclusive Most listed goals are covered, but the summaries don't clearly verify a built-in <Navigating> pending UI or the intended guard-reactivity semantics. Clarify or add the router-level <Navigating> support and confirm the guard pipeline matches the requested reactive behavior.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and matches the broad Brouter improvement changes.
Out of Scope Changes check ✅ Passed The added generators, benchmarks, demos, and docs appear to support the stated Brouter overhaul rather than introduce unrelated behavior.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@msynk

msynk commented Jul 4, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai re-review

@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown

@msynk Sure, I'll take another look at the changes now.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (2)
src/Brouter/Bit.Brouter/wwwroot/BitBrouter.js (1)

134-137: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Consider bounding scrollPositions growth.

Every distinct URL leaves a permanent entry, and persistScrollPositions writes the whole map into a single storage slot on each save. Over a long-lived session (or query-param-heavy URLs like search/pagination) this grows unbounded and can hit the Web Storage quota; the quota error is swallowed in persistScrollPositions, so persistence silently stops. A small cap (e.g. LRU eviction of oldest keys) keeps it bounded without changing behavior for typical apps.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Brouter/Bit.Brouter/wwwroot/BitBrouter.js` around lines 134 - 137, The
scroll position cache in `scrollPositions` is unbounded, so each new URL can
permanently add entries and eventually overflow Web Storage. Update the save
path around `scrollPositions.set(...)` and `persistScrollPositions()` to enforce
a small cap on stored keys, evicting the oldest entries first (LRU/oldest-first
is fine) before persisting. Keep the change localized to the scroll persistence
logic in `BitBrouter.js` so typical `currentScroll()` behavior remains
unchanged.
src/Brouter/Bit.Brouter/BrouterService.cs (1)

368-427: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicated catch blocks across the four JS-interop call sites.

ApplyNavigationEffectsAsync, SaveScrollPositionAsync, DisposeAsync, and GoAsync all repeat the same four-exception swallow list. Consider extracting a small SafeJsCallAsync helper to centralize this pattern and reduce duplication.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Brouter/Bit.Brouter/BrouterService.cs` around lines 368 - 427, The JS
interop error handling is duplicated across ApplyNavigationEffectsAsync,
SaveScrollPositionAsync, DisposeAsync, and GoAsync. Extract the repeated
try/catch swallow pattern into a small shared helper such as SafeJsCallAsync in
BrouterService, and have each of those call sites wrap their module invocation
through it so the same four exception types are handled in one place.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/Brouter/Bit.Brouter/Broute.cs`:
- Around line 122-125: Update the stale comment in Broute so it matches the
current constraint resolution flow: the parser in Broute.ParseTemplate should be
described as using the DI-container-scoped Brouter.Options.Constraints plus
built-in constraints only. Remove the reference to a “process-wide registry”
since the global static registry has been removed, and keep the comment aligned
with BrouterConstraintRegistry and BrouterTemplateParser.ParseTemplate.

In `@src/Brouter/Bit.Brouter/BroutePrerenderState.cs`:
- Around line 64-84: TryRestore currently only guards the JSON deserialization
path, but the Type.GetType lookup can still throw for stale or unloadable
persisted type names and should fall back to rerunning the loader instead of
crashing. Update BroutePrerenderState.TryRestore to catch type-resolution
failures around the Type.GetType(state.TypeName, throwOnError: false) step and
return false on those failures, using the same fallback behavior already used
for a missing type or JsonException.

In `@src/Brouter/Bit.Brouter/Brouter.cs`:
- Line 279: The `_navigating` flag in `Brouter` is never driven, so the
`Navigating` pending UI in `BuildRenderTree` never appears. Update
`ProcessNavigationAsync` (especially its loader loop) to set `_navigating` to
true when navigation starts and back to false when it completes or aborts, and
ensure state changes trigger a rerender so the `Navigating` fragment is
shown/hidden correctly. Keep the logic aligned with the existing `_navigating`
field and `Navigating` parameter behavior.

In `@src/Brouter/Bit.Brouter/BrouterRouteRenderer.cs`:
- Around line 99-100: The ApplyTypedParameters call in BrouterRouteRenderer can
leave reused component instances with stale route-parameter values when a
parameter disappears from the current template. Update the parameter application
logic around ApplyTypedParameters so that route parameters not present in the
current _route.TemplateParameterNames are explicitly emitted as default/cleared
frames instead of being skipped, ensuring reused components do not retain values
from a previous route.

In `@src/Brouter/README.md`:
- Around line 254-256: Clarify the navigation precedence wording in the README
so it explicitly states that when a fragment target resolves, it scrolls and
takes focus and no further focus handling occurs. Update the precedence sentence
around the navigation behavior description to make it clear that
FocusOnNavigateSelector only applies when no fragment target was resolved, so
the rules do not imply both focus targets run on the same navigation.

---

Nitpick comments:
In `@src/Brouter/Bit.Brouter/BrouterService.cs`:
- Around line 368-427: The JS interop error handling is duplicated across
ApplyNavigationEffectsAsync, SaveScrollPositionAsync, DisposeAsync, and GoAsync.
Extract the repeated try/catch swallow pattern into a small shared helper such
as SafeJsCallAsync in BrouterService, and have each of those call sites wrap
their module invocation through it so the same four exception types are handled
in one place.

In `@src/Brouter/Bit.Brouter/wwwroot/BitBrouter.js`:
- Around line 134-137: The scroll position cache in `scrollPositions` is
unbounded, so each new URL can permanently add entries and eventually overflow
Web Storage. Update the save path around `scrollPositions.set(...)` and
`persistScrollPositions()` to enforce a small cap on stored keys, evicting the
oldest entries first (LRU/oldest-first is fine) before persisting. Keep the
change localized to the scroll persistence logic in `BitBrouter.js` so typical
`currentScroll()` behavior remains unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: b9b04859-9f89-402b-bc03-dd74ed9d7c93

📥 Commits

Reviewing files that changed from the base of the PR and between 2bf38b5 and 70fd776.

📒 Files selected for processing (37)
  • src/Brouter/Bit.Brouter/Broute.cs
  • src/Brouter/Bit.Brouter/BroutePrerenderState.cs
  • src/Brouter/Bit.Brouter/BrouteScanner.cs
  • src/Brouter/Bit.Brouter/Brouter.cs
  • src/Brouter/Bit.Brouter/BrouterConstraintRegistry.cs
  • src/Brouter/Bit.Brouter/BrouterConstraints.cs
  • src/Brouter/Bit.Brouter/BrouterLink.cs
  • src/Brouter/Bit.Brouter/BrouterNavigationContext.cs
  • src/Brouter/Bit.Brouter/BrouterNavigationType.cs
  • src/Brouter/Bit.Brouter/BrouterOptions.cs
  • src/Brouter/Bit.Brouter/BrouterOutlet.cs
  • src/Brouter/Bit.Brouter/BrouterRouteConstraint.cs
  • src/Brouter/Bit.Brouter/BrouterRouteRenderer.cs
  • src/Brouter/Bit.Brouter/BrouterScrollPositionStorage.cs
  • src/Brouter/Bit.Brouter/BrouterService.cs
  • src/Brouter/Bit.Brouter/BrouterTemplateParser.cs
  • src/Brouter/Bit.Brouter/BrouterTemplateSegment.cs
  • src/Brouter/Bit.Brouter/wwwroot/BitBrouter.js
  • src/Brouter/InteralDemos/Core/AppRouter.razor
  • src/Brouter/InteralDemos/Core/Pages/DiscoveredPage.razor
  • src/Brouter/InteralDemos/Core/Shared/Header.razor
  • src/Brouter/README.md
  • src/Brouter/Tests/Bit.Brouter.Tests/BrouterLinkTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/BrouterTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/ConstraintHost.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/ConstraintIntegrationTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/ConstraintRegistryTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/DiscoveredPage.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/DiscoveryAndPersistenceTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/DiscoveryHost.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/GuardAndLoaderTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/NavigationEffectsHost.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/NavigationEffectsTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/NavigationTypeHost.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/NavigationTypeTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/PreventiveGuardHost.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/SampleDto.cs
💤 Files with no reviewable changes (1)
  • src/Brouter/Bit.Brouter/BrouterConstraints.cs
✅ Files skipped from review due to trivial changes (5)
  • src/Brouter/Tests/Bit.Brouter.Tests/DiscoveredPage.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/PreventiveGuardHost.razor
  • src/Brouter/InteralDemos/Core/Shared/Header.razor
  • src/Brouter/Bit.Brouter/BrouterNavigationType.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/BrouterLinkTests.cs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/Brouter/InteralDemos/Core/AppRouter.razor

Comment thread src/Brouter/Bit.Brouter/Broute.cs
Comment thread src/Brouter/Bit.Brouter/BroutePrerenderState.cs Outdated
Comment thread src/Brouter/Bit.Brouter/Brouter.cs
Comment thread src/Brouter/Bit.Brouter/BrouterRouteRenderer.cs Outdated
Comment thread src/Brouter/README.md Outdated
@msynk

msynk commented Jul 4, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai re-review

@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown

@msynk Sure, I'll take another look at the changes now.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
src/Brouter/Tests/Bit.Brouter.Tests/GuardAndLoaderTests.cs (1)

46-58: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Test doesn't actually assert concurrent execution.

The test only asserts render completion within 3s; per the inline comment this is meant to prove overlap indirectly (a sequential implementation would time out). Consider directly asserting on an events/timestamp collection (similar to the sequential test above) to make the concurrency guarantee explicit and resistant to a slow-but-still-sequential regression that happens to finish under 3s.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Brouter/Tests/Bit.Brouter.Tests/GuardAndLoaderTests.cs` around lines 46 -
58, The ParallelLoaders_runs_chain_loaders_concurrently test is only checking
that rendering finishes, which does not explicitly prove overlap. Update the
test in GuardAndLoaderTests to assert concurrent execution directly, using the
same event/timestamp collection approach as the sequential loader test and
referencing ParallelLoadersHost so you can verify both loaders started before
either completed. Keep the final render assertion if needed, but make the
concurrency guarantee explicit by checking the recorded ordering/timing rather
than relying on a timeout-based proxy.
src/Brouter/Bit.Brouter/BrouterService.cs (1)

115-131: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Consider logging swallowed JS interop failures.

SafeJsCallAsync silently swallows JSDisconnectedException, JSException, InvalidOperationException, and TaskCanceledException across all interop call sites (module import, scroll/focus effects, history.go, module dispose). This is reasonable for expected transient conditions (disconnected circuit, pre-render), but a genuine misconfiguration (e.g., wrong content path breaking the module import) would also be swallowed with zero diagnostics, making it hard to notice broken scroll/focus behavior in production.

♻️ Optional: add debug-level logging on swallowed exceptions
-    private static async ValueTask SafeJsCallAsync(Func<ValueTask> call)
+    private static async ValueTask SafeJsCallAsync(Func<ValueTask> call, ILogger? logger = null)
     {
         try { await call(); }
-        catch (JSDisconnectedException) { /* circuit disconnected mid-call */ }
-        catch (JSException) { /* JS interop failure (e.g. non-browser host) */ }
-        catch (InvalidOperationException) { /* JS interop unavailable during pre-render */ }
-        catch (TaskCanceledException) { /* component disposed mid-call */ }
+        catch (JSDisconnectedException ex) { logger?.LogDebug(ex, "Circuit disconnected mid-call."); }
+        catch (JSException ex) { logger?.LogDebug(ex, "JS interop failure."); }
+        catch (InvalidOperationException ex) { logger?.LogDebug(ex, "JS interop unavailable during pre-render."); }
+        catch (TaskCanceledException ex) { logger?.LogDebug(ex, "Component disposed mid-call."); }
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Brouter/Bit.Brouter/BrouterService.cs` around lines 115 - 131,
SafeJsCallAsync currently swallows JS interop exceptions with no diagnostics,
which can hide real failures at call sites like GoAsync and the other interop
uses in BrouterService. Update SafeJsCallAsync to log swallowed exceptions at
debug level (or equivalent) with enough context before suppressing them, while
still preserving the existing non-fatal behavior for JSDisconnectedException,
JSException, InvalidOperationException, and TaskCanceledException. Keep the
centralized handling in SafeJsCallAsync so all interop paths get the same
logging behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/Brouter/Bit.Brouter/Bit.Brouter.csproj`:
- Around line 84-92: The BuildJavaScript target is not configuration-aware
because its Inputs/Outputs only track the TypeScript files and
wwwroot/bit-brouter.js, so a Debug build can incorrectly satisfy up-to-date
checks for a later Release build. Update the target in Bit.Brouter.csproj so the
incremental build key includes $(Configuration) or separate the Release
minify/move path into configuration-specific outputs, ensuring BuildJavaScript
reruns when switching between Debug and Release. Use the existing
BuildJavaScript target, the esbuild minify step, and the Move action as the
symbols to adjust.

In `@src/Brouter/Bit.Brouter/BrouterRelativeUrl.cs`:
- Around line 18-24: `IsRelative` in `BrouterRelativeUrl` does not treat
dot-prefixed refs with a مباشرة appended query or hash as relative, so `Resolve`
can send them through base-relative navigation instead of preserving the
intended target. Update `IsRelative(string url)` to recognize forms like ".?..."
and "..?..."/".#..."/"..#..." as relative alongside the existing "."/"./" and
".."/"../" cases, keeping the logic aligned with `Resolve`’s
query/hash-preservation behavior.

---

Nitpick comments:
In `@src/Brouter/Bit.Brouter/BrouterService.cs`:
- Around line 115-131: SafeJsCallAsync currently swallows JS interop exceptions
with no diagnostics, which can hide real failures at call sites like GoAsync and
the other interop uses in BrouterService. Update SafeJsCallAsync to log
swallowed exceptions at debug level (or equivalent) with enough context before
suppressing them, while still preserving the existing non-fatal behavior for
JSDisconnectedException, JSException, InvalidOperationException, and
TaskCanceledException. Keep the centralized handling in SafeJsCallAsync so all
interop paths get the same logging behavior.

In `@src/Brouter/Tests/Bit.Brouter.Tests/GuardAndLoaderTests.cs`:
- Around line 46-58: The ParallelLoaders_runs_chain_loaders_concurrently test is
only checking that rendering finishes, which does not explicitly prove overlap.
Update the test in GuardAndLoaderTests to assert concurrent execution directly,
using the same event/timestamp collection approach as the sequential loader test
and referencing ParallelLoadersHost so you can verify both loaders started
before either completed. Keep the final render assertion if needed, but make the
concurrency guarantee explicit by checking the recorded ordering/timing rather
than relying on a timeout-based proxy.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: afea28b0-16f9-4a7e-b0b2-7c84c19ab68f

📥 Commits

Reviewing files that changed from the base of the PR and between 70fd776 and c484772.

⛔ Files ignored due to path filters (1)
  • src/Brouter/Bit.Brouter/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (43)
  • .gitignore
  • src/Brouter/Bit.Brouter.slnx
  • src/Brouter/Bit.Brouter/Bit.Brouter.csproj
  • src/Brouter/Bit.Brouter/Broute.cs
  • src/Brouter/Bit.Brouter/BroutePrerenderState.cs
  • src/Brouter/Bit.Brouter/Brouter.cs
  • src/Brouter/Bit.Brouter/BrouterLink.cs
  • src/Brouter/Bit.Brouter/BrouterNavigationContext.cs
  • src/Brouter/Bit.Brouter/BrouterRelativeUrl.cs
  • src/Brouter/Bit.Brouter/BrouterRouteData.cs
  • src/Brouter/Bit.Brouter/BrouterRouteRenderer.cs
  • src/Brouter/Bit.Brouter/BrouterService.cs
  • src/Brouter/Bit.Brouter/IBrouter.cs
  • src/Brouter/Bit.Brouter/Scripts/bit-brouter.ts
  • src/Brouter/Bit.Brouter/package.json
  • src/Brouter/Bit.Brouter/tsconfig.json
  • src/Brouter/README.md
  • src/Brouter/Tests/Bit.Brouter.Benchmarks/BenchmarkComponents.cs
  • src/Brouter/Tests/Bit.Brouter.Benchmarks/Bit.Brouter.Benchmarks.csproj
  • src/Brouter/Tests/Bit.Brouter.Benchmarks/Harness.cs
  • src/Brouter/Tests/Bit.Brouter.Benchmarks/Program.cs
  • src/Brouter/Tests/Bit.Brouter.Benchmarks/README.md
  • src/Brouter/Tests/Bit.Brouter.Tests/AmbiguousRouteTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/AmbiguousRoutesHost.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/BrouterLinkTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/DiscoveryOverrideHost.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/GuardAndLoaderTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/MultiReplaceLinkHost.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/NavigationEffectsTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/NestedIndexHost.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/ParallelLoadersHost.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/RelativeLinkHost.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/RelativeNavigationTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/RelativeRedirectHost.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/RenderInvalidationHost.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/RenderInvalidationTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/ResolveUrlTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/RouteDataCascadeTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/SequentialLoadersHost.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/SwapRouteHost.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/TypedDataHost.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/TypedValueReader.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/ValueReader.razor
✅ Files skipped from review due to trivial changes (3)
  • src/Brouter/Bit.Brouter/tsconfig.json
  • src/Brouter/Bit.Brouter.slnx
  • src/Brouter/Bit.Brouter/IBrouter.cs
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/Brouter/Bit.Brouter/BroutePrerenderState.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/NavigationEffectsTests.cs
  • src/Brouter/Bit.Brouter/Broute.cs

Comment thread src/Brouter/Bit.Brouter/Bit.Brouter.csproj Outdated
Comment thread src/Brouter/Bit.Brouter/BrouterRelativeUrl.cs
@msynk

msynk commented Jul 4, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai re-review

@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown

@msynk Sure, I'll take another look at the changes now.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@msynk

msynk commented Jul 4, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai re-review

@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown

@msynk Sure, I'll take another look at the changes now.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@msynk

msynk commented Jul 5, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai re-review

@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown

@msynk Sure, I'll take another look at the changes now.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (2)
src/Brouter/Bit.Brouter/BrouterView.cs (1)

41-59: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Stale registration if the cascading Route instance itself changes.

The unregister/re-register logic only handles a changed Name, not a changed Route (e.g., if the component is reparented to a different Broute instance across renders, which can happen with dynamic outlet content). In that case the old Route keeps the stale fragment registered under _registeredName since only the new Route receives SetNamedView. This is an edge case unlikely to occur in typical usage where BrouterView is statically nested inside a fixed Broute.

Optional defensive fix
     protected override void OnParametersSet()
     {
         if (Route is null)
             throw new InvalidOperationException(
                 "A BrouterView must be declared inside a Broute (its ChildContent), whose parent layout hosts the named outlet.");

         if (string.IsNullOrEmpty(Name))
             throw new InvalidOperationException(
                 "BrouterView requires a non-empty Name. The route's main content already renders in the primary (unnamed) outlet via Content/Component.");

-        // Re-register every parameter pass: a host re-render produces a fresh fragment instance
-        // that the outlet must pick up, and a changed Name must vacate the old slot.
-        if (_registeredName is not null && string.Equals(_registeredName, Name, StringComparison.Ordinal) is false)
-        {
-            Route.SetNamedView(_registeredName, null);
-        }
+        // Re-register every parameter pass: a host re-render produces a fresh fragment instance
+        // that the outlet must pick up, and a changed Name or Route must vacate the old slot.
+        if (_registeredName is not null && (_registeredRoute != Route || string.Equals(_registeredName, Name, StringComparison.Ordinal) is false))
+        {
+            _registeredRoute?.SetNamedView(_registeredName, null);
+        }
         Route.SetNamedView(Name, ChildContent);
         _registeredName = Name;
+        _registeredRoute = Route;
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Brouter/Bit.Brouter/BrouterView.cs` around lines 41 - 59, The
OnParametersSet logic in BrouterView only clears the previous registration when
Name changes, so a new cascading Route instance can leave the old Route with a
stale named view. Update the re-registration flow to detect when Route itself
changes, unregister the previously stored _registeredName from the old Route
before switching, then register ChildContent on the current Route and refresh
_registeredName. Keep the fix localized to BrouterView.OnParametersSet and the
_registeredName bookkeeping.
src/Brouter/Tests/Bit.Brouter.Tests/RevalidateTests.cs (1)

55-83: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Assertions run before the fire-and-forget invoke completes.

Both Revalidate_with_no_matched_chain_is_a_noop (Lines 56-67) and Routes_without_loaders_revalidate_as_a_noop (Lines 69-83) call cut.InvokeAsync(() => brouter.RevalidateAsync().AsTask()) without awaiting the returned task or wrapping the assertion in cut.WaitForAssertion, unlike every other test in this class. If RevalidateAsync throws or behaves asynchronously, these tests can pass trivially regardless of actual behavior, and any exception would be silently swallowed as an unobserved task fault.

🧪 Proposed fix
-        var brouter = Services.GetRequiredService<IBrouter>();
-        cut.InvokeAsync(() => brouter.RevalidateAsync().AsTask());
-
-        Assert.AreEqual(0, cut.Instance.ParentLoaderRuns);
-        Assert.AreEqual(0, cut.Instance.ChildLoaderRuns);
+        var brouter = Services.GetRequiredService<IBrouter>();
+        await cut.InvokeAsync(() => brouter.RevalidateAsync().AsTask());
+
+        Assert.AreEqual(0, cut.Instance.ParentLoaderRuns);
+        Assert.AreEqual(0, cut.Instance.ChildLoaderRuns);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Brouter/Tests/Bit.Brouter.Tests/RevalidateTests.cs` around lines 55 - 83,
The two no-op revalidation tests are asserting before `IBrouter.RevalidateAsync`
finishes because `cut.InvokeAsync(...)` is fire-and-forget. Update
`Revalidate_with_no_matched_chain_is_a_noop` and
`Routes_without_loaders_revalidate_as_a_noop` to await the `InvokeAsync` task or
verify results via `cut.WaitForAssertion`, matching the async pattern used
elsewhere in `RevalidateTests`. Ensure the assertions on `ParentLoaderRuns`,
`ChildLoaderRuns`, and the rendered `other` element happen only after
`RevalidateAsync` completes so failures are observed.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/Brouter/Bit.Brouter.Generators/BrouterRoutesGenerator.cs`:
- Around line 51-69: The route generator currently deduplicates templates in
Emit but still passes wildcard routes through, and EmitMethod does not handle
SegmentKind.Wildcard. Update BrouterRoutesGenerator so wildcard templates
emitted by RouteTemplateParser are either skipped during Emit or surfaced as a
diagnostic before generation, and make sure EmitMethod/related switch logic has
an explicit path for SegmentKind.Wildcard to avoid producing incomplete URL
builders.
- Around line 34-69: Duplicate route templates are still resolved by whichever
entry is seen first in BrouterRoutesGenerator.Emit, which silently drops
conflicting explicit names. Update the dedup logic in Emit to detect when the
same Template appears with conflicting route metadata (especially different
non-null Name values) and report a diagnostic through the generator context
instead of choosing a winner arbitrarily; keep the existing stable sort/output
path unchanged.

In `@src/Brouter/Bit.Brouter/BrouterAwait.cs`:
- Around line 41-68: The async render path in BrouterAwait’s ObserveAsync can
resume after the component has started disposing, so guard the final
InvokeAsync(StateHasChanged) call with a disposal check. Add a _disposed flag or
cancellation token to BrouterAwait, set it during disposal, and ensure
ObserveAsync exits without scheduling a render once disposal has begun; keep the
existing ReferenceEquals(_observed, task) check as part of the guard.

In `@src/Brouter/README.md`:
- Around line 320-342: Clarify the caching behavior in the README section around
preloading and loader caching: “No StaleTime anywhere → no caching” applies only
to the normal loader cache, while preloaded results are cached separately and
may still be reused during navigation via PreloadAsync and BrouterLinkPreload
with PreloadStaleTime. Update the wording in the StaleTime/preloading
explanation to distinguish the loader cache from the preload cache and avoid
implying that all caching is disabled when StaleTime is absent.

In
`@src/Brouter/Tests/Bit.Brouter.Generators.Tests/Bit.Brouter.Generators.Tests.csproj`:
- Around line 1-27: The test project is missing the shared build import/target
setup, so CI cannot resolve InstallNodejsDependencies. Update
Bit.Brouter.Generators.Tests.csproj to match the generator project’s build
integration by importing the shared Bit.Build.props/Bit.Build.targets pattern
and ensuring the InstallNodejsDependencies target is available. Use the existing
Bit.Brouter.Generators.csproj and its build-related symbols as the reference for
where the common build files and target wiring should be added.

In `@src/Brouter/Tests/Bit.Brouter.Tests/NavigateAsyncTests.cs`:
- Around line 20-129: The test methods in NavigateAsyncTests are reading the
navigation ValueTask before the cut.InvokeAsync dispatch has completed, so
navigation can still be the default value and produce a bogus outcome. Update
the affected tests to be async Task methods, await cut.InvokeAsync when
assigning navigation from BrouterNavigation.NavigateAsync, and then call Await
only after the dispatch has finished so the real ValueTask is observed.

---

Nitpick comments:
In `@src/Brouter/Bit.Brouter/BrouterView.cs`:
- Around line 41-59: The OnParametersSet logic in BrouterView only clears the
previous registration when Name changes, so a new cascading Route instance can
leave the old Route with a stale named view. Update the re-registration flow to
detect when Route itself changes, unregister the previously stored
_registeredName from the old Route before switching, then register ChildContent
on the current Route and refresh _registeredName. Keep the fix localized to
BrouterView.OnParametersSet and the _registeredName bookkeeping.

In `@src/Brouter/Tests/Bit.Brouter.Tests/RevalidateTests.cs`:
- Around line 55-83: The two no-op revalidation tests are asserting before
`IBrouter.RevalidateAsync` finishes because `cut.InvokeAsync(...)` is
fire-and-forget. Update `Revalidate_with_no_matched_chain_is_a_noop` and
`Routes_without_loaders_revalidate_as_a_noop` to await the `InvokeAsync` task or
verify results via `cut.WaitForAssertion`, matching the async pattern used
elsewhere in `RevalidateTests`. Ensure the assertions on `ParentLoaderRuns`,
`ChildLoaderRuns`, and the rendered `other` element happen only after
`RevalidateAsync` completes so failures are observed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 931608d6-38f7-480f-9527-d182d4ca6dd0

📥 Commits

Reviewing files that changed from the base of the PR and between 7a28e64 and 448ed58.

📒 Files selected for processing (75)
  • src/Brouter/Bit.Brouter.Generators/Bit.Brouter.Generators.csproj
  • src/Brouter/Bit.Brouter.Generators/BrouterRoutesGenerator.cs
  • src/Brouter/Bit.Brouter.Generators/IsExternalInit.cs
  • src/Brouter/Bit.Brouter.Generators/RazorRouteScanner.cs
  • src/Brouter/Bit.Brouter.Generators/RouteModel.cs
  • src/Brouter/Bit.Brouter.Generators/RouteTemplateParser.cs
  • src/Brouter/Bit.Brouter.slnx
  • src/Brouter/Bit.Brouter/Broute.cs
  • src/Brouter/Bit.Brouter/BroutePrerenderState.cs
  • src/Brouter/Bit.Brouter/Brouter.cs
  • src/Brouter/Bit.Brouter/BrouterAwait.cs
  • src/Brouter/Bit.Brouter/BrouterErrorContext.cs
  • src/Brouter/Bit.Brouter/BrouterLink.cs
  • src/Brouter/Bit.Brouter/BrouterLinkPreload.cs
  • src/Brouter/Bit.Brouter/BrouterLoaderCache.cs
  • src/Brouter/Bit.Brouter/BrouterLocation.cs
  • src/Brouter/Bit.Brouter/BrouterNavigationContext.cs
  • src/Brouter/Bit.Brouter/BrouterNavigationOutcome.cs
  • src/Brouter/Bit.Brouter/BrouterOptions.cs
  • src/Brouter/Bit.Brouter/BrouterOutlet.cs
  • src/Brouter/Bit.Brouter/BrouterQueryBuilder.cs
  • src/Brouter/Bit.Brouter/BrouterRouteRenderer.cs
  • src/Brouter/Bit.Brouter/BrouterService.cs
  • src/Brouter/Bit.Brouter/BrouterStaleReloadMode.cs
  • src/Brouter/Bit.Brouter/BrouterView.cs
  • src/Brouter/Bit.Brouter/IBrouter.cs
  • src/Brouter/Bit.Brouter/Scripts/bit-brouter.ts
  • src/Brouter/InteralDemos/Core/AppRouter.razor
  • src/Brouter/InteralDemos/Core/Bit.Brouter.Demos.Core.csproj
  • src/Brouter/InteralDemos/Core/DemoState.cs
  • src/Brouter/InteralDemos/Core/Extensions/IServiceCollectionExtensions.cs
  • src/Brouter/InteralDemos/Core/Pages/DataPage.razor
  • src/Brouter/InteralDemos/Core/Pages/DeferredPage.razor
  • src/Brouter/InteralDemos/Core/Pages/EditorPage.razor
  • src/Brouter/InteralDemos/Core/Pages/HistoryStatePage.razor
  • src/Brouter/InteralDemos/Core/Pages/HomePage.razor
  • src/Brouter/InteralDemos/Core/Pages/OutcomesPage.razor
  • src/Brouter/InteralDemos/Core/Pages/StickyNotePage.razor
  • src/Brouter/InteralDemos/Core/Pages/UnstablePage.razor
  • src/Brouter/InteralDemos/Core/Shared/Header.razor
  • src/Brouter/README.md
  • src/Brouter/Tests/Bit.Brouter.Generators.Tests/Bit.Brouter.Generators.Tests.csproj
  • src/Brouter/Tests/Bit.Brouter.Generators.Tests/BrouterRoutesGeneratorTests.cs
  • src/Brouter/Tests/Bit.Brouter.Generators.Tests/GeneratorTestHarness.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/CacheHost.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/CachedView.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/ChildDataView.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/DeferredDataTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/DeferredHost.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/DiscoveryAndPersistenceTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/ErrorContentHost.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/ErrorContentTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/GroupRouteHost.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/GroupRouteTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/HistoryStateHost.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/HistoryStateTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/KeepAliveHost.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/KeepAliveTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/LeaveGuardHost.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/LeaveGuardTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/LoaderCacheTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/NamedOutletHost.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/NamedOutletTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/NavigateAsyncHost.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/NavigateAsyncTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/NotFoundInteropHost.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/NotFoundInteropTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/OnNavigateAsyncTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/OnNavigateHost.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/QueryBuilderTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/RevalidateHost.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/RevalidateTests.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/SampleDto.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/StatefulCounter.razor
  • src/Brouter/Tests/Bit.Brouter.Tests/ViewTransitionTests.cs
✅ Files skipped from review due to trivial changes (4)
  • src/Brouter/Bit.Brouter/BrouterLinkPreload.cs
  • src/Brouter/Tests/Bit.Brouter.Tests/KeepAliveHost.razor
  • src/Brouter/InteralDemos/Core/DemoState.cs
  • src/Brouter/Bit.Brouter.slnx
🚧 Files skipped from review as they are similar to previous changes (6)
  • src/Brouter/Bit.Brouter/BroutePrerenderState.cs
  • src/Brouter/Bit.Brouter/BrouterNavigationContext.cs
  • src/Brouter/Bit.Brouter/Broute.cs
  • src/Brouter/Bit.Brouter/BrouterLink.cs
  • src/Brouter/Bit.Brouter/BrouterRouteRenderer.cs
  • src/Brouter/Bit.Brouter/BrouterService.cs

Comment thread src/Brouter/Bit.Brouter.Generators/BrouterRoutesGenerator.cs
Comment thread src/Brouter/Bit.Brouter.Generators/BrouterRoutesGenerator.cs Outdated
Comment thread src/Brouter/Bit.Brouter/BrouterAwait.cs
Comment thread src/Brouter/README.md
Comment thread src/Brouter/Tests/Bit.Brouter.Tests/NavigateAsyncTests.cs
@msynk

msynk commented Jul 5, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai re-review

@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown

@msynk Sure, I'll take another look at the changes now.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@msynk

msynk commented Jul 5, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai re-review

@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown

@msynk Sure, I'll take another look at the changes now.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

This comment was marked as resolved.

@bitfoundation bitfoundation deleted a comment from coderabbitai Bot Jul 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The Brouter improvements

1 participant