@mandujs/core 0.53.3 → 0.54.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 +1 -1
- 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 +394 -394
- package/src/a11y/types.ts +125 -125
- package/src/auth/__tests__/login.test.ts +1 -1
- package/src/auth/__tests__/password.test.ts +122 -122
- 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 +120 -120
- 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/bundler/__tests__/build-runner.ts +113 -113
- 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 +10 -10
- package/src/bundler/__tests__/hdr.test.ts +353 -353
- package/src/bundler/__tests__/hmr-client.test.ts +532 -532
- package/src/bundler/__tests__/manifest-schema.test.ts +266 -266
- package/src/bundler/__tests__/prod-smoke.test.ts +138 -138
- package/src/bundler/__tests__/reverse-import-graph.test.ts +519 -519
- 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/budget.ts +404 -404
- package/src/bundler/build.test.ts +179 -179
- package/src/bundler/build.ts +55 -55
- package/src/bundler/dev.ts +42 -42
- package/src/bundler/manifest-schema.ts +301 -301
- package/src/bundler/plugins/__tests__/block-generated-imports.test.ts +263 -263
- 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 +155 -155
- 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/reverse-import-graph.ts +339 -339
- package/src/bundler/safe-build.test.ts +201 -201
- package/src/bundler/safe-build.ts +103 -103
- package/src/bundler/scenario-matrix.ts +229 -229
- package/src/bundler/types.ts +10 -10
- 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__/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 +340 -340
- package/src/client/prefetch-helper.ts +55 -55
- package/src/client/router.ts +11 -11
- package/src/client/runtime.ts +47 -47
- package/src/client/serialize.ts +404 -404
- 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.tsx +162 -162
- package/src/config/validate.ts +3 -3
- package/src/config/watcher.ts +311 -311
- package/src/constants.ts +40 -40
- package/src/content/collection.ts +8 -8
- 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/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/schema.ts +48 -48
- package/src/contract/types.ts +58 -58
- package/src/db/__tests__/db.test.ts +482 -482
- package/src/db/index.ts +138 -138
- 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 +182 -182
- 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__/webview-fallback.test.ts +254 -254
- package/src/desktop/__tests__/window.test.ts +248 -248
- 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/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/overlay.tsx +368 -368
- 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 +320 -320
- package/src/devtools/client/components/panel/network-panel.tsx +291 -291
- package/src/devtools/client/components/panel/panel-container.tsx +500 -500
- 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/client/persistence.ts +335 -335
- 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/server/source-context.ts +450 -450
- 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/devtools/worker/worker-manager.ts +410 -410
- package/src/diagnose/__tests__/checks.test.ts +451 -451
- package/src/diagnose/checks.ts +832 -832
- package/src/diagnose/index.ts +17 -17
- package/src/diagnose/run.ts +93 -93
- 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/result.ts +60 -60
- 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 +454 -454
- package/src/filling/auth.ts +308 -308
- package/src/filling/cookie-codec.ts +299 -299
- package/src/filling/deps.ts +265 -265
- 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/index.ts +3 -3
- 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/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/graph.ts +1 -1
- package/src/guard/healing.ts +36 -36
- 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/index.ts +105 -105
- package/src/index.ts +2 -2
- package/src/kitchen/api/agent-devtools-api.ts +779 -544
- package/src/kitchen/api/errors-grouping.ts +126 -0
- package/src/kitchen/kitchen-handler.ts +192 -63
- package/src/kitchen/kitchen-ui.ts +842 -464
- 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/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 +32 -32
- package/src/resource/ddl/__tests__/diff.test.ts +639 -639
- package/src/resource/ddl/__tests__/emit.test.ts +823 -823
- package/src/resource/ddl/__tests__/snapshot.test.ts +499 -499
- package/src/resource/ddl/emit.ts +559 -559
- 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/schema.ts +1 -1
- package/src/router/fs-patterns.test.ts +96 -96
- package/src/router/fs-routes.ts +6 -6
- 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__/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__/not-found.test.ts +152 -152
- 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/fast-refresh-runtime.ts +322 -322
- package/src/runtime/handler.ts +65 -65
- package/src/runtime/handlers.ts +300 -300
- 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/openapi-endpoint.ts +236 -236
- package/src/runtime/ppr.ts +74 -74
- package/src/runtime/registry.ts +171 -171
- package/src/runtime/router.ts +105 -105
- package/src/runtime/server.ts +67 -67
- package/src/runtime/shims.ts +48 -48
- package/src/runtime/trace.ts +144 -144
- 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/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/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/watcher.ts +18 -18
|
@@ -1,113 +1,113 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Module-level HTTP error helpers.
|
|
3
|
-
*
|
|
4
|
-
* These are the standalone counterparts to `ctx.unauthorized()`,
|
|
5
|
-
* `ctx.forbidden()`, and `ctx.error()` on {@link ManduContext}. When a
|
|
6
|
-
* caller is inside a filling handler the ctx methods are ergonomic —
|
|
7
|
-
* they thread pending cookies through automatically. Outside the ctx
|
|
8
|
-
* (e.g. plain utilities, middleware composition, SSR loaders that
|
|
9
|
-
* prefer `return` over `ctx.json`), these module-level functions mint
|
|
10
|
-
* the same shape directly.
|
|
11
|
-
*
|
|
12
|
-
* ## Design notes
|
|
13
|
-
*
|
|
14
|
-
* - `unauthorized()` sets `WWW-Authenticate: Bearer` per RFC 7235 so
|
|
15
|
-
* browsers/proxies know a scheme. Opt out by passing a custom
|
|
16
|
-
* `WWW-Authenticate` header (or `null` via `{ headers }`).
|
|
17
|
-
* - `forbidden()` is JSON by default (same shape as `ctx.forbidden()`).
|
|
18
|
-
* - `badRequest()` accepts either a string (→ simple error body) or a
|
|
19
|
-
* `{ message, errors }` object for structured validation failures.
|
|
20
|
-
* - All three merge caller-provided headers via `new Headers(init)`
|
|
21
|
-
* semantics — later keys win, which matches Response constructor.
|
|
22
|
-
*
|
|
23
|
-
* The returned Response is plain — no brand symbol. Unlike `redirect()`
|
|
24
|
-
* / `notFound()`, these do not short-circuit the SSR pipeline; they are
|
|
25
|
-
* terminal API responses and the caller is expected to return them up.
|
|
26
|
-
*/
|
|
27
|
-
|
|
28
|
-
/** Shape of the JSON body for `badRequest()` when given an object. */
|
|
29
|
-
export interface BadRequestBody {
|
|
30
|
-
/** Human-readable message. Required. */
|
|
31
|
-
message: string;
|
|
32
|
-
/** Optional structured validation detail (e.g. per-field errors). */
|
|
33
|
-
errors?: unknown;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* 401 Unauthorized. Sets `WWW-Authenticate: Bearer` by default so clients
|
|
38
|
-
* know the expected auth scheme. To override, pass a custom header via
|
|
39
|
-
* `options.headers`:
|
|
40
|
-
*
|
|
41
|
-
* ```ts
|
|
42
|
-
* unauthorized("Token expired", { headers: { "WWW-Authenticate": 'Basic realm="app"' } });
|
|
43
|
-
* ```
|
|
44
|
-
*
|
|
45
|
-
* Body is JSON: `{ error: "Unauthorized" }` (or the provided `message`).
|
|
46
|
-
*/
|
|
47
|
-
export function unauthorized(message?: string, options: ResponseInit = {}): Response {
|
|
48
|
-
const body = JSON.stringify({ error: message ?? "Unauthorized" });
|
|
49
|
-
const headers = new Headers(options.headers);
|
|
50
|
-
if (!headers.has("WWW-Authenticate")) {
|
|
51
|
-
headers.set("WWW-Authenticate", "Bearer");
|
|
52
|
-
}
|
|
53
|
-
if (!headers.has("Content-Type")) {
|
|
54
|
-
headers.set("Content-Type", "application/json; charset=utf-8");
|
|
55
|
-
}
|
|
56
|
-
return new Response(body, {
|
|
57
|
-
status: 401,
|
|
58
|
-
statusText: options.statusText,
|
|
59
|
-
headers,
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* 403 Forbidden. JSON body: `{ error: string }`.
|
|
65
|
-
*
|
|
66
|
-
* Use this when the client is authenticated but not authorised for the
|
|
67
|
-
* resource (contrast with {@link unauthorized}, which signals a missing
|
|
68
|
-
* or invalid credential).
|
|
69
|
-
*/
|
|
70
|
-
export function forbidden(message?: string, options: ResponseInit = {}): Response {
|
|
71
|
-
const body = JSON.stringify({ error: message ?? "Forbidden" });
|
|
72
|
-
const headers = new Headers(options.headers);
|
|
73
|
-
if (!headers.has("Content-Type")) {
|
|
74
|
-
headers.set("Content-Type", "application/json; charset=utf-8");
|
|
75
|
-
}
|
|
76
|
-
return new Response(body, {
|
|
77
|
-
status: 403,
|
|
78
|
-
statusText: options.statusText,
|
|
79
|
-
headers,
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* 400 Bad Request. Accepts either a plain string or a `{ message, errors }`
|
|
85
|
-
* object. In both cases the response body is JSON.
|
|
86
|
-
*
|
|
87
|
-
* - `badRequest("invalid id")` → `{ "error": "invalid id" }`
|
|
88
|
-
* - `badRequest({ message: "validation failed", errors: { email: ["required"] } })`
|
|
89
|
-
* → `{ "error": "validation failed", "errors": { "email": ["required"] } }`
|
|
90
|
-
*
|
|
91
|
-
* The top-level key is always `error` (string), matching `ctx.error()` in
|
|
92
|
-
* `filling/context.ts`. Structured `errors` is passed through untouched —
|
|
93
|
-
* callers decide the shape (Zod flatten, per-field map, etc.).
|
|
94
|
-
*/
|
|
95
|
-
export function badRequest(
|
|
96
|
-
input: string | BadRequestBody = "Bad Request",
|
|
97
|
-
options: ResponseInit = {}
|
|
98
|
-
): Response {
|
|
99
|
-
const body =
|
|
100
|
-
typeof input === "string"
|
|
101
|
-
? { error: input }
|
|
102
|
-
: { error: input.message, ...(input.errors !== undefined ? { errors: input.errors } : {}) };
|
|
103
|
-
|
|
104
|
-
const headers = new Headers(options.headers);
|
|
105
|
-
if (!headers.has("Content-Type")) {
|
|
106
|
-
headers.set("Content-Type", "application/json; charset=utf-8");
|
|
107
|
-
}
|
|
108
|
-
return new Response(JSON.stringify(body), {
|
|
109
|
-
status: 400,
|
|
110
|
-
statusText: options.statusText,
|
|
111
|
-
headers,
|
|
112
|
-
});
|
|
113
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Module-level HTTP error helpers.
|
|
3
|
+
*
|
|
4
|
+
* These are the standalone counterparts to `ctx.unauthorized()`,
|
|
5
|
+
* `ctx.forbidden()`, and `ctx.error()` on {@link ManduContext}. When a
|
|
6
|
+
* caller is inside a filling handler the ctx methods are ergonomic —
|
|
7
|
+
* they thread pending cookies through automatically. Outside the ctx
|
|
8
|
+
* (e.g. plain utilities, middleware composition, SSR loaders that
|
|
9
|
+
* prefer `return` over `ctx.json`), these module-level functions mint
|
|
10
|
+
* the same shape directly.
|
|
11
|
+
*
|
|
12
|
+
* ## Design notes
|
|
13
|
+
*
|
|
14
|
+
* - `unauthorized()` sets `WWW-Authenticate: Bearer` per RFC 7235 so
|
|
15
|
+
* browsers/proxies know a scheme. Opt out by passing a custom
|
|
16
|
+
* `WWW-Authenticate` header (or `null` via `{ headers }`).
|
|
17
|
+
* - `forbidden()` is JSON by default (same shape as `ctx.forbidden()`).
|
|
18
|
+
* - `badRequest()` accepts either a string (→ simple error body) or a
|
|
19
|
+
* `{ message, errors }` object for structured validation failures.
|
|
20
|
+
* - All three merge caller-provided headers via `new Headers(init)`
|
|
21
|
+
* semantics — later keys win, which matches Response constructor.
|
|
22
|
+
*
|
|
23
|
+
* The returned Response is plain — no brand symbol. Unlike `redirect()`
|
|
24
|
+
* / `notFound()`, these do not short-circuit the SSR pipeline; they are
|
|
25
|
+
* terminal API responses and the caller is expected to return them up.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/** Shape of the JSON body for `badRequest()` when given an object. */
|
|
29
|
+
export interface BadRequestBody {
|
|
30
|
+
/** Human-readable message. Required. */
|
|
31
|
+
message: string;
|
|
32
|
+
/** Optional structured validation detail (e.g. per-field errors). */
|
|
33
|
+
errors?: unknown;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* 401 Unauthorized. Sets `WWW-Authenticate: Bearer` by default so clients
|
|
38
|
+
* know the expected auth scheme. To override, pass a custom header via
|
|
39
|
+
* `options.headers`:
|
|
40
|
+
*
|
|
41
|
+
* ```ts
|
|
42
|
+
* unauthorized("Token expired", { headers: { "WWW-Authenticate": 'Basic realm="app"' } });
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* Body is JSON: `{ error: "Unauthorized" }` (or the provided `message`).
|
|
46
|
+
*/
|
|
47
|
+
export function unauthorized(message?: string, options: ResponseInit = {}): Response {
|
|
48
|
+
const body = JSON.stringify({ error: message ?? "Unauthorized" });
|
|
49
|
+
const headers = new Headers(options.headers);
|
|
50
|
+
if (!headers.has("WWW-Authenticate")) {
|
|
51
|
+
headers.set("WWW-Authenticate", "Bearer");
|
|
52
|
+
}
|
|
53
|
+
if (!headers.has("Content-Type")) {
|
|
54
|
+
headers.set("Content-Type", "application/json; charset=utf-8");
|
|
55
|
+
}
|
|
56
|
+
return new Response(body, {
|
|
57
|
+
status: 401,
|
|
58
|
+
statusText: options.statusText,
|
|
59
|
+
headers,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* 403 Forbidden. JSON body: `{ error: string }`.
|
|
65
|
+
*
|
|
66
|
+
* Use this when the client is authenticated but not authorised for the
|
|
67
|
+
* resource (contrast with {@link unauthorized}, which signals a missing
|
|
68
|
+
* or invalid credential).
|
|
69
|
+
*/
|
|
70
|
+
export function forbidden(message?: string, options: ResponseInit = {}): Response {
|
|
71
|
+
const body = JSON.stringify({ error: message ?? "Forbidden" });
|
|
72
|
+
const headers = new Headers(options.headers);
|
|
73
|
+
if (!headers.has("Content-Type")) {
|
|
74
|
+
headers.set("Content-Type", "application/json; charset=utf-8");
|
|
75
|
+
}
|
|
76
|
+
return new Response(body, {
|
|
77
|
+
status: 403,
|
|
78
|
+
statusText: options.statusText,
|
|
79
|
+
headers,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* 400 Bad Request. Accepts either a plain string or a `{ message, errors }`
|
|
85
|
+
* object. In both cases the response body is JSON.
|
|
86
|
+
*
|
|
87
|
+
* - `badRequest("invalid id")` → `{ "error": "invalid id" }`
|
|
88
|
+
* - `badRequest({ message: "validation failed", errors: { email: ["required"] } })`
|
|
89
|
+
* → `{ "error": "validation failed", "errors": { "email": ["required"] } }`
|
|
90
|
+
*
|
|
91
|
+
* The top-level key is always `error` (string), matching `ctx.error()` in
|
|
92
|
+
* `filling/context.ts`. Structured `errors` is passed through untouched —
|
|
93
|
+
* callers decide the shape (Zod flatten, per-field map, etc.).
|
|
94
|
+
*/
|
|
95
|
+
export function badRequest(
|
|
96
|
+
input: string | BadRequestBody = "Bad Request",
|
|
97
|
+
options: ResponseInit = {}
|
|
98
|
+
): Response {
|
|
99
|
+
const body =
|
|
100
|
+
typeof input === "string"
|
|
101
|
+
? { error: input }
|
|
102
|
+
: { error: input.message, ...(input.errors !== undefined ? { errors: input.errors } : {}) };
|
|
103
|
+
|
|
104
|
+
const headers = new Headers(options.headers);
|
|
105
|
+
if (!headers.has("Content-Type")) {
|
|
106
|
+
headers.set("Content-Type", "application/json; charset=utf-8");
|
|
107
|
+
}
|
|
108
|
+
return new Response(JSON.stringify(body), {
|
|
109
|
+
status: 400,
|
|
110
|
+
statusText: options.statusText,
|
|
111
|
+
headers,
|
|
112
|
+
});
|
|
113
|
+
}
|