@wular/pnext 0.0.4 → 0.0.7

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 (395) hide show
  1. package/README.md +22 -16
  2. package/bin/pnext +6 -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 +87 -22
  8. package/reference/config.md +40 -93
  9. package/reference/css.md +42 -33
  10. package/reference/dev.md +26 -33
  11. package/reference/env.md +18 -20
  12. package/reference/getting-started.md +132 -0
  13. package/reference/metadata.md +31 -46
  14. package/reference/navigation.md +65 -105
  15. package/reference/performance.md +21 -142
  16. package/reference/rendering.md +78 -75
  17. package/reference/routing.md +97 -107
  18. package/reference/typegen.md +27 -29
  19. package/src/api/cache.ts +36 -37
  20. package/src/api/client-cache.ts +2 -2
  21. package/src/api/client-navigation.ts +121 -114
  22. package/src/api/dynamic.tsx +58 -55
  23. package/src/api/link.tsx +52 -53
  24. package/src/api/navigation.ts +59 -58
  25. package/src/api/server.ts +152 -144
  26. package/src/api/suspense.ts +4 -4
  27. package/src/cli/adapters/vercel-warm.ts +126 -121
  28. package/src/cli/adapters/vercel.ts +437 -443
  29. package/src/cli/analyze.ts +333 -144
  30. package/src/cli/{named-bin.ts → boot/named-bin.ts} +37 -37
  31. package/src/cli/{boot-trace.ts → boot/trace.ts} +10 -10
  32. package/src/cli/build.ts +976 -978
  33. package/src/cli/create.ts +72 -64
  34. package/src/cli/dev.ts +116 -116
  35. package/src/cli/index.ts +94 -85
  36. package/src/cli/migrate/package-json.ts +73 -71
  37. package/src/cli/migrate/report.ts +32 -33
  38. package/src/cli/migrate/{index.ts → run.ts} +48 -49
  39. package/src/cli/migrate/scan.ts +46 -46
  40. package/src/cli/migrate/spinner.ts +9 -9
  41. package/src/cli/migrate/tsconfig.ts +35 -35
  42. package/src/cli/{server-entry.ts → serve/entry.ts} +57 -57
  43. package/src/cli/{request-pipeline.ts → serve/pipeline.ts} +386 -394
  44. package/src/cli/{serve-ui.ts → serve/ui.ts} +47 -47
  45. package/src/cli/start.ts +65 -66
  46. package/src/{typegen.ts → cli/typegen.ts} +59 -59
  47. package/src/client/build.ts +802 -768
  48. package/src/client/chunk-fold.ts +245 -240
  49. package/src/client/{paths.ts → chunk-name.ts} +6 -6
  50. package/src/client/entry.ts +162 -147
  51. package/src/client/prebuilt.ts +231 -223
  52. package/src/client/profile.ts +29 -29
  53. package/src/client/react-compiler.ts +20 -15
  54. package/src/client/{compat-surface.ts → react-tier.ts} +64 -64
  55. package/src/client/reference-stub.ts +51 -51
  56. package/src/client/reference.ts +19 -19
  57. package/src/{api → client}/router/events.ts +32 -17
  58. package/src/{api → client}/router/history.ts +16 -16
  59. package/src/{api → client}/router/hub.ts +52 -53
  60. package/src/{api/router.ts → client/router/index.ts} +61 -60
  61. package/src/{api → client}/router/policies.ts +24 -24
  62. package/src/{api → client}/router/runtime.ts +2022 -1995
  63. package/src/{api → client}/router/types.ts +98 -98
  64. package/src/compat/actions/client-plugin.ts +42 -43
  65. package/src/compat/actions/client-stub.ts +14 -14
  66. package/src/compat/actions/{action-client.ts → client.ts} +194 -193
  67. package/src/compat/actions/config.ts +63 -64
  68. package/src/compat/actions/detect.ts +68 -68
  69. package/src/compat/actions/discovery.ts +105 -105
  70. package/src/compat/actions/{action-dispatch.ts → dispatch.ts} +277 -274
  71. package/src/compat/actions/early-submit.ts +1 -1
  72. package/src/compat/actions/endpoint.ts +198 -198
  73. package/src/compat/actions/extensions.ts +811 -0
  74. package/src/compat/actions/flight.ts +23 -23
  75. package/src/compat/actions/form-state.ts +34 -34
  76. package/src/compat/actions/hoist.ts +382 -236
  77. package/src/compat/actions/ids.ts +7 -12
  78. package/src/compat/actions/index.ts +8 -8
  79. package/src/compat/actions/instances.ts +46 -46
  80. package/src/compat/actions/origin.ts +47 -48
  81. package/src/compat/actions/protocol.ts +22 -22
  82. package/src/compat/actions/registry.ts +19 -19
  83. package/src/compat/{misc/action-return.ts → actions/return.ts} +60 -57
  84. package/src/compat/actions/rewrite.ts +125 -125
  85. package/src/compat/actions/{action-router.ts → router.ts} +10 -10
  86. package/src/compat/actions/serve.ts +132 -136
  87. package/src/compat/actions/server-tag.ts +4 -4
  88. package/src/compat/actions/{action-shared.ts → shared.ts} +34 -34
  89. package/src/compat/actions/unrecognized-error.ts +4 -4
  90. package/src/compat/{index.ts → aliases.ts} +112 -109
  91. package/src/compat/bundler/bun-externals.ts +18 -18
  92. package/src/compat/bundler/cjs-exports.ts +271 -223
  93. package/src/compat/bundler/config.ts +116 -111
  94. package/src/compat/bundler/externals.ts +12 -12
  95. package/src/compat/bundler/import-meta-url.ts +19 -19
  96. package/src/compat/bundler/modularize-imports.ts +36 -33
  97. package/src/compat/bundler/new-url-asset.ts +22 -24
  98. package/src/compat/bundler/optimize-package-imports.ts +111 -107
  99. package/src/compat/bundler/polyfill.ts +28 -28
  100. package/src/compat/bundler/react-compiler.ts +35 -29
  101. package/src/compat/bundler/react-profiler.tsx +11 -11
  102. package/src/compat/bundler/relay-transform.ts +48 -47
  103. package/src/compat/bundler/require-context.ts +119 -113
  104. package/src/compat/bundler/resolve-extensions.ts +19 -19
  105. package/src/compat/bundler/source-cache.ts +25 -25
  106. package/src/compat/bundler/static-imports.ts +7 -7
  107. package/src/compat/bundler/symlink-imports.ts +46 -46
  108. package/src/compat/bundler/tsconfig-paths.ts +13 -15
  109. package/src/compat/bundler/wasm.ts +58 -60
  110. package/src/compat/bundler/webpack-loaders.ts +254 -241
  111. package/src/compat/bundler/worker.ts +101 -104
  112. package/src/compat/cache/build-flags.ts +29 -29
  113. package/src/compat/cache/build-prerender-errors.ts +40 -44
  114. package/src/compat/cache/custom-handler.ts +60 -53
  115. package/src/compat/cache/fetch-patch.ts +240 -240
  116. package/src/compat/cache/handler.ts +27 -31
  117. package/src/compat/cache/modern-handler.ts +148 -126
  118. package/src/compat/cache/resume-data-cache.ts +47 -45
  119. package/src/compat/cache/revalidate.ts +233 -232
  120. package/src/compat/cache/runtime-error.ts +35 -35
  121. package/src/compat/cache/use-cache-transform.ts +442 -417
  122. package/src/compat/cache/use-cache.ts +650 -614
  123. package/src/compat/cache-control.ts +140 -142
  124. package/src/compat/client/base-path.ts +21 -20
  125. package/src/compat/client/css-order.ts +18 -18
  126. package/src/compat/client/errors/bare-boundary.ts +11 -11
  127. package/src/compat/client/errors/control-flow.ts +23 -23
  128. package/src/compat/client/errors/error-boundary.ts +61 -61
  129. package/src/compat/client/errors/global-error.ts +101 -91
  130. package/src/compat/client/errors/install.ts +71 -72
  131. package/src/compat/client/errors/lazy.ts +23 -23
  132. package/src/compat/client/errors/primitive-throw.ts +47 -45
  133. package/src/compat/client/errors/soft-refresh.ts +4 -4
  134. package/src/compat/client/link-status.ts +33 -33
  135. package/src/compat/client/{nav-compat-runtime.ts → nav-runtime.ts} +20 -20
  136. package/src/compat/client/{nav-compat.ts → nav.ts} +12 -13
  137. package/src/compat/client/navigation-scroll.ts +63 -63
  138. package/src/compat/client/optimistic-routing.ts +93 -88
  139. package/src/compat/client/prefetch-cache.ts +23 -24
  140. package/src/compat/client/route-announcer.ts +35 -35
  141. package/src/compat/client/segment-cache-policy.ts +20 -20
  142. package/src/compat/client/segment-cache.ts +309 -315
  143. package/src/compat/client/segment-prefetch.ts +127 -132
  144. package/src/compat/client/trailing-slash.ts +5 -4
  145. package/src/compat/css/chunking.ts +113 -116
  146. package/src/compat/css/inline-css.ts +21 -21
  147. package/src/compat/css/lightningcss.ts +37 -38
  148. package/src/compat/css/modules.ts +161 -175
  149. package/src/compat/css/nonce.ts +7 -7
  150. package/src/compat/css/sass-plugin.ts +18 -21
  151. package/src/compat/css/sass.ts +150 -152
  152. package/src/compat/css/styled-jsx-runtime.ts +27 -27
  153. package/src/compat/css/styled-jsx.ts +21 -21
  154. package/src/compat/edge-runtime.ts +27 -27
  155. package/src/compat/{adapter → export}/build-complete.ts +72 -75
  156. package/src/compat/export/client.ts +29 -31
  157. package/src/compat/export/{index.ts → emit.ts} +111 -110
  158. package/src/compat/export/standalone.ts +62 -54
  159. package/src/compat/image-optimizer/cache.ts +51 -49
  160. package/src/compat/image-optimizer/detect.ts +52 -52
  161. package/src/compat/image-optimizer/{index.ts → optimize.ts} +189 -194
  162. package/src/compat/image-optimizer/source.ts +77 -80
  163. package/src/compat/lifecycle/after-scope.ts +26 -26
  164. package/src/compat/lifecycle/after.ts +48 -45
  165. package/src/compat/lifecycle/error-funnel.ts +98 -102
  166. package/src/compat/lifecycle/error-serialize.ts +30 -26
  167. package/src/compat/lifecycle/error-ui.ts +67 -32
  168. package/src/compat/lifecycle/instrumentation-client.ts +36 -38
  169. package/src/compat/lifecycle/instrumentation.ts +85 -85
  170. package/src/compat/lifecycle/node-console.ts +11 -11
  171. package/src/compat/lifecycle/testmode.ts +160 -132
  172. package/src/compat/mdx/compile.ts +60 -57
  173. package/src/compat/mdx/plugin.ts +11 -11
  174. package/src/compat/mdx/{next-mdx-stub.ts → stub.ts} +5 -5
  175. package/src/compat/{metadata-route-artifacts.ts → metadata-artifacts.ts} +195 -191
  176. package/src/compat/metadata.ts +75 -81
  177. package/src/compat/next/cache.ts +68 -69
  178. package/src/compat/next/canonical-url.ts +9 -9
  179. package/src/compat/next/client-cache.ts +19 -19
  180. package/src/compat/next/client-navigation.ts +112 -116
  181. package/src/compat/next/client-only.ts +1 -1
  182. package/src/compat/next/client-script.tsx +99 -93
  183. package/src/compat/next/client-server.ts +10 -10
  184. package/src/compat/next/config-loader.ts +176 -173
  185. package/src/compat/next/config.ts +7 -7
  186. package/src/compat/next/constants.cjs +6 -6
  187. package/src/compat/next/constants.ts +6 -6
  188. package/src/compat/next/custom-server.ts +26 -24
  189. package/src/compat/next/dist/client/components/app-router-headers.ts +21 -21
  190. package/src/compat/next/dist/server/app-render/work-unit-async-storage.external.cjs +3 -4
  191. package/src/compat/next/dist/server/web/spec-extension/revalidate.ts +1 -1
  192. package/src/compat/next/dist/server/web/spec-extension/unstable-cache.ts +1 -1
  193. package/src/compat/next/dist/server/web/spec-extension/unstable-no-store.ts +1 -1
  194. package/src/compat/next/dynamic.tsx +21 -18
  195. package/src/compat/next/error.tsx +52 -52
  196. package/src/compat/next/font/cache.ts +74 -74
  197. package/src/compat/next/font/google.ts +2 -2
  198. package/src/compat/next/font/index.ts +1 -1
  199. package/src/compat/next/font/local.ts +3 -3
  200. package/src/compat/next/font/runtime-client.ts +17 -15
  201. package/src/compat/next/font/runtime.ts +443 -408
  202. package/src/compat/next/font/shared.ts +120 -108
  203. package/src/compat/next/form.tsx +63 -63
  204. package/src/compat/next/head.tsx +2 -2
  205. package/src/compat/next/headers.ts +103 -95
  206. package/src/compat/next/image/client.tsx +220 -0
  207. package/src/compat/next/image/config.ts +56 -58
  208. package/src/compat/next/image/optimizer.ts +40 -36
  209. package/src/compat/next/image/patterns.ts +37 -40
  210. package/src/compat/next/{image-props.ts → image/props.ts} +208 -202
  211. package/src/compat/next/image/shared.ts +65 -57
  212. package/src/compat/next/image/static-metadata.ts +98 -107
  213. package/src/compat/next/image/validate.ts +79 -88
  214. package/src/compat/next/image.tsx +19 -23
  215. package/src/compat/next/index.ts +1 -1
  216. package/src/compat/next/legacy-image.tsx +59 -60
  217. package/src/compat/next/{link-validation-transform.ts → link-transform.ts} +95 -96
  218. package/src/compat/next/link.tsx +158 -158
  219. package/src/compat/next/navigation.cjs +12 -3
  220. package/src/compat/next/navigation.ts +48 -50
  221. package/src/compat/next/offline.ts +27 -27
  222. package/src/compat/next/og.ts +121 -124
  223. package/src/compat/next/preferred-region.ts +13 -14
  224. package/src/compat/next/redirects.ts +58 -56
  225. package/src/compat/next/resource-hints.ts +73 -76
  226. package/src/compat/next/rewrites.ts +130 -133
  227. package/src/compat/next/root-params.ts +45 -45
  228. package/src/compat/next/{optimistic-route-state.ts → route-state.ts} +52 -52
  229. package/src/compat/next/router.cjs +4 -2
  230. package/src/compat/next/router.ts +58 -61
  231. package/src/compat/next/script.tsx +108 -108
  232. package/src/compat/next/server-only.ts +1 -1
  233. package/src/compat/next/server.ts +19 -19
  234. package/src/compat/next/svgr.ts +18 -17
  235. package/src/compat/next/telemetry.ts +24 -24
  236. package/src/compat/next/{image-usage.ts → usage.ts} +70 -39
  237. package/src/compat/next/user-agent.ts +53 -49
  238. package/src/compat/next/web-vitals.ts +22 -24
  239. package/src/compat/otel/api.ts +41 -41
  240. package/src/compat/otel/client-trace-metadata.ts +25 -27
  241. package/src/compat/otel/fetch-span.ts +29 -29
  242. package/src/compat/otel/tracer.ts +331 -331
  243. package/src/compat/pages/api.ts +456 -0
  244. package/src/compat/pages/client-plugin.ts +36 -36
  245. package/src/compat/pages/router-state.ts +34 -34
  246. package/src/compat/pages/{index.ts → router.ts} +130 -135
  247. package/src/compat/ppr/io.ts +12 -12
  248. package/src/compat/ppr/missing-root-params.ts +34 -38
  249. package/src/compat/ppr/root-params-scan.ts +66 -66
  250. package/src/compat/ppr/root-params-transform.ts +24 -26
  251. package/src/compat/ppr/root-params.ts +30 -30
  252. package/src/compat/ppr/segment-config-incompat.ts +6 -7
  253. package/src/compat/protocol.ts +71 -70
  254. package/src/compat/react/action-state.ts +47 -48
  255. package/src/compat/react/client-lite.ts +15 -15
  256. package/src/compat/react/client.ts +4 -4
  257. package/src/compat/react/compiler-runtime.ts +11 -11
  258. package/src/compat/react/dom-client.ts +44 -44
  259. package/src/compat/react/dom-react-server.ts +10 -16
  260. package/src/compat/react/dom-server.ts +10 -10
  261. package/src/compat/react/dom.ts +52 -52
  262. package/src/compat/react/hooks-extra.ts +34 -35
  263. package/src/compat/react/parity.ts +64 -61
  264. package/src/compat/react/preact.ts +81 -82
  265. package/src/compat/react/react-server.ts +28 -28
  266. package/src/compat/react/router-shim.ts +1 -1
  267. package/src/compat/react/server-component-use.ts +8 -8
  268. package/src/compat/react/server-inserted-html.ts +30 -31
  269. package/src/compat/react/server.ts +53 -55
  270. package/src/compat/react/use.ts +32 -32
  271. package/src/compat/react/view-transition.ts +20 -20
  272. package/src/compat/register/actions.ts +35 -824
  273. package/src/compat/register/boot.ts +41 -41
  274. package/src/compat/register/build-tier.ts +5 -5
  275. package/src/compat/register/build.ts +74 -70
  276. package/src/compat/register/bundler.ts +161 -156
  277. package/src/compat/register/cache.ts +20 -20
  278. package/src/compat/register/client-errors.ts +3 -3
  279. package/src/compat/register/config.ts +6 -6
  280. package/src/compat/register/css-extras.ts +30 -34
  281. package/src/compat/register/edge-runtime.ts +3 -3
  282. package/src/compat/register/errors.ts +10 -12
  283. package/src/compat/register/export.ts +16 -16
  284. package/src/compat/register/font.ts +11 -11
  285. package/src/compat/register/hooks.ts +2 -2
  286. package/src/compat/register/image.ts +40 -40
  287. package/src/compat/register/index.ts +59 -62
  288. package/src/compat/register/instrumentation-client.ts +10 -10
  289. package/src/compat/register/lifecycle.ts +25 -28
  290. package/src/compat/register/mdx.ts +10 -10
  291. package/src/compat/register/middleware.ts +226 -16
  292. package/src/compat/register/otel.ts +80 -88
  293. package/src/compat/register/pages-api.ts +10 -463
  294. package/src/compat/register/ppr.ts +16 -16
  295. package/src/compat/register/protocol.ts +17 -18
  296. package/src/compat/register/proxy.ts +49 -51
  297. package/src/compat/register/render.ts +79 -76
  298. package/src/compat/register/routing.ts +162 -159
  299. package/src/compat/register/segment.ts +24 -1897
  300. package/src/compat/register/static-image.ts +3 -3
  301. package/src/compat/register/{misc.ts → taint.ts} +9 -9
  302. package/src/compat/register/typed-routes.ts +14 -14
  303. package/src/compat/register/{usecache.ts → use-cache.ts} +39 -39
  304. package/src/compat/register/validation.ts +18 -18
  305. package/src/compat/segment/loading-boundary.ts +43 -45
  306. package/src/compat/segment/page-slot.ts +69 -69
  307. package/src/compat/segment/serve.ts +1884 -0
  308. package/src/compat/segment/tree.ts +113 -112
  309. package/src/compat/segment/vary-key.ts +38 -38
  310. package/src/compat/segment/vary-params.ts +138 -142
  311. package/src/compat/static-params.ts +14 -12
  312. package/src/compat/tsconfig-defaults.ts +87 -91
  313. package/src/compat/typecheck/{index.ts → check.ts} +234 -212
  314. package/src/compat/typecheck/worker.ts +15 -12
  315. package/src/compat/typed-routes/{index.ts → generate.ts} +36 -36
  316. package/src/compat/typed-routes/manifest.ts +174 -170
  317. package/src/compat/typed-routes/typegen.ts +127 -110
  318. package/src/compat/validation/errors.ts +16 -19
  319. package/src/compat/validation/prerender-diagnostics.ts +521 -504
  320. package/src/compat/validation/{index.ts → validate.ts} +647 -648
  321. package/src/compat-bootstrap.ts +16 -16
  322. package/src/config.ts +86 -69
  323. package/src/css/build.ts +230 -227
  324. package/src/css/postcss.ts +79 -80
  325. package/src/css/worker.ts +14 -15
  326. package/src/dev/client-actions.ts +10 -10
  327. package/src/dev/client-chunk-store.ts +27 -27
  328. package/src/dev/{client-key-cache.ts → restart/client-key.ts} +76 -76
  329. package/src/dev/{restart-cache.ts → restart/enabled.ts} +1 -1
  330. package/src/dev/{global-css-cache.ts → restart/global-css.ts} +91 -83
  331. package/src/dev/{node-module-bundle-cache.ts → restart/node-modules.ts} +24 -24
  332. package/src/dev/{route-bundle-key-cache.ts → restart/route-bundle-key.ts} +53 -53
  333. package/src/dev/{route-facts-cache.ts → restart/route-facts.ts} +82 -82
  334. package/src/dev/server.ts +804 -820
  335. package/src/env.ts +46 -43
  336. package/src/extensions.ts +491 -478
  337. package/src/index.ts +8 -8
  338. package/src/internal.ts +20 -23
  339. package/src/{islands → render}/boundary-error.ts +3 -3
  340. package/src/render/hooks.ts +71 -71
  341. package/src/render/island-context.ts +14 -14
  342. package/src/render/metadata.ts +310 -310
  343. package/src/{ppr-postpone.ts → render/postpone.ts} +5 -5
  344. package/src/{ppr.ts → render/ppr.ts} +244 -245
  345. package/src/render/renderer.ts +2087 -2082
  346. package/src/render/resource-hints.ts +16 -17
  347. package/src/render/slots.tsx +224 -235
  348. package/src/{islands → render}/static-children.ts +9 -12
  349. package/src/{islands → render}/static-slots.ts +37 -37
  350. package/src/{cache/context.ts → request/cache.ts} +20 -20
  351. package/src/request/context.ts +107 -107
  352. package/src/{dynamic/source.ts → resolve/dynamic.ts} +139 -139
  353. package/src/resolve/engine.ts +90 -77
  354. package/src/resolve/imports.ts +475 -463
  355. package/src/resolve/scan-facts.ts +318 -296
  356. package/src/resolve/source-text.ts +37 -37
  357. package/src/{dynamic → resolve}/tree-shake.ts +132 -128
  358. package/src/routing/forwarded.ts +19 -19
  359. package/src/routing/handler.ts +84 -91
  360. package/src/routing/href.ts +87 -70
  361. package/src/routing/{metadata.ts → metadata-files.ts} +403 -401
  362. package/src/{proxy.ts → routing/proxy.ts} +306 -312
  363. package/src/routing/{request-runtime.ts → request-environment.ts} +10 -10
  364. package/src/routing/routes.ts +827 -815
  365. package/src/routing/slots.ts +164 -160
  366. package/src/runtime/loader.ts +954 -0
  367. package/src/{dev → runtime}/module-cache.ts +309 -287
  368. package/src/{dev → runtime}/module-generations.ts +9 -9
  369. package/src/{dev → runtime}/module-transform.ts +81 -72
  370. package/src/{dev/imports.ts → runtime/modules.ts} +934 -847
  371. package/src/runtime/{server.ts → vendor-build.ts} +848 -1696
  372. package/src/runtime/vendor.ts +428 -406
  373. package/src/styles.d.ts +9 -0
  374. package/src/types.ts +324 -335
  375. package/src/utils/ansi.ts +5 -5
  376. package/src/utils/{source.ts → code.ts} +15 -12
  377. package/src/utils/content-type.ts +3 -3
  378. package/src/utils/decode.ts +2 -2
  379. package/src/utils/dev-profile.ts +13 -13
  380. package/src/utils/error-log.ts +6 -6
  381. package/src/utils/esbuild.ts +18 -18
  382. package/src/utils/fs-cache.ts +13 -13
  383. package/src/utils/fs.ts +57 -49
  384. package/src/utils/html.ts +20 -24
  385. package/src/utils/native-require.ts +8 -8
  386. package/src/utils/serialize.ts +139 -146
  387. package/src/utils/verbose.ts +18 -18
  388. package/reference/overview.md +0 -35
  389. package/src/cli/analyze-print.ts +0 -181
  390. package/src/compat/middleware/manifest.ts +0 -210
  391. package/src/compat/next/image-client.tsx +0 -215
  392. package/src/compat/next/link-usage.ts +0 -29
  393. package/src/css/index.ts +0 -2
  394. package/src/render/index.ts +0 -1
  395. package/src/style-modules.d.ts +0 -9
