@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,813 +0,0 @@
|
|
|
1
|
-
import { vi, describe, it, expect, beforeEach } from 'vitest'
|
|
2
|
-
import { EventEmitter } from 'node:events'
|
|
3
|
-
vi.mock('node:fs', () => ({
|
|
4
|
-
existsSync: vi.fn().mockReturnValue(false),
|
|
5
|
-
readFileSync: vi.fn().mockReturnValue('<html>shell</html>'),
|
|
6
|
-
}))
|
|
7
|
-
|
|
8
|
-
import { existsSync, readFileSync } from 'node:fs'
|
|
9
|
-
import { configureCerDevServer } from '../../plugin/dev-server.js'
|
|
10
|
-
import type { ResolvedCerConfig } from '../../plugin/dev-server.js'
|
|
11
|
-
|
|
12
|
-
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Creates a minimal mock IncomingMessage.
|
|
16
|
-
* Body events are emitted via setImmediate so they fire after readBody
|
|
17
|
-
* registers its 'data'/'end' listeners (which happens inside the async
|
|
18
|
-
* middleware after several awaited ssrLoadModule calls).
|
|
19
|
-
*/
|
|
20
|
-
function createReq(opts: {
|
|
21
|
-
url?: string
|
|
22
|
-
method?: string
|
|
23
|
-
headers?: Record<string, string>
|
|
24
|
-
body?: string
|
|
25
|
-
} = {}) {
|
|
26
|
-
const emitter = new EventEmitter()
|
|
27
|
-
setImmediate(() => {
|
|
28
|
-
if (opts.body !== undefined) emitter.emit('data', Buffer.from(opts.body))
|
|
29
|
-
emitter.emit('end')
|
|
30
|
-
})
|
|
31
|
-
return Object.assign(emitter, {
|
|
32
|
-
url: opts.url ?? '/',
|
|
33
|
-
method: opts.method ?? 'GET',
|
|
34
|
-
headers: opts.headers ?? {},
|
|
35
|
-
})
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function createRes() {
|
|
39
|
-
const res: any = { statusCode: 200, setHeader: vi.fn(), end: vi.fn() }
|
|
40
|
-
return res
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function makeConfig(overrides: Partial<ResolvedCerConfig> = {}): ResolvedCerConfig {
|
|
44
|
-
return {
|
|
45
|
-
mode: 'spa',
|
|
46
|
-
root: '/project',
|
|
47
|
-
srcDir: '/project/app',
|
|
48
|
-
pagesDir: '/project/app/pages',
|
|
49
|
-
layoutsDir: '/project/app/layouts',
|
|
50
|
-
componentsDir: '/project/app/components',
|
|
51
|
-
composablesDir: '/project/app/composables',
|
|
52
|
-
pluginsDir: '/project/app/plugins',
|
|
53
|
-
middlewareDir: '/project/app/middleware',
|
|
54
|
-
serverApiDir: '/project/server/api',
|
|
55
|
-
serverMiddlewareDir: '/project/server/middleware',
|
|
56
|
-
port: 3000,
|
|
57
|
-
ssg: { routes: 'auto', concurrency: 2, fallback: false },
|
|
58
|
-
router: {},
|
|
59
|
-
jitCss: { content: [], extendedColors: false },
|
|
60
|
-
autoImports: { components: true, composables: true, directives: true, runtime: true },
|
|
61
|
-
...overrides,
|
|
62
|
-
} as ResolvedCerConfig
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
type MockServer = {
|
|
66
|
-
middlewares: { use: ReturnType<typeof vi.fn> }
|
|
67
|
-
ssrLoadModule: ReturnType<typeof vi.fn>
|
|
68
|
-
ssrFixStacktrace: ReturnType<typeof vi.fn>
|
|
69
|
-
transformIndexHtml: ReturnType<typeof vi.fn>
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function makeServer(): { server: MockServer; getMiddleware: () => Function } {
|
|
73
|
-
const registered: Function[] = []
|
|
74
|
-
const server: MockServer = {
|
|
75
|
-
middlewares: { use: vi.fn((fn: Function) => registered.push(fn)) },
|
|
76
|
-
ssrLoadModule: vi.fn(async (path: string) => {
|
|
77
|
-
if (path.includes('server-middleware')) return { serverMiddleware: [] }
|
|
78
|
-
return { apiRoutes: [] }
|
|
79
|
-
}),
|
|
80
|
-
ssrFixStacktrace: vi.fn(),
|
|
81
|
-
transformIndexHtml: vi.fn(async (_url: string, html: string) => html),
|
|
82
|
-
}
|
|
83
|
-
return { server, getMiddleware: () => registered[0] }
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
beforeEach(() => {
|
|
87
|
-
vi.mocked(existsSync).mockReturnValue(false)
|
|
88
|
-
vi.mocked(readFileSync).mockReturnValue('<html>shell</html>' as never)
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
// ─── Registration ─────────────────────────────────────────────────────────────
|
|
92
|
-
|
|
93
|
-
describe('configureCerDevServer — registration', () => {
|
|
94
|
-
it('registers exactly one middleware via server.middlewares.use', () => {
|
|
95
|
-
const { server } = makeServer()
|
|
96
|
-
configureCerDevServer(server as any, makeConfig())
|
|
97
|
-
expect(server.middlewares.use).toHaveBeenCalledTimes(1)
|
|
98
|
-
expect(typeof (server.middlewares.use as any).mock.calls[0][0]).toBe('function')
|
|
99
|
-
})
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
// ─── Non-API pass-through ─────────────────────────────────────────────────────
|
|
103
|
-
|
|
104
|
-
describe('configureCerDevServer — non-API pass-through', () => {
|
|
105
|
-
it('calls next() for a non-HTML request with no matching routes', async () => {
|
|
106
|
-
const { server, getMiddleware } = makeServer()
|
|
107
|
-
configureCerDevServer(server as any, makeConfig())
|
|
108
|
-
const next = vi.fn()
|
|
109
|
-
await getMiddleware()(createReq({ url: '/assets/main.js', headers: { accept: 'application/javascript' } }), createRes(), next)
|
|
110
|
-
expect(next).toHaveBeenCalled()
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
it('calls next() when ssrLoadModule throws (module not ready)', async () => {
|
|
114
|
-
const { server, getMiddleware } = makeServer()
|
|
115
|
-
server.ssrLoadModule.mockRejectedValue(new Error('not ready'))
|
|
116
|
-
configureCerDevServer(server as any, makeConfig())
|
|
117
|
-
const next = vi.fn()
|
|
118
|
-
await getMiddleware()(createReq({ url: '/test' }), createRes(), next)
|
|
119
|
-
expect(next).toHaveBeenCalled()
|
|
120
|
-
})
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
// ─── SPA shell handling ──────────────────────────────────────────────────────
|
|
124
|
-
|
|
125
|
-
describe('configureCerDevServer — SPA shell handling', () => {
|
|
126
|
-
it('serves the transformed SPA shell for direct HTML navigations in spa mode', async () => {
|
|
127
|
-
const { server, getMiddleware } = makeServer()
|
|
128
|
-
server.transformIndexHtml.mockResolvedValue('<html>spa shell</html>')
|
|
129
|
-
vi.mocked(existsSync).mockReturnValue(true)
|
|
130
|
-
vi.mocked(readFileSync).mockReturnValue('<html>source shell</html>' as never)
|
|
131
|
-
const res = createRes()
|
|
132
|
-
|
|
133
|
-
configureCerDevServer(
|
|
134
|
-
server as any,
|
|
135
|
-
makeConfig({ mode: 'spa' }),
|
|
136
|
-
)
|
|
137
|
-
|
|
138
|
-
const next = vi.fn()
|
|
139
|
-
await getMiddleware()(
|
|
140
|
-
createReq({ url: '/music/effects/pro-co/rat', headers: { accept: 'text/html' } }),
|
|
141
|
-
res,
|
|
142
|
-
next,
|
|
143
|
-
)
|
|
144
|
-
|
|
145
|
-
expect(server.transformIndexHtml).toHaveBeenCalled()
|
|
146
|
-
expect(res.statusCode).toBe(200)
|
|
147
|
-
expect(res.setHeader).toHaveBeenCalledWith('Content-Type', 'text/html; charset=utf-8')
|
|
148
|
-
expect(res.end).toHaveBeenCalledWith('<html>spa shell</html>')
|
|
149
|
-
expect(next).not.toHaveBeenCalled()
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
it('does not serve the SPA shell for API requests in spa mode', async () => {
|
|
153
|
-
const { server, getMiddleware } = makeServer()
|
|
154
|
-
configureCerDevServer(
|
|
155
|
-
server as any,
|
|
156
|
-
makeConfig({ mode: 'spa' }),
|
|
157
|
-
)
|
|
158
|
-
|
|
159
|
-
const next = vi.fn()
|
|
160
|
-
await getMiddleware()(
|
|
161
|
-
createReq({ url: '/api/missing', headers: { accept: 'text/html' } }),
|
|
162
|
-
createRes(),
|
|
163
|
-
next,
|
|
164
|
-
)
|
|
165
|
-
|
|
166
|
-
expect(server.transformIndexHtml).not.toHaveBeenCalled()
|
|
167
|
-
expect(next).toHaveBeenCalled()
|
|
168
|
-
})
|
|
169
|
-
})
|
|
170
|
-
|
|
171
|
-
// ─── API route matching ───────────────────────────────────────────────────────
|
|
172
|
-
|
|
173
|
-
describe('configureCerDevServer — API route matching', () => {
|
|
174
|
-
function makeServerWithRoute(route: { path: string; handlers: Record<string, unknown> }) {
|
|
175
|
-
const { server, getMiddleware } = makeServer()
|
|
176
|
-
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
177
|
-
if (path.includes('server-middleware')) return { serverMiddleware: [] }
|
|
178
|
-
return { apiRoutes: [route] }
|
|
179
|
-
})
|
|
180
|
-
configureCerDevServer(server as any, makeConfig())
|
|
181
|
-
return getMiddleware()
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
it('calls GET handler for matching path', async () => {
|
|
185
|
-
const handler = vi.fn((req: any, res: any) => res.end('ok'))
|
|
186
|
-
const middleware = makeServerWithRoute({ path: '/api/health', handlers: { get: handler } })
|
|
187
|
-
const next = vi.fn()
|
|
188
|
-
await middleware(createReq({ url: '/api/health' }), createRes(), next)
|
|
189
|
-
expect(handler).toHaveBeenCalled()
|
|
190
|
-
expect(next).not.toHaveBeenCalled()
|
|
191
|
-
})
|
|
192
|
-
|
|
193
|
-
it('calls uppercase GET handler when lowercase is absent', async () => {
|
|
194
|
-
const handler = vi.fn((req: any, res: any) => res.end('ok'))
|
|
195
|
-
const middleware = makeServerWithRoute({ path: '/api/health', handlers: { GET: handler } })
|
|
196
|
-
await middleware(createReq({ url: '/api/health' }), createRes(), vi.fn())
|
|
197
|
-
expect(handler).toHaveBeenCalled()
|
|
198
|
-
})
|
|
199
|
-
|
|
200
|
-
it('calls default handler as fallback', async () => {
|
|
201
|
-
const handler = vi.fn((req: any, res: any) => res.end('ok'))
|
|
202
|
-
const middleware = makeServerWithRoute({ path: '/api/health', handlers: { default: handler } })
|
|
203
|
-
await middleware(createReq({ url: '/api/health' }), createRes(), vi.fn())
|
|
204
|
-
expect(handler).toHaveBeenCalled()
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
it('calls next() when no handler matches the HTTP method', async () => {
|
|
208
|
-
const middleware = makeServerWithRoute({ path: '/api/health', handlers: {} })
|
|
209
|
-
const next = vi.fn()
|
|
210
|
-
await middleware(createReq({ url: '/api/health' }), createRes(), next)
|
|
211
|
-
expect(next).toHaveBeenCalled()
|
|
212
|
-
})
|
|
213
|
-
|
|
214
|
-
it('does not match when segment counts differ', async () => {
|
|
215
|
-
const handler = vi.fn()
|
|
216
|
-
const middleware = makeServerWithRoute({ path: '/api/users/:id', handlers: { get: handler } })
|
|
217
|
-
const next = vi.fn()
|
|
218
|
-
await middleware(createReq({ url: '/api/users' }), createRes(), next)
|
|
219
|
-
expect(handler).not.toHaveBeenCalled()
|
|
220
|
-
expect(next).toHaveBeenCalled()
|
|
221
|
-
})
|
|
222
|
-
|
|
223
|
-
it('does not match when a static segment differs', async () => {
|
|
224
|
-
const handler = vi.fn()
|
|
225
|
-
const middleware = makeServerWithRoute({ path: '/api/posts', handlers: { get: handler } })
|
|
226
|
-
const next = vi.fn()
|
|
227
|
-
await middleware(createReq({ url: '/api/users' }), createRes(), next)
|
|
228
|
-
expect(handler).not.toHaveBeenCalled()
|
|
229
|
-
})
|
|
230
|
-
|
|
231
|
-
it('extracts dynamic route params and attaches to req', async () => {
|
|
232
|
-
let capturedReq: any
|
|
233
|
-
const handler = vi.fn((req: any, res: any) => { capturedReq = req; res.end('ok') })
|
|
234
|
-
const middleware = makeServerWithRoute({ path: '/api/users/:id', handlers: { get: handler } })
|
|
235
|
-
await middleware(createReq({ url: '/api/users/42' }), createRes(), vi.fn())
|
|
236
|
-
expect(capturedReq.params).toEqual({ id: '42' })
|
|
237
|
-
})
|
|
238
|
-
|
|
239
|
-
it('attaches parsed query string to req', async () => {
|
|
240
|
-
let capturedReq: any
|
|
241
|
-
const handler = vi.fn((req: any, res: any) => { capturedReq = req; res.end('ok') })
|
|
242
|
-
const middleware = makeServerWithRoute({ path: '/api/search', handlers: { get: handler } })
|
|
243
|
-
await middleware(createReq({ url: '/api/search?q=hello&page=2' }), createRes(), vi.fn())
|
|
244
|
-
expect(capturedReq.query).toEqual({ q: 'hello', page: '2' })
|
|
245
|
-
})
|
|
246
|
-
|
|
247
|
-
it('attaches empty query object when no query string', async () => {
|
|
248
|
-
let capturedReq: any
|
|
249
|
-
const handler = vi.fn((req: any, res: any) => { capturedReq = req; res.end('ok') })
|
|
250
|
-
const middleware = makeServerWithRoute({ path: '/api/health', handlers: { get: handler } })
|
|
251
|
-
await middleware(createReq({ url: '/api/health' }), createRes(), vi.fn())
|
|
252
|
-
expect(capturedReq.query).toEqual({})
|
|
253
|
-
})
|
|
254
|
-
|
|
255
|
-
it('handles query param with no value (flag style ?active)', async () => {
|
|
256
|
-
let capturedReq: any
|
|
257
|
-
const handler = vi.fn((req: any, res: any) => { capturedReq = req; res.end('ok') })
|
|
258
|
-
const middleware = makeServerWithRoute({ path: '/api/items', handlers: { get: handler } })
|
|
259
|
-
await middleware(createReq({ url: '/api/items?active' }), createRes(), vi.fn())
|
|
260
|
-
expect(capturedReq.query).toEqual({ active: '' })
|
|
261
|
-
})
|
|
262
|
-
|
|
263
|
-
it('skips empty segments from double-ampersand query strings', async () => {
|
|
264
|
-
let capturedReq: any
|
|
265
|
-
const handler = vi.fn((req: any, res: any) => { capturedReq = req; res.end('ok') })
|
|
266
|
-
const middleware = makeServerWithRoute({ path: '/api/items', handlers: { get: handler } })
|
|
267
|
-
await middleware(createReq({ url: '/api/items?a=1&&b=2' }), createRes(), vi.fn())
|
|
268
|
-
expect(capturedReq.query).toEqual({ a: '1', b: '2' })
|
|
269
|
-
})
|
|
270
|
-
|
|
271
|
-
it('decodes URL-encoded route params', async () => {
|
|
272
|
-
let capturedReq: any
|
|
273
|
-
const handler = vi.fn((req: any, res: any) => { capturedReq = req; res.end('ok') })
|
|
274
|
-
const middleware = makeServerWithRoute({ path: '/api/posts/:slug', handlers: { get: handler } })
|
|
275
|
-
await middleware(createReq({ url: '/api/posts/hello%20world' }), createRes(), vi.fn())
|
|
276
|
-
expect(capturedReq.params.slug).toBe('hello world')
|
|
277
|
-
})
|
|
278
|
-
|
|
279
|
-
it('returns 500 when API handler throws', async () => {
|
|
280
|
-
const handler = vi.fn(() => { throw new Error('oops') })
|
|
281
|
-
const { server, getMiddleware } = makeServer()
|
|
282
|
-
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
283
|
-
if (path.includes('server-middleware')) return { serverMiddleware: [] }
|
|
284
|
-
return { apiRoutes: [{ path: '/api/boom', handlers: { get: handler } }] }
|
|
285
|
-
})
|
|
286
|
-
configureCerDevServer(server as any, makeConfig())
|
|
287
|
-
const res = createRes()
|
|
288
|
-
await getMiddleware()(createReq({ url: '/api/boom' }), res, vi.fn())
|
|
289
|
-
expect(res.statusCode).toBe(500)
|
|
290
|
-
expect(res.end).toHaveBeenCalled()
|
|
291
|
-
})
|
|
292
|
-
})
|
|
293
|
-
|
|
294
|
-
// ─── Augmented response helpers ───────────────────────────────────────────────
|
|
295
|
-
|
|
296
|
-
describe('configureCerDevServer — augmented response helpers', () => {
|
|
297
|
-
function makeServerWithRoute(handler: Function) {
|
|
298
|
-
const { server, getMiddleware } = makeServer()
|
|
299
|
-
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
300
|
-
if (path.includes('server-middleware')) return { serverMiddleware: [] }
|
|
301
|
-
return { apiRoutes: [{ path: '/api/test', handlers: { get: handler } }] }
|
|
302
|
-
})
|
|
303
|
-
configureCerDevServer(server as any, makeConfig())
|
|
304
|
-
return getMiddleware()
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
it('res.json() serializes data and sets Content-Type', async () => {
|
|
308
|
-
const res = createRes()
|
|
309
|
-
const middleware = makeServerWithRoute((req: any, r: any) => r.json({ ok: true }))
|
|
310
|
-
await middleware(createReq({ url: '/api/test' }), res, vi.fn())
|
|
311
|
-
expect(res.setHeader).toHaveBeenCalledWith('Content-Type', 'application/json')
|
|
312
|
-
expect(res.end).toHaveBeenCalledWith('{"ok":true}')
|
|
313
|
-
})
|
|
314
|
-
|
|
315
|
-
it('res.status() sets statusCode and is chainable', async () => {
|
|
316
|
-
const res = createRes()
|
|
317
|
-
const middleware = makeServerWithRoute((req: any, r: any) => r.status(404).end('Not Found'))
|
|
318
|
-
await middleware(createReq({ url: '/api/test' }), res, vi.fn())
|
|
319
|
-
expect(res.statusCode).toBe(404)
|
|
320
|
-
expect(res.end).toHaveBeenCalledWith('Not Found')
|
|
321
|
-
})
|
|
322
|
-
})
|
|
323
|
-
|
|
324
|
-
// ─── POST body parsing ────────────────────────────────────────────────────────
|
|
325
|
-
|
|
326
|
-
describe('configureCerDevServer — POST body parsing', () => {
|
|
327
|
-
it('parses JSON body for POST request', async () => {
|
|
328
|
-
let capturedBody: unknown
|
|
329
|
-
const { server, getMiddleware } = makeServer()
|
|
330
|
-
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
331
|
-
if (path.includes('server-middleware')) return { serverMiddleware: [] }
|
|
332
|
-
return {
|
|
333
|
-
apiRoutes: [{
|
|
334
|
-
path: '/api/items',
|
|
335
|
-
handlers: { post: (req: any, res: any) => { capturedBody = req.body; res.end('ok') } },
|
|
336
|
-
}],
|
|
337
|
-
}
|
|
338
|
-
})
|
|
339
|
-
configureCerDevServer(server as any, makeConfig())
|
|
340
|
-
const req = createReq({
|
|
341
|
-
url: '/api/items',
|
|
342
|
-
method: 'POST',
|
|
343
|
-
headers: { 'content-type': 'application/json' },
|
|
344
|
-
body: JSON.stringify({ name: 'test' }),
|
|
345
|
-
})
|
|
346
|
-
await getMiddleware()(req, createRes(), vi.fn())
|
|
347
|
-
expect(capturedBody).toEqual({ name: 'test' })
|
|
348
|
-
})
|
|
349
|
-
|
|
350
|
-
it('returns raw Buffer body for POST with non-JSON content-type', async () => {
|
|
351
|
-
let capturedBody: unknown
|
|
352
|
-
const { server, getMiddleware } = makeServer()
|
|
353
|
-
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
354
|
-
if (path.includes('server-middleware')) return { serverMiddleware: [] }
|
|
355
|
-
return {
|
|
356
|
-
apiRoutes: [{
|
|
357
|
-
path: '/api/upload',
|
|
358
|
-
handlers: { post: (req: any, res: any) => { capturedBody = req.body; res.end('ok') } },
|
|
359
|
-
}],
|
|
360
|
-
}
|
|
361
|
-
})
|
|
362
|
-
configureCerDevServer(server as any, makeConfig())
|
|
363
|
-
const req = createReq({
|
|
364
|
-
url: '/api/upload',
|
|
365
|
-
method: 'POST',
|
|
366
|
-
headers: { 'content-type': 'text/plain' },
|
|
367
|
-
body: 'raw text',
|
|
368
|
-
})
|
|
369
|
-
await getMiddleware()(req, createRes(), vi.fn())
|
|
370
|
-
expect(Buffer.isBuffer(capturedBody)).toBe(true)
|
|
371
|
-
})
|
|
372
|
-
|
|
373
|
-
it('attaches undefined body for GET requests', async () => {
|
|
374
|
-
let capturedBody: unknown = 'sentinel'
|
|
375
|
-
const { server, getMiddleware } = makeServer()
|
|
376
|
-
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
377
|
-
if (path.includes('server-middleware')) return { serverMiddleware: [] }
|
|
378
|
-
return {
|
|
379
|
-
apiRoutes: [{
|
|
380
|
-
path: '/api/items',
|
|
381
|
-
handlers: { get: (req: any, res: any) => { capturedBody = req.body; res.end('ok') } },
|
|
382
|
-
}],
|
|
383
|
-
}
|
|
384
|
-
})
|
|
385
|
-
configureCerDevServer(server as any, makeConfig())
|
|
386
|
-
await getMiddleware()(createReq({ url: '/api/items' }), createRes(), vi.fn())
|
|
387
|
-
expect(capturedBody).toBeUndefined()
|
|
388
|
-
})
|
|
389
|
-
})
|
|
390
|
-
|
|
391
|
-
// ─── Server middleware execution ──────────────────────────────────────────────
|
|
392
|
-
|
|
393
|
-
describe('configureCerDevServer — server middleware', () => {
|
|
394
|
-
it('runs server middleware before API routes', async () => {
|
|
395
|
-
const callOrder: string[] = []
|
|
396
|
-
const smHandler = vi.fn((_req: any, _res: any, next: () => void) => {
|
|
397
|
-
callOrder.push('sm')
|
|
398
|
-
next()
|
|
399
|
-
})
|
|
400
|
-
const apiHandler = vi.fn((req: any, res: any) => { callOrder.push('api'); res.end('ok') })
|
|
401
|
-
const { server, getMiddleware } = makeServer()
|
|
402
|
-
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
403
|
-
if (path.includes('server-middleware')) return { serverMiddleware: [{ name: 'test', handler: smHandler }] }
|
|
404
|
-
return { apiRoutes: [{ path: '/api/health', handlers: { get: apiHandler } }] }
|
|
405
|
-
})
|
|
406
|
-
configureCerDevServer(server as any, makeConfig())
|
|
407
|
-
await getMiddleware()(createReq({ url: '/api/health' }), createRes(), vi.fn())
|
|
408
|
-
expect(callOrder).toEqual(['sm', 'api'])
|
|
409
|
-
})
|
|
410
|
-
|
|
411
|
-
it('stops processing when server middleware does not call next()', async () => {
|
|
412
|
-
const smHandler = vi.fn((_req: any, res: any) => { res.end('blocked') }) // no next() call
|
|
413
|
-
const apiHandler = vi.fn()
|
|
414
|
-
const { server, getMiddleware } = makeServer()
|
|
415
|
-
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
416
|
-
if (path.includes('server-middleware')) return { serverMiddleware: [{ name: 'block', handler: smHandler }] }
|
|
417
|
-
return { apiRoutes: [{ path: '/api/health', handlers: { get: apiHandler } }] }
|
|
418
|
-
})
|
|
419
|
-
configureCerDevServer(server as any, makeConfig())
|
|
420
|
-
await getMiddleware()(createReq({ url: '/api/health' }), createRes(), vi.fn())
|
|
421
|
-
expect(apiHandler).not.toHaveBeenCalled()
|
|
422
|
-
})
|
|
423
|
-
|
|
424
|
-
it('sends 500 and stops chain when middleware calls next(err)', async () => {
|
|
425
|
-
const smHandler = vi.fn((_req: any, _res: any, next: (err?: unknown) => void) => {
|
|
426
|
-
next(new Error('auth failed'))
|
|
427
|
-
})
|
|
428
|
-
const apiHandler = vi.fn()
|
|
429
|
-
const { server, getMiddleware } = makeServer()
|
|
430
|
-
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
431
|
-
if (path.includes('server-middleware')) return { serverMiddleware: [{ name: 'err', handler: smHandler }] }
|
|
432
|
-
return { apiRoutes: [{ path: '/api/health', handlers: { get: apiHandler } }] }
|
|
433
|
-
})
|
|
434
|
-
configureCerDevServer(server as any, makeConfig())
|
|
435
|
-
const res = createRes()
|
|
436
|
-
await getMiddleware()(createReq({ url: '/api/health' }), res, vi.fn())
|
|
437
|
-
expect(res.statusCode).toBe(500)
|
|
438
|
-
expect(res.end).toHaveBeenCalledWith('Internal Server Error')
|
|
439
|
-
expect(apiHandler).not.toHaveBeenCalled()
|
|
440
|
-
})
|
|
441
|
-
|
|
442
|
-
it('sends 500 and stops chain when middleware throws', async () => {
|
|
443
|
-
const smHandler = vi.fn(() => { throw new Error('unexpected') })
|
|
444
|
-
const apiHandler = vi.fn()
|
|
445
|
-
const { server, getMiddleware } = makeServer()
|
|
446
|
-
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
447
|
-
if (path.includes('server-middleware')) return { serverMiddleware: [{ name: 'throw', handler: smHandler }] }
|
|
448
|
-
return { apiRoutes: [{ path: '/api/health', handlers: { get: apiHandler } }] }
|
|
449
|
-
})
|
|
450
|
-
configureCerDevServer(server as any, makeConfig())
|
|
451
|
-
const res = createRes()
|
|
452
|
-
await getMiddleware()(createReq({ url: '/api/health' }), res, vi.fn())
|
|
453
|
-
expect(res.statusCode).toBe(500)
|
|
454
|
-
expect(apiHandler).not.toHaveBeenCalled()
|
|
455
|
-
})
|
|
456
|
-
|
|
457
|
-
it('handles async middleware that returns a Promise and calls next() after awaiting', async () => {
|
|
458
|
-
const callOrder: string[] = []
|
|
459
|
-
const smHandler = vi.fn((_req: any, _res: any, next: () => void) =>
|
|
460
|
-
new Promise<void>((resolve) => {
|
|
461
|
-
// Simulate async work before calling next
|
|
462
|
-
setImmediate(() => { callOrder.push('sm'); next(); resolve() })
|
|
463
|
-
}),
|
|
464
|
-
)
|
|
465
|
-
const apiHandler = vi.fn((_req: any, res: any) => { callOrder.push('api'); res.end('ok') })
|
|
466
|
-
const { server, getMiddleware } = makeServer()
|
|
467
|
-
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
468
|
-
if (path.includes('server-middleware')) return { serverMiddleware: [{ name: 'async', handler: smHandler }] }
|
|
469
|
-
return { apiRoutes: [{ path: '/api/health', handlers: { get: apiHandler } }] }
|
|
470
|
-
})
|
|
471
|
-
configureCerDevServer(server as any, makeConfig())
|
|
472
|
-
await getMiddleware()(createReq({ url: '/api/health' }), createRes(), vi.fn())
|
|
473
|
-
expect(callOrder).toEqual(['sm', 'api'])
|
|
474
|
-
})
|
|
475
|
-
|
|
476
|
-
it('handles async middleware that rejects (returns a rejected Promise)', async () => {
|
|
477
|
-
const smHandler = vi.fn(() => Promise.reject(new Error('async failure')))
|
|
478
|
-
const apiHandler = vi.fn()
|
|
479
|
-
const { server, getMiddleware } = makeServer()
|
|
480
|
-
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
481
|
-
if (path.includes('server-middleware')) return { serverMiddleware: [{ name: 'async-throw', handler: smHandler }] }
|
|
482
|
-
return { apiRoutes: [{ path: '/api/health', handlers: { get: apiHandler } }] }
|
|
483
|
-
})
|
|
484
|
-
configureCerDevServer(server as any, makeConfig())
|
|
485
|
-
const res = createRes()
|
|
486
|
-
await getMiddleware()(createReq({ url: '/api/health' }), res, vi.fn())
|
|
487
|
-
expect(res.statusCode).toBe(500)
|
|
488
|
-
expect(apiHandler).not.toHaveBeenCalled()
|
|
489
|
-
})
|
|
490
|
-
})
|
|
491
|
-
|
|
492
|
-
// ─── SSR mode ─────────────────────────────────────────────────────────────────
|
|
493
|
-
|
|
494
|
-
describe('configureCerDevServer — SSR mode', () => {
|
|
495
|
-
it('invokes SSR handler for HTML requests in ssr mode', async () => {
|
|
496
|
-
const ssrHandler = vi.fn(async (req: any, res: any) => res.end('<html>SSR</html>'))
|
|
497
|
-
const { server, getMiddleware } = makeServer()
|
|
498
|
-
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
499
|
-
if (path.includes('server-middleware')) return { serverMiddleware: [] }
|
|
500
|
-
if (path.includes('server-api')) return { apiRoutes: [] }
|
|
501
|
-
// SSR entry module
|
|
502
|
-
return { handler: ssrHandler }
|
|
503
|
-
})
|
|
504
|
-
configureCerDevServer(server as any, makeConfig({ mode: 'ssr' }))
|
|
505
|
-
const res = createRes()
|
|
506
|
-
await getMiddleware()(
|
|
507
|
-
createReq({ url: '/', headers: { accept: 'text/html' } }),
|
|
508
|
-
res,
|
|
509
|
-
vi.fn(),
|
|
510
|
-
)
|
|
511
|
-
expect(ssrHandler).toHaveBeenCalled()
|
|
512
|
-
})
|
|
513
|
-
|
|
514
|
-
it('invokes SSR handler for HTML requests in ssg mode', async () => {
|
|
515
|
-
const ssrHandler = vi.fn(async (req: any, res: any) => res.end('<html>SSG-DEV</html>'))
|
|
516
|
-
const { server, getMiddleware } = makeServer()
|
|
517
|
-
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
518
|
-
if (path.includes('server-middleware')) return { serverMiddleware: [] }
|
|
519
|
-
if (path.includes('server-api')) return { apiRoutes: [] }
|
|
520
|
-
return { handler: ssrHandler }
|
|
521
|
-
})
|
|
522
|
-
configureCerDevServer(server as any, makeConfig({ mode: 'ssg' }))
|
|
523
|
-
const res = createRes()
|
|
524
|
-
await getMiddleware()(
|
|
525
|
-
createReq({ url: '/', headers: { accept: 'text/html' } }),
|
|
526
|
-
res,
|
|
527
|
-
vi.fn(),
|
|
528
|
-
)
|
|
529
|
-
expect(ssrHandler).toHaveBeenCalled()
|
|
530
|
-
})
|
|
531
|
-
|
|
532
|
-
it('does not invoke SSR handler in spa mode', async () => {
|
|
533
|
-
const ssrHandler = vi.fn()
|
|
534
|
-
const { server, getMiddleware } = makeServer()
|
|
535
|
-
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
536
|
-
if (path.includes('server-middleware')) return { serverMiddleware: [] }
|
|
537
|
-
if (path.includes('server-api')) return { apiRoutes: [] }
|
|
538
|
-
return { handler: ssrHandler }
|
|
539
|
-
})
|
|
540
|
-
server.transformIndexHtml.mockResolvedValue('<html>spa shell</html>')
|
|
541
|
-
vi.mocked(existsSync).mockReturnValue(true)
|
|
542
|
-
vi.mocked(readFileSync).mockReturnValue('<html>source shell</html>' as never)
|
|
543
|
-
configureCerDevServer(
|
|
544
|
-
server as any,
|
|
545
|
-
makeConfig({ mode: 'spa' }),
|
|
546
|
-
)
|
|
547
|
-
const next = vi.fn()
|
|
548
|
-
const res = createRes()
|
|
549
|
-
await getMiddleware()(
|
|
550
|
-
createReq({ url: '/', headers: { accept: 'text/html' } }),
|
|
551
|
-
res,
|
|
552
|
-
next,
|
|
553
|
-
)
|
|
554
|
-
expect(ssrHandler).not.toHaveBeenCalled()
|
|
555
|
-
expect(res.end).toHaveBeenCalledWith('<html>spa shell</html>')
|
|
556
|
-
expect(next).not.toHaveBeenCalled()
|
|
557
|
-
})
|
|
558
|
-
|
|
559
|
-
it('does not invoke SSR handler for non-HTML requests (e.g. assets)', async () => {
|
|
560
|
-
const ssrHandler = vi.fn()
|
|
561
|
-
const { server, getMiddleware } = makeServer()
|
|
562
|
-
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
563
|
-
if (path.includes('server-middleware')) return { serverMiddleware: [] }
|
|
564
|
-
if (path.includes('server-api')) return { apiRoutes: [] }
|
|
565
|
-
return { handler: ssrHandler }
|
|
566
|
-
})
|
|
567
|
-
configureCerDevServer(server as any, makeConfig({ mode: 'ssr' }))
|
|
568
|
-
const next = vi.fn()
|
|
569
|
-
await getMiddleware()(
|
|
570
|
-
createReq({ url: '/assets/main.js', headers: { accept: 'application/javascript' } }),
|
|
571
|
-
createRes(),
|
|
572
|
-
next,
|
|
573
|
-
)
|
|
574
|
-
expect(ssrHandler).not.toHaveBeenCalled()
|
|
575
|
-
expect(next).toHaveBeenCalled()
|
|
576
|
-
})
|
|
577
|
-
|
|
578
|
-
it('does not invoke SSR handler for non-HTML requests in ssg mode', async () => {
|
|
579
|
-
const ssrHandler = vi.fn()
|
|
580
|
-
const { server, getMiddleware } = makeServer()
|
|
581
|
-
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
582
|
-
if (path.includes('server-middleware')) return { serverMiddleware: [] }
|
|
583
|
-
if (path.includes('server-api')) return { apiRoutes: [] }
|
|
584
|
-
return { handler: ssrHandler }
|
|
585
|
-
})
|
|
586
|
-
configureCerDevServer(server as any, makeConfig({ mode: 'ssg' }))
|
|
587
|
-
const next = vi.fn()
|
|
588
|
-
await getMiddleware()(
|
|
589
|
-
createReq({ url: '/assets/main.js', headers: { accept: 'application/javascript' } }),
|
|
590
|
-
createRes(),
|
|
591
|
-
next,
|
|
592
|
-
)
|
|
593
|
-
expect(ssrHandler).not.toHaveBeenCalled()
|
|
594
|
-
expect(next).toHaveBeenCalled()
|
|
595
|
-
})
|
|
596
|
-
|
|
597
|
-
it('returns 500 and error text when SSR handler throws', async () => {
|
|
598
|
-
const { server, getMiddleware } = makeServer()
|
|
599
|
-
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
600
|
-
if (path.includes('server-middleware')) return { serverMiddleware: [] }
|
|
601
|
-
if (path.includes('server-api')) return { apiRoutes: [] }
|
|
602
|
-
return { handler: async () => { throw new Error('render failed') } }
|
|
603
|
-
})
|
|
604
|
-
configureCerDevServer(server as any, makeConfig({ mode: 'ssr' }))
|
|
605
|
-
const res = createRes()
|
|
606
|
-
await getMiddleware()(createReq({ url: '/', headers: { accept: 'text/html' } }), res, vi.fn())
|
|
607
|
-
expect(res.statusCode).toBe(500)
|
|
608
|
-
})
|
|
609
|
-
|
|
610
|
-
it('calls next() for non-HTML in ssr mode without API match', async () => {
|
|
611
|
-
const { server, getMiddleware } = makeServer()
|
|
612
|
-
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
613
|
-
if (path.includes('server-middleware')) return { serverMiddleware: [] }
|
|
614
|
-
return { apiRoutes: [] }
|
|
615
|
-
})
|
|
616
|
-
configureCerDevServer(server as any, makeConfig({ mode: 'ssr' }))
|
|
617
|
-
const next = vi.fn()
|
|
618
|
-
await getMiddleware()(
|
|
619
|
-
createReq({ url: '/favicon.ico', headers: { accept: 'image/x-icon' } }),
|
|
620
|
-
createRes(),
|
|
621
|
-
next,
|
|
622
|
-
)
|
|
623
|
-
expect(next).toHaveBeenCalled()
|
|
624
|
-
})
|
|
625
|
-
|
|
626
|
-
it('uses renderFn fallback when SSR entry exports render instead of handler', async () => {
|
|
627
|
-
const renderFn = vi.fn().mockResolvedValue({ html: '<div>rendered</div>' })
|
|
628
|
-
const { server, getMiddleware } = makeServer()
|
|
629
|
-
;(server as any).transformIndexHtml = vi.fn().mockResolvedValue(
|
|
630
|
-
'<!DOCTYPE html><html><body><div id="app"></div></body></html>',
|
|
631
|
-
)
|
|
632
|
-
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
633
|
-
if (path.includes('server-middleware')) return { serverMiddleware: [] }
|
|
634
|
-
if (path.includes('server-api')) return { apiRoutes: [] }
|
|
635
|
-
return { render: renderFn }
|
|
636
|
-
})
|
|
637
|
-
configureCerDevServer(server as any, makeConfig({ mode: 'ssr' }))
|
|
638
|
-
const res = createRes()
|
|
639
|
-
await getMiddleware()(createReq({ url: '/', headers: { accept: 'text/html' } }), res, vi.fn())
|
|
640
|
-
expect(renderFn).toHaveBeenCalled()
|
|
641
|
-
expect(res.end).toHaveBeenCalledWith(expect.stringContaining('<div>rendered</div>'))
|
|
642
|
-
})
|
|
643
|
-
|
|
644
|
-
it('accepts html request when url is / even without text/html accept header', async () => {
|
|
645
|
-
const ssrHandler = vi.fn(async (req: any, res: any) => res.end('<html>home</html>'))
|
|
646
|
-
const { server, getMiddleware } = makeServer()
|
|
647
|
-
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
648
|
-
if (path.includes('server-middleware')) return { serverMiddleware: [] }
|
|
649
|
-
if (path.includes('server-api')) return { apiRoutes: [] }
|
|
650
|
-
return { handler: ssrHandler }
|
|
651
|
-
})
|
|
652
|
-
configureCerDevServer(server as any, makeConfig({ mode: 'ssr' }))
|
|
653
|
-
// url='/' triggers acceptsHtml without needing accept header
|
|
654
|
-
await getMiddleware()(createReq({ url: '/' }), createRes(), vi.fn())
|
|
655
|
-
expect(ssrHandler).toHaveBeenCalled()
|
|
656
|
-
})
|
|
657
|
-
})
|
|
658
|
-
|
|
659
|
-
// ─── Per-route render mode (SSR/SSG mode) ────────────────────────────────────
|
|
660
|
-
|
|
661
|
-
describe("configureCerDevServer — per-route render mode in SSR", () => {
|
|
662
|
-
/** Build a server where virtual:cer-routes returns the given routes array. */
|
|
663
|
-
function makeServerWithRoutes(
|
|
664
|
-
pageRoutes: Array<{ path: string; meta?: Record<string, unknown> }>,
|
|
665
|
-
ssrHandler = vi.fn(async (_req: any, res: any) => res.end('<html>SSR</html>')),
|
|
666
|
-
mode: 'ssr' | 'ssg' = 'ssr',
|
|
667
|
-
) {
|
|
668
|
-
const { server, getMiddleware } = makeServer()
|
|
669
|
-
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
670
|
-
if (path.includes('server-middleware')) return { serverMiddleware: [] }
|
|
671
|
-
if (path.includes('server-api') || path.includes('cer-server-api')) return { apiRoutes: [] }
|
|
672
|
-
if (path.includes('cer-routes')) return { default: pageRoutes }
|
|
673
|
-
return { handler: ssrHandler }
|
|
674
|
-
})
|
|
675
|
-
configureCerDevServer(server as any, makeConfig({ mode }))
|
|
676
|
-
return { middleware: getMiddleware(), ssrHandler }
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
it("calls next() instead of SSR for a route with render: 'spa'", async () => {
|
|
680
|
-
const { middleware, ssrHandler } = makeServerWithRoutes([
|
|
681
|
-
{ path: '/spa-page', meta: { render: 'spa' } },
|
|
682
|
-
])
|
|
683
|
-
const next = vi.fn()
|
|
684
|
-
await middleware(
|
|
685
|
-
createReq({ url: '/spa-page', headers: { accept: 'text/html' } }),
|
|
686
|
-
createRes(),
|
|
687
|
-
next,
|
|
688
|
-
)
|
|
689
|
-
expect(next).toHaveBeenCalled()
|
|
690
|
-
expect(ssrHandler).not.toHaveBeenCalled()
|
|
691
|
-
})
|
|
692
|
-
|
|
693
|
-
it("calls next() instead of SSR for a route with render: 'spa' in ssg mode", async () => {
|
|
694
|
-
const { middleware, ssrHandler } = makeServerWithRoutes(
|
|
695
|
-
[{ path: '/spa-page', meta: { render: 'spa' } }],
|
|
696
|
-
vi.fn(async (_req: any, res: any) => res.end('<html>SSG</html>')),
|
|
697
|
-
'ssg',
|
|
698
|
-
)
|
|
699
|
-
const next = vi.fn()
|
|
700
|
-
await middleware(
|
|
701
|
-
createReq({ url: '/spa-page', headers: { accept: 'text/html' } }),
|
|
702
|
-
createRes(),
|
|
703
|
-
next,
|
|
704
|
-
)
|
|
705
|
-
expect(next).toHaveBeenCalled()
|
|
706
|
-
expect(ssrHandler).not.toHaveBeenCalled()
|
|
707
|
-
})
|
|
708
|
-
|
|
709
|
-
it("proceeds to SSR for a route with render: 'server'", async () => {
|
|
710
|
-
const { middleware, ssrHandler } = makeServerWithRoutes([
|
|
711
|
-
{ path: '/server-page', meta: { render: 'server' } },
|
|
712
|
-
])
|
|
713
|
-
await middleware(
|
|
714
|
-
createReq({ url: '/server-page', headers: { accept: 'text/html' } }),
|
|
715
|
-
createRes(),
|
|
716
|
-
vi.fn(),
|
|
717
|
-
)
|
|
718
|
-
expect(ssrHandler).toHaveBeenCalled()
|
|
719
|
-
})
|
|
720
|
-
|
|
721
|
-
it("proceeds to SSR for a route with no render meta", async () => {
|
|
722
|
-
const { middleware, ssrHandler } = makeServerWithRoutes([
|
|
723
|
-
{ path: '/normal-page' },
|
|
724
|
-
])
|
|
725
|
-
await middleware(
|
|
726
|
-
createReq({ url: '/normal-page', headers: { accept: 'text/html' } }),
|
|
727
|
-
createRes(),
|
|
728
|
-
vi.fn(),
|
|
729
|
-
)
|
|
730
|
-
expect(ssrHandler).toHaveBeenCalled()
|
|
731
|
-
})
|
|
732
|
-
|
|
733
|
-
it("falls back to SSR when routes module throws during render mode check", async () => {
|
|
734
|
-
const ssrHandler = vi.fn(async (_req: any, res: any) => res.end('<html>SSR</html>'))
|
|
735
|
-
const { server, getMiddleware } = makeServer()
|
|
736
|
-
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
737
|
-
if (path.includes('server-middleware')) return { serverMiddleware: [] }
|
|
738
|
-
if (path.includes('server-api') || path.includes('cer-server-api')) return { apiRoutes: [] }
|
|
739
|
-
if (path.includes('cer-routes')) throw new Error('module not ready')
|
|
740
|
-
return { handler: ssrHandler }
|
|
741
|
-
})
|
|
742
|
-
configureCerDevServer(server as any, makeConfig({ mode: 'ssr' }))
|
|
743
|
-
await getMiddleware()(
|
|
744
|
-
createReq({ url: '/some-page', headers: { accept: 'text/html' } }),
|
|
745
|
-
createRes(),
|
|
746
|
-
vi.fn(),
|
|
747
|
-
)
|
|
748
|
-
// Despite the routes module throwing, SSR should still run
|
|
749
|
-
expect(ssrHandler).toHaveBeenCalled()
|
|
750
|
-
})
|
|
751
|
-
|
|
752
|
-
it("does not load routes module in SPA mode (no render mode check needed)", async () => {
|
|
753
|
-
const { server, getMiddleware } = makeServer()
|
|
754
|
-
configureCerDevServer(server as any, makeConfig({ mode: 'spa' }))
|
|
755
|
-
await getMiddleware()(
|
|
756
|
-
createReq({ url: '/about', headers: { accept: 'text/html' } }),
|
|
757
|
-
createRes(),
|
|
758
|
-
vi.fn(),
|
|
759
|
-
)
|
|
760
|
-
const routesCalls = (server.ssrLoadModule as any).mock.calls.filter(
|
|
761
|
-
([p]: [string]) => p.includes('cer-routes'),
|
|
762
|
-
)
|
|
763
|
-
expect(routesCalls).toHaveLength(0)
|
|
764
|
-
})
|
|
765
|
-
|
|
766
|
-
it("loads routes module in ssg mode to check per-route render mode", async () => {
|
|
767
|
-
const ssrHandler = vi.fn(async (_req: any, res: any) => res.end('<html>SSG</html>'))
|
|
768
|
-
const { server, getMiddleware } = makeServer()
|
|
769
|
-
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
770
|
-
if (path.includes('server-middleware')) return { serverMiddleware: [] }
|
|
771
|
-
if (path.includes('server-api') || path.includes('cer-server-api')) return { apiRoutes: [] }
|
|
772
|
-
if (path.includes('cer-routes')) return { default: [] }
|
|
773
|
-
return { handler: ssrHandler }
|
|
774
|
-
})
|
|
775
|
-
configureCerDevServer(server as any, makeConfig({ mode: 'ssg' }))
|
|
776
|
-
await getMiddleware()(
|
|
777
|
-
createReq({ url: '/about', headers: { accept: 'text/html' } }),
|
|
778
|
-
createRes(),
|
|
779
|
-
vi.fn(),
|
|
780
|
-
)
|
|
781
|
-
const routesCalls = (server.ssrLoadModule as any).mock.calls.filter(
|
|
782
|
-
([p]: [string]) => p.includes('cer-routes'),
|
|
783
|
-
)
|
|
784
|
-
expect(routesCalls.length).toBeGreaterThan(0)
|
|
785
|
-
})
|
|
786
|
-
})
|
|
787
|
-
|
|
788
|
-
// ─── parseBody edge cases ─────────────────────────────────────────────────────
|
|
789
|
-
|
|
790
|
-
describe('configureCerDevServer — malformed JSON body', () => {
|
|
791
|
-
it('returns undefined when POST body is malformed JSON', async () => {
|
|
792
|
-
let capturedBody: unknown = 'sentinel'
|
|
793
|
-
const { server, getMiddleware } = makeServer()
|
|
794
|
-
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
795
|
-
if (path.includes('server-middleware')) return { serverMiddleware: [] }
|
|
796
|
-
return {
|
|
797
|
-
apiRoutes: [{
|
|
798
|
-
path: '/api/items',
|
|
799
|
-
handlers: { post: (req: any, res: any) => { capturedBody = req.body; res.end('ok') } },
|
|
800
|
-
}],
|
|
801
|
-
}
|
|
802
|
-
})
|
|
803
|
-
configureCerDevServer(server as any, makeConfig())
|
|
804
|
-
const req = createReq({
|
|
805
|
-
url: '/api/items',
|
|
806
|
-
method: 'POST',
|
|
807
|
-
headers: { 'content-type': 'application/json' },
|
|
808
|
-
body: '{ invalid json }',
|
|
809
|
-
})
|
|
810
|
-
await getMiddleware()(req, createRes(), vi.fn())
|
|
811
|
-
expect(capturedBody).toBeUndefined()
|
|
812
|
-
})
|
|
813
|
-
})
|