@jasonshimmy/vite-plugin-cer-app 0.23.1 → 0.24.0

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 (397) hide show
  1. package/dist/cli/checks/lighthouse.d.ts +26 -0
  2. package/dist/cli/checks/lighthouse.d.ts.map +1 -0
  3. package/dist/cli/checks/lighthouse.js +121 -0
  4. package/dist/cli/checks/lighthouse.js.map +1 -0
  5. package/dist/cli/checks/links.d.ts +12 -0
  6. package/dist/cli/checks/links.d.ts.map +1 -0
  7. package/dist/cli/checks/links.js +89 -0
  8. package/dist/cli/checks/links.js.map +1 -0
  9. package/dist/cli/checks/performance.d.ts +17 -0
  10. package/dist/cli/checks/performance.d.ts.map +1 -0
  11. package/dist/cli/checks/performance.js +61 -0
  12. package/dist/cli/checks/performance.js.map +1 -0
  13. package/dist/cli/commands/check.d.ts +3 -0
  14. package/dist/cli/commands/check.d.ts.map +1 -0
  15. package/dist/cli/commands/check.js +85 -0
  16. package/dist/cli/commands/check.js.map +1 -0
  17. package/dist/cli/commands/preview.d.ts.map +1 -1
  18. package/dist/cli/commands/preview.js +37 -4
  19. package/dist/cli/commands/preview.js.map +1 -1
  20. package/dist/cli/create/index.d.ts +11 -1
  21. package/dist/cli/create/index.d.ts.map +1 -1
  22. package/dist/cli/create/index.js +135 -65
  23. package/dist/cli/create/index.js.map +1 -1
  24. package/dist/cli/create/templates/spa/package.json.tpl +5 -3
  25. package/dist/cli/create/templates/ssg/cer.config.ts.tpl +2 -0
  26. package/dist/cli/create/templates/ssg/package.json.tpl +5 -3
  27. package/dist/cli/create/templates/ssr/package.json.tpl +5 -3
  28. package/dist/cli/index.js +2 -0
  29. package/dist/cli/index.js.map +1 -1
  30. package/dist/index.d.ts +3 -1
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/plugin/build-ssg.d.ts +22 -4
  33. package/dist/plugin/build-ssg.d.ts.map +1 -1
  34. package/dist/plugin/build-ssg.js +273 -13
  35. package/dist/plugin/build-ssg.js.map +1 -1
  36. package/dist/plugin/content/parser.d.ts.map +1 -1
  37. package/dist/plugin/content/parser.js +54 -10
  38. package/dist/plugin/content/parser.js.map +1 -1
  39. package/dist/plugin/dev-server.d.ts +6 -1
  40. package/dist/plugin/dev-server.d.ts.map +1 -1
  41. package/dist/plugin/dev-server.js.map +1 -1
  42. package/dist/plugin/dts-generator.d.ts.map +1 -1
  43. package/dist/plugin/dts-generator.js +50 -8
  44. package/dist/plugin/dts-generator.js.map +1 -1
  45. package/dist/plugin/generated-dir.d.ts +2 -0
  46. package/dist/plugin/generated-dir.d.ts.map +1 -1
  47. package/dist/plugin/generated-dir.js +17 -6
  48. package/dist/plugin/generated-dir.js.map +1 -1
  49. package/dist/plugin/html-post-process.d.ts +35 -0
  50. package/dist/plugin/html-post-process.d.ts.map +1 -0
  51. package/dist/plugin/html-post-process.js +112 -0
  52. package/dist/plugin/html-post-process.js.map +1 -0
  53. package/dist/plugin/index.d.ts +9 -0
  54. package/dist/plugin/index.d.ts.map +1 -1
  55. package/dist/plugin/index.js +89 -14
  56. package/dist/plugin/index.js.map +1 -1
  57. package/dist/plugin/transforms/auto-import.d.ts.map +1 -1
  58. package/dist/plugin/transforms/auto-import.js +7 -0
  59. package/dist/plugin/transforms/auto-import.js.map +1 -1
  60. package/dist/plugin/transforms/prune-runtime-css.d.ts +8 -0
  61. package/dist/plugin/transforms/prune-runtime-css.d.ts.map +1 -0
  62. package/dist/plugin/transforms/prune-runtime-css.js +40 -0
  63. package/dist/plugin/transforms/prune-runtime-css.js.map +1 -0
  64. package/dist/runtime/app-template.d.ts +1 -4
  65. package/dist/runtime/app-template.d.ts.map +1 -1
  66. package/dist/runtime/app-template.js +211 -40
  67. package/dist/runtime/app-template.js.map +1 -1
  68. package/dist/runtime/composables/index.d.ts +4 -0
  69. package/dist/runtime/composables/index.d.ts.map +1 -1
  70. package/dist/runtime/composables/index.js +2 -0
  71. package/dist/runtime/composables/index.js.map +1 -1
  72. package/dist/runtime/composables/use-active-headings.d.ts +24 -0
  73. package/dist/runtime/composables/use-active-headings.d.ts.map +1 -0
  74. package/dist/runtime/composables/use-active-headings.js +112 -0
  75. package/dist/runtime/composables/use-active-headings.js.map +1 -0
  76. package/dist/runtime/composables/use-content-page.d.ts +45 -0
  77. package/dist/runtime/composables/use-content-page.d.ts.map +1 -0
  78. package/dist/runtime/composables/use-content-page.js +179 -0
  79. package/dist/runtime/composables/use-content-page.js.map +1 -0
  80. package/dist/runtime/composables/use-content-search.d.ts.map +1 -1
  81. package/dist/runtime/composables/use-content-search.js +1 -5
  82. package/dist/runtime/composables/use-content-search.js.map +1 -1
  83. package/dist/runtime/composables/use-fetch.d.ts +2 -1
  84. package/dist/runtime/composables/use-fetch.d.ts.map +1 -1
  85. package/dist/runtime/composables/use-fetch.js +112 -43
  86. package/dist/runtime/composables/use-fetch.js.map +1 -1
  87. package/dist/runtime/composables/use-head.d.ts.map +1 -1
  88. package/dist/runtime/composables/use-head.js +30 -6
  89. package/dist/runtime/composables/use-head.js.map +1 -1
  90. package/dist/runtime/composables/use-route.d.ts.map +1 -1
  91. package/dist/runtime/composables/use-route.js +39 -11
  92. package/dist/runtime/composables/use-route.js.map +1 -1
  93. package/dist/runtime/content/client.js +2 -2
  94. package/dist/runtime/content/client.js.map +1 -1
  95. package/dist/runtime/entry-server-template.d.ts +16 -1
  96. package/dist/runtime/entry-server-template.d.ts.map +1 -1
  97. package/dist/runtime/entry-server-template.js +120 -13
  98. package/dist/runtime/entry-server-template.js.map +1 -1
  99. package/dist/types/config.d.ts +53 -4
  100. package/dist/types/config.d.ts.map +1 -1
  101. package/dist/types/config.js.map +1 -1
  102. package/dist/types/middleware.d.ts +2 -2
  103. package/dist/types/middleware.d.ts.map +1 -1
  104. package/package.json +22 -19
  105. package/.github/copilot-instructions.md +0 -169
  106. package/.github/workflows/publish.yml +0 -257
  107. package/.nvmrc +0 -1
  108. package/CHANGELOG.md +0 -232
  109. package/CLAUDE.md +0 -113
  110. package/commits.txt +0 -1
  111. package/cypress.config.ts +0 -16
  112. package/docs/authentication.md +0 -285
  113. package/docs/cli.md +0 -324
  114. package/docs/components.md +0 -237
  115. package/docs/composables.md +0 -907
  116. package/docs/configuration.md +0 -667
  117. package/docs/content.md +0 -570
  118. package/docs/data-loading.md +0 -336
  119. package/docs/getting-started.md +0 -237
  120. package/docs/head-management.md +0 -212
  121. package/docs/i18n.md +0 -159
  122. package/docs/layouts.md +0 -224
  123. package/docs/middleware.md +0 -234
  124. package/docs/plugins.md +0 -170
  125. package/docs/rendering-modes.md +0 -377
  126. package/docs/routing.md +0 -485
  127. package/docs/server-api.md +0 -253
  128. package/docs/testing.md +0 -455
  129. package/docs/use-fetch.md +0 -183
  130. package/e2e/cypress/e2e/api.cy.ts +0 -123
  131. package/e2e/cypress/e2e/async-component.cy.ts +0 -27
  132. package/e2e/cypress/e2e/component-splitting.cy.ts +0 -50
  133. package/e2e/cypress/e2e/content.cy.ts +0 -425
  134. package/e2e/cypress/e2e/cookie.cy.ts +0 -85
  135. package/e2e/cypress/e2e/data.cy.ts +0 -158
  136. package/e2e/cypress/e2e/error-boundary.cy.ts +0 -88
  137. package/e2e/cypress/e2e/fouc.cy.ts +0 -254
  138. package/e2e/cypress/e2e/group-meta.cy.ts +0 -36
  139. package/e2e/cypress/e2e/head.cy.ts +0 -89
  140. package/e2e/cypress/e2e/i18n.cy.ts +0 -79
  141. package/e2e/cypress/e2e/interactive.cy.ts +0 -137
  142. package/e2e/cypress/e2e/isr-nested-runtime.cy.ts +0 -102
  143. package/e2e/cypress/e2e/jit-css-custom-colors.cy.ts +0 -43
  144. package/e2e/cypress/e2e/middleware-chain.cy.ts +0 -89
  145. package/e2e/cypress/e2e/middleware-status.cy.ts +0 -30
  146. package/e2e/cypress/e2e/middleware.cy.ts +0 -45
  147. package/e2e/cypress/e2e/navigate.cy.ts +0 -39
  148. package/e2e/cypress/e2e/observability.cy.ts +0 -77
  149. package/e2e/cypress/e2e/per-route-error.cy.ts +0 -42
  150. package/e2e/cypress/e2e/per-route-render.cy.ts +0 -70
  151. package/e2e/cypress/e2e/preview-hardening.cy.ts +0 -88
  152. package/e2e/cypress/e2e/routes.cy.ts +0 -128
  153. package/e2e/cypress/e2e/seo-meta.cy.ts +0 -108
  154. package/e2e/cypress/e2e/server-middleware.cy.ts +0 -46
  155. package/e2e/cypress/e2e/session-rotation.cy.ts +0 -25
  156. package/e2e/cypress/e2e/session.cy.ts +0 -73
  157. package/e2e/cypress/e2e/ssr-render-error.cy.ts +0 -68
  158. package/e2e/cypress/e2e/synthetic-404.cy.ts +0 -45
  159. package/e2e/cypress/e2e/use-page-data.cy.ts +0 -122
  160. package/e2e/cypress/e2e/use-state.cy.ts +0 -138
  161. package/e2e/cypress/support/commands.ts +0 -120
  162. package/e2e/cypress/support/e2e.ts +0 -10
  163. package/e2e/cypress/tsconfig.json +0 -14
  164. package/e2e/kitchen-sink/app/components/ks-badge.ts +0 -8
  165. package/e2e/kitchen-sink/app/composables/useKsCounter.ts +0 -9
  166. package/e2e/kitchen-sink/app/error.ts +0 -18
  167. package/e2e/kitchen-sink/app/layouts/admin.ts +0 -13
  168. package/e2e/kitchen-sink/app/layouts/default.ts +0 -25
  169. package/e2e/kitchen-sink/app/layouts/group.ts +0 -9
  170. package/e2e/kitchen-sink/app/layouts/minimal.ts +0 -7
  171. package/e2e/kitchen-sink/app/loading.ts +0 -9
  172. package/e2e/kitchen-sink/app/middleware/auth.ts +0 -9
  173. package/e2e/kitchen-sink/app/middleware/custom-log.ts +0 -4
  174. package/e2e/kitchen-sink/app/middleware/group-auth.ts +0 -7
  175. package/e2e/kitchen-sink/app/middleware/logger.ts +0 -14
  176. package/e2e/kitchen-sink/app/pages/(auth)/login.ts +0 -13
  177. package/e2e/kitchen-sink/app/pages/(auth)/protected.ts +0 -16
  178. package/e2e/kitchen-sink/app/pages/404.ts +0 -9
  179. package/e2e/kitchen-sink/app/pages/about.ts +0 -17
  180. package/e2e/kitchen-sink/app/pages/admin/_layout.ts +0 -1
  181. package/e2e/kitchen-sink/app/pages/admin/dashboard.ts +0 -11
  182. package/e2e/kitchen-sink/app/pages/async-component-error-test.ts +0 -18
  183. package/e2e/kitchen-sink/app/pages/async-component-test.ts +0 -18
  184. package/e2e/kitchen-sink/app/pages/blog/[slug].ts +0 -59
  185. package/e2e/kitchen-sink/app/pages/blog/index.ts +0 -51
  186. package/e2e/kitchen-sink/app/pages/content-blog.ts +0 -37
  187. package/e2e/kitchen-sink/app/pages/content-doc.ts +0 -42
  188. package/e2e/kitchen-sink/app/pages/content-fallback.ts +0 -36
  189. package/e2e/kitchen-sink/app/pages/content-guides.ts +0 -35
  190. package/e2e/kitchen-sink/app/pages/content-index.ts +0 -39
  191. package/e2e/kitchen-sink/app/pages/content-search.ts +0 -36
  192. package/e2e/kitchen-sink/app/pages/cookie-test.ts +0 -22
  193. package/e2e/kitchen-sink/app/pages/counter.ts +0 -17
  194. package/e2e/kitchen-sink/app/pages/group-auth-blocked.ts +0 -9
  195. package/e2e/kitchen-sink/app/pages/group-meta-test/_layout.ts +0 -6
  196. package/e2e/kitchen-sink/app/pages/group-meta-test/custom-mw.ts +0 -14
  197. package/e2e/kitchen-sink/app/pages/group-meta-test/page.ts +0 -9
  198. package/e2e/kitchen-sink/app/pages/group-meta-test/protected.ts +0 -8
  199. package/e2e/kitchen-sink/app/pages/head.ts +0 -20
  200. package/e2e/kitchen-sink/app/pages/i18n-test.ts +0 -14
  201. package/e2e/kitchen-sink/app/pages/index.ts +0 -27
  202. package/e2e/kitchen-sink/app/pages/isr-test.ts +0 -17
  203. package/e2e/kitchen-sink/app/pages/items/[id].ts +0 -20
  204. package/e2e/kitchen-sink/app/pages/jit-css-custom-colors-test.ts +0 -14
  205. package/e2e/kitchen-sink/app/pages/loader-error-test.ts +0 -13
  206. package/e2e/kitchen-sink/app/pages/loader-props-test.ts +0 -19
  207. package/e2e/kitchen-sink/app/pages/loader-response-error-test.ts +0 -13
  208. package/e2e/kitchen-sink/app/pages/middleware-chain-test.ts +0 -12
  209. package/e2e/kitchen-sink/app/pages/middleware-status-test.ts +0 -9
  210. package/e2e/kitchen-sink/app/pages/navigate-test.ts +0 -16
  211. package/e2e/kitchen-sink/app/pages/observability-test.ts +0 -25
  212. package/e2e/kitchen-sink/app/pages/per-route-error-test.error.ts +0 -13
  213. package/e2e/kitchen-sink/app/pages/per-route-error-test.ts +0 -15
  214. package/e2e/kitchen-sink/app/pages/plugin-dsd-test.ts +0 -10
  215. package/e2e/kitchen-sink/app/pages/render-error-test.ts +0 -12
  216. package/e2e/kitchen-sink/app/pages/render-server-test.ts +0 -12
  217. package/e2e/kitchen-sink/app/pages/render-spa-test.ts +0 -12
  218. package/e2e/kitchen-sink/app/pages/route-info.ts +0 -14
  219. package/e2e/kitchen-sink/app/pages/seo-test.ts +0 -23
  220. package/e2e/kitchen-sink/app/pages/session-rotation-test.ts +0 -25
  221. package/e2e/kitchen-sink/app/pages/use-state-test.ts +0 -37
  222. package/e2e/kitchen-sink/app/plugins/01.setup.ts +0 -7
  223. package/e2e/kitchen-sink/app/plugins/02.ks-plugin-components.ts +0 -27
  224. package/e2e/kitchen-sink/cer-auto-imports.d.ts +0 -51
  225. package/e2e/kitchen-sink/cer-env.d.ts +0 -35
  226. package/e2e/kitchen-sink/cer-tsconfig.json +0 -30
  227. package/e2e/kitchen-sink/cer.config.ts +0 -43
  228. package/e2e/kitchen-sink/content/01.guides/01.index.md +0 -8
  229. package/e2e/kitchen-sink/content/01.guides/02.intro.md +0 -8
  230. package/e2e/kitchen-sink/content/01.guides/10.advanced.md +0 -8
  231. package/e2e/kitchen-sink/content/blog/2026-04-01-hello.md +0 -26
  232. package/e2e/kitchen-sink/content/blog/2026-04-02-draft.md +0 -10
  233. package/e2e/kitchen-sink/content/blog/index.md +0 -8
  234. package/e2e/kitchen-sink/content/blog/no-frontmatter.md +0 -7
  235. package/e2e/kitchen-sink/content/docs/getting-started.md +0 -48
  236. package/e2e/kitchen-sink/content/index.md +0 -16
  237. package/e2e/kitchen-sink/server/api/echo.ts +0 -12
  238. package/e2e/kitchen-sink/server/api/health.ts +0 -3
  239. package/e2e/kitchen-sink/server/api/posts/[slug].ts +0 -11
  240. package/e2e/kitchen-sink/server/api/posts/index.ts +0 -5
  241. package/e2e/kitchen-sink/server/api/session.ts +0 -23
  242. package/e2e/kitchen-sink/server/data/posts.ts +0 -21
  243. package/e2e/kitchen-sink/server/middleware/01-headers.ts +0 -6
  244. package/e2e/kitchen-sink/server/middleware/02-status-test.ts +0 -10
  245. package/e2e/kitchen-sink/tsconfig.json +0 -3
  246. package/e2e/scripts/clean.mjs +0 -14
  247. package/eslint.config.ts +0 -22
  248. package/src/__tests__/cli/adapters/cloudflare-worker.integration.test.ts +0 -132
  249. package/src/__tests__/cli/adapters/cloudflare.test.ts +0 -332
  250. package/src/__tests__/cli/adapters/netlify-bridge.integration.test.ts +0 -139
  251. package/src/__tests__/cli/adapters/netlify.test.ts +0 -286
  252. package/src/__tests__/cli/adapters/vercel-launcher.integration.test.ts +0 -129
  253. package/src/__tests__/cli/adapters/vercel.test.ts +0 -263
  254. package/src/__tests__/cli/preview-hardening.test.ts +0 -265
  255. package/src/__tests__/cli/preview-isr.test.ts +0 -320
  256. package/src/__tests__/index.test.ts +0 -21
  257. package/src/__tests__/plugin/app-template.test.ts +0 -112
  258. package/src/__tests__/plugin/build-ssg-render.test.ts +0 -155
  259. package/src/__tests__/plugin/build-ssg.test.ts +0 -598
  260. package/src/__tests__/plugin/build-ssr.test.ts +0 -192
  261. package/src/__tests__/plugin/cer-app-plugin.test.ts +0 -552
  262. package/src/__tests__/plugin/content/emitter.test.ts +0 -117
  263. package/src/__tests__/plugin/content/loader.test.ts +0 -154
  264. package/src/__tests__/plugin/content/parser.test.ts +0 -381
  265. package/src/__tests__/plugin/content/path-utils.test.ts +0 -69
  266. package/src/__tests__/plugin/content/search.test.ts +0 -119
  267. package/src/__tests__/plugin/dev-server.test.ts +0 -813
  268. package/src/__tests__/plugin/dts-generator.test.ts +0 -394
  269. package/src/__tests__/plugin/entry-server-template.test.ts +0 -385
  270. package/src/__tests__/plugin/generated-dir.test.ts +0 -144
  271. package/src/__tests__/plugin/path-utils.test.ts +0 -411
  272. package/src/__tests__/plugin/resolve-config.test.ts +0 -200
  273. package/src/__tests__/plugin/scanner.test.ts +0 -186
  274. package/src/__tests__/plugin/transforms/auto-import.test.ts +0 -510
  275. package/src/__tests__/plugin/transforms/head-inject.test.ts +0 -178
  276. package/src/__tests__/plugin/virtual/composables.test.ts +0 -57
  277. package/src/__tests__/plugin/virtual/content-components.test.ts +0 -66
  278. package/src/__tests__/plugin/virtual/error.test.ts +0 -71
  279. package/src/__tests__/plugin/virtual/layouts.test.ts +0 -70
  280. package/src/__tests__/plugin/virtual/loading.test.ts +0 -72
  281. package/src/__tests__/plugin/virtual/middleware.test.ts +0 -83
  282. package/src/__tests__/plugin/virtual/plugins.test.ts +0 -129
  283. package/src/__tests__/plugin/virtual/routes.test.ts +0 -884
  284. package/src/__tests__/plugin/virtual/server-api.test.ts +0 -164
  285. package/src/__tests__/plugin/virtual/server-middleware.test.ts +0 -102
  286. package/src/__tests__/runtime/app-template.test.ts +0 -198
  287. package/src/__tests__/runtime/define-middleware.test.ts +0 -64
  288. package/src/__tests__/runtime/define-server-middleware.test.ts +0 -54
  289. package/src/__tests__/runtime/entry-client-template.test.ts +0 -61
  290. package/src/__tests__/runtime/isr-handler.test.ts +0 -338
  291. package/src/__tests__/runtime/oauth/handler.test.ts +0 -358
  292. package/src/__tests__/runtime/oauth/providers.test.ts +0 -47
  293. package/src/__tests__/runtime/oauth-index.test.ts +0 -43
  294. package/src/__tests__/runtime/use-auth.test.ts +0 -169
  295. package/src/__tests__/runtime/use-content-search-composable.test.ts +0 -405
  296. package/src/__tests__/runtime/use-content-search.test.ts +0 -163
  297. package/src/__tests__/runtime/use-content.test.ts +0 -226
  298. package/src/__tests__/runtime/use-cookie.test.ts +0 -277
  299. package/src/__tests__/runtime/use-fetch-component.test.ts +0 -214
  300. package/src/__tests__/runtime/use-fetch.test.ts +0 -377
  301. package/src/__tests__/runtime/use-head.test.ts +0 -266
  302. package/src/__tests__/runtime/use-inject-client.test.ts +0 -67
  303. package/src/__tests__/runtime/use-inject.test.ts +0 -66
  304. package/src/__tests__/runtime/use-locale.test.ts +0 -152
  305. package/src/__tests__/runtime/use-navigate.test.ts +0 -121
  306. package/src/__tests__/runtime/use-page-data.test.ts +0 -298
  307. package/src/__tests__/runtime/use-route.test.ts +0 -156
  308. package/src/__tests__/runtime/use-runtime-config.test.ts +0 -182
  309. package/src/__tests__/runtime/use-seo-meta.test.ts +0 -109
  310. package/src/__tests__/runtime/use-session.test.ts +0 -320
  311. package/src/__tests__/runtime/use-state.test.ts +0 -340
  312. package/src/__tests__/types/config.test.ts +0 -18
  313. package/src/cli/adapters/cloudflare.ts +0 -335
  314. package/src/cli/adapters/netlify.ts +0 -326
  315. package/src/cli/adapters/vercel.ts +0 -311
  316. package/src/cli/commands/adapt.ts +0 -84
  317. package/src/cli/commands/build.ts +0 -165
  318. package/src/cli/commands/dev.ts +0 -125
  319. package/src/cli/commands/generate.ts +0 -91
  320. package/src/cli/commands/preview-isr.ts +0 -172
  321. package/src/cli/commands/preview.ts +0 -489
  322. package/src/cli/create/index.ts +0 -275
  323. package/src/cli/create/templates/shared/.gitignore.tpl +0 -25
  324. package/src/cli/create/templates/shared/app/layouts/default.ts.tpl +0 -15
  325. package/src/cli/create/templates/shared/app/pages/index.ts.tpl +0 -8
  326. package/src/cli/create/templates/shared/index.html.tpl +0 -12
  327. package/src/cli/create/templates/shared/tsconfig.json.tpl +0 -6
  328. package/src/cli/create/templates/spa/cer.config.ts.tpl +0 -6
  329. package/src/cli/create/templates/spa/package.json.tpl +0 -18
  330. package/src/cli/create/templates/ssg/cer.config.ts.tpl +0 -10
  331. package/src/cli/create/templates/ssg/package.json.tpl +0 -19
  332. package/src/cli/create/templates/ssr/cer.config.ts.tpl +0 -6
  333. package/src/cli/create/templates/ssr/package.json.tpl +0 -18
  334. package/src/cli/index.ts +0 -22
  335. package/src/index.ts +0 -20
  336. package/src/plugin/build-ssg.ts +0 -336
  337. package/src/plugin/build-ssr.ts +0 -134
  338. package/src/plugin/content/emitter.ts +0 -50
  339. package/src/plugin/content/index.ts +0 -233
  340. package/src/plugin/content/parser.ts +0 -259
  341. package/src/plugin/content/path-utils.ts +0 -55
  342. package/src/plugin/content/scanner.ts +0 -26
  343. package/src/plugin/content/search.ts +0 -28
  344. package/src/plugin/dev-server.ts +0 -377
  345. package/src/plugin/dts-generator.ts +0 -273
  346. package/src/plugin/generated-dir.ts +0 -121
  347. package/src/plugin/index.ts +0 -553
  348. package/src/plugin/path-utils.ts +0 -186
  349. package/src/plugin/scanner.ts +0 -65
  350. package/src/plugin/transforms/auto-import.ts +0 -206
  351. package/src/plugin/transforms/head-inject.ts +0 -161
  352. package/src/plugin/virtual/composables.ts +0 -28
  353. package/src/plugin/virtual/content-components.ts +0 -83
  354. package/src/plugin/virtual/error.ts +0 -34
  355. package/src/plugin/virtual/layouts.ts +0 -41
  356. package/src/plugin/virtual/loading.ts +0 -32
  357. package/src/plugin/virtual/middleware.ts +0 -45
  358. package/src/plugin/virtual/plugins.ts +0 -46
  359. package/src/plugin/virtual/routes.ts +0 -514
  360. package/src/plugin/virtual/server-api.ts +0 -85
  361. package/src/plugin/virtual/server-middleware.ts +0 -44
  362. package/src/runtime/app-template.ts +0 -380
  363. package/src/runtime/composables/define-middleware.ts +0 -17
  364. package/src/runtime/composables/define-server-middleware.ts +0 -18
  365. package/src/runtime/composables/index.ts +0 -27
  366. package/src/runtime/composables/use-auth.ts +0 -125
  367. package/src/runtime/composables/use-content-search.ts +0 -205
  368. package/src/runtime/composables/use-content.ts +0 -146
  369. package/src/runtime/composables/use-cookie.ts +0 -135
  370. package/src/runtime/composables/use-fetch.ts +0 -438
  371. package/src/runtime/composables/use-head.ts +0 -212
  372. package/src/runtime/composables/use-inject.ts +0 -49
  373. package/src/runtime/composables/use-locale.ts +0 -109
  374. package/src/runtime/composables/use-navigate.ts +0 -58
  375. package/src/runtime/composables/use-page-data.ts +0 -93
  376. package/src/runtime/composables/use-route.ts +0 -71
  377. package/src/runtime/composables/use-runtime-config.ts +0 -123
  378. package/src/runtime/composables/use-seo-meta.ts +0 -80
  379. package/src/runtime/composables/use-session.ts +0 -186
  380. package/src/runtime/composables/use-state.ts +0 -92
  381. package/src/runtime/content/client.ts +0 -168
  382. package/src/runtime/entry-client-template.ts +0 -39
  383. package/src/runtime/entry-server-template.ts +0 -493
  384. package/src/runtime/isr-handler.ts +0 -184
  385. package/src/runtime/oauth/handler.ts +0 -407
  386. package/src/runtime/oauth/index.ts +0 -49
  387. package/src/runtime/oauth/providers.ts +0 -38
  388. package/src/types/api.ts +0 -40
  389. package/src/types/config.ts +0 -371
  390. package/src/types/content.ts +0 -66
  391. package/src/types/index.ts +0 -7
  392. package/src/types/middleware.ts +0 -63
  393. package/src/types/page.ts +0 -117
  394. package/src/types/plugin.ts +0 -34
  395. package/tsconfig.build.json +0 -10
  396. package/tsconfig.json +0 -19
  397. package/vitest.config.ts +0 -33
