@jasonshimmy/vite-plugin-cer-app 0.23.2 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/adapters/netlify.js +4 -2
- package/dist/cli/adapters/netlify.js.map +1 -1
- 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/commands/preview.d.ts.map +1 -1
- package/dist/cli/commands/preview.js +4 -2
- package/dist/cli/commands/preview.js.map +1 -1
- 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 +4 -2
- 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 +226 -17
- package/dist/plugin/build-ssg.js.map +1 -1
- package/dist/plugin/content/index.d.ts +1 -1
- package/dist/plugin/content/index.d.ts.map +1 -1
- package/dist/plugin/content/index.js +8 -8
- package/dist/plugin/content/index.js.map +1 -1
- package/dist/plugin/content/parser.d.ts +3 -3
- package/dist/plugin/content/parser.d.ts.map +1 -1
- package/dist/plugin/content/parser.js +103 -24
- 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 +7 -0
- package/dist/plugin/html-post-process.d.ts.map +1 -1
- package/dist/plugin/html-post-process.js +26 -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 +181 -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/content.d.ts +18 -1
- package/dist/types/content.d.ts.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,122 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* usePageData() timing regression tests — proves the queueMicrotask fix.
|
|
3
|
-
*
|
|
4
|
-
* Background:
|
|
5
|
-
* _doHydrate() runs _loadPageForPath (sets __CER_DATA__) then _replace(),
|
|
6
|
-
* which causes cer-layout-view to create a NEW page element via a queued
|
|
7
|
-
* microtask. That new element's setup() calls usePageData() to read __CER_DATA__.
|
|
8
|
-
*
|
|
9
|
-
* Pre-fix: delete __CER_DATA__ was synchronous → ran before the queued render
|
|
10
|
-
* → usePageData() saw undefined → returned null.
|
|
11
|
-
* Post-fix: queueMicrotask(() => delete __CER_DATA__) → delete is queued AFTER
|
|
12
|
-
* the render microtask → usePageData() reads the data correctly.
|
|
13
|
-
*
|
|
14
|
-
* Proof mechanism:
|
|
15
|
-
* Each blog page component captures `ssrData ? 'ssr' : 'client'` once, at the
|
|
16
|
-
* moment the element is created during hydration. In SSR/SSG/dev modes this
|
|
17
|
-
* value must always be 'ssr'. If it is 'client' the timing bug has regressed.
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
export {}
|
|
21
|
-
|
|
22
|
-
const mode = Cypress.env('mode') as 'spa' | 'ssr' | 'ssg' | 'dev'
|
|
23
|
-
|
|
24
|
-
// ─── Blog list — hard refresh ─────────────────────────────────────────────
|
|
25
|
-
|
|
26
|
-
describe('usePageData() — blog list hard refresh', () => {
|
|
27
|
-
if (mode !== 'spa') {
|
|
28
|
-
it('server response embeds __CER_DATA__ with both post titles', () => {
|
|
29
|
-
cy.request('/blog').then((res) => {
|
|
30
|
-
expect(res.body).to.include('__CER_DATA__')
|
|
31
|
-
expect(res.body).to.include('First Post')
|
|
32
|
-
expect(res.body).to.include('Second Post')
|
|
33
|
-
})
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
it('usePageData() is non-null during hydration re-render (data-source = "ssr")', () => {
|
|
37
|
-
cy.visit('/blog')
|
|
38
|
-
// Scope to the live shadow DOM (not the DSD pre-render copy) so the assertion
|
|
39
|
-
// targets the element created during hydration where usePageData() was called.
|
|
40
|
-
// 'ssr' proves queueMicrotask deferred the delete until after the render ran.
|
|
41
|
-
cy.get('cer-layout-view').shadow().find('page-blog').shadow()
|
|
42
|
-
.find('[data-cy=blog-data-source]').should('have.text', 'ssr')
|
|
43
|
-
})
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// In SSR and dev modes the /api/posts route exists on the server.
|
|
47
|
-
// If usePageData() is non-null, the blog page's useOnConnected guard
|
|
48
|
-
// (`if (ssrData) return`) skips the fetch entirely.
|
|
49
|
-
if (mode === 'ssr' || mode === 'dev') {
|
|
50
|
-
it('no /api/posts network request is made — usePageData() skips client fetch', () => {
|
|
51
|
-
cy.intercept('GET', '/api/posts').as('apiFetch')
|
|
52
|
-
cy.visit('/blog')
|
|
53
|
-
// Wait for the page component to fully hydrate before asserting no requests.
|
|
54
|
-
cy.get('cer-layout-view').shadow().find('page-blog').shadow()
|
|
55
|
-
.find('[data-cy=blog-list]').should('exist')
|
|
56
|
-
cy.get('@apiFetch.all').should('have.length', 0)
|
|
57
|
-
})
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
it('blog posts are visible after hydration (all modes)', () => {
|
|
61
|
-
cy.visit('/blog')
|
|
62
|
-
cy.get('[data-cy=blog-item]', { timeout: 8000 }).should('have.length.at.least', 2)
|
|
63
|
-
})
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
// ─── Blog detail — hard refresh ───────────────────────────────────────────
|
|
67
|
-
|
|
68
|
-
describe('usePageData() — blog detail hard refresh', () => {
|
|
69
|
-
if (mode !== 'spa') {
|
|
70
|
-
it('server response embeds __CER_DATA__ with post detail', () => {
|
|
71
|
-
cy.request('/blog/first-post').then((res) => {
|
|
72
|
-
expect(res.body).to.include('__CER_DATA__')
|
|
73
|
-
expect(res.body).to.include('First Post')
|
|
74
|
-
})
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
it('usePageData() is non-null during hydration re-render on detail page', () => {
|
|
78
|
-
cy.visit('/blog/first-post')
|
|
79
|
-
cy.get('cer-layout-view').shadow().find('page-blog-slug').shadow()
|
|
80
|
-
.find('[data-cy=blog-detail-data-source]').should('have.text', 'ssr')
|
|
81
|
-
})
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (mode === 'ssr' || mode === 'dev') {
|
|
85
|
-
it('no /api/posts/:slug network request is made — usePageData() skips client fetch', () => {
|
|
86
|
-
cy.intercept('GET', '/api/posts/*').as('apiPostDetail')
|
|
87
|
-
cy.visit('/blog/first-post')
|
|
88
|
-
cy.get('cer-layout-view').shadow().find('page-blog-slug').shadow()
|
|
89
|
-
.find('[data-cy=post-title]').should('exist')
|
|
90
|
-
cy.get('@apiPostDetail.all').should('have.length', 0)
|
|
91
|
-
})
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
it('"First Post" title renders on hard refresh (all modes)', () => {
|
|
95
|
-
cy.visit('/blog/first-post')
|
|
96
|
-
cy.get('[data-cy=post-title]', { timeout: 8000 }).should('contain', 'First Post')
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
it('"Second Post" title renders on hard refresh (all modes)', () => {
|
|
100
|
-
cy.visit('/blog/second-post')
|
|
101
|
-
cy.get('[data-cy=post-title]', { timeout: 8000 }).should('contain', 'Second Post')
|
|
102
|
-
})
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
// ─── Client-side navigation (post-hydration data loading) ─────────────────
|
|
106
|
-
|
|
107
|
-
describe('usePageData() — client-side navigation', () => {
|
|
108
|
-
it('navigating to blog from home shows posts', () => {
|
|
109
|
-
cy.visit('/')
|
|
110
|
-
cy.get('[data-cy=page-nav]').find('a[href="/blog"]').first().click({ force: true })
|
|
111
|
-
cy.get('[data-cy=blog-item]', { timeout: 8000 }).should('have.length.at.least', 2)
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
it('navigating between blog posts loads correct data each time', () => {
|
|
115
|
-
cy.visit('/blog/first-post')
|
|
116
|
-
cy.get('[data-cy=post-title]', { timeout: 8000 }).should('contain', 'First Post')
|
|
117
|
-
cy.get('[data-cy=post-back]').first().click({ force: true })
|
|
118
|
-
cy.url().should('include', '/blog')
|
|
119
|
-
cy.get('[data-cy=blog-link-second-post]', { timeout: 8000 }).first().click({ force: true })
|
|
120
|
-
cy.get('[data-cy=post-title]', { timeout: 8000 }).should('contain', 'Second Post')
|
|
121
|
-
})
|
|
122
|
-
})
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* useState() e2e tests — verifies globally-keyed reactive state works correctly
|
|
3
|
-
* in all rendering modes (SPA, SSR, SSG).
|
|
4
|
-
*
|
|
5
|
-
* Scenarios covered:
|
|
6
|
-
* - Layout shows the default useState title on pages that don't set it
|
|
7
|
-
* - Layout reacts to pageTitle set by the use-state-test page (client-side)
|
|
8
|
-
* - Mutating useState in the page re-renders the layout reactively
|
|
9
|
-
* - Navigating away from the page resets to the default title
|
|
10
|
-
* - SSR: initial HTML already contains the title set by the loader
|
|
11
|
-
* - SSR: window.__CER_STATE_INIT__ is injected and parsed by the browser
|
|
12
|
-
* - SSR: __CER_STATE_INIT__ JSON structure contains the correct key/value
|
|
13
|
-
*
|
|
14
|
-
* False-positive prevention:
|
|
15
|
-
* The kitchen-sink page uses 'useState Page Title' as its reactive title value.
|
|
16
|
-
* This string does NOT appear anywhere hardcoded in the page template — all
|
|
17
|
-
* occurrences are driven through ${pageTitle.value}. The 'Title Updated!' value
|
|
18
|
-
* used by changeTitle() is similarly unique. This means any assertion on these
|
|
19
|
-
* strings can only pass if the useState mechanism is actually working.
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
export {}
|
|
23
|
-
|
|
24
|
-
const mode = Cypress.env('mode') as 'spa' | 'ssr' | 'ssg'
|
|
25
|
-
|
|
26
|
-
// Helper: find inside the layout-default shadow DOM (post-hydration).
|
|
27
|
-
const layout = () => cy.get('cer-layout-view').shadow().find('layout-default').shadow()
|
|
28
|
-
// Helper: find inside the page-use-state-test shadow DOM (post-hydration).
|
|
29
|
-
const statePage = () => cy.get('cer-layout-view').shadow().find('page-use-state-test').shadow()
|
|
30
|
-
|
|
31
|
-
describe('useState() — default title in layout', () => {
|
|
32
|
-
it('shows the default "Kitchen Sink" title on the home page', () => {
|
|
33
|
-
cy.visit('/')
|
|
34
|
-
cy.get('[data-cy=layout-page-title]').first().should('contain', 'Kitchen Sink')
|
|
35
|
-
})
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
describe('useState() — page sets layout title', () => {
|
|
39
|
-
beforeEach(() => {
|
|
40
|
-
cy.visit('/use-state-test')
|
|
41
|
-
statePage().find('[data-cy=use-state-heading]').should('exist')
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
it('layout shows the title set by the use-state-test page', () => {
|
|
45
|
-
layout().find('[data-cy=layout-page-title]').should('contain', 'useState Page Title')
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
it('page heading is driven by the pageTitle ref', () => {
|
|
49
|
-
statePage().find('[data-cy=use-state-heading]').should('contain', 'useState Page Title')
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
it('page-title-display shows the pageTitle ref value', () => {
|
|
53
|
-
statePage().find('[data-cy=page-title-display]').should('contain', 'useState Page Title')
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
it('clicking "Change Title" updates the layout title reactively', () => {
|
|
57
|
-
statePage().find('[data-cy=change-title]').click({ force: true })
|
|
58
|
-
layout().find('[data-cy=layout-page-title]').should('contain', 'Title Updated!')
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
it('clicking "Change Title" also updates the page heading and in-page display', () => {
|
|
62
|
-
statePage().find('[data-cy=change-title]').click({ force: true })
|
|
63
|
-
statePage().find('[data-cy=use-state-heading]').should('contain', 'Title Updated!')
|
|
64
|
-
statePage().find('[data-cy=page-title-display]').should('contain', 'Title Updated!')
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
it('clicking "Reset Title" restores the title in layout and page', () => {
|
|
68
|
-
statePage().find('[data-cy=change-title]').click({ force: true })
|
|
69
|
-
layout().find('[data-cy=layout-page-title]').should('contain', 'Title Updated!')
|
|
70
|
-
statePage().find('[data-cy=reset-title]').click({ force: true })
|
|
71
|
-
layout().find('[data-cy=layout-page-title]').should('contain', 'useState Page Title')
|
|
72
|
-
statePage().find('[data-cy=page-title-display]').should('contain', 'useState Page Title')
|
|
73
|
-
})
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
describe('useState() — title resets to default when navigating away', () => {
|
|
77
|
-
it('layout shows default title after navigating from use-state-test to home', () => {
|
|
78
|
-
cy.visit('/use-state-test')
|
|
79
|
-
statePage().find('[data-cy=use-state-heading]').should('exist')
|
|
80
|
-
layout().find('[data-cy=layout-page-title]').should('contain', 'useState Page Title')
|
|
81
|
-
|
|
82
|
-
// Navigate to a page that does not set pageTitle
|
|
83
|
-
cy.get('[data-cy=nav-home]').first().click({ force: true })
|
|
84
|
-
cy.url().should('eq', Cypress.config('baseUrl') + '/')
|
|
85
|
-
|
|
86
|
-
// The layout default kicks in for the home page
|
|
87
|
-
layout().find('[data-cy=layout-page-title]').should('contain', 'Kitchen Sink')
|
|
88
|
-
})
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
// SSR/SSG only: verify the initial server-rendered HTML already contains
|
|
92
|
-
// the page title set by the loader — no JS required.
|
|
93
|
-
// 'useState Page Title' only appears in the rendered output via useState;
|
|
94
|
-
// it is not hardcoded anywhere in the template, so this check cannot pass
|
|
95
|
-
// unless the loader correctly wrote to useState before the layout rendered.
|
|
96
|
-
if (mode !== 'spa') {
|
|
97
|
-
describe('useState() — SSR: loader sets title before rendering', () => {
|
|
98
|
-
it('initial HTML from the server already contains the loader-set title', () => {
|
|
99
|
-
cy.request('/use-state-test').then((resp) => {
|
|
100
|
-
expect(resp.body).to.include('useState Page Title')
|
|
101
|
-
})
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
it('server injects __CER_STATE_INIT__ script with the loader-set state', () => {
|
|
105
|
-
cy.request('/use-state-test').then((resp) => {
|
|
106
|
-
expect(resp.body).to.include('__CER_STATE_INIT__')
|
|
107
|
-
expect(resp.body).to.include('useState Page Title')
|
|
108
|
-
})
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
it('__CER_STATE_INIT__ JSON contains the pageTitle key with the correct value', () => {
|
|
112
|
-
cy.request('/use-state-test').then((resp) => {
|
|
113
|
-
// Extract the __CER_STATE_INIT__ assignment from the HTML
|
|
114
|
-
const match = resp.body.match(/window\.__CER_STATE_INIT__\s*=\s*(\{[^<]+\})/)
|
|
115
|
-
expect(match, '__CER_STATE_INIT__ assignment found in HTML').to.not.be.null
|
|
116
|
-
const stateInit = JSON.parse(match![1])
|
|
117
|
-
expect(stateInit).to.have.property('pageTitle', 'useState Page Title')
|
|
118
|
-
})
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
it('window.__CER_STATE_INIT__ is present on the browser window after page load', () => {
|
|
122
|
-
cy.visit('/use-state-test')
|
|
123
|
-
statePage().find('[data-cy=use-state-heading]').should('exist')
|
|
124
|
-
cy.window().should('have.property', '__CER_STATE_INIT__')
|
|
125
|
-
cy.window().its('__CER_STATE_INIT__').should('have.property', 'pageTitle', 'useState Page Title')
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
it('layout title is visible in the SSR-rendered light DOM before JS hydrates', () => {
|
|
129
|
-
cy.visit('/use-state-test', {
|
|
130
|
-
onBeforeLoad(win) {
|
|
131
|
-
// Disable custom elements upgrade so we can inspect the pre-rendered light DOM
|
|
132
|
-
;(win as Window & { __CER_HYDRATE_DISABLED__?: boolean }).__CER_HYDRATE_DISABLED__ = true
|
|
133
|
-
},
|
|
134
|
-
})
|
|
135
|
-
cy.get('[data-cy=layout-page-title]').should('contain', 'useState Page Title')
|
|
136
|
-
})
|
|
137
|
-
})
|
|
138
|
-
}
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Custom Cypress commands for the kitchen sink e2e suite.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Assert that the raw HTML for a route has correct Declarative Shadow DOM structure:
|
|
7
|
-
* - Contains <template shadowrootmode="open"> elements (value must be "open")
|
|
8
|
-
* - Each shadow template has embedded <style> (JIT CSS not stripped to <head>)
|
|
9
|
-
* - No bare (unnamed) <style> blocks in <head>
|
|
10
|
-
* - No loading indicator in the pre-rendered HTML
|
|
11
|
-
* - cer-layout-view has pre-rendered content (not empty)
|
|
12
|
-
*/
|
|
13
|
-
Cypress.Commands.add('assertDSDStructure', (path: string) => {
|
|
14
|
-
cy.request(path).then((response) => {
|
|
15
|
-
const html: string = response.body
|
|
16
|
-
|
|
17
|
-
// Must have DSD templates with value "open" (not "closed", not missing)
|
|
18
|
-
expect(html, `${path}: should contain <template shadowrootmode="open">`).to.include(
|
|
19
|
-
'shadowrootmode="open"',
|
|
20
|
-
)
|
|
21
|
-
|
|
22
|
-
// Each shadow template must have its own <style> block (not hoisted to <head>)
|
|
23
|
-
const templateMatches = [
|
|
24
|
-
...html.matchAll(/<template shadowrootmode="open"[^>]*>([\s\S]*?)<\/template>/g),
|
|
25
|
-
]
|
|
26
|
-
expect(
|
|
27
|
-
templateMatches.length,
|
|
28
|
-
`${path}: should have at least 1 shadow template with shadowrootmode="open"`,
|
|
29
|
-
).to.be.greaterThan(0)
|
|
30
|
-
|
|
31
|
-
templateMatches.forEach(([, content], i) => {
|
|
32
|
-
expect(content, `${path}: template[${i}] must contain its own <style> block`).to.include(
|
|
33
|
-
'<style',
|
|
34
|
-
)
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
// The <head> must NOT contain raw unnamed <style> blocks (only id'd global ones are OK)
|
|
38
|
-
const headMatch = html.match(/<head>([\s\S]*?)<\/head>/)
|
|
39
|
-
if (headMatch) {
|
|
40
|
-
const bareStyles = headMatch[1].match(/<style(?!\s+id)[^>]*>/g) ?? []
|
|
41
|
-
expect(
|
|
42
|
-
bareStyles.length,
|
|
43
|
-
`${path}: <head> must not contain un-named <style> blocks`,
|
|
44
|
-
).to.equal(0)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Loading indicator must NOT appear in the initial server-rendered HTML
|
|
48
|
-
expect(html, `${path}: loading indicator must not be in initial HTML`).not.to.include(
|
|
49
|
-
'data-cy="loading-indicator"',
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
// cer-layout-view must have pre-rendered content (not an empty tag)
|
|
53
|
-
const layoutViewMatch = html.match(/<cer-layout-view>([\s\S]*?)<\/cer-layout-view>/)
|
|
54
|
-
if (layoutViewMatch) {
|
|
55
|
-
expect(
|
|
56
|
-
layoutViewMatch[1].trim(),
|
|
57
|
-
`${path}: cer-layout-view must have pre-rendered content`,
|
|
58
|
-
).not.to.be.empty
|
|
59
|
-
}
|
|
60
|
-
})
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Assert that the raw HTML for a route contains specific text inside a shadow template.
|
|
65
|
-
* Use this to verify that DSD actually rendered the component's content — not just
|
|
66
|
-
* that templates exist.
|
|
67
|
-
*
|
|
68
|
-
* Since shadow templates can be nested (a component's shadow template may contain
|
|
69
|
-
* child custom elements with their own shadow templates), we verify that the expected
|
|
70
|
-
* text appears anywhere in the raw HTML. assertDSDStructure already confirms that
|
|
71
|
-
* the content is wrapped in <template shadowrootmode="open"> — if templates exist
|
|
72
|
-
* and the attribute/text is in the HTML, it lives inside those templates.
|
|
73
|
-
*/
|
|
74
|
-
Cypress.Commands.add('assertDSDContains', (path: string, expectedText: string) => {
|
|
75
|
-
cy.request(path).then((response) => {
|
|
76
|
-
const html: string = response.body
|
|
77
|
-
|
|
78
|
-
// Confirm we're in DSD territory first
|
|
79
|
-
expect(html, `${path}: page must have DSD templates before checking content`).to.include(
|
|
80
|
-
'shadowrootmode="open"',
|
|
81
|
-
)
|
|
82
|
-
|
|
83
|
-
expect(html, `${path}: shadow templates should contain "${expectedText}"`).to.include(
|
|
84
|
-
expectedText,
|
|
85
|
-
)
|
|
86
|
-
})
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Assert that after JS hydration, a custom element has a live shadow root.
|
|
91
|
-
* This confirms that DSD was processed by the browser and the element was upgraded.
|
|
92
|
-
*/
|
|
93
|
-
Cypress.Commands.add('assertShadowRootLive', (selector: string) => {
|
|
94
|
-
cy.window().then((win) => {
|
|
95
|
-
const el = win.document.querySelector(selector)
|
|
96
|
-
expect(el, `${selector}: element should exist in the DOM`).to.not.be.null
|
|
97
|
-
expect(
|
|
98
|
-
(el as Element & { shadowRoot: ShadowRoot | null }).shadowRoot,
|
|
99
|
-
`${selector}: should have a live shadow root after hydration`,
|
|
100
|
-
).to.not.be.null
|
|
101
|
-
})
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Wait for a shadow DOM element to appear (handles lazy rendering).
|
|
106
|
-
*/
|
|
107
|
-
Cypress.Commands.add('getShadow', (selector: string) => {
|
|
108
|
-
return cy.get(selector, { includeShadowDom: true })
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
declare global {
|
|
112
|
-
namespace Cypress {
|
|
113
|
-
interface Chainable {
|
|
114
|
-
assertDSDStructure(path: string): Chainable<void>
|
|
115
|
-
assertDSDContains(path: string, expectedText: string): Chainable<void>
|
|
116
|
-
assertShadowRootLive(selector: string): Chainable<void>
|
|
117
|
-
getShadow(selector: string): Chainable<JQuery<HTMLElement>>
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import './commands'
|
|
2
|
-
|
|
3
|
-
// Fail tests on uncaught exceptions only if they're from the app (not network errors)
|
|
4
|
-
Cypress.on('uncaught:exception', (err) => {
|
|
5
|
-
// Ignore fetch errors (expected in SSG mode where API routes don't exist)
|
|
6
|
-
if (err.message.includes('Failed to fetch') || err.message.includes('NetworkError')) {
|
|
7
|
-
return false
|
|
8
|
-
}
|
|
9
|
-
return true
|
|
10
|
-
})
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"lib": ["ES2022", "DOM"],
|
|
5
|
-
"types": ["cypress"],
|
|
6
|
-
"strict": true,
|
|
7
|
-
"esModuleInterop": true,
|
|
8
|
-
"skipLibCheck": true,
|
|
9
|
-
"moduleResolution": "bundler",
|
|
10
|
-
"module": "ESNext",
|
|
11
|
-
"noEmit": true,
|
|
12
|
-
},
|
|
13
|
-
"include": ["**/*.cy.ts", "support/**/*.ts"]
|
|
14
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
component('ks-badge', () => {
|
|
2
|
-
const slots = useSlots()
|
|
3
|
-
return html`
|
|
4
|
-
<span data-cy="ks-badge" style="display:inline-block;background:#e0f2fe;color:#0369a1;padding:2px 8px;border-radius:4px;font-size:0.85em;font-weight:600">
|
|
5
|
-
${slots.default ?? 'badge'}
|
|
6
|
-
</span>
|
|
7
|
-
`
|
|
8
|
-
})
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { ref } from '@jasonshimmy/custom-elements-runtime'
|
|
2
|
-
|
|
3
|
-
export function useKsCounter(initial = 0) {
|
|
4
|
-
const count = ref(initial)
|
|
5
|
-
const increment = () => { count.value++ }
|
|
6
|
-
const decrement = () => { count.value-- }
|
|
7
|
-
const reset = () => { count.value = 0 }
|
|
8
|
-
return { count, increment, decrement, reset }
|
|
9
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
component('page-error', () => {
|
|
2
|
-
const props = useProps<{ error: string; status: string }>({
|
|
3
|
-
error: 'An unexpected error occurred.',
|
|
4
|
-
status: '500',
|
|
5
|
-
})
|
|
6
|
-
|
|
7
|
-
return html`
|
|
8
|
-
<div data-cy="error-boundary" style="padding:2rem;font-family:sans-serif">
|
|
9
|
-
<h2 data-cy="error-heading" style="color:#c00;margin-top:0">
|
|
10
|
-
Error ${props.status}
|
|
11
|
-
</h2>
|
|
12
|
-
<pre data-cy="error-message" style="background:#fff0f0;border:1px solid #fcc;padding:1rem;border-radius:4px">${props.error}</pre>
|
|
13
|
-
<button data-cy="error-retry" @click="${() => (globalThis as any).resetError?.()}">
|
|
14
|
-
Try again
|
|
15
|
-
</button>
|
|
16
|
-
</div>
|
|
17
|
-
`
|
|
18
|
-
})
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
component('layout-admin', () => {
|
|
2
|
-
return html`
|
|
3
|
-
<div data-cy="admin-layout">
|
|
4
|
-
<aside data-cy="admin-sidebar">
|
|
5
|
-
<p>Admin Panel</p>
|
|
6
|
-
<a href="/admin/dashboard" data-cy="admin-nav-dashboard">Dashboard</a>
|
|
7
|
-
</aside>
|
|
8
|
-
<section data-cy="admin-content">
|
|
9
|
-
<slot></slot>
|
|
10
|
-
</section>
|
|
11
|
-
</div>
|
|
12
|
-
`
|
|
13
|
-
})
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
component('layout-default', () => {
|
|
2
|
-
const pageTitle = useState('pageTitle', 'Kitchen Sink')
|
|
3
|
-
|
|
4
|
-
return html`
|
|
5
|
-
<div>
|
|
6
|
-
<header data-cy="site-header">
|
|
7
|
-
<span data-cy="layout-page-title">${pageTitle.value}</span>
|
|
8
|
-
<nav data-cy="site-nav">
|
|
9
|
-
<a data-cy="nav-home" href="/">Home</a>
|
|
10
|
-
<a data-cy="nav-about" href="/about">About</a>
|
|
11
|
-
<a data-cy="nav-counter" href="/counter">Counter</a>
|
|
12
|
-
<a data-cy="nav-blog" href="/blog">Blog</a>
|
|
13
|
-
<a data-cy="nav-protected" href="/protected">Protected</a>
|
|
14
|
-
<a data-cy="nav-use-state-test" href="/use-state-test">useState Test</a>
|
|
15
|
-
</nav>
|
|
16
|
-
</header>
|
|
17
|
-
<main data-cy="site-main">
|
|
18
|
-
<slot></slot>
|
|
19
|
-
</main>
|
|
20
|
-
<footer data-cy="site-footer">
|
|
21
|
-
<p>Kitchen Sink — testing every framework capability</p>
|
|
22
|
-
</footer>
|
|
23
|
-
</div>
|
|
24
|
-
`
|
|
25
|
-
})
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
component('page-loading', () => {
|
|
2
|
-
return html`
|
|
3
|
-
<div data-cy="loading-indicator" style="display:flex;align-items:center;gap:8px;padding:1rem;font-family:sans-serif;color:#888">
|
|
4
|
-
<span style="display:inline-block;width:14px;height:14px;border:2px solid #ccc;border-top-color:#555;border-radius:50%;animation:spin 0.7s linear infinite"></span>
|
|
5
|
-
Loading…
|
|
6
|
-
<style>@keyframes spin { to { transform: rotate(360deg) } }</style>
|
|
7
|
-
</div>
|
|
8
|
-
`
|
|
9
|
-
})
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
// Route middleware — redirects to /login if not authenticated.
|
|
2
|
-
// Set localStorage.setItem('ks-token', '1') to simulate login.
|
|
3
|
-
export default defineMiddleware((_to, _from) => {
|
|
4
|
-
const isLoggedIn = typeof localStorage !== 'undefined'
|
|
5
|
-
? !!localStorage.getItem('ks-token')
|
|
6
|
-
: false
|
|
7
|
-
|
|
8
|
-
return isLoggedIn ? true : '/login'
|
|
9
|
-
})
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
// P2-1: Group auth middleware — redirects unauthorized users.
|
|
2
|
-
// Adds a visible guard marker so e2e tests can detect it was applied.
|
|
3
|
-
export default defineMiddleware(() => {
|
|
4
|
-
// Returning a string path redirects to that route.
|
|
5
|
-
// In a real app this would check auth state first.
|
|
6
|
-
return '/group-auth-blocked'
|
|
7
|
-
})
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
// Wrapper middleware that uses next() to run code before and after the rest
|
|
2
|
-
// of the middleware chain. Stores a breadcrumb in sessionStorage so e2e tests
|
|
3
|
-
// can verify that next() was called in the correct order.
|
|
4
|
-
export default defineMiddleware(async (_to, _from, next) => {
|
|
5
|
-
if (typeof sessionStorage !== 'undefined') {
|
|
6
|
-
const prev = sessionStorage.getItem('mw-log') ?? ''
|
|
7
|
-
sessionStorage.setItem('mw-log', `${prev}before:`)
|
|
8
|
-
}
|
|
9
|
-
await next()
|
|
10
|
-
if (typeof sessionStorage !== 'undefined') {
|
|
11
|
-
const prev = sessionStorage.getItem('mw-log') ?? ''
|
|
12
|
-
sessionStorage.setItem('mw-log', `${prev}after`)
|
|
13
|
-
}
|
|
14
|
-
})
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
component('page-login', () => {
|
|
2
|
-
return html`
|
|
3
|
-
<div>
|
|
4
|
-
<h1 data-cy="login-heading">Login</h1>
|
|
5
|
-
<p data-cy="login-description">This page uses the <strong>minimal</strong> layout.</p>
|
|
6
|
-
<button data-cy="login-btn" @click="${() => { localStorage.setItem('ks-token', '1'); location.href = '/protected' }}">
|
|
7
|
-
Simulate Login
|
|
8
|
-
</button>
|
|
9
|
-
</div>
|
|
10
|
-
`
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
export const meta = { layout: 'minimal' }
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
component('page-protected', () => {
|
|
2
|
-
const greeting = useInject<string>('ks-greeting', 'No greeting')
|
|
3
|
-
|
|
4
|
-
return html`
|
|
5
|
-
<div>
|
|
6
|
-
<h1 data-cy="protected-heading">Protected Page</h1>
|
|
7
|
-
<p data-cy="protected-note">You are authenticated! This page requires the <code>auth</code> middleware.</p>
|
|
8
|
-
<p data-cy="plugin-greeting">Plugin says: <strong>${greeting}</strong></p>
|
|
9
|
-
<button data-cy="logout-btn" @click="${() => { localStorage.removeItem('ks-token'); location.href = '/protected' }}">
|
|
10
|
-
Log out and reload
|
|
11
|
-
</button>
|
|
12
|
-
</div>
|
|
13
|
-
`
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
export const meta = { middleware: ['auth'] }
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
component('page-404', () => {
|
|
2
|
-
return html`
|
|
3
|
-
<div>
|
|
4
|
-
<h1 data-cy="not-found-heading">404 — Not Found</h1>
|
|
5
|
-
<p data-cy="not-found-description">The page you are looking for does not exist.</p>
|
|
6
|
-
<p><a href="/" data-cy="not-found-home">← Back home</a></p>
|
|
7
|
-
</div>
|
|
8
|
-
`
|
|
9
|
-
})
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
component('page-about', () => {
|
|
2
|
-
useHead({
|
|
3
|
-
title: 'About — Kitchen Sink',
|
|
4
|
-
meta: [{ name: 'description', content: 'About the kitchen sink test app.' }],
|
|
5
|
-
})
|
|
6
|
-
|
|
7
|
-
return html`
|
|
8
|
-
<div>
|
|
9
|
-
<h1 data-cy="about-heading">About</h1>
|
|
10
|
-
<p data-cy="about-description">This page uses the <strong>minimal</strong> layout.</p>
|
|
11
|
-
<p data-cy="about-layout-note">It also calls <code>useHead()</code> to set title and meta tags.</p>
|
|
12
|
-
<p><a href="/" data-cy="about-back">← Back home</a></p>
|
|
13
|
-
</div>
|
|
14
|
-
`
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
export const meta = { layout: 'minimal' }
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export default 'admin'
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
component('page-admin-dashboard', () => {
|
|
2
|
-
const config = useRuntimeConfig()
|
|
3
|
-
const appName = config.public?.appName ?? 'Kitchen Sink'
|
|
4
|
-
|
|
5
|
-
return html`
|
|
6
|
-
<div>
|
|
7
|
-
<h1 data-cy="admin-dashboard-heading">Admin Dashboard</h1>
|
|
8
|
-
<p data-cy="admin-app-name">App: ${appName}</p>
|
|
9
|
-
</div>
|
|
10
|
-
`
|
|
11
|
-
})
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
// P2-4: Page that uses defineAsyncComponent with a failing loader.
|
|
2
|
-
defineAsyncComponent(
|
|
3
|
-
'ks-async-fail',
|
|
4
|
-
() => Promise.reject(new Error('Async component load failed')),
|
|
5
|
-
{
|
|
6
|
-
loading: () => html`<p>Loading…</p>`,
|
|
7
|
-
error: () => html`<p data-cy="async-component-error">Failed to load async component</p>`,
|
|
8
|
-
},
|
|
9
|
-
)
|
|
10
|
-
|
|
11
|
-
component('page-async-component-error-test', () => {
|
|
12
|
-
return html`
|
|
13
|
-
<div>
|
|
14
|
-
<h1 data-cy="async-error-page-heading">Async Component Error Test</h1>
|
|
15
|
-
<ks-async-fail></ks-async-fail>
|
|
16
|
-
</div>
|
|
17
|
-
`
|
|
18
|
-
})
|