@@ -10,58 +10,58 @@ import type {
10
10
  ResourceHint,
11
11
  MetadataTwitter,
12
12
  Viewport,
13
- } from '../types';
13
+ } from '../types'
14
14
  import {
15
15
  metadataHasOwnImages,
16
16
  staticMetadataLink,
17
17
  type StaticMetadataForPath,
18
- } from '../routing/metadata';
19
- import { escapeHtml, stringifyHtmlValue } from '../utils/html';
20
- import { getTrailingSlashUrls, withBasePath } from '../routing/href';
18
+ } from '../routing/metadata-files'
19
+ import { escapeHtml, stringifyHtmlValue } from '../utils/html'
20
+ import { getTrailingSlashUrls, withBasePath } from '../routing/href'
21
21
 
22
- export type MetadataExport = Metadata | (() => Metadata | Promise<Metadata>);
22
+ export type MetadataExport = Metadata | (() => Metadata | Promise<Metadata>)
23
23
 
24
- export type ViewportExport = Viewport | (() => Viewport | Promise<Viewport>);
24
+ export type ViewportExport = Viewport | (() => Viewport | Promise<Viewport>)
25
25
 
26
26
  export interface MetadataEntry {
27
- metadata: Metadata;
28
- dir?: string;
29
- kind?: 'layout' | 'page';
30
- root?: boolean;
27
+ metadata: Metadata
28
+ dir?: string
29
+ kind?: 'layout' | 'page'
30
+ root?: boolean
31
31
  }
