@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,102 @@
1
+ import { h, type ComponentType } from 'preact';
2
+ import { useEffect, useRef, useState } from 'preact/hooks';
3
+
4
+ export type DynamicModule<Props> = ComponentType<Props> | { default: ComponentType<Props> };
5
+ export type DynamicLoader<Props> = string | (() => Promise<DynamicModule<Props>>);
6
+ export const dynamicReferenceSymbol = Symbol.for('pnext.dynamic');
7
+
8
+ export interface DynamicTarget {
9
+ file: string;
10
+ exportName: string;
11
+ }
12
+
13
+ export interface DynamicReference<Props extends object = object> {
14
+ load: () => Promise<ComponentType<Props>>;
15
+ target?: DynamicTarget;
16
+ }
17
+
18
+ export interface DynamicOptions<Props> {
19
+ loading?: ComponentType<Props>;
20
+ load?: 'render' | 'visible';
21
+ rootMargin?: string;
22
+ ssr?: boolean;
23
+ threshold?: number | number[];
24
+ }
25
+
26
+ export function dynamic<Props extends object = object>(
27
+ loader: DynamicLoader<Props>,
28
+ options: DynamicOptions<Props> = {},
29
+ // Injected by the server compile (rewriteDynamicCallTargets); app code
30
+ // never passes this.
31
+ target?: DynamicTarget,
32
+ ) {
33
+ let loaded: ComponentType<Props> | null = null;
34
+ let pending: Promise<ComponentType<Props>> | null = null;
35
+ const loadModule = typeof loader === 'string'
36
+ ? () => {
37
+ throw new Error(`dynamic(${JSON.stringify(loader)}) was not compiled by PNext.`);
38
+ }
39
+ : loader;
40
+
41
+ const load = () => {
42
+ pending ??= Promise.resolve(loadModule()).then(module => {
43
+ loaded = typeof module === 'function' ? module : module.default;
44
+ return loaded;
45
+ });
46
+ return pending;
47
+ };
48
+
49
+ function DynamicComponent(props: Props) {
50
+ const [Component, setComponent] = useState<ComponentType<Props> | null>(() => loaded);
51
+ const [shouldLoad, setShouldLoad] = useState(() => options.load !== 'visible');
52
+ const visibleRef = useRef<HTMLDivElement>(null);
53
+
54
+ useEffect(() => {
55
+ if (Component || shouldLoad) return;
56
+ const node = visibleRef.current;
57
+ if (!node || typeof IntersectionObserver === 'undefined') {
58
+ setShouldLoad(true);
59
+ return;
60
+ }
61
+
62
+ const observer = new IntersectionObserver(
63
+ entries => {
64
+ if (!entries.some(entry => entry.isIntersecting)) return;
65
+ observer.disconnect();
66
+ setShouldLoad(true);
67
+ },
68
+ {
69
+ rootMargin: options.rootMargin,
70
+ threshold: options.threshold,
71
+ },
72
+ );
73
+
74
+ observer.observe(node);
75
+ return () => observer.disconnect();
76
+ }, [Component, shouldLoad]);
77
+
78
+ useEffect(() => {
79
+ if (Component || !shouldLoad) return;
80
+ let cancelled = false;
81
+ void load().then(next => {
82
+ if (!cancelled) setComponent(() => next);
83
+ });
84
+ return () => {
85
+ cancelled = true;
86
+ };
87
+ }, [Component, shouldLoad]);
88
+
89
+ if (Component) return h(Component, props);
90
+ const Loading = options.loading;
91
+ if (options.load === 'visible') {
92
+ return h('div', { ref: visibleRef }, Loading ? h(Loading, props) : null);
93
+ }
94
+ return Loading ? h(Loading, props) : null;
95
+ }
96
+
97
+ (DynamicComponent as typeof DynamicComponent & {
98
+ [dynamicReferenceSymbol]: DynamicReference<Props>;
99
+ })[dynamicReferenceSymbol] = { load, target };
100
+
101
+ return DynamicComponent;
102
+ }
@@ -0,0 +1,119 @@
1
+ import { h, type ComponentChildren, type JSX } from 'preact';
2
+ import { useEffect, useRef } from 'preact/hooks';
3
+ import type {
4
+ AnchorHTMLAttributes,
5
+ MouseEvent,
6
+ ReactNode,
7
+ } from 'react';
8
+ import { routeHref, type SearchInput } from '../routing/href';
9
+ import type { PrefetchMode, RouteParams, RoutePath } from '../types';
10
+
11
+ export interface NavigateEvent {
12
+ preventDefault(): void;
13
+ }
14
+
15
+ type LinkMouseEvent = MouseEvent<HTMLAnchorElement>;
16
+
17
+ type BaseLinkProps = Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href' | 'onClick'> & {
18
+ prefetch?: PrefetchMode;
19
+ replace?: boolean;
20
+ scroll?: boolean;
21
+ search?: SearchInput;
22
+ hash?: string;
23
+ onClick?: (event: LinkMouseEvent) => void;
24
+ onNavigate?: (event: NavigateEvent) => void;
25
+ onPrefetchStart?: () => void;
26
+ onPrefetchFinish?: () => void;
27
+ children?: ReactNode;
28
+ };
29
+
30
+ type ParamsProp<Route extends RoutePath> = RouteParams<Route> extends Record<string, never>
31
+ ? { params?: never }
32
+ : { params: RouteParams<Route> };
33
+
34
+ export type LinkProps<Route extends RoutePath = RoutePath> = BaseLinkProps &
35
+ ParamsProp<Route> & {
36
+ href: Route;
37
+ };
38
+
39
+ export function Link<Route extends RoutePath>({
40
+ href,
41
+ params,
42
+ prefetch = 'intent',
43
+ replace,
44
+ scroll,
45
+ search,
46
+ hash,
47
+ onClick,
48
+ onNavigate,
49
+ onPrefetchStart,
50
+ onPrefetchFinish,
51
+ children,
52
+ ...anchorProps
53
+ }: LinkProps<Route>): ReactNode {
54
+ const resolvedHref = routeHref(href, { params: params ?? {}, search, hash });
55
+ const anchorRef = usePrefetchLifecycle(onPrefetchStart, onPrefetchFinish);
56
+ return h(
57
+ 'a',
58
+ {
59
+ ...anchorProps,
60
+ ref: anchorRef,
61
+ href: resolvedHref,
62
+ 'data-pnext-link': true,
63
+ 'data-prefetch': prefetch === false ? 'false' : prefetch,
64
+ 'data-pnext-replace': replace ? 'true' : undefined,
65
+ 'data-pnext-scroll': scroll === false ? 'false' : undefined,
66
+ onClick: event => {
67
+ const clickEvent = event as unknown as LinkMouseEvent;
68
+ onClick?.(clickEvent);
69
+ if (clickEvent.defaultPrevented || !onNavigate || !isPlainLeftClick(clickEvent)) return;
70
+ const navEvent = navigationEvent();
71
+ onNavigate(navEvent);
72
+ if (navEvent.defaultPrevented) clickEvent.preventDefault();
73
+ },
74
+ } as JSX.HTMLAttributes<HTMLAnchorElement>,
75
+ children as ComponentChildren,
76
+ ) as unknown as ReactNode;
77
+ }
78
+
79
+ // The prefetch runtime dispatches lifecycle events on the anchor that
80
+ // triggered a prefetch, for every mode (intent, visible, load).
81
+ export function usePrefetchLifecycle(onStart?: () => void, onFinish?: () => void) {
82
+ const anchorRef = useRef<HTMLAnchorElement | null>(null);
83
+
84
+ useEffect(() => {
85
+ const node = anchorRef.current;
86
+ if (!node || (!onStart && !onFinish)) return;
87
+ const handleStart = () => onStart?.();
88
+ const handleFinish = () => onFinish?.();
89
+ node.addEventListener('pnext:prefetchstart', handleStart);
90
+ node.addEventListener('pnext:prefetchfinish', handleFinish);
91
+ return () => {
92
+ node.removeEventListener('pnext:prefetchstart', handleStart);
93
+ node.removeEventListener('pnext:prefetchfinish', handleFinish);
94
+ };
95
+ }, [onStart, onFinish]);
96
+
97
+ return anchorRef;
98
+ }
99
+
100
+ function navigationEvent() {
101
+ return {
102
+ defaultPrevented: false,
103
+ preventDefault() {
104
+ this.defaultPrevented = true;
105
+ },
106
+ };
107
+ }
108
+
109
+ function isPlainLeftClick(event: LinkMouseEvent) {
110
+ return (
111
+ event.button === 0 &&
112
+ !event.altKey &&
113
+ !event.ctrlKey &&
114
+ !event.metaKey &&
115
+ !event.shiftKey &&
116
+ !event.currentTarget.target &&
117
+ !event.currentTarget.download
118
+ );
119
+ }
@@ -0,0 +1,198 @@
1
+ import { routeHref, type SearchInput } from '../routing/href';
2
+ import type { RouteParams, RoutePath } from '../types';
3
+
4
+ export type { SearchInput, SearchValue } from '../routing/href';
5
+
6
+ const notFoundDigest = 'PNEXT_NOT_FOUND';
7
+ const redirectDigest = 'PNEXT_REDIRECT';
8
+ const forbiddenDigest = 'PNEXT_FORBIDDEN';
9
+ const unauthorizedDigest = 'PNEXT_UNAUTHORIZED';
10
+ const nextNotFoundDigest = 'NEXT_HTTP_ERROR_FALLBACK;404';
11
+ const nextForbiddenDigest = 'NEXT_HTTP_ERROR_FALLBACK;403';
12
+ const nextUnauthorizedDigest = 'NEXT_HTTP_ERROR_FALLBACK;401';
13
+
14
+ export type RedirectStatus = 303 | 307 | 308;
15
+
16
+ class ReadonlyURLSearchParamsError extends Error {
17
+ constructor() {
18
+ super(
19
+ 'Method unavailable on `ReadonlyURLSearchParams`. Read more: https://nextjs.org/docs/app/api-reference/functions/use-search-params#updating-searchparams',
20
+ );
21
+ }
22
+ }
23
+
24
+ /**
25
+ * A read-only `URLSearchParams`: mutation methods throw. Returned by
26
+ * `useSearchParams()` so search params rendered from the URL cannot be
27
+ * mutated in place (matches Next's `ReadonlyURLSearchParams`).
28
+ */
29
+ export class ReadonlyURLSearchParams extends URLSearchParams {
30
+ /** @deprecated Method unavailable on `ReadonlyURLSearchParams`. */
31
+ append(): never {
32
+ throw new ReadonlyURLSearchParamsError();
33
+ }
34
+ /** @deprecated Method unavailable on `ReadonlyURLSearchParams`. */
35
+ delete(): never {
36
+ throw new ReadonlyURLSearchParamsError();
37
+ }
38
+ /** @deprecated Method unavailable on `ReadonlyURLSearchParams`. */
39
+ set(): never {
40
+ throw new ReadonlyURLSearchParamsError();
41
+ }
42
+ /** @deprecated Method unavailable on `ReadonlyURLSearchParams`. */
43
+ sort(): never {
44
+ throw new ReadonlyURLSearchParamsError();
45
+ }
46
+ }
47
+
48
+ type ParamsProp<Route extends RoutePath> = RouteParams<Route> extends Record<string, never>
49
+ ? { params?: never }
50
+ : { params: RouteParams<Route> };
51
+
52
+ export type HrefOptions<Route extends RoutePath> = ParamsProp<Route> & {
53
+ search?: SearchInput;
54
+ hash?: string;
55
+ };
56
+
57
+ export type RedirectOptions<Route extends RoutePath> = HrefOptions<Route> & {
58
+ status?: RedirectStatus;
59
+ };
60
+
61
+ export function href<Route extends RoutePath>(
62
+ route: Route,
63
+ ...[options]: RouteParams<Route> extends Record<string, never>
64
+ ? [options?: HrefOptions<Route>]
65
+ : [options: HrefOptions<Route>]
66
+ ) {
67
+ return routeHref(route, options);
68
+ }
69
+
70
+ export class PNextNotFoundError extends Error {
71
+ digest = notFoundDigest;
72
+
73
+ constructor() {
74
+ super('not found');
75
+ }
76
+ }
77
+
78
+ export function notFound(): never {
79
+ throw new PNextNotFoundError();
80
+ }
81
+
82
+ export class PNextForbiddenError extends Error {
83
+ digest = forbiddenDigest;
84
+
85
+ constructor() {
86
+ super('forbidden');
87
+ }
88
+ }
89
+
90
+ /**
91
+ * COMPAT (Next authInterrupts): stop rendering and serve the nearest
92
+ * `forbidden.{tsx,...}` boundary with a 403. Only active when compat.next is on.
93
+ */
94
+ export function forbidden(): never {
95
+ throw new PNextForbiddenError();
96
+ }
97
+
98
+ export class PNextUnauthorizedError extends Error {
99
+ digest = unauthorizedDigest;
100
+
101
+ constructor() {
102
+ super('unauthorized');
103
+ }
104
+ }
105
+
106
+ /**
107
+ * COMPAT (Next authInterrupts): stop rendering and serve the nearest
108
+ * `unauthorized.{tsx,...}` boundary with a 401. Only active when compat.next is on.
109
+ */
110
+ export function unauthorized(): never {
111
+ throw new PNextUnauthorizedError();
112
+ }
113
+
114
+ export class PNextRedirectError extends Error {
115
+ digest = redirectDigest;
116
+
117
+ constructor(
118
+ public location: string,
119
+ public status: RedirectStatus = 307,
120
+ ) {
121
+ super(`redirect to ${location}`);
122
+ }
123
+ }
124
+
125
+ export function redirect<Route extends RoutePath>(
126
+ route: Route,
127
+ options: RedirectOptions<Route>,
128
+ ): never;
129
+ export function redirect(location: string, status?: RedirectStatus): never;
130
+ export function redirect<Route extends RoutePath>(
131
+ location: Route | string,
132
+ optionsOrStatus: RedirectOptions<Route> | RedirectStatus = 307,
133
+ ): never {
134
+ if (typeof optionsOrStatus === 'number') {
135
+ if (redirectInBrowser(location, 'replace')) return undefined as never;
136
+ throw new PNextRedirectError(location, optionsOrStatus);
137
+ }
138
+ const href = routeHref(location, optionsOrStatus);
139
+ if (redirectInBrowser(href, 'replace')) return undefined as never;
140
+ throw new PNextRedirectError(href, optionsOrStatus.status ?? 307);
141
+ }
142
+
143
+ export function permanentRedirect<Route extends RoutePath>(
144
+ route: Route,
145
+ options: HrefOptions<Route>,
146
+ ): never;
147
+ export function permanentRedirect(location: string): never;
148
+ export function permanentRedirect<Route extends RoutePath>(
149
+ location: Route | string,
150
+ options?: HrefOptions<Route>,
151
+ ): never {
152
+ const href = options ? routeHref(location, options) : location;
153
+ if (redirectInBrowser(href, 'replace')) return undefined as never;
154
+ throw new PNextRedirectError(href, 308);
155
+ }
156
+
157
+ export function isNotFoundError(error: unknown) {
158
+ return (
159
+ error instanceof PNextNotFoundError ||
160
+ errorDigest(error) === notFoundDigest ||
161
+ errorDigest(error) === nextNotFoundDigest
162
+ );
163
+ }
164
+
165
+ export function isRedirectError(error: unknown): error is PNextRedirectError {
166
+ return error instanceof PNextRedirectError || errorDigest(error) === redirectDigest;
167
+ }
168
+
169
+ export function isForbiddenError(error: unknown): error is PNextForbiddenError {
170
+ return (
171
+ error instanceof PNextForbiddenError ||
172
+ errorDigest(error) === forbiddenDigest ||
173
+ errorDigest(error) === nextForbiddenDigest
174
+ );
175
+ }
176
+
177
+ export function isUnauthorizedError(error: unknown): error is PNextUnauthorizedError {
178
+ return (
179
+ error instanceof PNextUnauthorizedError ||
180
+ errorDigest(error) === unauthorizedDigest ||
181
+ errorDigest(error) === nextUnauthorizedDigest
182
+ );
183
+ }
184
+
185
+ function errorDigest(error: unknown) {
186
+ return typeof error === 'object' && error !== null && 'digest' in error
187
+ ? (error as { digest?: unknown }).digest
188
+ : undefined;
189
+ }
190
+
191
+ function redirectInBrowser(location: string, mode: 'push' | 'replace') {
192
+ if (!process.browser && typeof window === 'undefined') return false;
193
+
194
+ const href = new URL(location, window.location.href).href;
195
+ if (mode === 'push') window.location.assign(href);
196
+ else window.location.replace(href);
197
+ return true;
198
+ }
@@ -0,0 +1,53 @@
1
+ // Router event seams: the location-change, navigation-start and navigation-commit listener sets
2
+ // compat hooks subscribe to, plus the post-navigation scroll action. All share one tier - an entry
3
+ // that reads router state pulls this in at first paint, one that only has a <Link> gets it with the
4
+ // runtime chunk - and none may sit in ./hub, which is a chunk shared with the runtime.
5
+ import { locationKey, routerState } from './hub';
6
+ import type { NavigationScrollAction, NavigationScrollOptions } from './types';
7
+
8
+ export let navigationScrollAction: NavigationScrollAction | undefined;
9
+
10
+ export function setNavigationScrollAction(action: NavigationScrollAction | undefined) {
11
+ navigationScrollAction = action;
12
+ }
13
+
14
+ export function scheduleNavigationScroll(url: URL, options: NavigationScrollOptions = {}) {
15
+ navigationScrollAction?.(url, options);
16
+ }
17
+
18
+ export function locationListeners() {
19
+ window.__PNEXT_LOCATION_LISTENERS__ ??= new Set();
20
+ return window.__PNEXT_LOCATION_LISTENERS__;
21
+ }
22
+
23
+ export function emitLocationChange() {
24
+ routerState.observedLocationKey = locationKey();
25
+ for (const listener of [...locationListeners()]) listener();
26
+ }
27
+
28
+ // Fires at the start of every soft navigation (link click, router.push,
29
+ // refresh). Compat's link-status uses it to end a link's pending state when a
30
+ // different navigation supersedes it.
31
+ // Annotated pure so an entry that subscribes to nothing (a link-only page)
32
+ // shakes the whole seam out of its first-paint closure.
33
+ export const navigationStartListeners = /* @__PURE__ */ new Set<() => void>();
34
+
35
+ export function onNavigationStart(listener: () => void) {
36
+ navigationStartListeners.add(listener);
37
+ return () => navigationStartListeners.delete(listener);
38
+ }
39
+
40
+ export function emitNavigationStart() {
41
+ for (const listener of [...navigationStartListeners]) listener();
42
+ }
43
+
44
+ export const navigationCommitListeners = /* @__PURE__ */ new Set<() => void>();
45
+
46
+ export function onNavigationCommit(listener: () => void) {
47
+ navigationCommitListeners.add(listener);
48
+ return () => navigationCommitListeners.delete(listener);
49
+ }
50
+
51
+ export function emitNavigationCommit() {
52
+ for (const listener of [...navigationCommitListeners]) listener();
53
+ }
@@ -0,0 +1,70 @@
1
+ // History entry identity: the ids pnext stamps on `history.state`, and the seed
2
+ // that puts them there for the hard-loaded document.
3
+ //
4
+ // Its own module because its tier is decided by the app, not by the router: a
5
+ // page whose client graph reads router state (`api/client-navigation`) seeds at
6
+ // first paint and pulls this in; a page that only has a <Link> never reads an id
7
+ // before the navigation runtime lands, so this rides the idle chunk with it.
8
+ import { routerState } from './hub';
9
+
10
+ export const HISTORY_BFCACHE_ID_KEY = '__pnextBfcacheId';
11
+
12
+ export function historyState(): Record<string, unknown> {
13
+ const state = history.state as Record<string, unknown> | null;
14
+ return state && typeof state === 'object' ? state : {};
15
+ }
16
+
17
+ export function historyBfcacheId(
18
+ state: Record<string, unknown> = historyState(),
19
+ ): string | undefined {
20
+ const value = state[HISTORY_BFCACHE_ID_KEY];
21
+ return typeof value === 'string' ? value : undefined;
22
+ }
23
+
24
+ function newHistoryId(prefix: string) {
25
+ return `${prefix}${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
26
+ }
27
+
28
+ export function newBfcacheId() {
29
+ return newHistoryId('b_');
30
+ }
31
+
32
+ export function newEntryId() {
33
+ return newHistoryId('e');
34
+ }
35
+
36
+ /**
37
+ * Stamp the hard-loaded entry's ids onto `history.state` and record which entry is on screen. Called
38
+ * at module scope by `api/client-navigation` - the module that reads them - rather than from the
39
+ * hub's install, so a page whose client graph never touches router state does not pay for them:
40
+ *
41
+ * - `useRouter().bfcacheId` keys client subtrees, so the id must be stable from the first client
42
+ * render; waiting for the runtime's load-event snapshot would flip it from '' to a real value on
43
+ * the first navigation and remount every keyed subtree.
44
+ * - an entry with no id is indistinguishable from an app-created (shallow) one, and `patchHistory`
45
+ * carries the ids forward onto an app pushState.
46
+ *
47
+ * The runtime seeds the same fields when it installs, so a page without this call still gets ids
48
+ * before it can navigate away.
49
+ */
50
+ export function seedHistoryEntry() {
51
+ if (!process.browser && typeof window === 'undefined') return;
52
+ const state = historyState();
53
+ const entryId = state.__pnextEntry;
54
+ const hasEntryId = typeof entryId === 'string';
55
+ routerState.renderedEntryId = hasEntryId ? entryId : newEntryId();
56
+ if (historyBfcacheId(state) && hasEntryId) return;
57
+ try {
58
+ history.replaceState(
59
+ {
60
+ ...state,
61
+ __pnextEntry: routerState.renderedEntryId,
62
+ [HISTORY_BFCACHE_ID_KEY]: historyBfcacheId(state) ?? newBfcacheId(),
63
+ },
64
+ '',
65
+ location.href,
66
+ );
67
+ } catch {
68
+ // Without a stable id, bfcache-keyed subtrees fall back to remounting.
69
+ }
70
+ }