vinext 0.0.30 → 0.0.32

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 (435) hide show
  1. package/README.md +15 -7
  2. package/dist/build/prerender.d.ts +188 -0
  3. package/dist/build/prerender.js +675 -0
  4. package/dist/build/prerender.js.map +1 -0
  5. package/dist/build/report.d.ts +45 -46
  6. package/dist/build/report.js +581 -276
  7. package/dist/build/report.js.map +1 -1
  8. package/dist/build/run-prerender.d.ts +62 -0
  9. package/dist/build/run-prerender.js +183 -0
  10. package/dist/build/run-prerender.js.map +1 -0
  11. package/dist/build/server-manifest.d.ts +19 -0
  12. package/dist/build/server-manifest.js +29 -0
  13. package/dist/build/server-manifest.js.map +1 -0
  14. package/dist/build/static-export.d.ts +51 -66
  15. package/dist/build/static-export.js +51 -545
  16. package/dist/build/static-export.js.map +1 -1
  17. package/dist/check.d.ts +26 -24
  18. package/dist/check.js +681 -571
  19. package/dist/check.js.map +1 -1
  20. package/dist/cli.d.ts +1 -15
  21. package/dist/cli.js +432 -491
  22. package/dist/cli.js.map +1 -1
  23. package/dist/client/entry.d.ts +1 -2
  24. package/dist/client/entry.js +49 -62
  25. package/dist/client/entry.js.map +1 -1
  26. package/dist/client/validate-module-path.d.ts +4 -1
  27. package/dist/client/validate-module-path.js +23 -28
  28. package/dist/client/validate-module-path.js.map +1 -1
  29. package/dist/client/vinext-next-data.d.ts +15 -20
  30. package/dist/client/vinext-next-data.js +0 -1
  31. package/dist/cloudflare/index.d.ts +3 -8
  32. package/dist/cloudflare/index.js +3 -8
  33. package/dist/cloudflare/kv-cache-handler.d.ts +95 -105
  34. package/dist/cloudflare/kv-cache-handler.js +354 -380
  35. package/dist/cloudflare/kv-cache-handler.js.map +1 -1
  36. package/dist/cloudflare/tpr.d.ts +36 -34
  37. package/dist/cloudflare/tpr.js +460 -603
  38. package/dist/cloudflare/tpr.js.map +1 -1
  39. package/dist/config/config-matchers.d.ts +31 -40
  40. package/dist/config/config-matchers.js +727 -936
  41. package/dist/config/config-matchers.js.map +1 -1
  42. package/dist/config/dotenv.d.ts +18 -11
  43. package/dist/config/dotenv.js +79 -84
  44. package/dist/config/dotenv.js.map +1 -1
  45. package/dist/config/next-config.d.ts +156 -146
  46. package/dist/config/next-config.js +376 -464
  47. package/dist/config/next-config.js.map +1 -1
  48. package/dist/deploy.d.ts +87 -96
  49. package/dist/deploy.js +490 -628
  50. package/dist/deploy.js.map +1 -1
  51. package/dist/entries/app-browser-entry.d.ts +4 -1
  52. package/dist/entries/app-browser-entry.js +12 -8
  53. package/dist/entries/app-browser-entry.js.map +1 -1
  54. package/dist/entries/app-rsc-entry.d.ts +33 -20
  55. package/dist/entries/app-rsc-entry.js +444 -212
  56. package/dist/entries/app-rsc-entry.js.map +1 -1
  57. package/dist/entries/app-ssr-entry.d.ts +9 -1
  58. package/dist/entries/app-ssr-entry.js +61 -28
  59. package/dist/entries/app-ssr-entry.js.map +1 -1
  60. package/dist/entries/pages-client-entry.d.ts +6 -2
  61. package/dist/entries/pages-client-entry.js +30 -33
  62. package/dist/entries/pages-client-entry.js.map +1 -1
  63. package/dist/entries/pages-entry-helpers.d.ts +5 -1
  64. package/dist/entries/pages-entry-helpers.js +17 -14
  65. package/dist/entries/pages-entry-helpers.js.map +1 -1
  66. package/dist/entries/pages-server-entry.d.ts +6 -2
  67. package/dist/entries/pages-server-entry.js +86 -114
  68. package/dist/entries/pages-server-entry.js.map +1 -1
  69. package/dist/index.d.ts +92 -60
  70. package/dist/index.js +2151 -3133
  71. package/dist/index.js.map +1 -1
  72. package/dist/init.d.ts +40 -37
  73. package/dist/init.js +201 -258
  74. package/dist/init.js.map +1 -1
  75. package/dist/plugins/async-hooks-stub.d.ts +7 -3
  76. package/dist/plugins/async-hooks-stub.js +39 -42
  77. package/dist/plugins/async-hooks-stub.js.map +1 -1
  78. package/dist/plugins/client-reference-dedup.d.ts +7 -3
  79. package/dist/plugins/client-reference-dedup.js +63 -88
  80. package/dist/plugins/client-reference-dedup.js.map +1 -1
  81. package/dist/routing/app-router.d.ts +100 -96
  82. package/dist/routing/app-router.js +560 -670
  83. package/dist/routing/app-router.js.map +1 -1
  84. package/dist/routing/file-matcher.d.ts +18 -15
  85. package/dist/routing/file-matcher.js +65 -65
  86. package/dist/routing/file-matcher.js.map +1 -1
  87. package/dist/routing/pages-router.d.ts +23 -24
  88. package/dist/routing/pages-router.js +147 -172
  89. package/dist/routing/pages-router.js.map +1 -1
  90. package/dist/routing/route-trie.d.ts +23 -20
  91. package/dist/routing/route-trie.js +131 -151
  92. package/dist/routing/route-trie.js.map +1 -1
  93. package/dist/routing/route-validation.d.ts +5 -2
  94. package/dist/routing/route-validation.js +98 -130
  95. package/dist/routing/route-validation.js.map +1 -1
  96. package/dist/routing/utils.d.ts +10 -7
  97. package/dist/routing/utils.js +75 -111
  98. package/dist/routing/utils.js.map +1 -1
  99. package/dist/server/api-handler.d.ts +8 -13
  100. package/dist/server/api-handler.js +160 -193
  101. package/dist/server/api-handler.js.map +1 -1
  102. package/dist/server/app-router-entry.d.ts +6 -16
  103. package/dist/server/app-router-entry.js +26 -54
  104. package/dist/server/app-router-entry.js.map +1 -1
  105. package/dist/server/dev-module-runner.d.ts +11 -64
  106. package/dist/server/dev-module-runner.js +89 -101
  107. package/dist/server/dev-module-runner.js.map +1 -1
  108. package/dist/server/dev-origin-check.d.ts +12 -10
  109. package/dist/server/dev-origin-check.js +98 -108
  110. package/dist/server/dev-origin-check.js.map +1 -1
  111. package/dist/server/dev-server.d.ts +19 -15
  112. package/dist/server/dev-server.js +543 -871
  113. package/dist/server/dev-server.js.map +1 -1
  114. package/dist/server/html.d.ts +4 -1
  115. package/dist/server/html.js +25 -26
  116. package/dist/server/html.js.map +1 -1
  117. package/dist/server/image-optimization.d.ts +31 -28
  118. package/dist/server/image-optimization.js +181 -210
  119. package/dist/server/image-optimization.js.map +1 -1
  120. package/dist/server/instrumentation.d.ts +34 -59
  121. package/dist/server/instrumentation.js +112 -125
  122. package/dist/server/instrumentation.js.map +1 -1
  123. package/dist/server/isr-cache.d.ts +16 -26
  124. package/dist/server/isr-cache.js +106 -128
  125. package/dist/server/isr-cache.js.map +1 -1
  126. package/dist/server/metadata-routes.d.ts +85 -88
  127. package/dist/server/metadata-routes.js +270 -317
  128. package/dist/server/metadata-routes.js.map +1 -1
  129. package/dist/server/middleware-codegen.d.ts +7 -4
  130. package/dist/server/middleware-codegen.js +61 -61
  131. package/dist/server/middleware-codegen.js.map +1 -1
  132. package/dist/server/middleware-request-headers.d.ts +8 -6
  133. package/dist/server/middleware-request-headers.js +47 -65
  134. package/dist/server/middleware-request-headers.js.map +1 -1
  135. package/dist/server/middleware.d.ts +32 -47
  136. package/dist/server/middleware.js +261 -409
  137. package/dist/server/middleware.js.map +1 -1
  138. package/dist/server/normalize-path.d.ts +4 -1
  139. package/dist/server/normalize-path.js +33 -47
  140. package/dist/server/normalize-path.js.map +1 -1
  141. package/dist/server/pages-i18n.d.ts +38 -30
  142. package/dist/server/pages-i18n.js +112 -139
  143. package/dist/server/pages-i18n.js.map +1 -1
  144. package/dist/server/prod-server.d.ts +19 -31
  145. package/dist/server/prod-server.js +715 -945
  146. package/dist/server/prod-server.js.map +1 -1
  147. package/dist/server/request-log.d.ts +18 -12
  148. package/dist/server/request-log.js +45 -52
  149. package/dist/server/request-log.js.map +1 -1
  150. package/dist/server/request-pipeline.d.ts +9 -17
  151. package/dist/server/request-pipeline.js +133 -184
  152. package/dist/server/request-pipeline.js.map +1 -1
  153. package/dist/server/worker-utils.d.ts +4 -1
  154. package/dist/server/worker-utils.js +31 -37
  155. package/dist/server/worker-utils.js.map +1 -1
  156. package/dist/shims/amp.d.ts +5 -2
  157. package/dist/shims/amp.js +19 -15
  158. package/dist/shims/amp.js.map +1 -1
  159. package/dist/shims/app.d.ts +8 -10
  160. package/dist/shims/app.js +0 -1
  161. package/dist/shims/cache-runtime.d.ts +20 -45
  162. package/dist/shims/cache-runtime.js +271 -422
  163. package/dist/shims/cache-runtime.js.map +1 -1
  164. package/dist/shims/cache.d.ts +130 -121
  165. package/dist/shims/cache.js +339 -427
  166. package/dist/shims/cache.js.map +1 -1
  167. package/dist/shims/client-only.d.ts +1 -18
  168. package/dist/shims/client-only.js +0 -17
  169. package/dist/shims/compat-router.d.ts +6 -1
  170. package/dist/shims/compat-router.js +23 -19
  171. package/dist/shims/compat-router.js.map +1 -1
  172. package/dist/shims/config.d.ts +7 -5
  173. package/dist/shims/config.js +16 -23
  174. package/dist/shims/config.js.map +1 -1
  175. package/dist/shims/constants.d.ts +119 -118
  176. package/dist/shims/constants.js +159 -164
  177. package/dist/shims/constants.js.map +1 -1
  178. package/dist/shims/document.d.ts +20 -16
  179. package/dist/shims/document.js +41 -22
  180. package/dist/shims/document.js.map +1 -1
  181. package/dist/shims/dynamic.d.ts +13 -22
  182. package/dist/shims/dynamic.js +122 -136
  183. package/dist/shims/dynamic.js.map +1 -1
  184. package/dist/shims/error-boundary.d.ts +22 -15
  185. package/dist/shims/error-boundary.js +81 -79
  186. package/dist/shims/error-boundary.js.map +1 -1
  187. package/dist/shims/error.d.ts +11 -12
  188. package/dist/shims/error.js +35 -39
  189. package/dist/shims/error.js.map +1 -1
  190. package/dist/shims/fetch-cache.d.ts +16 -14
  191. package/dist/shims/fetch-cache.js +439 -645
  192. package/dist/shims/fetch-cache.js.map +1 -1
  193. package/dist/shims/font-google-base.d.ts +28 -26
  194. package/dist/shims/font-google-base.js +238 -325
  195. package/dist/shims/font-google-base.js.map +1 -1
  196. package/dist/shims/font-google.d.ts +3 -3
  197. package/dist/shims/font-google.generated.d.ts +1928 -1924
  198. package/dist/shims/font-google.generated.js +1928 -2133
  199. package/dist/shims/font-google.generated.js.map +1 -1
  200. package/dist/shims/font-google.js +3 -3
  201. package/dist/shims/font-local.d.ts +28 -26
  202. package/dist/shims/font-local.js +204 -260
  203. package/dist/shims/font-local.js.map +1 -1
  204. package/dist/shims/form.d.ts +13 -27
  205. package/dist/shims/form.js +128 -180
  206. package/dist/shims/form.js.map +1 -1
  207. package/dist/shims/head-state.d.ts +8 -13
  208. package/dist/shims/head-state.js +25 -42
  209. package/dist/shims/head-state.js.map +1 -1
  210. package/dist/shims/head.d.ts +17 -20
  211. package/dist/shims/head.js +194 -250
  212. package/dist/shims/head.js.map +1 -1
  213. package/dist/shims/headers.d.ts +84 -78
  214. package/dist/shims/headers.js +447 -575
  215. package/dist/shims/headers.js.map +1 -1
  216. package/dist/shims/i18n-context.d.ts +16 -20
  217. package/dist/shims/i18n-context.js +35 -48
  218. package/dist/shims/i18n-context.js.map +1 -1
  219. package/dist/shims/i18n-state.d.ts +8 -14
  220. package/dist/shims/i18n-state.js +34 -42
  221. package/dist/shims/i18n-state.js.map +1 -1
  222. package/dist/shims/image-config.d.ts +11 -8
  223. package/dist/shims/image-config.js +50 -83
  224. package/dist/shims/image-config.js.map +1 -1
  225. package/dist/shims/image.d.ts +37 -46
  226. package/dist/shims/image.js +283 -308
  227. package/dist/shims/image.js.map +1 -1
  228. package/dist/shims/internal/api-utils.d.ts +7 -4
  229. package/dist/shims/internal/api-utils.js +0 -6
  230. package/dist/shims/internal/app-router-context.d.ts +22 -17
  231. package/dist/shims/internal/app-router-context.js +17 -13
  232. package/dist/shims/internal/app-router-context.js.map +1 -1
  233. package/dist/shims/internal/cookies.d.ts +2 -9
  234. package/dist/shims/internal/cookies.js +2 -9
  235. package/dist/shims/internal/parse-cookie-header.d.ts +4 -1
  236. package/dist/shims/internal/parse-cookie-header.js +29 -29
  237. package/dist/shims/internal/parse-cookie-header.js.map +1 -1
  238. package/dist/shims/internal/router-context.d.ts +7 -1
  239. package/dist/shims/internal/router-context.js +11 -7
  240. package/dist/shims/internal/router-context.js.map +1 -1
  241. package/dist/shims/internal/utils.d.ts +40 -37
  242. package/dist/shims/internal/utils.js +24 -30
  243. package/dist/shims/internal/utils.js.map +1 -1
  244. package/dist/shims/internal/work-unit-async-storage.d.ts +6 -10
  245. package/dist/shims/internal/work-unit-async-storage.js +14 -11
  246. package/dist/shims/internal/work-unit-async-storage.js.map +1 -1
  247. package/dist/shims/layout-segment-context.d.ts +11 -14
  248. package/dist/shims/layout-segment-context.js +24 -23
  249. package/dist/shims/layout-segment-context.js.map +1 -1
  250. package/dist/shims/legacy-image.d.ts +39 -46
  251. package/dist/shims/legacy-image.js +47 -42
  252. package/dist/shims/legacy-image.js.map +1 -1
  253. package/dist/shims/link.d.ts +32 -36
  254. package/dist/shims/link.js +255 -391
  255. package/dist/shims/link.js.map +1 -1
  256. package/dist/shims/metadata.d.ts +210 -202
  257. package/dist/shims/metadata.js +545 -546
  258. package/dist/shims/metadata.js.map +1 -1
  259. package/dist/shims/navigation-state.d.ts +10 -18
  260. package/dist/shims/navigation-state.js +66 -74
  261. package/dist/shims/navigation-state.js.map +1 -1
  262. package/dist/shims/navigation.d.ts +59 -63
  263. package/dist/shims/navigation.js +505 -704
  264. package/dist/shims/navigation.js.map +1 -1
  265. package/dist/shims/og.d.ts +2 -20
  266. package/dist/shims/og.js +2 -19
  267. package/dist/shims/readonly-url-search-params.d.ts +8 -5
  268. package/dist/shims/readonly-url-search-params.js +26 -22
  269. package/dist/shims/readonly-url-search-params.js.map +1 -1
  270. package/dist/shims/request-context.d.ts +8 -5
  271. package/dist/shims/request-context.js +50 -60
  272. package/dist/shims/request-context.js.map +1 -1
  273. package/dist/shims/request-state-types.d.ts +11 -11
  274. package/dist/shims/request-state-types.js +0 -1
  275. package/dist/shims/router-state.d.ts +13 -10
  276. package/dist/shims/router-state.js +34 -43
  277. package/dist/shims/router-state.js.map +1 -1
  278. package/dist/shims/router.d.ts +81 -85
  279. package/dist/shims/router.js +506 -628
  280. package/dist/shims/router.js.map +1 -1
  281. package/dist/shims/script.d.ts +39 -48
  282. package/dist/shims/script.js +107 -160
  283. package/dist/shims/script.js.map +1 -1
  284. package/dist/shims/server-only.d.ts +1 -19
  285. package/dist/shims/server-only.js +0 -18
  286. package/dist/shims/server.d.ts +213 -164
  287. package/dist/shims/server.js +545 -478
  288. package/dist/shims/server.js.map +1 -1
  289. package/dist/shims/unified-request-context.d.ts +20 -20
  290. package/dist/shims/unified-request-context.js +81 -99
  291. package/dist/shims/unified-request-context.js.map +1 -1
  292. package/dist/shims/url-safety.d.ts +4 -1
  293. package/dist/shims/url-safety.js +15 -11
  294. package/dist/shims/url-safety.js.map +1 -1
  295. package/dist/shims/url-utils.d.ts +8 -5
  296. package/dist/shims/url-utils.js +62 -93
  297. package/dist/shims/url-utils.js.map +1 -1
  298. package/dist/shims/web-vitals.d.ts +10 -8
  299. package/dist/shims/web-vitals.js +9 -15
  300. package/dist/shims/web-vitals.js.map +1 -1
  301. package/dist/utils/base-path.d.ts +5 -2
  302. package/dist/utils/base-path.js +21 -19
  303. package/dist/utils/base-path.js.map +1 -1
  304. package/dist/utils/domain-locale.d.ts +17 -9
  305. package/dist/utils/domain-locale.js +36 -56
  306. package/dist/utils/domain-locale.js.map +1 -1
  307. package/dist/utils/hash.d.ts +4 -1
  308. package/dist/utils/hash.js +19 -17
  309. package/dist/utils/hash.js.map +1 -1
  310. package/dist/utils/manifest-paths.d.ts +6 -3
  311. package/dist/utils/manifest-paths.js +15 -16
  312. package/dist/utils/manifest-paths.js.map +1 -1
  313. package/dist/utils/project.d.ts +13 -11
  314. package/dist/utils/project.js +169 -216
  315. package/dist/utils/project.js.map +1 -1
  316. package/dist/utils/query.d.ts +8 -6
  317. package/dist/utils/query.js +57 -67
  318. package/dist/utils/query.js.map +1 -1
  319. package/package.json +10 -9
  320. package/dist/build/report.d.ts.map +0 -1
  321. package/dist/build/static-export.d.ts.map +0 -1
  322. package/dist/check.d.ts.map +0 -1
  323. package/dist/cli.d.ts.map +0 -1
  324. package/dist/client/entry.d.ts.map +0 -1
  325. package/dist/client/validate-module-path.d.ts.map +0 -1
  326. package/dist/client/vinext-next-data.d.ts.map +0 -1
  327. package/dist/client/vinext-next-data.js.map +0 -1
  328. package/dist/cloudflare/index.d.ts.map +0 -1
  329. package/dist/cloudflare/index.js.map +0 -1
  330. package/dist/cloudflare/kv-cache-handler.d.ts.map +0 -1
  331. package/dist/cloudflare/tpr.d.ts.map +0 -1
  332. package/dist/config/config-matchers.d.ts.map +0 -1
  333. package/dist/config/dotenv.d.ts.map +0 -1
  334. package/dist/config/next-config.d.ts.map +0 -1
  335. package/dist/deploy.d.ts.map +0 -1
  336. package/dist/entries/app-browser-entry.d.ts.map +0 -1
  337. package/dist/entries/app-rsc-entry.d.ts.map +0 -1
  338. package/dist/entries/app-ssr-entry.d.ts.map +0 -1
  339. package/dist/entries/pages-client-entry.d.ts.map +0 -1
  340. package/dist/entries/pages-entry-helpers.d.ts.map +0 -1
  341. package/dist/entries/pages-server-entry.d.ts.map +0 -1
  342. package/dist/index.d.ts.map +0 -1
  343. package/dist/init.d.ts.map +0 -1
  344. package/dist/plugins/async-hooks-stub.d.ts.map +0 -1
  345. package/dist/plugins/client-reference-dedup.d.ts.map +0 -1
  346. package/dist/routing/app-router.d.ts.map +0 -1
  347. package/dist/routing/file-matcher.d.ts.map +0 -1
  348. package/dist/routing/pages-router.d.ts.map +0 -1
  349. package/dist/routing/route-trie.d.ts.map +0 -1
  350. package/dist/routing/route-validation.d.ts.map +0 -1
  351. package/dist/routing/utils.d.ts.map +0 -1
  352. package/dist/server/api-handler.d.ts.map +0 -1
  353. package/dist/server/app-router-entry.d.ts.map +0 -1
  354. package/dist/server/dev-module-runner.d.ts.map +0 -1
  355. package/dist/server/dev-origin-check.d.ts.map +0 -1
  356. package/dist/server/dev-server.d.ts.map +0 -1
  357. package/dist/server/html.d.ts.map +0 -1
  358. package/dist/server/image-optimization.d.ts.map +0 -1
  359. package/dist/server/instrumentation.d.ts.map +0 -1
  360. package/dist/server/isr-cache.d.ts.map +0 -1
  361. package/dist/server/metadata-routes.d.ts.map +0 -1
  362. package/dist/server/middleware-codegen.d.ts.map +0 -1
  363. package/dist/server/middleware-request-headers.d.ts.map +0 -1
  364. package/dist/server/middleware.d.ts.map +0 -1
  365. package/dist/server/normalize-path.d.ts.map +0 -1
  366. package/dist/server/pages-i18n.d.ts.map +0 -1
  367. package/dist/server/prod-server.d.ts.map +0 -1
  368. package/dist/server/request-log.d.ts.map +0 -1
  369. package/dist/server/request-pipeline.d.ts.map +0 -1
  370. package/dist/server/worker-utils.d.ts.map +0 -1
  371. package/dist/shims/amp.d.ts.map +0 -1
  372. package/dist/shims/app.d.ts.map +0 -1
  373. package/dist/shims/app.js.map +0 -1
  374. package/dist/shims/cache-runtime.d.ts.map +0 -1
  375. package/dist/shims/cache.d.ts.map +0 -1
  376. package/dist/shims/client-only.d.ts.map +0 -1
  377. package/dist/shims/client-only.js.map +0 -1
  378. package/dist/shims/compat-router.d.ts.map +0 -1
  379. package/dist/shims/config.d.ts.map +0 -1
  380. package/dist/shims/constants.d.ts.map +0 -1
  381. package/dist/shims/document.d.ts.map +0 -1
  382. package/dist/shims/dynamic.d.ts.map +0 -1
  383. package/dist/shims/error-boundary.d.ts.map +0 -1
  384. package/dist/shims/error.d.ts.map +0 -1
  385. package/dist/shims/fetch-cache.d.ts.map +0 -1
  386. package/dist/shims/font-google-base.d.ts.map +0 -1
  387. package/dist/shims/font-google.d.ts.map +0 -1
  388. package/dist/shims/font-google.generated.d.ts.map +0 -1
  389. package/dist/shims/font-google.js.map +0 -1
  390. package/dist/shims/font-local.d.ts.map +0 -1
  391. package/dist/shims/form.d.ts.map +0 -1
  392. package/dist/shims/head-state.d.ts.map +0 -1
  393. package/dist/shims/head.d.ts.map +0 -1
  394. package/dist/shims/headers.d.ts.map +0 -1
  395. package/dist/shims/i18n-context.d.ts.map +0 -1
  396. package/dist/shims/i18n-state.d.ts.map +0 -1
  397. package/dist/shims/image-config.d.ts.map +0 -1
  398. package/dist/shims/image.d.ts.map +0 -1
  399. package/dist/shims/internal/api-utils.d.ts.map +0 -1
  400. package/dist/shims/internal/api-utils.js.map +0 -1
  401. package/dist/shims/internal/app-router-context.d.ts.map +0 -1
  402. package/dist/shims/internal/cookies.d.ts.map +0 -1
  403. package/dist/shims/internal/cookies.js.map +0 -1
  404. package/dist/shims/internal/parse-cookie-header.d.ts.map +0 -1
  405. package/dist/shims/internal/router-context.d.ts.map +0 -1
  406. package/dist/shims/internal/utils.d.ts.map +0 -1
  407. package/dist/shims/internal/work-unit-async-storage.d.ts.map +0 -1
  408. package/dist/shims/layout-segment-context.d.ts.map +0 -1
  409. package/dist/shims/legacy-image.d.ts.map +0 -1
  410. package/dist/shims/link.d.ts.map +0 -1
  411. package/dist/shims/metadata.d.ts.map +0 -1
  412. package/dist/shims/navigation-state.d.ts.map +0 -1
  413. package/dist/shims/navigation.d.ts.map +0 -1
  414. package/dist/shims/og.d.ts.map +0 -1
  415. package/dist/shims/og.js.map +0 -1
  416. package/dist/shims/readonly-url-search-params.d.ts.map +0 -1
  417. package/dist/shims/request-context.d.ts.map +0 -1
  418. package/dist/shims/request-state-types.d.ts.map +0 -1
  419. package/dist/shims/request-state-types.js.map +0 -1
  420. package/dist/shims/router-state.d.ts.map +0 -1
  421. package/dist/shims/router.d.ts.map +0 -1
  422. package/dist/shims/script.d.ts.map +0 -1
  423. package/dist/shims/server-only.d.ts.map +0 -1
  424. package/dist/shims/server-only.js.map +0 -1
  425. package/dist/shims/server.d.ts.map +0 -1
  426. package/dist/shims/unified-request-context.d.ts.map +0 -1
  427. package/dist/shims/url-safety.d.ts.map +0 -1
  428. package/dist/shims/url-utils.d.ts.map +0 -1
  429. package/dist/shims/web-vitals.d.ts.map +0 -1
  430. package/dist/utils/base-path.d.ts.map +0 -1
  431. package/dist/utils/domain-locale.d.ts.map +0 -1
  432. package/dist/utils/hash.d.ts.map +0 -1
  433. package/dist/utils/manifest-paths.d.ts.map +0 -1
  434. package/dist/utils/project.d.ts.map +0 -1
  435. package/dist/utils/query.d.ts.map +0 -1
