@rangojs/router 0.0.0-experimental.9 → 0.0.0-experimental.91
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 +972 -4
- 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 +1619 -155
- 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/dist/browser/react/use-client-cache.js +39 -0
- 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/dist/handles/index.js +6 -0
- 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/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 +5565 -2291
- package/dist/vite/index.js.bak +5448 -0
- package/dist/vite/index.js.map +1 -0
- package/dist/vite/index.named-routes.gen.ts +103 -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 +72 -63
- package/skills/breadcrumbs/SKILL.md +252 -0
- package/skills/cache-guide/SKILL.md +294 -0
- package/skills/caching/SKILL.md +93 -23
- package/skills/composability/SKILL.md +172 -0
- package/skills/debug-manifest/SKILL.md +12 -8
- package/skills/document-cache/SKILL.md +18 -16
- package/skills/fonts/SKILL.md +6 -4
- package/skills/handler-use/SKILL.md +362 -0
- package/skills/hooks/SKILL.md +341 -71
- package/skills/host-router/SKILL.md +218 -0
- package/skills/intercept/SKILL.md +151 -8
- package/skills/layout/SKILL.md +122 -3
- package/skills/links/SKILL.md +158 -25
- package/skills/loader/SKILL.md +439 -46
- package/skills/middleware/SKILL.md +205 -37
- package/skills/migrate-nextjs/SKILL.md +560 -0
- package/skills/migrate-react-router/SKILL.md +765 -0
- package/skills/mime-routes/SKILL.md +15 -11
- package/skills/parallel/SKILL.md +263 -1
- package/skills/prerender/SKILL.md +467 -65
- package/skills/rango/SKILL.md +87 -21
- package/skills/response-routes/SKILL.md +152 -91
- package/skills/route/SKILL.md +281 -14
- package/skills/router-setup/SKILL.md +210 -32
- package/skills/streams-and-websockets/SKILL.md +283 -0
- package/skills/theme/SKILL.md +9 -8
- package/skills/typesafety/SKILL.md +327 -86
- package/skills/use-cache/SKILL.md +324 -0
- package/src/__internal.ts +102 -4
- package/src/bin/rango.ts +312 -15
- package/src/browser/action-coordinator.ts +97 -0
- package/src/browser/action-response-classifier.ts +99 -0
- package/src/browser/app-shell.ts +52 -0
- package/src/browser/app-version.ts +14 -0
- package/src/browser/event-controller.ts +92 -64
- package/src/browser/history-state.ts +80 -0
- package/src/browser/intercept-utils.ts +52 -0
- package/src/browser/link-interceptor.ts +24 -4
- package/src/browser/logging.ts +55 -0
- package/src/browser/merge-segment-loaders.ts +20 -12
- package/src/browser/navigation-bridge.ts +367 -561
- package/src/browser/navigation-client.ts +228 -70
- package/src/browser/navigation-store.ts +97 -55
- package/src/browser/navigation-transaction.ts +297 -0
- package/src/browser/network-error-handler.ts +61 -0
- package/src/browser/partial-update.ts +362 -316
- package/src/browser/prefetch/cache.ts +314 -0
- package/src/browser/prefetch/fetch.ts +282 -0
- package/src/browser/prefetch/observer.ts +65 -0
- package/src/browser/prefetch/policy.ts +48 -0
- package/src/browser/prefetch/queue.ts +191 -0
- package/src/browser/prefetch/resource-ready.ts +77 -0
- package/src/browser/rango-state.ts +152 -0
- package/src/browser/react/Link.tsx +255 -71
- package/src/browser/react/NavigationProvider.tsx +132 -17
- package/src/browser/react/context.ts +11 -0
- package/src/browser/react/filter-segment-order.ts +11 -0
- package/src/browser/react/index.ts +12 -12
- package/src/browser/react/location-state-shared.ts +95 -53
- package/src/browser/react/location-state.ts +60 -15
- 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 +29 -51
- package/src/browser/react/use-client-cache.ts +5 -3
- package/src/browser/react/use-handle.ts +30 -120
- package/src/browser/react/use-link-status.ts +6 -5
- package/src/browser/react/use-navigation.ts +44 -65
- package/src/browser/react/use-params.ts +75 -0
- package/src/browser/react/use-pathname.ts +47 -0
- package/src/browser/react/use-router.ts +83 -0
- package/src/browser/react/use-search-params.ts +56 -0
- package/src/browser/react/use-segments.ts +80 -97
- package/src/browser/response-adapter.ts +73 -0
- package/src/browser/rsc-router.tsx +246 -64
- package/src/browser/scroll-restoration.ts +127 -52
- package/src/browser/segment-reconciler.ts +243 -0
- package/src/browser/segment-structure-assert.ts +16 -0
- package/src/browser/server-action-bridge.ts +510 -603
- package/src/browser/shallow.ts +6 -1
- package/src/browser/types.ts +152 -48
- package/src/browser/validate-redirect-origin.ts +29 -0
- package/src/build/generate-manifest.ts +84 -23
- package/src/build/generate-route-types.ts +39 -752
- package/src/build/index.ts +6 -5
- package/src/build/route-trie.ts +83 -31
- 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 +102 -0
- package/src/build/route-types/include-resolution.ts +418 -0
- package/src/build/route-types/param-extraction.ts +48 -0
- package/src/build/route-types/per-module-writer.ts +128 -0
- package/src/build/route-types/router-processing.ts +618 -0
- package/src/build/route-types/scan-filter.ts +85 -0
- package/src/build/runtime-discovery.ts +231 -0
- package/src/cache/background-task.ts +34 -0
- package/src/cache/cache-key-utils.ts +44 -0
- package/src/cache/cache-policy.ts +125 -0
- package/src/cache/cache-runtime.ts +342 -0
- package/src/cache/cache-scope.ts +167 -307
- package/src/cache/cf/cf-cache-store.ts +573 -21
- package/src/cache/cf/index.ts +13 -3
- package/src/cache/document-cache.ts +116 -77
- package/src/cache/handle-capture.ts +81 -0
- package/src/cache/handle-snapshot.ts +41 -0
- package/src/cache/index.ts +1 -15
- package/src/cache/memory-segment-store.ts +191 -13
- package/src/cache/profile-registry.ts +73 -0
- package/src/cache/read-through-swr.ts +134 -0
- package/src/cache/segment-codec.ts +256 -0
- package/src/cache/taint.ts +153 -0
- package/src/cache/types.ts +72 -122
- package/src/client.rsc.tsx +3 -1
- package/src/client.tsx +113 -301
- package/src/component-utils.ts +4 -4
- package/src/components/DefaultDocument.tsx +5 -1
- package/src/context-var.ts +156 -0
- package/src/debug.ts +19 -9
- package/src/errors.ts +77 -7
- package/src/handle.ts +55 -10
- package/src/handles/MetaTags.tsx +73 -20
- package/src/handles/breadcrumbs.ts +66 -0
- package/src/handles/index.ts +1 -0
- package/src/handles/meta.ts +30 -13
- package/src/host/cookie-handler.ts +21 -15
- package/src/host/errors.ts +8 -8
- package/src/host/index.ts +4 -7
- package/src/host/pattern-matcher.ts +27 -27
- package/src/host/router.ts +61 -39
- package/src/host/testing.ts +8 -8
- package/src/host/types.ts +15 -7
- package/src/host/utils.ts +1 -1
- package/src/href-client.ts +65 -45
- package/src/index.rsc.ts +138 -21
- package/src/index.ts +206 -51
- package/src/internal-debug.ts +11 -0
- package/src/loader.rsc.ts +25 -143
- package/src/loader.ts +27 -10
- package/src/network-error-thrower.tsx +3 -1
- package/src/outlet-context.ts +1 -1
- package/src/outlet-provider.tsx +45 -0
- package/src/prerender/param-hash.ts +4 -2
- package/src/prerender/store.ts +159 -13
- package/src/prerender.ts +397 -29
- package/src/response-utils.ts +28 -0
- package/src/reverse.ts +209 -121
- package/src/root-error-boundary.tsx +41 -29
- package/src/route-content-wrapper.tsx +7 -4
- package/src/route-definition/dsl-helpers.ts +1134 -0
- package/src/route-definition/helper-factories.ts +200 -0
- package/src/route-definition/helpers-types.ts +478 -0
- package/src/route-definition/index.ts +55 -0
- package/src/route-definition/redirect.ts +101 -0
- package/src/route-definition/resolve-handler-use.ts +155 -0
- package/src/route-definition.ts +1 -1431
- package/src/route-map-builder.ts +162 -123
- package/src/route-name.ts +53 -0
- package/src/route-types.ts +66 -9
- package/src/router/content-negotiation.ts +215 -0
- package/src/router/debug-manifest.ts +72 -0
- package/src/router/error-handling.ts +9 -9
- package/src/router/find-match.ts +160 -0
- package/src/router/handler-context.ts +455 -86
- package/src/router/intercept-resolution.ts +35 -20
- package/src/router/lazy-includes.ts +237 -0
- package/src/router/loader-resolution.ts +359 -128
- package/src/router/logging.ts +251 -0
- package/src/router/manifest.ts +98 -32
- package/src/router/match-api.ts +195 -261
- package/src/router/match-context.ts +4 -2
- package/src/router/match-handlers.ts +440 -0
- package/src/router/match-middleware/background-revalidation.ts +108 -93
- package/src/router/match-middleware/cache-lookup.ts +415 -86
- package/src/router/match-middleware/cache-store.ts +91 -29
- package/src/router/match-middleware/intercept-resolution.ts +48 -21
- package/src/router/match-middleware/segment-resolution.ts +73 -9
- package/src/router/match-pipelines.ts +10 -45
- package/src/router/match-result.ts +135 -35
- package/src/router/metrics.ts +240 -15
- package/src/router/middleware-cookies.ts +55 -0
- package/src/router/middleware-types.ts +200 -0
- package/src/router/middleware.ts +373 -371
- package/src/router/navigation-snapshot.ts +182 -0
- package/src/router/pattern-matching.ts +251 -44
- package/src/router/prerender-match.ts +502 -0
- package/src/router/preview-match.ts +98 -0
- package/src/router/request-classification.ts +310 -0
- package/src/router/revalidation.ts +152 -39
- package/src/router/route-snapshot.ts +245 -0
- package/src/router/router-context.ts +41 -21
- package/src/router/router-interfaces.ts +484 -0
- package/src/router/router-options.ts +618 -0
- package/src/router/router-registry.ts +24 -0
- package/src/router/segment-resolution/fresh.ts +748 -0
- package/src/router/segment-resolution/helpers.ts +268 -0
- package/src/router/segment-resolution/loader-cache.ts +199 -0
- package/src/router/segment-resolution/revalidation.ts +1384 -0
- package/src/router/segment-resolution/static-store.ts +67 -0
- package/src/router/segment-resolution.ts +21 -1315
- package/src/router/segment-wrappers.ts +291 -0
- package/src/router/telemetry-otel.ts +299 -0
- package/src/router/telemetry.ts +300 -0
- package/src/router/timeout.ts +148 -0
- package/src/router/trie-matching.ts +103 -30
- package/src/router/types.ts +17 -9
- package/src/router/url-params.ts +49 -0
- package/src/router.ts +647 -1988
- package/src/rsc/handler-context.ts +45 -0
- package/src/rsc/handler.ts +864 -1114
- package/src/rsc/helpers.ts +181 -19
- package/src/rsc/index.ts +0 -20
- package/src/rsc/loader-fetch.ts +229 -0
- package/src/rsc/manifest-init.ts +90 -0
- package/src/rsc/nonce.ts +14 -0
- package/src/rsc/origin-guard.ts +141 -0
- package/src/rsc/progressive-enhancement.ts +393 -0
- package/src/rsc/response-error.ts +37 -0
- package/src/rsc/response-route-handler.ts +360 -0
- package/src/rsc/rsc-rendering.ts +253 -0
- package/src/rsc/runtime-warnings.ts +42 -0
- package/src/rsc/server-action.ts +358 -0
- package/src/rsc/ssr-setup.ts +128 -0
- package/src/rsc/types.ts +46 -11
- package/src/search-params.ts +230 -0
- package/src/segment-content-promise.ts +67 -0
- package/src/segment-loader-promise.ts +122 -0
- package/src/segment-system.tsx +134 -36
- package/src/server/context.ts +333 -59
- package/src/server/cookie-store.ts +190 -0
- package/src/server/fetchable-loader-store.ts +37 -0
- package/src/server/handle-store.ts +113 -15
- package/src/server/loader-registry.ts +24 -64
- package/src/server/request-context.ts +603 -109
- package/src/server.ts +35 -155
- package/src/ssr/index.tsx +103 -30
- package/src/static-handler.ts +126 -0
- package/src/theme/ThemeProvider.tsx +21 -15
- package/src/theme/ThemeScript.tsx +5 -5
- package/src/theme/constants.ts +5 -2
- package/src/theme/index.ts +4 -14
- package/src/theme/theme-context.ts +4 -30
- package/src/theme/theme-script.ts +21 -18
- package/src/types/boundaries.ts +158 -0
- package/src/types/cache-types.ts +198 -0
- package/src/types/error-types.ts +192 -0
- package/src/types/global-namespace.ts +100 -0
- package/src/types/handler-context.ts +759 -0
- package/src/types/index.ts +88 -0
- package/src/types/loader-types.ts +209 -0
- package/src/types/request-scope.ts +126 -0
- package/src/types/route-config.ts +170 -0
- package/src/types/route-entry.ts +120 -0
- package/src/types/segments.ts +150 -0
- package/src/types.ts +1 -1757
- package/src/urls/include-helper.ts +207 -0
- package/src/urls/index.ts +53 -0
- package/src/urls/path-helper-types.ts +372 -0
- package/src/urls/path-helper.ts +364 -0
- package/src/urls/pattern-types.ts +107 -0
- package/src/urls/response-types.ts +108 -0
- package/src/urls/type-extraction.ts +372 -0
- package/src/urls/urls-function.ts +98 -0
- package/src/urls.ts +1 -1282
- package/src/use-loader.tsx +161 -81
- package/src/vite/debug.ts +184 -0
- package/src/vite/discovery/bundle-postprocess.ts +181 -0
- package/src/vite/discovery/discover-routers.ts +376 -0
- package/src/vite/discovery/prerender-collection.ts +486 -0
- package/src/vite/discovery/route-types-writer.ts +258 -0
- package/src/vite/discovery/self-gen-tracking.ts +47 -0
- package/src/vite/discovery/state.ts +117 -0
- package/src/vite/discovery/virtual-module-codegen.ts +203 -0
- package/src/vite/index.ts +15 -1963
- package/src/vite/plugin-types.ts +103 -0
- package/src/vite/plugins/cjs-to-esm.ts +98 -0
- package/src/vite/plugins/client-ref-dedup.ts +131 -0
- package/src/vite/plugins/client-ref-hashing.ts +117 -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 +214 -0
- package/src/vite/{expose-action-id.ts → plugins/expose-action-id.ts} +107 -64
- package/src/vite/plugins/expose-id-utils.ts +299 -0
- package/src/vite/plugins/expose-ids/export-analysis.ts +296 -0
- package/src/vite/plugins/expose-ids/handler-transform.ts +209 -0
- package/src/vite/plugins/expose-ids/loader-transform.ts +74 -0
- package/src/vite/plugins/expose-ids/router-transform.ts +127 -0
- package/src/vite/plugins/expose-ids/types.ts +45 -0
- package/src/vite/plugins/expose-internal-ids.ts +816 -0
- package/src/vite/plugins/performance-tracks.ts +96 -0
- package/src/vite/plugins/refresh-cmd.ts +127 -0
- package/src/vite/plugins/use-cache-transform.ts +336 -0
- package/src/vite/plugins/version-injector.ts +83 -0
- package/src/vite/plugins/version-plugin.ts +266 -0
- package/src/vite/plugins/virtual-entries.ts +123 -0
- package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
- package/src/vite/rango.ts +497 -0
- package/src/vite/router-discovery.ts +1111 -0
- package/src/vite/utils/ast-handler-extract.ts +517 -0
- package/src/vite/utils/banner.ts +36 -0
- package/src/vite/utils/bundle-analysis.ts +137 -0
- package/src/vite/utils/manifest-utils.ts +70 -0
- package/src/vite/utils/package-resolution.ts +161 -0
- package/src/vite/utils/prerender-utils.ts +221 -0
- package/src/vite/utils/shared-utils.ts +170 -0
- package/CLAUDE.md +0 -43
- package/src/browser/lru-cache.ts +0 -69
- package/src/browser/request-controller.ts +0 -164
- package/src/cache/memory-store.ts +0 -253
- package/src/router.gen.ts +0 -6
- package/src/urls.gen.ts +0 -8
- package/src/vite/expose-handle-id.ts +0 -209
- package/src/vite/expose-loader-id.ts +0 -426
- package/src/vite/expose-location-state-id.ts +0 -177
- package/src/vite/expose-prerender-handler-id.ts +0 -429
- /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
package/src/rsc/handler.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="@vitejs/plugin-rsc/types" />
|
|
2
|
-
/// <reference path="../vite/version.d.ts" />
|
|
2
|
+
/// <reference path="../vite/plugins/version.d.ts" />
|
|
3
3
|
/**
|
|
4
4
|
* RSC Request Handler
|
|
5
5
|
*
|
|
@@ -8,68 +8,88 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { createElement } from "react";
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import type { ResponseError } from "../urls.js";
|
|
14
|
-
import { getLoaderLazy } from "../server/loader-registry.js";
|
|
15
|
-
import {
|
|
16
|
-
matchMiddleware,
|
|
17
|
-
executeMiddleware,
|
|
18
|
-
executeLoaderMiddleware,
|
|
19
|
-
} from "../router/middleware.js";
|
|
11
|
+
import { RouteNotFoundError } from "../errors.js";
|
|
12
|
+
import { matchMiddleware, executeMiddleware } from "../router/middleware.js";
|
|
20
13
|
import {
|
|
21
14
|
runWithRequestContext,
|
|
22
15
|
setRequestContextParams,
|
|
23
16
|
requireRequestContext,
|
|
17
|
+
getRequestContext,
|
|
18
|
+
_getRequestContext,
|
|
24
19
|
createRequestContext,
|
|
25
|
-
type ExecutionContext,
|
|
26
20
|
} from "../server/request-context.js";
|
|
27
21
|
import * as rscDeps from "@vitejs/plugin-rsc/rsc";
|
|
28
|
-
|
|
29
22
|
import type {
|
|
30
23
|
RscPayload,
|
|
31
|
-
ReactFormState,
|
|
32
24
|
CreateRSCHandlerOptions,
|
|
25
|
+
LoadSSRModule,
|
|
26
|
+
SSRModule,
|
|
33
27
|
} from "./types.js";
|
|
34
|
-
import {
|
|
35
|
-
|
|
28
|
+
import {
|
|
29
|
+
createResponseWithMergedHeaders,
|
|
30
|
+
finalizeResponse,
|
|
31
|
+
interceptRedirectForPartial,
|
|
32
|
+
buildRouteMiddlewareEntries,
|
|
33
|
+
} from "./helpers.js";
|
|
34
|
+
import { isWebSocketUpgradeResponse } from "../response-utils.js";
|
|
35
|
+
import {
|
|
36
|
+
handleResponseRoute,
|
|
37
|
+
type ResponseRouteMatch,
|
|
38
|
+
} from "./response-route-handler.js";
|
|
39
|
+
import { generateNonce, nonce as nonceToken } from "./nonce.js";
|
|
36
40
|
import { VERSION } from "@rangojs/router:version";
|
|
37
41
|
import type { ErrorPhase } from "../types.js";
|
|
42
|
+
import type { RouterRequestInput } from "../router/router-interfaces.js";
|
|
38
43
|
import { invokeOnError } from "../router/error-handling.js";
|
|
39
44
|
import {
|
|
40
|
-
|
|
45
|
+
createReverseFunction,
|
|
46
|
+
stripInternalParams,
|
|
47
|
+
} from "../router/handler-context.js";
|
|
48
|
+
import { getRouterContext } from "../router/router-context.js";
|
|
49
|
+
import { resolveSink, safeEmit } from "../router/telemetry.js";
|
|
50
|
+
import { contextSet } from "../context-var.js";
|
|
51
|
+
import {
|
|
41
52
|
hasCachedManifest,
|
|
42
|
-
setCachedManifest,
|
|
43
53
|
getRouteTrie,
|
|
44
|
-
setRouteTrie,
|
|
45
54
|
getPrecomputedEntries,
|
|
46
55
|
waitForManifestReady,
|
|
56
|
+
getRouterManifest,
|
|
57
|
+
getRouterTrie,
|
|
47
58
|
} from "../route-map-builder.js";
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
59
|
+
import type { HandlerContext } from "./handler-context.js";
|
|
60
|
+
import type { SegmentCacheStore } from "../cache/types.js";
|
|
61
|
+
import { buildRouterTrieFromUrlpatterns } from "./manifest-init.js";
|
|
62
|
+
import { handleProgressiveEnhancement } from "./progressive-enhancement.js";
|
|
63
|
+
import {
|
|
64
|
+
executeServerAction,
|
|
65
|
+
revalidateAfterAction,
|
|
66
|
+
type ActionContinuation,
|
|
67
|
+
} from "./server-action.js";
|
|
68
|
+
import { handleLoaderFetch } from "./loader-fetch.js";
|
|
69
|
+
import { checkRequestOrigin, type OriginCheckPhase } from "./origin-guard.js";
|
|
70
|
+
import { handleRscRendering } from "./rsc-rendering.js";
|
|
71
|
+
import {
|
|
72
|
+
withTimeout,
|
|
73
|
+
RouterTimeoutError,
|
|
74
|
+
createDefaultTimeoutResponse,
|
|
75
|
+
type TimeoutPhase,
|
|
76
|
+
} from "../router/timeout.js";
|
|
77
|
+
import {
|
|
78
|
+
createMetricsStore,
|
|
79
|
+
appendMetric,
|
|
80
|
+
buildMetricsTiming,
|
|
81
|
+
} from "../router/metrics.js";
|
|
82
|
+
import {
|
|
83
|
+
startSSRSetup,
|
|
84
|
+
getSSRSetup,
|
|
85
|
+
mayNeedSSR,
|
|
86
|
+
SSR_SETUP_VAR,
|
|
87
|
+
} from "./ssr-setup.js";
|
|
88
|
+
import {
|
|
89
|
+
classifyRequest,
|
|
90
|
+
type RequestPlan,
|
|
91
|
+
type ExecutableRequestPlan,
|
|
92
|
+
} from "../router/request-classification.js";
|
|
73
93
|
|
|
74
94
|
/**
|
|
75
95
|
* Create an RSC request handler.
|
|
@@ -121,33 +141,182 @@ export function createRSCHandler<
|
|
|
121
141
|
decodeFormState,
|
|
122
142
|
} = deps;
|
|
123
143
|
|
|
124
|
-
// Use provided loadSSRModule or default to vite RSC module loader
|
|
125
|
-
|
|
144
|
+
// Use provided loadSSRModule or default to vite RSC module loader.
|
|
145
|
+
// In production the SSR module is stable across requests, so memoize
|
|
146
|
+
// the dynamic import to avoid repeated module resolution overhead.
|
|
147
|
+
// In dev mode Vite may hot-reload the module, so skip memoization.
|
|
148
|
+
const rawLoadSSRModule: LoadSSRModule =
|
|
126
149
|
options.loadSSRModule ??
|
|
127
150
|
(() => import.meta.viteRsc.loadModule("ssr", "index"));
|
|
151
|
+
let _ssrModulePromise: Promise<SSRModule> | undefined;
|
|
152
|
+
const loadSSRModule: LoadSSRModule =
|
|
153
|
+
process.env.NODE_ENV === "production"
|
|
154
|
+
? () =>
|
|
155
|
+
(_ssrModulePromise ??= rawLoadSSRModule().catch((err) => {
|
|
156
|
+
_ssrModulePromise = undefined;
|
|
157
|
+
throw err;
|
|
158
|
+
}))
|
|
159
|
+
: rawLoadSSRModule;
|
|
128
160
|
|
|
129
161
|
/**
|
|
130
|
-
*
|
|
131
|
-
*
|
|
162
|
+
* Per-request error reporter that deduplicates via the ALS request context.
|
|
163
|
+
*
|
|
164
|
+
* Uses the same _reportedErrors WeakSet as the router layer so errors
|
|
165
|
+
* that propagate across layers are only reported once per request.
|
|
132
166
|
*/
|
|
133
167
|
function callOnError(
|
|
134
168
|
error: unknown,
|
|
135
169
|
phase: ErrorPhase,
|
|
136
170
|
context: Parameters<typeof invokeOnError<TEnv>>[3],
|
|
137
171
|
): void {
|
|
172
|
+
// Guard: abort signal handlers fire asynchronously outside the ALS
|
|
173
|
+
// request scope, so the context may be gone. Skip dedup in that
|
|
174
|
+
// case — the error is from a cancelled stream, not a real failure.
|
|
175
|
+
const reqCtx = _getRequestContext();
|
|
176
|
+
if (error != null && typeof error === "object" && reqCtx) {
|
|
177
|
+
if (reqCtx._reportedErrors.has(error)) return;
|
|
178
|
+
reqCtx._reportedErrors.add(error);
|
|
179
|
+
}
|
|
138
180
|
invokeOnError(router.onError, error, phase, context, "RSC");
|
|
139
181
|
}
|
|
140
182
|
|
|
141
|
-
|
|
183
|
+
function getRequiredRouteMap(): Record<string, string> {
|
|
184
|
+
const routeMap = getRouterManifest(router.id);
|
|
185
|
+
if (!routeMap) {
|
|
186
|
+
throw new Error(
|
|
187
|
+
`Route manifest for router "${router.id}" is not available.`,
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
return routeMap;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Handle a timeout by reporting the error, emitting telemetry,
|
|
195
|
+
* and returning either the custom onTimeout response or a default 504.
|
|
196
|
+
*/
|
|
197
|
+
async function handleTimeoutResponse(
|
|
142
198
|
request: Request,
|
|
143
|
-
env: TEnv
|
|
144
|
-
|
|
199
|
+
env: TEnv,
|
|
200
|
+
url: URL,
|
|
201
|
+
phase: TimeoutPhase,
|
|
202
|
+
durationMs: number,
|
|
203
|
+
routeKey?: string,
|
|
204
|
+
actionId?: string,
|
|
205
|
+
): Promise<Response> {
|
|
206
|
+
const timeoutError = new RouterTimeoutError(phase, durationMs);
|
|
207
|
+
|
|
208
|
+
callOnError(timeoutError, phase === "action" ? "action" : "handler", {
|
|
209
|
+
request,
|
|
210
|
+
url,
|
|
211
|
+
env,
|
|
212
|
+
routeKey,
|
|
213
|
+
actionId,
|
|
214
|
+
handledByBoundary: false,
|
|
215
|
+
metadata: { timeout: true, phase, durationMs },
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
try {
|
|
219
|
+
const routerCtx = getRouterContext();
|
|
220
|
+
if (routerCtx?.telemetry) {
|
|
221
|
+
safeEmit(resolveSink(routerCtx.telemetry), {
|
|
222
|
+
type: "request.timeout" as const,
|
|
223
|
+
timestamp: performance.now(),
|
|
224
|
+
requestId: routerCtx.requestId,
|
|
225
|
+
phase,
|
|
226
|
+
pathname: url.pathname,
|
|
227
|
+
routeKey,
|
|
228
|
+
actionId,
|
|
229
|
+
durationMs,
|
|
230
|
+
customHandler: !!router.onTimeout,
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
} catch {
|
|
234
|
+
// Router context may not be available
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (router.onTimeout) {
|
|
238
|
+
try {
|
|
239
|
+
return await router.onTimeout({
|
|
240
|
+
phase,
|
|
241
|
+
request,
|
|
242
|
+
url,
|
|
243
|
+
env,
|
|
244
|
+
routeKey,
|
|
245
|
+
actionId,
|
|
246
|
+
durationMs,
|
|
247
|
+
});
|
|
248
|
+
} catch (e) {
|
|
249
|
+
if (process.env.NODE_ENV !== "production") {
|
|
250
|
+
console.error("[RSC] onTimeout callback error:", e);
|
|
251
|
+
}
|
|
252
|
+
return createDefaultTimeoutResponse(phase);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return createDefaultTimeoutResponse(phase);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Build a 200 Flight response that carries a redirect URL and optional state.
|
|
261
|
+
* Used when a partial/action request results in a redirect -- fetch
|
|
262
|
+
* auto-follows 3xx so we send the redirect as payload metadata instead.
|
|
263
|
+
*/
|
|
264
|
+
function createRedirectFlightResponse(
|
|
265
|
+
redirectUrl: string,
|
|
266
|
+
locationState?: Record<string, unknown>,
|
|
267
|
+
): Response {
|
|
268
|
+
const redirectPayload: RscPayload = {
|
|
269
|
+
metadata: {
|
|
270
|
+
pathname: redirectUrl,
|
|
271
|
+
segments: [],
|
|
272
|
+
redirect: { url: redirectUrl },
|
|
273
|
+
...(locationState && { locationState }),
|
|
274
|
+
},
|
|
275
|
+
};
|
|
276
|
+
const rscStream = renderToReadableStream<RscPayload>(redirectPayload);
|
|
277
|
+
return createResponseWithMergedHeaders(rscStream, {
|
|
278
|
+
status: 200,
|
|
279
|
+
headers: { "content-type": "text/x-component;charset=utf-8" },
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Bundle shared dependencies for extracted handler functions.
|
|
284
|
+
// callOnError reads from ALS so it's inherently per-request scoped.
|
|
285
|
+
const handlerCtx: HandlerContext<TEnv> = {
|
|
286
|
+
router,
|
|
287
|
+
version,
|
|
288
|
+
renderToReadableStream,
|
|
289
|
+
decodeReply,
|
|
290
|
+
createTemporaryReferenceSet,
|
|
291
|
+
loadServerAction,
|
|
292
|
+
decodeAction,
|
|
293
|
+
decodeFormState,
|
|
294
|
+
loadSSRModule,
|
|
295
|
+
callOnError,
|
|
296
|
+
getRequiredRouteMap,
|
|
297
|
+
createRedirectFlightResponse,
|
|
298
|
+
resolveStreamMode: async (request, env, url) => {
|
|
299
|
+
const resolver = router.ssr?.resolveStreaming;
|
|
300
|
+
if (!resolver) return "stream";
|
|
301
|
+
return resolver({ request, env, url });
|
|
145
302
|
},
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
return async function handler(
|
|
306
|
+
request: Request,
|
|
307
|
+
input: RouterRequestInput<TEnv> = {},
|
|
146
308
|
): Promise<Response> {
|
|
147
309
|
const handlerStart = performance.now();
|
|
310
|
+
// Create the metrics store at handler start so handler:total has startTime=0
|
|
311
|
+
// and all metrics are relative to the request entry point.
|
|
312
|
+
const earlyMetricsStore = router.debugPerformance
|
|
313
|
+
? createMetricsStore(true, handlerStart)
|
|
314
|
+
: undefined;
|
|
315
|
+
|
|
316
|
+
const { env = {} as TEnv, vars: initialVars, ctx: executionCtx } = input;
|
|
148
317
|
|
|
149
318
|
// Connection warmup: return 204 immediately before any processing
|
|
150
|
-
if (router
|
|
319
|
+
if (router?.warmupEnabled && request.method === "HEAD") {
|
|
151
320
|
const warmupUrl = new URL(request.url);
|
|
152
321
|
if (warmupUrl.searchParams.has("_rsc_warmup")) {
|
|
153
322
|
return new Response(null, { status: 204 });
|
|
@@ -171,24 +340,27 @@ export function createRSCHandler<
|
|
|
171
340
|
const mwMatchDur = performance.now() - mwMatchStart;
|
|
172
341
|
|
|
173
342
|
// Shared variables between middleware and route handlers
|
|
174
|
-
// Initialize from
|
|
175
|
-
const variables: Record<string, any> =
|
|
176
|
-
|
|
177
|
-
|
|
343
|
+
// Initialize from input.vars if provided (allows pre-seeding from worker entry)
|
|
344
|
+
const variables: Record<string, any> = initialVars
|
|
345
|
+
? { ...initialVars }
|
|
346
|
+
: {};
|
|
178
347
|
|
|
179
|
-
// Store nonce
|
|
348
|
+
// Store nonce via ContextVar token and string key for backward compat
|
|
180
349
|
if (nonce) {
|
|
350
|
+
contextSet(variables, nonceToken, nonce);
|
|
181
351
|
variables.nonce = nonce;
|
|
182
352
|
}
|
|
183
353
|
|
|
184
354
|
// Resolve cache store configuration
|
|
185
355
|
// Priority: options.cache (handler override) > router.cache (router default)
|
|
186
356
|
// Store is enabled only if: config provided, enabled, and no ?__no_cache query param
|
|
187
|
-
let cacheStore
|
|
357
|
+
let cacheStore: SegmentCacheStore | undefined;
|
|
188
358
|
const cacheOption = options.cache ?? router.cache;
|
|
189
359
|
if (cacheOption && !url.searchParams.has("__no_cache")) {
|
|
190
360
|
const cacheConfig =
|
|
191
|
-
typeof cacheOption === "function"
|
|
361
|
+
typeof cacheOption === "function"
|
|
362
|
+
? cacheOption(env, executionCtx)
|
|
363
|
+
: cacheOption;
|
|
192
364
|
|
|
193
365
|
if (cacheConfig.enabled !== false) {
|
|
194
366
|
cacheStore = cacheConfig.store;
|
|
@@ -201,60 +373,43 @@ export function createRSCHandler<
|
|
|
201
373
|
// via setManifestReadyPromise(). In dev mode (Cloudflare), Miniflare runs
|
|
202
374
|
// in a separate isolate where module-level state doesn't carry over, so
|
|
203
375
|
// we generate inline from the router's urlpatterns.
|
|
376
|
+
//
|
|
377
|
+
// In multi-router setups (e.g. createHostRouter), each router must have
|
|
378
|
+
// its own per-router manifest. We check per-router data first: even if
|
|
379
|
+
// the global manifest was set by a different router, this router still
|
|
380
|
+
// needs its own trie and manifest for correct matching.
|
|
204
381
|
const manifestCacheStart = performance.now();
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
if (
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
// Cloudflare dev: generate manifest inline (no caching needed)
|
|
212
|
-
const { generateManifest } =
|
|
213
|
-
await import("../build/generate-manifest.js");
|
|
214
|
-
const generated = generateManifest(router.urlpatterns);
|
|
215
|
-
setCachedManifest(generated.routeManifest);
|
|
216
|
-
if (
|
|
217
|
-
generated._routeAncestry &&
|
|
218
|
-
Object.keys(generated._routeAncestry).length > 0
|
|
219
|
-
) {
|
|
220
|
-
const { buildRouteTrie } = await import("../build/route-trie.js");
|
|
221
|
-
// Map each route to its include() staticPrefix so the trie
|
|
222
|
-
// returns the correct sp for lazy entry lookup in findMatch.
|
|
223
|
-
const routeToStaticPrefix: Record<string, string> = {};
|
|
224
|
-
for (const name of Object.keys(generated.routeManifest)) {
|
|
225
|
-
routeToStaticPrefix[name] = "";
|
|
226
|
-
}
|
|
227
|
-
// Override with prefix from include() entries so the trie
|
|
228
|
-
// returns the correct sp for lazy entry lookup in findMatch.
|
|
229
|
-
if (generated.prefixTree) {
|
|
230
|
-
for (const [prefix, node] of Object.entries(generated.prefixTree)) {
|
|
231
|
-
for (const route of (node as { routes: string[] }).routes) {
|
|
232
|
-
routeToStaticPrefix[route] = prefix;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
const trie = buildRouteTrie(
|
|
237
|
-
generated.routeManifest,
|
|
238
|
-
generated._routeAncestry,
|
|
239
|
-
routeToStaticPrefix,
|
|
240
|
-
generated.routeTrailingSlash,
|
|
241
|
-
undefined, // prerenderRouteNames
|
|
242
|
-
undefined, // passthroughRouteNames
|
|
243
|
-
generated.responseTypeRoutes,
|
|
244
|
-
);
|
|
245
|
-
setRouteTrie(trie);
|
|
382
|
+
const hasRouterData = getRouterManifest(router.id) !== undefined;
|
|
383
|
+
if (!hasRouterData) {
|
|
384
|
+
if (!hasCachedManifest()) {
|
|
385
|
+
const readyPromise = waitForManifestReady();
|
|
386
|
+
if (readyPromise) {
|
|
387
|
+
await readyPromise;
|
|
246
388
|
}
|
|
247
389
|
}
|
|
248
|
-
if (!
|
|
390
|
+
if (!getRouterManifest(router.id) && router.urlpatterns) {
|
|
391
|
+
// Cloudflare dev: generate manifest inline for this router.
|
|
392
|
+
// Each router generates its own manifest independently so
|
|
393
|
+
// multi-router setups (host routing) work correctly.
|
|
394
|
+
await buildRouterTrieFromUrlpatterns(router);
|
|
395
|
+
}
|
|
396
|
+
if (!getRouterManifest(router.id) && !hasCachedManifest()) {
|
|
249
397
|
throw new Error(
|
|
250
398
|
'Route manifest not available. Ensure "virtual:rsc-router/routes-manifest" is imported in your entry file.',
|
|
251
399
|
);
|
|
252
400
|
}
|
|
253
401
|
}
|
|
254
|
-
const manifestCacheDur = performance.now() - manifestCacheStart;
|
|
255
402
|
|
|
256
|
-
//
|
|
257
|
-
// This
|
|
403
|
+
// Rebuild the trie when the manifest exists but the per-router trie is
|
|
404
|
+
// missing. This happens in dev mode after HMR: the virtual module sets
|
|
405
|
+
// the manifest (from fresh gen files) but the trie is intentionally not
|
|
406
|
+
// injected to avoid stale discovery-time data. Without the trie, route
|
|
407
|
+
// matching falls back to regex iteration which does not handle wildcard
|
|
408
|
+
// priority correctly (catch-all patterns match before specific routes).
|
|
409
|
+
if (!getRouterTrie(router.id) && router.urlpatterns) {
|
|
410
|
+
await buildRouterTrieFromUrlpatterns(router);
|
|
411
|
+
}
|
|
412
|
+
const manifestCacheDur = performance.now() - manifestCacheStart;
|
|
258
413
|
|
|
259
414
|
// Create unified request context with all methods
|
|
260
415
|
// Includes: stub response, handle store, loader memoization, use(), cookies, headers, cache store
|
|
@@ -266,9 +421,27 @@ export function createRSCHandler<
|
|
|
266
421
|
url,
|
|
267
422
|
variables,
|
|
268
423
|
cacheStore,
|
|
269
|
-
|
|
424
|
+
cacheProfiles: router.cacheProfiles,
|
|
425
|
+
executionContext: executionCtx,
|
|
270
426
|
themeConfig: router.themeConfig,
|
|
271
427
|
});
|
|
428
|
+
if (earlyMetricsStore) {
|
|
429
|
+
requestContext._debugPerformance = true;
|
|
430
|
+
requestContext._metricsStore = earlyMetricsStore;
|
|
431
|
+
}
|
|
432
|
+
// Wire background error reporting so "use cache" and other subsystems
|
|
433
|
+
// can surface non-fatal errors through the router's onError callback.
|
|
434
|
+
requestContext._reportBackgroundError = (
|
|
435
|
+
error: unknown,
|
|
436
|
+
category: string,
|
|
437
|
+
) => {
|
|
438
|
+
callOnError(error, "cache", {
|
|
439
|
+
request,
|
|
440
|
+
url,
|
|
441
|
+
metadata: { category },
|
|
442
|
+
});
|
|
443
|
+
};
|
|
444
|
+
|
|
272
445
|
const ctxCreateDur = performance.now() - ctxCreateStart;
|
|
273
446
|
|
|
274
447
|
// Accumulate handler-level timing for Server-Timing header
|
|
@@ -290,6 +463,9 @@ export function createRSCHandler<
|
|
|
290
463
|
// - Server components during rendering
|
|
291
464
|
// - Error boundaries
|
|
292
465
|
// - Streaming
|
|
466
|
+
// Store basename on request context (scoped per-request via existing ALS)
|
|
467
|
+
requestContext._basename = router.basename;
|
|
468
|
+
|
|
293
469
|
return runWithRequestContext(requestContext, async () => {
|
|
294
470
|
// Core handler logic (wrapped by middleware)
|
|
295
471
|
const coreHandler = async (): Promise<Response> => {
|
|
@@ -297,292 +473,104 @@ export function createRSCHandler<
|
|
|
297
473
|
};
|
|
298
474
|
|
|
299
475
|
// Execute middleware chain if any, otherwise call core handler directly
|
|
476
|
+
let response: Response;
|
|
300
477
|
if (matchedMiddleware.length > 0) {
|
|
301
|
-
|
|
478
|
+
const mwResponse = await executeMiddleware(
|
|
302
479
|
matchedMiddleware,
|
|
303
480
|
request,
|
|
304
481
|
env,
|
|
305
482
|
variables,
|
|
306
483
|
coreHandler,
|
|
484
|
+
createReverseFunction(getRequiredRouteMap()),
|
|
307
485
|
);
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
return coreHandler();
|
|
311
|
-
});
|
|
312
|
-
};
|
|
313
|
-
|
|
314
|
-
// Core request handling logic (separated for middleware wrapping)
|
|
315
|
-
async function coreRequestHandler(
|
|
316
|
-
request: Request,
|
|
317
|
-
env: TEnv,
|
|
318
|
-
url: URL,
|
|
319
|
-
variables: Record<string, any>,
|
|
320
|
-
nonce: string | undefined,
|
|
321
|
-
): Promise<Response> {
|
|
322
|
-
// First, check for route-level middleware
|
|
323
|
-
const previewStart = performance.now();
|
|
324
|
-
const preview = await router.previewMatch(request, env);
|
|
325
|
-
const previewDur = performance.now() - previewStart;
|
|
326
|
-
const handlerTiming: string[] = variables.__handlerTiming || [];
|
|
327
|
-
handlerTiming.push(`handler-preview-match;dur=${previewDur.toFixed(2)}`);
|
|
328
|
-
// Response route short-circuit: skip entire RSC pipeline
|
|
329
|
-
if (preview?.responseType && preview.handler) {
|
|
330
|
-
const isPartial = url.searchParams.has("_rsc_partial");
|
|
331
|
-
|
|
332
|
-
// Partial requests (client-side navigation) to response routes
|
|
333
|
-
// get X-RSC-Reload to trigger hard navigation in the browser
|
|
334
|
-
if (isPartial) {
|
|
335
|
-
const cleanUrl = new URL(url);
|
|
336
|
-
cleanUrl.searchParams.delete("_rsc_partial");
|
|
337
|
-
cleanUrl.searchParams.delete("_rsc_segments");
|
|
338
|
-
cleanUrl.searchParams.delete("_rsc_v");
|
|
339
|
-
cleanUrl.searchParams.delete("_rsc_stale");
|
|
340
|
-
cleanUrl.searchParams.delete("_rsc_action");
|
|
341
|
-
cleanUrl.searchParams.delete("_rsc_prev");
|
|
342
|
-
|
|
343
|
-
return createResponseWithMergedHeaders(null, {
|
|
344
|
-
status: 200,
|
|
345
|
-
headers: {
|
|
346
|
-
"X-RSC-Reload": cleanUrl.toString(),
|
|
347
|
-
"content-type": "text/x-component;charset=utf-8",
|
|
348
|
-
},
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
// Build lightweight context for response handler
|
|
353
|
-
const bindings = (env as any)?.Bindings ?? env;
|
|
354
|
-
const reqCtx = requireRequestContext();
|
|
355
|
-
const responseHandlerCtx = {
|
|
356
|
-
request,
|
|
357
|
-
params: preview.params || {},
|
|
358
|
-
env: bindings,
|
|
359
|
-
searchParams: url.searchParams,
|
|
360
|
-
url,
|
|
361
|
-
pathname: url.pathname,
|
|
362
|
-
href: (name: string, hrefParams?: Record<string, string>) => {
|
|
363
|
-
if (name.startsWith("/")) {
|
|
364
|
-
if (!hrefParams) return name;
|
|
365
|
-
return name.replace(/:([^/]+)/g, (_, key) => {
|
|
366
|
-
const value = hrefParams[key];
|
|
367
|
-
if (value === undefined) throw new Error(`Missing param "${key}" for path "${name}"`);
|
|
368
|
-
return encodeURIComponent(value);
|
|
369
|
-
});
|
|
370
|
-
}
|
|
371
|
-
return name;
|
|
372
|
-
},
|
|
373
|
-
get: (key: string) => variables[key],
|
|
374
|
-
header: (name: string, value: string) => reqCtx.header(name, value),
|
|
375
|
-
setCookie: (name: string, value: string, options?: any) => reqCtx.setCookie(name, value, options),
|
|
376
|
-
};
|
|
377
|
-
|
|
378
|
-
// Call handler directly, wrapped by route middleware if present
|
|
379
|
-
const callHandler = async () => {
|
|
380
|
-
// JSON response routes: wrap in { data } / { error } envelope
|
|
381
|
-
if (preview.responseType === "json") {
|
|
382
|
-
const errorCtx = { request, url, env };
|
|
383
|
-
try {
|
|
384
|
-
const result = await (preview.handler as Function)(responseHandlerCtx);
|
|
385
|
-
if (result instanceof Response) {
|
|
386
|
-
const mergedHeaders: Record<string, string> = {};
|
|
387
|
-
result.headers.forEach((value, key) => {
|
|
388
|
-
mergedHeaders[key] = value;
|
|
389
|
-
});
|
|
390
|
-
return createResponseWithMergedHeaders(result.body, {
|
|
391
|
-
status: result.status,
|
|
392
|
-
headers: mergedHeaders,
|
|
393
|
-
});
|
|
394
|
-
}
|
|
395
|
-
return createResponseWithMergedHeaders(
|
|
396
|
-
JSON.stringify({ data: result }),
|
|
397
|
-
{ status: 200, headers: { "content-type": "application/json;charset=utf-8" } },
|
|
398
|
-
);
|
|
399
|
-
} catch (error) {
|
|
400
|
-
callOnError(error, "handler", errorCtx);
|
|
401
|
-
const isDev = process.env.NODE_ENV !== "production";
|
|
402
|
-
const status = error instanceof RouterError ? error.status : 500;
|
|
403
|
-
return createResponseWithMergedHeaders(
|
|
404
|
-
JSON.stringify({ error: createResponseErrorPayload(error, isDev) }),
|
|
405
|
-
{ status, headers: { "content-type": "application/json;charset=utf-8" } },
|
|
406
|
-
);
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
// Non-JSON response routes: catch errors and return plain Response
|
|
411
|
-
const errorCtx = { request, url, env };
|
|
412
|
-
try {
|
|
413
|
-
const result = await (preview.handler as Function)(responseHandlerCtx);
|
|
414
|
-
|
|
415
|
-
if (result instanceof Response) {
|
|
416
|
-
// Handler returned a Response directly -- pass through
|
|
417
|
-
const mergedHeaders: Record<string, string> = {};
|
|
418
|
-
result.headers.forEach((value, key) => {
|
|
419
|
-
mergedHeaders[key] = value;
|
|
420
|
-
});
|
|
421
|
-
return createResponseWithMergedHeaders(result.body, {
|
|
422
|
-
status: result.status,
|
|
423
|
-
headers: mergedHeaders,
|
|
424
|
-
});
|
|
425
|
-
}
|
|
426
486
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
);
|
|
439
|
-
case "xml":
|
|
440
|
-
return createResponseWithMergedHeaders(
|
|
441
|
-
String(result),
|
|
442
|
-
{ status: 200, headers: { "content-type": "application/xml;charset=utf-8" } },
|
|
443
|
-
);
|
|
444
|
-
case "md":
|
|
445
|
-
return createResponseWithMergedHeaders(
|
|
446
|
-
String(result),
|
|
447
|
-
{ status: 200, headers: { "content-type": "text/markdown;charset=utf-8" } },
|
|
448
|
-
);
|
|
449
|
-
default:
|
|
450
|
-
// image, stream, any -- must return Response
|
|
451
|
-
throw new Error(
|
|
452
|
-
`Response route handler for "${preview.responseType}" must return a Response object, got ${typeof result}`
|
|
453
|
-
);
|
|
454
|
-
}
|
|
455
|
-
} catch (error) {
|
|
456
|
-
callOnError(error, "handler", errorCtx);
|
|
457
|
-
const isDev = process.env.NODE_ENV !== "production";
|
|
458
|
-
const status = error instanceof RouterError ? error.status : 500;
|
|
459
|
-
const message = error instanceof RouterError
|
|
460
|
-
? error.message
|
|
461
|
-
: isDev && error instanceof Error
|
|
462
|
-
? error.message
|
|
463
|
-
: "Internal Server Error";
|
|
464
|
-
return createResponseWithMergedHeaders(message, {
|
|
465
|
-
status,
|
|
466
|
-
headers: { "content-type": "text/plain;charset=utf-8" },
|
|
467
|
-
});
|
|
468
|
-
}
|
|
469
|
-
};
|
|
470
|
-
|
|
471
|
-
// Wrap callHandler to append Vary: Accept on content-negotiated responses
|
|
472
|
-
const callHandlerWithVary = async () => {
|
|
473
|
-
const response = await callHandler();
|
|
474
|
-
if (preview.negotiated) {
|
|
475
|
-
response.headers.append("Vary", "Accept");
|
|
487
|
+
if (
|
|
488
|
+
url.searchParams.has("_rsc_partial") ||
|
|
489
|
+
url.searchParams.has("_rsc_action")
|
|
490
|
+
) {
|
|
491
|
+
const intercepted = interceptRedirectForPartial(
|
|
492
|
+
mwResponse,
|
|
493
|
+
createRedirectFlightResponse,
|
|
494
|
+
);
|
|
495
|
+
response = intercepted ?? finalizeResponse(mwResponse);
|
|
496
|
+
} else {
|
|
497
|
+
response = finalizeResponse(mwResponse);
|
|
476
498
|
}
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
if (preview.routeMiddleware && preview.routeMiddleware.length > 0) {
|
|
481
|
-
const middlewareEntries = preview.routeMiddleware.map((mw) => ({
|
|
482
|
-
entry: {
|
|
483
|
-
pattern: null,
|
|
484
|
-
regex: null,
|
|
485
|
-
paramNames: [],
|
|
486
|
-
handler: mw.handler,
|
|
487
|
-
mountPrefix: null,
|
|
488
|
-
},
|
|
489
|
-
params: mw.params,
|
|
490
|
-
}));
|
|
491
|
-
return executeMiddleware(middlewareEntries, request, env, variables, callHandlerWithVary);
|
|
499
|
+
} else {
|
|
500
|
+
response = await coreHandler();
|
|
492
501
|
}
|
|
493
502
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
503
|
+
// Finalize metrics after all middleware (including post-next work)
|
|
504
|
+
// has completed so :post spans are captured in the timeline.
|
|
505
|
+
// Handler timing parts are always emitted (even without debug metrics)
|
|
506
|
+
// so non-debug requests still get bootstrap Server-Timing entries.
|
|
507
|
+
const handlerTimingArr: string[] = variables.__handlerTiming || [];
|
|
508
|
+
// Preserve any existing Server-Timing set by response routes or middleware
|
|
509
|
+
const existingTiming = response.headers.get("Server-Timing");
|
|
510
|
+
const timingParts = existingTiming
|
|
511
|
+
? [existingTiming, ...handlerTimingArr]
|
|
512
|
+
: [...handlerTimingArr];
|
|
513
|
+
|
|
514
|
+
const metricsStore = requestContext._metricsStore;
|
|
515
|
+
if (metricsStore) {
|
|
516
|
+
// When the store was created at handler start (earlyMetricsStore),
|
|
517
|
+
// handler:total covers the full request. When ctx.debugPerformance()
|
|
518
|
+
// created the store mid-request, use its requestStart to avoid a
|
|
519
|
+
// negative startTime offset.
|
|
520
|
+
const totalStart = earlyMetricsStore
|
|
521
|
+
? handlerStart
|
|
522
|
+
: metricsStore.requestStart;
|
|
523
|
+
appendMetric(
|
|
524
|
+
metricsStore,
|
|
525
|
+
"handler:total",
|
|
526
|
+
totalStart,
|
|
527
|
+
performance.now() - totalStart,
|
|
528
|
+
);
|
|
529
|
+
const metricsTiming = buildMetricsTiming(
|
|
530
|
+
request.method,
|
|
531
|
+
url.pathname,
|
|
532
|
+
metricsStore,
|
|
533
|
+
);
|
|
534
|
+
if (metricsTiming) timingParts.push(metricsTiming);
|
|
502
535
|
}
|
|
503
|
-
return response;
|
|
504
|
-
};
|
|
505
|
-
|
|
506
|
-
if (preview?.routeMiddleware && preview.routeMiddleware.length > 0) {
|
|
507
|
-
// Convert route middleware to app middleware format for execution
|
|
508
|
-
const middlewareEntries = preview.routeMiddleware.map((mw) => ({
|
|
509
|
-
entry: {
|
|
510
|
-
pattern: null,
|
|
511
|
-
regex: null,
|
|
512
|
-
paramNames: [],
|
|
513
|
-
handler: mw.handler,
|
|
514
|
-
mountPrefix: null,
|
|
515
|
-
},
|
|
516
|
-
params: mw.params,
|
|
517
|
-
}));
|
|
518
536
|
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
537
|
+
const fullTiming = timingParts.join(", ");
|
|
538
|
+
if (fullTiming && !isWebSocketUpgradeResponse(response)) {
|
|
539
|
+
response.headers.set("Server-Timing", fullTiming);
|
|
540
|
+
}
|
|
522
541
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
}
|
|
542
|
+
return response;
|
|
543
|
+
});
|
|
544
|
+
};
|
|
526
545
|
|
|
527
|
-
//
|
|
528
|
-
|
|
546
|
+
// Core request handling logic (separated for middleware wrapping).
|
|
547
|
+
// Uses the classify → execute model: classifyRequest produces a RequestPlan,
|
|
548
|
+
// then execution dispatches on the plan mode.
|
|
549
|
+
async function coreRequestHandler(
|
|
529
550
|
request: Request,
|
|
530
551
|
env: TEnv,
|
|
531
552
|
url: URL,
|
|
532
553
|
variables: Record<string, any>,
|
|
533
554
|
nonce: string | undefined,
|
|
534
555
|
): Promise<Response> {
|
|
535
|
-
const
|
|
536
|
-
const isAction =
|
|
537
|
-
request.headers.has("rsc-action") || url.searchParams.has("_rsc_action");
|
|
538
|
-
const actionId =
|
|
539
|
-
request.headers.get("rsc-action") || url.searchParams.get("_rsc_action");
|
|
540
|
-
|
|
541
|
-
// Version mismatch detection - client may have stale code after HMR/deployment
|
|
542
|
-
// If versions don't match, tell the client to reload
|
|
543
|
-
const clientVersion = url.searchParams.get("_rsc_v");
|
|
544
|
-
if (version && clientVersion && clientVersion !== version) {
|
|
545
|
-
console.log(
|
|
546
|
-
`[RSC] Version mismatch: client=${clientVersion}, server=${version}. Forcing reload.`,
|
|
547
|
-
);
|
|
556
|
+
const handlerTiming: string[] = variables.__handlerTiming || [];
|
|
548
557
|
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
cleanUrl.searchParams.delete("_rsc_partial");
|
|
552
|
-
cleanUrl.searchParams.delete("_rsc_segments");
|
|
553
|
-
cleanUrl.searchParams.delete("_rsc_v");
|
|
554
|
-
cleanUrl.searchParams.delete("_rsc_stale");
|
|
555
|
-
cleanUrl.searchParams.delete("_rsc_action");
|
|
556
|
-
cleanUrl.searchParams.delete("_rsc_prev");
|
|
557
|
-
|
|
558
|
-
// For actions, reload current page (referer)
|
|
559
|
-
// For navigation, load the target URL
|
|
560
|
-
const reloadUrl = isAction
|
|
561
|
-
? request.headers.get("referer") || cleanUrl.toString()
|
|
562
|
-
: cleanUrl.toString();
|
|
563
|
-
|
|
564
|
-
// Return special response that tells client to reload
|
|
565
|
-
return createResponseWithMergedHeaders(null, {
|
|
566
|
-
status: 200,
|
|
567
|
-
headers: {
|
|
568
|
-
"X-RSC-Reload": reloadUrl,
|
|
569
|
-
"content-type": "text/x-component;charset=utf-8",
|
|
570
|
-
},
|
|
571
|
-
});
|
|
572
|
-
}
|
|
573
|
-
// Debug manifest endpoint: ?__debug_manifest on any route.
|
|
574
|
-
// Always available in dev, requires allowDebugManifest option in production.
|
|
558
|
+
// Debug manifest endpoint: handled before classification since it
|
|
559
|
+
// doesn't need a route match and needs trie access from the closure.
|
|
575
560
|
const isDev = process.env.NODE_ENV !== "production";
|
|
576
561
|
if (
|
|
577
562
|
url.searchParams.has("__debug_manifest") &&
|
|
578
563
|
(isDev || router.allowDebugManifest)
|
|
579
564
|
) {
|
|
580
|
-
const trie = getRouteTrie();
|
|
581
|
-
const
|
|
565
|
+
const trie = getRouterTrie(router.id) ?? getRouteTrie();
|
|
566
|
+
const routeManifest = getRequiredRouteMap();
|
|
567
|
+
const { extractAncestryFromTrie } =
|
|
568
|
+
await import("../build/route-trie.js");
|
|
582
569
|
return new Response(
|
|
583
570
|
JSON.stringify(
|
|
584
571
|
{
|
|
585
|
-
|
|
572
|
+
routerId: router.id,
|
|
573
|
+
routeManifest,
|
|
586
574
|
routeAncestry: trie ? extractAncestryFromTrie(trie) : {},
|
|
587
575
|
routeTrie: trie,
|
|
588
576
|
precomputedEntries: getPrecomputedEntries(),
|
|
@@ -596,848 +584,610 @@ export function createRSCHandler<
|
|
|
596
584
|
);
|
|
597
585
|
}
|
|
598
586
|
|
|
599
|
-
//
|
|
600
|
-
|
|
601
|
-
|
|
587
|
+
// ---- 1. Classify ----
|
|
588
|
+
// classifyRequest may throw RouteNotFoundError for unknown routes.
|
|
589
|
+
// In that case, fall through to a full-render plan so the pipeline
|
|
590
|
+
// can render the 404 page via the existing error handling path.
|
|
591
|
+
const classifyStart = performance.now();
|
|
592
|
+
let plan: RequestPlan<TEnv>;
|
|
602
593
|
try {
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
594
|
+
plan = await classifyRequest<TEnv>(request, url, {
|
|
595
|
+
findMatch: router.findMatch,
|
|
596
|
+
routerVersion: version,
|
|
597
|
+
routerId: router.id,
|
|
598
|
+
});
|
|
599
|
+
} catch (error) {
|
|
600
|
+
if (
|
|
601
|
+
error instanceof RouteNotFoundError ||
|
|
602
|
+
(error instanceof Error && error.name === "RouteNotFoundError")
|
|
603
|
+
) {
|
|
604
|
+
// Let the render path handle 404 — match()/matchPartial() will
|
|
605
|
+
// re-throw RouteNotFoundError and the catch block in
|
|
606
|
+
// executeRenderWithMiddleware renders the not-found page.
|
|
607
|
+
plan = {
|
|
608
|
+
mode: "full-render",
|
|
609
|
+
route: {
|
|
610
|
+
matched: null as any,
|
|
611
|
+
manifestEntry: null as any,
|
|
612
|
+
entries: [],
|
|
613
|
+
routeKey: "",
|
|
614
|
+
localRouteName: "",
|
|
615
|
+
params: {},
|
|
616
|
+
routeMiddleware: [],
|
|
617
|
+
cacheScope: null,
|
|
618
|
+
isPassthrough: false,
|
|
619
|
+
},
|
|
620
|
+
negotiated: false,
|
|
621
|
+
};
|
|
622
|
+
} else {
|
|
623
|
+
throw error;
|
|
616
624
|
}
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
625
|
+
}
|
|
626
|
+
const classifyDur = performance.now() - classifyStart;
|
|
627
|
+
handlerTiming.push(`handler-classify;dur=${classifyDur.toFixed(2)}`);
|
|
628
|
+
|
|
629
|
+
// ---- 2. Terminal plans (no execution needed) ----
|
|
630
|
+
if (plan.mode === "redirect") {
|
|
631
|
+
// Redirects are handled by the pipeline (match/matchPartial),
|
|
632
|
+
// but for partial requests we short-circuit with a Flight redirect.
|
|
633
|
+
if (url.searchParams.has("_rsc_partial")) {
|
|
634
|
+
return createRedirectFlightResponse(plan.redirectUrl);
|
|
623
635
|
}
|
|
636
|
+
// Full requests: let the pipeline handle the redirect via match()
|
|
637
|
+
// which returns { redirect: url }. Fall through to full-render.
|
|
638
|
+
}
|
|
624
639
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
640
|
+
if (plan.mode === "version-mismatch") {
|
|
641
|
+
console.log(
|
|
642
|
+
`[RSC] Version mismatch: client=${url.searchParams.get("_rsc_v")}, server=${version}. Forcing reload.`,
|
|
643
|
+
);
|
|
644
|
+
return createResponseWithMergedHeaders(null, {
|
|
645
|
+
status: 200,
|
|
646
|
+
headers: {
|
|
647
|
+
"X-RSC-Reload": plan.reloadUrl,
|
|
648
|
+
"content-type": "text/x-component;charset=utf-8",
|
|
649
|
+
},
|
|
650
|
+
});
|
|
651
|
+
}
|
|
632
652
|
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
653
|
+
// ---- 3. Origin guard (gate for action/loader/PE modes) ----
|
|
654
|
+
const originPhase: OriginCheckPhase | null =
|
|
655
|
+
plan.mode === "action"
|
|
656
|
+
? "action"
|
|
657
|
+
: plan.mode === "loader"
|
|
658
|
+
? "loader"
|
|
659
|
+
: plan.mode === "pe-render"
|
|
660
|
+
? "pe-form"
|
|
661
|
+
: null;
|
|
662
|
+
if (originPhase) {
|
|
663
|
+
const originResult = await checkRequestOrigin(
|
|
638
664
|
request,
|
|
639
|
-
env,
|
|
640
665
|
url,
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
666
|
+
router.originCheck,
|
|
667
|
+
env,
|
|
668
|
+
router.id,
|
|
669
|
+
originPhase,
|
|
644
670
|
);
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
// Signal the browser to hard-navigate so it renders the raw response.
|
|
651
|
-
// Only for 200 — redirects (3xx) work already because the browser follows
|
|
652
|
-
// them automatically to a URL that serves Flight data.
|
|
653
|
-
if (isPartial && error.status === 200) {
|
|
654
|
-
console.warn(
|
|
655
|
-
`[RSC] Route handler at ${url.pathname} returned a Response during client-side navigation. ` +
|
|
656
|
-
`Falling back to hard navigation. Use data-external on the <Link> to avoid the extra round-trip.`,
|
|
657
|
-
);
|
|
658
|
-
const cleanUrl = new URL(url);
|
|
659
|
-
cleanUrl.searchParams.delete("_rsc_partial");
|
|
660
|
-
cleanUrl.searchParams.delete("_rsc_segments");
|
|
661
|
-
cleanUrl.searchParams.delete("_rsc_v");
|
|
662
|
-
cleanUrl.searchParams.delete("_rsc_stale");
|
|
663
|
-
cleanUrl.searchParams.delete("_rsc_action");
|
|
664
|
-
cleanUrl.searchParams.delete("_rsc_prev");
|
|
665
|
-
return createResponseWithMergedHeaders(null, {
|
|
666
|
-
status: 200,
|
|
667
|
-
headers: {
|
|
668
|
-
"X-RSC-Reload": cleanUrl.toString(),
|
|
669
|
-
"content-type": "text/x-component;charset=utf-8",
|
|
670
|
-
},
|
|
671
|
-
});
|
|
672
|
-
}
|
|
673
|
-
return error;
|
|
674
|
-
}
|
|
671
|
+
if (originResult) {
|
|
672
|
+
const originError = new Error(
|
|
673
|
+
`Origin check rejected: ${request.headers.get("origin") ?? "none"} vs ${request.headers.get("host") ?? "none"}`,
|
|
674
|
+
);
|
|
675
|
+
originError.name = "OriginCheckError";
|
|
675
676
|
|
|
676
|
-
|
|
677
|
-
// Check both instanceof and error.name for cross-bundle compatibility
|
|
678
|
-
const isRouteNotFound =
|
|
679
|
-
error instanceof RouteNotFoundError ||
|
|
680
|
-
(error instanceof Error && error.name === "RouteNotFoundError");
|
|
681
|
-
if (isRouteNotFound) {
|
|
682
|
-
callOnError(error, "routing", {
|
|
677
|
+
callOnError(originError, "origin", {
|
|
683
678
|
request,
|
|
684
679
|
url,
|
|
685
680
|
env,
|
|
686
|
-
handledByBoundary:
|
|
687
|
-
});
|
|
688
|
-
|
|
689
|
-
// Get notFound component from router options or use default
|
|
690
|
-
const notFoundOption = router.notFound;
|
|
691
|
-
const notFoundComponent =
|
|
692
|
-
typeof notFoundOption === "function"
|
|
693
|
-
? notFoundOption({ pathname: url.pathname })
|
|
694
|
-
: (notFoundOption ?? createElement("h1", null, "Not Found"));
|
|
695
|
-
|
|
696
|
-
// Create a simple segment for the 404 page
|
|
697
|
-
const notFoundSegment = {
|
|
698
|
-
id: "notFound",
|
|
699
|
-
namespace: "notFound",
|
|
700
|
-
type: "route" as const,
|
|
701
|
-
index: 0,
|
|
702
|
-
component: notFoundComponent,
|
|
703
|
-
params: {},
|
|
704
|
-
};
|
|
705
|
-
|
|
706
|
-
// Render with rootLayout to maintain app shell
|
|
707
|
-
const root = await renderSegments([notFoundSegment], {
|
|
708
|
-
rootLayout: router.rootLayout,
|
|
709
|
-
// No routeName for not-found routes
|
|
710
|
-
});
|
|
711
|
-
|
|
712
|
-
const payload: RscPayload = {
|
|
713
|
-
root,
|
|
681
|
+
handledByBoundary: false,
|
|
714
682
|
metadata: {
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
diff: [],
|
|
719
|
-
isPartial: false,
|
|
720
|
-
handles: handleStore.stream(),
|
|
721
|
-
version,
|
|
722
|
-
themeConfig: router.themeConfig,
|
|
723
|
-
warmupEnabled: router.warmupEnabled,
|
|
724
|
-
initialTheme: requireRequestContext().theme,
|
|
725
|
-
// No routeName for not-found routes
|
|
683
|
+
phase: originPhase,
|
|
684
|
+
origin: request.headers.get("origin"),
|
|
685
|
+
host: request.headers.get("host"),
|
|
726
686
|
},
|
|
727
|
-
};
|
|
728
|
-
|
|
729
|
-
const rscStream = renderToReadableStream(payload);
|
|
730
|
-
|
|
731
|
-
// Determine if this is an RSC request or HTML request
|
|
732
|
-
const isRscRequest =
|
|
733
|
-
(!request.headers.get("accept")?.includes("text/html") &&
|
|
734
|
-
!url.searchParams.has("__html")) ||
|
|
735
|
-
url.searchParams.has("__rsc");
|
|
687
|
+
});
|
|
736
688
|
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
689
|
+
try {
|
|
690
|
+
const routerCtx = getRouterContext();
|
|
691
|
+
if (routerCtx?.telemetry) {
|
|
692
|
+
safeEmit(resolveSink(routerCtx.telemetry), {
|
|
693
|
+
type: "request.origin-rejected" as const,
|
|
694
|
+
timestamp: performance.now(),
|
|
695
|
+
requestId: routerCtx.requestId,
|
|
696
|
+
method: request.method,
|
|
697
|
+
pathname: url.pathname,
|
|
698
|
+
phase: originPhase,
|
|
699
|
+
origin: request.headers.get("origin"),
|
|
700
|
+
host: request.headers.get("host"),
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
} catch {
|
|
704
|
+
// Router context may not be available
|
|
742
705
|
}
|
|
743
706
|
|
|
744
|
-
|
|
745
|
-
const ssrModule = await loadSSRModule();
|
|
746
|
-
const htmlStream = await ssrModule.renderHTML(rscStream, { nonce });
|
|
747
|
-
|
|
748
|
-
return createResponseWithMergedHeaders(htmlStream, {
|
|
749
|
-
status: 404,
|
|
750
|
-
headers: { "content-type": "text/html;charset=utf-8" },
|
|
751
|
-
});
|
|
707
|
+
return originResult;
|
|
752
708
|
}
|
|
753
|
-
|
|
754
|
-
// Report unhandled errors
|
|
755
|
-
callOnError(error, "routing", {
|
|
756
|
-
request,
|
|
757
|
-
url,
|
|
758
|
-
env,
|
|
759
|
-
handledByBoundary: false,
|
|
760
|
-
});
|
|
761
|
-
console.error(`[RSC] Error:`, error);
|
|
762
|
-
throw error;
|
|
763
709
|
}
|
|
710
|
+
|
|
711
|
+
// ---- 4. Execute ----
|
|
712
|
+
return executeRequest(
|
|
713
|
+
plan as ExecutableRequestPlan<TEnv>,
|
|
714
|
+
request,
|
|
715
|
+
env,
|
|
716
|
+
url,
|
|
717
|
+
variables,
|
|
718
|
+
nonce,
|
|
719
|
+
);
|
|
764
720
|
}
|
|
765
721
|
|
|
766
|
-
//
|
|
767
|
-
//
|
|
768
|
-
//
|
|
769
|
-
//
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
async function handleProgressiveEnhancement(
|
|
722
|
+
// Execute a classified request plan. Dispatches to the appropriate handler
|
|
723
|
+
// based on plan.mode. Lives in the createRSCHandler closure for access to
|
|
724
|
+
// handlerCtx, router, callOnError, etc.
|
|
725
|
+
// Only receives executable plans (version-mismatch is handled above).
|
|
726
|
+
async function executeRequest(
|
|
727
|
+
plan: ExecutableRequestPlan<TEnv>,
|
|
773
728
|
request: Request,
|
|
774
729
|
env: TEnv,
|
|
775
730
|
url: URL,
|
|
776
|
-
|
|
777
|
-
handleStore: ReturnType<typeof requireRequestContext>["_handleStore"],
|
|
731
|
+
variables: Record<string, any>,
|
|
778
732
|
nonce: string | undefined,
|
|
779
|
-
): Promise<Response
|
|
780
|
-
|
|
781
|
-
const
|
|
782
|
-
contentType.includes("multipart/form-data") ||
|
|
783
|
-
contentType.includes("application/x-www-form-urlencoded");
|
|
784
|
-
|
|
785
|
-
if (request.method !== "POST" || isAction || !isFormSubmission) {
|
|
786
|
-
return null;
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
// Clone the request to read FormData without consuming it
|
|
790
|
-
const formData = await request.clone().formData();
|
|
791
|
-
|
|
792
|
-
// Look for React's progressive enhancement hidden fields
|
|
793
|
-
let isDirectAction = false;
|
|
794
|
-
let isUseActionState = false;
|
|
795
|
-
let directActionId: string | null = null;
|
|
796
|
-
|
|
797
|
-
formData.forEach((_value, key) => {
|
|
798
|
-
if (key.startsWith("$ACTION_ID_")) {
|
|
799
|
-
isDirectAction = true;
|
|
800
|
-
directActionId = key.slice("$ACTION_ID_".length);
|
|
801
|
-
} else if (key.startsWith("$ACTION_REF_")) {
|
|
802
|
-
isUseActionState = true;
|
|
803
|
-
}
|
|
804
|
-
});
|
|
805
|
-
|
|
806
|
-
if (!isDirectAction && !isUseActionState) {
|
|
807
|
-
return null;
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
// Execute action and return HTML
|
|
811
|
-
let actionResult: unknown = undefined;
|
|
812
|
-
let reactFormState: ReactFormState | null = null;
|
|
733
|
+
): Promise<Response> {
|
|
734
|
+
// Common setup
|
|
735
|
+
const handleStore = requireRequestContext()._handleStore;
|
|
813
736
|
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
});
|
|
825
|
-
console.error("[RSC] Progressive enhancement action error:", error);
|
|
826
|
-
}
|
|
827
|
-
} else if (isDirectAction && directActionId) {
|
|
828
|
-
const temporaryReferences = createTemporaryReferenceSet();
|
|
829
|
-
|
|
830
|
-
let args: unknown[] = [];
|
|
737
|
+
// Wire up error reporting for late streaming-handle failures
|
|
738
|
+
handleStore.onError = (error: Error) => {
|
|
739
|
+
const reqCtx = requireRequestContext();
|
|
740
|
+
callOnError(error, "handler", {
|
|
741
|
+
request,
|
|
742
|
+
url,
|
|
743
|
+
routeKey: reqCtx._routeName,
|
|
744
|
+
params: reqCtx.params as Record<string, string>,
|
|
745
|
+
handledByBoundary: true,
|
|
746
|
+
});
|
|
831
747
|
try {
|
|
832
|
-
|
|
748
|
+
const routerCtx = getRouterContext();
|
|
749
|
+
if (routerCtx?.telemetry) {
|
|
750
|
+
safeEmit(resolveSink(routerCtx.telemetry), {
|
|
751
|
+
type: "handler.error" as const,
|
|
752
|
+
timestamp: performance.now(),
|
|
753
|
+
requestId: routerCtx.requestId,
|
|
754
|
+
error,
|
|
755
|
+
handledByBoundary: true,
|
|
756
|
+
pathname: url.pathname,
|
|
757
|
+
routeKey: reqCtx._routeName,
|
|
758
|
+
params: reqCtx.params as Record<string, string>,
|
|
759
|
+
});
|
|
760
|
+
}
|
|
833
761
|
} catch {
|
|
834
|
-
|
|
762
|
+
// Router context may not be available (e.g. prerender path)
|
|
835
763
|
}
|
|
764
|
+
};
|
|
836
765
|
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
766
|
+
// Set route params early so all execution paths can access ctx.params.
|
|
767
|
+
// Also store the classified snapshot so match/matchPartial can reuse it
|
|
768
|
+
// instead of calling resolveRoute again.
|
|
769
|
+
if (plan.mode !== "redirect") {
|
|
770
|
+
setRequestContextParams(plan.route.params, plan.route.routeKey);
|
|
771
|
+
requireRequestContext()._classifiedRoute = plan.route;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
const routeReverse = createReverseFunction(getRequiredRouteMap());
|
|
775
|
+
|
|
776
|
+
// ---- Response route: skip entire RSC pipeline ----
|
|
777
|
+
if (plan.mode === "response") {
|
|
778
|
+
// Build ResponseRouteMatch from plan fields. handleResponseRoute
|
|
779
|
+
// expects a flat object with params at the top level.
|
|
780
|
+
const responseMatch: ResponseRouteMatch = {
|
|
781
|
+
responseType: plan.responseType,
|
|
782
|
+
handler: plan.handler,
|
|
783
|
+
params: plan.route.params,
|
|
784
|
+
negotiated: plan.negotiated,
|
|
785
|
+
manifestEntry: plan.manifestEntry,
|
|
786
|
+
routeMiddleware: plan.routeMiddleware,
|
|
787
|
+
};
|
|
788
|
+
const responseOutcome = await withTimeout(
|
|
789
|
+
handleResponseRoute(
|
|
790
|
+
handlerCtx,
|
|
791
|
+
responseMatch,
|
|
842
792
|
request,
|
|
793
|
+
env,
|
|
843
794
|
url,
|
|
795
|
+
variables,
|
|
796
|
+
),
|
|
797
|
+
router.timeouts.renderStartMs,
|
|
798
|
+
"render-start",
|
|
799
|
+
);
|
|
800
|
+
if (responseOutcome.timedOut) {
|
|
801
|
+
return handleTimeoutResponse(
|
|
802
|
+
request,
|
|
844
803
|
env,
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
804
|
+
url,
|
|
805
|
+
"render-start",
|
|
806
|
+
responseOutcome.durationMs,
|
|
807
|
+
plan.route.routeKey,
|
|
808
|
+
);
|
|
849
809
|
}
|
|
810
|
+
const response = responseOutcome.result;
|
|
811
|
+
if (plan.negotiated && !isWebSocketUpgradeResponse(response)) {
|
|
812
|
+
response.headers.append("Vary", "Accept");
|
|
813
|
+
}
|
|
814
|
+
return response;
|
|
850
815
|
}
|
|
851
816
|
|
|
852
|
-
//
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
817
|
+
// SSR setup: kick off in parallel for modes that need HTML rendering.
|
|
818
|
+
// Placed after response-route short-circuit so response/mime routes
|
|
819
|
+
// never pay for SSR work.
|
|
820
|
+
if (plan.mode !== "loader" && mayNeedSSR(request, url)) {
|
|
821
|
+
variables[SSR_SETUP_VAR] = startSSRSetup(
|
|
822
|
+
handlerCtx,
|
|
857
823
|
request,
|
|
858
|
-
url,
|
|
859
824
|
env,
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
// Re-render the page and return HTML
|
|
866
|
-
const renderRequest = new Request(url.toString(), {
|
|
867
|
-
method: "GET",
|
|
868
|
-
headers: new Headers({ accept: "text/html" }),
|
|
869
|
-
});
|
|
870
|
-
|
|
871
|
-
const match = await router.match(renderRequest, env);
|
|
872
|
-
|
|
873
|
-
if (match.redirect) {
|
|
874
|
-
return new Response(null, {
|
|
875
|
-
status: 308,
|
|
876
|
-
headers: { Location: match.redirect },
|
|
877
|
-
});
|
|
825
|
+
url,
|
|
826
|
+
router.debugPerformance
|
|
827
|
+
? () => requireRequestContext()._metricsStore
|
|
828
|
+
: undefined,
|
|
829
|
+
);
|
|
878
830
|
}
|
|
879
831
|
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
const payload: RscPayload = {
|
|
885
|
-
root,
|
|
886
|
-
metadata: {
|
|
887
|
-
pathname: url.pathname,
|
|
888
|
-
segments: match.segments,
|
|
889
|
-
matched: match.matched,
|
|
890
|
-
diff: match.diff,
|
|
891
|
-
isPartial: false,
|
|
892
|
-
rootLayout: router.rootLayout,
|
|
893
|
-
handles: handleStore.stream(),
|
|
894
|
-
version,
|
|
895
|
-
themeConfig: router.themeConfig,
|
|
896
|
-
warmupEnabled: router.warmupEnabled,
|
|
897
|
-
initialTheme: requireRequestContext().theme,
|
|
898
|
-
},
|
|
899
|
-
formState: actionResult,
|
|
900
|
-
};
|
|
901
|
-
|
|
902
|
-
const rscStream = renderToReadableStream<RscPayload>(payload);
|
|
903
|
-
const ssrModule = await loadSSRModule();
|
|
904
|
-
const htmlStream = await ssrModule.renderHTML(rscStream, {
|
|
905
|
-
formState: reactFormState,
|
|
906
|
-
nonce,
|
|
907
|
-
});
|
|
908
|
-
|
|
909
|
-
return new Response(htmlStream, {
|
|
910
|
-
headers: { "content-type": "text/html;charset=utf-8" },
|
|
911
|
-
});
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
// ============================================================================
|
|
915
|
-
// SERVER ACTION HANDLER
|
|
916
|
-
// ============================================================================
|
|
917
|
-
async function handleServerAction(
|
|
918
|
-
request: Request,
|
|
919
|
-
env: TEnv,
|
|
920
|
-
url: URL,
|
|
921
|
-
actionId: string,
|
|
922
|
-
handleStore: ReturnType<typeof requireRequestContext>["_handleStore"],
|
|
923
|
-
): Promise<Response> {
|
|
924
|
-
const temporaryReferences = createTemporaryReferenceSet();
|
|
925
|
-
|
|
926
|
-
// Decode action arguments from request body
|
|
927
|
-
const contentType = request.headers.get("content-type") || "";
|
|
928
|
-
let args: unknown[] = [];
|
|
929
|
-
let actionFormData: FormData | undefined;
|
|
930
|
-
|
|
931
|
-
try {
|
|
932
|
-
const body = contentType.includes("multipart/form-data")
|
|
933
|
-
? await request.formData()
|
|
934
|
-
: await request.text();
|
|
935
|
-
|
|
936
|
-
if (body instanceof FormData) {
|
|
937
|
-
actionFormData = body;
|
|
938
|
-
}
|
|
939
|
-
|
|
940
|
-
if (hasBodyContent(body)) {
|
|
941
|
-
args = await decodeReply(body, { temporaryReferences });
|
|
942
|
-
}
|
|
943
|
-
} catch (error) {
|
|
944
|
-
callOnError(error, "action", {
|
|
832
|
+
// ---- Loader fetch ----
|
|
833
|
+
if (plan.mode === "loader") {
|
|
834
|
+
return handleLoaderFetch(
|
|
835
|
+
handlerCtx,
|
|
945
836
|
request,
|
|
946
|
-
url,
|
|
947
837
|
env,
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
cause: error,
|
|
953
|
-
});
|
|
838
|
+
url,
|
|
839
|
+
variables,
|
|
840
|
+
plan.route.params,
|
|
841
|
+
);
|
|
954
842
|
}
|
|
955
843
|
|
|
956
|
-
//
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
try {
|
|
962
|
-
loadedAction = await loadServerAction(actionId);
|
|
963
|
-
const data = await loadedAction!.apply(null, args);
|
|
964
|
-
returnValue = { ok: true, data };
|
|
965
|
-
} catch (error) {
|
|
966
|
-
returnValue = { ok: false, data: error };
|
|
967
|
-
actionStatus = 500;
|
|
968
|
-
|
|
969
|
-
// Try to render error boundary
|
|
970
|
-
const errorResult = await router.matchError(request, env, error, "route");
|
|
971
|
-
|
|
972
|
-
// Report the action error (handledByBoundary indicates if error boundary will render)
|
|
973
|
-
callOnError(error, "action", {
|
|
844
|
+
// ---- Progressive enhancement ----
|
|
845
|
+
if (plan.mode === "pe-render") {
|
|
846
|
+
const peResult = await handleProgressiveEnhancement(
|
|
847
|
+
handlerCtx,
|
|
974
848
|
request,
|
|
975
|
-
url,
|
|
976
849
|
env,
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
isPartial: true,
|
|
990
|
-
matched: errorResult.matched,
|
|
991
|
-
diff: errorResult.diff,
|
|
992
|
-
isError: true,
|
|
993
|
-
handles: handleStore.stream(),
|
|
994
|
-
version,
|
|
995
|
-
},
|
|
996
|
-
returnValue,
|
|
997
|
-
};
|
|
998
|
-
|
|
999
|
-
const rscStream = renderToReadableStream<RscPayload>(payload, {
|
|
1000
|
-
temporaryReferences,
|
|
1001
|
-
});
|
|
1002
|
-
|
|
1003
|
-
return createResponseWithMergedHeaders(rscStream, {
|
|
1004
|
-
status: actionStatus,
|
|
1005
|
-
headers: { "content-type": "text/x-component;charset=utf-8" },
|
|
1006
|
-
});
|
|
1007
|
-
}
|
|
850
|
+
url,
|
|
851
|
+
false, // isAction = false for PE
|
|
852
|
+
handleStore,
|
|
853
|
+
nonce,
|
|
854
|
+
{
|
|
855
|
+
routeMiddleware: plan.route.routeMiddleware,
|
|
856
|
+
variables,
|
|
857
|
+
routeReverse,
|
|
858
|
+
},
|
|
859
|
+
);
|
|
860
|
+
if (peResult) return peResult;
|
|
861
|
+
// PE handler returned null (not a PE form) — fall through to render
|
|
1008
862
|
}
|
|
1009
863
|
|
|
1010
|
-
//
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
864
|
+
// ---- Action: execute action, then revalidate wrapped in route middleware ----
|
|
865
|
+
if (plan.mode === "action") {
|
|
866
|
+
let actionContinuation: ActionContinuation | undefined;
|
|
867
|
+
try {
|
|
868
|
+
const actionOutcome = await withTimeout(
|
|
869
|
+
executeServerAction(
|
|
870
|
+
handlerCtx,
|
|
871
|
+
request,
|
|
872
|
+
env,
|
|
873
|
+
url,
|
|
874
|
+
plan.actionId,
|
|
875
|
+
handleStore,
|
|
876
|
+
),
|
|
877
|
+
router.timeouts.actionMs,
|
|
878
|
+
"action",
|
|
879
|
+
);
|
|
880
|
+
if (actionOutcome.timedOut) {
|
|
881
|
+
return handleTimeoutResponse(
|
|
882
|
+
request,
|
|
883
|
+
env,
|
|
884
|
+
url,
|
|
885
|
+
"action",
|
|
886
|
+
actionOutcome.durationMs,
|
|
887
|
+
plan.route.routeKey,
|
|
888
|
+
plan.actionId,
|
|
889
|
+
);
|
|
890
|
+
}
|
|
891
|
+
const result = actionOutcome.result;
|
|
892
|
+
// Response means redirect or error boundary — done.
|
|
893
|
+
if (result instanceof Response) return result;
|
|
894
|
+
actionContinuation = result;
|
|
895
|
+
} catch (error) {
|
|
896
|
+
callOnError(error, "action", {
|
|
897
|
+
request,
|
|
898
|
+
url,
|
|
899
|
+
env,
|
|
900
|
+
actionId: plan.actionId,
|
|
901
|
+
handledByBoundary: false,
|
|
1033
902
|
});
|
|
903
|
+
console.error(`[RSC] Action error:`, error);
|
|
904
|
+
throw error;
|
|
1034
905
|
}
|
|
1035
906
|
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
},
|
|
1056
|
-
returnValue,
|
|
1057
|
-
};
|
|
1058
|
-
|
|
1059
|
-
const rscStream = renderToReadableStream<RscPayload>(payload, {
|
|
1060
|
-
temporaryReferences,
|
|
1061
|
-
});
|
|
1062
|
-
|
|
1063
|
-
const headers: Record<string, string> = {
|
|
1064
|
-
"content-type": "text/x-component;charset=utf-8",
|
|
1065
|
-
};
|
|
1066
|
-
if (serverTiming) {
|
|
1067
|
-
headers["Server-Timing"] = serverTiming;
|
|
1068
|
-
}
|
|
1069
|
-
|
|
1070
|
-
return createResponseWithMergedHeaders(rscStream, {
|
|
1071
|
-
status: actionStatus,
|
|
1072
|
-
headers,
|
|
1073
|
-
});
|
|
907
|
+
// Revalidation render wrapped in route middleware.
|
|
908
|
+
// Actions from client-side navigation include _rsc_partial — preserve
|
|
909
|
+
// the partial flag so the revalidation returns a Flight stream, not HTML.
|
|
910
|
+
// App-switch is already excluded by classifyRequest (would be full-render).
|
|
911
|
+
const isPartialAction = url.searchParams.has("_rsc_partial");
|
|
912
|
+
return executeRenderWithMiddleware(
|
|
913
|
+
plan.route.routeMiddleware,
|
|
914
|
+
plan.negotiated,
|
|
915
|
+
plan.route.routeKey,
|
|
916
|
+
routeReverse,
|
|
917
|
+
request,
|
|
918
|
+
env,
|
|
919
|
+
url,
|
|
920
|
+
variables,
|
|
921
|
+
nonce,
|
|
922
|
+
handleStore,
|
|
923
|
+
isPartialAction,
|
|
924
|
+
actionContinuation,
|
|
925
|
+
);
|
|
1074
926
|
}
|
|
1075
927
|
|
|
1076
|
-
//
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
diff: matchResult.diff,
|
|
1094
|
-
slots: matchResult.slots,
|
|
1095
|
-
handles: handleStore.stream(),
|
|
1096
|
-
version,
|
|
1097
|
-
},
|
|
1098
|
-
returnValue,
|
|
1099
|
-
};
|
|
1100
|
-
|
|
1101
|
-
const rscStream = renderToReadableStream<RscPayload>(payload, {
|
|
1102
|
-
temporaryReferences,
|
|
1103
|
-
});
|
|
928
|
+
// ---- Full render / Partial render (or PE that fell through) ----
|
|
929
|
+
if (plan.mode === "full-render" || plan.mode === "partial-render") {
|
|
930
|
+
const isPartial = plan.mode === "partial-render";
|
|
931
|
+
return executeRenderWithMiddleware(
|
|
932
|
+
plan.route.routeMiddleware,
|
|
933
|
+
plan.negotiated,
|
|
934
|
+
plan.route.routeKey,
|
|
935
|
+
routeReverse,
|
|
936
|
+
request,
|
|
937
|
+
env,
|
|
938
|
+
url,
|
|
939
|
+
variables,
|
|
940
|
+
nonce,
|
|
941
|
+
handleStore,
|
|
942
|
+
isPartial,
|
|
943
|
+
);
|
|
944
|
+
}
|
|
1104
945
|
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
946
|
+
// PE that fell through (handleProgressiveEnhancement returned null)
|
|
947
|
+
// falls back to full render
|
|
948
|
+
if (plan.mode === "pe-render") {
|
|
949
|
+
return executeRenderWithMiddleware(
|
|
950
|
+
plan.route.routeMiddleware,
|
|
951
|
+
false,
|
|
952
|
+
plan.route.routeKey,
|
|
953
|
+
routeReverse,
|
|
954
|
+
request,
|
|
955
|
+
env,
|
|
956
|
+
url,
|
|
957
|
+
variables,
|
|
958
|
+
nonce,
|
|
959
|
+
handleStore,
|
|
960
|
+
false,
|
|
961
|
+
);
|
|
1110
962
|
}
|
|
1111
963
|
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
964
|
+
// Redirect plan that wasn't handled above (full-page redirect — let
|
|
965
|
+
// the pipeline handle it via match() which returns { redirect: url })
|
|
966
|
+
return executeRenderWithMiddleware(
|
|
967
|
+
plan.route.routeMiddleware,
|
|
968
|
+
false,
|
|
969
|
+
plan.route.routeKey,
|
|
970
|
+
routeReverse,
|
|
971
|
+
request,
|
|
972
|
+
env,
|
|
973
|
+
url,
|
|
974
|
+
variables,
|
|
975
|
+
nonce,
|
|
976
|
+
handleStore,
|
|
977
|
+
false,
|
|
978
|
+
);
|
|
1116
979
|
}
|
|
1117
980
|
|
|
1118
|
-
//
|
|
1119
|
-
//
|
|
1120
|
-
//
|
|
1121
|
-
|
|
1122
|
-
|
|
981
|
+
// Shared render execution: wraps handleRscRendering (or revalidateAfterAction)
|
|
982
|
+
// in route middleware and timeout handling. Consolidates the pattern used by
|
|
983
|
+
// action-revalidate, full-render, and partial-render modes.
|
|
984
|
+
async function executeRenderWithMiddleware(
|
|
985
|
+
routeMiddleware: import("../router/middleware-types.js").CollectedMiddleware[],
|
|
986
|
+
negotiated: boolean,
|
|
987
|
+
routeKey: string,
|
|
988
|
+
routeReverse: ReturnType<typeof createReverseFunction>,
|
|
1123
989
|
request: Request,
|
|
1124
990
|
env: TEnv,
|
|
1125
991
|
url: URL,
|
|
1126
992
|
variables: Record<string, any>,
|
|
993
|
+
nonce: string | undefined,
|
|
994
|
+
handleStore: ReturnType<typeof requireRequestContext>["_handleStore"],
|
|
995
|
+
isPartial: boolean,
|
|
996
|
+
actionContinuation?: ActionContinuation,
|
|
1127
997
|
): Promise<Response> {
|
|
1128
|
-
const
|
|
1129
|
-
|
|
1130
|
-
if (!loaderId) {
|
|
1131
|
-
return createResponseWithMergedHeaders("Missing _rsc_loader parameter", {
|
|
1132
|
-
status: 400,
|
|
1133
|
-
});
|
|
1134
|
-
}
|
|
1135
|
-
|
|
1136
|
-
// Look up loader lazily
|
|
1137
|
-
const registeredLoader = await getLoaderLazy(loaderId);
|
|
1138
|
-
if (!registeredLoader) {
|
|
1139
|
-
return createResponseWithMergedHeaders(
|
|
1140
|
-
`Loader "${loaderId}" not found in registry`,
|
|
1141
|
-
{ status: 404 },
|
|
1142
|
-
);
|
|
1143
|
-
}
|
|
1144
|
-
|
|
1145
|
-
// Parse params and body based on request method
|
|
1146
|
-
let loaderParams: Record<string, string> = {};
|
|
1147
|
-
let loaderBody: unknown = undefined;
|
|
1148
|
-
const isBodyMethod = request.method !== "GET" && request.method !== "HEAD";
|
|
1149
|
-
|
|
1150
|
-
if (isBodyMethod) {
|
|
998
|
+
const renderHandler = async (): Promise<Response> => {
|
|
1151
999
|
try {
|
|
1152
|
-
|
|
1153
|
-
if (
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
} catch {
|
|
1172
|
-
return createResponseWithMergedHeaders(
|
|
1173
|
-
"Invalid _rsc_loader_params JSON",
|
|
1174
|
-
{ status: 400 },
|
|
1000
|
+
let response: Response;
|
|
1001
|
+
if (actionContinuation) {
|
|
1002
|
+
response = await revalidateAfterAction(
|
|
1003
|
+
handlerCtx,
|
|
1004
|
+
request,
|
|
1005
|
+
env,
|
|
1006
|
+
url,
|
|
1007
|
+
handleStore,
|
|
1008
|
+
actionContinuation,
|
|
1009
|
+
);
|
|
1010
|
+
} else {
|
|
1011
|
+
response = await handleRscRendering(
|
|
1012
|
+
handlerCtx,
|
|
1013
|
+
request,
|
|
1014
|
+
env,
|
|
1015
|
+
url,
|
|
1016
|
+
isPartial,
|
|
1017
|
+
handleStore,
|
|
1018
|
+
nonce,
|
|
1175
1019
|
);
|
|
1176
1020
|
}
|
|
1177
|
-
|
|
1178
|
-
|
|
1021
|
+
if (negotiated && !isWebSocketUpgradeResponse(response)) {
|
|
1022
|
+
response.headers.append("Vary", "Accept");
|
|
1023
|
+
}
|
|
1024
|
+
return response;
|
|
1025
|
+
} catch (error) {
|
|
1026
|
+
// Check if middleware/handler returned Response
|
|
1027
|
+
if (error instanceof Response) {
|
|
1028
|
+
// During partial (client-side navigation), a 200 Response from a handler
|
|
1029
|
+
// means the route serves raw content (JSON, text, etc.), not JSX.
|
|
1030
|
+
// Signal the browser to hard-navigate so it renders the raw response.
|
|
1031
|
+
if (isPartial && error.status === 200) {
|
|
1032
|
+
console.warn(
|
|
1033
|
+
`[RSC] Route handler at ${url.pathname} returned a Response during client-side navigation. ` +
|
|
1034
|
+
`Falling back to hard navigation. Use data-external on the <Link> to avoid the extra round-trip.`,
|
|
1035
|
+
);
|
|
1036
|
+
return createResponseWithMergedHeaders(null, {
|
|
1037
|
+
status: 200,
|
|
1038
|
+
headers: {
|
|
1039
|
+
"X-RSC-Reload": stripInternalParams(url).toString(),
|
|
1040
|
+
"content-type": "text/x-component;charset=utf-8",
|
|
1041
|
+
},
|
|
1042
|
+
});
|
|
1043
|
+
}
|
|
1179
1044
|
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1045
|
+
if (isPartial) {
|
|
1046
|
+
const intercepted = interceptRedirectForPartial(
|
|
1047
|
+
error,
|
|
1048
|
+
createRedirectFlightResponse,
|
|
1049
|
+
);
|
|
1050
|
+
if (intercepted) return intercepted;
|
|
1051
|
+
}
|
|
1183
1052
|
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
request,
|
|
1187
|
-
env,
|
|
1188
|
-
loaderParams,
|
|
1189
|
-
variables,
|
|
1190
|
-
async () => {
|
|
1191
|
-
const ctx = requireRequestContext();
|
|
1192
|
-
const loaderCtx: any = {
|
|
1193
|
-
...ctx,
|
|
1194
|
-
params: loaderParams,
|
|
1195
|
-
body: loaderBody,
|
|
1196
|
-
};
|
|
1053
|
+
return error;
|
|
1054
|
+
}
|
|
1197
1055
|
|
|
1198
|
-
|
|
1056
|
+
// Render 404 page for unmatched routes
|
|
1057
|
+
const isRouteNotFound =
|
|
1058
|
+
error instanceof RouteNotFoundError ||
|
|
1059
|
+
(error instanceof Error && error.name === "RouteNotFoundError");
|
|
1060
|
+
if (isRouteNotFound) {
|
|
1061
|
+
callOnError(error, "routing", {
|
|
1062
|
+
request,
|
|
1063
|
+
url,
|
|
1064
|
+
env,
|
|
1065
|
+
handledByBoundary: true,
|
|
1066
|
+
});
|
|
1199
1067
|
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1068
|
+
const notFoundOption = router.notFound;
|
|
1069
|
+
const notFoundComponent =
|
|
1070
|
+
typeof notFoundOption === "function"
|
|
1071
|
+
? notFoundOption({ pathname: url.pathname })
|
|
1072
|
+
: (notFoundOption ?? createElement("h1", null, "Not Found"));
|
|
1073
|
+
|
|
1074
|
+
const notFoundSegment = {
|
|
1075
|
+
id: "notFound",
|
|
1076
|
+
namespace: "notFound",
|
|
1077
|
+
type: "route" as const,
|
|
1078
|
+
index: 0,
|
|
1079
|
+
component: notFoundComponent,
|
|
1080
|
+
params: {},
|
|
1081
|
+
};
|
|
1206
1082
|
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1083
|
+
const payload: RscPayload = {
|
|
1084
|
+
metadata: {
|
|
1085
|
+
pathname: url.pathname,
|
|
1086
|
+
routerId: router.id,
|
|
1087
|
+
basename: router.basename,
|
|
1088
|
+
segments: [notFoundSegment],
|
|
1089
|
+
matched: [],
|
|
1090
|
+
diff: [],
|
|
1091
|
+
isPartial: false,
|
|
1092
|
+
rootLayout: router.rootLayout,
|
|
1093
|
+
handles: handleStore.stream(),
|
|
1094
|
+
version,
|
|
1095
|
+
themeConfig: router.themeConfig,
|
|
1096
|
+
warmupEnabled: router.warmupEnabled,
|
|
1097
|
+
initialTheme: requireRequestContext().theme,
|
|
1098
|
+
},
|
|
1099
|
+
};
|
|
1215
1100
|
|
|
1216
|
-
|
|
1101
|
+
const rscStream = renderToReadableStream(payload, {
|
|
1102
|
+
onError: (error: unknown) => {
|
|
1103
|
+
callOnError(error, "rendering", { request, url, env });
|
|
1104
|
+
},
|
|
1105
|
+
});
|
|
1217
1106
|
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
handledByBoundary: false,
|
|
1224
|
-
});
|
|
1107
|
+
const isRscRequest =
|
|
1108
|
+
isPartial ||
|
|
1109
|
+
(!request.headers.get("accept")?.includes("text/html") &&
|
|
1110
|
+
!url.searchParams.has("__html")) ||
|
|
1111
|
+
url.searchParams.has("__rsc");
|
|
1225
1112
|
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
};
|
|
1233
|
-
const rscStream = renderToReadableStream(errorPayload);
|
|
1113
|
+
if (isRscRequest) {
|
|
1114
|
+
return createResponseWithMergedHeaders(rscStream, {
|
|
1115
|
+
status: 404,
|
|
1116
|
+
headers: { "content-type": "text/x-component;charset=utf-8" },
|
|
1117
|
+
});
|
|
1118
|
+
}
|
|
1234
1119
|
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1120
|
+
const [ssrModule, streamMode] = await getSSRSetup(
|
|
1121
|
+
handlerCtx,
|
|
1122
|
+
request,
|
|
1123
|
+
env,
|
|
1124
|
+
url,
|
|
1125
|
+
requireRequestContext()._metricsStore,
|
|
1126
|
+
);
|
|
1127
|
+
const htmlStream = await ssrModule.renderHTML(rscStream, {
|
|
1128
|
+
nonce,
|
|
1129
|
+
streamMode,
|
|
1130
|
+
});
|
|
1241
1131
|
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
async function handleRscRendering(
|
|
1246
|
-
request: Request,
|
|
1247
|
-
env: TEnv,
|
|
1248
|
-
url: URL,
|
|
1249
|
-
isPartial: boolean,
|
|
1250
|
-
handleStore: ReturnType<typeof requireRequestContext>["_handleStore"],
|
|
1251
|
-
nonce: string | undefined,
|
|
1252
|
-
): Promise<Response> {
|
|
1253
|
-
// Retrieve handler-level timing from variables
|
|
1254
|
-
const reqCtx = requireRequestContext();
|
|
1255
|
-
const handlerTimingArr: string[] = reqCtx.var.__handlerTiming || [];
|
|
1256
|
-
const handlerStart: number = reqCtx.var.__handlerStart || 0;
|
|
1257
|
-
|
|
1258
|
-
let payload: RscPayload;
|
|
1259
|
-
let serverTiming: string | undefined;
|
|
1260
|
-
|
|
1261
|
-
if (isPartial) {
|
|
1262
|
-
// Partial render (navigation)
|
|
1263
|
-
const result = await router.matchPartial(request, env);
|
|
1264
|
-
|
|
1265
|
-
if (!result) {
|
|
1266
|
-
// Fall back to full render
|
|
1267
|
-
const match = await router.match(request, env);
|
|
1268
|
-
setRequestContextParams(match.params);
|
|
1269
|
-
|
|
1270
|
-
if (match.redirect) {
|
|
1271
|
-
return createResponseWithMergedHeaders(null, {
|
|
1272
|
-
status: 308,
|
|
1273
|
-
headers: { Location: match.redirect },
|
|
1132
|
+
return createResponseWithMergedHeaders(htmlStream, {
|
|
1133
|
+
status: 404,
|
|
1134
|
+
headers: { "content-type": "text/html;charset=utf-8" },
|
|
1274
1135
|
});
|
|
1275
1136
|
}
|
|
1276
1137
|
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
? `${match.serverTiming}, rendering;dur=${renderDuration.toFixed(2)}`
|
|
1284
|
-
: `rendering;dur=${renderDuration.toFixed(2)}`;
|
|
1285
|
-
|
|
1286
|
-
payload = {
|
|
1287
|
-
root,
|
|
1288
|
-
metadata: {
|
|
1289
|
-
pathname: url.pathname,
|
|
1290
|
-
segments: match.segments,
|
|
1291
|
-
matched: match.matched,
|
|
1292
|
-
diff: match.diff,
|
|
1293
|
-
isPartial: false,
|
|
1294
|
-
handles: handleStore.stream(),
|
|
1295
|
-
version,
|
|
1296
|
-
themeConfig: router.themeConfig,
|
|
1297
|
-
initialTheme: reqCtx.theme,
|
|
1298
|
-
},
|
|
1299
|
-
};
|
|
1300
|
-
} else {
|
|
1301
|
-
setRequestContextParams(result.params);
|
|
1302
|
-
serverTiming = result.serverTiming;
|
|
1303
|
-
|
|
1304
|
-
payload = {
|
|
1305
|
-
root: null,
|
|
1306
|
-
metadata: {
|
|
1307
|
-
pathname: url.pathname,
|
|
1308
|
-
segments: result.segments,
|
|
1309
|
-
matched: result.matched,
|
|
1310
|
-
diff: result.diff,
|
|
1311
|
-
isPartial: true,
|
|
1312
|
-
slots: result.slots,
|
|
1313
|
-
handles: handleStore.stream(),
|
|
1314
|
-
version,
|
|
1315
|
-
},
|
|
1316
|
-
};
|
|
1317
|
-
}
|
|
1318
|
-
} else {
|
|
1319
|
-
// Full render (initial page load)
|
|
1320
|
-
const match = await router.match(request, env);
|
|
1321
|
-
setRequestContextParams(match.params);
|
|
1322
|
-
|
|
1323
|
-
if (match.redirect) {
|
|
1324
|
-
return createResponseWithMergedHeaders(null, {
|
|
1325
|
-
status: 308,
|
|
1326
|
-
headers: { Location: match.redirect },
|
|
1138
|
+
// Report unhandled errors
|
|
1139
|
+
callOnError(error, "routing", {
|
|
1140
|
+
request,
|
|
1141
|
+
url,
|
|
1142
|
+
env,
|
|
1143
|
+
handledByBoundary: false,
|
|
1327
1144
|
});
|
|
1145
|
+
console.error(`[RSC] Error:`, error);
|
|
1146
|
+
throw error;
|
|
1328
1147
|
}
|
|
1148
|
+
};
|
|
1329
1149
|
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
const serializedSegments = await serializeSegments(nonLoaderSegments);
|
|
1341
|
-
const handles: Record<string, Record<string, unknown[]>> = {};
|
|
1342
|
-
for (const seg of nonLoaderSegments) {
|
|
1343
|
-
handles[seg.id] = handleStore.getDataForSegment(seg.id);
|
|
1344
|
-
}
|
|
1345
|
-
return new Response(
|
|
1346
|
-
JSON.stringify({
|
|
1347
|
-
segments: serializedSegments,
|
|
1348
|
-
handles,
|
|
1349
|
-
routeName: match.routeName,
|
|
1350
|
-
params: match.params,
|
|
1351
|
-
}),
|
|
1352
|
-
{ headers: { "Content-Type": "application/json" } },
|
|
1150
|
+
// Wrap the render path in a renderStartMs timeout
|
|
1151
|
+
const executeRender = async (): Promise<Response> => {
|
|
1152
|
+
if (routeMiddleware.length > 0) {
|
|
1153
|
+
const mwResponse = await executeMiddleware(
|
|
1154
|
+
buildRouteMiddlewareEntries<TEnv>(routeMiddleware),
|
|
1155
|
+
request,
|
|
1156
|
+
env,
|
|
1157
|
+
variables,
|
|
1158
|
+
renderHandler,
|
|
1159
|
+
routeReverse,
|
|
1353
1160
|
);
|
|
1354
|
-
} else {
|
|
1355
|
-
const renderStart = performance.now();
|
|
1356
|
-
const root = renderSegments(match.segments, {
|
|
1357
|
-
rootLayout: router.rootLayout,
|
|
1358
|
-
});
|
|
1359
|
-
const renderDuration = performance.now() - renderStart;
|
|
1360
|
-
serverTiming = match.serverTiming
|
|
1361
|
-
? `${match.serverTiming}, rendering;dur=${renderDuration.toFixed(2)}`
|
|
1362
|
-
: `rendering;dur=${renderDuration.toFixed(2)}`;
|
|
1363
1161
|
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
isPartial: false,
|
|
1372
|
-
rootLayout: router.rootLayout,
|
|
1373
|
-
handles: handleStore.stream(),
|
|
1374
|
-
version,
|
|
1375
|
-
themeConfig: router.themeConfig,
|
|
1376
|
-
initialTheme: reqCtx.theme,
|
|
1377
|
-
},
|
|
1378
|
-
};
|
|
1379
|
-
}
|
|
1380
|
-
}
|
|
1381
|
-
|
|
1382
|
-
// Serialize to RSC stream
|
|
1383
|
-
const rscSerializeStart = performance.now();
|
|
1384
|
-
const rscStream = renderToReadableStream<RscPayload>(payload);
|
|
1385
|
-
const rscSerializeDur = performance.now() - rscSerializeStart;
|
|
1386
|
-
|
|
1387
|
-
// Determine if this is an RSC request or HTML request
|
|
1388
|
-
const isRscRequest =
|
|
1389
|
-
(!request.headers.get("accept")?.includes("text/html") &&
|
|
1390
|
-
!url.searchParams.has("__html")) ||
|
|
1391
|
-
url.searchParams.has("__rsc");
|
|
1392
|
-
|
|
1393
|
-
// Build complete Server-Timing: handler phases + match/manifest + rendering + RSC serialize
|
|
1394
|
-
const timingParts: string[] = [...handlerTimingArr];
|
|
1395
|
-
if (serverTiming) {
|
|
1396
|
-
timingParts.push(serverTiming);
|
|
1397
|
-
}
|
|
1398
|
-
timingParts.push(`rsc-serialize;dur=${rscSerializeDur.toFixed(2)}`);
|
|
1162
|
+
if (isPartial || actionContinuation) {
|
|
1163
|
+
const intercepted = interceptRedirectForPartial(
|
|
1164
|
+
mwResponse,
|
|
1165
|
+
createRedirectFlightResponse,
|
|
1166
|
+
);
|
|
1167
|
+
if (intercepted) return intercepted;
|
|
1168
|
+
}
|
|
1399
1169
|
|
|
1400
|
-
|
|
1401
|
-
const fullTiming = timingParts.join(", ");
|
|
1402
|
-
const rscHeaders: Record<string, string> = {
|
|
1403
|
-
"content-type": "text/x-component;charset=utf-8",
|
|
1404
|
-
vary: "accept",
|
|
1405
|
-
};
|
|
1406
|
-
if (fullTiming) {
|
|
1407
|
-
rscHeaders["Server-Timing"] = fullTiming;
|
|
1170
|
+
return finalizeResponse(mwResponse);
|
|
1408
1171
|
}
|
|
1409
|
-
return createResponseWithMergedHeaders(rscStream, {
|
|
1410
|
-
headers: rscHeaders,
|
|
1411
|
-
});
|
|
1412
|
-
}
|
|
1413
1172
|
|
|
1414
|
-
|
|
1415
|
-
const ssrModuleStart = performance.now();
|
|
1416
|
-
const ssrModule = await loadSSRModule();
|
|
1417
|
-
const ssrModuleDur = performance.now() - ssrModuleStart;
|
|
1418
|
-
timingParts.push(`ssr-module-load;dur=${ssrModuleDur.toFixed(2)}`);
|
|
1419
|
-
|
|
1420
|
-
const ssrRenderStart = performance.now();
|
|
1421
|
-
const htmlStream = await ssrModule.renderHTML(rscStream, { nonce });
|
|
1422
|
-
const ssrRenderDur = performance.now() - ssrRenderStart;
|
|
1423
|
-
timingParts.push(`ssr-render-html;dur=${ssrRenderDur.toFixed(2)}`);
|
|
1424
|
-
|
|
1425
|
-
// Add total handler duration
|
|
1426
|
-
if (handlerStart) {
|
|
1427
|
-
const totalHandler = performance.now() - handlerStart;
|
|
1428
|
-
timingParts.push(`handler-total;dur=${totalHandler.toFixed(2)}`);
|
|
1429
|
-
}
|
|
1430
|
-
|
|
1431
|
-
const fullTiming = timingParts.join(", ");
|
|
1432
|
-
const htmlHeaders: Record<string, string> = {
|
|
1433
|
-
"content-type": "text/html;charset=utf-8",
|
|
1173
|
+
return renderHandler();
|
|
1434
1174
|
};
|
|
1435
|
-
if (fullTiming) {
|
|
1436
|
-
htmlHeaders["Server-Timing"] = fullTiming;
|
|
1437
|
-
}
|
|
1438
1175
|
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1176
|
+
const renderOutcome = await withTimeout(
|
|
1177
|
+
executeRender(),
|
|
1178
|
+
router.timeouts.renderStartMs,
|
|
1179
|
+
"render-start",
|
|
1180
|
+
);
|
|
1181
|
+
if (renderOutcome.timedOut) {
|
|
1182
|
+
return handleTimeoutResponse(
|
|
1183
|
+
request,
|
|
1184
|
+
env,
|
|
1185
|
+
url,
|
|
1186
|
+
"render-start",
|
|
1187
|
+
renderOutcome.durationMs,
|
|
1188
|
+
routeKey,
|
|
1189
|
+
);
|
|
1190
|
+
}
|
|
1191
|
+
return renderOutcome.result;
|
|
1442
1192
|
}
|
|
1443
1193
|
}
|