32
32
 
33
33
  export interface MetadataContext {
34
- url?: URL;
35
- metadataBase?: URL;
34
+ url?: URL
35
+ metadataBase?: URL
36
36
  }
37
37
 
38
38
  export interface MetadataRenderPage {
39
- metadata: Metadata;
40
- metadataUrl?: string;
41
- fontPreloads: MetadataLink[];
42
- resourceHints?: ResourceHint[];
43
- stylesheets: StylesheetLink[];
44
- modulePreloads?: string[];
45
- dynamicScriptPreloads?: string[];
46
- staticMetadata?: StaticMetadataForPath;
47
- suppressIconLinks?: boolean;
39
+ metadata: Metadata
40
+ metadataUrl?: string
41
+ fontPreloads: MetadataLink[]
42
+ resourceHints?: ResourceHint[]
43
+ stylesheets: StylesheetLink[]
44
+ modulePreloads?: string[]
45
+ dynamicScriptPreloads?: string[]
46
+ staticMetadata?: StaticMetadataForPath
47
+ suppressIconLinks?: boolean
48
48
  }
49
49
 
50
50
  export interface StylesheetLink {
51
- url: string | string[];
52
- dataPrecedence?: string;
51
+ url: string | string[]
52
+ dataPrecedence?: string
53
53
  }
54
54
 
55
55
  export function metadataContext(page: MetadataRenderPage): MetadataContext {
56
- const url = page.metadataUrl ? new URL(page.metadataUrl) : undefined;
56
+ const url = page.metadataUrl ? new URL(page.metadataUrl) : undefined
57
57
  return {
58
58
  url,
59
59
  metadataBase: coerceMetadataBase(page.metadata.metadataBase, url),
60
- };
60
+ }
61
61
  }
62
62
 
63
63
  export function headLinks(page: MetadataRenderPage, context: MetadataContext) {
64
- const canonical = coerceCanonical(page.metadata.alternates, context);
64
+ const canonical = coerceCanonical(page.metadata.alternates, context)
65
65
  const links: (MetadataLink | ResourceHint)[] = [
66
66
  ...page.fontPreloads,
67
67
  ...(page.resourceHints ?? []),
@@ -85,8 +85,8 @@ export function headLinks(page: MetadataRenderPage, context: MetadataContext) {
85
85
  ...appleStartupLinks(page.metadata.appleWebApp, context),
86
86
  ...coerceIcons(page.metadata.icons, context),
87
87
  ...(page.metadata.links ?? []),
88
- ];
89
- return links.map(link => ` <link ${linkAttrs(link)}/>`).join('\n');
88
+ ]
89
+ return links.map(link => ` <link ${linkAttrs(link)}/>`).join('\n')
90
90
  }
