@rangojs/router 0.0.0-experimental.79 → 0.0.0-experimental.7c7e4327
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 +8 -4
- package/README.md +301 -797
- package/dist/bin/rango.js +603 -145
- package/dist/testing/vitest.js +82 -0
- package/dist/vite/index.js +3750 -1160
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +96 -24
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +85 -6
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +228 -33
- package/skills/caching/SKILL.md +336 -19
- package/skills/catalog.json +271 -0
- 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 +110 -4
- package/skills/css/SKILL.md +76 -0
- package/skills/debug-manifest/SKILL.md +5 -3
- package/skills/defer-hydration/SKILL.md +235 -0
- package/skills/document-cache/SKILL.md +87 -56
- package/skills/fonts/SKILL.md +1 -1
- package/skills/handler-use/SKILL.md +12 -10
- package/skills/hooks/SKILL.md +73 -691
- package/skills/hooks/data.md +273 -0
- package/skills/hooks/handle-and-actions.md +103 -0
- package/skills/hooks/navigation.md +110 -0
- package/skills/hooks/outlets.md +41 -0
- package/skills/hooks/state.md +228 -0
- package/skills/hooks/urls.md +135 -0
- package/skills/host-router/SKILL.md +129 -27
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +75 -19
- package/skills/layout/SKILL.md +40 -19
- package/skills/links/SKILL.md +247 -17
- package/skills/loader/SKILL.md +248 -10
- package/skills/middleware/SKILL.md +25 -13
- package/skills/migrate-nextjs/SKILL.md +205 -20
- package/skills/migrate-react-router/SKILL.md +59 -670
- package/skills/migrate-react-router/cloudflare-workers.md +129 -0
- package/skills/migrate-react-router/component-migration.md +196 -0
- package/skills/migrate-react-router/data-and-actions.md +225 -0
- package/skills/migrate-react-router/route-mapping.md +271 -0
- package/skills/mime-routes/SKILL.md +29 -2
- package/skills/observability/SKILL.md +202 -0
- package/skills/parallel/SKILL.md +40 -10
- package/skills/ppr/SKILL.md +616 -0
- package/skills/prerender/SKILL.md +72 -60
- package/skills/rango/SKILL.md +318 -26
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +138 -49
- package/skills/route/SKILL.md +117 -9
- package/skills/router-setup/SKILL.md +44 -9
- package/skills/scripts/SKILL.md +179 -0
- package/skills/server-actions/SKILL.md +776 -0
- package/skills/shell-manifest/SKILL.md +185 -0
- package/skills/streams-and-websockets/SKILL.md +283 -0
- package/skills/tailwind/SKILL.md +28 -4
- package/skills/testing/SKILL.md +130 -0
- 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 +1 -1
- package/skills/typesafety/SKILL.md +45 -626
- package/skills/typesafety/env-and-bindings.md +254 -0
- package/skills/typesafety/generated-files-and-cli.md +335 -0
- package/skills/typesafety/params-and-search.md +153 -0
- package/skills/typesafety/route-types.md +209 -0
- package/skills/use-cache/SKILL.md +74 -15
- 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 +0 -65
- package/src/browser/action-coordinator.ts +53 -36
- package/src/browser/action-fence.ts +47 -0
- package/src/browser/app-shell.ts +39 -0
- package/src/browser/connection-warmup.ts +134 -0
- package/src/browser/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +252 -158
- package/src/browser/history-state.ts +21 -0
- package/src/browser/index.ts +3 -3
- package/src/browser/invalidate-client-cache.ts +52 -0
- package/src/browser/logging.ts +28 -0
- package/src/browser/merge-segment-loaders.ts +6 -4
- package/src/browser/navigation-bridge.ts +94 -25
- package/src/browser/navigation-client.ts +144 -79
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +161 -73
- package/src/browser/navigation-transaction.ts +9 -59
- package/src/browser/network-error-handler.ts +34 -7
- package/src/browser/partial-update.ts +183 -144
- package/src/browser/prefetch/cache.ts +242 -77
- package/src/browser/prefetch/fetch.ts +325 -69
- package/src/browser/prefetch/queue.ts +61 -12
- package/src/browser/rango-state.ts +158 -76
- package/src/browser/react/Link.tsx +58 -20
- package/src/browser/react/NavigationProvider.tsx +202 -120
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/filter-segment-order.ts +66 -7
- package/src/browser/react/index.ts +0 -48
- package/src/browser/react/location-state-shared.ts +178 -8
- package/src/browser/react/location-state.ts +39 -14
- package/src/browser/react/use-action.ts +6 -15
- package/src/browser/react/use-handle.ts +17 -14
- package/src/browser/react/use-href.tsx +8 -1
- package/src/browser/react/use-link-status.ts +33 -8
- package/src/browser/react/use-navigation.ts +32 -7
- package/src/browser/react/use-params.ts +20 -10
- package/src/browser/react/use-reverse.ts +106 -0
- package/src/browser/react/use-router.ts +25 -3
- package/src/browser/react/use-search-params.ts +0 -5
- package/src/browser/react/use-segments.ts +11 -21
- package/src/browser/response-adapter.ts +99 -8
- package/src/browser/rsc-router.tsx +145 -28
- package/src/browser/scroll-restoration.ts +37 -22
- package/src/browser/segment-reconciler.ts +31 -21
- package/src/browser/segment-structure-assert.ts +2 -2
- package/src/browser/server-action-bridge.ts +236 -65
- package/src/browser/types.ts +102 -9
- package/src/browser/validate-redirect-origin.ts +43 -16
- package/src/build/collect-fallback-refs.ts +107 -0
- package/src/build/generate-manifest.ts +203 -154
- package/src/build/generate-route-types.ts +3 -1
- package/src/build/index.ts +11 -3
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +152 -21
- package/src/build/route-types/ast-route-extraction.ts +15 -8
- package/src/build/route-types/codegen.ts +16 -5
- package/src/build/route-types/include-resolution.ts +456 -62
- package/src/build/route-types/param-extraction.ts +6 -3
- package/src/build/route-types/per-module-writer.ts +22 -6
- package/src/build/route-types/router-processing.ts +128 -51
- package/src/build/route-types/scan-filter.ts +1 -1
- package/src/build/route-types/source-scan.ts +216 -0
- package/src/build/runtime-discovery.ts +13 -21
- package/src/cache/cache-error.ts +104 -0
- package/src/cache/cache-key-utils.ts +58 -13
- package/src/cache/cache-policy.ts +108 -34
- package/src/cache/cache-runtime.ts +421 -58
- package/src/cache/cache-scope.ts +187 -96
- package/src/cache/cache-tag.ts +149 -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 +2202 -372
- 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 +6 -16
- package/src/cache/document-cache.ts +126 -41
- package/src/cache/handle-snapshot.ts +70 -0
- package/src/cache/index.ts +23 -20
- package/src/cache/memory-segment-store.ts +243 -37
- package/src/cache/profile-registry.ts +46 -31
- package/src/cache/read-through-swr.ts +56 -12
- package/src/cache/segment-codec.ts +13 -21
- package/src/cache/shell-snapshot.ts +417 -0
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/types.ts +180 -99
- package/src/cache/vercel/index.ts +11 -0
- package/src/cache/vercel/vercel-cache-store.ts +1127 -0
- package/src/client.rsc.tsx +41 -21
- package/src/client.tsx +33 -61
- package/src/cloudflare/index.ts +11 -0
- package/src/cloudflare/tracing.ts +108 -0
- package/src/component-utils.ts +19 -0
- package/src/components/DefaultDocument.tsx +8 -2
- package/src/context-var.ts +18 -6
- 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 +30 -4
- package/src/escape-script.ts +52 -0
- package/src/handle.ts +67 -37
- package/src/handles/MetaTags.tsx +24 -53
- package/src/handles/Scripts.tsx +183 -0
- package/src/handles/breadcrumbs.ts +35 -8
- package/src/handles/deferred-resolution.ts +127 -0
- package/src/handles/is-thenable.ts +18 -0
- package/src/handles/meta.ts +14 -40
- package/src/handles/script.ts +244 -0
- package/src/host/cookie-handler.ts +9 -60
- package/src/host/errors.ts +13 -22
- package/src/host/index.ts +9 -2
- package/src/host/pattern-matcher.ts +23 -52
- package/src/host/router.ts +107 -99
- package/src/host/testing.ts +40 -27
- package/src/host/types.ts +37 -4
- package/src/host/utils.ts +1 -1
- package/src/href-client.ts +137 -22
- package/src/index.rsc.ts +97 -12
- package/src/index.ts +98 -14
- package/src/internal-debug.ts +11 -10
- package/src/loader-store.ts +500 -0
- package/src/loader.rsc.ts +20 -13
- package/src/loader.ts +12 -11
- package/src/missing-id-error.ts +68 -0
- package/src/outlet-context.ts +1 -1
- package/src/outlet-provider.tsx +1 -5
- package/src/prerender/param-hash.ts +16 -16
- package/src/prerender/store.ts +32 -37
- package/src/prerender.ts +78 -10
- package/src/redirect-origin.ts +114 -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 +65 -39
- package/src/root-error-boundary.tsx +1 -19
- package/src/route-content-wrapper.tsx +19 -77
- package/src/route-definition/dsl-helpers.ts +304 -309
- package/src/route-definition/helper-factories.ts +28 -140
- package/src/route-definition/helpers-types.ts +87 -59
- package/src/route-definition/index.ts +1 -2
- package/src/route-definition/redirect.ts +44 -11
- package/src/route-definition/resolve-handler-use.ts +12 -1
- package/src/route-definition/use-item-types.ts +29 -0
- package/src/route-map-builder.ts +41 -20
- package/src/route-types.ts +19 -46
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +73 -25
- package/src/router/error-handling.ts +45 -18
- package/src/router/find-match.ts +129 -30
- package/src/router/handler-context.ts +27 -42
- package/src/router/instrument.ts +355 -0
- package/src/router/intercept-resolution.ts +39 -20
- package/src/router/lazy-includes.ts +82 -59
- package/src/router/loader-resolution.ts +167 -72
- package/src/router/logging.ts +0 -6
- package/src/router/manifest.ts +74 -40
- package/src/router/match-api.ts +80 -55
- package/src/router/match-context.ts +0 -22
- package/src/router/match-handlers.ts +211 -165
- package/src/router/match-middleware/background-revalidation.ts +40 -24
- package/src/router/match-middleware/cache-lookup.ts +159 -285
- package/src/router/match-middleware/cache-store.ts +64 -52
- package/src/router/match-middleware/intercept-resolution.ts +0 -22
- package/src/router/match-middleware/segment-resolution.ts +0 -22
- package/src/router/match-pipelines.ts +1 -42
- package/src/router/match-result.ts +69 -79
- package/src/router/metrics.ts +0 -34
- package/src/router/middleware-types.ts +7 -134
- package/src/router/middleware.ts +298 -172
- package/src/router/navigation-snapshot.ts +7 -56
- package/src/router/params-util.ts +23 -0
- package/src/router/parse-pattern.ts +115 -0
- package/src/router/pattern-matching.ts +181 -150
- package/src/router/prefetch-cache-ttl.ts +51 -0
- package/src/router/prefetch-limits.ts +37 -0
- package/src/router/prerender-match.ts +112 -67
- package/src/router/preview-match.ts +6 -2
- package/src/router/request-classification.ts +50 -69
- package/src/router/revalidation.ts +123 -73
- package/src/router/route-snapshot.ts +14 -3
- package/src/router/router-context.ts +6 -29
- package/src/router/router-interfaces.ts +115 -36
- package/src/router/router-options.ts +166 -5
- package/src/router/router-registry.ts +2 -5
- package/src/router/segment-resolution/fresh.ts +131 -86
- package/src/router/segment-resolution/helpers.ts +86 -6
- package/src/router/segment-resolution/loader-cache.ts +139 -39
- package/src/router/segment-resolution/loader-mask.ts +67 -0
- package/src/router/segment-resolution/loader-snapshot.ts +251 -0
- package/src/router/segment-resolution/revalidation.ts +272 -320
- package/src/router/segment-resolution/static-store.ts +19 -5
- 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 +5 -1
- package/src/router/segment-wrappers.ts +6 -5
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/substitute-pattern-params.ts +75 -0
- package/src/router/telemetry-otel.ts +160 -200
- package/src/router/telemetry.ts +105 -20
- package/src/router/timeout.ts +0 -20
- package/src/router/tracing.ts +215 -0
- package/src/router/trie-matching.ts +171 -59
- package/src/router/types.ts +9 -63
- package/src/router/url-params.ts +57 -0
- package/src/router.ts +157 -71
- package/src/rsc/full-payload.ts +70 -0
- package/src/rsc/handler-context.ts +3 -2
- package/src/rsc/handler.ts +291 -217
- package/src/rsc/helpers.ts +168 -46
- package/src/rsc/index.ts +2 -5
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/loader-fetch.ts +114 -38
- package/src/rsc/manifest-init.ts +29 -42
- package/src/rsc/nonce.ts +10 -1
- package/src/rsc/origin-guard.ts +39 -25
- package/src/rsc/progressive-enhancement.ts +124 -13
- package/src/rsc/redirect-guard.ts +100 -0
- package/src/rsc/response-cache-serve.ts +238 -0
- package/src/rsc/response-error.ts +79 -12
- package/src/rsc/response-route-handler.ts +99 -189
- package/src/rsc/rsc-rendering.ts +421 -76
- package/src/rsc/runtime-warnings.ts +23 -10
- package/src/rsc/server-action.ts +282 -116
- package/src/rsc/shell-capture.ts +1158 -0
- package/src/rsc/shell-serve.ts +150 -0
- package/src/rsc/ssr-setup.ts +16 -0
- package/src/rsc/transition-gate.ts +89 -0
- package/src/rsc/types.ts +53 -5
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +35 -30
- package/src/segment-loader-promise.ts +49 -4
- package/src/segment-system.tsx +350 -149
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +208 -51
- package/src/server/cookie-parse.ts +32 -0
- package/src/server/cookie-store.ts +152 -5
- package/src/server/handle-store.ts +21 -38
- package/src/server/loader-registry.ts +33 -42
- package/src/server/request-context.ts +395 -176
- package/src/ssr/index.tsx +458 -178
- package/src/ssr/ssr-root.tsx +228 -0
- package/src/static-handler.ts +10 -13
- package/src/testing/cache-status.ts +162 -0
- package/src/testing/collect-handle.ts +46 -0
- package/src/testing/dispatch.ts +813 -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 +56 -84
- package/src/theme/ThemeScript.tsx +7 -9
- package/src/theme/constants.ts +52 -13
- package/src/theme/index.ts +0 -7
- package/src/theme/theme-context.ts +1 -5
- package/src/theme/theme-script.ts +22 -21
- package/src/theme/use-theme.ts +0 -3
- package/src/types/boundaries.ts +0 -35
- package/src/types/cache-types.ts +13 -4
- package/src/types/error-types.ts +30 -90
- package/src/types/global-namespace.ts +54 -41
- package/src/types/handler-context.ts +110 -62
- package/src/types/index.ts +3 -10
- package/src/types/loader-types.ts +11 -9
- package/src/types/request-scope.ts +112 -0
- package/src/types/route-config.ts +20 -52
- package/src/types/route-entry.ts +0 -6
- package/src/types/segments.ts +135 -14
- package/src/urls/include-helper.ts +19 -64
- package/src/urls/include-provider.ts +71 -0
- package/src/urls/index.ts +2 -11
- package/src/urls/path-helper-types.ts +63 -17
- package/src/urls/path-helper.ts +22 -106
- package/src/urls/pattern-types.ts +72 -19
- package/src/urls/response-types.ts +22 -29
- package/src/urls/type-extraction.ts +98 -154
- package/src/urls/urls-function.ts +1 -19
- package/src/use-loader.tsx +292 -107
- 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 +8 -7
- package/src/vite/discovery/dev-prerender-cache.ts +117 -0
- package/src/vite/discovery/discover-routers.ts +127 -86
- 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 +96 -68
- package/src/vite/discovery/route-types-writer.ts +40 -84
- package/src/vite/discovery/self-gen-tracking.ts +27 -1
- package/src/vite/discovery/state.ts +45 -1
- package/src/vite/discovery/virtual-module-codegen.ts +14 -34
- package/src/vite/index.ts +4 -0
- package/src/vite/inject-client-debug.ts +88 -0
- package/src/vite/plugin-types.ts +210 -10
- package/src/vite/plugins/cjs-to-esm.ts +16 -19
- package/src/vite/plugins/client-ref-dedup.ts +16 -11
- package/src/vite/plugins/client-ref-hashing.ts +28 -15
- 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/plugins/expose-action-id.ts +48 -95
- package/src/vite/plugins/expose-id-utils.ts +88 -55
- package/src/vite/plugins/expose-ids/export-analysis.ts +101 -34
- package/src/vite/plugins/expose-ids/handler-transform.ts +11 -90
- package/src/vite/plugins/expose-ids/loader-transform.ts +14 -24
- package/src/vite/plugins/expose-ids/router-transform.ts +118 -29
- package/src/vite/plugins/expose-internal-ids.ts +505 -486
- package/src/vite/plugins/performance-tracks.ts +26 -25
- package/src/vite/plugins/refresh-cmd.ts +1 -1
- package/src/vite/plugins/use-cache-transform.ts +73 -83
- package/src/vite/plugins/vercel-output.ts +384 -0
- package/src/vite/plugins/version-injector.ts +40 -29
- package/src/vite/plugins/version-plugin.ts +37 -40
- package/src/vite/plugins/virtual-entries.ts +138 -27
- package/src/vite/rango.ts +236 -138
- package/src/vite/router-discovery.ts +927 -136
- package/src/vite/utils/ast-handler-extract.ts +26 -35
- package/src/vite/utils/banner.ts +1 -1
- package/src/vite/utils/bundle-analysis.ts +10 -15
- 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 +4 -59
- package/src/vite/utils/package-resolution.ts +20 -52
- package/src/vite/utils/prerender-utils.ts +71 -43
- package/src/vite/utils/shared-utils.ts +142 -43
- package/src/browser/action-response-classifier.ts +0 -99
- package/src/browser/react/use-client-cache.ts +0 -58
- package/src/browser/shallow.ts +0 -40
- package/src/handles/index.ts +0 -7
- package/src/network-error-thrower.tsx +0 -23
- package/src/router/middleware-cookies.ts +0 -55
|
@@ -1,633 +1,52 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: typesafety
|
|
3
|
-
description: Set up type-safe routes, params, and environment types in @rangojs/router
|
|
3
|
+
description: Set up type-safe routes, params, and environment types in @rangojs/router. Use when route or search params aren't typed, TypeScript can't infer a loader's return type, or wiring up typed environment bindings.
|
|
4
4
|
argument-hint: [setup]
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Type Safety Setup
|
|
8
8
|
|
|
9
|
-
@rangojs/router provides end-to-end type safety for routes, parameters, and
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
- `
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
- `
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
namespace RSCRouter {
|
|
54
|
-
interface Env extends AppBindings {}
|
|
55
|
-
interface Vars extends AppVars {}
|
|
56
|
-
interface RegisteredRoutes extends typeof router.routeMap {}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## Route Definition with Type-Safe Names
|
|
62
|
-
|
|
63
|
-
```typescript
|
|
64
|
-
// urls.tsx
|
|
65
|
-
import { urls } from "@rangojs/router";
|
|
66
|
-
|
|
67
|
-
export const urlpatterns = urls(({ path, layout }) => [
|
|
68
|
-
path("/", HomePage, { name: "home" }),
|
|
69
|
-
path("/products", ProductsPage, { name: "products" }),
|
|
70
|
-
path("/product/:slug", ProductPage, { name: "product" }),
|
|
71
|
-
path("/cart", CartPage, { name: "cart" }),
|
|
72
|
-
path("/checkout/:step?", CheckoutPage, { name: "checkout" }),
|
|
73
|
-
]);
|
|
74
|
-
|
|
75
|
-
// Route names are inferred from the { name } option
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
## Type-Safe href()
|
|
79
|
-
|
|
80
|
-
### Server: ctx.reverse with route names
|
|
81
|
-
|
|
82
|
-
In route handlers, `ctx.reverse()` uses two namespaces:
|
|
83
|
-
|
|
84
|
-
- **`.name`** — local route, resolved within the current `include()` scope
|
|
85
|
-
- **`name`** — global route, from the named-routes definition
|
|
86
|
-
|
|
87
|
-
```typescript
|
|
88
|
-
import type { Handler } from "@rangojs/router";
|
|
89
|
-
|
|
90
|
-
export const ProductHandler: Handler<"shop.product"> = (ctx) => {
|
|
91
|
-
ctx.reverse(".cart"); // Local: /shop/cart
|
|
92
|
-
ctx.reverse(".product", { slug: "widget" }); // Local: /shop/product/widget
|
|
93
|
-
ctx.reverse("blog.post", { slug: "1" }); // Global: /blog/1
|
|
94
|
-
};
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
For type-safe local names, generate a route types file with `npx rango generate urls/shop.tsx`
|
|
98
|
-
and pass it as the second generic to `Handler` or `Prerender`:
|
|
99
|
-
|
|
100
|
-
```typescript
|
|
101
|
-
import type { Handler } from "@rangojs/router";
|
|
102
|
-
import type { routes } from "./shop.gen.js";
|
|
103
|
-
|
|
104
|
-
export const ProductHandler: Handler<"shop.product", routes> = (ctx) => {
|
|
105
|
-
ctx.reverse(".cart"); // Type-safe local name
|
|
106
|
-
ctx.reverse(".product", { slug: "widget" }); // Type-safe local with params
|
|
107
|
-
ctx.reverse("blog.post", { slug: "hi" }); // Type-safe global name
|
|
108
|
-
};
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
### Client: href + useHref
|
|
112
|
-
|
|
113
|
-
On the client, `href()` validates paths against registered route patterns at compile time:
|
|
114
|
-
|
|
115
|
-
```typescript
|
|
116
|
-
"use client";
|
|
117
|
-
import { href, useHref, Link } from "@rangojs/router/client";
|
|
118
|
-
|
|
119
|
-
// href() validates absolute paths via PatternToPath types
|
|
120
|
-
href("/about"); // Valid path
|
|
121
|
-
href("/blog/hello"); // Matches /blog/:slug
|
|
122
|
-
|
|
123
|
-
// useHref() auto-prefixes with include() mount
|
|
124
|
-
function ShopNav() {
|
|
125
|
-
const href = useHref();
|
|
126
|
-
return <Link to={href("/cart")}>Cart</Link>; // "/shop/cart"
|
|
127
|
-
}
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
`href()` and path-based response utilities read from `RegisteredRoutes`, so if
|
|
131
|
-
you want them typed globally you should augment:
|
|
132
|
-
|
|
133
|
-
```typescript
|
|
134
|
-
declare global {
|
|
135
|
-
namespace RSCRouter {
|
|
136
|
-
interface RegisteredRoutes extends typeof router.routeMap {}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
See `/links` for full URL generation guide.
|
|
142
|
-
|
|
143
|
-
## Environment Type Setup
|
|
144
|
-
|
|
145
|
-
Define your app's environment for type-safe bindings and variables:
|
|
146
|
-
|
|
147
|
-
```typescript
|
|
148
|
-
// env.ts
|
|
149
|
-
|
|
150
|
-
// Cloudflare bindings — passed as TEnv to createRouter<TEnv>()
|
|
151
|
-
export interface AppBindings {
|
|
152
|
-
DB: D1Database;
|
|
153
|
-
KV: KVNamespace;
|
|
154
|
-
CACHE: KVNamespace;
|
|
155
|
-
AI: Ai;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// Variables set by middleware — declared via module augmentation
|
|
159
|
-
export interface AppVariables {
|
|
160
|
-
user?: { id: string; email: string; role: string };
|
|
161
|
-
requestId?: string;
|
|
162
|
-
permissions?: string[];
|
|
163
|
-
}
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
### Using Environment Types
|
|
167
|
-
|
|
168
|
-
```typescript
|
|
169
|
-
// router.tsx
|
|
170
|
-
import type { AppBindings, AppVariables } from "./env";
|
|
171
|
-
|
|
172
|
-
const router = createRouter<AppBindings>({
|
|
173
|
-
document: Document,
|
|
174
|
-
}).routes(urlpatterns);
|
|
175
|
-
|
|
176
|
-
// Register bindings and variables globally for implicit typing
|
|
177
|
-
declare global {
|
|
178
|
-
namespace RSCRouter {
|
|
179
|
-
interface Env extends AppBindings {}
|
|
180
|
-
interface Vars extends AppVariables {}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// middleware - typed via ctx.set / ctx.get
|
|
185
|
-
import type { Middleware } from "@rangojs/router";
|
|
186
|
-
|
|
187
|
-
export const authMiddleware: Middleware = async (ctx, next) => {
|
|
188
|
-
ctx.set("user", {
|
|
189
|
-
id: "123",
|
|
190
|
-
email: "user@example.com",
|
|
191
|
-
role: "admin",
|
|
192
|
-
});
|
|
193
|
-
await next();
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
// loaders - typed context
|
|
197
|
-
export const UserLoader = createLoader(async (ctx) => {
|
|
198
|
-
const db = ctx.env.DB; // D1Database (plain bindings)
|
|
199
|
-
const userId = ctx.get("user")?.id; // from RSCRouter.Vars
|
|
200
|
-
return db.prepare("SELECT * FROM users WHERE id = ?").bind(userId).first();
|
|
201
|
-
});
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
## Global Environment Registration
|
|
205
|
-
|
|
206
|
-
Register environment types globally for implicit typing:
|
|
207
|
-
|
|
208
|
-
```typescript
|
|
209
|
-
// router.tsx
|
|
210
|
-
declare global {
|
|
211
|
-
namespace RSCRouter {
|
|
212
|
-
interface Env extends AppBindings {}
|
|
213
|
-
interface Vars extends AppVariables {}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
Now handlers have typed context without explicit imports:
|
|
219
|
-
|
|
220
|
-
```typescript
|
|
221
|
-
// In loaders
|
|
222
|
-
export const DashboardLoader = createLoader(async (ctx) => {
|
|
223
|
-
// ctx.env.DB is typed from global RSCRouter.Env
|
|
224
|
-
// ctx.get("user") is typed from global RSCRouter.Vars
|
|
225
|
-
const user = ctx.get("user");
|
|
226
|
-
return { user };
|
|
227
|
-
});
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
## Typed Search Params
|
|
231
|
-
|
|
232
|
-
Add a `search` schema to `path()` options for type-safe query parameters:
|
|
233
|
-
|
|
234
|
-
```typescript
|
|
235
|
-
// Route definition with search schema
|
|
236
|
-
path("/search", SearchPage, {
|
|
237
|
-
name: "search",
|
|
238
|
-
search: { q: "string", page: "number?", sort: "string?" },
|
|
239
|
-
});
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
### Handler with typed search params
|
|
243
|
-
|
|
244
|
-
`Handler<"name">` automatically resolves route params and search params from the
|
|
245
|
-
global `GeneratedRouteMap` (the gen file). No explicit route map import needed:
|
|
246
|
-
|
|
247
|
-
```typescript
|
|
248
|
-
// pages/search.tsx
|
|
249
|
-
import type { Handler } from "@rangojs/router";
|
|
250
|
-
|
|
251
|
-
export const SearchPage: Handler<"search"> = (ctx) => {
|
|
252
|
-
// ctx.search is typed: { q: string; page?: number; sort?: string }
|
|
253
|
-
const { q, page, sort } = ctx.search;
|
|
254
|
-
return <SearchResults q={q} page={page} sort={sort} />;
|
|
255
|
-
};
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
This avoids circular references because `Handler` defaults to `GeneratedRouteMap`
|
|
259
|
-
(from `router.named-routes.gen.ts`) instead of `RegisteredRoutes` (which depends on `router.tsx`).
|
|
260
|
-
|
|
261
|
-
You can also pass an explicit route map for per-module isolation (opt-in,
|
|
262
|
-
after running `npx rango generate`):
|
|
263
|
-
|
|
264
|
-
```typescript
|
|
265
|
-
import type { Handler } from "@rangojs/router";
|
|
266
|
-
import type { routes } from "./urls.gen.js";
|
|
267
|
-
|
|
268
|
-
export const SearchPage: Handler<"search", routes> = (ctx) => { ... };
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
Supported types: `"string"`, `"number"`, `"boolean"`, with `?` suffix for optional.
|
|
272
|
-
Values are automatically coerced from query string (e.g., `"2"` becomes `2` for numbers).
|
|
273
|
-
Routes without a `search` schema keep the standard `URLSearchParams` behavior.
|
|
274
|
-
|
|
275
|
-
### RouteSearchParams and RouteParams utility types
|
|
276
|
-
|
|
277
|
-
Extract typed params by route name for use in component props, return types, or anywhere:
|
|
278
|
-
|
|
279
|
-
```typescript
|
|
280
|
-
import type { RouteSearchParams, RouteParams } from "@rangojs/router";
|
|
281
|
-
|
|
282
|
-
// RouteSearchParams<"name"> resolves the search schema to a typed object
|
|
283
|
-
type SP = RouteSearchParams<"search">;
|
|
284
|
-
// { q: string | undefined; page?: number; sort?: string }
|
|
285
|
-
|
|
286
|
-
// RouteParams<"name"> resolves URL params from the route pattern
|
|
287
|
-
type P = RouteParams<"blogPost">;
|
|
288
|
-
// { slug: string }
|
|
289
|
-
|
|
290
|
-
// Use in component props
|
|
291
|
-
interface SearchResultsProps {
|
|
292
|
-
params: RouteSearchParams<"search">;
|
|
293
|
-
}
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
Both default to the global route map (`RegisteredRoutes` or `GeneratedRouteMap`).
|
|
297
|
-
Pass an explicit route map as the second type argument when needed:
|
|
298
|
-
|
|
299
|
-
```typescript
|
|
300
|
-
import type { routes } from "./urls.gen.js";
|
|
301
|
-
|
|
302
|
-
type SP = RouteSearchParams<"search", routes>;
|
|
303
|
-
type P = RouteParams<"blogPost", routes>;
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
### Generated route types
|
|
307
|
-
|
|
308
|
-
In the generated `router.named-routes.gen.ts`, routes with search schemas
|
|
309
|
-
use `{ path, search }` objects:
|
|
310
|
-
|
|
311
|
-
```typescript
|
|
312
|
-
// router.named-routes.gen.ts (auto-generated)
|
|
313
|
-
export const NamedRoutes = {
|
|
314
|
-
"search.index": {
|
|
315
|
-
path: "/search",
|
|
316
|
-
search: { q: "string", page: "number?", sort: "string?" },
|
|
317
|
-
},
|
|
318
|
-
"home.index": "/", // No search schema -> plain string
|
|
319
|
-
} as const;
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
## Loader Type Safety
|
|
323
|
-
|
|
324
|
-
Loaders have typed return values:
|
|
325
|
-
|
|
326
|
-
```typescript
|
|
327
|
-
// loaders/product.ts
|
|
328
|
-
export const ProductLoader = createLoader(async (ctx) => {
|
|
329
|
-
return {
|
|
330
|
-
id: ctx.params.slug,
|
|
331
|
-
name: "Widget",
|
|
332
|
-
price: 99,
|
|
333
|
-
};
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
// In server component - type is inferred
|
|
337
|
-
import { useLoader } from "@rangojs/router/client";
|
|
338
|
-
|
|
339
|
-
async function ProductPage() {
|
|
340
|
-
const product = await useLoader(ProductLoader);
|
|
341
|
-
// product: { id: string; name: string; price: number }
|
|
342
|
-
return <h1>{product.name}</h1>;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// In client component - same type
|
|
346
|
-
"use client";
|
|
347
|
-
import { useLoader } from "@rangojs/router/client";
|
|
348
|
-
|
|
349
|
-
function ProductPrice() {
|
|
350
|
-
const { data } = useLoader(ProductLoader);
|
|
351
|
-
// data: { id: string; name: string; price: number }
|
|
352
|
-
const product = data;
|
|
353
|
-
return <span>${product.price}</span>;
|
|
354
|
-
}
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
## Typed Context Variables
|
|
358
|
-
|
|
359
|
-
`createVar<T>()` creates a typed token for `ctx.set()`/`ctx.get()`, making
|
|
360
|
-
handler-to-layout data contracts explicit and compile-time verified:
|
|
361
|
-
|
|
362
|
-
```typescript
|
|
363
|
-
import { createVar } from "@rangojs/router";
|
|
364
|
-
|
|
365
|
-
// Define a typed token (shared between producer and consumer)
|
|
366
|
-
interface PaginationData {
|
|
367
|
-
current: number;
|
|
368
|
-
total: number;
|
|
369
|
-
perPage: number;
|
|
370
|
-
}
|
|
371
|
-
export const Pagination = createVar<PaginationData>();
|
|
372
|
-
|
|
373
|
-
// Non-cacheable var — reading inside cache() or "use cache" throws at runtime
|
|
374
|
-
const Session = createVar<SessionData>({ cache: false });
|
|
375
|
-
```
|
|
376
|
-
|
|
377
|
-
`createVar` accepts an optional options object. The `cache` option (default
|
|
378
|
-
`true`) controls whether the var's values can be read inside cache scopes.
|
|
379
|
-
Write-level escalation is also supported: `ctx.set(Var, value, { cache: false })`
|
|
380
|
-
marks a specific write as non-cacheable even if the var itself is cacheable.
|
|
381
|
-
"Least cacheable wins" — if either says `cache: false`, the value throws on
|
|
382
|
-
read inside `cache()` or `"use cache"`.
|
|
383
|
-
|
|
384
|
-
### Producer (handler or middleware)
|
|
385
|
-
|
|
386
|
-
```typescript
|
|
387
|
-
import { Pagination } from "../vars/pagination.js";
|
|
388
|
-
|
|
389
|
-
const ArticleList: Handler<"articles.list"> = async (ctx) => {
|
|
390
|
-
ctx.set(Pagination, { // type-checked
|
|
391
|
-
current: 1,
|
|
392
|
-
total: 10,
|
|
393
|
-
perPage: 5,
|
|
394
|
-
});
|
|
395
|
-
return <Articles />;
|
|
396
|
-
};
|
|
397
|
-
```
|
|
398
|
-
|
|
399
|
-
### Consumer (layout, parallel, or any context with get)
|
|
400
|
-
|
|
401
|
-
```typescript
|
|
402
|
-
import { Pagination } from "../vars/pagination.js";
|
|
403
|
-
|
|
404
|
-
export function PaginationLayout(ctx: any) {
|
|
405
|
-
const pagination = ctx.get(Pagination); // typed as PaginationData | undefined
|
|
406
|
-
if (!pagination) return <Outlet />;
|
|
407
|
-
return <nav>Page {pagination.current} of {pagination.total}</nav>;
|
|
408
|
-
}
|
|
409
|
-
```
|
|
410
|
-
|
|
411
|
-
### Why not just use RSCRouter.Vars?
|
|
412
|
-
|
|
413
|
-
`RSCRouter.Vars` (via module augmentation) provides app-global typing for
|
|
414
|
-
`ctx.get("key")` / `ctx.set("key", value)`. It works for middleware state
|
|
415
|
-
shared app-wide. `createVar<T>()` is for route-local or feature-scoped
|
|
416
|
-
context -- the producer and consumer import the same token, creating a
|
|
417
|
-
scoped contract without polluting global types.
|
|
418
|
-
|
|
419
|
-
Both approaches coexist: `ctx.get("user")` (global via Vars) and
|
|
420
|
-
`ctx.get(Pagination)` (scoped via createVar) work side by side.
|
|
421
|
-
|
|
422
|
-
## Handle Type Safety
|
|
423
|
-
|
|
424
|
-
Handles have typed data:
|
|
425
|
-
|
|
426
|
-
```typescript
|
|
427
|
-
// Built-in Breadcrumbs handle — import from "@rangojs/router"
|
|
428
|
-
import { Breadcrumbs } from "@rangojs/router";
|
|
429
|
-
// Type: Handle<BreadcrumbItem, BreadcrumbItem[]>
|
|
430
|
-
// BreadcrumbItem: { label: string; href: string; content?: ReactNode | Promise<ReactNode> }
|
|
431
|
-
|
|
432
|
-
// In route handler — push is fully typed
|
|
433
|
-
path("/shop/product/:slug", (ctx) => {
|
|
434
|
-
const breadcrumb = ctx.use(Breadcrumbs);
|
|
435
|
-
breadcrumb({ label: "Products", href: "/shop/products" });
|
|
436
|
-
return <ProductPage />;
|
|
437
|
-
}, { name: "product" });
|
|
438
|
-
|
|
439
|
-
// In client — typed array
|
|
440
|
-
import { useHandle, Breadcrumbs } from "@rangojs/router/client";
|
|
441
|
-
function BreadcrumbNav() {
|
|
442
|
-
const crumbs = useHandle(Breadcrumbs);
|
|
443
|
-
// crumbs: BreadcrumbItem[]
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
// Custom handles also work the same way
|
|
447
|
-
import { createHandle } from "@rangojs/router";
|
|
448
|
-
export const PageTitle = createHandle<string, string>(
|
|
449
|
-
(segments) => segments.flat().at(-1) ?? "Default Title"
|
|
450
|
-
);
|
|
451
|
-
```
|
|
452
|
-
|
|
453
|
-
## Ref Prop Type Safety (Loaders & Handles)
|
|
454
|
-
|
|
455
|
-
Loaders and handles can be passed as props from server to client components.
|
|
456
|
-
Use `typeof` to get the full typed definition without manually specifying generics:
|
|
457
|
-
|
|
458
|
-
```typescript
|
|
459
|
-
// loaders.ts
|
|
460
|
-
export const ProductLoader = createLoader(async (ctx) => {
|
|
461
|
-
return { product: await fetchProduct(ctx.params.slug) };
|
|
462
|
-
});
|
|
463
|
-
|
|
464
|
-
// Built-in Breadcrumbs — or any custom handle created with createHandle()
|
|
465
|
-
|
|
466
|
-
// Client component — typeof infers all generics
|
|
467
|
-
("use client");
|
|
468
|
-
import { useLoader, useHandle, type Breadcrumbs } from "@rangojs/router/client";
|
|
469
|
-
import type { ProductLoader } from "../loaders";
|
|
470
|
-
|
|
471
|
-
function MyComponent({
|
|
472
|
-
loader,
|
|
473
|
-
handle,
|
|
474
|
-
}: {
|
|
475
|
-
loader: typeof ProductLoader; // LoaderDefinition<{ product: Product }>
|
|
476
|
-
handle: typeof Breadcrumbs; // Handle<{ label: string; href: string }>
|
|
477
|
-
}) {
|
|
478
|
-
const { data } = useLoader(loader); // data is typed
|
|
479
|
-
const crumbs = useHandle(handle); // crumbs is typed array
|
|
480
|
-
// ...
|
|
481
|
-
}
|
|
482
|
-
```
|
|
483
|
-
|
|
484
|
-
RSC Flight serialization calls `toJSON()` on both loaders and handles,
|
|
485
|
-
sending only `{ __brand, $$id }` to the client. The hooks recover the
|
|
486
|
-
full functionality from module-level registries.
|
|
487
|
-
|
|
488
|
-
## Location State Type Safety
|
|
489
|
-
|
|
490
|
-
```typescript
|
|
491
|
-
// location-states.ts
|
|
492
|
-
import { createLocationState } from "@rangojs/router";
|
|
493
|
-
|
|
494
|
-
// All export patterns work: export const, const + export { X }, export { X as Y }
|
|
495
|
-
export const ProductPreview = createLocationState<{
|
|
496
|
-
name: string;
|
|
497
|
-
price: number;
|
|
498
|
-
image: string;
|
|
499
|
-
}>();
|
|
500
|
-
|
|
501
|
-
// Passing state through Link
|
|
502
|
-
<Link
|
|
503
|
-
to={href("product", { slug: "widget" })}
|
|
504
|
-
state={[ProductPreview({ name: "Widget", price: 99, image: "/img.jpg" })]}
|
|
505
|
-
>
|
|
506
|
-
View Product
|
|
507
|
-
</Link>
|
|
508
|
-
|
|
509
|
-
// Reading state in component
|
|
510
|
-
function ProductHeader() {
|
|
511
|
-
const preview = useLocationState(ProductPreview);
|
|
512
|
-
// preview: { name: string; price: number; image: string } | undefined
|
|
513
|
-
|
|
514
|
-
if (preview) {
|
|
515
|
-
return <h1>{preview.name} - ${preview.price}</h1>;
|
|
516
|
-
}
|
|
517
|
-
return <h1>Loading...</h1>;
|
|
518
|
-
}
|
|
519
|
-
```
|
|
520
|
-
|
|
521
|
-
## Multi-Project tsconfig Setup
|
|
522
|
-
|
|
523
|
-
For monorepos or multi-app setups, use a shared base tsconfig. Each app only needs
|
|
524
|
-
to extend the base and add its `router.tsx` to `files` so TypeScript picks up the
|
|
525
|
-
global type declarations (like `RSCRouter.Env`).
|
|
526
|
-
|
|
527
|
-
```jsonc
|
|
528
|
-
// tsconfig.base.json (root)
|
|
529
|
-
{
|
|
530
|
-
"compilerOptions": {
|
|
531
|
-
"target": "ES2022",
|
|
532
|
-
"module": "ESNext",
|
|
533
|
-
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
534
|
-
"jsx": "react-jsx",
|
|
535
|
-
"moduleResolution": "bundler",
|
|
536
|
-
"strict": true,
|
|
537
|
-
"noEmit": true,
|
|
538
|
-
"skipLibCheck": true,
|
|
539
|
-
"isolatedModules": true,
|
|
540
|
-
"esModuleInterop": true,
|
|
541
|
-
"resolveJsonModule": true,
|
|
542
|
-
},
|
|
543
|
-
}
|
|
544
|
-
```
|
|
545
|
-
|
|
546
|
-
```jsonc
|
|
547
|
-
// apps/shop/tsconfig.json
|
|
548
|
-
{
|
|
549
|
-
"extends": "../../tsconfig.base.json",
|
|
550
|
-
"include": ["src"],
|
|
551
|
-
"files": ["src/router.tsx"],
|
|
552
|
-
}
|
|
553
|
-
```
|
|
554
|
-
|
|
555
|
-
```jsonc
|
|
556
|
-
// apps/blog/tsconfig.json
|
|
557
|
-
{
|
|
558
|
-
"extends": "../../tsconfig.base.json",
|
|
559
|
-
"include": ["src"],
|
|
560
|
-
"files": ["src/router.tsx"],
|
|
561
|
-
}
|
|
562
|
-
```
|
|
563
|
-
|
|
564
|
-
The `files` array ensures `router.tsx` (which contains `declare global { namespace RSCRouter { interface Env; interface Vars } }`)
|
|
565
|
-
is always included in the compilation even if nothing directly imports it. Route types come from the
|
|
566
|
-
auto-generated `*.named-routes.gen.ts` file (via `rango generate`), not from manual declaration.
|
|
567
|
-
Each app gets its own typed environment without interfering with other apps.
|
|
568
|
-
|
|
569
|
-
## Complete Type-Safe Setup
|
|
570
|
-
|
|
571
|
-
```typescript
|
|
572
|
-
// 1. env.ts - Environment types
|
|
573
|
-
export interface AppBindings {
|
|
574
|
-
DB: D1Database;
|
|
575
|
-
KV: KVNamespace;
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
export interface AppVariables {
|
|
579
|
-
user?: { id: string; email: string; role: string };
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
// 2. urls.tsx - Route definitions with names
|
|
583
|
-
import { urls } from "@rangojs/router";
|
|
584
|
-
|
|
585
|
-
export const urlpatterns = urls(({ path, layout, loader }) => [
|
|
586
|
-
path("/", HomePage, { name: "home" }),
|
|
587
|
-
|
|
588
|
-
layout(<ShopLayout />, () => [
|
|
589
|
-
path("/shop", ShopIndex, { name: "shop" }),
|
|
590
|
-
path("/shop/product/:slug", ProductPage, { name: "product" }, () => [
|
|
591
|
-
loader(ProductLoader),
|
|
592
|
-
]),
|
|
593
|
-
]),
|
|
594
|
-
]);
|
|
595
|
-
|
|
596
|
-
// 3. router.tsx - Create router and export reverse
|
|
597
|
-
const router = createRouter<AppBindings>({
|
|
598
|
-
document: Document,
|
|
599
|
-
}).routes(urlpatterns);
|
|
600
|
-
|
|
601
|
-
// Register bindings and variables globally for implicit typing
|
|
602
|
-
declare global {
|
|
603
|
-
namespace RSCRouter {
|
|
604
|
-
interface Env extends AppBindings {}
|
|
605
|
-
interface Vars extends AppVariables {}
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
export const reverse = router.reverse;
|
|
610
|
-
export default router;
|
|
611
|
-
|
|
612
|
-
// 4. Run `npx rango generate src/router.tsx` to generate
|
|
613
|
-
// router.named-routes.gen.ts (auto-registers GeneratedRouteMap globally).
|
|
614
|
-
// No manual RegisteredRoutes declaration needed.
|
|
615
|
-
|
|
616
|
-
// 5. loaders/*.ts - Type-safe loaders
|
|
617
|
-
export const ProductLoader = createLoader(async (ctx) => {
|
|
618
|
-
// ctx.params: { slug: string }
|
|
619
|
-
// ctx.get("user"): User | undefined (from RSCRouter.Vars)
|
|
620
|
-
// ctx.env.DB: D1Database (plain bindings from RSCRouter.Env)
|
|
621
|
-
return { product: await fetchProduct(ctx.params.slug) };
|
|
622
|
-
});
|
|
623
|
-
|
|
624
|
-
// 6. Server: ctx.reverse for named routes
|
|
625
|
-
path("/product/:slug", (ctx) => {
|
|
626
|
-
return <Link to={ctx.reverse("shop")}>Back to Shop</Link>;
|
|
627
|
-
}, { name: "product" })
|
|
628
|
-
|
|
629
|
-
// 7. Client: useHref for mounted paths, href for absolute
|
|
630
|
-
"use client";
|
|
631
|
-
import { useHref, href, Link } from "@rangojs/router/client";
|
|
632
|
-
<Link to={href("/shop/product/widget")}>Widget</Link>
|
|
633
|
-
```
|
|
9
|
+
@rangojs/router provides end-to-end type safety for routes, parameters, and
|
|
10
|
+
environment. Without it: `ctx.reverse()`/`href()` accept any string (typos
|
|
11
|
+
404 at runtime, not compile time), `ctx.search`/`ctx.params` fall back to
|
|
12
|
+
loose `Record<string, string>`, and `ctx.env`/`ctx.get()` are untyped so a
|
|
13
|
+
missing binding surfaces as `undefined` in production instead of a build
|
|
14
|
+
error.
|
|
15
|
+
|
|
16
|
+
Each topic's full setup, code, and caveats live in a companion file linked
|
|
17
|
+
below. Read the one for your case.
|
|
18
|
+
|
|
19
|
+
## Routing table
|
|
20
|
+
|
|
21
|
+
| I need... | Topic | File |
|
|
22
|
+
| -------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | -------------------------------------------------------------- |
|
|
23
|
+
| Named routes, `.gen.ts` surfaces, `RegisteredRoutes` vs `GeneratedRouteMap`, tsconfig checklist | Router setup & generated route types | [`./generated-files-and-cli.md`](./generated-files-and-cli.md) |
|
|
24
|
+
| Type-safe `path()` names, `ctx.reverse()`, `href()`/`useHref()`, `Rango.PathResponse`, stable `path#export` identity | Route & href typing | [`./route-types.md`](./route-types.md) |
|
|
25
|
+
| Typed `search` schemas, `RouteSearchParams`/`RouteParams`, loader return types | Search params & loader typing | [`./params-and-search.md`](./params-and-search.md) |
|
|
26
|
+
| Typed `env`/bindings, `Rango.Vars`, `createVar()`, handle typing, loader/handle ref props, location state typing | Environment, context, and state typing | [`./env-and-bindings.md`](./env-and-bindings.md) |
|
|
27
|
+
| Multi-app / multi-router tsconfig setup, avoiding `GeneratedRouteMap` collisions | Multi-project setup & full walkthrough | [`./generated-files-and-cli.md`](./generated-files-and-cli.md) |
|
|
28
|
+
| Slow typecheck with many `include()` modules (instantiation blowup), wide `UrlPatterns<any>` annotations | Typecheck cost at route scale | [`./generated-files-and-cli.md`](./generated-files-and-cli.md) |
|
|
29
|
+
|
|
30
|
+
## Companion files
|
|
31
|
+
|
|
32
|
+
- [`./generated-files-and-cli.md`](./generated-files-and-cli.md) — Router
|
|
33
|
+
setup, the three route-typing surfaces (`GeneratedRouteMap` /
|
|
34
|
+
per-module `routes` / `RegisteredRoutes`), the single-app setup checklist,
|
|
35
|
+
`$$routeNames` vs `router.routeMap`, multi-project tsconfig setup, and the
|
|
36
|
+
complete end-to-end setup walkthrough.
|
|
37
|
+
- [`./route-types.md`](./route-types.md) — Type-safe route names, server
|
|
38
|
+
`ctx.reverse()`, client `href()`/`useHref()`, `Rango.Path`,
|
|
39
|
+
`Rango.PathResponse` (incl. overriding JSON/Flight serialization), and the
|
|
40
|
+
`path#export` stable identity scheme shared by loaders/handles/cached
|
|
41
|
+
functions/actions.
|
|
42
|
+
- [`./params-and-search.md`](./params-and-search.md) — Typed `search`
|
|
43
|
+
schemas on `path()`, `Handler<"name">` param/search inference,
|
|
44
|
+
`RouteSearchParams`/`RouteParams` utility types, and loader return-type
|
|
45
|
+
inference.
|
|
46
|
+
- [`./env-and-bindings.md`](./env-and-bindings.md) — Environment bindings
|
|
47
|
+
(`TEnv`) and `Rango.Env`/`Rango.Vars` registration, `createVar<T>()`
|
|
48
|
+
scoped context tokens, handle typing, passing loaders/handles as typed
|
|
49
|
+
props, and location state typing.
|
|
50
|
+
|
|
51
|
+
See `/links` for the full URL generation guide (per-module `*.gen.ts`,
|
|
52
|
+
`useReverse`).
|