@rangojs/router 0.0.0-experimental.14 → 0.0.0-experimental.141
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +17 -0
- package/README.md +432 -7
- package/dist/bin/rango.js +2073 -213
- package/dist/testing/vitest.js +82 -0
- package/dist/vite/index.js +7258 -2714
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +140 -67
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +329 -0
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +487 -0
- package/skills/caching/SKILL.md +357 -25
- package/skills/comparison/SKILL.md +50 -0
- package/skills/comparison/agents/openai.yaml +4 -0
- package/skills/comparison/references/framework-comparison.md +837 -0
- package/skills/composability/SKILL.md +246 -0
- package/skills/css/SKILL.md +76 -0
- package/skills/debug-manifest/SKILL.md +16 -10
- package/skills/document-cache/SKILL.md +87 -62
- package/skills/fonts/SKILL.md +6 -4
- package/skills/handler-use/SKILL.md +364 -0
- package/skills/hooks/SKILL.md +557 -79
- package/skills/host-router/SKILL.md +320 -0
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +207 -15
- package/skills/layout/SKILL.md +146 -6
- package/skills/links/SKILL.md +304 -25
- package/skills/loader/SKILL.md +616 -54
- package/skills/middleware/SKILL.md +217 -37
- package/skills/migrate-nextjs/SKILL.md +611 -0
- package/skills/migrate-react-router/SKILL.md +927 -0
- package/skills/mime-routes/SKILL.md +42 -11
- package/skills/observability/SKILL.md +194 -0
- package/skills/parallel/SKILL.md +284 -3
- package/skills/ppr/SKILL.md +293 -0
- package/skills/prerender/SKILL.md +437 -52
- package/skills/rango/SKILL.md +369 -22
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +263 -121
- package/skills/route/SKILL.md +350 -21
- package/skills/router-setup/SKILL.md +246 -33
- package/skills/scripts/SKILL.md +179 -0
- package/skills/server-actions/SKILL.md +775 -0
- package/skills/shell-manifest/SKILL.md +185 -0
- package/skills/streams-and-websockets/SKILL.md +283 -0
- package/skills/tailwind/SKILL.md +27 -3
- package/skills/testing/SKILL.md +126 -222
- package/skills/testing/bindings.md +103 -0
- package/skills/testing/cache-prerender.md +127 -0
- package/skills/testing/client-components.md +124 -0
- package/skills/testing/e2e-parity.md +125 -0
- package/skills/testing/flight.md +91 -0
- package/skills/testing/handles.md +131 -0
- package/skills/testing/loader.md +128 -0
- package/skills/testing/middleware.md +99 -0
- package/skills/testing/render-handler.md +122 -0
- package/skills/testing/response-routes.md +95 -0
- package/skills/testing/reverse-and-types.md +85 -0
- package/skills/testing/server-actions.md +107 -0
- package/skills/testing/server-tree.md +128 -0
- package/skills/testing/setup.md +123 -0
- package/skills/theme/SKILL.md +9 -8
- package/skills/typesafety/SKILL.md +532 -103
- package/skills/use-cache/SKILL.md +367 -0
- package/skills/vercel/SKILL.md +128 -0
- package/skills/view-transitions/SKILL.md +337 -0
- package/src/__augment-tests__/augment.ts +81 -0
- package/src/__augment-tests__/augmented.check.ts +116 -0
- package/src/__internal.ts +77 -44
- package/src/bin/rango.ts +312 -15
- package/src/browser/action-coordinator.ts +114 -0
- package/src/browser/action-fence.ts +47 -0
- package/src/browser/app-shell.ts +39 -0
- package/src/browser/app-version.ts +14 -0
- package/src/browser/connection-warmup.ts +134 -0
- package/src/browser/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +293 -202
- package/src/browser/history-state.ts +101 -0
- package/src/browser/index.ts +3 -3
- package/src/browser/intercept-utils.ts +52 -0
- package/src/browser/invalidate-client-cache.ts +52 -0
- package/src/browser/link-interceptor.ts +24 -4
- package/src/browser/logging.ts +11 -0
- package/src/browser/merge-segment-loaders.ts +20 -12
- package/src/browser/navigation-bridge.ts +385 -576
- package/src/browser/navigation-client.ts +245 -75
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +184 -118
- package/src/browser/navigation-transaction.ts +247 -0
- package/src/browser/network-error-handler.ts +88 -0
- package/src/browser/partial-update.ts +412 -364
- package/src/browser/prefetch/cache.ts +359 -0
- package/src/browser/prefetch/fetch.ts +452 -0
- package/src/browser/prefetch/observer.ts +65 -0
- package/src/browser/prefetch/policy.ts +48 -0
- package/src/browser/prefetch/queue.ts +209 -0
- package/src/browser/prefetch/resource-ready.ts +77 -0
- package/src/browser/rango-state.ts +194 -0
- package/src/browser/react/Link.tsx +275 -68
- package/src/browser/react/NavigationProvider.tsx +265 -109
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/context.ts +11 -0
- package/src/browser/react/filter-segment-order.ts +70 -0
- package/src/browser/react/index.ts +0 -48
- package/src/browser/react/location-state-shared.ts +272 -60
- package/src/browser/react/location-state.ts +90 -20
- package/src/browser/react/mount-context.ts +6 -1
- package/src/browser/react/nonce-context.ts +23 -0
- package/src/browser/react/shallow-equal.ts +27 -0
- package/src/browser/react/use-action.ts +35 -66
- package/src/browser/react/use-handle.ts +39 -126
- package/src/browser/react/use-href.tsx +8 -1
- package/src/browser/react/use-link-status.ts +39 -13
- package/src/browser/react/use-navigation.ts +53 -69
- package/src/browser/react/use-params.ts +75 -0
- package/src/browser/react/use-pathname.ts +47 -0
- package/src/browser/react/use-reverse.ts +106 -0
- package/src/browser/react/use-router.ts +98 -0
- package/src/browser/react/use-search-params.ts +51 -0
- package/src/browser/react/use-segments.ts +72 -99
- package/src/browser/response-adapter.ts +164 -0
- package/src/browser/rsc-router.tsx +300 -72
- package/src/browser/scroll-restoration.ts +138 -50
- package/src/browser/segment-reconciler.ts +243 -0
- package/src/browser/segment-structure-assert.ts +17 -1
- package/src/browser/server-action-bridge.ts +668 -613
- package/src/browser/types.ts +223 -51
- package/src/browser/validate-redirect-origin.ts +56 -0
- package/src/build/collect-fallback-refs.ts +107 -0
- package/src/build/generate-manifest.ts +252 -161
- package/src/build/generate-route-types.ts +41 -1038
- package/src/build/index.ts +12 -7
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +225 -42
- package/src/build/route-types/ast-helpers.ts +25 -0
- package/src/build/route-types/ast-route-extraction.ts +105 -0
- package/src/build/route-types/codegen.ts +113 -0
- package/src/build/route-types/include-resolution.ts +812 -0
- package/src/build/route-types/param-extraction.ts +51 -0
- package/src/build/route-types/per-module-writer.ts +144 -0
- package/src/build/route-types/router-processing.ts +695 -0
- package/src/build/route-types/scan-filter.ts +85 -0
- package/src/build/route-types/source-scan.ts +216 -0
- package/src/build/runtime-discovery.ts +223 -0
- package/src/cache/background-task.ts +34 -0
- package/src/cache/cache-error.ts +104 -0
- package/src/cache/cache-key-utils.ts +60 -0
- package/src/cache/cache-policy.ts +199 -0
- package/src/cache/cache-runtime.ts +525 -0
- package/src/cache/cache-scope.ts +298 -332
- package/src/cache/cache-tag.ts +103 -0
- package/src/cache/cf/cf-base64.ts +33 -0
- package/src/cache/cf/cf-cache-constants.ts +127 -0
- package/src/cache/cf/cf-cache-store.ts +2508 -158
- package/src/cache/cf/cf-cache-types.ts +349 -0
- package/src/cache/cf/cf-kv-utils.ts +46 -0
- package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
- package/src/cache/cf/index.ts +17 -17
- package/src/cache/document-cache.ts +199 -92
- package/src/cache/handle-capture.ts +81 -0
- package/src/cache/handle-snapshot.ts +111 -0
- package/src/cache/index.ts +24 -35
- package/src/cache/memory-segment-store.ts +363 -30
- package/src/cache/profile-registry.ts +88 -0
- package/src/cache/read-through-swr.ts +178 -0
- package/src/cache/segment-codec.ts +248 -0
- package/src/cache/shell-snapshot.ts +368 -0
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/taint.ts +153 -0
- package/src/cache/types.ts +222 -211
- package/src/cache/vercel/index.ts +11 -0
- package/src/cache/vercel/vercel-cache-store.ts +1113 -0
- package/src/client.rsc.tsx +43 -21
- package/src/client.tsx +131 -347
- package/src/cloudflare/index.ts +11 -0
- package/src/cloudflare/tracing.ts +109 -0
- package/src/component-utils.ts +23 -4
- package/src/components/DefaultDocument.tsx +13 -3
- package/src/context-var.ts +168 -0
- package/src/debug.ts +19 -9
- package/src/decode-loader-results.ts +52 -0
- package/src/defer.ts +185 -0
- package/src/deps/ssr.ts +0 -1
- package/src/encode-kv.ts +49 -0
- package/src/errors.ts +106 -10
- package/src/escape-script.ts +52 -0
- package/src/handle.ts +110 -35
- package/src/handles/MetaTags.tsx +83 -59
- package/src/handles/Scripts.tsx +183 -0
- package/src/handles/breadcrumbs.ts +93 -0
- package/src/handles/deferred-resolution.ts +127 -0
- package/src/handles/is-thenable.ts +18 -0
- package/src/handles/meta.ts +44 -53
- package/src/handles/script.ts +244 -0
- package/src/host/cookie-handler.ts +20 -65
- package/src/host/errors.ts +21 -30
- package/src/host/index.ts +13 -9
- package/src/host/pattern-matcher.ts +50 -79
- package/src/host/router.ts +151 -121
- package/src/host/testing.ts +45 -32
- package/src/host/types.ts +52 -11
- package/src/host/utils.ts +2 -2
- package/src/href-client.ts +192 -57
- package/src/index.rsc.ts +173 -35
- package/src/index.ts +241 -73
- package/src/internal-debug.ts +9 -2
- package/src/loader-store.ts +500 -0
- package/src/loader.rsc.ts +31 -99
- package/src/loader.ts +30 -12
- package/src/missing-id-error.ts +68 -0
- package/src/outlet-context.ts +1 -1
- package/src/outlet-provider.tsx +41 -0
- package/src/prerender/param-hash.ts +16 -14
- package/src/prerender/store.ts +121 -21
- package/src/prerender.ts +460 -26
- package/src/redirect-origin.ts +100 -0
- package/src/regex-escape.ts +8 -0
- package/src/render-error-thrower.tsx +20 -0
- package/src/response-utils.ts +62 -0
- package/src/reverse.ts +198 -128
- package/src/root-error-boundary.tsx +42 -48
- package/src/route-content-wrapper.tsx +22 -77
- package/src/route-definition/dsl-helpers.ts +1116 -0
- package/src/route-definition/helper-factories.ts +88 -0
- package/src/route-definition/helpers-types.ts +505 -0
- package/src/route-definition/index.ts +54 -0
- package/src/route-definition/redirect.ts +134 -0
- package/src/route-definition/resolve-handler-use.ts +160 -0
- package/src/route-definition/use-item-types.ts +29 -0
- package/src/route-definition.ts +1 -1481
- package/src/route-map-builder.ts +82 -144
- package/src/route-name.ts +53 -0
- package/src/route-types.ts +71 -45
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +263 -0
- package/src/router/debug-manifest.ts +72 -0
- package/src/router/error-handling.ts +54 -27
- package/src/router/find-match.ts +245 -0
- package/src/router/handler-context.ts +377 -125
- package/src/router/instrument.ts +350 -0
- package/src/router/intercept-resolution.ts +59 -28
- package/src/router/lazy-includes.ts +254 -0
- package/src/router/loader-resolution.ts +421 -157
- package/src/router/logging.ts +106 -6
- package/src/router/manifest.ts +131 -57
- package/src/router/match-api.ts +167 -246
- package/src/router/match-context.ts +4 -24
- package/src/router/match-handlers.ts +440 -0
- package/src/router/match-middleware/background-revalidation.ts +117 -93
- package/src/router/match-middleware/cache-lookup.ts +297 -150
- package/src/router/match-middleware/cache-store.ts +123 -51
- package/src/router/match-middleware/intercept-resolution.ts +44 -43
- package/src/router/match-middleware/segment-resolution.ts +64 -22
- package/src/router/match-pipelines.ts +11 -87
- package/src/router/match-result.ts +121 -50
- package/src/router/metrics.ts +219 -28
- package/src/router/middleware-types.ts +93 -0
- package/src/router/middleware.ts +505 -441
- package/src/router/navigation-snapshot.ts +133 -0
- package/src/router/params-util.ts +23 -0
- package/src/router/parse-pattern.ts +115 -0
- package/src/router/pattern-matching.ts +311 -142
- package/src/router/prefetch-cache-ttl.ts +51 -0
- package/src/router/prefetch-limits.ts +37 -0
- package/src/router/prerender-match.ts +547 -0
- package/src/router/preview-match.ts +102 -0
- package/src/router/request-classification.ts +278 -0
- package/src/router/revalidation.ts +203 -62
- package/src/router/route-snapshot.ts +246 -0
- package/src/router/router-context.ts +45 -48
- package/src/router/router-interfaces.ts +554 -0
- package/src/router/router-options.ts +779 -0
- package/src/router/router-registry.ts +21 -0
- package/src/router/segment-resolution/fresh.ts +772 -0
- package/src/router/segment-resolution/helpers.ts +348 -0
- package/src/router/segment-resolution/loader-cache.ts +250 -0
- package/src/router/segment-resolution/loader-mask.ts +44 -0
- package/src/router/segment-resolution/revalidation.ts +1331 -0
- package/src/router/segment-resolution/static-store.ts +81 -0
- package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
- package/src/router/segment-resolution/view-transition-default.ts +56 -0
- package/src/router/segment-resolution.ts +25 -1354
- package/src/router/segment-wrappers.ts +292 -0
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/substitute-pattern-params.ts +75 -0
- package/src/router/telemetry-otel.ts +261 -0
- package/src/router/telemetry.ts +377 -0
- package/src/router/timeout.ts +128 -0
- package/src/router/tracing.ts +206 -0
- package/src/router/trie-matching.ts +240 -61
- package/src/router/types.ts +23 -70
- package/src/router/url-params.ts +57 -0
- package/src/router.ts +781 -2378
- package/src/rsc/full-payload.ts +70 -0
- package/src/rsc/handler-context.ts +46 -0
- package/src/rsc/handler.ts +905 -1142
- package/src/rsc/helpers.ts +275 -19
- package/src/rsc/index.ts +2 -25
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/loader-fetch.ts +305 -0
- package/src/rsc/manifest-init.ts +77 -0
- package/src/rsc/nonce.ts +14 -0
- package/src/rsc/origin-guard.ts +155 -0
- package/src/rsc/progressive-enhancement.ts +502 -0
- package/src/rsc/redirect-guard.ts +99 -0
- package/src/rsc/response-cache-serve.ts +238 -0
- package/src/rsc/response-error.ts +104 -0
- package/src/rsc/response-route-handler.ts +257 -0
- package/src/rsc/rsc-rendering.ts +527 -0
- package/src/rsc/runtime-warnings.ts +55 -0
- package/src/rsc/server-action.ts +522 -0
- package/src/rsc/shell-capture.ts +897 -0
- package/src/rsc/shell-serve.ts +124 -0
- package/src/rsc/ssr-setup.ts +144 -0
- package/src/rsc/transition-gate.ts +89 -0
- package/src/rsc/types.ts +95 -12
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +99 -82
- package/src/segment-content-promise.ts +67 -0
- package/src/segment-loader-promise.ts +149 -0
- package/src/segment-system.tsx +349 -134
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +459 -85
- package/src/server/cookie-parse.ts +32 -0
- package/src/server/cookie-store.ts +310 -0
- package/src/server/fetchable-loader-store.ts +11 -6
- package/src/server/handle-store.ts +123 -42
- package/src/server/loader-registry.ts +51 -100
- package/src/server/request-context.ts +848 -157
- package/src/server.ts +15 -8
- package/src/ssr/index.tsx +443 -135
- package/src/ssr/ssr-root.tsx +228 -0
- package/src/static-handler.ts +45 -18
- package/src/testing/cache-status.ts +162 -0
- package/src/testing/collect-handle.ts +46 -0
- package/src/testing/dispatch.ts +701 -0
- package/src/testing/dom.entry.ts +22 -0
- package/src/testing/e2e/fixture.ts +188 -0
- package/src/testing/e2e/index.ts +128 -0
- package/src/testing/e2e/matchers.ts +35 -0
- package/src/testing/e2e/page-helpers.ts +272 -0
- package/src/testing/e2e/parity.ts +387 -0
- package/src/testing/e2e/server.ts +195 -0
- package/src/testing/flight-matchers.ts +97 -0
- package/src/testing/flight-normalize.ts +11 -0
- package/src/testing/flight-runtime.d.ts +57 -0
- package/src/testing/flight-tree.ts +682 -0
- package/src/testing/flight.entry.ts +52 -0
- package/src/testing/flight.ts +257 -0
- package/src/testing/generated-routes.ts +199 -0
- package/src/testing/index.ts +105 -0
- package/src/testing/internal/context.ts +371 -0
- package/src/testing/internal/flight-client-globals.ts +30 -0
- package/src/testing/internal/seed-vars.ts +54 -0
- package/src/testing/render-handler.ts +357 -0
- package/src/testing/render-route.tsx +584 -0
- package/src/testing/run-loader.ts +385 -0
- package/src/testing/run-middleware.ts +205 -0
- package/src/testing/run-transition-when.ts +164 -0
- package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
- package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
- package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
- package/src/testing/vitest-stubs/version.ts +5 -0
- package/src/testing/vitest.ts +305 -0
- package/src/theme/ThemeProvider.tsx +76 -98
- package/src/theme/ThemeScript.tsx +12 -14
- package/src/theme/constants.ts +57 -15
- package/src/theme/index.ts +3 -20
- package/src/theme/theme-context.ts +5 -35
- package/src/theme/theme-script.ts +43 -39
- package/src/theme/use-theme.ts +0 -3
- package/src/types/boundaries.ts +123 -0
- package/src/types/cache-types.ts +207 -0
- package/src/types/error-types.ts +132 -0
- package/src/types/global-namespace.ts +113 -0
- package/src/types/handler-context.ts +839 -0
- package/src/types/index.ts +81 -0
- package/src/types/loader-types.ts +212 -0
- package/src/types/request-scope.ts +112 -0
- package/src/types/route-config.ts +138 -0
- package/src/types/route-entry.ts +114 -0
- package/src/types/segments.ts +271 -0
- package/src/types.ts +1 -1795
- package/src/urls/include-helper.ts +162 -0
- package/src/urls/include-provider.ts +71 -0
- package/src/urls/index.ts +44 -0
- package/src/urls/path-helper-types.ts +413 -0
- package/src/urls/path-helper.ts +280 -0
- package/src/urls/pattern-types.ts +160 -0
- package/src/urls/response-types.ts +109 -0
- package/src/urls/type-extraction.ts +316 -0
- package/src/urls/urls-function.ts +80 -0
- package/src/urls.ts +1 -1341
- package/src/use-loader.tsx +406 -141
- package/src/vercel/index.ts +11 -0
- package/src/vercel/tracing.ts +88 -0
- package/src/vite/debug.ts +185 -0
- package/src/vite/discovery/bundle-postprocess.ts +182 -0
- package/src/vite/discovery/discover-routers.ts +389 -0
- package/src/vite/discovery/discovery-errors.ts +255 -0
- package/src/vite/discovery/gate-state.ts +171 -0
- package/src/vite/discovery/prerender-collection.ts +467 -0
- package/src/vite/discovery/route-types-writer.ts +214 -0
- package/src/vite/discovery/self-gen-tracking.ts +73 -0
- package/src/vite/discovery/state.ts +161 -0
- package/src/vite/discovery/virtual-module-codegen.ts +183 -0
- package/src/vite/index.ts +23 -2255
- package/src/vite/inject-client-debug.ts +36 -0
- package/src/vite/plugin-types.ts +303 -0
- package/src/vite/plugins/cjs-to-esm.ts +90 -0
- package/src/vite/plugins/client-ref-dedup.ts +120 -0
- package/src/vite/plugins/client-ref-hashing.ts +118 -0
- package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
- package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/src/vite/plugins/cloudflare-protocol-stub.ts +194 -0
- package/src/vite/{expose-action-id.ts → plugins/expose-action-id.ts} +88 -110
- package/src/vite/{expose-id-utils.ts → plugins/expose-id-utils.ts} +89 -79
- package/src/vite/plugins/expose-ids/export-analysis.ts +363 -0
- package/src/vite/plugins/expose-ids/handler-transform.ts +130 -0
- package/src/vite/plugins/expose-ids/loader-transform.ts +64 -0
- package/src/vite/plugins/expose-ids/router-transform.ts +199 -0
- package/src/vite/plugins/expose-ids/types.ts +45 -0
- package/src/vite/plugins/expose-internal-ids.ts +805 -0
- package/src/vite/plugins/performance-tracks.ts +89 -0
- package/src/vite/plugins/refresh-cmd.ts +127 -0
- package/src/vite/plugins/use-cache-transform.ts +313 -0
- package/src/vite/plugins/vercel-output.ts +384 -0
- package/src/vite/plugins/version-injector.ts +94 -0
- package/src/vite/plugins/version-plugin.ts +263 -0
- package/src/vite/plugins/virtual-entries.ts +234 -0
- package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
- package/src/vite/rango.ts +560 -0
- package/src/vite/router-discovery.ts +1638 -0
- package/src/vite/{ast-handler-extract.ts → utils/ast-handler-extract.ts} +200 -37
- package/src/vite/utils/banner.ts +36 -0
- package/src/vite/utils/bundle-analysis.ts +132 -0
- package/src/vite/utils/client-chunks.ts +184 -0
- package/src/vite/utils/directive-prologue.ts +40 -0
- package/src/vite/utils/forward-user-plugins.ts +171 -0
- package/src/vite/utils/manifest-utils.ts +15 -0
- package/src/vite/utils/package-resolution.ts +89 -0
- package/src/vite/utils/prerender-utils.ts +249 -0
- package/src/vite/utils/shared-utils.ts +269 -0
- package/CLAUDE.md +0 -43
- package/dist/vite/index.named-routes.gen.ts +0 -103
- package/src/browser/lru-cache.ts +0 -69
- package/src/browser/react/use-client-cache.ts +0 -56
- package/src/browser/request-controller.ts +0 -164
- package/src/browser/shallow.ts +0 -35
- package/src/cache/memory-store.ts +0 -253
- package/src/handles/index.ts +0 -6
- package/src/href-context.ts +0 -33
- package/src/network-error-thrower.tsx +0 -21
- package/src/router.gen.ts +0 -6
- package/src/static-handler.gen.ts +0 -5
- package/src/urls.gen.ts +0 -8
- package/src/vite/expose-internal-ids.ts +0 -1167
- package/src/vite/package-resolution.ts +0 -125
- package/src/vite/virtual-entries.ts +0 -114
- /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
package/skills/route/SKILL.md
CHANGED
|
@@ -33,6 +33,69 @@ urls(({ path }) => [
|
|
|
33
33
|
]);
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
+
### Optional URL params at runtime
|
|
37
|
+
|
|
38
|
+
Absent optional params are **omitted from `ctx.params`** — `ctx.params.<name>`
|
|
39
|
+
reads as `undefined`, matching the `RouteParams<"name">` type
|
|
40
|
+
(`{ query?: string }`). Use `??` to default and `=== undefined` to check
|
|
41
|
+
absence:
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
path("/search/:query?", (ctx) => {
|
|
45
|
+
const query = ctx.params.query ?? ""; // works — undefined coalesces
|
|
46
|
+
if (ctx.params.query === undefined) return <EmptySearch />;
|
|
47
|
+
return <Results query={ctx.params.query} />;
|
|
48
|
+
}, { name: "search" });
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
For the common pattern of an optional locale prefix
|
|
52
|
+
(`include("/:locale?", routes)`) and the wider react-intl integration —
|
|
53
|
+
locale detection, fallback chains, URL generation with absent locale —
|
|
54
|
+
see `/i18n`.
|
|
55
|
+
|
|
56
|
+
### Named catch-all params (`:name+` / `:name*`)
|
|
57
|
+
|
|
58
|
+
A catch-all consumes the **rest of the path** and exposes it as a single
|
|
59
|
+
decoded string at `ctx.params.<name>`, with the internal `/` separators kept.
|
|
60
|
+
It must be the **last** segment of the pattern.
|
|
61
|
+
|
|
62
|
+
- `:name+` — **one-or-more** segments (Next `[...name]`, React-Router splat).
|
|
63
|
+
`/docs/:slug+` matches `/docs/a` and `/docs/a/b/c`, but **not** the bare
|
|
64
|
+
`/docs`.
|
|
65
|
+
- `:name*` — **zero-or-more** segments (Next `[[...name]]`). `/docs/:slug*`
|
|
66
|
+
additionally matches the bare `/docs`, binding `ctx.params.slug` to `""`.
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
urls(({ path }) => [
|
|
70
|
+
// /shop/electronics/phones -> ctx.params.path === "electronics/phones"
|
|
71
|
+
path("/shop/:path+", ShopCatchAll, { name: "shopCatchAll" }),
|
|
72
|
+
|
|
73
|
+
// /docs -> ctx.params.slug === ""
|
|
74
|
+
// /docs/intro -> ctx.params.slug === "intro"
|
|
75
|
+
// /docs/a/b -> ctx.params.slug === "a/b"
|
|
76
|
+
path("/docs/:slug*", (ctx) => {
|
|
77
|
+
const parts = ctx.params.slug === "" ? [] : ctx.params.slug.split("/");
|
|
78
|
+
return <Docs segments={parts} />;
|
|
79
|
+
}, { name: "docs" }),
|
|
80
|
+
]);
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`ctx.params.<name>` is always a `string` for a catch-all (never `undefined`) —
|
|
84
|
+
`:name*` binds `""` for the empty case, so read it directly. `reverse()` /
|
|
85
|
+
`ctx.reverse()` rebuild the URL with separators preserved:
|
|
86
|
+
`reverse("docs", { slug: "a/b" })` -> `/docs/a/b`.
|
|
87
|
+
|
|
88
|
+
The value is the URL-decoded remainder. `split("/")` recovers the segments in the
|
|
89
|
+
common case, but note that a segment containing an encoded slash (`%2F`) decodes
|
|
90
|
+
to a literal `/` and is therefore indistinguishable from a separator — the same
|
|
91
|
+
trade-off the bare `*` splat has. If you need to distinguish those, match on the
|
|
92
|
+
raw pathname instead.
|
|
93
|
+
|
|
94
|
+
The bare unnamed wildcard `path("/files/*", …)` still works and is read at
|
|
95
|
+
`ctx.params["*"]`; prefer a named catch-all when you want a typed param key.
|
|
96
|
+
Combining a modifier with `?`, a literal suffix, or a constraint
|
|
97
|
+
(`:slug*?`, `:slug*.html`, `:slug(a|b)+`) is rejected at build time.
|
|
98
|
+
|
|
36
99
|
## Route Handler Patterns
|
|
37
100
|
|
|
38
101
|
### Component Function
|
|
@@ -74,19 +137,19 @@ path("/product/:slug", async (ctx) => {
|
|
|
74
137
|
|
|
75
138
|
```typescript
|
|
76
139
|
path("/product/:slug", ProductPage, {
|
|
77
|
-
name: "product",
|
|
78
|
-
})
|
|
140
|
+
name: "product", // Route name for href() and navigation
|
|
141
|
+
});
|
|
79
142
|
```
|
|
80
143
|
|
|
81
144
|
### Typed Search Params
|
|
82
145
|
|
|
83
|
-
Add a `search` schema to get typed `ctx.
|
|
146
|
+
Add a `search` schema to get typed `ctx.search`:
|
|
84
147
|
|
|
85
148
|
```typescript
|
|
86
149
|
path("/search", SearchPage, {
|
|
87
150
|
name: "search",
|
|
88
151
|
search: { q: "string", page: "number?", sort: "string?" },
|
|
89
|
-
})
|
|
152
|
+
});
|
|
90
153
|
```
|
|
91
154
|
|
|
92
155
|
Use `Handler<"name">` for typed search params (resolves from the generated route map automatically):
|
|
@@ -95,23 +158,24 @@ Use `Handler<"name">` for typed search params (resolves from the generated route
|
|
|
95
158
|
import type { Handler } from "@rangojs/router";
|
|
96
159
|
|
|
97
160
|
export const SearchPage: Handler<"search"> = (ctx) => {
|
|
98
|
-
// ctx.
|
|
99
|
-
const { q, page, sort } = ctx.
|
|
161
|
+
// ctx.search is typed: { q: string; page?: number; sort?: string }
|
|
162
|
+
const { q, page, sort } = ctx.search;
|
|
163
|
+
// ctx.searchParams is always URLSearchParams
|
|
100
164
|
return <SearchResults q={q} page={page} sort={sort} />;
|
|
101
165
|
};
|
|
102
166
|
```
|
|
103
167
|
|
|
104
168
|
Supported types: `"string"`, `"number"`, `"boolean"`, with `?` suffix for optional.
|
|
105
|
-
|
|
106
|
-
|
|
169
|
+
Missing params are `undefined` regardless of required/optional. The required/optional
|
|
170
|
+
distinction is a consumer-facing contract (for `href()` and `reverse()` autocomplete).
|
|
107
171
|
|
|
108
172
|
Use `RouteSearchParams<"name">` and `RouteParams<"name">` to extract types for props:
|
|
109
173
|
|
|
110
174
|
```typescript
|
|
111
175
|
import type { RouteSearchParams, RouteParams } from "@rangojs/router";
|
|
112
176
|
|
|
113
|
-
type SP = RouteSearchParams<"search">;
|
|
114
|
-
type P = RouteParams<"blogPost">;
|
|
177
|
+
type SP = RouteSearchParams<"search">; // { q: string; page?: number; sort?: string }
|
|
178
|
+
type P = RouteParams<"blogPost">; // { slug: string }
|
|
115
179
|
```
|
|
116
180
|
|
|
117
181
|
## Route Children
|
|
@@ -126,19 +190,257 @@ path("/product/:slug", ProductPage, { name: "product" }, () => [
|
|
|
126
190
|
])
|
|
127
191
|
```
|
|
128
192
|
|
|
193
|
+
## Handler Data Ownership
|
|
194
|
+
|
|
195
|
+
When a route has children (orphan layouts, parallels), the handler executes
|
|
196
|
+
first. Use `ctx.set(key, value)` to share data with children, who read it
|
|
197
|
+
via `ctx.get(key)`. Caching wraps all segments together, so either all run
|
|
198
|
+
or none do.
|
|
199
|
+
|
|
200
|
+
This pattern is also safe under partial action revalidation: on an action,
|
|
201
|
+
the route entry re-runs as a unit by default — route segment, loaders, and
|
|
202
|
+
`belongsToRoute` children (orphan layouts, entry parallels) all seed
|
|
203
|
+
revalidate-true, with handler-first ordering preserved. Handler-set data
|
|
204
|
+
stays consistent with no configuration. See `/rango` → "Passing data down
|
|
205
|
+
the tree" for the safest-first ladder.
|
|
206
|
+
|
|
207
|
+
### Typed context variables with createVar
|
|
208
|
+
|
|
209
|
+
Use `createVar<T>()` to create a typed token for `ctx.set()`/`ctx.get()`.
|
|
210
|
+
The token is imported by both the handler (producer) and layout (consumer),
|
|
211
|
+
making the data contract explicit and compile-time verified:
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
import { createVar } from "@rangojs/router";
|
|
215
|
+
import { Outlet, ParallelOutlet } from "@rangojs/router/client";
|
|
216
|
+
|
|
217
|
+
// Typed token -- shared between handler and layout
|
|
218
|
+
interface DashboardData {
|
|
219
|
+
title: string;
|
|
220
|
+
stats: { views: number };
|
|
221
|
+
}
|
|
222
|
+
const Dashboard = createVar<DashboardData>();
|
|
223
|
+
|
|
224
|
+
path("/dashboard/:id", async (ctx) => {
|
|
225
|
+
const data = await fetchDashboard(ctx.params.id);
|
|
226
|
+
ctx.set(Dashboard, data); // type-checked
|
|
227
|
+
return <DashboardPage data={data} />;
|
|
228
|
+
}, { name: "dashboard" }, () => [
|
|
229
|
+
layout((ctx) => {
|
|
230
|
+
const data = ctx.get(Dashboard); // typed as DashboardData | undefined
|
|
231
|
+
return (
|
|
232
|
+
<div>
|
|
233
|
+
<h1>{data?.title}</h1>
|
|
234
|
+
<Outlet />
|
|
235
|
+
<ParallelOutlet name="@sidebar" />
|
|
236
|
+
</div>
|
|
237
|
+
);
|
|
238
|
+
}),
|
|
239
|
+
parallel({
|
|
240
|
+
"@sidebar": (ctx) => {
|
|
241
|
+
const data = ctx.get(Dashboard);
|
|
242
|
+
return <Sidebar stats={data?.stats} />;
|
|
243
|
+
},
|
|
244
|
+
}),
|
|
245
|
+
])
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
String keys still work (`ctx.set("key", value)` / `ctx.get("key")`), but
|
|
249
|
+
`createVar<T>()` is preferred for type safety.
|
|
250
|
+
|
|
251
|
+
Only route handlers and middleware can call `ctx.set()`. Layouts, parallels,
|
|
252
|
+
and intercepts can only read via `ctx.get()`.
|
|
253
|
+
|
|
254
|
+
#### Non-cacheable context variables
|
|
255
|
+
|
|
256
|
+
Mark a var as non-cacheable when it holds inherently request-specific data
|
|
257
|
+
(sessions, auth tokens, per-request IDs). There are two ways:
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
// Var-level: every value written to this var is non-cacheable
|
|
261
|
+
const Session = createVar<SessionData>({ cache: false });
|
|
262
|
+
|
|
263
|
+
// Write-level: escalate a normally-cacheable var for this specific write
|
|
264
|
+
const Theme = createVar<string>();
|
|
265
|
+
ctx.set(Theme, userTheme, { cache: false });
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
"Least cacheable wins" — if either the var definition or the write site says
|
|
269
|
+
`cache: false`, the value is non-cacheable.
|
|
270
|
+
|
|
271
|
+
Reading a non-cacheable var inside `cache()` or `"use cache"` throws at
|
|
272
|
+
runtime. This prevents request-specific data from leaking into cached output:
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
// This throws — Session is non-cacheable
|
|
276
|
+
async function CachedWidget(ctx) {
|
|
277
|
+
"use cache";
|
|
278
|
+
const session = ctx.get(Session); // Error: non-cacheable var read inside cache scope
|
|
279
|
+
return <Widget />;
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Cacheable vars (the default) can be read freely inside cache scopes.
|
|
284
|
+
|
|
285
|
+
### Revalidation Contracts for Handler Data
|
|
286
|
+
|
|
287
|
+
> **Scope: `revalidate()` is a partial-render concern, not a cache concern.**
|
|
288
|
+
> It decides whether this segment re-runs and streams to the client on a
|
|
289
|
+
> navigation or action — never whether a cached value is stale. The cache
|
|
290
|
+
> decides hit/miss/ttl/swr independently and never reads `revalidate()`. See
|
|
291
|
+
> `/cache-guide` → "Two axes" and `/rango` → "The shape of rango".
|
|
292
|
+
|
|
293
|
+
With no `revalidate()` configured, an entry needs no contract: on an action
|
|
294
|
+
the route handler and its children re-run together by default, so handler
|
|
295
|
+
data stays consistent on its own. Contracts matter in two cases:
|
|
296
|
+
|
|
297
|
+
1. **You narrow the entry's revalidation** with a predicate that can return a
|
|
298
|
+
hard `false` (e.g. bare `ctx.isAction(X)`). A hard `false` on one side of a
|
|
299
|
+
producer/consumer pair desyncs it — the child re-runs by default and reads
|
|
300
|
+
`undefined`, or vice versa. Put the same named contract on the route and
|
|
301
|
+
its dependent children so they narrow together.
|
|
302
|
+
2. **The producer is an outer entry** (a standalone `layout()` above this
|
|
303
|
+
route). Outer entries skip action revalidation by default, so the shared
|
|
304
|
+
contract is mandatory — see `/layout` → "Revalidation Contracts".
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
// revalidation-contracts.ts
|
|
308
|
+
import * as CheckoutActions from "./actions/checkout";
|
|
309
|
+
|
|
310
|
+
// Defer (|| undefined), not ?? false: a hard `false` short-circuits the chain,
|
|
311
|
+
// so when the same segment composes multiple contracts the later ones never run.
|
|
312
|
+
export const revalidateCheckoutData = (ctx) =>
|
|
313
|
+
ctx.isAction(CheckoutActions) || undefined;
|
|
314
|
+
|
|
315
|
+
path("/checkout", CheckoutPage, { name: "checkout" }, () => [
|
|
316
|
+
revalidate(revalidateCheckoutData), // producer (route handler) reruns
|
|
317
|
+
layout(CheckoutLayout, () => [
|
|
318
|
+
revalidate(revalidateCheckoutData), // consumer reruns
|
|
319
|
+
parallel({ "@summary": CheckoutSummary }, () => [
|
|
320
|
+
revalidate(revalidateCheckoutData),
|
|
321
|
+
]),
|
|
322
|
+
]),
|
|
323
|
+
]);
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
If children depend on multiple upstream domains, compose multiple contracts on
|
|
327
|
+
the same segment (`revalidateAuthData`, `revalidateCheckoutData`, and so on).
|
|
328
|
+
|
|
329
|
+
For cleaner route trees, expose contract helpers and spread them:
|
|
330
|
+
|
|
331
|
+
```typescript
|
|
332
|
+
import { revalidate } from "@rangojs/router";
|
|
333
|
+
|
|
334
|
+
export const revalidateCheckout = () => [revalidate(revalidateCheckoutData)];
|
|
335
|
+
|
|
336
|
+
path("/checkout", CheckoutPage, { name: "checkout" }, () => [
|
|
337
|
+
revalidateCheckout(),
|
|
338
|
+
layout(CheckoutLayout, () => [revalidateCheckout()]),
|
|
339
|
+
]);
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
## Redirects
|
|
343
|
+
|
|
344
|
+
### Basic redirect
|
|
345
|
+
|
|
346
|
+
```typescript
|
|
347
|
+
import { redirect } from "@rangojs/router";
|
|
348
|
+
|
|
349
|
+
path("/old-page", () => redirect("/new-page"), { name: "oldPage" });
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### Redirect with custom status
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
path("/moved", () => redirect("/new-location", 301), { name: "moved" });
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
> **Redirecting from a route with `loading()`:** an `async` handler that returns
|
|
359
|
+
> a `Response`/`redirect()` on a route that also declares `loading()` is streamed,
|
|
360
|
+
> so the redirect is rendered into the RSC stream instead of becoming an HTTP
|
|
361
|
+
> redirect. Issue the redirect from `middleware`, a loader, or a **synchronous**
|
|
362
|
+
> handler return instead. (Dev logs a warning if this is hit.)
|
|
363
|
+
|
|
364
|
+
### Redirect with location state
|
|
365
|
+
|
|
366
|
+
Carry typed state through redirects (e.g. flash messages):
|
|
367
|
+
|
|
368
|
+
```typescript
|
|
369
|
+
import { redirect, createLocationState } from "@rangojs/router";
|
|
370
|
+
|
|
371
|
+
export const FlashMessage = createLocationState<{ text: string }>({
|
|
372
|
+
flash: true,
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
path(
|
|
376
|
+
"/save",
|
|
377
|
+
(ctx) => {
|
|
378
|
+
// ... save logic
|
|
379
|
+
return redirect("/dashboard", {
|
|
380
|
+
state: [FlashMessage({ text: "Item saved!" })],
|
|
381
|
+
});
|
|
382
|
+
},
|
|
383
|
+
{ name: "save" },
|
|
384
|
+
);
|
|
385
|
+
|
|
386
|
+
// With custom status + state
|
|
387
|
+
path(
|
|
388
|
+
"/action",
|
|
389
|
+
(ctx) => {
|
|
390
|
+
return redirect("/target", {
|
|
391
|
+
status: 303,
|
|
392
|
+
state: [FlashMessage({ text: "Action complete" })],
|
|
393
|
+
});
|
|
394
|
+
},
|
|
395
|
+
{ name: "action" },
|
|
396
|
+
);
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
Read the state on the target page with `useLocationState(FlashMessage)`. The
|
|
400
|
+
`{ flash: true }` option makes it auto-clear. Without `{ flash: true }`,
|
|
401
|
+
state persists on back/forward. See `/hooks` for details.
|
|
402
|
+
|
|
403
|
+
### ctx.setLocationState()
|
|
404
|
+
|
|
405
|
+
Attach location state to any server response (not just redirects):
|
|
406
|
+
|
|
407
|
+
```typescript
|
|
408
|
+
import { createLocationState } from "@rangojs/router";
|
|
409
|
+
|
|
410
|
+
const ServerInfo = createLocationState<{ data: string }>();
|
|
411
|
+
|
|
412
|
+
path("/dashboard", (ctx) => {
|
|
413
|
+
ctx.setLocationState(ServerInfo({ data: "welcome" }));
|
|
414
|
+
return <Dashboard />;
|
|
415
|
+
}, { name: "dashboard" })
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
State flows to the browser via the RSC payload and is merged into
|
|
419
|
+
`history.pushState()`. Only works for SPA (partial) navigations.
|
|
420
|
+
|
|
129
421
|
## Handler Context
|
|
130
422
|
|
|
131
423
|
Every handler receives a context object:
|
|
132
424
|
|
|
133
425
|
```typescript
|
|
134
426
|
interface HandlerContext<TParams = {}, TEnv = DefaultEnv, TSearch = {}> {
|
|
135
|
-
params: TParams;
|
|
136
|
-
request: Request;
|
|
137
|
-
searchParams: URLSearchParams
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
427
|
+
params: TParams; // URL parameters
|
|
428
|
+
request: Request; // Original request
|
|
429
|
+
searchParams: URLSearchParams; // Query params (always URLSearchParams)
|
|
430
|
+
search: {} | ResolveSearchSchema<TSearch>; // Typed search params (from search schema)
|
|
431
|
+
url: URL; // Parsed URL
|
|
432
|
+
env: TEnv; // Environment (bindings + variables)
|
|
433
|
+
set(key: string, value: any): void; // Set context variable (untyped string key)
|
|
434
|
+
set<T>(contextVar: ContextVar<T>, value: T): void; // Set typed context variable
|
|
435
|
+
get(key: string): any; // Read context variable (untyped string key)
|
|
436
|
+
get<T>(contextVar: ContextVar<T>): T | undefined; // Read typed context variable
|
|
437
|
+
use<T>(handle: Handle<T>): T; // Access handles
|
|
438
|
+
reverse(
|
|
439
|
+
name: string,
|
|
440
|
+
params?: Record<string, string>,
|
|
441
|
+
search?: Record<string, unknown>,
|
|
442
|
+
): string; // URL generation
|
|
443
|
+
setLocationState(entries: LocationStateEntry[]): void; // Attach state to response
|
|
142
444
|
}
|
|
143
445
|
```
|
|
144
446
|
|
|
@@ -152,8 +454,8 @@ path("/product/:slug", (ctx) => {
|
|
|
152
454
|
// Access query params (untyped - use search schema for typed access)
|
|
153
455
|
const tab = ctx.searchParams.get("tab");
|
|
154
456
|
|
|
155
|
-
// Access
|
|
156
|
-
const db = ctx.env.
|
|
457
|
+
// Access platform bindings
|
|
458
|
+
const db = ctx.env.DB;
|
|
157
459
|
|
|
158
460
|
// Access handles
|
|
159
461
|
const breadcrumbs = ctx.use(Breadcrumbs);
|
|
@@ -177,11 +479,38 @@ urls(({ path, layout }) => [
|
|
|
177
479
|
])
|
|
178
480
|
```
|
|
179
481
|
|
|
482
|
+
## View Transitions
|
|
483
|
+
|
|
484
|
+
A route can configure its own `transition()` — the wrap goes around the route's component itself (routes are leaves; they have no separate default outlet channel). If the route component renders a `<ParallelOutlet />` directly, that slot remains inside the route's VT subtree, so prefer mounting parallel slots in a layout when combining intercept modals with route-level transitions. See [skills/view-transitions](../view-transitions/SKILL.md) for examples and the wrap-location rules across layouts, routes, and slots.
|
|
485
|
+
|
|
486
|
+
## Handler-attached `.use`
|
|
487
|
+
|
|
488
|
+
Page handlers can carry their own loader, middleware, error boundaries, parallels, and other defaults via a `.use` callback — so the page is self-contained and reusable across mount sites without re-wiring the same items.
|
|
489
|
+
|
|
490
|
+
```typescript
|
|
491
|
+
const ProductPage: Handler<"/product/:slug"> = async (ctx) => {
|
|
492
|
+
const product = await ctx.use(ProductLoader);
|
|
493
|
+
return <ProductView product={product} />;
|
|
494
|
+
};
|
|
495
|
+
ProductPage.use = () => [
|
|
496
|
+
loader(ProductLoader),
|
|
497
|
+
loading(<ProductSkeleton />),
|
|
498
|
+
middleware(async (ctx, next) => {
|
|
499
|
+
await next();
|
|
500
|
+
ctx.header("Cache-Control", "private, max-age=60");
|
|
501
|
+
}),
|
|
502
|
+
];
|
|
503
|
+
|
|
504
|
+
// Mount site has no per-page wiring — defaults travel with the handler.
|
|
505
|
+
path("/product/:slug", ProductPage, { name: "product" });
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
Explicit `use()` at the mount site merges with `handler.use` (handler defaults first, explicit second). See [skills/handler-use](../handler-use/SKILL.md) for the merge order, allowed item types per mount site, and override semantics.
|
|
509
|
+
|
|
180
510
|
## Complete Example
|
|
181
511
|
|
|
182
512
|
```typescript
|
|
183
|
-
import { urls } from "@rangojs/router";
|
|
184
|
-
import { Breadcrumbs } from "./handles/breadcrumbs";
|
|
513
|
+
import { urls, Breadcrumbs } from "@rangojs/router";
|
|
185
514
|
|
|
186
515
|
export const urlpatterns = urls(({ path, layout, loader, loading }) => [
|
|
187
516
|
// Simple route
|