91
91
 
92
92
  function stylesheetLinks(stylesheets: StylesheetLink[]): MetadataLink[] {
@@ -96,25 +96,25 @@ function stylesheetLinks(stylesheets: StylesheetLink[]): MetadataLink[] {
96
96
  url: href,
97
97
  ...(dataPrecedence ? { dataPrecedence } : {}),
98
98
  })),
99
- );
99
+ )
100
100
  }
101
101
 
102
102
  export function metadataIconLinks(metadata: Metadata, context: MetadataContext, indent = ' ') {
103
103
  return coerceIcons(metadata.icons, context)
104
104
  .map(link => `${indent}<link ${linkAttrs(link)}/>`)
105
- .join('\n');
105
+ .join('\n')
106
106
  }
107
107
 
108
108
  function staticMetadataLinks(page: MetadataRenderPage): MetadataLink[] {
109
- const metadata = page.staticMetadata;
110
- if (!metadata) return [];
111
- const hasExplicitIcons = page.metadata.icons !== undefined;
112
- const hasExplicitManifest = page.metadata.manifest !== undefined;
109
+ const metadata = page.staticMetadata
110
+ if (!metadata) return []
111
+ const hasExplicitIcons = page.metadata.icons !== undefined
112
+ const hasExplicitManifest = page.metadata.manifest !== undefined
113
113
  if (page.suppressIconLinks) {
114
114
  return prefixLinks([
115
115
  ...(!hasExplicitManifest && metadata.manifestLink ? [metadata.manifestLink] : []),
116
116
  ...(!hasExplicitManifest && metadata.manifest ? [staticMetadataLink(metadata.manifest)] : []),
117
- ]);
117
+ ])
118
118
  }
119
119
  return prefixLinks([
120
120
  ...(metadata.favicon ? [staticMetadataLink(metadata.favicon)] : []),
@@ -127,25 +127,25 @@ function staticMetadataLinks(page: MetadataRenderPage): MetadataLink[] {
127
127
  ...(!hasExplicitIcons && metadata.icons.length === 0
128
128
  ? metadata.rootIcons.map(staticMetadataLink)
129
129
  : []),
130
- ]);
130
+ ])
131
131
  }
132
132
 
133
133
  // File-convention metadata assets (favicon, icons, manifest, ...) are served
134
134
  // under the configured basePath, so their hrefs carry the prefix. A no-basePath
135
135
  // app leaves every href untouched (withBasePath is a no-op).
136
136
  function prefixLinks(links: MetadataLink[]): MetadataLink[] {
137
- return links.map(link => ({ ...link, url: withBasePath(link.url) }));
137
+ return links.map(link => ({ ...link, url: withBasePath(link.url) }))
138
138
  }
139
139
 
140
140
  export function applyStaticMetadata(
141
141
  metadata: Metadata,
142
142
  staticMetadata: StaticMetadataForPath,
143
143
  ): Metadata {
144
- let next = metadata;
144
+ let next = metadata
145
145
  const openGraphImages = [
146
146
  ...(staticMetadata.openGraphImage ? [staticMetadata.openGraphImage] : []),
147
147
  ...(staticMetadata.dynamicOpenGraphImages ?? []),
148
- ].map(prefixImageBasePath);
148
+ ].map(prefixImageBasePath)
149
149
  if (openGraphImages.length > 0 && !metadataHasOwnImages(metadata, 'openGraph')) {
150
150
  next = {
151
151
  ...next,
@@ -153,12 +153,12 @@ export function applyStaticMetadata(
153
153
  ...(next.openGraph ?? {}),
154
154
  images: openGraphImages.length === 1 ? openGraphImages[0] : openGraphImages,
155
155
  },
156
- };
156
+ }
157
157
  }
158
158
  const twitterImages = [
159
159
  ...(staticMetadata.twitterImage ? [staticMetadata.twitterImage] : []),
160
160
  ...(staticMetadata.dynamicTwitterImages ?? []),
161
- ].map(prefixImageBasePath);
161
+ ].map(prefixImageBasePath)
162
162
  if (twitterImages.length > 0 && !metadataHasOwnImages(metadata, 'twitter')) {
163
163
  next = {
164
164
  ...next,
@@ -166,9 +166,9 @@ export function applyStaticMetadata(
166
166
  ...(next.twitter ?? {}),
167
167
  images: twitterImages.length === 1 ? twitterImages[0] : twitterImages,
168
168
  },
169
- };
169
+ }
170
170
  }
171
- return next;
171
+ return next
172
172
  }
173
173
 
174
174
  // File-convention og/twitter images resolve to a root-relative asset path
@@ -176,153 +176,153 @@ export function applyStaticMetadata(
176
176
  // served with that prefix, so the href carries it. String/URL images and a
177
177
  // no-basePath app are left untouched.
178
178
  function prefixImageBasePath(image: MetadataImage): MetadataImage {
179
- if (typeof image === 'string') return withBasePath(image);
180
- if (image instanceof URL) return image;
179
+ if (typeof image === 'string') return withBasePath(image)
180
+ if (image instanceof URL) return image
181
181
  if (typeof image === 'object' && image !== null && typeof image.url === 'string') {
182
- return { ...image, url: withBasePath(image.url) };
182
+ return { ...image, url: withBasePath(image.url) }
183
183
  }
184
- return image;
184
+ return image
185
185
  }
186
186
 
187
187
  // Emits the common metadata <meta> tags. Every value passes through
188
188
  // escapeHtml (which itself coerces via String()), so no value shape can throw.
189
189
  export function metadataTags(metadata: Metadata, context: MetadataContext): string {
190
- const meta = metadata;
191
- const tags: string[] = [];
190
+ const meta = metadata
191
+ const tags: string[] = []
192
192
  const push = (name: string, content: string | undefined) => {
193
- if (content) tags.push(`<meta name="${escapeHtml(name)}" content="${escapeHtml(content)}"/>`);
194
- };
193
+ if (content) tags.push(`<meta name="${escapeHtml(name)}" content="${escapeHtml(content)}"/>`)
194
+ }
195
195
  const pushProperty = (property: string, content: string | undefined) => {
196
196
  if (content)
197
- tags.push(`<meta property="${escapeHtml(property)}" content="${escapeHtml(content)}"/>`);
198
- };
199
-
200
- push('description', meta.description);
201
- push('keywords', coerceKeywords(meta.keywords));
202
- for (const author of coerceAuthors(meta.authors)) push('author', author);
203
- push('generator', meta.generator);
204
- push('application-name', meta.applicationName);
205
- push('referrer', meta.referrer);
206
- push('creator', meta.creator);
207
- push('publisher', meta.publisher);
208
- push('robots', coerceRobots(meta.robots));
197
+ tags.push(`<meta property="${escapeHtml(property)}" content="${escapeHtml(content)}"/>`)
198
+ }
199
+
200
+ push('description', meta.description)
201
+ push('keywords', coerceKeywords(meta.keywords))
202
+ for (const author of coerceAuthors(meta.authors)) push('author', author)
203
+ push('generator', meta.generator)
204
+ push('application-name', meta.applicationName)
205
+ push('referrer', meta.referrer)
206
+ push('creator', meta.creator)
207
+ push('publisher', meta.publisher)
208
+ push('robots', coerceRobots(meta.robots))
209
209
  push(
210
210
  'googlebot',
211
211
  coerceRobots(isRecord(meta.robots) ? (meta.robots.googleBot as MetadataRobots) : undefined),
212
- );
213
- push('format-detection', coerceFormatDetection(meta.formatDetection));
214
- for (const [name, value] of verificationTags(meta.verification)) push(name, value);
215
- for (const value of list(meta.verification?.other?.me)) push('me', value);
212
+ )
213
+ push('format-detection', coerceFormatDetection(meta.formatDetection))
214
+ for (const [name, value] of verificationTags(meta.verification)) push(name, value)
215
+ for (const value of list(meta.verification?.other?.me)) push('me', value)
216
216
  for (const [name, values] of Object.entries(meta.other ?? {})) {
217
- for (const value of list(values)) push(name, value);
217
+ for (const value of list(values)) push(name, value)
218
218
  }
219
- const itunes = itunesContent(meta.itunes);
220
- push('apple-itunes-app', itunes);
221
- const apple = meta.appleWebApp;
219
+ const itunes = itunesContent(meta.itunes)
220
+ push('apple-itunes-app', itunes)
221
+ const apple = meta.appleWebApp
222
222
  if (apple) {
223
- push('mobile-web-app-capable', appleWebAppCapable(apple) ? 'yes' : undefined);
223
+ push('mobile-web-app-capable', appleWebAppCapable(apple) ? 'yes' : undefined)
224
224
  if (typeof apple === 'object') {
225
- push('apple-mobile-web-app-title', apple.title);
226
- push('apple-mobile-web-app-status-bar-style', apple.statusBarStyle);
225
+ push('apple-mobile-web-app-title', apple.title)
226
+ push('apple-mobile-web-app-status-bar-style', apple.statusBarStyle)
227
227
  }
228
228
  }
229
- if (meta.facebook?.appId) pushProperty('fb:app_id', meta.facebook.appId);
230
- for (const admin of list(meta.facebook?.admins)) pushProperty('fb:admins', admin);
229
+ if (meta.facebook?.appId) pushProperty('fb:app_id', meta.facebook.appId)
230
+ for (const admin of list(meta.facebook?.admins)) pushProperty('fb:admins', admin)
231
231
  if (meta.pinterest?.richPin !== undefined) {
232
- pushProperty('pinterest-rich-pin', meta.pinterest.richPin ? 'true' : 'false');
232
+ pushProperty('pinterest-rich-pin', meta.pinterest.richPin ? 'true' : 'false')
233
233
  }
