@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
package/src/routes/types.ts
CHANGED
|
@@ -1,341 +1,341 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Metadata Route Types
|
|
3
|
-
*
|
|
4
|
-
* File-convention types for Next.js-style metadata routes. Each type
|
|
5
|
-
* matches the Next.js shape so developers familiar with that ecosystem
|
|
6
|
-
* can drop their existing contract in verbatim.
|
|
7
|
-
*
|
|
8
|
-
* Exposed via `@mandujs/core/routes`. For the legacy free-form SEO
|
|
9
|
-
* metadata types (Metadata, Icons, OpenGraph, ...) see `@mandujs/core`
|
|
10
|
-
* / `packages/core/src/seo/types.ts` — this module is scoped strictly
|
|
11
|
-
* to the file-convention routes (sitemap.ts, robots.ts, llms.txt.ts,
|
|
12
|
-
* manifest.ts) and their runtime handlers.
|
|
13
|
-
*
|
|
14
|
-
* @module routes/types
|
|
15
|
-
*/
|
|
16
|
-
import { z } from "zod";
|
|
17
|
-
|
|
18
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
19
|
-
// Sitemap (sitemap.ts → /sitemap.xml)
|
|
20
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Change frequency hint from the Sitemaps XML schema.
|
|
24
|
-
* @see https://www.sitemaps.org/protocol.html#changefreqdef
|
|
25
|
-
*/
|
|
26
|
-
export type ChangeFrequency =
|
|
27
|
-
| "always"
|
|
28
|
-
| "hourly"
|
|
29
|
-
| "daily"
|
|
30
|
-
| "weekly"
|
|
31
|
-
| "monthly"
|
|
32
|
-
| "yearly"
|
|
33
|
-
| "never";
|
|
34
|
-
|
|
35
|
-
/** Alternate language URLs for a sitemap entry (hreflang). */
|
|
36
|
-
export interface SitemapAlternates {
|
|
37
|
-
languages?: Record<string, string>;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Single sitemap entry. Next.js shape — `url` is required, everything
|
|
42
|
-
* else is optional. `lastModified` accepts a `Date` or ISO string so
|
|
43
|
-
* users can return e.g. `fs.statSync(...).mtime` directly.
|
|
44
|
-
*/
|
|
45
|
-
export interface SitemapEntry {
|
|
46
|
-
/** Absolute URL of the page. */
|
|
47
|
-
url: string;
|
|
48
|
-
/** Last modification time of the page. */
|
|
49
|
-
lastModified?: string | Date;
|
|
50
|
-
/** Crawl frequency hint for search engines. */
|
|
51
|
-
changeFrequency?: ChangeFrequency;
|
|
52
|
-
/** Priority hint [0.0, 1.0]. */
|
|
53
|
-
priority?: number;
|
|
54
|
-
/** Alternate URLs for i18n / hreflang. */
|
|
55
|
-
alternates?: SitemapAlternates;
|
|
56
|
-
/** Optional image URLs associated with the page. */
|
|
57
|
-
images?: string[];
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/** Full sitemap: an array of SitemapEntry. */
|
|
61
|
-
export type Sitemap = SitemapEntry[];
|
|
62
|
-
|
|
63
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
64
|
-
// Robots (robots.ts → /robots.txt)
|
|
65
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Single rule group in robots.txt. Each group applies to one or more
|
|
69
|
-
* user agents; `allow` / `disallow` accept a single string or array.
|
|
70
|
-
*/
|
|
71
|
-
export interface RobotsRule {
|
|
72
|
-
/** User agent string ("*", "Googlebot", ...). */
|
|
73
|
-
userAgent: string | string[];
|
|
74
|
-
/** Paths explicitly permitted. */
|
|
75
|
-
allow?: string | string[];
|
|
76
|
-
/** Paths explicitly denied. */
|
|
77
|
-
disallow?: string | string[];
|
|
78
|
-
/** Crawl delay in seconds. */
|
|
79
|
-
crawlDelay?: number;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Complete robots.txt definition. Matches Next.js `MetadataRoute.Robots`.
|
|
84
|
-
*/
|
|
85
|
-
export interface Robots {
|
|
86
|
-
/** One or more rule groups. */
|
|
87
|
-
rules: RobotsRule | RobotsRule[];
|
|
88
|
-
/** Sitemap URL(s) to announce. */
|
|
89
|
-
sitemap?: string | string[];
|
|
90
|
-
/** Host directive (Yandex). */
|
|
91
|
-
host?: string;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
95
|
-
// Web App Manifest (manifest.ts → /manifest.webmanifest)
|
|
96
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
97
|
-
|
|
98
|
-
export type DisplayMode = "fullscreen" | "standalone" | "minimal-ui" | "browser";
|
|
99
|
-
export type Orientation =
|
|
100
|
-
| "any"
|
|
101
|
-
| "natural"
|
|
102
|
-
| "landscape"
|
|
103
|
-
| "landscape-primary"
|
|
104
|
-
| "landscape-secondary"
|
|
105
|
-
| "portrait"
|
|
106
|
-
| "portrait-primary"
|
|
107
|
-
| "portrait-secondary";
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Icon descriptor in a web app manifest. `src` + `sizes` + `type` is
|
|
111
|
-
* the minimal W3C contract; `purpose` is optional but recommended for
|
|
112
|
-
* maskable icons.
|
|
113
|
-
*/
|
|
114
|
-
export interface WebAppManifestIcon {
|
|
115
|
-
src: string;
|
|
116
|
-
sizes?: string;
|
|
117
|
-
type?: string;
|
|
118
|
-
purpose?: "any" | "maskable" | "monochrome" | string;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/** Shortcut entry (jumplist) in a web app manifest. */
|
|
122
|
-
export interface WebAppManifestShortcut {
|
|
123
|
-
name: string;
|
|
124
|
-
short_name?: string;
|
|
125
|
-
description?: string;
|
|
126
|
-
url: string;
|
|
127
|
-
icons?: WebAppManifestIcon[];
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Web app manifest (application/manifest+json). We type the common
|
|
132
|
-
* subset defined by the W3C spec; unknown keys pass through via the
|
|
133
|
-
* index signature so callers can add experimental fields.
|
|
134
|
-
*/
|
|
135
|
-
export interface WebAppManifest {
|
|
136
|
-
/** Full name of the application (required per W3C). */
|
|
137
|
-
name: string;
|
|
138
|
-
/** Short name for home-screen / launcher. */
|
|
139
|
-
short_name: string;
|
|
140
|
-
/** Description. */
|
|
141
|
-
description?: string;
|
|
142
|
-
/** Starting URL. */
|
|
143
|
-
start_url?: string;
|
|
144
|
-
/** Application scope (URL prefix). */
|
|
145
|
-
scope?: string;
|
|
146
|
-
/** Display mode. */
|
|
147
|
-
display?: DisplayMode;
|
|
148
|
-
/** Orientation preference. */
|
|
149
|
-
orientation?: Orientation;
|
|
150
|
-
/** Primary theme color (toolbar). */
|
|
151
|
-
theme_color?: string;
|
|
152
|
-
/** Background color (splash). */
|
|
153
|
-
background_color?: string;
|
|
154
|
-
/** Icons — at least one is required by the spec. */
|
|
155
|
-
icons: WebAppManifestIcon[];
|
|
156
|
-
/** Language tag (e.g. "en-US"). */
|
|
157
|
-
lang?: string;
|
|
158
|
-
/** Text direction. */
|
|
159
|
-
dir?: "ltr" | "rtl" | "auto";
|
|
160
|
-
/** Categories (taxonomy). */
|
|
161
|
-
categories?: string[];
|
|
162
|
-
/** Shortcuts shown in the app launcher. */
|
|
163
|
-
shortcuts?: WebAppManifestShortcut[];
|
|
164
|
-
/** Additional W3C fields pass through unchanged. */
|
|
165
|
-
[key: string]: unknown;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
169
|
-
// Default export function signatures
|
|
170
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Default-export contract for `app/sitemap.ts`. Return `Sitemap` or a
|
|
174
|
-
* Promise — Mandu awaits the result during the request.
|
|
175
|
-
*/
|
|
176
|
-
export type SitemapFn = () => Sitemap | Promise<Sitemap>;
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Default-export contract for `app/robots.ts`.
|
|
180
|
-
*/
|
|
181
|
-
export type RobotsFn = () => Robots | Promise<Robots>;
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Default-export contract for `app/llms.txt.ts`. Return the complete
|
|
185
|
-
* text body; Mandu serves it verbatim with `text/plain` content type.
|
|
186
|
-
*/
|
|
187
|
-
export type LlmsTxtFn = () => string | Promise<string>;
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Default-export contract for `app/manifest.ts`.
|
|
191
|
-
*/
|
|
192
|
-
export type ManifestFn = () => WebAppManifest | Promise<WebAppManifest>;
|
|
193
|
-
|
|
194
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
195
|
-
// Metadata route kinds (for manifest / fs-scanner)
|
|
196
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Discriminator used in `RouteSpec.kind === "metadata"` entries and in
|
|
200
|
-
* `ScannedFile.metadataKind` when fs-scanner detects one of the four
|
|
201
|
-
* metadata files.
|
|
202
|
-
*/
|
|
203
|
-
export type MetadataRouteKind = "sitemap" | "robots" | "llms-txt" | "manifest";
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Static table mapping each metadata route kind to the file name the
|
|
207
|
-
* scanner recognizes, the URL pattern that serves the content, and the
|
|
208
|
-
* Content-Type header. Kept deliberately flat so both fs-scanner and
|
|
209
|
-
* the runtime dispatcher can read from the same source of truth.
|
|
210
|
-
*/
|
|
211
|
-
export const METADATA_ROUTES: Record<
|
|
212
|
-
MetadataRouteKind,
|
|
213
|
-
{ fileBase: string; pattern: string; contentType: string }
|
|
214
|
-
> = {
|
|
215
|
-
sitemap: {
|
|
216
|
-
fileBase: "sitemap",
|
|
217
|
-
pattern: "/sitemap.xml",
|
|
218
|
-
contentType: "application/xml; charset=utf-8",
|
|
219
|
-
},
|
|
220
|
-
robots: {
|
|
221
|
-
fileBase: "robots",
|
|
222
|
-
pattern: "/robots.txt",
|
|
223
|
-
contentType: "text/plain; charset=utf-8",
|
|
224
|
-
},
|
|
225
|
-
"llms-txt": {
|
|
226
|
-
// `llms.txt.ts` — filename contains a dot before the extension to
|
|
227
|
-
// mirror the served path (/llms.txt). Detected specifically in
|
|
228
|
-
// `detectMetadataFile()` since it doesn't match the common
|
|
229
|
-
// `<name>.<ext>` shape.
|
|
230
|
-
fileBase: "llms.txt",
|
|
231
|
-
pattern: "/llms.txt",
|
|
232
|
-
contentType: "text/plain; charset=utf-8",
|
|
233
|
-
},
|
|
234
|
-
manifest: {
|
|
235
|
-
fileBase: "manifest",
|
|
236
|
-
pattern: "/manifest.webmanifest",
|
|
237
|
-
contentType: "application/manifest+json; charset=utf-8",
|
|
238
|
-
},
|
|
239
|
-
};
|
|
240
|
-
|
|
241
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
242
|
-
// Zod schemas — runtime validation of user-returned values
|
|
243
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* Validates a single sitemap entry. `url` must be a URL-like string;
|
|
247
|
-
* we accept both protocol-absolute URLs and site-root-relative paths
|
|
248
|
-
* (`/docs/...`) so users building a sitemap for an internal base can
|
|
249
|
-
* return relative URLs. `lastModified` accepts Date or date-like string.
|
|
250
|
-
*/
|
|
251
|
-
export const SitemapEntrySchema = z.object({
|
|
252
|
-
url: z
|
|
253
|
-
.string()
|
|
254
|
-
.min(1, "SitemapEntry.url must not be empty")
|
|
255
|
-
.refine(
|
|
256
|
-
(v) => /^(https?:\/\/|\/)/.test(v),
|
|
257
|
-
"SitemapEntry.url must be absolute (http(s)://...) or site-root-relative (/...)"
|
|
258
|
-
),
|
|
259
|
-
lastModified: z
|
|
260
|
-
.union([z.date(), z.string().min(1)])
|
|
261
|
-
.optional(),
|
|
262
|
-
changeFrequency: z
|
|
263
|
-
.enum(["always", "hourly", "daily", "weekly", "monthly", "yearly", "never"])
|
|
264
|
-
.optional(),
|
|
265
|
-
priority: z.number().min(0).max(1).optional(),
|
|
266
|
-
alternates: z
|
|
267
|
-
.object({ languages: z.record(z.string()).optional() })
|
|
268
|
-
.optional(),
|
|
269
|
-
images: z.array(z.string().min(1)).optional(),
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
export const SitemapSchema = z.array(SitemapEntrySchema);
|
|
273
|
-
|
|
274
|
-
export const RobotsRuleSchema = z.object({
|
|
275
|
-
userAgent: z.union([z.string().min(1), z.array(z.string().min(1))]),
|
|
276
|
-
allow: z.union([z.string(), z.array(z.string())]).optional(),
|
|
277
|
-
disallow: z.union([z.string(), z.array(z.string())]).optional(),
|
|
278
|
-
crawlDelay: z.number().nonnegative().optional(),
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
export const RobotsSchema = z.object({
|
|
282
|
-
rules: z.union([RobotsRuleSchema, z.array(RobotsRuleSchema)]),
|
|
283
|
-
sitemap: z.union([z.string().min(1), z.array(z.string().min(1))]).optional(),
|
|
284
|
-
host: z.string().optional(),
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
export const WebAppManifestIconSchema = z.object({
|
|
288
|
-
src: z.string().min(1, "WebAppManifest icon.src must not be empty"),
|
|
289
|
-
sizes: z.string().optional(),
|
|
290
|
-
type: z.string().optional(),
|
|
291
|
-
purpose: z.string().optional(),
|
|
292
|
-
});
|
|
293
|
-
|
|
294
|
-
/**
|
|
295
|
-
* Minimum W3C-compliant manifest — `name`, `short_name`, and at least
|
|
296
|
-
* one icon. Unknown keys pass through via `.passthrough()` so users
|
|
297
|
-
* can add experimental manifest fields without fighting the validator.
|
|
298
|
-
*/
|
|
299
|
-
export const WebAppManifestSchema = z
|
|
300
|
-
.object({
|
|
301
|
-
name: z.string().min(1, "WebAppManifest.name is required"),
|
|
302
|
-
short_name: z.string().min(1, "WebAppManifest.short_name is required"),
|
|
303
|
-
description: z.string().optional(),
|
|
304
|
-
start_url: z.string().optional(),
|
|
305
|
-
scope: z.string().optional(),
|
|
306
|
-
display: z
|
|
307
|
-
.enum(["fullscreen", "standalone", "minimal-ui", "browser"])
|
|
308
|
-
.optional(),
|
|
309
|
-
orientation: z
|
|
310
|
-
.enum([
|
|
311
|
-
"any",
|
|
312
|
-
"natural",
|
|
313
|
-
"landscape",
|
|
314
|
-
"landscape-primary",
|
|
315
|
-
"landscape-secondary",
|
|
316
|
-
"portrait",
|
|
317
|
-
"portrait-primary",
|
|
318
|
-
"portrait-secondary",
|
|
319
|
-
])
|
|
320
|
-
.optional(),
|
|
321
|
-
theme_color: z.string().optional(),
|
|
322
|
-
background_color: z.string().optional(),
|
|
323
|
-
icons: z
|
|
324
|
-
.array(WebAppManifestIconSchema)
|
|
325
|
-
.min(1, "WebAppManifest.icons must contain at least one icon"),
|
|
326
|
-
lang: z.string().optional(),
|
|
327
|
-
dir: z.enum(["ltr", "rtl", "auto"]).optional(),
|
|
328
|
-
categories: z.array(z.string()).optional(),
|
|
329
|
-
shortcuts: z
|
|
330
|
-
.array(
|
|
331
|
-
z.object({
|
|
332
|
-
name: z.string().min(1),
|
|
333
|
-
short_name: z.string().optional(),
|
|
334
|
-
description: z.string().optional(),
|
|
335
|
-
url: z.string().min(1),
|
|
336
|
-
icons: z.array(WebAppManifestIconSchema).optional(),
|
|
337
|
-
})
|
|
338
|
-
)
|
|
339
|
-
.optional(),
|
|
340
|
-
})
|
|
341
|
-
.passthrough();
|
|
1
|
+
/**
|
|
2
|
+
* Metadata Route Types
|
|
3
|
+
*
|
|
4
|
+
* File-convention types for Next.js-style metadata routes. Each type
|
|
5
|
+
* matches the Next.js shape so developers familiar with that ecosystem
|
|
6
|
+
* can drop their existing contract in verbatim.
|
|
7
|
+
*
|
|
8
|
+
* Exposed via `@mandujs/core/routes`. For the legacy free-form SEO
|
|
9
|
+
* metadata types (Metadata, Icons, OpenGraph, ...) see `@mandujs/core`
|
|
10
|
+
* / `packages/core/src/seo/types.ts` — this module is scoped strictly
|
|
11
|
+
* to the file-convention routes (sitemap.ts, robots.ts, llms.txt.ts,
|
|
12
|
+
* manifest.ts) and their runtime handlers.
|
|
13
|
+
*
|
|
14
|
+
* @module routes/types
|
|
15
|
+
*/
|
|
16
|
+
import { z } from "zod";
|
|
17
|
+
|
|
18
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
19
|
+
// Sitemap (sitemap.ts → /sitemap.xml)
|
|
20
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Change frequency hint from the Sitemaps XML schema.
|
|
24
|
+
* @see https://www.sitemaps.org/protocol.html#changefreqdef
|
|
25
|
+
*/
|
|
26
|
+
export type ChangeFrequency =
|
|
27
|
+
| "always"
|
|
28
|
+
| "hourly"
|
|
29
|
+
| "daily"
|
|
30
|
+
| "weekly"
|
|
31
|
+
| "monthly"
|
|
32
|
+
| "yearly"
|
|
33
|
+
| "never";
|
|
34
|
+
|
|
35
|
+
/** Alternate language URLs for a sitemap entry (hreflang). */
|
|
36
|
+
export interface SitemapAlternates {
|
|
37
|
+
languages?: Record<string, string>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Single sitemap entry. Next.js shape — `url` is required, everything
|
|
42
|
+
* else is optional. `lastModified` accepts a `Date` or ISO string so
|
|
43
|
+
* users can return e.g. `fs.statSync(...).mtime` directly.
|
|
44
|
+
*/
|
|
45
|
+
export interface SitemapEntry {
|
|
46
|
+
/** Absolute URL of the page. */
|
|
47
|
+
url: string;
|
|
48
|
+
/** Last modification time of the page. */
|
|
49
|
+
lastModified?: string | Date;
|
|
50
|
+
/** Crawl frequency hint for search engines. */
|
|
51
|
+
changeFrequency?: ChangeFrequency;
|
|
52
|
+
/** Priority hint [0.0, 1.0]. */
|
|
53
|
+
priority?: number;
|
|
54
|
+
/** Alternate URLs for i18n / hreflang. */
|
|
55
|
+
alternates?: SitemapAlternates;
|
|
56
|
+
/** Optional image URLs associated with the page. */
|
|
57
|
+
images?: string[];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Full sitemap: an array of SitemapEntry. */
|
|
61
|
+
export type Sitemap = SitemapEntry[];
|
|
62
|
+
|
|
63
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
64
|
+
// Robots (robots.ts → /robots.txt)
|
|
65
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Single rule group in robots.txt. Each group applies to one or more
|
|
69
|
+
* user agents; `allow` / `disallow` accept a single string or array.
|
|
70
|
+
*/
|
|
71
|
+
export interface RobotsRule {
|
|
72
|
+
/** User agent string ("*", "Googlebot", ...). */
|
|
73
|
+
userAgent: string | string[];
|
|
74
|
+
/** Paths explicitly permitted. */
|
|
75
|
+
allow?: string | string[];
|
|
76
|
+
/** Paths explicitly denied. */
|
|
77
|
+
disallow?: string | string[];
|
|
78
|
+
/** Crawl delay in seconds. */
|
|
79
|
+
crawlDelay?: number;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Complete robots.txt definition. Matches Next.js `MetadataRoute.Robots`.
|
|
84
|
+
*/
|
|
85
|
+
export interface Robots {
|
|
86
|
+
/** One or more rule groups. */
|
|
87
|
+
rules: RobotsRule | RobotsRule[];
|
|
88
|
+
/** Sitemap URL(s) to announce. */
|
|
89
|
+
sitemap?: string | string[];
|
|
90
|
+
/** Host directive (Yandex). */
|
|
91
|
+
host?: string;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
95
|
+
// Web App Manifest (manifest.ts → /manifest.webmanifest)
|
|
96
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
97
|
+
|
|
98
|
+
export type DisplayMode = "fullscreen" | "standalone" | "minimal-ui" | "browser";
|
|
99
|
+
export type Orientation =
|
|
100
|
+
| "any"
|
|
101
|
+
| "natural"
|
|
102
|
+
| "landscape"
|
|
103
|
+
| "landscape-primary"
|
|
104
|
+
| "landscape-secondary"
|
|
105
|
+
| "portrait"
|
|
106
|
+
| "portrait-primary"
|
|
107
|
+
| "portrait-secondary";
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Icon descriptor in a web app manifest. `src` + `sizes` + `type` is
|
|
111
|
+
* the minimal W3C contract; `purpose` is optional but recommended for
|
|
112
|
+
* maskable icons.
|
|
113
|
+
*/
|
|
114
|
+
export interface WebAppManifestIcon {
|
|
115
|
+
src: string;
|
|
116
|
+
sizes?: string;
|
|
117
|
+
type?: string;
|
|
118
|
+
purpose?: "any" | "maskable" | "monochrome" | string;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Shortcut entry (jumplist) in a web app manifest. */
|
|
122
|
+
export interface WebAppManifestShortcut {
|
|
123
|
+
name: string;
|
|
124
|
+
short_name?: string;
|
|
125
|
+
description?: string;
|
|
126
|
+
url: string;
|
|
127
|
+
icons?: WebAppManifestIcon[];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Web app manifest (application/manifest+json). We type the common
|
|
132
|
+
* subset defined by the W3C spec; unknown keys pass through via the
|
|
133
|
+
* index signature so callers can add experimental fields.
|
|
134
|
+
*/
|
|
135
|
+
export interface WebAppManifest {
|
|
136
|
+
/** Full name of the application (required per W3C). */
|
|
137
|
+
name: string;
|
|
138
|
+
/** Short name for home-screen / launcher. */
|
|
139
|
+
short_name: string;
|
|
140
|
+
/** Description. */
|
|
141
|
+
description?: string;
|
|
142
|
+
/** Starting URL. */
|
|
143
|
+
start_url?: string;
|
|
144
|
+
/** Application scope (URL prefix). */
|
|
145
|
+
scope?: string;
|
|
146
|
+
/** Display mode. */
|
|
147
|
+
display?: DisplayMode;
|
|
148
|
+
/** Orientation preference. */
|
|
149
|
+
orientation?: Orientation;
|
|
150
|
+
/** Primary theme color (toolbar). */
|
|
151
|
+
theme_color?: string;
|
|
152
|
+
/** Background color (splash). */
|
|
153
|
+
background_color?: string;
|
|
154
|
+
/** Icons — at least one is required by the spec. */
|
|
155
|
+
icons: WebAppManifestIcon[];
|
|
156
|
+
/** Language tag (e.g. "en-US"). */
|
|
157
|
+
lang?: string;
|
|
158
|
+
/** Text direction. */
|
|
159
|
+
dir?: "ltr" | "rtl" | "auto";
|
|
160
|
+
/** Categories (taxonomy). */
|
|
161
|
+
categories?: string[];
|
|
162
|
+
/** Shortcuts shown in the app launcher. */
|
|
163
|
+
shortcuts?: WebAppManifestShortcut[];
|
|
164
|
+
/** Additional W3C fields pass through unchanged. */
|
|
165
|
+
[key: string]: unknown;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
169
|
+
// Default export function signatures
|
|
170
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Default-export contract for `app/sitemap.ts`. Return `Sitemap` or a
|
|
174
|
+
* Promise — Mandu awaits the result during the request.
|
|
175
|
+
*/
|
|
176
|
+
export type SitemapFn = () => Sitemap | Promise<Sitemap>;
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Default-export contract for `app/robots.ts`.
|
|
180
|
+
*/
|
|
181
|
+
export type RobotsFn = () => Robots | Promise<Robots>;
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Default-export contract for `app/llms.txt.ts`. Return the complete
|
|
185
|
+
* text body; Mandu serves it verbatim with `text/plain` content type.
|
|
186
|
+
*/
|
|
187
|
+
export type LlmsTxtFn = () => string | Promise<string>;
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Default-export contract for `app/manifest.ts`.
|
|
191
|
+
*/
|
|
192
|
+
export type ManifestFn = () => WebAppManifest | Promise<WebAppManifest>;
|
|
193
|
+
|
|
194
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
195
|
+
// Metadata route kinds (for manifest / fs-scanner)
|
|
196
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Discriminator used in `RouteSpec.kind === "metadata"` entries and in
|
|
200
|
+
* `ScannedFile.metadataKind` when fs-scanner detects one of the four
|
|
201
|
+
* metadata files.
|
|
202
|
+
*/
|
|
203
|
+
export type MetadataRouteKind = "sitemap" | "robots" | "llms-txt" | "manifest";
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Static table mapping each metadata route kind to the file name the
|
|
207
|
+
* scanner recognizes, the URL pattern that serves the content, and the
|
|
208
|
+
* Content-Type header. Kept deliberately flat so both fs-scanner and
|
|
209
|
+
* the runtime dispatcher can read from the same source of truth.
|
|
210
|
+
*/
|
|
211
|
+
export const METADATA_ROUTES: Record<
|
|
212
|
+
MetadataRouteKind,
|
|
213
|
+
{ fileBase: string; pattern: string; contentType: string }
|
|
214
|
+
> = {
|
|
215
|
+
sitemap: {
|
|
216
|
+
fileBase: "sitemap",
|
|
217
|
+
pattern: "/sitemap.xml",
|
|
218
|
+
contentType: "application/xml; charset=utf-8",
|
|
219
|
+
},
|
|
220
|
+
robots: {
|
|
221
|
+
fileBase: "robots",
|
|
222
|
+
pattern: "/robots.txt",
|
|
223
|
+
contentType: "text/plain; charset=utf-8",
|
|
224
|
+
},
|
|
225
|
+
"llms-txt": {
|
|
226
|
+
// `llms.txt.ts` — filename contains a dot before the extension to
|
|
227
|
+
// mirror the served path (/llms.txt). Detected specifically in
|
|
228
|
+
// `detectMetadataFile()` since it doesn't match the common
|
|
229
|
+
// `<name>.<ext>` shape.
|
|
230
|
+
fileBase: "llms.txt",
|
|
231
|
+
pattern: "/llms.txt",
|
|
232
|
+
contentType: "text/plain; charset=utf-8",
|
|
233
|
+
},
|
|
234
|
+
manifest: {
|
|
235
|
+
fileBase: "manifest",
|
|
236
|
+
pattern: "/manifest.webmanifest",
|
|
237
|
+
contentType: "application/manifest+json; charset=utf-8",
|
|
238
|
+
},
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
242
|
+
// Zod schemas — runtime validation of user-returned values
|
|
243
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Validates a single sitemap entry. `url` must be a URL-like string;
|
|
247
|
+
* we accept both protocol-absolute URLs and site-root-relative paths
|
|
248
|
+
* (`/docs/...`) so users building a sitemap for an internal base can
|
|
249
|
+
* return relative URLs. `lastModified` accepts Date or date-like string.
|
|
250
|
+
*/
|
|
251
|
+
export const SitemapEntrySchema = z.object({
|
|
252
|
+
url: z
|
|
253
|
+
.string()
|
|
254
|
+
.min(1, "SitemapEntry.url must not be empty")
|
|
255
|
+
.refine(
|
|
256
|
+
(v) => /^(https?:\/\/|\/)/.test(v),
|
|
257
|
+
"SitemapEntry.url must be absolute (http(s)://...) or site-root-relative (/...)"
|
|
258
|
+
),
|
|
259
|
+
lastModified: z
|
|
260
|
+
.union([z.date(), z.string().min(1)])
|
|
261
|
+
.optional(),
|
|
262
|
+
changeFrequency: z
|
|
263
|
+
.enum(["always", "hourly", "daily", "weekly", "monthly", "yearly", "never"])
|
|
264
|
+
.optional(),
|
|
265
|
+
priority: z.number().min(0).max(1).optional(),
|
|
266
|
+
alternates: z
|
|
267
|
+
.object({ languages: z.record(z.string()).optional() })
|
|
268
|
+
.optional(),
|
|
269
|
+
images: z.array(z.string().min(1)).optional(),
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
export const SitemapSchema = z.array(SitemapEntrySchema);
|
|
273
|
+
|
|
274
|
+
export const RobotsRuleSchema = z.object({
|
|
275
|
+
userAgent: z.union([z.string().min(1), z.array(z.string().min(1))]),
|
|
276
|
+
allow: z.union([z.string(), z.array(z.string())]).optional(),
|
|
277
|
+
disallow: z.union([z.string(), z.array(z.string())]).optional(),
|
|
278
|
+
crawlDelay: z.number().nonnegative().optional(),
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
export const RobotsSchema = z.object({
|
|
282
|
+
rules: z.union([RobotsRuleSchema, z.array(RobotsRuleSchema)]),
|
|
283
|
+
sitemap: z.union([z.string().min(1), z.array(z.string().min(1))]).optional(),
|
|
284
|
+
host: z.string().optional(),
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
export const WebAppManifestIconSchema = z.object({
|
|
288
|
+
src: z.string().min(1, "WebAppManifest icon.src must not be empty"),
|
|
289
|
+
sizes: z.string().optional(),
|
|
290
|
+
type: z.string().optional(),
|
|
291
|
+
purpose: z.string().optional(),
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Minimum W3C-compliant manifest — `name`, `short_name`, and at least
|
|
296
|
+
* one icon. Unknown keys pass through via `.passthrough()` so users
|
|
297
|
+
* can add experimental manifest fields without fighting the validator.
|
|
298
|
+
*/
|
|
299
|
+
export const WebAppManifestSchema = z
|
|
300
|
+
.object({
|
|
301
|
+
name: z.string().min(1, "WebAppManifest.name is required"),
|
|
302
|
+
short_name: z.string().min(1, "WebAppManifest.short_name is required"),
|
|
303
|
+
description: z.string().optional(),
|
|
304
|
+
start_url: z.string().optional(),
|
|
305
|
+
scope: z.string().optional(),
|
|
306
|
+
display: z
|
|
307
|
+
.enum(["fullscreen", "standalone", "minimal-ui", "browser"])
|
|
308
|
+
.optional(),
|
|
309
|
+
orientation: z
|
|
310
|
+
.enum([
|
|
311
|
+
"any",
|
|
312
|
+
"natural",
|
|
313
|
+
"landscape",
|
|
314
|
+
"landscape-primary",
|
|
315
|
+
"landscape-secondary",
|
|
316
|
+
"portrait",
|
|
317
|
+
"portrait-primary",
|
|
318
|
+
"portrait-secondary",
|
|
319
|
+
])
|
|
320
|
+
.optional(),
|
|
321
|
+
theme_color: z.string().optional(),
|
|
322
|
+
background_color: z.string().optional(),
|
|
323
|
+
icons: z
|
|
324
|
+
.array(WebAppManifestIconSchema)
|
|
325
|
+
.min(1, "WebAppManifest.icons must contain at least one icon"),
|
|
326
|
+
lang: z.string().optional(),
|
|
327
|
+
dir: z.enum(["ltr", "rtl", "auto"]).optional(),
|
|
328
|
+
categories: z.array(z.string()).optional(),
|
|
329
|
+
shortcuts: z
|
|
330
|
+
.array(
|
|
331
|
+
z.object({
|
|
332
|
+
name: z.string().min(1),
|
|
333
|
+
short_name: z.string().optional(),
|
|
334
|
+
description: z.string().optional(),
|
|
335
|
+
url: z.string().min(1),
|
|
336
|
+
icons: z.array(WebAppManifestIconSchema).optional(),
|
|
337
|
+
})
|
|
338
|
+
)
|
|
339
|
+
.optional(),
|
|
340
|
+
})
|
|
341
|
+
.passthrough();
|