@wular/pnext 0.0.3 → 0.0.6

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 (392) hide show
  1. package/README.md +11 -11
  2. package/bin/pnext +1 -1
  3. package/config/lint/base.js +7 -7
  4. package/config/ts/base.json +2 -4
  5. package/config/ts/react.json +2 -6
  6. package/package.json +23 -2
  7. package/reference/compat.md +1 -1
  8. package/reference/config.md +2 -2
  9. package/reference/css.md +13 -9
  10. package/reference/dev.md +1 -1
  11. package/reference/metadata.md +7 -7
  12. package/reference/navigation.md +35 -28
  13. package/reference/performance.md +70 -70
  14. package/reference/rendering.md +17 -17
  15. package/reference/routing.md +17 -17
  16. package/reference/typegen.md +12 -8
  17. package/src/api/cache.ts +36 -37
  18. package/src/api/client-cache.ts +2 -2
  19. package/src/api/client-navigation.ts +113 -109
  20. package/src/api/dynamic.tsx +58 -55
  21. package/src/api/link.tsx +49 -52
  22. package/src/api/navigation.ts +59 -58
  23. package/src/api/server.ts +152 -144
  24. package/src/api/suspense.ts +4 -4
  25. package/src/cli/adapters/vercel-warm.ts +126 -121
  26. package/src/cli/adapters/vercel.ts +437 -443
  27. package/src/cli/analyze.ts +333 -144
  28. package/src/cli/{named-bin.ts → boot/named-bin.ts} +37 -37
  29. package/src/cli/{boot-trace.ts → boot/trace.ts} +10 -10
  30. package/src/cli/build.ts +976 -978
  31. package/src/cli/create.ts +71 -63
  32. package/src/cli/dev.ts +116 -116
  33. package/src/cli/index.ts +88 -85
  34. package/src/cli/migrate/package-json.ts +73 -71
  35. package/src/cli/migrate/report.ts +32 -33
  36. package/src/cli/migrate/{index.ts → run.ts} +48 -49
  37. package/src/cli/migrate/scan.ts +46 -46
  38. package/src/cli/migrate/spinner.ts +9 -9
  39. package/src/cli/migrate/tsconfig.ts +35 -35
  40. package/src/cli/{server-entry.ts → serve/entry.ts} +57 -57
  41. package/src/cli/{request-pipeline.ts → serve/pipeline.ts} +386 -394
  42. package/src/cli/{serve-ui.ts → serve/ui.ts} +47 -47
  43. package/src/cli/start.ts +65 -66
  44. package/src/{typegen.ts → cli/typegen.ts} +59 -59
  45. package/src/client/build.ts +794 -768
  46. package/src/client/chunk-fold.ts +245 -240
  47. package/src/client/{paths.ts → chunk-name.ts} +6 -6
  48. package/src/client/entry.ts +162 -147
  49. package/src/client/prebuilt.ts +231 -223
  50. package/src/client/profile.ts +29 -29
  51. package/src/client/react-compiler.ts +20 -15
  52. package/src/client/{compat-surface.ts → react-tier.ts} +64 -64
  53. package/src/client/reference-stub.ts +51 -51
  54. package/src/client/reference.ts +19 -19
  55. package/src/{api → client}/router/events.ts +17 -17
  56. package/src/{api → client}/router/history.ts +16 -16
  57. package/src/{api → client}/router/hub.ts +52 -53
  58. package/src/{api/router.ts → client/router/index.ts} +61 -60
  59. package/src/{api → client}/router/policies.ts +24 -24
  60. package/src/{api → client}/router/runtime.ts +1988 -1961
  61. package/src/{api → client}/router/types.ts +93 -98
  62. package/src/compat/actions/client-plugin.ts +42 -43
  63. package/src/compat/actions/client-stub.ts +14 -14
  64. package/src/compat/actions/{action-client.ts → client.ts} +194 -193
  65. package/src/compat/actions/config.ts +63 -64
  66. package/src/compat/actions/detect.ts +68 -68
  67. package/src/compat/actions/discovery.ts +105 -105
  68. package/src/compat/actions/{action-dispatch.ts → dispatch.ts} +277 -274
  69. package/src/compat/actions/early-submit.ts +1 -1
  70. package/src/compat/actions/endpoint.ts +198 -198
  71. package/src/compat/actions/extensions.ts +811 -0
  72. package/src/compat/actions/flight.ts +23 -23
  73. package/src/compat/actions/form-state.ts +34 -34
  74. package/src/compat/actions/hoist.ts +382 -236
  75. package/src/compat/actions/ids.ts +7 -12
  76. package/src/compat/actions/index.ts +8 -8
  77. package/src/compat/actions/instances.ts +46 -46
  78. package/src/compat/actions/origin.ts +47 -48
  79. package/src/compat/actions/protocol.ts +22 -22
  80. package/src/compat/actions/registry.ts +19 -19
  81. package/src/compat/{misc/action-return.ts → actions/return.ts} +60 -57
  82. package/src/compat/actions/rewrite.ts +125 -125
  83. package/src/compat/actions/{action-router.ts → router.ts} +10 -10
  84. package/src/compat/actions/serve.ts +132 -136
  85. package/src/compat/actions/server-tag.ts +4 -4
  86. package/src/compat/actions/{action-shared.ts → shared.ts} +34 -34
  87. package/src/compat/actions/unrecognized-error.ts +4 -4
  88. package/src/compat/{index.ts → aliases.ts} +112 -109
  89. package/src/compat/bundler/bun-externals.ts +18 -18
  90. package/src/compat/bundler/cjs-exports.ts +271 -223
  91. package/src/compat/bundler/config.ts +116 -111
  92. package/src/compat/bundler/externals.ts +12 -12
  93. package/src/compat/bundler/import-meta-url.ts +19 -19
  94. package/src/compat/bundler/modularize-imports.ts +36 -33
  95. package/src/compat/bundler/new-url-asset.ts +22 -24
  96. package/src/compat/bundler/optimize-package-imports.ts +111 -107
  97. package/src/compat/bundler/polyfill.ts +28 -28
  98. package/src/compat/bundler/react-compiler.ts +35 -29
  99. package/src/compat/bundler/react-profiler.tsx +11 -11
  100. package/src/compat/bundler/relay-transform.ts +48 -47
  101. package/src/compat/bundler/require-context.ts +119 -113
  102. package/src/compat/bundler/resolve-extensions.ts +19 -19
  103. package/src/compat/bundler/source-cache.ts +25 -25
  104. package/src/compat/bundler/static-imports.ts +7 -7
  105. package/src/compat/bundler/symlink-imports.ts +46 -46
  106. package/src/compat/bundler/tsconfig-paths.ts +13 -15
  107. package/src/compat/bundler/wasm.ts +58 -60
  108. package/src/compat/bundler/webpack-loaders.ts +254 -241
  109. package/src/compat/bundler/worker.ts +101 -104
  110. package/src/compat/cache/build-flags.ts +29 -29
  111. package/src/compat/cache/build-prerender-errors.ts +40 -44
  112. package/src/compat/cache/custom-handler.ts +60 -53
  113. package/src/compat/cache/fetch-patch.ts +240 -240
  114. package/src/compat/cache/handler.ts +27 -31
  115. package/src/compat/cache/modern-handler.ts +148 -126
  116. package/src/compat/cache/resume-data-cache.ts +47 -45
  117. package/src/compat/cache/revalidate.ts +233 -232
  118. package/src/compat/cache/runtime-error.ts +35 -35
  119. package/src/compat/cache/use-cache-transform.ts +442 -417
  120. package/src/compat/cache/use-cache.ts +650 -614
  121. package/src/compat/cache-control.ts +140 -142
  122. package/src/compat/client/base-path.ts +21 -20
  123. package/src/compat/client/css-order.ts +18 -18
  124. package/src/compat/client/errors/bare-boundary.ts +11 -11
  125. package/src/compat/client/errors/control-flow.ts +23 -23
  126. package/src/compat/client/errors/error-boundary.ts +61 -61
  127. package/src/compat/client/errors/global-error.ts +101 -91
  128. package/src/compat/client/errors/install.ts +71 -72
  129. package/src/compat/client/errors/lazy.ts +23 -23
  130. package/src/compat/client/errors/primitive-throw.ts +47 -45
  131. package/src/compat/client/errors/soft-refresh.ts +4 -4
  132. package/src/compat/client/link-status.ts +33 -33
  133. package/src/compat/client/{nav-compat-runtime.ts → nav-runtime.ts} +20 -20
  134. package/src/compat/client/{nav-compat.ts → nav.ts} +12 -13
  135. package/src/compat/client/navigation-scroll.ts +63 -63
  136. package/src/compat/client/optimistic-routing.ts +93 -88
  137. package/src/compat/client/prefetch-cache.ts +23 -24
  138. package/src/compat/client/route-announcer.ts +35 -35
  139. package/src/compat/client/segment-cache-policy.ts +20 -20
  140. package/src/compat/client/segment-cache.ts +309 -315
  141. package/src/compat/client/segment-prefetch.ts +127 -132
  142. package/src/compat/client/trailing-slash.ts +5 -4
  143. package/src/compat/css/chunking.ts +113 -116
  144. package/src/compat/css/inline-css.ts +21 -21
  145. package/src/compat/css/lightningcss.ts +37 -38
  146. package/src/compat/css/modules.ts +161 -175
  147. package/src/compat/css/nonce.ts +7 -7
  148. package/src/compat/css/sass-plugin.ts +18 -21
  149. package/src/compat/css/sass.ts +150 -152
  150. package/src/compat/css/styled-jsx-runtime.ts +27 -27
  151. package/src/compat/css/styled-jsx.ts +21 -21
  152. package/src/compat/edge-runtime.ts +27 -27
  153. package/src/compat/{adapter → export}/build-complete.ts +72 -75
  154. package/src/compat/export/client.ts +29 -31
  155. package/src/compat/export/{index.ts → emit.ts} +111 -110
  156. package/src/compat/export/standalone.ts +62 -54
  157. package/src/compat/image-optimizer/cache.ts +51 -49
  158. package/src/compat/image-optimizer/detect.ts +52 -52
  159. package/src/compat/image-optimizer/{index.ts → optimize.ts} +189 -194
  160. package/src/compat/image-optimizer/source.ts +77 -80
  161. package/src/compat/lifecycle/after-scope.ts +26 -26
  162. package/src/compat/lifecycle/after.ts +48 -45
  163. package/src/compat/lifecycle/error-funnel.ts +98 -102
  164. package/src/compat/lifecycle/error-serialize.ts +30 -26
  165. package/src/compat/lifecycle/error-ui.ts +67 -32
  166. package/src/compat/lifecycle/instrumentation-client.ts +36 -38
  167. package/src/compat/lifecycle/instrumentation.ts +85 -85
  168. package/src/compat/lifecycle/node-console.ts +11 -11
  169. package/src/compat/lifecycle/testmode.ts +160 -132
  170. package/src/compat/mdx/compile.ts +60 -57
  171. package/src/compat/mdx/plugin.ts +11 -11
  172. package/src/compat/mdx/{next-mdx-stub.ts → stub.ts} +5 -5
  173. package/src/compat/{metadata-route-artifacts.ts → metadata-artifacts.ts} +195 -191
  174. package/src/compat/metadata.ts +75 -81
  175. package/src/compat/next/cache.ts +68 -69
  176. package/src/compat/next/canonical-url.ts +9 -9
  177. package/src/compat/next/client-cache.ts +19 -19
  178. package/src/compat/next/client-navigation.ts +112 -116
  179. package/src/compat/next/client-only.ts +1 -1
  180. package/src/compat/next/client-script.tsx +99 -93
  181. package/src/compat/next/client-server.ts +10 -10
  182. package/src/compat/next/config-loader.ts +176 -173
  183. package/src/compat/next/config.ts +7 -7
  184. package/src/compat/next/constants.cjs +6 -6
  185. package/src/compat/next/constants.ts +6 -6
  186. package/src/compat/next/custom-server.ts +26 -24
  187. package/src/compat/next/dist/client/components/app-router-headers.ts +21 -21
  188. package/src/compat/next/dist/server/app-render/work-unit-async-storage.external.cjs +3 -4
  189. package/src/compat/next/dist/server/web/spec-extension/revalidate.ts +1 -1
  190. package/src/compat/next/dist/server/web/spec-extension/unstable-cache.ts +1 -1
  191. package/src/compat/next/dist/server/web/spec-extension/unstable-no-store.ts +1 -1
  192. package/src/compat/next/dynamic.tsx +21 -18
  193. package/src/compat/next/error.tsx +52 -52
  194. package/src/compat/next/font/cache.ts +74 -74
  195. package/src/compat/next/font/google.ts +2 -2
  196. package/src/compat/next/font/index.ts +1 -1
  197. package/src/compat/next/font/local.ts +3 -3
  198. package/src/compat/next/font/runtime-client.ts +17 -15
  199. package/src/compat/next/font/runtime.ts +443 -408
  200. package/src/compat/next/font/shared.ts +120 -108
  201. package/src/compat/next/form.tsx +63 -63
  202. package/src/compat/next/head.tsx +2 -2
  203. package/src/compat/next/headers.ts +103 -95
  204. package/src/compat/next/image/client.tsx +220 -0
  205. package/src/compat/next/image/config.ts +56 -58
  206. package/src/compat/next/image/optimizer.ts +40 -36
  207. package/src/compat/next/image/patterns.ts +37 -40
  208. package/src/compat/next/{image-props.ts → image/props.ts} +208 -202
  209. package/src/compat/next/image/shared.ts +65 -57
  210. package/src/compat/next/image/static-metadata.ts +98 -107
  211. package/src/compat/next/image/validate.ts +79 -88
  212. package/src/compat/next/image.tsx +19 -23
  213. package/src/compat/next/index.ts +1 -1
  214. package/src/compat/next/legacy-image.tsx +59 -60
  215. package/src/compat/next/{link-validation-transform.ts → link-transform.ts} +95 -96
  216. package/src/compat/next/link.tsx +158 -158
  217. package/src/compat/next/navigation.cjs +12 -3
  218. package/src/compat/next/navigation.ts +48 -50
  219. package/src/compat/next/offline.ts +27 -27
  220. package/src/compat/next/og.ts +121 -124
  221. package/src/compat/next/preferred-region.ts +13 -14
  222. package/src/compat/next/redirects.ts +58 -56
  223. package/src/compat/next/resource-hints.ts +73 -76
  224. package/src/compat/next/rewrites.ts +130 -133
  225. package/src/compat/next/root-params.ts +45 -45
  226. package/src/compat/next/{optimistic-route-state.ts → route-state.ts} +52 -52
  227. package/src/compat/next/router.cjs +4 -2
  228. package/src/compat/next/router.ts +58 -61
  229. package/src/compat/next/script.tsx +108 -108
  230. package/src/compat/next/server-only.ts +1 -1
  231. package/src/compat/next/server.ts +19 -19
  232. package/src/compat/next/svgr.ts +18 -17
  233. package/src/compat/next/telemetry.ts +24 -24
  234. package/src/compat/next/{image-usage.ts → usage.ts} +70 -39
  235. package/src/compat/next/user-agent.ts +53 -49
  236. package/src/compat/next/web-vitals.ts +22 -24
  237. package/src/compat/otel/api.ts +41 -41
  238. package/src/compat/otel/client-trace-metadata.ts +25 -27
  239. package/src/compat/otel/fetch-span.ts +29 -29
  240. package/src/compat/otel/tracer.ts +331 -331
  241. package/src/compat/pages/api.ts +456 -0
  242. package/src/compat/pages/client-plugin.ts +36 -36
  243. package/src/compat/pages/router-state.ts +34 -34
  244. package/src/compat/pages/{index.ts → router.ts} +130 -135
  245. package/src/compat/ppr/io.ts +12 -12
  246. package/src/compat/ppr/missing-root-params.ts +34 -38
  247. package/src/compat/ppr/root-params-scan.ts +66 -66
  248. package/src/compat/ppr/root-params-transform.ts +24 -26
  249. package/src/compat/ppr/root-params.ts +30 -30
  250. package/src/compat/ppr/segment-config-incompat.ts +6 -7
  251. package/src/compat/protocol.ts +71 -70
  252. package/src/compat/react/action-state.ts +47 -48
  253. package/src/compat/react/client-lite.ts +15 -15
  254. package/src/compat/react/client.ts +4 -4
  255. package/src/compat/react/compiler-runtime.ts +11 -11
  256. package/src/compat/react/dom-client.ts +44 -44
  257. package/src/compat/react/dom-react-server.ts +10 -16
  258. package/src/compat/react/dom-server.ts +10 -10
  259. package/src/compat/react/dom.ts +52 -52
  260. package/src/compat/react/hooks-extra.ts +34 -35
  261. package/src/compat/react/parity.ts +64 -61
  262. package/src/compat/react/preact.ts +81 -82
  263. package/src/compat/react/react-server.ts +28 -28
  264. package/src/compat/react/router-shim.ts +1 -1
  265. package/src/compat/react/server-component-use.ts +8 -8
  266. package/src/compat/react/server-inserted-html.ts +30 -31
  267. package/src/compat/react/server.ts +53 -55
  268. package/src/compat/react/use.ts +32 -32
  269. package/src/compat/react/view-transition.ts +20 -20
  270. package/src/compat/register/actions.ts +35 -824
  271. package/src/compat/register/boot.ts +41 -41
  272. package/src/compat/register/build-tier.ts +5 -5
  273. package/src/compat/register/build.ts +74 -70
  274. package/src/compat/register/bundler.ts +161 -156
  275. package/src/compat/register/cache.ts +20 -20
  276. package/src/compat/register/client-errors.ts +3 -3
  277. package/src/compat/register/config.ts +6 -6
  278. package/src/compat/register/css-extras.ts +30 -34
  279. package/src/compat/register/edge-runtime.ts +3 -3
  280. package/src/compat/register/errors.ts +10 -12
  281. package/src/compat/register/export.ts +16 -16
  282. package/src/compat/register/font.ts +11 -11
  283. package/src/compat/register/hooks.ts +2 -2
  284. package/src/compat/register/image.ts +40 -40
  285. package/src/compat/register/index.ts +59 -62
  286. package/src/compat/register/instrumentation-client.ts +10 -10
  287. package/src/compat/register/lifecycle.ts +25 -28
  288. package/src/compat/register/mdx.ts +10 -10
  289. package/src/compat/register/middleware.ts +226 -16
  290. package/src/compat/register/otel.ts +80 -88
  291. package/src/compat/register/pages-api.ts +10 -463
  292. package/src/compat/register/ppr.ts +16 -16
  293. package/src/compat/register/protocol.ts +17 -18
  294. package/src/compat/register/proxy.ts +49 -51
  295. package/src/compat/register/render.ts +79 -76
  296. package/src/compat/register/routing.ts +162 -159
  297. package/src/compat/register/segment.ts +24 -1887
  298. package/src/compat/register/static-image.ts +3 -3
  299. package/src/compat/register/{misc.ts → taint.ts} +9 -9
  300. package/src/compat/register/typed-routes.ts +14 -14
  301. package/src/compat/register/{usecache.ts → use-cache.ts} +39 -39
  302. package/src/compat/register/validation.ts +18 -18
  303. package/src/compat/segment/loading-boundary.ts +43 -45
  304. package/src/compat/segment/page-slot.ts +69 -69
  305. package/src/compat/segment/serve.ts +1884 -0
  306. package/src/compat/segment/tree.ts +113 -112
  307. package/src/compat/segment/vary-key.ts +38 -38
  308. package/src/compat/segment/vary-params.ts +138 -142
  309. package/src/compat/static-params.ts +14 -12
  310. package/src/compat/tsconfig-defaults.ts +87 -91
  311. package/src/compat/typecheck/{index.ts → check.ts} +234 -212
  312. package/src/compat/typecheck/worker.ts +15 -12
  313. package/src/compat/typed-routes/{index.ts → generate.ts} +36 -36
  314. package/src/compat/typed-routes/manifest.ts +174 -170
  315. package/src/compat/typed-routes/typegen.ts +127 -110
  316. package/src/compat/validation/errors.ts +16 -19
  317. package/src/compat/validation/prerender-diagnostics.ts +521 -504
  318. package/src/compat/validation/{index.ts → validate.ts} +647 -648
  319. package/src/compat-bootstrap.ts +16 -16
  320. package/src/config.ts +69 -69
  321. package/src/css/build.ts +230 -227
  322. package/src/css/postcss.ts +79 -80
  323. package/src/css/worker.ts +14 -15
  324. package/src/dev/client-actions.ts +10 -10
  325. package/src/dev/client-chunk-store.ts +27 -27
  326. package/src/dev/{client-key-cache.ts → restart/client-key.ts} +76 -76
  327. package/src/dev/{restart-cache.ts → restart/enabled.ts} +1 -1
  328. package/src/dev/{global-css-cache.ts → restart/global-css.ts} +91 -83
  329. package/src/dev/{node-module-bundle-cache.ts → restart/node-modules.ts} +24 -24
  330. package/src/dev/{route-bundle-key-cache.ts → restart/route-bundle-key.ts} +53 -53
  331. package/src/dev/{route-facts-cache.ts → restart/route-facts.ts} +82 -82
  332. package/src/dev/server.ts +804 -820
  333. package/src/env.ts +46 -43
  334. package/src/extensions.ts +491 -478
  335. package/src/index.ts +8 -8
  336. package/src/internal.ts +20 -23
  337. package/src/{islands → render}/boundary-error.ts +3 -3
  338. package/src/render/hooks.ts +71 -71
  339. package/src/render/island-context.ts +14 -14
  340. package/src/render/metadata.ts +310 -310
  341. package/src/{ppr-postpone.ts → render/postpone.ts} +5 -5
  342. package/src/{ppr.ts → render/ppr.ts} +244 -245
  343. package/src/render/renderer.ts +2076 -2082
  344. package/src/render/resource-hints.ts +16 -17
  345. package/src/render/slots.tsx +224 -235
  346. package/src/{islands → render}/static-children.ts +9 -12
  347. package/src/{islands → render}/static-slots.ts +37 -37
  348. package/src/{cache/context.ts → request/cache.ts} +20 -20
  349. package/src/request/context.ts +107 -107
  350. package/src/{dynamic/source.ts → resolve/dynamic.ts} +152 -143
  351. package/src/resolve/engine.ts +90 -77
  352. package/src/resolve/imports.ts +475 -463
  353. package/src/resolve/scan-facts.ts +442 -186
  354. package/src/resolve/source-text.ts +37 -37
  355. package/src/{dynamic → resolve}/tree-shake.ts +132 -128
  356. package/src/routing/forwarded.ts +19 -19
  357. package/src/routing/handler.ts +84 -91
  358. package/src/routing/href.ts +69 -70
  359. package/src/routing/{metadata.ts → metadata-files.ts} +403 -401
  360. package/src/{proxy.ts → routing/proxy.ts} +306 -312
  361. package/src/routing/{request-runtime.ts → request-environment.ts} +10 -10
  362. package/src/routing/routes.ts +833 -848
  363. package/src/routing/slots.ts +164 -160
  364. package/src/runtime/loader.ts +952 -0
  365. package/src/{dev → runtime}/module-cache.ts +309 -287
  366. package/src/{dev → runtime}/module-generations.ts +9 -9
  367. package/src/{dev → runtime}/module-transform.ts +81 -72
  368. package/src/{dev/imports.ts → runtime/modules.ts} +934 -847
  369. package/src/runtime/{server.ts → vendor-build.ts} +848 -1696
  370. package/src/runtime/vendor.ts +425 -404
  371. package/src/styles.d.ts +9 -0
  372. package/src/types.ts +320 -335
  373. package/src/utils/ansi.ts +5 -5
  374. package/src/utils/{source.ts → code.ts} +15 -12
  375. package/src/utils/content-type.ts +3 -3
  376. package/src/utils/decode.ts +2 -2
  377. package/src/utils/dev-profile.ts +13 -13
  378. package/src/utils/error-log.ts +6 -6
  379. package/src/utils/esbuild.ts +18 -18
  380. package/src/utils/fs-cache.ts +13 -13
  381. package/src/utils/fs.ts +57 -49
  382. package/src/utils/html.ts +20 -24
  383. package/src/utils/native-require.ts +8 -8
  384. package/src/utils/serialize.ts +139 -146
  385. package/src/utils/verbose.ts +18 -18
  386. package/src/cli/analyze-print.ts +0 -181
  387. package/src/compat/middleware/manifest.ts +0 -210
  388. package/src/compat/next/image-client.tsx +0 -215
  389. package/src/compat/next/link-usage.ts +0 -29
  390. package/src/css/index.ts +0 -2
  391. package/src/render/index.ts +0 -1
  392. package/src/style-modules.d.ts +0 -9