234
- for (const [property, value] of appLinkTags(meta.appLinks)) pushProperty(property, value);
234
+ for (const [property, value] of appLinkTags(meta.appLinks)) pushProperty(property, value)
235
235
 
236
- tags.push(...openGraphTags(meta.openGraph, context));
237
- tags.push(...twitterTags(meta.twitter ?? twitterFromOpenGraph(meta.openGraph), context));
236
+ tags.push(...openGraphTags(meta.openGraph, context))
237
+ tags.push(...twitterTags(meta.twitter ?? twitterFromOpenGraph(meta.openGraph), context))
238
238
 
239
- return tags.join('\n ');
239
+ return tags.join('\n ')
240
240
  }
241
241
 
242
242
  function openGraphTags(og: MetadataOpenGraph | undefined, context: MetadataContext): string[] {
243
- if (!og) return [];
244
- const tags: string[] = [];
243
+ if (!og) return []
244
+ const tags: string[] = []
245
245
  const push = (property: string, content: string | undefined) => {
246
246
  if (content)
247
- tags.push(`<meta property="${escapeHtml(property)}" content="${escapeHtml(content)}"/>`);
248
- };
249
- push('og:title', og.title === undefined ? undefined : resolveTitleChain([{ title: og.title }]));
250
- push('og:description', og.description);
251
- push('og:url', og.url === undefined ? undefined : resolveMetadataUrl(og.url, context));
252
- push('og:site_name', og.siteName);
253
- push('og:locale', og.locale);
254
- push('og:type', og.type);
247
+ tags.push(`<meta property="${escapeHtml(property)}" content="${escapeHtml(content)}"/>`)
248
+ }
249
+ push('og:title', og.title === undefined ? undefined : resolveTitleChain([{ title: og.title }]))
250
+ push('og:description', og.description)
251
+ push('og:url', og.url === undefined ? undefined : resolveMetadataUrl(og.url, context))
252
+ push('og:site_name', og.siteName)
253
+ push('og:locale', og.locale)
254
+ push('og:type', og.type)
255
255
  for (const image of coerceImages(og.images, context)) {
256
- push('og:image', image.url);
257
- push('og:image:secure_url', image.secureUrl);
258
- push('og:image:width', image.width);
259
- push('og:image:height', image.height);
260
- push('og:image:alt', image.alt);
261
- push('og:image:type', image.type);
256
+ push('og:image', image.url)
257
+ push('og:image:secure_url', image.secureUrl)
258
+ push('og:image:width', image.width)
259
+ push('og:image:height', image.height)
260
+ push('og:image:alt', image.alt)
261
+ push('og:image:type', image.type)
262
262
  }
263
263
  for (const video of coerceImages(og.videos, context)) {
264
- push('og:video', video.url);
265
- push('og:video:width', video.width);
266
- push('og:video:height', video.height);
264
+ push('og:video', video.url)
265
+ push('og:video:width', video.width)
266
+ push('og:video:height', video.height)
267
267
  }
268
- for (const audio of coerceImages(og.audio, context)) push('og:audio', audio.url);
269
- push('article:published_time', og.publishedTime);
270
- for (const author of list(og.authors)) push('article:author', author);
271
- for (const email of list(og.emails)) push('og:email', email);
272
- for (const phone of list(og.phoneNumbers)) push('og:phone_number', phone);
273
- for (const fax of list(og.faxNumbers)) push('og:fax_number', fax);
274
- return tags;
268
+ for (const audio of coerceImages(og.audio, context)) push('og:audio', audio.url)
269
+ push('article:published_time', og.publishedTime)
270
+ for (const author of list(og.authors)) push('article:author', author)
271
+ for (const email of list(og.emails)) push('og:email', email)
272
+ for (const phone of list(og.phoneNumbers)) push('og:phone_number', phone)
273
+ for (const fax of list(og.faxNumbers)) push('og:fax_number', fax)
274
+ return tags
275
275
  }
276
276
 
277
277
  function twitterTags(twitter: MetadataTwitter | undefined, context: MetadataContext): string[] {
278
- if (!twitter) return [];
279
- const tags: string[] = [];
278
+ if (!twitter) return []
279
+ const tags: string[] = []
280
280
  const push = (name: string, content: string | undefined) => {
281
- if (content) tags.push(`<meta name="${escapeHtml(name)}" content="${escapeHtml(content)}"/>`);
282
- };
283
- push('twitter:card', twitterCard(twitter));
284
- push('twitter:site', twitter.site);
285
- push('twitter:site:id', twitter.siteId);
286
- push('twitter:creator', twitter.creator);
287
- push('twitter:creator:id', twitter.creatorId);
281
+ if (content) tags.push(`<meta name="${escapeHtml(name)}" content="${escapeHtml(content)}"/>`)
282
+ }
283
+ push('twitter:card', twitterCard(twitter))
284
+ push('twitter:site', twitter.site)
285
+ push('twitter:site:id', twitter.siteId)
286
+ push('twitter:creator', twitter.creator)
287
+ push('twitter:creator:id', twitter.creatorId)
288
288
  push(
289
289
  'twitter:title',
290
290
  twitter.title === undefined ? undefined : resolveTitleChain([{ title: twitter.title }]),
291
- );
292
- push('twitter:description', twitter.description);
291
+ )
292
+ push('twitter:description', twitter.description)
293
293
  for (const image of coerceImages(twitter.images, context)) {
294
- push('twitter:image', image.url);
295
- push('twitter:image:secure_url', image.secureUrl);
296
- push('twitter:image:width', image.width);
297
- push('twitter:image:height', image.height);
298
- push('twitter:image:alt', image.alt);
299
- push('twitter:image:type', image.type);
294
+ push('twitter:image', image.url)
295
+ push('twitter:image:secure_url', image.secureUrl)
296
+ push('twitter:image:width', image.width)
297
+ push('twitter:image:height', image.height)
298
+ push('twitter:image:alt', image.alt)
299
+ push('twitter:image:type', image.type)
300
300
  }
301
- push('twitter:player', resolveMetadataUrl(twitter.players?.playerUrl, context));
302
- push('twitter:player:stream', resolveMetadataUrl(twitter.players?.streamUrl, context));
303
- push('twitter:player:width', coerceString(twitter.players?.width) || undefined);
304
- push('twitter:player:height', coerceString(twitter.players?.height) || undefined);
301
+ push('twitter:player', resolveMetadataUrl(twitter.players?.playerUrl, context))
302
+ push('twitter:player:stream', resolveMetadataUrl(twitter.players?.streamUrl, context))
303
+ push('twitter:player:width', coerceString(twitter.players?.width) || undefined)
304
+ push('twitter:player:height', coerceString(twitter.players?.height) || undefined)
305
305
  for (const [device, id] of Object.entries(twitter.app?.id ?? {})) {
306
- push(`twitter:app:id:${device}`, id);
306
+ push(`twitter:app:id:${device}`, id)
307
307
  }
308
308
  for (const [device, url] of Object.entries(twitter.app?.url ?? {})) {
309
- push(`twitter:app:url:${device}`, resolveMetadataUrl(url, context));
309
+ push(`twitter:app:url:${device}`, resolveMetadataUrl(url, context))
310
310
  }
311
- return tags;
311
+ return tags
312
312
  }
313
313
 
314
314
  // theme-color: string | { color, media } | array of those.
315
315
  export function themeColorTags(value: Viewport['themeColor']): string {
316
- if (value === undefined) return '';
317
- const list = Array.isArray(value) ? value : [value];
316
+ if (value === undefined) return ''
317
+ const list = Array.isArray(value) ? value : [value]
318
318
  return list
319
319
  .map(entry => {
320
320
  if (typeof entry === 'string')
321
- return `<meta name="theme-color" content="${escapeHtml(entry)}"/>`;
322
- const media = entry.media ? ` media="${escapeHtml(entry.media)}"` : '';
323
- return `<meta name="theme-color"${media} content="${escapeHtml(entry.color)}"/>`;
321
+ return `<meta name="theme-color" content="${escapeHtml(entry)}"/>`
322
+ const media = entry.media ? ` media="${escapeHtml(entry.media)}"` : ''
323
+ return `<meta name="theme-color"${media} content="${escapeHtml(entry.color)}"/>`
324
324
  })
325
- .join('\n ');
325
+ .join('\n ')
326
326
  }
327
327
 
328
328
  function linkAttrs(link: MetadataLink | ResourceHint) {
@@ -341,12 +341,12 @@ function linkAttrs(link: MetadataLink | ResourceHint) {
341
341
  ['nonce', link.nonce],
342
342
  ]
343
343
  .filter((attr): attr is [string, string] => typeof attr[1] === 'string')
344
- .map(([key, value]) => `${key}="${escapeHtml(value)}"`);
345
- const attributes = 'attributes' in link ? link.attributes : undefined;
344
+ .map(([key, value]) => `${key}="${escapeHtml(value)}"`)
345
+ const attributes = 'attributes' in link ? link.attributes : undefined
346
346
  for (const [key, value] of Object.entries(attributes ?? {})) {
347
- attrs.push(`${escapeHtml(key)}="${escapeHtml(value)}"`);
347
+ attrs.push(`${escapeHtml(key)}="${escapeHtml(value)}"`)
348
348
  }
349
- return attrs.join(' ');
349
+ return attrs.join(' ')
350
350
  }
351
351
 
352
352
  export function viewportContent(viewport: Viewport) {
@@ -364,34 +364,34 @@ export function viewportContent(viewport: Viewport) {
364
364
  ],
365
365
  ['viewport-fit', viewport.viewportFit],
366
366
  ['interactive-widget', viewport.interactiveWidget],
367
- ];
367
+ ]
368
368
 
369
369
  return entries
370
370
  .filter((entry): entry is [string, string | number | boolean] => entry[1] !== undefined)
