@rangojs/router 0.0.0-experimental.2 → 0.0.0-experimental.204030a9
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 +1037 -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/{src/__mocks__/version.ts → dist/__mocks__/version.js} +1 -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 +1779 -0
- 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 +6440 -809
- 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} +18 -17
- package/dist/vite/virtual-entries.js.map +1 -0
- package/package.json +140 -57
- package/skills/breadcrumbs/SKILL.md +252 -0
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +484 -0
- package/skills/caching/SKILL.md +276 -226
- package/skills/composability/SKILL.md +197 -0
- package/skills/debug-manifest/SKILL.md +112 -0
- package/skills/document-cache/SKILL.md +106 -53
- package/skills/fonts/SKILL.md +167 -0
- package/skills/handler-use/SKILL.md +364 -0
- package/skills/hooks/SKILL.md +621 -67
- package/skills/host-router/SKILL.md +243 -0
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +265 -202
- package/skills/layout/SKILL.md +261 -146
- package/skills/links/SKILL.md +471 -0
- package/skills/loader/SKILL.md +701 -250
- package/skills/middleware/SKILL.md +254 -320
- package/skills/migrate-nextjs/SKILL.md +562 -0
- package/skills/migrate-react-router/SKILL.md +769 -0
- package/skills/mime-routes/SKILL.md +155 -0
- package/skills/observability/SKILL.md +137 -0
- package/skills/parallel/SKILL.md +399 -158
- package/skills/prerender/SKILL.md +666 -0
- package/skills/rango/SKILL.md +338 -0
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +468 -0
- package/skills/route/SKILL.md +417 -89
- package/skills/router-setup/SKILL.md +389 -268
- package/skills/server-actions/SKILL.md +751 -0
- package/skills/streams-and-websockets/SKILL.md +283 -0
- package/skills/tailwind/SKILL.md +129 -0
- package/skills/testing/SKILL.md +549 -0
- package/skills/theme/SKILL.md +36 -11
- package/skills/typesafety/SKILL.md +747 -174
- package/skills/use-cache/SKILL.md +353 -0
- package/skills/view-transitions/SKILL.md +294 -0
- package/src/__augment-tests__/augment.ts +81 -0
- package/src/__augment-tests__/augmented.check.ts +117 -0
- package/src/__internal.ts +273 -0
- package/src/bin/rango.ts +321 -0
- package/src/browser/action-coordinator.ts +114 -0
- package/src/browser/app-shell.ts +52 -0
- package/src/browser/app-version.ts +14 -0
- package/src/browser/event-controller.ts +172 -128
- package/src/browser/history-state.ts +101 -0
- package/src/browser/index.ts +3 -3
- package/src/browser/intercept-utils.ts +52 -0
- package/src/browser/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 +390 -557
- package/src/browser/navigation-client.ts +228 -70
- package/src/browser/navigation-store.ts +104 -63
- package/src/browser/navigation-transaction.ts +279 -0
- package/src/browser/network-error-handler.ts +61 -0
- package/src/browser/partial-update.ts +397 -303
- 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 +258 -74
- package/src/browser/react/NavigationProvider.tsx +237 -49
- package/src/browser/react/context.ts +11 -0
- package/src/browser/react/filter-segment-order.ts +55 -0
- package/src/browser/react/index.ts +15 -12
- package/src/browser/react/location-state-shared.ts +269 -56
- package/src/browser/react/location-state.ts +90 -19
- package/src/browser/react/mount-context.ts +37 -0
- 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 +41 -98
- package/src/browser/react/use-href.tsx +20 -188
- package/src/browser/react/use-link-status.ts +6 -5
- package/src/browser/react/use-mount.ts +31 -0
- package/src/browser/react/use-navigation.ts +49 -80
- package/src/browser/react/use-params.ts +77 -0
- package/src/browser/react/use-pathname.ts +47 -0
- package/src/browser/react/use-reverse.ts +106 -0
- package/src/browser/react/use-router.ts +96 -0
- package/src/browser/react/use-search-params.ts +56 -0
- package/src/browser/react/use-segments.ts +85 -99
- package/src/browser/response-adapter.ts +98 -0
- package/src/browser/rsc-router.tsx +273 -78
- package/src/browser/scroll-restoration.ts +132 -49
- package/src/browser/segment-reconciler.ts +243 -0
- package/src/browser/segment-structure-assert.ts +83 -0
- package/src/browser/server-action-bridge.ts +504 -589
- package/src/browser/shallow.ts +6 -1
- package/src/browser/types.ts +184 -58
- package/src/browser/validate-redirect-origin.ts +29 -0
- package/src/build/collect-fallback-refs.ts +107 -0
- package/src/build/generate-manifest.ts +463 -0
- package/src/build/generate-route-types.ts +41 -0
- package/src/build/index.ts +37 -0
- package/src/build/route-trie.ts +292 -0
- 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 +131 -0
- package/src/build/route-types/router-processing.ts +659 -0
- package/src/build/route-types/scan-filter.ts +85 -0
- package/src/build/route-types/source-scan.ts +118 -0
- package/src/build/runtime-discovery.ts +220 -0
- package/src/cache/background-task.ts +34 -0
- package/src/cache/cache-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 +150 -306
- package/src/cache/cf/cf-cache-store.ts +619 -24
- 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 +76 -121
- package/src/client.rsc.tsx +15 -15
- package/src/client.tsx +145 -309
- package/src/component-utils.ts +4 -4
- package/src/components/DefaultDocument.tsx +6 -2
- package/src/context-var.ts +156 -0
- package/src/debug.ts +243 -0
- package/src/decode-loader-results.ts +36 -0
- package/src/errors.ts +138 -3
- package/src/handle.ts +90 -22
- package/src/handles/MetaTags.tsx +76 -23
- package/src/handles/breadcrumbs.ts +66 -0
- package/src/handles/index.ts +1 -0
- package/src/handles/meta.ts +32 -15
- package/src/host/cookie-handler.ts +165 -0
- package/src/host/errors.ts +97 -0
- package/src/host/index.ts +53 -0
- package/src/host/pattern-matcher.ts +214 -0
- package/src/host/router.ts +424 -0
- package/src/host/testing.ts +79 -0
- package/src/host/types.ts +175 -0
- package/src/host/utils.ts +25 -0
- package/src/href-client.ts +263 -49
- package/src/index.rsc.ts +190 -29
- package/src/index.ts +278 -38
- package/src/internal-debug.ts +11 -0
- package/src/loader-store.ts +500 -0
- package/src/loader.rsc.ts +24 -142
- package/src/loader.ts +21 -11
- package/src/missing-id-error.ts +68 -0
- 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 +37 -0
- package/src/prerender/store.ts +186 -0
- package/src/prerender.ts +524 -0
- package/src/response-utils.ts +37 -0
- package/src/reverse.ts +380 -0
- package/src/root-error-boundary.tsx +41 -29
- package/src/route-content-wrapper.tsx +15 -39
- package/src/route-definition/dsl-helpers.ts +1109 -0
- package/src/route-definition/helper-factories.ts +90 -0
- package/src/route-definition/helpers-types.ts +506 -0
- package/src/route-definition/index.ts +55 -0
- package/src/route-definition/redirect.ts +101 -0
- package/src/route-definition/resolve-handler-use.ts +155 -0
- package/src/route-definition/use-item-types.ts +32 -0
- package/src/route-definition.ts +1 -1371
- package/src/route-map-builder.ts +247 -112
- package/src/route-name.ts +53 -0
- package/src/route-types.ts +99 -42
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +228 -0
- package/src/router/debug-manifest.ts +72 -0
- package/src/router/error-handling.ts +10 -10
- package/src/router/find-match.ts +160 -0
- package/src/router/handler-context.ts +420 -88
- package/src/router/intercept-resolution.ts +388 -0
- package/src/router/lazy-includes.ts +237 -0
- package/src/router/loader-resolution.ts +374 -128
- package/src/router/logging.ts +251 -0
- package/src/router/manifest.ts +187 -43
- package/src/router/match-api.ts +556 -0
- package/src/router/match-context.ts +6 -4
- package/src/router/match-handlers.ts +483 -0
- package/src/router/match-middleware/background-revalidation.ts +108 -93
- package/src/router/match-middleware/cache-lookup.ts +413 -10
- package/src/router/match-middleware/cache-store.ts +99 -26
- package/src/router/match-middleware/intercept-resolution.ts +57 -17
- package/src/router/match-middleware/segment-resolution.ts +80 -6
- package/src/router/match-pipelines.ts +10 -45
- package/src/router/match-result.ts +156 -36
- package/src/router/metrics.ts +241 -16
- package/src/router/middleware-cookies.ts +55 -0
- package/src/router/middleware-types.ts +209 -0
- package/src/router/middleware.ts +359 -346
- package/src/router/navigation-snapshot.ts +182 -0
- package/src/router/pattern-matching.ts +416 -41
- package/src/router/prerender-match.ts +502 -0
- package/src/router/preview-match.ts +100 -0
- package/src/router/request-classification.ts +286 -0
- package/src/router/revalidation.ts +195 -40
- package/src/router/route-snapshot.ts +245 -0
- package/src/router/router-context.ts +45 -23
- package/src/router/router-interfaces.ts +501 -0
- package/src/router/router-options.ts +657 -0
- package/src/router/router-registry.ts +21 -0
- package/src/router/segment-resolution/fresh.ts +769 -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 +1420 -0
- package/src/router/segment-resolution/static-store.ts +67 -0
- package/src/router/segment-resolution/view-transition-default.ts +36 -0
- package/src/router/segment-resolution.ts +21 -0
- package/src/router/segment-wrappers.ts +291 -0
- package/src/router/substitute-pattern-params.ts +56 -0
- package/src/router/telemetry-otel.ts +299 -0
- package/src/router/telemetry.ts +399 -0
- package/src/router/timeout.ts +148 -0
- package/src/router/trie-matching.ts +244 -0
- package/src/router/types.ts +87 -4
- package/src/router/url-params.ts +49 -0
- package/src/router.ts +768 -3574
- package/src/rsc/handler-context.ts +45 -0
- package/src/rsc/handler.ts +894 -806
- package/src/rsc/helpers.ts +201 -19
- package/src/rsc/index.ts +5 -25
- 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 +159 -0
- package/src/rsc/progressive-enhancement.ts +395 -0
- package/src/rsc/response-error.ts +37 -0
- package/src/rsc/response-route-handler.ts +340 -0
- package/src/rsc/rsc-rendering.ts +230 -0
- package/src/rsc/runtime-warnings.ts +41 -0
- package/src/rsc/server-action.ts +336 -0
- package/src/rsc/ssr-setup.ts +144 -0
- package/src/rsc/types.ts +54 -14
- 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 +265 -115
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +480 -90
- package/src/server/cookie-store.ts +214 -0
- package/src/server/fetchable-loader-store.ts +37 -0
- package/src/server/handle-store.ts +117 -20
- package/src/server/loader-registry.ts +24 -64
- package/src/server/request-context.ts +613 -109
- package/src/server.ts +36 -131
- package/src/ssr/index.tsx +164 -25
- package/src/static-handler.ts +126 -0
- package/src/testing/cache-status.ts +166 -0
- package/src/testing/collect-handle.ts +63 -0
- package/src/testing/dispatch.ts +440 -0
- package/src/testing/dom.entry.ts +22 -0
- package/src/testing/e2e/fixture.ts +154 -0
- package/src/testing/e2e/index.ts +149 -0
- package/src/testing/e2e/matchers.ts +51 -0
- package/src/testing/e2e/page-helpers.ts +272 -0
- package/src/testing/e2e/parity.ts +306 -0
- package/src/testing/e2e/server.ts +183 -0
- package/src/testing/flight-matchers.ts +104 -0
- package/src/testing/flight-runtime.d.ts +21 -0
- package/src/testing/flight.entry.ts +22 -0
- package/src/testing/flight.ts +182 -0
- package/src/testing/generated-routes.ts +223 -0
- package/src/testing/index.ts +98 -0
- package/src/testing/internal/context.ts +151 -0
- package/src/testing/render-route.tsx +536 -0
- package/src/testing/run-loader.ts +296 -0
- package/src/testing/run-middleware.ts +170 -0
- package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
- package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
- package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
- package/src/testing/vitest-stubs/version.ts +5 -0
- package/src/testing/vitest.ts +112 -0
- package/src/theme/ThemeProvider.tsx +21 -15
- package/src/theme/ThemeScript.tsx +5 -5
- package/src/theme/constants.ts +11 -4
- package/src/theme/index.ts +4 -14
- package/src/theme/theme-context.ts +5 -31
- package/src/theme/theme-script.ts +21 -18
- package/src/theme/types.ts +1 -1
- 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 +113 -0
- package/src/types/handler-context.ts +809 -0
- package/src/types/index.ts +89 -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 +184 -0
- package/src/types.ts +1 -1561
- package/src/urls/include-helper.ts +164 -0
- package/src/urls/index.ts +50 -0
- package/src/urls/path-helper-types.ts +380 -0
- package/src/urls/path-helper.ts +329 -0
- package/src/urls/pattern-types.ts +124 -0
- package/src/urls/response-types.ts +109 -0
- package/src/urls/type-extraction.ts +282 -0
- package/src/urls/urls-function.ts +94 -0
- package/src/urls.ts +1 -726
- package/src/use-loader.tsx +559 -108
- package/src/vite/debug.ts +185 -0
- package/src/vite/discovery/bundle-postprocess.ts +181 -0
- package/src/vite/discovery/discover-routers.ts +398 -0
- package/src/vite/discovery/discovery-errors.ts +194 -0
- package/src/vite/discovery/gate-state.ts +171 -0
- package/src/vite/discovery/prerender-collection.ts +480 -0
- package/src/vite/discovery/route-types-writer.ts +214 -0
- package/src/vite/discovery/self-gen-tracking.ts +73 -0
- package/src/vite/discovery/state.ts +150 -0
- package/src/vite/discovery/virtual-module-codegen.ts +193 -0
- package/src/vite/index.ts +20 -785
- package/src/vite/plugin-types.ts +170 -0
- package/src/vite/plugins/cjs-to-esm.ts +94 -0
- package/src/vite/plugins/client-ref-dedup.ts +131 -0
- package/src/vite/plugins/client-ref-hashing.ts +128 -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} +109 -66
- package/src/vite/plugins/expose-id-utils.ts +303 -0
- package/src/vite/plugins/expose-ids/export-analysis.ts +376 -0
- package/src/vite/plugins/expose-ids/handler-transform.ts +156 -0
- package/src/vite/plugins/expose-ids/loader-transform.ts +72 -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 +796 -0
- package/src/vite/plugins/performance-tracks.ts +92 -0
- package/src/vite/plugins/refresh-cmd.ts +127 -0
- package/src/vite/plugins/use-cache-transform.ts +338 -0
- package/src/vite/plugins/version-injector.ts +99 -0
- package/src/vite/plugins/version-plugin.ts +323 -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 +549 -0
- package/src/vite/router-discovery.ts +1568 -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 +139 -0
- package/src/vite/utils/client-chunks.ts +190 -0
- package/src/vite/utils/forward-user-plugins.ts +193 -0
- package/src/vite/utils/manifest-utils.ts +86 -0
- package/src/vite/utils/package-resolution.ts +161 -0
- package/src/vite/utils/prerender-utils.ts +222 -0
- package/src/vite/utils/shared-utils.ts +251 -0
- package/CLAUDE.md +0 -7
- package/src/__tests__/component-utils.test.ts +0 -76
- package/src/__tests__/route-definition.test.ts +0 -63
- package/src/__tests__/urls.test.tsx +0 -436
- package/src/browser/lru-cache.ts +0 -69
- package/src/browser/request-controller.ts +0 -164
- package/src/cache/__tests__/document-cache.test.ts +0 -522
- package/src/cache/__tests__/memory-segment-store.test.ts +0 -487
- package/src/cache/__tests__/memory-store.test.ts +0 -484
- package/src/cache/cf/__tests__/cf-cache-store.test.ts +0 -428
- package/src/cache/memory-store.ts +0 -253
- package/src/href.ts +0 -177
- package/src/route-utils.ts +0 -89
- package/src/router/__tests__/match-context.test.ts +0 -104
- package/src/router/__tests__/match-pipelines.test.ts +0 -537
- package/src/router/__tests__/match-result.test.ts +0 -566
- package/src/router/__tests__/on-error.test.ts +0 -935
- package/src/router/__tests__/pattern-matching.test.ts +0 -577
- package/src/router/middleware.test.ts +0 -1355
- package/src/rsc/__tests__/helpers.test.ts +0 -175
- package/src/server/__tests__/request-context.test.ts +0 -171
- package/src/ssr/__tests__/ssr-handler.test.tsx +0 -188
- package/src/theme/__tests__/theme.test.ts +0 -120
- package/src/vite/__tests__/expose-loader-id.test.ts +0 -117
- package/src/vite/expose-handle-id.ts +0 -209
- package/src/vite/expose-loader-id.ts +0 -357
- package/src/vite/expose-location-state-id.ts +0 -177
- /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,40 +8,108 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { createElement } from "react";
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import { getLoaderLazy } from "../server/loader-registry.js";
|
|
14
|
-
import {
|
|
15
|
-
matchMiddleware,
|
|
16
|
-
executeMiddleware,
|
|
17
|
-
executeLoaderMiddleware,
|
|
18
|
-
} from "../router/middleware.js";
|
|
11
|
+
import { isRouteNotFoundError } from "../errors.js";
|
|
12
|
+
import { matchMiddleware, executeMiddleware } from "../router/middleware.js";
|
|
19
13
|
import {
|
|
20
14
|
runWithRequestContext,
|
|
21
15
|
setRequestContextParams,
|
|
22
16
|
requireRequestContext,
|
|
17
|
+
getRequestContext,
|
|
18
|
+
_getRequestContext,
|
|
23
19
|
createRequestContext,
|
|
24
|
-
type ExecutionContext,
|
|
25
20
|
} from "../server/request-context.js";
|
|
26
21
|
import * as rscDeps from "@vitejs/plugin-rsc/rsc";
|
|
27
|
-
|
|
28
22
|
import type {
|
|
29
23
|
RscPayload,
|
|
30
|
-
ReactFormState,
|
|
31
24
|
CreateRSCHandlerOptions,
|
|
25
|
+
LoadSSRModule,
|
|
26
|
+
SSRModule,
|
|
32
27
|
} from "./types.js";
|
|
33
|
-
import {
|
|
34
|
-
|
|
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";
|
|
35
40
|
import { VERSION } from "@rangojs/router:version";
|
|
36
41
|
import type { ErrorPhase } from "../types.js";
|
|
42
|
+
import type { RouterRequestInput } from "../router/router-interfaces.js";
|
|
37
43
|
import { invokeOnError } from "../router/error-handling.js";
|
|
44
|
+
import {
|
|
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 {
|
|
52
|
+
hasCachedManifest,
|
|
53
|
+
getRouteTrie,
|
|
54
|
+
getPrecomputedEntries,
|
|
55
|
+
waitForManifestReady,
|
|
56
|
+
getRouterManifest,
|
|
57
|
+
getRouterTrie,
|
|
58
|
+
} from "../route-map-builder.js";
|
|
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 {
|
|
70
|
+
checkRequestOrigin,
|
|
71
|
+
ORIGIN_CHECK_PHASE_BY_MODE,
|
|
72
|
+
} from "./origin-guard.js";
|
|
73
|
+
import { handleRscRendering } from "./rsc-rendering.js";
|
|
74
|
+
import {
|
|
75
|
+
withTimeout,
|
|
76
|
+
RouterTimeoutError,
|
|
77
|
+
createDefaultTimeoutResponse,
|
|
78
|
+
type TimeoutPhase,
|
|
79
|
+
} from "../router/timeout.js";
|
|
80
|
+
import {
|
|
81
|
+
createMetricsStore,
|
|
82
|
+
appendMetric,
|
|
83
|
+
buildMetricsTiming,
|
|
84
|
+
} from "../router/metrics.js";
|
|
85
|
+
import {
|
|
86
|
+
startSSRSetup,
|
|
87
|
+
getSSRSetup,
|
|
88
|
+
mayNeedSSR,
|
|
89
|
+
isRscRequest,
|
|
90
|
+
SSR_SETUP_VAR,
|
|
91
|
+
} from "./ssr-setup.js";
|
|
92
|
+
import {
|
|
93
|
+
classifyRequest,
|
|
94
|
+
type RequestPlan,
|
|
95
|
+
type ExecutableRequestPlan,
|
|
96
|
+
} from "../router/request-classification.js";
|
|
38
97
|
|
|
39
98
|
/**
|
|
40
99
|
* Create an RSC request handler.
|
|
41
100
|
*
|
|
101
|
+
* **Recommended:** Use `router.createHandler()` instead for simpler setup:
|
|
102
|
+
* ```tsx
|
|
103
|
+
* const router = createRouter({ document, urls, nonce: () => true });
|
|
104
|
+
* export const fetch = router.createHandler();
|
|
105
|
+
* ```
|
|
106
|
+
*
|
|
107
|
+
* This function is still useful for advanced cases like per-request cache
|
|
108
|
+
* configuration (e.g., Cloudflare Workers with ExecutionContext).
|
|
109
|
+
*
|
|
42
110
|
* @example Basic usage (deps and loadSSRModule have sensible defaults)
|
|
43
111
|
* ```tsx
|
|
44
|
-
* import { createRSCHandler } from "
|
|
112
|
+
* import { createRSCHandler } from "@rangojs/router/rsc";
|
|
45
113
|
* import { router } from "./router.js";
|
|
46
114
|
*
|
|
47
115
|
* export default createRSCHandler({ router });
|
|
@@ -49,7 +117,7 @@ import { invokeOnError } from "../router/error-handling.js";
|
|
|
49
117
|
*
|
|
50
118
|
* @example With custom deps (advanced)
|
|
51
119
|
* ```tsx
|
|
52
|
-
* import { createRSCHandler } from "
|
|
120
|
+
* import { createRSCHandler } from "@rangojs/router/rsc";
|
|
53
121
|
* import * as rsc from "@vitejs/plugin-rsc/rsc";
|
|
54
122
|
* import { router } from "./router.js";
|
|
55
123
|
*
|
|
@@ -66,9 +134,6 @@ export function createRSCHandler<
|
|
|
66
134
|
>(options: CreateRSCHandlerOptions<TEnv, TRoutes>) {
|
|
67
135
|
const { router, version = VERSION, nonce: nonceProvider } = options;
|
|
68
136
|
|
|
69
|
-
// Get the route map for useHref() - converts route names to URL patterns
|
|
70
|
-
const routeMap = router.routeMap as Record<string, string>;
|
|
71
|
-
|
|
72
137
|
// Use provided deps or default to @vitejs/plugin-rsc/rsc exports
|
|
73
138
|
const deps = options.deps ?? rscDeps;
|
|
74
139
|
const {
|
|
@@ -80,75 +145,320 @@ export function createRSCHandler<
|
|
|
80
145
|
decodeFormState,
|
|
81
146
|
} = deps;
|
|
82
147
|
|
|
83
|
-
// Use provided loadSSRModule or default to vite RSC module loader
|
|
84
|
-
|
|
148
|
+
// Use provided loadSSRModule or default to vite RSC module loader.
|
|
149
|
+
// In production the SSR module is stable across requests, so memoize
|
|
150
|
+
// the dynamic import to avoid repeated module resolution overhead.
|
|
151
|
+
// In dev mode Vite may hot-reload the module, so skip memoization.
|
|
152
|
+
const rawLoadSSRModule: LoadSSRModule =
|
|
85
153
|
options.loadSSRModule ??
|
|
86
154
|
(() => import.meta.viteRsc.loadModule("ssr", "index"));
|
|
155
|
+
let _ssrModulePromise: Promise<SSRModule> | undefined;
|
|
156
|
+
const loadSSRModule: LoadSSRModule =
|
|
157
|
+
process.env.NODE_ENV === "production"
|
|
158
|
+
? () =>
|
|
159
|
+
(_ssrModulePromise ??= rawLoadSSRModule().catch((err) => {
|
|
160
|
+
_ssrModulePromise = undefined;
|
|
161
|
+
throw err;
|
|
162
|
+
}))
|
|
163
|
+
: rawLoadSSRModule;
|
|
87
164
|
|
|
88
165
|
/**
|
|
89
|
-
*
|
|
90
|
-
*
|
|
166
|
+
* Per-request error reporter that deduplicates via the ALS request context.
|
|
167
|
+
*
|
|
168
|
+
* Uses the same _reportedErrors WeakSet as the router layer so errors
|
|
169
|
+
* that propagate across layers are only reported once per request.
|
|
91
170
|
*/
|
|
92
171
|
function callOnError(
|
|
93
172
|
error: unknown,
|
|
94
173
|
phase: ErrorPhase,
|
|
95
174
|
context: Parameters<typeof invokeOnError<TEnv>>[3],
|
|
96
175
|
): void {
|
|
176
|
+
// Guard: abort signal handlers fire asynchronously outside the ALS
|
|
177
|
+
// request scope, so the context may be gone. Skip dedup in that
|
|
178
|
+
// case — the error is from a cancelled stream, not a real failure.
|
|
179
|
+
const reqCtx = _getRequestContext();
|
|
180
|
+
if (error != null && typeof error === "object" && reqCtx) {
|
|
181
|
+
if (reqCtx._reportedErrors.has(error)) return;
|
|
182
|
+
reqCtx._reportedErrors.add(error);
|
|
183
|
+
}
|
|
97
184
|
invokeOnError(router.onError, error, phase, context, "RSC");
|
|
98
185
|
}
|
|
99
186
|
|
|
100
|
-
|
|
187
|
+
function getRequiredRouteMap(): Record<string, string> {
|
|
188
|
+
const routeMap = getRouterManifest(router.id);
|
|
189
|
+
if (!routeMap) {
|
|
190
|
+
throw new Error(
|
|
191
|
+
`Route manifest for router "${router.id}" is not available.`,
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
return routeMap;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Handle a timeout by reporting the error, emitting telemetry,
|
|
199
|
+
* and returning either the custom onTimeout response or a default 504.
|
|
200
|
+
*/
|
|
201
|
+
async function handleTimeoutResponse(
|
|
101
202
|
request: Request,
|
|
102
|
-
env: TEnv
|
|
103
|
-
|
|
203
|
+
env: TEnv,
|
|
204
|
+
url: URL,
|
|
205
|
+
phase: TimeoutPhase,
|
|
206
|
+
durationMs: number,
|
|
207
|
+
routeKey?: string,
|
|
208
|
+
actionId?: string,
|
|
209
|
+
): Promise<Response> {
|
|
210
|
+
const timeoutError = new RouterTimeoutError(phase, durationMs);
|
|
211
|
+
|
|
212
|
+
callOnError(timeoutError, phase === "action" ? "action" : "handler", {
|
|
213
|
+
request,
|
|
214
|
+
url,
|
|
215
|
+
env,
|
|
216
|
+
routeKey,
|
|
217
|
+
actionId,
|
|
218
|
+
handledByBoundary: false,
|
|
219
|
+
metadata: { timeout: true, phase, durationMs },
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
try {
|
|
223
|
+
const routerCtx = getRouterContext();
|
|
224
|
+
if (routerCtx?.telemetry) {
|
|
225
|
+
safeEmit(resolveSink(routerCtx.telemetry), {
|
|
226
|
+
type: "request.timeout" as const,
|
|
227
|
+
timestamp: performance.now(),
|
|
228
|
+
requestId: routerCtx.requestId,
|
|
229
|
+
phase,
|
|
230
|
+
pathname: url.pathname,
|
|
231
|
+
routeKey,
|
|
232
|
+
actionId,
|
|
233
|
+
durationMs,
|
|
234
|
+
customHandler: !!router.onTimeout,
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
} catch {
|
|
238
|
+
// Router context may not be available
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (router.onTimeout) {
|
|
242
|
+
try {
|
|
243
|
+
return await router.onTimeout({
|
|
244
|
+
phase,
|
|
245
|
+
request,
|
|
246
|
+
url,
|
|
247
|
+
env,
|
|
248
|
+
routeKey,
|
|
249
|
+
actionId,
|
|
250
|
+
durationMs,
|
|
251
|
+
});
|
|
252
|
+
} catch (e) {
|
|
253
|
+
if (process.env.NODE_ENV !== "production") {
|
|
254
|
+
console.error("[RSC] onTimeout callback error:", e);
|
|
255
|
+
}
|
|
256
|
+
return createDefaultTimeoutResponse(phase);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return createDefaultTimeoutResponse(phase);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Build a 200 Flight response that carries a redirect URL and optional state.
|
|
265
|
+
* Used when a partial/action request results in a redirect -- fetch
|
|
266
|
+
* auto-follows 3xx so we send the redirect as payload metadata instead.
|
|
267
|
+
*/
|
|
268
|
+
function createRedirectFlightResponse(
|
|
269
|
+
redirectUrl: string,
|
|
270
|
+
locationState?: Record<string, unknown>,
|
|
271
|
+
): Response {
|
|
272
|
+
const redirectPayload: RscPayload = {
|
|
273
|
+
metadata: {
|
|
274
|
+
pathname: redirectUrl,
|
|
275
|
+
segments: [],
|
|
276
|
+
redirect: { url: redirectUrl },
|
|
277
|
+
...(locationState && { locationState }),
|
|
278
|
+
},
|
|
279
|
+
};
|
|
280
|
+
const rscStream = renderToReadableStream<RscPayload>(redirectPayload);
|
|
281
|
+
return createResponseWithMergedHeaders(rscStream, {
|
|
282
|
+
status: 200,
|
|
283
|
+
headers: { "content-type": "text/x-component;charset=utf-8" },
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Bundle shared dependencies for extracted handler functions.
|
|
288
|
+
// callOnError reads from ALS so it's inherently per-request scoped.
|
|
289
|
+
const handlerCtx: HandlerContext<TEnv> = {
|
|
290
|
+
router,
|
|
291
|
+
version,
|
|
292
|
+
renderToReadableStream,
|
|
293
|
+
decodeReply,
|
|
294
|
+
createTemporaryReferenceSet,
|
|
295
|
+
loadServerAction,
|
|
296
|
+
decodeAction,
|
|
297
|
+
decodeFormState,
|
|
298
|
+
loadSSRModule,
|
|
299
|
+
callOnError,
|
|
300
|
+
getRequiredRouteMap,
|
|
301
|
+
createRedirectFlightResponse,
|
|
302
|
+
resolveStreamMode: async (request, env, url) => {
|
|
303
|
+
const resolver = router.ssr?.resolveStreaming;
|
|
304
|
+
if (!resolver) return "stream";
|
|
305
|
+
return resolver({ request, env, url });
|
|
104
306
|
},
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
return async function handler(
|
|
310
|
+
request: Request,
|
|
311
|
+
input: RouterRequestInput<TEnv> = {},
|
|
105
312
|
): Promise<Response> {
|
|
313
|
+
const handlerStart = performance.now();
|
|
314
|
+
// Create the metrics store at handler start so handler:total has startTime=0
|
|
315
|
+
// and all metrics are relative to the request entry point.
|
|
316
|
+
const earlyMetricsStore = router.debugPerformance
|
|
317
|
+
? createMetricsStore(true, handlerStart)
|
|
318
|
+
: undefined;
|
|
319
|
+
|
|
320
|
+
const { env = {} as TEnv, vars: initialVars, ctx: executionCtx } = input;
|
|
321
|
+
|
|
322
|
+
// Connection warmup: return 204 immediately before any processing
|
|
323
|
+
if (router?.warmupEnabled && request.method === "HEAD") {
|
|
324
|
+
const warmupUrl = new URL(request.url);
|
|
325
|
+
if (warmupUrl.searchParams.has("_rsc_warmup")) {
|
|
326
|
+
return new Response(null, { status: 204 });
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
106
330
|
// Resolve nonce if provider is set
|
|
331
|
+
const nonceStart = performance.now();
|
|
107
332
|
let nonce: string | undefined;
|
|
108
333
|
if (nonceProvider) {
|
|
109
334
|
const result = await nonceProvider(request, env);
|
|
110
335
|
nonce = result === true ? generateNonce() : result;
|
|
111
336
|
}
|
|
337
|
+
const nonceDur = performance.now() - nonceStart;
|
|
112
338
|
|
|
113
339
|
const url = new URL(request.url);
|
|
114
340
|
|
|
115
341
|
// Match global middleware
|
|
342
|
+
const mwMatchStart = performance.now();
|
|
116
343
|
const matchedMiddleware = matchMiddleware(url.pathname, router.middleware);
|
|
344
|
+
const mwMatchDur = performance.now() - mwMatchStart;
|
|
117
345
|
|
|
118
346
|
// Shared variables between middleware and route handlers
|
|
119
|
-
|
|
347
|
+
// Initialize from input.vars if provided (allows pre-seeding from worker entry)
|
|
348
|
+
const variables: Record<string, any> = initialVars
|
|
349
|
+
? { ...initialVars }
|
|
350
|
+
: {};
|
|
120
351
|
|
|
121
|
-
// Store nonce
|
|
352
|
+
// Store nonce via ContextVar token and string key for backward compat
|
|
122
353
|
if (nonce) {
|
|
354
|
+
contextSet(variables, nonceToken, nonce);
|
|
123
355
|
variables.nonce = nonce;
|
|
124
356
|
}
|
|
125
357
|
|
|
126
358
|
// Resolve cache store configuration
|
|
127
359
|
// Priority: options.cache (handler override) > router.cache (router default)
|
|
128
360
|
// Store is enabled only if: config provided, enabled, and no ?__no_cache query param
|
|
129
|
-
let cacheStore
|
|
361
|
+
let cacheStore: SegmentCacheStore | undefined;
|
|
130
362
|
const cacheOption = options.cache ?? router.cache;
|
|
131
363
|
if (cacheOption && !url.searchParams.has("__no_cache")) {
|
|
132
364
|
const cacheConfig =
|
|
133
|
-
typeof cacheOption === "function"
|
|
365
|
+
typeof cacheOption === "function"
|
|
366
|
+
? cacheOption(env, executionCtx)
|
|
367
|
+
: cacheOption;
|
|
134
368
|
|
|
135
369
|
if (cacheConfig.enabled !== false) {
|
|
136
370
|
cacheStore = cacheConfig.store;
|
|
137
371
|
}
|
|
138
372
|
}
|
|
139
373
|
|
|
374
|
+
// Route manifest is populated at startup via the virtual module
|
|
375
|
+
// (virtual:rsc-router/routes-manifest). In build/production, it's inlined
|
|
376
|
+
// into the bundle. In dev mode (Node), the discovery plugin populates it
|
|
377
|
+
// via setManifestReadyPromise(). In dev mode (Cloudflare), Miniflare runs
|
|
378
|
+
// in a separate isolate where module-level state doesn't carry over, so
|
|
379
|
+
// we generate inline from the router's urlpatterns.
|
|
380
|
+
//
|
|
381
|
+
// In multi-router setups (e.g. createHostRouter), each router must have
|
|
382
|
+
// its own per-router manifest. We check per-router data first: even if
|
|
383
|
+
// the global manifest was set by a different router, this router still
|
|
384
|
+
// needs its own trie and manifest for correct matching.
|
|
385
|
+
const manifestCacheStart = performance.now();
|
|
386
|
+
const hasRouterData = getRouterManifest(router.id) !== undefined;
|
|
387
|
+
if (!hasRouterData) {
|
|
388
|
+
if (!hasCachedManifest()) {
|
|
389
|
+
const readyPromise = waitForManifestReady();
|
|
390
|
+
if (readyPromise) {
|
|
391
|
+
await readyPromise;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
if (!getRouterManifest(router.id) && router.urlpatterns) {
|
|
395
|
+
// Cloudflare dev: generate manifest inline for this router.
|
|
396
|
+
// Each router generates its own manifest independently so
|
|
397
|
+
// multi-router setups (host routing) work correctly.
|
|
398
|
+
await buildRouterTrieFromUrlpatterns(router);
|
|
399
|
+
}
|
|
400
|
+
if (!getRouterManifest(router.id) && !hasCachedManifest()) {
|
|
401
|
+
throw new Error(
|
|
402
|
+
'Route manifest not available. Ensure "virtual:rsc-router/routes-manifest" is imported in your entry file.',
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Rebuild the trie when the manifest exists but the per-router trie is
|
|
408
|
+
// missing. This happens in dev mode after HMR: the virtual module sets
|
|
409
|
+
// the manifest (from fresh gen files) but the trie is intentionally not
|
|
410
|
+
// injected to avoid stale discovery-time data. Without the trie, route
|
|
411
|
+
// matching falls back to regex iteration which does not handle wildcard
|
|
412
|
+
// priority correctly (catch-all patterns match before specific routes).
|
|
413
|
+
if (!getRouterTrie(router.id) && router.urlpatterns) {
|
|
414
|
+
await buildRouterTrieFromUrlpatterns(router);
|
|
415
|
+
}
|
|
416
|
+
const manifestCacheDur = performance.now() - manifestCacheStart;
|
|
417
|
+
|
|
140
418
|
// Create unified request context with all methods
|
|
141
419
|
// Includes: stub response, handle store, loader memoization, use(), cookies, headers, cache store
|
|
142
420
|
// params starts empty, populated after route matching via setRequestContextParams
|
|
421
|
+
const ctxCreateStart = performance.now();
|
|
143
422
|
const requestContext = createRequestContext({
|
|
144
423
|
env,
|
|
145
424
|
request,
|
|
146
425
|
url,
|
|
147
426
|
variables,
|
|
148
427
|
cacheStore,
|
|
149
|
-
|
|
428
|
+
cacheProfiles: router.cacheProfiles,
|
|
429
|
+
executionContext: executionCtx,
|
|
150
430
|
themeConfig: router.themeConfig,
|
|
151
431
|
});
|
|
432
|
+
if (earlyMetricsStore) {
|
|
433
|
+
requestContext._debugPerformance = true;
|
|
434
|
+
requestContext._metricsStore = earlyMetricsStore;
|
|
435
|
+
}
|
|
436
|
+
// Wire background error reporting so "use cache" and other subsystems
|
|
437
|
+
// can surface non-fatal errors through the router's onError callback.
|
|
438
|
+
requestContext._reportBackgroundError = (
|
|
439
|
+
error: unknown,
|
|
440
|
+
category: string,
|
|
441
|
+
) => {
|
|
442
|
+
callOnError(error, "cache", {
|
|
443
|
+
request,
|
|
444
|
+
url,
|
|
445
|
+
metadata: { category },
|
|
446
|
+
});
|
|
447
|
+
};
|
|
448
|
+
|
|
449
|
+
const ctxCreateDur = performance.now() - ctxCreateStart;
|
|
450
|
+
|
|
451
|
+
// Accumulate handler-level timing for Server-Timing header
|
|
452
|
+
const handlerTiming = [
|
|
453
|
+
`handler-nonce;dur=${nonceDur.toFixed(2)}`,
|
|
454
|
+
`handler-mw-match;dur=${mwMatchDur.toFixed(2)}`,
|
|
455
|
+
`handler-manifest-cache;dur=${manifestCacheDur.toFixed(2)}`,
|
|
456
|
+
`handler-ctx-create;dur=${ctxCreateDur.toFixed(2)}`,
|
|
457
|
+
];
|
|
458
|
+
|
|
459
|
+
// Store timing data in variables for downstream access
|
|
460
|
+
variables.__handlerTiming = handlerTiming;
|
|
461
|
+
variables.__handlerStart = handlerStart;
|
|
152
462
|
|
|
153
463
|
// Wrap entire request handling in request context
|
|
154
464
|
// Makes context available via getRequestContext() throughout:
|
|
@@ -157,6 +467,9 @@ export function createRSCHandler<
|
|
|
157
467
|
// - Server components during rendering
|
|
158
468
|
// - Error boundaries
|
|
159
469
|
// - Streaming
|
|
470
|
+
// Store basename on request context (scoped per-request via existing ALS)
|
|
471
|
+
requestContext._basename = router.basename;
|
|
472
|
+
|
|
160
473
|
return runWithRequestContext(requestContext, async () => {
|
|
161
474
|
// Core handler logic (wrapped by middleware)
|
|
162
475
|
const coreHandler = async (): Promise<Response> => {
|
|
@@ -164,21 +477,79 @@ export function createRSCHandler<
|
|
|
164
477
|
};
|
|
165
478
|
|
|
166
479
|
// Execute middleware chain if any, otherwise call core handler directly
|
|
480
|
+
let response: Response;
|
|
167
481
|
if (matchedMiddleware.length > 0) {
|
|
168
|
-
|
|
482
|
+
const mwResponse = await executeMiddleware(
|
|
169
483
|
matchedMiddleware,
|
|
170
484
|
request,
|
|
171
485
|
env,
|
|
172
486
|
variables,
|
|
173
487
|
coreHandler,
|
|
488
|
+
createReverseFunction(getRequiredRouteMap()),
|
|
174
489
|
);
|
|
490
|
+
|
|
491
|
+
if (
|
|
492
|
+
url.searchParams.has("_rsc_partial") ||
|
|
493
|
+
url.searchParams.has("_rsc_action")
|
|
494
|
+
) {
|
|
495
|
+
const intercepted = interceptRedirectForPartial(
|
|
496
|
+
mwResponse,
|
|
497
|
+
createRedirectFlightResponse,
|
|
498
|
+
);
|
|
499
|
+
response = intercepted ?? finalizeResponse(mwResponse);
|
|
500
|
+
} else {
|
|
501
|
+
response = finalizeResponse(mwResponse);
|
|
502
|
+
}
|
|
503
|
+
} else {
|
|
504
|
+
response = await coreHandler();
|
|
175
505
|
}
|
|
176
506
|
|
|
177
|
-
|
|
507
|
+
// Finalize metrics after all middleware (including post-next work)
|
|
508
|
+
// has completed so :post spans are captured in the timeline.
|
|
509
|
+
// Handler timing parts are always emitted (even without debug metrics)
|
|
510
|
+
// so non-debug requests still get bootstrap Server-Timing entries.
|
|
511
|
+
const handlerTimingArr: string[] = variables.__handlerTiming || [];
|
|
512
|
+
// Preserve any existing Server-Timing set by response routes or middleware
|
|
513
|
+
const existingTiming = response.headers.get("Server-Timing");
|
|
514
|
+
const timingParts = existingTiming
|
|
515
|
+
? [existingTiming, ...handlerTimingArr]
|
|
516
|
+
: [...handlerTimingArr];
|
|
517
|
+
|
|
518
|
+
const metricsStore = requestContext._metricsStore;
|
|
519
|
+
if (metricsStore) {
|
|
520
|
+
// When the store was created at handler start (earlyMetricsStore),
|
|
521
|
+
// handler:total covers the full request. When ctx.debugPerformance()
|
|
522
|
+
// created the store mid-request, use its requestStart to avoid a
|
|
523
|
+
// negative startTime offset.
|
|
524
|
+
const totalStart = earlyMetricsStore
|
|
525
|
+
? handlerStart
|
|
526
|
+
: metricsStore.requestStart;
|
|
527
|
+
appendMetric(
|
|
528
|
+
metricsStore,
|
|
529
|
+
"handler:total",
|
|
530
|
+
totalStart,
|
|
531
|
+
performance.now() - totalStart,
|
|
532
|
+
);
|
|
533
|
+
const metricsTiming = buildMetricsTiming(
|
|
534
|
+
request.method,
|
|
535
|
+
url.pathname,
|
|
536
|
+
metricsStore,
|
|
537
|
+
);
|
|
538
|
+
if (metricsTiming) timingParts.push(metricsTiming);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
const fullTiming = timingParts.join(", ");
|
|
542
|
+
if (fullTiming && !isWebSocketUpgradeResponse(response)) {
|
|
543
|
+
response.headers.set("Server-Timing", fullTiming);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
return response;
|
|
178
547
|
});
|
|
179
548
|
};
|
|
180
549
|
|
|
181
|
-
// Core request handling logic (separated for middleware wrapping)
|
|
550
|
+
// Core request handling logic (separated for middleware wrapping).
|
|
551
|
+
// Uses the classify → execute model: classifyRequest produces a RequestPlan,
|
|
552
|
+
// then execution dispatches on the plan mode.
|
|
182
553
|
async function coreRequestHandler(
|
|
183
554
|
request: Request,
|
|
184
555
|
env: TEnv,
|
|
@@ -186,875 +557,592 @@ export function createRSCHandler<
|
|
|
186
557
|
variables: Record<string, any>,
|
|
187
558
|
nonce: string | undefined,
|
|
188
559
|
): Promise<Response> {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
560
|
+
const handlerTiming: string[] = variables.__handlerTiming || [];
|
|
561
|
+
|
|
562
|
+
// Debug manifest endpoint: handled before classification since it
|
|
563
|
+
// doesn't need a route match and needs trie access from the closure.
|
|
564
|
+
const isDev = process.env.NODE_ENV !== "production";
|
|
565
|
+
if (
|
|
566
|
+
url.searchParams.has("__debug_manifest") &&
|
|
567
|
+
(isDev || router.allowDebugManifest)
|
|
568
|
+
) {
|
|
569
|
+
const trie = getRouterTrie(router.id) ?? getRouteTrie();
|
|
570
|
+
const routeManifest = getRequiredRouteMap();
|
|
571
|
+
const { extractAncestryFromTrie } =
|
|
572
|
+
await import("../build/route-trie.js");
|
|
573
|
+
return new Response(
|
|
574
|
+
JSON.stringify(
|
|
575
|
+
{
|
|
576
|
+
routerId: router.id,
|
|
577
|
+
routeManifest,
|
|
578
|
+
routeAncestry: trie ? extractAncestryFromTrie(trie) : {},
|
|
579
|
+
routeTrie: trie,
|
|
580
|
+
precomputedEntries: getPrecomputedEntries(),
|
|
581
|
+
},
|
|
582
|
+
null,
|
|
583
|
+
2,
|
|
584
|
+
),
|
|
585
|
+
{
|
|
586
|
+
headers: { "Content-Type": "application/json" },
|
|
200
587
|
},
|
|
201
|
-
params: mw.params,
|
|
202
|
-
}));
|
|
203
|
-
|
|
204
|
-
// Execute route middleware wrapping the actual request handling
|
|
205
|
-
return executeMiddleware(middlewareEntries, request, env, variables, () =>
|
|
206
|
-
coreRequestHandlerInner(request, env, url, variables, nonce),
|
|
207
588
|
);
|
|
208
589
|
}
|
|
209
590
|
|
|
210
|
-
//
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
591
|
+
// ---- 1. Classify ----
|
|
592
|
+
// classifyRequest may throw RouteNotFoundError for unknown routes.
|
|
593
|
+
// In that case, fall through to a full-render plan so the pipeline
|
|
594
|
+
// can render the 404 page via the existing error handling path.
|
|
595
|
+
const classifyStart = performance.now();
|
|
596
|
+
let plan: RequestPlan<TEnv>;
|
|
597
|
+
try {
|
|
598
|
+
plan = await classifyRequest<TEnv>(request, url, {
|
|
599
|
+
findMatch: router.findMatch,
|
|
600
|
+
routerVersion: version,
|
|
601
|
+
routerId: router.id,
|
|
602
|
+
});
|
|
603
|
+
} catch (error) {
|
|
604
|
+
if (isRouteNotFoundError(error)) {
|
|
605
|
+
// Let the render path handle 404 — match()/matchPartial() will
|
|
606
|
+
// re-throw RouteNotFoundError and the catch block in
|
|
607
|
+
// executeRenderWithMiddleware renders the not-found page.
|
|
608
|
+
plan = {
|
|
609
|
+
mode: "full-render",
|
|
610
|
+
route: {
|
|
611
|
+
matched: null as any,
|
|
612
|
+
manifestEntry: null as any,
|
|
613
|
+
entries: [],
|
|
614
|
+
routeKey: "",
|
|
615
|
+
localRouteName: "",
|
|
616
|
+
params: {},
|
|
617
|
+
routeMiddleware: [],
|
|
618
|
+
cacheScope: null,
|
|
619
|
+
isPassthrough: false,
|
|
620
|
+
},
|
|
621
|
+
negotiated: false,
|
|
622
|
+
};
|
|
623
|
+
} else {
|
|
624
|
+
throw error;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
const classifyDur = performance.now() - classifyStart;
|
|
628
|
+
handlerTiming.push(`handler-classify;dur=${classifyDur.toFixed(2)}`);
|
|
629
|
+
|
|
630
|
+
// ---- 2. Terminal plans (no execution needed) ----
|
|
631
|
+
if (plan.mode === "redirect") {
|
|
632
|
+
// Redirects are handled by the pipeline (match/matchPartial),
|
|
633
|
+
// but for partial requests we short-circuit with a Flight redirect.
|
|
634
|
+
if (url.searchParams.has("_rsc_partial")) {
|
|
635
|
+
return createRedirectFlightResponse(plan.redirectUrl);
|
|
636
|
+
}
|
|
637
|
+
// Full requests: let the pipeline handle the redirect via match()
|
|
638
|
+
// which returns { redirect: url }. Fall through to full-render.
|
|
225
639
|
}
|
|
226
640
|
|
|
227
|
-
|
|
228
|
-
const isAction =
|
|
229
|
-
request.headers.has("rsc-action") || url.searchParams.has("_rsc_action");
|
|
230
|
-
const actionId =
|
|
231
|
-
request.headers.get("rsc-action") || url.searchParams.get("_rsc_action");
|
|
232
|
-
|
|
233
|
-
// Version mismatch detection - client may have stale code after HMR/deployment
|
|
234
|
-
// If versions don't match, tell the client to reload
|
|
235
|
-
const clientVersion = url.searchParams.get("_rsc_v");
|
|
236
|
-
if (version && clientVersion && clientVersion !== version) {
|
|
641
|
+
if (plan.mode === "version-mismatch") {
|
|
237
642
|
console.log(
|
|
238
|
-
`[RSC] Version mismatch: client=${
|
|
643
|
+
`[RSC] Version mismatch: client=${url.searchParams.get("_rsc_v")}, server=${version}. Forcing reload.`,
|
|
239
644
|
);
|
|
240
|
-
|
|
241
|
-
// Clean URL by removing RSC params
|
|
242
|
-
const cleanUrl = new URL(url);
|
|
243
|
-
cleanUrl.searchParams.delete("_rsc_partial");
|
|
244
|
-
cleanUrl.searchParams.delete("_rsc_segments");
|
|
245
|
-
cleanUrl.searchParams.delete("_rsc_v");
|
|
246
|
-
cleanUrl.searchParams.delete("_rsc_stale");
|
|
247
|
-
cleanUrl.searchParams.delete("_rsc_action");
|
|
248
|
-
cleanUrl.searchParams.delete("_rsc_prev");
|
|
249
|
-
|
|
250
|
-
// For actions, reload current page (referer)
|
|
251
|
-
// For navigation, load the target URL
|
|
252
|
-
const reloadUrl = isAction
|
|
253
|
-
? request.headers.get("referer") || cleanUrl.toString()
|
|
254
|
-
: cleanUrl.toString();
|
|
255
|
-
|
|
256
|
-
// Return special response that tells client to reload
|
|
257
645
|
return createResponseWithMergedHeaders(null, {
|
|
258
646
|
status: 200,
|
|
259
647
|
headers: {
|
|
260
|
-
"X-RSC-Reload": reloadUrl,
|
|
648
|
+
"X-RSC-Reload": plan.reloadUrl,
|
|
261
649
|
"content-type": "text/x-component;charset=utf-8",
|
|
262
650
|
},
|
|
263
651
|
});
|
|
264
652
|
}
|
|
265
653
|
|
|
266
|
-
//
|
|
267
|
-
const
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
// ============================================================================
|
|
271
|
-
// PROGRESSIVE ENHANCEMENT: No-JS Form Submissions
|
|
272
|
-
// ============================================================================
|
|
273
|
-
const progressiveResult = await handleProgressiveEnhancement(
|
|
654
|
+
// ---- 3. Origin guard (gate for action/loader/PE modes) ----
|
|
655
|
+
const originPhase = ORIGIN_CHECK_PHASE_BY_MODE[plan.mode];
|
|
656
|
+
if (originPhase) {
|
|
657
|
+
const originResult = await checkRequestOrigin(
|
|
274
658
|
request,
|
|
275
|
-
env,
|
|
276
659
|
url,
|
|
277
|
-
|
|
278
|
-
handleStore,
|
|
279
|
-
nonce,
|
|
280
|
-
);
|
|
281
|
-
if (progressiveResult) {
|
|
282
|
-
return progressiveResult;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// ============================================================================
|
|
286
|
-
// SERVER ACTION EXECUTION (JavaScript-enabled client)
|
|
287
|
-
// ============================================================================
|
|
288
|
-
if (isAction && actionId) {
|
|
289
|
-
return handleServerAction(request, env, url, actionId, handleStore);
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
// ============================================================================
|
|
293
|
-
// LOADER FETCH EXECUTION (data fetching with RSC serialization)
|
|
294
|
-
// ============================================================================
|
|
295
|
-
const isLoaderRequest = url.searchParams.has("_rsc_loader");
|
|
296
|
-
if (isLoaderRequest) {
|
|
297
|
-
return handleLoaderFetch(request, env, url, variables);
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
// ============================================================================
|
|
301
|
-
// REGULAR RSC RENDERING (Navigation)
|
|
302
|
-
// ============================================================================
|
|
303
|
-
// Note: Must use "return await" for try/catch to catch async rejections
|
|
304
|
-
return await handleRscRendering(
|
|
305
|
-
request,
|
|
660
|
+
router.originCheck,
|
|
306
661
|
env,
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
handleStore,
|
|
310
|
-
nonce,
|
|
662
|
+
router.id,
|
|
663
|
+
originPhase,
|
|
311
664
|
);
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
665
|
+
if (originResult) {
|
|
666
|
+
const originError = new Error(
|
|
667
|
+
`Origin check rejected: ${request.headers.get("origin") ?? "none"} vs ${request.headers.get("host") ?? "none"}`,
|
|
668
|
+
);
|
|
669
|
+
originError.name = "OriginCheckError";
|
|
317
670
|
|
|
318
|
-
|
|
319
|
-
// Check both instanceof and error.name for cross-bundle compatibility
|
|
320
|
-
const isRouteNotFound =
|
|
321
|
-
error instanceof RouteNotFoundError ||
|
|
322
|
-
(error instanceof Error && error.name === "RouteNotFoundError");
|
|
323
|
-
if (isRouteNotFound) {
|
|
324
|
-
callOnError(error, "routing", {
|
|
671
|
+
callOnError(originError, "origin", {
|
|
325
672
|
request,
|
|
326
673
|
url,
|
|
327
674
|
env,
|
|
328
|
-
handledByBoundary:
|
|
329
|
-
});
|
|
330
|
-
|
|
331
|
-
// Get notFound component from router options or use default
|
|
332
|
-
const notFoundOption = router.notFound;
|
|
333
|
-
const notFoundComponent =
|
|
334
|
-
typeof notFoundOption === "function"
|
|
335
|
-
? notFoundOption({ pathname: url.pathname })
|
|
336
|
-
: (notFoundOption ?? createElement("h1", null, "Not Found"));
|
|
337
|
-
|
|
338
|
-
// Create a simple segment for the 404 page
|
|
339
|
-
const notFoundSegment = {
|
|
340
|
-
id: "notFound",
|
|
341
|
-
namespace: "notFound",
|
|
342
|
-
type: "route" as const,
|
|
343
|
-
index: 0,
|
|
344
|
-
component: notFoundComponent,
|
|
345
|
-
params: {},
|
|
346
|
-
};
|
|
347
|
-
|
|
348
|
-
// Render with rootLayout to maintain app shell
|
|
349
|
-
const root = await renderSegments([notFoundSegment], {
|
|
350
|
-
rootLayout: router.rootLayout,
|
|
351
|
-
routeMap,
|
|
352
|
-
// No routeName for not-found routes
|
|
353
|
-
});
|
|
354
|
-
|
|
355
|
-
const payload: RscPayload = {
|
|
356
|
-
root,
|
|
675
|
+
handledByBoundary: false,
|
|
357
676
|
metadata: {
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
diff: [],
|
|
362
|
-
isPartial: false,
|
|
363
|
-
handles: handleStore.stream(),
|
|
364
|
-
version,
|
|
365
|
-
themeConfig: router.themeConfig,
|
|
366
|
-
initialTheme: requireRequestContext().theme,
|
|
367
|
-
routeMap,
|
|
368
|
-
// No routeName for not-found routes
|
|
677
|
+
phase: originPhase,
|
|
678
|
+
origin: request.headers.get("origin"),
|
|
679
|
+
host: request.headers.get("host"),
|
|
369
680
|
},
|
|
370
|
-
};
|
|
371
|
-
|
|
372
|
-
const rscStream = renderToReadableStream(payload);
|
|
373
|
-
|
|
374
|
-
// Determine if this is an RSC request or HTML request
|
|
375
|
-
const isRscRequest =
|
|
376
|
-
(!request.headers.get("accept")?.includes("text/html") &&
|
|
377
|
-
!url.searchParams.has("__html")) ||
|
|
378
|
-
url.searchParams.has("__rsc");
|
|
681
|
+
});
|
|
379
682
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
683
|
+
try {
|
|
684
|
+
const routerCtx = getRouterContext();
|
|
685
|
+
if (routerCtx?.telemetry) {
|
|
686
|
+
safeEmit(resolveSink(routerCtx.telemetry), {
|
|
687
|
+
type: "request.origin-rejected" as const,
|
|
688
|
+
timestamp: performance.now(),
|
|
689
|
+
requestId: routerCtx.requestId,
|
|
690
|
+
method: request.method,
|
|
691
|
+
pathname: url.pathname,
|
|
692
|
+
phase: originPhase,
|
|
693
|
+
origin: request.headers.get("origin"),
|
|
694
|
+
host: request.headers.get("host"),
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
} catch {
|
|
698
|
+
// Router context may not be available
|
|
385
699
|
}
|
|
386
700
|
|
|
387
|
-
|
|
388
|
-
const ssrModule = await loadSSRModule();
|
|
389
|
-
const htmlStream = await ssrModule.renderHTML(rscStream, { nonce });
|
|
390
|
-
|
|
391
|
-
return createResponseWithMergedHeaders(htmlStream, {
|
|
392
|
-
status: 404,
|
|
393
|
-
headers: { "content-type": "text/html;charset=utf-8" },
|
|
394
|
-
});
|
|
701
|
+
return originResult;
|
|
395
702
|
}
|
|
396
|
-
|
|
397
|
-
// Report unhandled errors
|
|
398
|
-
callOnError(error, "routing", {
|
|
399
|
-
request,
|
|
400
|
-
url,
|
|
401
|
-
env,
|
|
402
|
-
handledByBoundary: false,
|
|
403
|
-
});
|
|
404
|
-
console.error(`[RSC] Error:`, error);
|
|
405
|
-
throw error;
|
|
406
703
|
}
|
|
704
|
+
|
|
705
|
+
// ---- 4. Execute ----
|
|
706
|
+
return executeRequest(
|
|
707
|
+
plan as ExecutableRequestPlan<TEnv>,
|
|
708
|
+
request,
|
|
709
|
+
env,
|
|
710
|
+
url,
|
|
711
|
+
variables,
|
|
712
|
+
nonce,
|
|
713
|
+
);
|
|
407
714
|
}
|
|
408
715
|
|
|
409
|
-
//
|
|
410
|
-
//
|
|
411
|
-
//
|
|
412
|
-
//
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
async function handleProgressiveEnhancement(
|
|
716
|
+
// Execute a classified request plan. Dispatches to the appropriate handler
|
|
717
|
+
// based on plan.mode. Lives in the createRSCHandler closure for access to
|
|
718
|
+
// handlerCtx, router, callOnError, etc.
|
|
719
|
+
// Only receives executable plans (version-mismatch is handled above).
|
|
720
|
+
async function executeRequest(
|
|
721
|
+
plan: ExecutableRequestPlan<TEnv>,
|
|
416
722
|
request: Request,
|
|
417
723
|
env: TEnv,
|
|
418
724
|
url: URL,
|
|
419
|
-
|
|
420
|
-
handleStore: ReturnType<typeof requireRequestContext>["_handleStore"],
|
|
725
|
+
variables: Record<string, any>,
|
|
421
726
|
nonce: string | undefined,
|
|
422
|
-
): Promise<Response
|
|
423
|
-
|
|
424
|
-
const
|
|
425
|
-
contentType.includes("multipart/form-data") ||
|
|
426
|
-
contentType.includes("application/x-www-form-urlencoded");
|
|
427
|
-
|
|
428
|
-
if (request.method !== "POST" || isAction || !isFormSubmission) {
|
|
429
|
-
return null;
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
// Clone the request to read FormData without consuming it
|
|
433
|
-
const formData = await request.clone().formData();
|
|
434
|
-
|
|
435
|
-
// Look for React's progressive enhancement hidden fields
|
|
436
|
-
let isDirectAction = false;
|
|
437
|
-
let isUseActionState = false;
|
|
438
|
-
let directActionId: string | null = null;
|
|
727
|
+
): Promise<Response> {
|
|
728
|
+
// Common setup
|
|
729
|
+
const handleStore = requireRequestContext()._handleStore;
|
|
439
730
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
731
|
+
// Wire up error reporting for late streaming-handle failures
|
|
732
|
+
handleStore.onError = (error: Error) => {
|
|
733
|
+
const reqCtx = requireRequestContext();
|
|
734
|
+
callOnError(error, "handler", {
|
|
735
|
+
request,
|
|
736
|
+
url,
|
|
737
|
+
routeKey: reqCtx._routeName,
|
|
738
|
+
params: reqCtx.params as Record<string, string>,
|
|
739
|
+
handledByBoundary: true,
|
|
740
|
+
});
|
|
741
|
+
try {
|
|
742
|
+
const routerCtx = getRouterContext();
|
|
743
|
+
if (routerCtx?.telemetry) {
|
|
744
|
+
safeEmit(resolveSink(routerCtx.telemetry), {
|
|
745
|
+
type: "handler.error" as const,
|
|
746
|
+
timestamp: performance.now(),
|
|
747
|
+
requestId: routerCtx.requestId,
|
|
748
|
+
error,
|
|
749
|
+
handledByBoundary: true,
|
|
750
|
+
pathname: url.pathname,
|
|
751
|
+
routeKey: reqCtx._routeName,
|
|
752
|
+
params: reqCtx.params as Record<string, string>,
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
} catch {
|
|
756
|
+
// Router context may not be available (e.g. prerender path)
|
|
446
757
|
}
|
|
447
|
-
}
|
|
758
|
+
};
|
|
448
759
|
|
|
449
|
-
|
|
450
|
-
|
|
760
|
+
// Set route params early so all execution paths can access ctx.params.
|
|
761
|
+
// Also store the classified snapshot so match/matchPartial can reuse it
|
|
762
|
+
// instead of calling resolveRoute again.
|
|
763
|
+
if (plan.mode !== "redirect") {
|
|
764
|
+
setRequestContextParams(plan.route.params, plan.route.routeKey);
|
|
765
|
+
requireRequestContext()._classifiedRoute = plan.route;
|
|
451
766
|
}
|
|
452
767
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
768
|
+
const routeReverse = createReverseFunction(getRequiredRouteMap());
|
|
769
|
+
|
|
770
|
+
// ---- Response route: skip entire RSC pipeline ----
|
|
771
|
+
if (plan.mode === "response") {
|
|
772
|
+
// Build ResponseRouteMatch from plan fields. handleResponseRoute
|
|
773
|
+
// expects a flat object with params at the top level.
|
|
774
|
+
const responseMatch: ResponseRouteMatch = {
|
|
775
|
+
responseType: plan.responseType,
|
|
776
|
+
handler: plan.handler,
|
|
777
|
+
params: plan.route.params,
|
|
778
|
+
negotiated: plan.negotiated,
|
|
779
|
+
manifestEntry: plan.manifestEntry,
|
|
780
|
+
routeMiddleware: plan.routeMiddleware,
|
|
781
|
+
};
|
|
782
|
+
const responseOutcome = await withTimeout(
|
|
783
|
+
handleResponseRoute(
|
|
784
|
+
handlerCtx,
|
|
785
|
+
responseMatch,
|
|
463
786
|
request,
|
|
464
|
-
url,
|
|
465
787
|
env,
|
|
466
|
-
handledByBoundary: false,
|
|
467
|
-
});
|
|
468
|
-
console.error("[RSC] Progressive enhancement action error:", error);
|
|
469
|
-
}
|
|
470
|
-
} else if (isDirectAction && directActionId) {
|
|
471
|
-
const temporaryReferences = createTemporaryReferenceSet();
|
|
472
|
-
|
|
473
|
-
let args: unknown[] = [];
|
|
474
|
-
try {
|
|
475
|
-
args = await decodeReply(formData, { temporaryReferences });
|
|
476
|
-
} catch {
|
|
477
|
-
args = [formData];
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
try {
|
|
481
|
-
const loadedAction = await loadServerAction(directActionId);
|
|
482
|
-
actionResult = await loadedAction.apply(null, args);
|
|
483
|
-
} catch (error) {
|
|
484
|
-
callOnError(error, "action", {
|
|
485
|
-
request,
|
|
486
788
|
url,
|
|
789
|
+
variables,
|
|
790
|
+
),
|
|
791
|
+
router.timeouts.renderStartMs,
|
|
792
|
+
"render-start",
|
|
793
|
+
);
|
|
794
|
+
if (responseOutcome.timedOut) {
|
|
795
|
+
return handleTimeoutResponse(
|
|
796
|
+
request,
|
|
487
797
|
env,
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
798
|
+
url,
|
|
799
|
+
"render-start",
|
|
800
|
+
responseOutcome.durationMs,
|
|
801
|
+
plan.route.routeKey,
|
|
802
|
+
);
|
|
492
803
|
}
|
|
804
|
+
const response = responseOutcome.result;
|
|
805
|
+
if (plan.negotiated && !isWebSocketUpgradeResponse(response)) {
|
|
806
|
+
response.headers.append("Vary", "Accept");
|
|
807
|
+
}
|
|
808
|
+
return response;
|
|
493
809
|
}
|
|
494
810
|
|
|
495
|
-
//
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
811
|
+
// SSR setup: kick off in parallel for modes that need HTML rendering.
|
|
812
|
+
// Placed after response-route short-circuit so response/mime routes
|
|
813
|
+
// never pay for SSR work.
|
|
814
|
+
if (plan.mode !== "loader" && mayNeedSSR(request, url)) {
|
|
815
|
+
variables[SSR_SETUP_VAR] = startSSRSetup(
|
|
816
|
+
handlerCtx,
|
|
500
817
|
request,
|
|
501
|
-
url,
|
|
502
818
|
env,
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
// Re-render the page and return HTML
|
|
509
|
-
const renderRequest = new Request(url.toString(), {
|
|
510
|
-
method: "GET",
|
|
511
|
-
headers: new Headers({ accept: "text/html" }),
|
|
512
|
-
});
|
|
513
|
-
|
|
514
|
-
const match = await router.match(renderRequest, env);
|
|
515
|
-
|
|
516
|
-
if (match.redirect) {
|
|
517
|
-
return new Response(null, {
|
|
518
|
-
status: 308,
|
|
519
|
-
headers: { Location: match.redirect },
|
|
520
|
-
});
|
|
819
|
+
url,
|
|
820
|
+
router.debugPerformance
|
|
821
|
+
? () => requireRequestContext()._metricsStore
|
|
822
|
+
: undefined,
|
|
823
|
+
);
|
|
521
824
|
}
|
|
522
825
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
});
|
|
528
|
-
|
|
529
|
-
const payload: RscPayload = {
|
|
530
|
-
root,
|
|
531
|
-
metadata: {
|
|
532
|
-
pathname: url.pathname,
|
|
533
|
-
segments: match.segments,
|
|
534
|
-
matched: match.matched,
|
|
535
|
-
diff: match.diff,
|
|
536
|
-
isPartial: false,
|
|
537
|
-
rootLayout: router.rootLayout,
|
|
538
|
-
handles: handleStore.stream(),
|
|
539
|
-
version,
|
|
540
|
-
themeConfig: router.themeConfig,
|
|
541
|
-
initialTheme: requireRequestContext().theme,
|
|
542
|
-
routeMap,
|
|
543
|
-
routeName: match.routeName,
|
|
544
|
-
},
|
|
545
|
-
formState: actionResult,
|
|
546
|
-
};
|
|
547
|
-
|
|
548
|
-
const rscStream = renderToReadableStream<RscPayload>(payload);
|
|
549
|
-
const ssrModule = await loadSSRModule();
|
|
550
|
-
const htmlStream = await ssrModule.renderHTML(rscStream, {
|
|
551
|
-
formState: reactFormState,
|
|
552
|
-
nonce,
|
|
553
|
-
});
|
|
554
|
-
|
|
555
|
-
return new Response(htmlStream, {
|
|
556
|
-
headers: { "content-type": "text/html;charset=utf-8" },
|
|
557
|
-
});
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
// ============================================================================
|
|
561
|
-
// SERVER ACTION HANDLER
|
|
562
|
-
// ============================================================================
|
|
563
|
-
async function handleServerAction(
|
|
564
|
-
request: Request,
|
|
565
|
-
env: TEnv,
|
|
566
|
-
url: URL,
|
|
567
|
-
actionId: string,
|
|
568
|
-
handleStore: ReturnType<typeof requireRequestContext>["_handleStore"],
|
|
569
|
-
): Promise<Response> {
|
|
570
|
-
const temporaryReferences = createTemporaryReferenceSet();
|
|
571
|
-
|
|
572
|
-
// Decode action arguments from request body
|
|
573
|
-
const contentType = request.headers.get("content-type") || "";
|
|
574
|
-
let args: unknown[] = [];
|
|
575
|
-
let actionFormData: FormData | undefined;
|
|
576
|
-
|
|
577
|
-
try {
|
|
578
|
-
const body = contentType.includes("multipart/form-data")
|
|
579
|
-
? await request.formData()
|
|
580
|
-
: await request.text();
|
|
581
|
-
|
|
582
|
-
if (body instanceof FormData) {
|
|
583
|
-
actionFormData = body;
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
if (hasBodyContent(body)) {
|
|
587
|
-
args = await decodeReply(body, { temporaryReferences });
|
|
588
|
-
}
|
|
589
|
-
} catch (error) {
|
|
590
|
-
callOnError(error, "action", {
|
|
826
|
+
// ---- Loader fetch ----
|
|
827
|
+
if (plan.mode === "loader") {
|
|
828
|
+
return handleLoaderFetch(
|
|
829
|
+
handlerCtx,
|
|
591
830
|
request,
|
|
592
|
-
url,
|
|
593
831
|
env,
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
cause: error,
|
|
599
|
-
});
|
|
832
|
+
url,
|
|
833
|
+
variables,
|
|
834
|
+
plan.route.params,
|
|
835
|
+
);
|
|
600
836
|
}
|
|
601
837
|
|
|
602
|
-
//
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
try {
|
|
608
|
-
loadedAction = await loadServerAction(actionId);
|
|
609
|
-
const data = await loadedAction!.apply(null, args);
|
|
610
|
-
returnValue = { ok: true, data };
|
|
611
|
-
} catch (error) {
|
|
612
|
-
returnValue = { ok: false, data: error };
|
|
613
|
-
actionStatus = 500;
|
|
614
|
-
|
|
615
|
-
// Try to render error boundary
|
|
616
|
-
const errorResult = await router.matchError(request, env, error, "route");
|
|
617
|
-
|
|
618
|
-
// Report the action error (handledByBoundary indicates if error boundary will render)
|
|
619
|
-
callOnError(error, "action", {
|
|
838
|
+
// ---- Progressive enhancement ----
|
|
839
|
+
if (plan.mode === "pe-render") {
|
|
840
|
+
const peResult = await handleProgressiveEnhancement(
|
|
841
|
+
handlerCtx,
|
|
620
842
|
request,
|
|
621
|
-
url,
|
|
622
843
|
env,
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
isPartial: true,
|
|
636
|
-
matched: errorResult.matched,
|
|
637
|
-
diff: errorResult.diff,
|
|
638
|
-
isError: true,
|
|
639
|
-
handles: handleStore.stream(),
|
|
640
|
-
version,
|
|
641
|
-
routeMap,
|
|
642
|
-
routeName: errorResult.routeName,
|
|
643
|
-
},
|
|
644
|
-
returnValue,
|
|
645
|
-
};
|
|
646
|
-
|
|
647
|
-
const rscStream = renderToReadableStream<RscPayload>(payload, {
|
|
648
|
-
temporaryReferences,
|
|
649
|
-
});
|
|
650
|
-
|
|
651
|
-
return createResponseWithMergedHeaders(rscStream, {
|
|
652
|
-
status: actionStatus,
|
|
653
|
-
headers: { "content-type": "text/x-component;charset=utf-8" },
|
|
654
|
-
});
|
|
655
|
-
}
|
|
844
|
+
url,
|
|
845
|
+
false, // isAction = false for PE
|
|
846
|
+
handleStore,
|
|
847
|
+
nonce,
|
|
848
|
+
{
|
|
849
|
+
routeMiddleware: plan.route.routeMiddleware,
|
|
850
|
+
variables,
|
|
851
|
+
routeReverse,
|
|
852
|
+
},
|
|
853
|
+
);
|
|
854
|
+
if (peResult) return peResult;
|
|
855
|
+
// PE handler returned null (not a PE form) — fall through to render
|
|
656
856
|
}
|
|
657
857
|
|
|
658
|
-
//
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
858
|
+
// ---- Action: execute action, then revalidate wrapped in route middleware ----
|
|
859
|
+
if (plan.mode === "action") {
|
|
860
|
+
let actionContinuation: ActionContinuation | undefined;
|
|
861
|
+
try {
|
|
862
|
+
const actionOutcome = await withTimeout(
|
|
863
|
+
executeServerAction(
|
|
864
|
+
handlerCtx,
|
|
865
|
+
request,
|
|
866
|
+
env,
|
|
867
|
+
url,
|
|
868
|
+
plan.actionId,
|
|
869
|
+
handleStore,
|
|
870
|
+
),
|
|
871
|
+
router.timeouts.actionMs,
|
|
872
|
+
"action",
|
|
873
|
+
);
|
|
874
|
+
if (actionOutcome.timedOut) {
|
|
875
|
+
return handleTimeoutResponse(
|
|
876
|
+
request,
|
|
877
|
+
env,
|
|
878
|
+
url,
|
|
879
|
+
"action",
|
|
880
|
+
actionOutcome.durationMs,
|
|
881
|
+
plan.route.routeKey,
|
|
882
|
+
plan.actionId,
|
|
883
|
+
);
|
|
884
|
+
}
|
|
885
|
+
const result = actionOutcome.result;
|
|
886
|
+
// Response means redirect or error boundary — done.
|
|
887
|
+
if (result instanceof Response) return result;
|
|
888
|
+
actionContinuation = result;
|
|
889
|
+
} catch (error) {
|
|
890
|
+
callOnError(error, "action", {
|
|
891
|
+
request,
|
|
892
|
+
url,
|
|
893
|
+
env,
|
|
894
|
+
actionId: plan.actionId,
|
|
895
|
+
handledByBoundary: false,
|
|
681
896
|
});
|
|
897
|
+
console.error(`[RSC] Action error:`, error);
|
|
898
|
+
throw error;
|
|
682
899
|
}
|
|
683
900
|
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
handles: handleStore.stream(),
|
|
704
|
-
version,
|
|
705
|
-
routeMap,
|
|
706
|
-
routeName: fullMatch.routeName,
|
|
707
|
-
},
|
|
708
|
-
returnValue,
|
|
709
|
-
};
|
|
710
|
-
|
|
711
|
-
const rscStream = renderToReadableStream<RscPayload>(payload, {
|
|
712
|
-
temporaryReferences,
|
|
713
|
-
});
|
|
714
|
-
|
|
715
|
-
const headers: Record<string, string> = {
|
|
716
|
-
"content-type": "text/x-component;charset=utf-8",
|
|
717
|
-
};
|
|
718
|
-
if (serverTiming) {
|
|
719
|
-
headers["Server-Timing"] = serverTiming;
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
return createResponseWithMergedHeaders(rscStream, {
|
|
723
|
-
status: actionStatus,
|
|
724
|
-
headers,
|
|
725
|
-
});
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
// Return updated segments
|
|
729
|
-
setRequestContextParams(matchResult.params);
|
|
730
|
-
|
|
731
|
-
const renderStart = performance.now();
|
|
732
|
-
renderSegments(matchResult.segments, {
|
|
733
|
-
rootLayout: router.rootLayout,
|
|
734
|
-
isAction: true,
|
|
735
|
-
routeMap,
|
|
736
|
-
routeName: matchResult.routeName,
|
|
737
|
-
});
|
|
738
|
-
const renderDuration = performance.now() - renderStart;
|
|
739
|
-
const serverTiming = matchResult.serverTiming
|
|
740
|
-
? `${matchResult.serverTiming}, rendering;dur=${renderDuration.toFixed(2)}`
|
|
741
|
-
: `rendering;dur=${renderDuration.toFixed(2)}`;
|
|
742
|
-
|
|
743
|
-
const payload: RscPayload = {
|
|
744
|
-
root: null,
|
|
745
|
-
metadata: {
|
|
746
|
-
pathname: url.pathname,
|
|
747
|
-
segments: matchResult.segments,
|
|
748
|
-
isPartial: true,
|
|
749
|
-
matched: matchResult.matched,
|
|
750
|
-
diff: matchResult.diff,
|
|
751
|
-
slots: matchResult.slots,
|
|
752
|
-
handles: handleStore.stream(),
|
|
753
|
-
version,
|
|
754
|
-
routeMap,
|
|
755
|
-
routeName: matchResult.routeName,
|
|
756
|
-
},
|
|
757
|
-
returnValue,
|
|
758
|
-
};
|
|
759
|
-
|
|
760
|
-
const rscStream = renderToReadableStream<RscPayload>(payload, {
|
|
761
|
-
temporaryReferences,
|
|
762
|
-
});
|
|
763
|
-
|
|
764
|
-
const actionHeaders: Record<string, string> = {
|
|
765
|
-
"content-type": "text/x-component;charset=utf-8",
|
|
766
|
-
};
|
|
767
|
-
if (serverTiming) {
|
|
768
|
-
actionHeaders["Server-Timing"] = serverTiming;
|
|
901
|
+
// Revalidation render wrapped in route middleware.
|
|
902
|
+
// Actions from client-side navigation include _rsc_partial — preserve
|
|
903
|
+
// the partial flag so the revalidation returns a Flight stream, not HTML.
|
|
904
|
+
// App-switch is already excluded by classifyRequest (would be full-render).
|
|
905
|
+
const isPartialAction = url.searchParams.has("_rsc_partial");
|
|
906
|
+
return executeRenderWithMiddleware(
|
|
907
|
+
plan.route.routeMiddleware,
|
|
908
|
+
plan.negotiated,
|
|
909
|
+
plan.route.routeKey,
|
|
910
|
+
routeReverse,
|
|
911
|
+
request,
|
|
912
|
+
env,
|
|
913
|
+
url,
|
|
914
|
+
variables,
|
|
915
|
+
nonce,
|
|
916
|
+
handleStore,
|
|
917
|
+
isPartialAction,
|
|
918
|
+
actionContinuation,
|
|
919
|
+
);
|
|
769
920
|
}
|
|
770
921
|
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
922
|
+
// Full render, partial render, fallen-through PE, and full-page redirect all
|
|
923
|
+
// render through the same middleware-wrapped path. Only full/partial-render
|
|
924
|
+
// carry negotiation + the partial flag; pe/redirect render plainly.
|
|
925
|
+
const isPartial = plan.mode === "partial-render";
|
|
926
|
+
const negotiated =
|
|
927
|
+
plan.mode === "full-render" || plan.mode === "partial-render"
|
|
928
|
+
? plan.negotiated
|
|
929
|
+
: false;
|
|
930
|
+
return executeRenderWithMiddleware(
|
|
931
|
+
plan.route.routeMiddleware,
|
|
932
|
+
negotiated,
|
|
933
|
+
plan.route.routeKey,
|
|
934
|
+
routeReverse,
|
|
935
|
+
request,
|
|
936
|
+
env,
|
|
937
|
+
url,
|
|
938
|
+
variables,
|
|
939
|
+
nonce,
|
|
940
|
+
handleStore,
|
|
941
|
+
isPartial,
|
|
942
|
+
);
|
|
775
943
|
}
|
|
776
944
|
|
|
777
|
-
//
|
|
778
|
-
//
|
|
779
|
-
//
|
|
780
|
-
|
|
781
|
-
|
|
945
|
+
// Shared render execution: wraps handleRscRendering (or revalidateAfterAction)
|
|
946
|
+
// in route middleware and timeout handling. Consolidates the pattern used by
|
|
947
|
+
// action-revalidate, full-render, and partial-render modes.
|
|
948
|
+
async function executeRenderWithMiddleware(
|
|
949
|
+
routeMiddleware: import("../router/middleware-types.js").CollectedMiddleware[],
|
|
950
|
+
negotiated: boolean,
|
|
951
|
+
routeKey: string,
|
|
952
|
+
routeReverse: ReturnType<typeof createReverseFunction>,
|
|
782
953
|
request: Request,
|
|
783
954
|
env: TEnv,
|
|
784
955
|
url: URL,
|
|
785
956
|
variables: Record<string, any>,
|
|
957
|
+
nonce: string | undefined,
|
|
958
|
+
handleStore: ReturnType<typeof requireRequestContext>["_handleStore"],
|
|
959
|
+
isPartial: boolean,
|
|
960
|
+
actionContinuation?: ActionContinuation,
|
|
786
961
|
): Promise<Response> {
|
|
787
|
-
const
|
|
962
|
+
const renderHandler = async (): Promise<Response> => {
|
|
963
|
+
try {
|
|
964
|
+
let response: Response;
|
|
965
|
+
if (actionContinuation) {
|
|
966
|
+
response = await revalidateAfterAction(
|
|
967
|
+
handlerCtx,
|
|
968
|
+
request,
|
|
969
|
+
env,
|
|
970
|
+
url,
|
|
971
|
+
handleStore,
|
|
972
|
+
actionContinuation,
|
|
973
|
+
);
|
|
974
|
+
} else {
|
|
975
|
+
response = await handleRscRendering(
|
|
976
|
+
handlerCtx,
|
|
977
|
+
request,
|
|
978
|
+
env,
|
|
979
|
+
url,
|
|
980
|
+
isPartial,
|
|
981
|
+
handleStore,
|
|
982
|
+
nonce,
|
|
983
|
+
);
|
|
984
|
+
}
|
|
985
|
+
if (negotiated && !isWebSocketUpgradeResponse(response)) {
|
|
986
|
+
response.headers.append("Vary", "Accept");
|
|
987
|
+
}
|
|
988
|
+
return response;
|
|
989
|
+
} catch (error) {
|
|
990
|
+
// Check if middleware/handler returned Response
|
|
991
|
+
if (error instanceof Response) {
|
|
992
|
+
// During partial (client-side navigation), a 200 Response from a handler
|
|
993
|
+
// means the route serves raw content (JSON, text, etc.), not JSX.
|
|
994
|
+
// Signal the browser to hard-navigate so it renders the raw response.
|
|
995
|
+
if (isPartial && error.status === 200) {
|
|
996
|
+
console.warn(
|
|
997
|
+
`[RSC] Route handler at ${url.pathname} returned a Response during client-side navigation. ` +
|
|
998
|
+
`Falling back to hard navigation. Use data-external on the <Link> to avoid the extra round-trip.`,
|
|
999
|
+
);
|
|
1000
|
+
return createResponseWithMergedHeaders(null, {
|
|
1001
|
+
status: 200,
|
|
1002
|
+
headers: {
|
|
1003
|
+
"X-RSC-Reload": stripInternalParams(url).toString(),
|
|
1004
|
+
"content-type": "text/x-component;charset=utf-8",
|
|
1005
|
+
},
|
|
1006
|
+
});
|
|
1007
|
+
}
|
|
788
1008
|
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
1009
|
+
if (isPartial) {
|
|
1010
|
+
const intercepted = interceptRedirectForPartial(
|
|
1011
|
+
error,
|
|
1012
|
+
createRedirectFlightResponse,
|
|
1013
|
+
);
|
|
1014
|
+
if (intercepted) return intercepted;
|
|
1015
|
+
}
|
|
794
1016
|
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
if (!registeredLoader) {
|
|
798
|
-
return createResponseWithMergedHeaders(
|
|
799
|
-
`Loader "${loaderId}" not found in registry`,
|
|
800
|
-
{ status: 404 },
|
|
801
|
-
);
|
|
802
|
-
}
|
|
1017
|
+
return error;
|
|
1018
|
+
}
|
|
803
1019
|
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
1020
|
+
// Render 404 page for unmatched routes
|
|
1021
|
+
if (isRouteNotFoundError(error)) {
|
|
1022
|
+
callOnError(error, "routing", {
|
|
1023
|
+
request,
|
|
1024
|
+
url,
|
|
1025
|
+
env,
|
|
1026
|
+
handledByBoundary: true,
|
|
1027
|
+
});
|
|
808
1028
|
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
1029
|
+
const notFoundOption = router.notFound;
|
|
1030
|
+
const notFoundComponent =
|
|
1031
|
+
typeof notFoundOption === "function"
|
|
1032
|
+
? notFoundOption({ pathname: url.pathname })
|
|
1033
|
+
: (notFoundOption ?? createElement("h1", null, "Not Found"));
|
|
1034
|
+
|
|
1035
|
+
const notFoundSegment = {
|
|
1036
|
+
id: "notFound",
|
|
1037
|
+
namespace: "notFound",
|
|
1038
|
+
type: "route" as const,
|
|
1039
|
+
index: 0,
|
|
1040
|
+
component: notFoundComponent,
|
|
1041
|
+
params: {},
|
|
816
1042
|
};
|
|
817
|
-
loaderParams = jsonBody.params ?? {};
|
|
818
|
-
loaderBody = jsonBody.body;
|
|
819
|
-
}
|
|
820
|
-
} catch {
|
|
821
|
-
return createResponseWithMergedHeaders("Invalid JSON body", {
|
|
822
|
-
status: 400,
|
|
823
|
-
});
|
|
824
|
-
}
|
|
825
|
-
} else {
|
|
826
|
-
const loaderParamsJson = url.searchParams.get("_rsc_loader_params");
|
|
827
|
-
if (loaderParamsJson) {
|
|
828
|
-
try {
|
|
829
|
-
loaderParams = JSON.parse(loaderParamsJson);
|
|
830
|
-
} catch {
|
|
831
|
-
return createResponseWithMergedHeaders(
|
|
832
|
-
"Invalid _rsc_loader_params JSON",
|
|
833
|
-
{ status: 400 },
|
|
834
|
-
);
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
1043
|
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
1044
|
+
const payload: RscPayload = {
|
|
1045
|
+
metadata: {
|
|
1046
|
+
pathname: url.pathname,
|
|
1047
|
+
routerId: router.id,
|
|
1048
|
+
basename: router.basename,
|
|
1049
|
+
segments: [notFoundSegment],
|
|
1050
|
+
matched: [],
|
|
1051
|
+
diff: [],
|
|
1052
|
+
isPartial: false,
|
|
1053
|
+
rootLayout: router.rootLayout,
|
|
1054
|
+
handles: handleStore.stream(),
|
|
1055
|
+
version,
|
|
1056
|
+
themeConfig: router.themeConfig,
|
|
1057
|
+
warmupEnabled: router.warmupEnabled,
|
|
1058
|
+
initialTheme: requireRequestContext().theme,
|
|
1059
|
+
},
|
|
855
1060
|
};
|
|
856
1061
|
|
|
857
|
-
const
|
|
1062
|
+
const rscStream = renderToReadableStream(payload, {
|
|
1063
|
+
onError: (error: unknown) => {
|
|
1064
|
+
callOnError(error, "rendering", { request, url, env });
|
|
1065
|
+
},
|
|
1066
|
+
});
|
|
858
1067
|
|
|
859
|
-
|
|
860
|
-
|
|
1068
|
+
if (isRscRequest(request, url, isPartial)) {
|
|
1069
|
+
return createResponseWithMergedHeaders(rscStream, {
|
|
1070
|
+
status: 404,
|
|
1071
|
+
headers: { "content-type": "text/x-component;charset=utf-8" },
|
|
1072
|
+
});
|
|
861
1073
|
}
|
|
862
|
-
const loaderPayload: LoaderPayload = { loaderResult: result };
|
|
863
|
-
const rscStream =
|
|
864
|
-
renderToReadableStream<LoaderPayload>(loaderPayload);
|
|
865
1074
|
|
|
866
|
-
|
|
867
|
-
|
|
1075
|
+
const [ssrModule, streamMode] = await getSSRSetup(
|
|
1076
|
+
handlerCtx,
|
|
1077
|
+
request,
|
|
1078
|
+
env,
|
|
1079
|
+
url,
|
|
1080
|
+
requireRequestContext()._metricsStore,
|
|
1081
|
+
);
|
|
1082
|
+
const htmlStream = await ssrModule.renderHTML(rscStream, {
|
|
1083
|
+
nonce,
|
|
1084
|
+
streamMode,
|
|
868
1085
|
});
|
|
869
|
-
},
|
|
870
|
-
);
|
|
871
|
-
} catch (error) {
|
|
872
|
-
const err = error instanceof Error ? error : new Error(String(error));
|
|
873
|
-
const isDev = process.env.NODE_ENV !== "production";
|
|
874
|
-
|
|
875
|
-
console.error("[RSC] Loader error:", error);
|
|
876
1086
|
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
env,
|
|
881
|
-
loaderName: loaderId,
|
|
882
|
-
handledByBoundary: false,
|
|
883
|
-
});
|
|
884
|
-
|
|
885
|
-
const errorPayload = {
|
|
886
|
-
loaderResult: null,
|
|
887
|
-
loaderError: {
|
|
888
|
-
message: isDev ? err.message : "An error occurred",
|
|
889
|
-
name: err.name,
|
|
890
|
-
},
|
|
891
|
-
};
|
|
892
|
-
const rscStream = renderToReadableStream(errorPayload);
|
|
893
|
-
|
|
894
|
-
return createResponseWithMergedHeaders(rscStream, {
|
|
895
|
-
status: 500,
|
|
896
|
-
headers: { "content-type": "text/x-component;charset=utf-8" },
|
|
897
|
-
});
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
|
-
|
|
901
|
-
// ============================================================================
|
|
902
|
-
// RSC RENDERING HANDLER (Navigation)
|
|
903
|
-
// ============================================================================
|
|
904
|
-
async function handleRscRendering(
|
|
905
|
-
request: Request,
|
|
906
|
-
env: TEnv,
|
|
907
|
-
url: URL,
|
|
908
|
-
isPartial: boolean,
|
|
909
|
-
handleStore: ReturnType<typeof requireRequestContext>["_handleStore"],
|
|
910
|
-
nonce: string | undefined,
|
|
911
|
-
): Promise<Response> {
|
|
912
|
-
let payload: RscPayload;
|
|
913
|
-
let serverTiming: string | undefined;
|
|
914
|
-
|
|
915
|
-
if (isPartial) {
|
|
916
|
-
// Partial render (navigation)
|
|
917
|
-
const result = await router.matchPartial(request, env);
|
|
918
|
-
|
|
919
|
-
if (!result) {
|
|
920
|
-
// Fall back to full render
|
|
921
|
-
const match = await router.match(request, env);
|
|
922
|
-
setRequestContextParams(match.params);
|
|
923
|
-
|
|
924
|
-
if (match.redirect) {
|
|
925
|
-
return createResponseWithMergedHeaders(null, {
|
|
926
|
-
status: 308,
|
|
927
|
-
headers: { Location: match.redirect },
|
|
1087
|
+
return createResponseWithMergedHeaders(htmlStream, {
|
|
1088
|
+
status: 404,
|
|
1089
|
+
headers: { "content-type": "text/html;charset=utf-8" },
|
|
928
1090
|
});
|
|
929
1091
|
}
|
|
930
1092
|
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
const renderDuration = performance.now() - renderStart;
|
|
938
|
-
serverTiming = match.serverTiming
|
|
939
|
-
? `${match.serverTiming}, rendering;dur=${renderDuration.toFixed(2)}`
|
|
940
|
-
: `rendering;dur=${renderDuration.toFixed(2)}`;
|
|
941
|
-
|
|
942
|
-
payload = {
|
|
943
|
-
root,
|
|
944
|
-
metadata: {
|
|
945
|
-
pathname: url.pathname,
|
|
946
|
-
segments: match.segments,
|
|
947
|
-
matched: match.matched,
|
|
948
|
-
diff: match.diff,
|
|
949
|
-
isPartial: false,
|
|
950
|
-
handles: handleStore.stream(),
|
|
951
|
-
version,
|
|
952
|
-
themeConfig: router.themeConfig,
|
|
953
|
-
initialTheme: requireRequestContext().theme,
|
|
954
|
-
routeMap,
|
|
955
|
-
routeName: match.routeName,
|
|
956
|
-
},
|
|
957
|
-
};
|
|
958
|
-
} else {
|
|
959
|
-
setRequestContextParams(result.params);
|
|
960
|
-
serverTiming = result.serverTiming;
|
|
961
|
-
|
|
962
|
-
payload = {
|
|
963
|
-
root: null,
|
|
964
|
-
metadata: {
|
|
965
|
-
pathname: url.pathname,
|
|
966
|
-
segments: result.segments,
|
|
967
|
-
matched: result.matched,
|
|
968
|
-
diff: result.diff,
|
|
969
|
-
isPartial: true,
|
|
970
|
-
slots: result.slots,
|
|
971
|
-
handles: handleStore.stream(),
|
|
972
|
-
version,
|
|
973
|
-
routeMap,
|
|
974
|
-
routeName: result.routeName,
|
|
975
|
-
},
|
|
976
|
-
};
|
|
977
|
-
}
|
|
978
|
-
} else {
|
|
979
|
-
// Full render (initial page load)
|
|
980
|
-
const match = await router.match(request, env);
|
|
981
|
-
setRequestContextParams(match.params);
|
|
982
|
-
|
|
983
|
-
if (match.redirect) {
|
|
984
|
-
return createResponseWithMergedHeaders(null, {
|
|
985
|
-
status: 308,
|
|
986
|
-
headers: { Location: match.redirect },
|
|
1093
|
+
// Report unhandled errors
|
|
1094
|
+
callOnError(error, "routing", {
|
|
1095
|
+
request,
|
|
1096
|
+
url,
|
|
1097
|
+
env,
|
|
1098
|
+
handledByBoundary: false,
|
|
987
1099
|
});
|
|
1100
|
+
console.error(`[RSC] Error:`, error);
|
|
1101
|
+
throw error;
|
|
988
1102
|
}
|
|
1103
|
+
};
|
|
989
1104
|
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
? `${match.serverTiming}, rendering;dur=${renderDuration.toFixed(2)}`
|
|
1002
|
-
: `rendering;dur=${renderDuration.toFixed(2)}`;
|
|
1003
|
-
|
|
1004
|
-
payload = {
|
|
1005
|
-
root,
|
|
1006
|
-
metadata: {
|
|
1007
|
-
pathname: url.pathname,
|
|
1008
|
-
segments: match.segments,
|
|
1009
|
-
matched: match.matched,
|
|
1010
|
-
diff: match.diff,
|
|
1011
|
-
isPartial: false,
|
|
1012
|
-
rootLayout: router.rootLayout,
|
|
1013
|
-
handles: handleStore.stream(),
|
|
1014
|
-
version,
|
|
1015
|
-
themeConfig: router.themeConfig,
|
|
1016
|
-
initialTheme: requireRequestContext().theme,
|
|
1017
|
-
routeMap,
|
|
1018
|
-
routeName: match.routeName,
|
|
1019
|
-
},
|
|
1020
|
-
};
|
|
1021
|
-
}
|
|
1022
|
-
|
|
1023
|
-
// Serialize to RSC stream
|
|
1024
|
-
const rscStream = renderToReadableStream<RscPayload>(payload);
|
|
1105
|
+
// Wrap the render path in a renderStartMs timeout
|
|
1106
|
+
const executeRender = async (): Promise<Response> => {
|
|
1107
|
+
if (routeMiddleware.length > 0) {
|
|
1108
|
+
const mwResponse = await executeMiddleware(
|
|
1109
|
+
buildRouteMiddlewareEntries<TEnv>(routeMiddleware),
|
|
1110
|
+
request,
|
|
1111
|
+
env,
|
|
1112
|
+
variables,
|
|
1113
|
+
renderHandler,
|
|
1114
|
+
routeReverse,
|
|
1115
|
+
);
|
|
1025
1116
|
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1117
|
+
if (isPartial || actionContinuation) {
|
|
1118
|
+
const intercepted = interceptRedirectForPartial(
|
|
1119
|
+
mwResponse,
|
|
1120
|
+
createRedirectFlightResponse,
|
|
1121
|
+
);
|
|
1122
|
+
if (intercepted) return intercepted;
|
|
1123
|
+
}
|
|
1031
1124
|
|
|
1032
|
-
|
|
1033
|
-
const rscHeaders: Record<string, string> = {
|
|
1034
|
-
"content-type": "text/x-component;charset=utf-8",
|
|
1035
|
-
vary: "accept",
|
|
1036
|
-
};
|
|
1037
|
-
if (serverTiming) {
|
|
1038
|
-
rscHeaders["Server-Timing"] = serverTiming;
|
|
1125
|
+
return finalizeResponse(mwResponse);
|
|
1039
1126
|
}
|
|
1040
|
-
return createResponseWithMergedHeaders(rscStream, {
|
|
1041
|
-
headers: rscHeaders,
|
|
1042
|
-
});
|
|
1043
|
-
}
|
|
1044
|
-
|
|
1045
|
-
// Delegate to SSR for HTML response
|
|
1046
|
-
const ssrModule = await loadSSRModule();
|
|
1047
|
-
const htmlStream = await ssrModule.renderHTML(rscStream, { nonce });
|
|
1048
1127
|
|
|
1049
|
-
|
|
1050
|
-
"content-type": "text/html;charset=utf-8",
|
|
1128
|
+
return renderHandler();
|
|
1051
1129
|
};
|
|
1052
|
-
if (serverTiming) {
|
|
1053
|
-
htmlHeaders["Server-Timing"] = serverTiming;
|
|
1054
|
-
}
|
|
1055
1130
|
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1131
|
+
const renderOutcome = await withTimeout(
|
|
1132
|
+
executeRender(),
|
|
1133
|
+
router.timeouts.renderStartMs,
|
|
1134
|
+
"render-start",
|
|
1135
|
+
);
|
|
1136
|
+
if (renderOutcome.timedOut) {
|
|
1137
|
+
return handleTimeoutResponse(
|
|
1138
|
+
request,
|
|
1139
|
+
env,
|
|
1140
|
+
url,
|
|
1141
|
+
"render-start",
|
|
1142
|
+
renderOutcome.durationMs,
|
|
1143
|
+
routeKey,
|
|
1144
|
+
);
|
|
1145
|
+
}
|
|
1146
|
+
return renderOutcome.result;
|
|
1059
1147
|
}
|
|
1060
1148
|
}
|