@@ -7,11 +7,11 @@
7
7
  * `<form action={fn}>` vnode hook, progressive-form enhancement, and synchronous island-prop revival.
8
8
  * Everything that can only run once an action has fired - argument encoding, the POST wire,
9
9
  * redirect/refresh/error semantics, action-return revival, the error overlay body - lives in
10
- * action-dispatch.ts and is reached through import(), so it rides a deferred chunk whose fetch
10
+ * dispatch.ts and is reached through import(), so it rides a deferred chunk whose fetch
11
11
  * overlaps the action's own round trip.
12
12
  */
13
- import { options as preactOptions, type ComponentType, type VNode } from 'preact';
14
- import { __pnextPushFormStatus } from '../react/dom';
13
+ import { options as preactOptions, type ComponentType, type VNode } from 'preact'
14
+ import { __pnextPushFormStatus } from '../react/dom'
15
15
  import {
16
16
  ACTION_ID_FIELD,
17
17
  FORM_STATE_FIELD,
@@ -20,7 +20,7 @@ import {
20
20
  isActionError,
21
21
  reviveBinaryMarker,
22
22
  type ActionFunction,
23
- } from './action-shared';
23
+ } from './shared'
24
24
 
25
25
  // Out-of-band carrier for a plain server-action form's id once the client