@@ -1,302 +1,234 @@
1
- /**
2
- * TPR: Traffic-aware Pre-Rendering
3
- *
4
- * Uses Cloudflare zone analytics to determine which pages actually get
5
- * traffic, and pre-renders only those during deploy. The pre-rendered
6
- * HTML is uploaded to KV in the same format ISR uses at runtime — no
7
- * runtime changes needed.
8
- *
9
- * Flow:
10
- * 1. Parse wrangler config to find custom domain and KV namespace
11
- * 2. Resolve the Cloudflare zone for the custom domain
12
- * 3. Query zone analytics (GraphQL) for top pages by request count
13
- * 4. Walk ranked list until coverage threshold is met
14
- * 5. Start the built production server locally
15
- * 6. Fetch each hot route to produce HTML
16
- * 7. Upload pre-rendered HTML to KV (same KVCacheEntry format ISR reads)
17
- *
18
- * TPR is an experimental feature enabled via --experimental-tpr. It
19
- * gracefully skips when no custom domain, no API token, no traffic data,
20
- * or no KV namespace is configured.
21
- */
22
1
  import fs from "node:fs";
23
2
  import path from "node:path";
24
3
  import { fileURLToPath } from "node:url";
25
4
  import { spawn } from "node:child_process";
26
- // ─── Wrangler Config Parsing ─────────────────────────────────────────────────
5
+ //#region src/cloudflare/tpr.ts
27
6
  /**
28
- * Parse wrangler config (JSONC or TOML) to extract the fields TPR needs:
29
- * account_id, VINEXT_CACHE KV namespace ID, and custom domain.
30
- */
31
- export function parseWranglerConfig(root) {
32
- // Try JSONC / JSON first
33
- for (const filename of ["wrangler.jsonc", "wrangler.json"]) {
34
- const filepath = path.join(root, filename);
35
- if (fs.existsSync(filepath)) {
36
- const content = fs.readFileSync(filepath, "utf-8");
37
- try {
38
- const json = JSON.parse(stripJsonComments(content));
39
- return extractFromJSON(json);
40
- }
41
- catch {
42
- continue;
43
- }
44
- }
45
- }
46
- // Try TOML
47
- const tomlPath = path.join(root, "wrangler.toml");
48
- if (fs.existsSync(tomlPath)) {
49
- const content = fs.readFileSync(tomlPath, "utf-8");
50
- return extractFromTOML(content);
51
- }
52
- return null;
7
+ * TPR: Traffic-aware Pre-Rendering
8
+ *
9
+ * Uses Cloudflare zone analytics to determine which pages actually get
10
+ * traffic, and pre-renders only those during deploy. The pre-rendered
11
+ * HTML is uploaded to KV in the same format ISR uses at runtime — no
12
+ * runtime changes needed.
13
+ *
14
+ * Flow:
15
+ * 1. Parse wrangler config to find custom domain and KV namespace
16
+ * 2. Resolve the Cloudflare zone for the custom domain
17
+ * 3. Query zone analytics (GraphQL) for top pages by request count
18
+ * 4. Walk ranked list until coverage threshold is met
19
+ * 5. Start the built production server locally
20
+ * 6. Fetch each hot route to produce HTML
21
+ * 7. Upload pre-rendered HTML to KV (same KVCacheEntry format ISR reads)
22
+ *
23
+ * TPR is an experimental feature enabled via --experimental-tpr. It
24
+ * gracefully skips when no custom domain, no API token, no traffic data,
25
+ * or no KV namespace is configured.
26
+ */
27
+ /**
28
+ * Parse wrangler config (JSONC or TOML) to extract the fields TPR needs:
29
+ * account_id, VINEXT_CACHE KV namespace ID, and custom domain.
30
+ */
31
+ function parseWranglerConfig(root) {
32
+ for (const filename of ["wrangler.jsonc", "wrangler.json"]) {
33
+ const filepath = path.join(root, filename);
34
+ if (fs.existsSync(filepath)) {
35
+ const content = fs.readFileSync(filepath, "utf-8");
36
+ try {
37
+ return extractFromJSON(JSON.parse(stripJsonComments(content)));
38
+ } catch {
39
+ continue;
40
+ }
41
+ }
42
+ }
43
+ const tomlPath = path.join(root, "wrangler.toml");
44
+ if (fs.existsSync(tomlPath)) return extractFromTOML(fs.readFileSync(tomlPath, "utf-8"));
45
+ return null;
53
46
  }
54
47
  /**
55
- * Strip single-line (//) and multi-line comments from JSONC while
56
- * preserving strings that contain slashes.
57
- */
48
+ * Strip single-line (//) and multi-line comments from JSONC while
49
+ * preserving strings that contain slashes.
50
+ */
58
51
  function stripJsonComments(str) {
59
- let result = "";
60
- let inString = false;
61
- let inSingleLine = false;
62
- let inMultiLine = false;
63
- let escapeNext = false;
64
- for (let i = 0; i < str.length; i++) {
65
- const ch = str[i];
66
- const next = str[i + 1];
67
- if (escapeNext) {
68
- if (!inSingleLine && !inMultiLine)
69
- result += ch;
70
- escapeNext = false;
71
- continue;
72
- }
73
- if (ch === "\\" && inString) {
74
- result += ch;
75
- escapeNext = true;
76
- continue;
77
- }
78
- if (inSingleLine) {
79
- if (ch === "\n") {
80
- inSingleLine = false;
81
- result += ch;
82
- }
83
- continue;
84
- }
85
- if (inMultiLine) {
86
- if (ch === "*" && next === "/") {
87
- inMultiLine = false;
88
- i++;
89
- }
90
- continue;
91
- }
92
- if (ch === '"' && !inString) {
93
- inString = true;
94
- result += ch;
95
- continue;
96
- }
97
- if (ch === '"' && inString) {
98
- inString = false;
99
- result += ch;
100
- continue;
101
- }
102
- if (!inString && ch === "/" && next === "/") {
103
- inSingleLine = true;
104
- i++;
105
- continue;
106
- }
107
- if (!inString && ch === "/" && next === "*") {
108
- inMultiLine = true;
109
- i++;
110
- continue;
111
- }
112
- result += ch;
113
- }
114
- return result;
52
+ let result = "";
53
+ let inString = false;
54
+ let inSingleLine = false;
55
+ let inMultiLine = false;
56
+ let escapeNext = false;
57
+ for (let i = 0; i < str.length; i++) {
58
+ const ch = str[i];
59
+ const next = str[i + 1];
60
+ if (escapeNext) {
61
+ if (!inSingleLine && !inMultiLine) result += ch;
62
+ escapeNext = false;
63
+ continue;
64
+ }
65
+ if (ch === "\\" && inString) {
66
+ result += ch;
67
+ escapeNext = true;
68
+ continue;
69
+ }
70
+ if (inSingleLine) {
71
+ if (ch === "\n") {
72
+ inSingleLine = false;
73
+ result += ch;
74
+ }
75
+ continue;
76
+ }
77
+ if (inMultiLine) {
78
+ if (ch === "*" && next === "/") {
79
+ inMultiLine = false;
80
+ i++;
81
+ }
82
+ continue;
83
+ }
84
+ if (ch === "\"" && !inString) {
85
+ inString = true;
86
+ result += ch;
87
+ continue;
88
+ }
89
+ if (ch === "\"" && inString) {
90
+ inString = false;
91
+ result += ch;
92
+ continue;
93
+ }
94
+ if (!inString && ch === "/" && next === "/") {
95
+ inSingleLine = true;
96
+ i++;
97
+ continue;
98
+ }
99
+ if (!inString && ch === "/" && next === "*") {
100
+ inMultiLine = true;
101
+ i++;
102
+ continue;
103
+ }
104
+ result += ch;
105
+ }
106
+ return result;
115
107
  }
116
108
  function extractFromJSON(config) {
117
- const result = {};
118
- // account_id
119
- if (typeof config.account_id === "string") {
120
- result.accountId = config.account_id;
121
- }
122
- // KV namespace ID for VINEXT_CACHE
123
- if (Array.isArray(config.kv_namespaces)) {
124
- const vinextKV = config.kv_namespaces.find((ns) => ns && typeof ns === "object" && ns.binding === "VINEXT_CACHE");
125
- if (vinextKV && typeof vinextKV.id === "string" && vinextKV.id !== "<your-kv-namespace-id>") {
126
- result.kvNamespaceId = vinextKV.id;
127
- }
128
- }
129
- // Custom domain — check routes[] and custom_domains[]
130
- const domain = extractDomainFromRoutes(config.routes) ?? extractDomainFromCustomDomains(config);
131
- if (domain)
132
- result.customDomain = domain;
133
- return result;
109
+ const result = {};
110
+ if (typeof config.account_id === "string") result.accountId = config.account_id;
111
+ if (Array.isArray(config.kv_namespaces)) {
112
+ const vinextKV = config.kv_namespaces.find((ns) => ns && typeof ns === "object" && ns.binding === "VINEXT_CACHE");
113
+ if (vinextKV && typeof vinextKV.id === "string" && vinextKV.id !== "<your-kv-namespace-id>") result.kvNamespaceId = vinextKV.id;
114
+ }
115
+ const domain = extractDomainFromRoutes(config.routes) ?? extractDomainFromCustomDomains(config);
116
+ if (domain) result.customDomain = domain;
117
+ return result;
134
118
  }
135
119
  function extractDomainFromRoutes(routes) {
136
- if (!Array.isArray(routes))
137
- return null;
138
- for (const route of routes) {
139
- if (typeof route === "string") {
140
- const domain = cleanDomain(route);
141
- if (domain && !domain.includes("workers.dev"))
142
- return domain;
143
- }
144
- else if (route && typeof route === "object") {
145
- const r = route;
146
- const pattern = typeof r.zone_name === "string"
147
- ? r.zone_name
148
- : typeof r.pattern === "string"
149
- ? r.pattern
150
- : null;
151
- if (pattern) {
152
- const domain = cleanDomain(pattern);
153
- if (domain && !domain.includes("workers.dev"))
154
- return domain;
155
- }
156
- }
157
- }
158
- return null;
120
+ if (!Array.isArray(routes)) return null;
121
+ for (const route of routes) if (typeof route === "string") {
122
+ const domain = cleanDomain(route);
123
+ if (domain && !domain.includes("workers.dev")) return domain;
124
+ } else if (route && typeof route === "object") {
125
+ const r = route;
126
+ const pattern = typeof r.zone_name === "string" ? r.zone_name : typeof r.pattern === "string" ? r.pattern : null;
127
+ if (pattern) {
128
+ const domain = cleanDomain(pattern);
129
+ if (domain && !domain.includes("workers.dev")) return domain;
130
+ }
131
+ }
132
+ return null;
159
133
  }
160
134
  function extractDomainFromCustomDomains(config) {
161
- // Workers Custom Domains: "custom_domains": ["example.com"]
162
- if (Array.isArray(config.custom_domains)) {
163
- for (const d of config.custom_domains) {
164
- if (typeof d === "string" && !d.includes("workers.dev")) {
165
- return cleanDomain(d);
166
- }
167
- }
168
- }
169
- return null;
135
+ if (Array.isArray(config.custom_domains)) {
136
+ for (const d of config.custom_domains) if (typeof d === "string" && !d.includes("workers.dev")) return cleanDomain(d);
137
+ }
138
+ return null;
170
139
  }
171
140
  /** Strip protocol and trailing wildcards from a route pattern to get a bare domain. */
172
141
  function cleanDomain(raw) {
173
- const cleaned = raw
174
- .replace(/^https?:\/\//, "")
175
- .replace(/\/\*$/, "")
176
- .replace(/\/+$/, "")
177
- .split("/")[0]; // Take only the host part
178
- return cleaned || null;
142
+ return raw.replace(/^https?:\/\//, "").replace(/\/\*$/, "").replace(/\/+$/, "").split("/")[0] || null;
179
143
  }
180
144
  /**
181
- * Simple extraction of specific fields from wrangler.toml content.
182
- * Not a full TOML parser — just enough for the fields we need.
183
- */
145
+ * Simple extraction of specific fields from wrangler.toml content.
146
+ * Not a full TOML parser — just enough for the fields we need.
147
+ */
184
148
  function extractFromTOML(content) {
185
- const result = {};
186
- // account_id = "..."
187
- const accountMatch = content.match(/^account_id\s*=\s*"([^"]+)"/m);
188
- if (accountMatch)
189
- result.accountId = accountMatch[1];
190
- // KV namespace with binding = "VINEXT_CACHE"
191
- // Look for [[kv_namespaces]] blocks
192
- const kvBlocks = content.split(/\[\[kv_namespaces\]\]/);
193
- for (let i = 1; i < kvBlocks.length; i++) {
194
- const block = kvBlocks[i].split(/\[\[/)[0]; // Take until next section
195
- const bindingMatch = block.match(/binding\s*=\s*"([^"]+)"/);
196
- const idMatch = block.match(/\bid\s*=\s*"([^"]+)"/);
197
- if (bindingMatch?.[1] === "VINEXT_CACHE" &&
198
- idMatch?.[1] &&
199
- idMatch[1] !== "<your-kv-namespace-id>") {
200
- result.kvNamespaceId = idMatch[1];
201
- }
202
- }
203
- // routes both string and table forms
204
- // route = "example.com/*"
205
- const routeMatch = content.match(/^route\s*=\s*"([^"]+)"/m);
206
- if (routeMatch) {
207
- const domain = cleanDomain(routeMatch[1]);
208
- if (domain && !domain.includes("workers.dev")) {
209
- result.customDomain = domain;
210
- }
211
- }
212
- // [[routes]] blocks
213
- if (!result.customDomain) {
214
- const routeBlocks = content.split(/\[\[routes\]\]/);
215
- for (let i = 1; i < routeBlocks.length; i++) {
216
- const block = routeBlocks[i].split(/\[\[/)[0];
217
- const patternMatch = block.match(/pattern\s*=\s*"([^"]+)"/);
218
- if (patternMatch) {
219
- const domain = cleanDomain(patternMatch[1]);
220
- if (domain && !domain.includes("workers.dev")) {
221
- result.customDomain = domain;
222
- break;
223
- }
224
- }
225
- }
226
- }
227
- return result;
149
+ const result = {};
150
+ const accountMatch = content.match(/^account_id\s*=\s*"([^"]+)"/m);
151
+ if (accountMatch) result.accountId = accountMatch[1];
152
+ const kvBlocks = content.split(/\[\[kv_namespaces\]\]/);
153
+ for (let i = 1; i < kvBlocks.length; i++) {
154
+ const block = kvBlocks[i].split(/\[\[/)[0];
155
+ const bindingMatch = block.match(/binding\s*=\s*"([^"]+)"/);
156
+ const idMatch = block.match(/\bid\s*=\s*"([^"]+)"/);
157
+ if (bindingMatch?.[1] === "VINEXT_CACHE" && idMatch?.[1] && idMatch[1] !== "<your-kv-namespace-id>") result.kvNamespaceId = idMatch[1];
158
+ }
159
+ const routeMatch = content.match(/^route\s*=\s*"([^"]+)"/m);
160
+ if (routeMatch) {
161
+ const domain = cleanDomain(routeMatch[1]);
162
+ if (domain && !domain.includes("workers.dev")) result.customDomain = domain;
163
+ }
164
+ if (!result.customDomain) {
165
+ const routeBlocks = content.split(/\[\[routes\]\]/);
166
+ for (let i = 1; i < routeBlocks.length; i++) {
167
+ const patternMatch = routeBlocks[i].split(/\[\[/)[0].match(/pattern\s*=\s*"([^"]+)"/);
168
+ if (patternMatch) {
169
+ const domain = cleanDomain(patternMatch[1]);
170
+ if (domain && !domain.includes("workers.dev")) {
171
+ result.customDomain = domain;
172
+ break;
173
+ }
174
+ }
175
+ }
176
+ }
177
+ return result;
228
178
  }
229
- // ─── Cloudflare API ──────────────────────────────────────────────────────────
230
179
  /**
231
- * Generate zone lookup candidates from shortest (2-part) to longest.
232
- * Tries the most common case first (e.g., "example.com") and progressively
233
- * adds labels for multi-part TLDs (e.g., "co.uk" → "example.co.uk").
234
- *
235
- * "shop.example.com" → ["example.com", "shop.example.com"]
236
- * "shop.example.co.uk" → ["co.uk", "example.co.uk", "shop.example.co.uk"]
237
- * "example.com" → ["example.com"]
238
- */
239
- export function domainCandidates(domain) {
240
- const parts = domain.split(".");
241
- const candidates = [];
242
- for (let i = parts.length - 2; i >= 0; i--) {
243
- candidates.push(parts.slice(i).join("."));
244
- }
245
- return candidates;
180
+ * Generate zone lookup candidates from shortest (2-part) to longest.
181
+ * Tries the most common case first (e.g., "example.com") and progressively
182
+ * adds labels for multi-part TLDs (e.g., "co.uk" → "example.co.uk").
183
+ *
184
+ * "shop.example.com" → ["example.com", "shop.example.com"]
185
+ * "shop.example.co.uk" → ["co.uk", "example.co.uk", "shop.example.co.uk"]
186
+ * "example.com" → ["example.com"]
187
+ */
188
+ function domainCandidates(domain) {
189
+ const parts = domain.split(".");
190
+ const candidates = [];
191
+ for (let i = parts.length - 2; i >= 0; i--) candidates.push(parts.slice(i).join("."));
192
+ return candidates;
246
193
  }
247
194
  /** Resolve zone ID from a domain name via the Cloudflare API. */
248
195
  async function resolveZoneId(domain, apiToken) {
249
- // Try progressively longer domain candidates until one matches a zone.
250
- // This handles all public suffixes without a hardcoded TLD list —
251
- // for simple TLDs (.com, .io) the 2-part candidate hits on the first try;
252
- // for multi-part TLDs (.co.uk, .com.au) it takes one extra call.
253
- for (const candidate of domainCandidates(domain)) {
254
- const response = await fetch(`https://api.cloudflare.com/client/v4/zones?name=${encodeURIComponent(candidate)}`, {
255
- headers: {
256
- Authorization: `Bearer ${apiToken}`,
257
- "Content-Type": "application/json",
258
- },
259
- });
260
- if (!response.ok)
261
- continue;
262
- const data = (await response.json());
263
- if (data.success && data.result?.length) {
264
- return data.result[0].id;
265
- }
266
- }
267
- return null;
196
+ for (const candidate of domainCandidates(domain)) {
197
+ const response = await fetch(`https://api.cloudflare.com/client/v4/zones?name=${encodeURIComponent(candidate)}`, { headers: {
198
+ Authorization: `Bearer ${apiToken}`,
199
+ "Content-Type": "application/json"
200
+ } });
201
+ if (!response.ok) continue;
202
+ const data = await response.json();
203
+ if (data.success && data.result?.length) return data.result[0].id;
204
+ }
205
+ return null;
268
206
  }
269
207
  /** Resolve the account ID associated with the API token. */
270
208
  async function resolveAccountId(apiToken) {
271
- const response = await fetch("https://api.cloudflare.com/client/v4/accounts?per_page=1", {
272
- headers: {
273
- Authorization: `Bearer ${apiToken}`,
274
- "Content-Type": "application/json",
275
- },
276
- });
277
- if (!response.ok)
278
- return null;
279
- const data = (await response.json());
280
- if (!data.success || !data.result?.length)
281
- return null;
282
- return data.result[0].id;
209
+ const response = await fetch("https://api.cloudflare.com/client/v4/accounts?per_page=1", { headers: {
210
+ Authorization: `Bearer ${apiToken}`,
211
+ "Content-Type": "application/json"
212
+ } });
213
+ if (!response.ok) return null;
214
+ const data = await response.json();
215
+ if (!data.success || !data.result?.length) return null;
216
+ return data.result[0].id;
283
217
  }
284
- // ─── Traffic Querying ────────────────────────────────────────────────────────
285
218
  /**
286
- * Query Cloudflare zone analytics for top page paths by request count
287
- * over the given time window.
288
- */
219
+ * Query Cloudflare zone analytics for top page paths by request count
220
+ * over the given time window.
221
+ */
289
222
  async function queryTraffic(zoneTag, apiToken, windowHours) {
290
- const now = new Date();
291
- const start = new Date(now.getTime() - windowHours * 60 * 60 * 1000);
292
- const query = `{
223
+ const now = /* @__PURE__ */ new Date();
224
+ const query = `{
293
225
  viewer {
294
226
  zones(filter: { zoneTag: "${zoneTag}" }) {
295
227
  httpRequestsAdaptiveGroups(
296
228
  limit: 10000
297
229
  orderBy: [sum_requests_DESC]
298
230
  filter: {
299
- datetime_geq: "${start.toISOString()}"
231
+ datetime_geq: "${(/* @__PURE__ */ new Date(now.getTime() - windowHours * 60 * 60 * 1e3)).toISOString()}"
300
232
  datetime_lt: "${now.toISOString()}"
301
233
  requestSource: "eyeball"
302
234
  }
@@ -307,372 +239,297 @@ async function queryTraffic(zoneTag, apiToken, windowHours) {
307
239
  }
308
240
  }
309
241
  }`;
310
- const response = await fetch("https://api.cloudflare.com/client/v4/graphql", {
311
- method: "POST",
312
- headers: {
313
- Authorization: `Bearer ${apiToken}`,
314
- "Content-Type": "application/json",
315
- },
316
- body: JSON.stringify({ query }),
317
- });
318
- if (!response.ok) {
319
- throw new Error(`Zone analytics query failed: ${response.status} ${response.statusText}`);
320
- }
321
- const data = (await response.json());
322
- if (data.errors?.length) {
323
- throw new Error(`Zone analytics error: ${data.errors[0].message}`);
324
- }
325
- const groups = data.data?.viewer?.zones?.[0]?.httpRequestsAdaptiveGroups;
326
- if (!groups || groups.length === 0)
327
- return [];
328
- return filterTrafficPaths(groups.map((g) => ({
329
- path: g.dimensions.clientRequestPath,
330
- requests: g.sum.requests,
331
- })));
242
+ const response = await fetch("https://api.cloudflare.com/client/v4/graphql", {
243
+ method: "POST",
244
+ headers: {
245
+ Authorization: `Bearer ${apiToken}`,
246
+ "Content-Type": "application/json"
247
+ },
248
+ body: JSON.stringify({ query })
249
+ });
250
+ if (!response.ok) throw new Error(`Zone analytics query failed: ${response.status} ${response.statusText}`);
251
+ const data = await response.json();
252
+ if (data.errors?.length) throw new Error(`Zone analytics error: ${data.errors[0].message}`);
253
+ const groups = data.data?.viewer?.zones?.[0]?.httpRequestsAdaptiveGroups;
254
+ if (!groups || groups.length === 0) return [];
255
+ return filterTrafficPaths(groups.map((g) => ({
256
+ path: g.dimensions.clientRequestPath,
257
+ requests: g.sum.requests
258
+ })));
332
259
  }
333
260
  /** Filter out non-page requests (static assets, API routes, internal routes). */
334
261
  function filterTrafficPaths(entries) {
335
- return entries.filter((e) => {
336
- if (!e.path.startsWith("/"))
337
- return false;
338
- // Static assets
339
- if (/\.(js|css|png|jpg|jpeg|gif|svg|ico|woff2?|ttf|eot|map|webp|avif)$/i.test(e.path))
340
- return false;
341
- // API routes
342
- if (e.path.startsWith("/api/"))
343
- return false;
344
- // Internal routes
345
- if (e.path.startsWith("/_vinext/") || e.path.startsWith("/_next/"))
346
- return false;
347
- // RSC requests
348
- if (e.path.endsWith(".rsc"))
349
- return false;
350
- return true;
351
- });
262
+ return entries.filter((e) => {
263
+ if (!e.path.startsWith("/")) return false;
264
+ if (/\.(js|css|png|jpg|jpeg|gif|svg|ico|woff2?|ttf|eot|map|webp|avif)$/i.test(e.path)) return false;
265
+ if (e.path.startsWith("/api/")) return false;
266
+ if (e.path.startsWith("/_vinext/") || e.path.startsWith("/_next/")) return false;
267
+ if (e.path.endsWith(".rsc")) return false;
268
+ return true;
269
+ });
352
270
  }
353
- // ─── Route Selection ─────────────────────────────────────────────────────────
354
271
  /**
355
- * Walk the ranked traffic list, accumulating request counts until the
356
- * coverage target is met or the hard cap is reached.
357
- */
358
- export function selectRoutes(traffic, coverageTarget, limit) {
359
- const totalRequests = traffic.reduce((sum, e) => sum + e.requests, 0);
360
- if (totalRequests === 0) {
361
- return { routes: [], totalRequests: 0, coveredRequests: 0, coveragePercent: 0 };
362
- }
363
- const target = totalRequests * (coverageTarget / 100);
364
- const selected = [];
365
- let accumulated = 0;
366
- // Traffic is already sorted DESC by requests from the GraphQL query
367
- for (const entry of traffic) {
368
- if (accumulated >= target || selected.length >= limit)
369
- break;
370
- selected.push(entry);
371
- accumulated += entry.requests;
372
- }
373
- return {
374
- routes: selected,
375
- totalRequests,
376
- coveredRequests: accumulated,
377
- coveragePercent: (accumulated / totalRequests) * 100,
378
- };
272
+ * Walk the ranked traffic list, accumulating request counts until the
273
+ * coverage target is met or the hard cap is reached.
274
+ */
275
+ function selectRoutes(traffic, coverageTarget, limit) {
276
+ const totalRequests = traffic.reduce((sum, e) => sum + e.requests, 0);
277
+ if (totalRequests === 0) return {
278
+ routes: [],
279
+ totalRequests: 0,
280
+ coveredRequests: 0,
281
+ coveragePercent: 0
282
+ };
283
+ const target = totalRequests * (coverageTarget / 100);
284
+ const selected = [];
285
+ let accumulated = 0;
286
+ for (const entry of traffic) {
287
+ if (accumulated >= target || selected.length >= limit) break;
288
+ selected.push(entry);
289
+ accumulated += entry.requests;
290
+ }
291
+ return {
292
+ routes: selected,
293
+ totalRequests,
294
+ coveredRequests: accumulated,
295
+ coveragePercent: accumulated / totalRequests * 100
296
+ };
379
297
  }
380
- // ─── Pre-rendering ───────────────────────────────────────────────────────────
381
298
  /** Pre-render port — high number to avoid collisions with dev servers. */
382
299
  const PRERENDER_PORT = 19384;
383
300
  /** Max time to wait for the local server to start (ms). */
384
- const SERVER_STARTUP_TIMEOUT = 30_000;
301
+ const SERVER_STARTUP_TIMEOUT = 3e4;
385
302
  /** Max concurrent fetch requests during pre-rendering. */
386
303
  const FETCH_CONCURRENCY = 10;
387
304
  /**
388
- * Start a local production server, fetch each route to produce HTML,
389
- * and return the results. Pages that fail to render are skipped.
390
- */
305
+ * Start a local production server, fetch each route to produce HTML,
306
+ * and return the results. Pages that fail to render are skipped.
307
+ */
391
308
  async function prerenderRoutes(routes, root, hostDomain) {
392
- const results = new Map();
393
- let failedCount = 0;
394
- const port = PRERENDER_PORT;
395
- // Verify dist/ exists
396
- const distDir = path.join(root, "dist");
397
- if (!fs.existsSync(distDir)) {
398
- console.log(" TPR: Skipping pre-render — dist/ directory not found");
399
- return results;
400
- }
401
- // Start the local production server as a subprocess
402
- const serverProcess = startLocalServer(root, port);
403
- try {
404
- await waitForServer(port, SERVER_STARTUP_TIMEOUT);
405
- // Fetch routes in batches to limit concurrency
406
- for (let i = 0; i < routes.length; i += FETCH_CONCURRENCY) {
407
- const batch = routes.slice(i, i + FETCH_CONCURRENCY);
408
- const promises = batch.map(async (routePath) => {
409
- try {
410
- const response = await fetch(`http://127.0.0.1:${port}${routePath}`, {
411
- headers: {
412
- "User-Agent": "vinext-tpr/1.0",
413
- ...(hostDomain ? { Host: hostDomain } : {}),
414
- },
415
- redirect: "manual", // Don't follow redirects — cache the redirect itself
416
- });
417
- // Only cache successful responses (2xx and 3xx)
418
- if (response.status < 400) {
419
- const html = await response.text();
420
- const headers = {};
421
- response.headers.forEach((value, key) => {
422
- // Only keep relevant headers
423
- if (key === "content-type" ||
424
- key === "cache-control" ||
425
- key === "x-vinext-revalidate" ||
426
- key === "location") {
427
- headers[key] = value;
428
- }
429
- });
430
- results.set(routePath, {
431
- html,
432
- status: response.status,
433
- headers,
434
- });
435
- }
436
- }
437
- catch {
438
- // Skip pages that fail to render — they may depend on
439
- // request-specific data (cookies, headers, auth) that
440
- // isn't available during pre-rendering.
441
- failedCount++;
442
- }
443
- });
444
- await Promise.all(promises);
445
- }
446
- if (failedCount > 0) {
447
- console.log(` TPR: ${failedCount} page(s) failed to pre-render (skipped)`);
448
- }
449
- }
450
- finally {
451
- serverProcess.kill("SIGTERM");
452
- // Give it a moment to clean up
453
- await new Promise((resolve) => {
454
- serverProcess.on("exit", resolve);
455
- setTimeout(resolve, 2000);
456
- });
457
- }
458
- return results;
309
+ const results = /* @__PURE__ */ new Map();
310
+ let failedCount = 0;
311
+ const port = PRERENDER_PORT;
312
+ const distDir = path.join(root, "dist");
313
+ if (!fs.existsSync(distDir)) {
314
+ console.log(" TPR: Skipping pre-render — dist/ directory not found");
315
+ return results;
316
+ }
317
+ const serverProcess = startLocalServer(root, port);
318
+ try {
319
+ await waitForServer(port, SERVER_STARTUP_TIMEOUT);
320
+ for (let i = 0; i < routes.length; i += FETCH_CONCURRENCY) {
321
+ const promises = routes.slice(i, i + FETCH_CONCURRENCY).map(async (routePath) => {
322
+ try {
323
+ const response = await fetch(`http://127.0.0.1:${port}${routePath}`, {
324
+ headers: {
325
+ "User-Agent": "vinext-tpr/1.0",
326
+ ...hostDomain ? { Host: hostDomain } : {}
327
+ },
328
+ redirect: "manual"
329
+ });
330
+ if (response.status < 400) {
331
+ const html = await response.text();
332
+ const headers = {};
333
+ response.headers.forEach((value, key) => {
334
+ if (key === "content-type" || key === "cache-control" || key === "x-vinext-revalidate" || key === "location") headers[key] = value;
335
+ });
336
+ results.set(routePath, {
337
+ html,
338
+ status: response.status,
339
+ headers
340
+ });
341
+ }
342
+ } catch {
343
+ failedCount++;
344
+ }
345
+ });
346
+ await Promise.all(promises);
347
+ }
348
+ if (failedCount > 0) console.log(` TPR: ${failedCount} page(s) failed to pre-render (skipped)`);
349
+ } finally {
350
+ serverProcess.kill("SIGTERM");
351
+ await new Promise((resolve) => {
352
+ serverProcess.on("exit", resolve);
353
+ setTimeout(resolve, 2e3);
354
+ });
355
+ }
356
+ return results;
459
357
  }
