@rangojs/router 0.0.0-experimental.13 → 0.0.0-experimental.131
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 +9 -0
- package/README.md +1040 -5
- package/dist/__internal.d.ts +83 -0
- package/dist/__internal.d.ts.map +1 -0
- package/dist/__internal.js +19 -0
- package/dist/__internal.js.map +1 -0
- package/dist/__mocks__/version.d.ts +7 -0
- package/dist/__mocks__/version.d.ts.map +1 -0
- package/dist/__mocks__/version.js +7 -0
- package/dist/__mocks__/version.js.map +1 -0
- package/dist/__tests__/client-href.test.d.ts +2 -0
- package/dist/__tests__/client-href.test.d.ts.map +1 -0
- package/dist/__tests__/client-href.test.js +74 -0
- package/dist/__tests__/client-href.test.js.map +1 -0
- package/dist/__tests__/component-utils.test.d.ts +2 -0
- package/dist/__tests__/component-utils.test.d.ts.map +1 -0
- package/dist/__tests__/component-utils.test.js +51 -0
- package/dist/__tests__/component-utils.test.js.map +1 -0
- package/dist/__tests__/event-controller.test.d.ts +2 -0
- package/dist/__tests__/event-controller.test.d.ts.map +1 -0
- package/dist/__tests__/event-controller.test.js +538 -0
- package/dist/__tests__/event-controller.test.js.map +1 -0
- package/dist/__tests__/helpers/route-tree.d.ts +118 -0
- package/dist/__tests__/helpers/route-tree.d.ts.map +1 -0
- package/dist/__tests__/helpers/route-tree.js +374 -0
- package/dist/__tests__/helpers/route-tree.js.map +1 -0
- package/dist/__tests__/match-result.test.d.ts +2 -0
- package/dist/__tests__/match-result.test.d.ts.map +1 -0
- package/dist/__tests__/match-result.test.js +154 -0
- package/dist/__tests__/match-result.test.js.map +1 -0
- package/dist/__tests__/navigation-store.test.d.ts +2 -0
- package/dist/__tests__/navigation-store.test.d.ts.map +1 -0
- package/dist/__tests__/navigation-store.test.js +440 -0
- package/dist/__tests__/navigation-store.test.js.map +1 -0
- package/dist/__tests__/partial-update.test.d.ts +2 -0
- package/dist/__tests__/partial-update.test.d.ts.map +1 -0
- package/dist/__tests__/partial-update.test.js +1009 -0
- package/dist/__tests__/partial-update.test.js.map +1 -0
- package/dist/__tests__/reverse-types.test.d.ts +8 -0
- package/dist/__tests__/reverse-types.test.d.ts.map +1 -0
- package/dist/__tests__/reverse-types.test.js +656 -0
- package/dist/__tests__/reverse-types.test.js.map +1 -0
- package/dist/__tests__/route-definition.test.d.ts +2 -0
- package/dist/__tests__/route-definition.test.d.ts.map +1 -0
- package/dist/__tests__/route-definition.test.js +55 -0
- package/dist/__tests__/route-definition.test.js.map +1 -0
- package/dist/__tests__/router-helpers.test.d.ts +2 -0
- package/dist/__tests__/router-helpers.test.d.ts.map +1 -0
- package/dist/__tests__/router-helpers.test.js +377 -0
- package/dist/__tests__/router-helpers.test.js.map +1 -0
- package/dist/__tests__/router-integration-2.test.d.ts +2 -0
- package/dist/__tests__/router-integration-2.test.d.ts.map +1 -0
- package/dist/__tests__/router-integration-2.test.js +426 -0
- package/dist/__tests__/router-integration-2.test.js.map +1 -0
- package/dist/__tests__/router-integration.test.d.ts +2 -0
- package/dist/__tests__/router-integration.test.d.ts.map +1 -0
- package/dist/__tests__/router-integration.test.js +1051 -0
- package/dist/__tests__/router-integration.test.js.map +1 -0
- package/dist/__tests__/search-params.test.d.ts +5 -0
- package/dist/__tests__/search-params.test.d.ts.map +1 -0
- package/dist/__tests__/search-params.test.js +306 -0
- package/dist/__tests__/search-params.test.js.map +1 -0
- package/dist/__tests__/segment-system.test.d.ts +2 -0
- package/dist/__tests__/segment-system.test.d.ts.map +1 -0
- package/dist/__tests__/segment-system.test.js +627 -0
- package/dist/__tests__/segment-system.test.js.map +1 -0
- package/dist/__tests__/static-handler-types.test.d.ts +8 -0
- package/dist/__tests__/static-handler-types.test.d.ts.map +1 -0
- package/dist/__tests__/static-handler-types.test.js +63 -0
- package/dist/__tests__/static-handler-types.test.js.map +1 -0
- package/dist/__tests__/urls.test.d.ts +2 -0
- package/dist/__tests__/urls.test.d.ts.map +1 -0
- package/dist/__tests__/urls.test.js +421 -0
- package/dist/__tests__/urls.test.js.map +1 -0
- package/dist/__tests__/use-mount.test.d.ts +2 -0
- package/dist/__tests__/use-mount.test.d.ts.map +1 -0
- package/dist/__tests__/use-mount.test.js +35 -0
- package/dist/__tests__/use-mount.test.js.map +1 -0
- package/dist/bin/rango.d.ts +2 -0
- package/dist/bin/rango.d.ts.map +1 -0
- package/dist/bin/rango.js +1712 -212
- package/dist/bin/rango.js.map +1 -0
- package/dist/browser/event-controller.d.ts +191 -0
- package/dist/browser/event-controller.d.ts.map +1 -0
- package/dist/browser/event-controller.js +559 -0
- package/dist/browser/event-controller.js.map +1 -0
- package/dist/browser/index.d.ts +2 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +14 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/link-interceptor.d.ts +38 -0
- package/dist/browser/link-interceptor.d.ts.map +1 -0
- package/dist/browser/link-interceptor.js +99 -0
- package/dist/browser/link-interceptor.js.map +1 -0
- package/dist/browser/logging.d.ts +10 -0
- package/dist/browser/logging.d.ts.map +1 -0
- package/dist/browser/logging.js +29 -0
- package/dist/browser/logging.js.map +1 -0
- package/dist/browser/lru-cache.d.ts +17 -0
- package/dist/browser/lru-cache.d.ts.map +1 -0
- package/dist/browser/lru-cache.js +50 -0
- package/dist/browser/lru-cache.js.map +1 -0
- package/dist/browser/merge-segment-loaders.d.ts +39 -0
- package/dist/browser/merge-segment-loaders.d.ts.map +1 -0
- package/dist/browser/merge-segment-loaders.js +102 -0
- package/dist/browser/merge-segment-loaders.js.map +1 -0
- package/dist/browser/navigation-bridge.d.ts +102 -0
- package/dist/browser/navigation-bridge.d.ts.map +1 -0
- package/dist/browser/navigation-bridge.js +708 -0
- package/dist/browser/navigation-bridge.js.map +1 -0
- package/dist/browser/navigation-client.d.ts +25 -0
- package/dist/browser/navigation-client.d.ts.map +1 -0
- package/dist/browser/navigation-client.js +157 -0
- package/dist/browser/navigation-client.js.map +1 -0
- package/dist/browser/navigation-store.d.ts +101 -0
- package/dist/browser/navigation-store.d.ts.map +1 -0
- package/dist/browser/navigation-store.js +625 -0
- package/dist/browser/navigation-store.js.map +1 -0
- package/dist/browser/partial-update.d.ts +75 -0
- package/dist/browser/partial-update.d.ts.map +1 -0
- package/dist/browser/partial-update.js +426 -0
- package/dist/browser/partial-update.js.map +1 -0
- package/dist/browser/react/Link.d.ts +86 -0
- package/dist/browser/react/Link.d.ts.map +1 -0
- package/dist/browser/react/Link.js +128 -0
- package/dist/browser/react/Link.js.map +1 -0
- package/dist/browser/react/NavigationProvider.d.ts +63 -0
- package/dist/browser/react/NavigationProvider.d.ts.map +1 -0
- package/dist/browser/react/NavigationProvider.js +216 -0
- package/dist/browser/react/NavigationProvider.js.map +1 -0
- package/dist/browser/react/ScrollRestoration.d.ts +75 -0
- package/dist/browser/react/ScrollRestoration.d.ts.map +1 -0
- package/dist/browser/react/ScrollRestoration.js +57 -0
- package/dist/browser/react/ScrollRestoration.js.map +1 -0
- package/dist/browser/react/context.d.ts +46 -0
- package/dist/browser/react/context.d.ts.map +1 -0
- package/dist/browser/react/context.js +10 -0
- package/dist/browser/react/context.js.map +1 -0
- package/dist/browser/react/index.d.ts +11 -0
- package/dist/browser/react/index.d.ts.map +1 -0
- package/dist/browser/react/index.js +22 -0
- package/dist/browser/react/index.js.map +1 -0
- package/dist/browser/react/location-state-shared.d.ts +63 -0
- package/dist/browser/react/location-state-shared.d.ts.map +1 -0
- package/dist/browser/react/location-state-shared.js +81 -0
- package/dist/browser/react/location-state-shared.js.map +1 -0
- package/dist/browser/react/location-state.d.ts +23 -0
- package/dist/browser/react/location-state.d.ts.map +1 -0
- package/dist/browser/react/location-state.js +29 -0
- package/dist/browser/react/location-state.js.map +1 -0
- package/dist/browser/react/mount-context.d.ts +24 -0
- package/dist/browser/react/mount-context.d.ts.map +1 -0
- package/dist/browser/react/mount-context.js +24 -0
- package/dist/browser/react/mount-context.js.map +1 -0
- package/dist/browser/react/use-action.d.ts +64 -0
- package/dist/browser/react/use-action.d.ts.map +1 -0
- package/dist/browser/react/use-action.js +134 -0
- package/dist/browser/react/use-action.js.map +1 -0
- package/dist/browser/react/use-client-cache.d.ts +41 -0
- package/dist/browser/react/use-client-cache.d.ts.map +1 -0
- package/{src/browser/react/use-client-cache.ts → dist/browser/react/use-client-cache.js} +9 -26
- package/dist/browser/react/use-client-cache.js.map +1 -0
- package/dist/browser/react/use-handle.d.ts +31 -0
- package/dist/browser/react/use-handle.d.ts.map +1 -0
- package/dist/browser/react/use-handle.js +144 -0
- package/dist/browser/react/use-handle.js.map +1 -0
- package/dist/browser/react/use-href.d.ts +33 -0
- package/dist/browser/react/use-href.d.ts.map +1 -0
- package/dist/browser/react/use-href.js +39 -0
- package/dist/browser/react/use-href.js.map +1 -0
- package/dist/browser/react/use-link-status.d.ts +37 -0
- package/dist/browser/react/use-link-status.d.ts.map +1 -0
- package/dist/browser/react/use-link-status.js +99 -0
- package/dist/browser/react/use-link-status.js.map +1 -0
- package/dist/browser/react/use-mount.d.ts +25 -0
- package/dist/browser/react/use-mount.d.ts.map +1 -0
- package/dist/browser/react/use-mount.js +30 -0
- package/dist/browser/react/use-mount.js.map +1 -0
- package/dist/browser/react/use-navigation.d.ts +27 -0
- package/dist/browser/react/use-navigation.d.ts.map +1 -0
- package/dist/browser/react/use-navigation.js +87 -0
- package/dist/browser/react/use-navigation.js.map +1 -0
- package/dist/browser/react/use-segments.d.ts +38 -0
- package/dist/browser/react/use-segments.d.ts.map +1 -0
- package/dist/browser/react/use-segments.js +130 -0
- package/dist/browser/react/use-segments.js.map +1 -0
- package/dist/browser/request-controller.d.ts +26 -0
- package/dist/browser/request-controller.d.ts.map +1 -0
- package/dist/browser/request-controller.js +147 -0
- package/dist/browser/request-controller.js.map +1 -0
- package/dist/browser/rsc-router.d.ts +129 -0
- package/dist/browser/rsc-router.d.ts.map +1 -0
- package/dist/browser/rsc-router.js +195 -0
- package/dist/browser/rsc-router.js.map +1 -0
- package/dist/browser/scroll-restoration.d.ts +93 -0
- package/dist/browser/scroll-restoration.d.ts.map +1 -0
- package/dist/browser/scroll-restoration.js +321 -0
- package/dist/browser/scroll-restoration.js.map +1 -0
- package/dist/browser/segment-structure-assert.d.ts +17 -0
- package/dist/browser/segment-structure-assert.d.ts.map +1 -0
- package/dist/browser/segment-structure-assert.js +59 -0
- package/dist/browser/segment-structure-assert.js.map +1 -0
- package/dist/browser/server-action-bridge.d.ts +26 -0
- package/dist/browser/server-action-bridge.d.ts.map +1 -0
- package/dist/browser/server-action-bridge.js +668 -0
- package/dist/browser/server-action-bridge.js.map +1 -0
- package/dist/browser/shallow.d.ts +12 -0
- package/dist/browser/shallow.d.ts.map +1 -0
- package/dist/browser/shallow.js +34 -0
- package/dist/browser/shallow.js.map +1 -0
- package/dist/browser/types.d.ts +369 -0
- package/dist/browser/types.d.ts.map +1 -0
- package/dist/browser/types.js +2 -0
- package/dist/browser/types.js.map +1 -0
- package/dist/build/__tests__/generate-cli.test.d.ts +2 -0
- package/dist/build/__tests__/generate-cli.test.d.ts.map +1 -0
- package/dist/build/__tests__/generate-cli.test.js +237 -0
- package/dist/build/__tests__/generate-cli.test.js.map +1 -0
- package/dist/build/__tests__/generate-manifest.test.d.ts +2 -0
- package/dist/build/__tests__/generate-manifest.test.d.ts.map +1 -0
- package/dist/build/__tests__/generate-manifest.test.js +119 -0
- package/dist/build/__tests__/generate-manifest.test.js.map +1 -0
- package/dist/build/__tests__/generate-route-types.test.d.ts +2 -0
- package/dist/build/__tests__/generate-route-types.test.d.ts.map +1 -0
- package/dist/build/__tests__/generate-route-types.test.js +620 -0
- package/dist/build/__tests__/generate-route-types.test.js.map +1 -0
- package/dist/build/__tests__/per-router-manifest.test.d.ts +2 -0
- package/dist/build/__tests__/per-router-manifest.test.d.ts.map +1 -0
- package/dist/build/__tests__/per-router-manifest.test.js +308 -0
- package/dist/build/__tests__/per-router-manifest.test.js.map +1 -0
- package/dist/build/generate-manifest.d.ts +81 -0
- package/dist/build/generate-manifest.d.ts.map +1 -0
- package/dist/build/generate-manifest.js +276 -0
- package/dist/build/generate-manifest.js.map +1 -0
- package/dist/build/generate-route-types.d.ts +115 -0
- package/dist/build/generate-route-types.d.ts.map +1 -0
- package/dist/build/generate-route-types.js +740 -0
- package/dist/build/generate-route-types.js.map +1 -0
- package/dist/build/index.d.ts +21 -0
- package/dist/build/index.d.ts.map +1 -0
- package/dist/build/index.js +21 -0
- package/dist/build/index.js.map +1 -0
- package/dist/build/route-trie.d.ts +71 -0
- package/dist/build/route-trie.d.ts.map +1 -0
- package/dist/build/route-trie.js +175 -0
- package/dist/build/route-trie.js.map +1 -0
- package/dist/cache/__tests__/cache-scope.test.d.ts +2 -0
- package/dist/cache/__tests__/cache-scope.test.d.ts.map +1 -0
- package/dist/cache/__tests__/cache-scope.test.js +208 -0
- package/dist/cache/__tests__/cache-scope.test.js.map +1 -0
- package/dist/cache/__tests__/document-cache.test.d.ts +2 -0
- package/dist/cache/__tests__/document-cache.test.d.ts.map +1 -0
- package/dist/cache/__tests__/document-cache.test.js +345 -0
- package/dist/cache/__tests__/document-cache.test.js.map +1 -0
- package/dist/cache/__tests__/memory-segment-store.test.d.ts +2 -0
- package/dist/cache/__tests__/memory-segment-store.test.d.ts.map +1 -0
- package/dist/cache/__tests__/memory-segment-store.test.js +425 -0
- package/dist/cache/__tests__/memory-segment-store.test.js.map +1 -0
- package/dist/cache/__tests__/memory-store.test.d.ts +2 -0
- package/dist/cache/__tests__/memory-store.test.d.ts.map +1 -0
- package/dist/cache/__tests__/memory-store.test.js +367 -0
- package/dist/cache/__tests__/memory-store.test.js.map +1 -0
- package/dist/cache/cache-scope.d.ts +102 -0
- package/dist/cache/cache-scope.d.ts.map +1 -0
- package/dist/cache/cache-scope.js +440 -0
- package/dist/cache/cache-scope.js.map +1 -0
- package/dist/cache/cf/__tests__/cf-cache-store.test.d.ts +2 -0
- package/dist/cache/cf/__tests__/cf-cache-store.test.d.ts.map +1 -0
- package/dist/cache/cf/__tests__/cf-cache-store.test.js +330 -0
- package/dist/cache/cf/__tests__/cf-cache-store.test.js.map +1 -0
- package/dist/cache/cf/cf-cache-store.d.ts +165 -0
- package/dist/cache/cf/cf-cache-store.d.ts.map +1 -0
- package/dist/cache/cf/cf-cache-store.js +242 -0
- package/dist/cache/cf/cf-cache-store.js.map +1 -0
- package/dist/cache/cf/index.d.ts +14 -0
- package/dist/cache/cf/index.d.ts.map +1 -0
- package/dist/cache/cf/index.js +17 -0
- package/dist/cache/cf/index.js.map +1 -0
- package/dist/cache/document-cache.d.ts +64 -0
- package/dist/cache/document-cache.d.ts.map +1 -0
- package/dist/cache/document-cache.js +228 -0
- package/dist/cache/document-cache.js.map +1 -0
- package/dist/cache/index.d.ts +19 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +21 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/cache/memory-segment-store.d.ts +110 -0
- package/dist/cache/memory-segment-store.d.ts.map +1 -0
- package/dist/cache/memory-segment-store.js +117 -0
- package/dist/cache/memory-segment-store.js.map +1 -0
- package/dist/cache/memory-store.d.ts +41 -0
- package/dist/cache/memory-store.d.ts.map +1 -0
- package/dist/cache/memory-store.js +191 -0
- package/dist/cache/memory-store.js.map +1 -0
- package/dist/cache/types.d.ts +317 -0
- package/dist/cache/types.d.ts.map +1 -0
- package/dist/cache/types.js +12 -0
- package/dist/cache/types.js.map +1 -0
- package/dist/client.d.ts +248 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +367 -0
- package/dist/client.js.map +1 -0
- package/dist/client.rsc.d.ts +26 -0
- package/dist/client.rsc.d.ts.map +1 -0
- package/dist/client.rsc.js +46 -0
- package/dist/client.rsc.js.map +1 -0
- package/dist/component-utils.d.ts +36 -0
- package/dist/component-utils.d.ts.map +1 -0
- package/dist/component-utils.js +61 -0
- package/dist/component-utils.js.map +1 -0
- package/dist/components/DefaultDocument.d.ts +13 -0
- package/dist/components/DefaultDocument.d.ts.map +1 -0
- package/dist/components/DefaultDocument.js +15 -0
- package/dist/components/DefaultDocument.js.map +1 -0
- package/dist/debug.d.ts +58 -0
- package/dist/debug.d.ts.map +1 -0
- package/dist/debug.js +157 -0
- package/dist/debug.js.map +1 -0
- package/dist/default-error-boundary.d.ts +11 -0
- package/dist/default-error-boundary.d.ts.map +1 -0
- package/dist/default-error-boundary.js +45 -0
- package/dist/default-error-boundary.js.map +1 -0
- package/dist/deps/browser.d.ts +2 -0
- package/dist/deps/browser.d.ts.map +1 -0
- package/dist/deps/browser.js +3 -0
- package/dist/deps/browser.js.map +1 -0
- package/dist/deps/html-stream-client.d.ts +2 -0
- package/dist/deps/html-stream-client.d.ts.map +1 -0
- package/dist/deps/html-stream-client.js +3 -0
- package/dist/deps/html-stream-client.js.map +1 -0
- package/dist/deps/html-stream-server.d.ts +2 -0
- package/dist/deps/html-stream-server.d.ts.map +1 -0
- package/dist/deps/html-stream-server.js +3 -0
- package/dist/deps/html-stream-server.js.map +1 -0
- package/dist/deps/rsc.d.ts +2 -0
- package/dist/deps/rsc.d.ts.map +1 -0
- package/dist/deps/rsc.js +4 -0
- package/dist/deps/rsc.js.map +1 -0
- package/dist/deps/ssr.d.ts +2 -0
- package/dist/deps/ssr.d.ts.map +1 -0
- package/dist/deps/ssr.js +3 -0
- package/dist/deps/ssr.js.map +1 -0
- package/dist/errors.d.ts +174 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +241 -0
- package/dist/errors.js.map +1 -0
- package/dist/handle.d.ts +78 -0
- package/dist/handle.d.ts.map +1 -0
- package/dist/handle.js +82 -0
- package/dist/handle.js.map +1 -0
- package/dist/handles/MetaTags.d.ts +14 -0
- package/dist/handles/MetaTags.d.ts.map +1 -0
- package/dist/handles/MetaTags.js +136 -0
- package/dist/handles/MetaTags.js.map +1 -0
- package/dist/handles/index.d.ts +6 -0
- package/dist/handles/index.d.ts.map +1 -0
- package/{src/handles/index.ts → dist/handles/index.js} +1 -1
- package/dist/handles/index.js.map +1 -0
- package/dist/handles/meta.d.ts +39 -0
- package/dist/handles/meta.d.ts.map +1 -0
- package/dist/handles/meta.js +202 -0
- package/dist/handles/meta.js.map +1 -0
- package/dist/host/__tests__/errors.test.d.ts +2 -0
- package/dist/host/__tests__/errors.test.d.ts.map +1 -0
- package/dist/host/__tests__/errors.test.js +76 -0
- package/dist/host/__tests__/errors.test.js.map +1 -0
- package/dist/host/__tests__/pattern-comprehensive.test.d.ts +2 -0
- package/dist/host/__tests__/pattern-comprehensive.test.d.ts.map +1 -0
- package/dist/host/__tests__/pattern-comprehensive.test.js +732 -0
- package/dist/host/__tests__/pattern-comprehensive.test.js.map +1 -0
- package/dist/host/__tests__/pattern-matcher.test.d.ts +2 -0
- package/dist/host/__tests__/pattern-matcher.test.d.ts.map +1 -0
- package/dist/host/__tests__/pattern-matcher.test.js +251 -0
- package/dist/host/__tests__/pattern-matcher.test.js.map +1 -0
- package/dist/host/__tests__/router.test.d.ts +2 -0
- package/dist/host/__tests__/router.test.d.ts.map +1 -0
- package/dist/host/__tests__/router.test.js +241 -0
- package/dist/host/__tests__/router.test.js.map +1 -0
- package/dist/host/__tests__/testing.test.d.ts +2 -0
- package/dist/host/__tests__/testing.test.d.ts.map +1 -0
- package/dist/host/__tests__/testing.test.js +64 -0
- package/dist/host/__tests__/testing.test.js.map +1 -0
- package/dist/host/__tests__/utils.test.d.ts +2 -0
- package/dist/host/__tests__/utils.test.d.ts.map +1 -0
- package/dist/host/__tests__/utils.test.js +29 -0
- package/dist/host/__tests__/utils.test.js.map +1 -0
- package/dist/host/cookie-handler.d.ts +34 -0
- package/dist/host/cookie-handler.d.ts.map +1 -0
- package/dist/host/cookie-handler.js +124 -0
- package/dist/host/cookie-handler.js.map +1 -0
- package/dist/host/errors.d.ts +56 -0
- package/dist/host/errors.d.ts.map +1 -0
- package/dist/host/errors.js +79 -0
- package/dist/host/errors.js.map +1 -0
- package/dist/host/index.d.ts +29 -0
- package/dist/host/index.d.ts.map +1 -0
- package/dist/host/index.js +32 -0
- package/dist/host/index.js.map +1 -0
- package/dist/host/pattern-matcher.d.ts +36 -0
- package/dist/host/pattern-matcher.d.ts.map +1 -0
- package/dist/host/pattern-matcher.js +172 -0
- package/dist/host/pattern-matcher.js.map +1 -0
- package/dist/host/router.d.ts +26 -0
- package/dist/host/router.d.ts.map +1 -0
- package/dist/host/router.js +218 -0
- package/dist/host/router.js.map +1 -0
- package/dist/host/testing.d.ts +36 -0
- package/dist/host/testing.d.ts.map +1 -0
- package/dist/host/testing.js +55 -0
- package/dist/host/testing.js.map +1 -0
- package/dist/host/types.d.ts +115 -0
- package/dist/host/types.d.ts.map +1 -0
- package/dist/host/types.js +7 -0
- package/dist/host/types.js.map +1 -0
- package/dist/host/utils.d.ts +21 -0
- package/dist/host/utils.d.ts.map +1 -0
- package/dist/host/utils.js +23 -0
- package/dist/host/utils.js.map +1 -0
- package/dist/href-client.d.ts +131 -0
- package/dist/href-client.d.ts.map +1 -0
- package/dist/href-client.js +64 -0
- package/dist/href-client.js.map +1 -0
- package/{src/href-context.ts → dist/href-context.d.ts} +7 -11
- package/dist/href-context.d.ts.map +1 -0
- package/dist/href-context.js +21 -0
- package/dist/href-context.js.map +1 -0
- package/dist/index.d.ts +73 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +91 -0
- package/dist/index.js.map +1 -0
- package/dist/index.rsc.d.ts +32 -0
- package/dist/index.rsc.d.ts.map +1 -0
- package/dist/index.rsc.js +40 -0
- package/dist/index.rsc.js.map +1 -0
- package/dist/internal-debug.d.ts +2 -0
- package/dist/internal-debug.d.ts.map +1 -0
- package/dist/internal-debug.js +5 -0
- package/dist/internal-debug.js.map +1 -0
- package/dist/loader.d.ts +14 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +20 -0
- package/dist/loader.js.map +1 -0
- package/dist/loader.rsc.d.ts +19 -0
- package/dist/loader.rsc.d.ts.map +1 -0
- package/dist/loader.rsc.js +99 -0
- package/dist/loader.rsc.js.map +1 -0
- package/dist/network-error-thrower.d.ts +17 -0
- package/dist/network-error-thrower.d.ts.map +1 -0
- package/dist/network-error-thrower.js +14 -0
- package/dist/network-error-thrower.js.map +1 -0
- package/dist/outlet-context.d.ts +13 -0
- package/dist/outlet-context.d.ts.map +1 -0
- package/dist/outlet-context.js +3 -0
- package/dist/outlet-context.js.map +1 -0
- package/dist/prerender/__tests__/param-hash.test.d.ts +2 -0
- package/dist/prerender/__tests__/param-hash.test.d.ts.map +1 -0
- package/dist/prerender/__tests__/param-hash.test.js +148 -0
- package/dist/prerender/__tests__/param-hash.test.js.map +1 -0
- package/dist/prerender/param-hash.d.ts +16 -0
- package/dist/prerender/param-hash.d.ts.map +1 -0
- package/dist/prerender/param-hash.js +36 -0
- package/dist/prerender/param-hash.js.map +1 -0
- package/dist/prerender/store.d.ts +38 -0
- package/dist/prerender/store.d.ts.map +1 -0
- package/dist/prerender/store.js +61 -0
- package/dist/prerender/store.js.map +1 -0
- package/dist/prerender.d.ts +66 -0
- package/dist/prerender.d.ts.map +1 -0
- package/dist/prerender.js +57 -0
- package/dist/prerender.js.map +1 -0
- package/dist/reverse.d.ts +196 -0
- package/dist/reverse.d.ts.map +1 -0
- package/dist/reverse.js +78 -0
- package/dist/reverse.js.map +1 -0
- package/dist/root-error-boundary.d.ts +33 -0
- package/dist/root-error-boundary.d.ts.map +1 -0
- package/dist/root-error-boundary.js +165 -0
- package/dist/root-error-boundary.js.map +1 -0
- package/dist/route-content-wrapper.d.ts +46 -0
- package/dist/route-content-wrapper.d.ts.map +1 -0
- package/dist/route-content-wrapper.js +77 -0
- package/dist/route-content-wrapper.js.map +1 -0
- package/dist/route-definition.d.ts +421 -0
- package/dist/route-definition.d.ts.map +1 -0
- package/dist/route-definition.js +868 -0
- package/dist/route-definition.js.map +1 -0
- package/dist/route-map-builder.d.ts +155 -0
- package/dist/route-map-builder.d.ts.map +1 -0
- package/dist/route-map-builder.js +237 -0
- package/dist/route-map-builder.js.map +1 -0
- package/dist/route-types.d.ts +165 -0
- package/dist/route-types.d.ts.map +1 -0
- package/dist/route-types.js +7 -0
- package/dist/route-types.js.map +1 -0
- package/dist/router/__tests__/handler-context.test.d.ts +2 -0
- package/dist/router/__tests__/handler-context.test.d.ts.map +1 -0
- package/dist/router/__tests__/handler-context.test.js +65 -0
- package/dist/router/__tests__/handler-context.test.js.map +1 -0
- package/dist/router/__tests__/loader-cycle-detection.test.d.ts +2 -0
- package/dist/router/__tests__/loader-cycle-detection.test.d.ts.map +1 -0
- package/dist/router/__tests__/loader-cycle-detection.test.js +221 -0
- package/dist/router/__tests__/loader-cycle-detection.test.js.map +1 -0
- package/dist/router/__tests__/match-context.test.d.ts +2 -0
- package/dist/router/__tests__/match-context.test.d.ts.map +1 -0
- package/dist/router/__tests__/match-context.test.js +92 -0
- package/dist/router/__tests__/match-context.test.js.map +1 -0
- package/dist/router/__tests__/match-pipelines.test.d.ts +2 -0
- package/dist/router/__tests__/match-pipelines.test.d.ts.map +1 -0
- package/dist/router/__tests__/match-pipelines.test.js +417 -0
- package/dist/router/__tests__/match-pipelines.test.js.map +1 -0
- package/dist/router/__tests__/match-result.test.d.ts +2 -0
- package/dist/router/__tests__/match-result.test.d.ts.map +1 -0
- package/dist/router/__tests__/match-result.test.js +457 -0
- package/dist/router/__tests__/match-result.test.js.map +1 -0
- package/dist/router/__tests__/on-error.test.d.ts +2 -0
- package/dist/router/__tests__/on-error.test.d.ts.map +1 -0
- package/dist/router/__tests__/on-error.test.js +678 -0
- package/dist/router/__tests__/on-error.test.js.map +1 -0
- package/dist/router/__tests__/pattern-matching.test.d.ts +2 -0
- package/dist/router/__tests__/pattern-matching.test.d.ts.map +1 -0
- package/dist/router/__tests__/pattern-matching.test.js +629 -0
- package/dist/router/__tests__/pattern-matching.test.js.map +1 -0
- package/dist/router/__tests__/segment-resolution-parallel-loading.test.d.ts +2 -0
- package/dist/router/__tests__/segment-resolution-parallel-loading.test.d.ts.map +1 -0
- package/dist/router/__tests__/segment-resolution-parallel-loading.test.js +155 -0
- package/dist/router/__tests__/segment-resolution-parallel-loading.test.js.map +1 -0
- package/dist/router/error-handling.d.ts +77 -0
- package/dist/router/error-handling.d.ts.map +1 -0
- package/dist/router/error-handling.js +202 -0
- package/dist/router/error-handling.js.map +1 -0
- package/dist/router/handler-context.d.ts +20 -0
- package/dist/router/handler-context.d.ts.map +1 -0
- package/dist/router/handler-context.js +198 -0
- package/dist/router/handler-context.js.map +1 -0
- package/dist/router/intercept-resolution.d.ts +66 -0
- package/dist/router/intercept-resolution.d.ts.map +1 -0
- package/dist/router/intercept-resolution.js +246 -0
- package/dist/router/intercept-resolution.js.map +1 -0
- package/dist/router/loader-resolution.d.ts +64 -0
- package/dist/router/loader-resolution.d.ts.map +1 -0
- package/dist/router/loader-resolution.js +284 -0
- package/dist/router/loader-resolution.js.map +1 -0
- package/dist/router/logging.d.ts +15 -0
- package/dist/router/logging.d.ts.map +1 -0
- package/dist/router/logging.js +99 -0
- package/dist/router/logging.js.map +1 -0
- package/dist/router/manifest.d.ts +22 -0
- package/dist/router/manifest.d.ts.map +1 -0
- package/dist/router/manifest.js +181 -0
- package/dist/router/manifest.js.map +1 -0
- package/dist/router/match-api.d.ts +35 -0
- package/dist/router/match-api.d.ts.map +1 -0
- package/dist/router/match-api.js +406 -0
- package/dist/router/match-api.js.map +1 -0
- package/dist/router/match-context.d.ts +206 -0
- package/dist/router/match-context.d.ts.map +1 -0
- package/dist/router/match-context.js +17 -0
- package/dist/router/match-context.js.map +1 -0
- package/dist/router/match-middleware/background-revalidation.d.ts +127 -0
- package/dist/router/match-middleware/background-revalidation.d.ts.map +1 -0
- package/dist/router/match-middleware/background-revalidation.js +75 -0
- package/dist/router/match-middleware/background-revalidation.js.map +1 -0
- package/dist/router/match-middleware/cache-lookup.d.ts +112 -0
- package/dist/router/match-middleware/cache-lookup.d.ts.map +1 -0
- package/dist/router/match-middleware/cache-lookup.js +257 -0
- package/dist/router/match-middleware/cache-lookup.js.map +1 -0
- package/dist/router/match-middleware/cache-store.d.ts +113 -0
- package/dist/router/match-middleware/cache-store.d.ts.map +1 -0
- package/dist/router/match-middleware/cache-store.js +108 -0
- package/dist/router/match-middleware/cache-store.js.map +1 -0
- package/dist/router/match-middleware/index.d.ts +81 -0
- package/dist/router/match-middleware/index.d.ts.map +1 -0
- package/dist/router/match-middleware/index.js +80 -0
- package/dist/router/match-middleware/index.js.map +1 -0
- package/dist/router/match-middleware/intercept-resolution.d.ts +117 -0
- package/dist/router/match-middleware/intercept-resolution.d.ts.map +1 -0
- package/dist/router/match-middleware/intercept-resolution.js +134 -0
- package/dist/router/match-middleware/intercept-resolution.js.map +1 -0
- package/dist/router/match-middleware/segment-resolution.d.ts +99 -0
- package/dist/router/match-middleware/segment-resolution.d.ts.map +1 -0
- package/dist/router/match-middleware/segment-resolution.js +53 -0
- package/dist/router/match-middleware/segment-resolution.js.map +1 -0
- package/dist/router/match-pipelines.d.ts +147 -0
- package/dist/router/match-pipelines.d.ts.map +1 -0
- package/dist/router/match-pipelines.js +82 -0
- package/dist/router/match-pipelines.js.map +1 -0
- package/dist/router/match-result.d.ts +126 -0
- package/dist/router/match-result.d.ts.map +1 -0
- package/dist/router/match-result.js +93 -0
- package/dist/router/match-result.js.map +1 -0
- package/dist/router/metrics.d.ts +20 -0
- package/dist/router/metrics.d.ts.map +1 -0
- package/dist/router/metrics.js +47 -0
- package/dist/router/metrics.js.map +1 -0
- package/dist/router/middleware.d.ts +249 -0
- package/dist/router/middleware.d.ts.map +1 -0
- package/dist/router/middleware.js +434 -0
- package/dist/router/middleware.js.map +1 -0
- package/dist/router/middleware.test.d.ts +2 -0
- package/dist/router/middleware.test.d.ts.map +1 -0
- package/dist/router/middleware.test.js +816 -0
- package/dist/router/middleware.test.js.map +1 -0
- package/dist/router/pattern-matching.d.ts +149 -0
- package/dist/router/pattern-matching.d.ts.map +1 -0
- package/dist/router/pattern-matching.js +349 -0
- package/dist/router/pattern-matching.js.map +1 -0
- package/dist/router/revalidation.d.ts +44 -0
- package/dist/router/revalidation.d.ts.map +1 -0
- package/dist/router/revalidation.js +147 -0
- package/dist/router/revalidation.js.map +1 -0
- package/dist/router/router-context.d.ts +135 -0
- package/dist/router/router-context.d.ts.map +1 -0
- package/dist/router/router-context.js +36 -0
- package/dist/router/router-context.js.map +1 -0
- package/dist/router/segment-resolution.d.ts +127 -0
- package/dist/router/segment-resolution.d.ts.map +1 -0
- package/dist/router/segment-resolution.js +919 -0
- package/dist/router/segment-resolution.js.map +1 -0
- package/dist/router/trie-matching.d.ts +40 -0
- package/dist/router/trie-matching.d.ts.map +1 -0
- package/dist/router/trie-matching.js +127 -0
- package/dist/router/trie-matching.js.map +1 -0
- package/dist/router/types.d.ts +136 -0
- package/dist/router/types.d.ts.map +1 -0
- package/dist/router/types.js +7 -0
- package/dist/router/types.js.map +1 -0
- package/dist/router.d.ts +753 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.gen.d.ts +6 -0
- package/dist/router.gen.d.ts.map +1 -0
- package/dist/router.gen.js +6 -0
- package/dist/router.gen.js.map +1 -0
- package/dist/router.js +1304 -0
- package/dist/router.js.map +1 -0
- package/dist/rsc/__tests__/helpers.test.d.ts +2 -0
- package/dist/rsc/__tests__/helpers.test.d.ts.map +1 -0
- package/dist/rsc/__tests__/helpers.test.js +140 -0
- package/dist/rsc/__tests__/helpers.test.js.map +1 -0
- package/dist/rsc/handler.d.ts +45 -0
- package/dist/rsc/handler.d.ts.map +1 -0
- package/dist/rsc/handler.js +1172 -0
- package/dist/rsc/handler.js.map +1 -0
- package/dist/rsc/helpers.d.ts +16 -0
- package/dist/rsc/helpers.d.ts.map +1 -0
- package/dist/rsc/helpers.js +55 -0
- package/dist/rsc/helpers.js.map +1 -0
- package/dist/rsc/index.d.ts +22 -0
- package/dist/rsc/index.d.ts.map +1 -0
- package/dist/rsc/index.js +23 -0
- package/dist/rsc/index.js.map +1 -0
- package/dist/rsc/nonce.d.ts +9 -0
- package/dist/rsc/nonce.d.ts.map +1 -0
- package/dist/rsc/nonce.js +18 -0
- package/dist/rsc/nonce.js.map +1 -0
- package/dist/rsc/types.d.ts +206 -0
- package/dist/rsc/types.d.ts.map +1 -0
- package/dist/rsc/types.js +8 -0
- package/dist/rsc/types.js.map +1 -0
- package/dist/search-params.d.ts +103 -0
- package/dist/search-params.d.ts.map +1 -0
- package/dist/search-params.js +74 -0
- package/dist/search-params.js.map +1 -0
- package/dist/segment-system.d.ts +75 -0
- package/dist/segment-system.d.ts.map +1 -0
- package/dist/segment-system.js +336 -0
- package/dist/segment-system.js.map +1 -0
- package/dist/server/context.d.ts +245 -0
- package/dist/server/context.d.ts.map +1 -0
- package/dist/server/context.js +197 -0
- package/dist/server/context.js.map +1 -0
- package/dist/server/fetchable-loader-store.d.ts +18 -0
- package/dist/server/fetchable-loader-store.d.ts.map +1 -0
- package/dist/server/fetchable-loader-store.js +18 -0
- package/dist/server/fetchable-loader-store.js.map +1 -0
- package/dist/server/handle-store.d.ts +85 -0
- package/dist/server/handle-store.d.ts.map +1 -0
- package/dist/server/handle-store.js +142 -0
- package/dist/server/handle-store.js.map +1 -0
- package/dist/server/loader-registry.d.ts +55 -0
- package/dist/server/loader-registry.d.ts.map +1 -0
- package/dist/server/loader-registry.js +132 -0
- package/dist/server/loader-registry.js.map +1 -0
- package/dist/server/request-context.d.ts +226 -0
- package/dist/server/request-context.d.ts.map +1 -0
- package/dist/server/request-context.js +290 -0
- package/dist/server/request-context.js.map +1 -0
- package/dist/server/root-layout.d.ts +4 -0
- package/dist/server/root-layout.d.ts.map +1 -0
- package/dist/server/root-layout.js +5 -0
- package/dist/server/root-layout.js.map +1 -0
- package/dist/server.d.ts +15 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +20 -0
- package/dist/server.js.map +1 -0
- package/dist/ssr/__tests__/ssr-handler.test.d.ts +2 -0
- package/dist/ssr/__tests__/ssr-handler.test.d.ts.map +1 -0
- package/dist/ssr/__tests__/ssr-handler.test.js +132 -0
- package/dist/ssr/__tests__/ssr-handler.test.js.map +1 -0
- package/dist/ssr/index.d.ts +98 -0
- package/dist/ssr/index.d.ts.map +1 -0
- package/dist/ssr/index.js +158 -0
- package/dist/ssr/index.js.map +1 -0
- package/dist/static-handler.d.ts +50 -0
- package/dist/static-handler.d.ts.map +1 -0
- package/dist/static-handler.gen.d.ts +5 -0
- package/dist/static-handler.gen.d.ts.map +1 -0
- package/dist/static-handler.gen.js +5 -0
- package/dist/static-handler.gen.js.map +1 -0
- package/dist/static-handler.js +29 -0
- package/dist/static-handler.js.map +1 -0
- package/dist/testing/vitest.js +82 -0
- package/dist/theme/ThemeProvider.d.ts +20 -0
- package/dist/theme/ThemeProvider.d.ts.map +1 -0
- package/dist/theme/ThemeProvider.js +240 -0
- package/dist/theme/ThemeProvider.js.map +1 -0
- package/dist/theme/ThemeScript.d.ts +48 -0
- package/dist/theme/ThemeScript.d.ts.map +1 -0
- package/dist/theme/ThemeScript.js +13 -0
- package/dist/theme/ThemeScript.js.map +1 -0
- package/dist/theme/__tests__/theme.test.d.ts +2 -0
- package/dist/theme/__tests__/theme.test.d.ts.map +1 -0
- package/dist/theme/__tests__/theme.test.js +103 -0
- package/dist/theme/__tests__/theme.test.js.map +1 -0
- package/dist/theme/constants.d.ts +29 -0
- package/dist/theme/constants.d.ts.map +1 -0
- package/dist/theme/constants.js +48 -0
- package/dist/theme/constants.js.map +1 -0
- package/dist/theme/index.d.ts +31 -0
- package/dist/theme/index.d.ts.map +1 -0
- package/dist/theme/index.js +36 -0
- package/dist/theme/index.js.map +1 -0
- package/dist/theme/theme-context.d.ts +40 -0
- package/dist/theme/theme-context.d.ts.map +1 -0
- package/dist/theme/theme-context.js +60 -0
- package/dist/theme/theme-context.js.map +1 -0
- package/dist/theme/theme-script.d.ts +27 -0
- package/dist/theme/theme-script.d.ts.map +1 -0
- package/dist/theme/theme-script.js +147 -0
- package/dist/theme/theme-script.js.map +1 -0
- package/dist/theme/types.d.ts +163 -0
- package/dist/theme/types.d.ts.map +1 -0
- package/dist/theme/types.js +11 -0
- package/dist/theme/types.js.map +1 -0
- package/dist/theme/use-theme.d.ts +12 -0
- package/dist/theme/use-theme.d.ts.map +1 -0
- package/dist/theme/use-theme.js +40 -0
- package/dist/theme/use-theme.js.map +1 -0
- package/dist/types.d.ts +1479 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -0
- package/dist/urls.d.ts +441 -0
- package/dist/urls.d.ts.map +1 -0
- package/dist/urls.gen.d.ts +8 -0
- package/dist/urls.gen.d.ts.map +1 -0
- package/dist/urls.gen.js +8 -0
- package/dist/urls.gen.js.map +1 -0
- package/dist/urls.js +443 -0
- package/dist/urls.js.map +1 -0
- package/dist/use-loader.d.ts +127 -0
- package/dist/use-loader.d.ts.map +1 -0
- package/dist/use-loader.js +237 -0
- package/dist/use-loader.js.map +1 -0
- package/dist/vite/__tests__/ast-handler-extract.test.d.ts +2 -0
- package/dist/vite/__tests__/ast-handler-extract.test.d.ts.map +1 -0
- package/dist/vite/__tests__/ast-handler-extract.test.js +294 -0
- package/dist/vite/__tests__/ast-handler-extract.test.js.map +1 -0
- package/dist/vite/__tests__/expose-id-utils.test.d.ts +2 -0
- package/dist/vite/__tests__/expose-id-utils.test.d.ts.map +1 -0
- package/dist/vite/__tests__/expose-id-utils.test.js +224 -0
- package/dist/vite/__tests__/expose-id-utils.test.js.map +1 -0
- package/dist/vite/__tests__/expose-internal-ids.test.d.ts +2 -0
- package/dist/vite/__tests__/expose-internal-ids.test.d.ts.map +1 -0
- package/dist/vite/__tests__/expose-internal-ids.test.js +647 -0
- package/dist/vite/__tests__/expose-internal-ids.test.js.map +1 -0
- package/dist/vite/__tests__/expose-router-id.test.d.ts +2 -0
- package/dist/vite/__tests__/expose-router-id.test.d.ts.map +1 -0
- package/dist/vite/__tests__/expose-router-id.test.js +39 -0
- package/dist/vite/__tests__/expose-router-id.test.js.map +1 -0
- package/dist/vite/ast-handler-extract.d.ts +49 -0
- package/dist/vite/ast-handler-extract.d.ts.map +1 -0
- package/dist/vite/ast-handler-extract.js +249 -0
- package/dist/vite/ast-handler-extract.js.map +1 -0
- package/dist/vite/expose-action-id.d.ts +19 -0
- package/dist/vite/expose-action-id.d.ts.map +1 -0
- package/dist/vite/expose-action-id.js +250 -0
- package/dist/vite/expose-action-id.js.map +1 -0
- package/dist/vite/expose-id-utils.d.ts +69 -0
- package/dist/vite/expose-id-utils.d.ts.map +1 -0
- package/dist/vite/expose-id-utils.js +289 -0
- package/dist/vite/expose-id-utils.js.map +1 -0
- package/dist/vite/expose-internal-ids.d.ts +22 -0
- package/dist/vite/expose-internal-ids.d.ts.map +1 -0
- package/dist/vite/expose-internal-ids.js +886 -0
- package/dist/vite/expose-internal-ids.js.map +1 -0
- package/dist/vite/index.d.ts +149 -0
- package/dist/vite/index.d.ts.map +1 -0
- package/dist/vite/index.js +6263 -2733
- package/dist/vite/index.js.bak +5448 -0
- package/dist/vite/index.js.map +1 -0
- package/dist/vite/package-resolution.d.ts +43 -0
- package/dist/vite/package-resolution.d.ts.map +1 -0
- package/{src/vite/package-resolution.ts → dist/vite/package-resolution.js} +53 -66
- package/dist/vite/package-resolution.js.map +1 -0
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/dist/vite/virtual-entries.d.ts +25 -0
- package/dist/vite/virtual-entries.d.ts.map +1 -0
- package/{src/vite/virtual-entries.ts → dist/vite/virtual-entries.js} +12 -16
- package/dist/vite/virtual-entries.js.map +1 -0
- package/package.json +123 -68
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +312 -0
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +486 -0
- package/skills/caching/SKILL.md +349 -24
- package/skills/composability/SKILL.md +197 -0
- package/skills/css/SKILL.md +76 -0
- package/skills/debug-manifest/SKILL.md +12 -8
- 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 +278 -0
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +175 -8
- package/skills/layout/SKILL.md +128 -5
- package/skills/links/SKILL.md +304 -25
- package/skills/loader/SKILL.md +604 -54
- package/skills/middleware/SKILL.md +213 -37
- package/skills/migrate-nextjs/SKILL.md +584 -0
- package/skills/migrate-react-router/SKILL.md +769 -0
- package/skills/mime-routes/SKILL.md +41 -10
- package/skills/observability/SKILL.md +172 -0
- package/skills/parallel/SKILL.md +276 -3
- package/skills/prerender/SKILL.md +432 -52
- package/skills/rango/SKILL.md +313 -21
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +248 -120
- package/skills/route/SKILL.md +287 -21
- package/skills/router-setup/SKILL.md +231 -33
- package/skills/server-actions/SKILL.md +775 -0
- package/skills/streams-and-websockets/SKILL.md +283 -0
- package/skills/tailwind/SKILL.md +27 -3
- package/skills/testing/SKILL.md +129 -0
- package/skills/testing/bindings.md +89 -0
- package/skills/testing/cache-prerender.md +124 -0
- package/skills/testing/client-components.md +122 -0
- package/skills/testing/e2e-parity.md +125 -0
- package/skills/testing/flight.md +92 -0
- package/skills/testing/handles.md +129 -0
- package/skills/testing/loader.md +128 -0
- package/skills/testing/middleware.md +99 -0
- package/skills/testing/render-handler.md +121 -0
- package/skills/testing/response-routes.md +95 -0
- package/skills/testing/reverse-and-types.md +84 -0
- package/skills/testing/server-actions.md +107 -0
- package/skills/testing/server-tree.md +128 -0
- package/skills/testing/setup.md +120 -0
- package/skills/theme/SKILL.md +9 -8
- package/skills/typesafety/SKILL.md +547 -107
- package/skills/use-cache/SKILL.md +355 -0
- package/skills/view-transitions/SKILL.md +294 -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/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +162 -200
- 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 +323 -563
- package/src/browser/navigation-client.ts +219 -75
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +104 -112
- package/src/browser/navigation-transaction.ts +247 -0
- package/src/browser/network-error-handler.ts +61 -0
- package/src/browser/partial-update.ts +328 -348
- package/src/browser/prefetch/cache.ts +324 -0
- package/src/browser/prefetch/fetch.ts +357 -0
- package/src/browser/prefetch/observer.ts +65 -0
- package/src/browser/prefetch/policy.ts +48 -0
- package/src/browser/prefetch/queue.ts +194 -0
- package/src/browser/prefetch/resource-ready.ts +77 -0
- package/src/browser/rango-state.ts +194 -0
- package/src/browser/react/Link.tsx +253 -71
- package/src/browser/react/NavigationProvider.tsx +155 -34
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/context.ts +11 -0
- package/src/browser/react/filter-segment-order.ts +53 -0
- package/src/browser/react/index.ts +0 -48
- package/src/browser/react/location-state-shared.ts +260 -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-link-status.ts +6 -9
- package/src/browser/react/use-navigation.ts +44 -68
- 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 +124 -0
- package/src/browser/rsc-router.tsx +290 -72
- package/src/browser/scroll-restoration.ts +132 -49
- package/src/browser/segment-reconciler.ts +243 -0
- package/src/browser/segment-structure-assert.ts +17 -1
- package/src/browser/server-action-bridge.ts +621 -613
- package/src/browser/types.ts +175 -50
- package/src/browser/validate-redirect-origin.ts +56 -0
- package/src/build/collect-fallback-refs.ts +107 -0
- package/src/build/generate-manifest.ts +123 -56
- package/src/build/generate-route-types.ts +41 -1038
- package/src/build/index.ts +9 -6
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +165 -34
- package/src/build/route-types/ast-helpers.ts +25 -0
- package/src/build/route-types/ast-route-extraction.ts +98 -0
- package/src/build/route-types/codegen.ts +113 -0
- package/src/build/route-types/include-resolution.ts +418 -0
- package/src/build/route-types/param-extraction.ts +51 -0
- package/src/build/route-types/per-module-writer.ts +131 -0
- package/src/build/route-types/router-processing.ts +651 -0
- package/src/build/route-types/scan-filter.ts +85 -0
- package/src/build/route-types/source-scan.ts +118 -0
- package/src/build/runtime-discovery.ts +220 -0
- package/src/cache/background-task.ts +34 -0
- package/src/cache/cache-error.ts +104 -0
- package/src/cache/cache-key-utils.ts +44 -0
- package/src/cache/cache-policy.ts +165 -0
- package/src/cache/cache-runtime.ts +444 -0
- package/src/cache/cache-scope.ts +231 -325
- package/src/cache/cache-tag.ts +98 -0
- package/src/cache/cf/cf-cache-store.ts +2644 -75
- package/src/cache/cf/index.ts +17 -17
- package/src/cache/document-cache.ts +172 -92
- package/src/cache/handle-capture.ts +81 -0
- package/src/cache/handle-snapshot.ts +104 -0
- package/src/cache/index.ts +11 -35
- package/src/cache/memory-segment-store.ts +307 -30
- package/src/cache/profile-registry.ts +49 -0
- package/src/cache/read-through-swr.ts +164 -0
- package/src/cache/segment-codec.ts +240 -0
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/taint.ts +153 -0
- package/src/cache/types.ts +94 -211
- package/src/client.rsc.tsx +8 -21
- package/src/client.tsx +123 -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 +5 -1
- package/src/context-var.ts +168 -0
- package/src/debug.ts +19 -9
- package/src/decode-loader-results.ts +36 -0
- package/src/defer.ts +196 -0
- package/src/deps/ssr.ts +0 -1
- package/src/errors.ts +106 -10
- package/src/handle.ts +76 -23
- package/src/handles/MetaTags.tsx +73 -34
- package/src/handles/breadcrumbs.ts +77 -0
- package/src/handles/meta.ts +30 -52
- package/src/host/cookie-handler.ts +21 -51
- package/src/host/errors.ts +8 -32
- package/src/host/index.ts +12 -9
- package/src/host/pattern-matcher.ts +34 -77
- 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 +174 -34
- package/src/index.ts +241 -73
- package/src/internal-debug.ts +8 -4
- 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/network-error-thrower.tsx +4 -7
- package/src/outlet-context.ts +1 -1
- package/src/outlet-provider.tsx +41 -0
- package/src/prerender/param-hash.ts +14 -13
- package/src/prerender/store.ts +121 -21
- package/src/prerender.ts +445 -24
- package/src/redirect-origin.ts +100 -0
- package/src/response-utils.ts +37 -0
- package/src/reverse.ts +198 -128
- package/src/root-error-boundary.tsx +42 -48
- package/src/route-content-wrapper.tsx +10 -72
- package/src/route-definition/dsl-helpers.ts +1116 -0
- package/src/route-definition/helper-factories.ts +90 -0
- package/src/route-definition/helpers-types.ts +506 -0
- package/src/route-definition/index.ts +55 -0
- package/src/route-definition/redirect.ts +135 -0
- package/src/route-definition/resolve-handler-use.ts +161 -0
- package/src/route-definition/use-item-types.ts +32 -0
- package/src/route-definition.ts +1 -1450
- package/src/route-map-builder.ts +82 -144
- package/src/route-name.ts +53 -0
- package/src/route-types.ts +72 -41
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +215 -0
- package/src/router/debug-manifest.ts +72 -0
- package/src/router/error-handling.ts +22 -26
- package/src/router/find-match.ts +181 -0
- package/src/router/handler-context.ts +372 -125
- package/src/router/instrument.ts +346 -0
- package/src/router/intercept-resolution.ts +34 -27
- package/src/router/lazy-includes.ts +200 -0
- package/src/router/loader-resolution.ts +381 -147
- package/src/router/logging.ts +106 -6
- package/src/router/manifest.ts +88 -51
- package/src/router/match-api.ts +162 -245
- package/src/router/match-context.ts +4 -24
- package/src/router/match-handlers.ts +440 -0
- package/src/router/match-middleware/background-revalidation.ts +90 -89
- package/src/router/match-middleware/cache-lookup.ts +297 -150
- package/src/router/match-middleware/cache-store.ts +75 -33
- 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 +421 -413
- package/src/router/navigation-snapshot.ts +131 -0
- package/src/router/params-util.ts +23 -0
- package/src/router/pattern-matching.ts +263 -79
- package/src/router/prerender-match.ts +541 -0
- package/src/router/preview-match.ts +100 -0
- package/src/router/request-classification.ts +276 -0
- package/src/router/revalidation.ts +143 -44
- package/src/router/route-snapshot.ts +244 -0
- package/src/router/router-context.ts +41 -47
- package/src/router/router-interfaces.ts +525 -0
- package/src/router/router-options.ts +726 -0
- package/src/router/router-registry.ts +21 -0
- package/src/router/segment-resolution/fresh.ts +747 -0
- package/src/router/segment-resolution/helpers.ts +314 -0
- package/src/router/segment-resolution/loader-cache.ts +207 -0
- package/src/router/segment-resolution/revalidation.ts +1322 -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 +36 -0
- package/src/router/segment-resolution.ts +24 -1354
- package/src/router/segment-wrappers.ts +289 -0
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/substitute-pattern-params.ts +56 -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 +172 -60
- package/src/router/types.ts +23 -70
- package/src/router/url-params.ts +44 -0
- package/src/router.ts +748 -2376
- package/src/rsc/handler-context.ts +46 -0
- package/src/rsc/handler.ts +861 -1141
- package/src/rsc/helpers.ts +269 -19
- package/src/rsc/index.ts +1 -21
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/loader-fetch.ts +235 -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 +413 -0
- package/src/rsc/redirect-guard.ts +99 -0
- package/src/rsc/response-error.ts +104 -0
- package/src/rsc/response-route-handler.ts +374 -0
- package/src/rsc/rsc-rendering.ts +261 -0
- package/src/rsc/runtime-warnings.ts +55 -0
- package/src/rsc/server-action.ts +376 -0
- package/src/rsc/ssr-setup.ts +144 -0
- package/src/rsc/types.ts +58 -12
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +70 -74
- package/src/segment-content-promise.ts +67 -0
- package/src/segment-loader-promise.ts +134 -0
- package/src/segment-system.tsx +292 -134
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +439 -85
- package/src/server/cookie-store.ts +265 -0
- package/src/server/fetchable-loader-store.ts +11 -6
- package/src/server/handle-store.ts +112 -31
- package/src/server/loader-registry.ts +23 -82
- package/src/server/request-context.ts +724 -143
- package/src/server.ts +26 -164
- package/src/ssr/index.tsx +113 -36
- package/src/static-handler.ts +45 -18
- package/src/testing/cache-status.ts +162 -0
- package/src/testing/collect-handle.ts +40 -0
- package/src/testing/dispatch.ts +618 -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 +232 -0
- package/src/testing/generated-routes.ts +183 -0
- package/src/testing/index.ts +99 -0
- package/src/testing/internal/context.ts +348 -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 +330 -0
- package/src/testing/render-route.tsx +566 -0
- package/src/testing/run-loader.ts +378 -0
- package/src/testing/run-middleware.ts +205 -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 +21 -67
- package/src/theme/ThemeScript.tsx +5 -11
- package/src/theme/constants.ts +5 -14
- package/src/theme/index.ts +3 -20
- package/src/theme/theme-context.ts +5 -35
- package/src/theme/theme-script.ts +21 -32
- 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 +79 -0
- package/src/types/loader-types.ts +212 -0
- package/src/types/request-scope.ts +107 -0
- package/src/types/route-config.ts +126 -0
- package/src/types/route-entry.ts +114 -0
- package/src/types/segments.ts +171 -0
- package/src/types.ts +1 -1795
- package/src/urls/include-helper.ts +160 -0
- package/src/urls/index.ts +43 -0
- package/src/urls/path-helper-types.ts +386 -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 +291 -0
- package/src/urls/urls-function.ts +81 -0
- package/src/urls.ts +1 -1323
- package/src/use-loader.tsx +406 -141
- 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 +194 -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 +17 -2259
- package/src/vite/plugin-types.ts +221 -0
- package/src/vite/plugins/cjs-to-esm.ts +83 -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} +13 -87
- package/src/vite/plugins/expose-ids/export-analysis.ts +338 -0
- package/src/vite/plugins/expose-ids/handler-transform.ts +141 -0
- package/src/vite/plugins/expose-ids/loader-transform.ts +57 -0
- package/src/vite/plugins/expose-ids/router-transform.ts +124 -0
- package/src/vite/plugins/expose-ids/types.ts +45 -0
- package/src/vite/plugins/expose-internal-ids.ts +806 -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/version-injector.ts +79 -0
- package/src/vite/plugins/version-plugin.ts +275 -0
- package/src/vite/plugins/virtual-entries.ts +108 -0
- package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
- package/src/vite/rango.ts +444 -0
- package/src/vite/router-discovery.ts +1581 -0
- package/src/vite/{ast-handler-extract.ts → utils/ast-handler-extract.ts} +193 -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/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 +223 -0
- package/src/vite/utils/shared-utils.ts +219 -0
- package/CLAUDE.md +0 -43
- package/src/browser/lru-cache.ts +0 -69
- 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/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/{version.d.ts → plugins/version.d.ts} +0 -0
package/src/router.ts
CHANGED
|
@@ -1,70 +1,43 @@
|
|
|
1
|
-
import type { ComponentType } from "react";
|
|
2
1
|
import { type ReactNode } from "react";
|
|
3
2
|
import { createCacheScope } from "./cache/cache-scope.js";
|
|
4
|
-
import
|
|
3
|
+
import { resolveCacheProfiles } from "./cache/profile-registry.js";
|
|
4
|
+
import { isCachedFunction } from "./cache/taint.js";
|
|
5
5
|
import { assertClientComponent } from "./component-utils.js";
|
|
6
6
|
import { DefaultDocument } from "./components/DefaultDocument.js";
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
} from "./errors";
|
|
10
|
-
import { serializeManifest, type SerializedManifest } from "./debug.js";
|
|
11
|
-
import {
|
|
12
|
-
createReverse,
|
|
13
|
-
type ReverseFunction,
|
|
14
|
-
type PrefixRoutePatterns,
|
|
15
|
-
} from "./reverse.js";
|
|
7
|
+
import type { SerializedManifest } from "./debug.js";
|
|
8
|
+
import { createReverse, type ReverseFunction } from "./reverse.js";
|
|
16
9
|
import {
|
|
17
10
|
registerRouteMap,
|
|
18
|
-
getGlobalRouteMap,
|
|
19
11
|
getPrecomputedEntries,
|
|
20
|
-
getRouteTrie,
|
|
21
12
|
getRouterManifest,
|
|
22
|
-
getRouterTrie,
|
|
23
13
|
getRouterPrecomputedEntries,
|
|
24
14
|
ensureRouterManifest,
|
|
25
15
|
} from "./route-map-builder.js";
|
|
26
|
-
import { tryTrieMatch } from "./router/trie-matching.js";
|
|
27
|
-
import {
|
|
28
|
-
createRouteHelpers,
|
|
29
|
-
type RouteHandlers,
|
|
30
|
-
} from "./route-definition.js";
|
|
31
16
|
import MapRootLayout from "./server/root-layout.js";
|
|
32
|
-
import type { AllUseItems
|
|
17
|
+
import type { AllUseItems } from "./route-types.js";
|
|
33
18
|
import type { UrlPatterns } from "./urls.js";
|
|
19
|
+
import type { UrlBuilder } from "./urls/pattern-types.js";
|
|
20
|
+
import { urls } from "./urls.js";
|
|
21
|
+
import { buildPrecomputedByPrefix } from "./build/prefix-tree-utils.js";
|
|
34
22
|
import {
|
|
35
|
-
EntryData,
|
|
36
|
-
InterceptEntry,
|
|
37
|
-
InterceptSelectorContext,
|
|
23
|
+
type EntryData,
|
|
38
24
|
getContext,
|
|
39
|
-
|
|
40
|
-
runWithPrefixes,
|
|
25
|
+
RangoContext,
|
|
41
26
|
type MetricsStore,
|
|
42
27
|
} from "./server/context";
|
|
43
28
|
import { createHandleStore, type HandleStore } from "./server/handle-store.js";
|
|
44
|
-
import {
|
|
29
|
+
import {
|
|
30
|
+
getRequestContext,
|
|
31
|
+
_getRequestContext,
|
|
32
|
+
} from "./server/request-context.js";
|
|
45
33
|
import type {
|
|
46
|
-
ErrorBoundaryHandler,
|
|
47
|
-
ErrorInfo,
|
|
48
34
|
ErrorPhase,
|
|
49
35
|
HandlerContext,
|
|
50
36
|
LoaderDataResult,
|
|
51
|
-
MatchResult,
|
|
52
|
-
NotFoundBoundaryHandler,
|
|
53
|
-
OnErrorCallback,
|
|
54
37
|
ResolvedRouteMap,
|
|
55
|
-
RouteDefinition,
|
|
56
38
|
RouteEntry,
|
|
57
39
|
TrailingSlashMode,
|
|
58
40
|
} from "./types";
|
|
59
|
-
import type {
|
|
60
|
-
NonceProvider,
|
|
61
|
-
} from "./rsc/types.js";
|
|
62
|
-
import {
|
|
63
|
-
runWithRequestContext,
|
|
64
|
-
type RequestContext,
|
|
65
|
-
type ExecutionContext,
|
|
66
|
-
} from "./server/request-context.js";
|
|
67
|
-
import type { SerializedSegmentData, SegmentHandleData } from "./cache/types.js";
|
|
68
41
|
|
|
69
42
|
// Extracted router utilities
|
|
70
43
|
import {
|
|
@@ -74,1072 +47,93 @@ import {
|
|
|
74
47
|
invokeOnError,
|
|
75
48
|
} from "./router/error-handling.js";
|
|
76
49
|
|
|
77
|
-
// Extracted
|
|
78
|
-
import {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
resolveLoadersOnlyWithRevalidation as _resolveLoadersOnlyWithRevalidation,
|
|
82
|
-
buildEntryRevalidateMap as _buildEntryRevalidateMap,
|
|
83
|
-
resolveAllSegmentsWithRevalidation as _resolveAllSegmentsWithRevalidation,
|
|
84
|
-
} from "./router/segment-resolution.js";
|
|
85
|
-
|
|
86
|
-
// Extracted intercept resolution functions
|
|
87
|
-
import {
|
|
88
|
-
findInterceptForRoute as _findInterceptForRoute,
|
|
89
|
-
resolveInterceptEntry as _resolveInterceptEntry,
|
|
90
|
-
resolveInterceptLoadersOnly as _resolveInterceptLoadersOnly,
|
|
91
|
-
} from "./router/intercept-resolution.js";
|
|
92
|
-
|
|
93
|
-
// Extracted match API functions
|
|
94
|
-
import {
|
|
95
|
-
createMatchContextForFull as _createMatchContextForFull,
|
|
96
|
-
createMatchContextForPartial as _createMatchContextForPartial,
|
|
97
|
-
matchError as _matchError,
|
|
98
|
-
} from "./router/match-api.js";
|
|
50
|
+
// Extracted module factories
|
|
51
|
+
import { createSegmentWrappers } from "./router/segment-wrappers.js";
|
|
52
|
+
import { createMatchHandlers } from "./router/match-handlers.js";
|
|
53
|
+
import { buildDebugManifest } from "./router/debug-manifest.js";
|
|
99
54
|
|
|
100
55
|
import type { SegmentResolutionDeps, MatchApiDeps } from "./router/types.js";
|
|
101
|
-
import { createHandlerContext
|
|
56
|
+
import { createHandlerContext } from "./router/handler-context.js";
|
|
57
|
+
import { normalizeBasename } from "./router/basename.js";
|
|
102
58
|
import {
|
|
103
59
|
setupLoaderAccess,
|
|
104
60
|
setupLoaderAccessSilent,
|
|
105
|
-
setupBuildUse,
|
|
106
61
|
wrapLoaderWithErrorHandling,
|
|
107
62
|
} from "./router/loader-resolution.js";
|
|
108
63
|
import { loadManifest } from "./router/manifest.js";
|
|
64
|
+
import { createMetricsStore } from "./router/metrics.js";
|
|
109
65
|
import {
|
|
110
|
-
createMetricsStore,
|
|
111
|
-
} from "./router/metrics.js";
|
|
112
|
-
import {
|
|
113
|
-
collectRouteMiddleware,
|
|
114
66
|
parsePattern,
|
|
115
67
|
type MiddlewareEntry,
|
|
116
68
|
type MiddlewareFn,
|
|
117
69
|
} from "./router/middleware.js";
|
|
118
70
|
import {
|
|
119
71
|
extractStaticPrefix,
|
|
120
|
-
|
|
121
|
-
isLazyEvaluationNeeded,
|
|
72
|
+
joinPrefix,
|
|
122
73
|
traverseBack,
|
|
123
|
-
type RouteMatchResult,
|
|
124
74
|
} from "./router/pattern-matching.js";
|
|
75
|
+
import { resolveSink, safeEmit, getRequestId } from "./router/telemetry.js";
|
|
76
|
+
import { resolveTracing } from "./router/tracing.js";
|
|
125
77
|
import { evaluateRevalidation } from "./router/revalidation.js";
|
|
126
78
|
import {
|
|
127
79
|
type RouterContext,
|
|
128
80
|
runWithRouterContext,
|
|
129
81
|
} from "./router/router-context.js";
|
|
130
|
-
import {
|
|
131
|
-
type ActionContext,
|
|
132
|
-
type MatchContext,
|
|
133
|
-
createPipelineState,
|
|
134
|
-
} from "./router/match-context.js";
|
|
135
|
-
import { createMatchPartialPipeline } from "./router/match-pipelines.js";
|
|
136
|
-
import { collectMatchResult } from "./router/match-result.js";
|
|
137
|
-
import {
|
|
138
|
-
runWithRouterLogContext,
|
|
139
|
-
withRouterLogScope,
|
|
140
|
-
} from "./router/logging.js";
|
|
141
82
|
import { resolveThemeConfig } from "./theme/constants.js";
|
|
83
|
+
import { resolveTimeouts } from "./router/timeout.js";
|
|
142
84
|
|
|
143
|
-
//
|
|
144
|
-
|
|
145
|
-
json: "application/json",
|
|
146
|
-
text: "text/plain",
|
|
147
|
-
xml: "application/xml",
|
|
148
|
-
html: "text/html",
|
|
149
|
-
md: "text/markdown",
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
// Reverse lookup: MIME type -> response type tag (e.g. "text/html" -> "html")
|
|
153
|
-
const MIME_RESPONSE_TYPE: Record<string, string> = Object.fromEntries(
|
|
154
|
-
Object.entries(RESPONSE_TYPE_MIME).map(([tag, mime]) => [mime, tag]),
|
|
155
|
-
);
|
|
156
|
-
|
|
157
|
-
interface AcceptEntry {
|
|
158
|
-
mime: string;
|
|
159
|
-
q: number;
|
|
160
|
-
order: number;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Parse an Accept header into a sorted array of MIME entries.
|
|
165
|
-
* Respects q-values (default 1.0) and uses client order as tiebreaker
|
|
166
|
-
* when q-values are equal (matching Express/Hono behavior).
|
|
167
|
-
*/
|
|
168
|
-
function parseAcceptTypes(accept: string): AcceptEntry[] {
|
|
169
|
-
const entries: AcceptEntry[] = [];
|
|
170
|
-
const parts = accept.split(",");
|
|
171
|
-
for (let i = 0; i < parts.length; i++) {
|
|
172
|
-
const part = parts[i]!;
|
|
173
|
-
const segments = part.split(";");
|
|
174
|
-
const mime = segments[0]!.trim();
|
|
175
|
-
if (!mime) continue;
|
|
176
|
-
let q = 1.0;
|
|
177
|
-
for (let j = 1; j < segments.length; j++) {
|
|
178
|
-
const param = segments[j]!.trim();
|
|
179
|
-
if (param.startsWith("q=")) {
|
|
180
|
-
q = Math.max(0, Math.min(1, Number(param.slice(2)) || 0));
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
entries.push({ mime, q, order: i });
|
|
184
|
-
}
|
|
185
|
-
// Sort: highest q first, then lowest client order first (stable)
|
|
186
|
-
entries.sort((a, b) => b.q - a.q || a.order - b.order);
|
|
187
|
-
return entries;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Sentinel response type for RSC routes in negotiation candidates
|
|
191
|
-
const RSC_RESPONSE_TYPE = "__rsc__";
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Pick the best negotiate variant by walking the client's sorted Accept list.
|
|
195
|
-
* For each accepted MIME type (in q-value/order priority), check if any
|
|
196
|
-
* candidate serves that type. Wildcards (*\/*) match the first candidate.
|
|
197
|
-
* Falls back to the first candidate if nothing matches.
|
|
198
|
-
*/
|
|
199
|
-
function pickNegotiateVariant(
|
|
200
|
-
acceptEntries: AcceptEntry[],
|
|
201
|
-
candidates: Array<{ routeKey: string; responseType: string }>,
|
|
202
|
-
): { routeKey: string; responseType: string } {
|
|
203
|
-
// Build a MIME -> candidate lookup for O(1) matching
|
|
204
|
-
const byCandidateMime = new Map<string, { routeKey: string; responseType: string }>();
|
|
205
|
-
for (const c of candidates) {
|
|
206
|
-
const mime = c.responseType === RSC_RESPONSE_TYPE ? "text/html" : RESPONSE_TYPE_MIME[c.responseType];
|
|
207
|
-
if (mime && !byCandidateMime.has(mime)) {
|
|
208
|
-
byCandidateMime.set(mime, c);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
for (const entry of acceptEntries) {
|
|
213
|
-
if (entry.q === 0) continue;
|
|
214
|
-
// Wildcard matches first candidate
|
|
215
|
-
if (entry.mime === "*/*") return candidates[0]!;
|
|
216
|
-
// Type wildcard (e.g. "text/*") — match first candidate with that type
|
|
217
|
-
if (entry.mime.endsWith("/*")) {
|
|
218
|
-
const typePrefix = entry.mime.slice(0, entry.mime.indexOf("/"));
|
|
219
|
-
for (const [mime, candidate] of byCandidateMime) {
|
|
220
|
-
if (mime.startsWith(typePrefix + "/")) return candidate;
|
|
221
|
-
}
|
|
222
|
-
continue;
|
|
223
|
-
}
|
|
224
|
-
const match = byCandidateMime.get(entry.mime);
|
|
225
|
-
if (match) return match;
|
|
226
|
-
}
|
|
227
|
-
// No match — use first candidate as default
|
|
228
|
-
return candidates[0]!;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* Props passed to the root layout component
|
|
233
|
-
*/
|
|
234
|
-
export interface RootLayoutProps {
|
|
235
|
-
children: ReactNode;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* Router configuration options
|
|
240
|
-
*/
|
|
241
|
-
/**
|
|
242
|
-
* Brand marker for identifying router instances at build time.
|
|
243
|
-
* Used by the Vite plugin to auto-discover routers from module exports.
|
|
244
|
-
*/
|
|
245
|
-
export const RSC_ROUTER_BRAND: "__rsc_router__" = "__rsc_router__";
|
|
246
|
-
|
|
247
|
-
/**
|
|
248
|
-
* Global registry of all router instances created via createRouter().
|
|
249
|
-
* Each router is keyed by its id (auto-generated or user-provided).
|
|
250
|
-
* Used by the Vite plugin at build time to discover routers and extract
|
|
251
|
-
* manifests, prefix trees, and pre-render candidates.
|
|
252
|
-
*/
|
|
253
|
-
export const RouterRegistry: Map<string, RSCRouter<any, any>> = new Map();
|
|
254
|
-
|
|
255
|
-
let routerAutoId = 0;
|
|
256
|
-
|
|
257
|
-
export interface RSCRouterOptions<TEnv = any> {
|
|
258
|
-
/**
|
|
259
|
-
* Unique identifier for this router instance.
|
|
260
|
-
* Used to namespace static output files and route maps.
|
|
261
|
-
* Auto-generated if not provided.
|
|
262
|
-
*/
|
|
263
|
-
id?: string;
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Injected by the Vite transform at compile time.
|
|
267
|
-
* Hash of filename + line number for stable cross-environment ID.
|
|
268
|
-
* @internal
|
|
269
|
-
*/
|
|
270
|
-
$$id?: string;
|
|
271
|
-
|
|
272
|
-
/**
|
|
273
|
-
* Enable performance metrics collection
|
|
274
|
-
* When enabled, metrics are output to console and available via Server-Timing header
|
|
275
|
-
*/
|
|
276
|
-
debugPerformance?: boolean;
|
|
277
|
-
|
|
278
|
-
/**
|
|
279
|
-
* Allow the `?__debug_manifest` query parameter to return route manifest data as JSON.
|
|
280
|
-
* In development mode this is always enabled regardless of this setting.
|
|
281
|
-
* Defaults to true. Set to false to disable in production.
|
|
282
|
-
* @internal
|
|
283
|
-
*/
|
|
284
|
-
allowDebugManifest?: boolean;
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Document component that wraps the entire application.
|
|
288
|
-
*
|
|
289
|
-
* This component provides the HTML structure for your app and wraps
|
|
290
|
-
* both normal route content AND error states, preventing the app shell
|
|
291
|
-
* from unmounting during errors (avoids FOUC).
|
|
292
|
-
*
|
|
293
|
-
* Must be a client component ("use client") that accepts { children }.
|
|
294
|
-
*
|
|
295
|
-
* If not provided, a default document with basic HTML structure is used:
|
|
296
|
-
* `<html><head><meta charset/viewport></head><body>{children}</body></html>`
|
|
297
|
-
*
|
|
298
|
-
* @example
|
|
299
|
-
* ```typescript
|
|
300
|
-
* // components/Document.tsx
|
|
301
|
-
* "use client";
|
|
302
|
-
* export function Document({ children }: { children: ReactNode }) {
|
|
303
|
-
* return (
|
|
304
|
-
* <html lang="en">
|
|
305
|
-
* <head>
|
|
306
|
-
* <link rel="stylesheet" href="/styles.css" />
|
|
307
|
-
* </head>
|
|
308
|
-
* <body>
|
|
309
|
-
* <nav>...</nav>
|
|
310
|
-
* {children}
|
|
311
|
-
* </body>
|
|
312
|
-
* </html>
|
|
313
|
-
* );
|
|
314
|
-
* }
|
|
315
|
-
*
|
|
316
|
-
* // router.tsx
|
|
317
|
-
* const router = createRouter<AppEnv>({
|
|
318
|
-
* document: Document,
|
|
319
|
-
* });
|
|
320
|
-
* ```
|
|
321
|
-
*/
|
|
322
|
-
document?: ComponentType<RootLayoutProps>;
|
|
323
|
-
|
|
324
|
-
/**
|
|
325
|
-
* Default error boundary fallback used when no error boundary is defined in the route tree
|
|
326
|
-
* If not provided, errors will propagate and crash the request
|
|
327
|
-
*/
|
|
328
|
-
defaultErrorBoundary?: ReactNode | ErrorBoundaryHandler;
|
|
329
|
-
|
|
330
|
-
/**
|
|
331
|
-
* Default not-found boundary fallback used when no notFoundBoundary is defined in the route tree
|
|
332
|
-
* If not provided, DataNotFoundError will be treated as a regular error
|
|
333
|
-
*/
|
|
334
|
-
defaultNotFoundBoundary?: ReactNode | NotFoundBoundaryHandler;
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
* Component to render when no route matches the requested URL.
|
|
338
|
-
*
|
|
339
|
-
* This is rendered within your document/app shell with a 404 status code.
|
|
340
|
-
* Use this for a custom 404 page that maintains your app's look and feel.
|
|
341
|
-
*
|
|
342
|
-
* If not provided, a default "Page not found" component is rendered.
|
|
343
|
-
*
|
|
344
|
-
* Can be a static ReactNode or a function receiving the pathname.
|
|
345
|
-
*
|
|
346
|
-
* @example
|
|
347
|
-
* ```typescript
|
|
348
|
-
* // Simple static component
|
|
349
|
-
* const router = createRouter<AppEnv>({
|
|
350
|
-
* document: Document,
|
|
351
|
-
* notFound: <NotFound404 />,
|
|
352
|
-
* });
|
|
353
|
-
*
|
|
354
|
-
* // Dynamic component with pathname
|
|
355
|
-
* const router = createRouter<AppEnv>({
|
|
356
|
-
* document: Document,
|
|
357
|
-
* notFound: ({ pathname }) => (
|
|
358
|
-
* <div>
|
|
359
|
-
* <h1>404 - Not Found</h1>
|
|
360
|
-
* <p>No page exists at {pathname}</p>
|
|
361
|
-
* <a href="/">Go home</a>
|
|
362
|
-
* </div>
|
|
363
|
-
* ),
|
|
364
|
-
* });
|
|
365
|
-
* ```
|
|
366
|
-
*/
|
|
367
|
-
notFound?: ReactNode | ((props: { pathname: string }) => ReactNode);
|
|
368
|
-
|
|
369
|
-
/**
|
|
370
|
-
* Callback invoked when an error occurs during request handling.
|
|
371
|
-
*
|
|
372
|
-
* This callback is for notification/logging purposes - it cannot modify
|
|
373
|
-
* the error handling flow. Use errorBoundary() in route definitions to
|
|
374
|
-
* customize error UI.
|
|
375
|
-
*
|
|
376
|
-
* The callback receives comprehensive context about the error including:
|
|
377
|
-
* - The error itself
|
|
378
|
-
* - Phase where it occurred (routing, middleware, loader, handler, etc.)
|
|
379
|
-
* - Request info (URL, method, params)
|
|
380
|
-
* - Route info (routeKey, segmentId)
|
|
381
|
-
* - Environment/bindings
|
|
382
|
-
* - Duration from request start
|
|
383
|
-
*
|
|
384
|
-
* @example
|
|
385
|
-
* ```typescript
|
|
386
|
-
* const router = createRouter<AppEnv>({
|
|
387
|
-
* onError: (context) => {
|
|
388
|
-
* // Send to error tracking service
|
|
389
|
-
* Sentry.captureException(context.error, {
|
|
390
|
-
* tags: {
|
|
391
|
-
* phase: context.phase,
|
|
392
|
-
* route: context.routeKey,
|
|
393
|
-
* },
|
|
394
|
-
* extra: {
|
|
395
|
-
* url: context.url.toString(),
|
|
396
|
-
* params: context.params,
|
|
397
|
-
* duration: context.duration,
|
|
398
|
-
* },
|
|
399
|
-
* });
|
|
400
|
-
* },
|
|
401
|
-
* });
|
|
402
|
-
* ```
|
|
403
|
-
*/
|
|
404
|
-
onError?: OnErrorCallback<TEnv>;
|
|
405
|
-
|
|
406
|
-
/**
|
|
407
|
-
* Cache store for segment caching.
|
|
408
|
-
*
|
|
409
|
-
* When provided, enables route-level caching via cache() boundaries.
|
|
410
|
-
* The store handles persistence (memory, KV, Redis, etc.).
|
|
411
|
-
*
|
|
412
|
-
* Can be a static config or a function receiving env for runtime bindings.
|
|
413
|
-
*
|
|
414
|
-
* @example Static config
|
|
415
|
-
* ```typescript
|
|
416
|
-
* import { MemorySegmentCacheStore } from "rsc-router/rsc";
|
|
417
|
-
*
|
|
418
|
-
* const router = createRouter({
|
|
419
|
-
* cache: {
|
|
420
|
-
* store: new MemorySegmentCacheStore({ defaults: { ttl: 60 } }),
|
|
421
|
-
* },
|
|
422
|
-
* });
|
|
423
|
-
* ```
|
|
424
|
-
*
|
|
425
|
-
* @example Dynamic config with env (e.g., Cloudflare Workers with ExecutionContext)
|
|
426
|
-
* ```typescript
|
|
427
|
-
* const router = createRouter<AppEnv>({
|
|
428
|
-
* cache: (env) => ({
|
|
429
|
-
* store: new CFCacheStore({
|
|
430
|
-
* defaults: { ttl: 60 },
|
|
431
|
-
* ctx: env.ctx, // ExecutionContext for non-blocking writes
|
|
432
|
-
* }),
|
|
433
|
-
* }),
|
|
434
|
-
* });
|
|
435
|
-
* ```
|
|
436
|
-
*/
|
|
437
|
-
cache?:
|
|
438
|
-
| { store: SegmentCacheStore; enabled?: boolean }
|
|
439
|
-
| ((env: TEnv & { ctx?: ExecutionContext }) => {
|
|
440
|
-
store: SegmentCacheStore;
|
|
441
|
-
enabled?: boolean;
|
|
442
|
-
});
|
|
443
|
-
|
|
444
|
-
/**
|
|
445
|
-
* Theme configuration for automatic theme management.
|
|
446
|
-
*
|
|
447
|
-
* When provided, enables:
|
|
448
|
-
* - ctx.theme and ctx.setTheme() in route handlers
|
|
449
|
-
* - useTheme() hook for client components
|
|
450
|
-
* - FOUC prevention via inline script in MetaTags
|
|
451
|
-
* - Automatic ThemeProvider wrapping in NavigationProvider
|
|
452
|
-
*
|
|
453
|
-
* @example
|
|
454
|
-
* ```typescript
|
|
455
|
-
* const router = createRouter<AppEnv>({
|
|
456
|
-
* theme: {
|
|
457
|
-
* defaultTheme: "system",
|
|
458
|
-
* themes: ["light", "dark"],
|
|
459
|
-
* }
|
|
460
|
-
* });
|
|
461
|
-
*
|
|
462
|
-
* // In route handler:
|
|
463
|
-
* route("settings", (ctx) => {
|
|
464
|
-
* const theme = ctx.theme; // "light" | "dark" | "system"
|
|
465
|
-
* ctx.setTheme("dark"); // Sets cookie
|
|
466
|
-
* return <SettingsPage />;
|
|
467
|
-
* });
|
|
468
|
-
*
|
|
469
|
-
* // In client component:
|
|
470
|
-
* import { useTheme } from "@rangojs/router/theme";
|
|
471
|
-
*
|
|
472
|
-
* function ThemeToggle() {
|
|
473
|
-
* const { theme, setTheme, themes } = useTheme();
|
|
474
|
-
* return <select value={theme} onChange={e => setTheme(e.target.value)}>
|
|
475
|
-
* {themes.map(t => <option key={t}>{t}</option>)}
|
|
476
|
-
* </select>;
|
|
477
|
-
* }
|
|
478
|
-
* ```
|
|
479
|
-
*
|
|
480
|
-
* Use `theme: true` to enable with all defaults.
|
|
481
|
-
*/
|
|
482
|
-
theme?: import("./theme/types.js").ThemeConfig | true;
|
|
483
|
-
|
|
484
|
-
/**
|
|
485
|
-
* URL patterns to register with the router.
|
|
486
|
-
*
|
|
487
|
-
* Alternative to calling `.routes()` method - allows passing patterns
|
|
488
|
-
* directly in the config for a more concise setup.
|
|
489
|
-
*
|
|
490
|
-
* @example
|
|
491
|
-
* ```typescript
|
|
492
|
-
* import { urls } from "@rangojs/router/server";
|
|
493
|
-
*
|
|
494
|
-
* const urlpatterns = urls(({ path, layout }) => [
|
|
495
|
-
* path("/", HomePage, { name: "home" }),
|
|
496
|
-
* path("/about", AboutPage, { name: "about" }),
|
|
497
|
-
* ]);
|
|
498
|
-
*
|
|
499
|
-
* const router = createRouter<AppEnv>({
|
|
500
|
-
* document: Document,
|
|
501
|
-
* urls: urlpatterns,
|
|
502
|
-
* });
|
|
503
|
-
* ```
|
|
504
|
-
*/
|
|
505
|
-
urls?: UrlPatterns<TEnv, any>;
|
|
506
|
-
|
|
507
|
-
/**
|
|
508
|
-
* Injected by the Vite transform at compile time.
|
|
509
|
-
* Static import of NamedRoutes from the generated named-routes file.
|
|
510
|
-
* Provides O(1) reverse() fallback when lazy includes haven't resolved.
|
|
511
|
-
* @internal
|
|
512
|
-
*/
|
|
513
|
-
$$routeNames?: Record<string, string>;
|
|
85
|
+
// Extracted content negotiation utilities
|
|
86
|
+
import { flattenNamedRoutes } from "./router/content-negotiation.js";
|
|
514
87
|
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
* ```tsx
|
|
528
|
-
* createRouter({
|
|
529
|
-
* nonce: () => true,
|
|
530
|
-
* });
|
|
531
|
-
* ```
|
|
532
|
-
*
|
|
533
|
-
* @example Custom nonce from request context
|
|
534
|
-
* ```tsx
|
|
535
|
-
* createRouter({
|
|
536
|
-
* nonce: (request, env) => env.nonce,
|
|
537
|
-
* });
|
|
538
|
-
* ```
|
|
539
|
-
*/
|
|
540
|
-
nonce?: NonceProvider<TEnv>;
|
|
541
|
-
|
|
542
|
-
/**
|
|
543
|
-
* RSC version string included in metadata.
|
|
544
|
-
* The browser sends this back on partial requests to detect version mismatches.
|
|
545
|
-
*
|
|
546
|
-
* Defaults to the auto-generated VERSION from `@rangojs/router:version` virtual module.
|
|
547
|
-
* Only set this if you need a custom versioning strategy.
|
|
548
|
-
*
|
|
549
|
-
* @default VERSION from @rangojs/router:version
|
|
550
|
-
*/
|
|
551
|
-
version?: string;
|
|
552
|
-
|
|
553
|
-
/**
|
|
554
|
-
* Enable connection warmup to keep TCP+TLS alive after idle periods.
|
|
555
|
-
*
|
|
556
|
-
* When enabled, the client sends a HEAD request after the user returns
|
|
557
|
-
* from an idle period (60s+), prewarming the TLS connection before
|
|
558
|
-
* the next navigation.
|
|
559
|
-
*
|
|
560
|
-
* @default true
|
|
561
|
-
*/
|
|
562
|
-
warmup?: boolean;
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
/**
|
|
566
|
-
* Merge route patterns with response types into a single route map.
|
|
567
|
-
* Routes with response types get { path, response } objects; others stay as strings.
|
|
568
|
-
* Handles both plain string routes and { path, search } object routes.
|
|
569
|
-
*/
|
|
570
|
-
type MergeRoutesWithResponses<
|
|
571
|
-
TRoutes extends Record<string, unknown>,
|
|
572
|
-
TResponses,
|
|
573
|
-
> = {
|
|
574
|
-
[K in keyof TRoutes]: K extends keyof NonNullable<TResponses>
|
|
575
|
-
? unknown extends NonNullable<TResponses>[K]
|
|
576
|
-
? TRoutes[K] // RSC route — TData defaults to unknown, keep as-is
|
|
577
|
-
: TRoutes[K] extends { readonly path: infer P extends string }
|
|
578
|
-
? TRoutes[K] & { readonly response: NonNullable<TResponses>[K] }
|
|
579
|
-
: { readonly path: TRoutes[K] & string; readonly response: NonNullable<TResponses>[K] }
|
|
580
|
-
: TRoutes[K]
|
|
581
|
-
};
|
|
582
|
-
|
|
583
|
-
/**
|
|
584
|
-
* Extract the URL pattern from a route entry (string or { path, response } object)
|
|
585
|
-
*/
|
|
586
|
-
type PatternOfEntry<V> =
|
|
587
|
-
V extends string ? V
|
|
588
|
-
: V extends { readonly path: infer P extends string } ? P
|
|
589
|
-
: never;
|
|
590
|
-
|
|
591
|
-
/**
|
|
592
|
-
* Type-level detection of conflicting route keys.
|
|
593
|
-
* Extracts keys that exist in both TExisting and TNew but with different URL patterns.
|
|
594
|
-
* Returns `never` if no conflicts exist.
|
|
595
|
-
* Compares patterns (not full entries) to handle both string and { path, response } values.
|
|
596
|
-
*
|
|
597
|
-
* @example
|
|
598
|
-
* ```typescript
|
|
599
|
-
* ConflictingKeys<{ a: "/a" }, { a: "/b" }> // "a" (conflict - same key, different URLs)
|
|
600
|
-
* ConflictingKeys<{ a: "/a" }, { a: "/a" }> // never (no conflict - same key and URL)
|
|
601
|
-
* ConflictingKeys<{ a: "/a" }, { b: "/b" }> // never (no conflict - different keys)
|
|
602
|
-
* ```
|
|
603
|
-
*/
|
|
604
|
-
type ConflictingKeys<
|
|
605
|
-
TExisting extends Record<string, unknown>,
|
|
606
|
-
TNew extends Record<string, unknown>,
|
|
607
|
-
> = {
|
|
608
|
-
[K in keyof TExisting & keyof TNew]: PatternOfEntry<TExisting[K]> extends PatternOfEntry<TNew[K]>
|
|
609
|
-
? PatternOfEntry<TNew[K]> extends PatternOfEntry<TExisting[K]>
|
|
610
|
-
? never // Same pattern, no conflict
|
|
611
|
-
: K // Different patterns, conflict
|
|
612
|
-
: K; // Different patterns, conflict
|
|
613
|
-
}[keyof TExisting & keyof TNew];
|
|
614
|
-
|
|
615
|
-
/**
|
|
616
|
-
* Error type returned when route keys conflict.
|
|
617
|
-
* Methods require an impossible `never` parameter so TypeScript errors at the call site.
|
|
618
|
-
*/
|
|
619
|
-
type RouteConflictError<TConflicts extends string> = {
|
|
620
|
-
__error: `Route key conflict! Key "${TConflicts}" already exists with a different URL pattern.`;
|
|
621
|
-
hint: "Route keys must be globally unique. Use prefixed names like 'blog.index' instead of 'index'.";
|
|
622
|
-
conflictingKeys: TConflicts;
|
|
623
|
-
// These methods require `never` so calling them produces an error at the call site
|
|
624
|
-
routes: (
|
|
625
|
-
__conflict: `Fix route key conflict: "${TConflicts}" is already defined with a different URL pattern`,
|
|
626
|
-
) => never;
|
|
627
|
-
map: (
|
|
628
|
-
__conflict: `Fix route key conflict: "${TConflicts}" is already defined with a different URL pattern`,
|
|
629
|
-
) => never;
|
|
630
|
-
};
|
|
631
|
-
|
|
632
|
-
/**
|
|
633
|
-
* Simplified route helpers for inline route definitions.
|
|
634
|
-
* Uses TRoutes (Record<string, string>) instead of RouteDefinition.
|
|
635
|
-
*
|
|
636
|
-
* Note: Some helpers use `any` for context types as a trade-off for simpler usage.
|
|
637
|
-
* The main type safety is in the `route` helper which enforces valid route names.
|
|
638
|
-
* For full type safety, use the standard map() API with separate handler files.
|
|
639
|
-
*/
|
|
640
|
-
type InlineRouteHelpers<TRoutes extends Record<string, string>, TEnv> = {
|
|
641
|
-
/**
|
|
642
|
-
* Define a route handler for a specific route pattern
|
|
643
|
-
*/
|
|
644
|
-
route: <K extends keyof TRoutes & string>(
|
|
645
|
-
name: K,
|
|
646
|
-
handler:
|
|
647
|
-
| ((ctx: HandlerContext<{}, TEnv>) => ReactNode | Promise<ReactNode>)
|
|
648
|
-
| ReactNode,
|
|
649
|
-
) => AllUseItems;
|
|
650
|
-
|
|
651
|
-
/**
|
|
652
|
-
* Define a layout that wraps child routes
|
|
653
|
-
*/
|
|
654
|
-
layout: (
|
|
655
|
-
component:
|
|
656
|
-
| ReactNode
|
|
657
|
-
| ((ctx: HandlerContext<any, TEnv>) => ReactNode | Promise<ReactNode>),
|
|
658
|
-
use?: () => AllUseItems[],
|
|
659
|
-
) => AllUseItems;
|
|
660
|
-
|
|
661
|
-
/**
|
|
662
|
-
* Define parallel routes
|
|
663
|
-
*/
|
|
664
|
-
parallel: (
|
|
665
|
-
slots: Record<
|
|
666
|
-
`@${string}`,
|
|
667
|
-
| ReactNode
|
|
668
|
-
| ((ctx: HandlerContext<any, TEnv>) => ReactNode | Promise<ReactNode>)
|
|
669
|
-
>,
|
|
670
|
-
use?: () => AllUseItems[],
|
|
671
|
-
) => AllUseItems;
|
|
672
|
-
|
|
673
|
-
/**
|
|
674
|
-
* Define route middleware
|
|
675
|
-
*/
|
|
676
|
-
middleware: (
|
|
677
|
-
fn: (ctx: any, next: () => Promise<void>) => Promise<void>,
|
|
678
|
-
) => AllUseItems;
|
|
679
|
-
|
|
680
|
-
/**
|
|
681
|
-
* Define revalidation handlers
|
|
682
|
-
*/
|
|
683
|
-
revalidate: (fn: (ctx: any) => boolean | Promise<boolean>) => AllUseItems;
|
|
684
|
-
|
|
685
|
-
/**
|
|
686
|
-
* Define data loaders
|
|
687
|
-
*/
|
|
688
|
-
loader: (loader: any, use?: () => AllUseItems[]) => AllUseItems;
|
|
689
|
-
|
|
690
|
-
/**
|
|
691
|
-
* Define loading states
|
|
692
|
-
*/
|
|
693
|
-
loading: (component: ReactNode) => AllUseItems;
|
|
694
|
-
|
|
695
|
-
/**
|
|
696
|
-
* Define error boundaries
|
|
697
|
-
*/
|
|
698
|
-
errorBoundary: (
|
|
699
|
-
handler: ReactNode | ((props: { error: Error }) => ReactNode),
|
|
700
|
-
) => AllUseItems;
|
|
701
|
-
|
|
702
|
-
/**
|
|
703
|
-
* Define not found boundaries
|
|
704
|
-
*/
|
|
705
|
-
notFoundBoundary: (
|
|
706
|
-
handler: ReactNode | ((props: { pathname: string }) => ReactNode),
|
|
707
|
-
) => AllUseItems;
|
|
708
|
-
|
|
709
|
-
/**
|
|
710
|
-
* Define intercept routes
|
|
711
|
-
*/
|
|
712
|
-
intercept: (
|
|
713
|
-
name: string,
|
|
714
|
-
handler:
|
|
715
|
-
| ReactNode
|
|
716
|
-
| ((ctx: HandlerContext<any, TEnv>) => ReactNode | Promise<ReactNode>),
|
|
717
|
-
use?: () => AllUseItems[],
|
|
718
|
-
) => AllUseItems;
|
|
719
|
-
|
|
720
|
-
/**
|
|
721
|
-
* Define when conditions for intercepts
|
|
722
|
-
*/
|
|
723
|
-
when: (condition: (ctx: any) => boolean | Promise<boolean>) => AllUseItems;
|
|
724
|
-
|
|
725
|
-
/**
|
|
726
|
-
* Define cache configuration
|
|
727
|
-
*/
|
|
728
|
-
cache: (
|
|
729
|
-
config: { ttl?: number; swr?: number } | false,
|
|
730
|
-
use?: () => AllUseItems[],
|
|
731
|
-
) => AllUseItems;
|
|
732
|
-
};
|
|
733
|
-
|
|
734
|
-
/**
|
|
735
|
-
* Router builder for chaining .use() and .map()
|
|
736
|
-
* TRoutes accumulates all registered route types through the chain
|
|
737
|
-
* TLocalRoutes contains the routes for the current .routes() call (for inline handler typing)
|
|
738
|
-
*/
|
|
739
|
-
interface RouteBuilder<
|
|
740
|
-
T extends RouteDefinition,
|
|
741
|
-
TEnv,
|
|
742
|
-
TRoutes extends Record<string, unknown>,
|
|
743
|
-
TLocalRoutes extends Record<string, string> = Record<string, string>,
|
|
744
|
-
> {
|
|
745
|
-
/**
|
|
746
|
-
* Add middleware scoped to this mount
|
|
747
|
-
* Called between .routes() and .map()
|
|
748
|
-
*
|
|
749
|
-
* @example
|
|
750
|
-
* ```typescript
|
|
751
|
-
* .routes("/admin", adminRoutes)
|
|
752
|
-
* .use(authMiddleware) // All of /admin/*
|
|
753
|
-
* .use("/danger/*", superAuth) // Only /admin/danger/*
|
|
754
|
-
* .map(() => import("./admin"))
|
|
755
|
-
* ```
|
|
756
|
-
*/
|
|
757
|
-
use(
|
|
758
|
-
patternOrMiddleware: string | MiddlewareFn<TEnv>,
|
|
759
|
-
middleware?: MiddlewareFn<TEnv>,
|
|
760
|
-
): RouteBuilder<T, TEnv, TRoutes, TLocalRoutes>;
|
|
761
|
-
|
|
762
|
-
/**
|
|
763
|
-
* Map routes to handlers
|
|
764
|
-
*
|
|
765
|
-
* Supports two patterns:
|
|
766
|
-
*
|
|
767
|
-
* 1. Lazy loading (code-split):
|
|
768
|
-
* ```typescript
|
|
769
|
-
* .routes(homeRoutes)
|
|
770
|
-
* .map(() => import("./handlers/home"))
|
|
771
|
-
* ```
|
|
772
|
-
*
|
|
773
|
-
* 2. Inline definition:
|
|
774
|
-
* ```typescript
|
|
775
|
-
* .routes({ index: "/", about: "/about" })
|
|
776
|
-
* .map(({ route }) => [
|
|
777
|
-
* route("index", () => <HomePage />),
|
|
778
|
-
* route("about", () => <AboutPage />),
|
|
779
|
-
* ])
|
|
780
|
-
* ```
|
|
781
|
-
*/
|
|
782
|
-
// Inline definition overload - handler receives helpers (must be first for correct inference)
|
|
783
|
-
// Uses TLocalRoutes so route names don't need the prefix
|
|
784
|
-
map<
|
|
785
|
-
H extends (
|
|
786
|
-
helpers: InlineRouteHelpers<TLocalRoutes, TEnv>,
|
|
787
|
-
) => Array<AllUseItems>,
|
|
788
|
-
>(
|
|
789
|
-
handler: H,
|
|
790
|
-
): RSCRouter<TEnv, TRoutes>;
|
|
791
|
-
// Lazy loading overload - verifies imported handlers match route definition
|
|
792
|
-
map(
|
|
793
|
-
handler: () =>
|
|
794
|
-
| Array<AllUseItems>
|
|
795
|
-
| Promise<{ default: RouteHandlers<TLocalRoutes> }>
|
|
796
|
-
| Promise<RouteHandlers<TLocalRoutes>>,
|
|
797
|
-
): RSCRouter<TEnv, TRoutes>;
|
|
798
|
-
|
|
799
|
-
/**
|
|
800
|
-
* Accumulated route map for typeof extraction
|
|
801
|
-
* Used for module augmentation: `type AppRoutes = typeof _router.routeMap`
|
|
802
|
-
*/
|
|
803
|
-
readonly routeMap: TRoutes;
|
|
804
|
-
}
|
|
805
|
-
|
|
806
|
-
/**
|
|
807
|
-
* RSC Router interface
|
|
808
|
-
* TRoutes accumulates all registered route types through the builder chain
|
|
809
|
-
*/
|
|
810
|
-
export interface RSCRouter<
|
|
811
|
-
TEnv = any,
|
|
812
|
-
TRoutes extends Record<string, unknown> = Record<string, string>,
|
|
813
|
-
> {
|
|
814
|
-
/**
|
|
815
|
-
* Brand marker for build-time discovery.
|
|
816
|
-
* The Vite plugin uses this to identify router instances in module exports.
|
|
817
|
-
*/
|
|
818
|
-
readonly __brand: typeof RSC_ROUTER_BRAND;
|
|
819
|
-
|
|
820
|
-
/**
|
|
821
|
-
* Unique identifier for this router instance.
|
|
822
|
-
* Used to namespace static output and isolate route maps between routers.
|
|
823
|
-
*/
|
|
824
|
-
readonly id: string;
|
|
825
|
-
|
|
826
|
-
/**
|
|
827
|
-
* Register routes with a prefix
|
|
828
|
-
* Route keys stay unchanged, only URL patterns get the prefix applied.
|
|
829
|
-
* This enables composable route modules that work regardless of mount point.
|
|
830
|
-
*
|
|
831
|
-
* @throws Compile-time error if route keys conflict with previously registered routes
|
|
832
|
-
*/
|
|
833
|
-
routes<const TPrefix extends string, const T extends Record<string, string>>(
|
|
834
|
-
prefix: TPrefix,
|
|
835
|
-
routes: T,
|
|
836
|
-
): ConflictingKeys<TRoutes, PrefixRoutePatterns<T, TPrefix>> extends never
|
|
837
|
-
? RouteBuilder<
|
|
838
|
-
RouteDefinition,
|
|
839
|
-
TEnv,
|
|
840
|
-
TRoutes & PrefixRoutePatterns<T, TPrefix>,
|
|
841
|
-
T
|
|
842
|
-
>
|
|
843
|
-
: RouteConflictError<
|
|
844
|
-
ConflictingKeys<TRoutes, PrefixRoutePatterns<T, TPrefix>> & string
|
|
845
|
-
>;
|
|
846
|
-
|
|
847
|
-
/**
|
|
848
|
-
* Register routes without a prefix
|
|
849
|
-
* Route types are accumulated through the chain
|
|
850
|
-
*
|
|
851
|
-
* @throws Compile-time error if route keys conflict with previously registered routes
|
|
852
|
-
*/
|
|
853
|
-
routes<const T extends Record<string, string>>(
|
|
854
|
-
routes: T,
|
|
855
|
-
): ConflictingKeys<TRoutes, T> extends never
|
|
856
|
-
? RouteBuilder<RouteDefinition, TEnv, TRoutes & T, T>
|
|
857
|
-
: RouteConflictError<ConflictingKeys<TRoutes, T> & string>;
|
|
858
|
-
|
|
859
|
-
/**
|
|
860
|
-
* Register routes using Django-style URL patterns
|
|
861
|
-
* This is the new API for @rangojs/router - call once with urls() result
|
|
862
|
-
*
|
|
863
|
-
* @example
|
|
864
|
-
* ```typescript
|
|
865
|
-
* createRouter({})
|
|
866
|
-
* .routes(urlpatterns) // Single call with urls() result
|
|
867
|
-
* ```
|
|
868
|
-
*/
|
|
869
|
-
routes<T extends UrlPatterns<TEnv, any>>(
|
|
870
|
-
patterns: T,
|
|
871
|
-
): RSCRouter<
|
|
872
|
-
TEnv,
|
|
873
|
-
TRoutes &
|
|
874
|
-
(NonNullable<T["_routes"]> extends Record<string, unknown>
|
|
875
|
-
? MergeRoutesWithResponses<NonNullable<T["_routes"]>, T["_responses"]>
|
|
876
|
-
: Record<string, string>)
|
|
877
|
-
>;
|
|
878
|
-
|
|
879
|
-
/**
|
|
880
|
-
* Add global middleware that runs on all routes
|
|
881
|
-
* Position matters: middleware before any .routes() is global
|
|
882
|
-
*
|
|
883
|
-
* @example
|
|
884
|
-
* ```typescript
|
|
885
|
-
* createRouter({ document: RootLayout })
|
|
886
|
-
* .use(loggerMiddleware) // All routes
|
|
887
|
-
* .use("/api/*", rateLimiter) // Pattern match
|
|
888
|
-
* .routes(homeRoutes)
|
|
889
|
-
* .map(() => import("./home"))
|
|
890
|
-
* ```
|
|
891
|
-
*/
|
|
892
|
-
use(
|
|
893
|
-
patternOrMiddleware: string | MiddlewareFn<TEnv>,
|
|
894
|
-
middleware?: MiddlewareFn<TEnv>,
|
|
895
|
-
): RSCRouter<TEnv, TRoutes>;
|
|
896
|
-
|
|
897
|
-
/**
|
|
898
|
-
* Type-safe URL builder for registered routes
|
|
899
|
-
* Types are inferred from the accumulated route registrations
|
|
900
|
-
* Route keys stay unchanged regardless of mount prefix.
|
|
901
|
-
*
|
|
902
|
-
* @example
|
|
903
|
-
* ```typescript
|
|
904
|
-
* // Given: .routes("/shop", { cart: "/cart", detail: "/product/:slug" })
|
|
905
|
-
* router.reverse("cart"); // "/shop/cart"
|
|
906
|
-
* router.reverse("detail", { slug: "widget" }); // "/shop/product/widget"
|
|
907
|
-
* ```
|
|
908
|
-
*/
|
|
909
|
-
reverse: ReverseFunction<TRoutes>;
|
|
910
|
-
|
|
911
|
-
/**
|
|
912
|
-
* Accumulated route map for typeof extraction
|
|
913
|
-
* Used for module augmentation: `type AppRoutes = typeof _router.routeMap`
|
|
914
|
-
*
|
|
915
|
-
* @example
|
|
916
|
-
* ```typescript
|
|
917
|
-
* const _router = createRouter<AppEnv>()
|
|
918
|
-
* .routes(homeRoutes).map(() => import('./home'))
|
|
919
|
-
* .routes('/shop', shopRoutes).map(() => import('./shop'));
|
|
920
|
-
*
|
|
921
|
-
* type AppRoutes = typeof _router.routeMap;
|
|
922
|
-
*
|
|
923
|
-
* declare global {
|
|
924
|
-
* namespace RSCRouter {
|
|
925
|
-
* interface RegisteredRoutes extends AppRoutes {}
|
|
926
|
-
* }
|
|
927
|
-
* }
|
|
928
|
-
* ```
|
|
929
|
-
*/
|
|
930
|
-
readonly routeMap: TRoutes;
|
|
931
|
-
|
|
932
|
-
/**
|
|
933
|
-
* Root layout component that wraps the entire application
|
|
934
|
-
* Access this to pass to renderSegments
|
|
935
|
-
*/
|
|
936
|
-
readonly rootLayout?: ComponentType<RootLayoutProps>;
|
|
937
|
-
|
|
938
|
-
/**
|
|
939
|
-
* Error callback for monitoring/alerting
|
|
940
|
-
* Called when errors occur in loaders, actions, or routes
|
|
941
|
-
*/
|
|
942
|
-
readonly onError?: RSCRouterOptions<TEnv>["onError"];
|
|
943
|
-
|
|
944
|
-
/**
|
|
945
|
-
* Cache configuration (for internal use by RSC handler)
|
|
946
|
-
*/
|
|
947
|
-
readonly cache?: RSCRouterOptions<TEnv>["cache"];
|
|
948
|
-
|
|
949
|
-
/**
|
|
950
|
-
* Not found component to render when no route matches (for internal use by RSC handler)
|
|
951
|
-
*/
|
|
952
|
-
readonly notFound?: RSCRouterOptions<TEnv>["notFound"];
|
|
953
|
-
|
|
954
|
-
/**
|
|
955
|
-
* Resolved theme configuration (null if theme not enabled)
|
|
956
|
-
* Used by NavigationProvider to include ThemeProvider and by MetaTags to render theme script
|
|
957
|
-
*/
|
|
958
|
-
readonly themeConfig: import("./theme/types.js").ResolvedThemeConfig | null;
|
|
959
|
-
|
|
960
|
-
/**
|
|
961
|
-
* Whether connection warmup is enabled.
|
|
962
|
-
* When true, the client sends HEAD /?_rsc_warmup after idle periods
|
|
963
|
-
* and the server responds with 204 No Content.
|
|
964
|
-
*/
|
|
965
|
-
readonly warmupEnabled: boolean;
|
|
966
|
-
|
|
967
|
-
/**
|
|
968
|
-
* Whether ?__debug_manifest is allowed in production.
|
|
969
|
-
* Always enabled in development.
|
|
970
|
-
* @internal
|
|
971
|
-
*/
|
|
972
|
-
readonly allowDebugManifest: boolean;
|
|
973
|
-
|
|
974
|
-
/**
|
|
975
|
-
* App-level middleware entries (for internal use by RSC handler)
|
|
976
|
-
* These wrap the entire request/response cycle
|
|
977
|
-
*/
|
|
978
|
-
readonly middleware: MiddlewareEntry<TEnv>[];
|
|
979
|
-
|
|
980
|
-
/**
|
|
981
|
-
* Nonce provider for CSP (for internal use by createHandler)
|
|
982
|
-
*/
|
|
983
|
-
readonly nonce?: NonceProvider<TEnv>;
|
|
984
|
-
|
|
985
|
-
/**
|
|
986
|
-
* RSC version string (for internal use by createHandler)
|
|
987
|
-
*/
|
|
988
|
-
readonly version?: string;
|
|
989
|
-
|
|
990
|
-
/**
|
|
991
|
-
* URL patterns reference for build-time manifest generation
|
|
992
|
-
* @internal
|
|
993
|
-
*/
|
|
994
|
-
readonly urlpatterns?: UrlPatterns<TEnv, any>;
|
|
995
|
-
|
|
996
|
-
/**
|
|
997
|
-
* Source file path where createRouter() was called.
|
|
998
|
-
* Set via Error.stack parsing at construction time.
|
|
999
|
-
* Used by the Vite plugin to write per-router named-routes.gen.ts files.
|
|
1000
|
-
* @internal
|
|
1001
|
-
*/
|
|
1002
|
-
readonly __sourceFile?: string;
|
|
1003
|
-
|
|
1004
|
-
match(request: Request, context: TEnv): Promise<MatchResult>;
|
|
1005
|
-
|
|
1006
|
-
/**
|
|
1007
|
-
* Build-time pre-render match. Resolves segments with a BuildContext
|
|
1008
|
-
* (no request/env/headers/cookies), skipping middleware and loaders.
|
|
1009
|
-
* Used by the Vite plugin to collect pre-render data at build time.
|
|
1010
|
-
* @internal
|
|
1011
|
-
*/
|
|
1012
|
-
matchForPrerender(
|
|
1013
|
-
pathname: string,
|
|
1014
|
-
params: Record<string, string>,
|
|
1015
|
-
): Promise<{
|
|
1016
|
-
segments: SerializedSegmentData[];
|
|
1017
|
-
handles: Record<string, SegmentHandleData>;
|
|
1018
|
-
routeName: string;
|
|
1019
|
-
params: Record<string, string>;
|
|
1020
|
-
} | null>;
|
|
1021
|
-
|
|
1022
|
-
/**
|
|
1023
|
-
* Preview match - returns route middleware without segment resolution.
|
|
1024
|
-
* Also returns responseType and handler for response routes (non-RSC short-circuit).
|
|
1025
|
-
*/
|
|
1026
|
-
previewMatch(
|
|
1027
|
-
request: Request,
|
|
1028
|
-
context: TEnv,
|
|
1029
|
-
): Promise<{
|
|
1030
|
-
routeMiddleware?: Array<{
|
|
1031
|
-
handler: import("./router/middleware.js").MiddlewareFn;
|
|
1032
|
-
params: Record<string, string>;
|
|
1033
|
-
}>;
|
|
1034
|
-
responseType?: string;
|
|
1035
|
-
handler?: Function;
|
|
1036
|
-
params?: Record<string, string>;
|
|
1037
|
-
negotiated?: boolean;
|
|
1038
|
-
} | null>;
|
|
1039
|
-
|
|
1040
|
-
matchPartial(
|
|
1041
|
-
request: Request,
|
|
1042
|
-
context: TEnv,
|
|
1043
|
-
actionContext?: {
|
|
1044
|
-
actionId?: string;
|
|
1045
|
-
actionUrl?: URL;
|
|
1046
|
-
actionResult?: any;
|
|
1047
|
-
formData?: FormData;
|
|
1048
|
-
},
|
|
1049
|
-
): Promise<MatchResult | null>;
|
|
1050
|
-
|
|
1051
|
-
/**
|
|
1052
|
-
* Match an error to the nearest error boundary and return error segments
|
|
1053
|
-
*
|
|
1054
|
-
* Used when an action or other operation fails and we need to render
|
|
1055
|
-
* the error boundary UI. Finds the nearest errorBoundary in the route tree
|
|
1056
|
-
* for the current URL and renders it with the error info.
|
|
1057
|
-
*
|
|
1058
|
-
* @param request - The current request (used to match the route)
|
|
1059
|
-
* @param context - Environment context
|
|
1060
|
-
* @param error - The error that occurred
|
|
1061
|
-
* @param segmentType - Type of segment where error occurred (default: "route")
|
|
1062
|
-
* @returns MatchResult with error segment, or null if no error boundary found
|
|
1063
|
-
*/
|
|
1064
|
-
matchError(
|
|
1065
|
-
request: Request,
|
|
1066
|
-
context: TEnv,
|
|
1067
|
-
error: unknown,
|
|
1068
|
-
segmentType?: ErrorInfo["segmentType"],
|
|
1069
|
-
): Promise<MatchResult | null>;
|
|
1070
|
-
|
|
1071
|
-
/**
|
|
1072
|
-
* @internal
|
|
1073
|
-
* Debug utility to serialize the manifest for inspection
|
|
1074
|
-
* Returns a JSON-friendly representation of all routes and layouts
|
|
1075
|
-
*/
|
|
1076
|
-
debugManifest(): Promise<SerializedManifest>;
|
|
1077
|
-
|
|
1078
|
-
/**
|
|
1079
|
-
* Handle an RSC request.
|
|
1080
|
-
*
|
|
1081
|
-
* Uses the router's configuration (nonce, version, cache) automatically.
|
|
1082
|
-
* The handler is lazily created on first call.
|
|
1083
|
-
*
|
|
1084
|
-
* @example Cloudflare Workers
|
|
1085
|
-
* ```tsx
|
|
1086
|
-
* import { router } from "./router";
|
|
1087
|
-
*
|
|
1088
|
-
* export default { fetch: router.fetch };
|
|
1089
|
-
* ```
|
|
1090
|
-
*
|
|
1091
|
-
* @example Direct export
|
|
1092
|
-
* ```tsx
|
|
1093
|
-
* const router = createRouter({
|
|
1094
|
-
* document: Document,
|
|
1095
|
-
* urls: urlpatterns,
|
|
1096
|
-
* nonce: () => true,
|
|
1097
|
-
* });
|
|
1098
|
-
*
|
|
1099
|
-
* export const fetch = router.fetch;
|
|
1100
|
-
* ```
|
|
1101
|
-
*/
|
|
1102
|
-
fetch(
|
|
1103
|
-
request: Request,
|
|
1104
|
-
env: TEnv & { ctx?: ExecutionContext },
|
|
1105
|
-
): Promise<Response>;
|
|
1106
|
-
}
|
|
88
|
+
// Extracted router types and registry
|
|
89
|
+
import {
|
|
90
|
+
RSC_ROUTER_BRAND,
|
|
91
|
+
RouterRegistry,
|
|
92
|
+
nextRouterAutoId,
|
|
93
|
+
} from "./router/router-registry.js";
|
|
94
|
+
import type { RangoOptions, RootLayoutProps } from "./router/router-options.js";
|
|
95
|
+
import type {
|
|
96
|
+
Rango,
|
|
97
|
+
RangoInternal,
|
|
98
|
+
RouterRequestInput,
|
|
99
|
+
} from "./router/router-interfaces.js";
|
|
1107
100
|
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
101
|
+
// Extracted closure functions
|
|
102
|
+
import {
|
|
103
|
+
findLazyIncludes,
|
|
104
|
+
evaluateLazyEntry as _evaluateLazyEntry,
|
|
105
|
+
type LazyEvalDeps,
|
|
106
|
+
} from "./router/lazy-includes.js";
|
|
107
|
+
import { createFindMatch } from "./router/find-match.js";
|
|
108
|
+
import {
|
|
109
|
+
matchForPrerender as _matchForPrerender,
|
|
110
|
+
renderStaticSegment as _renderStaticSegment,
|
|
111
|
+
} from "./router/prerender-match.js";
|
|
112
|
+
import { resolveStateCookieName } from "./router/state-cookie-name.js";
|
|
113
|
+
|
|
114
|
+
// Re-export public types and values from extracted modules
|
|
115
|
+
export { RSC_ROUTER_BRAND, RouterRegistry } from "./router/router-registry.js";
|
|
116
|
+
export type {
|
|
117
|
+
RangoOptions,
|
|
118
|
+
RootLayoutProps,
|
|
119
|
+
SSRStreamMode,
|
|
120
|
+
SSROptions,
|
|
121
|
+
ResolveStreamingContext,
|
|
122
|
+
} from "./router/router-options.js";
|
|
123
|
+
export type {
|
|
124
|
+
Rango,
|
|
125
|
+
RangoInternal,
|
|
126
|
+
RouterRequestInput,
|
|
127
|
+
} from "./router/router-interfaces.js";
|
|
128
|
+
export { toInternal } from "./router/router-interfaces.js";
|
|
1136
129
|
|
|
1137
130
|
export function createRouter<TEnv = any>(
|
|
1138
|
-
options:
|
|
1139
|
-
):
|
|
131
|
+
options: RangoOptions<TEnv> = {},
|
|
132
|
+
): Rango<TEnv, {}> {
|
|
1140
133
|
const {
|
|
1141
134
|
id: userProvidedId,
|
|
1142
135
|
$$id: injectedId,
|
|
136
|
+
basename: basenameOption,
|
|
1143
137
|
debugPerformance = false,
|
|
1144
138
|
document: documentOption,
|
|
1145
139
|
defaultErrorBoundary,
|
|
@@ -1147,38 +141,106 @@ export function createRouter<TEnv = any>(
|
|
|
1147
141
|
notFound,
|
|
1148
142
|
onError,
|
|
1149
143
|
cache,
|
|
144
|
+
cacheProfiles: cacheProfilesOption,
|
|
1150
145
|
theme: themeOption,
|
|
1151
146
|
urls: urlsOption,
|
|
1152
147
|
$$routeNames: staticRouteNames,
|
|
148
|
+
$$sourceFile: injectedSourceFile,
|
|
1153
149
|
nonce,
|
|
1154
150
|
version,
|
|
151
|
+
prefetchCacheTTL: prefetchCacheTTLOption,
|
|
152
|
+
stateCookiePrefix: stateCookiePrefixOption,
|
|
1155
153
|
warmup: warmupOption,
|
|
1156
|
-
allowDebugManifest: allowDebugManifestOption =
|
|
154
|
+
allowDebugManifest: allowDebugManifestOption = false,
|
|
155
|
+
telemetry: telemetrySink,
|
|
156
|
+
tracing: tracingOption,
|
|
157
|
+
ssr: ssrOption,
|
|
158
|
+
timeout: timeoutShorthand,
|
|
159
|
+
timeouts: timeoutsOption,
|
|
160
|
+
onTimeout,
|
|
161
|
+
originCheck: originCheckOption,
|
|
162
|
+
viewTransition: viewTransitionOption = "auto",
|
|
163
|
+
debugCacheSignal: debugCacheSignalOption = false,
|
|
1157
164
|
} = options;
|
|
1158
165
|
|
|
1159
|
-
//
|
|
1160
|
-
//
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
166
|
+
// Debug cache signal gate (DEVELOPMENT/TEST ONLY). Enabled by the
|
|
167
|
+
// debugCacheSignal option OR the RANGO_TEST_SIGNALS=1 env flag. When off,
|
|
168
|
+
// no X-Rango-Cache header is emitted and output is byte-identical.
|
|
169
|
+
const cacheSignalEnabled =
|
|
170
|
+
debugCacheSignalOption ||
|
|
171
|
+
(typeof process !== "undefined" &&
|
|
172
|
+
(process as { env?: Record<string, string | undefined> }).env
|
|
173
|
+
?.RANGO_TEST_SIGNALS === "1");
|
|
174
|
+
|
|
175
|
+
// Normalize basename: ensure leading slash, strip trailing slash.
|
|
176
|
+
// A bare "/" is equivalent to no basename. Shared with the testing
|
|
177
|
+
// primitives via normalizeBasename so they can never drift.
|
|
178
|
+
const basename = normalizeBasename(basenameOption);
|
|
179
|
+
|
|
180
|
+
// Resolve telemetry sink (no-op when not configured)
|
|
181
|
+
const telemetry = resolveSink(telemetrySink);
|
|
182
|
+
|
|
183
|
+
// Resolve span tracing (undefined when not configured; every traceSpan() call
|
|
184
|
+
// is then a direct pass-through with zero behavior change).
|
|
185
|
+
const resolvedTracing = resolveTracing(tracingOption);
|
|
186
|
+
|
|
187
|
+
// Resolve cache profiles: merge user config with the guaranteed default
|
|
188
|
+
// profile. This resolved map is threaded onto each request context; the
|
|
189
|
+
// "use cache: <profile>" runtime path reads it request-scoped.
|
|
190
|
+
const resolvedCacheProfiles = resolveCacheProfiles(cacheProfilesOption);
|
|
191
|
+
|
|
192
|
+
// Source file: prefer Vite-injected path (zero cost), fall back to
|
|
193
|
+
// stack trace parsing for non-Vite environments (e.g. tests).
|
|
194
|
+
let __sourceFile: string | undefined = injectedSourceFile;
|
|
195
|
+
if (!__sourceFile) {
|
|
196
|
+
try {
|
|
197
|
+
const stack = new Error().stack;
|
|
198
|
+
if (stack) {
|
|
199
|
+
const lines = stack.split("\n");
|
|
200
|
+
for (const line of lines) {
|
|
201
|
+
const match = line.match(/\((.+?\.(ts|tsx|js|jsx)):\d+:\d+\)/);
|
|
202
|
+
if (
|
|
203
|
+
match &&
|
|
204
|
+
!match[1].endsWith("/router.ts") &&
|
|
205
|
+
!match[1].includes("@rangojs/router") &&
|
|
206
|
+
!match[1].includes("node_modules")
|
|
207
|
+
) {
|
|
208
|
+
__sourceFile = match[1].startsWith("file:")
|
|
209
|
+
? match[1].slice(5)
|
|
210
|
+
: match[1];
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
1172
213
|
}
|
|
1173
214
|
}
|
|
1174
|
-
}
|
|
1175
|
-
}
|
|
215
|
+
} catch {}
|
|
216
|
+
}
|
|
1176
217
|
|
|
1177
218
|
// Router ID priority: explicit id > Vite-injected $$id > counter fallback.
|
|
1178
219
|
// $$id is a hash of filename+line injected by the Vite transform at compile
|
|
1179
220
|
// time, so it's stable across build/runtime regardless of module evaluation
|
|
1180
221
|
// order (unlike the counter which depends on import order).
|
|
1181
|
-
const routerId =
|
|
222
|
+
const routerId =
|
|
223
|
+
userProvidedId ?? injectedId ?? `router_${nextRouterAutoId()}`;
|
|
224
|
+
|
|
225
|
+
// Resolve the rango state cookie name once, here, so the two cookie writers
|
|
226
|
+
// (the client document.cookie writer and the server Set-Cookie writer)
|
|
227
|
+
// consume one pre-composed name and cannot drift.
|
|
228
|
+
const resolvedStateCookieName = resolveStateCookieName(
|
|
229
|
+
stateCookiePrefixOption,
|
|
230
|
+
routerId,
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
// Resolve prefetch cache TTL (default: 300 seconds / 5 minutes)
|
|
234
|
+
// Clamp to a non-negative integer for valid Cache-Control max-age.
|
|
235
|
+
const rawTTL =
|
|
236
|
+
prefetchCacheTTLOption !== undefined ? prefetchCacheTTLOption : 300;
|
|
237
|
+
const prefetchCacheTTLSeconds =
|
|
238
|
+
rawTTL === false ? 0 : Math.max(0, Math.floor(rawTTL));
|
|
239
|
+
const prefetchCacheTTL = prefetchCacheTTLSeconds * 1000;
|
|
240
|
+
const prefetchCacheControl: string | false =
|
|
241
|
+
prefetchCacheTTLSeconds === 0
|
|
242
|
+
? false
|
|
243
|
+
: `private, max-age=${prefetchCacheTTLSeconds}`;
|
|
1182
244
|
|
|
1183
245
|
// Resolve warmup enabled flag (default: true)
|
|
1184
246
|
const warmupEnabled = warmupOption !== false;
|
|
@@ -1188,21 +250,40 @@ export function createRouter<TEnv = any>(
|
|
|
1188
250
|
? resolveThemeConfig(themeOption)
|
|
1189
251
|
: null;
|
|
1190
252
|
|
|
253
|
+
// Resolve timeout config (merge shorthand + structured)
|
|
254
|
+
const resolvedTimeouts = resolveTimeouts(timeoutShorthand, timeoutsOption);
|
|
255
|
+
|
|
1191
256
|
/**
|
|
1192
257
|
* Wrapper for invokeOnError that binds the router's onError callback.
|
|
1193
258
|
* Uses the shared utility from router/error-handling.ts for consistent behavior.
|
|
259
|
+
*
|
|
260
|
+
* Deduplicates via per-request WeakSet stored on the ALS request context.
|
|
261
|
+
* A closure-level WeakSet would silently swallow errors if the same object
|
|
262
|
+
* instance is thrown across separate requests (e.g. a singleton error).
|
|
1194
263
|
*/
|
|
1195
264
|
function callOnError(
|
|
1196
265
|
error: unknown,
|
|
1197
266
|
phase: ErrorPhase,
|
|
1198
267
|
context: Parameters<typeof invokeOnError<TEnv>>[3],
|
|
1199
268
|
): void {
|
|
269
|
+
if (error != null && typeof error === "object") {
|
|
270
|
+
const reportedErrors = _getRequestContext()?._reportedErrors;
|
|
271
|
+
if (reportedErrors) {
|
|
272
|
+
if (reportedErrors.has(error)) return;
|
|
273
|
+
reportedErrors.add(error);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
1200
276
|
invokeOnError(onError, error, phase, context, "Router");
|
|
1201
277
|
}
|
|
1202
278
|
|
|
1203
|
-
// Validate document is a client component
|
|
279
|
+
// Validate document is a client component. Under a test runner the "use
|
|
280
|
+
// client" transform has not run, so a real exported document has no marker;
|
|
281
|
+
// allowServerInTest lets the router construct in a bare unit test (for
|
|
282
|
+
// dispatch / assertGeneratedRoutesMatch) while a real build still throws.
|
|
1204
283
|
if (documentOption !== undefined) {
|
|
1205
|
-
assertClientComponent(documentOption, "document"
|
|
284
|
+
assertClientComponent(documentOption, "document", {
|
|
285
|
+
allowServerInTest: true,
|
|
286
|
+
});
|
|
1206
287
|
}
|
|
1207
288
|
|
|
1208
289
|
// Use default document if none provided (keeps internal name as rootLayout)
|
|
@@ -1239,6 +320,18 @@ export function createRouter<TEnv = any>(
|
|
|
1239
320
|
handler = patternOrMiddleware;
|
|
1240
321
|
}
|
|
1241
322
|
|
|
323
|
+
// Prevent "use cache" functions from being used as middleware.
|
|
324
|
+
// They return data/JSX and do not call next() — silently accepting
|
|
325
|
+
// them would be a confusing no-op.
|
|
326
|
+
if (isCachedFunction(handler)) {
|
|
327
|
+
throw new Error(
|
|
328
|
+
`A "use cache" function cannot be used as middleware. ` +
|
|
329
|
+
`Cached functions return data and do not participate in the ` +
|
|
330
|
+
`middleware chain. Remove the "use cache" directive or use a ` +
|
|
331
|
+
`regular middleware function instead.`,
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
|
|
1242
335
|
// If mount-scoped, prepend mount prefix to pattern
|
|
1243
336
|
let fullPattern = pattern;
|
|
1244
337
|
if (mountPrefix && pattern) {
|
|
@@ -1264,836 +357,264 @@ export function createRouter<TEnv = any>(
|
|
|
1264
357
|
regex,
|
|
1265
358
|
paramNames,
|
|
1266
359
|
handler,
|
|
1267
|
-
mountPrefix,
|
|
1268
360
|
});
|
|
1269
361
|
}
|
|
1270
362
|
|
|
1271
|
-
// Track all registered routes with their prefixes for reverse()
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
// ensureRouterManifest(). At createRouter() time the data isn't available yet,
|
|
1277
|
-
// so we defer building the Map until first use and invalidate when the
|
|
1278
|
-
// per-router source changes.
|
|
1279
|
-
let precomputedByPrefix: Map<string, Record<string, string>> | null = null;
|
|
1280
|
-
let precomputedSource: Array<{ staticPrefix: string; routes: Record<string, string> }> | null | undefined;
|
|
1281
|
-
|
|
1282
|
-
function getPrecomputedByPrefix(): Map<string, Record<string, string>> | null {
|
|
1283
|
-
const current = getRouterPrecomputedEntries(routerId) ?? getPrecomputedEntries();
|
|
1284
|
-
if (current !== precomputedSource) {
|
|
1285
|
-
precomputedSource = current;
|
|
1286
|
-
precomputedByPrefix = current
|
|
1287
|
-
? new Map(current.map((e) => [e.staticPrefix, e.routes]))
|
|
1288
|
-
: null;
|
|
1289
|
-
}
|
|
1290
|
-
return precomputedByPrefix;
|
|
1291
|
-
}
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
// Wrapper to pass debugPerformance to external createMetricsStore
|
|
1295
|
-
const getMetricsStore = () => createMetricsStore(debugPerformance);
|
|
1296
|
-
|
|
1297
|
-
// Wrapper to pass defaults to error/notFound boundary finders
|
|
1298
|
-
const findNearestErrorBoundary = (entry: EntryData | null) =>
|
|
1299
|
-
findErrorBoundary(entry, defaultErrorBoundary);
|
|
1300
|
-
|
|
1301
|
-
const findNearestNotFoundBoundary = (entry: EntryData | null) =>
|
|
1302
|
-
findNotFoundBoundary(entry, defaultNotFoundBoundary);
|
|
1303
|
-
|
|
1304
|
-
// Helper to get handleStore from request context
|
|
1305
|
-
const getHandleStore = (): HandleStore | undefined => {
|
|
1306
|
-
return getRequestContext()?._handleStore;
|
|
1307
|
-
};
|
|
1308
|
-
|
|
1309
|
-
// Track a pending handler promise (non-blocking)
|
|
1310
|
-
const trackHandler = <T>(promise: Promise<T>): Promise<T> => {
|
|
1311
|
-
const store = getHandleStore();
|
|
1312
|
-
return store ? store.track(promise) : promise;
|
|
1313
|
-
};
|
|
1314
|
-
|
|
1315
|
-
// Wrapper for wrapLoaderWithErrorHandling that uses router's error boundary finder
|
|
1316
|
-
// Includes onError callback for loader error notification
|
|
1317
|
-
function wrapLoaderPromise<T>(
|
|
1318
|
-
promise: Promise<T>,
|
|
1319
|
-
entry: EntryData,
|
|
1320
|
-
segmentId: string,
|
|
1321
|
-
pathname: string,
|
|
1322
|
-
errorContext?: {
|
|
1323
|
-
request: Request;
|
|
1324
|
-
url: URL;
|
|
1325
|
-
routeKey?: string;
|
|
1326
|
-
params?: Record<string, string>;
|
|
1327
|
-
env?: TEnv;
|
|
1328
|
-
isPartial?: boolean;
|
|
1329
|
-
requestStartTime?: number;
|
|
1330
|
-
},
|
|
1331
|
-
): Promise<LoaderDataResult<T>> {
|
|
1332
|
-
return wrapLoaderWithErrorHandling(
|
|
1333
|
-
promise,
|
|
1334
|
-
entry,
|
|
1335
|
-
segmentId,
|
|
1336
|
-
pathname,
|
|
1337
|
-
findNearestErrorBoundary,
|
|
1338
|
-
createErrorInfo,
|
|
1339
|
-
// Invoke onError when loader fails
|
|
1340
|
-
errorContext
|
|
1341
|
-
? (error, ctx) => {
|
|
1342
|
-
callOnError(error, "loader", {
|
|
1343
|
-
request: errorContext.request,
|
|
1344
|
-
url: errorContext.url,
|
|
1345
|
-
routeKey: errorContext.routeKey,
|
|
1346
|
-
params: errorContext.params,
|
|
1347
|
-
segmentId: ctx.segmentId,
|
|
1348
|
-
segmentType: "loader",
|
|
1349
|
-
loaderName: ctx.loaderName,
|
|
1350
|
-
env: errorContext.env,
|
|
1351
|
-
isPartial: errorContext.isPartial,
|
|
1352
|
-
handledByBoundary: ctx.handledByBoundary,
|
|
1353
|
-
requestStartTime: errorContext.requestStartTime,
|
|
1354
|
-
});
|
|
1355
|
-
}
|
|
1356
|
-
: undefined,
|
|
1357
|
-
);
|
|
1358
|
-
}
|
|
1359
|
-
|
|
1360
|
-
// Dependencies object for extracted segment resolution functions.
|
|
1361
|
-
// Captures closure-bound helpers from createRouter.
|
|
1362
|
-
const segmentDeps: SegmentResolutionDeps<TEnv> = {
|
|
1363
|
-
wrapLoaderPromise,
|
|
1364
|
-
trackHandler,
|
|
1365
|
-
findNearestErrorBoundary,
|
|
1366
|
-
findNearestNotFoundBoundary,
|
|
1367
|
-
callOnError,
|
|
1368
|
-
};
|
|
1369
|
-
|
|
1370
|
-
// Match API dependencies
|
|
1371
|
-
const matchApiDeps: MatchApiDeps<TEnv> = {
|
|
1372
|
-
findMatch: (pathname: string, ms?: any) => findMatch(pathname, ms),
|
|
1373
|
-
getMetricsStore,
|
|
1374
|
-
findInterceptForRoute: (routeKey, parentEntry, selectorContext, isAction) =>
|
|
1375
|
-
findInterceptForRoute(routeKey, parentEntry, selectorContext, isAction),
|
|
1376
|
-
callOnError,
|
|
1377
|
-
findNearestErrorBoundary,
|
|
1378
|
-
getRouteMap: () => getRouterManifest(routerId) ?? getGlobalRouteMap(),
|
|
1379
|
-
};
|
|
1380
|
-
|
|
1381
|
-
// Thin wrappers that bind the deps to extracted functions.
|
|
1382
|
-
// These maintain the same signatures as the original inline functions
|
|
1383
|
-
// so that RouterContext and call sites don't need to change.
|
|
1384
|
-
|
|
1385
|
-
function resolveAllSegments(
|
|
1386
|
-
entries: EntryData[],
|
|
1387
|
-
routeKey: string,
|
|
1388
|
-
params: Record<string, string>,
|
|
1389
|
-
context: HandlerContext<any, TEnv>,
|
|
1390
|
-
loaderPromises: Map<string, Promise<any>>,
|
|
1391
|
-
options?: { skipLoaders?: boolean },
|
|
1392
|
-
) {
|
|
1393
|
-
return _resolveAllSegments(entries, routeKey, params, context, loaderPromises, segmentDeps, options);
|
|
1394
|
-
}
|
|
1395
|
-
|
|
1396
|
-
function resolveLoadersOnly(
|
|
1397
|
-
entries: EntryData[],
|
|
1398
|
-
context: HandlerContext<any, TEnv>,
|
|
1399
|
-
) {
|
|
1400
|
-
return _resolveLoadersOnly(entries, context, segmentDeps);
|
|
1401
|
-
}
|
|
1402
|
-
|
|
1403
|
-
function resolveLoadersOnlyWithRevalidation(
|
|
1404
|
-
entries: EntryData[],
|
|
1405
|
-
context: HandlerContext<any, TEnv>,
|
|
1406
|
-
clientSegmentIds: Set<string>,
|
|
1407
|
-
prevParams: Record<string, string>,
|
|
1408
|
-
request: Request,
|
|
1409
|
-
prevUrl: URL,
|
|
1410
|
-
nextUrl: URL,
|
|
1411
|
-
routeKey: string,
|
|
1412
|
-
actionContext?: { actionId?: string; actionUrl?: URL; actionResult?: any; formData?: FormData },
|
|
1413
|
-
) {
|
|
1414
|
-
return _resolveLoadersOnlyWithRevalidation(
|
|
1415
|
-
entries, context, clientSegmentIds, prevParams, request,
|
|
1416
|
-
prevUrl, nextUrl, routeKey, segmentDeps, actionContext,
|
|
1417
|
-
);
|
|
1418
|
-
}
|
|
1419
|
-
|
|
1420
|
-
function buildEntryRevalidateMap(entries: EntryData[]) {
|
|
1421
|
-
return _buildEntryRevalidateMap(entries);
|
|
1422
|
-
}
|
|
1423
|
-
|
|
1424
|
-
function resolveAllSegmentsWithRevalidation(
|
|
1425
|
-
entries: EntryData[],
|
|
1426
|
-
routeKey: string,
|
|
1427
|
-
params: Record<string, string>,
|
|
1428
|
-
context: HandlerContext<any, TEnv>,
|
|
1429
|
-
clientSegmentSet: Set<string>,
|
|
1430
|
-
prevParams: Record<string, string>,
|
|
1431
|
-
request: Request,
|
|
1432
|
-
prevUrl: URL,
|
|
1433
|
-
nextUrl: URL,
|
|
1434
|
-
loaderPromises: Map<string, Promise<any>>,
|
|
1435
|
-
actionContext: { actionId?: string; actionUrl?: URL; actionResult?: any; formData?: FormData } | undefined,
|
|
1436
|
-
interceptResult: { intercept: InterceptEntry; entry: EntryData } | null,
|
|
1437
|
-
localRouteName: string,
|
|
1438
|
-
pathname: string,
|
|
1439
|
-
) {
|
|
1440
|
-
return _resolveAllSegmentsWithRevalidation(
|
|
1441
|
-
entries, routeKey, params, context, clientSegmentSet, prevParams, request,
|
|
1442
|
-
prevUrl, nextUrl, loaderPromises, actionContext, interceptResult,
|
|
1443
|
-
localRouteName, pathname, segmentDeps,
|
|
1444
|
-
);
|
|
1445
|
-
}
|
|
1446
|
-
|
|
1447
|
-
function findInterceptForRoute(
|
|
1448
|
-
targetRouteKey: string,
|
|
1449
|
-
fromEntry: EntryData | null,
|
|
1450
|
-
selectorContext: InterceptSelectorContext | null = null,
|
|
1451
|
-
isAction: boolean = false,
|
|
1452
|
-
) {
|
|
1453
|
-
return _findInterceptForRoute(targetRouteKey, fromEntry, selectorContext, isAction);
|
|
1454
|
-
}
|
|
1455
|
-
|
|
1456
|
-
function resolveInterceptEntry(
|
|
1457
|
-
interceptEntry: InterceptEntry,
|
|
1458
|
-
parentEntry: EntryData,
|
|
1459
|
-
params: Record<string, string>,
|
|
1460
|
-
context: HandlerContext<any, TEnv>,
|
|
1461
|
-
belongsToRoute: boolean = true,
|
|
1462
|
-
revalidationContext?: any,
|
|
1463
|
-
) {
|
|
1464
|
-
return _resolveInterceptEntry(
|
|
1465
|
-
interceptEntry, parentEntry, params, context, belongsToRoute,
|
|
1466
|
-
segmentDeps, revalidationContext,
|
|
1467
|
-
);
|
|
1468
|
-
}
|
|
1469
|
-
|
|
1470
|
-
function resolveInterceptLoadersOnly(
|
|
1471
|
-
interceptEntry: InterceptEntry,
|
|
1472
|
-
parentEntry: EntryData,
|
|
1473
|
-
params: Record<string, string>,
|
|
1474
|
-
context: HandlerContext<any, TEnv>,
|
|
1475
|
-
belongsToRoute: boolean = true,
|
|
1476
|
-
revalidationContext: any,
|
|
1477
|
-
) {
|
|
1478
|
-
return _resolveInterceptLoadersOnly(
|
|
1479
|
-
interceptEntry, parentEntry, params, context, belongsToRoute,
|
|
1480
|
-
segmentDeps, revalidationContext,
|
|
1481
|
-
);
|
|
1482
|
-
}
|
|
1483
|
-
|
|
1484
|
-
// Detect lazy includes in handler result and create placeholder entries
|
|
1485
|
-
// Lazy includes are IncludeItem with lazy: true and _lazyContext
|
|
1486
|
-
// Moved to outer scope so it can be reused by evaluateLazyEntry for nested includes
|
|
1487
|
-
function findLazyIncludes(items: AllUseItems[]): Array<{
|
|
1488
|
-
prefix: string;
|
|
1489
|
-
patterns: UrlPatterns<TEnv>;
|
|
1490
|
-
context: {
|
|
1491
|
-
urlPrefix: string;
|
|
1492
|
-
namePrefix: string | undefined;
|
|
1493
|
-
parent: unknown;
|
|
1494
|
-
};
|
|
1495
|
-
}> {
|
|
1496
|
-
const lazyItems: Array<{
|
|
1497
|
-
prefix: string;
|
|
1498
|
-
patterns: UrlPatterns<TEnv>;
|
|
1499
|
-
context: {
|
|
1500
|
-
urlPrefix: string;
|
|
1501
|
-
namePrefix: string | undefined;
|
|
1502
|
-
parent: unknown;
|
|
1503
|
-
};
|
|
1504
|
-
}> = [];
|
|
1505
|
-
|
|
1506
|
-
for (const item of items) {
|
|
1507
|
-
if (!item) continue;
|
|
1508
|
-
if (item.type === "include") {
|
|
1509
|
-
const includeItem = item as IncludeItem;
|
|
1510
|
-
if (includeItem.lazy === true && includeItem._lazyContext) {
|
|
1511
|
-
lazyItems.push({
|
|
1512
|
-
prefix: includeItem.prefix,
|
|
1513
|
-
patterns: includeItem.patterns as UrlPatterns<TEnv>,
|
|
1514
|
-
context: includeItem._lazyContext,
|
|
1515
|
-
});
|
|
1516
|
-
}
|
|
1517
|
-
}
|
|
1518
|
-
// Recursively check nested items (in layouts, etc.)
|
|
1519
|
-
if ((item as any).uses && Array.isArray((item as any).uses)) {
|
|
1520
|
-
lazyItems.push(...findLazyIncludes((item as any).uses));
|
|
1521
|
-
}
|
|
1522
|
-
}
|
|
1523
|
-
|
|
1524
|
-
return lazyItems;
|
|
1525
|
-
}
|
|
1526
|
-
|
|
1527
|
-
/**
|
|
1528
|
-
* Evaluate a lazy entry's patterns and populate its routes
|
|
1529
|
-
* This runs the lazy patterns handler and updates the entry in-place
|
|
1530
|
-
* Also detects nested lazy includes and registers them as new entries
|
|
1531
|
-
*/
|
|
1532
|
-
function evaluateLazyEntry(entry: RouteEntry<TEnv>): void {
|
|
1533
|
-
if (!entry.lazy || entry.lazyEvaluated || !entry.lazyPatterns) {
|
|
1534
|
-
return;
|
|
1535
|
-
}
|
|
1536
|
-
|
|
1537
|
-
// Check for pre-computed routes from build-time data.
|
|
1538
|
-
// Only leaf nodes (no nested includes) are precomputed, so entries with
|
|
1539
|
-
// nested lazy includes fall through to the handler below.
|
|
1540
|
-
// When multiple entries share the same staticPrefix (e.g., several
|
|
1541
|
-
// include("/", ...) calls), the precomputed data merges all their routes
|
|
1542
|
-
// into one entry. Assigning that merged set to the first matching entry
|
|
1543
|
-
// causes findMatch to pick the wrong handler for routes belonging to a
|
|
1544
|
-
// different include. Skip the shortcut when the prefix is shared.
|
|
1545
|
-
const currentPrecomputed = getPrecomputedByPrefix();
|
|
1546
|
-
if (currentPrecomputed) {
|
|
1547
|
-
const routes = currentPrecomputed.get(entry.staticPrefix);
|
|
1548
|
-
if (routes) {
|
|
1549
|
-
const prefixIsShared = routesEntries.filter(
|
|
1550
|
-
(e) => e.staticPrefix === entry.staticPrefix,
|
|
1551
|
-
).length > 1;
|
|
1552
|
-
if (!prefixIsShared) {
|
|
1553
|
-
entry.lazyEvaluated = true;
|
|
1554
|
-
entry.routes = routes as ResolvedRouteMap<any>;
|
|
1555
|
-
for (const [name, pattern] of Object.entries(routes)) {
|
|
1556
|
-
mergedRouteMap[name] = pattern;
|
|
1557
|
-
}
|
|
1558
|
-
registerRouteMap(mergedRouteMap);
|
|
1559
|
-
return;
|
|
1560
|
-
}
|
|
1561
|
-
}
|
|
1562
|
-
}
|
|
1563
|
-
|
|
1564
|
-
// Mark as evaluated immediately to prevent concurrent evaluation.
|
|
1565
|
-
// JS is single-threaded but handlers.handler() could theoretically yield,
|
|
1566
|
-
// and the while-loop in findMatch retries after evaluation.
|
|
1567
|
-
entry.lazyEvaluated = true;
|
|
1568
|
-
|
|
1569
|
-
const lazyPatterns = entry.lazyPatterns as UrlPatterns<TEnv>;
|
|
1570
|
-
const lazyContext = entry.lazyContext;
|
|
1571
|
-
|
|
1572
|
-
// Create a new context for evaluating the lazy patterns
|
|
1573
|
-
const manifest = new Map<string, EntryData>();
|
|
1574
|
-
const patterns = new Map<string, string>();
|
|
1575
|
-
const patternsByPrefix = new Map<string, Map<string, string>>();
|
|
1576
|
-
const trailingSlashMap = new Map<string, TrailingSlashMode>();
|
|
1577
|
-
|
|
1578
|
-
// Capture the handler result to detect nested lazy includes
|
|
1579
|
-
let handlerResult: AllUseItems[] = [];
|
|
1580
|
-
|
|
1581
|
-
// Merge captured counters from include() to maintain consistent
|
|
1582
|
-
// shortCode indices with sibling entries from pattern extraction
|
|
1583
|
-
const lazyCounters: Record<string, number> = {};
|
|
1584
|
-
if (lazyContext && (lazyContext as any).counters) {
|
|
1585
|
-
const captured = (lazyContext as any).counters as Record<string, number>;
|
|
1586
|
-
for (const [key, value] of Object.entries(captured)) {
|
|
1587
|
-
lazyCounters[key] = value;
|
|
1588
|
-
}
|
|
1589
|
-
}
|
|
1590
|
-
|
|
1591
|
-
RSCRouterContext.run(
|
|
1592
|
-
{
|
|
1593
|
-
manifest,
|
|
1594
|
-
patterns,
|
|
1595
|
-
patternsByPrefix,
|
|
1596
|
-
trailingSlash: trailingSlashMap,
|
|
1597
|
-
namespace: "lazy",
|
|
1598
|
-
parent: (lazyContext?.parent as EntryData | null) ?? null,
|
|
1599
|
-
counters: lazyCounters,
|
|
1600
|
-
},
|
|
1601
|
-
() => {
|
|
1602
|
-
// Run the lazy patterns handler with the original context prefixes
|
|
1603
|
-
// The prefix comes from the IncludeItem stored in lazyPatterns
|
|
1604
|
-
const includePrefix = (entry as any)._lazyPrefix || "";
|
|
1605
|
-
const fullPrefix = (lazyContext?.urlPrefix || "") + includePrefix;
|
|
1606
|
-
|
|
1607
|
-
if (fullPrefix || lazyContext?.namePrefix) {
|
|
1608
|
-
runWithPrefixes(fullPrefix, lazyContext?.namePrefix, () => {
|
|
1609
|
-
handlerResult = lazyPatterns.handler() as AllUseItems[];
|
|
1610
|
-
});
|
|
1611
|
-
} else {
|
|
1612
|
-
handlerResult = lazyPatterns.handler() as AllUseItems[];
|
|
1613
|
-
}
|
|
1614
|
-
},
|
|
1615
|
-
);
|
|
1616
|
-
|
|
1617
|
-
// Populate the entry's routes from the patterns
|
|
1618
|
-
const routesObject: Record<string, string> = {};
|
|
1619
|
-
for (const [name, pattern] of patterns.entries()) {
|
|
1620
|
-
routesObject[name] = pattern;
|
|
1621
|
-
// Also add to merged route map for reverse() support
|
|
1622
|
-
const existingPattern = mergedRouteMap[name];
|
|
1623
|
-
if (existingPattern !== undefined && existingPattern !== pattern) {
|
|
1624
|
-
console.warn(
|
|
1625
|
-
`[@rangojs/router] Route name conflict: "${name}" already maps to "${existingPattern}", ` +
|
|
1626
|
-
`overwriting with "${pattern}" (from lazy include). Use unique route names to avoid this.`,
|
|
1627
|
-
);
|
|
1628
|
-
}
|
|
1629
|
-
mergedRouteMap[name] = pattern;
|
|
1630
|
-
}
|
|
1631
|
-
|
|
1632
|
-
// Update the entry in-place
|
|
1633
|
-
entry.routes = routesObject as ResolvedRouteMap<any>;
|
|
1634
|
-
|
|
1635
|
-
// Note: Do NOT clear lazyPatterns/lazyContext here.
|
|
1636
|
-
// loadManifest() needs them on every request to re-run the handler
|
|
1637
|
-
// in the correct AsyncLocalStorage context (Store.manifest).
|
|
1638
|
-
|
|
1639
|
-
// Update trailing slash config if available
|
|
1640
|
-
if (trailingSlashMap.size > 0) {
|
|
1641
|
-
entry.trailingSlash = Object.fromEntries(trailingSlashMap);
|
|
1642
|
-
}
|
|
1643
|
-
|
|
1644
|
-
// Detect nested lazy includes and register them as new entries
|
|
1645
|
-
const nestedLazyIncludes = findLazyIncludes(handlerResult);
|
|
1646
|
-
for (const lazyInclude of nestedLazyIncludes) {
|
|
1647
|
-
// Compute the full URL prefix (combining parent prefix if any)
|
|
1648
|
-
const fullPrefix = lazyInclude.context.urlPrefix
|
|
1649
|
-
? lazyInclude.context.urlPrefix + lazyInclude.prefix
|
|
1650
|
-
: lazyInclude.prefix;
|
|
1651
|
-
|
|
1652
|
-
const nestedEntry: RouteEntry<TEnv> & { _lazyPrefix?: string } = {
|
|
1653
|
-
prefix: "",
|
|
1654
|
-
staticPrefix: extractStaticPrefix(fullPrefix),
|
|
1655
|
-
routes: {} as ResolvedRouteMap<any>, // Empty until first match
|
|
1656
|
-
trailingSlash: entry.trailingSlash,
|
|
1657
|
-
handler: (lazyInclude.patterns as UrlPatterns<TEnv>).handler,
|
|
1658
|
-
mountIndex: entry.mountIndex,
|
|
1659
|
-
// Lazy evaluation fields
|
|
1660
|
-
lazy: true,
|
|
1661
|
-
lazyPatterns: lazyInclude.patterns,
|
|
1662
|
-
lazyContext: lazyInclude.context,
|
|
1663
|
-
lazyEvaluated: false,
|
|
1664
|
-
// Store the include prefix for evaluation
|
|
1665
|
-
_lazyPrefix: lazyInclude.prefix,
|
|
1666
|
-
};
|
|
1667
|
-
// Insert nested lazy entry before any entry whose staticPrefix is a
|
|
1668
|
-
// prefix of (but shorter than) this lazy entry's staticPrefix.
|
|
1669
|
-
// This ensures more specific lazy includes are matched before
|
|
1670
|
-
// less specific eager entries (e.g., "/href/nested" before "/href/:id").
|
|
1671
|
-
const nestedPrefix = nestedEntry.staticPrefix;
|
|
1672
|
-
let insertIndex = routesEntries.length;
|
|
1673
|
-
if (nestedPrefix) {
|
|
1674
|
-
for (let i = 0; i < routesEntries.length; i++) {
|
|
1675
|
-
const existing = routesEntries[i]!;
|
|
1676
|
-
if (
|
|
1677
|
-
nestedPrefix.startsWith(existing.staticPrefix) &&
|
|
1678
|
-
nestedPrefix.length > existing.staticPrefix.length
|
|
1679
|
-
) {
|
|
1680
|
-
insertIndex = i;
|
|
1681
|
-
break;
|
|
1682
|
-
}
|
|
1683
|
-
}
|
|
1684
|
-
}
|
|
1685
|
-
routesEntries.splice(insertIndex, 0, nestedEntry);
|
|
1686
|
-
}
|
|
1687
|
-
|
|
1688
|
-
// Re-register route map for runtime reverse() usage
|
|
1689
|
-
registerRouteMap(mergedRouteMap);
|
|
1690
|
-
}
|
|
1691
|
-
|
|
1692
|
-
// Single-entry cache for findMatch to avoid redundant matching within the same request.
|
|
1693
|
-
// previewMatch and match both call findMatch with the same pathname — this ensures
|
|
1694
|
-
// the route matching work (which may check thousands of routes) only happens once.
|
|
1695
|
-
let lastFindMatchPathname: string | null = null;
|
|
1696
|
-
let lastFindMatchResult: RouteMatchResult<TEnv> | null = null;
|
|
1697
|
-
|
|
1698
|
-
// Wrapper for findMatch that uses routesEntries
|
|
1699
|
-
// Handles lazy evaluation by evaluating lazy entries on first match.
|
|
1700
|
-
// Phase 1: try O(path_length) trie match.
|
|
1701
|
-
// Phase 2: fall back to regex iteration.
|
|
1702
|
-
function findMatch(
|
|
1703
|
-
pathname: string,
|
|
1704
|
-
ms?: MetricsStore,
|
|
1705
|
-
): RouteMatchResult<TEnv> | null {
|
|
1706
|
-
// Return cached result if same pathname (avoids double-match per request)
|
|
1707
|
-
if (lastFindMatchPathname === pathname) {
|
|
1708
|
-
return lastFindMatchResult;
|
|
1709
|
-
}
|
|
1710
|
-
|
|
1711
|
-
// Helper to push sub-metrics
|
|
1712
|
-
const pushMetric = ms
|
|
1713
|
-
? (label: string, start: number) => {
|
|
1714
|
-
ms.metrics.push({
|
|
1715
|
-
label,
|
|
1716
|
-
duration: performance.now() - start,
|
|
1717
|
-
startTime: start - ms.requestStart,
|
|
1718
|
-
});
|
|
1719
|
-
}
|
|
1720
|
-
: undefined;
|
|
1721
|
-
|
|
1722
|
-
// Phase 1: Try trie match (O(path_length))
|
|
1723
|
-
// Prefer per-router trie (isolated) over global trie (merged).
|
|
1724
|
-
const routeTrie = getRouterTrie(routerId) ?? getRouteTrie();
|
|
1725
|
-
if (routeTrie) {
|
|
1726
|
-
const trieStart = performance.now();
|
|
1727
|
-
const trieResult = tryTrieMatch(routeTrie, pathname);
|
|
1728
|
-
pushMetric?.("match:trie", trieStart);
|
|
1729
|
-
|
|
1730
|
-
if (trieResult) {
|
|
1731
|
-
// Find the RouteEntry that contains this route.
|
|
1732
|
-
// Multiple entries can share the same staticPrefix (e.g., several
|
|
1733
|
-
// include("/", patterns) calls all produce staticPrefix=""). Evaluate
|
|
1734
|
-
// each candidate and pick the one whose routes include the matched key.
|
|
1735
|
-
const entryStart = performance.now();
|
|
1736
|
-
let entry: RouteEntry<TEnv> | undefined;
|
|
1737
|
-
let fallbackEntry: RouteEntry<TEnv> | undefined;
|
|
1738
|
-
|
|
1739
|
-
for (const e of routesEntries) {
|
|
1740
|
-
if (e.staticPrefix !== trieResult.sp) continue;
|
|
1741
|
-
if (!fallbackEntry) fallbackEntry = e;
|
|
1742
|
-
evaluateLazyEntry(e);
|
|
1743
|
-
if (
|
|
1744
|
-
e.routes &&
|
|
1745
|
-
trieResult.routeKey in (e.routes as Record<string, unknown>)
|
|
1746
|
-
) {
|
|
1747
|
-
entry = e;
|
|
1748
|
-
break;
|
|
1749
|
-
}
|
|
1750
|
-
}
|
|
1751
|
-
|
|
1752
|
-
// If no entry had the route in its routes map, use the first matching
|
|
1753
|
-
// entry as fallback (handles main entry with inline routes not yet
|
|
1754
|
-
// reflected in its routes object).
|
|
1755
|
-
if (!entry) entry = fallbackEntry;
|
|
1756
|
-
|
|
1757
|
-
// If entry not found (nested include not yet discovered), evaluate parent
|
|
1758
|
-
if (!entry) {
|
|
1759
|
-
const parent = routesEntries.find(
|
|
1760
|
-
(e) =>
|
|
1761
|
-
trieResult.sp.startsWith(e.staticPrefix) &&
|
|
1762
|
-
e.staticPrefix !== trieResult.sp,
|
|
1763
|
-
);
|
|
1764
|
-
if (parent) {
|
|
1765
|
-
const lazyStart = performance.now();
|
|
1766
|
-
evaluateLazyEntry(parent);
|
|
1767
|
-
pushMetric?.("match:lazy-eval", lazyStart);
|
|
1768
|
-
}
|
|
1769
|
-
entry = routesEntries.find((e) => e.staticPrefix === trieResult.sp);
|
|
1770
|
-
}
|
|
1771
|
-
pushMetric?.("match:entry-resolve", entryStart);
|
|
1772
|
-
|
|
1773
|
-
if (entry) {
|
|
1774
|
-
lastFindMatchPathname = pathname;
|
|
1775
|
-
lastFindMatchResult = {
|
|
1776
|
-
entry,
|
|
1777
|
-
routeKey: trieResult.routeKey,
|
|
1778
|
-
params: trieResult.params,
|
|
1779
|
-
optionalParams: new Set(trieResult.optionalParams || []),
|
|
1780
|
-
redirectTo: trieResult.redirectTo,
|
|
1781
|
-
ancestry: trieResult.ancestry,
|
|
1782
|
-
...(trieResult.pr ? { pr: true } : {}),
|
|
1783
|
-
...(trieResult.pt ? { pt: true } : {}),
|
|
1784
|
-
...(trieResult.responseType ? { responseType: trieResult.responseType } : {}),
|
|
1785
|
-
...(trieResult.negotiateVariants ? { negotiateVariants: trieResult.negotiateVariants } : {}),
|
|
1786
|
-
...(trieResult.rscFirst ? { rscFirst: true } : {}),
|
|
1787
|
-
};
|
|
1788
|
-
return lastFindMatchResult;
|
|
1789
|
-
}
|
|
1790
|
-
}
|
|
1791
|
-
}
|
|
1792
|
-
|
|
1793
|
-
// Phase 2: Fall back to existing matching (regex iteration)
|
|
1794
|
-
const regexStart = performance.now();
|
|
1795
|
-
let result = findRouteMatch(pathname, routesEntries);
|
|
1796
|
-
|
|
1797
|
-
// If we hit a lazy entry that needs evaluation, evaluate and retry.
|
|
1798
|
-
// Cap iterations to prevent infinite loops from pathological nesting.
|
|
1799
|
-
const MAX_LAZY_ITERATIONS = 100;
|
|
1800
|
-
let iterations = 0;
|
|
1801
|
-
while (isLazyEvaluationNeeded(result)) {
|
|
1802
|
-
if (++iterations > MAX_LAZY_ITERATIONS) {
|
|
1803
|
-
console.error(
|
|
1804
|
-
`[@rangojs/router] Exceeded ${MAX_LAZY_ITERATIONS} lazy evaluation iterations ` +
|
|
1805
|
-
`for pathname "${pathname}". This likely indicates circular lazy includes.`,
|
|
1806
|
-
);
|
|
1807
|
-
lastFindMatchPathname = pathname;
|
|
1808
|
-
lastFindMatchResult = null;
|
|
1809
|
-
return null;
|
|
1810
|
-
}
|
|
1811
|
-
evaluateLazyEntry(result.lazyEntry);
|
|
1812
|
-
result = findRouteMatch(pathname, routesEntries);
|
|
1813
|
-
}
|
|
1814
|
-
pushMetric?.("match:regex-fallback", regexStart);
|
|
1815
|
-
|
|
1816
|
-
lastFindMatchPathname = pathname;
|
|
1817
|
-
lastFindMatchResult = result;
|
|
1818
|
-
return result;
|
|
1819
|
-
}
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
/**
|
|
1823
|
-
* Build-time pre-render match. Resolves segments with a BuildContext
|
|
1824
|
-
* (no request/env/headers/cookies), skipping middleware and loaders.
|
|
1825
|
-
*/
|
|
1826
|
-
async function matchForPrerender(
|
|
1827
|
-
pathname: string,
|
|
1828
|
-
params: Record<string, string>,
|
|
1829
|
-
): Promise<{
|
|
1830
|
-
segments: SerializedSegmentData[];
|
|
1831
|
-
handles: Record<string, SegmentHandleData>;
|
|
1832
|
-
routeName: string;
|
|
1833
|
-
params: Record<string, string>;
|
|
1834
|
-
} | null> {
|
|
1835
|
-
// 1. Find the matching route entry
|
|
1836
|
-
const matched = findMatch(pathname);
|
|
1837
|
-
if (!matched) return null;
|
|
1838
|
-
|
|
1839
|
-
// Use params from trie match if available, fall back to provided params
|
|
1840
|
-
const matchedParams = matched.params ?? params;
|
|
1841
|
-
|
|
1842
|
-
// Build a minimal RouterContext for loadManifest/traverseBack
|
|
1843
|
-
const routerCtx: RouterContext<TEnv> = {
|
|
1844
|
-
findMatch,
|
|
1845
|
-
loadManifest,
|
|
1846
|
-
traverseBack,
|
|
1847
|
-
createHandlerContext,
|
|
1848
|
-
setupLoaderAccess,
|
|
1849
|
-
setupLoaderAccessSilent,
|
|
1850
|
-
getContext,
|
|
1851
|
-
getMetricsStore,
|
|
1852
|
-
createCacheScope,
|
|
1853
|
-
findInterceptForRoute,
|
|
1854
|
-
resolveAllSegmentsWithRevalidation,
|
|
1855
|
-
resolveInterceptEntry,
|
|
1856
|
-
evaluateRevalidation,
|
|
1857
|
-
getRequestContext,
|
|
1858
|
-
resolveAllSegments,
|
|
1859
|
-
createHandleStore,
|
|
1860
|
-
buildEntryRevalidateMap,
|
|
1861
|
-
resolveLoadersOnlyWithRevalidation,
|
|
1862
|
-
resolveInterceptLoadersOnly,
|
|
1863
|
-
resolveLoadersOnly,
|
|
1864
|
-
};
|
|
1865
|
-
|
|
1866
|
-
return runWithRouterContext(routerCtx, async () => {
|
|
1867
|
-
// 2. Load the manifest entry tree
|
|
1868
|
-
const manifestEntry = await loadManifest(
|
|
1869
|
-
matched.entry,
|
|
1870
|
-
matched.routeKey,
|
|
1871
|
-
pathname,
|
|
1872
|
-
undefined,
|
|
1873
|
-
false,
|
|
1874
|
-
);
|
|
1875
|
-
|
|
1876
|
-
// 3. Build ancestor chain [root, ..., route]
|
|
1877
|
-
const entries: EntryData[] = [];
|
|
1878
|
-
for (const entry of traverseBack(manifestEntry)) {
|
|
1879
|
-
entries.push(entry);
|
|
1880
|
-
}
|
|
1881
|
-
|
|
1882
|
-
// 4. Create handle store for collecting handle data
|
|
1883
|
-
const handleStore = createHandleStore();
|
|
363
|
+
// Track all registered routes with their prefixes for reverse().
|
|
364
|
+
// Seed from injected NamedRoutes so reverse() works at module load time
|
|
365
|
+
// for routes that come from lazy includes.
|
|
366
|
+
const mergedRouteMap: Record<string, string> =
|
|
367
|
+
flattenNamedRoutes(staticRouteNames);
|
|
1884
368
|
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
request: new Request("http://prerender" + pathname),
|
|
1890
|
-
url: new URL("http://prerender" + pathname),
|
|
1891
|
-
pathname,
|
|
1892
|
-
searchParams: new URLSearchParams(),
|
|
1893
|
-
var: {},
|
|
1894
|
-
get: () => undefined as any,
|
|
1895
|
-
set: () => {},
|
|
1896
|
-
params: matchedParams,
|
|
1897
|
-
res: stubRes,
|
|
1898
|
-
cookie: () => undefined,
|
|
1899
|
-
cookies: () => ({}),
|
|
1900
|
-
setCookie: () => {},
|
|
1901
|
-
deleteCookie: () => {},
|
|
1902
|
-
header: () => {},
|
|
1903
|
-
use: (() => {
|
|
1904
|
-
throw new Error("use() not available during pre-rendering");
|
|
1905
|
-
}) as any,
|
|
1906
|
-
method: "GET",
|
|
1907
|
-
_handleStore: handleStore,
|
|
1908
|
-
waitUntil: () => {},
|
|
1909
|
-
onResponse: () => {},
|
|
1910
|
-
_onResponseCallbacks: [],
|
|
1911
|
-
};
|
|
1912
|
-
|
|
1913
|
-
return runWithRequestContext(minimalRequestContext, async () => {
|
|
1914
|
-
// 6. Create BuildContext (no request/env/headers/cookies)
|
|
1915
|
-
const buildCtx = createBuildContext<TEnv>(
|
|
1916
|
-
matchedParams,
|
|
1917
|
-
pathname,
|
|
1918
|
-
handleStore,
|
|
1919
|
-
);
|
|
1920
|
-
|
|
1921
|
-
// 7. Wire use() for handles only (loaders throw)
|
|
1922
|
-
setupBuildUse(buildCtx);
|
|
1923
|
-
|
|
1924
|
-
// 8. Resolve all segments with skipLoaders
|
|
1925
|
-
const loaderPromises = new Map<string, Promise<any>>();
|
|
1926
|
-
const allSegments = await resolveAllSegments(
|
|
1927
|
-
entries,
|
|
1928
|
-
matched.routeKey,
|
|
1929
|
-
matchedParams,
|
|
1930
|
-
buildCtx,
|
|
1931
|
-
loaderPromises,
|
|
1932
|
-
{ skipLoaders: true },
|
|
1933
|
-
);
|
|
369
|
+
// Track names that came from the static seed so we can silently overwrite
|
|
370
|
+
// them during routes() registration. The gen file may be stale during HMR,
|
|
371
|
+
// so conflicts between seeded and runtime-registered values are expected.
|
|
372
|
+
const seededNames = new Set(Object.keys(mergedRouteMap));
|
|
1934
373
|
|
|
1935
|
-
|
|
1936
|
-
|
|
374
|
+
// Lazy precomputed entries lookup: rebuilt when per-router data arrives.
|
|
375
|
+
// In production multi-router setups, per-router data is loaded lazily via
|
|
376
|
+
// ensureRouterManifest(). At createRouter() time the data isn't available yet,
|
|
377
|
+
// so we defer building the Map until first use and invalidate when the
|
|
378
|
+
// per-router source changes.
|
|
379
|
+
let precomputedByPrefix: Map<string, Record<string, string>> | null = null;
|
|
380
|
+
let precomputedSource:
|
|
381
|
+
| Array<{ staticPrefix: string; routes: Record<string, string> }>
|
|
382
|
+
| null
|
|
383
|
+
| undefined;
|
|
384
|
+
|
|
385
|
+
function getPrecomputedByPrefix(): Map<
|
|
386
|
+
string,
|
|
387
|
+
Record<string, string>
|
|
388
|
+
> | null {
|
|
389
|
+
const current =
|
|
390
|
+
getRouterPrecomputedEntries(routerId) ?? getPrecomputedEntries();
|
|
391
|
+
if (current !== precomputedSource) {
|
|
392
|
+
precomputedSource = current;
|
|
393
|
+
// buildPrecomputedByPrefix drops any staticPrefix owned by more than one
|
|
394
|
+
// leaf include instead of collapsing it last-wins (which would mis-assign
|
|
395
|
+
// one include's routes to another's entry and 500 a valid sibling route).
|
|
396
|
+
// Such shared-prefix includes resolve via the handler path instead.
|
|
397
|
+
precomputedByPrefix = current ? buildPrecomputedByPrefix(current) : null;
|
|
398
|
+
}
|
|
399
|
+
return precomputedByPrefix;
|
|
400
|
+
}
|
|
1937
401
|
|
|
1938
|
-
|
|
1939
|
-
|
|
402
|
+
// Wrapper to pass debugPerformance to external createMetricsStore.
|
|
403
|
+
// Also checks per-request flag set by ctx.debugPerformance() in middleware.
|
|
404
|
+
const getMetricsStore = () => {
|
|
405
|
+
const reqCtx = _getRequestContext();
|
|
406
|
+
const enabled = debugPerformance || !!reqCtx?._debugPerformance;
|
|
407
|
+
if (!enabled) return undefined;
|
|
408
|
+
if (!reqCtx) {
|
|
409
|
+
return createMetricsStore(true);
|
|
410
|
+
}
|
|
411
|
+
reqCtx._metricsStore ??= createMetricsStore(true);
|
|
412
|
+
return reqCtx._metricsStore;
|
|
413
|
+
};
|
|
1940
414
|
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
415
|
+
// Wrapper to pass defaults to error/notFound boundary finders
|
|
416
|
+
const findNearestErrorBoundary = (entry: EntryData | null) =>
|
|
417
|
+
findErrorBoundary(entry, defaultErrorBoundary);
|
|
1944
418
|
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
for (const seg of nonLoaderSegments) {
|
|
1948
|
-
const segHandles = handleStore.getDataForSegment(seg.id);
|
|
1949
|
-
if (Object.keys(segHandles).length > 0) {
|
|
1950
|
-
handles[seg.id] = segHandles;
|
|
1951
|
-
}
|
|
1952
|
-
}
|
|
419
|
+
const findNearestNotFoundBoundary = (entry: EntryData | null) =>
|
|
420
|
+
findNotFoundBoundary(entry, defaultNotFoundBoundary);
|
|
1953
421
|
|
|
1954
|
-
|
|
1955
|
-
|
|
422
|
+
// Helper to get handleStore from request context
|
|
423
|
+
const getHandleStore = (): HandleStore | undefined => {
|
|
424
|
+
return _getRequestContext()?._handleStore;
|
|
425
|
+
};
|
|
1956
426
|
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
427
|
+
// Track a pending handler promise (non-blocking).
|
|
428
|
+
// Attaches a side-effect .catch() to report streaming handler errors to onError
|
|
429
|
+
// without altering the rejection chain (React's streaming error boundary still handles it).
|
|
430
|
+
const trackHandler = <T>(
|
|
431
|
+
promise: Promise<T>,
|
|
432
|
+
errorContext?: {
|
|
433
|
+
segmentId?: string;
|
|
434
|
+
segmentType?: string;
|
|
435
|
+
},
|
|
436
|
+
): Promise<T> => {
|
|
437
|
+
const store = getHandleStore();
|
|
438
|
+
const tracked = store ? store.track(promise) : promise;
|
|
439
|
+
|
|
440
|
+
// Report streaming handler errors to onError as a side-effect.
|
|
441
|
+
// The rejection still propagates to the RSC stream for client error boundaries.
|
|
442
|
+
// Captures request context eagerly (closure) so the catch handler has full context.
|
|
443
|
+
const reqCtx = _getRequestContext();
|
|
444
|
+
if (reqCtx && onError) {
|
|
445
|
+
tracked.catch((error) => {
|
|
446
|
+
callOnError(error, "handler", {
|
|
447
|
+
request: reqCtx.request,
|
|
448
|
+
url: reqCtx.url,
|
|
449
|
+
routeKey: reqCtx._routeName,
|
|
450
|
+
params: reqCtx.params as Record<string, string>,
|
|
451
|
+
env: reqCtx.env as TEnv,
|
|
452
|
+
segmentId: errorContext?.segmentId,
|
|
453
|
+
segmentType: errorContext?.segmentType as any,
|
|
454
|
+
handledByBoundary: true,
|
|
455
|
+
});
|
|
1963
456
|
});
|
|
1964
|
-
}
|
|
1965
|
-
}
|
|
457
|
+
}
|
|
1966
458
|
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
*
|
|
1970
|
-
* Uses generator middleware pipeline for clean separation of concerns:
|
|
1971
|
-
* - cache-lookup: Check cache first
|
|
1972
|
-
* - segment-resolution: Resolve segments on cache miss
|
|
1973
|
-
* - cache-store: Store results in cache
|
|
1974
|
-
* - background-revalidation: SWR revalidation
|
|
1975
|
-
*/
|
|
1976
|
-
async function match(request: Request, env: TEnv): Promise<MatchResult> {
|
|
1977
|
-
// Build RouterContext with all closure functions needed by middleware
|
|
1978
|
-
const routerCtx: RouterContext<TEnv> = {
|
|
1979
|
-
findMatch,
|
|
1980
|
-
loadManifest,
|
|
1981
|
-
traverseBack,
|
|
1982
|
-
createHandlerContext,
|
|
1983
|
-
setupLoaderAccess,
|
|
1984
|
-
setupLoaderAccessSilent,
|
|
1985
|
-
getContext,
|
|
1986
|
-
getMetricsStore,
|
|
1987
|
-
createCacheScope,
|
|
1988
|
-
findInterceptForRoute,
|
|
1989
|
-
resolveAllSegmentsWithRevalidation,
|
|
1990
|
-
resolveInterceptEntry,
|
|
1991
|
-
evaluateRevalidation,
|
|
1992
|
-
getRequestContext,
|
|
1993
|
-
resolveAllSegments,
|
|
1994
|
-
createHandleStore,
|
|
1995
|
-
buildEntryRevalidateMap,
|
|
1996
|
-
resolveLoadersOnlyWithRevalidation,
|
|
1997
|
-
resolveInterceptLoadersOnly,
|
|
1998
|
-
resolveLoadersOnly,
|
|
1999
|
-
};
|
|
459
|
+
return tracked;
|
|
460
|
+
};
|
|
2000
461
|
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
462
|
+
// Wrapper for wrapLoaderWithErrorHandling that uses router's error boundary finder
|
|
463
|
+
// Includes onError callback for loader error notification and telemetry emission.
|
|
464
|
+
function wrapLoaderPromise<T>(
|
|
465
|
+
promise: Promise<T>,
|
|
466
|
+
entry: EntryData,
|
|
467
|
+
segmentId: string,
|
|
468
|
+
pathname: string,
|
|
469
|
+
errorContext?: {
|
|
470
|
+
request: Request;
|
|
471
|
+
url: URL;
|
|
472
|
+
routeKey?: string;
|
|
473
|
+
params?: Record<string, string>;
|
|
474
|
+
env?: TEnv;
|
|
475
|
+
isPartial?: boolean;
|
|
476
|
+
requestStartTime?: number;
|
|
477
|
+
},
|
|
478
|
+
): Promise<LoaderDataResult<T>> {
|
|
479
|
+
const loaderStart = telemetrySink ? performance.now() : 0;
|
|
480
|
+
const loaderRequestId = telemetrySink
|
|
481
|
+
? errorContext?.request
|
|
482
|
+
? getRequestId(errorContext.request)
|
|
483
|
+
: undefined
|
|
484
|
+
: undefined;
|
|
485
|
+
if (telemetrySink) {
|
|
486
|
+
const loaderName = segmentId.split(".").pop() || "unknown";
|
|
487
|
+
safeEmit(telemetry, {
|
|
488
|
+
type: "loader.start",
|
|
489
|
+
timestamp: loaderStart,
|
|
490
|
+
requestId: loaderRequestId,
|
|
491
|
+
segmentId,
|
|
492
|
+
loaderName,
|
|
493
|
+
pathname,
|
|
494
|
+
});
|
|
495
|
+
}
|
|
2018
496
|
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
497
|
+
const result = wrapLoaderWithErrorHandling(
|
|
498
|
+
promise,
|
|
499
|
+
entry,
|
|
500
|
+
segmentId,
|
|
501
|
+
pathname,
|
|
502
|
+
findNearestErrorBoundary,
|
|
503
|
+
createErrorInfo,
|
|
504
|
+
// Invoke onError when loader fails
|
|
505
|
+
errorContext
|
|
506
|
+
? (error, ctx) => {
|
|
507
|
+
callOnError(error, "loader", {
|
|
508
|
+
request: errorContext.request,
|
|
509
|
+
url: errorContext.url,
|
|
510
|
+
routeKey: errorContext.routeKey,
|
|
511
|
+
params: errorContext.params,
|
|
512
|
+
segmentId: ctx.segmentId,
|
|
513
|
+
segmentType: "loader",
|
|
514
|
+
loaderName: ctx.loaderName,
|
|
515
|
+
env: errorContext.env,
|
|
516
|
+
isPartial: errorContext.isPartial,
|
|
517
|
+
handledByBoundary: ctx.handledByBoundary,
|
|
518
|
+
requestStartTime: errorContext.requestStartTime,
|
|
519
|
+
});
|
|
520
|
+
if (telemetrySink) {
|
|
521
|
+
const errorObj =
|
|
522
|
+
error instanceof Error ? error : new Error(String(error));
|
|
523
|
+
safeEmit(telemetry, {
|
|
524
|
+
type: "loader.error",
|
|
525
|
+
timestamp: performance.now(),
|
|
526
|
+
requestId: loaderRequestId,
|
|
527
|
+
segmentId: ctx.segmentId,
|
|
528
|
+
loaderName: ctx.loaderName,
|
|
529
|
+
pathname,
|
|
530
|
+
error: errorObj,
|
|
531
|
+
handledByBoundary: ctx.handledByBoundary,
|
|
2034
532
|
});
|
|
2035
|
-
throw sanitizeError(error);
|
|
2036
533
|
}
|
|
2037
|
-
}
|
|
2038
|
-
|
|
534
|
+
}
|
|
535
|
+
: undefined,
|
|
2039
536
|
);
|
|
2040
|
-
}
|
|
2041
537
|
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
),
|
|
2061
|
-
);
|
|
538
|
+
// Emit loader.end after the promise settles (fire-and-forget)
|
|
539
|
+
if (telemetrySink) {
|
|
540
|
+
const loaderName = segmentId.split(".").pop() || "unknown";
|
|
541
|
+
result.then((r) => {
|
|
542
|
+
safeEmit(telemetry, {
|
|
543
|
+
type: "loader.end",
|
|
544
|
+
timestamp: performance.now(),
|
|
545
|
+
requestId: loaderRequestId,
|
|
546
|
+
segmentId,
|
|
547
|
+
loaderName,
|
|
548
|
+
pathname,
|
|
549
|
+
durationMs: performance.now() - loaderStart,
|
|
550
|
+
ok: r.ok,
|
|
551
|
+
});
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
return result;
|
|
2062
556
|
}
|
|
2063
557
|
|
|
558
|
+
// Dependencies object for extracted segment resolution functions.
|
|
559
|
+
// Captures closure-bound helpers from createRouter.
|
|
560
|
+
const segmentDeps: SegmentResolutionDeps<TEnv> = {
|
|
561
|
+
wrapLoaderPromise,
|
|
562
|
+
trackHandler,
|
|
563
|
+
findNearestErrorBoundary,
|
|
564
|
+
findNearestNotFoundBoundary,
|
|
565
|
+
notFoundComponent: notFound,
|
|
566
|
+
callOnError,
|
|
567
|
+
viewTransitionDefault: viewTransitionOption,
|
|
568
|
+
};
|
|
2064
569
|
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
570
|
+
// Match API dependencies
|
|
571
|
+
const matchApiDeps: MatchApiDeps<TEnv> = {
|
|
572
|
+
findMatch: (pathname: string, ms?: any) => findMatch(pathname, ms),
|
|
573
|
+
getMetricsStore,
|
|
574
|
+
findInterceptForRoute: (routeKey, parentEntry, selectorContext, isAction) =>
|
|
575
|
+
findInterceptForRoute(routeKey, parentEntry, selectorContext, isAction),
|
|
576
|
+
callOnError,
|
|
577
|
+
findNearestErrorBoundary,
|
|
578
|
+
// Use per-router manifest when available, otherwise the static named map
|
|
579
|
+
// seeded into mergedRouteMap at router creation.
|
|
580
|
+
getRouteMap: () => getRouterManifest(routerId) ?? mergedRouteMap,
|
|
581
|
+
};
|
|
2071
582
|
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
583
|
+
// Create segment resolution wrappers bound to segmentDeps
|
|
584
|
+
const {
|
|
585
|
+
resolveAllSegments,
|
|
586
|
+
resolveLoadersOnly,
|
|
587
|
+
resolveLoadersOnlyWithRevalidation,
|
|
588
|
+
buildEntryRevalidateMap,
|
|
589
|
+
resolveAllSegmentsWithRevalidation,
|
|
590
|
+
findInterceptForRoute,
|
|
591
|
+
resolveInterceptEntry,
|
|
592
|
+
resolveInterceptLoadersOnly,
|
|
593
|
+
} = createSegmentWrappers<TEnv>(segmentDeps);
|
|
594
|
+
|
|
595
|
+
// Lazy evaluation deps — captures closure state for extracted evaluateLazyEntry
|
|
596
|
+
const lazyEvalDeps: LazyEvalDeps<TEnv> = {
|
|
597
|
+
routesEntries,
|
|
598
|
+
mergedRouteMap,
|
|
599
|
+
nextMountIndex: () => mountIndex++,
|
|
600
|
+
getPrecomputedByPrefix,
|
|
601
|
+
routerId,
|
|
602
|
+
};
|
|
603
|
+
|
|
604
|
+
function evaluateLazyEntry(entry: RouteEntry<TEnv>): void {
|
|
605
|
+
_evaluateLazyEntry(entry, lazyEvalDeps);
|
|
2078
606
|
}
|
|
2079
607
|
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
async function matchPartial(
|
|
2091
|
-
request: Request,
|
|
2092
|
-
context: TEnv,
|
|
2093
|
-
actionContext?: ActionContext,
|
|
2094
|
-
): Promise<MatchResult | null> {
|
|
2095
|
-
// Build RouterContext with all closure functions needed by middleware
|
|
2096
|
-
const routerCtx: RouterContext<TEnv> = {
|
|
608
|
+
// Create findMatch with single-entry cache, bound to router state
|
|
609
|
+
const findMatch = createFindMatch<TEnv>({
|
|
610
|
+
routesEntries,
|
|
611
|
+
evaluateLazyEntry,
|
|
612
|
+
routerId,
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
// Build a RouterContext once — shared by match, matchPartial, matchForPrerender
|
|
616
|
+
function buildRouterContext(): RouterContext<TEnv> {
|
|
617
|
+
return {
|
|
2097
618
|
findMatch,
|
|
2098
619
|
loadManifest,
|
|
2099
620
|
traverseBack,
|
|
@@ -2113,479 +634,307 @@ export function createRouter<TEnv = any>(
|
|
|
2113
634
|
buildEntryRevalidateMap,
|
|
2114
635
|
resolveLoadersOnlyWithRevalidation,
|
|
2115
636
|
resolveInterceptLoadersOnly,
|
|
637
|
+
resolveLoadersOnly,
|
|
638
|
+
telemetry: telemetrySink,
|
|
2116
639
|
};
|
|
2117
|
-
|
|
2118
|
-
return runWithRouterLogContext(
|
|
2119
|
-
{ request, transaction: "matchPartial" },
|
|
2120
|
-
() =>
|
|
2121
|
-
runWithRouterContext(routerCtx, async () =>
|
|
2122
|
-
withRouterLogScope("matchPartial", async () => {
|
|
2123
|
-
const ctx = await createMatchContextForPartial(
|
|
2124
|
-
request,
|
|
2125
|
-
context,
|
|
2126
|
-
actionContext,
|
|
2127
|
-
);
|
|
2128
|
-
if (!ctx) return null;
|
|
2129
|
-
|
|
2130
|
-
try {
|
|
2131
|
-
const state = createPipelineState();
|
|
2132
|
-
const pipeline = createMatchPartialPipeline(ctx, state);
|
|
2133
|
-
return await collectMatchResult(pipeline, ctx, state);
|
|
2134
|
-
} catch (error) {
|
|
2135
|
-
if (error instanceof Response) throw error;
|
|
2136
|
-
// Report unhandled errors during partial match pipeline
|
|
2137
|
-
callOnError(error, actionContext ? "action" : "revalidation", {
|
|
2138
|
-
request,
|
|
2139
|
-
url: ctx.url,
|
|
2140
|
-
env: context,
|
|
2141
|
-
actionId: actionContext?.actionId,
|
|
2142
|
-
isPartial: true,
|
|
2143
|
-
handledByBoundary: false,
|
|
2144
|
-
});
|
|
2145
|
-
throw sanitizeError(error);
|
|
2146
|
-
}
|
|
2147
|
-
}),
|
|
2148
|
-
),
|
|
2149
|
-
);
|
|
2150
640
|
}
|
|
2151
641
|
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
): Promise<{
|
|
2160
|
-
routeMiddleware?: Array<{
|
|
2161
|
-
handler: import("./router/middleware.js").MiddlewareFn;
|
|
2162
|
-
params: Record<string, string>;
|
|
2163
|
-
}>;
|
|
2164
|
-
responseType?: string;
|
|
2165
|
-
handler?: Function;
|
|
2166
|
-
params?: Record<string, string>;
|
|
2167
|
-
negotiated?: boolean;
|
|
2168
|
-
} | null> {
|
|
2169
|
-
return runWithRouterLogContext(
|
|
2170
|
-
{ request, transaction: "previewMatch" },
|
|
2171
|
-
async () =>
|
|
2172
|
-
withRouterLogScope("previewMatch", async () => {
|
|
2173
|
-
const url = new URL(request.url);
|
|
2174
|
-
const pathname = url.pathname;
|
|
2175
|
-
|
|
2176
|
-
// Quick route matching
|
|
2177
|
-
const matched = findMatch(pathname);
|
|
2178
|
-
if (!matched) {
|
|
2179
|
-
return null;
|
|
2180
|
-
}
|
|
2181
|
-
|
|
2182
|
-
// Skip redirect check - will be handled in full match
|
|
2183
|
-
if (matched.redirectTo) {
|
|
2184
|
-
return { routeMiddleware: undefined };
|
|
2185
|
-
}
|
|
642
|
+
// Prerender/static match deps (bind closure state for extracted functions)
|
|
643
|
+
const prerenderDeps = {
|
|
644
|
+
findMatch,
|
|
645
|
+
buildRouterContext,
|
|
646
|
+
mergedRouteMap,
|
|
647
|
+
resolveAllSegments,
|
|
648
|
+
};
|
|
2186
649
|
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
650
|
+
async function matchForPrerender(
|
|
651
|
+
pathname: string,
|
|
652
|
+
params: Record<string, string>,
|
|
653
|
+
buildVars?: Record<string, any>,
|
|
654
|
+
isPassthroughRoute?: boolean,
|
|
655
|
+
buildEnv?: TEnv,
|
|
656
|
+
devMode?: boolean,
|
|
657
|
+
) {
|
|
658
|
+
return _matchForPrerender(
|
|
2191
659
|
pathname,
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
const routeMiddleware = collectRouteMiddleware(
|
|
2199
|
-
traverseBack(manifestEntry),
|
|
2200
|
-
matched.params,
|
|
660
|
+
params,
|
|
661
|
+
prerenderDeps,
|
|
662
|
+
buildVars,
|
|
663
|
+
isPassthroughRoute,
|
|
664
|
+
buildEnv,
|
|
665
|
+
devMode,
|
|
2201
666
|
);
|
|
667
|
+
}
|
|
2202
668
|
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
const variants = matched.negotiateVariants;
|
|
2218
|
-
let candidates: Array<{ routeKey: string; responseType: string }>;
|
|
2219
|
-
if (responseType) {
|
|
2220
|
-
// Primary is response-type — include it as a candidate
|
|
2221
|
-
candidates = [...variants, { routeKey: matched.routeKey, responseType }];
|
|
2222
|
-
} else {
|
|
2223
|
-
// Primary is RSC — insert as text/html candidate in definition order
|
|
2224
|
-
const rscCandidate = { routeKey: matched.routeKey, responseType: RSC_RESPONSE_TYPE };
|
|
2225
|
-
candidates = matched.rscFirst
|
|
2226
|
-
? [rscCandidate, ...variants]
|
|
2227
|
-
: [...variants, rscCandidate];
|
|
2228
|
-
}
|
|
2229
|
-
|
|
2230
|
-
const variant = pickNegotiateVariant(acceptEntries, candidates);
|
|
2231
|
-
|
|
2232
|
-
// If the winner is RSC, fall through to default RSC handling
|
|
2233
|
-
if (variant.responseType === RSC_RESPONSE_TYPE) {
|
|
2234
|
-
// Fall through — RSC won negotiation
|
|
2235
|
-
} else if (responseType && variant.routeKey === matched.routeKey) {
|
|
2236
|
-
// Fall through — response-type primary won, already set
|
|
2237
|
-
} else {
|
|
2238
|
-
const negotiateEntry = await loadManifest(
|
|
2239
|
-
matched.entry,
|
|
2240
|
-
variant.routeKey,
|
|
2241
|
-
pathname,
|
|
2242
|
-
undefined,
|
|
2243
|
-
false,
|
|
2244
|
-
);
|
|
2245
|
-
return {
|
|
2246
|
-
routeMiddleware: routeMiddleware.length > 0 ? routeMiddleware : undefined,
|
|
2247
|
-
responseType: variant.responseType,
|
|
2248
|
-
handler: negotiateEntry.type === "route" ? negotiateEntry.handler : undefined,
|
|
2249
|
-
params: matched.params,
|
|
2250
|
-
negotiated: true,
|
|
2251
|
-
};
|
|
2252
|
-
}
|
|
2253
|
-
}
|
|
2254
|
-
|
|
2255
|
-
// If we passed through the negotiation block (variants exist), mark as
|
|
2256
|
-
// negotiated so the handler sets Vary: Accept on the response.
|
|
2257
|
-
const hasVariants = matched.negotiateVariants && matched.negotiateVariants.length > 0;
|
|
2258
|
-
return {
|
|
2259
|
-
routeMiddleware: routeMiddleware.length > 0 ? routeMiddleware : undefined,
|
|
2260
|
-
...(responseType ? {
|
|
2261
|
-
responseType,
|
|
2262
|
-
handler: manifestEntry.type === "route" ? manifestEntry.handler : undefined,
|
|
2263
|
-
params: matched.params,
|
|
2264
|
-
} : {}),
|
|
2265
|
-
...(hasVariants ? { negotiated: true } : {}),
|
|
2266
|
-
};
|
|
2267
|
-
}),
|
|
669
|
+
async function renderStaticSegment(
|
|
670
|
+
handler: Function,
|
|
671
|
+
handlerId: string,
|
|
672
|
+
routeName?: string,
|
|
673
|
+
buildEnv?: TEnv,
|
|
674
|
+
devMode?: boolean,
|
|
675
|
+
) {
|
|
676
|
+
return _renderStaticSegment<TEnv>(
|
|
677
|
+
handler,
|
|
678
|
+
handlerId,
|
|
679
|
+
mergedRouteMap,
|
|
680
|
+
routeName,
|
|
681
|
+
buildEnv,
|
|
682
|
+
devMode,
|
|
2268
683
|
);
|
|
2269
684
|
}
|
|
2270
685
|
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
// Keys stay unchanged for composability - only URL patterns get prefixed
|
|
2283
|
-
const routeEntries = routes as Record<string, string>;
|
|
2284
|
-
for (const [key, pattern] of Object.entries(routeEntries)) {
|
|
2285
|
-
// Build prefixed pattern: "/shop" + "/cart" -> "/shop/cart"
|
|
2286
|
-
// Root prefix "/" is a no-op — don't double the leading slash.
|
|
2287
|
-
const effectivePrefix = prefix === "/" ? "" : prefix;
|
|
2288
|
-
const prefixedPattern =
|
|
2289
|
-
effectivePrefix && pattern !== "/"
|
|
2290
|
-
? `${effectivePrefix}${pattern}`
|
|
2291
|
-
: effectivePrefix && pattern === "/"
|
|
2292
|
-
? effectivePrefix
|
|
2293
|
-
: pattern;
|
|
2294
|
-
|
|
2295
|
-
// Runtime validation: warn if key already exists with different pattern
|
|
2296
|
-
const existingPattern = mergedRouteMap[key];
|
|
2297
|
-
if (
|
|
2298
|
-
existingPattern !== undefined &&
|
|
2299
|
-
existingPattern !== prefixedPattern
|
|
2300
|
-
) {
|
|
2301
|
-
console.warn(
|
|
2302
|
-
`[rsc-router] Route key conflict: "${key}" already maps to "${existingPattern}", ` +
|
|
2303
|
-
`overwriting with "${prefixedPattern}". Use unique key names to avoid this.`,
|
|
2304
|
-
);
|
|
2305
|
-
}
|
|
2306
|
-
|
|
2307
|
-
// Use original key - enables reusable route modules
|
|
2308
|
-
mergedRouteMap[key] = prefixedPattern;
|
|
2309
|
-
}
|
|
2310
|
-
|
|
2311
|
-
// Auto-register route map for runtime reverse() usage
|
|
2312
|
-
registerRouteMap(mergedRouteMap);
|
|
2313
|
-
|
|
2314
|
-
// Extract trailing slash config if present (attached by route())
|
|
2315
|
-
const trailingSlashConfig = (routes as any).__trailingSlash as
|
|
2316
|
-
| Record<string, TrailingSlashMode>
|
|
2317
|
-
| undefined;
|
|
2318
|
-
|
|
2319
|
-
// Create builder object so .use() can return it
|
|
2320
|
-
const builder: RouteBuilder<RouteDefinition, TEnv, any, TNewRoutes> = {
|
|
2321
|
-
use(
|
|
2322
|
-
patternOrMiddleware: string | MiddlewareFn<TEnv>,
|
|
2323
|
-
middleware?: MiddlewareFn<TEnv>,
|
|
2324
|
-
) {
|
|
2325
|
-
// Mount-scoped middleware - prefix is the mount prefix
|
|
2326
|
-
addMiddleware(patternOrMiddleware, middleware, prefix || null);
|
|
2327
|
-
return builder;
|
|
2328
|
-
},
|
|
2329
|
-
|
|
2330
|
-
map(
|
|
2331
|
-
handler:
|
|
2332
|
-
| ((
|
|
2333
|
-
helpers: InlineRouteHelpers<TNewRoutes, TEnv>,
|
|
2334
|
-
) => Array<AllUseItems>)
|
|
2335
|
-
| (() =>
|
|
2336
|
-
| Array<AllUseItems>
|
|
2337
|
-
| Promise<{ default: () => Array<AllUseItems> }>
|
|
2338
|
-
| Promise<() => Array<AllUseItems>>),
|
|
2339
|
-
) {
|
|
2340
|
-
// Store handler as-is - detection happens at call time based on return type
|
|
2341
|
-
// Both patterns use the same signature:
|
|
2342
|
-
// - Inline: ({ route }) => [...] - receives helpers, returns Array
|
|
2343
|
-
// - Lazy: () => import(...) - ignores helpers, returns Promise
|
|
2344
|
-
routesEntries.push({
|
|
2345
|
-
prefix,
|
|
2346
|
-
staticPrefix: extractStaticPrefix(prefix),
|
|
2347
|
-
routes: routes as ResolvedRouteMap<any>,
|
|
2348
|
-
trailingSlash: trailingSlashConfig,
|
|
2349
|
-
handler: handler as any,
|
|
2350
|
-
mountIndex: currentMountIndex,
|
|
2351
|
-
});
|
|
2352
|
-
// Return router with accumulated types
|
|
2353
|
-
// At runtime this is the same object, but TypeScript tracks the accumulated route types
|
|
2354
|
-
return router as any;
|
|
2355
|
-
},
|
|
2356
|
-
|
|
2357
|
-
// Expose accumulated route map for typeof extraction
|
|
2358
|
-
get routeMap() {
|
|
2359
|
-
return mergedRouteMap as TNewRoutes;
|
|
2360
|
-
},
|
|
2361
|
-
};
|
|
686
|
+
// Create match handler functions bound to router state
|
|
687
|
+
const matchHandlers = createMatchHandlers<TEnv>({
|
|
688
|
+
buildRouterContext,
|
|
689
|
+
callOnError,
|
|
690
|
+
matchApiDeps,
|
|
691
|
+
defaultErrorBoundary,
|
|
692
|
+
findMatch,
|
|
693
|
+
findInterceptForRoute,
|
|
694
|
+
telemetry: telemetrySink,
|
|
695
|
+
cacheSignalEnabled,
|
|
696
|
+
});
|
|
2362
697
|
|
|
2363
|
-
|
|
2364
|
-
}
|
|
698
|
+
const { match, matchPartial, matchError, previewMatch } = matchHandlers;
|
|
2365
699
|
|
|
2366
700
|
/**
|
|
2367
701
|
* Router instance
|
|
2368
702
|
* The type system tracks accumulated routes through the builder chain
|
|
2369
703
|
* Initial TRoutes is {} (empty) to avoid poisoning accumulated types with Record<string, string>
|
|
2370
704
|
*/
|
|
2371
|
-
const router:
|
|
705
|
+
const router: RangoInternal<TEnv, {}> = {
|
|
2372
706
|
__brand: RSC_ROUTER_BRAND,
|
|
2373
707
|
id: routerId,
|
|
708
|
+
basename,
|
|
2374
709
|
|
|
2375
|
-
routes(
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
// Check if argument is UrlPatterns (new Django-style API)
|
|
2383
|
-
// Detect by checking for handler and definitions properties
|
|
2384
|
-
if (
|
|
2385
|
-
typeof prefixOrRoutes === "object" &&
|
|
2386
|
-
prefixOrRoutes !== null &&
|
|
2387
|
-
"handler" in prefixOrRoutes &&
|
|
2388
|
-
"definitions" in prefixOrRoutes &&
|
|
2389
|
-
typeof (prefixOrRoutes as UrlPatterns<TEnv>).handler === "function"
|
|
2390
|
-
) {
|
|
2391
|
-
const urlPatterns = prefixOrRoutes as UrlPatterns<TEnv>;
|
|
2392
|
-
// Store reference for runtime manifest generation
|
|
2393
|
-
storedUrlPatterns = urlPatterns;
|
|
2394
|
-
const currentMountIndex = mountIndex++;
|
|
2395
|
-
|
|
2396
|
-
// Create manifest and patterns maps for route registration
|
|
2397
|
-
const manifest = new Map<string, EntryData>();
|
|
2398
|
-
const patterns = new Map<string, string>();
|
|
2399
|
-
const patternsByPrefix = new Map<string, Map<string, string>>();
|
|
2400
|
-
const trailingSlashMap = new Map<string, TrailingSlashMode>();
|
|
2401
|
-
|
|
2402
|
-
// Run the handler once to extract patterns for route matching.
|
|
2403
|
-
// Note: loadManifest will re-run the handler to register entries in its context.
|
|
2404
|
-
// Lazy includes are detected in the return value and handled separately.
|
|
2405
|
-
//
|
|
2406
|
-
// Pattern extraction must use the same mountIndex and MapRootLayout root
|
|
2407
|
-
// parent as loadManifest so that shortCodes produced here match those at
|
|
2408
|
-
// runtime. include() captures the current parent and counters; if those
|
|
2409
|
-
// shortCodes diverge from the runtime tree the segment reconciliation on
|
|
2410
|
-
// the client will see a full mismatch and remount the entire page.
|
|
2411
|
-
const syntheticMapRoot: EntryData = {
|
|
2412
|
-
type: "layout",
|
|
2413
|
-
id: `#synthetic-maproot-M${currentMountIndex}`,
|
|
2414
|
-
shortCode: `M${currentMountIndex}L0`,
|
|
2415
|
-
parent: null,
|
|
2416
|
-
handler: MapRootLayout,
|
|
2417
|
-
middleware: [],
|
|
2418
|
-
revalidate: [],
|
|
2419
|
-
errorBoundary: [],
|
|
2420
|
-
notFoundBoundary: [],
|
|
2421
|
-
layout: [],
|
|
2422
|
-
parallel: [],
|
|
2423
|
-
intercept: [],
|
|
2424
|
-
loader: [],
|
|
2425
|
-
};
|
|
710
|
+
routes(patternsOrBuilder: UrlPatterns<TEnv> | UrlBuilder<TEnv>): any {
|
|
711
|
+
// Wrap builder functions in urls() automatically
|
|
712
|
+
const urlPatterns: UrlPatterns<TEnv> =
|
|
713
|
+
typeof patternsOrBuilder === "function"
|
|
714
|
+
? (urls(patternsOrBuilder) as UrlPatterns<TEnv>)
|
|
715
|
+
: patternsOrBuilder;
|
|
2426
716
|
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
manifest,
|
|
2431
|
-
patterns,
|
|
2432
|
-
patternsByPrefix,
|
|
2433
|
-
trailingSlash: trailingSlashMap,
|
|
2434
|
-
namespace: "root",
|
|
2435
|
-
parent: syntheticMapRoot,
|
|
2436
|
-
counters: {},
|
|
2437
|
-
mountIndex: currentMountIndex,
|
|
2438
|
-
},
|
|
2439
|
-
() => {
|
|
2440
|
-
handlerResult = urlPatterns.handler() as AllUseItems[];
|
|
2441
|
-
},
|
|
2442
|
-
);
|
|
717
|
+
// Store reference for runtime manifest generation
|
|
718
|
+
storedUrlPatterns = urlPatterns;
|
|
719
|
+
const currentMountIndex = mountIndex++;
|
|
2443
720
|
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
721
|
+
// Create manifest and patterns maps for route registration
|
|
722
|
+
const manifest = new Map<string, EntryData>();
|
|
723
|
+
const routePatterns = new Map<string, string>();
|
|
724
|
+
const patternsByPrefix = new Map<string, Map<string, string>>();
|
|
725
|
+
const trailingSlashMap = new Map<string, TrailingSlashMode>();
|
|
726
|
+
|
|
727
|
+
// Run the handler once to extract patterns for route matching.
|
|
728
|
+
// Note: loadManifest will re-run the handler to register entries in its context.
|
|
729
|
+
// Lazy includes are detected in the return value and handled separately.
|
|
730
|
+
//
|
|
731
|
+
// Pattern extraction must use the same mountIndex and MapRootLayout root
|
|
732
|
+
// parent as loadManifest so that shortCodes produced here match those at
|
|
733
|
+
// runtime. include() captures the current parent and counters; if those
|
|
734
|
+
// shortCodes diverge from the runtime tree the segment reconciliation on
|
|
735
|
+
// the client will see a full mismatch and remount the entire page.
|
|
736
|
+
const syntheticMapRoot: EntryData = {
|
|
737
|
+
type: "layout",
|
|
738
|
+
id: `#synthetic-maproot-M${currentMountIndex}`,
|
|
739
|
+
shortCode: `M${currentMountIndex}L0`,
|
|
740
|
+
parent: null,
|
|
741
|
+
handler: MapRootLayout,
|
|
742
|
+
middleware: [],
|
|
743
|
+
revalidate: [],
|
|
744
|
+
errorBoundary: [],
|
|
745
|
+
notFoundBoundary: [],
|
|
746
|
+
layout: [],
|
|
747
|
+
parallel: {},
|
|
748
|
+
intercept: [],
|
|
749
|
+
loader: [],
|
|
750
|
+
};
|
|
2459
751
|
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
752
|
+
let handlerResult: AllUseItems[] = [];
|
|
753
|
+
RangoContext.run(
|
|
754
|
+
{
|
|
755
|
+
manifest,
|
|
756
|
+
patterns: routePatterns,
|
|
757
|
+
patternsByPrefix,
|
|
758
|
+
trailingSlash: trailingSlashMap,
|
|
759
|
+
namespace: "root",
|
|
760
|
+
parent: syntheticMapRoot,
|
|
761
|
+
counters: {},
|
|
762
|
+
mountIndex: currentMountIndex,
|
|
763
|
+
cacheProfiles: resolvedCacheProfiles,
|
|
764
|
+
// basename sets the initial URL prefix so all path() patterns
|
|
765
|
+
// are registered with the prefix (e.g. "/admin" + "/users" = "/admin/users").
|
|
766
|
+
// No namePrefix — route names stay unprefixed.
|
|
767
|
+
...(basename ? { urlPrefix: basename } : {}),
|
|
768
|
+
},
|
|
769
|
+
() => {
|
|
770
|
+
handlerResult = urlPatterns.handler() as AllUseItems[];
|
|
771
|
+
},
|
|
772
|
+
);
|
|
2468
773
|
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
774
|
+
// Convert trailingSlash map to object for the router
|
|
775
|
+
const trailingSlashConfig =
|
|
776
|
+
trailingSlashMap.size > 0
|
|
777
|
+
? Object.fromEntries(trailingSlashMap)
|
|
778
|
+
: undefined;
|
|
779
|
+
|
|
780
|
+
// Collect route keys that have prerender handlers (for non-trie match path)
|
|
781
|
+
let prerenderRouteKeys: Set<string> | undefined;
|
|
782
|
+
let passthroughRouteKeys: Set<string> | undefined;
|
|
783
|
+
for (const [name, entry] of manifest.entries()) {
|
|
784
|
+
if (entry.type === "route" && entry.isPrerender) {
|
|
785
|
+
if (!prerenderRouteKeys) prerenderRouteKeys = new Set();
|
|
786
|
+
prerenderRouteKeys.add(name);
|
|
787
|
+
if (entry.isPassthrough === true) {
|
|
788
|
+
if (!passthroughRouteKeys) passthroughRouteKeys = new Set();
|
|
789
|
+
passthroughRouteKeys.add(name);
|
|
2481
790
|
}
|
|
2482
|
-
}
|
|
2483
|
-
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
// Create separate RouteEntry for each URL prefix group
|
|
795
|
+
// This enables prefix-based short-circuit optimization
|
|
796
|
+
if (patternsByPrefix.size > 0) {
|
|
797
|
+
for (const [prefix, prefixPatterns] of patternsByPrefix.entries()) {
|
|
2484
798
|
const routesObject: Record<string, string> = {};
|
|
2485
|
-
for (const [name, pattern] of
|
|
799
|
+
for (const [name, pattern] of prefixPatterns.entries()) {
|
|
2486
800
|
routesObject[name] = pattern;
|
|
2487
801
|
}
|
|
2488
802
|
|
|
2489
803
|
routesEntries.push({
|
|
804
|
+
// prefix is "" because patterns already include the URL prefix
|
|
805
|
+
// (e.g., "/site/:locale/user1/:id" not just "/user1/:id")
|
|
2490
806
|
prefix: "",
|
|
2491
|
-
staticPrefix
|
|
807
|
+
// staticPrefix is the actual prefix for short-circuit optimization
|
|
808
|
+
staticPrefix: extractStaticPrefix(prefix),
|
|
2492
809
|
routes: routesObject as ResolvedRouteMap<any>,
|
|
2493
810
|
trailingSlash: trailingSlashConfig,
|
|
2494
811
|
handler: urlPatterns.handler,
|
|
2495
812
|
mountIndex: currentMountIndex,
|
|
813
|
+
routerId,
|
|
814
|
+
cacheProfiles: resolvedCacheProfiles,
|
|
2496
815
|
...(prerenderRouteKeys ? { prerenderRouteKeys } : {}),
|
|
816
|
+
...(passthroughRouteKeys ? { passthroughRouteKeys } : {}),
|
|
2497
817
|
});
|
|
2498
818
|
}
|
|
2499
|
-
|
|
2500
|
-
//
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
if (existingPattern !== undefined && existingPattern !== pattern) {
|
|
2505
|
-
console.warn(
|
|
2506
|
-
`[@rangojs/router] Route name conflict: "${name}" already maps to "${existingPattern}", ` +
|
|
2507
|
-
`overwriting with "${pattern}". Use unique route names to avoid this.`,
|
|
2508
|
-
);
|
|
2509
|
-
}
|
|
2510
|
-
mergedRouteMap[name] = pattern;
|
|
819
|
+
} else {
|
|
820
|
+
// Fallback: no prefix grouping, use flat patterns map
|
|
821
|
+
const routesObject: Record<string, string> = {};
|
|
822
|
+
for (const [name, pattern] of routePatterns.entries()) {
|
|
823
|
+
routesObject[name] = pattern;
|
|
2511
824
|
}
|
|
2512
825
|
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
826
|
+
routesEntries.push({
|
|
827
|
+
prefix: "",
|
|
828
|
+
staticPrefix: "",
|
|
829
|
+
routes: routesObject as ResolvedRouteMap<any>,
|
|
830
|
+
trailingSlash: trailingSlashConfig,
|
|
831
|
+
handler: urlPatterns.handler,
|
|
832
|
+
mountIndex: currentMountIndex,
|
|
833
|
+
routerId,
|
|
834
|
+
cacheProfiles: resolvedCacheProfiles,
|
|
835
|
+
...(prerenderRouteKeys ? { prerenderRouteKeys } : {}),
|
|
836
|
+
...(passthroughRouteKeys ? { passthroughRouteKeys } : {}),
|
|
837
|
+
});
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
// Build route map from registered patterns
|
|
841
|
+
for (const [name, pattern] of routePatterns.entries()) {
|
|
842
|
+
// Runtime validation: warn if key already exists with different pattern.
|
|
843
|
+
// Skip warning for entries that came from the static seed — the gen file
|
|
844
|
+
// can be stale during HMR, so runtime registration is authoritative.
|
|
845
|
+
const existingPattern = mergedRouteMap[name];
|
|
846
|
+
if (
|
|
847
|
+
existingPattern !== undefined &&
|
|
848
|
+
existingPattern !== pattern &&
|
|
849
|
+
!seededNames.has(name)
|
|
850
|
+
) {
|
|
851
|
+
console.warn(
|
|
852
|
+
`[@rangojs/router] Route name conflict: "${name}" already maps to "${existingPattern}", ` +
|
|
853
|
+
`overwriting with "${pattern}". Use unique route names to avoid this.`,
|
|
854
|
+
);
|
|
855
|
+
}
|
|
856
|
+
mergedRouteMap[name] = pattern;
|
|
857
|
+
seededNames.delete(name);
|
|
858
|
+
}
|
|
2516
859
|
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
860
|
+
// Detect lazy includes in handler result and create placeholder entries
|
|
861
|
+
const lazyIncludes = findLazyIncludes(handlerResult);
|
|
862
|
+
|
|
863
|
+
// Create placeholder RouteEntry for each lazy include
|
|
864
|
+
for (const lazyInclude of lazyIncludes) {
|
|
865
|
+
// Compute the full URL prefix (combining parent prefix if any). Use the
|
|
866
|
+
// slash-collapsing join so a trailing-slash parent prefix does not
|
|
867
|
+
// produce a double-slash staticPrefix the trie's sp can never match.
|
|
868
|
+
const fullPrefix = joinPrefix(
|
|
869
|
+
lazyInclude.context.urlPrefix,
|
|
870
|
+
lazyInclude.prefix,
|
|
871
|
+
);
|
|
2523
872
|
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
}
|
|
873
|
+
const lazyEntry: RouteEntry<TEnv> & { _lazyPrefix?: string } = {
|
|
874
|
+
prefix: "",
|
|
875
|
+
staticPrefix: extractStaticPrefix(fullPrefix),
|
|
876
|
+
routes: {} as ResolvedRouteMap<any>, // Empty until first match
|
|
877
|
+
trailingSlash: trailingSlashConfig,
|
|
878
|
+
handler: urlPatterns.handler,
|
|
879
|
+
mountIndex: mountIndex++,
|
|
880
|
+
routerId,
|
|
881
|
+
// Lazy evaluation fields
|
|
882
|
+
lazy: true,
|
|
883
|
+
lazyPatterns: lazyInclude.patterns,
|
|
884
|
+
lazyContext: lazyInclude.context,
|
|
885
|
+
lazyEvaluated: false,
|
|
886
|
+
_lazyPrefix: lazyInclude.prefix,
|
|
887
|
+
};
|
|
888
|
+
// Insert lazy entry before any entry whose staticPrefix is a
|
|
889
|
+
// prefix of (but shorter than) this lazy entry's staticPrefix.
|
|
890
|
+
// This ensures more specific lazy includes are matched before
|
|
891
|
+
// less specific eager entries (e.g., "/href/nested" before "/href/:id").
|
|
892
|
+
const lazyPrefix = lazyEntry.staticPrefix;
|
|
893
|
+
let insertIndex = routesEntries.length;
|
|
894
|
+
if (lazyPrefix) {
|
|
895
|
+
for (let i = 0; i < routesEntries.length; i++) {
|
|
896
|
+
const existing = routesEntries[i]!;
|
|
897
|
+
if (
|
|
898
|
+
lazyPrefix.startsWith(existing.staticPrefix) &&
|
|
899
|
+
lazyPrefix.length > existing.staticPrefix.length
|
|
900
|
+
) {
|
|
901
|
+
insertIndex = i;
|
|
902
|
+
break;
|
|
2555
903
|
}
|
|
2556
904
|
}
|
|
2557
|
-
routesEntries.splice(insertIndex, 0, lazyEntry);
|
|
2558
905
|
}
|
|
2559
|
-
|
|
2560
|
-
// Auto-register route map for runtime reverse() usage
|
|
2561
|
-
registerRouteMap(mergedRouteMap);
|
|
2562
|
-
|
|
2563
|
-
// Return the router (no .map() needed for UrlPatterns)
|
|
2564
|
-
return router;
|
|
906
|
+
routesEntries.splice(insertIndex, 0, lazyEntry);
|
|
2565
907
|
}
|
|
2566
908
|
|
|
2567
|
-
//
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
}
|
|
2572
|
-
// Otherwise, first argument is routes with empty prefix
|
|
2573
|
-
return createRouteBuilder("", prefixOrRoutes as Record<string, string>);
|
|
909
|
+
// Auto-register route map for runtime reverse() usage
|
|
910
|
+
registerRouteMap(mergedRouteMap);
|
|
911
|
+
|
|
912
|
+
return router;
|
|
2574
913
|
},
|
|
2575
914
|
|
|
2576
915
|
use(
|
|
2577
916
|
patternOrMiddleware: string | MiddlewareFn<TEnv>,
|
|
2578
917
|
middleware?: MiddlewareFn<TEnv>,
|
|
2579
918
|
): any {
|
|
2580
|
-
//
|
|
2581
|
-
|
|
919
|
+
// Auto-prefix pattern with basename so router-level middleware
|
|
920
|
+
// patterns are router-relative (e.g. "/users/*" matches "/app/users/*").
|
|
921
|
+
if (basename && typeof patternOrMiddleware === "string") {
|
|
922
|
+
const pattern = patternOrMiddleware;
|
|
923
|
+
const prefixed =
|
|
924
|
+
pattern === "/*" || pattern === "*"
|
|
925
|
+
? `${basename}/*`
|
|
926
|
+
: `${basename}${pattern}`;
|
|
927
|
+
addMiddleware(prefixed, middleware, null);
|
|
928
|
+
} else {
|
|
929
|
+
addMiddleware(patternOrMiddleware, middleware, null);
|
|
930
|
+
}
|
|
2582
931
|
return router;
|
|
2583
932
|
},
|
|
2584
933
|
|
|
2585
934
|
// Type-safe URL builder using merged route map
|
|
2586
935
|
// Types are tracked through the builder chain via TRoutes parameter
|
|
2587
|
-
//
|
|
2588
|
-
reverse: createReverse(mergedRouteMap
|
|
936
|
+
// Seeded with static route names from the generated file (injected by Vite)
|
|
937
|
+
reverse: createReverse(mergedRouteMap),
|
|
2589
938
|
|
|
2590
939
|
// Expose accumulated route map for typeof extraction
|
|
2591
940
|
// Returns {} initially, but builder chain accumulates specific route types
|
|
@@ -2608,20 +957,69 @@ export function createRouter<TEnv = any>(
|
|
|
2608
957
|
// Expose resolved theme configuration for NavigationProvider and MetaTags
|
|
2609
958
|
themeConfig: resolvedThemeConfig,
|
|
2610
959
|
|
|
960
|
+
// Expose resolved cache profiles for per-request resolution
|
|
961
|
+
cacheProfiles: resolvedCacheProfiles,
|
|
962
|
+
|
|
963
|
+
// Expose prefetch cache settings
|
|
964
|
+
prefetchCacheControl,
|
|
965
|
+
prefetchCacheTTL,
|
|
966
|
+
|
|
967
|
+
// Expose the resolved rango state cookie name for the server-side writer
|
|
968
|
+
// (invalidateClientCache) and for shipping to the client in metadata.
|
|
969
|
+
resolvedStateCookieName,
|
|
970
|
+
|
|
2611
971
|
// Expose warmup enabled flag for handler and client
|
|
2612
972
|
warmupEnabled,
|
|
2613
973
|
|
|
974
|
+
// Expose router-wide performance debugging for request-level metrics setup
|
|
975
|
+
debugPerformance,
|
|
976
|
+
|
|
977
|
+
// Expose resolved span tracing for the handler (Cloudflare custom spans)
|
|
978
|
+
tracing: resolvedTracing,
|
|
979
|
+
|
|
2614
980
|
// Expose debug manifest flag for handler
|
|
2615
981
|
allowDebugManifest: allowDebugManifestOption,
|
|
2616
982
|
|
|
983
|
+
// Expose origin check configuration for handler (default: enabled)
|
|
984
|
+
originCheck: originCheckOption ?? true,
|
|
985
|
+
|
|
986
|
+
// Expose SSR configuration for handler
|
|
987
|
+
ssr: ssrOption,
|
|
988
|
+
|
|
989
|
+
// Expose resolved timeouts for RSC handler
|
|
990
|
+
timeouts: resolvedTimeouts,
|
|
991
|
+
onTimeout,
|
|
992
|
+
|
|
2617
993
|
// Expose global middleware for RSC handler
|
|
2618
994
|
middleware: globalMiddleware,
|
|
2619
995
|
|
|
2620
|
-
match,
|
|
996
|
+
match: (request: Request, input: RouterRequestInput<TEnv> = {}) => {
|
|
997
|
+
const env = input.env ?? ({} as TEnv);
|
|
998
|
+
return match(request, env);
|
|
999
|
+
},
|
|
2621
1000
|
matchForPrerender,
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
1001
|
+
renderStaticSegment,
|
|
1002
|
+
matchPartial: (
|
|
1003
|
+
request: Request,
|
|
1004
|
+
input: RouterRequestInput<TEnv> = {},
|
|
1005
|
+
actionContext?: Parameters<typeof matchPartial>[2],
|
|
1006
|
+
) => {
|
|
1007
|
+
const env = input.env ?? ({} as TEnv);
|
|
1008
|
+
return matchPartial(request, env, actionContext);
|
|
1009
|
+
},
|
|
1010
|
+
matchError: (
|
|
1011
|
+
request: Request,
|
|
1012
|
+
input: RouterRequestInput<TEnv> | undefined,
|
|
1013
|
+
error: unknown,
|
|
1014
|
+
segmentType?: Parameters<typeof matchError>[3],
|
|
1015
|
+
) => {
|
|
1016
|
+
const env = input?.env ?? ({} as TEnv);
|
|
1017
|
+
return matchError(request, env, error, segmentType);
|
|
1018
|
+
},
|
|
1019
|
+
previewMatch: (request: Request, input: RouterRequestInput<TEnv> = {}) => {
|
|
1020
|
+
const env = input.env ?? ({} as TEnv);
|
|
1021
|
+
return previewMatch(request, env);
|
|
1022
|
+
},
|
|
2625
1023
|
|
|
2626
1024
|
// Expose nonce provider for fetch
|
|
2627
1025
|
nonce,
|
|
@@ -2637,93 +1035,67 @@ export function createRouter<TEnv = any>(
|
|
|
2637
1035
|
// Expose source file for per-router type generation
|
|
2638
1036
|
__sourceFile,
|
|
2639
1037
|
|
|
1038
|
+
// Expose basename for runtime manifest generation
|
|
1039
|
+
__basename: basename,
|
|
1040
|
+
|
|
1041
|
+
// Expose router-level boundary defaults for build-time clientChunks
|
|
1042
|
+
// discovery (so a "use client" default boundary lands in app-fallback).
|
|
1043
|
+
// These are createRouter options, never pushed onto EntryData.
|
|
1044
|
+
__defaultErrorBoundary: defaultErrorBoundary,
|
|
1045
|
+
__defaultNotFoundBoundary: defaultNotFoundBoundary,
|
|
1046
|
+
__notFound: notFound,
|
|
1047
|
+
|
|
2640
1048
|
// RSC request handler (lazily created on first call)
|
|
2641
1049
|
fetch: (() => {
|
|
2642
1050
|
// Handler is created on first call and reused
|
|
2643
1051
|
let handler:
|
|
2644
1052
|
| ((
|
|
2645
1053
|
request: Request,
|
|
2646
|
-
|
|
1054
|
+
input: RouterRequestInput<TEnv>,
|
|
2647
1055
|
) => Promise<Response>)
|
|
2648
1056
|
| null = null;
|
|
2649
1057
|
|
|
2650
|
-
return async (
|
|
2651
|
-
request: Request,
|
|
2652
|
-
env: TEnv & { ctx?: ExecutionContext },
|
|
2653
|
-
) => {
|
|
1058
|
+
return async (request: Request, input: RouterRequestInput<TEnv> = {}) => {
|
|
2654
1059
|
// Trigger lazy import of per-router manifest data before route matching.
|
|
2655
1060
|
// No-op if data is already loaded or no loader is registered.
|
|
2656
1061
|
await ensureRouterManifest(routerId);
|
|
2657
1062
|
if (!handler) {
|
|
2658
1063
|
// Lazy import deferred to first request to avoid dev mode issues
|
|
2659
1064
|
const { createRSCHandler } = await import("./rsc/handler.js");
|
|
1065
|
+
// Cast: createRSCHandler receives `router as any`, which erases TEnv
|
|
1066
|
+
// and infers its handler as RouterRequestInput<unknown>. Re-narrow the
|
|
1067
|
+
// returned handler to RouterRequestInput<TEnv> so the call below stays
|
|
1068
|
+
// typed. (The handler already accepts (request, RouterRequestInput).)
|
|
2660
1069
|
handler = createRSCHandler({
|
|
2661
1070
|
router: router as any,
|
|
2662
1071
|
cache,
|
|
2663
1072
|
nonce,
|
|
2664
1073
|
version,
|
|
2665
|
-
})
|
|
1074
|
+
}) as (
|
|
1075
|
+
request: Request,
|
|
1076
|
+
input: RouterRequestInput<TEnv>,
|
|
1077
|
+
) => Promise<Response>;
|
|
2666
1078
|
}
|
|
2667
|
-
return handler(request,
|
|
1079
|
+
return handler!(request, input);
|
|
2668
1080
|
};
|
|
2669
1081
|
})(),
|
|
2670
1082
|
|
|
2671
|
-
//
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
for (const entry of routesEntries) {
|
|
2676
|
-
const Store = {
|
|
2677
|
-
manifest,
|
|
2678
|
-
namespace: `debug.M${entry.mountIndex}`,
|
|
2679
|
-
parent: null as EntryData | null,
|
|
2680
|
-
counters: {} as Record<string, number>,
|
|
2681
|
-
mountIndex: entry.mountIndex,
|
|
2682
|
-
patterns: new Map<string, string>(),
|
|
2683
|
-
trailingSlash: new Map<string, TrailingSlashMode>(),
|
|
2684
|
-
};
|
|
2685
|
-
|
|
2686
|
-
await getContext().runWithStore(
|
|
2687
|
-
Store,
|
|
2688
|
-
`debug.M${entry.mountIndex}`,
|
|
2689
|
-
null,
|
|
2690
|
-
async () => {
|
|
2691
|
-
const helpers = createRouteHelpers();
|
|
2692
|
-
|
|
2693
|
-
// Wrap handler execution in root layout (same as loadManifest)
|
|
2694
|
-
let promiseResult: Promise<any> | null = null;
|
|
2695
|
-
helpers.layout(MapRootLayout, () => {
|
|
2696
|
-
const result = entry.handler();
|
|
2697
|
-
if (result instanceof Promise) {
|
|
2698
|
-
promiseResult = result;
|
|
2699
|
-
return [];
|
|
2700
|
-
}
|
|
2701
|
-
return result;
|
|
2702
|
-
});
|
|
2703
|
-
|
|
2704
|
-
if (promiseResult !== null) {
|
|
2705
|
-
const load = await (promiseResult as Promise<any>);
|
|
2706
|
-
if (load && typeof load === "object" && "default" in load) {
|
|
2707
|
-
const useItems = load.default;
|
|
2708
|
-
if (typeof useItems === "function") {
|
|
2709
|
-
useItems(helpers);
|
|
2710
|
-
}
|
|
2711
|
-
}
|
|
2712
|
-
}
|
|
2713
|
-
},
|
|
2714
|
-
);
|
|
2715
|
-
}
|
|
1083
|
+
// Low-level route matching for request classification
|
|
1084
|
+
findMatch: (pathname: string, metricsStore?: any) =>
|
|
1085
|
+
findMatch(pathname, metricsStore),
|
|
2716
1086
|
|
|
2717
|
-
|
|
2718
|
-
|
|
1087
|
+
// Debug utility for manifest inspection
|
|
1088
|
+
debugManifest: () => buildDebugManifest<TEnv>(routesEntries),
|
|
2719
1089
|
};
|
|
2720
1090
|
|
|
2721
1091
|
// Register router in the global registry for build-time discovery
|
|
2722
1092
|
RouterRegistry.set(routerId, router);
|
|
2723
1093
|
|
|
2724
1094
|
// If urls option was provided, auto-register them
|
|
2725
|
-
if (urlsOption) {
|
|
2726
|
-
return router.routes(urlsOption) as
|
|
1095
|
+
if (typeof urlsOption === "function") {
|
|
1096
|
+
return router.routes(urlsOption) as Rango<TEnv, {}>;
|
|
1097
|
+
} else if (urlsOption) {
|
|
1098
|
+
return router.routes(urlsOption) as Rango<TEnv, {}>;
|
|
2727
1099
|
}
|
|
2728
1100
|
|
|
2729
1101
|
return router;
|