26
26
  // runtime is up. React strips the progressive `$ACTION_ID` hidden inputs from a
@@ -29,12 +29,12 @@ import {
29
29
  // `form.innerHTML` leaks `<input name="$pnext_action_id" ...>`. We move the id
30
30
  // to this attribute and drop the hidden input (see stripProgressiveActionIds),
31
31
  // keeping submission working via the fallbacks that read it.
32
- const ACTION_ID_ATTR = 'data-pnext-action-id';
33
- const PROP_ACTION_MARKER = '$$pnextAction';
34
- const ACTION_CLICK_ID_ATTR = 'data-pnext-action-click';
35
- const PROP_ERROR_RESET_MARKER = '$$pnextErrorReset';
32
+ const ACTION_ID_ATTR = 'data-pnext-action-id'
33
+ const PROP_ACTION_MARKER = '$$pnextAction'
34
+ const ACTION_CLICK_ID_ATTR = 'data-pnext-action-click'
35
+ const PROP_ERROR_RESET_MARKER = '$$pnextErrorReset'
36
36
 
37
- export { isActionError };
37
+ export { isActionError }
38
38
 
39
39
  // ---------------------------------------------------------------------------
40
40
  // dispatch entry point (the wire itself is deferred)
@@ -45,28 +45,28 @@ export { isActionError };
45
45
  // fetched-and-evaluated chunk lands behind the frame and a driver reading the DOM the instant
46
46
  // `click()` resolves sees no request. Warm on `pnext:hydrated` and remember the entry point, so the
47
47
  // warm call is a microtask that drains in the click's own task.
48
- const dispatchRuntime = () => import('./action-dispatch');
48
+ const dispatchRuntime = () => import('./dispatch')
49
49
 
50
- let warmDispatch: ((id: string, args: unknown[]) => Promise<unknown>) | undefined;
50
+ let warmDispatch: ((id: string, args: unknown[]) => Promise<unknown>) | undefined
51
51
 
52
- const loadDispatch = () => dispatchRuntime().then(module => (warmDispatch = module.callAction));
52
+ const loadDispatch = () => dispatchRuntime().then(module => (warmDispatch = module.callAction))
53
53
 
54
54
  // Warming is speculative: offline (or any failed chunk fetch) must not surface as an unhandled
55
55
  // rejection, which the client error last-resort escalates to the global-error document. A real
56
56
  // action call still awaits - and rejects through - loadDispatch.
57
57
  const warmDispatchChunk = () => {
58
- void loadDispatch().catch(() => undefined);
59
- };
58
+ void loadDispatch().catch(() => undefined)
59
+ }
60
60
 