460
358
  /**
461
- * Spawn a subprocess running the vinext production server.
462
- * Uses the same Node.js binary and resolves prod-server.js relative
463
- * to the current module (works whether vinext is installed or linked).
464
- */
359
+ * Spawn a subprocess running the vinext production server.
360
+ * Uses the same Node.js binary and resolves prod-server.js relative
361
+ * to the current module (works whether vinext is installed or linked).
362
+ */
465
363
  function startLocalServer(root, port) {
466
- const thisDir = fileURLToPath(new URL(".", import.meta.url));
467
- const prodServerPath = path.resolve(thisDir, "..", "server", "prod-server.js");
468
- const outDir = path.join(root, "dist");
469
- // Escape backslashes for Windows paths inside the JS string
470
- const escapedProdServer = prodServerPath.replace(/\\/g, "\\\\");
471
- const escapedOutDir = outDir.replace(/\\/g, "\\\\");
472
- const script = [
473
- `import("file://${escapedProdServer}")`,
474
- `.then(m => m.startProdServer({ port: ${port}, host: "127.0.0.1", outDir: "${escapedOutDir}" }))`,
475
- `.catch(e => { console.error("[vinext-tpr] Server failed to start:", e); process.exit(1); });`,
476
- ].join("");
477
- const proc = spawn(process.execPath, ["--input-type=module", "-e", script], {
478
- cwd: root,
479
- stdio: "pipe",
480
- env: { ...process.env, NODE_ENV: "production" },
481
- });
482
- // Forward server errors to the parent's stderr for debugging
483
- proc.stderr?.on("data", (chunk) => {
484
- const msg = chunk.toString().trim();
485
- if (msg)
486
- console.error(` [tpr-server] ${msg}`);
487
- });
488
- return proc;
364
+ const thisDir = fileURLToPath(new URL(".", import.meta.url));
365
+ const prodServerPath = path.resolve(thisDir, "..", "server", "prod-server.js");
366
+ const outDir = path.join(root, "dist");
367
+ const escapedProdServer = prodServerPath.replace(/\\/g, "\\\\");
368
+ const escapedOutDir = outDir.replace(/\\/g, "\\\\");
369
+ const script = [
370
+ `import("file://${escapedProdServer}")`,
371
+ `.then(m => m.startProdServer({ port: ${port}, host: "127.0.0.1", outDir: "${escapedOutDir}" }))`,
372
+ `.catch(e => { console.error("[vinext-tpr] Server failed to start:", e); process.exit(1); });`
373
+ ].join("");
374
+ const proc = spawn(process.execPath, [
375
+ "--input-type=module",
376
+ "-e",
377
+ script
378
+ ], {
379
+ cwd: root,
380
+ stdio: "pipe",
381
+ env: {
382
+ ...process.env,
383
+ NODE_ENV: "production"
384
+ }
385
+ });
386
+ proc.stderr?.on("data", (chunk) => {
387
+ const msg = chunk.toString().trim();
388
+ if (msg) console.error(` [tpr-server] ${msg}`);
389
+ });
390
+ return proc;
489
391
  }
