@mandujs/core 0.54.32 → 0.55.0-beta.1
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/README.md +654 -654
- package/package.json +106 -210
- package/scripts/postinstall-lock.ts +153 -153
- package/src/a11y/__tests__/run-audit.test.ts +333 -333
- package/src/a11y/fix-hints.ts +76 -76
- package/src/a11y/index.ts +18 -18
- package/src/a11y/run-audit.ts +15 -15
- package/src/a11y/types.ts +125 -125
- package/src/agent/__tests__/apply.test.ts +224 -0
- package/src/agent/__tests__/context.test.ts +97 -98
- package/src/agent/apply.ts +1031 -0
- package/src/agent/context.ts +552 -552
- package/src/agent/index.ts +4 -3
- package/src/agent/plan.ts +161 -243
- package/src/agent/repair.ts +239 -162
- package/src/agent/sync.ts +197 -198
- package/src/agent/types.ts +242 -94
- package/src/agent/verify.ts +55 -55
- package/src/auth/__tests__/login.test.ts +1 -1
- package/src/auth/__tests__/password.test.ts +15 -5
- package/src/auth/__tests__/reset.test.ts +2 -2
- package/src/auth/__tests__/tokens.test.ts +274 -274
- package/src/auth/__tests__/verification.test.ts +274 -274
- package/src/auth/index.ts +76 -76
- package/src/auth/login.ts +225 -225
- package/src/auth/password.ts +14 -2
- package/src/auth/reset.ts +243 -243
- package/src/auth/tokens.ts +612 -612
- package/src/auth/verification.ts +253 -253
- package/src/brain/__tests__/redactor.test.ts +94 -94
- package/src/brain/adapters/__tests__/_helpers.ts +83 -83
- package/src/brain/adapters/__tests__/anthropic-oauth.test.ts +196 -196
- package/src/brain/adapters/__tests__/chatgpt-auth.test.ts +193 -193
- package/src/brain/adapters/__tests__/openai-oauth.test.ts +209 -209
- package/src/brain/adapters/__tests__/resolver.test.ts +143 -143
- package/src/brain/adapters/anthropic-oauth.ts +1 -1
- package/src/brain/adapters/chatgpt-auth.ts +300 -300
- package/src/brain/adapters/index.ts +319 -319
- package/src/brain/adapters/oauth-flow.ts +439 -439
- package/src/brain/consent.ts +240 -240
- package/src/brain/credentials.ts +396 -396
- package/src/brain/doctor/analyzer.ts +7 -7
- package/src/bundler/__snapshots__/build.test.ts.snap +5 -5
- package/src/bundler/__tests__/build-runner.ts +166 -166
- package/src/bundler/__tests__/client-boundary-transform.test.ts +524 -524
- package/src/bundler/__tests__/cold-start.test.ts +60 -60
- package/src/bundler/__tests__/css.test.ts +49 -20
- package/src/bundler/__tests__/dev-reliability.test.ts +619 -619
- package/src/bundler/__tests__/extended-watch.test.ts +711 -711
- package/src/bundler/__tests__/fast-refresh.test.ts +24 -24
- package/src/bundler/__tests__/generation.test.ts +447 -0
- package/src/bundler/__tests__/hdr.test.ts +24 -18
- package/src/bundler/__tests__/hmr-client.test.ts +62 -24
- package/src/bundler/__tests__/jsx-runtime-shim.test.ts +179 -140
- package/src/bundler/__tests__/manifest-schema.test.ts +305 -266
- package/src/bundler/__tests__/prod-smoke.test.ts +138 -138
- package/src/bundler/__tests__/reverse-import-graph.test.ts +42 -42
- package/src/bundler/__tests__/slot-dispatch.test.ts +573 -573
- package/src/bundler/__tests__/url-cap-and-slot-regex.test.ts +286 -286
- package/src/bundler/__tests__/vendor-cache.test.ts +455 -455
- package/src/bundler/analyzer.ts +15 -15
- package/src/bundler/budget.ts +404 -404
- package/src/bundler/build.test.ts +898 -915
- package/src/bundler/build.ts +113 -24
- package/src/bundler/client-boundary-transform.ts +977 -977
- package/src/bundler/css.ts +65 -44
- package/src/bundler/dev.ts +105 -73
- package/src/bundler/fast-refresh-preamble.ts +47 -47
- package/src/bundler/generation.ts +602 -0
- package/src/bundler/index.ts +3 -3
- package/src/bundler/manifest-schema.ts +55 -40
- package/src/bundler/plugins/__tests__/block-generated-imports.test.ts +13 -13
- package/src/bundler/plugins/__tests__/react-compiler-config.test.ts +83 -83
- package/src/bundler/plugins/__tests__/react-compiler-lint.test.ts +110 -110
- package/src/bundler/plugins/block-generated-imports.ts +16 -15
- package/src/bundler/plugins/index.ts +83 -83
- package/src/bundler/plugins/react-compiler-config.ts +108 -108
- package/src/bundler/plugins/react-compiler-lint.ts +253 -253
- package/src/bundler/plugins/react-compiler.ts +162 -162
- package/src/bundler/prerender.ts +29 -9
- package/src/bundler/reverse-import-graph.ts +339 -339
- package/src/bundler/safe-build.test.ts +1 -1
- package/src/bundler/safe-build.ts +103 -103
- package/src/bundler/scenario-matrix.ts +229 -229
- package/src/bundler/types.ts +58 -56
- package/src/bundler/vendor-cache-types.ts +130 -130
- package/src/bundler/vendor-cache.ts +526 -526
- package/src/change/snapshot.ts +18 -18
- package/src/client/Form.tsx +105 -105
- package/src/client/Link.tsx +9 -9
- package/src/client/__tests__/props-serialization.test.ts +37 -37
- package/src/client/__tests__/use-sse.test.ts +153 -153
- package/src/client/globals.ts +1 -1
- package/src/client/hooks.ts +362 -362
- package/src/client/hydrate.ts +2 -2
- package/src/client/index.ts +1 -1
- package/src/client/island.ts +79 -79
- package/src/client/prefetch-helper.ts +55 -55
- package/src/client/props-serialization.ts +233 -233
- package/src/client/runtime-entry.ts +598 -598
- package/src/client/runtime.ts +1 -1
- package/src/client/serialize.ts +50 -50
- package/src/client/use-fetch.ts +6 -6
- package/src/client/use-head.ts +197 -197
- package/src/client/use-sse.ts +378 -378
- package/src/client/window-state.ts +101 -101
- package/src/components/Image-compat.ts +3 -0
- package/src/components/Image.tsx +162 -162
- package/src/config/validate.ts +1 -1
- package/src/config/watcher.ts +311 -311
- package/src/constants.ts +40 -40
- package/src/content/collection.ts +9 -9
- package/src/content/content-layer.ts +7 -7
- package/src/content/data-store.ts +245 -245
- package/src/content/frontmatter.ts +189 -189
- package/src/content/generate-types.ts +1 -1
- package/src/content/index.ts +2 -2
- package/src/content/loader-context.ts +171 -171
- package/src/content/loaders/api.ts +216 -216
- package/src/content/loaders/file.ts +172 -172
- package/src/content/loaders/glob.ts +253 -253
- package/src/content/loaders/index.ts +34 -34
- package/src/content/loaders/types.ts +137 -137
- package/src/content/meta-store.ts +209 -209
- package/src/content/prebuild.test.ts +571 -571
- package/src/content/prebuild.ts +636 -636
- package/src/content/schema.ts +20 -20
- package/src/content/sidebar.ts +630 -630
- package/src/content/slug.ts +110 -110
- package/src/content/types.ts +282 -282
- package/src/content/watcher.ts +135 -135
- package/src/contract/client-safe.test.ts +42 -42
- package/src/contract/client-safe.ts +114 -114
- package/src/contract/define.ts +11 -11
- package/src/contract/index.ts +1 -1
- package/src/contract/normalize.test.ts +276 -276
- package/src/contract/normalize.ts +410 -410
- package/src/contract/registry.test.ts +206 -206
- package/src/contract/route-helpers.ts +1 -1
- package/src/contract/rpc.ts +443 -443
- package/src/contract/types.ts +58 -58
- package/src/db/__tests__/db.test.ts +9 -9
- package/src/db/index.ts +2 -2
- package/src/db/migrations/history-table.ts +345 -345
- package/src/db/migrations/index.ts +3 -3
- package/src/db/migrations/lock.ts +324 -324
- package/src/db/migrations/runner.ts +650 -650
- package/src/deploy/cache.ts +140 -140
- package/src/deploy/compile/vercel.ts +344 -344
- package/src/deploy/index.ts +87 -87
- package/src/deploy/inference/brain.ts +268 -268
- package/src/deploy/inference/context.ts +82 -82
- package/src/deploy/inference/filling-extract.ts +245 -245
- package/src/deploy/inference/heuristic.ts +182 -182
- package/src/deploy/intent.ts +173 -173
- package/src/deploy/plan.ts +178 -178
- package/src/design/__tests__/agents-link.test.ts +109 -109
- package/src/design/__tests__/extract-patch-diff.test.ts +265 -265
- package/src/design/__tests__/lint.test.ts +110 -110
- package/src/design/__tests__/parser.test.ts +195 -195
- package/src/design/__tests__/tailwind-theme.test.ts +229 -229
- package/src/design/agents-link.ts +165 -165
- package/src/design/diff.ts +138 -138
- package/src/design/extract.ts +285 -285
- package/src/design/index.ts +102 -102
- package/src/design/lint.ts +209 -209
- package/src/design/parser.ts +555 -555
- package/src/design/patch.ts +241 -241
- package/src/design/scaffold.ts +147 -147
- package/src/design/tailwind-theme.ts +441 -441
- package/src/design/types.ts +210 -210
- package/src/desktop/__tests__/smoke.test.ts +2 -2
- package/src/desktop/__tests__/webview-fallback.test.ts +12 -32
- package/src/desktop/__tests__/window.test.ts +20 -99
- package/src/desktop/__tests__/worker.test.ts +266 -266
- package/src/desktop/index.ts +43 -43
- package/src/desktop/types.ts +158 -158
- package/src/desktop/webview-fallback.ts +17 -4
- package/src/desktop/window.ts +17 -8
- package/src/desktop/worker.ts +180 -180
- package/src/dev-error-overlay/__tests__/overlay-injector.test.ts +241 -241
- package/src/dev-error-overlay/index.ts +30 -30
- package/src/dev-error-overlay/overlay-injector.ts +243 -243
- package/src/dev-error-overlay/overlay-styles.ts +52 -52
- package/src/dev-error-overlay/types.ts +66 -66
- package/src/devtools/ai/context-builder.ts +375 -375
- package/src/devtools/ai/index.ts +25 -25
- package/src/devtools/ai/mcp-connector.ts +25 -25
- package/src/devtools/client/catchers/error-catcher.ts +344 -344
- package/src/devtools/client/catchers/index.ts +18 -18
- package/src/devtools/client/components/index.ts +39 -39
- package/src/devtools/client/components/mandu-character.tsx +331 -331
- package/src/devtools/client/components/panel/errors-panel.tsx +259 -259
- package/src/devtools/client/components/panel/guard-panel.tsx +30 -30
- package/src/devtools/client/components/panel/islands-panel.tsx +16 -16
- package/src/devtools/client/components/panel/network-panel.tsx +291 -291
- package/src/devtools/client/components/panel/panel-container.tsx +1 -1
- package/src/devtools/client/components/panel/preview-panel.tsx +46 -46
- package/src/devtools/client/filters/context-filters.ts +282 -282
- package/src/devtools/client/filters/index.ts +16 -16
- package/src/devtools/client/index.ts +63 -63
- package/src/devtools/hook/create-hook.ts +207 -207
- package/src/devtools/hook/index.ts +13 -13
- package/src/devtools/index.ts +439 -439
- package/src/devtools/init.ts +265 -265
- package/src/devtools/protocol.ts +237 -237
- package/src/devtools/server/index.ts +17 -17
- package/src/devtools/types.ts +35 -35
- package/src/devtools/worker/index.ts +25 -25
- package/src/devtools/worker/redaction-worker.ts +233 -233
- package/src/diagnose/__tests__/checks.test.ts +136 -136
- package/src/diagnose/checks.ts +185 -185
- package/src/diagnose/index.ts +17 -17
- package/src/diagnose/run.ts +10 -10
- package/src/diagnose/types.ts +53 -53
- package/src/email/__tests__/email.test.ts +355 -355
- package/src/email/index.ts +282 -282
- package/src/email/smtp.ts +64 -64
- package/src/error/domains.ts +265 -265
- package/src/error/types.ts +6 -6
- package/src/errors/extractor.ts +409 -409
- package/src/errors/index.ts +19 -19
- package/src/filling/__tests__/session-sqlite.test.ts +5 -1
- package/src/filling/auth.ts +308 -308
- package/src/filling/body-parse.test.ts +60 -60
- package/src/filling/cookie-codec.ts +5 -3
- package/src/filling/deps.ts +265 -265
- package/src/filling/head-method.test.ts +154 -154
- package/src/filling/session-sqlite.ts +617 -617
- package/src/filling/sse.ts +5 -5
- package/src/filling/ws.ts +78 -78
- package/src/generator/generate.ts +30 -30
- package/src/generator/index.ts +3 -3
- package/src/generator/templates.test.ts +48 -48
- package/src/generator/templates.ts +219 -219
- package/src/guard/__tests__/design-inline-class.test.ts +219 -219
- package/src/guard/__tests__/tsgolint-bridge.test.ts +347 -347
- package/src/guard/analyzer.ts +360 -360
- package/src/guard/auto-correct.ts +1 -1
- package/src/guard/check.ts +39 -24
- package/src/guard/config-guard.ts +13 -13
- package/src/guard/contract-guard.ts +9 -9
- package/src/guard/define-rule.ts +243 -243
- package/src/guard/design-inline-class.ts +393 -393
- package/src/guard/file-type.test.ts +24 -24
- package/src/guard/fs-routes-policy.ts +51 -51
- package/src/guard/graph.ts +1 -1
- package/src/guard/healing.ts +36 -36
- package/src/guard/index.ts +11 -11
- package/src/guard/presets/atomic.ts +70 -70
- package/src/guard/presets/clean.ts +77 -77
- package/src/guard/presets/fsd.ts +79 -79
- package/src/guard/presets/hexagonal.ts +68 -68
- package/src/guard/reporter.ts +442 -442
- package/src/guard/rule-presets.ts +379 -379
- package/src/guard/semantic-slots.ts +1 -1
- package/src/guard/suggestions.ts +358 -358
- package/src/guard/tsgolint-bridge.ts +512 -512
- package/src/guard/types.ts +348 -348
- package/src/guard/watcher.ts +405 -405
- package/src/i18n/define.ts +126 -126
- package/src/i18n/index.ts +52 -52
- package/src/i18n/message-registry.ts +173 -173
- package/src/i18n/types.ts +112 -112
- package/src/id/__tests__/id.test.ts +3 -3
- package/src/id/index.ts +105 -105
- package/src/index.ts +9 -48
- package/src/internal/client-boundary.ts +266 -266
- package/src/internal/index.ts +2 -2
- package/src/kitchen/api/agent-devtools-api.ts +779 -779
- package/src/kitchen/api/bundle-inspector.ts +179 -0
- package/src/kitchen/api/errors-grouping.ts +126 -126
- package/src/kitchen/api/file-api.ts +11 -11
- package/src/kitchen/kitchen-handler.ts +36 -0
- package/src/kitchen/kitchen-ui.ts +456 -0
- package/src/logging/index.ts +22 -22
- package/src/logging/transports.ts +365 -365
- package/src/middleware/bridge.ts +147 -147
- package/src/middleware/compose.ts +134 -134
- package/src/middleware/compress.ts +62 -62
- package/src/middleware/cors.ts +47 -47
- package/src/middleware/csrf.ts +328 -328
- package/src/middleware/define.ts +132 -132
- package/src/middleware/jwt.ts +134 -134
- package/src/middleware/logger.ts +58 -58
- package/src/middleware/oauth/__tests__/oauth.test.ts +1 -1
- package/src/middleware/oauth/index.ts +505 -505
- package/src/middleware/oauth/providers.ts +115 -115
- package/src/middleware/rate-limit/index.ts +522 -522
- package/src/middleware/rate-limit/sqlite-store.ts +382 -382
- package/src/middleware/scheduler-cron.ts +96 -96
- package/src/middleware/secure/__tests__/secure.test.ts +360 -360
- package/src/middleware/secure/csp.ts +193 -193
- package/src/middleware/session.ts +174 -174
- package/src/middleware/timeout.ts +55 -55
- package/src/observability/logger-adapter.ts +36 -36
- package/src/observability/sqlite-store.ts +254 -254
- package/src/openapi/generator.ts +1 -1
- package/src/openapi/openapi.test.ts +43 -43
- package/src/perf/__tests__/user-marks.test.ts +354 -354
- package/src/perf/index.ts +133 -133
- package/src/perf/user-marks.ts +1 -1
- package/src/plugins/__tests__/lifecycle-integration.test.ts +272 -272
- package/src/plugins/__tests__/runner.test.ts +409 -409
- package/src/plugins/define.ts +124 -124
- package/src/plugins/examples/dep-check-plugin.ts +80 -80
- package/src/plugins/examples/prerender-cache-plugin.ts +111 -111
- package/src/plugins/examples/sitemap-plugin.ts +65 -65
- package/src/plugins/runner.ts +361 -361
- package/src/plugins/types.ts +368 -368
- package/src/report/index.ts +1 -1
- package/src/resource/__tests__/generator.test.ts +7 -7
- package/src/resource/__tests__/schema.test.ts +14 -14
- package/src/resource/ddl/__tests__/diff.test.ts +639 -639
- package/src/resource/ddl/__tests__/emit.test.ts +165 -165
- package/src/resource/ddl/__tests__/snapshot.test.ts +499 -499
- package/src/resource/ddl/emit.ts +146 -146
- package/src/resource/ddl/persistence-types.ts +218 -218
- package/src/resource/ddl/type-map.ts +223 -223
- package/src/resource/ddl/types.ts +232 -232
- package/src/resource/generator-repo.ts +630 -630
- package/src/resource/generator-schema.ts +11 -11
- package/src/resource/generators/slot.ts +72 -72
- package/src/resource/schema.ts +21 -21
- package/src/router/client-entry.test.ts +227 -227
- package/src/router/client-entry.ts +218 -218
- package/src/router/fs-patterns.test.ts +96 -96
- package/src/router/fs-routes.test.ts +532 -532
- package/src/router/fs-routes.ts +53 -53
- package/src/router/fs-scanner.ts +216 -216
- package/src/router/fs-types.ts +19 -19
- package/src/router/route-source-analyzer.ts +521 -521
- package/src/routes/index.ts +74 -74
- package/src/routes/metadata-routes.ts +427 -427
- package/src/routes/types.ts +341 -341
- package/src/runtime/__tests__/devtools-adapter.test.ts +68 -68
- package/src/runtime/__tests__/error-boundary-redaction.test.ts +141 -141
- package/src/runtime/__tests__/hdr-client.test.ts +223 -223
- package/src/runtime/__tests__/http-errors.test.ts +117 -117
- package/src/runtime/__tests__/inline-client-hydration.test.ts +237 -237
- package/src/runtime/__tests__/not-found.test.ts +152 -152
- package/src/runtime/__tests__/observability-lifecycle.test.ts +103 -103
- package/src/runtime/__tests__/page-render-response.test.ts +517 -517
- package/src/runtime/__tests__/request-middleware.test.ts +70 -70
- package/src/runtime/__tests__/searchparams-page-props.test.ts +81 -81
- package/src/runtime/adapter.ts +47 -47
- package/src/runtime/boundary.tsx +252 -252
- package/src/runtime/cache.ts +494 -494
- package/src/runtime/compose.ts +222 -222
- package/src/runtime/devtools-adapter.ts +68 -68
- package/src/runtime/escape.ts +34 -34
- package/src/runtime/fast-refresh-runtime.ts +322 -322
- package/src/runtime/fast-refresh-types.ts +1 -1
- package/src/runtime/handler.ts +65 -65
- package/src/runtime/handlers.ts +30 -11
- package/src/runtime/http-errors.ts +113 -113
- package/src/runtime/image-handler.ts +1 -1
- package/src/runtime/lifecycle.ts +381 -381
- package/src/runtime/logger.test.ts +345 -345
- package/src/runtime/middleware.ts +264 -264
- package/src/runtime/not-found.ts +93 -93
- package/src/runtime/observability-lifecycle.ts +290 -290
- package/src/runtime/openapi-endpoint.ts +236 -236
- package/src/runtime/page-render-response.ts +287 -274
- package/src/runtime/ppr.ts +74 -74
- package/src/runtime/rate-limit.ts +1 -1
- package/src/runtime/redirect.ts +1 -1
- package/src/runtime/registry.ts +171 -171
- package/src/runtime/request-middleware.ts +31 -31
- package/src/runtime/router.test.ts +4 -4
- package/src/runtime/router.ts +10 -10
- package/src/runtime/server.ts +127 -211
- package/src/runtime/shims.ts +48 -48
- package/src/runtime/ssr.ts +43 -17
- package/src/runtime/static-files.ts +369 -289
- package/src/runtime/streaming-ssr.ts +219 -180
- package/src/runtime/trace.ts +144 -144
- package/src/scheduler/__tests__/scheduler.test.ts +12 -11
- package/src/scheduler/index.ts +11 -5
- package/src/scheduler/validate.ts +169 -169
- package/src/seo/index.ts +219 -219
- package/src/seo/integration/ssr.ts +306 -306
- package/src/seo/render/basic.ts +435 -435
- package/src/seo/render/index.ts +143 -143
- package/src/seo/render/jsonld.ts +539 -539
- package/src/seo/render/opengraph.ts +197 -197
- package/src/seo/render/robots.ts +116 -116
- package/src/seo/render/sitemap.ts +137 -137
- package/src/seo/render/twitter.ts +127 -127
- package/src/seo/resolve/opengraph.ts +143 -143
- package/src/seo/resolve/robots.ts +73 -73
- package/src/seo/resolve/title.ts +94 -94
- package/src/seo/resolve/twitter.ts +73 -73
- package/src/seo/resolve/url.ts +104 -104
- package/src/seo/routes/index.ts +290 -290
- package/src/seo/types.ts +588 -588
- package/src/slot/validator.ts +39 -39
- package/src/spec/schema.ts +35 -35
- package/src/storage/s3/__tests__/s3.test.ts +479 -479
- package/src/storage/s3/index.ts +412 -412
- package/src/testing/__tests__/assertions.test.ts +632 -632
- package/src/testing/__tests__/reporter.test.ts +454 -454
- package/src/testing/assertions.ts +986 -986
- package/src/testing/db.ts +157 -157
- package/src/testing/index.ts +9 -3
- package/src/testing/lcov.ts +192 -0
- package/src/testing/mocks.ts +203 -203
- package/src/testing/session.ts +190 -190
- package/src/types/branded.ts +56 -56
- package/src/types/index.ts +1 -1
- package/src/utils/safe-io.ts +188 -188
- package/src/utils/string-safe.ts +298 -298
- package/src/watcher/__tests__/watcher.test.ts +59 -59
- package/src/watcher/watcher.ts +61 -61
|
@@ -1,154 +1,154 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Regression test for issue #319: a route that only registers a GET handler
|
|
3
|
-
* via `Mandu.filling().get(...)` must serve HEAD requests as a body-less GET
|
|
4
|
-
* (RFC 7231 §4.3.2) — returning the same status + headers with an empty body,
|
|
5
|
-
* not a 405 Method Not Allowed.
|
|
6
|
-
*/
|
|
7
|
-
import { describe, it, expect } from "bun:test";
|
|
8
|
-
import { ManduFillingFactory } from "./filling";
|
|
9
|
-
|
|
10
|
-
describe("Filling HEAD handling (#319)", () => {
|
|
11
|
-
it("serves HEAD via the GET handler with status + headers and an empty body", async () => {
|
|
12
|
-
const filling = ManduFillingFactory.filling().get((ctx) =>
|
|
13
|
-
ctx.json({ ok: true }),
|
|
14
|
-
);
|
|
15
|
-
|
|
16
|
-
const getRes = await filling.handle(
|
|
17
|
-
new Request("http://localhost/api/health", { method: "GET" }),
|
|
18
|
-
);
|
|
19
|
-
expect(getRes.status).toBe(200);
|
|
20
|
-
|
|
21
|
-
const headRes = await filling.handle(
|
|
22
|
-
new Request("http://localhost/api/health", { method: "HEAD" }),
|
|
23
|
-
);
|
|
24
|
-
|
|
25
|
-
expect(headRes.status).toBe(200);
|
|
26
|
-
expect(headRes.headers.get("content-type")).toBe(
|
|
27
|
-
getRes.headers.get("content-type"),
|
|
28
|
-
);
|
|
29
|
-
const headBody = await headRes.text();
|
|
30
|
-
expect(headBody).toBe("");
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it("prefers an explicit HEAD handler when one is registered", async () => {
|
|
34
|
-
const filling = ManduFillingFactory.filling()
|
|
35
|
-
.get((ctx) => ctx.json({ ok: true }))
|
|
36
|
-
.head((ctx) => {
|
|
37
|
-
const res = ctx.json({ ignored: true });
|
|
38
|
-
res.headers.set("X-Explicit-Head", "1");
|
|
39
|
-
return res;
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
const headRes = await filling.handle(
|
|
43
|
-
new Request("http://localhost/api/health", { method: "HEAD" }),
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
expect(headRes.status).toBe(200);
|
|
47
|
-
expect(headRes.headers.get("X-Explicit-Head")).toBe("1");
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it("still returns 405 for a method with no GET fallback", async () => {
|
|
51
|
-
const filling = ManduFillingFactory.filling().post((ctx) => ctx.json({ ok: true }));
|
|
52
|
-
|
|
53
|
-
const headRes = await filling.handle(
|
|
54
|
-
new Request("http://localhost/api/health", { method: "HEAD" }),
|
|
55
|
-
);
|
|
56
|
-
|
|
57
|
-
expect(headRes.status).toBe(405);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it("lists HEAD in the Allow set when GET is registered but the method is unsupported", async () => {
|
|
61
|
-
const filling = ManduFillingFactory.filling().get((ctx) => ctx.json({ ok: true }));
|
|
62
|
-
|
|
63
|
-
const putRes = await filling.handle(
|
|
64
|
-
new Request("http://localhost/api/health", { method: "PUT" }),
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
expect(putRes.status).toBe(405);
|
|
68
|
-
const body = (await putRes.json()) as { allowed: string[] };
|
|
69
|
-
expect(body.allowed).toContain("GET");
|
|
70
|
-
expect(body.allowed).toContain("HEAD");
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
// Issue #321: 405 responses MUST carry an `Allow` header listing every
|
|
74
|
-
// supported method — for multi-method routes too, not just single-method.
|
|
75
|
-
it("sets the Allow header to a single method route's methods", async () => {
|
|
76
|
-
const filling = ManduFillingFactory.filling().get((ctx) => ctx.json({ ok: true }));
|
|
77
|
-
|
|
78
|
-
const putRes = await filling.handle(
|
|
79
|
-
new Request("http://localhost/api/health", { method: "PUT" }),
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
expect(putRes.status).toBe(405);
|
|
83
|
-
const allow = putRes.headers.get("Allow") ?? "";
|
|
84
|
-
expect(allow.split(", ")).toContain("GET");
|
|
85
|
-
expect(allow.split(", ")).toContain("HEAD");
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it("sets the Allow header to ALL methods for a multi-method route (#321)", async () => {
|
|
89
|
-
const filling = ManduFillingFactory.filling()
|
|
90
|
-
.get((ctx) => ctx.json({ ok: true }))
|
|
91
|
-
.post((ctx) => ctx.json({ ok: true }))
|
|
92
|
-
.delete((ctx) => ctx.json({ ok: true }));
|
|
93
|
-
|
|
94
|
-
const putRes = await filling.handle(
|
|
95
|
-
new Request("http://localhost/api/pledges", { method: "PUT" }),
|
|
96
|
-
);
|
|
97
|
-
|
|
98
|
-
expect(putRes.status).toBe(405);
|
|
99
|
-
const allow = putRes.headers.get("Allow") ?? "";
|
|
100
|
-
const methods = allow.split(", ");
|
|
101
|
-
expect(methods).toContain("GET");
|
|
102
|
-
expect(methods).toContain("POST");
|
|
103
|
-
expect(methods).toContain("DELETE");
|
|
104
|
-
// HEAD is implied by GET.
|
|
105
|
-
expect(methods).toContain("HEAD");
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
// RFC 7231 §4.3.7: a plain OPTIONS request (no explicit OPTIONS handler)
|
|
109
|
-
// should return 204 with an Allow header, not 405.
|
|
110
|
-
it("auto-responds to a plain OPTIONS request with 204 + Allow", async () => {
|
|
111
|
-
const filling = ManduFillingFactory.filling()
|
|
112
|
-
.get((ctx) => ctx.json({ ok: true }))
|
|
113
|
-
.post((ctx) => ctx.json({ ok: true }));
|
|
114
|
-
|
|
115
|
-
const res = await filling.handle(
|
|
116
|
-
new Request("http://localhost/api/pledges", { method: "OPTIONS" }),
|
|
117
|
-
);
|
|
118
|
-
|
|
119
|
-
expect(res.status).toBe(204);
|
|
120
|
-
const methods = (res.headers.get("Allow") ?? "").split(", ");
|
|
121
|
-
expect(methods).toContain("GET");
|
|
122
|
-
expect(methods).toContain("POST");
|
|
123
|
-
expect(methods).toContain("HEAD");
|
|
124
|
-
expect(methods).toContain("OPTIONS");
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
it("defers CORS preflight OPTIONS (Access-Control-Request-Method) instead of auto-answering", async () => {
|
|
128
|
-
const filling = ManduFillingFactory.filling().get((ctx) => ctx.json({ ok: true }));
|
|
129
|
-
|
|
130
|
-
const res = await filling.handle(
|
|
131
|
-
new Request("http://localhost/api/pledges", {
|
|
132
|
-
method: "OPTIONS",
|
|
133
|
-
headers: { "Access-Control-Request-Method": "GET", Origin: "https://x" },
|
|
134
|
-
}),
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
// No CORS middleware registered → falls through to 405 (not the 204
|
|
138
|
-
// auto-OPTIONS path), leaving preflight handling to CORS middleware.
|
|
139
|
-
expect(res.status).toBe(405);
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
it("an explicit OPTIONS handler still takes precedence", async () => {
|
|
143
|
-
const filling = ManduFillingFactory.filling()
|
|
144
|
-
.get((ctx) => ctx.json({ ok: true }))
|
|
145
|
-
.options((ctx) => ctx.json({ custom: true }));
|
|
146
|
-
|
|
147
|
-
const res = await filling.handle(
|
|
148
|
-
new Request("http://localhost/api/pledges", { method: "OPTIONS" }),
|
|
149
|
-
);
|
|
150
|
-
|
|
151
|
-
expect(res.status).toBe(200);
|
|
152
|
-
expect(await res.json()).toEqual({ custom: true });
|
|
153
|
-
});
|
|
154
|
-
});
|
|
1
|
+
/**
|
|
2
|
+
* Regression test for issue #319: a route that only registers a GET handler
|
|
3
|
+
* via `Mandu.filling().get(...)` must serve HEAD requests as a body-less GET
|
|
4
|
+
* (RFC 7231 §4.3.2) — returning the same status + headers with an empty body,
|
|
5
|
+
* not a 405 Method Not Allowed.
|
|
6
|
+
*/
|
|
7
|
+
import { describe, it, expect } from "bun:test";
|
|
8
|
+
import { ManduFillingFactory } from "./filling";
|
|
9
|
+
|
|
10
|
+
describe("Filling HEAD handling (#319)", () => {
|
|
11
|
+
it("serves HEAD via the GET handler with status + headers and an empty body", async () => {
|
|
12
|
+
const filling = ManduFillingFactory.filling().get((ctx) =>
|
|
13
|
+
ctx.json({ ok: true }),
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
const getRes = await filling.handle(
|
|
17
|
+
new Request("http://localhost/api/health", { method: "GET" }),
|
|
18
|
+
);
|
|
19
|
+
expect(getRes.status).toBe(200);
|
|
20
|
+
|
|
21
|
+
const headRes = await filling.handle(
|
|
22
|
+
new Request("http://localhost/api/health", { method: "HEAD" }),
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
expect(headRes.status).toBe(200);
|
|
26
|
+
expect(headRes.headers.get("content-type")).toBe(
|
|
27
|
+
getRes.headers.get("content-type"),
|
|
28
|
+
);
|
|
29
|
+
const headBody = await headRes.text();
|
|
30
|
+
expect(headBody).toBe("");
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("prefers an explicit HEAD handler when one is registered", async () => {
|
|
34
|
+
const filling = ManduFillingFactory.filling()
|
|
35
|
+
.get((ctx) => ctx.json({ ok: true }))
|
|
36
|
+
.head((ctx) => {
|
|
37
|
+
const res = ctx.json({ ignored: true });
|
|
38
|
+
res.headers.set("X-Explicit-Head", "1");
|
|
39
|
+
return res;
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const headRes = await filling.handle(
|
|
43
|
+
new Request("http://localhost/api/health", { method: "HEAD" }),
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
expect(headRes.status).toBe(200);
|
|
47
|
+
expect(headRes.headers.get("X-Explicit-Head")).toBe("1");
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("still returns 405 for a method with no GET fallback", async () => {
|
|
51
|
+
const filling = ManduFillingFactory.filling().post((ctx) => ctx.json({ ok: true }));
|
|
52
|
+
|
|
53
|
+
const headRes = await filling.handle(
|
|
54
|
+
new Request("http://localhost/api/health", { method: "HEAD" }),
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
expect(headRes.status).toBe(405);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("lists HEAD in the Allow set when GET is registered but the method is unsupported", async () => {
|
|
61
|
+
const filling = ManduFillingFactory.filling().get((ctx) => ctx.json({ ok: true }));
|
|
62
|
+
|
|
63
|
+
const putRes = await filling.handle(
|
|
64
|
+
new Request("http://localhost/api/health", { method: "PUT" }),
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
expect(putRes.status).toBe(405);
|
|
68
|
+
const body = (await putRes.json()) as { allowed: string[] };
|
|
69
|
+
expect(body.allowed).toContain("GET");
|
|
70
|
+
expect(body.allowed).toContain("HEAD");
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Issue #321: 405 responses MUST carry an `Allow` header listing every
|
|
74
|
+
// supported method — for multi-method routes too, not just single-method.
|
|
75
|
+
it("sets the Allow header to a single method route's methods", async () => {
|
|
76
|
+
const filling = ManduFillingFactory.filling().get((ctx) => ctx.json({ ok: true }));
|
|
77
|
+
|
|
78
|
+
const putRes = await filling.handle(
|
|
79
|
+
new Request("http://localhost/api/health", { method: "PUT" }),
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
expect(putRes.status).toBe(405);
|
|
83
|
+
const allow = putRes.headers.get("Allow") ?? "";
|
|
84
|
+
expect(allow.split(", ")).toContain("GET");
|
|
85
|
+
expect(allow.split(", ")).toContain("HEAD");
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it("sets the Allow header to ALL methods for a multi-method route (#321)", async () => {
|
|
89
|
+
const filling = ManduFillingFactory.filling()
|
|
90
|
+
.get((ctx) => ctx.json({ ok: true }))
|
|
91
|
+
.post((ctx) => ctx.json({ ok: true }))
|
|
92
|
+
.delete((ctx) => ctx.json({ ok: true }));
|
|
93
|
+
|
|
94
|
+
const putRes = await filling.handle(
|
|
95
|
+
new Request("http://localhost/api/pledges", { method: "PUT" }),
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
expect(putRes.status).toBe(405);
|
|
99
|
+
const allow = putRes.headers.get("Allow") ?? "";
|
|
100
|
+
const methods = allow.split(", ");
|
|
101
|
+
expect(methods).toContain("GET");
|
|
102
|
+
expect(methods).toContain("POST");
|
|
103
|
+
expect(methods).toContain("DELETE");
|
|
104
|
+
// HEAD is implied by GET.
|
|
105
|
+
expect(methods).toContain("HEAD");
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// RFC 7231 §4.3.7: a plain OPTIONS request (no explicit OPTIONS handler)
|
|
109
|
+
// should return 204 with an Allow header, not 405.
|
|
110
|
+
it("auto-responds to a plain OPTIONS request with 204 + Allow", async () => {
|
|
111
|
+
const filling = ManduFillingFactory.filling()
|
|
112
|
+
.get((ctx) => ctx.json({ ok: true }))
|
|
113
|
+
.post((ctx) => ctx.json({ ok: true }));
|
|
114
|
+
|
|
115
|
+
const res = await filling.handle(
|
|
116
|
+
new Request("http://localhost/api/pledges", { method: "OPTIONS" }),
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
expect(res.status).toBe(204);
|
|
120
|
+
const methods = (res.headers.get("Allow") ?? "").split(", ");
|
|
121
|
+
expect(methods).toContain("GET");
|
|
122
|
+
expect(methods).toContain("POST");
|
|
123
|
+
expect(methods).toContain("HEAD");
|
|
124
|
+
expect(methods).toContain("OPTIONS");
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("defers CORS preflight OPTIONS (Access-Control-Request-Method) instead of auto-answering", async () => {
|
|
128
|
+
const filling = ManduFillingFactory.filling().get((ctx) => ctx.json({ ok: true }));
|
|
129
|
+
|
|
130
|
+
const res = await filling.handle(
|
|
131
|
+
new Request("http://localhost/api/pledges", {
|
|
132
|
+
method: "OPTIONS",
|
|
133
|
+
headers: { "Access-Control-Request-Method": "GET", Origin: "https://x" },
|
|
134
|
+
}),
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
// No CORS middleware registered → falls through to 405 (not the 204
|
|
138
|
+
// auto-OPTIONS path), leaving preflight handling to CORS middleware.
|
|
139
|
+
expect(res.status).toBe(405);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it("an explicit OPTIONS handler still takes precedence", async () => {
|
|
143
|
+
const filling = ManduFillingFactory.filling()
|
|
144
|
+
.get((ctx) => ctx.json({ ok: true }))
|
|
145
|
+
.options((ctx) => ctx.json({ custom: true }));
|
|
146
|
+
|
|
147
|
+
const res = await filling.handle(
|
|
148
|
+
new Request("http://localhost/api/pledges", { method: "OPTIONS" }),
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
expect(res.status).toBe(200);
|
|
152
|
+
expect(await res.json()).toEqual({ custom: true });
|
|
153
|
+
});
|
|
154
|
+
});
|