@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.
Files changed (371) hide show
  1. package/README.md +153 -0
  2. package/bin/pnext +67 -0
  3. package/config/lint/base.js +48 -0
  4. package/config/ts/base.json +26 -0
  5. package/config/ts/react.json +13 -0
  6. package/package.json +70 -0
  7. package/reference/compat.md +63 -0
  8. package/reference/config.md +120 -0
  9. package/reference/css.md +58 -0
  10. package/reference/dev.md +69 -0
  11. package/reference/env.md +40 -0
  12. package/reference/metadata.md +86 -0
  13. package/reference/navigation.md +149 -0
  14. package/reference/overview.md +35 -0
  15. package/reference/performance.md +97 -0
  16. package/reference/rendering.md +127 -0
  17. package/reference/routing.md +167 -0
  18. package/reference/typegen.md +64 -0
  19. package/src/api/cache.ts +80 -0
  20. package/src/api/client-cache.ts +9 -0
  21. package/src/api/client-navigation.ts +279 -0
  22. package/src/api/dynamic.tsx +102 -0
  23. package/src/api/link.tsx +119 -0
  24. package/src/api/navigation.ts +198 -0
  25. package/src/api/router/events.ts +53 -0
  26. package/src/api/router/history.ts +70 -0
  27. package/src/api/router/hub.ts +194 -0
  28. package/src/api/router/policies.ts +107 -0
  29. package/src/api/router/runtime.ts +5238 -0
  30. package/src/api/router/types.ts +299 -0
  31. package/src/api/router.ts +167 -0
  32. package/src/api/server.ts +323 -0
  33. package/src/api/suspense.ts +16 -0
  34. package/src/cache/context.ts +61 -0
  35. package/src/cli/adapters/vercel-warm.ts +375 -0
  36. package/src/cli/adapters/vercel.ts +1310 -0
  37. package/src/cli/analyze-print.ts +181 -0
  38. package/src/cli/analyze.ts +328 -0
  39. package/src/cli/boot-trace.ts +29 -0
  40. package/src/cli/build.ts +3114 -0
  41. package/src/cli/dev.ts +276 -0
  42. package/src/cli/index.ts +196 -0
  43. package/src/cli/named-bin.ts +119 -0
  44. package/src/cli/serve-ui.ts +160 -0
  45. package/src/cli/start.ts +1425 -0
  46. package/src/client/build.ts +2136 -0
  47. package/src/client/chunk-fold.ts +526 -0
  48. package/src/client/entry.ts +1525 -0
  49. package/src/client/paths.ts +22 -0
  50. package/src/client/prebuilt.ts +621 -0
  51. package/src/client/profile.ts +75 -0
  52. package/src/client/react-compiler.ts +94 -0
  53. package/src/client/reference-stub.ts +145 -0
  54. package/src/client/reference.ts +47 -0
  55. package/src/compat/actions/action-client.ts +531 -0
  56. package/src/compat/actions/action-dispatch.ts +676 -0
  57. package/src/compat/actions/action-router.ts +40 -0
  58. package/src/compat/actions/action-shared.ts +95 -0
  59. package/src/compat/actions/client-plugin.ts +135 -0
  60. package/src/compat/actions/client-stub.ts +65 -0
  61. package/src/compat/actions/config.ts +164 -0
  62. package/src/compat/actions/detect.ts +208 -0
  63. package/src/compat/actions/discovery.ts +244 -0
  64. package/src/compat/actions/early-submit.ts +40 -0
  65. package/src/compat/actions/endpoint.ts +602 -0
  66. package/src/compat/actions/flight.ts +52 -0
  67. package/src/compat/actions/form-state.ts +73 -0
  68. package/src/compat/actions/hoist.ts +485 -0
  69. package/src/compat/actions/ids.ts +39 -0
  70. package/src/compat/actions/index.ts +41 -0
  71. package/src/compat/actions/instances.ts +144 -0
  72. package/src/compat/actions/origin.ts +109 -0
  73. package/src/compat/actions/protocol.ts +125 -0
  74. package/src/compat/actions/registry.ts +74 -0
  75. package/src/compat/actions/rewrite.ts +282 -0
  76. package/src/compat/actions/serve.ts +414 -0
  77. package/src/compat/actions/server-tag.ts +21 -0
  78. package/src/compat/actions/unrecognized-error.ts +30 -0
  79. package/src/compat/adapter/build-complete.ts +257 -0
  80. package/src/compat/bundler/bun-externals.ts +53 -0
  81. package/src/compat/bundler/cjs-exports.ts +542 -0
  82. package/src/compat/bundler/config.ts +363 -0
  83. package/src/compat/bundler/externals.ts +34 -0
  84. package/src/compat/bundler/import-meta-url.ts +60 -0
  85. package/src/compat/bundler/modularize-imports.ts +119 -0
  86. package/src/compat/bundler/new-url-asset.ts +87 -0
  87. package/src/compat/bundler/optimize-package-imports.ts +273 -0
  88. package/src/compat/bundler/polyfill.ts +88 -0
  89. package/src/compat/bundler/react-compiler.ts +61 -0
  90. package/src/compat/bundler/react-profiler.tsx +25 -0
  91. package/src/compat/bundler/relay-transform.ts +116 -0
  92. package/src/compat/bundler/require-context.ts +281 -0
  93. package/src/compat/bundler/resolve-extensions.ts +75 -0
  94. package/src/compat/bundler/source-cache.ts +61 -0
  95. package/src/compat/bundler/static-imports.ts +25 -0
  96. package/src/compat/bundler/symlink-imports.ts +119 -0
  97. package/src/compat/bundler/tsconfig-paths.ts +50 -0
  98. package/src/compat/bundler/wasm.ts +153 -0
  99. package/src/compat/bundler/webpack-loaders.ts +685 -0
  100. package/src/compat/bundler/worker.ts +278 -0
  101. package/src/compat/cache/build-flags.ts +81 -0
  102. package/src/compat/cache/build-prerender-errors.ts +163 -0
  103. package/src/compat/cache/custom-handler.ts +159 -0
  104. package/src/compat/cache/fetch-patch.ts +745 -0
  105. package/src/compat/cache/handler.ts +100 -0
  106. package/src/compat/cache/modern-handler.ts +275 -0
  107. package/src/compat/cache/resume-data-cache.ts +143 -0
  108. package/src/compat/cache/revalidate.ts +759 -0
  109. package/src/compat/cache/runtime-error.ts +124 -0
  110. package/src/compat/cache/use-cache-transform.ts +961 -0
  111. package/src/compat/cache/use-cache.ts +1695 -0
  112. package/src/compat/cache-control.ts +269 -0
  113. package/src/compat/client/base-path.ts +64 -0
  114. package/src/compat/client/css-order.ts +36 -0
  115. package/src/compat/client/errors/control-flow.ts +92 -0
  116. package/src/compat/client/errors/error-boundary.ts +222 -0
  117. package/src/compat/client/errors/global-error.ts +238 -0
  118. package/src/compat/client/errors/install.ts +217 -0
  119. package/src/compat/client/errors/lazy.ts +53 -0
  120. package/src/compat/client/errors/primitive-throw.ts +126 -0
  121. package/src/compat/client/errors/soft-refresh.ts +14 -0
  122. package/src/compat/client/link-status.ts +86 -0
  123. package/src/compat/client/nav-compat-runtime.ts +57 -0
  124. package/src/compat/client/nav-compat.ts +42 -0
  125. package/src/compat/client/navigation-scroll.ts +154 -0
  126. package/src/compat/client/optimistic-routing.ts +206 -0
  127. package/src/compat/client/prefetch-cache.ts +111 -0
  128. package/src/compat/client/route-announcer.ts +72 -0
  129. package/src/compat/client/segment-cache-policy.ts +159 -0
  130. package/src/compat/client/segment-cache.ts +1077 -0
  131. package/src/compat/client/segment-prefetch.ts +375 -0
  132. package/src/compat/client/trailing-slash.ts +24 -0
  133. package/src/compat/css/chunking.ts +254 -0
  134. package/src/compat/css/inline-css.ts +73 -0
  135. package/src/compat/css/lightningcss.ts +90 -0
  136. package/src/compat/css/modules.ts +373 -0
  137. package/src/compat/css/nonce.ts +30 -0
  138. package/src/compat/css/sass-plugin.ts +65 -0
  139. package/src/compat/css/sass.ts +392 -0
  140. package/src/compat/css/styled-jsx-runtime.ts +80 -0
  141. package/src/compat/css/styled-jsx.ts +49 -0
  142. package/src/compat/edge-runtime.ts +71 -0
  143. package/src/compat/export/client.ts +112 -0
  144. package/src/compat/export/index.ts +272 -0
  145. package/src/compat/export/standalone.ts +207 -0
  146. package/src/compat/image-optimizer/cache.ts +119 -0
  147. package/src/compat/image-optimizer/detect.ts +143 -0
  148. package/src/compat/image-optimizer/index.ts +601 -0
  149. package/src/compat/image-optimizer/source.ts +243 -0
  150. package/src/compat/index.ts +458 -0
  151. package/src/compat/lifecycle/after-scope.ts +86 -0
  152. package/src/compat/lifecycle/after.ts +173 -0
  153. package/src/compat/lifecycle/error-funnel.ts +306 -0
  154. package/src/compat/lifecycle/error-serialize.ts +87 -0
  155. package/src/compat/lifecycle/error-ui.ts +167 -0
  156. package/src/compat/lifecycle/instrumentation-client.ts +138 -0
  157. package/src/compat/lifecycle/instrumentation.ts +277 -0
  158. package/src/compat/lifecycle/node-console.ts +19 -0
  159. package/src/compat/lifecycle/testmode.ts +263 -0
  160. package/src/compat/mdx/compile.ts +219 -0
  161. package/src/compat/mdx/next-mdx-stub.ts +46 -0
  162. package/src/compat/mdx/plugin.ts +37 -0
  163. package/src/compat/metadata-route-artifacts.ts +458 -0
  164. package/src/compat/metadata.ts +295 -0
  165. package/src/compat/middleware/manifest.ts +210 -0
  166. package/src/compat/misc/action-return.ts +173 -0
  167. package/src/compat/next/cache.ts +211 -0
  168. package/src/compat/next/canonical-url.ts +35 -0
  169. package/src/compat/next/client-cache.ts +57 -0
  170. package/src/compat/next/client-navigation.ts +313 -0
  171. package/src/compat/next/client-only.ts +3 -0
  172. package/src/compat/next/client-script.tsx +215 -0
  173. package/src/compat/next/client-server.ts +39 -0
  174. package/src/compat/next/config-loader.ts +569 -0
  175. package/src/compat/next/config.ts +29 -0
  176. package/src/compat/next/constants.cjs +6 -0
  177. package/src/compat/next/constants.ts +6 -0
  178. package/src/compat/next/custom-server.ts +236 -0
  179. package/src/compat/next/dist/client/components/app-router-headers.ts +32 -0
  180. package/src/compat/next/dist/server/app-render/work-unit-async-storage.external.cjs +38 -0
  181. package/src/compat/next/dist/server/web/spec-extension/revalidate.ts +1 -0
  182. package/src/compat/next/dist/server/web/spec-extension/unstable-cache.ts +1 -0
  183. package/src/compat/next/dist/server/web/spec-extension/unstable-no-store.ts +1 -0
  184. package/src/compat/next/dynamic.tsx +46 -0
  185. package/src/compat/next/error.tsx +148 -0
  186. package/src/compat/next/font/cache.ts +171 -0
  187. package/src/compat/next/font/google.ts +2 -0
  188. package/src/compat/next/font/index.ts +8 -0
  189. package/src/compat/next/font/local.ts +5 -0
  190. package/src/compat/next/font/runtime-client.ts +71 -0
  191. package/src/compat/next/font/runtime.ts +974 -0
  192. package/src/compat/next/font/shared.ts +281 -0
  193. package/src/compat/next/form.tsx +156 -0
  194. package/src/compat/next/head.tsx +10 -0
  195. package/src/compat/next/headers.ts +247 -0
  196. package/src/compat/next/image/config.ts +196 -0
  197. package/src/compat/next/image/optimizer.ts +96 -0
  198. package/src/compat/next/image/patterns.ts +103 -0
  199. package/src/compat/next/image/shared.ts +141 -0
  200. package/src/compat/next/image/static-metadata.ts +283 -0
  201. package/src/compat/next/image/validate.ts +269 -0
  202. package/src/compat/next/image-client.tsx +215 -0
  203. package/src/compat/next/image-props.ts +575 -0
  204. package/src/compat/next/image-usage.ts +102 -0
  205. package/src/compat/next/image.tsx +56 -0
  206. package/src/compat/next/index.ts +1 -0
  207. package/src/compat/next/legacy-image.tsx +97 -0
  208. package/src/compat/next/link-usage.ts +29 -0
  209. package/src/compat/next/link-validation-transform.ts +200 -0
  210. package/src/compat/next/link.tsx +466 -0
  211. package/src/compat/next/navigation.cjs +21 -0
  212. package/src/compat/next/navigation.ts +188 -0
  213. package/src/compat/next/offline.ts +51 -0
  214. package/src/compat/next/og.ts +324 -0
  215. package/src/compat/next/optimistic-route-state.ts +188 -0
  216. package/src/compat/next/preferred-region.ts +39 -0
  217. package/src/compat/next/redirects.ts +131 -0
  218. package/src/compat/next/resource-hints.ts +136 -0
  219. package/src/compat/next/rewrites.ts +350 -0
  220. package/src/compat/next/root-params.ts +142 -0
  221. package/src/compat/next/router.cjs +49 -0
  222. package/src/compat/next/router.ts +143 -0
  223. package/src/compat/next/script.tsx +355 -0
  224. package/src/compat/next/server-only.ts +3 -0
  225. package/src/compat/next/server.ts +28 -0
  226. package/src/compat/next/svgr.ts +58 -0
  227. package/src/compat/next/telemetry.ts +77 -0
  228. package/src/compat/next/user-agent.ts +100 -0
  229. package/src/compat/next/web-vitals.ts +56 -0
  230. package/src/compat/otel/api.ts +95 -0
  231. package/src/compat/otel/client-trace-metadata.ts +71 -0
  232. package/src/compat/otel/fetch-span.ts +77 -0
  233. package/src/compat/otel/tracer.ts +944 -0
  234. package/src/compat/pages/client-plugin.ts +108 -0
  235. package/src/compat/pages/index.ts +527 -0
  236. package/src/compat/pages/router-state.ts +94 -0
  237. package/src/compat/ppr/io.ts +38 -0
  238. package/src/compat/ppr/missing-root-params.ts +105 -0
  239. package/src/compat/ppr/root-params-scan.ts +164 -0
  240. package/src/compat/ppr/root-params-transform.ts +75 -0
  241. package/src/compat/ppr/root-params.ts +129 -0
  242. package/src/compat/ppr/segment-config-incompat.ts +34 -0
  243. package/src/compat/protocol.ts +202 -0
  244. package/src/compat/react/client.ts +59 -0
  245. package/src/compat/react/compiler-runtime.ts +60 -0
  246. package/src/compat/react/dom-client.ts +115 -0
  247. package/src/compat/react/dom-react-server.ts +20 -0
  248. package/src/compat/react/dom-server.ts +40 -0
  249. package/src/compat/react/dom.ts +154 -0
  250. package/src/compat/react/preact.ts +522 -0
  251. package/src/compat/react/react-server.ts +84 -0
  252. package/src/compat/react/router-shim.ts +26 -0
  253. package/src/compat/react/server-component-use.ts +48 -0
  254. package/src/compat/react/server-inserted-html.ts +87 -0
  255. package/src/compat/react/server.ts +156 -0
  256. package/src/compat/react/view-transition.ts +60 -0
  257. package/src/compat/register/actions.ts +875 -0
  258. package/src/compat/register/boot.ts +141 -0
  259. package/src/compat/register/build-tier.ts +11 -0
  260. package/src/compat/register/build.ts +182 -0
  261. package/src/compat/register/bundler.ts +587 -0
  262. package/src/compat/register/cache.ts +85 -0
  263. package/src/compat/register/client-errors.ts +18 -0
  264. package/src/compat/register/config.ts +17 -0
  265. package/src/compat/register/css-extras.ts +120 -0
  266. package/src/compat/register/edge-runtime.ts +6 -0
  267. package/src/compat/register/errors.ts +46 -0
  268. package/src/compat/register/export.ts +23 -0
  269. package/src/compat/register/font.ts +36 -0
  270. package/src/compat/register/hooks.ts +34 -0
  271. package/src/compat/register/image.ts +133 -0
  272. package/src/compat/register/index.ts +111 -0
  273. package/src/compat/register/instrumentation-client.ts +35 -0
  274. package/src/compat/register/lifecycle.ts +86 -0
  275. package/src/compat/register/mdx.ts +48 -0
  276. package/src/compat/register/middleware.ts +36 -0
  277. package/src/compat/register/misc.ts +44 -0
  278. package/src/compat/register/otel.ts +288 -0
  279. package/src/compat/register/pages-api.ts +473 -0
  280. package/src/compat/register/ppr.ts +56 -0
  281. package/src/compat/register/protocol.ts +57 -0
  282. package/src/compat/register/proxy.ts +127 -0
  283. package/src/compat/register/render.ts +268 -0
  284. package/src/compat/register/routing.ts +410 -0
  285. package/src/compat/register/segment.ts +1903 -0
  286. package/src/compat/register/static-image.ts +21 -0
  287. package/src/compat/register/typed-routes.ts +35 -0
  288. package/src/compat/register/usecache.ts +131 -0
  289. package/src/compat/register/validation.ts +56 -0
  290. package/src/compat/segment/loading-boundary.ts +113 -0
  291. package/src/compat/segment/page-slot.ts +200 -0
  292. package/src/compat/segment/tree.ts +481 -0
  293. package/src/compat/segment/vary-key.ts +102 -0
  294. package/src/compat/segment/vary-params.ts +551 -0
  295. package/src/compat/static-params.ts +33 -0
  296. package/src/compat/tsconfig-defaults.ts +301 -0
  297. package/src/compat/typecheck/index.ts +1481 -0
  298. package/src/compat/typecheck/worker.ts +26 -0
  299. package/src/compat/typed-routes/index.ts +92 -0
  300. package/src/compat/typed-routes/manifest.ts +356 -0
  301. package/src/compat/typed-routes/typegen.ts +566 -0
  302. package/src/compat/validation/errors.ts +159 -0
  303. package/src/compat/validation/index.ts +1770 -0
  304. package/src/compat/validation/prerender-diagnostics.ts +1508 -0
  305. package/src/compat-bootstrap.ts +67 -0
  306. package/src/config.ts +218 -0
  307. package/src/css/build.ts +697 -0
  308. package/src/css/index.ts +2 -0
  309. package/src/css/postcss.ts +236 -0
  310. package/src/css/worker.ts +34 -0
  311. package/src/dev/client-actions.ts +35 -0
  312. package/src/dev/client-chunk-store.ts +92 -0
  313. package/src/dev/client-key-cache.ts +178 -0
  314. package/src/dev/global-css-cache.ts +212 -0
  315. package/src/dev/imports.ts +2430 -0
  316. package/src/dev/module-cache.ts +721 -0
  317. package/src/dev/module-generations.ts +38 -0
  318. package/src/dev/module-transform.ts +188 -0
  319. package/src/dev/node-module-bundle-cache.ts +63 -0
  320. package/src/dev/restart-cache.ts +10 -0
  321. package/src/dev/route-bundle-key-cache.ts +154 -0
  322. package/src/dev/route-facts-cache.ts +223 -0
  323. package/src/dev/server.ts +1710 -0
  324. package/src/dynamic/source.ts +307 -0
  325. package/src/dynamic/tree-shake.ts +262 -0
  326. package/src/env.ts +92 -0
  327. package/src/extensions.ts +1898 -0
  328. package/src/index.ts +34 -0
  329. package/src/internal.ts +43 -0
  330. package/src/islands/boundary-error.ts +8 -0
  331. package/src/islands/static-children.ts +37 -0
  332. package/src/islands/static-slots.ts +106 -0
  333. package/src/ppr-postpone.ts +24 -0
  334. package/src/ppr.ts +784 -0
  335. package/src/proxy.ts +752 -0
  336. package/src/render/hooks.ts +384 -0
  337. package/src/render/index.ts +1 -0
  338. package/src/render/island-context.ts +47 -0
  339. package/src/render/metadata.ts +857 -0
  340. package/src/render/renderer.ts +7391 -0
  341. package/src/render/resource-hints.ts +44 -0
  342. package/src/render/slots.tsx +679 -0
  343. package/src/request/context.ts +396 -0
  344. package/src/resolve/engine.ts +219 -0
  345. package/src/resolve/imports.ts +1104 -0
  346. package/src/resolve/scan-facts.ts +474 -0
  347. package/src/resolve/source-text.ts +86 -0
  348. package/src/routing/forwarded.ts +41 -0
  349. package/src/routing/handler.ts +271 -0
  350. package/src/routing/href.ts +203 -0
  351. package/src/routing/metadata.ts +1018 -0
  352. package/src/routing/request-runtime.ts +43 -0
  353. package/src/routing/routes.ts +2560 -0
  354. package/src/routing/slots.ts +432 -0
  355. package/src/runtime/server.ts +3453 -0
  356. package/src/runtime/vendor.ts +1160 -0
  357. package/src/style-modules.d.ts +9 -0
  358. package/src/typegen.ts +151 -0
  359. package/src/types.ts +725 -0
  360. package/src/utils/ansi.ts +9 -0
  361. package/src/utils/content-type.ts +31 -0
  362. package/src/utils/decode.ts +7 -0
  363. package/src/utils/dev-profile.ts +31 -0
  364. package/src/utils/error-log.ts +29 -0
  365. package/src/utils/fs-cache.ts +31 -0
  366. package/src/utils/fs.ts +119 -0
  367. package/src/utils/html.ts +46 -0
  368. package/src/utils/serialize.ts +378 -0
  369. package/src/utils/source.ts +35 -0
  370. package/src/utils/verbose.ts +39 -0
  371. package/tsconfig.json +10 -0