490
392
  /** Poll the local server until it responds or the timeout is reached. */
491
393
  async function waitForServer(port, timeoutMs) {
492
- const start = Date.now();
493
- while (Date.now() - start < timeoutMs) {
494
- try {
495
- const controller = new AbortController();
496
- const timer = setTimeout(() => controller.abort(), 2000);
497
- const response = await fetch(`http://127.0.0.1:${port}/`, {
498
- redirect: "manual",
499
- signal: controller.signal,
500
- });
501
- clearTimeout(timer);
502
- // Any response means the server is up
503
- await response.text(); // consume body
504
- return;
505
- }
506
- catch {
507
- await new Promise((r) => setTimeout(r, 300));
508
- }
509
- }
510
- throw new Error(`Local production server failed to start within ${timeoutMs / 1000}s`);
394
+ const start = Date.now();
395
+ while (Date.now() - start < timeoutMs) try {
396
+ const controller = new AbortController();
397
+ const timer = setTimeout(() => controller.abort(), 2e3);
398
+ const response = await fetch(`http://127.0.0.1:${port}/`, {
399
+ redirect: "manual",
400
+ signal: controller.signal
401
+ });
402
+ clearTimeout(timer);
403
+ await response.text();
404
+ return;
405
+ } catch {
406
+ await new Promise((r) => setTimeout(r, 300));
407
+ }
408
+ throw new Error(`Local production server failed to start within ${timeoutMs / 1e3}s`);
511
409
  }
