@jasonshimmy/vite-plugin-cer-app 0.23.2 → 0.25.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 (404) hide show
  1. package/dist/cli/adapters/netlify.js +4 -2
  2. package/dist/cli/adapters/netlify.js.map +1 -1
  3. package/dist/cli/checks/lighthouse.d.ts +26 -0
  4. package/dist/cli/checks/lighthouse.d.ts.map +1 -0
  5. package/dist/cli/checks/lighthouse.js +121 -0
  6. package/dist/cli/checks/lighthouse.js.map +1 -0
  7. package/dist/cli/checks/links.d.ts +12 -0
  8. package/dist/cli/checks/links.d.ts.map +1 -0
  9. package/dist/cli/checks/links.js +89 -0
  10. package/dist/cli/checks/links.js.map +1 -0
  11. package/dist/cli/checks/performance.d.ts +17 -0
  12. package/dist/cli/checks/performance.d.ts.map +1 -0
  13. package/dist/cli/checks/performance.js +61 -0
  14. package/dist/cli/checks/performance.js.map +1 -0
  15. package/dist/cli/commands/check.d.ts +3 -0
  16. package/dist/cli/commands/check.d.ts.map +1 -0
  17. package/dist/cli/commands/check.js +85 -0
  18. package/dist/cli/commands/check.js.map +1 -0
  19. package/dist/cli/commands/preview.d.ts.map +1 -1
  20. package/dist/cli/commands/preview.js +4 -2
  21. package/dist/cli/commands/preview.js.map +1 -1
  22. package/dist/cli/create/index.d.ts +11 -1
  23. package/dist/cli/create/index.d.ts.map +1 -1
  24. package/dist/cli/create/index.js +135 -65
  25. package/dist/cli/create/index.js.map +1 -1
  26. package/dist/cli/create/templates/spa/package.json.tpl +5 -3
  27. package/dist/cli/create/templates/ssg/cer.config.ts.tpl +2 -0
  28. package/dist/cli/create/templates/ssg/package.json.tpl +5 -3
  29. package/dist/cli/create/templates/ssr/package.json.tpl +5 -3
  30. package/dist/cli/index.js +2 -0
  31. package/dist/cli/index.js.map +1 -1
  32. package/dist/index.d.ts +4 -2
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/plugin/build-ssg.d.ts +22 -6
  35. package/dist/plugin/build-ssg.d.ts.map +1 -1
  36. package/dist/plugin/build-ssg.js +226 -17
  37. package/dist/plugin/build-ssg.js.map +1 -1
  38. package/dist/plugin/content/index.d.ts +1 -1
  39. package/dist/plugin/content/index.d.ts.map +1 -1
  40. package/dist/plugin/content/index.js +8 -8
  41. package/dist/plugin/content/index.js.map +1 -1
  42. package/dist/plugin/content/parser.d.ts +3 -3
  43. package/dist/plugin/content/parser.d.ts.map +1 -1
  44. package/dist/plugin/content/parser.js +103 -24
  45. package/dist/plugin/content/parser.js.map +1 -1
  46. package/dist/plugin/dev-server.d.ts +4 -1
  47. package/dist/plugin/dev-server.d.ts.map +1 -1
  48. package/dist/plugin/dev-server.js.map +1 -1
  49. package/dist/plugin/dts-generator.d.ts.map +1 -1
  50. package/dist/plugin/dts-generator.js +50 -8
  51. package/dist/plugin/dts-generator.js.map +1 -1
  52. package/dist/plugin/generated-dir.d.ts +2 -0
  53. package/dist/plugin/generated-dir.d.ts.map +1 -1
  54. package/dist/plugin/generated-dir.js +17 -6
  55. package/dist/plugin/generated-dir.js.map +1 -1
  56. package/dist/plugin/html-post-process.d.ts +7 -0
  57. package/dist/plugin/html-post-process.d.ts.map +1 -1
  58. package/dist/plugin/html-post-process.js +26 -0
  59. package/dist/plugin/html-post-process.js.map +1 -1
  60. package/dist/plugin/index.d.ts.map +1 -1
  61. package/dist/plugin/index.js +60 -13
  62. package/dist/plugin/index.js.map +1 -1
  63. package/dist/plugin/transforms/auto-import.d.ts.map +1 -1
  64. package/dist/plugin/transforms/auto-import.js +7 -0
  65. package/dist/plugin/transforms/auto-import.js.map +1 -1
  66. package/dist/plugin/transforms/prune-runtime-css.d.ts +8 -0
  67. package/dist/plugin/transforms/prune-runtime-css.d.ts.map +1 -0
  68. package/dist/plugin/transforms/prune-runtime-css.js +40 -0
  69. package/dist/plugin/transforms/prune-runtime-css.js.map +1 -0
  70. package/dist/runtime/app-template.d.ts +1 -1
  71. package/dist/runtime/app-template.d.ts.map +1 -1
  72. package/dist/runtime/app-template.js +206 -36
  73. package/dist/runtime/app-template.js.map +1 -1
  74. package/dist/runtime/composables/index.d.ts +4 -0
  75. package/dist/runtime/composables/index.d.ts.map +1 -1
  76. package/dist/runtime/composables/index.js +2 -0
  77. package/dist/runtime/composables/index.js.map +1 -1
  78. package/dist/runtime/composables/use-active-headings.d.ts +24 -0
  79. package/dist/runtime/composables/use-active-headings.d.ts.map +1 -0
  80. package/dist/runtime/composables/use-active-headings.js +112 -0
  81. package/dist/runtime/composables/use-active-headings.js.map +1 -0
  82. package/dist/runtime/composables/use-content-page.d.ts +45 -0
  83. package/dist/runtime/composables/use-content-page.d.ts.map +1 -0
  84. package/dist/runtime/composables/use-content-page.js +181 -0
  85. package/dist/runtime/composables/use-content-page.js.map +1 -0
  86. package/dist/runtime/composables/use-content-search.d.ts.map +1 -1
  87. package/dist/runtime/composables/use-content-search.js +1 -5
  88. package/dist/runtime/composables/use-content-search.js.map +1 -1
  89. package/dist/runtime/composables/use-fetch.d.ts +2 -1
  90. package/dist/runtime/composables/use-fetch.d.ts.map +1 -1
  91. package/dist/runtime/composables/use-fetch.js +112 -43
  92. package/dist/runtime/composables/use-fetch.js.map +1 -1
  93. package/dist/runtime/composables/use-route.d.ts.map +1 -1
  94. package/dist/runtime/composables/use-route.js +39 -11
  95. package/dist/runtime/composables/use-route.js.map +1 -1
  96. package/dist/runtime/content/client.js +2 -2
  97. package/dist/runtime/content/client.js.map +1 -1
  98. package/dist/runtime/entry-server-template.d.ts +16 -1
  99. package/dist/runtime/entry-server-template.d.ts.map +1 -1
  100. package/dist/runtime/entry-server-template.js +120 -13
  101. package/dist/runtime/entry-server-template.js.map +1 -1
  102. package/dist/types/config.d.ts +45 -4
  103. package/dist/types/config.d.ts.map +1 -1
  104. package/dist/types/config.js.map +1 -1
  105. package/dist/types/content.d.ts +18 -1
  106. package/dist/types/content.d.ts.map +1 -1
  107. package/dist/types/middleware.d.ts +2 -2
  108. package/dist/types/middleware.d.ts.map +1 -1
  109. package/package.json +22 -19
  110. package/.github/copilot-instructions.md +0 -169
  111. package/.github/workflows/publish.yml +0 -257
  112. package/.nvmrc +0 -1
  113. package/CHANGELOG.md +0 -236
  114. package/CLAUDE.md +0 -113
  115. package/commits.txt +0 -1
  116. package/cypress.config.ts +0 -16
  117. package/docs/authentication.md +0 -285
  118. package/docs/cli.md +0 -324
  119. package/docs/components.md +0 -237
  120. package/docs/composables.md +0 -907
  121. package/docs/configuration.md +0 -696
  122. package/docs/content.md +0 -570
  123. package/docs/data-loading.md +0 -336
  124. package/docs/getting-started.md +0 -237
  125. package/docs/head-management.md +0 -212
  126. package/docs/i18n.md +0 -159
  127. package/docs/layouts.md +0 -224
  128. package/docs/middleware.md +0 -234
  129. package/docs/plugins.md +0 -170
  130. package/docs/rendering-modes.md +0 -377
  131. package/docs/routing.md +0 -485
  132. package/docs/server-api.md +0 -253
  133. package/docs/testing.md +0 -455
  134. package/docs/use-fetch.md +0 -183
  135. package/e2e/cypress/e2e/api.cy.ts +0 -123
  136. package/e2e/cypress/e2e/async-component.cy.ts +0 -27
  137. package/e2e/cypress/e2e/component-splitting.cy.ts +0 -50
  138. package/e2e/cypress/e2e/content.cy.ts +0 -425
  139. package/e2e/cypress/e2e/cookie.cy.ts +0 -85
  140. package/e2e/cypress/e2e/data.cy.ts +0 -158
  141. package/e2e/cypress/e2e/error-boundary.cy.ts +0 -88
  142. package/e2e/cypress/e2e/fouc.cy.ts +0 -254
  143. package/e2e/cypress/e2e/group-meta.cy.ts +0 -36
  144. package/e2e/cypress/e2e/head.cy.ts +0 -89
  145. package/e2e/cypress/e2e/i18n.cy.ts +0 -79
  146. package/e2e/cypress/e2e/interactive.cy.ts +0 -137
  147. package/e2e/cypress/e2e/isr-nested-runtime.cy.ts +0 -102
  148. package/e2e/cypress/e2e/jit-css-custom-colors.cy.ts +0 -43
  149. package/e2e/cypress/e2e/middleware-chain.cy.ts +0 -89
  150. package/e2e/cypress/e2e/middleware-status.cy.ts +0 -30
  151. package/e2e/cypress/e2e/middleware.cy.ts +0 -45
  152. package/e2e/cypress/e2e/navigate.cy.ts +0 -39
  153. package/e2e/cypress/e2e/observability.cy.ts +0 -77
  154. package/e2e/cypress/e2e/per-route-error.cy.ts +0 -42
  155. package/e2e/cypress/e2e/per-route-render.cy.ts +0 -70
  156. package/e2e/cypress/e2e/preview-hardening.cy.ts +0 -88
  157. package/e2e/cypress/e2e/routes.cy.ts +0 -128
  158. package/e2e/cypress/e2e/seo-meta.cy.ts +0 -108
  159. package/e2e/cypress/e2e/server-middleware.cy.ts +0 -46
  160. package/e2e/cypress/e2e/session-rotation.cy.ts +0 -25
  161. package/e2e/cypress/e2e/session.cy.ts +0 -73
  162. package/e2e/cypress/e2e/ssr-render-error.cy.ts +0 -68
  163. package/e2e/cypress/e2e/synthetic-404.cy.ts +0 -45
  164. package/e2e/cypress/e2e/use-page-data.cy.ts +0 -122
  165. package/e2e/cypress/e2e/use-state.cy.ts +0 -138
  166. package/e2e/cypress/support/commands.ts +0 -120
  167. package/e2e/cypress/support/e2e.ts +0 -10
  168. package/e2e/cypress/tsconfig.json +0 -14
  169. package/e2e/kitchen-sink/app/components/ks-badge.ts +0 -8
  170. package/e2e/kitchen-sink/app/composables/useKsCounter.ts +0 -9
  171. package/e2e/kitchen-sink/app/error.ts +0 -18
  172. package/e2e/kitchen-sink/app/layouts/admin.ts +0 -13
  173. package/e2e/kitchen-sink/app/layouts/default.ts +0 -25
  174. package/e2e/kitchen-sink/app/layouts/group.ts +0 -9
  175. package/e2e/kitchen-sink/app/layouts/minimal.ts +0 -7
  176. package/e2e/kitchen-sink/app/loading.ts +0 -9
  177. package/e2e/kitchen-sink/app/middleware/auth.ts +0 -9
  178. package/e2e/kitchen-sink/app/middleware/custom-log.ts +0 -4
  179. package/e2e/kitchen-sink/app/middleware/group-auth.ts +0 -7
  180. package/e2e/kitchen-sink/app/middleware/logger.ts +0 -14
  181. package/e2e/kitchen-sink/app/pages/(auth)/login.ts +0 -13
  182. package/e2e/kitchen-sink/app/pages/(auth)/protected.ts +0 -16
  183. package/e2e/kitchen-sink/app/pages/404.ts +0 -9
  184. package/e2e/kitchen-sink/app/pages/about.ts +0 -17
  185. package/e2e/kitchen-sink/app/pages/admin/_layout.ts +0 -1
  186. package/e2e/kitchen-sink/app/pages/admin/dashboard.ts +0 -11
  187. package/e2e/kitchen-sink/app/pages/async-component-error-test.ts +0 -18
  188. package/e2e/kitchen-sink/app/pages/async-component-test.ts +0 -18
  189. package/e2e/kitchen-sink/app/pages/blog/[slug].ts +0 -59
  190. package/e2e/kitchen-sink/app/pages/blog/index.ts +0 -51
  191. package/e2e/kitchen-sink/app/pages/content-blog.ts +0 -37
  192. package/e2e/kitchen-sink/app/pages/content-doc.ts +0 -42
  193. package/e2e/kitchen-sink/app/pages/content-fallback.ts +0 -36
  194. package/e2e/kitchen-sink/app/pages/content-guides.ts +0 -35
  195. package/e2e/kitchen-sink/app/pages/content-index.ts +0 -39
  196. package/e2e/kitchen-sink/app/pages/content-search.ts +0 -36
  197. package/e2e/kitchen-sink/app/pages/cookie-test.ts +0 -22
  198. package/e2e/kitchen-sink/app/pages/counter.ts +0 -17
  199. package/e2e/kitchen-sink/app/pages/group-auth-blocked.ts +0 -9
  200. package/e2e/kitchen-sink/app/pages/group-meta-test/_layout.ts +0 -6
  201. package/e2e/kitchen-sink/app/pages/group-meta-test/custom-mw.ts +0 -14
  202. package/e2e/kitchen-sink/app/pages/group-meta-test/page.ts +0 -9
  203. package/e2e/kitchen-sink/app/pages/group-meta-test/protected.ts +0 -8
  204. package/e2e/kitchen-sink/app/pages/head.ts +0 -20
  205. package/e2e/kitchen-sink/app/pages/i18n-test.ts +0 -14
  206. package/e2e/kitchen-sink/app/pages/index.ts +0 -27
  207. package/e2e/kitchen-sink/app/pages/isr-test.ts +0 -17
  208. package/e2e/kitchen-sink/app/pages/items/[id].ts +0 -20
  209. package/e2e/kitchen-sink/app/pages/jit-css-custom-colors-test.ts +0 -14
  210. package/e2e/kitchen-sink/app/pages/loader-error-test.ts +0 -13
  211. package/e2e/kitchen-sink/app/pages/loader-props-test.ts +0 -19
  212. package/e2e/kitchen-sink/app/pages/loader-response-error-test.ts +0 -13
  213. package/e2e/kitchen-sink/app/pages/middleware-chain-test.ts +0 -12
  214. package/e2e/kitchen-sink/app/pages/middleware-status-test.ts +0 -9
  215. package/e2e/kitchen-sink/app/pages/navigate-test.ts +0 -16
  216. package/e2e/kitchen-sink/app/pages/observability-test.ts +0 -25
  217. package/e2e/kitchen-sink/app/pages/per-route-error-test.error.ts +0 -13
  218. package/e2e/kitchen-sink/app/pages/per-route-error-test.ts +0 -15
  219. package/e2e/kitchen-sink/app/pages/plugin-dsd-test.ts +0 -10
  220. package/e2e/kitchen-sink/app/pages/render-error-test.ts +0 -12
  221. package/e2e/kitchen-sink/app/pages/render-server-test.ts +0 -12
  222. package/e2e/kitchen-sink/app/pages/render-spa-test.ts +0 -12
  223. package/e2e/kitchen-sink/app/pages/route-info.ts +0 -14
  224. package/e2e/kitchen-sink/app/pages/seo-test.ts +0 -23
  225. package/e2e/kitchen-sink/app/pages/session-rotation-test.ts +0 -25
  226. package/e2e/kitchen-sink/app/pages/use-state-test.ts +0 -37
  227. package/e2e/kitchen-sink/app/plugins/01.setup.ts +0 -7
  228. package/e2e/kitchen-sink/app/plugins/02.ks-plugin-components.ts +0 -27
  229. package/e2e/kitchen-sink/cer-auto-imports.d.ts +0 -51
  230. package/e2e/kitchen-sink/cer-env.d.ts +0 -35
  231. package/e2e/kitchen-sink/cer-tsconfig.json +0 -30
  232. package/e2e/kitchen-sink/cer.config.ts +0 -43
  233. package/e2e/kitchen-sink/content/01.guides/01.index.md +0 -8
  234. package/e2e/kitchen-sink/content/01.guides/02.intro.md +0 -8
  235. package/e2e/kitchen-sink/content/01.guides/10.advanced.md +0 -8
  236. package/e2e/kitchen-sink/content/blog/2026-04-01-hello.md +0 -26
  237. package/e2e/kitchen-sink/content/blog/2026-04-02-draft.md +0 -10
  238. package/e2e/kitchen-sink/content/blog/index.md +0 -8
  239. package/e2e/kitchen-sink/content/blog/no-frontmatter.md +0 -7
  240. package/e2e/kitchen-sink/content/docs/getting-started.md +0 -48
  241. package/e2e/kitchen-sink/content/index.md +0 -16
  242. package/e2e/kitchen-sink/server/api/echo.ts +0 -12
  243. package/e2e/kitchen-sink/server/api/health.ts +0 -3
  244. package/e2e/kitchen-sink/server/api/posts/[slug].ts +0 -11
  245. package/e2e/kitchen-sink/server/api/posts/index.ts +0 -5
  246. package/e2e/kitchen-sink/server/api/session.ts +0 -23
  247. package/e2e/kitchen-sink/server/data/posts.ts +0 -21
  248. package/e2e/kitchen-sink/server/middleware/01-headers.ts +0 -6
  249. package/e2e/kitchen-sink/server/middleware/02-status-test.ts +0 -10
  250. package/e2e/kitchen-sink/tsconfig.json +0 -3
  251. package/e2e/scripts/clean.mjs +0 -14
  252. package/eslint.config.ts +0 -22
  253. package/src/__tests__/cli/adapters/cloudflare-worker.integration.test.ts +0 -132
  254. package/src/__tests__/cli/adapters/cloudflare.test.ts +0 -332
  255. package/src/__tests__/cli/adapters/netlify-bridge.integration.test.ts +0 -139
  256. package/src/__tests__/cli/adapters/netlify.test.ts +0 -286
  257. package/src/__tests__/cli/adapters/vercel-launcher.integration.test.ts +0 -129
  258. package/src/__tests__/cli/adapters/vercel.test.ts +0 -263
  259. package/src/__tests__/cli/preview-hardening.test.ts +0 -265
  260. package/src/__tests__/cli/preview-isr.test.ts +0 -320
  261. package/src/__tests__/index.test.ts +0 -21
  262. package/src/__tests__/plugin/app-template.test.ts +0 -166
  263. package/src/__tests__/plugin/build-ssg-render.test.ts +0 -155
  264. package/src/__tests__/plugin/build-ssg.test.ts +0 -598
  265. package/src/__tests__/plugin/build-ssr.test.ts +0 -192
  266. package/src/__tests__/plugin/cer-app-plugin.test.ts +0 -552
  267. package/src/__tests__/plugin/content/emitter.test.ts +0 -117
  268. package/src/__tests__/plugin/content/loader.test.ts +0 -154
  269. package/src/__tests__/plugin/content/parser.test.ts +0 -381
  270. package/src/__tests__/plugin/content/path-utils.test.ts +0 -69
  271. package/src/__tests__/plugin/content/search.test.ts +0 -119
  272. package/src/__tests__/plugin/dev-server.test.ts +0 -813
  273. package/src/__tests__/plugin/dts-generator.test.ts +0 -394
  274. package/src/__tests__/plugin/entry-server-template.test.ts +0 -385
  275. package/src/__tests__/plugin/generated-dir.test.ts +0 -144
  276. package/src/__tests__/plugin/html-post-process.test.ts +0 -146
  277. package/src/__tests__/plugin/path-utils.test.ts +0 -411
  278. package/src/__tests__/plugin/resolve-config.test.ts +0 -233
  279. package/src/__tests__/plugin/scanner.test.ts +0 -186
  280. package/src/__tests__/plugin/transforms/auto-import.test.ts +0 -510
  281. package/src/__tests__/plugin/transforms/head-inject.test.ts +0 -178
  282. package/src/__tests__/plugin/virtual/composables.test.ts +0 -57
  283. package/src/__tests__/plugin/virtual/content-components.test.ts +0 -66
  284. package/src/__tests__/plugin/virtual/error.test.ts +0 -71
  285. package/src/__tests__/plugin/virtual/layouts.test.ts +0 -70
  286. package/src/__tests__/plugin/virtual/loading.test.ts +0 -72
  287. package/src/__tests__/plugin/virtual/middleware.test.ts +0 -83
  288. package/src/__tests__/plugin/virtual/plugins.test.ts +0 -129
  289. package/src/__tests__/plugin/virtual/routes.test.ts +0 -884
  290. package/src/__tests__/plugin/virtual/server-api.test.ts +0 -164
  291. package/src/__tests__/plugin/virtual/server-middleware.test.ts +0 -102
  292. package/src/__tests__/runtime/app-template.test.ts +0 -208
  293. package/src/__tests__/runtime/define-middleware.test.ts +0 -64
  294. package/src/__tests__/runtime/define-server-middleware.test.ts +0 -54
  295. package/src/__tests__/runtime/entry-client-template.test.ts +0 -61
  296. package/src/__tests__/runtime/isr-handler.test.ts +0 -338
  297. package/src/__tests__/runtime/oauth/handler.test.ts +0 -358
  298. package/src/__tests__/runtime/oauth/providers.test.ts +0 -47
  299. package/src/__tests__/runtime/oauth-index.test.ts +0 -43
  300. package/src/__tests__/runtime/use-auth.test.ts +0 -169
  301. package/src/__tests__/runtime/use-content-search-composable.test.ts +0 -405
  302. package/src/__tests__/runtime/use-content-search.test.ts +0 -163
  303. package/src/__tests__/runtime/use-content.test.ts +0 -226
  304. package/src/__tests__/runtime/use-cookie.test.ts +0 -277
  305. package/src/__tests__/runtime/use-fetch-component.test.ts +0 -214
  306. package/src/__tests__/runtime/use-fetch.test.ts +0 -377
  307. package/src/__tests__/runtime/use-head.test.ts +0 -311
  308. package/src/__tests__/runtime/use-inject-client.test.ts +0 -67
  309. package/src/__tests__/runtime/use-inject.test.ts +0 -66
  310. package/src/__tests__/runtime/use-locale.test.ts +0 -152
  311. package/src/__tests__/runtime/use-navigate.test.ts +0 -121
  312. package/src/__tests__/runtime/use-page-data.test.ts +0 -298
  313. package/src/__tests__/runtime/use-route.test.ts +0 -156
  314. package/src/__tests__/runtime/use-runtime-config.test.ts +0 -182
  315. package/src/__tests__/runtime/use-seo-meta.test.ts +0 -109
  316. package/src/__tests__/runtime/use-session.test.ts +0 -320
  317. package/src/__tests__/runtime/use-state.test.ts +0 -340
  318. package/src/__tests__/types/config.test.ts +0 -18
  319. package/src/cli/adapters/cloudflare.ts +0 -335
  320. package/src/cli/adapters/netlify.ts +0 -326
  321. package/src/cli/adapters/vercel.ts +0 -311
  322. package/src/cli/commands/adapt.ts +0 -84
  323. package/src/cli/commands/build.ts +0 -165
  324. package/src/cli/commands/dev.ts +0 -125
  325. package/src/cli/commands/generate.ts +0 -91
  326. package/src/cli/commands/preview-isr.ts +0 -172
  327. package/src/cli/commands/preview.ts +0 -523
  328. package/src/cli/create/index.ts +0 -275
  329. package/src/cli/create/templates/shared/.gitignore.tpl +0 -25
  330. package/src/cli/create/templates/shared/app/layouts/default.ts.tpl +0 -15
  331. package/src/cli/create/templates/shared/app/pages/index.ts.tpl +0 -8
  332. package/src/cli/create/templates/shared/index.html.tpl +0 -12
  333. package/src/cli/create/templates/shared/tsconfig.json.tpl +0 -6
  334. package/src/cli/create/templates/spa/cer.config.ts.tpl +0 -6
  335. package/src/cli/create/templates/spa/package.json.tpl +0 -18
  336. package/src/cli/create/templates/ssg/cer.config.ts.tpl +0 -10
  337. package/src/cli/create/templates/ssg/package.json.tpl +0 -19
  338. package/src/cli/create/templates/ssr/cer.config.ts.tpl +0 -6
  339. package/src/cli/create/templates/ssr/package.json.tpl +0 -18
  340. package/src/cli/index.ts +0 -22
  341. package/src/index.ts +0 -20
  342. package/src/plugin/build-ssg.ts +0 -403
  343. package/src/plugin/build-ssr.ts +0 -134
  344. package/src/plugin/content/emitter.ts +0 -50
  345. package/src/plugin/content/index.ts +0 -233
  346. package/src/plugin/content/parser.ts +0 -259
  347. package/src/plugin/content/path-utils.ts +0 -55
  348. package/src/plugin/content/scanner.ts +0 -26
  349. package/src/plugin/content/search.ts +0 -28
  350. package/src/plugin/dev-server.ts +0 -379
  351. package/src/plugin/dts-generator.ts +0 -273
  352. package/src/plugin/generated-dir.ts +0 -121
  353. package/src/plugin/html-post-process.ts +0 -96
  354. package/src/plugin/index.ts +0 -584
  355. package/src/plugin/path-utils.ts +0 -186
  356. package/src/plugin/scanner.ts +0 -65
  357. package/src/plugin/transforms/auto-import.ts +0 -206
  358. package/src/plugin/transforms/head-inject.ts +0 -161
  359. package/src/plugin/virtual/composables.ts +0 -28
  360. package/src/plugin/virtual/content-components.ts +0 -83
  361. package/src/plugin/virtual/error.ts +0 -34
  362. package/src/plugin/virtual/layouts.ts +0 -41
  363. package/src/plugin/virtual/loading.ts +0 -32
  364. package/src/plugin/virtual/middleware.ts +0 -45
  365. package/src/plugin/virtual/plugins.ts +0 -46
  366. package/src/plugin/virtual/routes.ts +0 -514
  367. package/src/plugin/virtual/server-api.ts +0 -85
  368. package/src/plugin/virtual/server-middleware.ts +0 -44
  369. package/src/runtime/app-template.ts +0 -377
  370. package/src/runtime/composables/define-middleware.ts +0 -17
  371. package/src/runtime/composables/define-server-middleware.ts +0 -18
  372. package/src/runtime/composables/index.ts +0 -27
  373. package/src/runtime/composables/use-auth.ts +0 -125
  374. package/src/runtime/composables/use-content-search.ts +0 -205
  375. package/src/runtime/composables/use-content.ts +0 -146
  376. package/src/runtime/composables/use-cookie.ts +0 -135
  377. package/src/runtime/composables/use-fetch.ts +0 -438
  378. package/src/runtime/composables/use-head.ts +0 -234
  379. package/src/runtime/composables/use-inject.ts +0 -49
  380. package/src/runtime/composables/use-locale.ts +0 -109
  381. package/src/runtime/composables/use-navigate.ts +0 -58
  382. package/src/runtime/composables/use-page-data.ts +0 -93
  383. package/src/runtime/composables/use-route.ts +0 -71
  384. package/src/runtime/composables/use-runtime-config.ts +0 -123
  385. package/src/runtime/composables/use-seo-meta.ts +0 -80
  386. package/src/runtime/composables/use-session.ts +0 -186
  387. package/src/runtime/composables/use-state.ts +0 -92
  388. package/src/runtime/content/client.ts +0 -168
  389. package/src/runtime/entry-client-template.ts +0 -39
  390. package/src/runtime/entry-server-template.ts +0 -493
  391. package/src/runtime/isr-handler.ts +0 -184
  392. package/src/runtime/oauth/handler.ts +0 -407
  393. package/src/runtime/oauth/index.ts +0 -49
  394. package/src/runtime/oauth/providers.ts +0 -38
  395. package/src/types/api.ts +0 -40
  396. package/src/types/config.ts +0 -379
  397. package/src/types/content.ts +0 -66
  398. package/src/types/index.ts +0 -7
  399. package/src/types/middleware.ts +0 -63
  400. package/src/types/page.ts +0 -117
  401. package/src/types/plugin.ts +0 -34
  402. package/tsconfig.build.json +0 -10
  403. package/tsconfig.json +0 -19
  404. package/vitest.config.ts +0 -33
