@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,380 +0,0 @@
1
- /**
2
- * Generates the `.cer/app.ts` framework client entry point.
3
- *
4
- * Always written to `.cer/app.ts` on every dev/build so consumers
5
- * automatically receive the latest bootstrap code on plugin update.
6
- * This file is gitignored and should never be edited directly.
7
- *
8
- * @param customColors - Project-specific color families to register in the JIT
9
- * CSS engine at runtime. Serialized as a JSON literal in the generated source.
10
- */
11
- export function generateAppEntryTemplate(
12
- customColors?: Record<string, Record<string, string>>,
13
- ): string {
14
- const enableJITCSSCall =
15
- customColors && Object.keys(customColors).length > 0
16
- ? `enableJITCSS({ customColors: ${JSON.stringify(customColors)} })`
17
- : `enableJITCSS()`
18
-
19
- return `// AUTO-GENERATED by @jasonshimmy/vite-plugin-cer-app — do not edit.
20
- // Regenerated automatically on every dev server start and build.
21
-
22
- import '@jasonshimmy/custom-elements-runtime/css'
23
- import 'virtual:cer-jit-css'
24
- import 'virtual:cer-content-components'
25
- import routes from 'virtual:cer-routes'
26
- import layouts from 'virtual:cer-layouts'
27
- import plugins from 'virtual:cer-plugins'
28
- import { hasLoading, loadingTag } from 'virtual:cer-loading'
29
- import { hasError, errorTag } from 'virtual:cer-error'
30
- import { runtimeConfig } from 'virtual:cer-app-config'
31
- import {
32
- component,
33
- ref,
34
- provide,
35
- setDevMode,
36
- useOnConnected,
37
- useOnDisconnected,
38
- registerBuiltinComponents,
39
- } from '@jasonshimmy/custom-elements-runtime'
40
- import { initRouter } from '@jasonshimmy/custom-elements-runtime/router'
41
- import { enableJITCSS } from '@jasonshimmy/custom-elements-runtime/jit-css'
42
- import { initRuntimeConfig } from '@jasonshimmy/vite-plugin-cer-app/composables'
43
-
44
- const _cerProcess = (globalThis).process
45
- const _cerNodeEnv = _cerProcess?.env?.NODE_ENV ?? _cerProcess?.env?.MODE
46
- const _cerRuntimeDev =
47
- typeof _cerNodeEnv === 'string'
48
- ? _cerNodeEnv !== 'production'
49
- : typeof import.meta.env?.DEV === 'boolean'
50
- ? import.meta.env.DEV
51
- : typeof import.meta.env?.PROD === 'boolean'
52
- ? !import.meta.env.PROD
53
- : typeof import.meta.env?.MODE === 'string'
54
- ? import.meta.env.MODE !== 'production'
55
- : false
56
- ;(globalThis).__CE_RUNTIME_DEV__ = _cerRuntimeDev
57
-
58
- registerBuiltinComponents()
59
- setDevMode(_cerRuntimeDev)
60
- ${enableJITCSSCall}
61
- initRuntimeConfig(runtimeConfig)
62
-
63
- const router = initRouter({ routes })
64
-
65
- // Expose the router globally so useRoute() and navigateTo() can access it
66
- // from any composable without circular imports.
67
- ;(globalThis).__cerRouter = router
68
-
69
- // ─── Page loader state ───────────────────────────────────────────────────────
70
-
71
- // Holds the pre-loaded page tag and loader-derived attrs for the current route.
72
- // Set by _loadPageForPath before every navigation so cer-layout-view can render
73
- // the page element directly with the correct attributes (enabling useProps()).
74
- let _currentPageTag = null
75
- let _currentPageAttrs = {}
76
- // The pathname this tag was loaded for — used to detect router-internal
77
- // redirects (e.g. middleware returning '/login') so cer-layout-view falls
78
- // back to <router-view> when the current route differs from what was pre-loaded.
79
- let _currentPagePath = null
80
-
81
- function _toLoaderAttrs(data) {
82
- if (data === undefined || data === null || typeof data !== 'object') return {}
83
- return Object.fromEntries(
84
- Object.entries(data).filter(([, v]) => v !== null && v !== undefined && typeof v !== 'object' && typeof v !== 'function')
85
- )
86
- }
87
-
88
- // Pre-loads the page module for \`path\`, calls its loader if present, and
89
- // stores the results so cer-layout-view can pass them as element attributes.
90
- async function _loadPageForPath(path, options = {}) {
91
- try {
92
- const url = new URL(path, 'http://x')
93
- const query = Object.fromEntries(url.searchParams)
94
- const { runLoader = true, initialData } = options ?? {}
95
- const matched = router.matchRoute(url.pathname)
96
- const route = matched?.route
97
- if (!route?.load) {
98
- _currentPageTag = null
99
- _currentPageAttrs = {}
100
- _currentPagePath = url.pathname
101
- return
102
- }
103
- const mod = await route.load()
104
- _currentPageTag = mod.default ?? null
105
- _currentPagePath = url.pathname
106
- const params = matched.params ?? {}
107
- let loaderAttrs = { ...params }
108
- let loaderData = initialData
109
- if (typeof mod.loader === 'function' && runLoader) {
110
- try {
111
- const data = await mod.loader({ params, query })
112
- if (data !== undefined && data !== null) {
113
- loaderData = data
114
- // Make loader data available via usePageData() for this navigation.
115
- ;(globalThis).__CER_DATA__ = data
116
- }
117
- } catch (err) {
118
- // Loader errors are surfaced through currentError so the error boundary
119
- // (app/error.ts) can display a meaningful message — consistent with how
120
- // the server-side handler behaves when a loader throws.
121
- currentError.value = err instanceof Error ? err.message : String(err)
122
- }
123
- }
124
- // For the very first hydration pass in SSR/SSG we already have the server's
125
- // loader payload in globalThis.__CER_DATA__ / window.__CER_DATA__. Reuse it
126
- // instead of re-running the loader on the client, then derive primitive attrs
127
- // from that payload so useProps() stays consistent with usePageData().
128
- loaderAttrs = { ...loaderAttrs, ..._toLoaderAttrs(loaderData) }
129
- _currentPageAttrs = loaderAttrs
130
- } catch {
131
- _currentPageTag = null
132
- _currentPageAttrs = {}
133
- _currentPagePath = null
134
- }
135
- }
136
-
137
- // ─── Navigation state ────────────────────────────────────────────────────────
138
-
139
- const isNavigating = ref(false)
140
- const currentError = ref(null)
141
-
142
- const resetError = () => {
143
- currentError.value = null
144
- void router.replace(router.getCurrent().path)
145
- }
146
- ;(globalThis).resetError = resetError
147
-
148
- const _push = router.push.bind(router)
149
- const _replace = router.replace.bind(router)
150
-
151
- router.push = async (path) => {
152
- isNavigating.value = true
153
- currentError.value = null
154
- try {
155
- // Clear stale loader data from the previous route before loading the new one.
156
- // If the new route has no loader, __CER_DATA__ stays undefined so usePageData()
157
- // correctly returns null instead of leaking the previous page's data.
158
- delete (globalThis).__CER_DATA__
159
- await _loadPageForPath(path)
160
- await _push(path)
161
- } catch (err) {
162
- currentError.value = err instanceof Error ? err.message : String(err)
163
- } finally {
164
- isNavigating.value = false
165
- }
166
- }
167
-
168
- router.replace = async (path) => {
169
- isNavigating.value = true
170
- currentError.value = null
171
- try {
172
- // Clear stale loader data from the previous route before loading the new one.
173
- delete (globalThis).__CER_DATA__
174
- await _loadPageForPath(path)
175
- await _replace(path)
176
- } catch (err) {
177
- currentError.value = err instanceof Error ? err.message : String(err)
178
- } finally {
179
- isNavigating.value = false
180
- }
181
- }
182
-
183
- // ─── Plugins ─────────────────────────────────────────────────────────────────
184
-
185
- // Collect plugin-provided values so cer-layout-view can forward them into
186
- // the component context tree via the real provide() hook (which inject() walks).
187
- // Declared BEFORE component('cer-layout-view') to avoid a temporal dead zone
188
- // ReferenceError: customElements.define() upgrades existing DOM elements
189
- // synchronously, calling the render function immediately.
190
- const _pluginProvides = new Map()
191
- // Expose plugin provides globally so page components can read them synchronously
192
- // regardless of render order.
193
- ;(globalThis).__cerPluginProvides = _pluginProvides
194
-
195
- // ─── <cer-layout-view> ───────────────────────────────────────────────────────
196
-
197
- // True until the initial page module has loaded and _replace has been called.
198
- // While true, cer-layout-view renders a <slot> so the SSR/SSG pre-rendered
199
- // light-DOM content stays visible and no FOUC occurs during the hydration gap.
200
- // Declared here (before component()) because customElements.define() upgrades
201
- // existing DOM elements synchronously, so the render function reads this ref
202
- // on the very first call — before _doHydrate has a chance to run.
203
- const _cerHydrating = ref(true)
204
-
205
- component('cer-layout-view', () => {
206
- // Forward plugin-provided values into the component context so inject() in
207
- // any descendant component can resolve them by walking up the DOM tree.
208
- for (const [key, value] of _pluginProvides) {
209
- provide(key, value)
210
- }
211
-
212
- const current = ref(router.getCurrent())
213
- let unsub
214
- let _sawInitialRouteState = false
215
-
216
- useOnConnected(() => {
217
- // store.subscribe() synchronously pushes the current route once on
218
- // subscription. That initial callback is not a real navigation and must not
219
- // tear down the SSR slot before _doHydrate has pre-loaded the page.
220
- // Subsequent callbacks are real navigations (including the initial _replace
221
- // in _doHydrate), so if they arrive during the hydration gap we drop the
222
- // slot immediately and let the live render take over.
223
- unsub = router.subscribe((s) => {
224
- const _isInitialSubscribePush = !_sawInitialRouteState
225
- _sawInitialRouteState = true
226
- if (_isInitialSubscribePush) {
227
- current.value = s
228
- return
229
- }
230
- if (_cerHydrating.value) _cerHydrating.value = false
231
- current.value = s
232
- })
233
- })
234
- useOnDisconnected(() => { unsub?.(); unsub = undefined })
235
-
236
- // While the initial page module is being loaded, keep the SSR/SSG
237
- // pre-rendered light-DOM content visible by forwarding it through a <slot>.
238
- // This prevents the intermediate blank state that occurs when the shadow DOM
239
- // renders layout-default with an empty <router-view> before the page chunk
240
- // has arrived. In SPA mode (no pre-rendered content) the slot is empty, which
241
- // is no worse than the current router-view behaviour.
242
- if (_cerHydrating.value) {
243
- return { tag: 'slot', props: {}, children: [] }
244
- }
245
-
246
- const matched = router.matchRoute(current.value.path)
247
- const routeMeta = matched?.route?.meta
248
-
249
- if (currentError.value !== null) {
250
- const routeErrorTag = routeMeta?.errorTag ?? null
251
- const effectiveErrorTag = routeErrorTag ?? (hasError ? errorTag : null)
252
- if (effectiveErrorTag) {
253
- return { tag: effectiveErrorTag, props: { attrs: { error: String(currentError.value) } }, children: [] }
254
- }
255
- return { tag: 'div', props: { attrs: { style: 'padding:2rem;font-family:monospace' } }, children: String(currentError.value) }
256
- }
257
-
258
- if (isNavigating.value && hasLoading && loadingTag) {
259
- return { tag: loadingTag, props: {}, children: [] }
260
- }
261
-
262
- // Render the page component directly when a pre-loaded tag is available AND
263
- // the loaded path matches the current route. The path guard detects
264
- // router-internal redirects (e.g. middleware returning '/login'): when the
265
- // router redirects to a different path, _currentPagePath won't match
266
- // current.value.path and we fall back to <router-view> so the correct page
267
- // is rendered without stale pre-loaded state.
268
- const _useDirectRender = _currentPageTag && _currentPagePath === current.value.path
269
- const pageVnode = _useDirectRender
270
- ? { tag: _currentPageTag, props: { attrs: _currentPageAttrs }, children: [] }
271
- : { tag: 'router-view', props: {}, children: [] }
272
-
273
- // Support nested layout chains: meta.layoutChain = ['default', 'admin']
274
- // renders <layout-default><layout-admin><page/></layout-admin></layout-default>
275
- const chain = routeMeta?.layoutChain
276
- ? routeMeta.layoutChain
277
- : [routeMeta?.layout ?? 'default']
278
-
279
- // Build nested vnodes from innermost to outermost.
280
- let vnode = pageVnode
281
- for (let i = chain.length - 1; i >= 0; i--) {
282
- const tag = layouts[chain[i]]
283
- if (tag) vnode = { tag, props: {}, children: [vnode] }
284
- }
285
- return vnode
286
- })
287
-
288
- for (const plugin of plugins) {
289
- if (plugin && typeof plugin.setup === 'function') {
290
- await plugin.setup({
291
- router,
292
- provide: (key, value) => { _pluginProvides.set(key, value) },
293
- config: {},
294
- })
295
- }
296
- }
297
-
298
- // ─── Pre-load initial route + hydration strategy ─────────────────────────────
299
- // Download the current page's route chunk AFTER plugins run so that
300
- // cer-layout-view's first render (which calls provide()) completes before
301
- // page components are defined and their renders are scheduled. This ensures
302
- // inject() in child components can find values stored by provide().
303
- //
304
- // meta.hydrate controls WHEN the initial page activates:
305
- // 'load' — immediately (default)
306
- // 'idle' — deferred until requestIdleCallback (browser idle)
307
- // 'visible' — deferred until cer-layout-view enters the viewport
308
- // 'none' — never: SSR HTML stays as-is, no JS activation
309
-
310
- if (typeof window !== 'undefined') {
311
- const _initMatch = router.matchRoute(window.location.pathname)
312
- const _hydrateStrategy = _initMatch?.route?.meta?.hydrate ?? 'load'
313
-
314
- if (_hydrateStrategy === 'none') {
315
- // Static HTML only — leave SSR output untouched, clean up data immediately.
316
- delete (globalThis).__CER_DATA__
317
- } else {
318
- const _doHydrate = async () => {
319
- const _initPath = window.location.pathname + window.location.search + window.location.hash
320
- const _hasInitialLoaderData = Object.prototype.hasOwnProperty.call(globalThis, '__CER_DATA__')
321
- // Pre-load the page module and run the loader so cer-layout-view renders
322
- // the page tag directly with loader attrs (enables useProps() on hydration).
323
- await _loadPageForPath(
324
- _initPath,
325
- _hasInitialLoaderData
326
- ? { runLoader: false, initialData: (globalThis).__CER_DATA__ }
327
- : undefined,
328
- )
329
- // Only activate the initial route if the URL hasn't changed while we were
330
- // loading the module asynchronously (e.g. a test or plugin navigated away
331
- // before _doHydrate finished). Calling _replace with a stale path would
332
- // override any navigation that happened during the async gap.
333
- const _currentPath = window.location.pathname + window.location.search + window.location.hash
334
- // Drop the hydration slot cover unconditionally: the page module is loaded
335
- // and cer-layout-view must switch from the <slot> to live rendering whether
336
- // or not a redirect changed the path during loading.
337
- _cerHydrating.value = false
338
- if (_currentPath === _initPath) {
339
- // Use the original (unwrapped) replace so isNavigating stays false during
340
- // the initial paint — the loading component must not flash over pre-rendered content.
341
- await _replace(_initPath)
342
- }
343
- // The client entry marks the already-rendered entry URL so generated
344
- // route middleware can skip the browser router's startup replay once.
345
- // Clear any leftover flag after the first hydrated route commits so later
346
- // navigations always run middleware normally.
347
- queueMicrotask(() => { delete (globalThis).__CER_HYDRATION_ENTRY__ })
348
- // Keep the initial route's SSR data available after hydration.
349
- // Browser engines do not all upgrade and re-render custom elements with
350
- // identical timing, so deleting __CER_DATA__ here can cause a later
351
- // hydration render to fall back to the client-only path. The next real
352
- // router.push/router.replace clears __CER_DATA__ before loading the new
353
- // route, so stale page data still does not leak across navigations.
354
- }
355
-
356
- if (_hydrateStrategy === 'idle') {
357
- // Defer until the browser has finished higher-priority work.
358
- if (typeof requestIdleCallback !== 'undefined') {
359
- requestIdleCallback(() => { void _doHydrate() })
360
- } else {
361
- // Safari / older environments fallback.
362
- setTimeout(() => { void _doHydrate() }, 1)
363
- }
364
- } else if (_hydrateStrategy === 'visible') {
365
- // Defer until cer-layout-view (or body as fallback) enters the viewport.
366
- const _el = document.querySelector('cer-layout-view') ?? document.body
367
- const _io = new IntersectionObserver(([entry]) => {
368
- if (entry.isIntersecting) { _io.disconnect(); void _doHydrate() }
369
- })
370
- _io.observe(_el)
371
- } else {
372
- // 'load' — hydrate immediately (default behaviour).
373
- await _doHydrate()
374
- }
375
- }
376
- }
377
-
378
- export { router }
379
- `
380
- }
@@ -1,17 +0,0 @@
1
- import type { MiddlewareFn } from '../../types/middleware.js'
2
-
3
- /**
4
- * Identity helper that gives TypeScript the correct `MiddlewareFn` type
5
- * without any runtime cost.
6
- *
7
- * @example
8
- * // app/middleware/auth.ts
9
- * export default defineMiddleware(async (to, from) => {
10
- * const isLoggedIn = checkSession()
11
- * if (!isLoggedIn) return '/login' // redirect
12
- * return true // allow
13
- * })
14
- */
15
- export function defineMiddleware(fn: MiddlewareFn): MiddlewareFn {
16
- return fn
17
- }
@@ -1,18 +0,0 @@
1
- import type { ServerMiddleware } from '../../types/middleware.js'
2
-
3
- /**
4
- * Identity helper that gives `ServerMiddleware` functions full TypeScript
5
- * types without any runtime cost. Usage:
6
- *
7
- * ```ts
8
- * // server/middleware/auth.ts
9
- * export default defineServerMiddleware(async (req, res, next) => {
10
- * const session = await useSession().get()
11
- * if (!session) { res.statusCode = 401; res.end('Unauthorized'); return }
12
- * next()
13
- * })
14
- * ```
15
- */
16
- export function defineServerMiddleware(fn: ServerMiddleware): ServerMiddleware {
17
- return fn
18
- }
@@ -1,27 +0,0 @@
1
- export { useHead, beginHeadCollection, endHeadCollection, serializeHeadTags } from './use-head.js'
2
- export type { HeadInput } from './use-head.js'
3
- export { usePageData } from './use-page-data.js'
4
- export { useInject } from './use-inject.js'
5
- export { useRuntimeConfig, initRuntimeConfig, resolvePrivateConfig } from './use-runtime-config.js'
6
- export type { RuntimeConfigResult, RuntimeConfigPublic, RuntimeConfigPrivate } from './use-runtime-config.js'
7
- export { defineMiddleware } from './define-middleware.js'
8
- export { defineServerMiddleware } from './define-server-middleware.js'
9
- export { useSeoMeta } from './use-seo-meta.js'
10
- export type { SeoMetaInput } from './use-seo-meta.js'
11
- export { useCookie } from './use-cookie.js'
12
- export type { CookieOptions, CookieRef } from './use-cookie.js'
13
- export { useSession } from './use-session.js'
14
- export type { SessionOptions, SessionComposable } from './use-session.js'
15
- export { useAuth } from './use-auth.js'
16
- export type { AuthUser, AuthComposable } from './use-auth.js'
17
- export { useFetch } from './use-fetch.js'
18
- export type { UseFetchOptions, UseFetchReturn, UseFetchResult, UseFetchReactiveReturn } from './use-fetch.js'
19
- export { useRoute } from './use-route.js'
20
- export type { RouteInfo } from './use-route.js'
21
- export { navigateTo } from './use-navigate.js'
22
- export { useState } from './use-state.js'
23
- export { useLocale } from './use-locale.js'
24
- export type { LocaleComposable } from './use-locale.js'
25
- export { queryContent, QueryBuilder } from './use-content.js'
26
- export { useContentSearch } from './use-content-search.js'
27
- export type { UseContentSearchReturn } from './use-content-search.js'
@@ -1,125 +0,0 @@
1
- import { useSession } from './use-session.js'
2
-
3
- // ─── Types ────────────────────────────────────────────────────────────────────
4
-
5
- /**
6
- * Normalised user profile stored in the auth session after a successful OAuth login.
7
- * The `provider`, `id`, and at least one of `name`/`email` fields are populated by the built-in
8
- * provider normalisers. Additional fields from `mapUser()` are merged in.
9
- */
10
- export interface AuthUser {
11
- provider: string
12
- id: string
13
- name?: string
14
- email?: string
15
- avatar?: string
16
- [key: string]: unknown
17
- }
18
-
19
- /** Return value of `useAuth()`. Exposes the current user and helpers for login/logout. */
20
- export interface AuthComposable {
21
- /** The currently authenticated user, or `null` if not logged in. */
22
- readonly user: AuthUser | null
23
- /** `true` when a user is authenticated. */
24
- readonly loggedIn: boolean
25
- /**
26
- * Initiates an OAuth login flow by redirecting to `/api/auth/:provider`.
27
- * Only meaningful on the client — calling this on the server is a no-op.
28
- */
29
- login(provider: string): void
30
- /**
31
- * Logs out the current user.
32
- *
33
- * - **Server context** (inside a loader / middleware): clears the auth
34
- * session cookie immediately via `useSession().clear()`.
35
- * - **Client context**: redirects to `/api/auth/logout` which clears the
36
- * cookie server-side and redirects to `redirectAfterLogout`.
37
- */
38
- logout(): Promise<void>
39
- }
40
-
41
- // ─── Composable ───────────────────────────────────────────────────────────────
42
-
43
- /**
44
- * Returns the currently authenticated user and helpers for login/logout.
45
- *
46
- * Works isomorphically:
47
- * - **Server render pass** — reads from `globalThis.__CER_AUTH_STORE__`
48
- * (AsyncLocalStorage populated by the entry-server handler before rendering).
49
- * - **Client hydration** — reads from `globalThis.__CER_AUTH_USER__` (injected
50
- * as `window.__CER_AUTH_USER__` by the entry-server and captured by the
51
- * client entry before the app boots).
52
- *
53
- * @param sessionKey - Session cookie name; must match `auth.sessionKey` in
54
- * `cer.config.ts` (defaults to `'auth'`).
55
- *
56
- * @example
57
- * ```ts
58
- * // app/pages/profile.ts
59
- * component('page-profile', () => {
60
- * const { user, loggedIn, logout } = useAuth()
61
- *
62
- * if (!loggedIn) {
63
- * // Redirect to login
64
- * useHead({ title: 'Login required' })
65
- * }
66
- * })
67
- * ```
68
- *
69
- * @example
70
- * ```ts
71
- * // app/middleware/require-auth.ts
72
- * export default defineMiddleware((to) => {
73
- * const { loggedIn } = useAuth()
74
- * if (!loggedIn) return '/login'
75
- * return true
76
- * })
77
- * ```
78
- */
79
- export function useAuth(sessionKey = 'auth'): AuthComposable {
80
- const g = globalThis as Record<string, unknown>
81
-
82
- // Server: read from the per-request AsyncLocalStorage context.
83
- // __CER_AUTH_STORE__ is only present in Node.js (tree-shaken on client).
84
- const authStore = g['__CER_AUTH_STORE__'] as { getStore(): unknown } | undefined
85
- let user: AuthUser | null = null
86
-
87
- if (authStore) {
88
- user = (authStore.getStore() as AuthUser | null) ?? null
89
- } else {
90
- // Client: read from the global hydrated by the client entry.
91
- user = (g['__CER_AUTH_USER__'] as AuthUser | null) ?? null
92
- }
93
-
94
- return {
95
- get user() {
96
- return user
97
- },
98
-
99
- get loggedIn() {
100
- return user !== null
101
- },
102
-
103
- login(provider: string) {
104
- if (typeof window !== 'undefined') {
105
- window.location.href = `/api/auth/${provider}`
106
- }
107
- },
108
-
109
- async logout() {
110
- if (typeof window !== 'undefined') {
111
- // Client: let the server clear the cookie via the logout route.
112
- window.location.href = '/api/auth/logout'
113
- } else {
114
- // Server context: clear the session cookie directly.
115
- const session = useSession({ name: sessionKey })
116
- await session.clear()
117
- // Also clear the local user reference so the current render sees null.
118
- user = null
119
- // Clear the ALS store value so concurrent requests are unaffected.
120
- const store = (g['__CER_AUTH_STORE__'] as { enterWith(v: unknown): void } | undefined)
121
- if (store) store.enterWith(null)
122
- }
123
- },
124
- }
125
- }