371
371
  .map(([key, value]) => `${key}=${value}`)
372
- .join(', ');
372
+ .join(', ')
373
373
  }
374
374
 
375
375
  // Core metadata is static for a route render: object exports are read as-is and
376
376
  // function exports run without request data. Compat registers the Next
377
377
  // generateMetadata/generateViewport resolver separately.
378
378
  export async function readModuleMetadata(module: {
379
- metadata?: MetadataExport;
379
+ metadata?: MetadataExport
380
380
  }): Promise<Metadata | undefined> {
381
- return typeof module.metadata === 'function' ? module.metadata() : module.metadata;
381
+ return typeof module.metadata === 'function' ? module.metadata() : module.metadata
382
382
  }
383
383
 
384
384
  export async function readModuleViewport(module: {
385
- viewport?: ViewportExport;
385
+ viewport?: ViewportExport
386
386
  }): Promise<Viewport | undefined> {
387
- return typeof module.viewport === 'function' ? module.viewport() : module.viewport;
387
+ return typeof module.viewport === 'function' ? module.viewport() : module.viewport
388
388
  }
389
389
 
390
390
  export function mergeMetadataEntries(
391
391
  ...entryGroups: (MetadataEntry | MetadataEntry[])[]
392
392
  ): Metadata {
393
- const entries = entryGroups.flat();
394
- const items = entries.map(entry => entry.metadata);
393
+ const entries = entryGroups.flat()
394
+ const items = entries.map(entry => entry.metadata)
395
395
  const merged = items.reduce<Metadata>(
396
396
  (metadata, item) => ({
397
397
  ...metadata,
@@ -400,41 +400,41 @@ export function mergeMetadataEntries(
400
400
  links: [...(metadata.links ?? []), ...(item.links ?? [])],
401
401
  }),
402
402
  {},
403
- );
404
- merged.title = resolveTitleEntries(entries);
405
- return merged;
403
+ )
404
+ merged.title = resolveTitleEntries(entries)
405
+ return merged
406
406
  }
407
407
 
408
408
  function mergeIcons(base: Metadata['icons'], next: Metadata['icons']): Metadata['icons'] {
409
- if (next === undefined) return base;
410
- if (Array.isArray(base) && Array.isArray(next)) return [...base, ...next];
411
- return next;
409
+ if (next === undefined) return base
410
+ if (Array.isArray(base) && Array.isArray(next)) return [...base, ...next]
411
+ return next
412
412
  }
413
413
 
414
414
  interface TitleTemplateState {
415
- template: string | null;
416
- previous: string | null;
417
- dir?: string;
418
- root?: boolean;
415
+ template: string | null
416
+ previous: string | null
417
+ dir?: string
418
+ root?: boolean
419
419
  }
420
420
 
421
421
  function resolveTitleEntries(entries: MetadataEntry[]): string | undefined {
422
- let template: TitleTemplateState = { template: null, previous: null };
423
- let resolved: string | undefined;
422
+ let template: TitleTemplateState = { template: null, previous: null }
423
+ let resolved: string | undefined
424
424
 
425
425
  for (const entry of entries) {
426
- const title = entry.metadata.title;
427
- if (title === undefined) continue;
426
+ const title = entry.metadata.title
427
+ if (title === undefined) continue
428
428
  const activeTemplate =
429
429
  entry.kind === 'page' && entry.dir && entry.dir === template.dir && !template.root
430
430
  ? template.previous
431
- : template.template;
431
+ : template.template
432
432
 
433
433
  if (typeof title === 'object' && title !== null) {
434
434
  if (typeof title.absolute === 'string') {
435
- resolved = title.absolute;
435
+ resolved = title.absolute
436
436
  } else if (typeof title.default === 'string') {
437
- resolved = applyTitleTemplate(activeTemplate, title.default);
437
+ resolved = applyTitleTemplate(activeTemplate, title.default)
438
438
  }
439
439
  if ('template' in title) {
440
440
  template = {
@@ -442,68 +442,68 @@ function resolveTitleEntries(entries: MetadataEntry[]): string | undefined {
442
442
  previous: activeTemplate,
443
443
  dir: entry.dir,
444
444
  root: entry.root,
445
- };
445
+ }
446
446
  }
447
447
  } else {
448
- resolved = applyTitleTemplate(activeTemplate, coerceString(title));
448
+ resolved = applyTitleTemplate(activeTemplate, coerceString(title))
449
449
  }
450
450
  }
451
- return resolved;
451
+ return resolved
452
452
  }
453
453
 
454
454
  // Walks the chain root->page tracking the last-seen template. A child's plain
455
455
  // string title is wrapped by the nearest ancestor template; an `absolute`
456
456
  // bypasses the template; a `default` supplies a title when the child has none.
457
457
  function resolveTitleChain(items: Metadata[]): string | undefined {
458
- return resolveTitleEntries(items.map(metadata => ({ metadata })));
458
+ return resolveTitleEntries(items.map(metadata => ({ metadata })))
459
459
  }
460
460
 
461
461
  function applyTitleTemplate(template: string | null, value: string): string {
462
- return template ? template.replace('%s', value) : value;
462
+ return template ? template.replace('%s', value) : value
463
463
  }
464
464
 
465
465
  // Coerces any metadata scalar (string | number | URL | unknown) into a string.
466
466
  // Numbers go through String(); undefined/null collapse to ''. This is the guard
467
467
  // that keeps emission from ever crashing on an unexpected value shape.
468
468
  export function coerceString(value: unknown): string {
469
- return stringifyHtmlValue(value);
469
+ return stringifyHtmlValue(value)
470
470
  }
471
471
 
472
472
  // keywords: string | number | Array -> comma-joined string.
473
473
  function coerceKeywords(value: Metadata['keywords']): string | undefined {
474
- const list = normalizeKeywordList(value);
475
- if (list === undefined) return undefined;
476
- const joined = list.map(coerceString).filter(Boolean).join(',');
477
- return joined || undefined;
474
+ const list = normalizeKeywordList(value)
475
+ if (list === undefined) return undefined
476
+ const joined = list.map(coerceString).filter(Boolean).join(',')
477
+ return joined || undefined
478
478
  }
479
479
 
480
480
  function normalizeKeywordList(value: Metadata['keywords']): (string | number)[] | undefined {
481
- if (value === undefined) return undefined;
482
- return Array.isArray(value) ? value : [value];
481
+ if (value === undefined) return undefined
482
+ return Array.isArray(value) ? value : [value]
483
483
  }
484
484
 
485
485
  // authors -> list of display names for meta[name=author].
486
486
  function coerceAuthors(value: Metadata['authors']): string[] {
487
- if (value === undefined) return [];
488
- const list = Array.isArray(value) ? value : [value];
487
+ if (value === undefined) return []
488
+ const list = Array.isArray(value) ? value : [value]
489
489
  return list
490
490
  .map(author => (typeof author === 'string' ? author : author.name))
491
491
  .map(name => coerceString(name))
492
- .filter(Boolean);
492
+ .filter(Boolean)
493
493
  }
494
494
 
495
495
  // robots: string passthrough, or object -> "index, follow, noarchive" style.