61
61
  function callAction(id: string, args: unknown[]): Promise<unknown> {
62
- return warmDispatch ? warmDispatch(id, args) : loadDispatch().then(call => call(id, args));
62
+ return warmDispatch ? warmDispatch(id, args) : loadDispatch().then(call => call(id, args))
63
63
  }
64
64
 
65
65
  function registerClientReference(
66
66
  id: string,
67
67
  component: ComponentType<Record<string, unknown>>,
68
68
  ): void {
69
- actionReturnClientReferences.set(id, component);
69
+ actionReturnClientReferences.set(id, component)
70
70
  }
71
71
 
72
72
  // ---------------------------------------------------------------------------
@@ -74,44 +74,44 @@ function registerClientReference(
74
74
  // ---------------------------------------------------------------------------
75
75
 
76
76
  function reviveProps<T>(value: T): T {
77
- return reviveValue(value) as T;
77
+ return reviveValue(value) as T
78
78
  }
79
79
 
80
80
  function reviveValue(value: unknown): unknown {
81
- if (value === null || typeof value !== 'object') return value;
82
- if (Array.isArray(value)) return value.map(reviveValue);
83
- const record = value as Record<string, unknown>;
84
- const error = reviveErrorMarker(record);
85
- if (error) return error;
86
- if (record[PROP_ERROR_RESET_MARKER] === true) return refreshCurrentRoute;
81
+ if (value === null || typeof value !== 'object') return value
82
+ if (Array.isArray(value)) return value.map(reviveValue)
83
+ const record = value as Record<string, unknown>
84
+ const error = reviveErrorMarker(record)
85
+ if (error) return error
86
+ if (record[PROP_ERROR_RESET_MARKER] === true) return refreshCurrentRoute
87
87
  if (typeof record[PROP_ACTION_MARKER] === 'string') {
88
- return createAction(record[PROP_ACTION_MARKER]);
88
+ return createAction(record[PROP_ACTION_MARKER])
89
89
  }
90
- const binary = reviveBinaryMarker(record);
91
- if (binary !== undefined) return binary;
92
- const revived: Record<string, unknown> = {};
93
- for (const [key, item] of Object.entries(record)) revived[key] = reviveValue(item);
94
- return revived;
90
+ const binary = reviveBinaryMarker(record)
91
+ if (binary !== undefined) return binary
92
+ const revived: Record<string, unknown> = {}
93
+ for (const [key, item] of Object.entries(record)) revived[key] = reviveValue(item)
94
+ return revived
95
95
  }
96
96
 
97
97
  function reviveErrorMarker(record: Record<string, unknown>): Error | undefined {
98
- const marker = record.$$pnextError;
99
- if (marker === null || typeof marker !== 'object') return undefined;
100
- const data = marker as Record<string, unknown>;
101
- const error = new Error(typeof data.message === 'string' ? data.message : '');
102
- if (typeof data.name === 'string') error.name = data.name;
103
- if (typeof data.digest === 'string') (error as Error & { digest?: string }).digest = data.digest;
104
- return error;
98
+ const marker = record.$$pnextError
99
+ if (marker === null || typeof marker !== 'object') return undefined
100
+ const data = marker as Record<string, unknown>
101
+ const error = new Error(typeof data.message === 'string' ? data.message : '')
102
+ if (typeof data.name === 'string') error.name = data.name
103
+ if (typeof data.digest === 'string') (error as Error & { digest?: string }).digest = data.digest
104
+ return error
105
105
  }
106
106
 
107
107
  function refreshCurrentRoute(): void {
108
- location.reload();
108
+ location.reload()
109
109
  }
110
110
 
111
111
  function createAction(id: string): ActionFunction {
112
- const action: ActionFunction = async (...args: unknown[]) => callAction(id, args);
113
- action.$$pnextActionId = id;
114
- return action;
112
+ const action: ActionFunction = async (...args: unknown[]) => callAction(id, args)
113
+ action.$$pnextActionId = id
114
+ return action
115
115
  }
116
116
 
117
117
  // ---------------------------------------------------------------------------
@@ -119,7 +119,7 @@ function createAction(id: string): ActionFunction {
119
119
  // ---------------------------------------------------------------------------
120
120
 
121
121
  interface ActionDomNode extends Element {
122
- __pnextFormAction?: (formData: FormData) => unknown;
122
+ __pnextFormAction?: (formData: FormData) => unknown
123
123
  }
124
124
 
125
125
  // ---------------------------------------------------------------------------
@@ -132,18 +132,18 @@ interface ActionDomNode extends Element {
132
132
  * time (including the submitter's pair) parked on the form node.
133
133
  */
134
134
  interface QueuedSubmission {
135
- data: FormData;
136
- submitter: ActionDomNode | null;
135
+ data: FormData
136
+ submitter: ActionDomNode | null
137
137
  }
138
138
 
139
139
  interface QueuedForm extends HTMLFormElement {
140
- __pnextQueuedSubmit?: QueuedSubmission;
140
+ __pnextQueuedSubmit?: QueuedSubmission
141
141
  }
142
142
 
143
143
  function takeQueuedSubmission(form: HTMLFormElement): QueuedSubmission | undefined {
144
- const queued = (form as QueuedForm).__pnextQueuedSubmit;
145
- if (queued) delete (form as QueuedForm).__pnextQueuedSubmit;
146
- return queued;
144
+ const queued = (form as QueuedForm).__pnextQueuedSubmit
145
+ if (queued) delete (form as QueuedForm).__pnextQueuedSubmit
146
+ return queued
147
147
  }
148
148
 
149
149
  /** Dispatch a captured submission with form-status + post-action reset (the
@@ -153,47 +153,49 @@ function runFormSubmission(
153
153
  formData: FormData,
154
154
  dispatch: (formData: FormData) => unknown,
155
155
  ): void {
156
- const pop = pushFormStatus(form, formData);
156
+ const pop = pushFormStatus(form, formData)
157
157
  void Promise.resolve(dispatch(formData))
158
158
  .then(() => {
159
159
  // React resets uncontrolled fields after a completed form action.
160
- form.reset();
160
+ form.reset()
161
161
  })
162
162
  .catch(error => {
163
- if (!throwActionErrorAt(form, error)) throw error;
163
+ if (!throwActionErrorAt(form, error)) throw error
164
164
  })
165
- .finally(pop);
165
+ .finally(pop)
166
166
  }
167
167
 
168
168
  function throwActionErrorAt(node: Element, error: unknown): boolean {
169
- const root = node.closest('pnext-client');
170
- const rootVNode = (root as unknown as { __k?: VNode } | null)?.__k;
171
- const vnode = rootVNode ? findVNodeForElement(rootVNode, node) : undefined;
172
- const handler = (preactOptions as typeof preactOptions & {
173
- __e?: (error: unknown, vnode: VNode, oldVNode: VNode) => void;
174
- }).__e;
175
- if (!vnode || !handler) return false;
176
- handler(error, vnode, vnode);
177
- return true;
169
+ const root = node.closest('pnext-client')
170
+ const rootVNode = (root as unknown as { __k?: VNode } | null)?.__k
171
+ const vnode = rootVNode ? findVNodeForElement(rootVNode, node) : undefined
172
+ const handler = (
173
+ preactOptions as typeof preactOptions & {
174
+ __e?: (error: unknown, vnode: VNode, oldVNode: VNode) => void
175
+ }
176
+ ).__e
177
+ if (!vnode || !handler) return false
178
+ handler(error, vnode, vnode)
179
+ return true
178
180
  }
179
181
 
180
182
  function findVNodeForElement(vnode: VNode, element: Element): VNode | undefined {
181
- if ((vnode as VNode & { __e?: unknown }).__e === element) return vnode;
182
- const children = (vnode as VNode & { __k?: (VNode | null)[] }).__k;
183
- if (!children) return undefined;
183
+ if ((vnode as VNode & { __e?: unknown }).__e === element) return vnode
184
+ const children = (vnode as VNode & { __k?: (VNode | null)[] }).__k
185
+ if (!children) return undefined
184
186
  for (const child of children) {
185
- if (!child) continue;
186
- const found = findVNodeForElement(child, element);
187
- if (found) return found;
187
+ if (!child) continue
188
+ const found = findVNodeForElement(child, element)
189
+ if (found) return found
188
190
  }
189
- return undefined;
191
+ return undefined
190
192
  }
191
193
 
192
194
  /** Replay a pre-hydration submission the moment the form's function action
193
195
  * hydrates (called from the stashed ref below). */
194
196
  function replayQueuedSubmission(form: HTMLFormElement, fn: (formData: FormData) => unknown): void {
195
- const queued = takeQueuedSubmission(form);
196
- if (queued) runFormSubmission(form, queued.data, fn);
197
+ const queued = takeQueuedSubmission(form)
198
+ if (queued) runFormSubmission(form, queued.data, fn)
197
199
  }
198
200
 
199
201
  /**
@@ -204,74 +206,73 @@ function replayQueuedSubmission(form: HTMLFormElement, fn: (formData: FormData)
204
206
  */
205
207
  function adoptEarlySubmissions(): void {
206
208
  const holder = window as typeof window & {
207
- __pnextEarlySubmits?: HTMLFormElement[];
208
- __pnextRemoveEarlySubmit?: () => void;
209
- };
210
- holder.__pnextRemoveEarlySubmit?.();
211
- const forms = holder.__pnextEarlySubmits;
212
- if (!forms?.length) return;
209
+ __pnextEarlySubmits?: HTMLFormElement[]
210
+ __pnextRemoveEarlySubmit?: () => void
211
+ }
212
+ holder.__pnextRemoveEarlySubmit?.()
213
+ const forms = holder.__pnextEarlySubmits
214
+ if (!forms?.length) return
213
215
  const flush = () => {
214
216
  for (const form of forms.splice(0)) {
215
- const queued = takeQueuedSubmission(form);
216
- if (!queued) continue; // hydration replayed it already
217
+ const queued = takeQueuedSubmission(form)
218
+ if (!queued) continue // hydration replayed it already
217
219
  const stashed =
218
- queued.submitter?.__pnextFormAction ??
219
- (form as unknown as ActionDomNode).__pnextFormAction;
220
+ queued.submitter?.__pnextFormAction ?? (form as unknown as ActionDomNode).__pnextFormAction
220
221
  if (stashed) {
221
- runFormSubmission(form, queued.data, stashed);
222
- continue;
222
+ runFormSubmission(form, queued.data, stashed)
223
+ continue
223
224
  }
224
225
  const submitterId =
225
226
  queued.submitter?.getAttribute('name') === SUBMIT_ACTION_ID_FIELD
226
227
  ? queued.submitter.getAttribute('value')
227
- : null;
228
+ : null
228
229
  const id =
229
230
  submitterId ??
230
231
  form.querySelector<HTMLInputElement>(`input[name="${cssEscape(ACTION_ID_FIELD)}"]`)
231
232
  ?.value ??
232
233
  form.getAttribute(ACTION_ID_ATTR) ??
233
- undefined;
234
+ undefined
234
235
  const hasFormState = Boolean(
235
236
  form.querySelector(`input[name="${cssEscape(FORM_STATE_FIELD)}"]`),
236
- );
237
+ )
237
238
  if (id && !hasFormState) {
238
239
  // Server-only progressive form (no live state to update): dispatch the
239
240
  // RPC directly, like the live listener's unhydrated-form branch.
240
- runFormSubmission(form, queued.data, formData => callAction(id, [formData]));
241
+ runFormSubmission(form, queued.data, formData => callAction(id, [formData]))
241
242
  } else if (form.isConnected) {
242
243
  // A useActionState form whose island never hydrated (or an unknown
243
244
  // shape): give it the native progressive POST the capture prevented.
244
- form.submit();
245
+ form.submit()
245
246
  }
246
247
  }
247
- };
248
+ }
248
249
  // Islands hydrate asynchronously after this runtime installs; give their
249
250
  // refs (replayQueuedSubmission) first claim before falling back.
250
- setTimeout(flush, 300);
251
+ setTimeout(flush, 300)
251
252
  }
252
253
 
253
254
  type FunctionActionProps = Record<string, unknown> & {
254
- action?: unknown;
255
- formAction?: unknown;
256
- ref?: unknown;
257
- };
255
+ action?: unknown
256
+ formAction?: unknown
257
+ ref?: unknown
258
+ }
258
259
 
