@rangojs/router 0.0.0-experimental.14 → 0.0.0-experimental.140
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 +426 -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 +2500 -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 +29 -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-cache.ts +386 -0
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/taint.ts +153 -0
- package/src/cache/types.ts +156 -211
- package/src/cache/vercel/index.ts +11 -0
- package/src/cache/vercel/vercel-cache-store.ts +1102 -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 +177 -35
- package/src/index.ts +255 -71
- 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 +337 -0
- package/src/rsc/runtime-warnings.ts +55 -0
- package/src/rsc/server-action.ts +522 -0
- package/src/rsc/shell-capture.ts +439 -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 +452 -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/live.ts +130 -0
- package/src/server/loader-registry.ts +51 -100
- package/src/server/request-context.ts +842 -157
- package/src/server.ts +15 -8
- package/src/ssr/index.tsx +412 -136
- 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 +40 -72
- 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 +43 -0
- package/src/urls/path-helper-types.ts +413 -0
- package/src/urls/path-helper.ts +275 -0
- package/src/urls/pattern-types.ts +124 -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
|
@@ -8,11 +8,11 @@ import {
|
|
|
8
8
|
generateHistoryKey,
|
|
9
9
|
} from "./navigation-store.js";
|
|
10
10
|
import { createEventController } from "./event-controller.js";
|
|
11
|
+
import { validateRedirectOrigin } from "./validate-redirect-origin.js";
|
|
11
12
|
import { createNavigationClient } from "./navigation-client.js";
|
|
12
13
|
import { createServerActionBridge } from "./server-action-bridge.js";
|
|
13
14
|
import { createNavigationBridge } from "./navigation-bridge.js";
|
|
14
|
-
import { NavigationProvider
|
|
15
|
-
import { initThemeConfigSync } from "../theme/theme-context.js";
|
|
15
|
+
import { NavigationProvider } from "./react/index.js";
|
|
16
16
|
import type {
|
|
17
17
|
RscPayload,
|
|
18
18
|
RscBrowserDependencies,
|
|
@@ -22,6 +22,17 @@ import type {
|
|
|
22
22
|
} from "./types.js";
|
|
23
23
|
import type { EventController } from "./event-controller.js";
|
|
24
24
|
import type { ResolvedThemeConfig, Theme } from "../theme/types.js";
|
|
25
|
+
import { initRangoState } from "./rango-state.js";
|
|
26
|
+
import { registerNavigationStore } from "./navigation-store-handle.js";
|
|
27
|
+
import { initPrefetchCache } from "./prefetch/cache.js";
|
|
28
|
+
import { setPrefetchConcurrency } from "./prefetch/queue.js";
|
|
29
|
+
import { setPrefetchDecoder } from "./prefetch/fetch.js";
|
|
30
|
+
import { setAppVersion } from "./app-version.js";
|
|
31
|
+
import {
|
|
32
|
+
isInterceptSegment,
|
|
33
|
+
splitInterceptSegments,
|
|
34
|
+
} from "./intercept-utils.js";
|
|
35
|
+
import { createAppShellRef } from "./app-shell.js";
|
|
25
36
|
|
|
26
37
|
// Vite HMR types are provided by vite/client
|
|
27
38
|
|
|
@@ -89,7 +100,6 @@ export interface InitBrowserAppOptions {
|
|
|
89
100
|
* Only used when themeConfig is provided.
|
|
90
101
|
*/
|
|
91
102
|
initialTheme?: Theme;
|
|
92
|
-
|
|
93
103
|
}
|
|
94
104
|
|
|
95
105
|
/**
|
|
@@ -107,13 +117,26 @@ export interface BrowserAppContext {
|
|
|
107
117
|
initialTheme?: Theme;
|
|
108
118
|
/** Whether connection warmup is enabled */
|
|
109
119
|
warmupEnabled?: boolean;
|
|
120
|
+
/** Whether the hydrated tree should be wrapped in React.StrictMode */
|
|
121
|
+
strictMode?: boolean;
|
|
122
|
+
/** App version for prefetch version mismatch detection */
|
|
123
|
+
version?: string;
|
|
124
|
+
/**
|
|
125
|
+
* App-shell ref, read through on each render so renderSegments and the
|
|
126
|
+
* NavigationProvider see rootLayout/basename/version without closing over a
|
|
127
|
+
* stale snapshot. Set once from the initial payload and not swapped within a
|
|
128
|
+
* session: a cross-app navigation is a full document load (X-RSC-Reload), so
|
|
129
|
+
* the target app establishes its own shell on load. Theme, warmup, and
|
|
130
|
+
* prefetch TTL are document-lifetime too (see AppShell).
|
|
131
|
+
*/
|
|
132
|
+
appShellRef?: import("./app-shell.js").AppShellRef;
|
|
110
133
|
}
|
|
111
134
|
|
|
112
135
|
// Module-level state for the initialized app
|
|
113
136
|
let browserAppContext: BrowserAppContext | null = null;
|
|
114
137
|
|
|
115
138
|
/**
|
|
116
|
-
* Initialize the browser app. Must be called before rendering
|
|
139
|
+
* Initialize the browser app. Must be called before rendering Rango.
|
|
117
140
|
*
|
|
118
141
|
* This function:
|
|
119
142
|
* - Loads the initial RSC payload from the stream
|
|
@@ -122,18 +145,26 @@ let browserAppContext: BrowserAppContext | null = null;
|
|
|
122
145
|
* - Configures HMR support
|
|
123
146
|
*/
|
|
124
147
|
export async function initBrowserApp(
|
|
125
|
-
options: InitBrowserAppOptions
|
|
148
|
+
options: InitBrowserAppOptions,
|
|
126
149
|
): Promise<BrowserAppContext> {
|
|
127
|
-
const {
|
|
150
|
+
const {
|
|
151
|
+
rscStream,
|
|
152
|
+
deps,
|
|
153
|
+
storeOptions,
|
|
154
|
+
linkInterception = true,
|
|
155
|
+
themeConfig,
|
|
156
|
+
initialTheme,
|
|
157
|
+
} = options;
|
|
128
158
|
|
|
129
|
-
// Load initial payload from SSR-injected __FLIGHT_DATA__
|
|
130
159
|
const initialPayload =
|
|
131
160
|
await deps.createFromReadableStream<RscPayload>(rscStream);
|
|
132
161
|
|
|
133
162
|
// Extract themeConfig and initialTheme from payload if not explicitly provided
|
|
134
163
|
// This allows virtual entries to work without importing the router
|
|
135
|
-
const effectiveThemeConfig =
|
|
136
|
-
|
|
164
|
+
const effectiveThemeConfig =
|
|
165
|
+
themeConfig ?? initialPayload.metadata?.themeConfig ?? null;
|
|
166
|
+
const effectiveInitialTheme =
|
|
167
|
+
initialTheme ?? initialPayload.metadata?.initialTheme;
|
|
137
168
|
|
|
138
169
|
// Get initial segments and compute history key from current URL
|
|
139
170
|
const initialSegments = (initialPayload.metadata?.segments ??
|
|
@@ -149,20 +180,29 @@ export async function initBrowserApp(
|
|
|
149
180
|
...(storeOptions?.cacheSize && { cacheSize: storeOptions.cacheSize }),
|
|
150
181
|
});
|
|
151
182
|
|
|
183
|
+
// Register the active store on the module-level handle and wire the
|
|
184
|
+
// jar-divergence observer before any getRangoState() read can detect a
|
|
185
|
+
// cross-tab/server rotation. There is no global store singleton, so this
|
|
186
|
+
// handle is the live reference.
|
|
187
|
+
registerNavigationStore(store);
|
|
188
|
+
|
|
189
|
+
// Seed router identity from the initial SSR payload so the first
|
|
190
|
+
// cross-app SPA navigation can detect the app switch.
|
|
191
|
+
if (initialPayload.metadata?.routerId) {
|
|
192
|
+
store.setRouterId?.(initialPayload.metadata.routerId);
|
|
193
|
+
}
|
|
194
|
+
|
|
152
195
|
// Create event controller for reactive state management
|
|
153
196
|
const eventController = createEventController({
|
|
154
197
|
initialLocation: new URL(window.location.href),
|
|
155
198
|
});
|
|
156
199
|
|
|
157
|
-
// Initialize segments state BEFORE hydration to avoid mismatch
|
|
158
|
-
initSegmentsSync(initialPayload.metadata?.matched, initialPayload.metadata?.pathname);
|
|
159
|
-
|
|
160
|
-
// Initialize theme config for MetaTags (must match SSR state)
|
|
161
|
-
initThemeConfigSync(effectiveThemeConfig);
|
|
162
|
-
|
|
163
200
|
// Initialize event controller with segment order (even without handles)
|
|
164
201
|
eventController.setHandleData({}, initialPayload.metadata?.matched);
|
|
165
202
|
|
|
203
|
+
// Initialize route params
|
|
204
|
+
eventController.setParams(initialPayload.metadata?.params ?? {});
|
|
205
|
+
|
|
166
206
|
// Initialize handle data from initial payload BEFORE hydration
|
|
167
207
|
// This ensures useHandle returns correct data during hydration to avoid mismatch
|
|
168
208
|
// The handles property is an async generator that yields on each push
|
|
@@ -172,28 +212,73 @@ export async function initBrowserApp(
|
|
|
172
212
|
for await (const handleData of handlesGenerator) {
|
|
173
213
|
lastHandleData = handleData;
|
|
174
214
|
}
|
|
175
|
-
// Initialize
|
|
176
|
-
eventController.setHandleData(
|
|
177
|
-
|
|
215
|
+
// Initialize event controller with initial handle state before hydration.
|
|
216
|
+
eventController.setHandleData(
|
|
217
|
+
lastHandleData,
|
|
218
|
+
initialPayload.metadata?.matched,
|
|
219
|
+
);
|
|
178
220
|
|
|
179
221
|
// Update the initial cache entry with the processed handleData
|
|
180
222
|
// The cache entry was created by createNavigationStore but without handleData
|
|
181
223
|
store.updateCacheHandleData(initialHistoryKey, lastHandleData);
|
|
182
224
|
}
|
|
183
225
|
|
|
184
|
-
|
|
185
226
|
// Create composable utilities
|
|
186
227
|
const client = createNavigationClient(deps);
|
|
187
228
|
|
|
188
|
-
//
|
|
189
|
-
|
|
229
|
+
// Capture the per-router app-shell. rootLayout, basename, and version live
|
|
230
|
+
// here and are read through the ref at call time rather than closed over.
|
|
231
|
+
// It is set once from the initial payload and not swapped within a session:
|
|
232
|
+
// a cross-app navigation is a full document load (X-RSC-Reload), so the
|
|
233
|
+
// target app establishes its own shell on load.
|
|
190
234
|
const version = initialPayload.metadata?.version;
|
|
235
|
+
const appShellRef = createAppShellRef({
|
|
236
|
+
routerId: initialPayload.metadata?.routerId,
|
|
237
|
+
rootLayout: initialPayload.metadata?.rootLayout,
|
|
238
|
+
basename: initialPayload.metadata?.basename,
|
|
239
|
+
version,
|
|
240
|
+
});
|
|
191
241
|
|
|
192
|
-
//
|
|
242
|
+
// Initialize the rango state cookie for cache invalidation. The build version
|
|
243
|
+
// busts cached prefetches on deploy; the server-resolved cookie name
|
|
244
|
+
// namespaces the cookie so sibling apps on the same origin don't collide
|
|
245
|
+
// (falls back to the bare default prefix if metadata lacks the name).
|
|
246
|
+
initRangoState(version ?? "0", initialPayload.metadata?.stateCookieName);
|
|
247
|
+
setAppVersion(version);
|
|
248
|
+
|
|
249
|
+
// Initialize the in-memory prefetch cache (TTL + max size) and the prefetch
|
|
250
|
+
// queue concurrency from server config. A TTL of 0 disables the cache;
|
|
251
|
+
// undefined values fall back to the module defaults.
|
|
252
|
+
const prefetchCacheTTL = initialPayload.metadata?.prefetchCacheTTL;
|
|
253
|
+
const prefetchCacheSize = initialPayload.metadata?.prefetchCacheSize;
|
|
254
|
+
if (prefetchCacheTTL !== undefined || prefetchCacheSize !== undefined) {
|
|
255
|
+
initPrefetchCache(prefetchCacheTTL, prefetchCacheSize);
|
|
256
|
+
}
|
|
257
|
+
const prefetchConcurrency = initialPayload.metadata?.prefetchConcurrency;
|
|
258
|
+
if (prefetchConcurrency !== undefined) {
|
|
259
|
+
setPrefetchConcurrency(prefetchConcurrency);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Wire the RSC decoder so prefetches decode eagerly and warm the route's
|
|
263
|
+
// client chunks (same createFromFetch the navigation client uses).
|
|
264
|
+
setPrefetchDecoder((response) => deps.createFromFetch<RscPayload>(response));
|
|
265
|
+
|
|
266
|
+
// Create a bound renderSegments that reads rootLayout through the shell ref.
|
|
267
|
+
// The shell is set once at init and not swapped within a session (a cross-app
|
|
268
|
+
// navigation is a full document load), so this always renders this app's
|
|
269
|
+
// Document; reading through the ref just avoids closing over a stale value.
|
|
193
270
|
const renderSegments = (
|
|
194
271
|
segments: ResolvedSegment[],
|
|
195
|
-
options?: RenderSegmentsOptions
|
|
196
|
-
) =>
|
|
272
|
+
options?: RenderSegmentsOptions,
|
|
273
|
+
) =>
|
|
274
|
+
baseRenderSegments(segments, {
|
|
275
|
+
...options,
|
|
276
|
+
rootLayout: appShellRef.get().rootLayout,
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
// Lazy reference for navigation bridge — the action bridge is created first
|
|
280
|
+
// but may need to trigger SPA navigation for action redirects.
|
|
281
|
+
let navigateFn: ((url: string, options?: any) => Promise<void>) | null = null;
|
|
197
282
|
|
|
198
283
|
// Setup server action bridge
|
|
199
284
|
const actionBridge = createServerActionBridge({
|
|
@@ -203,7 +288,19 @@ export async function initBrowserApp(
|
|
|
203
288
|
deps,
|
|
204
289
|
onUpdate: (update) => store.emitUpdate(update),
|
|
205
290
|
renderSegments,
|
|
206
|
-
|
|
291
|
+
onNavigate: (url, options) => {
|
|
292
|
+
if (!navigateFn) {
|
|
293
|
+
// Navigation bridge not wired yet: hard-navigate, but re-validate
|
|
294
|
+
// same-origin defensively so this init-window fallback cannot become an
|
|
295
|
+
// open redirect (the normal path validates inside the navigation bridge).
|
|
296
|
+
const safe = validateRedirectOrigin(url, window.location.origin);
|
|
297
|
+
if (safe) {
|
|
298
|
+
window.location.href = safe;
|
|
299
|
+
}
|
|
300
|
+
return Promise.resolve();
|
|
301
|
+
}
|
|
302
|
+
return navigateFn(url, options);
|
|
303
|
+
},
|
|
207
304
|
});
|
|
208
305
|
actionBridge.register();
|
|
209
306
|
|
|
@@ -214,9 +311,12 @@ export async function initBrowserApp(
|
|
|
214
311
|
client,
|
|
215
312
|
onUpdate: (update) => store.emitUpdate(update),
|
|
216
313
|
renderSegments,
|
|
217
|
-
version,
|
|
314
|
+
version: version,
|
|
218
315
|
});
|
|
219
316
|
|
|
317
|
+
// Connect action redirect → navigation bridge (now that both are initialized)
|
|
318
|
+
navigateFn = (url, options) => navigationBridge.navigate(url, options);
|
|
319
|
+
|
|
220
320
|
// Optionally enable global link interception
|
|
221
321
|
if (linkInterception) {
|
|
222
322
|
navigationBridge.registerLinkInterception();
|
|
@@ -225,52 +325,157 @@ export async function initBrowserApp(
|
|
|
225
325
|
// Build initial tree with rootLayout
|
|
226
326
|
const initialTree = renderSegments(initialPayload.metadata!.segments);
|
|
227
327
|
|
|
228
|
-
// Setup HMR
|
|
328
|
+
// Setup HMR with debounce — burst saves (format-on-save, rapid edits)
|
|
329
|
+
// fire many rsc:update events in quick succession. Without debouncing,
|
|
330
|
+
// each event triggers a fetchPartial() which on slow routes can pile up
|
|
331
|
+
// and overwhelm the worker (cross-request promise issues, 500s).
|
|
229
332
|
if (import.meta.hot) {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
const handle = eventController.startNavigation(window.location.href, {
|
|
234
|
-
replace: true,
|
|
235
|
-
});
|
|
236
|
-
const streamingToken = handle.startStreaming();
|
|
237
|
-
|
|
238
|
-
try {
|
|
239
|
-
const { payload, streamComplete } = await client.fetchPartial({
|
|
240
|
-
targetUrl: window.location.href,
|
|
241
|
-
segmentIds: [],
|
|
242
|
-
previousUrl: store.getSegmentState().currentUrl,
|
|
243
|
-
hmr: true,
|
|
244
|
-
});
|
|
333
|
+
let hmrTimer: ReturnType<typeof setTimeout> | null = null;
|
|
334
|
+
let hmrAbort: AbortController | null = null;
|
|
245
335
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
336
|
+
import.meta.hot.on("rsc:update", () => {
|
|
337
|
+
// Cancel any pending debounce timer
|
|
338
|
+
if (hmrTimer !== null) {
|
|
339
|
+
clearTimeout(hmrTimer);
|
|
340
|
+
}
|
|
249
341
|
|
|
250
|
-
|
|
251
|
-
|
|
342
|
+
// Abort any in-flight HMR fetch so it doesn't race with the next one
|
|
343
|
+
if (hmrAbort) {
|
|
344
|
+
hmrAbort.abort();
|
|
345
|
+
hmrAbort = null;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Debounce: wait 200ms of quiet before fetching
|
|
349
|
+
hmrTimer = setTimeout(async () => {
|
|
350
|
+
hmrTimer = null;
|
|
351
|
+
|
|
352
|
+
// Don't interrupt an active user navigation — startNavigation()
|
|
353
|
+
// would abort it and refetch the old URL (window.location.href
|
|
354
|
+
// hasn't updated yet). The user's navigation will pick up the
|
|
355
|
+
// new server code when it completes. isNavigating covers the
|
|
356
|
+
// full lifecycle (fetching + streaming, before commit) without
|
|
357
|
+
// blocking on server actions.
|
|
358
|
+
if (eventController.getState().isNavigating) {
|
|
359
|
+
console.log("[Rango] HMR: Skipping — navigation in progress");
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
252
362
|
|
|
253
|
-
|
|
254
|
-
store.setHistoryKey(historyKey);
|
|
255
|
-
const currentHandleData = eventController.getHandleState().data;
|
|
256
|
-
store.cacheSegmentsForHistory(historyKey, segments, currentHandleData);
|
|
363
|
+
console.log("[Rango] HMR: Server update, refetching RSC");
|
|
257
364
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
365
|
+
const abort = new AbortController();
|
|
366
|
+
hmrAbort = abort;
|
|
367
|
+
|
|
368
|
+
const handle = eventController.startNavigation(window.location.href, {
|
|
369
|
+
replace: true,
|
|
370
|
+
});
|
|
371
|
+
const streamingToken = handle.startStreaming();
|
|
372
|
+
|
|
373
|
+
const interceptSourceUrl = store.getInterceptSourceUrl();
|
|
374
|
+
|
|
375
|
+
try {
|
|
376
|
+
const { payload, streamComplete } = await client.fetchPartial({
|
|
377
|
+
targetUrl: window.location.href,
|
|
378
|
+
segmentIds: [],
|
|
379
|
+
previousUrl: store.getSegmentState().currentUrl,
|
|
380
|
+
interceptSourceUrl: interceptSourceUrl || undefined,
|
|
381
|
+
routerId: store.getRouterId?.(),
|
|
382
|
+
hmr: true,
|
|
383
|
+
signal: abort.signal,
|
|
261
384
|
});
|
|
262
|
-
}
|
|
263
385
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
386
|
+
if (abort.signal.aborted) return;
|
|
387
|
+
|
|
388
|
+
// If the server returned a non-RSC response (404, 500 without
|
|
389
|
+
// error boundary), the payload won't have valid metadata.
|
|
390
|
+
// Reload to recover rather than leaving the page stale.
|
|
391
|
+
if (!payload.metadata) {
|
|
392
|
+
throw new Error("HMR refetch returned invalid payload");
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// Update version BEFORE rebuilding state so that
|
|
396
|
+
// clearHistoryCache() runs first, then the fresh segment
|
|
397
|
+
// cache entry we create below survives.
|
|
398
|
+
//
|
|
399
|
+
// Compare against the bridge's live version, not the init-time
|
|
400
|
+
// `version` const: after the first HMR bump the const is stale, so a
|
|
401
|
+
// later update with an unchanged version would otherwise re-clear the
|
|
402
|
+
// cache and re-broadcast across tabs/apps. The live read fires only
|
|
403
|
+
// on a genuine version change.
|
|
404
|
+
const newVersion = payload.metadata.version;
|
|
405
|
+
const currentVersion = navigationBridge.getVersion();
|
|
406
|
+
if (newVersion && newVersion !== currentVersion) {
|
|
407
|
+
console.log(
|
|
408
|
+
"[Rango] HMR: version changed",
|
|
409
|
+
currentVersion,
|
|
410
|
+
"→",
|
|
411
|
+
newVersion,
|
|
412
|
+
"clearing caches",
|
|
413
|
+
);
|
|
414
|
+
navigationBridge.updateVersion(newVersion);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// Apply only partial segment updates. A non-partial payload during
|
|
418
|
+
// HMR is transient: the worker route table is still rebuilding after
|
|
419
|
+
// the edit, so the URL momentarily resolves to not-found/catch-all.
|
|
420
|
+
// Skip it -- the debounced follow-up refetch returns the settled
|
|
421
|
+
// route's partial payload and renders it below. We never reload here:
|
|
422
|
+
// a paramless document GET would run the SSR path and surface the
|
|
423
|
+
// not-found page during that same transient.
|
|
424
|
+
if (payload.metadata?.isPartial) {
|
|
425
|
+
const segments = payload.metadata.segments || [];
|
|
426
|
+
const matched = payload.metadata.matched || [];
|
|
427
|
+
|
|
428
|
+
// Derive intercept state from the returned payload, not the
|
|
429
|
+
// pre-fetch store snapshot. If the HMR edit removed intercept
|
|
430
|
+
// behavior, the response won't contain intercept segments.
|
|
431
|
+
const responseIsIntercept = segments.some(isInterceptSegment);
|
|
432
|
+
|
|
433
|
+
// Sync store intercept state with what the server returned
|
|
434
|
+
if (!responseIsIntercept && interceptSourceUrl) {
|
|
435
|
+
store.setInterceptSourceUrl(null);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
store.setSegmentIds(matched);
|
|
439
|
+
store.setCurrentUrl(window.location.href);
|
|
440
|
+
|
|
441
|
+
const historyKey = generateHistoryKey(window.location.href, {
|
|
442
|
+
intercept: responseIsIntercept,
|
|
443
|
+
});
|
|
444
|
+
store.setHistoryKey(historyKey);
|
|
445
|
+
const currentHandleData = eventController.getHandleState().data;
|
|
446
|
+
store.cacheSegmentsForHistory(
|
|
447
|
+
historyKey,
|
|
448
|
+
segments,
|
|
449
|
+
currentHandleData,
|
|
450
|
+
);
|
|
451
|
+
|
|
452
|
+
const { main, intercept } = splitInterceptSegments(segments);
|
|
453
|
+
store.emitUpdate({
|
|
454
|
+
root: renderSegments(main, {
|
|
455
|
+
interceptSegments: intercept.length > 0 ? intercept : undefined,
|
|
456
|
+
}),
|
|
457
|
+
metadata: payload.metadata,
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
await streamComplete;
|
|
462
|
+
handle.complete(new URL(window.location.href));
|
|
463
|
+
console.log("[Rango] HMR: RSC stream complete");
|
|
464
|
+
} catch (err) {
|
|
465
|
+
if (abort.signal.aborted) return;
|
|
466
|
+
console.warn("[Rango] HMR: Refetch failed, reloading page", err);
|
|
467
|
+
window.location.reload();
|
|
468
|
+
return;
|
|
469
|
+
} finally {
|
|
470
|
+
if (hmrAbort === abort) hmrAbort = null;
|
|
471
|
+
streamingToken.end();
|
|
472
|
+
handle[Symbol.dispose]();
|
|
473
|
+
}
|
|
474
|
+
}, 200);
|
|
270
475
|
});
|
|
271
476
|
}
|
|
272
477
|
|
|
273
|
-
// Store context for
|
|
478
|
+
// Store context for Rango component
|
|
274
479
|
const context: BrowserAppContext = {
|
|
275
480
|
store,
|
|
276
481
|
eventController,
|
|
@@ -280,6 +485,9 @@ export async function initBrowserApp(
|
|
|
280
485
|
themeConfig: effectiveThemeConfig,
|
|
281
486
|
initialTheme: effectiveInitialTheme,
|
|
282
487
|
warmupEnabled: initialPayload.metadata?.warmupEnabled ?? true,
|
|
488
|
+
strictMode: initialPayload.metadata?.strictMode ?? true,
|
|
489
|
+
version,
|
|
490
|
+
appShellRef,
|
|
283
491
|
};
|
|
284
492
|
browserAppContext = context;
|
|
285
493
|
|
|
@@ -292,7 +500,7 @@ export async function initBrowserApp(
|
|
|
292
500
|
export function getBrowserAppContext(): BrowserAppContext {
|
|
293
501
|
if (!browserAppContext) {
|
|
294
502
|
throw new Error(
|
|
295
|
-
"
|
|
503
|
+
"Rango: initBrowserApp() must be called before rendering Rango",
|
|
296
504
|
);
|
|
297
505
|
}
|
|
298
506
|
return browserAppContext;
|
|
@@ -306,18 +514,18 @@ export function resetBrowserAppContext(): void {
|
|
|
306
514
|
}
|
|
307
515
|
|
|
308
516
|
/**
|
|
309
|
-
* Props for the
|
|
517
|
+
* Props for the Rango component
|
|
310
518
|
*/
|
|
311
|
-
export interface
|
|
519
|
+
export interface RangoProps {}
|
|
312
520
|
|
|
313
521
|
/**
|
|
314
|
-
*
|
|
522
|
+
* Rango component - renders the RSC router with all internal wiring.
|
|
315
523
|
*
|
|
316
524
|
* Must be called after initBrowserApp() has completed.
|
|
317
525
|
*
|
|
318
526
|
* @example
|
|
319
527
|
* ```tsx
|
|
320
|
-
* import { initBrowserApp,
|
|
528
|
+
* import { initBrowserApp, Rango } from "rsc-router/browser";
|
|
321
529
|
* import { rscStream } from "rsc-html-stream/client";
|
|
322
530
|
* import * as rscBrowser from "@vitejs/plugin-rsc/browser";
|
|
323
531
|
*
|
|
@@ -327,26 +535,46 @@ export interface RSCRouterProps {}
|
|
|
327
535
|
* hydrateRoot(
|
|
328
536
|
* document,
|
|
329
537
|
* <React.StrictMode>
|
|
330
|
-
* <
|
|
538
|
+
* <Rango />
|
|
331
539
|
* </React.StrictMode>
|
|
332
540
|
* );
|
|
333
541
|
* }
|
|
334
542
|
* main();
|
|
335
543
|
* ```
|
|
336
544
|
*/
|
|
337
|
-
export function
|
|
338
|
-
const {
|
|
339
|
-
|
|
545
|
+
export function Rango(_props: RangoProps): React.ReactElement {
|
|
546
|
+
const {
|
|
547
|
+
store,
|
|
548
|
+
eventController,
|
|
549
|
+
bridge,
|
|
550
|
+
initialPayload,
|
|
551
|
+
initialTree,
|
|
552
|
+
themeConfig,
|
|
553
|
+
initialTheme,
|
|
554
|
+
warmupEnabled,
|
|
555
|
+
version,
|
|
556
|
+
appShellRef,
|
|
557
|
+
} = getBrowserAppContext();
|
|
558
|
+
|
|
559
|
+
// Signal that the React tree has hydrated. useEffect only fires after
|
|
560
|
+
// hydration completes, so this attribute is a stable readiness marker
|
|
561
|
+
// that does not depend on React internals like __reactFiber.
|
|
562
|
+
React.useEffect(() => {
|
|
563
|
+
document.documentElement.dataset.hydrated = "";
|
|
564
|
+
}, []);
|
|
340
565
|
|
|
341
566
|
return (
|
|
342
567
|
<NavigationProvider
|
|
343
568
|
store={store}
|
|
344
569
|
eventController={eventController}
|
|
345
|
-
initialPayload={{
|
|
570
|
+
initialPayload={{ root: initialTree, metadata: initialPayload.metadata! }}
|
|
346
571
|
bridge={bridge}
|
|
347
572
|
themeConfig={themeConfig}
|
|
348
573
|
initialTheme={initialTheme}
|
|
349
574
|
warmupEnabled={warmupEnabled}
|
|
575
|
+
version={version}
|
|
576
|
+
basename={initialPayload.metadata?.basename}
|
|
577
|
+
appShellRef={appShellRef}
|
|
350
578
|
/>
|
|
351
579
|
);
|
|
352
580
|
}
|