512
- // ─── KV Upload ───────────────────────────────────────────────────────────────
513
410
  /**
514
- * Upload pre-rendered pages to KV using the Cloudflare REST API.
515
- * Writes in the same KVCacheEntry format that KVCacheHandler reads
516
- * at runtime, so ISR serves these entries without any code changes.
517
- */
411
+ * Upload pre-rendered pages to KV using the Cloudflare REST API.
412
+ * Writes in the same KVCacheEntry format that KVCacheHandler reads
413
+ * at runtime, so ISR serves these entries without any code changes.
414
+ */
518
415
  async function uploadToKV(entries, namespaceId, accountId, apiToken, defaultRevalidateSeconds) {
519
- const now = Date.now();
520
- // Build the bulk write payload
521
- const pairs = [];
522
- for (const [routePath, result] of entries) {
523
- // Determine revalidation window use the page's revalidate header
524
- // if present, otherwise fall back to the default
525
- const revalidateHeader = result.headers["x-vinext-revalidate"];
526
- const revalidateSeconds = revalidateHeader && !isNaN(Number(revalidateHeader))
527
- ? Number(revalidateHeader)
528
- : defaultRevalidateSeconds;
529
- const revalidateAt = revalidateSeconds > 0 ? now + revalidateSeconds * 1000 : null;
530
- // KV TTL: 10x the revalidation period, clamped to [60s, 30d]
531
- // (matches the logic in KVCacheHandler.set)
532
- const kvTtl = revalidateSeconds > 0
533
- ? Math.max(Math.min(revalidateSeconds * 10, 30 * 24 * 3600), 60)
534
- : 24 * 3600; // 24h fallback if no revalidation
535
- const entry = {
536
- value: {
537
- kind: "APP_PAGE",
538
- html: result.html,
539
- headers: result.headers,
540
- status: result.status,
541
- },
542
- tags: [],
543
- lastModified: now,
544
- revalidateAt,
545
- };
546
- pairs.push({
547
- key: `cache:${routePath}`,
548
- value: JSON.stringify(entry),
549
- expiration_ttl: kvTtl,
550
- });
551
- }
552
- // Upload in batches (KV bulk API accepts up to 10,000 per request)
553
- const BATCH_SIZE = 10_000;
554
- for (let i = 0; i < pairs.length; i += BATCH_SIZE) {
555
- const batch = pairs.slice(i, i + BATCH_SIZE);
556
- const response = await fetch(`https://api.cloudflare.com/client/v4/accounts/${accountId}/storage/kv/namespaces/${namespaceId}/bulk`, {
557
- method: "PUT",
558
- headers: {
559
- Authorization: `Bearer ${apiToken}`,
560
- "Content-Type": "application/json",
561
- },
562
- body: JSON.stringify(batch),
563
- });
564
- if (!response.ok) {
565
- const text = await response.text();
566
- throw new Error(`KV bulk upload failed (batch ${Math.floor(i / BATCH_SIZE) + 1}): ${response.status} — ${text}`);
567
- }
568
- }
416
+ const now = Date.now();
417
+ const pairs = [];
418
+ for (const [routePath, result] of entries) {
419
+ const revalidateHeader = result.headers["x-vinext-revalidate"];
420
+ const revalidateSeconds = revalidateHeader && !isNaN(Number(revalidateHeader)) ? Number(revalidateHeader) : defaultRevalidateSeconds;
421
+ const revalidateAt = revalidateSeconds > 0 ? now + revalidateSeconds * 1e3 : null;
422
+ const kvTtl = revalidateSeconds > 0 ? Math.max(Math.min(revalidateSeconds * 10, 720 * 3600), 60) : 24 * 3600;
423
+ const entry = {
424
+ value: {
425
+ kind: "APP_PAGE",
426
+ html: result.html,
427
+ headers: result.headers,
428
+ status: result.status
429
+ },
430
+ tags: [],
431
+ lastModified: now,
432
+ revalidateAt
433
+ };
434
+ pairs.push({
435
+ key: `cache:${routePath}`,
436
+ value: JSON.stringify(entry),
437
+ expiration_ttl: kvTtl
438
+ });
439
+ }
440
+ const BATCH_SIZE = 1e4;
441
+ for (let i = 0; i < pairs.length; i += BATCH_SIZE) {
442
+ const batch = pairs.slice(i, i + BATCH_SIZE);
443
+ const response = await fetch(`https://api.cloudflare.com/client/v4/accounts/${accountId}/storage/kv/namespaces/${namespaceId}/bulk`, {
444
+ method: "PUT",
445
+ headers: {
446
+ Authorization: `Bearer ${apiToken}`,
447
+ "Content-Type": "application/json"
448
+ },
449
+ body: JSON.stringify(batch)
450
+ });
451
+ if (!response.ok) {
452
+ const text = await response.text();
453
+ throw new Error(`KV bulk upload failed (batch ${Math.floor(i / BATCH_SIZE) + 1}): ${response.status} — ${text}`);
454
+ }
455
+ }
569
456
  }