259
260
  function installVNodeHook() {
260
- const previous = preactOptions.vnode?.bind(preactOptions);
261
+ const previous = preactOptions.vnode?.bind(preactOptions)
261
262
  preactOptions.vnode = (vnode: VNode) => {
262
- previous?.(vnode);
263
- if (typeof vnode.type !== 'string') return;
264
- const props = vnode.props as FunctionActionProps;
263
+ previous?.(vnode)
264
+ if (typeof vnode.type !== 'string') return
265
+ const props = vnode.props as FunctionActionProps
265
266
  if (vnode.type === 'form' && typeof props.action === 'function') {
266
- stashFunctionAction(vnode, props, 'action');
267
+ stashFunctionAction(vnode, props, 'action')
267
268
  }
268
269
  if (
269
270
  (vnode.type === 'button' || vnode.type === 'input') &&
270
271
  typeof props.formAction === 'function'
271
272
  ) {
272
- stashFunctionAction(vnode, props, 'formAction');
273
+ stashFunctionAction(vnode, props, 'formAction')
273
274
  }
274
- };
275
+ }
275
276
  }
276
277
 
277
278
  /**
@@ -287,33 +288,33 @@ function stashFunctionAction(
287
288
  props: FunctionActionProps,
288
289
  key: 'action' | 'formAction',
289
290
  ) {
290
- const fn = props[key] as (formData: FormData) => unknown;
291
- delete props[key];
292
- const existingRef = (vnode as { ref?: unknown }).ref;
293
- (vnode as { ref?: unknown }).ref = (node: ActionDomNode | null) => {
291
+ const fn = props[key] as (formData: FormData) => unknown
292
+ delete props[key]
293
+ const existingRef = (vnode as { ref?: unknown }).ref
294
+ ;(vnode as { ref?: unknown }).ref = (node: ActionDomNode | null) => {
294
295
  if (node) {
295
- node.__pnextFormAction = fn;
296
+ node.__pnextFormAction = fn
296
297
  if (key === 'action' && node instanceof HTMLFormElement) {
297
- enhanceProgressiveForm(node, fn);
298
- replayQueuedSubmission(node, fn);
298
+ enhanceProgressiveForm(node, fn)
299
+ replayQueuedSubmission(node, fn)
299
300
  }
300
301
  if (key === 'formAction' && node instanceof HTMLElement) {
301
- const form = (node as { form?: HTMLFormElement | null }).form ?? null;
302
- const queued = form && (form as QueuedForm).__pnextQueuedSubmit;
302
+ const form = (node as { form?: HTMLFormElement | null }).form ?? null
303
+ const queued = form && (form as QueuedForm).__pnextQueuedSubmit
303
304
  if (form && queued?.submitter === node) {
304
- delete (form as QueuedForm).__pnextQueuedSubmit;
305
- runFormSubmission(form, queued.data, fn);
305
+ delete (form as QueuedForm).__pnextQueuedSubmit
306
+ runFormSubmission(form, queued.data, fn)
306
307
  }
307
308
  }
308
309
  }
309
- applyRef(existingRef, node);
310
- };
310
+ applyRef(existingRef, node)
311
+ }
311
312
  }
312
313
 
313
314
  interface FormStateMeta {
314
- action?: { $$pnextActionId?: string };
315
- state?: unknown;
316
- permalink?: string;
315
+ action?: { $$pnextActionId?: string }
316
+ state?: unknown
317
+ permalink?: string
317
318
  }
318
319
 
319
320
  /**
@@ -323,88 +324,88 @@ interface FormStateMeta {
323
324
  * every render, keeping the state field current.
324
325
  */
