@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,142 @@
1
+ import { currentParams, currentRequest, getWorkUnit } from '../../request/context';
2
+ import {
3
+ cacheComponents,
4
+ hangingPromise,
5
+ isPrerendering,
6
+ isRuntimePrefetchPrerender,
7
+ } from '../../ppr';
8
+ import { currentRenderCacheMeta, insideUnstableCacheProducer } from '../cache/revalidate';
9
+ import { insideUseCacheProducer, recordUseCacheRootParamRead } from '../cache/use-cache';
10
+ import { generateStaticParamsScope } from '../static-params';
11
+ import { accumulateRootVaryParam } from '../segment/vary-params';
12
+
13
+ function currentRoutePattern(): string {
14
+ let pathname: string;
15
+ try {
16
+ pathname = new URL(currentRequest()?.url ?? '').pathname;
17
+ } catch {
18
+ return '';
19
+ }
20
+ const paramNamesByValue = new Map<string, string>();
21
+ for (const [name, value] of Object.entries(currentParams())) {
22
+ if (typeof value === 'string') paramNamesByValue.set(value, name);
23
+ }
24
+ return pathname
25
+ .split('/')
26
+ .map(segment => {
27
+ try {
28
+ const name = paramNamesByValue.get(decodeURIComponent(segment));
29
+ return name ? `[${name}]` : segment;
30
+ } catch {
31
+ return segment;
32
+ }
33
+ })
34
+ .join('/');
35
+ }
36
+
37
+ function rootParamContextError(name: string): Error | undefined {
38
+ const unit = getWorkUnit();
39
+ // Keep the module specifier out of a literal source string: the static
40
+ // compat-import rewrite must not rewrite this user-facing diagnostic.
41
+ const specifier = ['next', 'root-params'].join('/');
42
+ const call = `\`import('${specifier}').${name}()\``;
43
+ const route = currentRoutePattern();
44
+
45
+ const inUseCache = insideUseCacheProducer();
46
+ const inUnstableCache = insideUnstableCacheProducer();
47
+
48
+ if (inUseCache && inUnstableCache) {
49
+ return Object.assign(
50
+ new Error(
51
+ `Route ${route} used ${call} inside \`"use cache"\` nested within \`unstable_cache\`. Root params are not available in this context.`,
52
+ ),
53
+ { digest: 'E1140' },
54
+ );
55
+ }
56
+
57
+ if (inUseCache) {
58
+ recordUseCacheRootParamRead(name);
59
+ return undefined;
60
+ }
61
+
62
+ if (inUnstableCache) {
63
+ return Object.assign(
64
+ new Error(
65
+ `Route ${route} used ${call} inside \`unstable_cache\`. This is not supported. Use \`"use cache"\` instead.`,
66
+ ),
67
+ { digest: 'E1141' },
68
+ );
69
+ }
70
+
71
+ if (!unit) return undefined;
72
+
73
+ if (unit.phase === 'action') {
74
+ return new Error(
75
+ `${call} was used inside a Server Action. This is not supported. ` +
76
+ `Functions from '${specifier}' can only be called in the context of a route.`,
77
+ );
78
+ }
79
+
80
+ if (unit.phase !== 'after' && unit.routeKind === 'route-handler') {
81
+ return new Error(
82
+ `Route ${route} used ${call} inside a Route Handler. ` +
83
+ `Support for this API in Route Handlers is planned for a future version of Next.js.`,
84
+ );
85
+ }
86
+
87
+ return undefined;
88
+ }
89
+
90
+ export function rootParam<T = string | string[] | undefined>(name: string): Promise<T> {
91
+ // Inside generateStaticParams, a root param resolves only when a PARENT
92
+ // generateStaticParams already provided it; reading the param in the very
93
+ // call that defines it is a build error (Next E394).
94
+ const gsp = generateStaticParamsScope();
95
+ if (gsp) {
96
+ if (name in gsp.provided) return Promise.resolve(gsp.provided[name] as T);
97
+ const route = (currentRenderCacheMeta()?.route ?? '')
98
+ .replace(/:\.\.\.([^/*]+)\*?/g, '[...$1]')
99
+ .replace(/:([^/*]+)\*/g, '[...$1]')
100
+ .replace(/:([^/*]+)/g, '[$1]');
101
+ return Promise.reject(
102
+ new Error(
103
+ `Route ${route} used \`import('${['next', 'root-params'].join('/')}').${name}()\` inside \`generateStaticParams\`, ` +
104
+ `but the \`${name}\` parameter was not provided by a parent \`generateStaticParams\`. ` +
105
+ `In \`generateStaticParams\`, root params are only available for segments nested below the segment that provides them.`,
106
+ ),
107
+ );
108
+ }
109
+ // Segment-M2: a root param read varies EVERY segment of the response (Next
110
+ // merges the rootParams set into each segment accumulator).
111
+ accumulateRootVaryParam(name);
112
+ const error = rootParamContextError(name);
113
+ if (error) return Promise.reject(error);
114
+ // A runtime-prefetch prerender renders against the REAL sampled request, so root params are concrete
115
+ // there (root params are always available in a static prerender, so a runtime prefetch has them too).
116
+ // Hanging them would postpone the ROOT LAYOUT itself - the whole document, not a boundary - so the
117
+ // render would produce no shell at all.
118
+ if (
119
+ !insideUseCacheProducer() &&
120
+ cacheComponents() &&
121
+ isPrerendering() &&
122
+ !isRuntimePrefetchPrerender()
123
+ ) {
124
+ return hangingPromise<T>(`rootParam(${name})`);
125
+ }
126
+ const value = currentParams()[name];
127
+ return Promise.resolve((Array.isArray(value) && value.length === 0 ? undefined : value) as T);
128
+ }
129
+
130
+ const rootParamsModule = new Proxy(
131
+ {},
132
+ {
133
+ get(_target, prop: string | symbol): unknown {
134
+ if (typeof prop !== 'string') return undefined;
135
+ if (prop === '__esModule') return true;
136
+ if (prop === 'default') return undefined;
137
+ return () => rootParam(prop);
138
+ },
139
+ },
140
+ ) as Record<string, () => Promise<unknown>>;
141
+
142
+ export default rootParamsModule;
@@ -0,0 +1,49 @@
1
+ // Pages-router surface for the server layers (pages islands SSR with the
2
+ // pages/pages-edge condition targets — see serverRequireAlias). The
3
+ // materialized page wrapper stashes the request's router state (route pattern,
4
+ // canonical asPath, merged query) on the globalThis-anchored request scope;
5
+ // useRouter() here returns it so pages components SSR the same values Next's
6
+ // pages router would. isReady stays false during SSR (Next semantics).
7
+ const noop = () => undefined
8
+ const events = { on: noop, off: noop, emit: noop }
9
+
10
+ function state() {
11
+ try {
12
+ const anchored = /** @type {Record<PropertyKey, any>} */ (globalThis)
13
+ const storage = anchored[Symbol.for('pnext.requestStorage')]
14
+ const scope = storage && storage.getStore ? storage.getStore() : undefined
15
+ return (scope && scope[Symbol.for('pnext.pagesRouterState')]) || undefined
16
+ } catch {
17
+ return undefined
18
+ }
19
+ }
20
+
21
+ function currentRouter() {
22
+ const s = state()
23
+ const pathname = (s && s.pathname) || '/'
24
+ return {
25
+ pathname,
26
+ route: pathname,
27
+ query: (s && s.query) || {},
28
+ asPath: (s && s.asPath) || '/',
29
+ basePath: '',
30
+ isReady: false,
31
+ isFallback: false,
32
+ isPreview: false,
33
+ events,
34
+ push: async () => true,
35
+ replace: async () => true,
36
+ prefetch: async () => {},
37
+ back: noop,
38
+ forward: noop,
39
+ reload: noop,
40
+ }
41
+ }
42
+
43
+ exports.Router = { events }
44
+ exports.default = exports.Router
45
+ exports.useRouter = () => currentRouter()
46
+ /** @param {(props: object) => unknown} Component */
47
+ exports.withRouter = Component =>
48
+ /** @param {object} props */
49
+ props => Component({ ...props, router: currentRouter() })
@@ -0,0 +1,143 @@
1
+ import { useEffect, useState } from 'preact/hooks';
2
+ import { blockJavascriptUrl } from '../../api/router';
3
+
4
+ /**
5
+ * Pages-router surface, present so shared components importing next/router
6
+ * still build. pnext is app-router only; navigation maps to the pnext router
7
+ * where it can and no-ops where pages-router concepts don't exist.
8
+ */
9
+
10
+ type RouterEventHandler = (...args: unknown[]) => void;
11
+
12
+ const noop = () => undefined;
13
+
14
+ const routerEvents = {
15
+ on: noop as (event: string, handler: RouterEventHandler) => void,
16
+ off: noop as (event: string, handler: RouterEventHandler) => void,
17
+ emit: noop as (event: string, ...args: unknown[]) => void,
18
+ };
19
+
20
+ export interface PagesRouter {
21
+ pathname: string;
22
+ route: string;
23
+ query: Record<string, string | string[]>;
24
+ asPath: string;
25
+ basePath: string;
26
+ isReady: boolean;
27
+ isFallback: boolean;
28
+ isPreview: boolean;
29
+ events: typeof routerEvents;
30
+ push(url: string): Promise<boolean>;
31
+ replace(url: string): Promise<boolean>;
32
+ prefetch(url: string): Promise<void>;
33
+ back(): void;
34
+ forward(): void;
35
+ reload(): void;
36
+ }
37
+
38
+ interface PagesRouterState {
39
+ pathname?: string;
40
+ asPath?: string;
41
+ query?: Record<string, string | string[]>;
42
+ }
43
+
44
+ // The pages-router state the materialized page wrapper emits: SSR reads the
45
+ // per-request scope (anchored on globalThis — this module is bundled per
46
+ // layer), the browser reads the inline __PNEXT_PAGES_DATA__ JSON node that
47
+ // ships with (and is swapped along with) the page HTML.
48
+ function pagesRouterState(browser: boolean): PagesRouterState | undefined {
49
+ if (!browser) {
50
+ const storage = (globalThis as Record<PropertyKey, unknown>)[
51
+ Symbol.for('pnext.requestStorage')
52
+ ] as { getStore(): Record<PropertyKey, unknown> | undefined } | undefined;
53
+ return storage?.getStore?.()?.[Symbol.for('pnext.pagesRouterState')] as
54
+ | PagesRouterState
55
+ | undefined;
56
+ }
57
+ const node = document.getElementById('__PNEXT_PAGES_DATA__');
58
+ if (!node?.textContent) return undefined;
59
+ try {
60
+ return JSON.parse(node.textContent) as PagesRouterState;
61
+ } catch {
62
+ return undefined;
63
+ }
64
+ }
65
+
66
+ function browserQuery(url: URL): Record<string, string> {
67
+ const query: Record<string, string> = {};
68
+ for (const [key, value] of url.searchParams) {
69
+ if (key !== '_rsc') query[key] = value;
70
+ }
71
+ return query;
72
+ }
73
+
74
+ function currentRouter(ready: boolean): PagesRouter {
75
+ const browser = process.browser || typeof window !== 'undefined';
76
+ const url = browser ? new URL(window.location.href) : undefined;
77
+ const state = pagesRouterState(browser);
78
+ const pathname = state?.pathname ?? url?.pathname ?? '/';
79
+ return {
80
+ pathname,
81
+ route: pathname,
82
+ // In the browser the address bar's own search params overlay the
83
+ // server-computed query (they are the live values after shallow/query-only
84
+ // history updates); on the server the state already merged them. The
85
+ // router-fetch cache key (`_rsc`) is never part of the page's query.
86
+ query: url
87
+ ? { ...(state?.query ?? {}), ...browserQuery(url) }
88
+ : (state?.query ?? {}),
89
+ asPath: url ? `${url.pathname}${url.search}` : (state?.asPath ?? '/'),
90
+ basePath: '',
91
+ isReady: browser && ready,
92
+ isFallback: false,
93
+ isPreview: false,
94
+ events: routerEvents,
95
+ push(target: string) {
96
+ if (blockJavascriptUrl(target)) return Promise.resolve(false);
97
+ if (browser) window.location.href = target;
98
+ return Promise.resolve(true);
99
+ },
100
+ replace(target: string) {
101
+ if (blockJavascriptUrl(target)) return Promise.resolve(false);
102
+ if (browser) window.location.replace(target);
103
+ return Promise.resolve(true);
104
+ },
105
+ prefetch(target: string) {
106
+ blockJavascriptUrl(target);
107
+ return Promise.resolve();
108
+ },
109
+ back() {
110
+ if (browser) window.history.back();
111
+ },
112
+ forward() {
113
+ if (browser) window.history.forward();
114
+ },
115
+ reload() {
116
+ if (browser) window.location.reload();
117
+ },
118
+ };
119
+ }
120
+
121
+ // Next semantics: isReady is FALSE during the hydration render (matching the SSR markup - preact
122
+ // hydrate adopts DOM without patching mismatches, so a true-at-hydration value would never reach
123
+ // attributes) and flips via a post-hydration re-render. Once flipped, later mounts see true immediately.
124
+ let pagesRouterReady = false;
125
+
126
+ export function useRouter(): PagesRouter {
127
+ const [ready, setReady] = useState(pagesRouterReady);
128
+ useEffect(() => {
129
+ pagesRouterReady = true;
130
+ setReady(true);
131
+ }, []);
132
+ return currentRouter(ready);
133
+ }
134
+
135
+ export const Router = { events: routerEvents };
136
+ export default Router;
137
+
138
+ export function withRouter<Props extends { router?: PagesRouter }>(
139
+ Component: (props: Props) => unknown,
140
+ ) {
141
+ return (props: Omit<Props, 'router'>) =>
142
+ Component({ ...props, router: currentRouter(pagesRouterReady) } as Props);
143
+ }
@@ -0,0 +1,355 @@
1
+ import type { JSX } from 'preact';
2
+ import { escapeHtml } from '../../utils/html';
3
+ import { getNextConfig } from './config-loader';
4
+ import { registerResourceHint } from '../../render/resource-hints';
5
+
6
+ export type ScriptStrategy = 'beforeInteractive' | 'afterInteractive' | 'lazyOnload' | 'worker';
7
+
8
+ export type ScriptProps = Omit<JSX.ScriptHTMLAttributes<HTMLScriptElement>, 'src'> & {
9
+ src?: string;
10
+ strategy?: ScriptStrategy;
11
+ onLoad?: (event: Event) => void;
12
+ onReady?: () => void;
13
+ onError?: (event: Event) => void;
14
+ children?: string;
15
+ /** Stylesheets the script depends on; Next preloads these alongside the script itself. */
16
+ stylesheets?: string[];
17
+ };
18
+
19
+ /**
20
+ * Server-renderable approximation of next/script. onLoad/onReady/onError are unserializable across a
21
+ * Server-to-Client boundary (this module has no 'use client' pragma of its own) and never fire from
22
+ * here; they land in `scriptProps` and are filtered out wherever attrs get serialized. A `<Script>`
23
+ * rendered from an actual client component hydrates through client-script.tsx instead, where those
24
+ * callbacks do fire.
25
+ */
26
+ export default function Script({
27
+ strategy = 'afterInteractive',
28
+ children,
29
+ stylesheets,
30
+ ...scriptProps
31
+ }: ScriptProps) {
32
+ const src = typeof scriptProps.src === 'string' ? scriptProps.src : undefined;
33
+
34
+ // Dedup on Next's cache key (`id ?? src`): two `<Script id="x">` must be serialized to the document
35
+ // exactly once. The executed-set is scoped to the current render (tied to the per-request
36
+ // resource-hints buffer) so it never leaks across requests.
37
+ const dedupKey = (typeof scriptProps.id === 'string' && scriptProps.id) || src;
38
+ if (dedupKey) {
39
+ const keys = executedScriptKeys();
40
+ if (keys.has(dedupKey)) return null;
41
+ keys.add(dedupKey);
42
+ }
43
+
44
+ // A manually-passed `nonce` prop always wins, matching Next. The CSP-detected case has no per-Script
45
+ // signal to read here - it is stamped uniformly, after the whole document is assembled, by the
46
+ // renderer's stampDocumentNonce - so only the explicit override needs threading through this module.
47
+ const manualNonce = typeof scriptProps.nonce === 'string' ? scriptProps.nonce : undefined;
48
+
49
+ // lazyOnload scripts load well after hydration on a browser idle callback;
50
+ // Next doesn't preload them (a preload hint for something fetched minutes
51
+ // later just wastes bandwidth budget), so skip the hint for that strategy.
52
+ if (src && strategy !== 'lazyOnload') {
53
+ registerResourceHint({
54
+ rel: 'preload',
55
+ url: src,
56
+ as: 'script',
57
+ ...(manualNonce ? { nonce: manualNonce } : {}),
58
+ ...(typeof scriptProps.crossOrigin === 'string'
59
+ ? { crossOrigin: scriptProps.crossOrigin }
60
+ : {}),
61
+ });
62
+ }
63
+
64
+ if (stylesheets) {
65
+ for (const url of stylesheets) {
66
+ registerResourceHint({ rel: 'stylesheet', url });
67
+ }
68
+ }
69
+
70
+ if (strategy === 'beforeInteractive') {
71
+ // Next injects beforeInteractive scripts straight into the SSR document
72
+ // `<head>` (or the very top of `<body>`) with a `data-nscript` marker so its
73
+ // client bootstrapper can skip re-executing them. We collect into the shared
74
+ // head-script buffer the renderer flushes into `<head>`; the marker rides
75
+ // along as a normal prop so the core head-script serializer emits it.
76
+ headScripts().push({
77
+ props: { 'data-nscript': 'beforeInteractive', ...scriptProps },
78
+ content: inlineScriptContent(scriptProps, children),
79
+ });
80
+ return null;
81
+ }
82
+
83
+ if (strategy === 'worker' && nextScriptWorkersEnabled()) {
84
+ // experimental.nextScriptWorkers: run the script off-main-thread via
85
+ // Partytown. Next rewrites the tag to `type="text/partytown"` (Partytown's
86
+ // library, served under /_next/static/~partytown/, hijacks these on load).
87
+ const partytownProps: Record<string, unknown> = {
88
+ ...scriptProps,
89
+ type: 'text/partytown',
90
+ 'data-nscript': 'worker',
91
+ };
92
+ const workerInline =
93
+ typeof children === 'string' ? { dangerouslySetInnerHTML: { __html: children } } : {};
94
+ return <script {...partytownProps} {...workerInline} />;
95
+ }
96
+
97
+ // afterInteractive / lazyOnload: Next never SSRs the actual tag for these - only the preload hint
98
+ // above - because the real element is inserted client-side once its own hydration bootstrap has run,
99
+ // so a script that mutates shared state lands after earlier client-component effects rather than
100
+ // racing them. A bare `<Script>` usage inside a Server Component tree hydrates nothing here, so SSRing
101
+ // the tag inline would execute it immediately during HTML parse. Queue a descriptor instead; the
102
+ // renderer flushes one shared bootstrap that creates and appends the real elements at the right time.
103
+ const deferredContent = inlineScriptContent(scriptProps, children);
104
+ deferredScripts().push({
105
+ strategy: strategy === 'lazyOnload' ? 'lazyOnload' : 'afterInteractive',
106
+ attrs: deferredAttrs({ ...scriptProps, ...(manualNonce ? { nonce: manualNonce } : {}) }),
107
+ ...(typeof scriptProps.id === 'string' ? { id: scriptProps.id } : {}),
108
+ ...(src ? { src } : {}),
109
+ ...(deferredContent !== undefined ? { content: deferredContent } : {}),
110
+ });
111
+ return null;
112
+ }
113
+
114
+ export { Script };
115
+
116
+ /**
117
+ * `experimental.nextScriptWorkers` gate. When on, `strategy="worker"` scripts
118
+ * are rewritten to Partytown (`type="text/partytown"`).
119
+ */
120
+ function nextScriptWorkersEnabled(): boolean {
121
+ const experimental = getNextConfig().experimental as { nextScriptWorkers?: boolean } | undefined;
122
+ return experimental?.nextScriptWorkers === true;
123
+ }
124
+
125
+ /**
126
+ * The Partytown loader path Next serves the library from. Copied verbatim by the
127
+ * asset pipeline; the injected snippet points the worker sandbox here.
128
+ */
129
+ export const PARTYTOWN_LIB_PATH = '/_next/static/~partytown/';
130
+
131
+ /**
132
+ * Partytown config plus the inline snippet Next injects into <head> once when any `worker` script is
133
+ * present. `partytownSnippet()` returns the loader IIFE; users override config via a
134
+ * `data-partytown-config` block, mirrored here as a `window.partytown` seed.
135
+ */
136
+ export function partytownHeadScripts(): HeadScript[] {
137
+ const config = getNextConfig() as {
138
+ experimental?: { nextScriptWorkers?: boolean };
139
+ partytown?: Record<string, unknown>;
140
+ };
141
+ if (config.experimental?.nextScriptWorkers !== true) return [];
142
+ const partytownConfig = {
143
+ lib: PARTYTOWN_LIB_PATH,
144
+ ...(config.partytown ?? {}),
145
+ };
146
+ return [
147
+ {
148
+ props: { 'data-partytown-config': '' },
149
+ content: `partytown = ${JSON.stringify(partytownConfig)};`,
150
+ },
151
+ {
152
+ props: { 'data-partytown': '' },
153
+ content: partytownSnippet(partytownConfig.lib),
154
+ },
155
+ ];
156
+ }
157
+
158
+ /**
159
+ * Render the Partytown head scripts (config seed + loader snippet) to an HTML string for injection via
160
+ * the render seam. Returns '' when nextScriptWorkers is disabled - a no-op for every other app.
161
+ */
162
+ export function renderPartytownHeadScripts(): string {
163
+ return partytownHeadScripts().map(renderHeadScript).join('');
164
+ }
165
+
166
+ /**
167
+ * Minimal Partytown bootstrap snippet: registers the forwarding queue and lazily
168
+ * loads `partytown.js` from the configured lib path. Matches the shape Next
169
+ * emits closely enough for the `type="text/partytown"` rewrite + lib-path
170
+ * assertions; the full vendored snippet is copied by the asset pipeline.
171
+ */
172
+ function partytownSnippet(lib: string): string {
173
+ return (
174
+ `!(function(w,p,f,c){` +
175
+ `c=w[p]=Object.assign(w[p]||{},{lib:${JSON.stringify(lib)}});` +
176
+ `c.forward=c.forward||[];` +
177
+ `f=document.createElement('script');` +
178
+ `f.async=!0;f.src=c.lib+'partytown.js';` +
179
+ `document.head.appendChild(f);` +
180
+ `})(window,'partytown');`
181
+ );
182
+ }
183
+
184
+ // afterInteractive/lazyOnload descriptors (§ deferred bootstrap). Consumed by
185
+ // src/render/renderer.ts's renderDeferredScriptRuntime, which owns its own
186
+ // copy of this shape (core may not import compat) keyed off the same global —
187
+ // mirrors the ResourceHint/HeadScript protocol above.
188
+ export interface DeferredScript {
189
+ strategy: 'afterInteractive' | 'lazyOnload';
190
+ attrs: Record<string, string>;
191
+ id?: string;
192
+ src?: string;
193
+ content?: string;
194
+ }
195
+
196
+ function deferredScripts() {
197
+ const holder = globalThis as { __PNEXT_DEFERRED_SCRIPTS__?: DeferredScript[] };
198
+ holder.__PNEXT_DEFERRED_SCRIPTS__ ??= [];
199
+ return holder.__PNEXT_DEFERRED_SCRIPTS__;
200
+ }
201
+
202
+ export function clearDeferredScripts() {
203
+ (globalThis as { __PNEXT_DEFERRED_SCRIPTS__?: DeferredScript[] }).__PNEXT_DEFERRED_SCRIPTS__ = [];
204
+ }
205
+
206
+ export function takeDeferredScripts() {
207
+ const holder = globalThis as { __PNEXT_DEFERRED_SCRIPTS__?: DeferredScript[] };
208
+ const scripts = holder.__PNEXT_DEFERRED_SCRIPTS__ ?? [];
209
+ holder.__PNEXT_DEFERRED_SCRIPTS__ = [];
210
+ return scripts;
211
+ }
212
+
213
+ // Like scriptAttrs, but building a raw name -> value map (for
214
+ // `element.setAttribute(name, value)` client-side) instead of an
215
+ // HTML-escaped string — the deferred bootstrap reconstructs real elements via
216
+ // the DOM, never via innerHTML.
217
+ const DEFERRED_SKIP_PROPS = new Set(['src', 'strategy', 'dangerouslysetinnerhtml', 'id']);
218
+
219
+ function deferredAttrs(props: Record<string, unknown>): Record<string, string> {
220
+ const attrs: Record<string, string> = {};
221
+ for (const [key, value] of Object.entries(props)) {
222
+ const name = attrName(key);
223
+ if (!isAttrName(name) || DEFERRED_SKIP_PROPS.has(name) || name.startsWith('on')) continue;
224
+ if (value == null || value === false || typeof value === 'function') continue;
225
+ if (value === true) {
226
+ attrs[name] = '';
227
+ continue;
228
+ }
229
+ if (name === 'class' && Array.isArray(value)) {
230
+ const className = value
231
+ .filter(
232
+ (item): item is string | number => typeof item === 'string' || typeof item === 'number',
233
+ )
234
+ .join(' ');
235
+ if (className) attrs[name] = className;
236
+ continue;
237
+ }
238
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'bigint') {
239
+ attrs[name] = String(value);
240
+ }
241
+ }
242
+ return attrs;
243
+ }
244
+
245
+ export interface HeadScript {
246
+ props: Record<string, unknown>;
247
+ content?: string;
248
+ }
249
+
250
+ // The renderer replaces the resource-hints array with a fresh `[]` at the start
251
+ // of every render (clearResourceHints). Keying the executed-set off that array
252
+ // via a WeakMap gives us a dedup scope that lives exactly one render and is
253
+ // garbage-collected with it — no cross-request leakage.
254
+ const scriptDedupRegistry = new WeakMap<object, Set<string>>();
255
+
256
+ function executedScriptKeys(): Set<string> {
257
+ const holder = globalThis as { __PNEXT_RESOURCE_HINTS__?: object };
258
+ holder.__PNEXT_RESOURCE_HINTS__ ??= [];
259
+ const arr = holder.__PNEXT_RESOURCE_HINTS__;
260
+ let keys = scriptDedupRegistry.get(arr);
261
+ if (!keys) {
262
+ keys = new Set<string>();
263
+ scriptDedupRegistry.set(arr, keys);
264
+ }
265
+ return keys;
266
+ }
267
+
268
+ function headScripts() {
269
+ const holder = globalThis as { __PNEXT_HEAD_SCRIPTS__?: HeadScript[] };
270
+ holder.__PNEXT_HEAD_SCRIPTS__ ??= [];
271
+ return holder.__PNEXT_HEAD_SCRIPTS__;
272
+ }
273
+
274
+ export function clearHeadScripts() {
275
+ (globalThis as { __PNEXT_HEAD_SCRIPTS__?: HeadScript[] }).__PNEXT_HEAD_SCRIPTS__ = [];
276
+ }
277
+
278
+ export function takeHeadScripts() {
279
+ const holder = globalThis as { __PNEXT_HEAD_SCRIPTS__?: HeadScript[] };
280
+ const scripts = holder.__PNEXT_HEAD_SCRIPTS__ ?? [];
281
+ holder.__PNEXT_HEAD_SCRIPTS__ = [];
282
+ return scripts;
283
+ }
284
+
285
+ export function renderHeadScripts() {
286
+ return takeHeadScripts().map(renderHeadScript).join('\n ');
287
+ }
288
+
289
+ function renderHeadScript(script: HeadScript) {
290
+ const attrs = scriptAttrs(script.props);
291
+ const open = attrs ? `<script ${attrs}>` : '<script>';
292
+ return script.content === undefined
293
+ ? `${open}</script>`
294
+ : `${open}${escapeScriptText(script.content)}</script>`;
295
+ }
296
+
297
+ function inlineScriptContent(
298
+ props: Record<string, unknown>,
299
+ children: string | undefined,
300
+ ): string | undefined {
301
+ if (typeof children === 'string') return children;
302
+ const dangerous = props.dangerouslySetInnerHTML;
303
+ if (
304
+ dangerous &&
305
+ typeof dangerous === 'object' &&
306
+ typeof (dangerous as { __html?: unknown }).__html === 'string'
307
+ ) {
308
+ return (dangerous as { __html: string }).__html;
309
+ }
310
+ return undefined;
311
+ }
312
+
313
+ function scriptAttrs(props: Record<string, unknown>) {
314
+ const attrs = Object.entries(props).flatMap(([key, value]) => scriptAttr(attrName(key), value));
315
+ return attrs.join(' ');
316
+ }
317
+
318
+ function scriptAttr(name: string, value: unknown): string[] {
319
+ if (!isAttrName(name)) return [];
320
+ if (value == null || value === false || typeof value === 'function') return [];
321
+ if (name === 'strategy' || name === 'dangerouslysetinnerhtml' || name.startsWith('on')) return [];
322
+ if (value === true) return [name];
323
+ if (name === 'class' && Array.isArray(value)) {
324
+ const className = value
325
+ .filter(
326
+ (item): item is string | number => typeof item === 'string' || typeof item === 'number',
327
+ )
328
+ .join(' ');
329
+ return className ? [`class="${escapeHtml(className)}"`] : [];
330
+ }
331
+ if (typeof value !== 'string' && typeof value !== 'number' && typeof value !== 'bigint') {
332
+ return [];
333
+ }
334
+ return [`${name}="${escapeHtml(value)}"`];
335
+ }
336
+
337
+ function attrName(key: string) {
338
+ if (key === 'className') return 'class';
339
+ if (key === 'htmlFor') return 'for';
340
+ return key.toLowerCase();
341
+ }
342
+
343
+ function isAttrName(name: string) {
344
+ return /^[a-zA-Z_:][a-zA-Z0-9:._-]*$/.test(name);
345
+ }
346
+
347
+ const scriptTerminator = /(<\/|<)(s)(cript)/gi;
348
+
349
+ function escapeScriptText(text: string) {
350
+ return text.replace(
351
+ scriptTerminator,
352
+ (_, prefix: string, s: string, suffix: string) =>
353
+ `${prefix}${s === 's' ? '\\u0073' : '\\u0053'}${suffix}`,
354
+ );
355
+ }
@@ -0,0 +1,3 @@
1
+ // server-only import marker: valid in server modules (react-server condition
2
+ // equivalent); the client bundler keeps the real package error path.
3
+ export {};