@rangojs/router 0.0.0-experimental.bd6e11bc → 0.0.0-experimental.bdaf10aa
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 +296 -887
- package/dist/bin/rango.js +459 -91
- package/dist/testing/vitest.js +36 -2
- package/dist/vite/index.js +1708 -414
- package/package.json +35 -10
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +82 -5
- package/skills/bundle-analysis/SKILL.md +2 -2
- package/skills/cache-guide/SKILL.md +14 -9
- package/skills/caching/SKILL.md +221 -12
- 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 +83 -2
- 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 +11 -3
- package/skills/fonts/SKILL.md +1 -1
- package/skills/handler-use/SKILL.md +9 -9
- package/skills/hooks/SKILL.md +73 -900
- 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 +84 -7
- package/skills/i18n/SKILL.md +1 -1
- package/skills/intercept/SKILL.md +51 -17
- package/skills/layout/SKILL.md +38 -16
- package/skills/links/SKILL.md +1 -1
- package/skills/loader/SKILL.md +48 -20
- package/skills/middleware/SKILL.md +11 -5
- package/skills/migrate-nextjs/SKILL.md +203 -20
- package/skills/migrate-react-router/SKILL.md +59 -675
- 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 +3 -3
- package/skills/observability/SKILL.md +70 -5
- package/skills/parallel/SKILL.md +32 -8
- package/skills/ppr/SKILL.md +622 -0
- package/skills/prerender/SKILL.md +59 -28
- package/skills/rango/SKILL.md +124 -50
- package/skills/response-routes/SKILL.md +78 -46
- package/skills/route/SKILL.md +85 -6
- package/skills/router-setup/SKILL.md +41 -6
- package/skills/scripts/SKILL.md +179 -0
- package/skills/server-actions/SKILL.md +28 -3
- package/skills/shell-manifest/SKILL.md +185 -0
- package/skills/streams-and-websockets/SKILL.md +1 -1
- package/skills/tailwind/SKILL.md +28 -4
- package/skills/testing/SKILL.md +68 -654
- 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 -918
- 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 +47 -17
- package/skills/vercel/SKILL.md +128 -0
- package/skills/view-transitions/SKILL.md +44 -1
- package/src/__augment-tests__/augmented.check.ts +2 -3
- package/src/__internal.ts +0 -65
- package/src/browser/action-coordinator.ts +1 -1
- package/src/browser/action-fence.ts +47 -0
- package/src/browser/app-shell.ts +14 -27
- package/src/browser/connection-warmup.ts +134 -0
- package/src/browser/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +178 -100
- 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 +81 -68
- package/src/browser/navigation-client.ts +115 -70
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +153 -88
- package/src/browser/navigation-transaction.ts +0 -32
- package/src/browser/network-error-handler.ts +34 -7
- package/src/browser/partial-update.ts +157 -144
- package/src/browser/prefetch/cache.ts +148 -81
- package/src/browser/prefetch/fetch.ts +231 -51
- package/src/browser/prefetch/queue.ts +25 -7
- package/src/browser/rango-state.ts +157 -115
- package/src/browser/react/Link.tsx +40 -7
- package/src/browser/react/NavigationProvider.tsx +140 -99
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/filter-segment-order.ts +17 -2
- package/src/browser/react/index.ts +0 -51
- package/src/browser/react/location-state-shared.ts +14 -15
- package/src/browser/react/location-state.ts +0 -1
- package/src/browser/react/use-action.ts +6 -15
- package/src/browser/react/use-handle.ts +0 -5
- 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 +10 -5
- package/src/browser/react/use-params.ts +0 -2
- package/src/browser/react/use-router.ts +6 -4
- package/src/browser/react/use-search-params.ts +0 -5
- package/src/browser/react/use-segments.ts +0 -13
- package/src/browser/response-adapter.ts +74 -8
- package/src/browser/rsc-router.tsx +97 -22
- package/src/browser/scroll-restoration.ts +15 -8
- package/src/browser/segment-reconciler.ts +31 -21
- package/src/browser/server-action-bridge.ts +216 -38
- package/src/browser/types.ts +94 -22
- package/src/browser/validate-redirect-origin.ts +43 -16
- package/src/build/generate-manifest.ts +155 -131
- package/src/build/generate-route-types.ts +1 -1
- package/src/build/index.ts +11 -5
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +152 -22
- package/src/build/route-types/ast-route-extraction.ts +15 -8
- package/src/build/route-types/codegen.ts +12 -1
- package/src/build/route-types/include-resolution.ts +455 -61
- package/src/build/route-types/param-extraction.ts +6 -3
- package/src/build/route-types/per-module-writer.ts +15 -2
- package/src/build/route-types/router-processing.ts +77 -41
- package/src/build/route-types/source-scan.ts +105 -7
- package/src/build/runtime-discovery.ts +4 -1
- 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 +454 -101
- package/src/cache/cache-scope.ts +159 -54
- 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 +2170 -377
- 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 +194 -99
- package/src/cache/vercel/index.ts +11 -0
- package/src/cache/vercel/vercel-cache-store.ts +1132 -0
- package/src/client.rsc.tsx +39 -22
- package/src/client.tsx +28 -58
- 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 +13 -1
- package/src/decode-loader-results.ts +18 -2
- package/src/defer.ts +185 -0
- package/src/deps/ssr.ts +0 -1
- package/src/encode-kv.ts +49 -0
- package/src/errors.ts +0 -3
- package/src/escape-script.ts +52 -0
- package/src/handle.ts +57 -40
- 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 +7 -0
- package/src/host/pattern-matcher.ts +23 -52
- package/src/host/router.ts +1 -65
- package/src/host/testing.ts +40 -27
- package/src/host/types.ts +6 -2
- package/src/href-client.ts +7 -12
- package/src/index.rsc.ts +88 -8
- package/src/index.ts +90 -16
- package/src/internal-debug.ts +11 -10
- package/src/loader.rsc.ts +19 -9
- package/src/loader.ts +12 -4
- 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 +75 -7
- 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 +25 -0
- package/src/root-error-boundary.tsx +1 -19
- package/src/route-content-wrapper.tsx +13 -49
- package/src/route-definition/dsl-helpers.ts +60 -53
- package/src/route-definition/helper-factories.ts +0 -2
- package/src/route-definition/helpers-types.ts +46 -46
- package/src/route-definition/index.ts +1 -2
- package/src/route-definition/redirect.ts +44 -11
- package/src/route-definition/resolve-handler-use.ts +6 -1
- package/src/route-definition/use-item-types.ts +3 -6
- package/src/route-map-builder.ts +41 -20
- package/src/route-types.ts +0 -5
- package/src/router/content-negotiation.ts +58 -23
- package/src/router/error-handling.ts +44 -17
- package/src/router/find-match.ts +129 -30
- package/src/router/handler-context.ts +6 -1
- package/src/router/instrument.ts +355 -0
- package/src/router/intercept-resolution.ts +35 -2
- package/src/router/lazy-includes.ts +79 -56
- package/src/router/loader-resolution.ts +151 -73
- package/src/router/logging.ts +0 -6
- package/src/router/manifest.ts +74 -40
- package/src/router/match-api.ts +76 -52
- package/src/router/match-context.ts +0 -22
- package/src/router/match-handlers.ts +181 -178
- package/src/router/match-middleware/background-revalidation.ts +40 -24
- package/src/router/match-middleware/cache-lookup.ts +115 -194
- package/src/router/match-middleware/cache-store.ts +61 -50
- 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 +36 -67
- package/src/router/metrics.ts +0 -34
- package/src/router/middleware-types.ts +0 -116
- package/src/router/middleware.ts +231 -120
- 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 +99 -152
- package/src/router/prefetch-cache-ttl.ts +51 -0
- package/src/router/prefetch-limits.ts +37 -0
- package/src/router/prerender-match.ts +111 -66
- package/src/router/preview-match.ts +3 -1
- package/src/router/request-classification.ts +47 -42
- package/src/router/revalidation.ts +75 -81
- package/src/router/route-snapshot.ts +14 -3
- package/src/router/router-context.ts +6 -29
- package/src/router/router-interfaces.ts +70 -8
- package/src/router/router-options.ts +126 -4
- package/src/router/segment-resolution/fresh.ts +104 -80
- package/src/router/segment-resolution/helpers.ts +86 -6
- package/src/router/segment-resolution/loader-cache.ts +155 -39
- package/src/router/segment-resolution/loader-mask.ts +60 -0
- package/src/router/segment-resolution/loader-snapshot.ts +259 -0
- package/src/router/segment-resolution/mask-nested.ts +83 -0
- package/src/router/segment-resolution/revalidation.ts +215 -304
- 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 +35 -15
- 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 +54 -35
- package/src/router/telemetry-otel.ts +160 -200
- package/src/router/telemetry.ts +9 -23
- package/src/router/timeout.ts +0 -20
- package/src/router/tracing.ts +215 -0
- package/src/router/trie-matching.ts +171 -64
- package/src/router/types.ts +1 -63
- package/src/router/url-params.ts +13 -5
- package/src/router.ts +119 -48
- package/src/rsc/full-payload.ts +70 -0
- package/src/rsc/handler-context.ts +1 -0
- package/src/rsc/handler.ts +267 -152
- package/src/rsc/helpers.ts +78 -4
- package/src/rsc/index.ts +1 -4
- 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 +11 -15
- package/src/rsc/progressive-enhancement.ts +120 -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 +58 -141
- package/src/rsc/rsc-rendering.ts +492 -49
- package/src/rsc/runtime-warnings.ts +14 -0
- package/src/rsc/server-action.ts +268 -82
- package/src/rsc/shell-capture.ts +1190 -0
- package/src/rsc/shell-serve.ts +181 -0
- package/src/rsc/transition-gate.ts +89 -0
- package/src/rsc/types.ts +45 -3
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +31 -26
- package/src/segment-loader-promise.ts +49 -4
- package/src/segment-system.tsx +260 -95
- package/src/server/context.ts +99 -9
- package/src/server/cookie-parse.ts +32 -0
- package/src/server/cookie-store.ts +125 -2
- package/src/server/handle-store.ts +21 -38
- package/src/server/loader-registry.ts +33 -42
- package/src/server/request-context.ts +379 -138
- package/src/ssr/index.tsx +491 -182
- package/src/ssr/inject-rsc-eager.ts +167 -0
- package/src/ssr/ssr-root.tsx +228 -0
- package/src/static-handler.ts +10 -13
- package/src/testing/cache-status.ts +44 -48
- package/src/testing/collect-handle.ts +14 -31
- package/src/testing/dispatch.ts +533 -160
- package/src/testing/e2e/fixture.ts +45 -11
- package/src/testing/e2e/index.ts +1 -22
- package/src/testing/e2e/matchers.ts +0 -16
- package/src/testing/e2e/parity.ts +85 -4
- package/src/testing/e2e/server.ts +12 -0
- package/src/testing/flight-matchers.ts +7 -14
- package/src/testing/flight-normalize.ts +11 -0
- package/src/testing/flight-runtime.d.ts +36 -0
- package/src/testing/flight-tree.ts +682 -0
- package/src/testing/flight.entry.ts +30 -0
- package/src/testing/flight.ts +145 -70
- package/src/testing/generated-routes.ts +26 -50
- package/src/testing/index.ts +18 -19
- package/src/testing/internal/context.ts +184 -68
- 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 +134 -115
- package/src/testing/run-loader.ts +140 -51
- package/src/testing/run-middleware.ts +59 -33
- package/src/testing/run-transition-when.ts +164 -0
- package/src/testing/vitest-stubs/cloudflare-email.ts +1 -1
- package/src/testing/vitest-stubs/cloudflare-workers.ts +1 -1
- package/src/testing/vitest.ts +138 -16
- 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 +15 -15
- package/src/types/handler-context.ts +45 -15
- package/src/types/index.ts +2 -10
- package/src/types/loader-types.ts +6 -3
- package/src/types/request-scope.ts +8 -22
- package/src/types/route-config.ts +20 -52
- package/src/types/route-entry.ts +0 -6
- package/src/types/segments.ts +100 -13
- package/src/urls/include-helper.ts +10 -12
- package/src/urls/include-provider.ts +71 -0
- package/src/urls/index.ts +2 -8
- package/src/urls/path-helper-types.ts +52 -14
- package/src/urls/path-helper.ts +5 -54
- package/src/urls/pattern-types.ts +36 -0
- package/src/urls/type-extraction.ts +76 -42
- package/src/urls/urls-function.ts +0 -14
- package/src/use-loader.tsx +0 -186
- package/src/vercel/index.ts +11 -0
- package/src/vercel/tracing.ts +88 -0
- package/src/vite/discovery/bundle-postprocess.ts +2 -1
- package/src/vite/discovery/dev-prerender-cache.ts +117 -0
- package/src/vite/discovery/discover-routers.ts +34 -43
- package/src/vite/discovery/discovery-errors.ts +61 -0
- package/src/vite/discovery/prerender-collection.ts +33 -46
- package/src/vite/discovery/state.ts +12 -1
- package/src/vite/discovery/virtual-module-codegen.ts +1 -11
- package/src/vite/index.ts +9 -0
- package/src/vite/inject-client-debug.ts +88 -0
- package/src/vite/plugin-types.ts +143 -10
- package/src/vite/plugins/cjs-to-esm.ts +8 -12
- package/src/vite/plugins/client-ref-dedup.ts +0 -11
- package/src/vite/plugins/client-ref-hashing.ts +0 -10
- package/src/vite/plugins/cloudflare-protocol-stub.ts +0 -20
- package/src/vite/plugins/expose-action-id.ts +2 -73
- package/src/vite/plugins/expose-id-utils.ts +85 -56
- package/src/vite/plugins/expose-ids/export-analysis.ts +30 -43
- package/src/vite/plugins/expose-ids/handler-transform.ts +5 -31
- package/src/vite/plugins/expose-ids/loader-transform.ts +12 -20
- package/src/vite/plugins/expose-ids/router-transform.ts +98 -26
- package/src/vite/plugins/expose-internal-ids.ts +10 -1
- package/src/vite/plugins/performance-tracks.ts +0 -3
- package/src/vite/plugins/refresh-cmd.ts +1 -1
- package/src/vite/plugins/use-cache-transform.ts +21 -46
- package/src/vite/plugins/vercel-output.ts +384 -0
- package/src/vite/plugins/version-injector.ts +22 -27
- package/src/vite/plugins/version-plugin.ts +6 -66
- package/src/vite/plugins/virtual-entries.ts +137 -26
- package/src/vite/rango.ts +146 -135
- package/src/vite/router-discovery.ts +189 -48
- package/src/vite/utils/ast-handler-extract.ts +11 -20
- package/src/vite/utils/bundle-analysis.ts +6 -13
- package/src/vite/utils/client-chunks.ts +0 -6
- package/src/vite/utils/directive-prologue.ts +40 -0
- package/src/vite/utils/forward-user-plugins.ts +0 -22
- package/src/vite/utils/manifest-utils.ts +4 -75
- package/src/vite/utils/package-resolution.ts +1 -73
- package/src/vite/utils/prerender-utils.ts +71 -44
- package/src/vite/utils/shared-utils.ts +55 -37
- 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
package/src/browser/types.ts
CHANGED
|
@@ -14,7 +14,6 @@ import type { RenderSegmentsOptions } from "../segment-system.js";
|
|
|
14
14
|
export interface RscPayload<TMetadata = RscMetadata> {
|
|
15
15
|
metadata?: TMetadata;
|
|
16
16
|
returnValue?: ActionResult;
|
|
17
|
-
formState?: unknown;
|
|
18
17
|
}
|
|
19
18
|
|
|
20
19
|
/**
|
|
@@ -32,8 +31,10 @@ export type HandleData = Record<string, Record<string, unknown[]>>;
|
|
|
32
31
|
export interface RscMetadata {
|
|
33
32
|
pathname: string;
|
|
34
33
|
segments: ResolvedSegment[];
|
|
35
|
-
/** Router instance ID
|
|
36
|
-
*
|
|
34
|
+
/** Router instance ID — the current app's identity. A mismatch with the
|
|
35
|
+
* client's id (sent as _rsc_rid) is detected server-side and answered with
|
|
36
|
+
* X-RSC-Reload (full document load), so the client never swaps apps
|
|
37
|
+
* in-session; within a session this always equals the current app. */
|
|
37
38
|
routerId?: string;
|
|
38
39
|
isPartial?: boolean;
|
|
39
40
|
isError?: boolean;
|
|
@@ -69,6 +70,22 @@ export interface RscMetadata {
|
|
|
69
70
|
* Sent on initial render so the browser can configure its cache duration.
|
|
70
71
|
*/
|
|
71
72
|
prefetchCacheTTL?: number;
|
|
73
|
+
/**
|
|
74
|
+
* Max entries in the client-side in-memory prefetch cache (FIFO eviction).
|
|
75
|
+
* Sent on initial render so the browser can configure its cache capacity.
|
|
76
|
+
*/
|
|
77
|
+
prefetchCacheSize?: number;
|
|
78
|
+
/**
|
|
79
|
+
* Max concurrent speculative prefetch requests on the client.
|
|
80
|
+
* Sent on initial render so the browser can configure its prefetch queue.
|
|
81
|
+
*/
|
|
82
|
+
prefetchConcurrency?: number;
|
|
83
|
+
/**
|
|
84
|
+
* Server-resolved rango state cookie name (`{prefix}_{routerId}`). The client
|
|
85
|
+
* reads it verbatim and binds the rango state cookie to it; composition
|
|
86
|
+
* happens only server-side.
|
|
87
|
+
*/
|
|
88
|
+
stateCookieName?: string;
|
|
72
89
|
/**
|
|
73
90
|
* Theme configuration from router.
|
|
74
91
|
* Included when theme is enabled in router config.
|
|
@@ -83,8 +100,18 @@ export interface RscMetadata {
|
|
|
83
100
|
basename?: string;
|
|
84
101
|
/** Whether connection warmup is enabled */
|
|
85
102
|
warmupEnabled?: boolean;
|
|
86
|
-
/**
|
|
87
|
-
|
|
103
|
+
/**
|
|
104
|
+
* Whether the client should hydrate inside React.StrictMode. Carried on the
|
|
105
|
+
* initial full-render payload only; the browser entry reads it once at
|
|
106
|
+
* hydration. Defaults to true on the client when omitted.
|
|
107
|
+
*/
|
|
108
|
+
strictMode?: boolean;
|
|
109
|
+
/**
|
|
110
|
+
* Server-side redirect with optional state (for partial requests).
|
|
111
|
+
* `external: true` (from redirect(url, { external: true })) tells the client
|
|
112
|
+
* to hard-navigate to an off-host target instead of validating same-origin.
|
|
113
|
+
*/
|
|
114
|
+
redirect?: { url: string; external?: boolean };
|
|
88
115
|
/** Server-set location state to include in history.pushState */
|
|
89
116
|
locationState?: Record<string, unknown>;
|
|
90
117
|
}
|
|
@@ -185,6 +212,15 @@ export interface TrackedActionState {
|
|
|
185
212
|
result: unknown | null;
|
|
186
213
|
}
|
|
187
214
|
|
|
215
|
+
/**
|
|
216
|
+
* The value returned by {@link useAction} when called without a selector.
|
|
217
|
+
*
|
|
218
|
+
* This is the stable, public name for the action-state shape; consumers can
|
|
219
|
+
* name it in their own signatures (e.g. a wrapper hook). It aliases the
|
|
220
|
+
* internal {@link TrackedActionState}.
|
|
221
|
+
*/
|
|
222
|
+
export type ActionState = TrackedActionState;
|
|
223
|
+
|
|
188
224
|
/**
|
|
189
225
|
* Listener for action state changes
|
|
190
226
|
*
|
|
@@ -322,8 +358,14 @@ export interface RouterInstance {
|
|
|
322
358
|
replace(url: string, options?: RouterNavigateOptions): Promise<void>;
|
|
323
359
|
/** Refresh the current route (re-fetch server data, preserve client state) */
|
|
324
360
|
refresh(): Promise<void>;
|
|
325
|
-
/**
|
|
326
|
-
|
|
361
|
+
/**
|
|
362
|
+
* Prefetch a URL for faster client-side transition.
|
|
363
|
+
*
|
|
364
|
+
* Pass `{ key: ":source" }` to source-scope the prefetch cache entry (parity
|
|
365
|
+
* with `<Link prefetchKey=":source">`) when the target's response can differ
|
|
366
|
+
* by source page.
|
|
367
|
+
*/
|
|
368
|
+
prefetch(url: string, options?: { key?: ":source" }): void;
|
|
327
369
|
/** Go back in browser history */
|
|
328
370
|
back(): void;
|
|
329
371
|
/** Go forward in browser history */
|
|
@@ -415,6 +457,10 @@ export interface NavigationStore {
|
|
|
415
457
|
// History-based segment cache (for back/forward navigation and partial merging)
|
|
416
458
|
getHistoryKey(): string;
|
|
417
459
|
setHistoryKey(key: string): void;
|
|
460
|
+
/** Monotonic token of the most recently committed navigation. */
|
|
461
|
+
getNavInstance(): number;
|
|
462
|
+
/** Nav-instance token recorded on a cache entry (undefined if absent). */
|
|
463
|
+
getCacheEntryInstance(historyKey: string): number | undefined;
|
|
418
464
|
cacheSegmentsForHistory(
|
|
419
465
|
historyKey: string,
|
|
420
466
|
segments: ResolvedSegment[],
|
|
@@ -426,20 +472,44 @@ export interface NavigationStore {
|
|
|
426
472
|
stale: boolean;
|
|
427
473
|
handleData?: HandleData;
|
|
428
474
|
routerId?: string;
|
|
475
|
+
/**
|
|
476
|
+
* True when the entry's handle data is incomplete (a deferred Meta was
|
|
477
|
+
* still pending at navigate-away). A popstate return must revalidate with
|
|
478
|
+
* a FULL re-render so the server re-streams handles.
|
|
479
|
+
*/
|
|
480
|
+
handlesPending?: boolean;
|
|
429
481
|
}
|
|
430
482
|
| undefined;
|
|
431
483
|
hasHistoryCache(historyKey: string): boolean;
|
|
432
|
-
|
|
484
|
+
/**
|
|
485
|
+
* Update only the handleData (and optionally the stale / handlesPending flags)
|
|
486
|
+
* of an existing cache entry. When a flag is omitted the entry's current value
|
|
487
|
+
* is preserved. `stale=true` marks a single entry stale so a popstate return
|
|
488
|
+
* revalidates it; `handlesPending=true` additionally forces that revalidation
|
|
489
|
+
* to be a full re-render (so a deferred Meta re-streams).
|
|
490
|
+
*/
|
|
491
|
+
updateCacheHandleData(
|
|
492
|
+
historyKey: string,
|
|
493
|
+
handleData: HandleData,
|
|
494
|
+
stale?: boolean,
|
|
495
|
+
handlesPending?: boolean,
|
|
496
|
+
): void;
|
|
497
|
+
/**
|
|
498
|
+
* Owner-guarded variant of updateCacheHandleData: writes only when the entry
|
|
499
|
+
* is still owned by `ownerInstance`. Folds the caller's separate ownership
|
|
500
|
+
* probe and write into one historyCache scan for the per-yield streaming path.
|
|
501
|
+
*/
|
|
502
|
+
updateCacheHandleDataIfOwned(
|
|
503
|
+
historyKey: string,
|
|
504
|
+
handleData: HandleData,
|
|
505
|
+
ownerInstance: number,
|
|
506
|
+
stale?: boolean,
|
|
507
|
+
handlesPending?: boolean,
|
|
508
|
+
): void;
|
|
433
509
|
markCacheAsStale(): void;
|
|
510
|
+
markHistoryCacheStale(): void;
|
|
434
511
|
markCacheAsStaleAndBroadcast(): void;
|
|
435
512
|
clearHistoryCache(): void;
|
|
436
|
-
/**
|
|
437
|
-
* Clear this tab's nav + prefetch caches without broadcasting or rotating
|
|
438
|
-
* shared state. Intended for app-switch transitions that affect only this
|
|
439
|
-
* tab's session.
|
|
440
|
-
*/
|
|
441
|
-
clearHistoryCacheLocal(): void;
|
|
442
|
-
broadcastCacheInvalidation(): void;
|
|
443
513
|
|
|
444
514
|
// Cross-tab refresh callback (set by navigation bridge)
|
|
445
515
|
setCrossTabRefreshCallback(callback: () => void): void;
|
|
@@ -495,6 +565,15 @@ export interface FetchPartialResult {
|
|
|
495
565
|
payload: RscPayload;
|
|
496
566
|
/** Promise that resolves when the response stream is fully consumed */
|
|
497
567
|
streamComplete: Promise<void>;
|
|
568
|
+
/**
|
|
569
|
+
* True only when this payload came from a prefetch-cache hit whose stream had
|
|
570
|
+
* ALREADY fully drained at fetch time (the route was fully prefetched). The
|
|
571
|
+
* commit then runs in a startTransition so loading()/Suspense content — already
|
|
572
|
+
* resolved — swaps in directly without flashing a fallback. A partially-warmed
|
|
573
|
+
* (still-streaming) prefetch hit and a cold fetch leave this false so their
|
|
574
|
+
* fallbacks stream as usual.
|
|
575
|
+
*/
|
|
576
|
+
fullyPrefetched?: boolean;
|
|
498
577
|
}
|
|
499
578
|
|
|
500
579
|
/**
|
|
@@ -556,13 +635,6 @@ export interface NavigationBridge {
|
|
|
556
635
|
getVersion(): string | undefined;
|
|
557
636
|
/** Update the RSC version (e.g. after HMR). Clears prefetch cache. */
|
|
558
637
|
updateVersion(newVersion: string): void;
|
|
559
|
-
/**
|
|
560
|
-
* Replace the active app-shell snapshot (rootLayout, basename, version)
|
|
561
|
-
* atomically. Used on cross-app navigations when the response's routerId
|
|
562
|
-
* indicates the user entered a different app. Theme, warmup, and prefetch
|
|
563
|
-
* TTL are document-lifetime and not part of the shell.
|
|
564
|
-
*/
|
|
565
|
-
updateAppShell(next: import("./app-shell.js").AppShell): void;
|
|
566
638
|
}
|
|
567
639
|
|
|
568
640
|
/**
|
|
@@ -1,29 +1,56 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveSameOriginRedirect,
|
|
3
|
+
resolveExternalRedirect,
|
|
4
|
+
} from "../redirect-origin.js";
|
|
5
|
+
|
|
1
6
|
/**
|
|
2
7
|
* Validate that a client-consumed redirect URL (from headers or Flight payload)
|
|
3
8
|
* targets the same origin as the current page. Prevents open-redirect attacks
|
|
4
9
|
* via crafted responses.
|
|
5
10
|
*
|
|
11
|
+
* Thin wrapper over the shared {@link resolveSameOriginRedirect} rule (also used
|
|
12
|
+
* by the server guard in `rsc/redirect-guard.ts`) so client and server enforce
|
|
13
|
+
* the identical same-origin contract. Adds the client-side `console.error` on a
|
|
14
|
+
* block; the resolver itself stays pure.
|
|
15
|
+
*
|
|
6
16
|
* @returns The canonical (normalized) URL string on success, or null if blocked.
|
|
7
17
|
*/
|
|
8
18
|
export function validateRedirectOrigin(
|
|
9
19
|
url: string,
|
|
10
20
|
currentOrigin: string,
|
|
11
21
|
): string | null {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
const resolved = resolveSameOriginRedirect(url, currentOrigin);
|
|
23
|
+
if (resolved === null) {
|
|
24
|
+
console.error(
|
|
25
|
+
`[rango] Redirect blocked: cross-origin or invalid target "${url}"`,
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
return resolved;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Validate an explicit off-origin redirect (`redirect(url, { external: true })`)
|
|
33
|
+
* the client is about to hard-navigate to via `window.location.assign()`.
|
|
34
|
+
*
|
|
35
|
+
* Thin wrapper over the shared {@link resolveExternalRedirect} rule (also used by
|
|
36
|
+
* the server guard in `rsc/redirect-guard.ts`) so client and server enforce the
|
|
37
|
+
* identical contract: `external` allows an off-origin target but only an
|
|
38
|
+
* http(s) scheme. This stops a forged or mistaken external payload carrying a
|
|
39
|
+
* `javascript:`/`data:` URL from turning `location.assign` into a scriptable
|
|
40
|
+
* navigation. Adds the client-side `console.error` on a block; the resolver
|
|
41
|
+
* itself stays pure.
|
|
42
|
+
*
|
|
43
|
+
* @returns The normalized URL string on success, or null if blocked.
|
|
44
|
+
*/
|
|
45
|
+
export function validateExternalRedirect(
|
|
46
|
+
url: string,
|
|
47
|
+
currentOrigin: string,
|
|
48
|
+
): string | null {
|
|
49
|
+
const resolved = resolveExternalRedirect(url, currentOrigin);
|
|
50
|
+
if (resolved === null) {
|
|
51
|
+
console.error(
|
|
52
|
+
`[rango] External redirect blocked: non-http(s) target "${url}"`,
|
|
53
|
+
);
|
|
28
54
|
}
|
|
55
|
+
return resolved;
|
|
29
56
|
}
|
|
@@ -17,6 +17,11 @@ import type { TrailingSlashMode } from "../types.js";
|
|
|
17
17
|
import { createRouteHelpers } from "../route-definition.js";
|
|
18
18
|
import MapRootLayout from "../server/root-layout.js";
|
|
19
19
|
import { collectFallbackClientRefs } from "./collect-fallback-refs.js";
|
|
20
|
+
import {
|
|
21
|
+
isIncludeProvider,
|
|
22
|
+
resolveIncludeModule,
|
|
23
|
+
type IncludeProvider,
|
|
24
|
+
} from "../urls/include-provider.js";
|
|
20
25
|
|
|
21
26
|
/**
|
|
22
27
|
* Node in the prefix tree
|
|
@@ -61,13 +66,32 @@ export interface GeneratedManifest {
|
|
|
61
66
|
// Merge tracked nested includes into `target`. Multiple includes can share a
|
|
62
67
|
// fullPrefix (e.g. include("/", a), include("/", b)) — concat their routes and
|
|
63
68
|
// Object.assign children rather than overwrite.
|
|
64
|
-
function mergeIncludeNodes(
|
|
69
|
+
async function mergeIncludeNodes(
|
|
65
70
|
target: Record<string, PrefixTreeNode>,
|
|
66
71
|
includes: TrackedInclude[],
|
|
67
|
-
buildChild: (include: TrackedInclude) => PrefixTreeNode
|
|
68
|
-
): void {
|
|
72
|
+
buildChild: (include: TrackedInclude) => Promise<PrefixTreeNode>,
|
|
73
|
+
): Promise<void> {
|
|
69
74
|
for (const include of includes) {
|
|
70
|
-
|
|
75
|
+
let node: PrefixTreeNode;
|
|
76
|
+
try {
|
|
77
|
+
node = await buildChild(include);
|
|
78
|
+
} catch (err) {
|
|
79
|
+
// Discovery (build-time, and the dev trie-rebuild) populates the
|
|
80
|
+
// manifest / trie / generated types for the WHOLE app. A failing async
|
|
81
|
+
// include provider here — a broken import, a module that throws at eval —
|
|
82
|
+
// must HARD-FAIL, not be swallowed: swallowing produces a green build with
|
|
83
|
+
// the entire route group silently absent from the manifest/trie/types, so
|
|
84
|
+
// CI passes, the deploy ships, and every one of that group's URLs then
|
|
85
|
+
// 404s/500s in production. On main an eager include that threw failed the
|
|
86
|
+
// build loudly; the async form must keep that contract. Rethrow with the
|
|
87
|
+
// offending prefix so the failure is actionable. (Sibling isolation
|
|
88
|
+
// belongs at PER-REQUEST runtime — see find-match.ts — not at discovery.)
|
|
89
|
+
throw new Error(
|
|
90
|
+
`[@rangojs/router] Failed to resolve include at prefix "${include.fullPrefix}" ` +
|
|
91
|
+
`during route discovery: ${(err as Error)?.message ?? String(err)}`,
|
|
92
|
+
{ cause: err },
|
|
93
|
+
);
|
|
94
|
+
}
|
|
71
95
|
const existing = target[include.fullPrefix];
|
|
72
96
|
if (existing) {
|
|
73
97
|
existing.routes.push(...node.routes);
|
|
@@ -78,10 +102,10 @@ function mergeIncludeNodes(
|
|
|
78
102
|
}
|
|
79
103
|
}
|
|
80
104
|
|
|
81
|
-
function buildPrefixTreeNode(
|
|
105
|
+
async function buildPrefixTreeNode(
|
|
82
106
|
urlPrefix: string,
|
|
83
107
|
namePrefix: string | undefined,
|
|
84
|
-
|
|
108
|
+
patternsOrProvider: UrlPatterns<any> | IncludeProvider<any>,
|
|
85
109
|
routeManifest: Record<string, string>,
|
|
86
110
|
routeAncestry: Record<string, string[]>, // internal: feeds trie building, not exported
|
|
87
111
|
mountIndex: number,
|
|
@@ -92,7 +116,14 @@ function buildPrefixTreeNode(
|
|
|
92
116
|
passthroughRoutes?: string[],
|
|
93
117
|
responseTypeRoutes?: Record<string, string>,
|
|
94
118
|
routeSearchSchemas?: Record<string, Record<string, string>>,
|
|
95
|
-
): PrefixTreeNode {
|
|
119
|
+
): Promise<PrefixTreeNode> {
|
|
120
|
+
// Resolve an async include provider (`() => import("./routes")`) so its routes
|
|
121
|
+
// are walked into the build-time manifest/types/href. Runtime matching still
|
|
122
|
+
// defers the import via lazy-includes; this only runs during build/dev
|
|
123
|
+
// discovery, which is async.
|
|
124
|
+
const patterns: UrlPatterns<any> = isIncludeProvider(patternsOrProvider)
|
|
125
|
+
? resolveIncludeModule(await patternsOrProvider(), urlPrefix)
|
|
126
|
+
: patternsOrProvider;
|
|
96
127
|
if (visited.has(patterns)) {
|
|
97
128
|
console.warn(
|
|
98
129
|
`[@rangojs/router] Circular include detected at prefix "${urlPrefix}". Skipping.`,
|
|
@@ -106,118 +137,117 @@ function buildPrefixTreeNode(
|
|
|
106
137
|
};
|
|
107
138
|
}
|
|
108
139
|
visited.add(patterns);
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
140
|
+
try {
|
|
141
|
+
// Create context for running patterns with include tracking
|
|
142
|
+
const manifest = new Map<string, EntryData>();
|
|
143
|
+
const patternsMap = new Map<string, string>();
|
|
144
|
+
const patternsByPrefix = new Map<string, Map<string, string>>();
|
|
145
|
+
const trailingSlashMap = new Map<string, TrailingSlashMode>();
|
|
146
|
+
const searchSchemasMap = new Map<string, Record<string, string>>();
|
|
147
|
+
const trackedIncludes: TrackedInclude[] = [];
|
|
116
148
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
149
|
+
RangoContext.run(
|
|
150
|
+
{
|
|
151
|
+
manifest,
|
|
152
|
+
patterns: patternsMap,
|
|
153
|
+
patternsByPrefix,
|
|
154
|
+
trailingSlash: trailingSlashMap,
|
|
155
|
+
searchSchemas: searchSchemasMap,
|
|
156
|
+
namespace: "build",
|
|
157
|
+
parent: null,
|
|
158
|
+
counters: {},
|
|
159
|
+
mountIndex,
|
|
160
|
+
trackedIncludes, // Enable nested include tracking
|
|
161
|
+
},
|
|
162
|
+
() => {
|
|
163
|
+
const helpers = createRouteHelpers();
|
|
164
|
+
// Wrap in root layout for correct parent hierarchy (matches runtime)
|
|
165
|
+
helpers.layout(MapRootLayout, () => {
|
|
166
|
+
if (urlPrefix || namePrefix) {
|
|
167
|
+
return runWithPrefixes(urlPrefix, namePrefix, () => {
|
|
168
|
+
return patterns.handler() as AllUseItems[];
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
return patterns.handler() as AllUseItems[];
|
|
172
|
+
});
|
|
173
|
+
},
|
|
174
|
+
);
|
|
143
175
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
routes.push(name);
|
|
148
|
-
routeManifest[name] = pattern;
|
|
149
|
-
}
|
|
176
|
+
// Collect route names defined in this include (routes have prefixes applied)
|
|
177
|
+
const routes = [...patternsMap.keys()];
|
|
178
|
+
Object.assign(routeManifest, Object.fromEntries(patternsMap));
|
|
150
179
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
180
|
+
// Collect trailing slash config
|
|
181
|
+
if (routeTrailingSlash) {
|
|
182
|
+
for (const [name, mode] of trailingSlashMap.entries()) {
|
|
183
|
+
routeTrailingSlash[name] = mode;
|
|
184
|
+
}
|
|
155
185
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
186
|
+
if (routeSearchSchemas) {
|
|
187
|
+
for (const [name, schema] of searchSchemasMap.entries()) {
|
|
188
|
+
routeSearchSchemas[name] = schema;
|
|
189
|
+
}
|
|
160
190
|
}
|
|
161
|
-
}
|
|
162
191
|
|
|
163
|
-
|
|
164
|
-
|
|
192
|
+
// Capture ancestry from manifest entries' parent chains
|
|
193
|
+
captureAncestry(manifest, routeAncestry);
|
|
165
194
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
195
|
+
// Collect prerender route names and handler definitions from manifest entries
|
|
196
|
+
if (prerenderRoutes) {
|
|
197
|
+
for (const [name, entry] of manifest) {
|
|
198
|
+
if (entry.type === "route" && entry.isPrerender) {
|
|
199
|
+
prerenderRoutes.push(name);
|
|
200
|
+
if (prerenderDefs && entry.prerenderDef) {
|
|
201
|
+
prerenderDefs[name] = entry.prerenderDef;
|
|
202
|
+
}
|
|
203
|
+
if (passthroughRoutes && entry.isPassthrough === true) {
|
|
204
|
+
passthroughRoutes.push(name);
|
|
205
|
+
}
|
|
176
206
|
}
|
|
177
207
|
}
|
|
178
208
|
}
|
|
179
|
-
}
|
|
180
209
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
210
|
+
// Collect response type routes from manifest entries
|
|
211
|
+
if (responseTypeRoutes) {
|
|
212
|
+
for (const [name, entry] of manifest) {
|
|
213
|
+
if (entry.type === "route" && entry.responseType) {
|
|
214
|
+
responseTypeRoutes[name] = entry.responseType;
|
|
215
|
+
}
|
|
186
216
|
}
|
|
187
217
|
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
const children: Record<string, PrefixTreeNode> = {};
|
|
191
|
-
mergeIncludeNodes(children, trackedIncludes, (include) =>
|
|
192
|
-
buildPrefixTreeNode(
|
|
193
|
-
include.fullPrefix,
|
|
194
|
-
include.namePrefix,
|
|
195
|
-
include.patterns as UrlPatterns<any>,
|
|
196
|
-
routeManifest,
|
|
197
|
-
routeAncestry,
|
|
198
|
-
mountIndex,
|
|
199
|
-
visited,
|
|
200
|
-
routeTrailingSlash,
|
|
201
|
-
prerenderRoutes,
|
|
202
|
-
prerenderDefs,
|
|
203
|
-
passthroughRoutes,
|
|
204
|
-
responseTypeRoutes,
|
|
205
|
-
routeSearchSchemas,
|
|
206
|
-
),
|
|
207
|
-
);
|
|
208
218
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
219
|
+
const children: Record<string, PrefixTreeNode> = {};
|
|
220
|
+
await mergeIncludeNodes(children, trackedIncludes, (include) =>
|
|
221
|
+
buildPrefixTreeNode(
|
|
222
|
+
include.fullPrefix,
|
|
223
|
+
include.namePrefix,
|
|
224
|
+
include.patterns as UrlPatterns<any> | IncludeProvider<any>,
|
|
225
|
+
routeManifest,
|
|
226
|
+
routeAncestry,
|
|
227
|
+
mountIndex,
|
|
228
|
+
visited,
|
|
229
|
+
routeTrailingSlash,
|
|
230
|
+
prerenderRoutes,
|
|
231
|
+
prerenderDefs,
|
|
232
|
+
passthroughRoutes,
|
|
233
|
+
responseTypeRoutes,
|
|
234
|
+
routeSearchSchemas,
|
|
235
|
+
),
|
|
236
|
+
);
|
|
213
237
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
238
|
+
return {
|
|
239
|
+
staticPrefix: extractStaticPrefix(urlPrefix),
|
|
240
|
+
fullPrefix: urlPrefix,
|
|
241
|
+
namePrefix: namePrefix || undefined,
|
|
242
|
+
children,
|
|
243
|
+
routes,
|
|
244
|
+
};
|
|
245
|
+
} finally {
|
|
246
|
+
// Remove from visited so sibling branches can reuse the same patterns without
|
|
247
|
+
// false circular-include detection — and so a throwing handler (caught by the
|
|
248
|
+
// parent mergeIncludeNodes) does not leak this entry into the shared set.
|
|
249
|
+
visited.delete(patterns);
|
|
250
|
+
}
|
|
221
251
|
}
|
|
222
252
|
|
|
223
253
|
/**
|
|
@@ -261,7 +291,8 @@ export interface FullManifest extends GeneratedManifest {
|
|
|
261
291
|
* import { generateManifest } from "@rangojs/router/build";
|
|
262
292
|
* import { urlpatterns } from "./urls";
|
|
263
293
|
*
|
|
264
|
-
*
|
|
294
|
+
* // Async: awaits async include() providers (`() => import("./routes")`).
|
|
295
|
+
* const manifest = await generateManifest(urlpatterns);
|
|
265
296
|
* // Write to file for runtime use
|
|
266
297
|
* fs.writeFileSync(
|
|
267
298
|
* "src/generated/route-manifest.json",
|
|
@@ -269,15 +300,12 @@ export interface FullManifest extends GeneratedManifest {
|
|
|
269
300
|
* );
|
|
270
301
|
* ```
|
|
271
302
|
*/
|
|
272
|
-
export function generateManifest<TEnv>(
|
|
303
|
+
export async function generateManifest<TEnv>(
|
|
273
304
|
urlpatterns: UrlPatterns<TEnv, any>,
|
|
274
305
|
mountIndex: number = 0,
|
|
275
|
-
): GeneratedManifest {
|
|
276
|
-
const {
|
|
277
|
-
|
|
278
|
-
_prerenderDefs: __,
|
|
279
|
-
...publicManifest
|
|
280
|
-
} = generateManifestFull(urlpatterns, mountIndex);
|
|
306
|
+
): Promise<GeneratedManifest> {
|
|
307
|
+
const { _routeAncestry, _prerenderDefs, ...publicManifest } =
|
|
308
|
+
await generateManifestFull(urlpatterns, mountIndex);
|
|
281
309
|
return publicManifest;
|
|
282
310
|
}
|
|
283
311
|
|
|
@@ -288,7 +316,7 @@ export function generateManifest<TEnv>(
|
|
|
288
316
|
* @rangojs/router/build), manifest-init (direct import), and trie
|
|
289
317
|
* building. Not intended for external use.
|
|
290
318
|
*/
|
|
291
|
-
export function generateManifestFull<TEnv>(
|
|
319
|
+
export async function generateManifestFull<TEnv>(
|
|
292
320
|
urlpatterns: UrlPatterns<TEnv, any>,
|
|
293
321
|
mountIndex: number = 0,
|
|
294
322
|
options?: {
|
|
@@ -302,7 +330,7 @@ export function generateManifestFull<TEnv>(
|
|
|
302
330
|
*/
|
|
303
331
|
collectClientFallbackRef?: (refKey: string) => void;
|
|
304
332
|
},
|
|
305
|
-
): FullManifest {
|
|
333
|
+
): Promise<FullManifest> {
|
|
306
334
|
const routeManifest: Record<string, string> = {};
|
|
307
335
|
const routeAncestry: Record<string, string[]> = {};
|
|
308
336
|
const prefixTree: Record<string, PrefixTreeNode> = {};
|
|
@@ -356,17 +384,13 @@ export function generateManifestFull<TEnv>(
|
|
|
356
384
|
}
|
|
357
385
|
|
|
358
386
|
// Collect root-level routes and trailing slash config
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
const routeSearchSchemas: Record<string, Record<string, string>> = {};
|
|
367
|
-
for (const [name, schema] of searchSchemasMap.entries()) {
|
|
368
|
-
routeSearchSchemas[name] = schema;
|
|
369
|
-
}
|
|
387
|
+
Object.assign(routeManifest, Object.fromEntries(patternsMap));
|
|
388
|
+
const routeTrailingSlash: Record<string, string> =
|
|
389
|
+
Object.fromEntries(trailingSlashMap);
|
|
390
|
+
const routeSearchSchemas: Record<
|
|
391
|
+
string,
|
|
392
|
+
Record<string, string>
|
|
393
|
+
> = Object.fromEntries(searchSchemasMap);
|
|
370
394
|
|
|
371
395
|
// Capture ancestry from manifest entries' parent chains
|
|
372
396
|
captureAncestry(manifest, routeAncestry);
|
|
@@ -393,11 +417,11 @@ export function generateManifestFull<TEnv>(
|
|
|
393
417
|
|
|
394
418
|
// Shared visited set for cycle detection across all root-level includes.
|
|
395
419
|
const visited = new Set<unknown>();
|
|
396
|
-
mergeIncludeNodes(prefixTree, trackedIncludes, (include) =>
|
|
420
|
+
await mergeIncludeNodes(prefixTree, trackedIncludes, (include) =>
|
|
397
421
|
buildPrefixTreeNode(
|
|
398
422
|
include.fullPrefix,
|
|
399
423
|
include.namePrefix,
|
|
400
|
-
include.patterns as UrlPatterns<any>,
|
|
424
|
+
include.patterns as UrlPatterns<any> | IncludeProvider<any>,
|
|
401
425
|
routeManifest,
|
|
402
426
|
routeAncestry,
|
|
403
427
|
mountIndex,
|
|
@@ -441,14 +465,14 @@ export function generateManifestFull<TEnv>(
|
|
|
441
465
|
*
|
|
442
466
|
* @example
|
|
443
467
|
* ```typescript
|
|
444
|
-
* const code = generateManifestCode(urlpatterns);
|
|
468
|
+
* const code = await generateManifestCode(urlpatterns);
|
|
445
469
|
* fs.writeFileSync("src/generated/route-manifest.ts", code);
|
|
446
470
|
* ```
|
|
447
471
|
*/
|
|
448
|
-
export function generateManifestCode<TEnv>(
|
|
472
|
+
export async function generateManifestCode<TEnv>(
|
|
449
473
|
urlpatterns: UrlPatterns<TEnv, any>,
|
|
450
|
-
): string {
|
|
451
|
-
const manifest = generateManifest(urlpatterns);
|
|
474
|
+
): Promise<string> {
|
|
475
|
+
const manifest = await generateManifest(urlpatterns);
|
|
452
476
|
|
|
453
477
|
return `/**
|
|
454
478
|
* Auto-generated route manifest
|
|
@@ -24,7 +24,6 @@ export {
|
|
|
24
24
|
extractIncludesWithDiagnostics,
|
|
25
25
|
} from "./route-types/include-resolution.js";
|
|
26
26
|
export {
|
|
27
|
-
extractUrlsVariableFromRouter,
|
|
28
27
|
extractUrlsFromRouter,
|
|
29
28
|
extractBasenameFromRouter,
|
|
30
29
|
type UrlsExtractionResult,
|
|
@@ -34,6 +33,7 @@ export {
|
|
|
34
33
|
findNestedRouterConflict,
|
|
35
34
|
formatNestedRouterConflictError,
|
|
36
35
|
findRouterFiles,
|
|
36
|
+
findHostRouterFiles,
|
|
37
37
|
writeCombinedRouteTypes,
|
|
38
38
|
genFileTsPath,
|
|
39
39
|
resolveSearchSchemas,
|