325
326
  function enhanceProgressiveForm(form: HTMLFormElement, fn: unknown) {
326
- const meta = (fn as { $$pnextFormState?: FormStateMeta }).$$pnextFormState;
327
- if (!meta) return;
328
- const id = meta.action?.$$pnextActionId;
329
- if (!id) return;
330
- form.setAttribute('method', 'post');
331
- form.setAttribute('enctype', 'multipart/form-data');
332
- if (meta.permalink) form.setAttribute('action', meta.permalink);
333
- setHiddenField(form, ACTION_ID_FIELD, id);
327
+ const meta = (fn as { $$pnextFormState?: FormStateMeta }).$$pnextFormState
328
+ if (!meta) return
329
+ const id = meta.action?.$$pnextActionId
330
+ if (!id) return
331
+ form.setAttribute('method', 'post')
332
+ form.setAttribute('enctype', 'multipart/form-data')
333
+ if (meta.permalink) form.setAttribute('action', meta.permalink)
334
+ setHiddenField(form, ACTION_ID_FIELD, id)
334
335
  // Non-JSON-serializable state (an action can return React elements, Maps,
335
336
  // circular structures, ...) cannot ride the progressive wire; fall back to
336
337
  // null rather than throwing inside the render's ref (which would take the
337
338
  // whole island down with it).
338
- let serializedState = 'null';
339
+ let serializedState = 'null'
339
340
  try {
340
- serializedState = JSON.stringify(meta.state ?? null) ?? 'null';
341
+ serializedState = JSON.stringify(meta.state ?? null) ?? 'null'
341
342
  } catch {
342
- serializedState = 'null';
343
+ serializedState = 'null'
343
344
  }
344
- setHiddenField(form, FORM_STATE_FIELD, serializedState);
345
+ setHiddenField(form, FORM_STATE_FIELD, serializedState)
345
346
  }
