@wular/pnext 0.0.1
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/README.md +153 -0
- package/bin/pnext +67 -0
- package/config/lint/base.js +48 -0
- package/config/ts/base.json +26 -0
- package/config/ts/react.json +13 -0
- package/package.json +70 -0
- package/reference/compat.md +63 -0
- package/reference/config.md +120 -0
- package/reference/css.md +58 -0
- package/reference/dev.md +69 -0
- package/reference/env.md +40 -0
- package/reference/metadata.md +86 -0
- package/reference/navigation.md +149 -0
- package/reference/overview.md +35 -0
- package/reference/performance.md +97 -0
- package/reference/rendering.md +127 -0
- package/reference/routing.md +167 -0
- package/reference/typegen.md +64 -0
- package/src/api/cache.ts +80 -0
- package/src/api/client-cache.ts +9 -0
- package/src/api/client-navigation.ts +279 -0
- package/src/api/dynamic.tsx +102 -0
- package/src/api/link.tsx +119 -0
- package/src/api/navigation.ts +198 -0
- package/src/api/router/events.ts +53 -0
- package/src/api/router/history.ts +70 -0
- package/src/api/router/hub.ts +194 -0
- package/src/api/router/policies.ts +107 -0
- package/src/api/router/runtime.ts +5238 -0
- package/src/api/router/types.ts +299 -0
- package/src/api/router.ts +167 -0
- package/src/api/server.ts +323 -0
- package/src/api/suspense.ts +16 -0
- package/src/cache/context.ts +61 -0
- package/src/cli/adapters/vercel-warm.ts +375 -0
- package/src/cli/adapters/vercel.ts +1310 -0
- package/src/cli/analyze-print.ts +181 -0
- package/src/cli/analyze.ts +328 -0
- package/src/cli/boot-trace.ts +29 -0
- package/src/cli/build.ts +3114 -0
- package/src/cli/dev.ts +276 -0
- package/src/cli/index.ts +196 -0
- package/src/cli/named-bin.ts +119 -0
- package/src/cli/serve-ui.ts +160 -0
- package/src/cli/start.ts +1425 -0
- package/src/client/build.ts +2136 -0
- package/src/client/chunk-fold.ts +526 -0
- package/src/client/entry.ts +1525 -0
- package/src/client/paths.ts +22 -0
- package/src/client/prebuilt.ts +621 -0
- package/src/client/profile.ts +75 -0
- package/src/client/react-compiler.ts +94 -0
- package/src/client/reference-stub.ts +145 -0
- package/src/client/reference.ts +47 -0
- package/src/compat/actions/action-client.ts +531 -0
- package/src/compat/actions/action-dispatch.ts +676 -0
- package/src/compat/actions/action-router.ts +40 -0
- package/src/compat/actions/action-shared.ts +95 -0
- package/src/compat/actions/client-plugin.ts +135 -0
- package/src/compat/actions/client-stub.ts +65 -0
- package/src/compat/actions/config.ts +164 -0
- package/src/compat/actions/detect.ts +208 -0
- package/src/compat/actions/discovery.ts +244 -0
- package/src/compat/actions/early-submit.ts +40 -0
- package/src/compat/actions/endpoint.ts +602 -0
- package/src/compat/actions/flight.ts +52 -0
- package/src/compat/actions/form-state.ts +73 -0
- package/src/compat/actions/hoist.ts +485 -0
- package/src/compat/actions/ids.ts +39 -0
- package/src/compat/actions/index.ts +41 -0
- package/src/compat/actions/instances.ts +144 -0
- package/src/compat/actions/origin.ts +109 -0
- package/src/compat/actions/protocol.ts +125 -0
- package/src/compat/actions/registry.ts +74 -0
- package/src/compat/actions/rewrite.ts +282 -0
- package/src/compat/actions/serve.ts +414 -0
- package/src/compat/actions/server-tag.ts +21 -0
- package/src/compat/actions/unrecognized-error.ts +30 -0
- package/src/compat/adapter/build-complete.ts +257 -0
- package/src/compat/bundler/bun-externals.ts +53 -0
- package/src/compat/bundler/cjs-exports.ts +542 -0
- package/src/compat/bundler/config.ts +363 -0
- package/src/compat/bundler/externals.ts +34 -0
- package/src/compat/bundler/import-meta-url.ts +60 -0
- package/src/compat/bundler/modularize-imports.ts +119 -0
- package/src/compat/bundler/new-url-asset.ts +87 -0
- package/src/compat/bundler/optimize-package-imports.ts +273 -0
- package/src/compat/bundler/polyfill.ts +88 -0
- package/src/compat/bundler/react-compiler.ts +61 -0
- package/src/compat/bundler/react-profiler.tsx +25 -0
- package/src/compat/bundler/relay-transform.ts +116 -0
- package/src/compat/bundler/require-context.ts +281 -0
- package/src/compat/bundler/resolve-extensions.ts +75 -0
- package/src/compat/bundler/source-cache.ts +61 -0
- package/src/compat/bundler/static-imports.ts +25 -0
- package/src/compat/bundler/symlink-imports.ts +119 -0
- package/src/compat/bundler/tsconfig-paths.ts +50 -0
- package/src/compat/bundler/wasm.ts +153 -0
- package/src/compat/bundler/webpack-loaders.ts +685 -0
- package/src/compat/bundler/worker.ts +278 -0
- package/src/compat/cache/build-flags.ts +81 -0
- package/src/compat/cache/build-prerender-errors.ts +163 -0
- package/src/compat/cache/custom-handler.ts +159 -0
- package/src/compat/cache/fetch-patch.ts +745 -0
- package/src/compat/cache/handler.ts +100 -0
- package/src/compat/cache/modern-handler.ts +275 -0
- package/src/compat/cache/resume-data-cache.ts +143 -0
- package/src/compat/cache/revalidate.ts +759 -0
- package/src/compat/cache/runtime-error.ts +124 -0
- package/src/compat/cache/use-cache-transform.ts +961 -0
- package/src/compat/cache/use-cache.ts +1695 -0
- package/src/compat/cache-control.ts +269 -0
- package/src/compat/client/base-path.ts +64 -0
- package/src/compat/client/css-order.ts +36 -0
- package/src/compat/client/errors/control-flow.ts +92 -0
- package/src/compat/client/errors/error-boundary.ts +222 -0
- package/src/compat/client/errors/global-error.ts +238 -0
- package/src/compat/client/errors/install.ts +217 -0
- package/src/compat/client/errors/lazy.ts +53 -0
- package/src/compat/client/errors/primitive-throw.ts +126 -0
- package/src/compat/client/errors/soft-refresh.ts +14 -0
- package/src/compat/client/link-status.ts +86 -0
- package/src/compat/client/nav-compat-runtime.ts +57 -0
- package/src/compat/client/nav-compat.ts +42 -0
- package/src/compat/client/navigation-scroll.ts +154 -0
- package/src/compat/client/optimistic-routing.ts +206 -0
- package/src/compat/client/prefetch-cache.ts +111 -0
- package/src/compat/client/route-announcer.ts +72 -0
- package/src/compat/client/segment-cache-policy.ts +159 -0
- package/src/compat/client/segment-cache.ts +1077 -0
- package/src/compat/client/segment-prefetch.ts +375 -0
- package/src/compat/client/trailing-slash.ts +24 -0
- package/src/compat/css/chunking.ts +254 -0
- package/src/compat/css/inline-css.ts +73 -0
- package/src/compat/css/lightningcss.ts +90 -0
- package/src/compat/css/modules.ts +373 -0
- package/src/compat/css/nonce.ts +30 -0
- package/src/compat/css/sass-plugin.ts +65 -0
- package/src/compat/css/sass.ts +392 -0
- package/src/compat/css/styled-jsx-runtime.ts +80 -0
- package/src/compat/css/styled-jsx.ts +49 -0
- package/src/compat/edge-runtime.ts +71 -0
- package/src/compat/export/client.ts +112 -0
- package/src/compat/export/index.ts +272 -0
- package/src/compat/export/standalone.ts +207 -0
- package/src/compat/image-optimizer/cache.ts +119 -0
- package/src/compat/image-optimizer/detect.ts +143 -0
- package/src/compat/image-optimizer/index.ts +601 -0
- package/src/compat/image-optimizer/source.ts +243 -0
- package/src/compat/index.ts +458 -0
- package/src/compat/lifecycle/after-scope.ts +86 -0
- package/src/compat/lifecycle/after.ts +173 -0
- package/src/compat/lifecycle/error-funnel.ts +306 -0
- package/src/compat/lifecycle/error-serialize.ts +87 -0
- package/src/compat/lifecycle/error-ui.ts +167 -0
- package/src/compat/lifecycle/instrumentation-client.ts +138 -0
- package/src/compat/lifecycle/instrumentation.ts +277 -0
- package/src/compat/lifecycle/node-console.ts +19 -0
- package/src/compat/lifecycle/testmode.ts +263 -0
- package/src/compat/mdx/compile.ts +219 -0
- package/src/compat/mdx/next-mdx-stub.ts +46 -0
- package/src/compat/mdx/plugin.ts +37 -0
- package/src/compat/metadata-route-artifacts.ts +458 -0
- package/src/compat/metadata.ts +295 -0
- package/src/compat/middleware/manifest.ts +210 -0
- package/src/compat/misc/action-return.ts +173 -0
- package/src/compat/next/cache.ts +211 -0
- package/src/compat/next/canonical-url.ts +35 -0
- package/src/compat/next/client-cache.ts +57 -0
- package/src/compat/next/client-navigation.ts +313 -0
- package/src/compat/next/client-only.ts +3 -0
- package/src/compat/next/client-script.tsx +215 -0
- package/src/compat/next/client-server.ts +39 -0
- package/src/compat/next/config-loader.ts +569 -0
- package/src/compat/next/config.ts +29 -0
- package/src/compat/next/constants.cjs +6 -0
- package/src/compat/next/constants.ts +6 -0
- package/src/compat/next/custom-server.ts +236 -0
- package/src/compat/next/dist/client/components/app-router-headers.ts +32 -0
- package/src/compat/next/dist/server/app-render/work-unit-async-storage.external.cjs +38 -0
- package/src/compat/next/dist/server/web/spec-extension/revalidate.ts +1 -0
- package/src/compat/next/dist/server/web/spec-extension/unstable-cache.ts +1 -0
- package/src/compat/next/dist/server/web/spec-extension/unstable-no-store.ts +1 -0
- package/src/compat/next/dynamic.tsx +46 -0
- package/src/compat/next/error.tsx +148 -0
- package/src/compat/next/font/cache.ts +171 -0
- package/src/compat/next/font/google.ts +2 -0
- package/src/compat/next/font/index.ts +8 -0
- package/src/compat/next/font/local.ts +5 -0
- package/src/compat/next/font/runtime-client.ts +71 -0
- package/src/compat/next/font/runtime.ts +974 -0
- package/src/compat/next/font/shared.ts +281 -0
- package/src/compat/next/form.tsx +156 -0
- package/src/compat/next/head.tsx +10 -0
- package/src/compat/next/headers.ts +247 -0
- package/src/compat/next/image/config.ts +196 -0
- package/src/compat/next/image/optimizer.ts +96 -0
- package/src/compat/next/image/patterns.ts +103 -0
- package/src/compat/next/image/shared.ts +141 -0
- package/src/compat/next/image/static-metadata.ts +283 -0
- package/src/compat/next/image/validate.ts +269 -0
- package/src/compat/next/image-client.tsx +215 -0
- package/src/compat/next/image-props.ts +575 -0
- package/src/compat/next/image-usage.ts +102 -0
- package/src/compat/next/image.tsx +56 -0
- package/src/compat/next/index.ts +1 -0
- package/src/compat/next/legacy-image.tsx +97 -0
- package/src/compat/next/link-usage.ts +29 -0
- package/src/compat/next/link-validation-transform.ts +200 -0
- package/src/compat/next/link.tsx +466 -0
- package/src/compat/next/navigation.cjs +21 -0
- package/src/compat/next/navigation.ts +188 -0
- package/src/compat/next/offline.ts +51 -0
- package/src/compat/next/og.ts +324 -0
- package/src/compat/next/optimistic-route-state.ts +188 -0
- package/src/compat/next/preferred-region.ts +39 -0
- package/src/compat/next/redirects.ts +131 -0
- package/src/compat/next/resource-hints.ts +136 -0
- package/src/compat/next/rewrites.ts +350 -0
- package/src/compat/next/root-params.ts +142 -0
- package/src/compat/next/router.cjs +49 -0
- package/src/compat/next/router.ts +143 -0
- package/src/compat/next/script.tsx +355 -0
- package/src/compat/next/server-only.ts +3 -0
- package/src/compat/next/server.ts +28 -0
- package/src/compat/next/svgr.ts +58 -0
- package/src/compat/next/telemetry.ts +77 -0
- package/src/compat/next/user-agent.ts +100 -0
- package/src/compat/next/web-vitals.ts +56 -0
- package/src/compat/otel/api.ts +95 -0
- package/src/compat/otel/client-trace-metadata.ts +71 -0
- package/src/compat/otel/fetch-span.ts +77 -0
- package/src/compat/otel/tracer.ts +944 -0
- package/src/compat/pages/client-plugin.ts +108 -0
- package/src/compat/pages/index.ts +527 -0
- package/src/compat/pages/router-state.ts +94 -0
- package/src/compat/ppr/io.ts +38 -0
- package/src/compat/ppr/missing-root-params.ts +105 -0
- package/src/compat/ppr/root-params-scan.ts +164 -0
- package/src/compat/ppr/root-params-transform.ts +75 -0
- package/src/compat/ppr/root-params.ts +129 -0
- package/src/compat/ppr/segment-config-incompat.ts +34 -0
- package/src/compat/protocol.ts +202 -0
- package/src/compat/react/client.ts +59 -0
- package/src/compat/react/compiler-runtime.ts +60 -0
- package/src/compat/react/dom-client.ts +115 -0
- package/src/compat/react/dom-react-server.ts +20 -0
- package/src/compat/react/dom-server.ts +40 -0
- package/src/compat/react/dom.ts +154 -0
- package/src/compat/react/preact.ts +522 -0
- package/src/compat/react/react-server.ts +84 -0
- package/src/compat/react/router-shim.ts +26 -0
- package/src/compat/react/server-component-use.ts +48 -0
- package/src/compat/react/server-inserted-html.ts +87 -0
- package/src/compat/react/server.ts +156 -0
- package/src/compat/react/view-transition.ts +60 -0
- package/src/compat/register/actions.ts +875 -0
- package/src/compat/register/boot.ts +141 -0
- package/src/compat/register/build-tier.ts +11 -0
- package/src/compat/register/build.ts +182 -0
- package/src/compat/register/bundler.ts +587 -0
- package/src/compat/register/cache.ts +85 -0
- package/src/compat/register/client-errors.ts +18 -0
- package/src/compat/register/config.ts +17 -0
- package/src/compat/register/css-extras.ts +120 -0
- package/src/compat/register/edge-runtime.ts +6 -0
- package/src/compat/register/errors.ts +46 -0
- package/src/compat/register/export.ts +23 -0
- package/src/compat/register/font.ts +36 -0
- package/src/compat/register/hooks.ts +34 -0
- package/src/compat/register/image.ts +133 -0
- package/src/compat/register/index.ts +111 -0
- package/src/compat/register/instrumentation-client.ts +35 -0
- package/src/compat/register/lifecycle.ts +86 -0
- package/src/compat/register/mdx.ts +48 -0
- package/src/compat/register/middleware.ts +36 -0
- package/src/compat/register/misc.ts +44 -0
- package/src/compat/register/otel.ts +288 -0
- package/src/compat/register/pages-api.ts +473 -0
- package/src/compat/register/ppr.ts +56 -0
- package/src/compat/register/protocol.ts +57 -0
- package/src/compat/register/proxy.ts +127 -0
- package/src/compat/register/render.ts +268 -0
- package/src/compat/register/routing.ts +410 -0
- package/src/compat/register/segment.ts +1903 -0
- package/src/compat/register/static-image.ts +21 -0
- package/src/compat/register/typed-routes.ts +35 -0
- package/src/compat/register/usecache.ts +131 -0
- package/src/compat/register/validation.ts +56 -0
- package/src/compat/segment/loading-boundary.ts +113 -0
- package/src/compat/segment/page-slot.ts +200 -0
- package/src/compat/segment/tree.ts +481 -0
- package/src/compat/segment/vary-key.ts +102 -0
- package/src/compat/segment/vary-params.ts +551 -0
- package/src/compat/static-params.ts +33 -0
- package/src/compat/tsconfig-defaults.ts +301 -0
- package/src/compat/typecheck/index.ts +1481 -0
- package/src/compat/typecheck/worker.ts +26 -0
- package/src/compat/typed-routes/index.ts +92 -0
- package/src/compat/typed-routes/manifest.ts +356 -0
- package/src/compat/typed-routes/typegen.ts +566 -0
- package/src/compat/validation/errors.ts +159 -0
- package/src/compat/validation/index.ts +1770 -0
- package/src/compat/validation/prerender-diagnostics.ts +1508 -0
- package/src/compat-bootstrap.ts +67 -0
- package/src/config.ts +218 -0
- package/src/css/build.ts +697 -0
- package/src/css/index.ts +2 -0
- package/src/css/postcss.ts +236 -0
- package/src/css/worker.ts +34 -0
- package/src/dev/client-actions.ts +35 -0
- package/src/dev/client-chunk-store.ts +92 -0
- package/src/dev/client-key-cache.ts +178 -0
- package/src/dev/global-css-cache.ts +212 -0
- package/src/dev/imports.ts +2430 -0
- package/src/dev/module-cache.ts +721 -0
- package/src/dev/module-generations.ts +38 -0
- package/src/dev/module-transform.ts +188 -0
- package/src/dev/node-module-bundle-cache.ts +63 -0
- package/src/dev/restart-cache.ts +10 -0
- package/src/dev/route-bundle-key-cache.ts +154 -0
- package/src/dev/route-facts-cache.ts +223 -0
- package/src/dev/server.ts +1710 -0
- package/src/dynamic/source.ts +307 -0
- package/src/dynamic/tree-shake.ts +262 -0
- package/src/env.ts +92 -0
- package/src/extensions.ts +1898 -0
- package/src/index.ts +34 -0
- package/src/internal.ts +43 -0
- package/src/islands/boundary-error.ts +8 -0
- package/src/islands/static-children.ts +37 -0
- package/src/islands/static-slots.ts +106 -0
- package/src/ppr-postpone.ts +24 -0
- package/src/ppr.ts +784 -0
- package/src/proxy.ts +752 -0
- package/src/render/hooks.ts +384 -0
- package/src/render/index.ts +1 -0
- package/src/render/island-context.ts +47 -0
- package/src/render/metadata.ts +857 -0
- package/src/render/renderer.ts +7391 -0
- package/src/render/resource-hints.ts +44 -0
- package/src/render/slots.tsx +679 -0
- package/src/request/context.ts +396 -0
- package/src/resolve/engine.ts +219 -0
- package/src/resolve/imports.ts +1104 -0
- package/src/resolve/scan-facts.ts +474 -0
- package/src/resolve/source-text.ts +86 -0
- package/src/routing/forwarded.ts +41 -0
- package/src/routing/handler.ts +271 -0
- package/src/routing/href.ts +203 -0
- package/src/routing/metadata.ts +1018 -0
- package/src/routing/request-runtime.ts +43 -0
- package/src/routing/routes.ts +2560 -0
- package/src/routing/slots.ts +432 -0
- package/src/runtime/server.ts +3453 -0
- package/src/runtime/vendor.ts +1160 -0
- package/src/style-modules.d.ts +9 -0
- package/src/typegen.ts +151 -0
- package/src/types.ts +725 -0
- package/src/utils/ansi.ts +9 -0
- package/src/utils/content-type.ts +31 -0
- package/src/utils/decode.ts +7 -0
- package/src/utils/dev-profile.ts +31 -0
- package/src/utils/error-log.ts +29 -0
- package/src/utils/fs-cache.ts +31 -0
- package/src/utils/fs.ts +119 -0
- package/src/utils/html.ts +46 -0
- package/src/utils/serialize.ts +378 -0
- package/src/utils/source.ts +35 -0
- package/src/utils/verbose.ts +39 -0
- package/tsconfig.json +10 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// Request-lifecycle extension registration (COMPAT).
|
|
2
|
+
//
|
|
3
|
+
// Wires after()/onRequestError/instrumentation/testmode onto the core seams:
|
|
4
|
+
// - initHooks (build + start): load instrumentation.ts and run its register() once; install the
|
|
5
|
+
// testmode fetch patch once (a no-op until a request carries Next-Test-* headers).
|
|
6
|
+
// - RequestExtensions.onRequestError: the error funnel (classify control-flow, dedupe, forward).
|
|
7
|
+
// - a request interceptor: await the instrumentation register() gate so async register() completes
|
|
8
|
+
// before the first request is served, and activate the testmode proxy for Next-Test-* requests.
|
|
9
|
+
//
|
|
10
|
+
// after() itself needs no registration - it is exported from the next/server alias and builds directly on
|
|
11
|
+
// the core work-unit after-queue.
|
|
12
|
+
//
|
|
13
|
+
// Split across the two registration tiers: the hooks core runs at server start register eagerly via
|
|
14
|
+
// registerLifecycleBootHooks(), while the request interceptor registers with the rest of the graph so its
|
|
15
|
+
// position in the interceptor chain is unchanged.
|
|
16
|
+
|
|
17
|
+
import type { ResolvedConfig } from '../../config';
|
|
18
|
+
import {
|
|
19
|
+
registerInitHooks,
|
|
20
|
+
registerRequestInterceptors,
|
|
21
|
+
setRequestExtensions,
|
|
22
|
+
type RequestInterceptor,
|
|
23
|
+
} from '../../extensions';
|
|
24
|
+
import { nextCompatEnabled } from '../index';
|
|
25
|
+
import { getNextConfig } from '../next/config-loader';
|
|
26
|
+
import { instrumentationReady, loadInstrumentation } from '../lifecycle/instrumentation';
|
|
27
|
+
import {
|
|
28
|
+
installUnhandledRejectionGuard,
|
|
29
|
+
reportRequestErrorToUser,
|
|
30
|
+
} from '../lifecycle/error-funnel';
|
|
31
|
+
import { activateTestProxy, installTestProxyFetch } from '../lifecycle/testmode';
|
|
32
|
+
import { recordRequestPath } from '../lifecycle/after-scope';
|
|
33
|
+
import { installNodeConsoleFormat } from '../lifecycle/node-console';
|
|
34
|
+
|
|
35
|
+
/** experimental.testProxy from the loaded next.config. */
|
|
36
|
+
function testProxyEnabled(): boolean {
|
|
37
|
+
const experimental = getNextConfig().experimental as { testProxy?: boolean } | undefined;
|
|
38
|
+
return experimental?.testProxy === true;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Boot tier: everything that must be installed before the server starts. */
|
|
42
|
+
export function registerLifecycleBootHooks(config: ResolvedConfig): void {
|
|
43
|
+
if (!nextCompatEnabled(config)) return;
|
|
44
|
+
installNodeConsoleFormat();
|
|
45
|
+
|
|
46
|
+
// The user's onRequestError hook (once instrumentation has loaded) receives
|
|
47
|
+
// every real request error; control-flow errors are filtered in the funnel.
|
|
48
|
+
setRequestExtensions({ onRequestError: reportRequestErrorToUser });
|
|
49
|
+
|
|
50
|
+
// Keep the server alive when an SSR error escapes as an unhandled rejection
|
|
51
|
+
// (a client component that throws during server render — preact resolves the
|
|
52
|
+
// string pass to '' and floats the rejection). Without this the process
|
|
53
|
+
// crashes and every later request in the shared harness server fails.
|
|
54
|
+
installUnhandledRejectionGuard();
|
|
55
|
+
|
|
56
|
+
// Load instrumentation and patch fetch at server start. The fetch patch is a no-op until a request
|
|
57
|
+
// activates the test proxy. Instrumentation register() must NOT run during a build: Next only detects
|
|
58
|
+
// the file at build and runs register() at server boot, so build prerenders see a noop tracer - a live
|
|
59
|
+
// TracerProvider at build would bake real span ids into the static shell and 'use cache' entries.
|
|
60
|
+
registerInitHooks((cfg, context) => {
|
|
61
|
+
if (!context.build) loadInstrumentation(cfg);
|
|
62
|
+
installTestProxyFetch();
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function registerLifecycleExtensions(config: ResolvedConfig): void {
|
|
67
|
+
if (!nextCompatEnabled(config)) return;
|
|
68
|
+
|
|
69
|
+
const lifecycleInterceptor: RequestInterceptor = async request => {
|
|
70
|
+
// Block the very first requests until instrumentation register() settles.
|
|
71
|
+
await instrumentationReady();
|
|
72
|
+
// Remember the route pathname so an after() callback that runs detached
|
|
73
|
+
// (after a page render) can name the route in its "used ... inside after()"
|
|
74
|
+
// error, matching Next's message.
|
|
75
|
+
try {
|
|
76
|
+
recordRequestPath(new URL(request.url).pathname);
|
|
77
|
+
} catch {
|
|
78
|
+
// ignore malformed URLs
|
|
79
|
+
}
|
|
80
|
+
// Route this request's outgoing fetch through the test proxy when it carries
|
|
81
|
+
// Next-Test-* headers (gated on experimental.testProxy in next.config).
|
|
82
|
+
if (testProxyEnabled()) activateTestProxy(request.headers);
|
|
83
|
+
return undefined;
|
|
84
|
+
};
|
|
85
|
+
registerRequestInterceptors(lifecycleInterceptor);
|
|
86
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// MDX extension registration (COMPAT).
|
|
2
|
+
//
|
|
3
|
+
// Wires the MDX esbuild plugin into the client and server build graphs so `.mdx`/`.md` modules compile
|
|
4
|
+
// via the JS pipeline. Two integration points:
|
|
5
|
+
//
|
|
6
|
+
// 1. BUNDLER: the MDX plugin is appended to clientEsbuildPlugins and serverEsbuildPlugins.
|
|
7
|
+
// `setBundlerExtensions` REPLACES the factory and register-actions already sets clientEsbuildPlugins,
|
|
8
|
+
// so this COMPOSES with any previously-registered factory rather than clobbering it. Note that
|
|
9
|
+
// `serverEsbuildPlugins` is defined but not yet applied at every server compile site, so until that
|
|
10
|
+
// seam is threaded MDX compiles in the CLIENT graph only; the server factory is registered here so it
|
|
11
|
+
// activates for free once it lands.
|
|
12
|
+
//
|
|
13
|
+
// 2. PAGE EXTENSIONS: core derives its page/convention extension list lazily from a base plus whatever
|
|
14
|
+
// compat registers, so the route scanner discovers `page.mdx` and top-level `.mdx` pages once `mdx`/
|
|
15
|
+
// `md` are registered. `pageExtensions` in next.config (as set by @next/mdx's createMDX) is the single
|
|
16
|
+
// source of truth: when the app sets it, exactly the listed extensions core does not already carry are
|
|
17
|
+
// registered, so `.mdx` routes only when the app opted in - matching Next. When none is configured,
|
|
18
|
+
// nothing extra is registered.
|
|
19
|
+
//
|
|
20
|
+
// The seam is additive-only, so core's base `mjs` cannot be removed even if a configured
|
|
21
|
+
// `pageExtensions` omits it - a documented, harmless divergence. The route scanner needs these
|
|
22
|
+
// extensions at boot, so the registration itself lives in register-boot.ts; only the compilation
|
|
23
|
+
// wiring is here.
|
|
24
|
+
|
|
25
|
+
import type { Plugin } from 'esbuild';
|
|
26
|
+
import type { ResolvedConfig } from '../../config';
|
|
27
|
+
import { getBundlerExtensions, setBundlerExtensions } from '../../extensions';
|
|
28
|
+
import { nextCompatEnabled } from '../../render/hooks';
|
|
29
|
+
import { mdxEsbuildPlugin } from '../mdx/plugin';
|
|
30
|
+
|
|
31
|
+
export function registerMdxExtensions(config: ResolvedConfig): void {
|
|
32
|
+
if (!nextCompatEnabled(config)) return;
|
|
33
|
+
|
|
34
|
+
const existing = getBundlerExtensions();
|
|
35
|
+
const priorClient = existing.clientEsbuildPlugins;
|
|
36
|
+
const priorServer = existing.serverEsbuildPlugins;
|
|
37
|
+
|
|
38
|
+
setBundlerExtensions({
|
|
39
|
+
clientEsbuildPlugins: (cfg: ResolvedConfig): Plugin[] => [
|
|
40
|
+
...priorClient(cfg),
|
|
41
|
+
mdxEsbuildPlugin(config.root),
|
|
42
|
+
],
|
|
43
|
+
serverEsbuildPlugins: (cfg: ResolvedConfig, opts?): Plugin[] => [
|
|
44
|
+
...priorServer(cfg, opts),
|
|
45
|
+
mdxEsbuildPlugin(config.root),
|
|
46
|
+
],
|
|
47
|
+
});
|
|
48
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Middleware extension registration (COMPAT - may import core freely). Registers the build step that
|
|
2
|
+
// emits the Next-shaped middleware manifests (middleware-manifest.json +
|
|
3
|
+
// functions-config-manifest.json). The middleware runtime itself is the existing proxy machinery; this
|
|
4
|
+
// module owns only the build-time manifest output.
|
|
5
|
+
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
import { registerBuildSteps } from '../../extensions';
|
|
9
|
+
import { nextCompatEnabled } from '../../compat';
|
|
10
|
+
import { findProxyFile, proxyExternalLoadTarget } from '../../proxy';
|
|
11
|
+
import { devServerModuleHref } from '../../dev/imports';
|
|
12
|
+
import { toPosixPath } from '../../utils/fs';
|
|
13
|
+
import type { RouteManifestEntry } from '../../types';
|
|
14
|
+
import { writeMiddlewareManifests } from '../middleware/manifest';
|
|
15
|
+
|
|
16
|
+
export function registerMiddlewareExtensions(): void {
|
|
17
|
+
registerBuildSteps(async ({ config, routes }) => {
|
|
18
|
+
if (!nextCompatEnabled(config)) return;
|
|
19
|
+
const file = findProxyFile(config);
|
|
20
|
+
let relative: string | undefined;
|
|
21
|
+
if (file) {
|
|
22
|
+
// Must name the SAME artifact buildProxyModule emits (the build copies it to
|
|
23
|
+
// .next/server/middleware.js), so every option that keys the compile profile is spelled out here - a
|
|
24
|
+
// divergence would be a second full compile of the proxy AND a manifest entrypoint pointing at a copy
|
|
25
|
+
// the build never emitted. Same href, so this joins that build's promise.
|
|
26
|
+
const href = await devServerModuleHref(config, file, 'prod', {
|
|
27
|
+
conditionTarget: 'edge',
|
|
28
|
+
externalLoadTarget: proxyExternalLoadTarget(file),
|
|
29
|
+
reactServerLayer: true,
|
|
30
|
+
});
|
|
31
|
+
relative = toPosixPath(path.relative(config.outPath, fileURLToPath(href)));
|
|
32
|
+
}
|
|
33
|
+
// Edge-runtime segments produce manifest entries even with no middleware.
|
|
34
|
+
await writeMiddlewareManifests(config, relative, routes as RouteManifestEntry[]);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Misc long-tail compat cluster registration (COMPAT).
|
|
2
|
+
//
|
|
3
|
+
// The misc singletons in this cluster (temporary-references, actions-streaming) hook the server-action
|
|
4
|
+
// return path directly through the shared action endpoint, and their client counterparts live inline in
|
|
5
|
+
// the action-client runtime bundle - there is no core registry seam to populate for them. The rest of the
|
|
6
|
+
// cluster is satisfied by existing core/compat behavior, so this registrar is a stable no-op hook.
|
|
7
|
+
//
|
|
8
|
+
// Kept as an explicit registrar rather than nothing, so future misc features that DO need a registry
|
|
9
|
+
// have an owned place to register without touching another file.
|
|
10
|
+
|
|
11
|
+
import type { ResolvedConfig } from '../../config';
|
|
12
|
+
import { taintObjectReference } from '../../utils/serialize';
|
|
13
|
+
import { getNextConfig } from '../next/config-loader';
|
|
14
|
+
|
|
15
|
+
// Next's `experimental.taint` message for a `process.env` reference reaching a
|
|
16
|
+
// client component (asserted verbatim by test/e2e/app-dir/taint in dev; prod
|
|
17
|
+
// sees the redacted React #441 text via the normal boundary error path).
|
|
18
|
+
const PROCESS_ENV_TAINT_MESSAGE =
|
|
19
|
+
'Do not pass process.env to Client Components since it will leak sensitive data';
|
|
20
|
+
|
|
21
|
+
// Prod redacts every RSC serialization error to React's minified #441 text
|
|
22
|
+
// (test/e2e/app-dir/taint asserts this verbatim for a production build).
|
|
23
|
+
const REDACTED_RSC_ERROR_MESSAGE =
|
|
24
|
+
'Minified React error #441; visit https://react.dev/errors/441 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.';
|
|
25
|
+
|
|
26
|
+
export function registerMiscExtensions(_config: ResolvedConfig): void {
|
|
27
|
+
// No registry wiring required for the current misc cluster; behavior is
|
|
28
|
+
// activated via direct imports in the action endpoint + client runtime.
|
|
29
|
+
registerTaintedReferences();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* `experimental.taint`: React's taint APIs do not exist under preact, so the client-props serializer
|
|
34
|
+
* enforces the same contract by identity - registering `process.env` makes any client-component prop that
|
|
35
|
+
* IS that object throw.
|
|
36
|
+
*/
|
|
37
|
+
function registerTaintedReferences(): void {
|
|
38
|
+
const experimental = getNextConfig().experimental as { taint?: unknown } | undefined;
|
|
39
|
+
if (experimental?.taint !== true) return;
|
|
40
|
+
taintObjectReference(
|
|
41
|
+
{ dev: PROCESS_ENV_TAINT_MESSAGE, prod: REDACTED_RSC_ERROR_MESSAGE },
|
|
42
|
+
process.env,
|
|
43
|
+
);
|
|
44
|
+
}
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
// OpenTelemetry extension registration (COMPAT).
|
|
2
|
+
//
|
|
3
|
+
// Wires the Next span taxonomy onto core seams without any core edit:
|
|
4
|
+
// - initHooks (build + start): remember the app root (for @opentelemetry/api resolution) and install
|
|
5
|
+
// the AppRender.fetch span wrapper.
|
|
6
|
+
// - requestExtensions.interceptors: open the root BaseServer.handleRequest span (extracting an incoming
|
|
7
|
+
// traceparent) and set its `next.route`/`http.route` from the matched route pattern. Runs late so it
|
|
8
|
+
// observes the request after action-dispatch and rewrites.
|
|
9
|
+
// - requestExtensions.responseFinalizers: close the root span with the final `http.status_code`,
|
|
10
|
+
// pre-flush.
|
|
11
|
+
// - requestExtensions.onRequestError: mark the root span errored for anything the funnel catches.
|
|
12
|
+
//
|
|
13
|
+
// Child spans are emitted from their own compat call sites. The root span alone satisfies the bulk of the
|
|
14
|
+
// opentelemetry suite. Everything is inert unless next compat is on AND @opentelemetry/api resolves from
|
|
15
|
+
// the app.
|
|
16
|
+
|
|
17
|
+
import { readFileSync } from 'node:fs';
|
|
18
|
+
import path from 'node:path';
|
|
19
|
+
import type { ResolvedConfig } from '../../config';
|
|
20
|
+
import type { RouteManifestEntry } from '../../types';
|
|
21
|
+
import {
|
|
22
|
+
registerInitHooks,
|
|
23
|
+
registerRequestInterceptors,
|
|
24
|
+
registerRequestWarmHooks,
|
|
25
|
+
registerResponseFinalizers,
|
|
26
|
+
getRequestExtensions,
|
|
27
|
+
setRequestExtensions,
|
|
28
|
+
type RequestInterceptor,
|
|
29
|
+
type ResponseFinalizer,
|
|
30
|
+
} from '../../extensions';
|
|
31
|
+
import { nextCompatEnabled } from '../index';
|
|
32
|
+
import { getRequestRuntime } from '../../routing/request-runtime';
|
|
33
|
+
import { selectRouteForRequest } from '../../routing/routes';
|
|
34
|
+
import { queueAfterTask } from '../../request/context';
|
|
35
|
+
import {
|
|
36
|
+
getDocumentScriptExtensions,
|
|
37
|
+
setRenderSpanExtensions,
|
|
38
|
+
setDocumentScriptExtensions,
|
|
39
|
+
setStreamBoundaryExtensions,
|
|
40
|
+
} from '../../render/hooks';
|
|
41
|
+
import { setProxyRunObserver } from '../../proxy';
|
|
42
|
+
import {
|
|
43
|
+
SPAN_TYPE,
|
|
44
|
+
emitClientComponentLoadingSpan,
|
|
45
|
+
emitLeafSpan,
|
|
46
|
+
emitStartResponseSpan,
|
|
47
|
+
endRootSpan,
|
|
48
|
+
endRootSpanIfUnclosed,
|
|
49
|
+
markRenderSpanError,
|
|
50
|
+
setOtelAppRoot,
|
|
51
|
+
setRootSpanRoute,
|
|
52
|
+
startRootSpan,
|
|
53
|
+
withChildSpan,
|
|
54
|
+
withMiddlewareSpan,
|
|
55
|
+
withPagesApiHandlerSpan,
|
|
56
|
+
withPagesDataSpan,
|
|
57
|
+
withRenderBodySpan,
|
|
58
|
+
withRouteHandlerSpan,
|
|
59
|
+
} from '../otel/tracer';
|
|
60
|
+
import { getOtelApi } from '../otel/api';
|
|
61
|
+
import { installFetchSpan } from '../otel/fetch-span';
|
|
62
|
+
import { clientTraceMetadataTags } from '../otel/client-trace-metadata';
|
|
63
|
+
import { instrumentationReady } from '../lifecycle/instrumentation';
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The ROOT-span interceptor. Registered FIRST, before every other sub-registrar, so the
|
|
67
|
+
* `BaseServer.handleRequest` span is open before any short-circuiting interceptor (segment `_tree`
|
|
68
|
+
* prefetches, the RSC protocol responder, action dispatch) produces a response - those responses still
|
|
69
|
+
* flow through the response finalizer, which closes the span. The route attributes are stamped
|
|
70
|
+
* immediately from the pre-rewrite match; the LATE interceptor re-stamps them after rewrites.
|
|
71
|
+
*/
|
|
72
|
+
export function registerOtelRootInterceptor(config: ResolvedConfig): void {
|
|
73
|
+
if (!nextCompatEnabled(config)) return;
|
|
74
|
+
setOtelAppRoot(config.root);
|
|
75
|
+
|
|
76
|
+
const rootInterceptor: RequestInterceptor = async request => {
|
|
77
|
+
try {
|
|
78
|
+
// Instrumentation register() installs the app's TracerProvider; opening
|
|
79
|
+
// the root span before it completes would produce a non-recording span.
|
|
80
|
+
await instrumentationReady();
|
|
81
|
+
const url = new URL(request.url);
|
|
82
|
+
startRootSpan({
|
|
83
|
+
method: request.method.toUpperCase(),
|
|
84
|
+
target: url.pathname + url.search,
|
|
85
|
+
rsc: request.headers.get('rsc') === '1',
|
|
86
|
+
headers: request.headers,
|
|
87
|
+
});
|
|
88
|
+
stampMatchedRoute(url.pathname);
|
|
89
|
+
// Safety net for the synchronous-500 error path: core's top-level catch
|
|
90
|
+
// returns a bare 500 WITHOUT running responseFinalizers, so the finalizer
|
|
91
|
+
// never closes the root span there. The work-unit after-queue DOES flush
|
|
92
|
+
// on that path (flushWorkUnit in the catch), so end the span as 500 from
|
|
93
|
+
// an after-task. Idempotent: on success paths the finalizer ends it first.
|
|
94
|
+
queueAfterTask(() => endRootSpanIfUnclosed(500));
|
|
95
|
+
} catch {
|
|
96
|
+
// Never let tracing break the request.
|
|
97
|
+
}
|
|
98
|
+
return undefined;
|
|
99
|
+
};
|
|
100
|
+
registerRequestInterceptors(rootInterceptor);
|
|
101
|
+
// Resolving @opentelemetry/api out of the app loads the whole package inside this interceptor on
|
|
102
|
+
// the first request. The result is memoized, so paying it in the dev warm just moves it off that
|
|
103
|
+
// request.
|
|
104
|
+
registerRequestWarmHooks(() => void getOtelApi(config.root));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Resolve the matched route for `pathname` and stamp it on the root span. */
|
|
108
|
+
function stampMatchedRoute(pathname: string): void {
|
|
109
|
+
const runtime = getRequestRuntime();
|
|
110
|
+
if (!runtime) return;
|
|
111
|
+
const matched = selectRouteForRequest(runtime.routes, pathname, undefined);
|
|
112
|
+
if (!matched) return;
|
|
113
|
+
const routeRuntime = matched.route.segmentConfig?.runtime;
|
|
114
|
+
setRootSpanRoute(routeEntryToDisplay(matched.route), {
|
|
115
|
+
edge: routeRuntime === 'edge' || routeRuntime === 'experimental-edge',
|
|
116
|
+
kind: matched.route.kind === 'handler' ? 'handler' : 'page',
|
|
117
|
+
params: matched.params,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function registerOtelExtensions(config: ResolvedConfig): void {
|
|
122
|
+
if (!nextCompatEnabled(config)) return;
|
|
123
|
+
|
|
124
|
+
const appRoot = config.root;
|
|
125
|
+
setOtelAppRoot(appRoot);
|
|
126
|
+
|
|
127
|
+
// Install the fetch span wrapper at server (and build) start, AFTER the cache
|
|
128
|
+
// fetch-patch has wrapped globalThis.fetch (register order: cache before otel).
|
|
129
|
+
registerInitHooks(() => {
|
|
130
|
+
installFetchSpan(appRoot);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// Materialized pages wrappers (compat/pages wrapperSource) call this global —
|
|
134
|
+
// when present — around their getServerSideProps/getStaticProps invocation so
|
|
135
|
+
// the `Render.<kind>` span lands beside the document render span. A global
|
|
136
|
+
// (not an import) keeps the generated bundles pnext-agnostic.
|
|
137
|
+
(
|
|
138
|
+
globalThis as { __PNEXT_PAGES_DATA_SPAN__?: typeof withPagesDataSpan }
|
|
139
|
+
).__PNEXT_PAGES_DATA_SPAN__ = withPagesDataSpan;
|
|
140
|
+
|
|
141
|
+
// Render-internal spans (nest under the request root span via the work-unit
|
|
142
|
+
// ALS the tracer threads): the render-body span (`render route (app)`), the
|
|
143
|
+
// route-resolution span (`resolve page components`), and cheap leaf
|
|
144
|
+
// segment-module spans. All inert when no root span is open.
|
|
145
|
+
setRenderSpanExtensions({
|
|
146
|
+
withRenderBodySpan: (route, fn) => {
|
|
147
|
+
const displayRoute = routePatternToDisplay(route);
|
|
148
|
+
// A materialized pages route renders through the app pipeline, but Next
|
|
149
|
+
// reports it as the pages-router document render span.
|
|
150
|
+
if (isPagesCompatRoute(route)) {
|
|
151
|
+
return withRenderBodySpan(
|
|
152
|
+
`render route (pages) ${displayRoute}`,
|
|
153
|
+
displayRoute,
|
|
154
|
+
fn,
|
|
155
|
+
SPAN_TYPE.renderDocument,
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
return withRenderBodySpan(
|
|
159
|
+
`render route (app) ${displayRoute}`,
|
|
160
|
+
displayRoute,
|
|
161
|
+
fn,
|
|
162
|
+
);
|
|
163
|
+
},
|
|
164
|
+
withFindPageComponentsSpan: (route, fn) => {
|
|
165
|
+
const entry = routeEntryFor(route);
|
|
166
|
+
// A materialized pages-API route reports ONLY its Node.runHandler span
|
|
167
|
+
// (Next's pages-api dispatch has no findPageComponents phase).
|
|
168
|
+
if (entry?.kind === 'handler' && isPagesCompatEntry(entry)) return fn();
|
|
169
|
+
const displayRoute = routePatternToDisplay(route);
|
|
170
|
+
return withChildSpan(
|
|
171
|
+
'resolve page components',
|
|
172
|
+
SPAN_TYPE.findPageComponents,
|
|
173
|
+
{ 'next.route': displayRoute },
|
|
174
|
+
fn,
|
|
175
|
+
);
|
|
176
|
+
},
|
|
177
|
+
emitResolveSegmentSpan: segment =>
|
|
178
|
+
emitLeafSpan('resolve segment modules', SPAN_TYPE.getLayoutOrPageModule, {
|
|
179
|
+
'next.segment': segment,
|
|
180
|
+
}),
|
|
181
|
+
withRouteHandlerSpan: (route, fn) =>
|
|
182
|
+
isPagesCompatRoute(route)
|
|
183
|
+
? withPagesApiHandlerSpan(routePatternToDisplay(route), fn)
|
|
184
|
+
: withRouteHandlerSpan(routePatternToDisplay(route), fn),
|
|
185
|
+
});
|
|
186
|
+
setStreamBoundaryExtensions({ onStreamBoundaryError: markRenderSpanError });
|
|
187
|
+
|
|
188
|
+
// clientTraceMetadata meta tags injected once into the document head (dynamic pages only; a production
|
|
189
|
+
// start skips static). Composed with register-render's documentBodyScripts under a separate key.
|
|
190
|
+
// The renderer's `ctx.dynamic` already encodes Next's gating: dev renders are always dynamic, a prod
|
|
191
|
+
// STATIC page is dynamic:false, a prod DYNAMIC page is dynamic:true. So isNextStart:true is safe -
|
|
192
|
+
// clientTraceMetadataTags only drops when isNextStart && !dynamic, exactly the prod-static case.
|
|
193
|
+
const previousHeadTags = getDocumentScriptExtensions().documentHeadTags;
|
|
194
|
+
setDocumentScriptExtensions({
|
|
195
|
+
documentHeadTags: (cfg, ctx) =>
|
|
196
|
+
`${previousHeadTags?.(cfg, ctx) ?? ''}${clientTraceMetadataTags({ dynamic: ctx.dynamic, isNextStart: true, rsc: ctx.rsc })}`,
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// Middleware.execute span around the proxy/middleware handler run. Parents
|
|
200
|
+
// under the incoming traceparent (top-level trace), NOT the request root span.
|
|
201
|
+
setProxyRunObserver((request, fn) => withMiddlewareSpan(request, fn));
|
|
202
|
+
|
|
203
|
+
const previousOnRequestError = getRequestExtensions().onRequestError;
|
|
204
|
+
setRequestExtensions({
|
|
205
|
+
onRequestError: async (error, requestInfo, context) => {
|
|
206
|
+
markRenderSpanError(error);
|
|
207
|
+
await previousOnRequestError(error, requestInfo, context);
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
// Late interceptor: re-stamp the route attributes after the rewrite/action
|
|
212
|
+
// interceptors ran, so a rewritten request reports its DESTINATION route
|
|
213
|
+
// (the root span itself was opened by the early interceptor with the
|
|
214
|
+
// original target — see registerOtelRootInterceptor).
|
|
215
|
+
const otelRouteInterceptor: RequestInterceptor = request => {
|
|
216
|
+
try {
|
|
217
|
+
stampMatchedRoute(new URL(request.url).pathname);
|
|
218
|
+
} catch {
|
|
219
|
+
// Never let tracing break the request.
|
|
220
|
+
}
|
|
221
|
+
return Promise.resolve(undefined);
|
|
222
|
+
};
|
|
223
|
+
registerRequestInterceptors(otelRouteInterceptor);
|
|
224
|
+
|
|
225
|
+
// Close the root span pre-flush with the final status. Runs on every response-producing path (page
|
|
226
|
+
// render, route handler, static file, redirect, 404). Before closing, emit the pre-flush leaf spans Next
|
|
227
|
+
// nests in the tree: `clientComponentLoading` (page renders only) and `start response` under the open
|
|
228
|
+
// render span for pages, or the root for handlers.
|
|
229
|
+
const otelFinalizer: ResponseFinalizer = ctx => {
|
|
230
|
+
try {
|
|
231
|
+
if (ctx.routeKind === 'html') emitClientComponentLoadingSpan(0);
|
|
232
|
+
if (ctx.routeKind === 'html' || ctx.routeKind === 'route-handler') {
|
|
233
|
+
emitStartResponseSpan();
|
|
234
|
+
}
|
|
235
|
+
endRootSpan(ctx.status);
|
|
236
|
+
} catch {
|
|
237
|
+
// ignore
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
registerResponseFinalizers(otelFinalizer);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/** The runtime route entry matching a raw route pattern. */
|
|
244
|
+
function routeEntryFor(routePattern: string): RouteManifestEntry | undefined {
|
|
245
|
+
return getRequestRuntime()?.routes.find(r => r.route === routePattern);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// A hybrid app materializes BOTH trees under `pnext-pages-compat`: native app
|
|
249
|
+
// files become `source-app/...` shims, pages files become `source-pages/...`
|
|
250
|
+
// wrappers. Only the latter are pages-router routes. The import specifier is a
|
|
251
|
+
// stable generator-owned marker; cache per file (routes don't change at start).
|
|
252
|
+
const pagesCompatFileCache = new Map<string, boolean>();
|
|
253
|
+
function isPagesCompatEntry(entry: RouteManifestEntry | undefined): boolean {
|
|
254
|
+
if (!entry?.file.includes(`${path.sep}pnext-pages-compat${path.sep}`)) return false;
|
|
255
|
+
let cached = pagesCompatFileCache.get(entry.file);
|
|
256
|
+
if (cached === undefined) {
|
|
257
|
+
try {
|
|
258
|
+
cached = readFileSync(entry.file, 'utf8').includes('source-pages/');
|
|
259
|
+
} catch {
|
|
260
|
+
cached = false;
|
|
261
|
+
}
|
|
262
|
+
pagesCompatFileCache.set(entry.file, cached);
|
|
263
|
+
}
|
|
264
|
+
return cached;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/** Whether `routePattern` matches a route materialized from `pages/`. */
|
|
268
|
+
function isPagesCompatRoute(routePattern: string): boolean {
|
|
269
|
+
return isPagesCompatEntry(routeEntryFor(routePattern));
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function routeEntryToDisplay(route: RouteManifestEntry): string {
|
|
273
|
+
let value = route.route || '/';
|
|
274
|
+
if (route.catchAll) {
|
|
275
|
+
const token = route.catchAllOptional
|
|
276
|
+
? `[[...${route.catchAll}]]`
|
|
277
|
+
: `[...${route.catchAll}]`;
|
|
278
|
+
value = value.replace(`:${route.catchAll}*`, token);
|
|
279
|
+
}
|
|
280
|
+
for (const param of route.params) value = value.replace(`:${param}`, `[${param}]`);
|
|
281
|
+
return value;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function routePatternToDisplay(route: string): string {
|
|
285
|
+
return route
|
|
286
|
+
.replace(/:([A-Za-z0-9_]+)\*/g, '[...$1]')
|
|
287
|
+
.replace(/:([A-Za-z0-9_]+)/g, '[$1]');
|
|
288
|
+
}
|