@jasonshimmy/vite-plugin-cer-app 0.23.2 → 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.
- package/dist/cli/checks/lighthouse.d.ts +26 -0
- package/dist/cli/checks/lighthouse.d.ts.map +1 -0
- package/dist/cli/checks/lighthouse.js +121 -0
- package/dist/cli/checks/lighthouse.js.map +1 -0
- package/dist/cli/checks/links.d.ts +12 -0
- package/dist/cli/checks/links.d.ts.map +1 -0
- package/dist/cli/checks/links.js +89 -0
- package/dist/cli/checks/links.js.map +1 -0
- package/dist/cli/checks/performance.d.ts +17 -0
- package/dist/cli/checks/performance.d.ts.map +1 -0
- package/dist/cli/checks/performance.js +61 -0
- package/dist/cli/checks/performance.js.map +1 -0
- package/dist/cli/commands/check.d.ts +3 -0
- package/dist/cli/commands/check.d.ts.map +1 -0
- package/dist/cli/commands/check.js +85 -0
- package/dist/cli/commands/check.js.map +1 -0
- package/dist/cli/create/index.d.ts +11 -1
- package/dist/cli/create/index.d.ts.map +1 -1
- package/dist/cli/create/index.js +135 -65
- package/dist/cli/create/index.js.map +1 -1
- package/dist/cli/create/templates/spa/package.json.tpl +5 -3
- package/dist/cli/create/templates/ssg/cer.config.ts.tpl +2 -0
- package/dist/cli/create/templates/ssg/package.json.tpl +5 -3
- package/dist/cli/create/templates/ssr/package.json.tpl +5 -3
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/plugin/build-ssg.d.ts +22 -6
- package/dist/plugin/build-ssg.d.ts.map +1 -1
- package/dist/plugin/build-ssg.js +227 -17
- package/dist/plugin/build-ssg.js.map +1 -1
- package/dist/plugin/content/parser.d.ts.map +1 -1
- package/dist/plugin/content/parser.js +54 -10
- package/dist/plugin/content/parser.js.map +1 -1
- package/dist/plugin/dev-server.d.ts +4 -1
- package/dist/plugin/dev-server.d.ts.map +1 -1
- package/dist/plugin/dev-server.js.map +1 -1
- package/dist/plugin/dts-generator.d.ts.map +1 -1
- package/dist/plugin/dts-generator.js +50 -8
- package/dist/plugin/dts-generator.js.map +1 -1
- package/dist/plugin/generated-dir.d.ts +2 -0
- package/dist/plugin/generated-dir.d.ts.map +1 -1
- package/dist/plugin/generated-dir.js +17 -6
- package/dist/plugin/generated-dir.js.map +1 -1
- package/dist/plugin/html-post-process.d.ts +6 -0
- package/dist/plugin/html-post-process.d.ts.map +1 -1
- package/dist/plugin/html-post-process.js +24 -0
- package/dist/plugin/html-post-process.js.map +1 -1
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +60 -13
- package/dist/plugin/index.js.map +1 -1
- package/dist/plugin/transforms/auto-import.d.ts.map +1 -1
- package/dist/plugin/transforms/auto-import.js +7 -0
- package/dist/plugin/transforms/auto-import.js.map +1 -1
- package/dist/plugin/transforms/prune-runtime-css.d.ts +8 -0
- package/dist/plugin/transforms/prune-runtime-css.d.ts.map +1 -0
- package/dist/plugin/transforms/prune-runtime-css.js +40 -0
- package/dist/plugin/transforms/prune-runtime-css.js.map +1 -0
- package/dist/runtime/app-template.d.ts +1 -1
- package/dist/runtime/app-template.d.ts.map +1 -1
- package/dist/runtime/app-template.js +206 -36
- package/dist/runtime/app-template.js.map +1 -1
- package/dist/runtime/composables/index.d.ts +4 -0
- package/dist/runtime/composables/index.d.ts.map +1 -1
- package/dist/runtime/composables/index.js +2 -0
- package/dist/runtime/composables/index.js.map +1 -1
- package/dist/runtime/composables/use-active-headings.d.ts +24 -0
- package/dist/runtime/composables/use-active-headings.d.ts.map +1 -0
- package/dist/runtime/composables/use-active-headings.js +112 -0
- package/dist/runtime/composables/use-active-headings.js.map +1 -0
- package/dist/runtime/composables/use-content-page.d.ts +45 -0
- package/dist/runtime/composables/use-content-page.d.ts.map +1 -0
- package/dist/runtime/composables/use-content-page.js +179 -0
- package/dist/runtime/composables/use-content-page.js.map +1 -0
- package/dist/runtime/composables/use-content-search.d.ts.map +1 -1
- package/dist/runtime/composables/use-content-search.js +1 -5
- package/dist/runtime/composables/use-content-search.js.map +1 -1
- package/dist/runtime/composables/use-fetch.d.ts +2 -1
- package/dist/runtime/composables/use-fetch.d.ts.map +1 -1
- package/dist/runtime/composables/use-fetch.js +112 -43
- package/dist/runtime/composables/use-fetch.js.map +1 -1
- package/dist/runtime/composables/use-route.d.ts.map +1 -1
- package/dist/runtime/composables/use-route.js +39 -11
- package/dist/runtime/composables/use-route.js.map +1 -1
- package/dist/runtime/content/client.js +2 -2
- package/dist/runtime/content/client.js.map +1 -1
- package/dist/runtime/entry-server-template.d.ts +16 -1
- package/dist/runtime/entry-server-template.d.ts.map +1 -1
- package/dist/runtime/entry-server-template.js +120 -13
- package/dist/runtime/entry-server-template.js.map +1 -1
- package/dist/types/config.d.ts +45 -4
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js.map +1 -1
- package/dist/types/middleware.d.ts +2 -2
- package/dist/types/middleware.d.ts.map +1 -1
- package/package.json +22 -19
- package/.github/copilot-instructions.md +0 -169
- package/.github/workflows/publish.yml +0 -257
- package/.nvmrc +0 -1
- package/CHANGELOG.md +0 -236
- package/CLAUDE.md +0 -113
- package/commits.txt +0 -1
- package/cypress.config.ts +0 -16
- package/docs/authentication.md +0 -285
- package/docs/cli.md +0 -324
- package/docs/components.md +0 -237
- package/docs/composables.md +0 -907
- package/docs/configuration.md +0 -696
- package/docs/content.md +0 -570
- package/docs/data-loading.md +0 -336
- package/docs/getting-started.md +0 -237
- package/docs/head-management.md +0 -212
- package/docs/i18n.md +0 -159
- package/docs/layouts.md +0 -224
- package/docs/middleware.md +0 -234
- package/docs/plugins.md +0 -170
- package/docs/rendering-modes.md +0 -377
- package/docs/routing.md +0 -485
- package/docs/server-api.md +0 -253
- package/docs/testing.md +0 -455
- package/docs/use-fetch.md +0 -183
- package/e2e/cypress/e2e/api.cy.ts +0 -123
- package/e2e/cypress/e2e/async-component.cy.ts +0 -27
- package/e2e/cypress/e2e/component-splitting.cy.ts +0 -50
- package/e2e/cypress/e2e/content.cy.ts +0 -425
- package/e2e/cypress/e2e/cookie.cy.ts +0 -85
- package/e2e/cypress/e2e/data.cy.ts +0 -158
- package/e2e/cypress/e2e/error-boundary.cy.ts +0 -88
- package/e2e/cypress/e2e/fouc.cy.ts +0 -254
- package/e2e/cypress/e2e/group-meta.cy.ts +0 -36
- package/e2e/cypress/e2e/head.cy.ts +0 -89
- package/e2e/cypress/e2e/i18n.cy.ts +0 -79
- package/e2e/cypress/e2e/interactive.cy.ts +0 -137
- package/e2e/cypress/e2e/isr-nested-runtime.cy.ts +0 -102
- package/e2e/cypress/e2e/jit-css-custom-colors.cy.ts +0 -43
- package/e2e/cypress/e2e/middleware-chain.cy.ts +0 -89
- package/e2e/cypress/e2e/middleware-status.cy.ts +0 -30
- package/e2e/cypress/e2e/middleware.cy.ts +0 -45
- package/e2e/cypress/e2e/navigate.cy.ts +0 -39
- package/e2e/cypress/e2e/observability.cy.ts +0 -77
- package/e2e/cypress/e2e/per-route-error.cy.ts +0 -42
- package/e2e/cypress/e2e/per-route-render.cy.ts +0 -70
- package/e2e/cypress/e2e/preview-hardening.cy.ts +0 -88
- package/e2e/cypress/e2e/routes.cy.ts +0 -128
- package/e2e/cypress/e2e/seo-meta.cy.ts +0 -108
- package/e2e/cypress/e2e/server-middleware.cy.ts +0 -46
- package/e2e/cypress/e2e/session-rotation.cy.ts +0 -25
- package/e2e/cypress/e2e/session.cy.ts +0 -73
- package/e2e/cypress/e2e/ssr-render-error.cy.ts +0 -68
- package/e2e/cypress/e2e/synthetic-404.cy.ts +0 -45
- package/e2e/cypress/e2e/use-page-data.cy.ts +0 -122
- package/e2e/cypress/e2e/use-state.cy.ts +0 -138
- package/e2e/cypress/support/commands.ts +0 -120
- package/e2e/cypress/support/e2e.ts +0 -10
- package/e2e/cypress/tsconfig.json +0 -14
- package/e2e/kitchen-sink/app/components/ks-badge.ts +0 -8
- package/e2e/kitchen-sink/app/composables/useKsCounter.ts +0 -9
- package/e2e/kitchen-sink/app/error.ts +0 -18
- package/e2e/kitchen-sink/app/layouts/admin.ts +0 -13
- package/e2e/kitchen-sink/app/layouts/default.ts +0 -25
- package/e2e/kitchen-sink/app/layouts/group.ts +0 -9
- package/e2e/kitchen-sink/app/layouts/minimal.ts +0 -7
- package/e2e/kitchen-sink/app/loading.ts +0 -9
- package/e2e/kitchen-sink/app/middleware/auth.ts +0 -9
- package/e2e/kitchen-sink/app/middleware/custom-log.ts +0 -4
- package/e2e/kitchen-sink/app/middleware/group-auth.ts +0 -7
- package/e2e/kitchen-sink/app/middleware/logger.ts +0 -14
- package/e2e/kitchen-sink/app/pages/(auth)/login.ts +0 -13
- package/e2e/kitchen-sink/app/pages/(auth)/protected.ts +0 -16
- package/e2e/kitchen-sink/app/pages/404.ts +0 -9
- package/e2e/kitchen-sink/app/pages/about.ts +0 -17
- package/e2e/kitchen-sink/app/pages/admin/_layout.ts +0 -1
- package/e2e/kitchen-sink/app/pages/admin/dashboard.ts +0 -11
- package/e2e/kitchen-sink/app/pages/async-component-error-test.ts +0 -18
- package/e2e/kitchen-sink/app/pages/async-component-test.ts +0 -18
- package/e2e/kitchen-sink/app/pages/blog/[slug].ts +0 -59
- package/e2e/kitchen-sink/app/pages/blog/index.ts +0 -51
- package/e2e/kitchen-sink/app/pages/content-blog.ts +0 -37
- package/e2e/kitchen-sink/app/pages/content-doc.ts +0 -42
- package/e2e/kitchen-sink/app/pages/content-fallback.ts +0 -36
- package/e2e/kitchen-sink/app/pages/content-guides.ts +0 -35
- package/e2e/kitchen-sink/app/pages/content-index.ts +0 -39
- package/e2e/kitchen-sink/app/pages/content-search.ts +0 -36
- package/e2e/kitchen-sink/app/pages/cookie-test.ts +0 -22
- package/e2e/kitchen-sink/app/pages/counter.ts +0 -17
- package/e2e/kitchen-sink/app/pages/group-auth-blocked.ts +0 -9
- package/e2e/kitchen-sink/app/pages/group-meta-test/_layout.ts +0 -6
- package/e2e/kitchen-sink/app/pages/group-meta-test/custom-mw.ts +0 -14
- package/e2e/kitchen-sink/app/pages/group-meta-test/page.ts +0 -9
- package/e2e/kitchen-sink/app/pages/group-meta-test/protected.ts +0 -8
- package/e2e/kitchen-sink/app/pages/head.ts +0 -20
- package/e2e/kitchen-sink/app/pages/i18n-test.ts +0 -14
- package/e2e/kitchen-sink/app/pages/index.ts +0 -27
- package/e2e/kitchen-sink/app/pages/isr-test.ts +0 -17
- package/e2e/kitchen-sink/app/pages/items/[id].ts +0 -20
- package/e2e/kitchen-sink/app/pages/jit-css-custom-colors-test.ts +0 -14
- package/e2e/kitchen-sink/app/pages/loader-error-test.ts +0 -13
- package/e2e/kitchen-sink/app/pages/loader-props-test.ts +0 -19
- package/e2e/kitchen-sink/app/pages/loader-response-error-test.ts +0 -13
- package/e2e/kitchen-sink/app/pages/middleware-chain-test.ts +0 -12
- package/e2e/kitchen-sink/app/pages/middleware-status-test.ts +0 -9
- package/e2e/kitchen-sink/app/pages/navigate-test.ts +0 -16
- package/e2e/kitchen-sink/app/pages/observability-test.ts +0 -25
- package/e2e/kitchen-sink/app/pages/per-route-error-test.error.ts +0 -13
- package/e2e/kitchen-sink/app/pages/per-route-error-test.ts +0 -15
- package/e2e/kitchen-sink/app/pages/plugin-dsd-test.ts +0 -10
- package/e2e/kitchen-sink/app/pages/render-error-test.ts +0 -12
- package/e2e/kitchen-sink/app/pages/render-server-test.ts +0 -12
- package/e2e/kitchen-sink/app/pages/render-spa-test.ts +0 -12
- package/e2e/kitchen-sink/app/pages/route-info.ts +0 -14
- package/e2e/kitchen-sink/app/pages/seo-test.ts +0 -23
- package/e2e/kitchen-sink/app/pages/session-rotation-test.ts +0 -25
- package/e2e/kitchen-sink/app/pages/use-state-test.ts +0 -37
- package/e2e/kitchen-sink/app/plugins/01.setup.ts +0 -7
- package/e2e/kitchen-sink/app/plugins/02.ks-plugin-components.ts +0 -27
- package/e2e/kitchen-sink/cer-auto-imports.d.ts +0 -51
- package/e2e/kitchen-sink/cer-env.d.ts +0 -35
- package/e2e/kitchen-sink/cer-tsconfig.json +0 -30
- package/e2e/kitchen-sink/cer.config.ts +0 -43
- package/e2e/kitchen-sink/content/01.guides/01.index.md +0 -8
- package/e2e/kitchen-sink/content/01.guides/02.intro.md +0 -8
- package/e2e/kitchen-sink/content/01.guides/10.advanced.md +0 -8
- package/e2e/kitchen-sink/content/blog/2026-04-01-hello.md +0 -26
- package/e2e/kitchen-sink/content/blog/2026-04-02-draft.md +0 -10
- package/e2e/kitchen-sink/content/blog/index.md +0 -8
- package/e2e/kitchen-sink/content/blog/no-frontmatter.md +0 -7
- package/e2e/kitchen-sink/content/docs/getting-started.md +0 -48
- package/e2e/kitchen-sink/content/index.md +0 -16
- package/e2e/kitchen-sink/server/api/echo.ts +0 -12
- package/e2e/kitchen-sink/server/api/health.ts +0 -3
- package/e2e/kitchen-sink/server/api/posts/[slug].ts +0 -11
- package/e2e/kitchen-sink/server/api/posts/index.ts +0 -5
- package/e2e/kitchen-sink/server/api/session.ts +0 -23
- package/e2e/kitchen-sink/server/data/posts.ts +0 -21
- package/e2e/kitchen-sink/server/middleware/01-headers.ts +0 -6
- package/e2e/kitchen-sink/server/middleware/02-status-test.ts +0 -10
- package/e2e/kitchen-sink/tsconfig.json +0 -3
- package/e2e/scripts/clean.mjs +0 -14
- package/eslint.config.ts +0 -22
- package/src/__tests__/cli/adapters/cloudflare-worker.integration.test.ts +0 -132
- package/src/__tests__/cli/adapters/cloudflare.test.ts +0 -332
- package/src/__tests__/cli/adapters/netlify-bridge.integration.test.ts +0 -139
- package/src/__tests__/cli/adapters/netlify.test.ts +0 -286
- package/src/__tests__/cli/adapters/vercel-launcher.integration.test.ts +0 -129
- package/src/__tests__/cli/adapters/vercel.test.ts +0 -263
- package/src/__tests__/cli/preview-hardening.test.ts +0 -265
- package/src/__tests__/cli/preview-isr.test.ts +0 -320
- package/src/__tests__/index.test.ts +0 -21
- package/src/__tests__/plugin/app-template.test.ts +0 -166
- package/src/__tests__/plugin/build-ssg-render.test.ts +0 -155
- package/src/__tests__/plugin/build-ssg.test.ts +0 -598
- package/src/__tests__/plugin/build-ssr.test.ts +0 -192
- package/src/__tests__/plugin/cer-app-plugin.test.ts +0 -552
- package/src/__tests__/plugin/content/emitter.test.ts +0 -117
- package/src/__tests__/plugin/content/loader.test.ts +0 -154
- package/src/__tests__/plugin/content/parser.test.ts +0 -381
- package/src/__tests__/plugin/content/path-utils.test.ts +0 -69
- package/src/__tests__/plugin/content/search.test.ts +0 -119
- package/src/__tests__/plugin/dev-server.test.ts +0 -813
- package/src/__tests__/plugin/dts-generator.test.ts +0 -394
- package/src/__tests__/plugin/entry-server-template.test.ts +0 -385
- package/src/__tests__/plugin/generated-dir.test.ts +0 -144
- package/src/__tests__/plugin/html-post-process.test.ts +0 -146
- package/src/__tests__/plugin/path-utils.test.ts +0 -411
- package/src/__tests__/plugin/resolve-config.test.ts +0 -233
- package/src/__tests__/plugin/scanner.test.ts +0 -186
- package/src/__tests__/plugin/transforms/auto-import.test.ts +0 -510
- package/src/__tests__/plugin/transforms/head-inject.test.ts +0 -178
- package/src/__tests__/plugin/virtual/composables.test.ts +0 -57
- package/src/__tests__/plugin/virtual/content-components.test.ts +0 -66
- package/src/__tests__/plugin/virtual/error.test.ts +0 -71
- package/src/__tests__/plugin/virtual/layouts.test.ts +0 -70
- package/src/__tests__/plugin/virtual/loading.test.ts +0 -72
- package/src/__tests__/plugin/virtual/middleware.test.ts +0 -83
- package/src/__tests__/plugin/virtual/plugins.test.ts +0 -129
- package/src/__tests__/plugin/virtual/routes.test.ts +0 -884
- package/src/__tests__/plugin/virtual/server-api.test.ts +0 -164
- package/src/__tests__/plugin/virtual/server-middleware.test.ts +0 -102
- package/src/__tests__/runtime/app-template.test.ts +0 -208
- package/src/__tests__/runtime/define-middleware.test.ts +0 -64
- package/src/__tests__/runtime/define-server-middleware.test.ts +0 -54
- package/src/__tests__/runtime/entry-client-template.test.ts +0 -61
- package/src/__tests__/runtime/isr-handler.test.ts +0 -338
- package/src/__tests__/runtime/oauth/handler.test.ts +0 -358
- package/src/__tests__/runtime/oauth/providers.test.ts +0 -47
- package/src/__tests__/runtime/oauth-index.test.ts +0 -43
- package/src/__tests__/runtime/use-auth.test.ts +0 -169
- package/src/__tests__/runtime/use-content-search-composable.test.ts +0 -405
- package/src/__tests__/runtime/use-content-search.test.ts +0 -163
- package/src/__tests__/runtime/use-content.test.ts +0 -226
- package/src/__tests__/runtime/use-cookie.test.ts +0 -277
- package/src/__tests__/runtime/use-fetch-component.test.ts +0 -214
- package/src/__tests__/runtime/use-fetch.test.ts +0 -377
- package/src/__tests__/runtime/use-head.test.ts +0 -311
- package/src/__tests__/runtime/use-inject-client.test.ts +0 -67
- package/src/__tests__/runtime/use-inject.test.ts +0 -66
- package/src/__tests__/runtime/use-locale.test.ts +0 -152
- package/src/__tests__/runtime/use-navigate.test.ts +0 -121
- package/src/__tests__/runtime/use-page-data.test.ts +0 -298
- package/src/__tests__/runtime/use-route.test.ts +0 -156
- package/src/__tests__/runtime/use-runtime-config.test.ts +0 -182
- package/src/__tests__/runtime/use-seo-meta.test.ts +0 -109
- package/src/__tests__/runtime/use-session.test.ts +0 -320
- package/src/__tests__/runtime/use-state.test.ts +0 -340
- package/src/__tests__/types/config.test.ts +0 -18
- package/src/cli/adapters/cloudflare.ts +0 -335
- package/src/cli/adapters/netlify.ts +0 -326
- package/src/cli/adapters/vercel.ts +0 -311
- package/src/cli/commands/adapt.ts +0 -84
- package/src/cli/commands/build.ts +0 -165
- package/src/cli/commands/dev.ts +0 -125
- package/src/cli/commands/generate.ts +0 -91
- package/src/cli/commands/preview-isr.ts +0 -172
- package/src/cli/commands/preview.ts +0 -523
- package/src/cli/create/index.ts +0 -275
- package/src/cli/create/templates/shared/.gitignore.tpl +0 -25
- package/src/cli/create/templates/shared/app/layouts/default.ts.tpl +0 -15
- package/src/cli/create/templates/shared/app/pages/index.ts.tpl +0 -8
- package/src/cli/create/templates/shared/index.html.tpl +0 -12
- package/src/cli/create/templates/shared/tsconfig.json.tpl +0 -6
- package/src/cli/create/templates/spa/cer.config.ts.tpl +0 -6
- package/src/cli/create/templates/spa/package.json.tpl +0 -18
- package/src/cli/create/templates/ssg/cer.config.ts.tpl +0 -10
- package/src/cli/create/templates/ssg/package.json.tpl +0 -19
- package/src/cli/create/templates/ssr/cer.config.ts.tpl +0 -6
- package/src/cli/create/templates/ssr/package.json.tpl +0 -18
- package/src/cli/index.ts +0 -22
- package/src/index.ts +0 -20
- package/src/plugin/build-ssg.ts +0 -403
- package/src/plugin/build-ssr.ts +0 -134
- package/src/plugin/content/emitter.ts +0 -50
- package/src/plugin/content/index.ts +0 -233
- package/src/plugin/content/parser.ts +0 -259
- package/src/plugin/content/path-utils.ts +0 -55
- package/src/plugin/content/scanner.ts +0 -26
- package/src/plugin/content/search.ts +0 -28
- package/src/plugin/dev-server.ts +0 -379
- package/src/plugin/dts-generator.ts +0 -273
- package/src/plugin/generated-dir.ts +0 -121
- package/src/plugin/html-post-process.ts +0 -96
- package/src/plugin/index.ts +0 -584
- package/src/plugin/path-utils.ts +0 -186
- package/src/plugin/scanner.ts +0 -65
- package/src/plugin/transforms/auto-import.ts +0 -206
- package/src/plugin/transforms/head-inject.ts +0 -161
- package/src/plugin/virtual/composables.ts +0 -28
- package/src/plugin/virtual/content-components.ts +0 -83
- package/src/plugin/virtual/error.ts +0 -34
- package/src/plugin/virtual/layouts.ts +0 -41
- package/src/plugin/virtual/loading.ts +0 -32
- package/src/plugin/virtual/middleware.ts +0 -45
- package/src/plugin/virtual/plugins.ts +0 -46
- package/src/plugin/virtual/routes.ts +0 -514
- package/src/plugin/virtual/server-api.ts +0 -85
- package/src/plugin/virtual/server-middleware.ts +0 -44
- package/src/runtime/app-template.ts +0 -377
- package/src/runtime/composables/define-middleware.ts +0 -17
- package/src/runtime/composables/define-server-middleware.ts +0 -18
- package/src/runtime/composables/index.ts +0 -27
- package/src/runtime/composables/use-auth.ts +0 -125
- package/src/runtime/composables/use-content-search.ts +0 -205
- package/src/runtime/composables/use-content.ts +0 -146
- package/src/runtime/composables/use-cookie.ts +0 -135
- package/src/runtime/composables/use-fetch.ts +0 -438
- package/src/runtime/composables/use-head.ts +0 -234
- package/src/runtime/composables/use-inject.ts +0 -49
- package/src/runtime/composables/use-locale.ts +0 -109
- package/src/runtime/composables/use-navigate.ts +0 -58
- package/src/runtime/composables/use-page-data.ts +0 -93
- package/src/runtime/composables/use-route.ts +0 -71
- package/src/runtime/composables/use-runtime-config.ts +0 -123
- package/src/runtime/composables/use-seo-meta.ts +0 -80
- package/src/runtime/composables/use-session.ts +0 -186
- package/src/runtime/composables/use-state.ts +0 -92
- package/src/runtime/content/client.ts +0 -168
- package/src/runtime/entry-client-template.ts +0 -39
- package/src/runtime/entry-server-template.ts +0 -493
- package/src/runtime/isr-handler.ts +0 -184
- package/src/runtime/oauth/handler.ts +0 -407
- package/src/runtime/oauth/index.ts +0 -49
- package/src/runtime/oauth/providers.ts +0 -38
- package/src/types/api.ts +0 -40
- package/src/types/config.ts +0 -379
- package/src/types/content.ts +0 -66
- package/src/types/index.ts +0 -7
- package/src/types/middleware.ts +0 -63
- package/src/types/page.ts +0 -117
- package/src/types/plugin.ts +0 -34
- package/tsconfig.build.json +0 -10
- package/tsconfig.json +0 -19
- package/vitest.config.ts +0 -33
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
import { useCookie } from './use-cookie.js'
|
|
2
|
-
import { useRuntimeConfig } from './use-runtime-config.js'
|
|
3
|
-
|
|
4
|
-
// ─── Types ────────────────────────────────────────────────────────────────────
|
|
5
|
-
|
|
6
|
-
/** Options for `useSession()`. Controls the cookie name and expiry. */
|
|
7
|
-
export interface SessionOptions {
|
|
8
|
-
/**
|
|
9
|
-
* Cookie name for the session. Defaults to `'session'`.
|
|
10
|
-
*/
|
|
11
|
-
name?: string
|
|
12
|
-
/**
|
|
13
|
-
* Max-age in seconds. Defaults to 7 days (604 800 s).
|
|
14
|
-
*/
|
|
15
|
-
maxAge?: number
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* HMAC-signed cookie session returned by `useSession()`.
|
|
20
|
-
* All methods are async because signing and verification use the Web Crypto API.
|
|
21
|
-
*/
|
|
22
|
-
export interface SessionComposable<T extends Record<string, unknown> = Record<string, unknown>> {
|
|
23
|
-
/**
|
|
24
|
-
* Reads and verifies the session cookie. Returns the session data or `null`
|
|
25
|
-
* if the cookie is absent, expired, or its signature is invalid.
|
|
26
|
-
*/
|
|
27
|
-
get(): Promise<T | null>
|
|
28
|
-
/**
|
|
29
|
-
* Signs `data` and writes it as a session cookie. Existing session data is
|
|
30
|
-
* replaced entirely.
|
|
31
|
-
*/
|
|
32
|
-
set(data: T): Promise<void>
|
|
33
|
-
/**
|
|
34
|
-
* Clears the session cookie by setting `maxAge = 0`.
|
|
35
|
-
*/
|
|
36
|
-
clear(): Promise<void>
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// ─── HMAC-SHA-256 helpers (Web Crypto — available in Node ≥ 18 and Workers) ──
|
|
40
|
-
|
|
41
|
-
const ENC = new TextEncoder()
|
|
42
|
-
|
|
43
|
-
async function _importKey(secret: string): Promise<CryptoKey> {
|
|
44
|
-
return crypto.subtle.importKey(
|
|
45
|
-
'raw',
|
|
46
|
-
ENC.encode(secret),
|
|
47
|
-
{ name: 'HMAC', hash: 'SHA-256' },
|
|
48
|
-
false,
|
|
49
|
-
['sign', 'verify'],
|
|
50
|
-
)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function _b64u(buf: ArrayBuffer): string {
|
|
54
|
-
return btoa(String.fromCharCode(...new Uint8Array(buf)))
|
|
55
|
-
.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '')
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function _b64uDecode(s: string): Uint8Array {
|
|
59
|
-
const b64 = s.replace(/-/g, '+').replace(/_/g, '/')
|
|
60
|
-
const raw = atob(b64.padEnd(b64.length + (4 - b64.length % 4) % 4, '='))
|
|
61
|
-
return Uint8Array.from(raw, (c) => c.charCodeAt(0))
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Signs a JSON-serialisable payload. Returns `<payload_b64u>.<sig_b64u>`.
|
|
66
|
-
*/
|
|
67
|
-
async function _sign(key: CryptoKey, data: unknown): Promise<string> {
|
|
68
|
-
const payload = _b64u(ENC.encode(JSON.stringify(data)).buffer as ArrayBuffer)
|
|
69
|
-
const sig = await crypto.subtle.sign('HMAC', key, ENC.encode(payload))
|
|
70
|
-
return `${payload}.${_b64u(sig)}`
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Verifies a signed cookie value. Returns the payload or `null` on failure.
|
|
75
|
-
*/
|
|
76
|
-
async function _verify<T>(key: CryptoKey, token: string): Promise<T | null> {
|
|
77
|
-
const dot = token.lastIndexOf('.')
|
|
78
|
-
if (dot < 0) return null
|
|
79
|
-
const payload = token.slice(0, dot)
|
|
80
|
-
const sig = _b64uDecode(token.slice(dot + 1))
|
|
81
|
-
const ok = await crypto.subtle.verify('HMAC', key, sig.buffer as ArrayBuffer, ENC.encode(payload))
|
|
82
|
-
if (!ok) return null
|
|
83
|
-
try {
|
|
84
|
-
return JSON.parse(new TextDecoder().decode(_b64uDecode(payload))) as T
|
|
85
|
-
} catch {
|
|
86
|
-
return null
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// ─── Composable ───────────────────────────────────────────────────────────────
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Signed-cookie session composable.
|
|
94
|
-
*
|
|
95
|
-
* Session data is JSON-serialised, HMAC-SHA-256 signed, and stored in a single
|
|
96
|
-
* HTTP cookie. The signing key is read from `runtimeConfig.private.sessionSecret`
|
|
97
|
-
* (declared as an empty-string default; resolved from `SESSION_SECRET` env var
|
|
98
|
-
* at server startup).
|
|
99
|
-
*
|
|
100
|
-
* Works isomorphically: on the server it uses `useCookie()` which reads/writes
|
|
101
|
-
* HTTP headers via `AsyncLocalStorage`; on the client it reads the cookie from
|
|
102
|
-
* `document.cookie` (client-side session reading only — no signing key in client).
|
|
103
|
-
*
|
|
104
|
-
* @example
|
|
105
|
-
* ```ts
|
|
106
|
-
* // server/middleware/auth.ts
|
|
107
|
-
* export default defineServerMiddleware(async (req, res, next) => {
|
|
108
|
-
* const session = useSession<{ userId: string }>()
|
|
109
|
-
* const data = await session.get()
|
|
110
|
-
* if (!data?.userId) { res.statusCode = 401; res.end(); return }
|
|
111
|
-
* ;(req as any).user = data
|
|
112
|
-
* next()
|
|
113
|
-
* })
|
|
114
|
-
*
|
|
115
|
-
* // app/pages/login.ts — loader
|
|
116
|
-
* export const loader = async ({ req }) => {
|
|
117
|
-
* const session = useSession<{ userId: string }>()
|
|
118
|
-
* await session.set({ userId: user.id })
|
|
119
|
-
* return { ok: true }
|
|
120
|
-
* }
|
|
121
|
-
* ```
|
|
122
|
-
*/
|
|
123
|
-
export function useSession<T extends Record<string, unknown> = Record<string, unknown>>(
|
|
124
|
-
options: SessionOptions = {},
|
|
125
|
-
): SessionComposable<T> {
|
|
126
|
-
const name = options.name ?? 'session'
|
|
127
|
-
const maxAge = options.maxAge ?? 60 * 60 * 24 * 7 // 7 days
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Returns the list of signing secrets in priority order.
|
|
131
|
-
* The first secret is the active key (used for signing new sessions).
|
|
132
|
-
* Subsequent secrets are accepted for verification only (rotation window).
|
|
133
|
-
*/
|
|
134
|
-
function _getSecrets(): string[] {
|
|
135
|
-
try {
|
|
136
|
-
const cfg = useRuntimeConfig()
|
|
137
|
-
const raw = (cfg as { private?: { sessionSecret?: string | string[] } }).private?.sessionSecret ?? ''
|
|
138
|
-
const secrets = Array.isArray(raw) ? raw.filter(Boolean) : (raw ? [raw] : [])
|
|
139
|
-
if (secrets.length === 0) {
|
|
140
|
-
console.warn(
|
|
141
|
-
'[cer-app] useSession: runtimeConfig.private.sessionSecret is empty. ' +
|
|
142
|
-
'Declare it with an empty-string default and set SESSION_SECRET in your environment.',
|
|
143
|
-
)
|
|
144
|
-
}
|
|
145
|
-
return secrets
|
|
146
|
-
} catch {
|
|
147
|
-
return []
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return {
|
|
152
|
-
async get(): Promise<T | null> {
|
|
153
|
-
const cookie = useCookie(name)
|
|
154
|
-
const raw = cookie.value
|
|
155
|
-
if (!raw) return null
|
|
156
|
-
const secrets = _getSecrets()
|
|
157
|
-
if (secrets.length === 0) return null
|
|
158
|
-
// Try each secret in order — first match wins (supports rotation).
|
|
159
|
-
for (const secret of secrets) {
|
|
160
|
-
try {
|
|
161
|
-
const key = await _importKey(secret)
|
|
162
|
-
const result = await _verify<T>(key, raw)
|
|
163
|
-
if (result !== null) return result
|
|
164
|
-
} catch {
|
|
165
|
-
// Try next key
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
return null
|
|
169
|
-
},
|
|
170
|
-
|
|
171
|
-
async set(data: T): Promise<void> {
|
|
172
|
-
const secrets = _getSecrets()
|
|
173
|
-
if (secrets.length === 0) throw new Error('[cer-app] useSession: sessionSecret is not configured.')
|
|
174
|
-
// Always sign with the first (active) key.
|
|
175
|
-
const key = await _importKey(secrets[0])
|
|
176
|
-
const token = await _sign(key, data)
|
|
177
|
-
const cookie = useCookie(name, { maxAge, httpOnly: true, sameSite: 'Lax', path: '/' })
|
|
178
|
-
cookie.set(token)
|
|
179
|
-
},
|
|
180
|
-
|
|
181
|
-
async clear(): Promise<void> {
|
|
182
|
-
const cookie = useCookie(name, { httpOnly: true, sameSite: 'Lax', path: '/' })
|
|
183
|
-
cookie.remove()
|
|
184
|
-
},
|
|
185
|
-
}
|
|
186
|
-
}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { ref } from '@jasonshimmy/custom-elements-runtime'
|
|
2
|
-
import type { ReactiveState } from '@jasonshimmy/custom-elements-runtime'
|
|
3
|
-
|
|
4
|
-
type StateMap = Map<string, ReactiveState<unknown>>
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* useState — globally-keyed reactive state shared across layouts, pages, and components.
|
|
8
|
-
*
|
|
9
|
-
* Returns the same reactive ref for a given key across all components. Mutating the
|
|
10
|
-
* ref in one component (page, layout, or component) automatically triggers re-renders
|
|
11
|
-
* in every other component that reads the same key.
|
|
12
|
-
*
|
|
13
|
-
* Works isomorphically:
|
|
14
|
-
* - **SSR/SSG**: state is scoped per-request via AsyncLocalStorage so concurrent renders
|
|
15
|
-
* never share state. Set initial values inside a page `loader` (which runs before
|
|
16
|
-
* rendering) so the layout can read them synchronously during the render pass.
|
|
17
|
-
* After rendering, all state values are serialized into `window.__CER_STATE_INIT__`
|
|
18
|
-
* and hydrated on the client so there is no flash to default values after hydration.
|
|
19
|
-
* - **Client**: state is a global singleton Map — refs are shared across the whole
|
|
20
|
-
* component tree and changes propagate reactively. On first use, the Map is
|
|
21
|
-
* pre-populated from `window.__CER_STATE_INIT__` (the SSR snapshot) if present.
|
|
22
|
-
*
|
|
23
|
-
* @param key Unique string key for this piece of state.
|
|
24
|
-
* @param init Initial value or factory function. Only evaluated when the key does not
|
|
25
|
-
* yet exist in the store (i.e. on first call for a given key per request/session).
|
|
26
|
-
*
|
|
27
|
-
* @example
|
|
28
|
-
* ```ts
|
|
29
|
-
* // app/pages/about.ts — set title in loader so layout sees it on SSR
|
|
30
|
-
* export const loader = async () => {
|
|
31
|
-
* useState<string>('pageTitle').value = 'About Us'
|
|
32
|
-
* return {}
|
|
33
|
-
* }
|
|
34
|
-
*
|
|
35
|
-
* component('page-about', () => {
|
|
36
|
-
* const title = useState<string>('pageTitle')
|
|
37
|
-
* return html`<h1>${title.value}</h1>`
|
|
38
|
-
* })
|
|
39
|
-
* ```
|
|
40
|
-
*
|
|
41
|
-
* @example
|
|
42
|
-
* ```ts
|
|
43
|
-
* // app/layouts/default.ts — reads the same ref; re-renders when value changes
|
|
44
|
-
* component('layout-default', () => {
|
|
45
|
-
* const title = useState('pageTitle', 'My App') // fallback default
|
|
46
|
-
* return html`
|
|
47
|
-
* <h1>${title.value}</h1>
|
|
48
|
-
* <slot></slot>
|
|
49
|
-
* `
|
|
50
|
-
* })
|
|
51
|
-
* ```
|
|
52
|
-
*/
|
|
53
|
-
export function useState<T>(key: string, init?: T | (() => T)): ReactiveState<T> {
|
|
54
|
-
const g = globalThis as Record<string, unknown>
|
|
55
|
-
|
|
56
|
-
// ── SSR path ──────────────────────────────────────────────────────────────
|
|
57
|
-
// __CER_STATE_STORE__ is an AsyncLocalStorage<StateMap> set by entry-server-template.
|
|
58
|
-
// Only set on the server — not present in the client bundle.
|
|
59
|
-
const stateStore = g['__CER_STATE_STORE__'] as { getStore(): StateMap | undefined } | undefined
|
|
60
|
-
if (stateStore) {
|
|
61
|
-
const map = stateStore.getStore()
|
|
62
|
-
if (map) {
|
|
63
|
-
if (!map.has(key)) {
|
|
64
|
-
const initValue = typeof init === 'function' ? (init as () => T)() : (init as T | undefined)
|
|
65
|
-
map.set(key, ref(initValue) as ReactiveState<unknown>)
|
|
66
|
-
}
|
|
67
|
-
return map.get(key) as ReactiveState<T>
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// ── Client path ───────────────────────────────────────────────────────────
|
|
72
|
-
// __CER_STATE__ is a singleton Map on globalThis, created lazily on first use.
|
|
73
|
-
// On creation, pre-populate from window.__CER_STATE_INIT__ (the SSR-serialized
|
|
74
|
-
// snapshot injected by the server handler) so the client boots with the same
|
|
75
|
-
// state the server rendered — no flash to default values on hydration.
|
|
76
|
-
if (!g['__CER_STATE__']) {
|
|
77
|
-
const clientMap = new Map<string, ReactiveState<unknown>>()
|
|
78
|
-
const ssrInit = g['__CER_STATE_INIT__'] as Record<string, unknown> | undefined
|
|
79
|
-
if (ssrInit) {
|
|
80
|
-
for (const [k, v] of Object.entries(ssrInit)) {
|
|
81
|
-
clientMap.set(k, ref(v) as ReactiveState<unknown>)
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
g['__CER_STATE__'] = clientMap
|
|
85
|
-
}
|
|
86
|
-
const clientMap = g['__CER_STATE__'] as StateMap
|
|
87
|
-
if (!clientMap.has(key)) {
|
|
88
|
-
const initValue = typeof init === 'function' ? (init as () => T)() : (init as T | undefined)
|
|
89
|
-
clientMap.set(key, ref(initValue) as ReactiveState<unknown>)
|
|
90
|
-
}
|
|
91
|
-
return clientMap.get(key) as ReactiveState<T>
|
|
92
|
-
}
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import type { ContentItem, ContentMeta } from '../../types/content.js'
|
|
2
|
-
|
|
3
|
-
// ─── Types ─────────────────────────────────────────────────────────────────────
|
|
4
|
-
|
|
5
|
-
/** Reads `router.base` from `virtual:cer-app-config` at module initialisation. */
|
|
6
|
-
let _base: string = ''
|
|
7
|
-
|
|
8
|
-
try {
|
|
9
|
-
// Dynamic import is not viable for a module-level side effect, so we read from
|
|
10
|
-
// globalThis where the virtual module writes it during app bootstrap.
|
|
11
|
-
const g = globalThis as Record<string, unknown>
|
|
12
|
-
const appConfig = g['__CER_APP_CONFIG__'] as { router?: { base?: string } } | undefined
|
|
13
|
-
_base = appConfig?.router?.base ?? ''
|
|
14
|
-
// Normalise: strip trailing slash, keep empty string for no base
|
|
15
|
-
if (_base === '/') _base = ''
|
|
16
|
-
} catch {
|
|
17
|
-
_base = ''
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// ─── Path helpers ─────────────────────────────────────────────────────────────
|
|
21
|
-
|
|
22
|
-
function contentPathToJsonFile(path: string): string {
|
|
23
|
-
if (path === '/') return 'index.json'
|
|
24
|
-
return path.slice(1) + '.json'
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/** Returns the full URL for the search index (includes router.base prefix). */
|
|
28
|
-
export function contentSearchIndexUrl(): string {
|
|
29
|
-
return `${_base}/_content/search-index.json`
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// ─── Lazy manifest cache ──────────────────────────────────────────────────────
|
|
33
|
-
|
|
34
|
-
let _manifestPromise: Promise<ContentMeta[]> | null = null
|
|
35
|
-
|
|
36
|
-
function fetchManifest(): Promise<ContentMeta[]> {
|
|
37
|
-
if (_manifestPromise) return _manifestPromise
|
|
38
|
-
_manifestPromise = fetch(`${_base}/_content/manifest.json`).then((r) => {
|
|
39
|
-
if (!r.ok) throw new Error(`Failed to fetch content manifest: ${r.status}`)
|
|
40
|
-
return r.json() as Promise<ContentMeta[]>
|
|
41
|
-
})
|
|
42
|
-
return _manifestPromise
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// ─── Server-side production caches ───────────────────────────────────────────
|
|
46
|
-
// In production SSR the Vite build process is not running, so __CER_CONTENT_STORE__
|
|
47
|
-
// is absent. We cache the manifest and per-document reads here to avoid repeated
|
|
48
|
-
// disk I/O on every request — critical at 10k+ pages where manifest.json is ~2MB.
|
|
49
|
-
|
|
50
|
-
let _ssrManifest: ContentMeta[] | null = null
|
|
51
|
-
const _ssrItemCache = new Map<string, ContentItem | null>()
|
|
52
|
-
|
|
53
|
-
// ─── ContentClient ────────────────────────────────────────────────────────────
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Low-level content data access layer. Used by `queryContent()`.
|
|
57
|
-
*
|
|
58
|
-
* Resolution strategy:
|
|
59
|
-
* - **Server (dev + SSG build-time)**: reads from `globalThis.__CER_CONTENT_STORE__`
|
|
60
|
-
* populated by the `cerContent()` Vite plugin's `buildStart` hook.
|
|
61
|
-
* - **Server (production SSR runtime)**: `__CER_CONTENT_STORE__` is absent (no
|
|
62
|
-
* Vite build process at runtime), so falls back to `node:fs` reads from
|
|
63
|
-
* `dist/_content/`.
|
|
64
|
-
* - **Client (SPA / browser navigation)**: lazy-fetches `/_content/manifest.json`
|
|
65
|
-
* once (cached) for listing; fetches `/_content/[path].json` per `.first()`.
|
|
66
|
-
*/
|
|
67
|
-
export const ContentClient = {
|
|
68
|
-
async getManifest(): Promise<ContentMeta[]> {
|
|
69
|
-
const g = globalThis as Record<string, unknown>
|
|
70
|
-
|
|
71
|
-
// Server: in-memory store (dev + SSG build-time rendering)
|
|
72
|
-
const store = g['__CER_CONTENT_STORE__'] as ContentItem[] | undefined
|
|
73
|
-
if (store) {
|
|
74
|
-
return store.map((item) => {
|
|
75
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
76
|
-
const { _file, body, toc, excerpt, ...meta } = item
|
|
77
|
-
return meta as ContentMeta
|
|
78
|
-
})
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Server: production SSR runtime — resolve content files from the app root.
|
|
82
|
-
// The preview CLI sets process.env.__CER_APP_ROOT__ to the project root before
|
|
83
|
-
// loading the server bundle. Content files are written to dist/server/_content/
|
|
84
|
-
// and dist/client/_content/ by cerContent's closeBundle hook.
|
|
85
|
-
// _ssrManifest is a module-level cache — populated once and reused for the
|
|
86
|
-
// lifetime of the process so manifest.json is only read and parsed once at scale.
|
|
87
|
-
if (typeof window === 'undefined' && typeof process !== 'undefined') {
|
|
88
|
-
if (_ssrManifest) return _ssrManifest
|
|
89
|
-
try {
|
|
90
|
-
const { readFileSync, existsSync } = await import('node:fs')
|
|
91
|
-
const { join } = await import('node:path')
|
|
92
|
-
const appRoot = process.env.__CER_APP_ROOT__ ?? process.cwd()
|
|
93
|
-
const candidates = [
|
|
94
|
-
join(appRoot, 'dist', 'server', '_content', 'manifest.json'),
|
|
95
|
-
join(appRoot, 'dist', 'client', '_content', 'manifest.json'),
|
|
96
|
-
join(appRoot, 'dist', '_content', 'manifest.json'),
|
|
97
|
-
]
|
|
98
|
-
for (const p of candidates) {
|
|
99
|
-
if (!existsSync(p)) continue
|
|
100
|
-
try {
|
|
101
|
-
const raw = readFileSync(p, 'utf-8')
|
|
102
|
-
_ssrManifest = JSON.parse(raw) as ContentMeta[]
|
|
103
|
-
return _ssrManifest
|
|
104
|
-
} catch { /* try next */ }
|
|
105
|
-
}
|
|
106
|
-
_ssrManifest = []
|
|
107
|
-
return _ssrManifest
|
|
108
|
-
} catch {
|
|
109
|
-
return []
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// Client: fetch manifest (cached)
|
|
114
|
-
return fetchManifest()
|
|
115
|
-
},
|
|
116
|
-
|
|
117
|
-
async getItem(path: string): Promise<ContentItem | null> {
|
|
118
|
-
const g = globalThis as Record<string, unknown>
|
|
119
|
-
|
|
120
|
-
// Server: in-memory store
|
|
121
|
-
const store = g['__CER_CONTENT_STORE__'] as ContentItem[] | undefined
|
|
122
|
-
if (store) {
|
|
123
|
-
return store.find((item) => item._path === path) ?? null
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Server: production SSR runtime — see getManifest() for path resolution strategy.
|
|
127
|
-
// _ssrItemCache is a module-level Map so each document is read and parsed at
|
|
128
|
-
// most once per process lifetime, regardless of how many concurrent requests
|
|
129
|
-
// ask for the same path.
|
|
130
|
-
if (typeof window === 'undefined' && typeof process !== 'undefined') {
|
|
131
|
-
if (_ssrItemCache.has(path)) return _ssrItemCache.get(path) ?? null
|
|
132
|
-
try {
|
|
133
|
-
const { readFileSync, existsSync } = await import('node:fs')
|
|
134
|
-
const { join } = await import('node:path')
|
|
135
|
-
const appRoot = process.env.__CER_APP_ROOT__ ?? process.cwd()
|
|
136
|
-
const jsonFile = contentPathToJsonFile(path)
|
|
137
|
-
const candidates = [
|
|
138
|
-
join(appRoot, 'dist', 'server', '_content', jsonFile),
|
|
139
|
-
join(appRoot, 'dist', 'client', '_content', jsonFile),
|
|
140
|
-
join(appRoot, 'dist', '_content', jsonFile),
|
|
141
|
-
]
|
|
142
|
-
for (const p of candidates) {
|
|
143
|
-
if (!existsSync(p)) continue
|
|
144
|
-
try {
|
|
145
|
-
const raw = readFileSync(p, 'utf-8')
|
|
146
|
-
const item = JSON.parse(raw) as ContentItem
|
|
147
|
-
_ssrItemCache.set(path, item)
|
|
148
|
-
return item
|
|
149
|
-
} catch { /* try next */ }
|
|
150
|
-
}
|
|
151
|
-
_ssrItemCache.set(path, null)
|
|
152
|
-
return null
|
|
153
|
-
} catch {
|
|
154
|
-
return null
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// Client: fetch individual document
|
|
159
|
-
const jsonFile = contentPathToJsonFile(path)
|
|
160
|
-
try {
|
|
161
|
-
const res = await fetch(`${_base}/_content/${jsonFile}`)
|
|
162
|
-
if (!res.ok) return null
|
|
163
|
-
return (await res.json()) as ContentItem
|
|
164
|
-
} catch {
|
|
165
|
-
return null
|
|
166
|
-
}
|
|
167
|
-
},
|
|
168
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Template string for `entry-client.ts`.
|
|
3
|
-
*
|
|
4
|
-
* This is the browser-side entry point for SSR/SSG modes.
|
|
5
|
-
* It hydrates the server-rendered HTML and activates client-side routing.
|
|
6
|
-
*/
|
|
7
|
-
export const ENTRY_CLIENT_TEMPLATE = `// Client-side entry — hydrates SSR output
|
|
8
|
-
|
|
9
|
-
// Mark the already-rendered entry URL so plugin-generated route middleware can
|
|
10
|
-
// skip replaying guards once during hydration. This is cleared by the app
|
|
11
|
-
// bootstrap after the initial hydrated route commits.
|
|
12
|
-
if (typeof window !== 'undefined') {
|
|
13
|
-
(globalThis).__CER_HYDRATION_ENTRY__ = {
|
|
14
|
-
path: window.location.pathname,
|
|
15
|
-
query: Object.fromEntries(new URLSearchParams(window.location.search)),
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Capture SSR loader data before any scripts clear it.
|
|
20
|
-
// usePageData() reads from this global; it is cleared after the first read
|
|
21
|
-
// so subsequent client-side navigations don't reuse stale data.
|
|
22
|
-
if (typeof window !== 'undefined' && window.__CER_DATA__) {
|
|
23
|
-
(globalThis).__CER_DATA__ = window.__CER_DATA__
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Capture useFetch() data pre-fetched on the server.
|
|
27
|
-
// Keys are consumed on first read; subsequent navigations fetch fresh.
|
|
28
|
-
if (typeof window !== 'undefined' && window.__CER_FETCH_DATA__) {
|
|
29
|
-
(globalThis).__CER_FETCH_DATA__ = window.__CER_FETCH_DATA__
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Capture the authenticated user injected by the SSR handler.
|
|
33
|
-
// useAuth() reads this on the client instead of re-reading the cookie.
|
|
34
|
-
if (typeof window !== 'undefined' && window.__CER_AUTH_USER__) {
|
|
35
|
-
(globalThis).__CER_AUTH_USER__ = window.__CER_AUTH_USER__
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
import './app.js'
|
|
39
|
-
`
|