346
347
 
347
348
  function setHiddenField(form: HTMLFormElement, name: string, value: string) {
348
349
  let input = form.querySelector<HTMLInputElement>(
349
350
  `input[type="hidden"][name="${cssEscape(name)}"]`,
350
- );
351
+ )
351
352
  if (!input) {
352
- input = document.createElement('input');
353
- input.type = 'hidden';
354
- input.name = name;
355
- form.appendChild(input);
353
+ input = document.createElement('input')
354
+ input.type = 'hidden'
355
+ input.name = name
356
+ form.appendChild(input)
356
357
  }
357
- input.value = value;
358
+ input.value = value
358
359
  }
359
360
 
360
361
  function applyRef(ref: unknown, node: Element | null) {
361
- if (typeof ref === 'function') (ref as (node: Element | null) => void)(node);
362
- else if (ref && typeof ref === 'object') (ref as { current: Element | null }).current = node;
362
+ if (typeof ref === 'function') (ref as (node: Element | null) => void)(node)
363
+ else if (ref && typeof ref === 'object') (ref as { current: Element | null }).current = node
363
364
  }
364
365
 
365
366
  function installSubmitListener() {
366
367
  document.addEventListener(
367
368
  'submit',
368
369
  event => {
369
- const form = event.target as HTMLFormElement | null;
370
- if (!form || !(form instanceof HTMLFormElement)) return;
371
- const submitter = event.submitter as ActionDomNode | null;
370
+ const form = event.target as HTMLFormElement | null
371
+ if (!form || !(form instanceof HTMLFormElement)) return
372
+ const submitter = event.submitter as ActionDomNode | null
372
373
 
373
374
  const fn =
374
- submitter?.__pnextFormAction || (form as unknown as ActionDomNode).__pnextFormAction;
375
+ submitter?.__pnextFormAction || (form as unknown as ActionDomNode).__pnextFormAction
375
376
 
376
- let dispatch: ((formData: FormData) => unknown) | undefined = fn;
377
+ let dispatch: ((formData: FormData) => unknown) | undefined = fn
377
378
  if (!dispatch) {
378
379
  // A useActionState form that never hydrated (rendered by a server
379
380
  // component or an unhydrated client layout) has no live state to
380
381
  // update — let the native progressive POST run so the server
381
382
  // re-renders the page with the new form state.
382
- if (form.querySelector(`input[name="${cssEscape(FORM_STATE_FIELD)}"]`)) return;
383
+ if (form.querySelector(`input[name="${cssEscape(FORM_STATE_FIELD)}"]`)) return
383
384
  // Server-rendered progressive form: the id travels in a hidden field
384
385
  // (or the submitter button's own name/value pair under its distinct
385
386
  // field name, which overrides the form-level default).
386
387
  const submitterId =
387
388
  submitter?.getAttribute('name') === SUBMIT_ACTION_ID_FIELD
388
389
  ? submitter.getAttribute('value')
389
- : null;
390
+ : null
390
391
  const field = form.querySelector<HTMLInputElement>(
391
392
  `input[name="${cssEscape(ACTION_ID_FIELD)}"]`,
392
- );
393
+ )
393
394
  // The hidden id may have been moved out-of-band (stripProgressiveActionIds).
394
- const id = submitterId ?? field?.value ?? form.getAttribute(ACTION_ID_ATTR);
395
- if (!id) return; // not an action form; let the browser submit it
396
- dispatch = formData => callAction(id, [formData]);
395
+ const id = submitterId ?? field?.value ?? form.getAttribute(ACTION_ID_ATTR)
396
+ if (!id) return // not an action form; let the browser submit it
397
+ dispatch = formData => callAction(id, [formData])
397
398
  }
398
399
 
399
- event.preventDefault();
400
- const formData = new FormData(form, (submitter ?? undefined) as HTMLElement | undefined);
401
- runFormSubmission(form, formData, dispatch);
400
+ event.preventDefault()
401
+ const formData = new FormData(form, (submitter ?? undefined) as HTMLElement | undefined)
402
+ runFormSubmission(form, formData, dispatch)
402
403
  },
403
404
  // Bubble phase, so app-level onSubmit handlers that preventDefault
404
405
  // themselves run first and can opt out of the default action behavior.
405
406
  false,
406
- );
407
- adoptEarlySubmissions();
407
+ )
408
+ adoptEarlySubmissions()
408
409
  }
409
410
 
410
411
  /**
@@ -421,18 +422,18 @@ function installSubmitListener() {
421
422
  * POST fallback (installSubmitListener bails to native for form-state forms).
422
423
  */