496
496
  function coerceRobots(value: Metadata['robots']): string | undefined {
497
- if (value === undefined) return undefined;
498
- if (typeof value === 'string') return value;
499
- const flags: string[] = [];
500
- const r = value;
501
- if (r.index !== undefined) flags.push(r.index ? 'index' : 'noindex');
502
- if (r.follow !== undefined) flags.push(r.follow ? 'follow' : 'nofollow');
503
- if (r.noarchive) flags.push('noarchive');
504
- if (r.nosnippet) flags.push('nosnippet');
505
- if (r.noimageindex) flags.push('noimageindex');
506
- if (r.nocache) flags.push('nocache');
497
+ if (value === undefined) return undefined
498
+ if (typeof value === 'string') return value
499
+ const flags: string[] = []
500
+ const r = value
501
+ if (r.index !== undefined) flags.push(r.index ? 'index' : 'noindex')
502
+ if (r.follow !== undefined) flags.push(r.follow ? 'follow' : 'nofollow')
503
+ if (r.noarchive) flags.push('noarchive')
504
+ if (r.nosnippet) flags.push('nosnippet')
505
+ if (r.noimageindex) flags.push('noimageindex')
506
+ if (r.nocache) flags.push('nocache')
507
507
  for (const [key, item] of Object.entries(r)) {
508
508
  if (
509
509
  item === undefined ||
@@ -516,36 +516,36 @@ function coerceRobots(value: Metadata['robots']): string | undefined {
516
516
  key === 'nocache' ||
517
517
  key === 'googleBot'
518
518
  ) {
519
- continue;
519
+ continue
520
520
  }
521
- if (item === true) flags.push(key);
522
- else flags.push(`${key}:${String(item)}`);
521
+ if (item === true) flags.push(key)
522
+ else flags.push(`${key}:${String(item)}`)
523
523
  }
524
- return flags.length ? flags.join(', ') : undefined;
524
+ return flags.length ? flags.join(', ') : undefined
525
525
  }
526
526
 
527
527
  interface ResolvedImage {
528
- url: string;
529
- secureUrl?: string;
530
- width?: string;
531
- height?: string;
532
- alt?: string;
533
- type?: string;
528
+ url: string
529
+ secureUrl?: string
530
+ width?: string
531
+ height?: string
532
+ alt?: string
533
+ type?: string
534
534
  }
535
535
 
536
536
  function coerceImages(
537
537
  value: MetadataImage | MetadataImage[] | undefined,
538
538
  context: MetadataContext,
539
539
  ): ResolvedImage[] {
540
- if (value === undefined) return [];
541
- const list = Array.isArray(value) ? value : [value];
540
+ if (value === undefined) return []
541
+ const list = Array.isArray(value) ? value : [value]
542
542
  return list
543
543
  .map((image): ResolvedImage | undefined => {
544
544
  if (typeof image === 'string')
545
- return { url: resolveMetadataUrl(image, context, true) ?? image };
546
- if (image instanceof URL) return { url: image.href };
545
+ return { url: resolveMetadataUrl(image, context, true) ?? image }
546
+ if (image instanceof URL) return { url: image.href }
547
547
  if (typeof image === 'object' && image !== null && 'url' in image) {
548
- const img = image;
548
+ const img = image
549
549
  return {
550
550
  url: resolveMetadataUrl(img.url, context, true) ?? coerceString(img.url),
551
551
  secureUrl: resolveMetadataUrl(img.secureUrl, context, true),
@@ -553,36 +553,36 @@ function coerceImages(
553
553
  height: img.height === undefined ? undefined : coerceString(img.height),
554
554
  alt: img.alt,
555
555
  type: img.type,
556
- };
556
+ }
557
557
  }
558
- return undefined;
558
+ return undefined
559
559
  })
560
- .filter((image): image is ResolvedImage => image !== undefined && Boolean(image.url));
560
+ .filter((image): image is ResolvedImage => image !== undefined && Boolean(image.url))
561
561
  }
562
562
 
563
563
  function coerceCanonical(
564
564
  value: Metadata['alternates'],
565
565
  context: MetadataContext,
566
566
  ): string | undefined {
567
- const canonical = value?.canonical;
568
- if (canonical === undefined) return undefined;
569
- if (typeof canonical === 'string') return resolveMetadataUrl(canonical, context);
570
- if (canonical instanceof URL) return canonical.href;
567
+ const canonical = value?.canonical
568
+ if (canonical === undefined) return undefined
569
+ if (typeof canonical === 'string') return resolveMetadataUrl(canonical, context)
570
+ if (canonical instanceof URL) return canonical.href
571
571
  if (typeof canonical === 'object' && 'url' in canonical)
572
- return resolveMetadataUrl(canonical.url, context);
573
- return undefined;
572
+ return resolveMetadataUrl(canonical.url, context)
573
+ return undefined
574
574
  }
575
575
 
576
576
  function coerceMetadataBase(value: Metadata['metadataBase'], url?: URL): URL | undefined {
577
- if (value instanceof URL) return value;
577
+ if (value instanceof URL) return value
578
578
  if (typeof value === 'string' && value) {
579
579
  try {
580
- return new URL(value);
580
+ return new URL(value)
581
581
  } catch {
582
- return url ? new URL(value, url) : undefined;
582
+ return url ? new URL(value, url) : undefined
583
583
  }
584
584
  }
585
- return undefined;
585
+ return undefined
586
586
  }
587
587
 
588
588
  function resolveMetadataUrl(
@@ -590,35 +590,35 @@ function resolveMetadataUrl(
590
590
  context: MetadataContext,
591
591
  fallbackToRequestUrl = false,
592
592
  ): string | undefined {
593
- if (value === undefined || value === null) return undefined;
594
- if (value instanceof URL) return value.href;
595
- const raw = coerceString(value);
596
- if (!raw) return undefined;
597
- if (/^[a-z][a-z\d+.-]*:/i.test(raw)) return raw;
593
+ if (value === undefined || value === null) return undefined
594
+ if (value instanceof URL) return value.href
595
+ const raw = coerceString(value)
596
+ if (!raw) return undefined
597
+ if (/^[a-z][a-z\d+.-]*:/i.test(raw)) return raw
598
598
  const base =
599
- context.metadataBase ?? (fallbackToRequestUrl ? requestFallbackBase(context.url) : undefined);
600
- if (!base) return raw;
601
- const origin = base.origin;
602
- const prefix = base.pathname === '/' ? '' : `/${base.pathname.replace(/^\/+|\/+$/g, '')}`;
599
+ context.metadataBase ?? (fallbackToRequestUrl ? requestFallbackBase(context.url) : undefined)
600
+ if (!base) return raw
601
+ const origin = base.origin
602
+ const prefix = base.pathname === '/' ? '' : `/${base.pathname.replace(/^\/+|\/+$/g, '')}`
603
603
  if (raw.startsWith('./') && context.url) {
604
- const requestPath = joinUrlPath(prefix, context.url.pathname);
605
- const directory = requestPath.endsWith('/') ? requestPath : `${requestPath}/`;
606
- const resolved = new URL(raw, `${origin}${directory}`).pathname;
604
+ const requestPath = joinUrlPath(prefix, context.url.pathname)
605
+ const directory = requestPath.endsWith('/') ? requestPath : `${requestPath}/`
606
+ const resolved = new URL(raw, `${origin}${directory}`).pathname
607
607
  const pathname =
608
- resolved.length > 1 && resolved.endsWith('/') ? resolved.slice(0, -1) : resolved;
609
- return joinMetadataUrl(origin, pathname);
608
+ resolved.length > 1 && resolved.endsWith('/') ? resolved.slice(0, -1) : resolved
609
+ return joinMetadataUrl(origin, pathname)
610
610
  }
611
- const relative = metadataRelativePath(raw);
612
- const resolvedPath = joinUrlPath(prefix, relative);
613
- return joinMetadataUrl(origin, resolvedPath);
611
+ const relative = metadataRelativePath(raw)
612
+ const resolvedPath = joinUrlPath(prefix, relative)
613
+ return joinMetadataUrl(origin, resolvedPath)
614
614
  }
615
615
 
616
616
  function requestFallbackBase(url?: URL) {
617
- if (!url) return undefined;
618
- if (url.hostname !== 'pnext.local') return new URL(url.origin);
617
+ if (!url) return undefined
618
+ if (url.hostname !== 'pnext.local') return new URL(url.origin)
619
619
  // eslint-disable-next-line turbo/no-undeclared-env-vars
620
- const port = process.env.PORT;
621
- return port && port !== '0' ? new URL(`http://localhost:${port}`) : undefined;
620
+ const port = process.env.PORT
621
+ return port && port !== '0' ? new URL(`http://localhost:${port}`) : undefined
622
622
  }
623
623
 
624
624
  // Join a resolved origin + pathname into an absolute metadata URL, honoring the
@@ -627,46 +627,46 @@ function requestFallbackBase(url?: URL) {
627
627
  // bare path, and `/metadata?query=string` must not become `/metadata/?...`.
628
628
  function joinMetadataUrl(origin: string, pathname: string) {
629
629
  if (/[?#]/.test(pathname)) {
630
- return pathname === '/' ? origin : `${origin}${pathname}`;
630
+ return pathname === '/' ? origin : `${origin}${pathname}`
631
631
  }
632
632
  if (getTrailingSlashUrls()) {
633
- if (pathname === '/') return `${origin}/`;
634
- return pathname.endsWith('/') ? `${origin}${pathname}` : `${origin}${pathname}/`;
633
+ if (pathname === '/') return `${origin}/`
634
+ return pathname.endsWith('/') ? `${origin}${pathname}` : `${origin}${pathname}/`
635
635
  }
636
- return pathname === '/' ? origin : `${origin}${pathname}`;
636
+ return pathname === '/' ? origin : `${origin}${pathname}`
637
637
  }
638
638
 
639
639
  function metadataRelativePath(value: string) {
640
- let next = value;
641
- while (next.startsWith('./')) next = next.slice(2);
642
- while (next.startsWith('../')) next = next.slice(3);
643
- while (next.startsWith('/')) next = next.slice(1);
644
- return next;
640
+ let next = value
641
+ while (next.startsWith('./')) next = next.slice(2)
642
+ while (next.startsWith('../')) next = next.slice(3)
643
+ while (next.startsWith('/')) next = next.slice(1)
644
+ return next
645
645
  }
646
646
 
647
647
  function joinUrlPath(...parts: string[]) {
648
- const path = parts.filter(Boolean).join('/').replace(/\/+/g, '/');
649
- return path.startsWith('/') ? path : `/${path}`;
648
+ const path = parts.filter(Boolean).join('/').replace(/\/+/g, '/')
649
+ return path.startsWith('/') ? path : `/${path}`
650
650
  }
651
651
 
652
652
  // Normalizes every icon form (string | URL | object | group) into <link> descriptors.
653
653
  function coerceIcons(value: Metadata['icons'], context: MetadataContext): MetadataLink[] {
654
- if (value === undefined) return [];
654
+ if (value === undefined) return []
655
655
  if (isIconGroups(value)) {
656
656
  return [
657
657
  ...iconList(value.icon, 'icon', context),
658
658
  ...iconList(value.shortcut, 'shortcut icon', context),
659
659
  ...iconList(value.apple, 'apple-touch-icon', context),
660
660
  ...iconList(value.other, 'icon', context),
661
- ];
661
+ ]
662
662
  }
663
- return iconList(value, 'icon', context);
663
+ return iconList(value, 'icon', context)
664
664
  }
665
665
 
666
666
  function isIconGroups(value: NonNullable<Metadata['icons']>): value is MetadataIconGroups {
667
- if (Array.isArray(value) || typeof value === 'string' || value instanceof URL) return false;
668
- if (typeof value !== 'object') return false;
669
- return 'icon' in value || 'shortcut' in value || 'apple' in value || 'other' in value;
667
+ if (Array.isArray(value) || typeof value === 'string' || value instanceof URL) return false
668
+ if (typeof value !== 'object') return false
669
+ return 'icon' in value || 'shortcut' in value || 'apple' in value || 'other' in value
670
670
  }
671
671
 
672
672
  function iconList(
@@ -674,33 +674,33 @@ function iconList(
674
674
  rel: string,
675
675
  context: MetadataContext,
676
676
  ): MetadataLink[] {
677
- if (value === undefined) return [];
678
- const list = Array.isArray(value) ? value : [value];
677
+ if (value === undefined) return []
678
+ const list = Array.isArray(value) ? value : [value]
679
679
  return list.map((icon): MetadataLink => {
680
- if (typeof icon === 'string') return { rel, url: resolveMetadataUrl(icon, context) ?? icon };
681
- if (icon instanceof URL) return { rel, url: icon.href };
682
- const obj = icon;
680
+ if (typeof icon === 'string') return { rel, url: resolveMetadataUrl(icon, context) ?? icon }
681
+ if (icon instanceof URL) return { rel, url: icon.href }
682
+ const obj = icon
683
683
  return {
684
684
  ...obj,
685
685
  rel: obj.rel ?? rel,
686
686
  url: resolveMetadataUrl(obj.url, context) ?? coerceString(obj.url),
687
- };
688
- });
687
+ }
688
+ })
689
689
  }
690
690
 
691
691
  function authorLinks(value: Metadata['authors'], context: MetadataContext): MetadataLink[] {
692
- if (value === undefined) return [];
692
+ if (value === undefined) return []
693
693
  return (Array.isArray(value) ? value : [value])
694
694
  .filter((author): author is MetadataAuthor => typeof author === 'object' && author !== null)
695
695
  .flatMap(author => {
696
- const url = resolveMetadataUrl(author.url, context);
697
- return url ? [{ rel: 'author', url }] : [];
698
- });
696
+ const url = resolveMetadataUrl(author.url, context)
697
+ return url ? [{ rel: 'author', url }] : []
698
+ })
699
699
  }
