@jasonshimmy/vite-plugin-cer-app 0.23.1 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +37 -4
- 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 +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/plugin/build-ssg.d.ts +22 -4
- package/dist/plugin/build-ssg.d.ts.map +1 -1
- package/dist/plugin/build-ssg.js +273 -13
- 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 +6 -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 +35 -0
- package/dist/plugin/html-post-process.d.ts.map +1 -0
- package/dist/plugin/html-post-process.js +112 -0
- package/dist/plugin/html-post-process.js.map +1 -0
- package/dist/plugin/index.d.ts +9 -0
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +89 -14
- 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 -4
- package/dist/runtime/app-template.d.ts.map +1 -1
- package/dist/runtime/app-template.js +211 -40
- 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-head.d.ts.map +1 -1
- package/dist/runtime/composables/use-head.js +30 -6
- package/dist/runtime/composables/use-head.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 +53 -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 -232
- 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 -667
- 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 -112
- 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/path-utils.test.ts +0 -411
- package/src/__tests__/plugin/resolve-config.test.ts +0 -200
- 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 -198
- 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 -266
- 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 -489
- 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 -336
- 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 -377
- package/src/plugin/dts-generator.ts +0 -273
- package/src/plugin/generated-dir.ts +0 -121
- package/src/plugin/index.ts +0 -553
- 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 -380
- 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 -212
- 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 -371
- 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,226 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for queryContent() composable and QueryBuilder.
|
|
3
|
-
*
|
|
4
|
-
* Covers:
|
|
5
|
-
* - Server-side path: reads from globalThis.__CER_CONTENT_STORE__
|
|
6
|
-
* - .where() predicate filtering
|
|
7
|
-
* - .sortBy() sorting
|
|
8
|
-
* - .limit() and .skip() pagination
|
|
9
|
-
* - .find() returns ContentMeta[]
|
|
10
|
-
* - .count() returns number
|
|
11
|
-
* - .first() returns ContentItem (direct path fetch fast path)
|
|
12
|
-
* - .first() with filters (slow path through manifest)
|
|
13
|
-
* - prefix scoping
|
|
14
|
-
* - empty results
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
|
|
18
|
-
import type { ContentItem } from '../../types/content.js'
|
|
19
|
-
|
|
20
|
-
const g = globalThis as Record<string, unknown>
|
|
21
|
-
|
|
22
|
-
const STORE: ContentItem[] = [
|
|
23
|
-
{
|
|
24
|
-
_path: '/blog/hello',
|
|
25
|
-
_file: 'blog/hello.md',
|
|
26
|
-
_type: 'markdown',
|
|
27
|
-
title: 'Hello World',
|
|
28
|
-
description: 'First post',
|
|
29
|
-
date: '2026-04-03',
|
|
30
|
-
draft: false,
|
|
31
|
-
body: '<p>Hello</p>',
|
|
32
|
-
toc: [],
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
_path: '/blog/world',
|
|
36
|
-
_file: 'blog/world.md',
|
|
37
|
-
_type: 'markdown',
|
|
38
|
-
title: 'World Post',
|
|
39
|
-
description: 'Second post',
|
|
40
|
-
date: '2026-04-10',
|
|
41
|
-
draft: true,
|
|
42
|
-
body: '<p>World</p>',
|
|
43
|
-
toc: [],
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
_path: '/about',
|
|
47
|
-
_file: 'about.md',
|
|
48
|
-
_type: 'markdown',
|
|
49
|
-
title: 'About',
|
|
50
|
-
body: '<p>About</p>',
|
|
51
|
-
toc: [],
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
_path: '/blog',
|
|
55
|
-
_file: 'blog/index.md',
|
|
56
|
-
_type: 'markdown',
|
|
57
|
-
title: 'Blog',
|
|
58
|
-
body: '<p>Blog index</p>',
|
|
59
|
-
toc: [],
|
|
60
|
-
},
|
|
61
|
-
]
|
|
62
|
-
|
|
63
|
-
function setup() {
|
|
64
|
-
g['__CER_CONTENT_STORE__'] = STORE
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function teardown() {
|
|
68
|
-
delete g['__CER_CONTENT_STORE__']
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
describe('queryContent() — .find()', () => {
|
|
72
|
-
beforeEach(setup)
|
|
73
|
-
afterEach(teardown)
|
|
74
|
-
|
|
75
|
-
it('returns all items when no prefix', async () => {
|
|
76
|
-
const { queryContent } = await import('../../runtime/composables/use-content.js')
|
|
77
|
-
const result = await queryContent().find()
|
|
78
|
-
expect(result).toHaveLength(STORE.length)
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
it('filters by prefix — exact match', async () => {
|
|
82
|
-
const { queryContent } = await import('../../runtime/composables/use-content.js')
|
|
83
|
-
const result = await queryContent('/about').find()
|
|
84
|
-
expect(result).toHaveLength(1)
|
|
85
|
-
expect(result[0]._path).toBe('/about')
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
it('filters by prefix — includes children', async () => {
|
|
89
|
-
const { queryContent } = await import('../../runtime/composables/use-content.js')
|
|
90
|
-
const result = await queryContent('/blog').find()
|
|
91
|
-
expect(result.map((r) => r._path).sort()).toEqual(['/blog', '/blog/hello', '/blog/world'])
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
it('.where() filters items', async () => {
|
|
95
|
-
const { queryContent } = await import('../../runtime/composables/use-content.js')
|
|
96
|
-
const result = await queryContent('/blog').where((doc) => !doc.draft).find()
|
|
97
|
-
expect(result.every((r) => !r.draft)).toBe(true)
|
|
98
|
-
expect(result.some((r) => r._path === '/blog/world')).toBe(false)
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
it('.where() with date filter', async () => {
|
|
102
|
-
const { queryContent } = await import('../../runtime/composables/use-content.js')
|
|
103
|
-
const result = await queryContent('/blog')
|
|
104
|
-
.where((doc) => typeof doc.date === 'string' && doc.date >= '2026-04-09')
|
|
105
|
-
.find()
|
|
106
|
-
expect(result).toHaveLength(1)
|
|
107
|
-
expect(result[0]._path).toBe('/blog/world')
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
it('.sortBy() ascending', async () => {
|
|
111
|
-
const { queryContent } = await import('../../runtime/composables/use-content.js')
|
|
112
|
-
const result = await queryContent('/blog').sortBy('date').find()
|
|
113
|
-
const dates = result.filter((r) => r.date).map((r) => r.date as string)
|
|
114
|
-
expect(dates).toEqual([...dates].sort())
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
it('.sortBy() descending', async () => {
|
|
118
|
-
const { queryContent } = await import('../../runtime/composables/use-content.js')
|
|
119
|
-
const result = await queryContent('/blog').sortBy('date', 'desc').find()
|
|
120
|
-
const dates = result.filter((r) => r.date).map((r) => r.date as string)
|
|
121
|
-
expect(dates).toEqual([...dates].sort().reverse())
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
it('.limit() caps results', async () => {
|
|
125
|
-
const { queryContent } = await import('../../runtime/composables/use-content.js')
|
|
126
|
-
const result = await queryContent().limit(2).find()
|
|
127
|
-
expect(result).toHaveLength(2)
|
|
128
|
-
})
|
|
129
|
-
|
|
130
|
-
it('.skip() offsets results', async () => {
|
|
131
|
-
const { queryContent } = await import('../../runtime/composables/use-content.js')
|
|
132
|
-
const all = await queryContent().find()
|
|
133
|
-
const skipped = await queryContent().skip(1).find()
|
|
134
|
-
expect(skipped).toHaveLength(all.length - 1)
|
|
135
|
-
expect(skipped[0]._path).toBe(all[1]._path)
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
it('chained .where().sortBy().limit()', async () => {
|
|
139
|
-
const { queryContent } = await import('../../runtime/composables/use-content.js')
|
|
140
|
-
const result = await queryContent('/blog')
|
|
141
|
-
.where((doc) => !doc.draft)
|
|
142
|
-
.sortBy('date', 'desc')
|
|
143
|
-
.limit(1)
|
|
144
|
-
.find()
|
|
145
|
-
expect(result).toHaveLength(1)
|
|
146
|
-
})
|
|
147
|
-
|
|
148
|
-
it('returns ContentMeta — no body in results', async () => {
|
|
149
|
-
const { queryContent } = await import('../../runtime/composables/use-content.js')
|
|
150
|
-
const result = await queryContent().find()
|
|
151
|
-
for (const item of result) {
|
|
152
|
-
expect('body' in item).toBe(false)
|
|
153
|
-
}
|
|
154
|
-
})
|
|
155
|
-
|
|
156
|
-
it('no prefix returns all items including those outside /blog', async () => {
|
|
157
|
-
const { queryContent } = await import('../../runtime/composables/use-content.js')
|
|
158
|
-
const result = await queryContent().find()
|
|
159
|
-
expect(result.some((r) => r._path === '/about')).toBe(true)
|
|
160
|
-
})
|
|
161
|
-
})
|
|
162
|
-
|
|
163
|
-
describe('queryContent() — .count()', () => {
|
|
164
|
-
beforeEach(setup)
|
|
165
|
-
afterEach(teardown)
|
|
166
|
-
|
|
167
|
-
it('returns total count with no filters', async () => {
|
|
168
|
-
const { queryContent } = await import('../../runtime/composables/use-content.js')
|
|
169
|
-
const count = await queryContent().count()
|
|
170
|
-
expect(count).toBe(STORE.length)
|
|
171
|
-
})
|
|
172
|
-
|
|
173
|
-
it('returns filtered count with .where()', async () => {
|
|
174
|
-
const { queryContent } = await import('../../runtime/composables/use-content.js')
|
|
175
|
-
const count = await queryContent('/blog').where((doc) => !doc.draft).count()
|
|
176
|
-
// /blog index (no draft field) + /blog/hello (draft: false)
|
|
177
|
-
expect(count).toBe(2)
|
|
178
|
-
})
|
|
179
|
-
})
|
|
180
|
-
|
|
181
|
-
describe('queryContent() — .first()', () => {
|
|
182
|
-
beforeEach(setup)
|
|
183
|
-
afterEach(teardown)
|
|
184
|
-
|
|
185
|
-
it('fast path: fetches item directly by path', async () => {
|
|
186
|
-
const { queryContent } = await import('../../runtime/composables/use-content.js')
|
|
187
|
-
const item = await queryContent('/about').first()
|
|
188
|
-
expect(item).not.toBeNull()
|
|
189
|
-
expect(item?._path).toBe('/about')
|
|
190
|
-
expect(item?.body).toBe('<p>About</p>')
|
|
191
|
-
})
|
|
192
|
-
|
|
193
|
-
it('fast path: returns null for unknown path', async () => {
|
|
194
|
-
const { queryContent } = await import('../../runtime/composables/use-content.js')
|
|
195
|
-
const item = await queryContent('/does-not-exist').first()
|
|
196
|
-
expect(item).toBeNull()
|
|
197
|
-
})
|
|
198
|
-
|
|
199
|
-
it('slow path: applies .where() filter then fetches first match', async () => {
|
|
200
|
-
const { queryContent } = await import('../../runtime/composables/use-content.js')
|
|
201
|
-
const item = await queryContent('/blog')
|
|
202
|
-
.where((doc) => !doc.draft)
|
|
203
|
-
.first()
|
|
204
|
-
expect(item).not.toBeNull()
|
|
205
|
-
expect(item?.draft).not.toBe(true)
|
|
206
|
-
})
|
|
207
|
-
|
|
208
|
-
it('returns full ContentItem with body and toc', async () => {
|
|
209
|
-
const { queryContent } = await import('../../runtime/composables/use-content.js')
|
|
210
|
-
const item = await queryContent('/blog/hello').first()
|
|
211
|
-
expect(item?.body).toBeDefined()
|
|
212
|
-
expect(Array.isArray(item?.toc)).toBe(true)
|
|
213
|
-
})
|
|
214
|
-
|
|
215
|
-
it('returns null when no prefix is set and no store', async () => {
|
|
216
|
-
// Remove store temporarily
|
|
217
|
-
delete g['__CER_CONTENT_STORE__']
|
|
218
|
-
const { queryContent } = await import('../../runtime/composables/use-content.js')
|
|
219
|
-
// Without store, the client fetch path will run; since there's no real server, it may fail.
|
|
220
|
-
// Just verify it doesn't throw — result can be null.
|
|
221
|
-
const item = await queryContent('/about').first().catch(() => null)
|
|
222
|
-
expect(item === null || item === undefined || typeof item === 'object').toBe(true)
|
|
223
|
-
// Restore
|
|
224
|
-
g['__CER_CONTENT_STORE__'] = STORE
|
|
225
|
-
})
|
|
226
|
-
})
|
|
@@ -1,277 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @vitest-environment happy-dom
|
|
3
|
-
*/
|
|
4
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
|
|
5
|
-
import type { IncomingMessage, ServerResponse } from 'node:http'
|
|
6
|
-
import { AsyncLocalStorage } from 'node:async_hooks'
|
|
7
|
-
import { useCookie } from '../../runtime/composables/use-cookie.js'
|
|
8
|
-
|
|
9
|
-
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
10
|
-
|
|
11
|
-
function makeReqRes(cookieHeader = ''): { req: IncomingMessage; res: ServerResponse } {
|
|
12
|
-
const req = { headers: { cookie: cookieHeader } } as unknown as IncomingMessage
|
|
13
|
-
const headers: Record<string, string | string[]> = {}
|
|
14
|
-
const res = {
|
|
15
|
-
getHeader: (name: string) => headers[name.toLowerCase()],
|
|
16
|
-
setHeader(name: string, value: string | string[]) { headers[name.toLowerCase()] = value },
|
|
17
|
-
} as unknown as ServerResponse
|
|
18
|
-
return { req, res }
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// ─── SSR path ─────────────────────────────────────────────────────────────────
|
|
22
|
-
|
|
23
|
-
describe('useCookie — SSR (via AsyncLocalStorage)', () => {
|
|
24
|
-
const store = new AsyncLocalStorage<{ req: IncomingMessage; res: ServerResponse }>()
|
|
25
|
-
|
|
26
|
-
beforeEach(() => {
|
|
27
|
-
;(globalThis as Record<string, unknown>)['__CER_REQ_STORE__'] = store
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
afterEach(() => {
|
|
31
|
-
delete (globalThis as Record<string, unknown>)['__CER_REQ_STORE__']
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
it('reads a cookie from the request', () => {
|
|
35
|
-
const { req, res } = makeReqRes('token=abc123; other=xyz')
|
|
36
|
-
store.run({ req, res }, () => {
|
|
37
|
-
const cookie = useCookie('token')
|
|
38
|
-
expect(cookie.value).toBe('abc123')
|
|
39
|
-
})
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
it('returns undefined for a missing cookie', () => {
|
|
43
|
-
const { req, res } = makeReqRes('other=xyz')
|
|
44
|
-
store.run({ req, res }, () => {
|
|
45
|
-
const cookie = useCookie('missing')
|
|
46
|
-
expect(cookie.value).toBeUndefined()
|
|
47
|
-
})
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
it('writes a Set-Cookie header on set()', () => {
|
|
51
|
-
const { req, res } = makeReqRes()
|
|
52
|
-
store.run({ req, res }, () => {
|
|
53
|
-
useCookie('session').set('s1')
|
|
54
|
-
})
|
|
55
|
-
const header = res.getHeader('Set-Cookie') as string[]
|
|
56
|
-
expect(header).toBeDefined()
|
|
57
|
-
const value = Array.isArray(header) ? header[0] : header
|
|
58
|
-
expect(value).toContain('session=s1')
|
|
59
|
-
expect(value).toContain('Path=/')
|
|
60
|
-
expect(value).toContain('SameSite=Lax')
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
it('defaults SameSite to Lax when no sameSite option is provided', () => {
|
|
64
|
-
const { req, res } = makeReqRes()
|
|
65
|
-
store.run({ req, res }, () => {
|
|
66
|
-
useCookie('tok').set('v')
|
|
67
|
-
})
|
|
68
|
-
const header = res.getHeader('Set-Cookie') as string[]
|
|
69
|
-
const value = Array.isArray(header) ? header[0] : header
|
|
70
|
-
expect(value).toContain('SameSite=Lax')
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
it('appends to existing Set-Cookie headers', () => {
|
|
74
|
-
const { req, res } = makeReqRes()
|
|
75
|
-
store.run({ req, res }, () => {
|
|
76
|
-
useCookie('a').set('1')
|
|
77
|
-
useCookie('b').set('2')
|
|
78
|
-
})
|
|
79
|
-
const header = res.getHeader('Set-Cookie') as string[]
|
|
80
|
-
expect(Array.isArray(header)).toBe(true)
|
|
81
|
-
expect(header).toHaveLength(2)
|
|
82
|
-
expect(header[0]).toContain('a=1')
|
|
83
|
-
expect(header[1]).toContain('b=2')
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
it('writes Max-Age=0 on remove()', () => {
|
|
87
|
-
const { req, res } = makeReqRes('session=old')
|
|
88
|
-
store.run({ req, res }, () => {
|
|
89
|
-
useCookie('session').remove()
|
|
90
|
-
})
|
|
91
|
-
const header = res.getHeader('Set-Cookie') as string[]
|
|
92
|
-
const value = Array.isArray(header) ? header[0] : header
|
|
93
|
-
expect(value).toContain('Max-Age=0')
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
it('forwards options (httpOnly, secure, sameSite) when setting', () => {
|
|
97
|
-
const { req, res } = makeReqRes()
|
|
98
|
-
store.run({ req, res }, () => {
|
|
99
|
-
useCookie('auth').set('tok', { httpOnly: true, secure: true, sameSite: 'Strict' })
|
|
100
|
-
})
|
|
101
|
-
const header = res.getHeader('Set-Cookie') as string[]
|
|
102
|
-
const value = Array.isArray(header) ? header[0] : header
|
|
103
|
-
expect(value).toContain('HttpOnly')
|
|
104
|
-
expect(value).toContain('Secure')
|
|
105
|
-
expect(value).toContain('SameSite=Strict')
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
it('forwards options (maxAge, path, domain) when removing', () => {
|
|
109
|
-
const { req, res } = makeReqRes('auth=tok')
|
|
110
|
-
store.run({ req, res }, () => {
|
|
111
|
-
useCookie('auth').remove({ path: '/app', domain: 'example.com' })
|
|
112
|
-
})
|
|
113
|
-
const header = res.getHeader('Set-Cookie') as string[]
|
|
114
|
-
const value = Array.isArray(header) ? header[0] : header
|
|
115
|
-
expect(value).toContain('Max-Age=0')
|
|
116
|
-
expect(value).toContain('Path=/app')
|
|
117
|
-
expect(value).toContain('Domain=example.com')
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
it('decodes percent-encoded cookie values', () => {
|
|
121
|
-
const { req, res } = makeReqRes(`msg=${encodeURIComponent('hello world')}`)
|
|
122
|
-
store.run({ req, res }, () => {
|
|
123
|
-
const cookie = useCookie('msg')
|
|
124
|
-
expect(cookie.value).toBe('hello world')
|
|
125
|
-
})
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
it('round-trips values with special characters (spaces, slashes, unicode)', () => {
|
|
129
|
-
const specialValue = 'hello world/path?q=1&r=2 ✓'
|
|
130
|
-
const { req, res } = makeReqRes(`special=${encodeURIComponent(specialValue)}`)
|
|
131
|
-
store.run({ req, res }, () => {
|
|
132
|
-
const cookie = useCookie('special')
|
|
133
|
-
expect(cookie.value).toBe(specialValue)
|
|
134
|
-
})
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
it('encodes special characters in Set-Cookie when setting a value', () => {
|
|
138
|
-
const { req, res } = makeReqRes()
|
|
139
|
-
const specialValue = 'hello world/path?q=1'
|
|
140
|
-
store.run({ req, res }, () => {
|
|
141
|
-
useCookie('data').set(specialValue)
|
|
142
|
-
})
|
|
143
|
-
const header = res.getHeader('Set-Cookie') as string[]
|
|
144
|
-
const cookieStr = Array.isArray(header) ? header[0] : header
|
|
145
|
-
// Value must be percent-encoded in the Set-Cookie header
|
|
146
|
-
expect(cookieStr).toContain(encodeURIComponent(specialValue))
|
|
147
|
-
expect(cookieStr).not.toContain(specialValue)
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
it('survives a malformed cookie segment without throwing', () => {
|
|
151
|
-
// A segment with no '=' should be skipped gracefully
|
|
152
|
-
const { req, res } = makeReqRes('broken; valid=ok; =noname')
|
|
153
|
-
store.run({ req, res }, () => {
|
|
154
|
-
const cookie = useCookie('valid')
|
|
155
|
-
expect(cookie.value).toBe('ok')
|
|
156
|
-
expect(useCookie('broken').value).toBeUndefined()
|
|
157
|
-
})
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
it('uses raw value when decodeURIComponent throws (malformed percent-encoding)', () => {
|
|
161
|
-
// '%ZZ' is invalid percent-encoding and causes decodeURIComponent to throw.
|
|
162
|
-
// The parser must fall back to the raw value instead of crashing.
|
|
163
|
-
const { req, res } = makeReqRes('bad=%ZZ; good=ok')
|
|
164
|
-
store.run({ req, res }, () => {
|
|
165
|
-
expect(useCookie('bad').value).toBe('%ZZ')
|
|
166
|
-
expect(useCookie('good').value).toBe('ok')
|
|
167
|
-
})
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
it('returns undefined value outside a store context', () => {
|
|
171
|
-
// store is registered but no run() context — getStore() returns null
|
|
172
|
-
const cookie = useCookie('x')
|
|
173
|
-
expect(cookie.value).toBeUndefined()
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
it('applies defaultOptions when no call-time options are passed to set()', () => {
|
|
177
|
-
const { req, res } = makeReqRes()
|
|
178
|
-
store.run({ req, res }, () => {
|
|
179
|
-
useCookie('auth', { httpOnly: true, secure: true, sameSite: 'Strict' }).set('tok')
|
|
180
|
-
})
|
|
181
|
-
const header = res.getHeader('Set-Cookie') as string[]
|
|
182
|
-
const value = Array.isArray(header) ? header[0] : header
|
|
183
|
-
expect(value).toContain('HttpOnly')
|
|
184
|
-
expect(value).toContain('Secure')
|
|
185
|
-
expect(value).toContain('SameSite=Strict')
|
|
186
|
-
})
|
|
187
|
-
|
|
188
|
-
it('call-time options override defaultOptions', () => {
|
|
189
|
-
const { req, res } = makeReqRes()
|
|
190
|
-
store.run({ req, res }, () => {
|
|
191
|
-
useCookie('pref', { sameSite: 'Strict', httpOnly: true }).set('v', { sameSite: 'Lax' })
|
|
192
|
-
})
|
|
193
|
-
const header = res.getHeader('Set-Cookie') as string[]
|
|
194
|
-
const value = Array.isArray(header) ? header[0] : header
|
|
195
|
-
// call-time sameSite: 'Lax' must win over the default 'Strict'
|
|
196
|
-
expect(value).toContain('SameSite=Lax')
|
|
197
|
-
expect(value).not.toContain('SameSite=Strict')
|
|
198
|
-
// defaultOptions httpOnly is still inherited
|
|
199
|
-
expect(value).toContain('HttpOnly')
|
|
200
|
-
})
|
|
201
|
-
|
|
202
|
-
it('defaultOptions are applied on remove() when no call-time options are passed', () => {
|
|
203
|
-
const { req, res } = makeReqRes('secure=tok')
|
|
204
|
-
store.run({ req, res }, () => {
|
|
205
|
-
useCookie('secure', { path: '/app', domain: 'example.com' }).remove()
|
|
206
|
-
})
|
|
207
|
-
const header = res.getHeader('Set-Cookie') as string[]
|
|
208
|
-
const value = Array.isArray(header) ? header[0] : header
|
|
209
|
-
expect(value).toContain('Max-Age=0')
|
|
210
|
-
expect(value).toContain('Path=/app')
|
|
211
|
-
expect(value).toContain('Domain=example.com')
|
|
212
|
-
})
|
|
213
|
-
})
|
|
214
|
-
|
|
215
|
-
// ─── Client path ──────────────────────────────────────────────────────────────
|
|
216
|
-
|
|
217
|
-
describe('useCookie — client (document.cookie)', () => {
|
|
218
|
-
beforeEach(() => {
|
|
219
|
-
// Ensure no SSR store leaks into client tests
|
|
220
|
-
delete (globalThis as Record<string, unknown>)['__CER_REQ_STORE__']
|
|
221
|
-
// Clear document cookies
|
|
222
|
-
document.cookie.split(';').forEach((c) => {
|
|
223
|
-
const name = c.split('=')[0].trim()
|
|
224
|
-
if (name) document.cookie = `${name}=; Max-Age=0; Path=/`
|
|
225
|
-
})
|
|
226
|
-
})
|
|
227
|
-
|
|
228
|
-
it('reads a cookie set via document.cookie', () => {
|
|
229
|
-
document.cookie = 'theme=dark'
|
|
230
|
-
const cookie = useCookie('theme')
|
|
231
|
-
expect(cookie.value).toBe('dark')
|
|
232
|
-
})
|
|
233
|
-
|
|
234
|
-
it('returns undefined when the cookie is not set', () => {
|
|
235
|
-
const cookie = useCookie('nonexistent')
|
|
236
|
-
expect(cookie.value).toBeUndefined()
|
|
237
|
-
})
|
|
238
|
-
|
|
239
|
-
it('writes to document.cookie on set()', () => {
|
|
240
|
-
useCookie('lang').set('en')
|
|
241
|
-
const cookie = useCookie('lang')
|
|
242
|
-
expect(cookie.value).toBe('en')
|
|
243
|
-
})
|
|
244
|
-
|
|
245
|
-
it('removes a cookie on remove()', () => {
|
|
246
|
-
document.cookie = 'removeme=yes'
|
|
247
|
-
useCookie('removeme').remove()
|
|
248
|
-
const cookie = useCookie('removeme')
|
|
249
|
-
// After removal the cookie value should be empty or undefined
|
|
250
|
-
expect(cookie.value === undefined || cookie.value === '').toBe(true)
|
|
251
|
-
})
|
|
252
|
-
|
|
253
|
-
it('percent-encodes values with special characters', () => {
|
|
254
|
-
useCookie('data').set('hello world')
|
|
255
|
-
const raw = document.cookie
|
|
256
|
-
expect(raw).toContain('hello%20world')
|
|
257
|
-
})
|
|
258
|
-
})
|
|
259
|
-
|
|
260
|
-
// ─── Build-time / unknown context ─────────────────────────────────────────────
|
|
261
|
-
|
|
262
|
-
describe('useCookie — unknown context (no store, no document)', () => {
|
|
263
|
-
it('returns undefined value and no-op set/remove when neither SSR nor client context is available', () => {
|
|
264
|
-
delete (globalThis as Record<string, unknown>)['__CER_REQ_STORE__']
|
|
265
|
-
// Simulate a non-browser, non-SSR context by verifying the composable
|
|
266
|
-
// falls through to the default branch (value === undefined, methods are no-ops).
|
|
267
|
-
// We can verify this by calling with a store that has no active context.
|
|
268
|
-
const store = new AsyncLocalStorage()
|
|
269
|
-
;(globalThis as Record<string, unknown>)['__CER_REQ_STORE__'] = store
|
|
270
|
-
// getStore() returns null because we're outside a run() context
|
|
271
|
-
const cookie = useCookie('x')
|
|
272
|
-
expect(cookie.value).toBeUndefined()
|
|
273
|
-
expect(() => cookie.set('val')).not.toThrow()
|
|
274
|
-
expect(() => cookie.remove()).not.toThrow()
|
|
275
|
-
delete (globalThis as Record<string, unknown>)['__CER_REQ_STORE__']
|
|
276
|
-
})
|
|
277
|
-
})
|