423
424
  function stripProgressiveActionIds() {
424
- if (typeof document === 'undefined') return;
425
+ if (typeof document === 'undefined') return
425
426
  const inputs = document.querySelectorAll<HTMLInputElement>(
426
427
  `input[type="hidden"][name="${cssEscape(ACTION_ID_FIELD)}"]`,
427
- );
428
+ )
428
429
  for (const input of inputs) {
429
- const form = input.form;
430
- if (!form) continue;
431
- if (form.querySelector(`input[name="${cssEscape(FORM_STATE_FIELD)}"]`)) continue;
430
+ const form = input.form
431
+ if (!form) continue
432
+ if (form.querySelector(`input[name="${cssEscape(FORM_STATE_FIELD)}"]`)) continue
432
433
  if (input.value && !form.hasAttribute(ACTION_ID_ATTR)) {
433
- form.setAttribute(ACTION_ID_ATTR, input.value);
434
+ form.setAttribute(ACTION_ID_ATTR, input.value)
434
435
  }
435
- input.remove();
436
+ input.remove()
436
437
  }
437
438
  }
438
439
 
@@ -441,18 +442,18 @@ function installClickActionListener() {
441
442
  const target =
442
443
  event.target instanceof Element
443
444
  ? event.target.closest<HTMLElement>(`[${ACTION_CLICK_ID_ATTR}]`)
444
- : null;
445
- if (!target || (target instanceof HTMLButtonElement && target.disabled)) return;
446
- const id = target.getAttribute(ACTION_CLICK_ID_ATTR);
447
- if (!id) return;
448
- event.preventDefault();
449
- void callAction(id, []);
450
- });
445
+ : null
446
+ if (!target || (target instanceof HTMLButtonElement && target.disabled)) return
447
+ const id = target.getAttribute(ACTION_CLICK_ID_ATTR)
448
+ if (!id) return
449
+ event.preventDefault()
450
+ void callAction(id, [])
451
+ })
451
452
  }
452
453
 
453
454
  function cssEscape(value: string) {
454
- const escape = (globalThis as { CSS?: { escape?: (v: string) => string } }).CSS?.escape;
455
- return escape ? escape(value) : value.replace(/[^a-zA-Z0-9_-]/g, match => `\\${match}`);
455
+ const escape = (globalThis as { CSS?: { escape?: (v: string) => string } }).CSS?.escape
456
+ return escape ? escape(value) : value.replace(/[^a-zA-Z0-9_-]/g, match => `\\${match}`)
456
457
  }
457
458
 
458
459
  // Form-status feed for useFormStatus (react-dom compat).
@@ -463,9 +464,9 @@ function pushFormStatus(form: HTMLFormElement, data: FormData): () => void {
463
464
  data,
464
465
  method: (form.getAttribute('method') || 'get').toLowerCase(),
465
466
  action: form.getAttribute('action') ?? '',
466
- });
467
+ })
467
468
  } catch {
468
- return () => undefined;
469
+ return () => undefined
469
470
  }
470
471
  }
471
472
 
@@ -477,35 +478,35 @@ function pushFormStatus(form: HTMLFormElement, data: FormData): () => void {
477
478
  // pnext's server-rendered pages have no client-side boundary components, so the compat entry installs
478
479
  // the route's error.js as an overlay. Only the listeners are initial - the overlay body, which needs
479
480
  // preact's renderer and the refresh path, rides the deferred dispatch chunk.
480
- type ErrorComponentType = ComponentType<{ error: Error; reset: () => void }>;
481
+ type ErrorComponentType = ComponentType<{ error: Error; reset: () => void }>
481
482
 
482
- let overlayInstalled = false;
483
+ let overlayInstalled = false
483
484
 
484
485
  export function installActionErrorOverlay(Component: ErrorComponentType) {
485
- if ((!process.browser && typeof window === 'undefined') || overlayInstalled) return;
486
- overlayInstalled = true;
486
+ if ((!process.browser && typeof window === 'undefined') || overlayInstalled) return
487
+ overlayInstalled = true
487
488
 
488
489
  // Chained, not concurrent: two errors arriving before the chunk lands must
489
490
  // still see each other's effect on the overlay's "already showing" guard.
490
- let chain: Promise<unknown> = Promise.resolve();
491
+ let chain: Promise<unknown> = Promise.resolve()
491
492
  const show = (reason: unknown) => {
492
493
  chain = chain.then(async () => {
493
- const { showActionErrorOverlay } = await dispatchRuntime();
494
- showActionErrorOverlay(Component, reason);
495
- });
496
- };
494
+ const { showActionErrorOverlay } = await dispatchRuntime()
495
+ showActionErrorOverlay(Component, reason)
496
+ })
497
+ }
497
498
 
498
499
  window.addEventListener('unhandledrejection', event => {
499
- if (isActionError(event.reason)) show(event.reason);
500
- });
500
+ if (isActionError(event.reason)) show(event.reason)
501
+ })
501
502
  // useActionState rethrows action errors during render; without a class
502
503
  // error boundary in the tree the uncaught render error lands here.
503
504
  window.addEventListener('error', event => {
504
- if (isActionError(event.error)) show(event.error);
505
- });
505
+ if (isActionError(event.error)) show(event.error)
506
+ })
506
507
  window.addEventListener('pnext:action-error', event => {
507
- show((event as CustomEvent).detail);
508
- });
508
+ show((event as CustomEvent).detail)
509
+ })
509
510
  }
510
511
 
511
512
  // ---------------------------------------------------------------------------
@@ -513,26 +514,26 @@ export function installActionErrorOverlay(Component: ErrorComponentType) {
513
514
  // ---------------------------------------------------------------------------
514
515
 
515
516
  export function installActionRuntime() {
516
- if (!process.browser && typeof window === 'undefined') return;
517
+ if (!process.browser && typeof window === 'undefined') return
517
518
  if (!window.__PNEXT_ACTIONS__) {
518
519
  window.__PNEXT_ACTIONS__ = {
519
520
  call: callAction,
520
521
  createAction,
521
522
  registerClientReference,
522
523
  reviveProps,
523
- };
524
- installSubmitListener();
525
- installClickActionListener();
524
+ }
525
+ installSubmitListener()
526
+ installClickActionListener()
526
527
  // Every mountRoute (initial hydration + each soft-nav commit) fires
527
528
  // `pnext:hydrated`; strip leaked progressive action-id inputs from the
528
529
  // freshly committed DOM so a hydrated form matches React (no `$ACTION_ID`).
529
530
  // Hydration is also where the dispatch chunk gets warmed (see loadDispatch):
530
531
  // past first paint, before any click, and `import()` dedups the repeats.
531
- window.addEventListener('pnext:hydrated', stripProgressiveActionIds);
532
- window.addEventListener('pnext:hydrated', warmDispatchChunk);
533
- stripProgressiveActionIds();
532
+ window.addEventListener('pnext:hydrated', stripProgressiveActionIds)
533
+ window.addEventListener('pnext:hydrated', warmDispatchChunk)
534
+ stripProgressiveActionIds()
534
535
  }
535
- installVNodeHook();
536
+ installVNodeHook()
536
537
  }
537
538
 
538
- export { createAction, callAction, registerClientReference, reviveProps };
539
+ export { createAction, callAction, registerClientReference, reviveProps }