@@ -1,320 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest'
2
- import type { IncomingMessage, ServerResponse } from 'node:http'
3
- import {
4
- isPathBounded,
5
- matchRoutePattern,
6
- findRevalidate,
7
- findRenderMode,
8
- renderForIsr,
9
- serveFromIsrCache,
10
- type IsrCacheEntry,
11
- } from '../../cli/commands/preview-isr.js'
12
-
13
- // ─── isPathBounded ────────────────────────────────────────────────────────────
14
-
15
- describe('isPathBounded', () => {
16
- it('allows normal file paths inside the root', () => {
17
- expect(isPathBounded('/dist', '/index.html')).toBe(true)
18
- })
19
-
20
- it('allows nested paths inside the root', () => {
21
- expect(isPathBounded('/dist', '/assets/app.js')).toBe(true)
22
- })
23
-
24
- it('allows the root path itself', () => {
25
- expect(isPathBounded('/dist', '/')).toBe(true)
26
- })
27
-
28
- it('blocks simple path traversal (../ escape)', () => {
29
- expect(isPathBounded('/dist', '/../../../../etc/passwd')).toBe(false)
30
- })
31
-
32
- it('blocks a path that escapes by one level', () => {
33
- expect(isPathBounded('/dist', '/../secret')).toBe(false)
34
- })
35
-
36
- it('does not confuse a sibling directory for the root', () => {
37
- // /dist-other starts with /dist but is NOT inside /dist
38
- expect(isPathBounded('/dist', '/../dist-other/file')).toBe(false)
39
- })
40
- })
41
-
42
- // ─── matchRoutePattern ────────────────────────────────────────────────────────
43
-
44
- describe('matchRoutePattern', () => {
45
- it('matches identical paths', () => {
46
- expect(matchRoutePattern('/about', '/about')).toBe(true)
47
- })
48
-
49
- it('matches root path', () => {
50
- expect(matchRoutePattern('/', '/')).toBe(true)
51
- })
52
-
53
- it('does not match different static paths', () => {
54
- expect(matchRoutePattern('/about', '/contact')).toBe(false)
55
- })
56
-
57
- it('matches :param segments', () => {
58
- expect(matchRoutePattern('/blog/:slug', '/blog/hello-world')).toBe(true)
59
- })
60
-
61
- it('does not match when param segment is missing', () => {
62
- expect(matchRoutePattern('/blog/:slug', '/blog')).toBe(false)
63
- })
64
-
65
- it('matches :param* catch-all against single segment', () => {
66
- expect(matchRoutePattern('/:all*', '/about')).toBe(true)
67
- })
68
-
69
- it('matches :param* catch-all against multi-segment path', () => {
70
- expect(matchRoutePattern('/:all*', '/deeply/nested/path')).toBe(true)
71
- })
72
-
73
- it('matches :param* catch-all against root', () => {
74
- expect(matchRoutePattern('/:all*', '/')).toBe(true)
75
- })
76
-
77
- it('does not match longer path against shorter static pattern', () => {
78
- expect(matchRoutePattern('/blog', '/blog/extra')).toBe(false)
79
- })
80
-
81
- it('handles trailing slashes gracefully', () => {
82
- expect(matchRoutePattern('/about/', '/about')).toBe(true)
83
- expect(matchRoutePattern('/about', '/about/')).toBe(true)
84
- })
85
-
86
- it('matches multiple :param segments', () => {
87
- expect(matchRoutePattern('/users/:id/posts/:postId', '/users/42/posts/99')).toBe(true)
88
- })
89
-
90
- it('does not match paths that differ only by a regex wildcard character (dot-safety)', () => {
91
- // Without escaping, '/api.v1' regex would be '^/apixv1$' which matches '/apixv1'.
92
- // With escaping, the dot is literal and '/apixv1' must not match '/api.v1'.
93
- expect(matchRoutePattern('/api.v1/users', '/apixv1/users')).toBe(false)
94
- })
95
-
96
- it('matches route with literal dot in static segment', () => {
97
- expect(matchRoutePattern('/api.v1/users', '/api.v1/users')).toBe(true)
98
- })
99
- })
100
-
101
- // ─── findRevalidate ───────────────────────────────────────────────────────────
102
-
103
- describe('findRevalidate', () => {
104
- it('returns null for an empty routes array', () => {
105
- expect(findRevalidate([], '/about')).toBeNull()
106
- })
107
-
108
- it('returns null when no route matches', () => {
109
- const routes = [{ path: '/contact', meta: { ssg: { revalidate: 60 } } }]
110
- expect(findRevalidate(routes, '/about')).toBeNull()
111
- })
112
-
113
- it('returns null when matched route has no meta', () => {
114
- const routes = [{ path: '/about' }]
115
- expect(findRevalidate(routes, '/about')).toBeNull()
116
- })
117
-
118
- it('returns null when matched route has no ssg.revalidate', () => {
119
- const routes = [{ path: '/about', meta: { layout: 'default' } }]
120
- expect(findRevalidate(routes, '/about')).toBeNull()
121
- })
122
-
123
- it('returns revalidate value for a matching static route', () => {
124
- const routes = [{ path: '/about', meta: { ssg: { revalidate: 60 } } }]
125
- expect(findRevalidate(routes, '/about')).toBe(60)
126
- })
127
-
128
- it('returns revalidate value for a matching dynamic route', () => {
129
- const routes = [{ path: '/blog/:slug', meta: { ssg: { revalidate: 300 } } }]
130
- expect(findRevalidate(routes, '/blog/hello')).toBe(300)
131
- })
132
-
133
- it('returns revalidate value for a catch-all route', () => {
134
- const routes = [{ path: '/:all*', meta: { ssg: { revalidate: 120 } } }]
135
- expect(findRevalidate(routes, '/some/unmatched/path')).toBe(120)
136
- })
137
-
138
- it('picks the first matching route when multiple match', () => {
139
- const routes = [
140
- { path: '/blog/:slug', meta: { ssg: { revalidate: 300 } } },
141
- { path: '/:all*', meta: { ssg: { revalidate: 60 } } },
142
- ]
143
- // /blog/:slug matches first
144
- expect(findRevalidate(routes, '/blog/post')).toBe(300)
145
- })
146
-
147
- it('ignores non-numeric revalidate values', () => {
148
- const routes = [{ path: '/about', meta: { ssg: { revalidate: 'invalid' } } }]
149
- expect(findRevalidate(routes, '/about')).toBeNull()
150
- })
151
- })
152
-
153
- // ─── findRenderMode ───────────────────────────────────────────────────────────
154
-
155
- describe('findRenderMode', () => {
156
- it('returns null for an empty routes array', () => {
157
- expect(findRenderMode([], '/about')).toBeNull()
158
- })
159
-
160
- it('returns null when no route matches', () => {
161
- const routes = [{ path: '/contact', meta: { render: 'server' } }]
162
- expect(findRenderMode(routes, '/about')).toBeNull()
163
- })
164
-
165
- it('returns null when matched route has no render meta', () => {
166
- const routes = [{ path: '/about' }]
167
- expect(findRenderMode(routes, '/about')).toBeNull()
168
- })
169
-
170
- it('returns "server" for a matching route with render: server', () => {
171
- const routes = [{ path: '/dashboard', meta: { render: 'server' } }]
172
- expect(findRenderMode(routes, '/dashboard')).toBe('server')
173
- })
174
-
175
- it('returns "spa" for a matching route with render: spa', () => {
176
- const routes = [{ path: '/profile', meta: { render: 'spa' } }]
177
- expect(findRenderMode(routes, '/profile')).toBe('spa')
178
- })
179
-
180
- it('returns "static" for a matching route with render: static', () => {
181
- const routes = [{ path: '/about', meta: { render: 'static' } }]
182
- expect(findRenderMode(routes, '/about')).toBe('static')
183
- })
184
-
185
- it('returns null for unrecognised render values', () => {
186
- const routes = [{ path: '/about', meta: { render: 'unknown' } }]
187
- expect(findRenderMode(routes, '/about')).toBeNull()
188
- })
189
-
190
- it('matches dynamic routes', () => {
191
- const routes = [{ path: '/blog/:slug', meta: { render: 'server' } }]
192
- expect(findRenderMode(routes, '/blog/my-post')).toBe('server')
193
- })
194
- })
195
-
196
- // ─── renderForIsr ─────────────────────────────────────────────────────────────
197
-
198
- describe('renderForIsr', () => {
199
- it('captures HTML from the handler', async () => {
200
- const handler = (_req: IncomingMessage, res: ServerResponse) => {
201
- res.setHeader('Content-Type', 'text/html')
202
- res.end('<html>hello</html>')
203
- }
204
- const entry = await renderForIsr('/about', handler, 60)
205
- expect(entry).not.toBeNull()
206
- expect(entry!.html).toBe('<html>hello</html>')
207
- })
208
-
209
- it('captures status code from the handler', async () => {
210
- const handler = (_req: IncomingMessage, res: ServerResponse) => {
211
- res.statusCode = 404
212
- res.end('Not Found')
213
- }
214
- const entry = await renderForIsr('/missing', handler, 30)
215
- expect(entry!.statusCode).toBe(404)
216
- })
217
-
218
- it('captures response headers from the handler', async () => {
219
- const handler = (_req: IncomingMessage, res: ServerResponse) => {
220
- res.setHeader('Content-Type', 'text/html; charset=utf-8')
221
- res.end('<html/>')
222
- }
223
- const entry = await renderForIsr('/about', handler, 60)
224
- expect(entry!.headers['content-type']).toBe('text/html; charset=utf-8')
225
- })
226
-
227
- it('sets revalidate to the provided TTL', async () => {
228
- const handler = (_req: IncomingMessage, res: ServerResponse) => { res.end('ok') }
229
- const entry = await renderForIsr('/about', handler, 300)
230
- expect(entry!.revalidate).toBe(300)
231
- })
232
-
233
- it('sets revalidating to false on the returned entry', async () => {
234
- const handler = (_req: IncomingMessage, res: ServerResponse) => { res.end('ok') }
235
- const entry = await renderForIsr('/about', handler, 60)
236
- expect(entry!.revalidating).toBe(false)
237
- })
238
-
239
- it('returns null when the handler throws', async () => {
240
- const handler = () => { throw new Error('boom') }
241
- const entry = await renderForIsr('/about', handler as SsrHandlerFn, 60)
242
- expect(entry).toBeNull()
243
- })
244
-
245
- it('passes the correct URL to the synthetic request', async () => {
246
- let capturedUrl = ''
247
- const handler = (req: IncomingMessage, res: ServerResponse) => {
248
- capturedUrl = req.url ?? ''
249
- res.end('ok')
250
- }
251
- await renderForIsr('/blog/hello', handler, 60)
252
- expect(capturedUrl).toBe('/blog/hello')
253
- })
254
- })
255
-
256
- type SsrHandlerFn = (req: IncomingMessage, res: ServerResponse) => void | Promise<void>
257
-
258
- // ─── serveFromIsrCache ────────────────────────────────────────────────────────
259
-
260
- describe('serveFromIsrCache', () => {
261
- function makeFakeRes() {
262
- const headers: Record<string, string> = {}
263
- let statusCode = 200
264
- let body = ''
265
- const res = {
266
- get statusCode() { return statusCode },
267
- set statusCode(v: number) { statusCode = v },
268
- setHeader: vi.fn((name: string, value: string) => { headers[name] = value }),
269
- end: vi.fn((chunk: string) => { body = chunk }),
270
- _headers: headers,
271
- _body: () => body,
272
- _status: () => statusCode,
273
- }
274
- return res
275
- }
276
-
277
- function makeEntry(overrides: Partial<IsrCacheEntry> = {}): IsrCacheEntry {
278
- return {
279
- html: '<html>cached</html>',
280
- headers: { 'content-type': 'text/html' },
281
- statusCode: 200,
282
- builtAt: Date.now(),
283
- revalidate: 60,
284
- revalidating: false,
285
- ...overrides,
286
- }
287
- }
288
-
289
- it('writes the cached HTML to the response', () => {
290
- const res = makeFakeRes()
291
- serveFromIsrCache(makeEntry(), res as unknown as ServerResponse, 'HIT')
292
- expect(res.end).toHaveBeenCalledWith('<html>cached</html>')
293
- })
294
-
295
- it('sets X-Cache: HIT header', () => {
296
- const res = makeFakeRes()
297
- serveFromIsrCache(makeEntry(), res as unknown as ServerResponse, 'HIT')
298
- expect(res.setHeader).toHaveBeenCalledWith('X-Cache', 'HIT')
299
- })
300
-
301
- it('sets X-Cache: STALE header', () => {
302
- const res = makeFakeRes()
303
- serveFromIsrCache(makeEntry(), res as unknown as ServerResponse, 'STALE')
304
- expect(res.setHeader).toHaveBeenCalledWith('X-Cache', 'STALE')
305
- })
306
-
307
- it('forwards cached headers to the response', () => {
308
- const entry = makeEntry({ headers: { 'content-type': 'text/html; charset=utf-8' } })
309
- const res = makeFakeRes()
310
- serveFromIsrCache(entry, res as unknown as ServerResponse, 'HIT')
311
- expect(res.setHeader).toHaveBeenCalledWith('content-type', 'text/html; charset=utf-8')
312
- })
313
-
314
- it('sets the status code from the cache entry', () => {
315
- const entry = makeEntry({ statusCode: 404 })
316
- const res = makeFakeRes()
317
- serveFromIsrCache(entry, res as unknown as ServerResponse, 'HIT')
318
- expect(res._status()).toBe(404)
319
- })
320
- })
@@ -1,21 +0,0 @@
1
- import { describe, it, expect } from 'vitest'
2
-
3
- // Import from the main package entry to trigger coverage of src/index.ts
4
- // re-exports. These are all re-exports of other modules so we just verify
5
- // the named exports resolve without errors.
6
- import { defineConfig, cerApp } from '../index.js'
7
-
8
- describe('package main entry', () => {
9
- it('exports defineConfig', () => {
10
- expect(typeof defineConfig).toBe('function')
11
- })
12
-
13
- it('defineConfig is a pass-through', () => {
14
- const cfg = { mode: 'spa' as const }
15
- expect(defineConfig(cfg)).toBe(cfg)
16
- })
17
-
18
- it('exports cerApp', () => {
19
- expect(typeof cerApp).toBe('function')
20
- })
21
- })
@@ -1,112 +0,0 @@
1
- import { describe, it, expect } from 'vitest'
2
- import { readFileSync } from 'node:fs'
3
- import { resolve } from 'pathe'
4
- import { generateAppEntryTemplate } from '../../runtime/app-template.js'
5
-
6
- const src = readFileSync(
7
- resolve(import.meta.dirname, '../../runtime/app-template.ts'),
8
- 'utf-8',
9
- )
10
-
11
- describe('app-template (source content)', () => {
12
- it('does not import virtual:cer-components (components injected per-file by cerComponentImports)', () => {
13
- expect(src).not.toContain('virtual:cer-components')
14
- })
15
-
16
- it('imports virtual:cer-routes', () => {
17
- expect(src).toContain('virtual:cer-routes')
18
- })
19
-
20
- it('imports virtual:cer-layouts', () => {
21
- expect(src).toContain('virtual:cer-layouts')
22
- })
23
-
24
- it('imports virtual:cer-plugins', () => {
25
- expect(src).toContain('virtual:cer-plugins')
26
- })
27
-
28
- it('imports registerBuiltinComponents from custom-elements-runtime', () => {
29
- expect(src).toContain('registerBuiltinComponents')
30
- expect(src).toContain('setDevMode')
31
- expect(src).toContain('@jasonshimmy/custom-elements-runtime')
32
- })
33
-
34
- it('enables runtime dev logging from the downstream Vite env', () => {
35
- expect(src).toContain('const _cerRuntimeDev')
36
- expect(src).toContain('import.meta.env?.DEV')
37
- expect(src).toContain('_cerProcess?.env')
38
- expect(src).toContain('(globalThis).__CE_RUNTIME_DEV__ = _cerRuntimeDev')
39
- expect(src).toContain('setDevMode(_cerRuntimeDev)')
40
- })
41
-
42
- it('imports initRouter from the router subpath', () => {
43
- expect(src).toContain('initRouter')
44
- expect(src).toContain('custom-elements-runtime/router')
45
- })
46
-
47
- it('imports enableJITCSS from the jit-css subpath', () => {
48
- expect(src).toContain('enableJITCSS')
49
- expect(src).toContain('custom-elements-runtime/jit-css')
50
- })
51
-
52
- it('imports virtual:cer-jit-css', () => {
53
- expect(src).toContain('virtual:cer-jit-css')
54
- })
55
-
56
- it('imports virtual:cer-content-components for markdown-backed custom elements', () => {
57
- expect(src).toContain('virtual:cer-content-components')
58
- })
59
-
60
- it('exports router', () => {
61
- expect(src).toContain('export { router }')
62
- })
63
- })
64
-
65
- describe('generateAppEntryTemplate', () => {
66
- it('calls enableJITCSS() with no arguments when customColors is omitted', () => {
67
- const out = generateAppEntryTemplate()
68
- expect(out).toContain('enableJITCSS()')
69
- expect(out).not.toContain('customColors')
70
- })
71
-
72
- it('calls enableJITCSS() with no arguments when customColors is an empty object', () => {
73
- const out = generateAppEntryTemplate({})
74
- expect(out).toContain('enableJITCSS()')
75
- expect(out).not.toContain('customColors')
76
- })
77
-
78
- it('serializes a single color family into the enableJITCSS call', () => {
79
- const out = generateAppEntryTemplate({ brand: { '500': '#7c3aed' } })
80
- expect(out).toContain('enableJITCSS({ customColors:')
81
- expect(out).toContain('"brand"')
82
- expect(out).toContain('"500"')
83
- expect(out).toContain('"#7c3aed"')
84
- })
85
-
86
- it('serializes multiple color families correctly', () => {
87
- const out = generateAppEntryTemplate({
88
- brand: { '100': '#ede9fe', '900': '#4c1d95' },
89
- accent: { DEFAULT: '#f59e0b' },
90
- })
91
- expect(out).toContain('"brand"')
92
- expect(out).toContain('"accent"')
93
- expect(out).toContain('"DEFAULT"')
94
- expect(out).toContain('"#f59e0b"')
95
- })
96
-
97
- it('serializes CSS variable references as color values', () => {
98
- const out = generateAppEntryTemplate({
99
- surface: { DEFAULT: 'var(--md-sys-color-surface)' },
100
- })
101
- expect(out).toContain('"surface"')
102
- expect(out).toContain('var(--md-sys-color-surface)')
103
- })
104
-
105
- it('still includes all standard template content when customColors is provided', () => {
106
- const out = generateAppEntryTemplate({ brand: { '500': '#ff0000' } })
107
- expect(out).toContain('virtual:cer-jit-css')
108
- expect(out).toContain('virtual:cer-routes')
109
- expect(out).toContain('enableJITCSS')
110
- expect(out).toContain('export { router }')
111
- })
112
- })
@@ -1,155 +0,0 @@
1
- /**
2
- * Integration tests for the build-ssg renderPath success path.
3
- *
4
- * These tests use a real temporary ESM module as the "server bundle" so that
5
- * the dynamic import() inside renderPath actually resolves, exercising the
6
- * success branches (writeRenderedPath call, generatedPaths.push, etc.) that
7
- * are unreachable when the bundle is absent.
8
- *
9
- * A separate test file is required so the node:fs/promises mock does NOT
10
- * shadow the real writeFile/mkdir used to set up the temp bundle.
11
- */
12
- import { vi, describe, it, expect, beforeAll, afterAll } from 'vitest'
13
- import { mkdirSync, writeFileSync, rmSync } from 'node:fs'
14
- import { tmpdir } from 'node:os'
15
- import { join } from 'pathe'
16
-
17
- // Mock buildSSR so the SSG pipeline skips the Vite build step.
18
- vi.mock('../../plugin/build-ssr.js', () => ({ buildSSR: vi.fn().mockResolvedValue(undefined) }))
19
- vi.mock('fast-glob', () => ({ default: vi.fn().mockResolvedValue([]) }))
20
- // Intentionally NOT mocking node:fs or node:fs/promises so real writes work.
21
-
22
- import type { ResolvedCerConfig } from '../../plugin/dev-server.js'
23
-
24
- let tmpRoot: string
25
-
26
- beforeAll(() => {
27
- // Create a minimal "server bundle" that exports a handler.
28
- // The handler writes a minimal HTML string to res.end so renderPath captures it.
29
- tmpRoot = join(tmpdir(), `cer-ssg-render-${Date.now()}`)
30
- const serverDir = join(tmpRoot, 'dist', 'server')
31
- mkdirSync(serverDir, { recursive: true })
32
- writeFileSync(
33
- join(serverDir, 'server.js'),
34
- // ESM module — works because Vitest runs with Node's native ESM loader.
35
- `export const handler = async (req, res) => {
36
- res.setHeader('Content-Type', 'text/html');
37
- res.end('<!DOCTYPE html><html><head></head><body>Hello from ' + req.url + '</body></html>');
38
- };
39
- export const apiRoutes = [];
40
- export const plugins = [];
41
- export const layouts = {};
42
- `,
43
- 'utf-8',
44
- )
45
- })
46
-
47
- afterAll(() => {
48
- rmSync(tmpRoot, { recursive: true, force: true })
49
- })
50
-
51
- function makeConfig(overrides: Partial<ResolvedCerConfig> = {}): ResolvedCerConfig {
52
- return {
53
- root: tmpRoot,
54
- srcDir: join(tmpRoot, 'app'),
55
- pagesDir: join(tmpRoot, 'app', 'pages'),
56
- mode: 'ssg',
57
- ssg: { routes: ['/'], concurrency: 1 },
58
- ...overrides,
59
- } as unknown as ResolvedCerConfig
60
- }
61
-
62
- describe('buildSSG — renderPath success (real server bundle)', () => {
63
- it('writes rendered HTML for the root path to dist/index.html', async () => {
64
- // Reset module registry so _serverMod cache is cleared between test runs.
65
- await vi.resetModules()
66
- const { buildSSG } = await import('../../plugin/build-ssg.js')
67
- await buildSSG(makeConfig())
68
-
69
- const { readFileSync, existsSync } = await import('node:fs')
70
- const outPath = join(tmpRoot, 'dist', 'index.html')
71
- expect(existsSync(outPath)).toBe(true)
72
- const html = readFileSync(outPath, 'utf-8')
73
- expect(html).toContain('Hello from /')
74
- })
75
-
76
- it('records the path in the ssg-manifest paths array', async () => {
77
- await vi.resetModules()
78
- const { buildSSG } = await import('../../plugin/build-ssg.js')
79
- await buildSSG(makeConfig())
80
-
81
- const { readFileSync } = await import('node:fs')
82
- const manifest = JSON.parse(readFileSync(join(tmpRoot, 'dist', 'ssg-manifest.json'), 'utf-8'))
83
- expect(manifest.paths).toContain('/')
84
- expect(manifest.errors).toHaveLength(0)
85
- })
86
-
87
- it('renders multiple paths with concurrency > 1', async () => {
88
- await vi.resetModules()
89
- const { buildSSG } = await import('../../plugin/build-ssg.js')
90
- const config = makeConfig({ ssg: { routes: ['/', '/about'], concurrency: 2 } } as Partial<ResolvedCerConfig>)
91
- await buildSSG(config)
92
-
93
- const { readFileSync, existsSync } = await import('node:fs')
94
- expect(existsSync(join(tmpRoot, 'dist', 'index.html'))).toBe(true)
95
- expect(existsSync(join(tmpRoot, 'dist', 'about', 'index.html'))).toBe(true)
96
- const manifest = JSON.parse(readFileSync(join(tmpRoot, 'dist', 'ssg-manifest.json'), 'utf-8'))
97
- expect(manifest.paths).toHaveLength(2)
98
- })
99
-
100
- it('captures HTML from a streaming handler that calls write() then end()', async () => {
101
- // Simulate the renderToStreamWithJITCSSDSD-based handler which calls
102
- // res.write(firstChunk) for sync content and res.end(polyfill + tail).
103
- // Use a completely separate tmpdir with a unique path so Node's native ESM
104
- // import cache cannot return a previously-loaded module for the same URL.
105
- const streamRoot = join(tmpdir(), `cer-ssg-stream-${Date.now()}`)
106
- const streamServerDir = join(streamRoot, 'dist', 'server')
107
- mkdirSync(streamServerDir, { recursive: true })
108
- writeFileSync(
109
- join(streamServerDir, 'server.js'),
110
- `export const handler = async (req, res) => {
111
- res.setHeader('Content-Type', 'text/html');
112
- res.setHeader('Transfer-Encoding', 'chunked');
113
- res.write('<html><head></head>');
114
- res.write('<body>streamed</body>');
115
- res.end('</html>');
116
- };
117
- export const apiRoutes = [];
118
- export const plugins = [];
119
- export const layouts = {};
120
- `,
121
- 'utf-8',
122
- )
123
-
124
- await vi.resetModules()
125
- const { buildSSG } = await import('../../plugin/build-ssg.js')
126
- const config = {
127
- root: streamRoot,
128
- srcDir: join(streamRoot, 'app'),
129
- pagesDir: join(streamRoot, 'app', 'pages'),
130
- mode: 'ssg',
131
- ssg: { routes: ['/'], concurrency: 1 },
132
- } as unknown as ResolvedCerConfig
133
- await buildSSG(config)
134
-
135
- const { readFileSync, existsSync } = await import('node:fs')
136
- const outPath = join(streamRoot, 'dist', 'index.html')
137
- expect(existsSync(outPath)).toBe(true)
138
- const html = readFileSync(outPath, 'utf-8')
139
- expect(html).toContain('<html><head></head>')
140
- expect(html).toContain('<body>streamed</body>')
141
- expect(html).toContain('</html>')
142
-
143
- rmSync(streamRoot, { recursive: true, force: true })
144
- })
145
-
146
- it('uses cached _serverMod on second renderPath call (no double import)', async () => {
147
- // In a fresh module instance, render two paths sequentially.
148
- // The second renderPath call hits the !_serverMod === false branch (cache).
149
- await vi.resetModules()
150
- const { buildSSG } = await import('../../plugin/build-ssg.js')
151
- const config = makeConfig({ ssg: { routes: ['/', '/page2'], concurrency: 1 } } as Partial<ResolvedCerConfig>)
152
- // Should complete without error — second call uses cached module
153
- await expect(buildSSG(config)).resolves.not.toThrow()
154
- })
155
- })