700
700
 
701
701
  function manifestLink(value: Metadata['manifest'], context: MetadataContext): MetadataLink[] {
702
- const url = resolveMetadataUrl(value, context);
703
- return url ? [{ rel: 'manifest', url }] : [];
702
+ const url = resolveMetadataUrl(value, context)
703
+ return url ? [{ rel: 'manifest', url }] : []
704
704
  }
705
705
 
706
706
  function paginationLinks(value: Metadata['pagination'], context: MetadataContext): MetadataLink[] {
@@ -716,130 +716,130 @@ function paginationLinks(value: Metadata['pagination'], context: MetadataContext
716
716
  ...(value?.next
717
717
  ? [{ rel: 'next', url: resolveMetadataUrl(value.next, context) ?? coerceString(value.next) }]
718
718
  : []),
719
- ];
719
+ ]
720
720
  }
721
721
 
722
722
  function alternateLinks(value: Metadata['alternates'], context: MetadataContext): MetadataLink[] {
723
- if (!value) return [];
724
- const links: MetadataLink[] = [];
723
+ if (!value) return []
724
+ const links: MetadataLink[] = []
725
725
  for (const [hrefLang, url] of Object.entries(value.languages ?? {})) {
726
726
  links.push({
727
727
  rel: 'alternate',
728
728
  url: resolveMetadataUrl(url, context) ?? coerceString(url),
729
729
  hrefLang,
730
- });
730
+ })
731
731
  }
732
732
  for (const [media, url] of Object.entries(value.media ?? {})) {
733
733
  links.push({
734
734
  rel: 'alternate',
735
735
  media,
736
736
  url: resolveMetadataUrl(url, context) ?? coerceString(url),
737
- });
737
+ })
738
738
  }
739
739
  for (const [type, entries] of Object.entries(value.types ?? {})) {
740
- const listEntries = Array.isArray(entries) ? entries : [entries];
740
+ const listEntries = Array.isArray(entries) ? entries : [entries]
741
741
  for (const entry of listEntries) {
742
742
  const record =
743
743
  typeof entry === 'object' && !(entry instanceof URL) && entry !== null && 'url' in entry
744
744
  ? entry
745
- : { url: entry };
745
+ : { url: entry }
746
746
  links.push({
747
747
  rel: 'alternate',
748
748
  type,
749
749
  ...(record.title ? { title: record.title } : {}),
750
750
  url: resolveMetadataUrl(record.url, context) ?? coerceString(record.url),
751
- });
751
+ })
752
752
  }
753
753
  }
754
- return links;
754
+ return links
755
755
  }
756
756
 
757
757
  function appleStartupLinks(
758
758
  value: Metadata['appleWebApp'],
759
759
  context: MetadataContext,
760
760
  ): MetadataLink[] {
761
- if (!value || typeof value !== 'object' || value.startupImage === undefined) return [];
762
- const images = Array.isArray(value.startupImage) ? value.startupImage : [value.startupImage];
761
+ if (!value || typeof value !== 'object' || value.startupImage === undefined) return []
762
+ const images = Array.isArray(value.startupImage) ? value.startupImage : [value.startupImage]
763
763
  return images.map(image => {
764
764
  if (typeof image === 'string' || image instanceof URL) {
765
765
  return {
766
766
  rel: 'apple-touch-startup-image',
767
767
  url: resolveMetadataUrl(image, context) ?? coerceString(image),
768
- };
768
+ }
769
769
  }
770
770
  return {
771
771
  rel: 'apple-touch-startup-image',
772
772
  url: resolveMetadataUrl(image.url, context) ?? coerceString(image.url),
773
773
  media: image.media,
774
- };
775
- });
774
+ }
775
+ })
776
776
  }
777
777
 
778
778
  function list(value: unknown): string[] {
779
- if (value === undefined) return [];
780
- return Array.isArray(value) ? value.map(coerceString) : [coerceString(value)];
779
+ if (value === undefined) return []
780
+ return Array.isArray(value) ? value.map(coerceString) : [coerceString(value)]
781
781
  }
782
782
 
783
783
  function coerceFormatDetection(value: Metadata['formatDetection']): string | undefined {
784
- if (!value) return undefined;
785
- const entries: string[] = [];
786
- if (value.telephone === false) entries.push('telephone=no');
787
- if (value.address === false) entries.push('address=no');
788
- if (value.email === false) entries.push('email=no');
789
- if (value.url === false) entries.push('url=no');
790
- return entries.length ? entries.join(', ') : undefined;
784
+ if (!value) return undefined
785
+ const entries: string[] = []
786
+ if (value.telephone === false) entries.push('telephone=no')
787
+ if (value.address === false) entries.push('address=no')
788
+ if (value.email === false) entries.push('email=no')
789
+ if (value.url === false) entries.push('url=no')
790
+ return entries.length ? entries.join(', ') : undefined
791
791
  }
792
792
 
793
793
  function verificationTags(value: Metadata['verification']): [string, string][] {
794
- if (!value) return [];
794
+ if (!value) return []
795
795
  return [
796
796
  ...list(value.google).map(item => ['google-site-verification', item] as [string, string]),
797
797
  ...list(value.yahoo).map(item => ['y_key', item] as [string, string]),
798
798
  ...list(value.yandex).map(item => ['yandex-verification', item] as [string, string]),
799
- ];
799
+ ]
800
800
  }
801
801
 
802
802
  function itunesContent(value: Metadata['itunes']): string | undefined {
803
- if (!value?.appId) return undefined;
803
+ if (!value?.appId) return undefined
804
804
  return [
805
805
  `app-id=${value.appId}`,
806
806
  value.appArgument ? `app-argument=${value.appArgument}` : undefined,
807
807
  ]
808
808
  .filter(Boolean)
809
- .join(', ');
809
+ .join(', ')
810
810
  }
811
811
 
812
812
  function appleWebAppCapable(value: NonNullable<Metadata['appleWebApp']>) {
813
- return typeof value === 'boolean' ? value : (value.capable ?? true);
813
+ return typeof value === 'boolean' ? value : (value.capable ?? true)
814
814
  }
815
815
 
816
816
  function appLinkTags(value: Metadata['appLinks']): [string, string][] {
817
- if (!value) return [];
818
- const tags: [string, string][] = [];
817
+ if (!value) return []
818
+ const tags: [string, string][] = []
819
819
  for (const [platform, entries] of Object.entries(value)) {
820
820
  for (const [name, item] of Object.entries(entries)) {
821
- if (item !== undefined) tags.push([`al:${platform}:${name}`, String(item)]);
821
+ if (item !== undefined) tags.push([`al:${platform}:${name}`, String(item)])
822
822
  }
823
823
  }
824
- return tags;
824
+ return tags
825
825
  }
826
826
 
827
827
  function twitterCard(twitter: MetadataTwitter) {
828
- if (twitter.card) return twitter.card;
829
- if (twitter.players) return 'player';
830
- if (twitter.app) return 'app';
831
- return twitter.images === undefined ? 'summary' : 'summary_large_image';
828
+ if (twitter.card) return twitter.card
829
+ if (twitter.players) return 'player'
830
+ if (twitter.app) return 'app'
831
+ return twitter.images === undefined ? 'summary' : 'summary_large_image'
832
832
  }
833
833
 
834
834
  function twitterFromOpenGraph(
835
835
  openGraph: MetadataOpenGraph | undefined,
836
836
  ): MetadataTwitter | undefined {
837
- if (!openGraph) return undefined;
837
+ if (!openGraph) return undefined
838
838
  return {
839
839
  title: openGraph.title,
840
840
  description: openGraph.description,
841
841
  images: openGraph.images,
842
- };
842
+ }
843
843
  }
844
844
 
845
845
  export function mergeViewport(...items: Viewport[]) {
@@ -849,9 +849,9 @@ export function mergeViewport(...items: Viewport[]) {
849
849
  ...item,
850
850
  }),
851
851
  {},
852
- );
852
+ )
853
853
  }
854
854
 
855
855
  function isRecord(value: unknown): value is Record<string, unknown> {
856
- return typeof value === 'object' && value !== null;
856
+ return typeof value === 'object' && value !== null
857
857
  }