@@ -1,49 +0,0 @@
1
- import { inject } from '@jasonshimmy/custom-elements-runtime'
2
-
3
- const _g = globalThis as Record<string, unknown>
4
- const _PROVIDES_KEY = '__cerPluginProvides'
5
-
6
- /**
7
- * useInject — reads a value provided by a plugin via plugin.setup()'s provide().
8
- *
9
- * Works consistently across all rendering modes:
10
- *
11
- * - **SPA/Client**: Uses inject() from the component context tree (established
12
- * by cer-layout-view calling provide() for each plugin-provided value).
13
- *
14
- * - **SSR/SSG**: Reads from globalThis.__cerPluginProvides, populated when the
15
- * server entry runs plugin.setup() before rendering.
16
- *
17
- * @example
18
- * ```ts
19
- * // In a plugin (app/plugins/my-plugin.ts):
20
- * export default {
21
- * name: 'my-plugin',
22
- * setup({ provide }) {
23
- * provide('my-service', { greet: () => 'hello' })
24
- * }
25
- * }
26
- *
27
- * // In a component:
28
- * component('my-page', () => {
29
- * const service = useInject<{ greet(): string }>('my-service')
30
- * })
31
- * ```
32
- */
33
- export function useInject<T = unknown>(key: string, defaultValue?: T): T | undefined {
34
- // Server-side (SSR/SSG): read from the global plugin provides map.
35
- // __cerPluginProvides is populated by the server entry before the render pass.
36
- if (typeof document === 'undefined') {
37
- const pluginProvides = _g[_PROVIDES_KEY] as Map<PropertyKey, unknown> | undefined
38
- const value = pluginProvides?.get(key)
39
- return value !== undefined ? (value as T) : defaultValue
40
- }
41
-
42
- // Client-side: inject() walks the component context tree established by
43
- // cer-layout-view's provide() calls. Falls back to __cerPluginProvides for
44
- // reads before cer-layout-view mounts (e.g. during plugin-registered components).
45
- const value = inject<T>(key)
46
- if (value !== undefined) return value
47
- const pluginProvides = _g[_PROVIDES_KEY] as Map<PropertyKey, unknown> | undefined
48
- return (pluginProvides?.get(key) as T | undefined) ?? defaultValue
49
- }
@@ -1,109 +0,0 @@
1
- import type { IncomingMessage } from 'node:http'
2
-
3
- /** Return value of `useLocale()`. Exposes the active locale and helpers for locale-aware navigation. */
4
- export interface LocaleComposable {
5
- /** The active locale code for the current request / page. */
6
- readonly locale: string
7
- /** All configured locale codes. */
8
- readonly locales: string[]
9
- /** The default locale code. */
10
- readonly defaultLocale: string
11
- /**
12
- * Returns the localised version of `path` for `targetLocale`.
13
- *
14
- * @example
15
- * switchLocalePath('fr', '/about') // → '/fr/about'
16
- * switchLocalePath('en', '/fr/about') // → '/about' (when en is default + prefix_except_default)
17
- */
18
- switchLocalePath(targetLocale: string, path?: string): string
19
- }
20
-
21
- interface I18nVirtualConfig {
22
- locales: string[]
23
- defaultLocale: string
24
- strategy: 'prefix' | 'prefix_except_default' | 'no_prefix'
25
- }
26
-
27
- // ─── Internal helpers ─────────────────────────────────────────────────────────
28
-
29
- function _extractLocaleFromPath(pathname: string, locales: string[]): string | null {
30
- const first = pathname.split('/')[1]
31
- return locales.includes(first) ? first : null
32
- }
33
-
34
- function _stripLocalePrefix(pathname: string, locale: string): string {
35
- const prefix = `/${locale}`
36
- if (pathname === prefix) return '/'
37
- if (pathname.startsWith(`${prefix}/`)) return pathname.slice(prefix.length)
38
- return pathname
39
- }
40
-
41
- function _buildLocalePath(
42
- pathname: string,
43
- targetLocale: string,
44
- currentLocale: string,
45
- config: I18nVirtualConfig,
46
- ): string {
47
- // Strip the current locale prefix (if any) to get the bare path
48
- const bare = _stripLocalePrefix(pathname, currentLocale)
49
- if (config.strategy === 'no_prefix') return bare
50
- if (config.strategy === 'prefix_except_default' && targetLocale === config.defaultLocale) return bare
51
- return `/${targetLocale}${bare === '/' ? '' : bare}`
52
- }
53
-
54
- // ─── Composable ───────────────────────────────────────────────────────────────
55
-
56
- /**
57
- * Internationalisation composable. Returns the active locale and helpers for
58
- * building locale-aware URLs. Requires `i18n` to be configured in `cer.config.ts`.
59
- *
60
- * Works isomorphically: on the server it reads the URL path via AsyncLocalStorage;
61
- * on the client it reads `window.location.pathname`.
62
- *
63
- * When `i18n` is not configured, `locale` equals `'default'` and `locales` is `['default']`.
64
- *
65
- * @example
66
- * ```ts
67
- * const { locale, switchLocalePath } = useLocale()
68
- * console.log(locale) // 'fr'
69
- * console.log(switchLocalePath('en', '/fr/about')) // '/about'
70
- * ```
71
- */
72
- export function useLocale(): LocaleComposable {
73
- // Read i18n config from the virtual module at runtime.
74
- // The virtual module is replaced by the bundler at build time.
75
- const g = globalThis as Record<string, unknown>
76
- const i18nConfig = g['__CER_I18N_CONFIG__'] as I18nVirtualConfig | null | undefined
77
-
78
- const locales = i18nConfig?.locales ?? ['default']
79
- const defaultLocale = i18nConfig?.defaultLocale ?? 'default'
80
- const strategy = i18nConfig?.strategy ?? 'no_prefix'
81
-
82
- // Resolve the current pathname from the server request context or window.
83
- let pathname = '/'
84
- const reqStore = g['__CER_REQ_STORE__'] as
85
- | { getStore(): { req: IncomingMessage } | null }
86
- | undefined
87
- if (reqStore) {
88
- const ctx = reqStore.getStore()
89
- if (ctx?.req.url) {
90
- try { pathname = new URL(ctx.req.url, 'http://x').pathname } catch { /* ignore */ }
91
- }
92
- } else if (typeof window !== 'undefined') {
93
- pathname = window.location.pathname
94
- }
95
-
96
- const detectedLocale = strategy !== 'no_prefix'
97
- ? (_extractLocaleFromPath(pathname, locales) ?? defaultLocale)
98
- : defaultLocale
99
-
100
- return {
101
- get locale() { return detectedLocale },
102
- get locales() { return locales },
103
- get defaultLocale() { return defaultLocale },
104
- switchLocalePath(targetLocale: string, path?: string): string {
105
- const base = path ?? pathname
106
- return _buildLocalePath(base, targetLocale, detectedLocale, { locales, defaultLocale, strategy })
107
- },
108
- }
109
- }
@@ -1,58 +0,0 @@
1
- /**
2
- * navigateTo — programmatic navigation.
3
- *
4
- * Works isomorphically:
5
- * - **Server context** (inside a loader or middleware): sends a 302 redirect
6
- * immediately by writing to the current request's `res` object via
7
- * `AsyncLocalStorage`. The response is ended and the function returns.
8
- * - **Client context**: delegates to the framework router so the SPA
9
- * navigation pipeline (middleware, loaders, isNavigating) runs normally.
10
- * Falls back to `window.location.href` if the router is not available.
11
- *
12
- * @example
13
- * ```ts
14
- * // app/middleware/require-auth.ts
15
- * export default defineMiddleware(() => {
16
- * const { loggedIn } = useAuth()
17
- * if (!loggedIn) return navigateTo('/login')
18
- * })
19
- * ```
20
- *
21
- * @example
22
- * ```ts
23
- * // app/pages/dashboard.ts
24
- * component('page-dashboard', () => {
25
- * useOnConnected(() => {
26
- * if (someCondition) navigateTo('/home')
27
- * })
28
- * })
29
- * ```
30
- */
31
-
32
- export function navigateTo(path: string): void | Promise<void> {
33
- const g = globalThis as Record<string, unknown>
34
-
35
- // Server: redirect via the request-scoped req/res store.
36
- const reqStore = g['__CER_REQ_STORE__'] as {
37
- getStore(): { res: { statusCode: number; setHeader(k: string, v: string): void; end(): void; writableEnded?: boolean } } | null
38
- } | undefined
39
-
40
- if (reqStore) {
41
- const store = reqStore.getStore()
42
- if (store?.res && !store.res.writableEnded) {
43
- store.res.statusCode = 302
44
- store.res.setHeader('Location', path)
45
- store.res.end()
46
- return
47
- }
48
- }
49
-
50
- // Client: use the framework router so the full navigation pipeline runs.
51
- const router = g['__cerRouter'] as { push(path: string): Promise<void> } | undefined
52
- if (router) return router.push(path)
53
-
54
- // Fallback: hard redirect.
55
- if (typeof window !== 'undefined') {
56
- window.location.href = path
57
- }
58
- }
@@ -1,93 +0,0 @@
1
- /**
2
- * usePageData — reads SSR-injected loader data for the current page.
3
- *
4
- * During SSR/SSG the server calls the matched route's `loader()` function
5
- * and makes the result available in two ways:
6
- *
7
- * 1. **Server render pass** — the data is stored in a per-request
8
- * `AsyncLocalStorage` context (set via `_cerDataStore.run(data, ...)` in the
9
- * entry-server template). `usePageData()` reads this store so the component
10
- * renders with real data in the initial SSR/SSG HTML.
11
- *
12
- * 2. **Client hydration** — the server also serializes the data as
13
- * `window.__CER_DATA__` in the page `<head>`. On first component render
14
- * `usePageData()` returns that value, caches it on the component context, and
15
- * returns the same cached value on all subsequent re-renders of that component
16
- * instance. The data remains available for the initial hydrated route until
17
- * the next client-side navigation clears it before loading new page data.
18
- *
19
- * **Why caching is necessary**: the render function passed to `component()` is
20
- * called on every re-render (it is the render function, not a setup function).
21
- * Without caching, `usePageData()` could return `null` on later re-renders if a
22
- * browser upgrades or re-renders the hydrated page after the initial read,
23
- * flip the `ssrData` guard from truthy → null, and re-trigger client-side fetches.
24
- *
25
- * @returns The serialized loader result, or `null` if no SSR data is present.
26
- *
27
- * @example
28
- * ```ts
29
- * component('page-blog-slug', () => {
30
- * const ssrData = usePageData<{ title: string; body: string }>()
31
- * const title = ref(ssrData?.title ?? '')
32
- * const body = ref(ssrData?.body ?? '')
33
- *
34
- * useOnConnected(() => {
35
- * if (ssrData) return // already hydrated from SSR — skip fetch
36
- * fetch(`/api/posts/${props.slug}`).then(r => r.json()).then(post => {
37
- * title.value = post.title
38
- * body.value = post.body
39
- * })
40
- * })
41
- * })
42
- * ```
43
- */
44
- import { getCurrentComponentContext } from '@jasonshimmy/custom-elements-runtime'
45
-
46
- // Key used to cache the page data on the component context object across re-renders.
47
- const _PAGE_DATA_KEY = '_cerPageData'
48
-
49
- export function usePageData<T = unknown>(): T | null {
50
- const g = globalThis as Record<string, unknown>
51
-
52
- // Server-side: read from the per-request AsyncLocalStorage context.
53
- // __CER_DATA_STORE__ is set by the entry-server template and is only present
54
- // in Node.js, so this branch is tree-shaken out of the client bundle.
55
- const store = g['__CER_DATA_STORE__'] as { getStore(): unknown } | undefined
56
- if (store) {
57
- const ssrData = store.getStore() as T | null | undefined
58
- if (ssrData !== undefined && ssrData !== null) return ssrData
59
- }
60
-
61
- // Client-side: check the component context cache first.
62
- // getCurrentComponentContext() returns the context object for the component
63
- // whose renderFn is currently executing (set by the component() runtime
64
- // before calling renderFn). Caching on the context ensures the same value is
65
- // returned on every re-render of the same element instance even if the
66
- // browser performs a later hydration-time re-render.
67
- const ctx = getCurrentComponentContext() as Record<string, unknown> | null
68
- if (ctx) {
69
- if (_PAGE_DATA_KEY in ctx) {
70
- return ctx[_PAGE_DATA_KEY] as T | null
71
- }
72
- }
73
-
74
- // Read the raw value from the global set by the server-rendered <script> tag.
75
- const data = g['__CER_DATA__'] as T | undefined | null
76
- const result: T | null = (data === undefined || data === null) ? null : data
77
-
78
- // Cache on the component context so subsequent re-renders of this element
79
- // instance return the same value without reading __CER_DATA__ again.
80
- // Use Object.defineProperty to bypass the reactive Proxy set-trap on context,
81
- // which would otherwise schedule a spurious re-render (and risk an infinite loop)
82
- // every time we first cache the value.
83
- if (ctx) {
84
- Object.defineProperty(ctx, _PAGE_DATA_KEY, {
85
- value: result,
86
- writable: false,
87
- enumerable: false,
88
- configurable: true,
89
- })
90
- }
91
-
92
- return result
93
- }
@@ -1,71 +0,0 @@
1
- /**
2
- * useRoute — returns the current route's path, params, query, and meta.
3
- *
4
- * Works isomorphically:
5
- * - **Server render pass** — reads from `globalThis.__CER_ROUTE_STORE__`
6
- * (AsyncLocalStorage populated by the entry-server handler before rendering).
7
- * - **Client** — reads from the global router instance exposed by the app
8
- * entry (`globalThis.__cerRouter`).
9
- *
10
- * @example
11
- * ```ts
12
- * // app/layouts/default.ts
13
- * component('layout-default', () => {
14
- * const route = useRoute()
15
- * return html`
16
- * <nav>${route.meta?.title ?? 'My App'}</nav>
17
- * <slot></slot>
18
- * `
19
- * })
20
- * ```
21
- *
22
- * @example
23
- * ```ts
24
- * // app/pages/post.ts
25
- * component('page-post', () => {
26
- * const { params } = useRoute()
27
- * const { data: post } = useFetch(\`/api/posts/\${params.id}\`)
28
- * })
29
- * ```
30
- */
31
-
32
- export interface RouteInfo {
33
- /** Current URL path, e.g. `'/posts/42'`. */
34
- path: string
35
- /** Dynamic route params, e.g. `{ id: '42' }`. */
36
- params: Record<string, string>
37
- /** Parsed query string params, e.g. `{ page: '2' }`. */
38
- query: Record<string, string>
39
- /** Static route meta object exported by the matched page module. */
40
- meta: Record<string, unknown> | null
41
- }
42
-
43
- export function useRoute(): RouteInfo {
44
- const g = globalThis as Record<string, unknown>
45
-
46
- // Server: read from the per-request AsyncLocalStorage context.
47
- const routeStore = g['__CER_ROUTE_STORE__'] as { getStore(): unknown } | undefined
48
- if (routeStore) {
49
- const info = routeStore.getStore() as RouteInfo | null
50
- if (info) return info
51
- }
52
-
53
- // Client: read from the global router set by the app entry.
54
- const router = g['__cerRouter'] as {
55
- getCurrent(): { path: string; query?: Record<string, string> }
56
- matchRoute(path: string): { route?: { meta?: unknown }; params?: Record<string, string> } | null
57
- } | undefined
58
-
59
- if (router) {
60
- const current = router.getCurrent()
61
- const matched = router.matchRoute(current.path)
62
- return {
63
- path: current.path,
64
- params: (matched?.params ?? {}) as Record<string, string>,
65
- query: (current.query ?? {}) as Record<string, string>,
66
- meta: (matched?.route?.meta as Record<string, unknown>) ?? null,
67
- }
68
- }
69
-
70
- return { path: '/', params: {}, query: {}, meta: null }
71
- }
@@ -1,123 +0,0 @@
1
- /** Resolved public runtime config values. Available on both server and client. */
2
- export interface RuntimeConfigPublic {
3
- [key: string]: unknown
4
- }
5
-
6
- /** Resolved private runtime config values. Available on the server only — never present on the client. */
7
- export interface RuntimeConfigPrivate {
8
- [key: string]: string | string[]
9
- }
10
-
11
- /** Return value of `useRuntimeConfig()`. */
12
- export interface RuntimeConfigResult {
13
- public: RuntimeConfigPublic
14
- private?: RuntimeConfigPrivate
15
- }
16
-
17
- /**
18
- * Returns the runtime configuration set in `cer.config.ts`.
19
- *
20
- * - `public` — available on both server and client.
21
- * - `private` — available on the server only (resolved from `process.env` at
22
- * startup). Never present on the client.
23
- *
24
- * @example
25
- * // cer.config.ts
26
- * export default defineConfig({
27
- * runtimeConfig: {
28
- * public: { apiBase: process.env.VITE_API_BASE ?? '/api' },
29
- * private: { dbUrl: '', secretKey: '' },
30
- * },
31
- * })
32
- *
33
- * // app/pages/index.ts (loader — server-only)
34
- * const { private: priv } = useRuntimeConfig()
35
- * const rows = await db.query(priv.dbUrl)
36
- */
37
- export function useRuntimeConfig(): RuntimeConfigResult {
38
- // Dynamic import resolved at runtime — avoids a static circular dependency
39
- // between the composable and the virtual module.
40
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
41
- const mod = (globalThis as any).__cerRuntimeConfig
42
- const config: RuntimeConfigResult = mod ? (mod as RuntimeConfigResult) : { public: {} }
43
-
44
- // In browser contexts, wrap the result in a Proxy that throws a clear,
45
- // actionable error if any code attempts to read `runtimeConfig.private`.
46
- // Private values are server-only secrets and are never serialized into the
47
- // client bundle — accessing them client-side is always a bug.
48
- if (typeof window !== 'undefined') {
49
- return new Proxy(config, {
50
- get(target, prop) {
51
- if (prop === 'private') {
52
- throw new Error(
53
- '[cer-app] runtimeConfig.private is not available in the browser. ' +
54
- 'Move this access into a server-only loader, middleware, or API handler.',
55
- )
56
- }
57
- return Reflect.get(target, prop)
58
- },
59
- })
60
- }
61
-
62
- return config
63
- }
64
-
65
- /**
66
- * Called once during app bootstrap to store the resolved runtimeConfig on
67
- * globalThis so useRuntimeConfig() can access it synchronously in any context
68
- * (component render, composable, server handler).
69
- */
70
- export function initRuntimeConfig(config: RuntimeConfigResult): void {
71
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
72
- ;(globalThis as any).__cerRuntimeConfig = config
73
- }
74
-
75
- /**
76
- * Converts a camelCase or mixed key to UPPER_SNAKE_CASE for env var lookup.
77
- * Examples: `dbUrl` → `DB_URL`, `secretKey` → `SECRET_KEY`, `API_KEY` → `API_KEY`.
78
- */
79
- function toUpperSnakeCase(key: string): string {
80
- return key
81
- .replace(/([a-z])([A-Z])/g, '$1_$2')
82
- .toUpperCase()
83
- }
84
-
85
- /**
86
- * Resolves a private config object by looking up each key in the supplied
87
- * environment variable map, with the following precedence:
88
- *
89
- * 1. `env[key]` — exact case (e.g. `process.env.dbUrl`)
90
- * 2. `env[UPPER_SNAKE_CASE(key)]` — conventional env var form (e.g. `process.env.DB_URL`)
91
- * 3. `defaultValue` — the declared default from `cer.config.ts`
92
- *
93
- * Array values (e.g. `sessionSecret: [newSecret, oldSecret]`) are passed
94
- * through unchanged — they are already resolved by the caller at config time.
95
- *
96
- * Accepts an optional `env` parameter so the function is unit-testable
97
- * without mutating `process.env`.
98
- */
99
- export function resolvePrivateConfig(
100
- defaults: Record<string, string | string[]>,
101
- env: Record<string, string | undefined> = process.env as Record<string, string | undefined>,
102
- ): Record<string, string | string[]> {
103
- return Object.fromEntries(
104
- Object.entries(defaults).map(([key, defaultValue]) => {
105
- // Array values are already fully resolved at config build time — pass through.
106
- if (Array.isArray(defaultValue)) {
107
- return [key, defaultValue.filter(Boolean)]
108
- }
109
- const envKey = toUpperSnakeCase(key)
110
- const resolved = env[key] ?? env[envKey] ?? defaultValue
111
- // Warn when no env var was found and the declared default is an empty string.
112
- // An empty-string default is the conventional way to declare a required secret
113
- // (the key exists for typing purposes but has no safe default value).
114
- if (resolved === '' && env[key] === undefined && env[envKey] === undefined) {
115
- console.warn(
116
- `[cer-app] runtimeConfig.private: "${key}" is an empty string — ` +
117
- `set ${envKey} in the environment to provide a value.`,
118
- )
119
- }
120
- return [key, resolved]
121
- }),
122
- )
123
- }
@@ -1,80 +0,0 @@
1
- import { useHead } from './use-head.js'
2
-
3
- /**
4
- * Convenience input for common SEO meta tags.
5
- * Pass to `useSeoMeta()` — it maps each field to the correct `<meta>` or `<title>` tag automatically.
6
- * All fields are optional.
7
- */
8
- export interface SeoMetaInput {
9
- /** Sets the document title. */
10
- title?: string
11
- /** Sets the meta description. */
12
- description?: string
13
- // Open Graph
14
- ogTitle?: string
15
- ogDescription?: string
16
- ogImage?: string
17
- ogUrl?: string
18
- /** e.g. `'website'`, `'article'`. No tag is emitted when omitted. */
19
- ogType?: string
20
- ogSiteName?: string
21
- // Twitter / X
22
- /** e.g. `'summary'`, `'summary_large_image'`. No tag is emitted when omitted. */
23
- twitterCard?: string
24
- twitterTitle?: string
25
- twitterDescription?: string
26
- twitterImage?: string
27
- /** Twitter/X site handle, e.g. '@mysite'. */
28
- twitterSite?: string
29
- /** Canonical URL injected as <link rel="canonical">. */
30
- canonical?: string
31
- }
32
-
33
- /**
34
- * Thin wrapper over `useHead()` for common SEO tags.
35
- *
36
- * Sets the page title, meta description, Open Graph tags, Twitter Card tags,
37
- * and a canonical link element. Only tags with a non-undefined value are emitted.
38
- *
39
- * It is auto-imported, so you don't need to import it manually.
40
- *
41
- * @example
42
- * ```ts
43
- * useSeoMeta({
44
- * title: 'My page',
45
- * description: 'A great page.',
46
- * ogImage: 'https://example.com/og.png',
47
- * canonical: 'https://example.com/my-page',
48
- * })
49
- * ```
50
- */
51
- export function useSeoMeta(input: SeoMetaInput): void {
52
- const meta: Array<Record<string, string>> = []
53
- const link: Array<Record<string, string>> = []
54
-
55
- if (input.description !== undefined) meta.push({ name: 'description', content: input.description })
56
-
57
- // Open Graph
58
- if (input.ogTitle !== undefined) meta.push({ property: 'og:title', content: input.ogTitle })
59
- if (input.ogDescription !== undefined) meta.push({ property: 'og:description', content: input.ogDescription })
60
- if (input.ogImage !== undefined) meta.push({ property: 'og:image', content: input.ogImage })
61
- if (input.ogUrl !== undefined) meta.push({ property: 'og:url', content: input.ogUrl })
62
- if (input.ogType !== undefined) meta.push({ property: 'og:type', content: input.ogType })
63
- if (input.ogSiteName !== undefined) meta.push({ property: 'og:site_name', content: input.ogSiteName })
64
-
65
- // Twitter / X
66
- if (input.twitterCard !== undefined) meta.push({ name: 'twitter:card', content: input.twitterCard })
67
- if (input.twitterTitle !== undefined) meta.push({ name: 'twitter:title', content: input.twitterTitle })
68
- if (input.twitterDescription !== undefined) meta.push({ name: 'twitter:description', content: input.twitterDescription })
69
- if (input.twitterImage !== undefined) meta.push({ name: 'twitter:image', content: input.twitterImage })
70
- if (input.twitterSite !== undefined) meta.push({ name: 'twitter:site', content: input.twitterSite })
71
-
72
- // Canonical link
73
- if (input.canonical !== undefined) link.push({ rel: 'canonical', href: input.canonical })
74
-
75
- useHead({
76
- title: input.title,
77
- meta: meta.length > 0 ? meta : undefined,
78
- link: link.length > 0 ? link : undefined,
79
- })
80
- }