570
- // ─── Main Entry ──────────────────────────────────────────────────────────────
571
457
  /** Default revalidation TTL for pre-rendered pages (1 hour). */
572
458
  const DEFAULT_REVALIDATE_SECONDS = 3600;
573
459
  /**
574
- * Run the TPR pipeline: query traffic, select routes, pre-render, upload.
575
- *
576
- * Designed to be called between the build step and wrangler deploy in
577
- * the `vinext deploy` pipeline. Gracefully skips (never errors) when
578
- * the prerequisites aren't met.
579
- */
580
- export async function runTPR(options) {
581
- const startTime = Date.now();
582
- const { root, coverage, limit, window: windowHours } = options;
583
- const skip = (reason) => ({
584
- totalPaths: 0,
585
- prerenderedCount: 0,
586
- coverageAchieved: 0,
587
- durationMs: Date.now() - startTime,
588
- skipped: reason,
589
- });
590
- // ── 1. Check for API token ────────────────────────────────────
591
- const apiToken = process.env.CLOUDFLARE_API_TOKEN;
592
- if (!apiToken) {
593
- return skip("no CLOUDFLARE_API_TOKEN set");
594
- }
595
- // ── 2. Parse wrangler config ──────────────────────────────────
596
- const wranglerConfig = parseWranglerConfig(root);
597
- if (!wranglerConfig) {
598
- return skip("could not parse wrangler config");
599
- }
600
- // ── 3. Check for custom domain ────────────────────────────────
601
- if (!wranglerConfig.customDomain) {
602
- return skip("no custom domain — zone analytics unavailable");
603
- }
604
- // ── 4. Check for KV namespace ─────────────────────────────────
605
- if (!wranglerConfig.kvNamespaceId) {
606
- return skip("no VINEXT_CACHE KV namespace configured");
607
- }
608
- // ── 5. Resolve account ID ─────────────────────────────────────
609
- const accountId = wranglerConfig.accountId ?? (await resolveAccountId(apiToken));
610
- if (!accountId) {
611
- return skip("could not resolve Cloudflare account ID");
612
- }
613
- // ── 6. Resolve zone ID ────────────────────────────────────────
614
- console.log(` TPR: Analyzing traffic for ${wranglerConfig.customDomain} (last ${windowHours}h)`);
615
- const zoneId = await resolveZoneId(wranglerConfig.customDomain, apiToken);
616
- if (!zoneId) {
617
- return skip(`could not resolve zone for ${wranglerConfig.customDomain}`);
618
- }
619
- // ── 7. Query traffic data ─────────────────────────────────────
620
- let traffic;
621
- try {
622
- traffic = await queryTraffic(zoneId, apiToken, windowHours);
623
- }
624
- catch (err) {
625
- return skip(`analytics query failed: ${err instanceof Error ? err.message : String(err)}`);
626
- }
627
- if (traffic.length === 0) {
628
- return skip("no traffic data available (first deploy?)");
629
- }
630
- // ── 8. Select routes by coverage ──────────────────────────────
631
- const selection = selectRoutes(traffic, coverage, limit);
632
- console.log(` TPR: ${traffic.length.toLocaleString()} unique paths — ` +
633
- `${selection.routes.length} pages cover ${Math.round(selection.coveragePercent)}% of traffic`);
634
- if (selection.routes.length === 0) {
635
- return {
636
- totalPaths: traffic.length,
637
- prerenderedCount: 0,
638
- coverageAchieved: 0,
639
- durationMs: Date.now() - startTime,
640
- skipped: "no pre-renderable routes after filtering",
641
- };
642
- }
643
- // ── 9. Pre-render selected routes ─────────────────────────────
644
- console.log(` TPR: Pre-rendering ${selection.routes.length} pages...`);
645
- const routePaths = selection.routes.map((r) => r.path);
646
- let rendered;
647
- try {
648
- rendered = await prerenderRoutes(routePaths, root, wranglerConfig.customDomain);
649
- }
650
- catch (err) {
651
- return skip(`pre-rendering failed: ${err instanceof Error ? err.message : String(err)}`);
652
- }
653
- if (rendered.size === 0) {
654
- return {
655
- totalPaths: traffic.length,
656
- prerenderedCount: 0,
657
- coverageAchieved: selection.coveragePercent,
658
- durationMs: Date.now() - startTime,
659
- skipped: "all pages failed to pre-render (request-dependent?)",
660
- };
661
- }
662
- // ── 10. Upload to KV ──────────────────────────────────────────
663
- try {
664
- await uploadToKV(rendered, wranglerConfig.kvNamespaceId, accountId, apiToken, DEFAULT_REVALIDATE_SECONDS);
665
- }
666
- catch (err) {
667
- return skip(`KV upload failed: ${err instanceof Error ? err.message : String(err)}`);
668
- }
669
- const durationMs = Date.now() - startTime;
670
- console.log(` TPR: Pre-rendered ${rendered.size} pages in ${(durationMs / 1000).toFixed(1)}s → KV cache`);
671
- return {
672
- totalPaths: traffic.length,
673
- prerenderedCount: rendered.size,
674
- coverageAchieved: selection.coveragePercent,
675
- durationMs,
676
- };
460
+ * Run the TPR pipeline: query traffic, select routes, pre-render, upload.
461
+ *
462
+ * Designed to be called between the build step and wrangler deploy in
463
+ * the `vinext deploy` pipeline. Gracefully skips (never errors) when
464
+ * the prerequisites aren't met.
465
+ */
466
+ async function runTPR(options) {
467
+ const startTime = Date.now();
468
+ const { root, coverage, limit, window: windowHours } = options;
469
+ const skip = (reason) => ({
470
+ totalPaths: 0,
471
+ prerenderedCount: 0,
472
+ coverageAchieved: 0,
473
+ durationMs: Date.now() - startTime,
474
+ skipped: reason
475
+ });
476
+ const apiToken = process.env.CLOUDFLARE_API_TOKEN;
477
+ if (!apiToken) return skip("no CLOUDFLARE_API_TOKEN set");
478
+ const wranglerConfig = parseWranglerConfig(root);
479
+ if (!wranglerConfig) return skip("could not parse wrangler config");
480
+ if (!wranglerConfig.customDomain) return skip("no custom domain — zone analytics unavailable");
481
+ if (!wranglerConfig.kvNamespaceId) return skip("no VINEXT_CACHE KV namespace configured");
482
+ const accountId = wranglerConfig.accountId ?? await resolveAccountId(apiToken);
483
+ if (!accountId) return skip("could not resolve Cloudflare account ID");
484
+ console.log(` TPR: Analyzing traffic for ${wranglerConfig.customDomain} (last ${windowHours}h)`);
485
+ const zoneId = await resolveZoneId(wranglerConfig.customDomain, apiToken);
486
+ if (!zoneId) return skip(`could not resolve zone for ${wranglerConfig.customDomain}`);
487
+ let traffic;
488
+ try {
489
+ traffic = await queryTraffic(zoneId, apiToken, windowHours);
490
+ } catch (err) {
491
+ return skip(`analytics query failed: ${err instanceof Error ? err.message : String(err)}`);
492
+ }
493
+ if (traffic.length === 0) return skip("no traffic data available (first deploy?)");
494
+ const selection = selectRoutes(traffic, coverage, limit);
495
+ console.log(` TPR: ${traffic.length.toLocaleString()} unique paths — ${selection.routes.length} pages cover ${Math.round(selection.coveragePercent)}% of traffic`);
496
+ if (selection.routes.length === 0) return {
497
+ totalPaths: traffic.length,
498
+ prerenderedCount: 0,
499
+ coverageAchieved: 0,
500
+ durationMs: Date.now() - startTime,
501
+ skipped: "no pre-renderable routes after filtering"
502
+ };
503
+ console.log(` TPR: Pre-rendering ${selection.routes.length} pages...`);
504
+ const routePaths = selection.routes.map((r) => r.path);
505
+ let rendered;
506
+ try {
507
+ rendered = await prerenderRoutes(routePaths, root, wranglerConfig.customDomain);
508
+ } catch (err) {
509
+ return skip(`pre-rendering failed: ${err instanceof Error ? err.message : String(err)}`);
510
+ }
511
+ if (rendered.size === 0) return {
512
+ totalPaths: traffic.length,
513
+ prerenderedCount: 0,
514
+ coverageAchieved: selection.coveragePercent,
515
+ durationMs: Date.now() - startTime,
516
+ skipped: "all pages failed to pre-render (request-dependent?)"
517
+ };
518
+ try {
519
+ await uploadToKV(rendered, wranglerConfig.kvNamespaceId, accountId, apiToken, DEFAULT_REVALIDATE_SECONDS);
520
+ } catch (err) {
521
+ return skip(`KV upload failed: ${err instanceof Error ? err.message : String(err)}`);
522
+ }
523
+ const durationMs = Date.now() - startTime;
524
+ console.log(` TPR: Pre-rendered ${rendered.size} pages in ${(durationMs / 1e3).toFixed(1)}s → KV cache`);
525
+ return {
526
+ totalPaths: traffic.length,
527
+ prerenderedCount: rendered.size,
528
+ coverageAchieved: selection.coveragePercent,
529
+ durationMs
530
+ };
677
531
  }
532
+ //#endregion
533
+ export { domainCandidates, parseWranglerConfig, runTPR, selectRoutes };
534
+
678
535
  //# sourceMappingURL=tpr.js.map