@@ -0,0 +1,466 @@
1
+ import {
2
+ Children,
3
+ cloneElement,
4
+ createElement,
5
+ forwardRef,
6
+ useContext,
7
+ useEffect,
8
+ useRef,
9
+ useState,
10
+ type MutableRefObject,
11
+ type ReactElement,
12
+ type ReactNode,
13
+ type Ref,
14
+ } from 'preact/compat';
15
+ import type { JSX } from 'preact';
16
+ import { usePrefetchLifecycle } from '../../api/link';
17
+ import { blockJavascriptUrl, isJavascriptUrl } from '../../api/router';
18
+ import { applyTrailingSlash, routeHref, type SearchInput } from '../../routing/href';
19
+ import { skipTrailingSlashRedirect } from '../client/trailing-slash';
20
+ import type { PrefetchMode } from '../../types';
21
+ import {
22
+ LinkStatusContext,
23
+ linkPending,
24
+ navigateWithStatus,
25
+ subscribeLinkStatus,
26
+ } from '../client/link-status';
27
+ import { addBasePath } from '../client/base-path';
28
+ import { addTransitionType } from '../react/view-transition';
29
+
30
+ const reactClientReferenceSymbol = Symbol.for('react.client.reference');
31
+
32
+ // Client-graph bundler define (compat/register/bundler.ts): false drops the
33
+ // whole legacy child path from a bundle whose app provably never renders
34
+ // `<Link legacyBehavior>`. Undefined (server render, unbundled consumer) keeps
35
+ // it, so the gate can only ever remove bytes an app proved it cannot use.
36
+ declare const __PNEXT_LINK_LEGACY__: boolean;
37
+ type LegacyChildKind =
38
+ | 'server-sync'
39
+ | 'server-async'
40
+ | 'server-async-through-client'
41
+ | 'lazy'
42
+ | 'client-lazy';
43
+
44
+ export interface UrlObject {
45
+ pathname?: string;
46
+ query?: SearchInput;
47
+ hash?: string;
48
+ }
49
+
50
+ export interface NavigateEvent {
51
+ preventDefault(): void;
52
+ }
53
+
54
+ export type LinkProps = Omit<JSX.HTMLAttributes<HTMLAnchorElement>, 'href' | 'onClick' | 'ref'> & {
55
+ href: string | URL | UrlObject;
56
+ as?: string | URL | UrlObject;
57
+ replace?: boolean;
58
+ scroll?: boolean;
59
+ prefetch?: boolean | 'auto' | 'unstable_forceStale' | null;
60
+ /** Hovering the link upgrades its prefetch to include the dynamic data. */
61
+ unstable_dynamicOnHover?: boolean;
62
+ locale?: string | false;
63
+ legacyBehavior?: boolean;
64
+ passHref?: boolean;
65
+ onClick?: JSX.MouseEventHandler<HTMLAnchorElement>;
66
+ onNavigate?: (event: NavigateEvent) => void;
67
+ /**
68
+ * View-transition types declared for the navigation this Link starts, so
69
+ * `:active-view-transition-type(...)` rules match while it runs. Consumed
70
+ * here (never forwarded to the anchor as an attribute).
71
+ */
72
+ transitionTypes?: string[];
73
+ onPrefetchStart?: () => void;
74
+ onPrefetchFinish?: () => void;
75
+ /** @internal Preserves legacy child classification across server resolution. */
76
+ __pnextLegacyChildKind?: LegacyChildKind;
77
+ ref?: Ref<HTMLAnchorElement>;
78
+ children?: ReactNode;
79
+ };
80
+
81
+ const Link = forwardRef<HTMLAnchorElement, LinkProps>(function Link(
82
+ {
83
+ href,
84
+ as,
85
+ prefetch = null,
86
+ unstable_dynamicOnHover,
87
+ replace,
88
+ scroll,
89
+ locale: _locale,
90
+ legacyBehavior,
91
+ passHref,
92
+ onClick,
93
+ onNavigate,
94
+ transitionTypes,
95
+ onPrefetchStart,
96
+ onPrefetchFinish,
97
+ __pnextLegacyChildKind,
98
+ children,
99
+ ...anchorProps
100
+ },
101
+ forwardedRef,
102
+ ) {
103
+ // `as` supersedes `href` for what the anchor actually points at (app router).
104
+ const target = as == null ? href : as;
105
+ // basePath: prefix in-app hrefs so the rendered anchor (and the soft-nav it
106
+ // drives) points under the configured basePath, matching Next. addBasePath
107
+ // leaves external/absolute/already-prefixed hrefs untouched, and is a no-op
108
+ // when no basePath is configured.
109
+ // skipTrailingSlashRedirect preserves the author's exact trailing slash (both
110
+ // the rendered anchor and the soft-nav it drives); otherwise normalize per
111
+ // the trailingSlash config so the anchor matches the canonical URL.
112
+ const hrefBase = hrefString(target);
113
+ const resolvedHref = addBasePath(
114
+ skipTrailingSlashRedirect() ? hrefBase : applyTrailingSlash(hrefBase),
115
+ );
116
+ const blocked = isJavascriptUrl(resolvedHref);
117
+ const prefetchMode = nextPrefetchMode(prefetch);
118
+ const lifecycleRef = usePrefetchLifecycle(onPrefetchStart, onPrefetchFinish);
119
+ const anchorRef = useComposedRef(lifecycleRef, forwardedRef);
120
+ const statusToken = useLinkToken();
121
+
122
+ const handleClick = (event: JSX.TargetedMouseEvent<HTMLAnchorElement>) => {
123
+ onClick?.(event);
124
+ if (event.defaultPrevented) return;
125
+
126
+ if (blocked) {
127
+ // Same guard the runtime applies to static links; a hydrated Link cancels
128
+ // its own default so the javascript: URL never runs.
129
+ if (blockJavascriptUrl(resolvedHref)) event.preventDefault();
130
+ return;
131
+ }
132
+
133
+ // Modifier/middle clicks, target, download: let the browser handle it;
134
+ // onNavigate does not fire (matches Next).
135
+ if (!isPlainLeftClick(event)) return;
136
+
137
+ if (isExternalHref(resolvedHref)) {
138
+ // External hrefs never soft-navigate and never fire onNavigate. `replace`
139
+ // still swaps history rather than pushing.
140
+ if (replace) {
141
+ event.preventDefault();
142
+ window.location.replace(resolvedHref);
143
+ }
144
+ return;
145
+ }
146
+
147
+ // Internal soft navigation: onNavigate can cancel, and this Link drives the
148
+ // navigation itself so useLinkStatus tracks it. preventDefault keeps the
149
+ // router's document-level handler from navigating a second time.
150
+ if (onNavigate) {
151
+ const navEvent = navigationEvent();
152
+ onNavigate(navEvent);
153
+ if (navEvent.defaultPrevented) {
154
+ event.preventDefault();
155
+ return;
156
+ }
157
+ }
158
+
159
+ event.preventDefault();
160
+ for (const type of transitionTypes ?? []) addTransitionType(type);
161
+ const url = new URL(resolvedHref, window.location.href);
162
+ const samePage =
163
+ url.pathname === window.location.pathname && url.search === window.location.search;
164
+ if (samePage && url.hash) {
165
+ window.location.hash = url.hash;
166
+ return;
167
+ }
168
+ navigateWithStatus(statusToken, url.href, { replace, scroll });
169
+ };
170
+
171
+ const anchorAttributes: Record<string, unknown> = {
172
+ ...anchorProps,
173
+ ref: anchorRef,
174
+ href: resolvedHref,
175
+ 'data-pnext-link': true,
176
+ 'data-prefetch': prefetchMode === false ? 'false' : prefetchMode,
177
+ // prefetch={true} requests a FULL prefetch (5-min static window) vs the
178
+ // default partial/dynamic 30s window; the router reads this attribute.
179
+ // 'unstable_forceStale' is Next 16's alias for the full prefetch mode.
180
+ 'data-prefetch-full': prefetch === true || prefetch === 'unstable_forceStale' ? 'true' : undefined,
181
+ // unstable_dynamicOnHover: hover intent upgrades the (viewport, partial)
182
+ // prefetch to a full one that includes the dynamic data.
183
+ 'data-prefetch-hover-full': unstable_dynamicOnHover ? 'true' : undefined,
184
+ 'data-pnext-replace': replace ? 'true' : undefined,
185
+ 'data-pnext-scroll': scroll === false ? 'false' : undefined,
186
+ onClick: handleClick,
187
+ };
188
+ if (blocked) anchorAttributes['data-pnext-blocked-href'] = resolvedHref;
189
+
190
+ if (
191
+ (typeof __PNEXT_LINK_LEGACY__ === 'boolean' ? __PNEXT_LINK_LEGACY__ : true) &&
192
+ legacyBehavior
193
+ ) {
194
+ return renderLegacyChild(
195
+ children,
196
+ resolvedHref,
197
+ passHref,
198
+ handleClick,
199
+ anchorAttributes,
200
+ __pnextLegacyChildKind,
201
+ );
202
+ }
203
+
204
+ return createElement(
205
+ 'a',
206
+ anchorAttributes,
207
+ createElement(LinkStatusContext.Provider, { value: { pending: linkPending(statusToken) } }, children),
208
+ ) as ReactElement;
209
+ });
210
+
211
+ export default Link;
212
+ export { Link };
213
+
214
+ export function useLinkStatus() {
215
+ return useContext(LinkStatusContext);
216
+ }
217
+
218
+ // A stable per-Link identity used to key the pending navigation, plus a
219
+ // re-render on pending change so useLinkStatus consumers update.
220
+ function useLinkToken() {
221
+ const tokenRef = useRef<symbol | null>(null);
222
+ tokenRef.current ??= Symbol('pnext-link');
223
+ const token = tokenRef.current;
224
+ const [, force] = useState(0);
225
+ useEffect(() => subscribeLinkStatus(token, () => force(n => n + 1)), [token]);
226
+ return token;
227
+ }
228
+
229
+ // `legacyBehavior`: the single child element becomes the interactive element;
230
+ // with passHref it receives the resolved href. Validates child count like Next.
231
+ function renderLegacyChild(
232
+ children: ReactNode,
233
+ resolvedHref: string,
234
+ passHref: boolean | undefined,
235
+ onClick: (event: JSX.TargetedMouseEvent<HTMLAnchorElement>) => void,
236
+ anchorAttributes: Record<string, unknown>,
237
+ annotatedKind?: LegacyChildKind,
238
+ ): ReactElement {
239
+ reportLegacyDeprecation();
240
+ // eslint-disable-next-line turbo/no-undeclared-env-vars
241
+ const isDev = process.env.NODE_ENV !== 'production';
242
+ const isServer = !process.browser && typeof window === 'undefined';
243
+
244
+ if (children == null || children === false) {
245
+ if (isDev) {
246
+ throw validationError(
247
+ `No children were passed to <Link> with \`href\` of \`${resolvedHref}\` but one child is required https://nextjs.org/docs/messages/link-no-children`,
248
+ 'E320',
249
+ );
250
+ }
251
+ return childrenOnlyOrThrow(children);
252
+ }
253
+
254
+ // A bare string/number child renders its own <a> (Next's legacy behavior).
255
+ if (typeof children === 'string' || typeof children === 'number') {
256
+ return createElement('a', { ...anchorAttributes, href: resolvedHref }, children);
257
+ }
258
+
259
+ const count = Children.count(children);
260
+ if (count > 1) {
261
+ if (isDev) {
262
+ throw validationError(
263
+ `Multiple children were passed to <Link> with \`href\` of \`${resolvedHref}\` but only one child is supported https://nextjs.org/docs/messages/link-multiple-children`,
264
+ 'E266',
265
+ );
266
+ }
267
+ return childrenOnlyOrThrow(children);
268
+ }
269
+
270
+ const child = Children.only(children) as ReactElement<Record<string, unknown>>;
271
+ const kind =
272
+ annotatedKind ??
273
+ (isAsyncFunctionComponent(child.type)
274
+ ? 'server-async'
275
+ : isLazyComponent(child.type)
276
+ ? 'lazy'
277
+ : undefined);
278
+ if (isServer && (kind === 'server-sync' || kind === 'server-async' || kind === 'lazy')) {
279
+ reportUnsupportedServerChild(kind, isDev);
280
+ }
281
+ if (kind && kind !== 'server-sync') {
282
+ const error = unsupportedLegacyChildError();
283
+ if (isServer && kind === 'server-async-through-client') {
284
+ // Print the full trace, not just the message: the thrown error is
285
+ // swallowed downstream in this path, so without the ` at` frame lines
286
+ // the server log for this case would end at the message and the console
287
+ // snapshot (which slices up to the first ` at` line) would pick up the
288
+ // trailing blank line instead of terminating at the stack.
289
+ console.error(`⨯ ${error.stack ?? `Error: ${error.message}`}`);
290
+ }
291
+ throw error;
292
+ }
293
+
294
+ if (isServer && isDev && isServerComponent(child.type)) {
295
+ reportUnsupportedServerChild('server-sync', isDev);
296
+ }
297
+
298
+ const childProps: Record<string, unknown> = {
299
+ onClick: (event: JSX.TargetedMouseEvent<HTMLAnchorElement>) => {
300
+ (child.props as { onClick?: (event: unknown) => void }).onClick?.(event);
301
+ onClick(event);
302
+ },
303
+ };
304
+ if (passHref || (child.type as unknown) === 'a') {
305
+ // The child becomes the anchor: give it the href plus the runtime's
306
+ // soft-nav markers, so navigation/prefetch work even when the child is a
307
+ // static (unhydrated) element and the onClick prop never runs.
308
+ childProps.href = resolvedHref;
309
+ childProps['data-pnext-link'] = anchorAttributes['data-pnext-link'];
310
+ childProps['data-prefetch'] = anchorAttributes['data-prefetch'];
311
+ childProps['data-prefetch-full'] = anchorAttributes['data-prefetch-full'];
312
+ childProps['data-prefetch-hover-full'] = anchorAttributes['data-prefetch-hover-full'];
313
+ childProps['data-pnext-replace'] = anchorAttributes['data-pnext-replace'];
314
+ childProps['data-pnext-scroll'] = anchorAttributes['data-pnext-scroll'];
315
+ }
316
+ return cloneElement(child, childProps);
317
+ }
318
+
319
+ function reportUnsupportedServerChild(kind: LegacyChildKind, isDev: boolean) {
320
+ const message =
321
+ kind === 'lazy'
322
+ ? 'Using a Lazy Component as a direct child of `<Link legacyBehavior>` from a Server Component is not supported. If you need legacyBehavior, wrap your Lazy Component in a Client Component that renders the Link\'s `<a>` tag.'
323
+ : 'Using a Server Component as a direct child of `<Link legacyBehavior>` is not supported. If you need legacyBehavior, wrap your Server Component in a Client Component that renders the Link\'s `<a>` tag.';
324
+ console.error(isDev ? validationError(message, 'E394') : message);
325
+ }
326
+
327
+ function unsupportedLegacyChildError() {
328
+ return validationError(
329
+ '`<Link legacyBehavior>` received a direct child that is either a Server Component, or JSX that was loaded with React.lazy(). This is not supported. Either remove legacyBehavior, or make the direct child a Client Component that renders the Link\'s `<a>` tag.',
330
+ 'E863',
331
+ );
332
+ }
333
+
334
+ let deprecationWarned = false;
335
+ function reportLegacyDeprecation() {
336
+ if (
337
+ deprecationWarned ||
338
+ (!process.browser && typeof window === 'undefined') ||
339
+ // eslint-disable-next-line turbo/no-undeclared-env-vars
340
+ process.env.NODE_ENV === 'production'
341
+ ) {
342
+ return;
343
+ }
344
+ deprecationWarned = true;
345
+ console.error(
346
+ '`legacyBehavior` is deprecated and will be removed in a future release. A codemod is available to upgrade your components:\n\n' +
347
+ 'npx @next/codemod@latest new-link .\n\n' +
348
+ 'Learn more: https://nextjs.org/docs/app/building-your-application/upgrading/codemods#remove-a-tags-from-link-components',
349
+ );
350
+ }
351
+
352
+ function validationError(message: string, digest: string) {
353
+ return Object.assign(new Error(message), { digest });
354
+ }
355
+
356
+ // preact/compat's `Children.only` throws a bare string ("Children.only")
357
+ // instead of an Error, and its message doesn't match React's. Production
358
+ // builds (no dev-mode validation) fall through to native Children.only
359
+ // semantics for the no-children/multiple-children cases, so reproduce React's
360
+ // exact wording here rather than surfacing preact's own throw.
361
+ function childrenOnlyOrThrow(children: ReactNode): ReactElement {
362
+ try {
363
+ return Children.only(children) as ReactElement;
364
+ } catch {
365
+ throw new Error('React.Children.only expected to receive a single React element child.');
366
+ }
367
+ }
368
+
369
+ function isAsyncFunctionComponent(type: unknown) {
370
+ if (typeof type !== 'function') return false;
371
+ const asyncFunctionName = Object.prototype.toString.call(type);
372
+ return asyncFunctionName === '[object AsyncFunction]';
373
+ }
374
+
375
+ function isLazyComponent(type: unknown) {
376
+ return (
377
+ type !== null &&
378
+ typeof type === 'object' &&
379
+ (type as { $$typeof?: unknown }).$$typeof === Symbol.for('react.lazy')
380
+ );
381
+ }
382
+
383
+ function isServerComponent(type: unknown) {
384
+ if (isClientComponent(type)) return false;
385
+ return (
386
+ typeof type === 'function' &&
387
+ (type as { $$typeof?: unknown }).$$typeof === undefined
388
+ );
389
+ }
390
+
391
+ function isClientComponent(type: unknown) {
392
+ return (
393
+ (typeof type === 'object' || typeof type === 'function') &&
394
+ (type as { $$typeof?: unknown }).$$typeof === reactClientReferenceSymbol
395
+ );
396
+ }
397
+
398
+ function useComposedRef(
399
+ internalRef: MutableRefObject<HTMLAnchorElement | null>,
400
+ userRef: Ref<HTMLAnchorElement> | undefined,
401
+ ) {
402
+ return (node: HTMLAnchorElement | null) => {
403
+ internalRef.current = node;
404
+ assignRef(userRef, node);
405
+ };
406
+ }
407
+
408
+ function assignRef(ref: Ref<HTMLAnchorElement> | undefined, node: HTMLAnchorElement | null) {
409
+ if (!ref) return;
410
+ if (typeof ref === 'function') {
411
+ // Callback refs may return a cleanup; Preact ignores it, which is fine —
412
+ // the ref is re-run with null on unmount, matching the manual-cleanup path.
413
+ ref(node);
414
+ return;
415
+ }
416
+ (ref as MutableRefObject<HTMLAnchorElement | null>).current = node;
417
+ }
418
+
419
+ function hrefString(href: string | URL | UrlObject) {
420
+ if (typeof href === 'string') return href;
421
+ if (href instanceof URL) return href.toString();
422
+ return routeHref(href.pathname ?? '', { search: href.query, hash: href.hash });
423
+ }
424
+
425
+ function nextPrefetchMode(
426
+ prefetch: boolean | 'auto' | 'unstable_forceStale' | null,
427
+ ): PrefetchMode {
428
+ // Next's default prefetches when the link enters the viewport; `false` opts
429
+ // out entirely. (`true`/'auto'/'unstable_forceStale' also map to viewport
430
+ // prefetch here — 'auto' is an explicit alias for the default.)
431
+ return prefetch === false ? false : 'visible';
432
+ }
433
+
434
+ function isExternalHref(href: string) {
435
+ if (!process.browser && typeof window === 'undefined') return false;
436
+ try {
437
+ return new URL(href, window.location.href).origin !== window.location.origin;
438
+ } catch {
439
+ return true;
440
+ }
441
+ }
442
+
443
+ function navigationEvent() {
444
+ return {
445
+ defaultPrevented: false,
446
+ preventDefault() {
447
+ this.defaultPrevented = true;
448
+ },
449
+ };
450
+ }
451
+
452
+ function isPlainLeftClick(event: JSX.TargetedMouseEvent<HTMLAnchorElement>) {
453
+ return (
454
+ event.button === 0 &&
455
+ !event.altKey &&
456
+ !event.ctrlKey &&
457
+ !event.metaKey &&
458
+ !event.shiftKey &&
459
+ isSelfTarget(event.currentTarget.target) &&
460
+ !event.currentTarget.hasAttribute('download')
461
+ );
462
+ }
463
+
464
+ function isSelfTarget(target: string) {
465
+ return target === '' || target === '_self';
466
+ }
@@ -0,0 +1,21 @@
1
+ const router = {
2
+ push: () => undefined, replace: () => undefined, prefetch: () => undefined,
3
+ refresh: () => undefined, back: () => undefined, forward: () => undefined,
4
+ bfcacheId: '',
5
+ }
6
+ const noop = () => undefined
7
+
8
+ exports.RedirectType = { push: 'push', replace: 'replace' }
9
+ exports.redirect = noop
10
+ exports.permanentRedirect = noop
11
+ exports.notFound = noop
12
+ exports.forbidden = noop
13
+ exports.unauthorized = noop
14
+ exports.useRouter = () => router
15
+ exports.usePathname = () => null
16
+ exports.useSearchParams = () => new URLSearchParams()
17
+ exports.useParams = () => ({})
18
+ exports.useRoute = () => ({ route: null, pathname: '', params: {}, searchParams: new URLSearchParams() })
19
+ exports.useSelectedLayoutSegment = () => null
20
+ exports.useSelectedLayoutSegments = () => []
21
+ exports.useLinkStatus = () => ({ pending: false })
@@ -0,0 +1,188 @@
1
+ export {
2
+ forbidden,
3
+ notFound,
4
+ PNextForbiddenError,
5
+ PNextNotFoundError,
6
+ PNextRedirectError,
7
+ PNextUnauthorizedError,
8
+ unauthorized,
9
+ } from '../../api/navigation';
10
+ import {
11
+ permanentRedirect as pnextPermanentRedirect,
12
+ PNextForbiddenError,
13
+ PNextNotFoundError,
14
+ PNextRedirectError,
15
+ PNextUnauthorizedError,
16
+ ReadonlyURLSearchParams,
17
+ redirect as pnextRedirect,
18
+ } from '../../api/navigation';
19
+ import { isPostpone } from '../../ppr-postpone';
20
+ import { currentParams, currentRequest } from '../../request/context';
21
+ import { useContext } from 'preact/hooks';
22
+ import {
23
+ currentLayoutSegments,
24
+ currentParamsSnapshot,
25
+ hasLayoutSegmentScope,
26
+ } from '../../render/slots';
27
+ import { LayoutSegmentContext, RouteParamsContext } from '../../render/island-context';
28
+ import { canonicalUrlHref } from './canonical-url';
29
+ import { isUnrecognizedActionError } from '../actions/unrecognized-error';
30
+ import { stripBasePath } from '../client/base-path';
31
+ import { addBasePath } from '../client/base-path';
32
+ import type { CurrentRoute, PNextRouter } from '../../api/client-navigation';
33
+ import type { RouteParams, RoutePath } from '../../types';
34
+
35
+ export type { RedirectStatus } from '../../api/navigation';
36
+ export type { CurrentRoute, PNextRouter } from '../../api/client-navigation';
37
+ export { ReadonlyURLSearchParams };
38
+
39
+ export const RedirectType = {
40
+ push: 'push',
41
+ replace: 'replace',
42
+ } as const;
43
+
44
+ export type RedirectType = (typeof RedirectType)[keyof typeof RedirectType];
45
+
46
+ export function redirect(location: string, type?: RedirectType): never {
47
+ try {
48
+ // Next prefixes a root-relative redirect target with basePath; absolute URLs (including same-host
49
+ // targets outside the basePath) are left as-is. Normalizing here means every downstream consumer -
50
+ // the page-GET redirect response and the server-action redirect envelope - sees a basePath-space
51
+ // location uniformly.
52
+ pnextRedirect(addBasePath(location));
53
+ } catch (error) {
54
+ // Server actions honor push/replace history semantics on the client;
55
+ // carry the requested type on the control-flow error.
56
+ if (type && error instanceof PNextRedirectError) {
57
+ (error as PNextRedirectError & { redirectType?: RedirectType }).redirectType = type;
58
+ }
59
+ throw error;
60
+ }
61
+ }
62
+
63
+ export function permanentRedirect(location: string, _type?: RedirectType): never {
64
+ pnextPermanentRedirect(addBasePath(location));
65
+ }
66
+
67
+ /** Rethrow framework control-flow errors so user catch blocks don't swallow them. */
68
+ export function unstable_rethrow(error: unknown): void {
69
+ if (
70
+ error instanceof PNextRedirectError ||
71
+ error instanceof PNextNotFoundError ||
72
+ error instanceof PNextForbiddenError ||
73
+ error instanceof PNextUnauthorizedError ||
74
+ isPostpone(error)
75
+ ) {
76
+ throw error;
77
+ }
78
+ }
79
+
80
+ const serverRouter: PNextRouter = {
81
+ push: () => undefined,
82
+ replace: () => undefined,
83
+ prefetch: () => undefined,
84
+ refresh: () => undefined,
85
+ back: () => undefined,
86
+ forward: () => undefined,
87
+ bfcacheId: '',
88
+ };
89
+
90
+ export function useRouter(): PNextRouter {
91
+ return serverRouter;
92
+ }
93
+
94
+ export function usePathname() {
95
+ return stripBasePath(currentUrl().pathname);
96
+ }
97
+
98
+ export function useSearchParams(): ReadonlyURLSearchParams {
99
+ return new ReadonlyURLSearchParams(currentUrl().search);
100
+ }
101
+
102
+ export function useParams<Route extends RoutePath = RoutePath>() {
103
+ return resolveParams() as RouteParams<Route>;
104
+ }
105
+
106
+ /**
107
+ * A SERVER component inside a parallel-route slot runs within the slot's params scope (route params plus
108
+ * the slot's own dynamic/catch-all captures), so read it directly. A `'use client'` component in a slot
109
+ * is SSR'd as an island, rendered to string OUTSIDE that scope, so it falls back to the
110
+ * RouteParamsContext the renderer provides around the island - matching what the client re-provides at
111
+ * mount. Otherwise the global route params apply. useContext is safe because the context branch only
112
+ * runs during a preact render.
113
+ */
114
+ function resolveParams(): Record<string, string | string[]> {
115
+ const scope = currentParamsSnapshot();
116
+ if (scope) return scope;
117
+ // Island SSR (a `'use client'` component in a slot) reads the snapshot from
118
+ // the RouteParamsContext the renderer wraps around it. useContext is only
119
+ // valid inside a preact render; a plain server component resolved by direct
120
+ // call has no hook context, so guard it and fall back to the global params.
121
+ try {
122
+ const snapshot = useContext(RouteParamsContext);
123
+ if (snapshot) return snapshot;
124
+ } catch {
125
+ // not in a preact render — fall through to global route params
126
+ }
127
+ return currentParams();
128
+ }
129
+
130
+ export function useRoute<Route extends RoutePath = RoutePath>(): CurrentRoute<Route> {
131
+ const url = currentUrl();
132
+ return {
133
+ route: null,
134
+ pathname: url.pathname,
135
+ params: resolveParams() as RouteParams<Route>,
136
+ searchParams: new ReadonlyURLSearchParams(url.search),
137
+ };
138
+ }
139
+
140
+ export function useSelectedLayoutSegment(
141
+ parallelRoutesKey?: string,
142
+ ): string | null {
143
+ const segments = selectedLayoutSegments(parallelRoutesKey);
144
+ return segments[parallelRoutesKey ? segments.length - 1 : 0] ?? null;
145
+ }
146
+
147
+ export function useSelectedLayoutSegments(parallelRoutesKey?: string): string[] {
148
+ // A defensive copy so callers can't mutate the render-scoped array.
149
+ return [...selectedLayoutSegments(parallelRoutesKey)];
150
+ }
151
+
152
+ /**
153
+ * A SERVER component in a layout runs inside the layout-segment scope, so read it directly. A
154
+ * `'use client'` layout is SSR'd as an island, rendered to string OUTSIDE that scope, so it falls back
155
+ * to the LayoutSegmentContext the renderer provides around the island - matching what the client
156
+ * re-provides at mount. useContext is safe: the no-scope branch only runs during a preact render.
157
+ */
158
+ function selectedLayoutSegments(parallelRoutesKey?: string): string[] {
159
+ if (hasLayoutSegmentScope()) return currentLayoutSegments(parallelRoutesKey);
160
+ const snapshot = useContext(LayoutSegmentContext);
161
+ if (!snapshot) return [];
162
+ return parallelRoutesKey ? (snapshot.slots[parallelRoutesKey] ?? []) : snapshot.segments;
163
+ }
164
+
165
+ export function useLinkStatus() {
166
+ return { pending: false };
167
+ }
168
+
169
+ /**
170
+ * The canonical (as-requested) URL for the active render. After a rewrite the
171
+ * request URL is the destination, so hooks that must reflect what the browser
172
+ * asked for read the recorded canonical URL first (see canonical-url.ts).
173
+ */
174
+ function currentUrl() {
175
+ return new URL(canonicalUrlHref() ?? currentRequest()?.url ?? 'http://pnext.local/');
176
+ }
177
+
178
+ /**
179
+ * True for the error a server-action dispatch throws when the server no longer
180
+ * recognizes the action id (version skew). Matches the message the pnext
181
+ * action endpoint sends for an unknown id.
182
+ */
183
+ export function unstable_isUnrecognizedActionError(error: unknown): boolean {
184
+ return isUnrecognizedActionError(error);
185
+ }
186
+
187
+ // CSS-in-JS SSR insertion hook (Next exports it from next/navigation).
188
+ export { useServerInsertedHTML } from '../react/server-inserted-html';