From 20332bef3b7e249ef9b70447fed2b502e01adafa Mon Sep 17 00:00:00 2001 From: Francesca Giannino Date: Thu, 29 Jan 2026 16:05:18 +0100 Subject: [PATCH 01/17] Redesign: Technical Setup and Project Base (#2167) Co-authored-by: Sebastian Beltran --- .editorconfig | 19 + .github/CODEOWNERS | 4 +- .gitignore | 10 + .vscode/extensions.json | 8 + .vscode/launch.json | 11 + .vscode/settings.json | 21 + astro/.gitignore | 24 + astro/.nvmrc | 1 + astro/.prettierignore | 5 + astro/.prettierrc | 9 + astro/CONTRIBUTING.md | 129 + astro/README.md | 7 + astro/astro.config.mjs | 14 + astro/eslint.config.js | 34 + astro/package-lock.json | 10288 ++++++++++++++++ astro/package.json | 53 + astro/postcss.config.mjs | 11 + astro/public/apple-touch-icon.png | Bin 0 -> 3557 bytes astro/public/favicon.ico | Bin 0 -> 15086 bytes astro/public/favicon.svg | 1 + astro/public/fonts/JetBrainsMono-Light.woff2 | Bin 0 -> 93856 bytes .../fonts/JetBrainsMono-LightItalic.woff2 | Bin 0 -> 97280 bytes astro/public/site.webmanifest | 21 + .../patterns/Breadcrumbs/Breadcrumbs.astro | 35 + .../ThemeSwitcher/ThemeSwitcher.astro | 85 + astro/src/components/patterns/index.ts | 8 + .../components/primitives/Button/Button.astro | 48 + .../components/primitives/Button/Button.css | 85 + .../src/components/primitives/Button/index.ts | 6 + .../src/components/primitives/Button/types.ts | 22 + .../primitives/Container/Container.astro | 26 + .../primitives/Container/Container.css | 13 + .../components/primitives/Container/index.ts | 2 + .../components/primitives/Container/types.ts | 18 + .../src/components/primitives/Grid/Col.astro | 27 + .../src/components/primitives/Grid/Flex.astro | 37 + .../components/primitives/Grid/FlexItem.astro | 35 + .../src/components/primitives/Grid/Grid.astro | 34 + astro/src/components/primitives/Grid/Grid.css | 532 + astro/src/components/primitives/Grid/index.ts | 12 + astro/src/components/primitives/Grid/types.ts | 70 + .../primitives/Typography/Body.astro | 30 + .../primitives/Typography/BodyMd.astro | 30 + .../primitives/Typography/BodySm.astro | 30 + .../primitives/Typography/BodyXs.astro | 30 + .../primitives/Typography/Code.astro | 29 + .../components/primitives/Typography/H1.astro | 27 + .../components/primitives/Typography/H2.astro | 27 + .../components/primitives/Typography/H3.astro | 27 + .../components/primitives/Typography/H4.astro | 27 + .../components/primitives/Typography/H5.astro | 30 + .../primitives/Typography/Typography.astro | 56 + .../primitives/Typography/Typography.css | 66 + .../components/primitives/Typography/index.ts | 28 + .../components/primitives/Typography/types.ts | 59 + astro/src/components/primitives/index.ts | 15 + astro/src/config/menu.ts | 8 + astro/src/content.config.ts | 16 + .../en/advanced/best-practice-performance.md | 309 + .../en/advanced/best-practice-security.md | 285 + .../advanced/developing-template-engines.md | 47 + .../advanced/healthcheck-graceful-shutdown.md | 32 + .../docs/en/advanced/security-updates.md | 85 + .../content/docs/en/guide/behind-proxies.md | 94 + .../docs/en/guide/database-integration.md | 503 + astro/src/content/docs/en/guide/debugging.md | 129 + .../content/docs/en/guide/error-handling.md | 308 + .../src/content/docs/en/guide/migrating-4.md | 615 + .../src/content/docs/en/guide/migrating-5.md | 616 + .../docs/en/guide/overriding-express-api.md | 72 + astro/src/content/docs/en/guide/routing.md | 419 + .../content/docs/en/guide/using-middleware.md | 297 + .../docs/en/guide/using-template-engines.md | 65 + .../docs/en/guide/writing-middleware.md | 220 + .../content/docs/en/resources/community.md | 92 + .../content/docs/en/resources/contributing.md | 484 + .../src/content/docs/en/resources/glossary.md | 64 + .../content/docs/en/resources/middleware.md | 43 + .../en/resources/middleware/body-parser.md | 499 + .../en/resources/middleware/compression.md | 315 + .../en/resources/middleware/connect-rid.md | 64 + .../en/resources/middleware/cookie-parser.md | 125 + .../en/resources/middleware/cookie-session.md | 125 + .../docs/en/resources/middleware/cors.md | 262 + .../en/resources/middleware/errorhandler.md | 134 + .../resources/middleware/method-override.md | 188 + .../docs/en/resources/middleware/morgan.md | 459 + .../docs/en/resources/middleware/multer.md | 353 + .../en/resources/middleware/response-time.md | 315 + .../en/resources/middleware/serve-favicon.md | 157 + .../en/resources/middleware/serve-index.md | 157 + .../en/resources/middleware/serve-static.md | 261 + .../docs/en/resources/middleware/session.md | 1047 ++ .../docs/en/resources/middleware/timeout.md | 177 + .../docs/en/resources/middleware/vhost.md | 175 + astro/src/content/docs/en/resources/utils.md | 24 + .../content/docs/en/starter/basic-routing.md | 65 + astro/src/content/docs/en/starter/examples.md | 18 + astro/src/content/docs/en/starter/faq.md | 94 + .../src/content/docs/en/starter/generator.md | 124 + .../content/docs/en/starter/hello-world.md | 48 + .../src/content/docs/en/starter/installing.md | 50 + .../content/docs/en/starter/static-files.md | 78 + astro/src/i18n/ui.ts | 15 + astro/src/i18n/utils.ts | 13 + astro/src/layouts/DocLayout.astro | 25 + astro/src/layouts/Layout.astro | 38 + astro/src/pages/[lang]/[...slug].astro | 37 + astro/src/pages/[lang]/docs/index.astro | 54 + astro/src/pages/[lang]/ds-foundations.astro | 1090 ++ astro/src/pages/[lang]/index.astro | 30 + astro/src/pages/index.astro | 1 + astro/src/styles/base/_fonts.css | 24 + astro/src/styles/base/_global.css | 221 + astro/src/styles/base/_reset.css | 82 + astro/src/styles/main.css | 18 + astro/src/styles/tokens/_borders.css | 31 + astro/src/styles/tokens/_breakpoints.css | 46 + astro/src/styles/tokens/_colors.css | 156 + astro/src/styles/tokens/_spacing.css | 48 + astro/src/styles/tokens/_transitions.css | 47 + astro/src/styles/tokens/_typography.css | 82 + astro/src/styles/tokens/index.css | 12 + astro/src/styles/utilities/_utilities.css | 144 + astro/src/utils/content.ts | 84 + astro/tsconfig.json | 18 + legacy/.github-legacy/CODEOWNERS | 8 + .../.github-legacy}/dependabot.yml | 0 .../scripts/get-contributing.sh | 0 .../scripts/get-express-version.mjs | 0 .../.github-legacy}/scripts/get-readmes.sh | 0 .../.github-legacy}/workflows/ci.yml | 0 legacy/.github-legacy/workflows/codeql.yml | 73 + .../.github-legacy}/workflows/crowdin.yml | 0 .../.github-legacy}/workflows/deploy.yml | 0 .../.github-legacy}/workflows/lighthouse.yml | 0 .../.github-legacy/workflows/scorecards.yml | 76 + .../workflows/update-external-docs.yml | 0 .ruby-version => legacy/.ruby-version | 0 {2x => legacy/2x}/applications.md | 0 {2x => legacy/2x}/contrib.md | 0 {2x => legacy/2x}/docs/applications.md | 0 {2x => legacy/2x}/docs/contrib.md | 0 {2x => legacy/2x}/docs/executable.md | 0 {2x => legacy/2x}/docs/guide.md | 0 {2x => legacy/2x}/docs/index.md | 0 {2x => legacy/2x}/docs/migrate.md | 0 {2x => legacy/2x}/docs/screencasts.md | 0 {2x => legacy/2x}/executable.md | 0 {2x => legacy/2x}/guide.md | 0 {2x => legacy/2x}/index.md | 0 {2x => legacy/2x}/migrate.md | 0 {2x => legacy/2x}/screencasts.md | 0 404.md => legacy/404.md | 0 CNAME => legacy/CNAME | 0 CONTRIBUTING.md => legacy/CONTRIBUTING.md | 0 Dockerfile => legacy/Dockerfile | 0 Gemfile => legacy/Gemfile | 0 Gemfile.lock => legacy/Gemfile.lock | 0 Makefile => legacy/Makefile | 0 README.md => legacy/README.md | 0 _config.yml => legacy/_config.yml | 0 {_data => legacy/_data}/de/footer.yml | 0 {_data => legacy/_data}/de/general.yml | 0 {_data => legacy/_data}/de/menu.yml | 0 {_data => legacy/_data}/docsearch.yml | 0 {_data => legacy/_data}/en/footer.yml | 0 {_data => legacy/_data}/en/general.yml | 0 {_data => legacy/_data}/en/menu.yml | 0 {_data => legacy/_data}/es/footer.yml | 0 {_data => legacy/_data}/es/general.yml | 0 {_data => legacy/_data}/es/menu.yml | 0 {_data => legacy/_data}/express.yml | 0 {_data => legacy/_data}/fr/footer.yml | 0 {_data => legacy/_data}/fr/general.yml | 0 {_data => legacy/_data}/fr/menu.yml | 0 {_data => legacy/_data}/it/footer.yml | 0 {_data => legacy/_data}/it/general.yml | 0 {_data => legacy/_data}/it/menu.yml | 0 {_data => legacy/_data}/ja/footer.yml | 0 {_data => legacy/_data}/ja/general.yml | 0 {_data => legacy/_data}/ja/menu.yml | 0 {_data => legacy/_data}/ko/footer.yml | 0 {_data => legacy/_data}/ko/general.yml | 0 {_data => legacy/_data}/ko/menu.yml | 0 {_data => legacy/_data}/languages.yml | 0 {_data => legacy/_data}/pt-br/footer.yml | 0 {_data => legacy/_data}/pt-br/general.yml | 0 {_data => legacy/_data}/pt-br/menu.yml | 0 {_data => legacy/_data}/zh-cn/footer.yml | 0 {_data => legacy/_data}/zh-cn/general.yml | 0 {_data => legacy/_data}/zh-cn/menu.yml | 0 {_data => legacy/_data}/zh-tw/footer.yml | 0 {_data => legacy/_data}/zh-tw/general.yml | 0 {_data => legacy/_data}/zh-tw/menu.yml | 0 .../_includes}/admonitions/caution.html | 0 .../_includes}/admonitions/note.html | 0 .../_includes}/admonitions/warning.html | 0 .../_includes}/announcement.html | 0 .../_includes}/api/en/3x/app-VERB.md | 0 .../_includes}/api/en/3x/app-all.md | 0 .../_includes}/api/en/3x/app-configure.md | 0 .../_includes}/api/en/3x/app-disable.md | 0 .../_includes}/api/en/3x/app-disabled.md | 0 .../_includes}/api/en/3x/app-enable.md | 0 .../_includes}/api/en/3x/app-enabled.md | 0 .../_includes}/api/en/3x/app-engine.md | 0 .../_includes}/api/en/3x/app-get.md | 0 .../_includes}/api/en/3x/app-listen.md | 0 .../_includes}/api/en/3x/app-locals.md | 0 .../_includes}/api/en/3x/app-param.md | 0 .../_includes}/api/en/3x/app-render.md | 0 .../_includes}/api/en/3x/app-routes.md | 0 .../_includes}/api/en/3x/app-set.md | 0 .../_includes}/api/en/3x/app-settings.md | 0 .../_includes}/api/en/3x/app-use.md | 0 .../_includes}/api/en/3x/app.md | 0 .../_includes}/api/en/3x/express.md | 0 .../_includes}/api/en/3x/menu.md | 0 .../_includes}/api/en/3x/middleware.md | 0 .../_includes}/api/en/3x/mw-basicAuth.md | 0 .../_includes}/api/en/3x/mw-bodyParser.md | 0 .../_includes}/api/en/3x/mw-compress.md | 0 .../_includes}/api/en/3x/mw-cookieParser.md | 0 .../_includes}/api/en/3x/mw-cookieSession.md | 0 .../_includes}/api/en/3x/mw-csrf.md | 0 .../_includes}/api/en/3x/mw-directory.md | 0 .../_includes}/api/en/3x/req-accepted.md | 0 .../api/en/3x/req-acceptedCharsets.md | 0 .../api/en/3x/req-acceptedLanguages.md | 0 .../_includes}/api/en/3x/req-accepts.md | 0 .../api/en/3x/req-acceptsCharset.md | 0 .../api/en/3x/req-acceptsLanguage.md | 0 .../_includes}/api/en/3x/req-body.md | 0 .../_includes}/api/en/3x/req-cookies.md | 0 .../_includes}/api/en/3x/req-files.md | 0 .../_includes}/api/en/3x/req-fresh.md | 0 .../_includes}/api/en/3x/req-header.md | 0 .../_includes}/api/en/3x/req-host.md | 0 .../_includes}/api/en/3x/req-ip.md | 0 .../_includes}/api/en/3x/req-ips.md | 0 .../_includes}/api/en/3x/req-is.md | 0 .../_includes}/api/en/3x/req-originalUrl.md | 0 .../_includes}/api/en/3x/req-param.md | 0 .../_includes}/api/en/3x/req-params.md | 0 .../_includes}/api/en/3x/req-path.md | 0 .../_includes}/api/en/3x/req-protocol.md | 0 .../_includes}/api/en/3x/req-query.md | 0 .../_includes}/api/en/3x/req-res.md | 0 .../_includes}/api/en/3x/req-route.md | 0 .../_includes}/api/en/3x/req-secure.md | 0 .../_includes}/api/en/3x/req-signedCookies.md | 0 .../_includes}/api/en/3x/req-stale.md | 0 .../_includes}/api/en/3x/req-subdomains.md | 0 .../_includes}/api/en/3x/req-xhr.md | 0 .../_includes}/api/en/3x/req.md | 0 .../_includes}/api/en/3x/res-attachment.md | 0 .../_includes}/api/en/3x/res-charset.md | 0 .../_includes}/api/en/3x/res-clearCookie.md | 0 .../_includes}/api/en/3x/res-cookie.md | 0 .../_includes}/api/en/3x/res-download.md | 0 .../_includes}/api/en/3x/res-format.md | 0 .../_includes}/api/en/3x/res-get.md | 0 .../_includes}/api/en/3x/res-json.md | 0 .../_includes}/api/en/3x/res-jsonp.md | 0 .../_includes}/api/en/3x/res-links.md | 0 .../_includes}/api/en/3x/res-locals.md | 0 .../_includes}/api/en/3x/res-location.md | 0 .../_includes}/api/en/3x/res-redirect.md | 0 .../_includes}/api/en/3x/res-render.md | 0 .../_includes}/api/en/3x/res-req.md | 0 .../_includes}/api/en/3x/res-send.md | 0 .../_includes}/api/en/3x/res-sendfile.md | 0 .../_includes}/api/en/3x/res-set.md | 0 .../_includes}/api/en/3x/res-status.md | 0 .../_includes}/api/en/3x/res-type.md | 0 .../_includes}/api/en/3x/res.md | 0 .../_includes}/api/en/4x/app-METHOD.md | 0 .../_includes}/api/en/4x/app-all.md | 0 .../_includes}/api/en/4x/app-delete-method.md | 0 .../_includes}/api/en/4x/app-disable.md | 0 .../_includes}/api/en/4x/app-disabled.md | 0 .../_includes}/api/en/4x/app-enable.md | 0 .../_includes}/api/en/4x/app-enabled.md | 0 .../_includes}/api/en/4x/app-engine.md | 0 .../_includes}/api/en/4x/app-get-method.md | 0 .../_includes}/api/en/4x/app-get.md | 0 .../_includes}/api/en/4x/app-listen.md | 0 .../_includes}/api/en/4x/app-locals.md | 0 .../_includes}/api/en/4x/app-mountpath.md | 0 .../_includes}/api/en/4x/app-onmount.md | 0 .../_includes}/api/en/4x/app-param.md | 0 .../_includes}/api/en/4x/app-path.md | 0 .../_includes}/api/en/4x/app-post-method.md | 0 .../_includes}/api/en/4x/app-put-method.md | 0 .../_includes}/api/en/4x/app-render.md | 0 .../_includes}/api/en/4x/app-route.md | 0 .../_includes}/api/en/4x/app-set.md | 0 .../_includes}/api/en/4x/app-settings.md | 0 .../_includes}/api/en/4x/app-use.md | 0 .../_includes}/api/en/4x/app.md | 0 .../_includes}/api/en/4x/express.json.md | 0 .../_includes}/api/en/4x/express.md | 0 .../_includes}/api/en/4x/express.raw.md | 0 .../_includes}/api/en/4x/express.router.md | 0 .../_includes}/api/en/4x/express.static.md | 0 .../_includes}/api/en/4x/express.text.md | 0 .../api/en/4x/express.urlencoded.md | 0 .../_includes}/api/en/4x/menu.md | 0 .../_includes}/api/en/4x/req-accepts.md | 0 .../api/en/4x/req-acceptsCharsets.md | 0 .../api/en/4x/req-acceptsEncodings.md | 0 .../api/en/4x/req-acceptsLanguages.md | 0 .../_includes}/api/en/4x/req-app.md | 0 .../_includes}/api/en/4x/req-baseUrl.md | 0 .../_includes}/api/en/4x/req-body.md | 0 .../_includes}/api/en/4x/req-cookies.md | 0 .../_includes}/api/en/4x/req-fresh.md | 0 .../_includes}/api/en/4x/req-get.md | 0 .../_includes}/api/en/4x/req-hostname.md | 0 .../_includes}/api/en/4x/req-ip.md | 0 .../_includes}/api/en/4x/req-ips.md | 0 .../_includes}/api/en/4x/req-is.md | 0 .../_includes}/api/en/4x/req-method.md | 0 .../_includes}/api/en/4x/req-originalUrl.md | 0 .../_includes}/api/en/4x/req-param.md | 0 .../_includes}/api/en/4x/req-params.md | 0 .../_includes}/api/en/4x/req-path.md | 0 .../_includes}/api/en/4x/req-protocol.md | 0 .../_includes}/api/en/4x/req-query.md | 0 .../_includes}/api/en/4x/req-range.md | 0 .../_includes}/api/en/4x/req-res.md | 0 .../_includes}/api/en/4x/req-route.md | 0 .../_includes}/api/en/4x/req-secure.md | 0 .../_includes}/api/en/4x/req-signedCookies.md | 0 .../_includes}/api/en/4x/req-stale.md | 0 .../_includes}/api/en/4x/req-subdomains.md | 0 .../_includes}/api/en/4x/req-xhr.md | 0 .../_includes}/api/en/4x/req.md | 0 .../_includes}/api/en/4x/res-app.md | 0 .../_includes}/api/en/4x/res-append.md | 0 .../_includes}/api/en/4x/res-attachment.md | 0 .../_includes}/api/en/4x/res-clearCookie.md | 0 .../_includes}/api/en/4x/res-cookie.md | 0 .../_includes}/api/en/4x/res-download.md | 0 .../_includes}/api/en/4x/res-end.md | 0 .../_includes}/api/en/4x/res-format.md | 0 .../_includes}/api/en/4x/res-get.md | 0 .../_includes}/api/en/4x/res-headersSent.md | 0 .../_includes}/api/en/4x/res-json.md | 0 .../_includes}/api/en/4x/res-jsonp.md | 0 .../_includes}/api/en/4x/res-links.md | 0 .../_includes}/api/en/4x/res-locals.md | 0 .../_includes}/api/en/4x/res-location.md | 0 .../_includes}/api/en/4x/res-redirect.md | 0 .../_includes}/api/en/4x/res-render.md | 0 .../_includes}/api/en/4x/res-req.md | 0 .../_includes}/api/en/4x/res-send.md | 0 .../_includes}/api/en/4x/res-sendFile.md | 0 .../_includes}/api/en/4x/res-sendStatus.md | 0 .../_includes}/api/en/4x/res-set.md | 0 .../_includes}/api/en/4x/res-status.md | 0 .../_includes}/api/en/4x/res-type.md | 0 .../_includes}/api/en/4x/res-vary.md | 0 .../_includes}/api/en/4x/res.md | 0 .../_includes}/api/en/4x/router-METHOD.md | 0 .../_includes}/api/en/4x/router-Router.md | 0 .../_includes}/api/en/4x/router-all.md | 0 .../_includes}/api/en/4x/router-param.md | 0 .../_includes}/api/en/4x/router-route.md | 0 .../_includes}/api/en/4x/router-use.md | 0 .../_includes}/api/en/4x/router.md | 0 .../_includes}/api/en/4x/routing-args.html | 0 .../_includes}/api/en/5x/app-METHOD.md | 0 .../_includes}/api/en/5x/app-all.md | 0 .../_includes}/api/en/5x/app-delete-method.md | 0 .../_includes}/api/en/5x/app-disable.md | 0 .../_includes}/api/en/5x/app-disabled.md | 0 .../_includes}/api/en/5x/app-enable.md | 0 .../_includes}/api/en/5x/app-enabled.md | 0 .../_includes}/api/en/5x/app-engine.md | 0 .../_includes}/api/en/5x/app-get-method.md | 0 .../_includes}/api/en/5x/app-get.md | 0 .../_includes}/api/en/5x/app-listen.md | 0 .../_includes}/api/en/5x/app-locals.md | 0 .../_includes}/api/en/5x/app-mountpath.md | 0 .../_includes}/api/en/5x/app-onmount.md | 0 .../_includes}/api/en/5x/app-param.md | 0 .../_includes}/api/en/5x/app-path.md | 0 .../_includes}/api/en/5x/app-post-method.md | 0 .../_includes}/api/en/5x/app-put-method.md | 0 .../_includes}/api/en/5x/app-render.md | 0 .../_includes}/api/en/5x/app-route.md | 0 .../_includes}/api/en/5x/app-router.md | 0 .../_includes}/api/en/5x/app-set.md | 0 .../_includes}/api/en/5x/app-settings.md | 0 .../_includes}/api/en/5x/app-use.md | 0 .../_includes}/api/en/5x/app.md | 0 .../_includes}/api/en/5x/express.json.md | 0 .../_includes}/api/en/5x/express.md | 0 .../_includes}/api/en/5x/express.raw.md | 0 .../_includes}/api/en/5x/express.router.md | 0 .../_includes}/api/en/5x/express.static.md | 0 .../_includes}/api/en/5x/express.text.md | 0 .../api/en/5x/express.urlencoded.md | 0 .../_includes}/api/en/5x/menu.md | 0 .../_includes}/api/en/5x/req-accepts.md | 0 .../api/en/5x/req-acceptsCharsets.md | 0 .../api/en/5x/req-acceptsEncodings.md | 0 .../api/en/5x/req-acceptsLanguages.md | 0 .../_includes}/api/en/5x/req-app.md | 0 .../_includes}/api/en/5x/req-baseUrl.md | 0 .../_includes}/api/en/5x/req-body.md | 0 .../_includes}/api/en/5x/req-cookies.md | 0 .../_includes}/api/en/5x/req-fresh.md | 0 .../_includes}/api/en/5x/req-get.md | 0 .../_includes}/api/en/5x/req-host.md | 0 .../_includes}/api/en/5x/req-hostname.md | 0 .../_includes}/api/en/5x/req-ip.md | 0 .../_includes}/api/en/5x/req-ips.md | 0 .../_includes}/api/en/5x/req-is.md | 0 .../_includes}/api/en/5x/req-method.md | 0 .../_includes}/api/en/5x/req-originalUrl.md | 0 .../_includes}/api/en/5x/req-params.md | 0 .../_includes}/api/en/5x/req-path.md | 0 .../_includes}/api/en/5x/req-protocol.md | 0 .../_includes}/api/en/5x/req-query.md | 0 .../_includes}/api/en/5x/req-range.md | 0 .../_includes}/api/en/5x/req-res.md | 0 .../_includes}/api/en/5x/req-route.md | 0 .../_includes}/api/en/5x/req-secure.md | 0 .../_includes}/api/en/5x/req-signedCookies.md | 0 .../_includes}/api/en/5x/req-stale.md | 0 .../_includes}/api/en/5x/req-subdomains.md | 0 .../_includes}/api/en/5x/req-xhr.md | 0 .../_includes}/api/en/5x/req.md | 0 .../_includes}/api/en/5x/res-app.md | 0 .../_includes}/api/en/5x/res-append.md | 0 .../_includes}/api/en/5x/res-attachment.md | 0 .../_includes}/api/en/5x/res-clearCookie.md | 0 .../_includes}/api/en/5x/res-cookie.md | 0 .../_includes}/api/en/5x/res-download.md | 0 .../_includes}/api/en/5x/res-end.md | 0 .../_includes}/api/en/5x/res-format.md | 0 .../_includes}/api/en/5x/res-get.md | 0 .../_includes}/api/en/5x/res-headersSent.md | 0 .../_includes}/api/en/5x/res-json.md | 0 .../_includes}/api/en/5x/res-jsonp.md | 0 .../_includes}/api/en/5x/res-links.md | 0 .../_includes}/api/en/5x/res-locals.md | 0 .../_includes}/api/en/5x/res-location.md | 0 .../_includes}/api/en/5x/res-redirect.md | 0 .../_includes}/api/en/5x/res-render.md | 0 .../_includes}/api/en/5x/res-req.md | 0 .../_includes}/api/en/5x/res-send.md | 0 .../_includes}/api/en/5x/res-sendFile.md | 0 .../_includes}/api/en/5x/res-sendStatus.md | 0 .../_includes}/api/en/5x/res-set.md | 0 .../_includes}/api/en/5x/res-status.md | 0 .../_includes}/api/en/5x/res-type.md | 0 .../_includes}/api/en/5x/res-vary.md | 0 .../_includes}/api/en/5x/res.md | 0 .../_includes}/api/en/5x/router-METHOD.md | 0 .../_includes}/api/en/5x/router-Router.md | 0 .../_includes}/api/en/5x/router-all.md | 0 .../_includes}/api/en/5x/router-param.md | 0 .../_includes}/api/en/5x/router-route.md | 0 .../_includes}/api/en/5x/router-use.md | 0 .../_includes}/api/en/5x/router.md | 0 .../_includes}/api/en/5x/routing-args.html | 0 .../_includes}/blog/authors.html | 0 .../_includes}/blog/posts-menu.md | 0 .../_includes}/bottom-navigation.html | 0 .../_includes}/changelog/menu.md | 0 .../_includes}/community-caveat.html | 0 .../_includes}/feed-entry.xml | 0 {_includes => legacy/_includes}/footer.html | 0 .../_includes}/github-edit-btn.html | 0 {_includes => legacy/_includes}/head.html | 0 {_includes => legacy/_includes}/header.html | 0 .../_includes}/i18n-notice.html | 0 {_includes => legacy/_includes}/icons/X.svg | 0 .../_includes}/icons/announcement.svg | 0 .../_includes}/icons/arrow.svg | 0 .../_includes}/icons/bluesky.svg | 0 .../_includes}/icons/caution.svg | 0 .../_includes}/icons/express-logo.svg | 0 .../_includes}/icons/github.svg | 0 .../_includes}/icons/hamburger.svg | 0 .../_includes}/icons/i18n.svg | 0 .../_includes}/icons/moon.svg | 0 .../_includes}/icons/note.svg | 0 .../_includes}/icons/opencollective.svg | 0 ...penjs_foundation-logo-horizontal-white.svg | 0 .../_includes}/icons/slack.svg | 0 {_includes => legacy/_includes}/icons/sun.svg | 0 .../_includes}/icons/warning.svg | 0 .../_includes}/icons/youtube.svg | 0 .../_includes}/language-picker.html | 0 {_includes => legacy/_includes}/mw-list.md | 0 .../_includes}/readmes/body-parser.md | 0 .../_includes}/readmes/compression.md | 0 .../_includes}/readmes/connect-rid.md | 0 .../_includes}/readmes/cookie-parser.md | 0 .../_includes}/readmes/cookie-session.md | 0 .../_includes}/readmes/cors.md | 0 .../_includes}/readmes/errorhandler.md | 0 .../readmes/express-master/examples.md | 0 .../_includes}/readmes/method-override.md | 0 .../_includes}/readmes/morgan.md | 0 .../_includes}/readmes/multer.md | 0 .../_includes}/readmes/response-time.md | 0 .../_includes}/readmes/serve-favicon.md | 0 .../_includes}/readmes/serve-index.md | 0 .../_includes}/readmes/serve-static.md | 0 .../_includes}/readmes/session.md | 0 .../_includes}/readmes/timeout.md | 0 .../_includes}/readmes/vhost.md | 0 {_includes => legacy/_includes}/util-list.md | 0 {_layouts => legacy/_layouts}/404.html | 0 {_layouts => legacy/_layouts}/api.html | 0 {_layouts => legacy/_layouts}/feed.xml | 0 {_layouts => legacy/_layouts}/home.html | 0 {_layouts => legacy/_layouts}/middleware.html | 0 {_layouts => legacy/_layouts}/page.html | 0 {_layouts => legacy/_layouts}/post.html | 0 .../_posts}/2024-07-16-welcome-post.md | 0 .../_posts}/2024-09-29-security-releases.md | 0 ...10-01-HeroDevs-partnership-announcement.md | 0 .../_posts}/2024-10-15-v5-release.md | 0 ...22-security-audit-milestone-achievement.md | 0 ...09-rewind-2024-triumphs-and-2025-vision.md | 0 .../_posts}/2025-03-31-v5-1-latest-release.md | 0 ...5-05-16-express-cleanup-legacy-packages.md | 0 .../_posts}/2025-05-19-security-releases.md | 0 ...ulnerability-reporting-process-overhaul.md | 0 .../_posts}/2025-07-18-security-releases.md | 0 .../_posts}/2025-07-31-security-releases.md | 0 .../_posts}/2025-12-01-security-releases.md | 0 crowdin.yml => legacy/crowdin.yml | 0 {css => legacy/css}/langs/de.css | 0 {css => legacy/css}/langs/en.css | 0 {css => legacy/css}/langs/es.css | 0 {css => legacy/css}/langs/fr.css | 0 {css => legacy/css}/langs/it.css | 0 {css => legacy/css}/langs/ja.css | 0 {css => legacy/css}/langs/ko.css | 0 {css => legacy/css}/langs/pt-br.css | 0 {css => legacy/css}/langs/zh-cn.css | 0 {css => legacy/css}/langs/zh-tw.css | 0 {css => legacy/css}/search.css | 0 {css => legacy/css}/sintax.css | 0 {css => legacy/css}/style.css | 0 {css => legacy/css}/themes/dark-theme.css | 0 {css => legacy/css}/variables.css | 0 {de => legacy/de}/3x/api.md | 0 {de => legacy/de}/4x/api.md | 0 {de => legacy/de}/5x/api.md | 0 .../de}/advanced/best-practice-performance.md | 0 .../de}/advanced/best-practice-security.md | 0 .../advanced/developing-template-engines.md | 0 .../advanced/healthcheck-graceful-shutdown.md | 0 .../de}/advanced/security-updates.md | 0 {de => legacy/de}/api.md | 0 {de => legacy/de}/changelog/index.md | 0 {de => legacy/de}/guide/behind-proxies.md | 0 .../de}/guide/database-integration.md | 0 {de => legacy/de}/guide/debugging.md | 0 {de => legacy/de}/guide/error-handling.md | 0 {de => legacy/de}/guide/migrating-4.md | 0 {de => legacy/de}/guide/migrating-5.md | 0 .../de}/guide/overriding-express-api.md | 0 {de => legacy/de}/guide/routing.md | 0 {de => legacy/de}/guide/using-middleware.md | 0 .../de}/guide/using-template-engines.md | 0 {de => legacy/de}/guide/writing-middleware.md | 0 {de => legacy/de}/index.md | 0 {de => legacy/de}/resources/community.md | 0 {de => legacy/de}/resources/contributing.md | 0 {de => legacy/de}/resources/glossary.md | 0 {de => legacy/de}/resources/middleware.md | 0 .../de}/resources/middleware/body-parser.md | 0 .../de}/resources/middleware/compression.md | 0 .../de}/resources/middleware/connect-rid.md | 0 .../de}/resources/middleware/cookie-parser.md | 0 .../resources/middleware/cookie-session.md | 0 .../de}/resources/middleware/cors.md | 0 .../de}/resources/middleware/errorhandler.md | 0 .../resources/middleware/method-override.md | 0 .../de}/resources/middleware/morgan.md | 0 .../de}/resources/middleware/multer.md | 0 .../de}/resources/middleware/response-time.md | 0 .../de}/resources/middleware/serve-favicon.md | 0 .../de}/resources/middleware/serve-index.md | 0 .../de}/resources/middleware/serve-static.md | 0 .../de}/resources/middleware/session.md | 0 .../de}/resources/middleware/timeout.md | 0 .../de}/resources/middleware/vhost.md | 0 {de => legacy/de}/resources/utils.md | 0 {de => legacy/de}/starter/basic-routing.md | 0 {de => legacy/de}/starter/examples.md | 0 {de => legacy/de}/starter/faq.md | 0 {de => legacy/de}/starter/generator.md | 0 {de => legacy/de}/starter/hello-world.md | 0 {de => legacy/de}/starter/installing.md | 0 {de => legacy/de}/starter/static-files.md | 0 {de => legacy/de}/support/index.md | 0 {en => legacy/en}/3x/api.md | 0 {en => legacy/en}/4x/api.md | 0 {en => legacy/en}/5x/api.md | 0 .../en}/advanced/best-practice-performance.md | 0 .../en}/advanced/best-practice-security.md | 0 .../advanced/developing-template-engines.md | 0 .../advanced/healthcheck-graceful-shutdown.md | 0 .../en}/advanced/security-updates.md | 0 {en => legacy/en}/api.md | 0 {en => legacy/en}/blog/posts.md | 0 {en => legacy/en}/blog/write-post.md | 0 {en => legacy/en}/changelog/index.md | 0 {en => legacy/en}/guide/behind-proxies.md | 0 .../en}/guide/database-integration.md | 0 {en => legacy/en}/guide/debugging.md | 0 {en => legacy/en}/guide/error-handling.md | 0 {en => legacy/en}/guide/migrating-4.md | 0 {en => legacy/en}/guide/migrating-5.md | 0 .../en}/guide/overriding-express-api.md | 0 {en => legacy/en}/guide/routing.md | 0 {en => legacy/en}/guide/using-middleware.md | 0 .../en}/guide/using-template-engines.md | 0 {en => legacy/en}/guide/writing-middleware.md | 0 {en => legacy/en}/resources/community.md | 0 {en => legacy/en}/resources/contributing.md | 0 {en => legacy/en}/resources/glossary.md | 0 {en => legacy/en}/resources/middleware.md | 0 .../en}/resources/middleware/body-parser.md | 0 .../en}/resources/middleware/compression.md | 0 .../en}/resources/middleware/connect-rid.md | 0 .../en}/resources/middleware/cookie-parser.md | 0 .../resources/middleware/cookie-session.md | 0 .../en}/resources/middleware/cors.md | 0 .../en}/resources/middleware/errorhandler.md | 0 .../resources/middleware/method-override.md | 0 .../en}/resources/middleware/morgan.md | 0 .../en}/resources/middleware/multer.md | 0 .../en}/resources/middleware/response-time.md | 0 .../en}/resources/middleware/serve-favicon.md | 0 .../en}/resources/middleware/serve-index.md | 0 .../en}/resources/middleware/serve-static.md | 0 .../en}/resources/middleware/session.md | 0 .../en}/resources/middleware/timeout.md | 0 .../en}/resources/middleware/vhost.md | 0 {en => legacy/en}/resources/utils.md | 0 {en => legacy/en}/starter/basic-routing.md | 0 {en => legacy/en}/starter/examples.md | 0 {en => legacy/en}/starter/faq.md | 0 {en => legacy/en}/starter/generator.md | 0 {en => legacy/en}/starter/hello-world.md | 0 {en => legacy/en}/starter/installing.md | 0 {en => legacy/en}/starter/static-files.md | 0 {en => legacy/en}/support/index.md | 0 {es => legacy/es}/3x/api.md | 0 {es => legacy/es}/4x/api.md | 0 {es => legacy/es}/5x/api.md | 0 .../es}/advanced/best-practice-performance.md | 0 .../es}/advanced/best-practice-security.md | 0 .../advanced/developing-template-engines.md | 0 .../advanced/healthcheck-graceful-shutdown.md | 0 .../es}/advanced/security-updates.md | 0 {es => legacy/es}/api.md | 0 {es => legacy/es}/changelog/index.md | 0 {es => legacy/es}/guide/behind-proxies.md | 0 .../es}/guide/database-integration.md | 0 {es => legacy/es}/guide/debugging.md | 0 {es => legacy/es}/guide/error-handling.md | 0 {es => legacy/es}/guide/migrating-4.md | 0 {es => legacy/es}/guide/migrating-5.md | 0 .../es}/guide/overriding-express-api.md | 0 {es => legacy/es}/guide/routing.md | 0 {es => legacy/es}/guide/using-middleware.md | 0 .../es}/guide/using-template-engines.md | 0 {es => legacy/es}/guide/writing-middleware.md | 0 {es => legacy/es}/index.md | 0 {es => legacy/es}/resources/community.md | 0 {es => legacy/es}/resources/contributing.md | 0 {es => legacy/es}/resources/glossary.md | 0 {es => legacy/es}/resources/middleware.md | 0 .../es}/resources/middleware/body-parser.md | 0 .../es}/resources/middleware/compression.md | 0 .../es}/resources/middleware/connect-rid.md | 0 .../es}/resources/middleware/cookie-parser.md | 0 .../resources/middleware/cookie-session.md | 0 .../es}/resources/middleware/cors.md | 0 .../es}/resources/middleware/errorhandler.md | 0 .../resources/middleware/method-override.md | 0 .../es}/resources/middleware/morgan.md | 0 .../es}/resources/middleware/multer.md | 0 .../es}/resources/middleware/response-time.md | 0 .../es}/resources/middleware/serve-favicon.md | 0 .../es}/resources/middleware/serve-index.md | 0 .../es}/resources/middleware/serve-static.md | 0 .../es}/resources/middleware/session.md | 0 .../es}/resources/middleware/timeout.md | 0 .../es}/resources/middleware/vhost.md | 0 {es => legacy/es}/resources/utils.md | 0 {es => legacy/es}/starter/basic-routing.md | 0 {es => legacy/es}/starter/examples.md | 0 {es => legacy/es}/starter/faq.md | 0 {es => legacy/es}/starter/generator.md | 0 {es => legacy/es}/starter/hello-world.md | 0 {es => legacy/es}/starter/installing.md | 0 {es => legacy/es}/starter/static-files.md | 0 {es => legacy/es}/support/index.md | 0 feed.xml => legacy/feed.xml | 0 {fonts => legacy/fonts}/ko/pretendard.css | 0 .../fonts}/ko/woff/Pretendard-Black.woff | Bin .../fonts}/ko/woff/Pretendard-Bold.woff | Bin .../fonts}/ko/woff/Pretendard-ExtraBold.woff | Bin .../fonts}/ko/woff/Pretendard-ExtraLight.woff | Bin .../fonts}/ko/woff/Pretendard-Light.woff | Bin .../fonts}/ko/woff/Pretendard-Medium.woff | Bin .../fonts}/ko/woff/Pretendard-Regular.woff | Bin .../fonts}/ko/woff/Pretendard-SemiBold.woff | Bin .../fonts}/ko/woff/Pretendard-Thin.woff | Bin .../fonts}/ko/woff2/Pretendard-Black.woff2 | Bin .../fonts}/ko/woff2/Pretendard-Bold.woff2 | Bin .../ko/woff2/Pretendard-ExtraBold.woff2 | Bin .../ko/woff2/Pretendard-ExtraLight.woff2 | Bin .../fonts}/ko/woff2/Pretendard-Light.woff2 | Bin .../fonts}/ko/woff2/Pretendard-Medium.woff2 | Bin .../fonts}/ko/woff2/Pretendard-Regular.woff2 | Bin .../fonts}/ko/woff2/Pretendard-SemiBold.woff2 | Bin .../fonts}/ko/woff2/Pretendard-Thin.woff2 | Bin {fonts => legacy/fonts}/open-sans/fonts.css | 0 .../open-sans/woff/OpenSans-Italic.woff | Bin .../fonts}/open-sans/woff/OpenSans.woff | Bin .../woff2/open-sans-latin-wght-italic.woff2 | Bin .../woff2/open-sans-latin-wght-normal.woff2 | Bin {fr => legacy/fr}/3x/api.md | 0 {fr => legacy/fr}/4x/api.md | 0 {fr => legacy/fr}/5x/api.md | 0 .../fr}/advanced/best-practice-performance.md | 0 .../fr}/advanced/best-practice-security.md | 0 .../advanced/developing-template-engines.md | 0 .../advanced/healthcheck-graceful-shutdown.md | 0 .../fr}/advanced/security-updates.md | 0 {fr => legacy/fr}/api.md | 0 {fr => legacy/fr}/changelog/index.md | 0 {fr => legacy/fr}/guide/behind-proxies.md | 0 .../fr}/guide/database-integration.md | 0 {fr => legacy/fr}/guide/debugging.md | 0 {fr => legacy/fr}/guide/error-handling.md | 0 {fr => legacy/fr}/guide/migrating-4.md | 0 {fr => legacy/fr}/guide/migrating-5.md | 0 .../fr}/guide/overriding-express-api.md | 0 {fr => legacy/fr}/guide/routing.md | 0 {fr => legacy/fr}/guide/using-middleware.md | 0 .../fr}/guide/using-template-engines.md | 0 {fr => legacy/fr}/guide/writing-middleware.md | 0 {fr => legacy/fr}/index.md | 0 {fr => legacy/fr}/resources/community.md | 0 {fr => legacy/fr}/resources/contributing.md | 0 {fr => legacy/fr}/resources/glossary.md | 0 {fr => legacy/fr}/resources/middleware.md | 0 .../fr}/resources/middleware/body-parser.md | 0 .../fr}/resources/middleware/compression.md | 0 .../fr}/resources/middleware/connect-rid.md | 0 .../fr}/resources/middleware/cookie-parser.md | 0 .../resources/middleware/cookie-session.md | 0 .../fr}/resources/middleware/cors.md | 0 .../fr}/resources/middleware/errorhandler.md | 0 .../resources/middleware/method-override.md | 0 .../fr}/resources/middleware/morgan.md | 0 .../fr}/resources/middleware/multer.md | 0 .../fr}/resources/middleware/response-time.md | 0 .../fr}/resources/middleware/serve-favicon.md | 0 .../fr}/resources/middleware/serve-index.md | 0 .../fr}/resources/middleware/serve-static.md | 0 .../fr}/resources/middleware/session.md | 0 .../fr}/resources/middleware/timeout.md | 0 .../fr}/resources/middleware/vhost.md | 0 {fr => legacy/fr}/resources/utils.md | 0 {fr => legacy/fr}/starter/basic-routing.md | 0 {fr => legacy/fr}/starter/examples.md | 0 {fr => legacy/fr}/starter/faq.md | 0 {fr => legacy/fr}/starter/generator.md | 0 {fr => legacy/fr}/starter/hello-world.md | 0 {fr => legacy/fr}/starter/installing.md | 0 {fr => legacy/fr}/starter/static-files.md | 0 {fr => legacy/fr}/support/index.md | 0 {images => legacy/images}/blogger.jpg | Bin {images => legacy/images}/brand/logo-dark.svg | 0 .../images}/brand/logo-light.svg | 0 .../images}/brand/logotype-dark.svg | 0 .../images}/brand/logotype-light.svg | 0 {images => legacy/images}/clustering.png | Bin {images => legacy/images}/copy-btn.svg | 0 {images => legacy/images}/express-mw.png | Bin {images => legacy/images}/favicon.ico | Bin {images => legacy/images}/favicon.png | Bin {images => legacy/images}/og.png | Bin index.md => legacy/index.md | 0 {it => legacy/it}/3x/api.md | 0 {it => legacy/it}/4x/api.md | 0 {it => legacy/it}/5x/api.md | 0 .../it}/advanced/best-practice-performance.md | 0 .../it}/advanced/best-practice-security.md | 0 .../advanced/developing-template-engines.md | 0 .../advanced/healthcheck-graceful-shutdown.md | 0 .../it}/advanced/security-updates.md | 0 {it => legacy/it}/api.md | 0 {it => legacy/it}/changelog/index.md | 0 {it => legacy/it}/guide/behind-proxies.md | 0 .../it}/guide/database-integration.md | 0 {it => legacy/it}/guide/debugging.md | 0 {it => legacy/it}/guide/error-handling.md | 0 {it => legacy/it}/guide/migrating-4.md | 0 {it => legacy/it}/guide/migrating-5.md | 0 .../it}/guide/overriding-express-api.md | 0 {it => legacy/it}/guide/routing.md | 0 {it => legacy/it}/guide/using-middleware.md | 0 .../it}/guide/using-template-engines.md | 0 {it => legacy/it}/guide/writing-middleware.md | 0 {it => legacy/it}/index.md | 0 {it => legacy/it}/resources/community.md | 0 {it => legacy/it}/resources/contributing.md | 0 {it => legacy/it}/resources/glossary.md | 0 {it => legacy/it}/resources/middleware.md | 0 .../it}/resources/middleware/body-parser.md | 0 .../it}/resources/middleware/compression.md | 0 .../it}/resources/middleware/connect-rid.md | 0 .../it}/resources/middleware/cookie-parser.md | 0 .../resources/middleware/cookie-session.md | 0 .../it}/resources/middleware/cors.md | 0 .../it}/resources/middleware/errorhandler.md | 0 .../resources/middleware/method-override.md | 0 .../it}/resources/middleware/morgan.md | 0 .../it}/resources/middleware/multer.md | 0 .../it}/resources/middleware/response-time.md | 0 .../it}/resources/middleware/serve-favicon.md | 0 .../it}/resources/middleware/serve-index.md | 0 .../it}/resources/middleware/serve-static.md | 0 .../it}/resources/middleware/session.md | 0 .../it}/resources/middleware/timeout.md | 0 .../it}/resources/middleware/vhost.md | 0 {it => legacy/it}/resources/utils.md | 0 {it => legacy/it}/starter/basic-routing.md | 0 {it => legacy/it}/starter/examples.md | 0 {it => legacy/it}/starter/faq.md | 0 {it => legacy/it}/starter/generator.md | 0 {it => legacy/it}/starter/hello-world.md | 0 {it => legacy/it}/starter/installing.md | 0 {it => legacy/it}/starter/static-files.md | 0 {it => legacy/it}/support/index.md | 0 {ja => legacy/ja}/3x/api.md | 0 {ja => legacy/ja}/4x/api.md | 0 {ja => legacy/ja}/5x/api.md | 0 .../ja}/advanced/best-practice-performance.md | 0 .../ja}/advanced/best-practice-security.md | 0 .../advanced/developing-template-engines.md | 0 .../advanced/healthcheck-graceful-shutdown.md | 0 .../ja}/advanced/security-updates.md | 0 {ja => legacy/ja}/api.md | 0 {ja => legacy/ja}/changelog/index.md | 0 {ja => legacy/ja}/guide/behind-proxies.md | 0 .../ja}/guide/database-integration.md | 0 {ja => legacy/ja}/guide/debugging.md | 0 {ja => legacy/ja}/guide/error-handling.md | 0 {ja => legacy/ja}/guide/migrating-4.md | 0 {ja => legacy/ja}/guide/migrating-5.md | 0 .../ja}/guide/overriding-express-api.md | 0 {ja => legacy/ja}/guide/routing.md | 0 {ja => legacy/ja}/guide/using-middleware.md | 0 .../ja}/guide/using-template-engines.md | 0 {ja => legacy/ja}/guide/writing-middleware.md | 0 {ja => legacy/ja}/index.md | 0 {ja => legacy/ja}/resources/community.md | 0 {ja => legacy/ja}/resources/contributing.md | 0 {ja => legacy/ja}/resources/glossary.md | 0 {ja => legacy/ja}/resources/middleware.md | 0 .../ja}/resources/middleware/body-parser.md | 0 .../ja}/resources/middleware/compression.md | 0 .../ja}/resources/middleware/connect-rid.md | 0 .../ja}/resources/middleware/cookie-parser.md | 0 .../resources/middleware/cookie-session.md | 0 .../ja}/resources/middleware/cors.md | 0 .../ja}/resources/middleware/errorhandler.md | 0 .../resources/middleware/method-override.md | 0 .../ja}/resources/middleware/morgan.md | 0 .../ja}/resources/middleware/multer.md | 0 .../ja}/resources/middleware/response-time.md | 0 .../ja}/resources/middleware/serve-favicon.md | 0 .../ja}/resources/middleware/serve-index.md | 0 .../ja}/resources/middleware/serve-static.md | 0 .../ja}/resources/middleware/session.md | 0 .../ja}/resources/middleware/timeout.md | 0 .../ja}/resources/middleware/vhost.md | 0 {ja => legacy/ja}/resources/utils.md | 0 {ja => legacy/ja}/starter/basic-routing.md | 0 {ja => legacy/ja}/starter/examples.md | 0 {ja => legacy/ja}/starter/faq.md | 0 {ja => legacy/ja}/starter/generator.md | 0 {ja => legacy/ja}/starter/hello-world.md | 0 {ja => legacy/ja}/starter/installing.md | 0 {ja => legacy/ja}/starter/static-files.md | 0 {ja => legacy/ja}/support/index.md | 0 {js => legacy/js}/app.js | 0 {js => legacy/js}/copycode.js | 0 {js => legacy/js}/menu.js | 0 {js => legacy/js}/theme.js | 0 {ko => legacy/ko}/3x/api.md | 0 {ko => legacy/ko}/4x/api.md | 0 {ko => legacy/ko}/5x/api.md | 0 .../ko}/advanced/best-practice-performance.md | 0 .../ko}/advanced/best-practice-security.md | 0 .../advanced/developing-template-engines.md | 0 .../advanced/healthcheck-graceful-shutdown.md | 0 .../ko}/advanced/security-updates.md | 0 {ko => legacy/ko}/api.md | 0 {ko => legacy/ko}/changelog/4x.md | 0 {ko => legacy/ko}/changelog/index.md | 0 {ko => legacy/ko}/guide/behind-proxies.md | 0 .../ko}/guide/database-integration.md | 0 {ko => legacy/ko}/guide/debugging.md | 0 {ko => legacy/ko}/guide/error-handling.md | 0 {ko => legacy/ko}/guide/migrating-4.md | 0 {ko => legacy/ko}/guide/migrating-5.md | 0 .../ko}/guide/overriding-express-api.md | 0 {ko => legacy/ko}/guide/routing.md | 0 {ko => legacy/ko}/guide/using-middleware.md | 0 .../ko}/guide/using-template-engines.md | 0 {ko => legacy/ko}/guide/writing-middleware.md | 0 {ko => legacy/ko}/index.md | 0 {ko => legacy/ko}/resources/community.md | 0 {ko => legacy/ko}/resources/contributing.md | 0 {ko => legacy/ko}/resources/glossary.md | 0 {ko => legacy/ko}/resources/middleware.md | 0 .../ko}/resources/middleware/body-parser.md | 0 .../ko}/resources/middleware/compression.md | 0 .../ko}/resources/middleware/connect-rid.md | 0 .../ko}/resources/middleware/cookie-parser.md | 0 .../resources/middleware/cookie-session.md | 0 .../ko}/resources/middleware/cors.md | 0 .../ko}/resources/middleware/errorhandler.md | 0 .../resources/middleware/method-override.md | 0 .../ko}/resources/middleware/morgan.md | 0 .../ko}/resources/middleware/multer.md | 0 .../ko}/resources/middleware/response-time.md | 0 .../ko}/resources/middleware/serve-favicon.md | 0 .../ko}/resources/middleware/serve-index.md | 0 .../ko}/resources/middleware/serve-static.md | 0 .../ko}/resources/middleware/session.md | 0 .../ko}/resources/middleware/timeout.md | 0 .../ko}/resources/middleware/vhost.md | 0 {ko => legacy/ko}/resources/utils.md | 0 {ko => legacy/ko}/starter/basic-routing.md | 0 {ko => legacy/ko}/starter/examples.md | 0 {ko => legacy/ko}/starter/faq.md | 0 {ko => legacy/ko}/starter/generator.md | 0 {ko => legacy/ko}/starter/hello-world.md | 0 {ko => legacy/ko}/starter/installing.md | 0 {ko => legacy/ko}/starter/static-files.md | 0 {ko => legacy/ko}/support/index.md | 0 package-lock.json => legacy/package-lock.json | 0 package.json => legacy/package.json | 0 {pt-br => legacy/pt-br}/3x/api.md | 0 {pt-br => legacy/pt-br}/4x/api.md | 0 {pt-br => legacy/pt-br}/5x/api.md | 0 .../advanced/best-practice-performance.md | 0 .../pt-br}/advanced/best-practice-security.md | 0 .../advanced/developing-template-engines.md | 0 .../advanced/healthcheck-graceful-shutdown.md | 0 .../pt-br}/advanced/security-updates.md | 0 {pt-br => legacy/pt-br}/api.md | 0 {pt-br => legacy/pt-br}/changelog/index.md | 0 .../pt-br}/guide/behind-proxies.md | 0 .../pt-br}/guide/database-integration.md | 0 {pt-br => legacy/pt-br}/guide/debugging.md | 0 .../pt-br}/guide/error-handling.md | 0 {pt-br => legacy/pt-br}/guide/migrating-4.md | 0 {pt-br => legacy/pt-br}/guide/migrating-5.md | 0 .../pt-br}/guide/overriding-express-api.md | 0 {pt-br => legacy/pt-br}/guide/routing.md | 0 .../pt-br}/guide/using-middleware.md | 0 .../pt-br}/guide/using-template-engines.md | 0 .../pt-br}/guide/writing-middleware.md | 0 {pt-br => legacy/pt-br}/index.md | 0 .../pt-br}/resources/community.md | 0 .../pt-br}/resources/contributing.md | 0 {pt-br => legacy/pt-br}/resources/glossary.md | 0 .../pt-br}/resources/middleware.md | 0 .../resources/middleware/body-parser.md | 0 .../resources/middleware/compression.md | 0 .../resources/middleware/connect-rid.md | 0 .../resources/middleware/cookie-parser.md | 0 .../resources/middleware/cookie-session.md | 0 .../pt-br}/resources/middleware/cors.md | 0 .../resources/middleware/errorhandler.md | 0 .../resources/middleware/method-override.md | 0 .../pt-br}/resources/middleware/morgan.md | 0 .../pt-br}/resources/middleware/multer.md | 0 .../resources/middleware/response-time.md | 0 .../resources/middleware/serve-favicon.md | 0 .../resources/middleware/serve-index.md | 0 .../resources/middleware/serve-static.md | 0 .../pt-br}/resources/middleware/session.md | 0 .../pt-br}/resources/middleware/timeout.md | 0 .../pt-br}/resources/middleware/vhost.md | 0 {pt-br => legacy/pt-br}/resources/utils.md | 0 .../pt-br}/starter/basic-routing.md | 0 {pt-br => legacy/pt-br}/starter/examples.md | 0 {pt-br => legacy/pt-br}/starter/faq.md | 0 {pt-br => legacy/pt-br}/starter/generator.md | 0 .../pt-br}/starter/hello-world.md | 0 {pt-br => legacy/pt-br}/starter/installing.md | 0 .../pt-br}/starter/static-files.md | 0 {pt-br => legacy/pt-br}/support/index.md | 0 sitemap.xml => legacy/sitemap.xml | 0 .../vulnerabilities.xml | 0 {zh-cn => legacy/zh-cn}/3x/api.md | 0 {zh-cn => legacy/zh-cn}/4x/api.md | 0 {zh-cn => legacy/zh-cn}/5x/api.md | 0 .../advanced/best-practice-performance.md | 0 .../zh-cn}/advanced/best-practice-security.md | 0 .../advanced/developing-template-engines.md | 0 .../advanced/healthcheck-graceful-shutdown.md | 0 .../zh-cn}/advanced/security-updates.md | 0 {zh-cn => legacy/zh-cn}/api.md | 0 {zh-cn => legacy/zh-cn}/changelog/index.md | 0 .../zh-cn}/guide/behind-proxies.md | 0 .../zh-cn}/guide/database-integration.md | 0 {zh-cn => legacy/zh-cn}/guide/debugging.md | 0 .../zh-cn}/guide/error-handling.md | 0 {zh-cn => legacy/zh-cn}/guide/migrating-4.md | 0 {zh-cn => legacy/zh-cn}/guide/migrating-5.md | 0 .../zh-cn}/guide/overriding-express-api.md | 0 {zh-cn => legacy/zh-cn}/guide/routing.md | 0 .../zh-cn}/guide/using-middleware.md | 0 .../zh-cn}/guide/using-template-engines.md | 0 .../zh-cn}/guide/writing-middleware.md | 0 {zh-cn => legacy/zh-cn}/index.md | 0 .../zh-cn}/resources/community.md | 0 .../zh-cn}/resources/contributing.md | 0 {zh-cn => legacy/zh-cn}/resources/glossary.md | 0 .../zh-cn}/resources/middleware.md | 0 .../resources/middleware/body-parser.md | 0 .../resources/middleware/compression.md | 0 .../resources/middleware/connect-rid.md | 0 .../resources/middleware/cookie-parser.md | 0 .../resources/middleware/cookie-session.md | 0 .../zh-cn}/resources/middleware/cors.md | 0 .../resources/middleware/errorhandler.md | 0 .../resources/middleware/method-override.md | 0 .../zh-cn}/resources/middleware/morgan.md | 0 .../zh-cn}/resources/middleware/multer.md | 0 .../resources/middleware/response-time.md | 0 .../resources/middleware/serve-favicon.md | 0 .../resources/middleware/serve-index.md | 0 .../resources/middleware/serve-static.md | 0 .../zh-cn}/resources/middleware/session.md | 0 .../zh-cn}/resources/middleware/timeout.md | 0 .../zh-cn}/resources/middleware/vhost.md | 0 {zh-cn => legacy/zh-cn}/resources/utils.md | 0 .../zh-cn}/starter/basic-routing.md | 0 {zh-cn => legacy/zh-cn}/starter/examples.md | 0 {zh-cn => legacy/zh-cn}/starter/faq.md | 0 {zh-cn => legacy/zh-cn}/starter/generator.md | 0 .../zh-cn}/starter/hello-world.md | 0 {zh-cn => legacy/zh-cn}/starter/installing.md | 0 .../zh-cn}/starter/static-files.md | 0 {zh-cn => legacy/zh-cn}/support/index.md | 0 {zh-tw => legacy/zh-tw}/3x/api.md | 0 {zh-tw => legacy/zh-tw}/4x/api.md | 0 {zh-tw => legacy/zh-tw}/5x/api.md | 0 .../advanced/best-practice-performance.md | 0 .../zh-tw}/advanced/best-practice-security.md | 0 .../advanced/developing-template-engines.md | 0 .../advanced/healthcheck-graceful-shutdown.md | 0 .../zh-tw}/advanced/security-updates.md | 0 {zh-tw => legacy/zh-tw}/api.md | 0 {zh-tw => legacy/zh-tw}/changelog/index.md | 0 .../zh-tw}/guide/behind-proxies.md | 0 .../zh-tw}/guide/database-integration.md | 0 {zh-tw => legacy/zh-tw}/guide/debugging.md | 0 .../zh-tw}/guide/error-handling.md | 0 {zh-tw => legacy/zh-tw}/guide/migrating-4.md | 0 {zh-tw => legacy/zh-tw}/guide/migrating-5.md | 0 .../zh-tw}/guide/overriding-express-api.md | 0 {zh-tw => legacy/zh-tw}/guide/routing.md | 0 .../zh-tw}/guide/using-middleware.md | 0 .../zh-tw}/guide/using-template-engines.md | 0 .../zh-tw}/guide/writing-middleware.md | 0 {zh-tw => legacy/zh-tw}/index.md | 0 .../zh-tw}/resources/community.md | 0 .../zh-tw}/resources/contributing.md | 0 {zh-tw => legacy/zh-tw}/resources/glossary.md | 0 .../zh-tw}/resources/middleware.md | 0 .../resources/middleware/body-parser.md | 0 .../resources/middleware/compression.md | 0 .../resources/middleware/connect-rid.md | 0 .../resources/middleware/cookie-parser.md | 0 .../resources/middleware/cookie-session.md | 0 .../zh-tw}/resources/middleware/cors.md | 0 .../resources/middleware/errorhandler.md | 0 .../resources/middleware/method-override.md | 0 .../zh-tw}/resources/middleware/morgan.md | 0 .../zh-tw}/resources/middleware/multer.md | 0 .../resources/middleware/response-time.md | 0 .../resources/middleware/serve-favicon.md | 0 .../resources/middleware/serve-index.md | 0 .../resources/middleware/serve-static.md | 0 .../zh-tw}/resources/middleware/session.md | 0 .../zh-tw}/resources/middleware/timeout.md | 0 .../zh-tw}/resources/middleware/vhost.md | 0 {zh-tw => legacy/zh-tw}/resources/utils.md | 0 .../zh-tw}/starter/basic-routing.md | 0 {zh-tw => legacy/zh-tw}/starter/examples.md | 0 {zh-tw => legacy/zh-tw}/starter/faq.md | 0 {zh-tw => legacy/zh-tw}/starter/generator.md | 0 .../zh-tw}/starter/hello-world.md | 0 {zh-tw => legacy/zh-tw}/starter/installing.md | 0 .../zh-tw}/starter/static-files.md | 0 {zh-tw => legacy/zh-tw}/support/index.md | 0 netlify.toml | 4 + 1123 files changed, 24868 insertions(+), 2 deletions(-) create mode 100644 .editorconfig create mode 100644 .vscode/extensions.json create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 astro/.gitignore create mode 100644 astro/.nvmrc create mode 100644 astro/.prettierignore create mode 100644 astro/.prettierrc create mode 100644 astro/CONTRIBUTING.md create mode 100644 astro/README.md create mode 100644 astro/astro.config.mjs create mode 100644 astro/eslint.config.js create mode 100644 astro/package-lock.json create mode 100644 astro/package.json create mode 100644 astro/postcss.config.mjs create mode 100644 astro/public/apple-touch-icon.png create mode 100644 astro/public/favicon.ico create mode 100644 astro/public/favicon.svg create mode 100644 astro/public/fonts/JetBrainsMono-Light.woff2 create mode 100644 astro/public/fonts/JetBrainsMono-LightItalic.woff2 create mode 100644 astro/public/site.webmanifest create mode 100644 astro/src/components/patterns/Breadcrumbs/Breadcrumbs.astro create mode 100644 astro/src/components/patterns/ThemeSwitcher/ThemeSwitcher.astro create mode 100644 astro/src/components/patterns/index.ts create mode 100644 astro/src/components/primitives/Button/Button.astro create mode 100644 astro/src/components/primitives/Button/Button.css create mode 100644 astro/src/components/primitives/Button/index.ts create mode 100644 astro/src/components/primitives/Button/types.ts create mode 100644 astro/src/components/primitives/Container/Container.astro create mode 100644 astro/src/components/primitives/Container/Container.css create mode 100644 astro/src/components/primitives/Container/index.ts create mode 100644 astro/src/components/primitives/Container/types.ts create mode 100644 astro/src/components/primitives/Grid/Col.astro create mode 100644 astro/src/components/primitives/Grid/Flex.astro create mode 100644 astro/src/components/primitives/Grid/FlexItem.astro create mode 100644 astro/src/components/primitives/Grid/Grid.astro create mode 100644 astro/src/components/primitives/Grid/Grid.css create mode 100644 astro/src/components/primitives/Grid/index.ts create mode 100644 astro/src/components/primitives/Grid/types.ts create mode 100644 astro/src/components/primitives/Typography/Body.astro create mode 100644 astro/src/components/primitives/Typography/BodyMd.astro create mode 100644 astro/src/components/primitives/Typography/BodySm.astro create mode 100644 astro/src/components/primitives/Typography/BodyXs.astro create mode 100644 astro/src/components/primitives/Typography/Code.astro create mode 100644 astro/src/components/primitives/Typography/H1.astro create mode 100644 astro/src/components/primitives/Typography/H2.astro create mode 100644 astro/src/components/primitives/Typography/H3.astro create mode 100644 astro/src/components/primitives/Typography/H4.astro create mode 100644 astro/src/components/primitives/Typography/H5.astro create mode 100644 astro/src/components/primitives/Typography/Typography.astro create mode 100644 astro/src/components/primitives/Typography/Typography.css create mode 100644 astro/src/components/primitives/Typography/index.ts create mode 100644 astro/src/components/primitives/Typography/types.ts create mode 100644 astro/src/components/primitives/index.ts create mode 100644 astro/src/config/menu.ts create mode 100644 astro/src/content.config.ts create mode 100644 astro/src/content/docs/en/advanced/best-practice-performance.md create mode 100644 astro/src/content/docs/en/advanced/best-practice-security.md create mode 100755 astro/src/content/docs/en/advanced/developing-template-engines.md create mode 100644 astro/src/content/docs/en/advanced/healthcheck-graceful-shutdown.md create mode 100755 astro/src/content/docs/en/advanced/security-updates.md create mode 100755 astro/src/content/docs/en/guide/behind-proxies.md create mode 100644 astro/src/content/docs/en/guide/database-integration.md create mode 100755 astro/src/content/docs/en/guide/debugging.md create mode 100755 astro/src/content/docs/en/guide/error-handling.md create mode 100755 astro/src/content/docs/en/guide/migrating-4.md create mode 100755 astro/src/content/docs/en/guide/migrating-5.md create mode 100644 astro/src/content/docs/en/guide/overriding-express-api.md create mode 100755 astro/src/content/docs/en/guide/routing.md create mode 100644 astro/src/content/docs/en/guide/using-middleware.md create mode 100755 astro/src/content/docs/en/guide/using-template-engines.md create mode 100755 astro/src/content/docs/en/guide/writing-middleware.md create mode 100755 astro/src/content/docs/en/resources/community.md create mode 100644 astro/src/content/docs/en/resources/contributing.md create mode 100755 astro/src/content/docs/en/resources/glossary.md create mode 100755 astro/src/content/docs/en/resources/middleware.md create mode 100644 astro/src/content/docs/en/resources/middleware/body-parser.md create mode 100644 astro/src/content/docs/en/resources/middleware/compression.md create mode 100644 astro/src/content/docs/en/resources/middleware/connect-rid.md create mode 100644 astro/src/content/docs/en/resources/middleware/cookie-parser.md create mode 100644 astro/src/content/docs/en/resources/middleware/cookie-session.md create mode 100644 astro/src/content/docs/en/resources/middleware/cors.md create mode 100644 astro/src/content/docs/en/resources/middleware/errorhandler.md create mode 100644 astro/src/content/docs/en/resources/middleware/method-override.md create mode 100644 astro/src/content/docs/en/resources/middleware/morgan.md create mode 100644 astro/src/content/docs/en/resources/middleware/multer.md create mode 100644 astro/src/content/docs/en/resources/middleware/response-time.md create mode 100644 astro/src/content/docs/en/resources/middleware/serve-favicon.md create mode 100644 astro/src/content/docs/en/resources/middleware/serve-index.md create mode 100644 astro/src/content/docs/en/resources/middleware/serve-static.md create mode 100644 astro/src/content/docs/en/resources/middleware/session.md create mode 100644 astro/src/content/docs/en/resources/middleware/timeout.md create mode 100644 astro/src/content/docs/en/resources/middleware/vhost.md create mode 100644 astro/src/content/docs/en/resources/utils.md create mode 100755 astro/src/content/docs/en/starter/basic-routing.md create mode 100755 astro/src/content/docs/en/starter/examples.md create mode 100755 astro/src/content/docs/en/starter/faq.md create mode 100755 astro/src/content/docs/en/starter/generator.md create mode 100755 astro/src/content/docs/en/starter/hello-world.md create mode 100755 astro/src/content/docs/en/starter/installing.md create mode 100755 astro/src/content/docs/en/starter/static-files.md create mode 100644 astro/src/i18n/ui.ts create mode 100644 astro/src/i18n/utils.ts create mode 100644 astro/src/layouts/DocLayout.astro create mode 100644 astro/src/layouts/Layout.astro create mode 100644 astro/src/pages/[lang]/[...slug].astro create mode 100644 astro/src/pages/[lang]/docs/index.astro create mode 100644 astro/src/pages/[lang]/ds-foundations.astro create mode 100644 astro/src/pages/[lang]/index.astro create mode 100644 astro/src/pages/index.astro create mode 100644 astro/src/styles/base/_fonts.css create mode 100644 astro/src/styles/base/_global.css create mode 100644 astro/src/styles/base/_reset.css create mode 100644 astro/src/styles/main.css create mode 100644 astro/src/styles/tokens/_borders.css create mode 100644 astro/src/styles/tokens/_breakpoints.css create mode 100644 astro/src/styles/tokens/_colors.css create mode 100644 astro/src/styles/tokens/_spacing.css create mode 100644 astro/src/styles/tokens/_transitions.css create mode 100644 astro/src/styles/tokens/_typography.css create mode 100644 astro/src/styles/tokens/index.css create mode 100644 astro/src/styles/utilities/_utilities.css create mode 100644 astro/src/utils/content.ts create mode 100644 astro/tsconfig.json create mode 100644 legacy/.github-legacy/CODEOWNERS rename {.github => legacy/.github-legacy}/dependabot.yml (100%) rename {.github => legacy/.github-legacy}/scripts/get-contributing.sh (100%) rename {.github => legacy/.github-legacy}/scripts/get-express-version.mjs (100%) rename {.github => legacy/.github-legacy}/scripts/get-readmes.sh (100%) rename {.github => legacy/.github-legacy}/workflows/ci.yml (100%) create mode 100644 legacy/.github-legacy/workflows/codeql.yml rename {.github => legacy/.github-legacy}/workflows/crowdin.yml (100%) rename {.github => legacy/.github-legacy}/workflows/deploy.yml (100%) rename {.github => legacy/.github-legacy}/workflows/lighthouse.yml (100%) create mode 100644 legacy/.github-legacy/workflows/scorecards.yml rename {.github => legacy/.github-legacy}/workflows/update-external-docs.yml (100%) rename .ruby-version => legacy/.ruby-version (100%) rename {2x => legacy/2x}/applications.md (100%) rename {2x => legacy/2x}/contrib.md (100%) rename {2x => legacy/2x}/docs/applications.md (100%) rename {2x => legacy/2x}/docs/contrib.md (100%) rename {2x => legacy/2x}/docs/executable.md (100%) rename {2x => legacy/2x}/docs/guide.md (100%) rename {2x => legacy/2x}/docs/index.md (100%) rename {2x => legacy/2x}/docs/migrate.md (100%) rename {2x => legacy/2x}/docs/screencasts.md (100%) rename {2x => legacy/2x}/executable.md (100%) rename {2x => legacy/2x}/guide.md (100%) rename {2x => legacy/2x}/index.md (100%) rename {2x => legacy/2x}/migrate.md (100%) rename {2x => legacy/2x}/screencasts.md (100%) rename 404.md => legacy/404.md (100%) rename CNAME => legacy/CNAME (100%) rename CONTRIBUTING.md => legacy/CONTRIBUTING.md (100%) rename Dockerfile => legacy/Dockerfile (100%) rename Gemfile => legacy/Gemfile (100%) rename Gemfile.lock => legacy/Gemfile.lock (100%) rename Makefile => legacy/Makefile (100%) rename README.md => legacy/README.md (100%) rename _config.yml => legacy/_config.yml (100%) rename {_data => legacy/_data}/de/footer.yml (100%) rename {_data => legacy/_data}/de/general.yml (100%) rename {_data => legacy/_data}/de/menu.yml (100%) rename {_data => legacy/_data}/docsearch.yml (100%) rename {_data => legacy/_data}/en/footer.yml (100%) rename {_data => legacy/_data}/en/general.yml (100%) rename {_data => legacy/_data}/en/menu.yml (100%) rename {_data => legacy/_data}/es/footer.yml (100%) rename {_data => legacy/_data}/es/general.yml (100%) rename {_data => legacy/_data}/es/menu.yml (100%) rename {_data => legacy/_data}/express.yml (100%) rename {_data => legacy/_data}/fr/footer.yml (100%) rename {_data => legacy/_data}/fr/general.yml (100%) rename {_data => legacy/_data}/fr/menu.yml (100%) rename {_data => legacy/_data}/it/footer.yml (100%) rename {_data => legacy/_data}/it/general.yml (100%) rename {_data => legacy/_data}/it/menu.yml (100%) rename {_data => legacy/_data}/ja/footer.yml (100%) rename {_data => legacy/_data}/ja/general.yml (100%) rename {_data => legacy/_data}/ja/menu.yml (100%) rename {_data => legacy/_data}/ko/footer.yml (100%) rename {_data => legacy/_data}/ko/general.yml (100%) rename {_data => legacy/_data}/ko/menu.yml (100%) rename {_data => legacy/_data}/languages.yml (100%) rename {_data => legacy/_data}/pt-br/footer.yml (100%) rename {_data => legacy/_data}/pt-br/general.yml (100%) rename {_data => legacy/_data}/pt-br/menu.yml (100%) rename {_data => legacy/_data}/zh-cn/footer.yml (100%) rename {_data => legacy/_data}/zh-cn/general.yml (100%) rename {_data => legacy/_data}/zh-cn/menu.yml (100%) rename {_data => legacy/_data}/zh-tw/footer.yml (100%) rename {_data => legacy/_data}/zh-tw/general.yml (100%) rename {_data => legacy/_data}/zh-tw/menu.yml (100%) rename {_includes => legacy/_includes}/admonitions/caution.html (100%) rename {_includes => legacy/_includes}/admonitions/note.html (100%) rename {_includes => legacy/_includes}/admonitions/warning.html (100%) rename {_includes => legacy/_includes}/announcement.html (100%) rename {_includes => legacy/_includes}/api/en/3x/app-VERB.md (100%) rename {_includes => legacy/_includes}/api/en/3x/app-all.md (100%) rename {_includes => legacy/_includes}/api/en/3x/app-configure.md (100%) rename {_includes => legacy/_includes}/api/en/3x/app-disable.md (100%) rename {_includes => legacy/_includes}/api/en/3x/app-disabled.md (100%) rename {_includes => legacy/_includes}/api/en/3x/app-enable.md (100%) rename {_includes => legacy/_includes}/api/en/3x/app-enabled.md (100%) rename {_includes => legacy/_includes}/api/en/3x/app-engine.md (100%) rename {_includes => legacy/_includes}/api/en/3x/app-get.md (100%) rename {_includes => legacy/_includes}/api/en/3x/app-listen.md (100%) rename {_includes => legacy/_includes}/api/en/3x/app-locals.md (100%) rename {_includes => legacy/_includes}/api/en/3x/app-param.md (100%) rename {_includes => legacy/_includes}/api/en/3x/app-render.md (100%) rename {_includes => legacy/_includes}/api/en/3x/app-routes.md (100%) rename {_includes => legacy/_includes}/api/en/3x/app-set.md (100%) rename {_includes => legacy/_includes}/api/en/3x/app-settings.md (100%) rename {_includes => legacy/_includes}/api/en/3x/app-use.md (100%) rename {_includes => legacy/_includes}/api/en/3x/app.md (100%) rename {_includes => legacy/_includes}/api/en/3x/express.md (100%) rename {_includes => legacy/_includes}/api/en/3x/menu.md (100%) rename {_includes => legacy/_includes}/api/en/3x/middleware.md (100%) rename {_includes => legacy/_includes}/api/en/3x/mw-basicAuth.md (100%) rename {_includes => legacy/_includes}/api/en/3x/mw-bodyParser.md (100%) rename {_includes => legacy/_includes}/api/en/3x/mw-compress.md (100%) rename {_includes => legacy/_includes}/api/en/3x/mw-cookieParser.md (100%) rename {_includes => legacy/_includes}/api/en/3x/mw-cookieSession.md (100%) rename {_includes => legacy/_includes}/api/en/3x/mw-csrf.md (100%) rename {_includes => legacy/_includes}/api/en/3x/mw-directory.md (100%) rename {_includes => legacy/_includes}/api/en/3x/req-accepted.md (100%) rename {_includes => legacy/_includes}/api/en/3x/req-acceptedCharsets.md (100%) rename {_includes => legacy/_includes}/api/en/3x/req-acceptedLanguages.md (100%) rename {_includes => legacy/_includes}/api/en/3x/req-accepts.md (100%) rename {_includes => legacy/_includes}/api/en/3x/req-acceptsCharset.md (100%) rename {_includes => legacy/_includes}/api/en/3x/req-acceptsLanguage.md (100%) rename {_includes => legacy/_includes}/api/en/3x/req-body.md (100%) rename {_includes => legacy/_includes}/api/en/3x/req-cookies.md (100%) rename {_includes => legacy/_includes}/api/en/3x/req-files.md (100%) rename {_includes => legacy/_includes}/api/en/3x/req-fresh.md (100%) rename {_includes => legacy/_includes}/api/en/3x/req-header.md (100%) rename {_includes => legacy/_includes}/api/en/3x/req-host.md (100%) rename {_includes => legacy/_includes}/api/en/3x/req-ip.md (100%) rename {_includes => legacy/_includes}/api/en/3x/req-ips.md (100%) rename {_includes => legacy/_includes}/api/en/3x/req-is.md (100%) rename {_includes => legacy/_includes}/api/en/3x/req-originalUrl.md (100%) rename {_includes => legacy/_includes}/api/en/3x/req-param.md (100%) rename {_includes => legacy/_includes}/api/en/3x/req-params.md (100%) rename {_includes => legacy/_includes}/api/en/3x/req-path.md (100%) rename {_includes => legacy/_includes}/api/en/3x/req-protocol.md (100%) rename {_includes => legacy/_includes}/api/en/3x/req-query.md (100%) rename {_includes => legacy/_includes}/api/en/3x/req-res.md (100%) rename {_includes => legacy/_includes}/api/en/3x/req-route.md (100%) rename {_includes => legacy/_includes}/api/en/3x/req-secure.md (100%) rename {_includes => legacy/_includes}/api/en/3x/req-signedCookies.md (100%) rename {_includes => legacy/_includes}/api/en/3x/req-stale.md (100%) rename {_includes => legacy/_includes}/api/en/3x/req-subdomains.md (100%) rename {_includes => legacy/_includes}/api/en/3x/req-xhr.md (100%) rename {_includes => legacy/_includes}/api/en/3x/req.md (100%) rename {_includes => legacy/_includes}/api/en/3x/res-attachment.md (100%) rename {_includes => legacy/_includes}/api/en/3x/res-charset.md (100%) rename {_includes => legacy/_includes}/api/en/3x/res-clearCookie.md (100%) rename {_includes => legacy/_includes}/api/en/3x/res-cookie.md (100%) rename {_includes => legacy/_includes}/api/en/3x/res-download.md (100%) rename {_includes => legacy/_includes}/api/en/3x/res-format.md (100%) rename {_includes => legacy/_includes}/api/en/3x/res-get.md (100%) rename {_includes => legacy/_includes}/api/en/3x/res-json.md (100%) rename {_includes => legacy/_includes}/api/en/3x/res-jsonp.md (100%) rename {_includes => legacy/_includes}/api/en/3x/res-links.md (100%) rename {_includes => legacy/_includes}/api/en/3x/res-locals.md (100%) rename {_includes => legacy/_includes}/api/en/3x/res-location.md (100%) rename {_includes => legacy/_includes}/api/en/3x/res-redirect.md (100%) rename {_includes => legacy/_includes}/api/en/3x/res-render.md (100%) rename {_includes => legacy/_includes}/api/en/3x/res-req.md (100%) rename {_includes => legacy/_includes}/api/en/3x/res-send.md (100%) rename {_includes => legacy/_includes}/api/en/3x/res-sendfile.md (100%) rename {_includes => legacy/_includes}/api/en/3x/res-set.md (100%) rename {_includes => legacy/_includes}/api/en/3x/res-status.md (100%) rename {_includes => legacy/_includes}/api/en/3x/res-type.md (100%) rename {_includes => legacy/_includes}/api/en/3x/res.md (100%) rename {_includes => legacy/_includes}/api/en/4x/app-METHOD.md (100%) rename {_includes => legacy/_includes}/api/en/4x/app-all.md (100%) rename {_includes => legacy/_includes}/api/en/4x/app-delete-method.md (100%) rename {_includes => legacy/_includes}/api/en/4x/app-disable.md (100%) rename {_includes => legacy/_includes}/api/en/4x/app-disabled.md (100%) rename {_includes => legacy/_includes}/api/en/4x/app-enable.md (100%) rename {_includes => legacy/_includes}/api/en/4x/app-enabled.md (100%) rename {_includes => legacy/_includes}/api/en/4x/app-engine.md (100%) rename {_includes => legacy/_includes}/api/en/4x/app-get-method.md (100%) rename {_includes => legacy/_includes}/api/en/4x/app-get.md (100%) rename {_includes => legacy/_includes}/api/en/4x/app-listen.md (100%) rename {_includes => legacy/_includes}/api/en/4x/app-locals.md (100%) rename {_includes => legacy/_includes}/api/en/4x/app-mountpath.md (100%) rename {_includes => legacy/_includes}/api/en/4x/app-onmount.md (100%) rename {_includes => legacy/_includes}/api/en/4x/app-param.md (100%) rename {_includes => legacy/_includes}/api/en/4x/app-path.md (100%) rename {_includes => legacy/_includes}/api/en/4x/app-post-method.md (100%) rename {_includes => legacy/_includes}/api/en/4x/app-put-method.md (100%) rename {_includes => legacy/_includes}/api/en/4x/app-render.md (100%) rename {_includes => legacy/_includes}/api/en/4x/app-route.md (100%) rename {_includes => legacy/_includes}/api/en/4x/app-set.md (100%) rename {_includes => legacy/_includes}/api/en/4x/app-settings.md (100%) rename {_includes => legacy/_includes}/api/en/4x/app-use.md (100%) rename {_includes => legacy/_includes}/api/en/4x/app.md (100%) rename {_includes => legacy/_includes}/api/en/4x/express.json.md (100%) rename {_includes => legacy/_includes}/api/en/4x/express.md (100%) rename {_includes => legacy/_includes}/api/en/4x/express.raw.md (100%) rename {_includes => legacy/_includes}/api/en/4x/express.router.md (100%) rename {_includes => legacy/_includes}/api/en/4x/express.static.md (100%) rename {_includes => legacy/_includes}/api/en/4x/express.text.md (100%) rename {_includes => legacy/_includes}/api/en/4x/express.urlencoded.md (100%) rename {_includes => legacy/_includes}/api/en/4x/menu.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req-accepts.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req-acceptsCharsets.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req-acceptsEncodings.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req-acceptsLanguages.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req-app.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req-baseUrl.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req-body.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req-cookies.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req-fresh.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req-get.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req-hostname.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req-ip.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req-ips.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req-is.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req-method.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req-originalUrl.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req-param.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req-params.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req-path.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req-protocol.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req-query.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req-range.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req-res.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req-route.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req-secure.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req-signedCookies.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req-stale.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req-subdomains.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req-xhr.md (100%) rename {_includes => legacy/_includes}/api/en/4x/req.md (100%) rename {_includes => legacy/_includes}/api/en/4x/res-app.md (100%) rename {_includes => legacy/_includes}/api/en/4x/res-append.md (100%) rename {_includes => legacy/_includes}/api/en/4x/res-attachment.md (100%) rename {_includes => legacy/_includes}/api/en/4x/res-clearCookie.md (100%) rename {_includes => legacy/_includes}/api/en/4x/res-cookie.md (100%) rename {_includes => legacy/_includes}/api/en/4x/res-download.md (100%) rename {_includes => legacy/_includes}/api/en/4x/res-end.md (100%) rename {_includes => legacy/_includes}/api/en/4x/res-format.md (100%) rename {_includes => legacy/_includes}/api/en/4x/res-get.md (100%) rename {_includes => legacy/_includes}/api/en/4x/res-headersSent.md (100%) rename {_includes => legacy/_includes}/api/en/4x/res-json.md (100%) rename {_includes => legacy/_includes}/api/en/4x/res-jsonp.md (100%) rename {_includes => legacy/_includes}/api/en/4x/res-links.md (100%) rename {_includes => legacy/_includes}/api/en/4x/res-locals.md (100%) rename {_includes => legacy/_includes}/api/en/4x/res-location.md (100%) rename {_includes => legacy/_includes}/api/en/4x/res-redirect.md (100%) rename {_includes => legacy/_includes}/api/en/4x/res-render.md (100%) rename {_includes => legacy/_includes}/api/en/4x/res-req.md (100%) rename {_includes => legacy/_includes}/api/en/4x/res-send.md (100%) rename {_includes => legacy/_includes}/api/en/4x/res-sendFile.md (100%) rename {_includes => legacy/_includes}/api/en/4x/res-sendStatus.md (100%) rename {_includes => legacy/_includes}/api/en/4x/res-set.md (100%) rename {_includes => legacy/_includes}/api/en/4x/res-status.md (100%) rename {_includes => legacy/_includes}/api/en/4x/res-type.md (100%) rename {_includes => legacy/_includes}/api/en/4x/res-vary.md (100%) rename {_includes => legacy/_includes}/api/en/4x/res.md (100%) rename {_includes => legacy/_includes}/api/en/4x/router-METHOD.md (100%) rename {_includes => legacy/_includes}/api/en/4x/router-Router.md (100%) rename {_includes => legacy/_includes}/api/en/4x/router-all.md (100%) rename {_includes => legacy/_includes}/api/en/4x/router-param.md (100%) rename {_includes => legacy/_includes}/api/en/4x/router-route.md (100%) rename {_includes => legacy/_includes}/api/en/4x/router-use.md (100%) rename {_includes => legacy/_includes}/api/en/4x/router.md (100%) rename {_includes => legacy/_includes}/api/en/4x/routing-args.html (100%) rename {_includes => legacy/_includes}/api/en/5x/app-METHOD.md (100%) rename {_includes => legacy/_includes}/api/en/5x/app-all.md (100%) rename {_includes => legacy/_includes}/api/en/5x/app-delete-method.md (100%) rename {_includes => legacy/_includes}/api/en/5x/app-disable.md (100%) rename {_includes => legacy/_includes}/api/en/5x/app-disabled.md (100%) rename {_includes => legacy/_includes}/api/en/5x/app-enable.md (100%) rename {_includes => legacy/_includes}/api/en/5x/app-enabled.md (100%) rename {_includes => legacy/_includes}/api/en/5x/app-engine.md (100%) rename {_includes => legacy/_includes}/api/en/5x/app-get-method.md (100%) rename {_includes => legacy/_includes}/api/en/5x/app-get.md (100%) rename {_includes => legacy/_includes}/api/en/5x/app-listen.md (100%) rename {_includes => legacy/_includes}/api/en/5x/app-locals.md (100%) rename {_includes => legacy/_includes}/api/en/5x/app-mountpath.md (100%) rename {_includes => legacy/_includes}/api/en/5x/app-onmount.md (100%) rename {_includes => legacy/_includes}/api/en/5x/app-param.md (100%) rename {_includes => legacy/_includes}/api/en/5x/app-path.md (100%) rename {_includes => legacy/_includes}/api/en/5x/app-post-method.md (100%) rename {_includes => legacy/_includes}/api/en/5x/app-put-method.md (100%) rename {_includes => legacy/_includes}/api/en/5x/app-render.md (100%) rename {_includes => legacy/_includes}/api/en/5x/app-route.md (100%) rename {_includes => legacy/_includes}/api/en/5x/app-router.md (100%) rename {_includes => legacy/_includes}/api/en/5x/app-set.md (100%) rename {_includes => legacy/_includes}/api/en/5x/app-settings.md (100%) rename {_includes => legacy/_includes}/api/en/5x/app-use.md (100%) rename {_includes => legacy/_includes}/api/en/5x/app.md (100%) rename {_includes => legacy/_includes}/api/en/5x/express.json.md (100%) rename {_includes => legacy/_includes}/api/en/5x/express.md (100%) rename {_includes => legacy/_includes}/api/en/5x/express.raw.md (100%) rename {_includes => legacy/_includes}/api/en/5x/express.router.md (100%) rename {_includes => legacy/_includes}/api/en/5x/express.static.md (100%) rename {_includes => legacy/_includes}/api/en/5x/express.text.md (100%) rename {_includes => legacy/_includes}/api/en/5x/express.urlencoded.md (100%) rename {_includes => legacy/_includes}/api/en/5x/menu.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req-accepts.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req-acceptsCharsets.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req-acceptsEncodings.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req-acceptsLanguages.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req-app.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req-baseUrl.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req-body.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req-cookies.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req-fresh.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req-get.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req-host.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req-hostname.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req-ip.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req-ips.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req-is.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req-method.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req-originalUrl.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req-params.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req-path.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req-protocol.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req-query.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req-range.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req-res.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req-route.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req-secure.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req-signedCookies.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req-stale.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req-subdomains.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req-xhr.md (100%) rename {_includes => legacy/_includes}/api/en/5x/req.md (100%) rename {_includes => legacy/_includes}/api/en/5x/res-app.md (100%) rename {_includes => legacy/_includes}/api/en/5x/res-append.md (100%) rename {_includes => legacy/_includes}/api/en/5x/res-attachment.md (100%) rename {_includes => legacy/_includes}/api/en/5x/res-clearCookie.md (100%) rename {_includes => legacy/_includes}/api/en/5x/res-cookie.md (100%) rename {_includes => legacy/_includes}/api/en/5x/res-download.md (100%) rename {_includes => legacy/_includes}/api/en/5x/res-end.md (100%) rename {_includes => legacy/_includes}/api/en/5x/res-format.md (100%) rename {_includes => legacy/_includes}/api/en/5x/res-get.md (100%) rename {_includes => legacy/_includes}/api/en/5x/res-headersSent.md (100%) rename {_includes => legacy/_includes}/api/en/5x/res-json.md (100%) rename {_includes => legacy/_includes}/api/en/5x/res-jsonp.md (100%) rename {_includes => legacy/_includes}/api/en/5x/res-links.md (100%) rename {_includes => legacy/_includes}/api/en/5x/res-locals.md (100%) rename {_includes => legacy/_includes}/api/en/5x/res-location.md (100%) rename {_includes => legacy/_includes}/api/en/5x/res-redirect.md (100%) rename {_includes => legacy/_includes}/api/en/5x/res-render.md (100%) rename {_includes => legacy/_includes}/api/en/5x/res-req.md (100%) rename {_includes => legacy/_includes}/api/en/5x/res-send.md (100%) rename {_includes => legacy/_includes}/api/en/5x/res-sendFile.md (100%) rename {_includes => legacy/_includes}/api/en/5x/res-sendStatus.md (100%) rename {_includes => legacy/_includes}/api/en/5x/res-set.md (100%) rename {_includes => legacy/_includes}/api/en/5x/res-status.md (100%) rename {_includes => legacy/_includes}/api/en/5x/res-type.md (100%) rename {_includes => legacy/_includes}/api/en/5x/res-vary.md (100%) rename {_includes => legacy/_includes}/api/en/5x/res.md (100%) rename {_includes => legacy/_includes}/api/en/5x/router-METHOD.md (100%) rename {_includes => legacy/_includes}/api/en/5x/router-Router.md (100%) rename {_includes => legacy/_includes}/api/en/5x/router-all.md (100%) rename {_includes => legacy/_includes}/api/en/5x/router-param.md (100%) rename {_includes => legacy/_includes}/api/en/5x/router-route.md (100%) rename {_includes => legacy/_includes}/api/en/5x/router-use.md (100%) rename {_includes => legacy/_includes}/api/en/5x/router.md (100%) rename {_includes => legacy/_includes}/api/en/5x/routing-args.html (100%) rename {_includes => legacy/_includes}/blog/authors.html (100%) rename {_includes => legacy/_includes}/blog/posts-menu.md (100%) rename {_includes => legacy/_includes}/bottom-navigation.html (100%) rename {_includes => legacy/_includes}/changelog/menu.md (100%) rename {_includes => legacy/_includes}/community-caveat.html (100%) rename {_includes => legacy/_includes}/feed-entry.xml (100%) rename {_includes => legacy/_includes}/footer.html (100%) rename {_includes => legacy/_includes}/github-edit-btn.html (100%) rename {_includes => legacy/_includes}/head.html (100%) rename {_includes => legacy/_includes}/header.html (100%) rename {_includes => legacy/_includes}/i18n-notice.html (100%) rename {_includes => legacy/_includes}/icons/X.svg (100%) rename {_includes => legacy/_includes}/icons/announcement.svg (100%) rename {_includes => legacy/_includes}/icons/arrow.svg (100%) rename {_includes => legacy/_includes}/icons/bluesky.svg (100%) rename {_includes => legacy/_includes}/icons/caution.svg (100%) rename {_includes => legacy/_includes}/icons/express-logo.svg (100%) rename {_includes => legacy/_includes}/icons/github.svg (100%) rename {_includes => legacy/_includes}/icons/hamburger.svg (100%) rename {_includes => legacy/_includes}/icons/i18n.svg (100%) rename {_includes => legacy/_includes}/icons/moon.svg (100%) rename {_includes => legacy/_includes}/icons/note.svg (100%) rename {_includes => legacy/_includes}/icons/opencollective.svg (100%) rename {_includes => legacy/_includes}/icons/openjs_foundation-logo-horizontal-white.svg (100%) rename {_includes => legacy/_includes}/icons/slack.svg (100%) rename {_includes => legacy/_includes}/icons/sun.svg (100%) rename {_includes => legacy/_includes}/icons/warning.svg (100%) rename {_includes => legacy/_includes}/icons/youtube.svg (100%) rename {_includes => legacy/_includes}/language-picker.html (100%) rename {_includes => legacy/_includes}/mw-list.md (100%) rename {_includes => legacy/_includes}/readmes/body-parser.md (100%) rename {_includes => legacy/_includes}/readmes/compression.md (100%) rename {_includes => legacy/_includes}/readmes/connect-rid.md (100%) rename {_includes => legacy/_includes}/readmes/cookie-parser.md (100%) rename {_includes => legacy/_includes}/readmes/cookie-session.md (100%) rename {_includes => legacy/_includes}/readmes/cors.md (100%) rename {_includes => legacy/_includes}/readmes/errorhandler.md (100%) rename {_includes => legacy/_includes}/readmes/express-master/examples.md (100%) rename {_includes => legacy/_includes}/readmes/method-override.md (100%) rename {_includes => legacy/_includes}/readmes/morgan.md (100%) rename {_includes => legacy/_includes}/readmes/multer.md (100%) rename {_includes => legacy/_includes}/readmes/response-time.md (100%) rename {_includes => legacy/_includes}/readmes/serve-favicon.md (100%) rename {_includes => legacy/_includes}/readmes/serve-index.md (100%) rename {_includes => legacy/_includes}/readmes/serve-static.md (100%) rename {_includes => legacy/_includes}/readmes/session.md (100%) rename {_includes => legacy/_includes}/readmes/timeout.md (100%) rename {_includes => legacy/_includes}/readmes/vhost.md (100%) rename {_includes => legacy/_includes}/util-list.md (100%) rename {_layouts => legacy/_layouts}/404.html (100%) rename {_layouts => legacy/_layouts}/api.html (100%) rename {_layouts => legacy/_layouts}/feed.xml (100%) rename {_layouts => legacy/_layouts}/home.html (100%) rename {_layouts => legacy/_layouts}/middleware.html (100%) rename {_layouts => legacy/_layouts}/page.html (100%) rename {_layouts => legacy/_layouts}/post.html (100%) rename {_posts => legacy/_posts}/2024-07-16-welcome-post.md (100%) rename {_posts => legacy/_posts}/2024-09-29-security-releases.md (100%) rename {_posts => legacy/_posts}/2024-10-01-HeroDevs-partnership-announcement.md (100%) rename {_posts => legacy/_posts}/2024-10-15-v5-release.md (100%) rename {_posts => legacy/_posts}/2024-10-22-security-audit-milestone-achievement.md (100%) rename {_posts => legacy/_posts}/2025-01-09-rewind-2024-triumphs-and-2025-vision.md (100%) rename {_posts => legacy/_posts}/2025-03-31-v5-1-latest-release.md (100%) rename {_posts => legacy/_posts}/2025-05-16-express-cleanup-legacy-packages.md (100%) rename {_posts => legacy/_posts}/2025-05-19-security-releases.md (100%) rename {_posts => legacy/_posts}/2025-06-05-vulnerability-reporting-process-overhaul.md (100%) rename {_posts => legacy/_posts}/2025-07-18-security-releases.md (100%) rename {_posts => legacy/_posts}/2025-07-31-security-releases.md (100%) rename {_posts => legacy/_posts}/2025-12-01-security-releases.md (100%) rename crowdin.yml => legacy/crowdin.yml (100%) rename {css => legacy/css}/langs/de.css (100%) rename {css => legacy/css}/langs/en.css (100%) rename {css => legacy/css}/langs/es.css (100%) rename {css => legacy/css}/langs/fr.css (100%) rename {css => legacy/css}/langs/it.css (100%) rename {css => legacy/css}/langs/ja.css (100%) rename {css => legacy/css}/langs/ko.css (100%) rename {css => legacy/css}/langs/pt-br.css (100%) rename {css => legacy/css}/langs/zh-cn.css (100%) rename {css => legacy/css}/langs/zh-tw.css (100%) rename {css => legacy/css}/search.css (100%) rename {css => legacy/css}/sintax.css (100%) rename {css => legacy/css}/style.css (100%) rename {css => legacy/css}/themes/dark-theme.css (100%) rename {css => legacy/css}/variables.css (100%) rename {de => legacy/de}/3x/api.md (100%) rename {de => legacy/de}/4x/api.md (100%) rename {de => legacy/de}/5x/api.md (100%) rename {de => legacy/de}/advanced/best-practice-performance.md (100%) rename {de => legacy/de}/advanced/best-practice-security.md (100%) rename {de => legacy/de}/advanced/developing-template-engines.md (100%) rename {de => legacy/de}/advanced/healthcheck-graceful-shutdown.md (100%) rename {de => legacy/de}/advanced/security-updates.md (100%) rename {de => legacy/de}/api.md (100%) rename {de => legacy/de}/changelog/index.md (100%) rename {de => legacy/de}/guide/behind-proxies.md (100%) rename {de => legacy/de}/guide/database-integration.md (100%) rename {de => legacy/de}/guide/debugging.md (100%) rename {de => legacy/de}/guide/error-handling.md (100%) rename {de => legacy/de}/guide/migrating-4.md (100%) rename {de => legacy/de}/guide/migrating-5.md (100%) rename {de => legacy/de}/guide/overriding-express-api.md (100%) rename {de => legacy/de}/guide/routing.md (100%) rename {de => legacy/de}/guide/using-middleware.md (100%) rename {de => legacy/de}/guide/using-template-engines.md (100%) rename {de => legacy/de}/guide/writing-middleware.md (100%) rename {de => legacy/de}/index.md (100%) rename {de => legacy/de}/resources/community.md (100%) rename {de => legacy/de}/resources/contributing.md (100%) rename {de => legacy/de}/resources/glossary.md (100%) rename {de => legacy/de}/resources/middleware.md (100%) rename {de => legacy/de}/resources/middleware/body-parser.md (100%) rename {de => legacy/de}/resources/middleware/compression.md (100%) rename {de => legacy/de}/resources/middleware/connect-rid.md (100%) rename {de => legacy/de}/resources/middleware/cookie-parser.md (100%) rename {de => legacy/de}/resources/middleware/cookie-session.md (100%) rename {de => legacy/de}/resources/middleware/cors.md (100%) rename {de => legacy/de}/resources/middleware/errorhandler.md (100%) rename {de => legacy/de}/resources/middleware/method-override.md (100%) rename {de => legacy/de}/resources/middleware/morgan.md (100%) rename {de => legacy/de}/resources/middleware/multer.md (100%) rename {de => legacy/de}/resources/middleware/response-time.md (100%) rename {de => legacy/de}/resources/middleware/serve-favicon.md (100%) rename {de => legacy/de}/resources/middleware/serve-index.md (100%) rename {de => legacy/de}/resources/middleware/serve-static.md (100%) rename {de => legacy/de}/resources/middleware/session.md (100%) rename {de => legacy/de}/resources/middleware/timeout.md (100%) rename {de => legacy/de}/resources/middleware/vhost.md (100%) rename {de => legacy/de}/resources/utils.md (100%) rename {de => legacy/de}/starter/basic-routing.md (100%) rename {de => legacy/de}/starter/examples.md (100%) rename {de => legacy/de}/starter/faq.md (100%) rename {de => legacy/de}/starter/generator.md (100%) rename {de => legacy/de}/starter/hello-world.md (100%) rename {de => legacy/de}/starter/installing.md (100%) rename {de => legacy/de}/starter/static-files.md (100%) rename {de => legacy/de}/support/index.md (100%) rename {en => legacy/en}/3x/api.md (100%) rename {en => legacy/en}/4x/api.md (100%) rename {en => legacy/en}/5x/api.md (100%) rename {en => legacy/en}/advanced/best-practice-performance.md (100%) rename {en => legacy/en}/advanced/best-practice-security.md (100%) rename {en => legacy/en}/advanced/developing-template-engines.md (100%) rename {en => legacy/en}/advanced/healthcheck-graceful-shutdown.md (100%) rename {en => legacy/en}/advanced/security-updates.md (100%) rename {en => legacy/en}/api.md (100%) rename {en => legacy/en}/blog/posts.md (100%) rename {en => legacy/en}/blog/write-post.md (100%) rename {en => legacy/en}/changelog/index.md (100%) rename {en => legacy/en}/guide/behind-proxies.md (100%) rename {en => legacy/en}/guide/database-integration.md (100%) rename {en => legacy/en}/guide/debugging.md (100%) rename {en => legacy/en}/guide/error-handling.md (100%) rename {en => legacy/en}/guide/migrating-4.md (100%) rename {en => legacy/en}/guide/migrating-5.md (100%) rename {en => legacy/en}/guide/overriding-express-api.md (100%) rename {en => legacy/en}/guide/routing.md (100%) rename {en => legacy/en}/guide/using-middleware.md (100%) rename {en => legacy/en}/guide/using-template-engines.md (100%) rename {en => legacy/en}/guide/writing-middleware.md (100%) rename {en => legacy/en}/resources/community.md (100%) rename {en => legacy/en}/resources/contributing.md (100%) rename {en => legacy/en}/resources/glossary.md (100%) rename {en => legacy/en}/resources/middleware.md (100%) rename {en => legacy/en}/resources/middleware/body-parser.md (100%) rename {en => legacy/en}/resources/middleware/compression.md (100%) rename {en => legacy/en}/resources/middleware/connect-rid.md (100%) rename {en => legacy/en}/resources/middleware/cookie-parser.md (100%) rename {en => legacy/en}/resources/middleware/cookie-session.md (100%) rename {en => legacy/en}/resources/middleware/cors.md (100%) rename {en => legacy/en}/resources/middleware/errorhandler.md (100%) rename {en => legacy/en}/resources/middleware/method-override.md (100%) rename {en => legacy/en}/resources/middleware/morgan.md (100%) rename {en => legacy/en}/resources/middleware/multer.md (100%) rename {en => legacy/en}/resources/middleware/response-time.md (100%) rename {en => legacy/en}/resources/middleware/serve-favicon.md (100%) rename {en => legacy/en}/resources/middleware/serve-index.md (100%) rename {en => legacy/en}/resources/middleware/serve-static.md (100%) rename {en => legacy/en}/resources/middleware/session.md (100%) rename {en => legacy/en}/resources/middleware/timeout.md (100%) rename {en => legacy/en}/resources/middleware/vhost.md (100%) rename {en => legacy/en}/resources/utils.md (100%) rename {en => legacy/en}/starter/basic-routing.md (100%) rename {en => legacy/en}/starter/examples.md (100%) rename {en => legacy/en}/starter/faq.md (100%) rename {en => legacy/en}/starter/generator.md (100%) rename {en => legacy/en}/starter/hello-world.md (100%) rename {en => legacy/en}/starter/installing.md (100%) rename {en => legacy/en}/starter/static-files.md (100%) rename {en => legacy/en}/support/index.md (100%) rename {es => legacy/es}/3x/api.md (100%) rename {es => legacy/es}/4x/api.md (100%) rename {es => legacy/es}/5x/api.md (100%) rename {es => legacy/es}/advanced/best-practice-performance.md (100%) rename {es => legacy/es}/advanced/best-practice-security.md (100%) rename {es => legacy/es}/advanced/developing-template-engines.md (100%) rename {es => legacy/es}/advanced/healthcheck-graceful-shutdown.md (100%) rename {es => legacy/es}/advanced/security-updates.md (100%) rename {es => legacy/es}/api.md (100%) rename {es => legacy/es}/changelog/index.md (100%) rename {es => legacy/es}/guide/behind-proxies.md (100%) rename {es => legacy/es}/guide/database-integration.md (100%) rename {es => legacy/es}/guide/debugging.md (100%) rename {es => legacy/es}/guide/error-handling.md (100%) rename {es => legacy/es}/guide/migrating-4.md (100%) rename {es => legacy/es}/guide/migrating-5.md (100%) rename {es => legacy/es}/guide/overriding-express-api.md (100%) rename {es => legacy/es}/guide/routing.md (100%) rename {es => legacy/es}/guide/using-middleware.md (100%) rename {es => legacy/es}/guide/using-template-engines.md (100%) rename {es => legacy/es}/guide/writing-middleware.md (100%) rename {es => legacy/es}/index.md (100%) rename {es => legacy/es}/resources/community.md (100%) rename {es => legacy/es}/resources/contributing.md (100%) rename {es => legacy/es}/resources/glossary.md (100%) rename {es => legacy/es}/resources/middleware.md (100%) rename {es => legacy/es}/resources/middleware/body-parser.md (100%) rename {es => legacy/es}/resources/middleware/compression.md (100%) rename {es => legacy/es}/resources/middleware/connect-rid.md (100%) rename {es => legacy/es}/resources/middleware/cookie-parser.md (100%) rename {es => legacy/es}/resources/middleware/cookie-session.md (100%) rename {es => legacy/es}/resources/middleware/cors.md (100%) rename {es => legacy/es}/resources/middleware/errorhandler.md (100%) rename {es => legacy/es}/resources/middleware/method-override.md (100%) rename {es => legacy/es}/resources/middleware/morgan.md (100%) rename {es => legacy/es}/resources/middleware/multer.md (100%) rename {es => legacy/es}/resources/middleware/response-time.md (100%) rename {es => legacy/es}/resources/middleware/serve-favicon.md (100%) rename {es => legacy/es}/resources/middleware/serve-index.md (100%) rename {es => legacy/es}/resources/middleware/serve-static.md (100%) rename {es => legacy/es}/resources/middleware/session.md (100%) rename {es => legacy/es}/resources/middleware/timeout.md (100%) rename {es => legacy/es}/resources/middleware/vhost.md (100%) rename {es => legacy/es}/resources/utils.md (100%) rename {es => legacy/es}/starter/basic-routing.md (100%) rename {es => legacy/es}/starter/examples.md (100%) rename {es => legacy/es}/starter/faq.md (100%) rename {es => legacy/es}/starter/generator.md (100%) rename {es => legacy/es}/starter/hello-world.md (100%) rename {es => legacy/es}/starter/installing.md (100%) rename {es => legacy/es}/starter/static-files.md (100%) rename {es => legacy/es}/support/index.md (100%) rename feed.xml => legacy/feed.xml (100%) rename {fonts => legacy/fonts}/ko/pretendard.css (100%) rename {fonts => legacy/fonts}/ko/woff/Pretendard-Black.woff (100%) rename {fonts => legacy/fonts}/ko/woff/Pretendard-Bold.woff (100%) rename {fonts => legacy/fonts}/ko/woff/Pretendard-ExtraBold.woff (100%) rename {fonts => legacy/fonts}/ko/woff/Pretendard-ExtraLight.woff (100%) rename {fonts => legacy/fonts}/ko/woff/Pretendard-Light.woff (100%) rename {fonts => legacy/fonts}/ko/woff/Pretendard-Medium.woff (100%) rename {fonts => legacy/fonts}/ko/woff/Pretendard-Regular.woff (100%) rename {fonts => legacy/fonts}/ko/woff/Pretendard-SemiBold.woff (100%) rename {fonts => legacy/fonts}/ko/woff/Pretendard-Thin.woff (100%) rename {fonts => legacy/fonts}/ko/woff2/Pretendard-Black.woff2 (100%) rename {fonts => legacy/fonts}/ko/woff2/Pretendard-Bold.woff2 (100%) rename {fonts => legacy/fonts}/ko/woff2/Pretendard-ExtraBold.woff2 (100%) rename {fonts => legacy/fonts}/ko/woff2/Pretendard-ExtraLight.woff2 (100%) rename {fonts => legacy/fonts}/ko/woff2/Pretendard-Light.woff2 (100%) rename {fonts => legacy/fonts}/ko/woff2/Pretendard-Medium.woff2 (100%) rename {fonts => legacy/fonts}/ko/woff2/Pretendard-Regular.woff2 (100%) rename {fonts => legacy/fonts}/ko/woff2/Pretendard-SemiBold.woff2 (100%) rename {fonts => legacy/fonts}/ko/woff2/Pretendard-Thin.woff2 (100%) rename {fonts => legacy/fonts}/open-sans/fonts.css (100%) rename {fonts => legacy/fonts}/open-sans/woff/OpenSans-Italic.woff (100%) rename {fonts => legacy/fonts}/open-sans/woff/OpenSans.woff (100%) rename {fonts => legacy/fonts}/open-sans/woff2/open-sans-latin-wght-italic.woff2 (100%) rename {fonts => legacy/fonts}/open-sans/woff2/open-sans-latin-wght-normal.woff2 (100%) rename {fr => legacy/fr}/3x/api.md (100%) rename {fr => legacy/fr}/4x/api.md (100%) rename {fr => legacy/fr}/5x/api.md (100%) rename {fr => legacy/fr}/advanced/best-practice-performance.md (100%) rename {fr => legacy/fr}/advanced/best-practice-security.md (100%) rename {fr => legacy/fr}/advanced/developing-template-engines.md (100%) rename {fr => legacy/fr}/advanced/healthcheck-graceful-shutdown.md (100%) rename {fr => legacy/fr}/advanced/security-updates.md (100%) rename {fr => legacy/fr}/api.md (100%) rename {fr => legacy/fr}/changelog/index.md (100%) rename {fr => legacy/fr}/guide/behind-proxies.md (100%) rename {fr => legacy/fr}/guide/database-integration.md (100%) rename {fr => legacy/fr}/guide/debugging.md (100%) rename {fr => legacy/fr}/guide/error-handling.md (100%) rename {fr => legacy/fr}/guide/migrating-4.md (100%) rename {fr => legacy/fr}/guide/migrating-5.md (100%) rename {fr => legacy/fr}/guide/overriding-express-api.md (100%) rename {fr => legacy/fr}/guide/routing.md (100%) rename {fr => legacy/fr}/guide/using-middleware.md (100%) rename {fr => legacy/fr}/guide/using-template-engines.md (100%) rename {fr => legacy/fr}/guide/writing-middleware.md (100%) rename {fr => legacy/fr}/index.md (100%) rename {fr => legacy/fr}/resources/community.md (100%) rename {fr => legacy/fr}/resources/contributing.md (100%) rename {fr => legacy/fr}/resources/glossary.md (100%) rename {fr => legacy/fr}/resources/middleware.md (100%) rename {fr => legacy/fr}/resources/middleware/body-parser.md (100%) rename {fr => legacy/fr}/resources/middleware/compression.md (100%) rename {fr => legacy/fr}/resources/middleware/connect-rid.md (100%) rename {fr => legacy/fr}/resources/middleware/cookie-parser.md (100%) rename {fr => legacy/fr}/resources/middleware/cookie-session.md (100%) rename {fr => legacy/fr}/resources/middleware/cors.md (100%) rename {fr => legacy/fr}/resources/middleware/errorhandler.md (100%) rename {fr => legacy/fr}/resources/middleware/method-override.md (100%) rename {fr => legacy/fr}/resources/middleware/morgan.md (100%) rename {fr => legacy/fr}/resources/middleware/multer.md (100%) rename {fr => legacy/fr}/resources/middleware/response-time.md (100%) rename {fr => legacy/fr}/resources/middleware/serve-favicon.md (100%) rename {fr => legacy/fr}/resources/middleware/serve-index.md (100%) rename {fr => legacy/fr}/resources/middleware/serve-static.md (100%) rename {fr => legacy/fr}/resources/middleware/session.md (100%) rename {fr => legacy/fr}/resources/middleware/timeout.md (100%) rename {fr => legacy/fr}/resources/middleware/vhost.md (100%) rename {fr => legacy/fr}/resources/utils.md (100%) rename {fr => legacy/fr}/starter/basic-routing.md (100%) rename {fr => legacy/fr}/starter/examples.md (100%) rename {fr => legacy/fr}/starter/faq.md (100%) rename {fr => legacy/fr}/starter/generator.md (100%) rename {fr => legacy/fr}/starter/hello-world.md (100%) rename {fr => legacy/fr}/starter/installing.md (100%) rename {fr => legacy/fr}/starter/static-files.md (100%) rename {fr => legacy/fr}/support/index.md (100%) rename {images => legacy/images}/blogger.jpg (100%) rename {images => legacy/images}/brand/logo-dark.svg (100%) rename {images => legacy/images}/brand/logo-light.svg (100%) rename {images => legacy/images}/brand/logotype-dark.svg (100%) rename {images => legacy/images}/brand/logotype-light.svg (100%) rename {images => legacy/images}/clustering.png (100%) rename {images => legacy/images}/copy-btn.svg (100%) rename {images => legacy/images}/express-mw.png (100%) rename {images => legacy/images}/favicon.ico (100%) rename {images => legacy/images}/favicon.png (100%) rename {images => legacy/images}/og.png (100%) rename index.md => legacy/index.md (100%) rename {it => legacy/it}/3x/api.md (100%) rename {it => legacy/it}/4x/api.md (100%) rename {it => legacy/it}/5x/api.md (100%) rename {it => legacy/it}/advanced/best-practice-performance.md (100%) rename {it => legacy/it}/advanced/best-practice-security.md (100%) rename {it => legacy/it}/advanced/developing-template-engines.md (100%) rename {it => legacy/it}/advanced/healthcheck-graceful-shutdown.md (100%) rename {it => legacy/it}/advanced/security-updates.md (100%) rename {it => legacy/it}/api.md (100%) rename {it => legacy/it}/changelog/index.md (100%) rename {it => legacy/it}/guide/behind-proxies.md (100%) rename {it => legacy/it}/guide/database-integration.md (100%) rename {it => legacy/it}/guide/debugging.md (100%) rename {it => legacy/it}/guide/error-handling.md (100%) rename {it => legacy/it}/guide/migrating-4.md (100%) rename {it => legacy/it}/guide/migrating-5.md (100%) rename {it => legacy/it}/guide/overriding-express-api.md (100%) rename {it => legacy/it}/guide/routing.md (100%) rename {it => legacy/it}/guide/using-middleware.md (100%) rename {it => legacy/it}/guide/using-template-engines.md (100%) rename {it => legacy/it}/guide/writing-middleware.md (100%) rename {it => legacy/it}/index.md (100%) rename {it => legacy/it}/resources/community.md (100%) rename {it => legacy/it}/resources/contributing.md (100%) rename {it => legacy/it}/resources/glossary.md (100%) rename {it => legacy/it}/resources/middleware.md (100%) rename {it => legacy/it}/resources/middleware/body-parser.md (100%) rename {it => legacy/it}/resources/middleware/compression.md (100%) rename {it => legacy/it}/resources/middleware/connect-rid.md (100%) rename {it => legacy/it}/resources/middleware/cookie-parser.md (100%) rename {it => legacy/it}/resources/middleware/cookie-session.md (100%) rename {it => legacy/it}/resources/middleware/cors.md (100%) rename {it => legacy/it}/resources/middleware/errorhandler.md (100%) rename {it => legacy/it}/resources/middleware/method-override.md (100%) rename {it => legacy/it}/resources/middleware/morgan.md (100%) rename {it => legacy/it}/resources/middleware/multer.md (100%) rename {it => legacy/it}/resources/middleware/response-time.md (100%) rename {it => legacy/it}/resources/middleware/serve-favicon.md (100%) rename {it => legacy/it}/resources/middleware/serve-index.md (100%) rename {it => legacy/it}/resources/middleware/serve-static.md (100%) rename {it => legacy/it}/resources/middleware/session.md (100%) rename {it => legacy/it}/resources/middleware/timeout.md (100%) rename {it => legacy/it}/resources/middleware/vhost.md (100%) rename {it => legacy/it}/resources/utils.md (100%) rename {it => legacy/it}/starter/basic-routing.md (100%) rename {it => legacy/it}/starter/examples.md (100%) rename {it => legacy/it}/starter/faq.md (100%) rename {it => legacy/it}/starter/generator.md (100%) rename {it => legacy/it}/starter/hello-world.md (100%) rename {it => legacy/it}/starter/installing.md (100%) rename {it => legacy/it}/starter/static-files.md (100%) rename {it => legacy/it}/support/index.md (100%) rename {ja => legacy/ja}/3x/api.md (100%) rename {ja => legacy/ja}/4x/api.md (100%) rename {ja => legacy/ja}/5x/api.md (100%) rename {ja => legacy/ja}/advanced/best-practice-performance.md (100%) rename {ja => legacy/ja}/advanced/best-practice-security.md (100%) rename {ja => legacy/ja}/advanced/developing-template-engines.md (100%) rename {ja => legacy/ja}/advanced/healthcheck-graceful-shutdown.md (100%) rename {ja => legacy/ja}/advanced/security-updates.md (100%) rename {ja => legacy/ja}/api.md (100%) rename {ja => legacy/ja}/changelog/index.md (100%) rename {ja => legacy/ja}/guide/behind-proxies.md (100%) rename {ja => legacy/ja}/guide/database-integration.md (100%) rename {ja => legacy/ja}/guide/debugging.md (100%) rename {ja => legacy/ja}/guide/error-handling.md (100%) rename {ja => legacy/ja}/guide/migrating-4.md (100%) rename {ja => legacy/ja}/guide/migrating-5.md (100%) rename {ja => legacy/ja}/guide/overriding-express-api.md (100%) rename {ja => legacy/ja}/guide/routing.md (100%) rename {ja => legacy/ja}/guide/using-middleware.md (100%) rename {ja => legacy/ja}/guide/using-template-engines.md (100%) rename {ja => legacy/ja}/guide/writing-middleware.md (100%) rename {ja => legacy/ja}/index.md (100%) rename {ja => legacy/ja}/resources/community.md (100%) rename {ja => legacy/ja}/resources/contributing.md (100%) rename {ja => legacy/ja}/resources/glossary.md (100%) rename {ja => legacy/ja}/resources/middleware.md (100%) rename {ja => legacy/ja}/resources/middleware/body-parser.md (100%) rename {ja => legacy/ja}/resources/middleware/compression.md (100%) rename {ja => legacy/ja}/resources/middleware/connect-rid.md (100%) rename {ja => legacy/ja}/resources/middleware/cookie-parser.md (100%) rename {ja => legacy/ja}/resources/middleware/cookie-session.md (100%) rename {ja => legacy/ja}/resources/middleware/cors.md (100%) rename {ja => legacy/ja}/resources/middleware/errorhandler.md (100%) rename {ja => legacy/ja}/resources/middleware/method-override.md (100%) rename {ja => legacy/ja}/resources/middleware/morgan.md (100%) rename {ja => legacy/ja}/resources/middleware/multer.md (100%) rename {ja => legacy/ja}/resources/middleware/response-time.md (100%) rename {ja => legacy/ja}/resources/middleware/serve-favicon.md (100%) rename {ja => legacy/ja}/resources/middleware/serve-index.md (100%) rename {ja => legacy/ja}/resources/middleware/serve-static.md (100%) rename {ja => legacy/ja}/resources/middleware/session.md (100%) rename {ja => legacy/ja}/resources/middleware/timeout.md (100%) rename {ja => legacy/ja}/resources/middleware/vhost.md (100%) rename {ja => legacy/ja}/resources/utils.md (100%) rename {ja => legacy/ja}/starter/basic-routing.md (100%) rename {ja => legacy/ja}/starter/examples.md (100%) rename {ja => legacy/ja}/starter/faq.md (100%) rename {ja => legacy/ja}/starter/generator.md (100%) rename {ja => legacy/ja}/starter/hello-world.md (100%) rename {ja => legacy/ja}/starter/installing.md (100%) rename {ja => legacy/ja}/starter/static-files.md (100%) rename {ja => legacy/ja}/support/index.md (100%) rename {js => legacy/js}/app.js (100%) rename {js => legacy/js}/copycode.js (100%) rename {js => legacy/js}/menu.js (100%) rename {js => legacy/js}/theme.js (100%) rename {ko => legacy/ko}/3x/api.md (100%) rename {ko => legacy/ko}/4x/api.md (100%) rename {ko => legacy/ko}/5x/api.md (100%) rename {ko => legacy/ko}/advanced/best-practice-performance.md (100%) rename {ko => legacy/ko}/advanced/best-practice-security.md (100%) rename {ko => legacy/ko}/advanced/developing-template-engines.md (100%) rename {ko => legacy/ko}/advanced/healthcheck-graceful-shutdown.md (100%) rename {ko => legacy/ko}/advanced/security-updates.md (100%) rename {ko => legacy/ko}/api.md (100%) rename {ko => legacy/ko}/changelog/4x.md (100%) rename {ko => legacy/ko}/changelog/index.md (100%) rename {ko => legacy/ko}/guide/behind-proxies.md (100%) rename {ko => legacy/ko}/guide/database-integration.md (100%) rename {ko => legacy/ko}/guide/debugging.md (100%) rename {ko => legacy/ko}/guide/error-handling.md (100%) rename {ko => legacy/ko}/guide/migrating-4.md (100%) rename {ko => legacy/ko}/guide/migrating-5.md (100%) rename {ko => legacy/ko}/guide/overriding-express-api.md (100%) rename {ko => legacy/ko}/guide/routing.md (100%) rename {ko => legacy/ko}/guide/using-middleware.md (100%) rename {ko => legacy/ko}/guide/using-template-engines.md (100%) rename {ko => legacy/ko}/guide/writing-middleware.md (100%) rename {ko => legacy/ko}/index.md (100%) rename {ko => legacy/ko}/resources/community.md (100%) rename {ko => legacy/ko}/resources/contributing.md (100%) rename {ko => legacy/ko}/resources/glossary.md (100%) rename {ko => legacy/ko}/resources/middleware.md (100%) rename {ko => legacy/ko}/resources/middleware/body-parser.md (100%) rename {ko => legacy/ko}/resources/middleware/compression.md (100%) rename {ko => legacy/ko}/resources/middleware/connect-rid.md (100%) rename {ko => legacy/ko}/resources/middleware/cookie-parser.md (100%) rename {ko => legacy/ko}/resources/middleware/cookie-session.md (100%) rename {ko => legacy/ko}/resources/middleware/cors.md (100%) rename {ko => legacy/ko}/resources/middleware/errorhandler.md (100%) rename {ko => legacy/ko}/resources/middleware/method-override.md (100%) rename {ko => legacy/ko}/resources/middleware/morgan.md (100%) rename {ko => legacy/ko}/resources/middleware/multer.md (100%) rename {ko => legacy/ko}/resources/middleware/response-time.md (100%) rename {ko => legacy/ko}/resources/middleware/serve-favicon.md (100%) rename {ko => legacy/ko}/resources/middleware/serve-index.md (100%) rename {ko => legacy/ko}/resources/middleware/serve-static.md (100%) rename {ko => legacy/ko}/resources/middleware/session.md (100%) rename {ko => legacy/ko}/resources/middleware/timeout.md (100%) rename {ko => legacy/ko}/resources/middleware/vhost.md (100%) rename {ko => legacy/ko}/resources/utils.md (100%) rename {ko => legacy/ko}/starter/basic-routing.md (100%) rename {ko => legacy/ko}/starter/examples.md (100%) rename {ko => legacy/ko}/starter/faq.md (100%) rename {ko => legacy/ko}/starter/generator.md (100%) rename {ko => legacy/ko}/starter/hello-world.md (100%) rename {ko => legacy/ko}/starter/installing.md (100%) rename {ko => legacy/ko}/starter/static-files.md (100%) rename {ko => legacy/ko}/support/index.md (100%) rename package-lock.json => legacy/package-lock.json (100%) rename package.json => legacy/package.json (100%) rename {pt-br => legacy/pt-br}/3x/api.md (100%) rename {pt-br => legacy/pt-br}/4x/api.md (100%) rename {pt-br => legacy/pt-br}/5x/api.md (100%) rename {pt-br => legacy/pt-br}/advanced/best-practice-performance.md (100%) rename {pt-br => legacy/pt-br}/advanced/best-practice-security.md (100%) rename {pt-br => legacy/pt-br}/advanced/developing-template-engines.md (100%) rename {pt-br => legacy/pt-br}/advanced/healthcheck-graceful-shutdown.md (100%) rename {pt-br => legacy/pt-br}/advanced/security-updates.md (100%) rename {pt-br => legacy/pt-br}/api.md (100%) rename {pt-br => legacy/pt-br}/changelog/index.md (100%) rename {pt-br => legacy/pt-br}/guide/behind-proxies.md (100%) rename {pt-br => legacy/pt-br}/guide/database-integration.md (100%) rename {pt-br => legacy/pt-br}/guide/debugging.md (100%) rename {pt-br => legacy/pt-br}/guide/error-handling.md (100%) rename {pt-br => legacy/pt-br}/guide/migrating-4.md (100%) rename {pt-br => legacy/pt-br}/guide/migrating-5.md (100%) rename {pt-br => legacy/pt-br}/guide/overriding-express-api.md (100%) rename {pt-br => legacy/pt-br}/guide/routing.md (100%) rename {pt-br => legacy/pt-br}/guide/using-middleware.md (100%) rename {pt-br => legacy/pt-br}/guide/using-template-engines.md (100%) rename {pt-br => legacy/pt-br}/guide/writing-middleware.md (100%) rename {pt-br => legacy/pt-br}/index.md (100%) rename {pt-br => legacy/pt-br}/resources/community.md (100%) rename {pt-br => legacy/pt-br}/resources/contributing.md (100%) rename {pt-br => legacy/pt-br}/resources/glossary.md (100%) rename {pt-br => legacy/pt-br}/resources/middleware.md (100%) rename {pt-br => legacy/pt-br}/resources/middleware/body-parser.md (100%) rename {pt-br => legacy/pt-br}/resources/middleware/compression.md (100%) rename {pt-br => legacy/pt-br}/resources/middleware/connect-rid.md (100%) rename {pt-br => legacy/pt-br}/resources/middleware/cookie-parser.md (100%) rename {pt-br => legacy/pt-br}/resources/middleware/cookie-session.md (100%) rename {pt-br => legacy/pt-br}/resources/middleware/cors.md (100%) rename {pt-br => legacy/pt-br}/resources/middleware/errorhandler.md (100%) rename {pt-br => legacy/pt-br}/resources/middleware/method-override.md (100%) rename {pt-br => legacy/pt-br}/resources/middleware/morgan.md (100%) rename {pt-br => legacy/pt-br}/resources/middleware/multer.md (100%) rename {pt-br => legacy/pt-br}/resources/middleware/response-time.md (100%) rename {pt-br => legacy/pt-br}/resources/middleware/serve-favicon.md (100%) rename {pt-br => legacy/pt-br}/resources/middleware/serve-index.md (100%) rename {pt-br => legacy/pt-br}/resources/middleware/serve-static.md (100%) rename {pt-br => legacy/pt-br}/resources/middleware/session.md (100%) rename {pt-br => legacy/pt-br}/resources/middleware/timeout.md (100%) rename {pt-br => legacy/pt-br}/resources/middleware/vhost.md (100%) rename {pt-br => legacy/pt-br}/resources/utils.md (100%) rename {pt-br => legacy/pt-br}/starter/basic-routing.md (100%) rename {pt-br => legacy/pt-br}/starter/examples.md (100%) rename {pt-br => legacy/pt-br}/starter/faq.md (100%) rename {pt-br => legacy/pt-br}/starter/generator.md (100%) rename {pt-br => legacy/pt-br}/starter/hello-world.md (100%) rename {pt-br => legacy/pt-br}/starter/installing.md (100%) rename {pt-br => legacy/pt-br}/starter/static-files.md (100%) rename {pt-br => legacy/pt-br}/support/index.md (100%) rename sitemap.xml => legacy/sitemap.xml (100%) rename vulnerabilities.xml => legacy/vulnerabilities.xml (100%) rename {zh-cn => legacy/zh-cn}/3x/api.md (100%) rename {zh-cn => legacy/zh-cn}/4x/api.md (100%) rename {zh-cn => legacy/zh-cn}/5x/api.md (100%) rename {zh-cn => legacy/zh-cn}/advanced/best-practice-performance.md (100%) rename {zh-cn => legacy/zh-cn}/advanced/best-practice-security.md (100%) rename {zh-cn => legacy/zh-cn}/advanced/developing-template-engines.md (100%) rename {zh-cn => legacy/zh-cn}/advanced/healthcheck-graceful-shutdown.md (100%) rename {zh-cn => legacy/zh-cn}/advanced/security-updates.md (100%) rename {zh-cn => legacy/zh-cn}/api.md (100%) rename {zh-cn => legacy/zh-cn}/changelog/index.md (100%) rename {zh-cn => legacy/zh-cn}/guide/behind-proxies.md (100%) rename {zh-cn => legacy/zh-cn}/guide/database-integration.md (100%) rename {zh-cn => legacy/zh-cn}/guide/debugging.md (100%) rename {zh-cn => legacy/zh-cn}/guide/error-handling.md (100%) rename {zh-cn => legacy/zh-cn}/guide/migrating-4.md (100%) rename {zh-cn => legacy/zh-cn}/guide/migrating-5.md (100%) rename {zh-cn => legacy/zh-cn}/guide/overriding-express-api.md (100%) rename {zh-cn => legacy/zh-cn}/guide/routing.md (100%) rename {zh-cn => legacy/zh-cn}/guide/using-middleware.md (100%) rename {zh-cn => legacy/zh-cn}/guide/using-template-engines.md (100%) rename {zh-cn => legacy/zh-cn}/guide/writing-middleware.md (100%) rename {zh-cn => legacy/zh-cn}/index.md (100%) rename {zh-cn => legacy/zh-cn}/resources/community.md (100%) rename {zh-cn => legacy/zh-cn}/resources/contributing.md (100%) rename {zh-cn => legacy/zh-cn}/resources/glossary.md (100%) rename {zh-cn => legacy/zh-cn}/resources/middleware.md (100%) rename {zh-cn => legacy/zh-cn}/resources/middleware/body-parser.md (100%) rename {zh-cn => legacy/zh-cn}/resources/middleware/compression.md (100%) rename {zh-cn => legacy/zh-cn}/resources/middleware/connect-rid.md (100%) rename {zh-cn => legacy/zh-cn}/resources/middleware/cookie-parser.md (100%) rename {zh-cn => legacy/zh-cn}/resources/middleware/cookie-session.md (100%) rename {zh-cn => legacy/zh-cn}/resources/middleware/cors.md (100%) rename {zh-cn => legacy/zh-cn}/resources/middleware/errorhandler.md (100%) rename {zh-cn => legacy/zh-cn}/resources/middleware/method-override.md (100%) rename {zh-cn => legacy/zh-cn}/resources/middleware/morgan.md (100%) rename {zh-cn => legacy/zh-cn}/resources/middleware/multer.md (100%) rename {zh-cn => legacy/zh-cn}/resources/middleware/response-time.md (100%) rename {zh-cn => legacy/zh-cn}/resources/middleware/serve-favicon.md (100%) rename {zh-cn => legacy/zh-cn}/resources/middleware/serve-index.md (100%) rename {zh-cn => legacy/zh-cn}/resources/middleware/serve-static.md (100%) rename {zh-cn => legacy/zh-cn}/resources/middleware/session.md (100%) rename {zh-cn => legacy/zh-cn}/resources/middleware/timeout.md (100%) rename {zh-cn => legacy/zh-cn}/resources/middleware/vhost.md (100%) rename {zh-cn => legacy/zh-cn}/resources/utils.md (100%) rename {zh-cn => legacy/zh-cn}/starter/basic-routing.md (100%) rename {zh-cn => legacy/zh-cn}/starter/examples.md (100%) rename {zh-cn => legacy/zh-cn}/starter/faq.md (100%) rename {zh-cn => legacy/zh-cn}/starter/generator.md (100%) rename {zh-cn => legacy/zh-cn}/starter/hello-world.md (100%) rename {zh-cn => legacy/zh-cn}/starter/installing.md (100%) rename {zh-cn => legacy/zh-cn}/starter/static-files.md (100%) rename {zh-cn => legacy/zh-cn}/support/index.md (100%) rename {zh-tw => legacy/zh-tw}/3x/api.md (100%) rename {zh-tw => legacy/zh-tw}/4x/api.md (100%) rename {zh-tw => legacy/zh-tw}/5x/api.md (100%) rename {zh-tw => legacy/zh-tw}/advanced/best-practice-performance.md (100%) rename {zh-tw => legacy/zh-tw}/advanced/best-practice-security.md (100%) rename {zh-tw => legacy/zh-tw}/advanced/developing-template-engines.md (100%) rename {zh-tw => legacy/zh-tw}/advanced/healthcheck-graceful-shutdown.md (100%) rename {zh-tw => legacy/zh-tw}/advanced/security-updates.md (100%) rename {zh-tw => legacy/zh-tw}/api.md (100%) rename {zh-tw => legacy/zh-tw}/changelog/index.md (100%) rename {zh-tw => legacy/zh-tw}/guide/behind-proxies.md (100%) rename {zh-tw => legacy/zh-tw}/guide/database-integration.md (100%) rename {zh-tw => legacy/zh-tw}/guide/debugging.md (100%) rename {zh-tw => legacy/zh-tw}/guide/error-handling.md (100%) rename {zh-tw => legacy/zh-tw}/guide/migrating-4.md (100%) rename {zh-tw => legacy/zh-tw}/guide/migrating-5.md (100%) rename {zh-tw => legacy/zh-tw}/guide/overriding-express-api.md (100%) rename {zh-tw => legacy/zh-tw}/guide/routing.md (100%) rename {zh-tw => legacy/zh-tw}/guide/using-middleware.md (100%) rename {zh-tw => legacy/zh-tw}/guide/using-template-engines.md (100%) rename {zh-tw => legacy/zh-tw}/guide/writing-middleware.md (100%) rename {zh-tw => legacy/zh-tw}/index.md (100%) rename {zh-tw => legacy/zh-tw}/resources/community.md (100%) rename {zh-tw => legacy/zh-tw}/resources/contributing.md (100%) rename {zh-tw => legacy/zh-tw}/resources/glossary.md (100%) rename {zh-tw => legacy/zh-tw}/resources/middleware.md (100%) rename {zh-tw => legacy/zh-tw}/resources/middleware/body-parser.md (100%) rename {zh-tw => legacy/zh-tw}/resources/middleware/compression.md (100%) rename {zh-tw => legacy/zh-tw}/resources/middleware/connect-rid.md (100%) rename {zh-tw => legacy/zh-tw}/resources/middleware/cookie-parser.md (100%) rename {zh-tw => legacy/zh-tw}/resources/middleware/cookie-session.md (100%) rename {zh-tw => legacy/zh-tw}/resources/middleware/cors.md (100%) rename {zh-tw => legacy/zh-tw}/resources/middleware/errorhandler.md (100%) rename {zh-tw => legacy/zh-tw}/resources/middleware/method-override.md (100%) rename {zh-tw => legacy/zh-tw}/resources/middleware/morgan.md (100%) rename {zh-tw => legacy/zh-tw}/resources/middleware/multer.md (100%) rename {zh-tw => legacy/zh-tw}/resources/middleware/response-time.md (100%) rename {zh-tw => legacy/zh-tw}/resources/middleware/serve-favicon.md (100%) rename {zh-tw => legacy/zh-tw}/resources/middleware/serve-index.md (100%) rename {zh-tw => legacy/zh-tw}/resources/middleware/serve-static.md (100%) rename {zh-tw => legacy/zh-tw}/resources/middleware/session.md (100%) rename {zh-tw => legacy/zh-tw}/resources/middleware/timeout.md (100%) rename {zh-tw => legacy/zh-tw}/resources/middleware/vhost.md (100%) rename {zh-tw => legacy/zh-tw}/resources/utils.md (100%) rename {zh-tw => legacy/zh-tw}/starter/basic-routing.md (100%) rename {zh-tw => legacy/zh-tw}/starter/examples.md (100%) rename {zh-tw => legacy/zh-tw}/starter/faq.md (100%) rename {zh-tw => legacy/zh-tw}/starter/generator.md (100%) rename {zh-tw => legacy/zh-tw}/starter/hello-world.md (100%) rename {zh-tw => legacy/zh-tw}/starter/installing.md (100%) rename {zh-tw => legacy/zh-tw}/starter/static-files.md (100%) rename {zh-tw => legacy/zh-tw}/support/index.md (100%) create mode 100644 netlify.toml diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..f7b1786dd5 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,19 @@ +# EditorConfig: https://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false + +[*.{yml,yaml}] +indent_size = 2 + +[Makefile] +indent_style = tab diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index b983583855..22dcf27c02 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,5 +4,5 @@ # Codeowners .github/CODEOWNERS @expressjs/docs-captains -# Blog -_posts @expressjs/express-tc \ No newline at end of file +# Blog - TODO: Add once Astro blog structure is set up +# _posts @expressjs/express-tc \ No newline at end of file diff --git a/.gitignore b/.gitignore index 8323fd83be..84bfee1b6a 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,13 @@ _site .jekyll-metadata vendor .bundle + +pnpm-lock.yaml +yarn.lock +bun.lockb + +.astro/ +dist/ + +.env +.env.* diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000000..832b4b216b --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + "recommendations": [ + "astro-build.astro-vscode", + "esbenp.prettier-vscode", + "dbaeumer.vscode-eslint" + ], + "unwantedRecommendations": [] +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000000..d642209762 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,11 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "command": "./node_modules/.bin/astro dev", + "name": "Development server", + "request": "launch", + "type": "node-terminal" + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..55dcf7232f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,21 @@ +{ + "prettier.enable": true, + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "[astro]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true + }, + "[javascript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[json]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[css]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + } +} diff --git a/astro/.gitignore b/astro/.gitignore new file mode 100644 index 0000000000..016b59ea14 --- /dev/null +++ b/astro/.gitignore @@ -0,0 +1,24 @@ +# build output +dist/ + +# generated types +.astro/ + +# dependencies +node_modules/ + +# logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# environment variables +.env +.env.production + +# macOS-specific files +.DS_Store + +# jetbrains setting folder +.idea/ diff --git a/astro/.nvmrc b/astro/.nvmrc new file mode 100644 index 0000000000..cabf43b5dd --- /dev/null +++ b/astro/.nvmrc @@ -0,0 +1 @@ +24 \ No newline at end of file diff --git a/astro/.prettierignore b/astro/.prettierignore new file mode 100644 index 0000000000..44d3bded77 --- /dev/null +++ b/astro/.prettierignore @@ -0,0 +1,5 @@ +dist/ +.astro/ +node_modules/ +package-lock.json +pnpm-lock.yaml diff --git a/astro/.prettierrc b/astro/.prettierrc new file mode 100644 index 0000000000..167200c363 --- /dev/null +++ b/astro/.prettierrc @@ -0,0 +1,9 @@ +{ + "semi": true, + "singleQuote": true, + "tabWidth": 2, + "useTabs": false, + "trailingComma": "es5", + "printWidth": 100, + "plugins": ["prettier-plugin-astro"] +} diff --git a/astro/CONTRIBUTING.md b/astro/CONTRIBUTING.md new file mode 100644 index 0000000000..af56697819 --- /dev/null +++ b/astro/CONTRIBUTING.md @@ -0,0 +1,129 @@ +# Contributing to Expressjs.com + +### The Official Documentation of the Express.js Framework + +This is the contribution documentation for the [expressjs.com](https://github.com/expressjs/expressjs.com) website. + +> [!NOTE] +> This is not the repo for Express.js framework. To contribute to the _[Express.js framework](https://github.com/expressjs/express)_, check out the [GitHub repo contributing page](https://github.com/expressjs/express?tab=contributing-ov-file) or the website's [Contributing to Express](https://expressjs.com/en/resources/contributing.html) page. + +#### Need some ideas? These are some typical issues. + +1. **Website issues**: If you see anything on the site that could use a tune-up, think about how to fix it. + - Display or screen sizing problems + - Mobile responsiveness issues + - Missing or broken accessibility features + - Website outages + - Broken links + - Page structure or user interface enhancements + +2. **Content Issues**: Fix anything related to site content or typos. + - Spelling errors + - Incorrect/outdated Express.js documentation + - Missing content + +3. **Translation Issues**: Fix any translation errors or contribute new content. + - Fix spelling errors + - Fix incorrect/poorly translated words + - Check out the [Contributing translations](#contributing-translations) section below for a contributing guide. + +#### Want to work on a backlog issue? + +We often have bugs or enhancements that need work. You can find these under our repo's [Issues tab](https://github.com/expressjs/expressjs.com/issues). Check out the tags to find something that's a good match for you. + +#### Have an idea? Found a bug? + +If you've found a bug or a typo, or if you have an idea for an enhancement, you can: + +- Submit a [new issue](https://github.com/expressjs/expressjs.com/issues/new/choose) on our repo. Do this for larger proposals, or if you'd like to discuss or get feedback first. + +- Make a [GitHub pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request). If you have already done work, and it's ready to go, feel free to send it our way. + +## Getting Started + +The steps below will guide you through the Expressjs.com contribution process. + +#### Step 1: (OPTIONAL) Open a New Issue + +So you've found a problem that you want to fix, or have a site enhancement you want to make. + +1. If you want to get feedback or discuss, open a discussion [issue](https://github.com/expressjs/expressjs.com/issues/new/choose) prior to starting work. This is not required, but encouraged for larger proposals. + - While we highly encourage this step, it is only for submissions proposing significant change. It helps us to clarify and focus the work, and ensure it aligns with overall project priorities. + - For submissions proposing minor improvements or corrections, this is not needed. You can skip this step. + - When opening an issue please give it a title and fill in the description section. The more details you provide, the more feedback we can give. + +2. After receiving your issue the Express.js documentation team will respond with feedback. We read every submission and always try to respond quickly with feedback. + - For submissions proposing significant change, we encourage you to follow the review process before starting work. + +#### Step 2: Get the Application Code Base + +## Prerequisites + +- **Node.js**: v24.13.0 or higher +- **npm**: v11.0.0 or higher (comes with Node 24) + +> We recommend using [nvm](https://github.com/nvm-sh/nvm) to manage Node.js versions. This project includes an `.nvmrc` file for automatic version switching. + +## Getting Started + +1. **Clone the repository:** + + ```bash + git clone https://github.com/expressjs/expressjs.com.git + cd expressjs.com + ``` + +2. **Install the correct Node.js version** (if using nvm): + + ```bash + nvm install + nvm use + ``` + +3. **Install dependencies:** + + ```bash + npm install + ``` + +4. **Start the development server:** + + ```bash + npm run dev + ``` + + The site will be available at `http://localhost:4321` + +## Available Scripts + +| Command | Description | +| ----------------- | ---------------------------------------- | +| `npm run dev` | Start development server with hot reload | +| `npm run build` | Build production site to `./dist` | +| `npm run preview` | Preview production build locally | + +## Project Structure + +``` +astro/ +├── src/ +│ ├── assets/ # Static assets (images, icons, etc.) +│ ├── components/ # Reusable UI components +│ │ ├── patterns/ # Complex UI patterns +│ │ └── primitives/ # Base UI primitives +│ ├── config/ # Configuration files +│ ├── content/ # Content collections +│ │ └── docs/ # Documentation content +│ ├── i18n/ # Internationalization +│ ├── layouts/ # Page layouts +│ ├── pages/ # Route pages +│ │ └── [lang]/ # Localized pages +│ ├── styles/ # Global styles +│ │ ├── base/ # Base styles +│ │ ├── tokens/ # Design tokens +│ │ └── utilities/ # Utility classes +│ └── utils/ # Utility functions +├── public/ # Static assets +│ └── fonts/ # Font files +└── astro.config.mjs # Astro configuration +``` diff --git a/astro/README.md b/astro/README.md new file mode 100644 index 0000000000..7ad84277e2 --- /dev/null +++ b/astro/README.md @@ -0,0 +1,7 @@ +# expressjs.com + +This is the repository of the website [expressjs.com](https://expressjs.com). It is hosted directly from the repository as a [GitHub Pages](https://pages.github.com/) website. + +## Contributing + +Any person who wants to contribute to the Website is welcome! Please read [Contributors' Guide](CONTRIBUTING.md) for more information on contributing to the Express.js documentation. diff --git a/astro/astro.config.mjs b/astro/astro.config.mjs new file mode 100644 index 0000000000..095044e693 --- /dev/null +++ b/astro/astro.config.mjs @@ -0,0 +1,14 @@ +// @ts-check +import { defineConfig } from 'astro/config'; +import mdx from '@astrojs/mdx'; +import icon from 'astro-icon'; + +// https://astro.build/config +export default defineConfig({ + integrations: [mdx(), icon()], + markdown: { + shikiConfig: { + theme: 'github-dark', + }, + }, +}); diff --git a/astro/eslint.config.js b/astro/eslint.config.js new file mode 100644 index 0000000000..eec9807e7a --- /dev/null +++ b/astro/eslint.config.js @@ -0,0 +1,34 @@ +import eslint from '@eslint/js'; +import tseslint from 'typescript-eslint'; +import eslintAstroPlugin from 'eslint-plugin-astro'; +import jsxA11y from 'eslint-plugin-jsx-a11y'; +import eslintConfigPrettier from 'eslint-config-prettier'; + +export default [ + // Global ignores + { + ignores: ['dist/', '.astro/', 'node_modules/', 'package-lock.json'], + }, + + // Base ESLint recommended rules + eslint.configs.recommended, + + // TypeScript ESLint recommended rules + ...tseslint.configs.recommended, + + // Astro files + ...eslintAstroPlugin.configs.recommended, + ...eslintAstroPlugin.configs['jsx-a11y-recommended'], + + // JSX Accessibility for non-Astro files + { + files: ['**/*.{jsx,tsx}'], + plugins: { + 'jsx-a11y': jsxA11y, + }, + rules: jsxA11y.configs.recommended.rules, + }, + + // Prettier - keep as last to override conflicting rules + eslintConfigPrettier, +]; diff --git a/astro/package-lock.json b/astro/package-lock.json new file mode 100644 index 0000000000..8e15e1a4ba --- /dev/null +++ b/astro/package-lock.json @@ -0,0 +1,10288 @@ +{ + "name": "expressjs-astro-project", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "expressjs-astro-project", + "version": "0.0.1", + "dependencies": { + "@astrojs/mdx": "^4.3.13", + "astro": "^5.16.11", + "astro-icon": "^1.1.5" + }, + "devDependencies": { + "@csstools/postcss-global-data": "^4.0.0", + "@eslint/js": "^9.39.2", + "@iconify-json/ph": "^1.2.2", + "eslint": "^9.39.2", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-astro": "^1.5.0", + "eslint-plugin-jsx-a11y": "^6.10.2", + "lint-staged": "^16.2.7", + "postcss-custom-media": "^12.0.0", + "prettier": "^3.8.1", + "prettier-plugin-astro": "^0.14.1", + "typescript": "^5.9.3", + "typescript-eslint": "^8.53.1" + }, + "engines": { + "node": ">=24.13.0", + "npm": ">=11.0.0" + } + }, + "node_modules/@antfu/install-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-1.1.0.tgz", + "integrity": "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==", + "license": "MIT", + "dependencies": { + "package-manager-detector": "^1.3.0", + "tinyexec": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@antfu/utils": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-8.1.1.tgz", + "integrity": "sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@astrojs/compiler": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-2.13.0.tgz", + "integrity": "sha512-mqVORhUJViA28fwHYaWmsXSzLO9osbdZ5ImUfxBarqsYdMlPbqAqGJCxsNzvppp1BEzc1mJNjOVvQqeDN8Vspw==", + "license": "MIT", + "peer": true + }, + "node_modules/@astrojs/internal-helpers": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.7.5.tgz", + "integrity": "sha512-vreGnYSSKhAjFJCWAwe/CNhONvoc5lokxtRoZims+0wa3KbHBdPHSSthJsKxPd8d/aic6lWKpRTYGY/hsgK6EA==", + "license": "MIT" + }, + "node_modules/@astrojs/markdown-remark": { + "version": "6.3.10", + "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-6.3.10.tgz", + "integrity": "sha512-kk4HeYR6AcnzC4QV8iSlOfh+N8TZ3MEStxPyenyCtemqn8IpEATBFMTJcfrNW32dgpt6MY3oCkMM/Tv3/I4G3A==", + "license": "MIT", + "dependencies": { + "@astrojs/internal-helpers": "0.7.5", + "@astrojs/prism": "3.3.0", + "github-slugger": "^2.0.0", + "hast-util-from-html": "^2.0.3", + "hast-util-to-text": "^4.0.2", + "import-meta-resolve": "^4.2.0", + "js-yaml": "^4.1.1", + "mdast-util-definitions": "^6.0.0", + "rehype-raw": "^7.0.0", + "rehype-stringify": "^10.0.1", + "remark-gfm": "^4.0.1", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.1.2", + "remark-smartypants": "^3.0.2", + "shiki": "^3.19.0", + "smol-toml": "^1.5.2", + "unified": "^11.0.5", + "unist-util-remove-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "unist-util-visit-parents": "^6.0.2", + "vfile": "^6.0.3" + } + }, + "node_modules/@astrojs/mdx": { + "version": "4.3.13", + "resolved": "https://registry.npmjs.org/@astrojs/mdx/-/mdx-4.3.13.tgz", + "integrity": "sha512-IHDHVKz0JfKBy3//52JSiyWv089b7GVSChIXLrlUOoTLWowG3wr2/8hkaEgEyd/vysvNQvGk+QhysXpJW5ve6Q==", + "license": "MIT", + "dependencies": { + "@astrojs/markdown-remark": "6.3.10", + "@mdx-js/mdx": "^3.1.1", + "acorn": "^8.15.0", + "es-module-lexer": "^1.7.0", + "estree-util-visit": "^2.0.0", + "hast-util-to-html": "^9.0.5", + "piccolore": "^0.1.3", + "rehype-raw": "^7.0.0", + "remark-gfm": "^4.0.1", + "remark-smartypants": "^3.0.2", + "source-map": "^0.7.6", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.3" + }, + "engines": { + "node": "18.20.8 || ^20.3.0 || >=22.0.0" + }, + "peerDependencies": { + "astro": "^5.0.0" + } + }, + "node_modules/@astrojs/prism": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-3.3.0.tgz", + "integrity": "sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ==", + "license": "MIT", + "dependencies": { + "prismjs": "^1.30.0" + }, + "engines": { + "node": "18.20.8 || ^20.3.0 || >=22.0.0" + } + }, + "node_modules/@astrojs/telemetry": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.3.0.tgz", + "integrity": "sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ==", + "license": "MIT", + "dependencies": { + "ci-info": "^4.2.0", + "debug": "^4.4.0", + "dlv": "^1.1.3", + "dset": "^3.1.4", + "is-docker": "^3.0.0", + "is-wsl": "^3.1.0", + "which-pm-runs": "^1.1.0" + }, + "engines": { + "node": "18.20.8 || ^20.3.0 || >=22.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz", + "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.6" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz", + "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@capsizecss/unpack": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@capsizecss/unpack/-/unpack-4.0.0.tgz", + "integrity": "sha512-VERIM64vtTP1C4mxQ5thVT9fK0apjPFobqybMtA1UdUujWka24ERHbRHFGmpbbhp73MhV+KSsHQH9C6uOTdEQA==", + "license": "MIT", + "dependencies": { + "fontkitten": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/cascade-layer-name-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-3.0.0.tgz", + "integrity": "sha512-/3iksyevwRfSJx5yH0RkcrcYXwuhMQx3Juqf40t97PeEy2/Mz2TItZ/z/216qpe4GgOyFBP8MKIwVvytzHmfIQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", + "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "peer": true, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", + "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "peer": true, + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@csstools/media-query-list-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-5.0.0.tgz", + "integrity": "sha512-T9lXmZOfnam3eMERPsszjY5NK0jX8RmThmmm99FZ8b7z8yMaFZWKwLWGZuTwdO3ddRY5fy13GmmEYZXB4I98Eg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/postcss-global-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-global-data/-/postcss-global-data-4.0.0.tgz", + "integrity": "sha512-mPKrL3Tzt8k1V+hTkU8XTH6JKRekB97oKHv/MekC9nfmRa+gMf1swlHRt8YK722sYN4xOipl17FZst99jsScLA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", + "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@iconify-json/ph": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@iconify-json/ph/-/ph-1.2.2.tgz", + "integrity": "sha512-PgkEZNtqa8hBGjHXQa4pMwZa93hmfu8FUSjs/nv4oUU6yLsgv+gh9nu28Kqi8Fz9CCVu4hj1MZs9/60J57IzFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@iconify/types": "*" + } + }, + "node_modules/@iconify/tools": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@iconify/tools/-/tools-4.2.0.tgz", + "integrity": "sha512-WRxPva/ipxYkqZd1+CkEAQmd86dQmrwH0vwK89gmp2Kh2WyyVw57XbPng0NehP3x4V1LzLsXUneP1uMfTMZmUA==", + "license": "MIT", + "dependencies": { + "@iconify/types": "^2.0.0", + "@iconify/utils": "^2.3.0", + "cheerio": "^1.1.2", + "domhandler": "^5.0.3", + "extract-zip": "^2.0.1", + "local-pkg": "^1.1.2", + "pathe": "^2.0.3", + "svgo": "^3.3.2", + "tar": "^7.5.2" + } + }, + "node_modules/@iconify/tools/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@iconify/tools/node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/@iconify/tools/node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "license": "CC0-1.0" + }, + "node_modules/@iconify/tools/node_modules/svgo": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz", + "integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==", + "license": "MIT", + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^5.1.0", + "css-tree": "^2.3.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.0.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "license": "MIT" + }, + "node_modules/@iconify/utils": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-2.3.0.tgz", + "integrity": "sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA==", + "license": "MIT", + "dependencies": { + "@antfu/install-pkg": "^1.0.0", + "@antfu/utils": "^8.1.0", + "@iconify/types": "^2.0.0", + "debug": "^4.4.0", + "globals": "^15.14.0", + "kolorist": "^1.8.0", + "local-pkg": "^1.0.0", + "mlly": "^1.7.4" + } + }, + "node_modules/@iconify/utils/node_modules/globals": { + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@img/colour": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz", + "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@mdx-js/mdx": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.1.1.tgz", + "integrity": "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdx": "^2.0.0", + "acorn": "^8.0.0", + "collapse-white-space": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-util-scope": "^1.0.0", + "estree-walker": "^3.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "markdown-extensions": "^2.0.0", + "recma-build-jsx": "^1.0.0", + "recma-jsx": "^1.0.0", + "recma-stringify": "^1.0.0", + "rehype-recma": "^1.0.0", + "remark-mdx": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "source-map": "^0.7.0", + "unified": "^11.0.0", + "unist-util-position-from-estree": "^2.0.0", + "unist-util-stringify-position": "^4.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@oslojs/encoding": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-1.1.0.tgz", + "integrity": "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==", + "license": "MIT" + }, + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.3.tgz", + "integrity": "sha512-qyX8+93kK/7R5BEXPC2PjUt0+fS/VO2BVHjEHyIEWiYn88rcRBHmdLgoJjktBltgAf+NY7RfCGB1SoyKS/p9kg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.55.3.tgz", + "integrity": "sha512-6sHrL42bjt5dHQzJ12Q4vMKfN+kUnZ0atHHnv4V0Wd9JMTk7FDzSY35+7qbz3ypQYMBPANbpGK7JpnWNnhGt8g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.55.3.tgz", + "integrity": "sha512-1ht2SpGIjEl2igJ9AbNpPIKzb1B5goXOcmtD0RFxnwNuMxqkR6AUaaErZz+4o+FKmzxcSNBOLrzsICZVNYa1Rw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.55.3.tgz", + "integrity": "sha512-FYZ4iVunXxtT+CZqQoPVwPhH7549e/Gy7PIRRtq4t5f/vt54pX6eG9ebttRH6QSH7r/zxAFA4EZGlQ0h0FvXiA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.55.3.tgz", + "integrity": "sha512-M/mwDCJ4wLsIgyxv2Lj7Len+UMHd4zAXu4GQ2UaCdksStglWhP61U3uowkaYBQBhVoNpwx5Hputo8eSqM7K82Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.55.3.tgz", + "integrity": "sha512-5jZT2c7jBCrMegKYTYTpni8mg8y3uY8gzeq2ndFOANwNuC/xJbVAoGKR9LhMDA0H3nIhvaqUoBEuJoICBudFrA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.55.3.tgz", + "integrity": "sha512-YeGUhkN1oA+iSPzzhEjVPS29YbViOr8s4lSsFaZKLHswgqP911xx25fPOyE9+khmN6W4VeM0aevbDp4kkEoHiA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.55.3.tgz", + "integrity": "sha512-eo0iOIOvcAlWB3Z3eh8pVM8hZ0oVkK3AjEM9nSrkSug2l15qHzF3TOwT0747omI6+CJJvl7drwZepT+re6Fy/w==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.55.3.tgz", + "integrity": "sha512-DJay3ep76bKUDImmn//W5SvpjRN5LmK/ntWyeJs/dcnwiiHESd3N4uteK9FDLf0S0W8E6Y0sVRXpOCoQclQqNg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.55.3.tgz", + "integrity": "sha512-BKKWQkY2WgJ5MC/ayvIJTHjy0JUGb5efaHCUiG/39sSUvAYRBaO3+/EK0AZT1RF3pSj86O24GLLik9mAYu0IJg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.55.3.tgz", + "integrity": "sha512-Q9nVlWtKAG7ISW80OiZGxTr6rYtyDSkauHUtvkQI6TNOJjFvpj4gcH+KaJihqYInnAzEEUetPQubRwHef4exVg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.55.3.tgz", + "integrity": "sha512-2H5LmhzrpC4fFRNwknzmmTvvyJPHwESoJgyReXeFoYYuIDfBhP29TEXOkCJE/KxHi27mj7wDUClNq78ue3QEBQ==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.55.3.tgz", + "integrity": "sha512-9S542V0ie9LCTznPYlvaeySwBeIEa7rDBgLHKZ5S9DBgcqdJYburabm8TqiqG6mrdTzfV5uttQRHcbKff9lWtA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.55.3.tgz", + "integrity": "sha512-ukxw+YH3XXpcezLgbJeasgxyTbdpnNAkrIlFGDl7t+pgCxZ89/6n1a+MxlY7CegU+nDgrgdqDelPRNQ/47zs0g==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.55.3.tgz", + "integrity": "sha512-Iauw9UsTTvlF++FhghFJjqYxyXdggXsOqGpFBylaRopVpcbfyIIsNvkf9oGwfgIcf57z3m8+/oSYTo6HutBFNw==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.55.3.tgz", + "integrity": "sha512-3OqKAHSEQXKdq9mQ4eajqUgNIK27VZPW3I26EP8miIzuKzCJ3aW3oEn2pzF+4/Hj/Moc0YDsOtBgT5bZ56/vcA==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.55.3.tgz", + "integrity": "sha512-0CM8dSVzVIaqMcXIFej8zZrSFLnGrAE8qlNbbHfTw1EEPnFTg1U1ekI0JdzjPyzSfUsHWtodilQQG/RA55berA==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.55.3.tgz", + "integrity": "sha512-+fgJE12FZMIgBaKIAGd45rxf+5ftcycANJRWk8Vz0NnMTM5rADPGuRFTYar+Mqs560xuART7XsX2lSACa1iOmQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.55.3.tgz", + "integrity": "sha512-tMD7NnbAolWPzQlJQJjVFh/fNH3K/KnA7K8gv2dJWCwwnaK6DFCYST1QXYWfu5V0cDwarWC8Sf/cfMHniNq21A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.55.3.tgz", + "integrity": "sha512-u5KsqxOxjEeIbn7bUK1MPM34jrnPwjeqgyin4/N6e/KzXKfpE9Mi0nCxcQjaM9lLmPcHmn/xx1yOjgTMtu1jWQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.55.3.tgz", + "integrity": "sha512-vo54aXwjpTtsAnb3ca7Yxs9t2INZg7QdXN/7yaoG7nPGbOBXYXQY41Km+S1Ov26vzOAzLcAjmMdjyEqS1JkVhw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.55.3.tgz", + "integrity": "sha512-HI+PIVZ+m+9AgpnY3pt6rinUdRYrGHvmVdsNQ4odNqQ/eRF78DVpMR7mOq7nW06QxpczibwBmeQzB68wJ+4W4A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.55.3.tgz", + "integrity": "sha512-vRByotbdMo3Wdi+8oC2nVxtc3RkkFKrGaok+a62AT8lz/YBuQjaVYAS5Zcs3tPzW43Vsf9J0wehJbUY5xRSekA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.55.3.tgz", + "integrity": "sha512-POZHq7UeuzMJljC5NjKi8vKMFN6/5EOqcX1yGntNLp7rUTpBAXQ1hW8kWPFxYLv07QMcNM75xqVLGPWQq6TKFA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.55.3.tgz", + "integrity": "sha512-aPFONczE4fUFKNXszdvnd2GqKEYQdV5oEsIbKPujJmWlCI9zEsv1Otig8RKK+X9bed9gFUN6LAeN4ZcNuu4zjg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@shikijs/core": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-3.21.0.tgz", + "integrity": "sha512-AXSQu/2n1UIQekY8euBJlvFYZIw0PHY63jUzGbrOma4wPxzznJXTXkri+QcHeBNaFxiiOljKxxJkVSoB3PjbyA==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.21.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.5" + } + }, + "node_modules/@shikijs/engine-javascript": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-3.21.0.tgz", + "integrity": "sha512-ATwv86xlbmfD9n9gKRiwuPpWgPENAWCLwYCGz9ugTJlsO2kOzhOkvoyV/UD+tJ0uT7YRyD530x6ugNSffmvIiQ==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.21.0", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^4.3.4" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.21.0.tgz", + "integrity": "sha512-OYknTCct6qiwpQDqDdf3iedRdzj6hFlOPv5hMvI+hkWfCKs5mlJ4TXziBG9nyabLwGulrUjHiCq3xCspSzErYQ==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.21.0", + "@shikijs/vscode-textmate": "^10.0.2" + } + }, + "node_modules/@shikijs/langs": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.21.0.tgz", + "integrity": "sha512-g6mn5m+Y6GBJ4wxmBYqalK9Sp0CFkUqfNzUy2pJglUginz6ZpWbaWjDB4fbQ/8SHzFjYbtU6Ddlp1pc+PPNDVA==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.21.0" + } + }, + "node_modules/@shikijs/themes": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.21.0.tgz", + "integrity": "sha512-BAE4cr9EDiZyYzwIHEk7JTBJ9CzlPuM4PchfcA5ao1dWXb25nv6hYsoDiBq2aZK9E3dlt3WB78uI96UESD+8Mw==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.21.0" + } + }, + "node_modules/@shikijs/types": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.21.0.tgz", + "integrity": "sha512-zGrWOxZ0/+0ovPY7PvBU2gIS9tmhSUUt30jAcNV0Bq0gb2S98gwfjIs1vxlmH5zM7/4YxLamT6ChlqqAJmPPjA==", + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "license": "MIT" + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "license": "ISC", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdx": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", + "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==", + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/nlcst": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/nlcst/-/nlcst-2.0.3.tgz", + "integrity": "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.53.1.tgz", + "integrity": "sha512-cFYYFZ+oQFi6hUnBTbLRXfTJiaQtYE3t4O692agbBl+2Zy+eqSKWtPjhPXJu1G7j4RLjKgeJPDdq3EqOwmX5Ag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.53.1", + "@typescript-eslint/type-utils": "8.53.1", + "@typescript-eslint/utils": "8.53.1", + "@typescript-eslint/visitor-keys": "8.53.1", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.53.1", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.53.1.tgz", + "integrity": "sha512-nm3cvFN9SqZGXjmw5bZ6cGmvJSyJPn0wU9gHAZZHDnZl2wF9PhHv78Xf06E0MaNk4zLVHL8hb2/c32XvyJOLQg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@typescript-eslint/scope-manager": "8.53.1", + "@typescript-eslint/types": "8.53.1", + "@typescript-eslint/typescript-estree": "8.53.1", + "@typescript-eslint/visitor-keys": "8.53.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.53.1.tgz", + "integrity": "sha512-WYC4FB5Ra0xidsmlPb+1SsnaSKPmS3gsjIARwbEkHkoWloQmuzcfypljaJcR78uyLA1h8sHdWWPHSLDI+MtNog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.53.1", + "@typescript-eslint/types": "^8.53.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.53.1.tgz", + "integrity": "sha512-Lu23yw1uJMFY8cUeq7JlrizAgeQvWugNQzJp8C3x8Eo5Jw5Q2ykMdiiTB9vBVOOUBysMzmRRmUfwFrZuI2C4SQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.53.1", + "@typescript-eslint/visitor-keys": "8.53.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.53.1.tgz", + "integrity": "sha512-qfvLXS6F6b1y43pnf0pPbXJ+YoXIC7HKg0UGZ27uMIemKMKA6XH2DTxsEDdpdN29D+vHV07x/pnlPNVLhdhWiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.53.1.tgz", + "integrity": "sha512-MOrdtNvyhy0rHyv0ENzub1d4wQYKb2NmIqG7qEqPWFW7Mpy2jzFC3pQ2yKDvirZB7jypm5uGjF2Qqs6OIqu47w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.53.1", + "@typescript-eslint/typescript-estree": "8.53.1", + "@typescript-eslint/utils": "8.53.1", + "debug": "^4.4.3", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.53.1.tgz", + "integrity": "sha512-jr/swrr2aRmUAUjW5/zQHbMaui//vQlsZcJKijZf3M26bnmLj8LyZUpj8/Rd6uzaek06OWsqdofN/Thenm5O8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.53.1.tgz", + "integrity": "sha512-RGlVipGhQAG4GxV1s34O91cxQ/vWiHJTDHbXRr0li2q/BGg3RR/7NM8QDWgkEgrwQYCvmJV9ichIwyoKCQ+DTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.53.1", + "@typescript-eslint/tsconfig-utils": "8.53.1", + "@typescript-eslint/types": "8.53.1", + "@typescript-eslint/visitor-keys": "8.53.1", + "debug": "^4.4.3", + "minimatch": "^9.0.5", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.53.1.tgz", + "integrity": "sha512-c4bMvGVWW4hv6JmDUEG7fSYlWOl3II2I4ylt0NM+seinYQlZMQIaKaXIIVJWt9Ofh6whrpM+EdDQXKXjNovvrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.53.1", + "@typescript-eslint/types": "8.53.1", + "@typescript-eslint/typescript-estree": "8.53.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.53.1.tgz", + "integrity": "sha512-oy+wV7xDKFPRyNggmXuZQSBzvoLnpmJs+GhzRhPjrxl2b/jIlyjVokzm47CZCDUdXKr2zd7ZLodPfOBpOPyPlg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.53.1", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "license": "ISC" + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "license": "MIT", + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "license": "ISC", + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-align/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/ansi-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-align/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-escapes": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.2.0.tgz", + "integrity": "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-iterate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/array-iterate/-/array-iterate-2.0.1.tgz", + "integrity": "sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/astring": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz", + "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==", + "license": "MIT", + "bin": { + "astring": "bin/astring" + } + }, + "node_modules/astro": { + "version": "5.16.11", + "resolved": "https://registry.npmjs.org/astro/-/astro-5.16.11.tgz", + "integrity": "sha512-Z7kvkTTT5n6Hn5lCm6T3WU6pkxx84Hn25dtQ6dR7ATrBGq9eVa8EuB/h1S8xvaoVyCMZnIESu99Z9RJfdLRLDA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@astrojs/compiler": "^2.13.0", + "@astrojs/internal-helpers": "0.7.5", + "@astrojs/markdown-remark": "6.3.10", + "@astrojs/telemetry": "3.3.0", + "@capsizecss/unpack": "^4.0.0", + "@oslojs/encoding": "^1.1.0", + "@rollup/pluginutils": "^5.3.0", + "acorn": "^8.15.0", + "aria-query": "^5.3.2", + "axobject-query": "^4.1.0", + "boxen": "8.0.1", + "ci-info": "^4.3.1", + "clsx": "^2.1.1", + "common-ancestor-path": "^1.0.1", + "cookie": "^1.1.1", + "cssesc": "^3.0.0", + "debug": "^4.4.3", + "deterministic-object-hash": "^2.0.2", + "devalue": "^5.6.2", + "diff": "^8.0.3", + "dlv": "^1.1.3", + "dset": "^3.1.4", + "es-module-lexer": "^1.7.0", + "esbuild": "^0.25.0", + "estree-walker": "^3.0.3", + "flattie": "^1.1.1", + "fontace": "~0.4.0", + "github-slugger": "^2.0.0", + "html-escaper": "3.0.3", + "http-cache-semantics": "^4.2.0", + "import-meta-resolve": "^4.2.0", + "js-yaml": "^4.1.1", + "magic-string": "^0.30.21", + "magicast": "^0.5.1", + "mrmime": "^2.0.1", + "neotraverse": "^0.6.18", + "p-limit": "^6.2.0", + "p-queue": "^8.1.1", + "package-manager-detector": "^1.6.0", + "piccolore": "^0.1.3", + "picomatch": "^4.0.3", + "prompts": "^2.4.2", + "rehype": "^13.0.2", + "semver": "^7.7.3", + "shiki": "^3.20.0", + "smol-toml": "^1.6.0", + "svgo": "^4.0.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tsconfck": "^3.1.6", + "ultrahtml": "^1.6.0", + "unifont": "~0.7.1", + "unist-util-visit": "^5.0.0", + "unstorage": "^1.17.3", + "vfile": "^6.0.3", + "vite": "^6.4.1", + "vitefu": "^1.1.1", + "xxhash-wasm": "^1.1.0", + "yargs-parser": "^21.1.1", + "yocto-spinner": "^0.2.3", + "zod": "^3.25.76", + "zod-to-json-schema": "^3.25.1", + "zod-to-ts": "^1.2.0" + }, + "bin": { + "astro": "astro.js" + }, + "engines": { + "node": "18.20.8 || ^20.3.0 || >=22.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/astrodotbuild" + }, + "optionalDependencies": { + "sharp": "^0.34.0" + } + }, + "node_modules/astro-eslint-parser": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/astro-eslint-parser/-/astro-eslint-parser-1.2.2.tgz", + "integrity": "sha512-JepyLROIad6f44uyqMF6HKE2QbunNzp3mYKRcPoDGt0QkxXmH222FAFC64WTyQu2Kg8NNEXHTN/sWuUId9sSxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@astrojs/compiler": "^2.0.0", + "@typescript-eslint/scope-manager": "^7.0.0 || ^8.0.0", + "@typescript-eslint/types": "^7.0.0 || ^8.0.0", + "astrojs-compiler-sync": "^1.0.0", + "debug": "^4.3.4", + "entities": "^6.0.0", + "eslint-scope": "^8.0.1", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.0.0", + "fast-glob": "^3.3.3", + "is-glob": "^4.0.3", + "semver": "^7.3.8" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + } + }, + "node_modules/astro-icon": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/astro-icon/-/astro-icon-1.1.5.tgz", + "integrity": "sha512-CJYS5nWOw9jz4RpGWmzNQY7D0y2ZZacH7atL2K9DeJXJVaz7/5WrxeyIxO8KASk1jCM96Q4LjRx/F3R+InjJrw==", + "license": "MIT", + "dependencies": { + "@iconify/tools": "^4.0.5", + "@iconify/types": "^2.0.0", + "@iconify/utils": "^2.1.30" + } + }, + "node_modules/astrojs-compiler-sync": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/astrojs-compiler-sync/-/astrojs-compiler-sync-1.1.1.tgz", + "integrity": "sha512-0mKvB9sDQRIZPsEJadw6OaFbGJ92cJPPR++ICca9XEyiUAZqgVuk25jNmzHPT0KF80rI94trSZrUR5iHFXGGOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "synckit": "^0.11.0" + }, + "engines": { + "node": "^18.18.0 || >=20.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "@astrojs/compiler": ">=0.27.0" + } + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axe-core": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.1.tgz", + "integrity": "sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A==", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/base-64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz", + "integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==", + "license": "MIT" + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC" + }, + "node_modules/boxen": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-8.0.1.tgz", + "integrity": "sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==", + "license": "MIT", + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^8.0.0", + "chalk": "^5.3.0", + "cli-boxes": "^3.0.0", + "string-width": "^7.2.0", + "type-fest": "^4.21.0", + "widest-line": "^5.0.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz", + "integrity": "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/cheerio": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.2.0.tgz", + "integrity": "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==", + "license": "MIT", + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "encoding-sniffer": "^0.2.1", + "htmlparser2": "^10.1.0", + "parse5": "^7.3.0", + "parse5-htmlparser2-tree-adapter": "^7.1.0", + "parse5-parser-stream": "^7.1.2", + "undici": "^7.19.0", + "whatwg-mimetype": "^4.0.0" + }, + "engines": { + "node": ">=20.18.1" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.1.1.tgz", + "integrity": "sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^7.1.0", + "string-width": "^8.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/string-width": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.1.0.tgz", + "integrity": "sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/collapse-white-space": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz", + "integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/common-ancestor-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz", + "integrity": "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==", + "license": "ISC" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/confbox": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", + "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cookie-es": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-1.2.2.tgz", + "integrity": "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==", + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crossws": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.5.tgz", + "integrity": "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==", + "license": "MIT", + "dependencies": { + "uncrypto": "^0.1.3" + } + }, + "node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz", + "integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.12.2", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "license": "MIT", + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "license": "CC0-1.0" + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "license": "MIT" + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/deterministic-object-hash": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/deterministic-object-hash/-/deterministic-object-hash-2.0.2.tgz", + "integrity": "sha512-KxektNH63SrbfUyDiwXqRb1rLwKt33AmMv+5Nhsw1kqZ13SJBRTgZHtGbE+hH3a1mVW1cz+4pqSWVPAtLVXTzQ==", + "license": "MIT", + "dependencies": { + "base-64": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/devalue": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.2.tgz", + "integrity": "sha512-nPRkjWzzDQlsejL1WVifk5rvcFi/y1onBRxjaFMjZeR9mFpqu2gmAZ9xUB9/IEanEP/vBtGeGganC/GO1fmufg==", + "license": "MIT" + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/diff": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.3.tgz", + "integrity": "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "license": "MIT" + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dset": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.4.tgz", + "integrity": "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "license": "MIT" + }, + "node_modules/encoding-sniffer": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz", + "integrity": "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==", + "license": "MIT", + "dependencies": { + "iconv-lite": "^0.6.3", + "whatwg-encoding": "^3.1.1" + }, + "funding": { + "url": "https://github.com/fb55/encoding-sniffer?sponsor=1" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/es-abstract": { + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", + "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/esast-util-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz", + "integrity": "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esast-util-from-js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esast-util-from-js/-/esast-util-from-js-2.0.1.tgz", + "integrity": "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "acorn": "^8.0.0", + "esast-util-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", + "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.2", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-compat-utils": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.6.5.tgz", + "integrity": "sha512-vAUHYzue4YAa2hNACjB8HvUQj5yehAZgiClyFVVom9cP8z5NSFq3PwB/TtJslN2zAMgRX6FCFCjYBbQh71g5RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/eslint-config-prettier": { + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-astro": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-astro/-/eslint-plugin-astro-1.5.0.tgz", + "integrity": "sha512-IWy4kY3DKTJxd7g652zIWpBGFuxw7NIIt16kyqc8BlhnIKvI8yGJj+Maua0DiNYED3F/D8AmzoTTTA6A95WX9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@jridgewell/sourcemap-codec": "^1.4.14", + "@typescript-eslint/types": "^7.7.1 || ^8", + "astro-eslint-parser": "^1.0.2", + "eslint-compat-utils": "^0.6.0", + "globals": "^16.0.0", + "postcss": "^8.4.14", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "eslint": ">=8.57.0" + } + }, + "node_modules/eslint-plugin-astro/node_modules/globals": { + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", + "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", + "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "aria-query": "^5.3.2", + "array-includes": "^3.1.8", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "^4.10.0", + "axobject-query": "^4.1.0", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "hasown": "^2.0.2", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "safe-regex-test": "^1.0.3", + "string.prototype.includes": "^2.0.1" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-util-attach-comments": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz", + "integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-build-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz", + "integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-walker": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-scope": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/estree-util-scope/-/estree-util-scope-1.0.0.tgz", + "integrity": "sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-to-js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz", + "integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "astring": "^1.8.0", + "source-map": "^0.7.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-visit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz", + "integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "license": "MIT" + }, + "node_modules/exsolve": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", + "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", + "license": "MIT" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "license": "BSD-2-Clause", + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/flattie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flattie/-/flattie-1.1.1.tgz", + "integrity": "sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/fontace": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/fontace/-/fontace-0.4.0.tgz", + "integrity": "sha512-moThBCItUe2bjZip5PF/iZClpKHGLwMvR79Kp8XpGRBrvoRSnySN4VcILdv3/MJzbhvUA5WeiUXF5o538m5fvg==", + "license": "MIT", + "dependencies": { + "fontkitten": "^1.0.0" + } + }, + "node_modules/fontkitten": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fontkitten/-/fontkitten-1.0.2.tgz", + "integrity": "sha512-piJxbLnkD9Xcyi7dWJRnqszEURixe7CrF/efBfbffe2DPyabmuIuqraruY8cXTs19QoM8VJzx47BDRVNXETM7Q==", + "license": "MIT", + "dependencies": { + "tiny-inflate": "^1.0.3" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", + "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/github-slugger": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", + "license": "ISC" + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/h3": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.5.tgz", + "integrity": "sha512-xEyq3rSl+dhGX2Lm0+eFQIAzlDN6Fs0EcC4f7BNUmzaRX/PTzeuM+Tr2lHB8FoXggsQIeXLj8EDVgs5ywxyxmg==", + "license": "MIT", + "dependencies": { + "cookie-es": "^1.2.2", + "crossws": "^0.3.5", + "defu": "^6.1.4", + "destr": "^2.0.5", + "iron-webcrypto": "^1.2.1", + "node-mock-http": "^1.0.4", + "radix3": "^1.1.2", + "ufo": "^1.6.3", + "uncrypto": "^0.1.3" + } + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-from-html": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", + "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "devlop": "^1.1.0", + "hast-util-from-parse5": "^8.0.0", + "parse5": "^7.0.0", + "vfile": "^6.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-parse5": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", + "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^9.0.0", + "property-information": "^7.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-is-element": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-raw": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.1.0.tgz", + "integrity": "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-from-parse5": "^8.0.0", + "hast-util-to-parse5": "^8.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "parse5": "^7.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-estree": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.3.tgz", + "integrity": "sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-attach-comments": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-html": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", + "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.1.tgz", + "integrity": "sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-text": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz", + "integrity": "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "hast-util-is-element": "^3.0.0", + "unist-util-find-after": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", + "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/html-escaper": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz", + "integrity": "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==", + "license": "MIT" + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/htmlparser2": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz", + "integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "entities": "^7.0.1" + } + }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "license": "BSD-2-Clause" + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inline-style-parser": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", + "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==", + "license": "MIT" + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/iron-webcrypto": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz", + "integrity": "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/brc-dd" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/kolorist": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", + "license": "MIT" + }, + "node_modules/language-subtag-registry": { + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", + "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "license": "MIT", + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lint-staged": { + "version": "16.2.7", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.2.7.tgz", + "integrity": "sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^14.0.2", + "listr2": "^9.0.5", + "micromatch": "^4.0.8", + "nano-spawn": "^2.0.0", + "pidtree": "^0.6.0", + "string-argv": "^0.3.2", + "yaml": "^2.8.1" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=20.17" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/lint-staged/node_modules/commander": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", + "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/listr2": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", + "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^5.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/local-pkg": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.2.tgz", + "integrity": "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==", + "license": "MIT", + "dependencies": { + "mlly": "^1.7.4", + "pkg-types": "^2.3.0", + "quansync": "^0.2.11" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/lru-cache": { + "version": "11.2.4", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", + "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/magicast": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.1.tgz", + "integrity": "sha512-xrHS24IxaLrvuo613F719wvOIv9xPHFWQHuvGUBmPnCA/3MQxKI3b+r7n1jAoDHmsbC5bRhTZYR77invLAxVnw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "source-map-js": "^1.2.1" + } + }, + "node_modules/markdown-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", + "integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdast-util-definitions": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-6.0.0.tgz", + "integrity": "sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", + "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", + "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz", + "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", + "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdn-data": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz", + "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==", + "license": "CC0-1.0" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "license": "MIT", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdx-expression": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.1.tgz", + "integrity": "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-jsx": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.2.tgz", + "integrity": "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdx-md": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz", + "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz", + "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==", + "license": "MIT", + "dependencies": { + "acorn": "^8.0.0", + "acorn-jsx": "^5.0.0", + "micromark-extension-mdx-expression": "^3.0.0", + "micromark-extension-mdx-jsx": "^3.0.0", + "micromark-extension-mdx-md": "^2.0.0", + "micromark-extension-mdxjs-esm": "^3.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs-esm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz", + "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-mdx-expression": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.3.tgz", + "integrity": "sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-events-to-acorn": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.3.tgz", + "integrity": "sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mlly": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", + "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", + "license": "MIT", + "dependencies": { + "acorn": "^8.15.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.1" + } + }, + "node_modules/mlly/node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "license": "MIT" + }, + "node_modules/mlly/node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nano-spawn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/nano-spawn/-/nano-spawn-2.0.0.tgz", + "integrity": "sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/nano-spawn?sponsor=1" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/neotraverse": { + "version": "0.6.18", + "resolved": "https://registry.npmjs.org/neotraverse/-/neotraverse-0.6.18.tgz", + "integrity": "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/nlcst-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-4.0.0.tgz", + "integrity": "sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/node-fetch-native": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", + "license": "MIT" + }, + "node_modules/node-mock-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.4.tgz", + "integrity": "sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==", + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ofetch": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-1.5.1.tgz", + "integrity": "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==", + "license": "MIT", + "dependencies": { + "destr": "^2.0.5", + "node-fetch-native": "^1.6.7", + "ufo": "^1.6.1" + } + }, + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "license": "MIT" + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/oniguruma-parser": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.1.tgz", + "integrity": "sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==", + "license": "MIT" + }, + "node_modules/oniguruma-to-es": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.4.tgz", + "integrity": "sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==", + "license": "MIT", + "dependencies": { + "oniguruma-parser": "^0.12.1", + "regex": "^6.0.1", + "regex-recursion": "^6.0.2" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-limit": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-6.2.0.tgz", + "integrity": "sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-queue": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-8.1.1.tgz", + "integrity": "sha512-aNZ+VfjobsWryoiPnEApGGmf5WmNsCo9xu8dfaYamG5qaLP7ClhLN6NgsFe6SwJ2UbLEBK5dv9x8Mn5+RVhMWQ==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^5.0.1", + "p-timeout": "^6.1.2" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-timeout": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.4.tgz", + "integrity": "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-manager-detector": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.6.0.tgz", + "integrity": "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==", + "license": "MIT" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/parse-latin": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse-latin/-/parse-latin-7.0.0.tgz", + "integrity": "sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0", + "@types/unist": "^3.0.0", + "nlcst-to-string": "^4.0.0", + "unist-util-modify-children": "^4.0.0", + "unist-util-visit-children": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", + "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==", + "license": "MIT", + "dependencies": { + "domhandler": "^5.0.3", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-parser-stream": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz", + "integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==", + "license": "MIT", + "dependencies": { + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "license": "MIT" + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "license": "MIT" + }, + "node_modules/piccolore": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/piccolore/-/piccolore-0.1.3.tgz", + "integrity": "sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==", + "license": "ISC" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/pkg-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "license": "MIT", + "dependencies": { + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-custom-media": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-12.0.0.tgz", + "integrity": "sha512-jIgEvqceN6ru2uQ0f75W1g+JDi0UyECFeJKjPG7UcSkW3+03LDKH2c6h+9C0XuDTV4y2pEHmD5AJtVBq1OGnZA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/cascade-layer-name-parser": "^3.0.0", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0", + "@csstools/media-query-list-parser": "^5.0.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-plugin-astro": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/prettier-plugin-astro/-/prettier-plugin-astro-0.14.1.tgz", + "integrity": "sha512-RiBETaaP9veVstE4vUwSIcdATj6dKmXljouXc/DDNwBSPTp8FRkLGDSGFClKsAFeeg+13SB0Z1JZvbD76bigJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@astrojs/compiler": "^2.9.1", + "prettier": "^3.0.0", + "sass-formatter": "^0.7.6" + }, + "engines": { + "node": "^14.15.0 || >=16.0.0" + } + }, + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/pump": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/quansync": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", + "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/radix3": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz", + "integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==", + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/recma-build-jsx": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz", + "integrity": "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-build-jsx": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-jsx": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/recma-jsx/-/recma-jsx-1.0.1.tgz", + "integrity": "sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w==", + "license": "MIT", + "dependencies": { + "acorn-jsx": "^5.0.0", + "estree-util-to-js": "^2.0.0", + "recma-parse": "^1.0.0", + "recma-stringify": "^1.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/recma-parse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-parse/-/recma-parse-1.0.0.tgz", + "integrity": "sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "esast-util-from-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-stringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-stringify/-/recma-stringify-1.0.0.tgz", + "integrity": "sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-to-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz", + "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-recursion": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", + "license": "MIT" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/rehype": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/rehype/-/rehype-13.0.2.tgz", + "integrity": "sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "rehype-parse": "^9.0.0", + "rehype-stringify": "^10.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-parse": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-9.0.1.tgz", + "integrity": "sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-from-html": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-raw": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", + "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-raw": "^9.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-recma": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rehype-recma/-/rehype-recma-1.0.0.tgz", + "integrity": "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "hast-util-to-estree": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-stringify": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-10.0.1.tgz", + "integrity": "sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-to-html": "^9.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", + "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-mdx": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.1.1.tgz", + "integrity": "sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==", + "license": "MIT", + "dependencies": { + "mdast-util-mdx": "^3.0.0", + "micromark-extension-mdxjs": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-smartypants": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/remark-smartypants/-/remark-smartypants-3.0.2.tgz", + "integrity": "sha512-ILTWeOriIluwEvPjv67v7Blgrcx+LZOkAUVtKI3putuhlZm84FnqDORNXPPm+HY3NdZOMhyDwZ1E+eZB/Df5dA==", + "license": "MIT", + "dependencies": { + "retext": "^9.0.0", + "retext-smartypants": "^6.0.0", + "unified": "^11.0.4", + "unist-util-visit": "^5.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/retext": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/retext/-/retext-9.0.0.tgz", + "integrity": "sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0", + "retext-latin": "^4.0.0", + "retext-stringify": "^4.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/retext-latin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/retext-latin/-/retext-latin-4.0.0.tgz", + "integrity": "sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0", + "parse-latin": "^7.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/retext-smartypants": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/retext-smartypants/-/retext-smartypants-6.2.0.tgz", + "integrity": "sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0", + "nlcst-to-string": "^4.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/retext-stringify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/retext-stringify/-/retext-stringify-4.0.0.tgz", + "integrity": "sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0", + "nlcst-to-string": "^4.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/rollup": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.55.3.tgz", + "integrity": "sha512-y9yUpfQvetAjiDLtNMf1hL9NXchIJgWt6zIKeoB+tCd3npX08Eqfzg60V9DhIGVMtQ0AlMkFw5xa+AQ37zxnAA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.55.3", + "@rollup/rollup-android-arm64": "4.55.3", + "@rollup/rollup-darwin-arm64": "4.55.3", + "@rollup/rollup-darwin-x64": "4.55.3", + "@rollup/rollup-freebsd-arm64": "4.55.3", + "@rollup/rollup-freebsd-x64": "4.55.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.55.3", + "@rollup/rollup-linux-arm-musleabihf": "4.55.3", + "@rollup/rollup-linux-arm64-gnu": "4.55.3", + "@rollup/rollup-linux-arm64-musl": "4.55.3", + "@rollup/rollup-linux-loong64-gnu": "4.55.3", + "@rollup/rollup-linux-loong64-musl": "4.55.3", + "@rollup/rollup-linux-ppc64-gnu": "4.55.3", + "@rollup/rollup-linux-ppc64-musl": "4.55.3", + "@rollup/rollup-linux-riscv64-gnu": "4.55.3", + "@rollup/rollup-linux-riscv64-musl": "4.55.3", + "@rollup/rollup-linux-s390x-gnu": "4.55.3", + "@rollup/rollup-linux-x64-gnu": "4.55.3", + "@rollup/rollup-linux-x64-musl": "4.55.3", + "@rollup/rollup-openbsd-x64": "4.55.3", + "@rollup/rollup-openharmony-arm64": "4.55.3", + "@rollup/rollup-win32-arm64-msvc": "4.55.3", + "@rollup/rollup-win32-ia32-msvc": "4.55.3", + "@rollup/rollup-win32-x64-gnu": "4.55.3", + "@rollup/rollup-win32-x64-msvc": "4.55.3", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/s.color": { + "version": "0.0.15", + "resolved": "https://registry.npmjs.org/s.color/-/s.color-0.0.15.tgz", + "integrity": "sha512-AUNrbEUHeKY8XsYr/DYpl+qk5+aM+DChopnWOPEzn8YKzOhv4l2zH6LzZms3tOZP3wwdOyc0RmTciyi46HLIuA==", + "dev": true, + "license": "MIT" + }, + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/sass-formatter": { + "version": "0.7.9", + "resolved": "https://registry.npmjs.org/sass-formatter/-/sass-formatter-0.7.9.tgz", + "integrity": "sha512-CWZ8XiSim+fJVG0cFLStwDvft1VI7uvXdCNJYXhDvowiv+DsbD1nXLiQ4zrE5UBvj5DWZJ93cwN0NX5PMsr1Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "suf-log": "^2.5.3" + } + }, + "node_modules/sax": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.4.tgz", + "integrity": "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shiki": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-3.21.0.tgz", + "integrity": "sha512-N65B/3bqL/TI2crrXr+4UivctrAGEjmsib5rPMMPpFp1xAx/w03v8WZ9RDDFYteXoEgY7qZ4HGgl5KBIu1153w==", + "license": "MIT", + "dependencies": { + "@shikijs/core": "3.21.0", + "@shikijs/engine-javascript": "3.21.0", + "@shikijs/engine-oniguruma": "3.21.0", + "@shikijs/langs": "3.21.0", + "@shikijs/themes": "3.21.0", + "@shikijs/types": "3.21.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "license": "MIT" + }, + "node_modules/slice-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/smol-toml": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.6.0.tgz", + "integrity": "sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 18" + }, + "funding": { + "url": "https://github.com/sponsors/cyyynthia" + } + }, + "node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string.prototype.includes": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", + "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-to-js": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz", + "integrity": "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==", + "license": "MIT", + "dependencies": { + "style-to-object": "1.0.14" + } + }, + "node_modules/style-to-object": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz", + "integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.7" + } + }, + "node_modules/suf-log": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/suf-log/-/suf-log-2.5.3.tgz", + "integrity": "sha512-KvC8OPjzdNOe+xQ4XWJV2whQA0aM1kGVczMQ8+dStAO6KfEB140JEVQ9dE76ONZ0/Ylf67ni4tILPJB41U0eow==", + "dev": true, + "license": "MIT", + "dependencies": { + "s.color": "0.0.15" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/svgo": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.0.tgz", + "integrity": "sha512-VvrHQ+9uniE+Mvx3+C9IEe/lWasXCU0nXMY2kZeLrHNICuRiC8uMPyM14UEaMOFA5mhyQqEkB02VoQ16n3DLaw==", + "license": "MIT", + "dependencies": { + "commander": "^11.1.0", + "css-select": "^5.1.0", + "css-tree": "^3.0.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.1.1", + "sax": "^1.4.1" + }, + "bin": { + "svgo": "bin/svgo.js" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/synckit": { + "version": "0.11.12", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", + "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.2.9" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" + } + }, + "node_modules/tar": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.7.tgz", + "integrity": "sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", + "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/ts-api-utils": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", + "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tsconfck": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.6.tgz", + "integrity": "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==", + "license": "MIT", + "bin": { + "tsconfck": "bin/tsconfck.js" + }, + "engines": { + "node": "^18 || >=20" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "optional": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.53.1.tgz", + "integrity": "sha512-gB+EVQfP5RDElh9ittfXlhZJdjSU4jUSTyE2+ia8CYyNvet4ElfaLlAIqDvQV9JPknKx0jQH1racTYe/4LaLSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.53.1", + "@typescript-eslint/parser": "8.53.1", + "@typescript-eslint/typescript-estree": "8.53.1", + "@typescript-eslint/utils": "8.53.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/ufo": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", + "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", + "license": "MIT" + }, + "node_modules/ultrahtml": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.6.0.tgz", + "integrity": "sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==", + "license": "MIT" + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/uncrypto": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz", + "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==", + "license": "MIT" + }, + "node_modules/undici": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.19.1.tgz", + "integrity": "sha512-Gpq0iNm5M6cQWlyHQv9MV+uOj1jWk7LpkoE5vSp/7zjb4zMdAcUD+VL5y0nH4p9EbUklq00eVIIX/XcDHzu5xg==", + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "license": "MIT", + "optional": true + }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unifont": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/unifont/-/unifont-0.7.3.tgz", + "integrity": "sha512-b0GtQzKCyuSHGsfj5vyN8st7muZ6VCI4XD4vFlr7Uy1rlWVYxC3npnfk8MyreHxJYrz1ooLDqDzFe9XqQTlAhA==", + "license": "MIT", + "dependencies": { + "css-tree": "^3.1.0", + "ofetch": "^1.5.1", + "ohash": "^2.0.11" + } + }, + "node_modules/unist-util-find-after": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", + "integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-modify-children": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-modify-children/-/unist-util-modify-children-4.0.0.tgz", + "integrity": "sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "array-iterate": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz", + "integrity": "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", + "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-children": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit-children/-/unist-util-visit-children-3.0.0.tgz", + "integrity": "sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unstorage": { + "version": "1.17.4", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.4.tgz", + "integrity": "sha512-fHK0yNg38tBiJKp/Vgsq4j0JEsCmgqH58HAn707S7zGkArbZsVr/CwINoi+nh3h98BRCwKvx1K3Xg9u3VV83sw==", + "license": "MIT", + "dependencies": { + "anymatch": "^3.1.3", + "chokidar": "^5.0.0", + "destr": "^2.0.5", + "h3": "^1.15.5", + "lru-cache": "^11.2.0", + "node-fetch-native": "^1.6.7", + "ofetch": "^1.5.1", + "ufo": "^1.6.3" + }, + "peerDependencies": { + "@azure/app-configuration": "^1.8.0", + "@azure/cosmos": "^4.2.0", + "@azure/data-tables": "^13.3.0", + "@azure/identity": "^4.6.0", + "@azure/keyvault-secrets": "^4.9.0", + "@azure/storage-blob": "^12.26.0", + "@capacitor/preferences": "^6 || ^7 || ^8", + "@deno/kv": ">=0.9.0", + "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", + "@planetscale/database": "^1.19.0", + "@upstash/redis": "^1.34.3", + "@vercel/blob": ">=0.27.1", + "@vercel/functions": "^2.2.12 || ^3.0.0", + "@vercel/kv": "^1 || ^2 || ^3", + "aws4fetch": "^1.0.20", + "db0": ">=0.2.1", + "idb-keyval": "^6.2.1", + "ioredis": "^5.4.2", + "uploadthing": "^7.4.4" + }, + "peerDependenciesMeta": { + "@azure/app-configuration": { + "optional": true + }, + "@azure/cosmos": { + "optional": true + }, + "@azure/data-tables": { + "optional": true + }, + "@azure/identity": { + "optional": true + }, + "@azure/keyvault-secrets": { + "optional": true + }, + "@azure/storage-blob": { + "optional": true + }, + "@capacitor/preferences": { + "optional": true + }, + "@deno/kv": { + "optional": true + }, + "@netlify/blobs": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@upstash/redis": { + "optional": true + }, + "@vercel/blob": { + "optional": true + }, + "@vercel/functions": { + "optional": true + }, + "@vercel/kv": { + "optional": true + }, + "aws4fetch": { + "optional": true + }, + "db0": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "uploadthing": { + "optional": true + } + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-location": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vite": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", + "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", + "license": "MIT", + "peer": true, + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vitefu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.1.tgz", + "integrity": "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==", + "license": "MIT", + "workspaces": [ + "tests/deps/*", + "tests/projects/*", + "tests/projects/workspace/packages/*" + ], + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-pm-runs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz", + "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.20", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", + "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/widest-line": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-5.0.0.tgz", + "integrity": "sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==", + "license": "MIT", + "dependencies": { + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/xxhash-wasm": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.1.0.tgz", + "integrity": "sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==", + "license": "MIT" + }, + "node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/yaml": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "devOptional": true, + "license": "ISC", + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yocto-queue": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", + "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yocto-spinner": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/yocto-spinner/-/yocto-spinner-0.2.3.tgz", + "integrity": "sha512-sqBChb33loEnkoXte1bLg45bEBsOP9N1kzQh5JZNKj/0rik4zAPTNSAVPj3uQAdc6slYJ0Ksc403G2XgxsJQFQ==", + "license": "MIT", + "dependencies": { + "yoctocolors": "^2.1.1" + }, + "engines": { + "node": ">=18.19" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yoctocolors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", + "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", + "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.25 || ^4" + } + }, + "node_modules/zod-to-ts": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/zod-to-ts/-/zod-to-ts-1.2.0.tgz", + "integrity": "sha512-x30XE43V+InwGpvTySRNz9kB7qFU8DlyEy7BsSTCHPH1R0QasMmHWZDCzYm6bVXtj/9NNJAZF3jW8rzFvH5OFA==", + "peerDependencies": { + "typescript": "^4.9.4 || ^5.0.2", + "zod": "^3" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/astro/package.json b/astro/package.json new file mode 100644 index 0000000000..5e4a3d8d52 --- /dev/null +++ b/astro/package.json @@ -0,0 +1,53 @@ +{ + "name": "expressjs-astro-project", + "type": "module", + "version": "0.0.1", + "scripts": { + "dev": "astro dev", + "build": "astro build", + "preview": "astro preview", + "astro": "astro", + "lint": "eslint .", + "lint:fix": "eslint . --fix", + "format": "prettier --write .", + "format:check": "prettier --check .", + "check": "npm run format:check && npm run lint", + "fix": "npm run format && npm run lint:fix" + }, + "dependencies": { + "@astrojs/mdx": "^4.3.13", + "astro": "^5.16.11", + "astro-icon": "^1.1.5" + }, + "devEngines": { + "runtime": { + "name": "node", + "version": ">=24.13.0", + "onFail": "error" + }, + "packageManager": { + "name": "npm", + "version": ">=11.0.0", + "onFail": "error" + } + }, + "engines": { + "node": ">=24.13.0", + "npm": ">=11.0.0" + }, + "devDependencies": { + "@csstools/postcss-global-data": "^4.0.0", + "@eslint/js": "^9.39.2", + "@iconify-json/ph": "^1.2.2", + "eslint": "^9.39.2", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-astro": "^1.5.0", + "eslint-plugin-jsx-a11y": "^6.10.2", + "lint-staged": "^16.2.7", + "postcss-custom-media": "^12.0.0", + "prettier": "^3.8.1", + "prettier-plugin-astro": "^0.14.1", + "typescript": "^5.9.3", + "typescript-eslint": "^8.53.1" + } +} diff --git a/astro/postcss.config.mjs b/astro/postcss.config.mjs new file mode 100644 index 0000000000..ef00bed1ed --- /dev/null +++ b/astro/postcss.config.mjs @@ -0,0 +1,11 @@ +import postcssGlobalData from '@csstools/postcss-global-data'; +import postcssCustomMedia from 'postcss-custom-media'; + +export default { + plugins: [ + postcssGlobalData({ + files: ['./src/styles/tokens/_breakpoints.css'], + }), + postcssCustomMedia(), + ], +}; diff --git a/astro/public/apple-touch-icon.png b/astro/public/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..1246e42e69eabd7f20aa34b8adabd23a0ea0a24f GIT binary patch literal 3557 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 GB>V?fYpJ^c literal 0 HcmV?d00001 diff --git a/astro/public/favicon.ico b/astro/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..45865d9e1760331075c67f54aa226720f470ca80 GIT binary patch literal 15086 zcmeI3O>WyT5QSN^2guqhZwhpoRoA_PFVJOAlAZ6-llU0DO3KgZ0|o;Qe-z0wR1%Pf z9L~J=IAoMaa8mk|KBw2$l_QhLh)-*QY&Nk8+2 zKWeAb>3v?a2J;NeGceDoq%@QGps>6M$WZ#kK}9- zt2&O<9v#o1pEFFuj@D*x{U6c3cl|jlG-^0ncg6SCA1-R8D>|oC_LrD)9b`P}HQfvvg z$G3+5h(~(02CVu~&ZxhnpZeI^iMM8>nv!F&M)kGgd-UH0G(Ku)jX7FN%aZw$esE|# zd+qniYtX**;`#j6xTYV@R=)I0r;XPfzOBwtq`#N1b~ZeAFQ%-88t5Ot{y&O*3vKS*k0~6;?~ely=h>rp=ktT z4gFxyMtIkX6}Q&0#G?I?XWp)z^SVT{&3W{hxB6#)|98-H59S`sGceD)L`J zO!#Yc*IdMp-!|}6ODyxkuvT@qzFNP;uV;7Vf$8g6$|Ig8oyxCSk5khRwq3X9@)~Qr zn)CdA?TW*q&904Hn&!y0@jd+#zc|F_t;JQoa_n4BU-^nv4e_fM-YQnsW60lQeXbu{ z3~BN{# zPn^{xe`F*6C?5ZkoCt3ei+I)^;f?x7_)B{}%ID+ZA8EvUj5$8W-=cFL|BrpluLpK* zyr;lko?}?r{b#Rqd|DGiZ9*UiBX(>?=cpRa%6=it9)-2 zkL41F@?@2#7&}&sur#(-@%R*nPknD~E`6J?yi$&hvlx*d4CZWX)F-xdMe#@RfAl8x E7eqR0UjP6A literal 0 HcmV?d00001 diff --git a/astro/public/favicon.svg b/astro/public/favicon.svg new file mode 100644 index 0000000000..a026d6f3ed --- /dev/null +++ b/astro/public/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/astro/public/fonts/JetBrainsMono-Light.woff2 b/astro/public/fonts/JetBrainsMono-Light.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..65384987368389e57b7d1fef5ebbed55fc6fdd17 GIT binary patch literal 93856 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

da86Jexg>>4 zxFnY_m!KpdpK_4fDRT)aJFHnT-4=;e)Nor+8CHQpyZF;k+Ka7VG?jVV3U=C>?dOS)7FU?wf*8%e8Yd zC#}jyqkd$MH$>(NzRPhO&s*x%8uNy5UJtDE0q%29%T45DPU1}#e@UPce>S#P_frPg zdJ%}u3dMDTle0XWlfg-dyGHL6gJy{W4U6<=0fif)gLQ78+xG!Uz0qX8Bv4D=jfcIr z<2q5nnQfKWwR1lTMyiN~mwuJRRbGHWTTo&$YsZO@+?Y1180u%&UihuxY zn?)Sd39r2&7!k+C;VDv2tfnC{fRoC&Wz0!RKWYgyjcd@FaSf*RGPOa@Ml7g(SZw)N z>`4eI>lQbXdH^DWLu&=B_Iw1BuzEx+Bg<1*4!NjRW1m^kPQ>9}p|cf?`ioOKT2$GDnkma@>%zuP#4kMI#33B*af3Gv7%A0o-K%0D_6 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 literal 0 HcmV?d00001 diff --git a/astro/public/fonts/JetBrainsMono-LightItalic.woff2 b/astro/public/fonts/JetBrainsMono-LightItalic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..66ca3d2b993159bd9624275004f31f3546ce3556 GIT binary patch literal 97280 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 E0Tw4E$^ZZW literal 0 HcmV?d00001 diff --git a/astro/public/site.webmanifest b/astro/public/site.webmanifest new file mode 100644 index 0000000000..3fbbdf62be --- /dev/null +++ b/astro/public/site.webmanifest @@ -0,0 +1,21 @@ +{ + "name": "Express.js", + "short_name": "Express.js", + "icons": [ + { + "src": "/web-app-manifest-192x192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "/web-app-manifest-512x512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ], + "theme_color": "#ffffff", + "background_color": "#1a1a1a", + "display": "standalone" +} diff --git a/astro/src/components/patterns/Breadcrumbs/Breadcrumbs.astro b/astro/src/components/patterns/Breadcrumbs/Breadcrumbs.astro new file mode 100644 index 0000000000..220e6db0b3 --- /dev/null +++ b/astro/src/components/patterns/Breadcrumbs/Breadcrumbs.astro @@ -0,0 +1,35 @@ +--- +/** + * Breadcrumbs Component + * Renders a breadcrumb navigation based on provided items + * TODO: wip - Improve styling and accessibility in future iterations + */ +import { Body } from '@components/primitives'; +import { Icon } from 'astro-icon/components'; +import type { BreadcrumbItem } from '@utils/breadcrumb'; + +interface Props { + items: BreadcrumbItem[]; +} + +const { items } = Astro.props; +--- + +

diff --git a/astro/src/components/patterns/ThemeSwitcher/ThemeSwitcher.astro b/astro/src/components/patterns/ThemeSwitcher/ThemeSwitcher.astro new file mode 100644 index 0000000000..1b58c4dbef --- /dev/null +++ b/astro/src/components/patterns/ThemeSwitcher/ThemeSwitcher.astro @@ -0,0 +1,85 @@ +--- +/** + * TODO: wip - improve styling and accessibility in future iterations + * Theme Switcher Component + * Allows users to toggle between light and dark themes + * Persists theme preference to localStorage + */ + +import { Icon } from 'astro-icon/components'; +--- + + + + + + diff --git a/astro/src/components/patterns/index.ts b/astro/src/components/patterns/index.ts new file mode 100644 index 0000000000..5bf3c6214e --- /dev/null +++ b/astro/src/components/patterns/index.ts @@ -0,0 +1,8 @@ +/** + * Index + * + * Re-export all primitive components for easy importing + */ + +export { default as Breadcrumbs } from './Breadcrumbs/Breadcrumbs.astro'; +export { default as ThemeSwitcher } from './ThemeSwitcher/ThemeSwitcher.astro'; diff --git a/astro/src/components/primitives/Button/Button.astro b/astro/src/components/primitives/Button/Button.astro new file mode 100644 index 0000000000..8e1e2481d7 --- /dev/null +++ b/astro/src/components/primitives/Button/Button.astro @@ -0,0 +1,48 @@ +--- +/** + * Button Primitive Component + * + * Interactive button with support for icon slots and variants. + * Can render as button, anchor, or any interactive element. + * + * @example + * + * + * + */ + +import type { HTMLAttributes } from 'astro/types'; +import type { ButtonSize, ButtonVariant, ButtonHTMLTag, ButtonBaseProps } from './types'; +import './Button.css'; + +type Props = + | ({ as?: 'a' } & ButtonBaseProps & HTMLAttributes<'a'>) + | ({ as?: 'button' } & ButtonBaseProps & HTMLAttributes<'button'>); + +const { + as: Tag = 'button', + size = 'md', + variant = 'primary', + ghost = false, + type = 'button', + class: className, + ...rest +} = Astro.props; +--- + + + + diff --git a/astro/src/components/primitives/Button/Button.css b/astro/src/components/primitives/Button/Button.css new file mode 100644 index 0000000000..ce9035e233 --- /dev/null +++ b/astro/src/components/primitives/Button/Button.css @@ -0,0 +1,85 @@ +/** + * Button Component Styles + */ + +/* ============================================ + BASE STYLES + ============================================ */ + +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + gap: var(--space-2); + line-height: var(--line-height-normal); + border: 1px solid; + border-radius: var(--radius-base); + cursor: pointer; + transition: all 0.2s ease; + white-space: nowrap; + text-decoration: none; + + &:disabled { + cursor: not-allowed; + opacity: 0.6; + } +} + +/* ============================================ + SIZES + ============================================ */ + +.btn--size-md { + padding: var(--space-3); + font-size: var(--font-size-sm); +} + +.btn--size-sm { + padding: var(--space-2) var(--space-4); + font-size: var(--font-size-xs); +} + +.btn--size-xs { + padding: var(--space-1) var(--space-2); + font-size: var(--font-size-xxs); +} + +/* ============================================ + VARIANTS + ============================================ */ + +/* Primary variant */ +.btn--variant-primary { + background-color: var(--color-bg-inverse); + color: var(--color-text-inverse); + border-color: var(--color-border-inverse); + + &:hover:not(:disabled) { + background-color: var(--color-bg-inverse-secondary); + color: var(--color-text-inverse); + } +} + +/* Secondary variant */ +.btn--variant-secondary { + background-color: var(--color-bg-primary); + color: var(--color-text-primary); + border-color: var(--color-border-primary); + + &:hover:not(:disabled) { + background-color: var(--color-bg-tertiary); + border-color: var(--color-border-secondary); + color: var(--color-text-primary); + } +} + +/* ============================================ + GHOST MODIFIER + ============================================ */ + +.btn--ghost { + &:not(:hover):not(:disabled) { + border-color: transparent; + background-color: transparent; + } +} diff --git a/astro/src/components/primitives/Button/index.ts b/astro/src/components/primitives/Button/index.ts new file mode 100644 index 0000000000..589efc1a68 --- /dev/null +++ b/astro/src/components/primitives/Button/index.ts @@ -0,0 +1,6 @@ +/** + * Button Component Exports + */ + +export { default as Button } from './Button.astro'; +export type { ButtonBaseProps, ButtonSize, ButtonVariant, ButtonHTMLTag } from './types'; diff --git a/astro/src/components/primitives/Button/types.ts b/astro/src/components/primitives/Button/types.ts new file mode 100644 index 0000000000..2794c78ba5 --- /dev/null +++ b/astro/src/components/primitives/Button/types.ts @@ -0,0 +1,22 @@ +/** + * Button Component Types + */ + +export type ButtonSize = 'md' | 'sm' | 'xs'; + +export type ButtonVariant = 'primary' | 'secondary'; + +export type ButtonHTMLTag = 'button' | 'a'; + +export interface ButtonBaseProps { + /** HTML element to render */ + as?: ButtonHTMLTag; + /** Button size variant */ + size?: ButtonSize; + /** Button style variant */ + variant?: ButtonVariant; + /** Ghost style (no background) */ + ghost?: boolean; + /** Button type (only for button element) */ + type?: 'button' | 'submit' | 'reset'; +} diff --git a/astro/src/components/primitives/Container/Container.astro b/astro/src/components/primitives/Container/Container.astro new file mode 100644 index 0000000000..8e7677091b --- /dev/null +++ b/astro/src/components/primitives/Container/Container.astro @@ -0,0 +1,26 @@ +--- +/** + * Container Layout Primitive + * + * Centers content with a max-width constraint. + * Use for page-level content wrapping. + * + * @example + * + *

Page Title

+ * Content goes here + *
+ */ + +import type { HTMLAttributes } from 'astro/types'; +import type { ContainerProps } from './types'; +import './Container.css'; + +interface Props extends HTMLAttributes<'div'>, ContainerProps {} + +const { as: Tag = 'div', class: className, ...rest } = Astro.props; +--- + + + + diff --git a/astro/src/components/primitives/Container/Container.css b/astro/src/components/primitives/Container/Container.css new file mode 100644 index 0000000000..164c305006 --- /dev/null +++ b/astro/src/components/primitives/Container/Container.css @@ -0,0 +1,13 @@ +/** + * Container Component Styles + */ + +.container { + width: 90%; + max-width: 1440px; + margin-inline: auto; + + @media (--lg-up) { + width: 95%; + } +} diff --git a/astro/src/components/primitives/Container/index.ts b/astro/src/components/primitives/Container/index.ts new file mode 100644 index 0000000000..ebbf2d2f82 --- /dev/null +++ b/astro/src/components/primitives/Container/index.ts @@ -0,0 +1,2 @@ +export { default as Container } from './Container.astro'; +export type { ContainerProps, ContainerHTMLTag } from './types'; diff --git a/astro/src/components/primitives/Container/types.ts b/astro/src/components/primitives/Container/types.ts new file mode 100644 index 0000000000..ae7781dcbf --- /dev/null +++ b/astro/src/components/primitives/Container/types.ts @@ -0,0 +1,18 @@ +/** + * Container Component Types + */ + +export type ContainerHTMLTag = + | 'div' + | 'section' + | 'article' + | 'main' + | 'header' + | 'footer' + | 'aside' + | 'nav'; + +export interface ContainerProps { + /** HTML element to render */ + as?: ContainerHTMLTag; +} diff --git a/astro/src/components/primitives/Grid/Col.astro b/astro/src/components/primitives/Grid/Col.astro new file mode 100644 index 0000000000..456a4004b1 --- /dev/null +++ b/astro/src/components/primitives/Grid/Col.astro @@ -0,0 +1,27 @@ +--- +/** + * Col Component + * + * Responsive grid column. Spans 1-12 columns out of 12-column grid. + * Breakpoint props cascade: xs → md → lg + * + * @example + * Full mobile, half tablet, third desktop + * Always half width + */ + +import type { HTMLAttributes } from 'astro/types'; +import type { ColProps } from './types'; +import './Grid.css'; + +type Props = ColProps & HTMLAttributes<'div'>; + +const { xs, md, lg, class: className, ...rest } = Astro.props; +--- + +
+ +
diff --git a/astro/src/components/primitives/Grid/Flex.astro b/astro/src/components/primitives/Grid/Flex.astro new file mode 100644 index 0000000000..d4ebf20e82 --- /dev/null +++ b/astro/src/components/primitives/Grid/Flex.astro @@ -0,0 +1,37 @@ +--- +/** + * Flex Component + * + * Flexbox container for 1D layouts. + * Use for simple directional layouts, navbars, stacks. + * + * @example + * + *
Item 1
+ *
Item 2
+ *
+ */ + +import type { HTMLAttributes } from 'astro/types'; +import type { FlexProps } from './types'; +import './Grid.css'; + +type Props = FlexProps & HTMLAttributes<'div'>; + +const { direction = 'row', align, justify, wrap, gap, class: className, ...rest } = Astro.props; +--- + +
+ +
diff --git a/astro/src/components/primitives/Grid/FlexItem.astro b/astro/src/components/primitives/Grid/FlexItem.astro new file mode 100644 index 0000000000..810146cc46 --- /dev/null +++ b/astro/src/components/primitives/Grid/FlexItem.astro @@ -0,0 +1,35 @@ +--- +/** + * FlexItem Component + * + * Wrapper for flex items with control over grow, shrink, and basis. + * Use inside a Flex component to control individual item behavior. + * + * @example + * + * Flexible item + * Auto-sized item + * + */ + +import type { HTMLAttributes } from 'astro/types'; +import type { FlexItemProps } from './types'; +import './Grid.css'; + +type Props = FlexItemProps & HTMLAttributes<'div'>; + +const { grow, shrink, basis, flex, class: className, ...rest } = Astro.props; +--- + +
+ +
diff --git a/astro/src/components/primitives/Grid/Grid.astro b/astro/src/components/primitives/Grid/Grid.astro new file mode 100644 index 0000000000..e9b4f78be4 --- /dev/null +++ b/astro/src/components/primitives/Grid/Grid.astro @@ -0,0 +1,34 @@ +--- +/** + * Grid Component + * + * 12-column responsive grid container. + * Use with children for responsive column layouts. + * + * @example + * + * Content + * + */ + +import type { HTMLAttributes } from 'astro/types'; +import type { GridProps } from './types'; +import './Grid.css'; + +type Props = GridProps & HTMLAttributes<'div'>; + +const { gap, rowGap, columnGap, class: className, ...rest } = Astro.props; +--- + +
+ +
diff --git a/astro/src/components/primitives/Grid/Grid.css b/astro/src/components/primitives/Grid/Grid.css new file mode 100644 index 0000000000..07193b70ba --- /dev/null +++ b/astro/src/components/primitives/Grid/Grid.css @@ -0,0 +1,532 @@ +/** + * Grid System Styles + * + * 12-column responsive grid with breakpoint support + * Includes both component classes and utility classes + */ + +/* ============================================ + GRID COMPONENT + ============================================ */ + +.grid { + display: grid; + grid-template-columns: repeat(12, 1fr); +} + +/* Grid Gaps */ +.grid--gap-0 { + gap: 0; +} +.grid--gap-1 { + gap: var(--space-1); +} +.grid--gap-2 { + gap: var(--space-2); +} +.grid--gap-3 { + gap: var(--space-3); +} +.grid--gap-4 { + gap: var(--space-4); +} +.grid--gap-6 { + gap: var(--space-6); +} +.grid--gap-8 { + gap: var(--space-8); +} +.grid--gap-12 { + gap: var(--space-12); +} +.grid--gap-16 { + gap: var(--space-16); +} + +/* Row Gaps */ +.grid--row-gap-0 { + row-gap: 0; +} +.grid--row-gap-1 { + row-gap: var(--space-1); +} +.grid--row-gap-2 { + row-gap: var(--space-2); +} +.grid--row-gap-3 { + row-gap: var(--space-3); +} +.grid--row-gap-4 { + row-gap: var(--space-4); +} +.grid--row-gap-6 { + row-gap: var(--space-6); +} +.grid--row-gap-8 { + row-gap: var(--space-8); +} +.grid--row-gap-12 { + row-gap: var(--space-12); +} +.grid--row-gap-16 { + row-gap: var(--space-16); +} + +/* Column Gaps */ +.grid--col-gap-0 { + column-gap: 0; +} +.grid--col-gap-1 { + column-gap: var(--space-1); +} +.grid--col-gap-2 { + column-gap: var(--space-2); +} +.grid--col-gap-3 { + column-gap: var(--space-3); +} +.grid--col-gap-4 { + column-gap: var(--space-4); +} +.grid--col-gap-6 { + column-gap: var(--space-6); +} +.grid--col-gap-8 { + column-gap: var(--space-8); +} +.grid--col-gap-12 { + column-gap: var(--space-12); +} +.grid--col-gap-16 { + column-gap: var(--space-16); +} + +/* ============================================ + COL COMPONENT (Responsive Column Spans) + ============================================ */ + +/* Mobile (xs) - Base spans */ +.col-xs-1 { + grid-column: span 1; +} +.col-xs-2 { + grid-column: span 2; +} +.col-xs-3 { + grid-column: span 3; +} +.col-xs-4 { + grid-column: span 4; +} +.col-xs-5 { + grid-column: span 5; +} +.col-xs-6 { + grid-column: span 6; +} +.col-xs-7 { + grid-column: span 7; +} +.col-xs-8 { + grid-column: span 8; +} +.col-xs-9 { + grid-column: span 9; +} +.col-xs-10 { + grid-column: span 10; +} +.col-xs-11 { + grid-column: span 11; +} +.col-xs-12 { + grid-column: span 12; +} + +/* Tablet (md) breakpoint */ +@media (--md-only) { + .col-md-1 { + grid-column: span 1; + } + .col-md-2 { + grid-column: span 2; + } + .col-md-3 { + grid-column: span 3; + } + .col-md-4 { + grid-column: span 4; + } + .col-md-5 { + grid-column: span 5; + } + .col-md-6 { + grid-column: span 6; + } + .col-md-7 { + grid-column: span 7; + } + .col-md-8 { + grid-column: span 8; + } + .col-md-9 { + grid-column: span 9; + } + .col-md-10 { + grid-column: span 10; + } + .col-md-11 { + grid-column: span 11; + } + .col-md-12 { + grid-column: span 12; + } +} + +/* Desktop (lg) breakpoint */ +@media (--lg-up) { + .col-lg-1 { + grid-column: span 1; + } + .col-lg-2 { + grid-column: span 2; + } + .col-lg-3 { + grid-column: span 3; + } + .col-lg-4 { + grid-column: span 4; + } + .col-lg-5 { + grid-column: span 5; + } + .col-lg-6 { + grid-column: span 6; + } + .col-lg-7 { + grid-column: span 7; + } + .col-lg-8 { + grid-column: span 8; + } + .col-lg-9 { + grid-column: span 9; + } + .col-lg-10 { + grid-column: span 10; + } + .col-lg-11 { + grid-column: span 11; + } + .col-lg-12 { + grid-column: span 12; + } +} + +/* ============================================ + FLEX COMPONENT + ============================================ */ + +.flex { + display: flex; +} + +/* Direction */ +.flex--row { + flex-direction: row; +} +.flex--column { + flex-direction: column; +} +.flex--row-reverse { + flex-direction: row-reverse; +} +.flex--column-reverse { + flex-direction: column-reverse; +} + +/* Align Items */ +.flex--align-start { + align-items: flex-start; +} +.flex--align-center { + align-items: center; +} +.flex--align-end { + align-items: flex-end; +} +.flex--align-stretch { + align-items: stretch; +} +.flex--align-baseline { + align-items: baseline; +} + +/* Justify Content */ +.flex--justify-start { + justify-content: flex-start; +} +.flex--justify-center { + justify-content: center; +} +.flex--justify-end { + justify-content: flex-end; +} +.flex--justify-between { + justify-content: space-between; +} +.flex--justify-around { + justify-content: space-around; +} +.flex--justify-evenly { + justify-content: space-evenly; +} + +/* Wrap */ +.flex--nowrap { + flex-wrap: nowrap; +} +.flex--wrap { + flex-wrap: wrap; +} +.flex--wrap-reverse { + flex-wrap: wrap-reverse; +} + +/* Flex Gaps */ +.flex--gap-0 { + gap: 0; +} +.flex--gap-1 { + gap: var(--space-1); +} +.flex--gap-2 { + gap: var(--space-2); +} +.flex--gap-3 { + gap: var(--space-3); +} +.flex--gap-4 { + gap: var(--space-4); +} +.flex--gap-6 { + gap: var(--space-6); +} +.flex--gap-8 { + gap: var(--space-8); +} +.flex--gap-12 { + gap: var(--space-12); +} +.flex--gap-16 { + gap: var(--space-16); +} + +/* ============================================ + FLEX ITEM COMPONENT + ============================================ */ + +/* Flex Grow */ +.flex-item--grow-0 { + flex-grow: 0; +} +.flex-item--grow-1 { + flex-grow: 1; +} + +/* Flex Shrink */ +.flex-item--shrink-0 { + flex-shrink: 0; +} +.flex-item--shrink-1 { + flex-shrink: 1; +} + +/* Flex Basis */ +.flex-item--basis-0 { + flex-basis: 0; +} +.flex-item--basis-auto { + flex-basis: auto; +} +.flex-item--basis-full { + flex-basis: 100%; +} +.flex-item--basis-1\/2 { + flex-basis: 50%; +} +.flex-item--basis-1\/3 { + flex-basis: 33.333333%; +} +.flex-item--basis-2\/3 { + flex-basis: 66.666667%; +} +.flex-item--basis-1\/4 { + flex-basis: 25%; +} +.flex-item--basis-3\/4 { + flex-basis: 75%; +} + +/* Flex Shorthand */ +.flex-item--flex-1 { + flex: 1 1 0%; +} +.flex-item--flex-auto { + flex: 1 1 auto; +} +.flex-item--flex-initial { + flex: 0 1 auto; +} +.flex-item--flex-none { + flex: none; +} + +/* ============================================ + UTILITY CLASSES + ============================================ */ + +/* Grid Utilities */ +.grid { + display: grid; +} + +.grid-cols-1 { + grid-template-columns: repeat(1, 1fr); +} +.grid-cols-2 { + grid-template-columns: repeat(2, 1fr); +} +.grid-cols-3 { + grid-template-columns: repeat(3, 1fr); +} +.grid-cols-4 { + grid-template-columns: repeat(4, 1fr); +} +.grid-cols-6 { + grid-template-columns: repeat(6, 1fr); +} +.grid-cols-12 { + grid-template-columns: repeat(12, 1fr); +} + +/* Responsive Grid Utilities */ +@media (--md-only) { + .md-grid-cols-1 { + grid-template-columns: repeat(1, 1fr); + } + .md-grid-cols-2 { + grid-template-columns: repeat(2, 1fr); + } + .md-grid-cols-3 { + grid-template-columns: repeat(3, 1fr); + } + .md-grid-cols-4 { + grid-template-columns: repeat(4, 1fr); + } + .md-grid-cols-6 { + grid-template-columns: repeat(6, 1fr); + } + .md-grid-cols-12 { + grid-template-columns: repeat(12, 1fr); + } +} + +@media (--lg-up) { + .lg-grid-cols-1 { + grid-template-columns: repeat(1, 1fr); + } + .lg-grid-cols-2 { + grid-template-columns: repeat(2, 1fr); + } + .lg-grid-cols-3 { + grid-template-columns: repeat(3, 1fr); + } + .lg-grid-cols-4 { + grid-template-columns: repeat(4, 1fr); + } + .lg-grid-cols-6 { + grid-template-columns: repeat(6, 1fr); + } + .lg-grid-cols-12 { + grid-template-columns: repeat(12, 1fr); + } +} + +/* Column Span Utilities */ +.col-span-full { + grid-column: 1 / -1; +} +.col-span-1 { + grid-column: span 1; +} +.col-span-2 { + grid-column: span 2; +} +.col-span-3 { + grid-column: span 3; +} +.col-span-4 { + grid-column: span 4; +} +.col-span-6 { + grid-column: span 6; +} +.col-span-12 { + grid-column: span 12; +} + +/* Flex Utilities */ +.flex { + display: flex; +} +.flex-row { + flex-direction: row; +} +.flex-col { + flex-direction: column; +} +.items-start { + align-items: flex-start; +} +.items-center { + align-items: center; +} +.items-end { + align-items: flex-end; +} +.justify-start { + justify-content: flex-start; +} +.justify-center { + justify-content: center; +} +.justify-end { + justify-content: flex-end; +} +.justify-between { + justify-content: space-between; +} +.flex-wrap { + flex-wrap: wrap; +} + +/* Gap Utilities */ +.gap-1 { + gap: var(--space-1); +} +.gap-2 { + gap: var(--space-2); +} +.gap-3 { + gap: var(--space-3); +} +.gap-4 { + gap: var(--space-4); +} +.gap-6 { + gap: var(--space-6); +} +.gap-8 { + gap: var(--space-8); +} diff --git a/astro/src/components/primitives/Grid/index.ts b/astro/src/components/primitives/Grid/index.ts new file mode 100644 index 0000000000..0dc718bcaf --- /dev/null +++ b/astro/src/components/primitives/Grid/index.ts @@ -0,0 +1,12 @@ +/** + * Grid Layout Components + * + * Responsive grid system with 12-column layout + */ + +export { default as Grid } from './Grid.astro'; +export { default as Col } from './Col.astro'; +export { default as Flex } from './Flex.astro'; +export { default as FlexItem } from './FlexItem.astro'; + +export type { GridProps, ColProps, FlexProps, FlexItemProps, GapSize } from './types'; diff --git a/astro/src/components/primitives/Grid/types.ts b/astro/src/components/primitives/Grid/types.ts new file mode 100644 index 0000000000..d28fff8dbe --- /dev/null +++ b/astro/src/components/primitives/Grid/types.ts @@ -0,0 +1,70 @@ +/** + * Grid System Component Types + */ + +// Shared +export type GapSize = '0' | '1' | '2' | '3' | '4' | '6' | '8' | '12' | '16'; + +// Grid +export interface GridProps { + /** Gap between grid items */ + gap?: GapSize; + /** Vertical gap override */ + rowGap?: GapSize; + /** Horizontal gap override */ + columnGap?: GapSize; +} + +// Col +export type ColSpan = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; + +export interface ColProps { + /** Column span for mobile (xs) breakpoint */ + xs?: ColSpan; + /** Column span for tablet (md) breakpoint */ + md?: ColSpan; + /** Column span for desktop (lg) breakpoint */ + lg?: ColSpan; +} + +// Flex +export type FlexDirection = 'row' | 'column' | 'row-reverse' | 'column-reverse'; + +export type FlexAlign = 'start' | 'center' | 'end' | 'stretch' | 'baseline'; + +export type FlexJustify = 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly'; + +export type FlexWrap = 'nowrap' | 'wrap' | 'wrap-reverse'; + +export interface FlexProps { + /** Flex direction */ + direction?: FlexDirection; + /** Align items on cross axis */ + align?: FlexAlign; + /** Justify content on main axis */ + justify?: FlexJustify; + /** Flex wrap behavior */ + wrap?: FlexWrap; + /** Gap between flex items */ + gap?: GapSize; +} + +// FlexItem +export type FlexGrow = boolean; + +export type FlexShrink = boolean; + +export type FlexBasis = '0' | 'auto' | 'full' | '1/2' | '1/3' | '2/3' | '1/4' | '3/4'; + +export type FlexShorthand = '1' | 'auto' | 'initial' | 'none'; + +export interface FlexItemProps { + /** Flex grow factor (ability to grow) */ + grow?: FlexGrow; + /** Flex shrink factor (ability to shrink) */ + shrink?: FlexShrink; + /** Flex basis (initial size) */ + basis?: FlexBasis; + /** Flex shorthand (overrides grow/shrink/basis) */ + flex?: FlexShorthand; +} diff --git a/astro/src/components/primitives/Typography/Body.astro b/astro/src/components/primitives/Typography/Body.astro new file mode 100644 index 0000000000..ca013e23a8 --- /dev/null +++ b/astro/src/components/primitives/Typography/Body.astro @@ -0,0 +1,30 @@ +--- +/** + * Body - Default paragraph text + * + * @example + * Regular paragraph text. + * Inline body text + */ + +import type { HTMLAttributes } from 'astro/types'; +import Typography from './Typography.astro'; +import type { TypographyColor, TypographyWeight } from './Typography.astro'; + +type BaseProps = { + color?: TypographyColor; + weight?: TypographyWeight; +}; + +type Props = + | ({ as?: 'p' } & BaseProps & HTMLAttributes<'p'>) + | ({ as: 'span' } & BaseProps & HTMLAttributes<'span'>) + | ({ as: 'small' } & BaseProps & HTMLAttributes<'small'>) + | ({ as: 'label' } & BaseProps & HTMLAttributes<'label'>); + +const { as = 'p', ...rest } = Astro.props; +--- + + + + diff --git a/astro/src/components/primitives/Typography/BodyMd.astro b/astro/src/components/primitives/Typography/BodyMd.astro new file mode 100644 index 0000000000..f21db324e5 --- /dev/null +++ b/astro/src/components/primitives/Typography/BodyMd.astro @@ -0,0 +1,30 @@ +--- +/** + * BodyMd - Medium body text + * + * @example + * Medium sized content. + * Subdued helper text + */ + +import type { HTMLAttributes } from 'astro/types'; +import Typography from './Typography.astro'; +import type { TypographyColor, TypographyWeight } from './Typography.astro'; + +type BaseProps = { + color?: TypographyColor; + weight?: TypographyWeight; +}; + +type Props = + | ({ as?: 'span' } & BaseProps & HTMLAttributes<'span'>) + | ({ as: 'p' } & BaseProps & HTMLAttributes<'p'>) + | ({ as: 'small' } & BaseProps & HTMLAttributes<'small'>) + | ({ as: 'label' } & BaseProps & HTMLAttributes<'label'>); + +const { as = 'span', ...rest } = Astro.props; +--- + + + + diff --git a/astro/src/components/primitives/Typography/BodySm.astro b/astro/src/components/primitives/Typography/BodySm.astro new file mode 100644 index 0000000000..0a43987868 --- /dev/null +++ b/astro/src/components/primitives/Typography/BodySm.astro @@ -0,0 +1,30 @@ +--- +/** + * BodySm - Smaller body text / fine print + * + * @example + * Fine print or secondary content. + * Subdued helper text + */ + +import type { HTMLAttributes } from 'astro/types'; +import Typography from './Typography.astro'; +import type { TypographyColor, TypographyWeight } from './Typography.astro'; + +type BaseProps = { + color?: TypographyColor; + weight?: TypographyWeight; +}; + +type Props = + | ({ as?: 'small' } & BaseProps & HTMLAttributes<'small'>) + | ({ as: 'p' } & BaseProps & HTMLAttributes<'p'>) + | ({ as: 'span' } & BaseProps & HTMLAttributes<'span'>) + | ({ as: 'label' } & BaseProps & HTMLAttributes<'label'>); + +const { as = 'small', ...rest } = Astro.props; +--- + + + + diff --git a/astro/src/components/primitives/Typography/BodyXs.astro b/astro/src/components/primitives/Typography/BodyXs.astro new file mode 100644 index 0000000000..0ebb821fa9 --- /dev/null +++ b/astro/src/components/primitives/Typography/BodyXs.astro @@ -0,0 +1,30 @@ +--- +/** + * BodyXs - Extra small body text + * + * @example + * Fine print text + * Subdued small text + */ + +import type { HTMLAttributes } from 'astro/types'; +import Typography from './Typography.astro'; +import type { TypographyColor, TypographyWeight } from './Typography.astro'; + +type BaseProps = { + color?: TypographyColor; + weight?: TypographyWeight; +}; + +type Props = + | ({ as?: 'small' } & BaseProps & HTMLAttributes<'small'>) + | ({ as: 'p' } & BaseProps & HTMLAttributes<'p'>) + | ({ as: 'span' } & BaseProps & HTMLAttributes<'span'>) + | ({ as: 'label' } & BaseProps & HTMLAttributes<'label'>); + +const { as = 'small', ...rest } = Astro.props; +--- + + + + diff --git a/astro/src/components/primitives/Typography/Code.astro b/astro/src/components/primitives/Typography/Code.astro new file mode 100644 index 0000000000..025f03ab00 --- /dev/null +++ b/astro/src/components/primitives/Typography/Code.astro @@ -0,0 +1,29 @@ +--- +/** + * Code - Inline monospace text + * + * @example + * npm install express + * Multi-line code block + */ + +import type { HTMLAttributes } from 'astro/types'; +import Typography from './Typography.astro'; +import type { TypographyColor, TypographyWeight } from './Typography.astro'; + +type BaseProps = { + color?: TypographyColor; + weight?: TypographyWeight; +}; + +type Props = + | ({ as?: 'code' } & BaseProps & HTMLAttributes<'code'>) + | ({ as: 'pre' } & BaseProps & HTMLAttributes<'pre'>) + | ({ as: 'span' } & BaseProps & HTMLAttributes<'span'>); + +const { as = 'code', ...rest } = Astro.props; +--- + + + + diff --git a/astro/src/components/primitives/Typography/H1.astro b/astro/src/components/primitives/Typography/H1.astro new file mode 100644 index 0000000000..29f3149e97 --- /dev/null +++ b/astro/src/components/primitives/Typography/H1.astro @@ -0,0 +1,27 @@ +--- +/** + * H1 - Page title heading + * + * @example + *

Page Title

+ *

Styled as h1, rendered as h2

+ */ + +import type { HTMLAttributes } from 'astro/types'; +import Typography from './Typography.astro'; +import type { TypographyColor, TypographyWeight } from './Typography.astro'; + +type HTMLTag = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'; + +interface Props extends HTMLAttributes<'h1'> { + as?: HTMLTag; + color?: TypographyColor; + weight?: TypographyWeight; +} + +const { as = 'h1', ...rest } = Astro.props; +--- + + + + diff --git a/astro/src/components/primitives/Typography/H2.astro b/astro/src/components/primitives/Typography/H2.astro new file mode 100644 index 0000000000..64dba83a4c --- /dev/null +++ b/astro/src/components/primitives/Typography/H2.astro @@ -0,0 +1,27 @@ +--- +/** + * H2 - Section heading + * + * @example + *

Section Title

+ *

Styled as h2, rendered as h3

+ */ + +import type { HTMLAttributes } from 'astro/types'; +import Typography from './Typography.astro'; +import type { TypographyColor, TypographyWeight } from './Typography.astro'; + +type HTMLTag = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'; + +interface Props extends HTMLAttributes<'h2'> { + as?: HTMLTag; + color?: TypographyColor; + weight?: TypographyWeight; +} + +const { as = 'h2', ...rest } = Astro.props; +--- + + + + diff --git a/astro/src/components/primitives/Typography/H3.astro b/astro/src/components/primitives/Typography/H3.astro new file mode 100644 index 0000000000..f9221fcfef --- /dev/null +++ b/astro/src/components/primitives/Typography/H3.astro @@ -0,0 +1,27 @@ +--- +/** + * H3 - Subsection heading + * + * @example + *

Subsection Title

+ *

Styled as h3, rendered as h4

+ */ + +import type { HTMLAttributes } from 'astro/types'; +import Typography from './Typography.astro'; +import type { TypographyColor, TypographyWeight } from './Typography.astro'; + +type HTMLTag = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'; + +interface Props extends HTMLAttributes<'h3'> { + as?: HTMLTag; + color?: TypographyColor; + weight?: TypographyWeight; +} + +const { as = 'h3', ...rest } = Astro.props; +--- + + + + diff --git a/astro/src/components/primitives/Typography/H4.astro b/astro/src/components/primitives/Typography/H4.astro new file mode 100644 index 0000000000..ea863b9d8a --- /dev/null +++ b/astro/src/components/primitives/Typography/H4.astro @@ -0,0 +1,27 @@ +--- +/** + * H4 - Card/smaller section heading + * + * @example + *

Card Title

+ *

Styled as h4, rendered as h5

+ */ + +import type { HTMLAttributes } from 'astro/types'; +import Typography from './Typography.astro'; +import type { TypographyColor, TypographyWeight } from './Typography.astro'; + +type HTMLTag = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'; + +interface Props extends HTMLAttributes<'h4'> { + as?: HTMLTag; + color?: TypographyColor; + weight?: TypographyWeight; +} + +const { as = 'h4', ...rest } = Astro.props; +--- + + + + diff --git a/astro/src/components/primitives/Typography/H5.astro b/astro/src/components/primitives/Typography/H5.astro new file mode 100644 index 0000000000..56d82c6447 --- /dev/null +++ b/astro/src/components/primitives/Typography/H5.astro @@ -0,0 +1,30 @@ +--- +/** + * H5 - Lead/intro paragraph text + * + * @example + *
Introduction paragraph with larger text.
+ */ + +import type { HTMLAttributes } from 'astro/types'; +import Typography from './Typography.astro'; +import type { TypographyColor, TypographyWeight } from './Typography.astro'; + +type BaseProps = { + color?: TypographyColor; + weight?: TypographyWeight; +}; + +type Props = + | ({ as?: 'h5' } & BaseProps & HTMLAttributes<'h5'>) + | ({ as: 'p' } & BaseProps & HTMLAttributes<'p'>) + | ({ as: 'span' } & BaseProps & HTMLAttributes<'span'>) + | ({ as: 'small' } & BaseProps & HTMLAttributes<'small'>) + | ({ as: 'label' } & BaseProps & HTMLAttributes<'label'>); + +const { as = 'p', ...rest } = Astro.props; +--- + + + + diff --git a/astro/src/components/primitives/Typography/Typography.astro b/astro/src/components/primitives/Typography/Typography.astro new file mode 100644 index 0000000000..2e1713aa06 --- /dev/null +++ b/astro/src/components/primitives/Typography/Typography.astro @@ -0,0 +1,56 @@ +--- +/** + * Typography Primitive Component (Base) + * + * Low-level polymorphic text component. This is the foundation for all + * typography shorthand components (H1, H2, Body, etc.). + * + * PREFER SHORTHAND COMPONENTS for better DX: + * -

Page Title

+ * -

Styled as H1, rendered as h2

+ * - Subdued text + * - npm install express + * + * Use this base component only when you need full control over variant + element. + */ + +import type { HTMLAttributes } from 'astro/types'; +import type { + TypographyVariant, + TypographyHTMLTag, + TypographyColor, + TypographyWeight, + TypographyBaseProps, +} from './types'; +import './Typography.css'; + +type Props = TypographyBaseProps & HTMLAttributes<'p'>; + +const { + as: Tag = 'p', + variant = 'body', + color = 'primary', + center, + left, + right, + weight, + class: className, + ...rest +} = Astro.props; +--- + + + + diff --git a/astro/src/components/primitives/Typography/Typography.css b/astro/src/components/primitives/Typography/Typography.css new file mode 100644 index 0000000000..b43b47847d --- /dev/null +++ b/astro/src/components/primitives/Typography/Typography.css @@ -0,0 +1,66 @@ +/** + * Typography Component Styles + */ + +/* ============================================ + COLORS + ============================================ */ + +.text--color-primary { + color: var(--color-text-primary); +} + +.text--color-secondary { + color: var(--color-text-secondary); +} + +.text--color-tertiary { + color: var(--color-text-tertiary); +} + +.text--color-inverse { + color: var(--color-text-inverse); +} + +.text--color-mute { + color: var(--color-text-mute); +} + +.text--color-success { + color: var(--color-text-success); +} + +.text--color-warning { + color: var(--color-text-warning); +} + +.text--color-error { + color: var(--color-text-error); +} + +.text--color-inherit { + color: inherit; +} + +/* ============================================ + WEIGHTS (Overrides) + ============================================ */ +.text--weight-light { + font-weight: var(--font-weight-light); +} + +.text--weight-normal { + font-weight: var(--font-weight-normal); +} + +.text--weight-medium { + font-weight: var(--font-weight-medium); +} + +.text--weight-semibold { + font-weight: var(--font-weight-semibold); +} + +.text--weight-bold { + font-weight: var(--font-weight-bold); +} diff --git a/astro/src/components/primitives/Typography/index.ts b/astro/src/components/primitives/Typography/index.ts new file mode 100644 index 0000000000..1868eaf40e --- /dev/null +++ b/astro/src/components/primitives/Typography/index.ts @@ -0,0 +1,28 @@ +/** + * Typography Components + * + * Base component + shorthand variants for better DX + */ + +// Base component (full control) +export { default as Typography } from './Typography.astro'; + +// Shorthand components (preset variants) +export { default as H1 } from './H1.astro'; +export { default as H2 } from './H2.astro'; +export { default as H3 } from './H3.astro'; +export { default as H4 } from './H4.astro'; +export { default as H5 } from './H5.astro'; +export { default as Body } from './Body.astro'; +export { default as BodyMd } from './BodyMd.astro'; +export { default as BodySm } from './BodySm.astro'; +export { default as BodyXs } from './BodyXs.astro'; +export { default as Code } from './Code.astro'; + +export type { + TypographyVariant, + TypographyColor, + TypographyWeight, + TypographyHTMLTag, + TypographyBaseProps, +} from './types'; diff --git a/astro/src/components/primitives/Typography/types.ts b/astro/src/components/primitives/Typography/types.ts new file mode 100644 index 0000000000..4783f38be4 --- /dev/null +++ b/astro/src/components/primitives/Typography/types.ts @@ -0,0 +1,59 @@ +/** + * Typography Component Types + */ + +export type TypographyVariant = + | 'h1' + | 'h2' + | 'h3' + | 'h4' + | 'h5' + | 'body-lg' + | 'body' + | 'body-md' + | 'body-sm' + | 'body-xs' + | 'code'; + +export type TypographyColor = + | 'primary' + | 'secondary' + | 'tertiary' + | 'inverse' + | 'inactive' + | 'error' + | 'success' + | 'warning'; + +export type TypographyWeight = 'light' | 'normal' | 'medium' | 'semibold' | 'bold'; + +export type TypographyHTMLTag = + | 'h1' + | 'h2' + | 'h3' + | 'h4' + | 'h5' + | 'h6' + | 'p' + | 'span' + | 'small' + | 'label' + | 'code' + | 'pre'; + +export interface TypographyBaseProps { + /** HTML element to render */ + as?: TypographyHTMLTag; + /** Typography style variant */ + variant?: TypographyVariant; + /** Text color */ + color?: TypographyColor; + /** Font weight override */ + weight?: TypographyWeight; + /** Center text alignment */ + center?: boolean; + /** Left text alignment */ + left?: boolean; + /** Right text alignment */ + right?: boolean; +} diff --git a/astro/src/components/primitives/index.ts b/astro/src/components/primitives/index.ts new file mode 100644 index 0000000000..fbb458e635 --- /dev/null +++ b/astro/src/components/primitives/index.ts @@ -0,0 +1,15 @@ +/** + * Primitives Components + * + * Re-export all primitive components for easy importing + */ + +// Typography +export { Typography, H1, H2, H3, H4, H5, Body, BodySm, BodyMd, BodyXs, Code } from './Typography'; + +// Layout +export { Container } from './Container'; +export { Grid, Col, Flex, FlexItem } from './Grid'; + +// Button +export { Button } from './Button'; diff --git a/astro/src/config/menu.ts b/astro/src/config/menu.ts new file mode 100644 index 0000000000..a637eafc6d --- /dev/null +++ b/astro/src/config/menu.ts @@ -0,0 +1,8 @@ +export const menuSections = { + starter: 'Getting started', + guide: 'Guide', + advanced: 'Advanced topics', + resources: 'Resources', +} as const; + +export type MenuSection = keyof typeof menuSections; diff --git a/astro/src/content.config.ts b/astro/src/content.config.ts new file mode 100644 index 0000000000..cff7e179b8 --- /dev/null +++ b/astro/src/content.config.ts @@ -0,0 +1,16 @@ +import { defineCollection, z } from 'astro:content'; +import { glob } from 'astro/loaders'; + +const docsCollection = defineCollection({ + loader: glob({ pattern: '**/[^_]*.{md,mdx}', base: './src/content/docs' }), + schema: z.object({ + title: z.string(), + description: z.string().optional(), + menu: z.string(), + order: z.number().optional(), + }), +}); + +export const collections = { + docs: docsCollection, +}; diff --git a/astro/src/content/docs/en/advanced/best-practice-performance.md b/astro/src/content/docs/en/advanced/best-practice-performance.md new file mode 100644 index 0000000000..5b8bbf3cca --- /dev/null +++ b/astro/src/content/docs/en/advanced/best-practice-performance.md @@ -0,0 +1,309 @@ +--- +title: Performance Best Practices Using Express in Production +description: Discover performance and reliability best practices for Express apps in production, covering code optimizations and environment setups for optimal performance. +menu: advanced +order: 4 +--- + +# Production best practices: performance and reliability + +This article discusses performance and reliability best practices for Express applications deployed to production. + +This topic clearly falls into the "devops" world, spanning both traditional development and operations. Accordingly, the information is divided into two parts: + +- Things to do in your code (the dev part): + - [Use gzip compression](#use-gzip-compression) + - [Don't use synchronous functions](#dont-use-synchronous-functions) + - [Do logging correctly](#do-logging-correctly) + - [Handle exceptions properly](#handle-exceptions-properly) +- Things to do in your environment / setup (the ops part): + - [Set NODE_ENV to "production"](#set-node_env-to-production) + - [Ensure your app automatically restarts](#ensure-your-app-automatically-restarts) + - [Run your app in a cluster](#run-your-app-in-a-cluster) + - [Cache request results](#cache-request-results) + - [Use a load balancer](#use-a-load-balancer) + - [Use a reverse proxy](#use-a-reverse-proxy) + +## Things to do in your code {#in-code} + +Here are some things you can do in your code to improve your application's performance: + +- [Use gzip compression](#use-gzip-compression) +- [Don't use synchronous functions](#dont-use-synchronous-functions) +- [Do logging correctly](#do-logging-correctly) +- [Handle exceptions properly](#handle-exceptions-properly) + +### Use gzip compression + +Gzip compressing can greatly decrease the size of the response body and hence increase the speed of a web app. Use the [compression](https://www.npmjs.com/package/compression) middleware for gzip compression in your Express app. For example: + +```js +const compression = require('compression'); +const express = require('express'); +const app = express(); + +app.use(compression()); +``` + +For a high-traffic website in production, the best way to put compression in place is to implement it at a reverse proxy level (see [Use a reverse proxy](#use-a-reverse-proxy)). In that case, you do not need to use compression middleware. For details on enabling gzip compression in Nginx, see [Module ngx_http_gzip_module](http://nginx.org/en/docs/http/ngx_http_gzip_module.html) in the Nginx documentation. + +### Don't use synchronous functions + +Synchronous functions and methods tie up the executing process until they return. A single call to a synchronous function might return in a few microseconds or milliseconds, however in high-traffic websites, these calls add up and reduce the performance of the app. Avoid their use in production. + +Although Node and many modules provide synchronous and asynchronous versions of their functions, always use the asynchronous version in production. The only time when a synchronous function can be justified is upon initial startup. + +You can use the `--trace-sync-io` command-line flag to print a warning and a stack trace whenever your application uses a synchronous API. Of course, you wouldn't want to use this in production, but rather to ensure that your code is ready for production. See the [node command-line options documentation](https://nodejs.org/api/cli.html#cli_trace_sync_io) for more information. + +### Do logging correctly + +In general, there are two reasons for logging from your app: For debugging and for logging app activity (essentially, everything else). Using `console.log()` or `console.error()` to print log messages to the terminal is common practice in development. But [these functions are synchronous](https://nodejs.org/api/console.html#console) when the destination is a terminal or a file, so they are not suitable for production, unless you pipe the output to another program. + +#### For debugging + +If you're logging for purposes of debugging, then instead of using `console.log()`, use a special debugging module like [debug](https://www.npmjs.com/package/debug). This module enables you to use the DEBUG environment variable to control what debug messages are sent to `console.error()`, if any. To keep your app purely asynchronous, you'd still want to pipe `console.error()` to another program. But then, you're not really going to debug in production, are you? + +#### For app activity + +If you're logging app activity (for example, tracking traffic or API calls), instead of using `console.log()`, use a logging library like [Pino](https://www.npmjs.com/package/pino), which is the fastest and most efficient option available. + +### Handle exceptions properly + +Node apps crash when they encounter an uncaught exception. Not handling exceptions and taking appropriate actions will make your Express app crash and go offline. If you follow the advice in [Ensure your app automatically restarts](#ensure-your-app-automatically-restarts) below, then your app will recover from a crash. Fortunately, Express apps typically have a short startup time. Nevertheless, you want to avoid crashing in the first place, and to do that, you need to handle exceptions properly. + +To ensure you handle all exceptions, use the following techniques: + +- [Use try-catch](#use-try-catch) +- [Use promises](#use-promises) + +Before diving into these topics, you should have a basic understanding of Node/Express error handling: using error-first callbacks, and propagating errors in middleware. Node uses an "error-first callback" convention for returning errors from asynchronous functions, where the first parameter to the callback function is the error object, followed by result data in succeeding parameters. To indicate no error, pass null as the first parameter. The callback function must correspondingly follow the error-first callback convention to meaningfully handle the error. And in Express, the best practice is to use the next() function to propagate errors through the middleware chain. + +For more on the fundamentals of error handling, see: + +- [Error Handling in Node.js](https://www.tritondatacenter.com/node-js/production/design/errors) + +#### Use try-catch + +Try-catch is a JavaScript language construct that you can use to catch exceptions in synchronous code. Use try-catch, for example, to handle JSON parsing errors as shown below. + +Here is an example of using try-catch to handle a potential process-crashing exception. +This middleware function accepts a query field parameter named "params" that is a JSON object. + +```js +app.get('/search', (req, res) => { + // Simulating async operation + setImmediate(() => { + const jsonStr = req.query.params; + try { + const jsonObj = JSON.parse(jsonStr); + res.send('Success'); + } catch (e) { + res.status(400).send('Invalid JSON string'); + } + }); +}); +``` + +However, try-catch works only for synchronous code. Because the Node platform is primarily asynchronous (particularly in a production environment), try-catch won't catch a lot of exceptions. + +#### Use promises + +When an error is thrown in an `async` function or a rejected promise is awaited inside an `async` function, those errors will be passed to the error handler as if calling `next(err)` + +```js +app.get('/', async (req, res, next) => { + const data = await userData(); // If this promise fails, it will automatically call `next(err)` to handle the error. + + res.send(data); +}); + +app.use((err, req, res, next) => { + res.status(err.status ?? 500).send({ error: err.message }); +}); +``` + +Also, you can use asynchronous functions for your middleware, and the router will handle errors if the promise fails, for example: + +```js +app.use(async (req, res, next) => { + req.locals.user = await getUser(req); + + next(); // This will be called if the promise does not throw an error. +}); +``` + +Best practice is to handle errors as close to the site as possible. So while this is now handled in the router, it’s best to catch the error in the middleware and handle it without relying on separate error-handling middleware. + +#### What not to do + +One thing you should _not_ do is to listen for the `uncaughtException` event, emitted when an exception bubbles all the way back to the event loop. Adding an event listener for `uncaughtException` will change the default behavior of the process that is encountering an exception; the process will continue to run despite the exception. This might sound like a good way of preventing your app from crashing, but continuing to run the app after an uncaught exception is a dangerous practice and is not recommended, because the state of the process becomes unreliable and unpredictable. + +Additionally, using `uncaughtException` is officially recognized as [crude](https://nodejs.org/api/process.html#process_event_uncaughtexception). So listening for `uncaughtException` is just a bad idea. This is why we recommend things like multiple processes and supervisors: crashing and restarting is often the most reliable way to recover from an error. + +We also don't recommend using [domains](https://nodejs.org/api/domain.html). It generally doesn't solve the problem and is a deprecated module. + +## Things to do in your environment / setup {#in-environment} + +Here are some things you can do in your system environment to improve your app's performance: + +- [Set NODE_ENV to "production"](#set-node_env-to-production) +- [Ensure your app automatically restarts](#ensure-your-app-automatically-restarts) +- [Run your app in a cluster](#run-your-app-in-a-cluster) +- [Cache request results](#cache-request-results) +- [Use a load balancer](#use-a-load-balancer) +- [Use a reverse proxy](#use-a-reverse-proxy) + +### Set NODE_ENV to "production" + +The NODE_ENV environment variable specifies the environment in which an application is running (usually, development or production). One of the simplest things you can do to improve performance is to set NODE_ENV to `production`. + +Setting NODE_ENV to "production" makes Express: + +- Cache view templates. +- Cache CSS files generated from CSS extensions. +- Generate less verbose error messages. + +[Tests indicate](https://www.dynatrace.com/news/blog/the-drastic-effects-of-omitting-node-env-in-your-express-js-applications/) that just doing this can improve app performance by a factor of three! + +If you need to write environment-specific code, you can check the value of NODE_ENV with `process.env.NODE_ENV`. Be aware that checking the value of any environment variable incurs a performance penalty, and so should be done sparingly. + +In development, you typically set environment variables in your interactive shell, for example by using `export` or your `.bash_profile` file. But in general, you shouldn't do that on a production server; instead, use your OS's init system (systemd). The next section provides more details about using your init system in general, but setting `NODE_ENV` is so important for performance (and easy to do), that it's highlighted here. + +With systemd, use the `Environment` directive in your unit file. For example: + +```sh +# /etc/systemd/system/myservice.service +Environment=NODE_ENV=production +``` + +For more information, see [Using Environment Variables In systemd Units](https://www.flatcar.org/docs/latest/setup/systemd/environment-variables/). + +### Ensure your app automatically restarts + +In production, you don't want your application to be offline, ever. This means you need to make sure it restarts both if the app crashes and if the server itself crashes. Although you hope that neither of those events occurs, realistically you must account for both eventualities by: + +- Using a process manager to restart the app (and Node) when it crashes. +- Using the init system provided by your OS to restart the process manager when the OS crashes. It's also possible to use the init system without a process manager. + +Node applications crash if they encounter an uncaught exception. The foremost thing you need to do is to ensure your app is well-tested and handles all exceptions (see [handle exceptions properly](#handle-exceptions-properly) for details). But as a fail-safe, put a mechanism in place to ensure that if and when your app crashes, it will automatically restart. + +#### Use a process manager + +In development, you started your app simply from the command line with `node server.js` or something similar. But doing this in production is a recipe for disaster. If the app crashes, it will be offline until you restart it. To ensure your app restarts if it crashes, use a process manager. A process manager is a "container" for applications that facilitates deployment, provides high availability, and enables you to manage the application at runtime. + +In addition to restarting your app when it crashes, a process manager can enable you to: + +- Gain insights into runtime performance and resource consumption. +- Modify settings dynamically to improve performance. +- Control clustering (pm2). + +Historically, it was popular to use a Node.js process manager like [PM2](https://github.com/Unitech/pm2). See their documentation if you wish to do this. However, we recommend using your init system for process management. + +#### Use an init system + +The next layer of reliability is to ensure that your app restarts when the server restarts. Systems can still go down for a variety of reasons. To ensure that your app restarts if the server crashes, use the init system built into your OS. The main init system in use today is [systemd](https://wiki.debian.org/systemd). + +There are two ways to use init systems with your Express app: + +- Run your app in a process manager, and install the process manager as a service with the init system. The process manager will restart your app when the app crashes, and the init system will restart the process manager when the OS restarts. This is the recommended approach. +- Run your app (and Node) directly with the init system. This is somewhat simpler, but you don't get the additional advantages of using a process manager. + +##### Systemd + +Systemd is a Linux system and service manager. Most major Linux distributions have adopted systemd as their default init system. + +A systemd service configuration file is called a _unit file_, with a filename ending in `.service`. Here's an example unit file to manage a Node app directly. Replace the values enclosed in `` for your system and app: + +```sh +[Unit] +Description= + +[Service] +Type=simple +ExecStart=/usr/local/bin/node +WorkingDirectory= + +User=nobody +Group=nogroup + +# Environment variables: +Environment=NODE_ENV=production + +# Allow many incoming connections +LimitNOFILE=infinity + +# Allow core dumps for debugging +LimitCORE=infinity + +StandardInput=null +StandardOutput=syslog +StandardError=syslog +Restart=always + +[Install] +WantedBy=multi-user.target +``` + +For more information on systemd, see the [systemd reference (man page)](http://www.freedesktop.org/software/systemd/man/systemd.unit.html). + +### Run your app in a cluster + +In a multi-core system, you can increase the performance of a Node app by many times by launching a cluster of processes. A cluster runs multiple instances of the app, ideally one instance on each CPU core, thereby distributing the load and tasks among the instances. + +![Balancing between application instances using the cluster API](/images/clustering.png) + +IMPORTANT: Since the app instances run as separate processes, they do not share the same memory space. That is, objects are local to each instance of the app. Therefore, you cannot maintain state in the application code. However, you can use an in-memory datastore like [Redis](http://redis.io/) to store session-related data and state. This caveat applies to essentially all forms of horizontal scaling, whether clustering with multiple processes or multiple physical servers. + +In clustered apps, worker processes can crash individually without affecting the rest of the processes. Apart from performance advantages, failure isolation is another reason to run a cluster of app processes. Whenever a worker process crashes, always make sure to log the event and spawn a new process using cluster.fork(). + +#### Using Node's cluster module + +Clustering is made possible with Node's [cluster module](https://nodejs.org/api/cluster.html). This enables a master process to spawn worker processes and distribute incoming connections among the workers. + +#### Using PM2 + +If you deploy your application with PM2, then you can take advantage of clustering _without_ modifying your application code. You should ensure your [application is stateless](https://pm2.keymetrics.io/docs/usage/specifics/#stateless-apps) first, meaning no local data is stored in the process (such as sessions, websocket connections and the like). + +When running an application with PM2, you can enable **cluster mode** to run it in a cluster with a number of instances of your choosing, such as the matching the number of available CPUs on the machine. You can manually change the number of processes in the cluster using the `pm2` command line tool without stopping the app. + +To enable cluster mode, start your application like so: + +```bash +# Start 4 worker processes +$ pm2 start npm --name my-app -i 4 -- start +# Auto-detect number of available CPUs and start that many worker processes +$ pm2 start npm --name my-app -i max -- start +``` + +This can also be configured within a PM2 process file (`ecosystem.config.js` or similar) by setting `exec_mode` to `cluster` and `instances` to the number of workers to start. + +Once running, the application can be scaled like so: + +```bash +# Add 3 more workers +$ pm2 scale my-app +3 +# Scale to a specific number of workers +$ pm2 scale my-app 2 +``` + +For more information on clustering with PM2, see [Cluster Mode](https://pm2.keymetrics.io/docs/usage/cluster-mode/) in the PM2 documentation. + +### Cache request results + +Another strategy to improve the performance in production is to cache the result of requests, so that your app does not repeat the operation to serve the same request repeatedly. + +Use a caching server like [Varnish](https://www.varnish-cache.org/) or [Nginx](https://blog.nginx.org/blog/nginx-caching-guide) (see also [Nginx Caching](https://serversforhackers.com/nginx-caching/)) to greatly improve the speed and performance of your app. + +### Use a load balancer + +No matter how optimized an app is, a single instance can handle only a limited amount of load and traffic. One way to scale an app is to run multiple instances of it and distribute the traffic via a load balancer. Setting up a load balancer can improve your app's performance and speed, and enable it to scale more than is possible with a single instance. + +A load balancer is usually a reverse proxy that orchestrates traffic to and from multiple application instances and servers. You can easily set up a load balancer for your app by using [Nginx](https://nginx.org/en/docs/http/load_balancing.html) or [HAProxy](https://www.digitalocean.com/community/tutorials/an-introduction-to-haproxy-and-load-balancing-concepts). + +With load balancing, you might have to ensure that requests that are associated with a particular session ID connect to the process that originated them. This is known as _session affinity_, or _sticky sessions_, and may be addressed by the suggestion above to use a data store such as Redis for session data (depending on your application). For a discussion, see [Using multiple nodes](https://socket.io/docs/v4/using-multiple-nodes/). + +### Use a reverse proxy + +A reverse proxy sits in front of a web app and performs supporting operations on the requests, apart from directing requests to the app. It can handle error pages, compression, caching, serving files, and load balancing among other things. + +Handing over tasks that do not require knowledge of application state to a reverse proxy frees up Express to perform specialized application tasks. For this reason, it is recommended to run Express behind a reverse proxy like [Nginx](https://www.nginx.org/) or [HAProxy](https://www.haproxy.org/) in production. diff --git a/astro/src/content/docs/en/advanced/best-practice-security.md b/astro/src/content/docs/en/advanced/best-practice-security.md new file mode 100644 index 0000000000..50a81981ba --- /dev/null +++ b/astro/src/content/docs/en/advanced/best-practice-security.md @@ -0,0 +1,285 @@ +--- +title: Security Best Practices for Express in Production +description: Discover crucial security best practices for Express apps in production, including using TLS, input validation, secure cookies, and preventing vulnerabilities. +menu: advanced +order: 3 +--- + +# Production Best Practices: Security + +## Overview + +The term _"production"_ refers to the stage in the software lifecycle when an application or API is generally available to its end-users or consumers. In contrast, in the _"development"_ stage, you're still actively writing and testing code, and the application is not open to external access. The corresponding system environments are known as _production_ and _development_ environments, respectively. + +Development and production environments are usually set up differently and have vastly different requirements. What's fine in development may not be acceptable in production. For example, in a development environment you may want verbose logging of errors for debugging, while the same behavior can become a security concern in a production environment. And in development, you don't need to worry about scalability, reliability, and performance, while those concerns become critical in production. + +{% capture security-note %} + +If you believe you have discovered a security vulnerability in Express, please see +[Security Policies and Procedures](/en/resources/contributing.html#security-policies-and-procedures). + +{% endcapture %} + +{% include admonitions/note.html content=security-note %} + +Security best practices for Express applications in production include: + +- [Production Best Practices: Security](#production-best-practices-security) + - [Overview](#overview) + - [Don't use deprecated or vulnerable versions of Express](#dont-use-deprecated-or-vulnerable-versions-of-express) + - [Use TLS](#use-tls) + - [Do not trust user input](#do-not-trust-user-input) + - [Prevent open redirects](#prevent-open-redirects) + - [Use Helmet](#use-helmet) + - [Reduce fingerprinting](#reduce-fingerprinting) + - [Use cookies securely](#use-cookies-securely) + - [Don't use the default session cookie name](#dont-use-the-default-session-cookie-name) + - [Set cookie security options](#set-cookie-security-options) + - [Prevent brute-force attacks against authorization](#prevent-brute-force-attacks-against-authorization) + - [Ensure your dependencies are secure](#ensure-your-dependencies-are-secure) + - [Avoid other known vulnerabilities](#avoid-other-known-vulnerabilities) + - [Additional considerations](#additional-considerations) + +## Don't use deprecated or vulnerable versions of Express + +Express 2.x and 3.x are no longer maintained. Security and performance issues in these versions won't be fixed. Do not use them! If you haven't moved to version 4, follow the [migration guide](/{{ page.lang }}/guide/migrating-4.html) or consider [Commercial Support Options](/{{ page.lang }}/support#commercial-support-options). + +Also ensure you are not using any of the vulnerable Express versions listed on the [Security updates page](/{{ page.lang }}/advanced/security-updates.html). If you are, update to one of the stable releases, preferably the latest. + +## Use TLS + +If your app deals with or transmits sensitive data, use [Transport Layer Security](https://en.wikipedia.org/wiki/Transport_Layer_Security) (TLS) to secure the connection and the data. This technology encrypts data before it is sent from the client to the server, thus preventing some common (and easy) hacks. Although Ajax and POST requests might not be visibly obvious and seem "hidden" in browsers, their network traffic is vulnerable to [packet sniffing](https://en.wikipedia.org/wiki/Packet_analyzer) and [man-in-the-middle attacks](https://en.wikipedia.org/wiki/Man-in-the-middle_attack). + +You may be familiar with Secure Socket Layer (SSL) encryption. [TLS is simply the next progression of SSL](). In other words, if you were using SSL before, consider upgrading to TLS. In general, we recommend Nginx to handle TLS. For a good reference to configure TLS on Nginx (and other servers), see [Recommended Server Configurations (Mozilla Wiki)](https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_Server_Configurations). + +Also, a handy tool to get a free TLS certificate is [Let's Encrypt](https://letsencrypt.org/about/), a free, automated, and open certificate authority (CA) provided by the [Internet Security Research Group (ISRG)](https://www.abetterinternet.org/). + +## Do not trust user input + +For web applications, one of the most critical security requirements is proper user input validation and handling. This comes in many forms and we will not cover all of them here. +Ultimately, the responsibility for validating and correctly handling the types of user input your application accepts is yours. + +### Prevent open redirects + +An example of potentially dangerous user input is an _open redirect_, where an application accepts a URL as user input (often in the URL query, for example `?url=https://example.com`) and uses `res.redirect` to set the `location` header and +return a 3xx status. + +An application must validate that it supports redirecting to the incoming URL to avoid sending users to malicious links such as phishing websites, among other risks. + +Here is an example of checking URLs before using `res.redirect` or `res.location`: + +```js +app.use((req, res) => { + try { + if (new Url(req.query.url).host !== 'example.com') { + return res.status(400).end(`Unsupported redirect to host: ${req.query.url}`); + } + } catch (e) { + return res.status(400).end(`Invalid url: ${req.query.url}`); + } + res.redirect(req.query.url); +}); +``` + +## Use Helmet + +[Helmet][helmet] can help protect your app from some well-known web vulnerabilities by setting HTTP headers appropriately. + +Helmet is a middleware function that sets security-related HTTP response headers. Helmet sets the following headers by default: + +- `Content-Security-Policy`: A powerful allow-list of what can happen on your page which mitigates many attacks +- `Cross-Origin-Opener-Policy`: Helps process-isolate your page +- `Cross-Origin-Resource-Policy`: Blocks others from loading your resources cross-origin +- `Origin-Agent-Cluster`: Changes process isolation to be origin-based +- `Referrer-Policy`: Controls the [`Referer`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referer) header +- `Strict-Transport-Security`: Tells browsers to prefer HTTPS +- `X-Content-Type-Options`: Avoids [MIME sniffing](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#mime_sniffing) +- `X-DNS-Prefetch-Control`: Controls DNS prefetching +- `X-Download-Options`: Forces downloads to be saved (Internet Explorer only) +- `X-Frame-Options`: Legacy header that mitigates [Clickjacking](https://en.wikipedia.org/wiki/Clickjacking) attacks +- `X-Permitted-Cross-Domain-Policies`: Controls cross-domain behavior for Adobe products, like Acrobat +- `X-Powered-By`: Info about the web server. Removed because it could be used in simple attacks +- `X-XSS-Protection`: Legacy header that tries to mitigate [XSS attacks](https://developer.mozilla.org/en-US/docs/Glossary/Cross-site_scripting), but makes things worse, so Helmet disables it + +Each header can be configured or disabled. To read more about it please go to [its documentation website][helmet]. + +Install Helmet like any other module: + +```bash +$ npm install helmet +``` + +Then to use it in your code: + +```js +// ... + +const helmet = require('helmet'); +app.use(helmet()); + +// ... +``` + +## Reduce fingerprinting + +It can help to provide an extra layer of security to reduce the ability of attackers to determine +the software that a server uses, known as "fingerprinting." Though not a security issue itself, +reducing the ability to fingerprint an application improves its overall security posture. +Server software can be fingerprinted by quirks in how it responds to specific requests, for example in +the HTTP response headers. + +By default, Express sends the `X-Powered-By` response header that you can +disable using the `app.disable()` method: + +```js +app.disable('x-powered-by'); +``` + +{% capture powered-advisory %} + +Disabling the `X-Powered-By header` does not prevent +a sophisticated attacker from determining that an app is running Express. It may +discourage a casual exploit, but there are other ways to determine an app is running +Express. + +{% endcapture %} + +{% include admonitions/note.html content=powered-advisory %} + +Express also sends its own formatted "404 Not Found" messages and formatter error +response messages. These can be changed by +[adding your own not found handler](/en/starter/faq.html#how-do-i-handle-404-responses) +and +[writing your own error handler](/en/guide/error-handling.html#writing-error-handlers): + +```js +// last app.use calls right before app.listen(): + +// custom 404 +app.use((req, res, next) => { + res.status(404).send("Sorry can't find that!"); +}); + +// custom error handler +app.use((err, req, res, next) => { + console.error(err.stack); + res.status(500).send('Something broke!'); +}); +``` + +## Use cookies securely + +To ensure cookies don't open your app to exploits, don't use the default session cookie name and set cookie security options appropriately. + +There are two main middleware cookie session modules: + +- [express-session](https://www.npmjs.com/package/express-session) that replaces `express.session` middleware built-in to Express 3.x. +- [cookie-session](https://www.npmjs.com/package/cookie-session) that replaces `express.cookieSession` middleware built-in to Express 3.x. + +The main difference between these two modules is how they save cookie session data. The [express-session](https://www.npmjs.com/package/express-session) middleware stores session data on the server; it only saves the session ID in the cookie itself, not session data. By default, it uses in-memory storage and is not designed for a production environment. In production, you'll need to set up a scalable session-store; see the list of [compatible session stores](https://github.com/expressjs/session#compatible-session-stores). + +In contrast, [cookie-session](https://www.npmjs.com/package/cookie-session) middleware implements cookie-backed storage: it serializes the entire session to the cookie, rather than just a session key. Only use it when session data is relatively small and easily encoded as primitive values (rather than objects). Although browsers are supposed to support at least 4096 bytes per cookie, to ensure you don't exceed the limit, don't exceed a size of 4093 bytes per domain. Also, be aware that the cookie data will be visible to the client, so if there is any reason to keep it secure or obscure, then `express-session` may be a better choice. + +### Don't use the default session cookie name + +Using the default session cookie name can open your app to attacks. The security issue posed is similar to `X-Powered-By`: a potential attacker can use it to fingerprint the server and target attacks accordingly. + +To avoid this problem, use generic cookie names; for example using [express-session](https://www.npmjs.com/package/express-session) middleware: + +```js +const session = require('express-session'); +app.set('trust proxy', 1); // trust first proxy +app.use( + session({ + secret: 's3Cur3', + name: 'sessionId', + }) +); +``` + +### Set cookie security options + +Set the following cookie options to enhance security: + +- `secure` - Ensures the browser only sends the cookie over HTTPS. +- `httpOnly` - Ensures the cookie is sent only over HTTP(S), not client JavaScript, helping to protect against cross-site scripting attacks. +- `domain` - indicates the domain of the cookie; use it to compare against the domain of the server in which the URL is being requested. If they match, then check the path attribute next. +- `path` - indicates the path of the cookie; use it to compare against the request path. If this and domain match, then send the cookie in the request. +- `expires` - use to set expiration date for persistent cookies. + +Here is an example using [cookie-session](https://www.npmjs.com/package/cookie-session) middleware: + +```js +const session = require('cookie-session'); +const express = require('express'); +const app = express(); + +const expiryDate = new Date(Date.now() + 60 * 60 * 1000); // 1 hour +app.use( + session({ + name: 'session', + keys: ['key1', 'key2'], + cookie: { + secure: true, + httpOnly: true, + domain: 'example.com', + path: 'foo/bar', + expires: expiryDate, + }, + }) +); +``` + +## Prevent brute-force attacks against authorization + +Make sure login endpoints are protected to make private data more secure. + +A simple and powerful technique is to block authorization attempts using two metrics: + +1. The number of consecutive failed attempts by the same user name and IP address. +1. The number of failed attempts from an IP address over some long period of time. For example, block an IP address if it makes 100 failed attempts in one day. + +[rate-limiter-flexible](https://github.com/animir/node-rate-limiter-flexible) package provides tools to make this technique easy and fast. You can find [an example of brute-force protection in the documentation](https://github.com/animir/node-rate-limiter-flexible/wiki/Overall-example#login-endpoint-protection) + +## Ensure your dependencies are secure + +Using npm to manage your application's dependencies is powerful and convenient. But the packages that you use may contain critical security vulnerabilities that could also affect your application. The security of your app is only as strong as the "weakest link" in your dependencies. + +Since npm@6, npm automatically reviews every install request. Also, you can use `npm audit` to analyze your dependency tree. + +```bash +$ npm audit +``` + +If you want to stay more secure, consider [Snyk](https://snyk.io/). + +Snyk offers both a [command-line tool](https://www.npmjs.com/package/snyk) and a [Github integration](https://snyk.io/docs/github) that checks your application against [Snyk's open source vulnerability database](https://snyk.io/vuln/) for any known vulnerabilities in your dependencies. Install the CLI as follows: + +```bash +$ npm install -g snyk +$ cd your-app +``` + +Use this command to test your application for vulnerabilities: + +```bash +$ snyk test +``` + +### Avoid other known vulnerabilities + +Keep an eye out for [Node Security Project](https://npmjs.com/advisories) or [Snyk](https://snyk.io/vuln/) advisories that may affect Express or other modules that your app uses. In general, these databases are excellent resources for knowledge and tools about Node security. + +Finally, Express apps—like any other web apps—can be vulnerable to a variety of web-based attacks. Familiarize yourself with known [web vulnerabilities](https://www.owasp.org/www-project-top-ten/) and take precautions to avoid them. + +## Additional considerations + +Here are some further recommendations from the excellent [Node.js Security Checklist](https://blog.risingstack.com/node-js-security-checklist/). Refer to that blog post for all the details on these recommendations: + +- Always filter and sanitize user input to protect against cross-site scripting (XSS) and command injection attacks. +- Defend against SQL injection attacks by using parameterized queries or prepared statements. +- Use the open-source [sqlmap](http://sqlmap.org/) tool to detect SQL injection vulnerabilities in your app. +- Use the [nmap](https://nmap.org/) and [sslyze](https://github.com/nabla-c0d3/sslyze) tools to test the configuration of your SSL ciphers, keys, and renegotiation as well as the validity of your certificate. +- Use [safe-regex](https://www.npmjs.com/package/safe-regex) to ensure your regular expressions are not susceptible to [regular expression denial of service](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS) attacks. + +[helmet]: https://helmetjs.github.io/ diff --git a/astro/src/content/docs/en/advanced/developing-template-engines.md b/astro/src/content/docs/en/advanced/developing-template-engines.md new file mode 100755 index 0000000000..9ec72c8e2b --- /dev/null +++ b/astro/src/content/docs/en/advanced/developing-template-engines.md @@ -0,0 +1,47 @@ +--- +title: Developing template engines for Express +description: Learn how to develop custom template engines for Express.js using app.engine(), with examples on creating and integrating your own template rendering logic. +menu: advanced +order: 1 +--- + +# Developing template engines for Express + +Use the `app.engine(ext, callback)` method to create your own template engine. `ext` refers to the file extension, and `callback` is the template engine function, which accepts the following items as parameters: the location of the file, the options object, and the callback function. + +The following code is an example of implementing a very simple template engine for rendering `.ntl` files. + +```js +const fs = require('fs'); // this engine requires the fs module +app.engine('ntl', (filePath, options, callback) => { + // define the template engine + fs.readFile(filePath, (err, content) => { + if (err) return callback(err); + // this is an extremely simple template engine + const rendered = content + .toString() + .replace('#title#', `${options.title}`) + .replace('#message#', `

${options.message}

`); + return callback(null, rendered); + }); +}); +app.set('views', './views'); // specify the views directory +app.set('view engine', 'ntl'); // register the template engine +``` + +Your app will now be able to render `.ntl` files. Create a file named `index.ntl` in the `views` directory with the following content. + +```pug +#title# +#message# +``` + +Then, create the following route in your app. + +```js +app.get('/', (req, res) => { + res.render('index', { title: 'Hey', message: 'Hello there!' }); +}); +``` + +When you make a request to the home page, `index.ntl` will be rendered as HTML. diff --git a/astro/src/content/docs/en/advanced/healthcheck-graceful-shutdown.md b/astro/src/content/docs/en/advanced/healthcheck-graceful-shutdown.md new file mode 100644 index 0000000000..e80a86708d --- /dev/null +++ b/astro/src/content/docs/en/advanced/healthcheck-graceful-shutdown.md @@ -0,0 +1,32 @@ +--- +title: Health Checks and Graceful Shutdown +description: Learn how to implement health checks and graceful shutdown in Express apps to enhance reliability, manage deployments, and integrate with load balancers like Kubernetes. +menu: advanced +order: 5 +--- + +# Health Checks and Graceful Shutdown + +## Graceful shutdown + +When you deploy a new version of your application, you must replace the previous version. The process manager you're using will first send a SIGTERM signal to the application to notify it that it will be killed. Once the application gets this signal, it should stop accepting new requests, finish all the ongoing requests, clean up the resources it used, including database connections and file locks then exit. + +### Example + +```js +const server = app.listen(port); + +process.on('SIGTERM', () => { + debug('SIGTERM signal received: closing HTTP server'); + server.close(() => { + debug('HTTP server closed'); + }); +}); +``` + +## Health checks + +A load balancer uses health checks to determine if an application instance is healthy and can accept requests. For example, [Kubernetes has two health checks](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/): + +- `liveness`, that determines when to restart a container. +- `readiness`, that determines when a container is ready to start accepting traffic. When a pod is not ready, it is removed from the service load balancers. diff --git a/astro/src/content/docs/en/advanced/security-updates.md b/astro/src/content/docs/en/advanced/security-updates.md new file mode 100755 index 0000000000..64a3d6ff75 --- /dev/null +++ b/astro/src/content/docs/en/advanced/security-updates.md @@ -0,0 +1,85 @@ +--- +title: Express security updates +description: Review the latest security updates and patches for Express.js, including detailed vulnerability lists for different versions to help maintain a secure application. +menu: advanced +order: 2 +--- + +# Security updates + +
+Node.js vulnerabilities directly affect Express. Therefore, [keep a watch on Node.js vulnerabilities](https://nodejs.org/en/blog/vulnerability/) and make sure you are using the latest stable version of Node.js. +
+ +The list below enumerates the Express vulnerabilities that were fixed in the specified version update. + +{% capture security-policy %} +If you believe you have discovered a security vulnerability in Express, please see +[Security Policies and Procedures](/{{page.lang}}/resources/contributing.html#security-policies-and-procedures). +{% endcapture %} + +{% include admonitions/note.html content=security-policy %} + +## 4.x + +- 4.21.2 + - The dependency `path-to-regexp` has been updated to address a [vulnerability](https://github.com/pillarjs/path-to-regexp/security/advisories/GHSA-rhx6-c78j-4q9w). +- 4.21.1 + - The dependency `cookie` has been updated to address a [vulnerability](https://github.com/jshttp/cookie/security/advisories/GHSA-pxg6-pf52-xh8x), This may affect your application if you use `res.cookie`. +- 4.20.0 + - Fixed XSS vulnerability in `res.redirect` ([advisory](https://github.com/expressjs/express/security/advisories/GHSA-qw6h-vgh9-j6wx), [CVE-2024-43796](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-43796)). + - The dependency `serve-static` has been updated to address a [vulnerability](https://github.com/advisories/GHSA-cm22-4g7w-348p). + - The dependency `send` has been updated to address a [vulnerability](https://github.com/advisories/GHSA-m6fv-jmcg-4jfg). + - The dependency `path-to-regexp` has been updated to address a [vulnerability](https://github.com/pillarjs/path-to-regexp/security/advisories/GHSA-9wv6-86v2-598j). + - The dependency `body-parser` has been updated to addres a [vulnerability](https://github.com/advisories/GHSA-qwcr-r2fm-qrc7), This may affect your application if you had url enconding activated. +- 4.19.0, 4.19.1 + - Fixed open redirect vulnerability in `res.location` and `res.redirect` ([advisory](https://github.com/expressjs/express/security/advisories/GHSA-rv95-896h-c2vc), [CVE-2024-29041](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-29041)). +- 4.17.3 + - The dependency `qs` has been updated to address a [vulnerability](https://github.com/advisories/GHSA-hrpp-h998-j3pp). This may affect your application if the following APIs are used: `req.query`, `req.body`, `req.param`. +- 4.16.0 + - The dependency `forwarded` has been updated to address a [vulnerability](https://npmjs.com/advisories/527). This may affect your application if the following APIs are used: `req.host`, `req.hostname`, `req.ip`, `req.ips`, `req.protocol`. + - The dependency `mime` has been updated to address a [vulnerability](https://npmjs.com/advisories/535), but this issue does not impact Express. + - The dependency `send` has been updated to provide a protection against a [Node.js 8.5.0 vulnerability](https://nodejs.org/en/blog/vulnerability/september-2017-path-validation/). This only impacts running Express on the specific Node.js version 8.5.0. +- 4.15.5 + - The dependency `debug` has been updated to address a [vulnerability](https://snyk.io/vuln/npm:debug:20170905), but this issue does not impact Express. + - The dependency `fresh` has been updated to address a [vulnerability](https://npmjs.com/advisories/526). This will affect your application if the following APIs are used: `express.static`, `req.fresh`, `res.json`, `res.jsonp`, `res.send`, `res.sendfile` `res.sendFile`, `res.sendStatus`. +- 4.15.3 + - The dependency `ms` has been updated to address a [vulnerability](https://snyk.io/vuln/npm:ms:20170412). This may affect your application if untrusted string input is passed to the `maxAge` option in the following APIs: `express.static`, `res.sendfile`, and `res.sendFile`. +- 4.15.2 + - The dependency `qs` has been updated to address a [vulnerability](https://snyk.io/vuln/npm:qs:20170213), but this issue does not impact Express. Updating to 4.15.2 is a good practice, but not required to address the vulnerability. +- 4.11.1 + - Fixed root path disclosure vulnerability in `express.static`, `res.sendfile`, and `res.sendFile` +- 4.10.7 + - Fixed open redirect vulnerability in `express.static` ([advisory](https://npmjs.com/advisories/35), [CVE-2015-1164](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-1164)). +- 4.8.8 + - Fixed directory traversal vulnerabilities in `express.static` ([advisory](http://npmjs.com/advisories/32) , [CVE-2014-6394](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-6394)). +- 4.8.4 + - Node.js 0.10 can leak `fd`s in certain situations that affect `express.static` and `res.sendfile`. Malicious requests could cause `fd`s to leak and eventually lead to `EMFILE` errors and server unresponsiveness. +- 4.8.0 + - Sparse arrays that have extremely high indexes in the query string could cause the process to run out of memory and crash the server. + - Extremely nested query string objects could cause the process to block and make the server unresponsive temporarily. + +## 3.x + +
+ **Express 3.x IS END-OF-LIFE AND NO LONGER MAINTAINED** + +Known and unknown security and performance issues in 3.x have not been addressed since the last update (1 August, 2015). It is highly recommended to use the latest version of Express. + +If you are unable to upgrade past 3.x, please consider [Commercial Support Options](/{{ page.lang }}/support#commercial-support-options). + +
+ +- 3.19.1 + - Fixed root path disclosure vulnerability in `express.static`, `res.sendfile`, and `res.sendFile` +- 3.19.0 + - Fixed open redirect vulnerability in `express.static` ([advisory](https://npmjs.com/advisories/35), [CVE-2015-1164](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-1164)). +- 3.16.10 + - Fixed directory traversal vulnerabilities in `express.static`. +- 3.16.6 + - Node.js 0.10 can leak `fd`s in certain situations that affect `express.static` and `res.sendfile`. Malicious requests could cause `fd`s to leak and eventually lead to `EMFILE` errors and server unresponsiveness. +- 3.16.0 + - Sparse arrays that have extremely high indexes in query string could cause the process to run out of memory and crash the server. + - Extremely nested query string objects could cause the process to block and make the server unresponsive temporarily. +- 3.3.0 + - The 404 response of an unsupported method override attempt was susceptible to cross-site scripting attacks. diff --git a/astro/src/content/docs/en/guide/behind-proxies.md b/astro/src/content/docs/en/guide/behind-proxies.md new file mode 100755 index 0000000000..bbd812a043 --- /dev/null +++ b/astro/src/content/docs/en/guide/behind-proxies.md @@ -0,0 +1,94 @@ +--- +title: Express behind proxies +description: Learn how to configure Express.js applications to work correctly behind reverse proxies, including using the trust proxy setting to handle client IP addresses. +menu: guide +order: 8 +--- + +# Express behind proxies + +When running an Express app behind a reverse proxy, some of the Express APIs may return different values than expected. In order to adjust for this, the `trust proxy` application setting may be used to expose information provided by the reverse proxy in the Express APIs. The most common issue is express APIs that expose the client's IP address may instead show an internal IP address of the reverse proxy. + +
+When configuring the `trust proxy` setting, it is important to understand the exact setup of the reverse proxy. Since this setting will trust values provided in the request, it is important that the combination of the setting in Express matches how the reverse proxy operates. +
+ +The application setting `trust proxy` may be set to one of the values listed in the following table. + + + + + + + + + + + + + + + + + + + + + +
TypeValue
Boolean +If `true`, the client's IP address is understood as the left-most entry in the `X-Forwarded-For` header. + +If `false`, the app is understood as directly facing the client and the client's IP address is derived from `req.socket.remoteAddress`. This is the default setting. + +
+When setting to `true`, it is important to ensure that the last reverse proxy trusted is removing/overwriting all of the following HTTP headers: `X-Forwarded-For`, `X-Forwarded-Host`, and `X-Forwarded-Proto`, otherwise it may be possible for the client to provide any value. +
+
IP addresses +An IP address, subnet, or an array of IP addresses and subnets to trust as being a reverse proxy. The following list shows the pre-configured subnet names: + +- loopback - `127.0.0.1/8`, `::1/128` +- linklocal - `169.254.0.0/16`, `fe80::/10` +- uniquelocal - `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `fc00::/7` + +You can set IP addresses in any of the following ways: + +```js +app.set('trust proxy', 'loopback'); // specify a single subnet +app.set('trust proxy', 'loopback, 123.123.123.123'); // specify a subnet and an address +app.set('trust proxy', 'loopback, linklocal, uniquelocal'); // specify multiple subnets as CSV +app.set('trust proxy', ['loopback', 'linklocal', 'uniquelocal']); // specify multiple subnets as an array +``` + +When specified, the IP addresses or the subnets are excluded from the address determination process, and the untrusted IP address nearest to the application server is determined as the client's IP address. This works by checking if `req.socket.remoteAddress` is trusted. If so, then each address in `X-Forwarded-For` is checked from right to left until the first non-trusted address. + +
Number +Use the address that is at most `n` number of hops away from the Express application. `req.socket.remoteAddress` is the first hop, and the rest are looked for in the `X-Forwarded-For` header from right to left. A value of `0` means that the first untrusted address would be `req.socket.remoteAddress`, i.e. there is no reverse proxy. + +
+When using this setting, it is important to ensure there are not multiple, different-length paths to the Express application such that the client can be less than the configured number of hops away, otherwise it may be possible for the client to provide any value. +
+
Function +Custom trust implementation. + +```js +app.set('trust proxy', (ip) => { + if (ip === '127.0.0.1' || ip === '123.123.123.123') + return true; // trusted IPs + else return false; +}); +``` + +
+ +Enabling `trust proxy` will have the following impact: + +
    +
  • The value of [req.hostname](/{{ page.lang }}/api.html#req.hostname) is derived from the value set in the `X-Forwarded-Host` header, which can be set by the client or by the proxy. +
  • +
  • `X-Forwarded-Proto` can be set by the reverse proxy to tell the app whether it is `https` or `http` or even an invalid name. This value is reflected by [req.protocol](/{{ page.lang }}/api.html#req.protocol). +
  • +
  • The [req.ip](/{{ page.lang }}/api.html#req.ip) and [req.ips](/{{ page.lang }}/api.html#req.ips) values are populated based on the socket address and `X-Forwarded-For` header, starting at the first untrusted address. +
  • +
+ +The `trust proxy` setting is implemented using the [proxy-addr](https://www.npmjs.com/package/proxy-addr) package. For more information, see its documentation. diff --git a/astro/src/content/docs/en/guide/database-integration.md b/astro/src/content/docs/en/guide/database-integration.md new file mode 100644 index 0000000000..3383a7eccc --- /dev/null +++ b/astro/src/content/docs/en/guide/database-integration.md @@ -0,0 +1,503 @@ +--- +title: Express database integration +description: Discover how to integrate various databases with Express.js applications, including setup examples for MongoDB, MySQL, PostgreSQL, and more. +menu: guide +order: 11 +--- + +# Database integration + +Adding the capability to connect databases to Express apps is just a matter of loading an appropriate Node.js driver for the database in your app. This document briefly explains how to add and use some of the most popular Node.js modules for database systems in your Express app: + +- [Cassandra](#cassandra) +- [Couchbase](#couchbase) +- [CouchDB](#couchdb) +- [LevelDB](#leveldb) +- [MySQL](#mysql) +- [MongoDB](#mongodb) +- [Neo4j](#neo4j) +- [Oracle](#oracle) +- [PostgreSQL](#postgresql) +- [Redis](#redis) +- [SQL Server](#sql-server) +- [SQLite](#sqlite) +- [Elasticsearch](#elasticsearch) + +
+These database drivers are among many that are available. For other options, +search on the [npm](https://www.npmjs.com/) site. +
+ +## Cassandra + +**Module**: [cassandra-driver](https://github.com/datastax/nodejs-driver) + +### Installation + +```bash +$ npm install cassandra-driver +``` + +### Example + +```js +const cassandra = require('cassandra-driver'); +const client = new cassandra.Client({ contactPoints: ['localhost'] }); + +client.execute('select key from system.local', (err, result) => { + if (err) throw err; + console.log(result.rows[0]); +}); +``` + +## Couchbase + +**Module**: [couchnode](https://github.com/couchbase/couchnode) + +### Installation + +```bash +$ npm install couchbase +``` + +### Example + +```js +const couchbase = require('couchbase'); +const bucket = new couchbase.Cluster('http://localhost:8091').openBucket('bucketName'); + +// add a document to a bucket +bucket.insert('document-key', { name: 'Matt', shoeSize: 13 }, (err, result) => { + if (err) { + console.log(err); + } else { + console.log(result); + } +}); + +// get all documents with shoe size 13 +const n1ql = 'SELECT d.* FROM `bucketName` d WHERE shoeSize = $1'; +const query = N1qlQuery.fromString(n1ql); +bucket.query(query, [13], (err, result) => { + if (err) { + console.log(err); + } else { + console.log(result); + } +}); +``` + +## CouchDB + +**Module**: [nano](https://github.com/dscape/nano) + +### Installation + +```bash +$ npm install nano +``` + +### Example + +```js +const nano = require('nano')('http://localhost:5984'); +nano.db.create('books'); +const books = nano.db.use('books'); + +// Insert a book document in the books database +books.insert({ name: 'The Art of war' }, null, (err, body) => { + if (err) { + console.log(err); + } else { + console.log(body); + } +}); + +// Get a list of all books +books.list((err, body) => { + if (err) { + console.log(err); + } else { + console.log(body.rows); + } +}); +``` + +## LevelDB + +**Module**: [levelup](https://github.com/rvagg/node-levelup) + +### Installation + +```bash +$ npm install level levelup leveldown +``` + +### Example + +```js +const levelup = require('levelup'); +const db = levelup('./mydb'); + +db.put('name', 'LevelUP', (err) => { + if (err) return console.log('Ooops!', err); + + db.get('name', (err, value) => { + if (err) return console.log('Ooops!', err); + + console.log(`name=${value}`); + }); +}); +``` + +## MySQL + +**Module**: [mysql](https://github.com/felixge/node-mysql/) + +### Installation + +```bash +$ npm install mysql +``` + +### Example + +```js +const mysql = require('mysql'); +const connection = mysql.createConnection({ + host: 'localhost', + user: 'dbuser', + password: 's3kreee7', + database: 'my_db', +}); + +connection.connect(); + +connection.query('SELECT 1 + 1 AS solution', (err, rows, fields) => { + if (err) throw err; + + console.log('The solution is: ', rows[0].solution); +}); + +connection.end(); +``` + +## MongoDB + +**Module**: [mongodb](https://github.com/mongodb/node-mongodb-native) + +### Installation + +```bash +$ npm install mongodb +``` + +### Example (v2.\*) + +```js +const MongoClient = require('mongodb').MongoClient; + +MongoClient.connect('mongodb://localhost:27017/animals', (err, db) => { + if (err) throw err; + + db.collection('mammals') + .find() + .toArray((err, result) => { + if (err) throw err; + + console.log(result); + }); +}); +``` + +### Example (v3.\*) + +```js +const MongoClient = require('mongodb').MongoClient; + +MongoClient.connect('mongodb://localhost:27017/animals', (err, client) => { + if (err) throw err; + + const db = client.db('animals'); + + db.collection('mammals') + .find() + .toArray((err, result) => { + if (err) throw err; + + console.log(result); + }); +}); +``` + +If you want an object model driver for MongoDB, look at [Mongoose](https://github.com/LearnBoost/mongoose). + +## Neo4j + +**Module**: [neo4j-driver](https://github.com/neo4j/neo4j-javascript-driver) + +### Installation + +```bash +$ npm install neo4j-driver +``` + +### Example + +```js +const neo4j = require('neo4j-driver'); +const driver = neo4j.driver('neo4j://localhost:7687', neo4j.auth.basic('neo4j', 'letmein')); + +const session = driver.session(); + +session.readTransaction((tx) => { + return tx + .run('MATCH (n) RETURN count(n) AS count') + .then((res) => { + console.log(res.records[0].get('count')); + }) + .catch((error) => { + console.log(error); + }); +}); +``` + +## Oracle + +**Module**: [oracledb](https://github.com/oracle/node-oracledb) + +### Installation + +NOTE: [See installation prerequisites](https://github.com/oracle/node-oracledb#-installation). + +```bash +$ npm install oracledb +``` + +### Example + +```js +const oracledb = require('oracledb'); +const config = { + user: '', + password: '', + connectString: 'localhost:1521/orcl', +}; + +async function getEmployee(empId) { + let conn; + + try { + conn = await oracledb.getConnection(config); + + const result = await conn.execute('select * from employees where employee_id = :id', [empId]); + + console.log(result.rows[0]); + } catch (err) { + console.log('Ouch!', err); + } finally { + if (conn) { + // conn assignment worked, need to close + await conn.close(); + } + } +} + +getEmployee(101); +``` + +## PostgreSQL + +**Module**: [pg-promise](https://github.com/vitaly-t/pg-promise) + +### Installation + +```bash +$ npm install pg-promise +``` + +### Example + +```js +const pgp = require('pg-promise')(/* options */); +const db = pgp('postgres://username:password@host:port/database'); + +db.one('SELECT $1 AS value', 123) + .then((data) => { + console.log('DATA:', data.value); + }) + .catch((error) => { + console.log('ERROR:', error); + }); +``` + +## Redis + +**Module**: [redis](https://github.com/mranney/node_redis) + +### Installation + +```bash +$ npm install redis +``` + +### Example + +```js +const redis = require('redis'); +const client = redis.createClient(); + +client.on('error', (err) => { + console.log(`Error ${err}`); +}); + +client.set('string key', 'string val', redis.print); +client.hset('hash key', 'hashtest 1', 'some value', redis.print); +client.hset(['hash key', 'hashtest 2', 'some other value'], redis.print); + +client.hkeys('hash key', (err, replies) => { + console.log(`${replies.length} replies:`); + + replies.forEach((reply, i) => { + console.log(` ${i}: ${reply}`); + }); + + client.quit(); +}); +``` + +## SQL Server + +**Module**: [tedious](https://github.com/tediousjs/tedious) + +### Installation + +```bash +$ npm install tedious +``` + +### Example + +```js +const Connection = require('tedious').Connection; +const Request = require('tedious').Request; + +const config = { + server: 'localhost', + authentication: { + type: 'default', + options: { + userName: 'your_username', // update me + password: 'your_password', // update me + }, + }, +}; + +const connection = new Connection(config); + +connection.on('connect', (err) => { + if (err) { + console.log(err); + } else { + executeStatement(); + } +}); + +function executeStatement() { + request = new Request("select 123, 'hello world'", (err, rowCount) => { + if (err) { + console.log(err); + } else { + console.log(`${rowCount} rows`); + } + connection.close(); + }); + + request.on('row', (columns) => { + columns.forEach((column) => { + if (column.value === null) { + console.log('NULL'); + } else { + console.log(column.value); + } + }); + }); + + connection.execSql(request); +} +``` + +## SQLite + +**Module**: [sqlite3](https://github.com/mapbox/node-sqlite3) + +### Installation + +```bash +$ npm install sqlite3 +``` + +### Example + +```js +const sqlite3 = require('sqlite3').verbose(); +const db = new sqlite3.Database(':memory:'); + +db.serialize(() => { + db.run('CREATE TABLE lorem (info TEXT)'); + const stmt = db.prepare('INSERT INTO lorem VALUES (?)'); + + for (let i = 0; i < 10; i++) { + stmt.run(`Ipsum ${i}`); + } + + stmt.finalize(); + + db.each('SELECT rowid AS id, info FROM lorem', (err, row) => { + console.log(`${row.id}: ${row.info}`); + }); +}); + +db.close(); +``` + +## Elasticsearch + +**Module**: [elasticsearch](https://github.com/elastic/elasticsearch-js) + +### Installation + +```bash +$ npm install elasticsearch +``` + +### Example + +```js +const elasticsearch = require('elasticsearch'); +const client = elasticsearch.Client({ + host: 'localhost:9200', +}); + +client + .search({ + index: 'books', + type: 'book', + body: { + query: { + multi_match: { + query: 'express js', + fields: ['title', 'description'], + }, + }, + }, + }) + .then( + (response) => { + const hits = response.hits.hits; + }, + (error) => { + console.trace(error.message); + } + ); +``` diff --git a/astro/src/content/docs/en/guide/debugging.md b/astro/src/content/docs/en/guide/debugging.md new file mode 100755 index 0000000000..27be4d5134 --- /dev/null +++ b/astro/src/content/docs/en/guide/debugging.md @@ -0,0 +1,129 @@ +--- +title: Debugging Express +description: Learn how to enable and use debugging logs in Express.js applications by setting the DEBUG environment variable for enhanced troubleshooting. +menu: guide +order: 7 +--- + +# Debugging Express + +To see all the internal logs used in Express, set the `DEBUG` environment variable to +`express:*` when launching your app. + +```bash +$ DEBUG=express:* node index.js +``` + +On Windows, use the corresponding command. + +```bash +> $env:DEBUG = "express:*"; node index.js +``` + +Running this command on the default app generated by the [express generator](/{{ page.lang }}/starter/generator.html) prints the following output: + +```bash +$ DEBUG=express:* node ./bin/www + express:router:route new / +0ms + express:router:layer new / +1ms + express:router:route get / +1ms + express:router:layer new / +0ms + express:router:route new / +1ms + express:router:layer new / +0ms + express:router:route get / +0ms + express:router:layer new / +0ms + express:application compile etag weak +1ms + express:application compile query parser extended +0ms + express:application compile trust proxy false +0ms + express:application booting in development mode +1ms + express:router use / query +0ms + express:router:layer new / +0ms + express:router use / expressInit +0ms + express:router:layer new / +0ms + express:router use / favicon +1ms + express:router:layer new / +0ms + express:router use / logger +0ms + express:router:layer new / +0ms + express:router use / jsonParser +0ms + express:router:layer new / +1ms + express:router use / urlencodedParser +0ms + express:router:layer new / +0ms + express:router use / cookieParser +0ms + express:router:layer new / +0ms + express:router use / stylus +90ms + express:router:layer new / +0ms + express:router use / serveStatic +0ms + express:router:layer new / +0ms + express:router use / router +0ms + express:router:layer new / +1ms + express:router use /users router +0ms + express:router:layer new /users +0ms + express:router use / <anonymous> +0ms + express:router:layer new / +0ms + express:router use / <anonymous> +0ms + express:router:layer new / +0ms + express:router use / <anonymous> +0ms + express:router:layer new / +0ms +``` + +When a request is then made to the app, you will see the logs specified in the Express code: + +```bash + express:router dispatching GET / +4h + express:router query : / +2ms + express:router expressInit : / +0ms + express:router favicon : / +0ms + express:router logger : / +1ms + express:router jsonParser : / +0ms + express:router urlencodedParser : / +1ms + express:router cookieParser : / +0ms + express:router stylus : / +0ms + express:router serveStatic : / +2ms + express:router router : / +2ms + express:router dispatching GET / +1ms + express:view lookup "index.pug" +338ms + express:view stat "/projects/example/views/index.pug" +0ms + express:view render "/projects/example/views/index.pug" +1ms +``` + +To see the logs only from the router implementation, set the value of `DEBUG` to `express:router`. Likewise, to see logs only from the application implementation, set the value of `DEBUG` to `express:application`, and so on. + +## Applications generated by `express` + +An application generated by the `express` command uses the `debug` module and its debug namespace is scoped to the name of the application. + +For example, if you generated the app with `$ express sample-app`, you can enable the debug statements with the following command: + +```bash +$ DEBUG=sample-app:* node ./bin/www +``` + +You can specify more than one debug namespace by assigning a comma-separated list of names: + +```bash +$ DEBUG=http,mail,express:* node index.js +``` + +## Advanced options + +When running through Node.js, you can set a few environment variables that will change the behavior of the debug logging: + +| Name | Purpose | +| ------------------- | ------------------------------------------------- | +| `DEBUG` | Enables/disables specific debugging namespaces. | +| `DEBUG_COLORS` | Whether or not to use colors in the debug output. | +| `DEBUG_DEPTH` | Object inspection depth. | +| `DEBUG_FD` | File descriptor to write debug output to. | +| `DEBUG_SHOW_HIDDEN` | Shows hidden properties on inspected objects. | + +{% capture debug-text %} + +The environment variables beginning with `DEBUG_` end up being +converted into an Options object that gets used with `%o`/`%O` formatters. +See the Node.js documentation for +[`util.inspect()`](https://nodejs.org/api/util.html#util_util_inspect_object_options) +for the complete list. + +{% endcapture %} + +{% include admonitions/note.html content=debug-text %} diff --git a/astro/src/content/docs/en/guide/error-handling.md b/astro/src/content/docs/en/guide/error-handling.md new file mode 100755 index 0000000000..3d09588c9a --- /dev/null +++ b/astro/src/content/docs/en/guide/error-handling.md @@ -0,0 +1,308 @@ +--- +title: Express error handling +description: Understand how Express.js handles errors in synchronous and asynchronous code, and learn to implement custom error handling middleware for your applications. +menu: guide +order: 6 +--- + +# Error Handling + +_Error Handling_ refers to how Express catches and processes errors that +occur both synchronously and asynchronously. Express comes with a default error +handler so you don't need to write your own to get started. + +## Catching Errors + +It's important to ensure that Express catches all errors that occur while +running route handlers and middleware. + +Errors that occur in synchronous code inside route handlers and middleware +require no extra work. If synchronous code throws an error, then Express will +catch and process it. For example: + +```js +app.get('/', (req, res) => { + throw new Error('BROKEN'); // Express will catch this on its own. +}); +``` + +For errors returned from asynchronous functions invoked by route handlers +and middleware, you must pass them to the `next()` function, where Express will +catch and process them. For example: + +```js +app.get('/', (req, res, next) => { + fs.readFile('/file-does-not-exist', (err, data) => { + if (err) { + next(err); // Pass errors to Express. + } else { + res.send(data); + } + }); +}); +``` + +Starting with Express 5, route handlers and middleware that return a Promise +will call `next(value)` automatically when they reject or throw an error. +For example: + +```js +app.get('/user/:id', async (req, res, next) => { + const user = await getUserById(req.params.id); + res.send(user); +}); +``` + +If `getUserById` throws an error or rejects, `next` will be called with either +the thrown error or the rejected value. If no rejected value is provided, `next` +will be called with a default Error object provided by the Express router. + +If you pass anything to the `next()` function (except the string `'route'`), +Express regards the current request as being an error and will skip any +remaining non-error handling routing and middleware functions. + +If the callback in a sequence provides no data, only errors, you can simplify +this code as follows: + +```js +app.get('/', [ + function (req, res, next) { + fs.writeFile('/inaccessible-path', 'data', next); + }, + function (req, res) { + res.send('OK'); + }, +]); +``` + +In the above example, `next` is provided as the callback for `fs.writeFile`, +which is called with or without errors. If there is no error, the second +handler is executed, otherwise Express catches and processes the error. + +You must catch errors that occur in asynchronous code invoked by route handlers or +middleware and pass them to Express for processing. For example: + +```js +app.get('/', (req, res, next) => { + setTimeout(() => { + try { + throw new Error('BROKEN'); + } catch (err) { + next(err); + } + }, 100); +}); +``` + +The above example uses a `try...catch` block to catch errors in the +asynchronous code and pass them to Express. If the `try...catch` +block were omitted, Express would not catch the error since it is not part of the synchronous +handler code. + +Use promises to avoid the overhead of the `try...catch` block or when using functions +that return promises. For example: + +```js +app.get('/', (req, res, next) => { + Promise.resolve() + .then(() => { + throw new Error('BROKEN'); + }) + .catch(next); // Errors will be passed to Express. +}); +``` + +Since promises automatically catch both synchronous errors and rejected promises, +you can simply provide `next` as the final catch handler and Express will catch errors, +because the catch handler is given the error as the first argument. + +You could also use a chain of handlers to rely on synchronous error +catching, by reducing the asynchronous code to something trivial. For example: + +```js +app.get('/', [ + function (req, res, next) { + fs.readFile('/maybe-valid-file', 'utf-8', (err, data) => { + res.locals.data = data; + next(err); + }); + }, + function (req, res) { + res.locals.data = res.locals.data.split(',')[1]; + res.send(res.locals.data); + }, +]); +``` + +The above example has a couple of trivial statements from the `readFile` +call. If `readFile` causes an error, then it passes the error to Express, otherwise you +quickly return to the world of synchronous error handling in the next handler +in the chain. Then, the example above tries to process the data. If this fails, then the +synchronous error handler will catch it. If you had done this processing inside +the `readFile` callback, then the application might exit and the Express error +handlers would not run. + +Whichever method you use, if you want Express error handlers to be called in and the +application to survive, you must ensure that Express receives the error. + +## The default error handler + +Express comes with a built-in error handler that takes care of any errors that might be encountered in the app. This default error-handling middleware function is added at the end of the middleware function stack. + +If you pass an error to `next()` and you do not handle it in a custom error +handler, it will be handled by the built-in error handler; the error will be +written to the client with the stack trace. The stack trace is not included +in the production environment. + +
+Set the environment variable `NODE_ENV` to `production`, to run the app in production mode. +
+ +When an error is written, the following information is added to the +response: + +- The `res.statusCode` is set from `err.status` (or `err.statusCode`). If + this value is outside the 4xx or 5xx range, it will be set to 500. +- The `res.statusMessage` is set according to the status code. +- The body will be the HTML of the status code message when in production + environment, otherwise will be `err.stack`. +- Any headers specified in an `err.headers` object. + +If you call `next()` with an error after you have started writing the +response (for example, if you encounter an error while streaming the +response to the client), the Express default error handler closes the +connection and fails the request. + +So when you add a custom error handler, you must delegate to +the default Express error handler, when the headers +have already been sent to the client: + +```js +function errorHandler(err, req, res, next) { + if (res.headersSent) { + return next(err); + } + res.status(500); + res.render('error', { error: err }); +} +``` + +Note that the default error handler can get triggered if you call `next()` with an error +in your code more than once, even if custom error handling middleware is in place. + +Other error handling middleware can be found at [Express middleware](/{{ page.lang }}/resources/middleware.html). + +## Writing error handlers + +Define error-handling middleware functions in the same way as other middleware functions, +except error-handling functions have four arguments instead of three: +`(err, req, res, next)`. For example: + +```js +app.use((err, req, res, next) => { + console.error(err.stack); + res.status(500).send('Something broke!'); +}); +``` + +You define error-handling middleware last, after other `app.use()` and routes calls; for example: + +```js +const bodyParser = require('body-parser'); +const methodOverride = require('method-override'); + +app.use( + bodyParser.urlencoded({ + extended: true, + }) +); +app.use(bodyParser.json()); +app.use(methodOverride()); +app.use((err, req, res, next) => { + // logic +}); +``` + +Responses from within a middleware function can be in any format, such as an HTML error page, a simple message, or a JSON string. + +For organizational (and higher-level framework) purposes, you can define +several error-handling middleware functions, much as you would with +regular middleware functions. For example, to define an error-handler +for requests made by using `XHR` and those without: + +```js +const bodyParser = require('body-parser'); +const methodOverride = require('method-override'); + +app.use( + bodyParser.urlencoded({ + extended: true, + }) +); +app.use(bodyParser.json()); +app.use(methodOverride()); +app.use(logErrors); +app.use(clientErrorHandler); +app.use(errorHandler); +``` + +In this example, the generic `logErrors` might write request and +error information to `stderr`, for example: + +```js +function logErrors(err, req, res, next) { + console.error(err.stack); + next(err); +} +``` + +Also in this example, `clientErrorHandler` is defined as follows; in this case, the error is explicitly passed along to the next one. + +Notice that when _not_ calling "next" in an error-handling function, you are responsible for writing (and ending) the response. Otherwise, those requests will "hang" and will not be eligible for garbage collection. + +```js +function clientErrorHandler(err, req, res, next) { + if (req.xhr) { + res.status(500).send({ error: 'Something failed!' }); + } else { + next(err); + } +} +``` + +Implement the "catch-all" `errorHandler` function as follows (for example): + +```js +function errorHandler(err, req, res, next) { + res.status(500); + res.render('error', { error: err }); +} +``` + +If you have a route handler with multiple callback functions, you can use the `route` parameter to skip to the next route handler. For example: + +```js +app.get( + '/a_route_behind_paywall', + (req, res, next) => { + if (!req.user.hasPaid) { + // continue handling this request + next('route'); + } else { + next(); + } + }, + (req, res, next) => { + PaidContent.find((err, doc) => { + if (err) return next(err); + res.json(doc); + }); + } +); +``` + +In this example, the `getPaidContent` handler will be skipped but any remaining handlers in `app` for `/a_route_behind_paywall` would continue to be executed. + +
+Calls to `next()` and `next(err)` indicate that the current handler is complete and in what state. `next(err)` will skip all remaining handlers in the chain except for those that are set up to handle errors as described above. +
diff --git a/astro/src/content/docs/en/guide/migrating-4.md b/astro/src/content/docs/en/guide/migrating-4.md new file mode 100755 index 0000000000..ba06664382 --- /dev/null +++ b/astro/src/content/docs/en/guide/migrating-4.md @@ -0,0 +1,615 @@ +--- +title: Migrating to Express 4 +description: A guide to migrating your Express.js applications from version 3 to 4, covering changes in middleware, routing, and how to update your codebase effectively. +menu: guide +order: 9 +--- + +# Moving to Express 4 + +

Overview

+ +Express 4 is a breaking change from Express 3. That means an existing Express 3 app will _not_ work if you update the Express version in its dependencies. + +This article covers: + + + +

Changes in Express 4

+ +There are several significant changes in Express 4: + + + +See also: + +- [New features in 4.x.](https://github.com/expressjs/express/wiki/New-features-in-4.x) +- [Migrating from 3.x to 4.x.](https://github.com/expressjs/express/wiki/Migrating-from-3.x-to-4.x) + +

+Changes to Express core and middleware system +

+ +Express 4 no longer depends on Connect, and removes all built-in +middleware from its core, except for the `express.static` function. This means that +Express is now an independent routing and middleware web framework, and +Express versioning and releases are not affected by middleware updates. + +Without built-in middleware, you must explicitly add all the +middleware that is required to run your app. Simply follow these steps: + +1. Install the module: `npm install --save ` +2. In your app, require the module: `require('module-name')` +3. Use the module according to its documentation: `app.use( ... )` + +The following table lists Express 3 middleware and their counterparts in Express 4. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Express 3Express 4
express.bodyParserbody-parser + +multer
express.compresscompression
express.cookieSessioncookie-session
express.cookieParsercookie-parser
express.loggermorgan
express.sessionexpress-session
express.faviconserve-favicon
express.responseTimeresponse-time
express.errorHandlererrorhandler
express.methodOverridemethod-override
express.timeoutconnect-timeout
express.vhostvhost
express.csrfcsurf
express.directoryserve-index
express.staticserve-static
+ +Here is the [complete list](https://github.com/senchalabs/connect#middleware) of Express 4 middleware. + +In most cases, you can simply replace the old version 3 middleware with +its Express 4 counterpart. For details, see the module documentation in +GitHub. + +

app.use accepts parameters

+ +In version 4 you can use a variable parameter to define the path where middleware functions are loaded, then read the value of the parameter from the route handler. +For example: + +```js +app.use('/book/:id', (req, res, next) => { + console.log('ID:', req.params.id); + next(); +}); +``` + +

+The routing system +

+ +Apps now implicitly load routing middleware, so you no longer have to +worry about the order in which middleware is loaded with respect to +the `router` middleware. + +The way you define routes is unchanged, but the routing system has two +new features to help organize your routes: + +{: .doclist } + +- A new method, `app.route()`, to create chainable route handlers for a route path. +- A new class, `express.Router`, to create modular mountable route handlers. + +

app.route() method

+ +The new `app.route()` method enables you to create chainable route handlers +for a route path. Because the path is specified in a single location, creating modular routes is helpful, as is reducing redundancy and typos. For more +information about routes, see [`Router()` documentation](/{{ page.lang }}/4x/api.html#router). + +Here is an example of chained route handlers that are defined by using the `app.route()` function. + +```js +app + .route('/book') + .get((req, res) => { + res.send('Get a random book'); + }) + .post((req, res) => { + res.send('Add a book'); + }) + .put((req, res) => { + res.send('Update the book'); + }); +``` + +

express.Router class

+ +The other feature that helps to organize routes is a new class, +`express.Router`, that you can use to create modular mountable +route handlers. A `Router` instance is a complete middleware and +routing system; for this reason it is often referred to as a "mini-app". + +The following example creates a router as a module, loads middleware in +it, defines some routes, and mounts it on a path on the main app. + +For example, create a router file named `birds.js` in the app directory, +with the following content: + +```js +var express = require('express'); +var router = express.Router(); + +// middleware specific to this router +router.use((req, res, next) => { + console.log('Time: ', Date.now()); + next(); +}); +// define the home page route +router.get('/', (req, res) => { + res.send('Birds home page'); +}); +// define the about route +router.get('/about', (req, res) => { + res.send('About birds'); +}); + +module.exports = router; +``` + +Then, load the router module in the app: + +```js +var birds = require('./birds'); + +// ... + +app.use('/birds', birds); +``` + +The app will now be able to handle requests to the `/birds` and +`/birds/about` paths, and will call the `timeLog` +middleware that is specific to the route. + +

+Other changes +

+ +The following table lists other small but important changes in Express 4: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ObjectDescription
Node.jsExpress 4 requires Node.js 0.10.x or later and has dropped support for +Node.js 0.8.x.
+`http.createServer()` + +The `http` module is no longer needed, unless you need to directly work with it (socket.io/SPDY/HTTPS). The app can be started by using the +`app.listen()` function. +
+`app.configure()` + +The `app.configure()` function has been removed. Use the +`process.env.NODE_ENV` or +`app.get('env')` function to detect the environment and configure the app accordingly. +
+`json spaces` + +The `json spaces` application property is disabled by default in Express 4. +
+`req.accepted()` + +Use `req.accepts()`, `req.acceptsEncodings()`, +`req.acceptsCharsets()`, and `req.acceptsLanguages()`. +
+`res.location()` + +No longer resolves relative URLs. +
+`req.params` + +Was an array; now an object. +
+`res.locals` + +Was a function; now an object. +
+`res.headerSent` + +Changed to `res.headersSent`. +
+`app.route` + +Now available as `app.mountpath`. +
+`res.on('header')` + +Removed. +
+`res.charset` + +Removed. +
+`res.setHeader('Set-Cookie', val)` + +Functionality is now limited to setting the basic cookie value. Use +`res.cookie()` for added functionality. +
+ +

Example app migration

+ +Here is an example of migrating an Express 3 application to Express 4. +The files of interest are `app.js` and `package.json`. + +

+Version 3 app +

+ +

app.js

+ +Consider an Express v.3 application with the following `app.js` file: + +```js +var express = require('express'); +var routes = require('./routes'); +var user = require('./routes/user'); +var http = require('http'); +var path = require('path'); + +var app = express(); + +// all environments +app.set('port', process.env.PORT || 3000); +app.set('views', path.join(__dirname, 'views')); +app.set('view engine', 'pug'); +app.use(express.favicon()); +app.use(express.logger('dev')); +app.use(express.methodOverride()); +app.use(express.session({ secret: 'your secret here' })); +app.use(express.bodyParser()); +app.use(app.router); +app.use(express.static(path.join(__dirname, 'public'))); + +// development only +if (app.get('env') === 'development') { + app.use(express.errorHandler()); +} + +app.get('/', routes.index); +app.get('/users', user.list); + +http.createServer(app).listen(app.get('port'), () => { + console.log('Express server listening on port ' + app.get('port')); +}); +``` + +

package.json

+ +The accompanying version 3 `package.json` file might look +something like this: + +```json +{ + "name": "application-name", + "version": "0.0.1", + "private": true, + "scripts": { + "start": "node app.js" + }, + "dependencies": { + "express": "3.12.0", + "pug": "*" + } +} +``` + +

+Process +

+ +Begin the migration process by installing the required middleware for the +Express 4 app and updating Express and Pug to their respective latest +version with the following command: + +```bash +$ npm install serve-favicon morgan method-override express-session body-parser multer errorhandler express@latest pug@latest --save +``` + +Make the following changes to `app.js`: + +1. The built-in Express middleware functions `express.favicon`, + `express.logger`, `express.methodOverride`, + `express.session`, `express.bodyParser` and + `express.errorHandler` are no longer available on the + `express` object. You must install their alternatives + manually and load them in the app. + +2. You no longer need to load the `app.router` function. + It is not a valid Express 4 app object, so remove the + `app.use(app.router);` code. + +3. Make sure that the middleware functions are loaded in the correct order - load `errorHandler` after loading the app routes. + +

Version 4 app

+ +

package.json

+ +Running the above `npm` command will update `package.json` as follows: + +```json +{ + "name": "application-name", + "version": "0.0.1", + "private": true, + "scripts": { + "start": "node app.js" + }, + "dependencies": { + "body-parser": "^1.5.2", + "errorhandler": "^1.1.1", + "express": "^4.8.0", + "express-session": "^1.7.2", + "pug": "^2.0.0", + "method-override": "^2.1.2", + "morgan": "^1.2.2", + "multer": "^0.1.3", + "serve-favicon": "^2.0.1" + } +} +``` + +

app.js

+ +Then, remove invalid code, load the required middleware, and make other +changes as necessary. The `app.js` file will look like this: + +```js +var http = require('http'); +var express = require('express'); +var routes = require('./routes'); +var user = require('./routes/user'); +var path = require('path'); + +var favicon = require('serve-favicon'); +var logger = require('morgan'); +var methodOverride = require('method-override'); +var session = require('express-session'); +var bodyParser = require('body-parser'); +var multer = require('multer'); +var errorHandler = require('errorhandler'); + +var app = express(); + +// all environments +app.set('port', process.env.PORT || 3000); +app.set('views', path.join(__dirname, 'views')); +app.set('view engine', 'pug'); +app.use(favicon(path.join(__dirname, '/public/favicon.ico'))); +app.use(logger('dev')); +app.use(methodOverride()); +app.use( + session({ + resave: true, + saveUninitialized: true, + secret: 'uwotm8', + }) +); +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: true })); +app.use(multer()); +app.use(express.static(path.join(__dirname, 'public'))); + +app.get('/', routes.index); +app.get('/users', user.list); + +// error handling middleware should be loaded after the loading the routes +if (app.get('env') === 'development') { + app.use(errorHandler()); +} + +var server = http.createServer(app); +server.listen(app.get('port'), () => { + console.log('Express server listening on port ' + app.get('port')); +}); +``` + +
+Unless you need to work directly with the `http` module (socket.io/SPDY/HTTPS), loading it is not required, and the app can be simply started this way: + +```js +app.listen(app.get('port'), () => { + console.log('Express server listening on port ' + app.get('port')); +}); +``` + +
+ +

Run the app

+ +The migration process is complete, and the app is now an +Express 4 app. To confirm, start the app by using the following command: + +```bash +$ node . +``` + +Load [http://localhost:3000](http://localhost:3000) +and see the home page being rendered by Express 4. + +

Upgrading to the Express 4 app generator

+ +The command-line tool to generate an Express app is still +`express`, but to upgrade to the new version, you must uninstall +the Express 3 app generator and then install the new +`express-generator`. + +

Installing

+ +If you already have the Express 3 app generator installed on your system, +you must uninstall it: + +```bash +$ npm uninstall -g express +``` + +Depending on how your file and directory privileges are configured, +you might need to run this command with `sudo`. + +Now install the new generator: + +```bash +$ npm install -g express-generator +``` + +Depending on how your file and directory privileges are configured, +you might need to run this command with `sudo`. + +Now the `express` command on your system is updated to the +Express 4 generator. + +

Changes to the app generator

+ +Command options and use largely remain the same, with the following exceptions: + +{: .doclist } + +- Removed the `--sessions` option. +- Removed the `--jshtml` option. +- Added the `--hogan` option to support [Hogan.js](http://twitter.github.io/hogan.js/). + +

Example

+ +Execute the following command to create an Express 4 app: + +```bash +$ express app4 +``` + +If you look at the contents of the `app4/app.js` file, you will notice +that all the middleware functions (except `express.static`) that are required for +the app are loaded as independent modules, and the `router` middleware +is no longer explicitly loaded in the app. + +You will also notice that the `app.js` file is now a Node.js module, in contrast to the standalone app that was generated by the old generator. + +After installing the dependencies, start the app by using the following command: + +```bash +$ npm start +``` + +If you look at the `npm start` script in the `package.json` file, +you will notice that the actual command that starts the app is +`node ./bin/www`, which used to be `node app.js` +in Express 3. + +Because the `app.js` file that was generated by the Express 4 generator +is now a Node.js module, it can no longer be started independently as an app +(unless you modify the code). The module must be loaded in a Node.js file +and started via the Node.js file. The Node.js file is `./bin/www` +in this case. + +Neither the `bin` directory nor the extensionless `www` +file is mandatory for creating an Express app or starting the app. They are +just suggestions made by the generator, so feel free to modify them to suit your +needs. + +To get rid of the `www` directory and keep things the "Express 3 way", +delete the line that says `module.exports = app;` at the end of the +`app.js` file, then paste the following code in its place: + +```js +app.set('port', process.env.PORT || 3000); + +var server = app.listen(app.get('port'), () => { + debug('Express server listening on port ' + server.address().port); +}); +``` + +Ensure that you load the `debug` module at the top of the `app.js` file by using the following code: + +```js +var debug = require('debug')('app4'); +``` + +Next, change `"start": "node ./bin/www"` in the `package.json` file to `"start": "node app.js"`. + +You have now moved the functionality of `./bin/www` back to +`app.js`. This change is not recommended, but the exercise helps you +to understand how the `./bin/www` file works, and why the `app.js` file +no longer starts on its own. diff --git a/astro/src/content/docs/en/guide/migrating-5.md b/astro/src/content/docs/en/guide/migrating-5.md new file mode 100755 index 0000000000..95a1576fe3 --- /dev/null +++ b/astro/src/content/docs/en/guide/migrating-5.md @@ -0,0 +1,616 @@ +--- +title: Migrating to Express 5 +description: A comprehensive guide to migrating your Express.js applications from version 4 to 5, detailing breaking changes, deprecated methods, and new improvements. +menu: guide +order: 10 +--- + +# Moving to Express 5 + +

Overview

+ +Express 5 is not very different from Express 4; although it maintains the same basic API, there are still changes that break compatibility with the previous version. Therefore, an application built with Express 4 might not work if you update it to use Express 5. + +To install this version, you need to have a Node.js version 18 or higher. Then, execute the following command in your application directory: + +```sh +npm install "express@5" +``` + +You can then run your automated tests to see what fails, and fix problems according to the updates listed below. After addressing test failures, run your app to see what errors occur. You'll find out right away if the app uses any methods or properties that are not supported. + +## Express 5 Codemods + +To help you migrate your express server, we have created a set of codemods that will help you automatically update your code to the latest version of Express. + +Run the following command for run all the codemods available: + +```sh +npx codemod@latest @expressjs/v5-migration-recipe +``` + +If you want to run a specific codemod, you can run the following command: + +```sh +npx codemod@latest @expressjs/name-of-the-codemod +``` + +You can find the list of available codemods [here](https://codemod.link/express). + +

Changes in Express 5

+ +**Removed methods and properties** + + + +**Changed** + + + +**Improvements** + + + +## Removed methods and properties + +If you use any of these methods or properties in your app, it will crash. So, you'll need to change your app after you update to version 5. + +

app.del()

+ +Express 5 no longer supports the `app.del()` function. If you use this function, an error is thrown. For registering HTTP DELETE routes, use the `app.delete()` function instead. + +Initially, `del` was used instead of `delete`, because `delete` is a reserved keyword in JavaScript. However, as of ECMAScript 6, `delete` and other reserved keywords can legally be used as property names. + +{% capture codemod-route-del-to-delete %} +You can replace the deprecated signatures with the following command: + +```plain-text +npx codemod@latest @expressjs/route-del-to-delete +``` + +{% endcapture %} + +{% include admonitions/note.html content=codemod-route-del-to-delete %} + +```js +// v4 +app.del('/user/:id', (req, res) => { + res.send(`DELETE /user/${req.params.id}`); +}); + +// v5 +app.delete('/user/:id', (req, res) => { + res.send(`DELETE /user/${req.params.id}`); +}); +``` + +

app.param(fn)

+ +The `app.param(fn)` signature was used for modifying the behavior of the `app.param(name, fn)` function. It has been deprecated since v4.11.0, and Express 5 no longer supports it at all. + +

Pluralized method names

+ +The following method names have been pluralized. In Express 4, using the old methods resulted in a deprecation warning. Express 5 no longer supports them at all: + +`req.acceptsCharset()` is replaced by `req.acceptsCharsets()`. + +`req.acceptsEncoding()` is replaced by `req.acceptsEncodings()`. + +`req.acceptsLanguage()` is replaced by `req.acceptsLanguages()`. + +{% capture codemod-pluralized-methods %} +You can replace the deprecated signatures with the following command: + +```plain-text +npx codemod@latest @expressjs/pluralize-method-names +``` + +{% endcapture %} + +{% include admonitions/note.html content=codemod-pluralized-methods %} + +```js +// v4 +app.all('/', (req, res) => { + req.acceptsCharset('utf-8'); + req.acceptsEncoding('br'); + req.acceptsLanguage('en'); + + // ... +}); + +// v5 +app.all('/', (req, res) => { + req.acceptsCharsets('utf-8'); + req.acceptsEncodings('br'); + req.acceptsLanguages('en'); + + // ... +}); +``` + +

Leading colon (:) in the name for app.param(name, fn)

+ +A leading colon character (:) in the name for the `app.param(name, fn)` function is a remnant of Express 3, and for the sake of backwards compatibility, Express 4 supported it with a deprecation notice. Express 5 will silently ignore it and use the name parameter without prefixing it with a colon. + +This should not affect your code if you follow the Express 4 documentation of [app.param](/{{ page.lang }}/4x/api.html#app.param), as it makes no mention of the leading colon. + +

req.param(name)

+ +This potentially confusing and dangerous method of retrieving form data has been removed. You will now need to specifically look for the submitted parameter name in the `req.params`, `req.body`, or `req.query` object. + +{% capture codemod-req-param %} +You can replace the deprecated signatures with the following command: + +```plain-text +npx codemod@latest @expressjs/explicit-request-params +``` + +{% endcapture %} + +{% include admonitions/note.html content=codemod-req-param %} + +```js +// v4 +app.post('/user', (req, res) => { + const id = req.param('id'); + const body = req.param('body'); + const query = req.param('query'); + + // ... +}); + +// v5 +app.post('/user', (req, res) => { + const id = req.params.id; + const body = req.body; + const query = req.query; + + // ... +}); +``` + +

res.json(obj, status)

+ +Express 5 no longer supports the signature `res.json(obj, status)`. Instead, set the status and then chain it to the `res.json()` method like this: `res.status(status).json(obj)`. + +{% capture codemod-status-send-order %} +You can replace the deprecated signatures with the following command: + +```plain-text +npx codemod@latest @expressjs/status-send-order +``` + +{% endcapture %} + +{% include admonitions/note.html content=codemod-status-send-order %} + +```js +// v4 +app.post('/user', (req, res) => { + res.json({ name: 'Ruben' }, 201); +}); + +// v5 +app.post('/user', (req, res) => { + res.status(201).json({ name: 'Ruben' }); +}); +``` + +

res.jsonp(obj, status)

+ +Express 5 no longer supports the signature `res.jsonp(obj, status)`. Instead, set the status and then chain it to the `res.jsonp()` method like this: `res.status(status).jsonp(obj)`. + +{% include admonitions/note.html content=codemod-status-send-order %} + +```js +// v4 +app.post('/user', (req, res) => { + res.jsonp({ name: 'Ruben' }, 201); +}); + +// v5 +app.post('/user', (req, res) => { + res.status(201).jsonp({ name: 'Ruben' }); +}); +``` + +

res.redirect(url, status)

+ +Express 5 no longer supports the signature `res.redirect(url, status)`. Instead, use the following signature: `res.redirect(status, url)`. + +{% capture codemod-redirect-arg-order %} +You can replace the deprecated signatures with the following command: + +```plain-text +npx codemod@latest @expressjs/redirect-arg-order +``` + +{% endcapture %} + +{% include admonitions/note.html content=codemod-redirect-arg-order %} + +```js +// v4 +app.get('/user', (req, res) => { + res.redirect('/users', 301); +}); + +// v5 +app.get('/user', (req, res) => { + res.redirect(301, '/users'); +}); +``` + +

res.redirect('back') and res.location('back')

+ +Express 5 no longer supports the magic string `back` in the `res.redirect()` and `res.location()` methods. Instead, use the `req.get('Referrer') || '/'` value to redirect back to the previous page. In Express 4, the `res.redirect('back')` and `res.location('back')` methods were deprecated. + +{% capture codemod-back-redirect-deprecated %} +You can replace the deprecated signatures with the following command: + +```plain-text +npx codemod@latest @expressjs/back-redirect-deprecated +``` + +{% endcapture %} + +{% include admonitions/note.html content=codemod-back-redirect-deprecated %} + +```js +// v4 +app.get('/user', (req, res) => { + res.redirect('back'); +}); + +// v5 +app.get('/user', (req, res) => { + res.redirect(req.get('Referrer') || '/'); +}); +``` + +

res.send(body, status)

+ +Express 5 no longer supports the signature `res.send(obj, status)`. Instead, set the status and then chain it to the `res.send()` method like this: `res.status(status).send(obj)`. + +{% include admonitions/note.html content=codemod-status-send-order %} + +```js +// v4 +app.get('/user', (req, res) => { + res.send({ name: 'Ruben' }, 200); +}); + +// v5 +app.get('/user', (req, res) => { + res.status(200).send({ name: 'Ruben' }); +}); +``` + +

res.send(status)

+ +Express 5 no longer supports the signature `res.send(status)`, where `status` is a number. Instead, use the `res.sendStatus(statusCode)` function, which sets the HTTP response header status code and sends the text version of the code: "Not Found", "Internal Server Error", and so on. +If you need to send a number by using the `res.send()` function, quote the number to convert it to a string, so that Express does not interpret it as an attempt to use the unsupported old signature. + +{% include admonitions/note.html content=codemod-status-send-order %} + +```js +// v4 +app.get('/user', (req, res) => { + res.send(200); +}); + +// v5 +app.get('/user', (req, res) => { + res.sendStatus(200); +}); +``` + +

res.sendfile()

+ +The `res.sendfile()` function has been replaced by a camel-cased version `res.sendFile()` in Express 5. + +**Note:** In Express 5, `res.sendFile()` uses the `mime-types` package for MIME type detection, which returns different Content-Type values than Express 4 for several common file types: + +- JavaScript files (.js): now "text/javascript" instead of "application/javascript" +- JSON files (.json): now "application/json" instead of "text/json" +- CSS files (.css): now "text/css" instead of "text/plain" +- XML files (.xml): now "application/xml" instead of "text/xml" +- Font files (.woff): now "font/woff" instead of "application/font-woff" +- SVG files (.svg): now "image/svg+xml" instead of "application/svg+xml" + +{% capture codemod-camelcase-sendfile %} +You can replace the deprecated signatures with the following command: + +```plain-text +npx codemod@latest @expressjs/camelcase-sendfile +``` + +{% endcapture %} + +{% include admonitions/note.html content=codemod-camelcase-sendfile %} + +```js +// v4 +app.get('/user', (req, res) => { + res.sendfile('/path/to/file'); +}); + +// v5 +app.get('/user', (req, res) => { + res.sendFile('/path/to/file'); +}); +``` + +

router.param(fn)

+ +The `router.param(fn)` signature was used for modifying the behavior of the `router.param(name, fn)` function. It has been deprecated since v4.11.0, and Express 5 no longer supports it at all. + +

express.static.mime

+ +In Express 5, `mime` is no longer an exported property of the `static` field. +Use the [`mime-types` package](https://github.com/jshttp/mime-types) to work with MIME type values. + +**Important:** This change affects not only direct usage of `express.static.mime` but also other Express methods that rely on MIME type detection, such as `res.sendFile()`. The following MIME types have changed from Express 4: + +- JavaScript files (.js): now served as "text/javascript" instead of "application/javascript" +- JSON files (.json): now served as "application/json" instead of "text/json" +- CSS files (.css): now served as "text/css" instead of "text/plain" +- HTML files (.html): now served as "text/html; charset=utf-8" instead of just "text/html" +- XML files (.xml): now served as "application/xml" instead of "text/xml" +- Font files (.woff): now served as "font/woff" instead of "application/font-woff" + +```js +// v4 +express.static.mime.lookup('json'); + +// v5 +const mime = require('mime-types'); +mime.lookup('json'); +``` + +

express:router debug logs

+ +In Express 5, router handling logic is performed by a dependency. Therefore, the +debug logs for the router are no longer available under the `express:` namespace. +In v4, the logs were available under the namespaces `express:router`, `express:router:layer`, +and `express:router:route`. All of these were included under the namespace `express:*`. +In v5.1+, the logs are available under the namespaces `router`, `router:layer`, and `router:route`. +The logs from `router:layer` and `router:route` are included in the namespace `router:*`. +To achieve the same detail of debug logging when using `express:*` in v4, use a conjunction of +`express:*`, `router`, and `router:*`. + +```sh +# v4 +DEBUG=express:* node index.js + +# v5 +DEBUG=express:*,router,router:* node index.js +``` + +## Changed + +

Path route matching syntax

+ +Path route matching syntax is when a string is supplied as the first parameter to the `app.all()`, `app.use()`, `app.METHOD()`, `router.all()`, `router.METHOD()`, and `router.use()` APIs. The following changes have been made to how the path string is matched to an incoming request: + +- The wildcard `*` must have a name, matching the behavior of parameters `:`, use `/*splat` instead of `/*` + +```js +// v4 +app.get('/*', async (req, res) => { + res.send('ok'); +}); + +// v5 +app.get('/*splat', async (req, res) => { + res.send('ok'); +}); +``` + +{% capture note_wildcard %} +`*splat` matches any path without the root path. If you need to match the root path as well `/`, you can use `/{*splat}`, wrapping the wildcard in braces. + +```js +// v5 +app.get('/{*splat}', async (req, res) => { + res.send('ok'); +}); +``` + +{% endcapture %} +{% include admonitions/note.html content=note_wildcard %} + +- The optional character `?` is no longer supported, use braces instead. + +```js +// v4 +app.get('/:file.:ext?', async (req, res) => { + res.send('ok'); +}); + +// v5 +app.get('/:file{.:ext}', async (req, res) => { + res.send('ok'); +}); +``` + +- Regexp characters are not supported. For example: + +```js +app.get('/[discussion|page]/:slug', async (req, res) => { + res.status(200).send('ok'); +}); +``` + +should be changed to: + +```js +app.get(['/discussion/:slug', '/page/:slug'], async (req, res) => { + res.status(200).send('ok'); +}); +``` + +- Some characters have been reserved to avoid confusion during upgrade (`()[]?+!`), use `\` to escape them. +- Parameter names now support valid JavaScript identifiers, or quoted like `:"this"`. + +

Rejected promises handled from middleware and handlers

+ +Request middleware and handlers that return rejected promises are now handled by forwarding the rejected value as an `Error` to the error handling middleware. This means that using `async` functions as middleware and handlers are easier than ever. When an error is thrown in an `async` function or a rejected promise is `await`ed inside an async function, those errors will be passed to the error handler as if calling `next(err)`. + +Details of how Express handles errors is covered in the [error handling documentation](/en/guide/error-handling.html). + +

express.urlencoded

+ +The `express.urlencoded` method makes the `extended` option `false` by default. + +

express.static dotfiles

+ +In Express 5, the `express.static` middleware's `dotfiles` option now defaults to `"ignore"`. This is a change from Express 4, where dotfiles were served by default. As a result, files inside a directory that starts with a dot (`.`), such as `.well-known`, will no longer be accessible and will return a **404 Not Found** error. This can break functionality that depends on serving dot-directories, such as Android App Links, and Apple Universal Links. + +Example of breaking code: + +```js +// v4 +app.use(express.static('public')); +``` + +After migrating to Express 5, a request to `/.well-known/assetlinks.json` will result in a **404 Not Found**. + +To fix this, serve specific dot-directories explicitly using the `dotfiles: "allow"` option: + +```js +// v5 +app.use('/.well-known', express.static('public/.well-known', { dotfiles: 'allow' })); +app.use(express.static('public')); +``` + +This approach allows you to safely serve only the intended dot-directories while keeping the default secure behavior for other dotfiles, which remain inaccessible. + +

app.listen

+ +In Express 5, the `app.listen` method will invoke the user-provided callback function (if provided) when the server receives an error event. In Express 4, such errors would be thrown. This change shifts error-handling responsibility to the callback function in Express 5. If there is an error, it will be passed to the callback as an argument. +For example: + +```js +const server = app.listen(8080, '0.0.0.0', (error) => { + if (error) { + throw error; // e.g. EADDRINUSE + } + console.log(`Listening on ${JSON.stringify(server.address())}`); +}); +``` + +

app.router

+ +The `app.router` object, which was removed in Express 4, has made a comeback in Express 5. In the new version, this object is a just a reference to the base Express router, unlike in Express 3, where an app had to explicitly load it. + +

req.body

+ +The `req.body` property returns `undefined` when the body has not been parsed. In Express 4, it returns `{}` by default. + +

req.host

+ +In Express 4, the `req.host` function incorrectly stripped off the port number if it was present. In Express 5, the port number is maintained. + +

req.params

+ +The `req.params` object now has a **null prototype** when using string paths. However, if the path is defined with a regular expression, `req.params` remains a standard object with a normal prototype. Additionally, there are two important behavioral changes: + +**Wildcard parameters are now arrays:** + +Wildcards (e.g., `/*splat`) capture path segments as an array instead of a single string. + +```js +app.get('/*splat', (req, res) => { + // GET /foo/bar + console.dir(req.params); + // => [Object: null prototype] { splat: [ 'foo', 'bar' ] } +}); +``` + +**Unmatched parameters are omitted:** + +In Express 4, unmatched wildcards were empty strings (`''`) and optional `:` parameters (using `?`) had a key with value `undefined`. In Express 5, unmatched parameters are completely omitted from `req.params`. + +```js +// v4: unmatched wildcard is empty string +app.get('/*', (req, res) => { + // GET / + console.dir(req.params); + // => { '0': '' } +}); + +// v4: unmatched optional param is undefined +app.get('/:file.:ext?', (req, res) => { + // GET /image + console.dir(req.params); + // => { file: 'image', ext: undefined } +}); + +// v5: unmatched optional param is omitted +app.get('/:file{.:ext}', (req, res) => { + // GET /image + console.dir(req.params); + // => [Object: null prototype] { file: 'image' } +}); +``` + +

req.query

+ +The `req.query` property is no longer a writable property and is instead a getter. The default query parser has been changed from "extended" to "simple". + +

res.clearCookie

+ +The `res.clearCookie` method ignores the `maxAge` and `expires` options provided by the user. + +

res.status

+ +The `res.status` method only accepts integers in the range of `100` to `999`, following the behavior defined by Node.js, and it returns an error when the status code is not an integer. + +

res.vary

+ +The `res.vary` throws an error when the `field` argument is missing. In Express 4, if the argument was omitted, it gave a warning in the console + +## Improvements + +

res.render()

+ +This method now enforces asynchronous behavior for all view engines, avoiding bugs caused by view engines that had a synchronous implementation and that violated the recommended interface. + +

Brotli encoding support

+ +Express 5 supports Brotli encoding for requests received from clients that support it. diff --git a/astro/src/content/docs/en/guide/overriding-express-api.md b/astro/src/content/docs/en/guide/overriding-express-api.md new file mode 100644 index 0000000000..33e3bcf83f --- /dev/null +++ b/astro/src/content/docs/en/guide/overriding-express-api.md @@ -0,0 +1,72 @@ +--- +title: Overriding the Express API +description: Discover how to customize and extend the Express.js API by overriding methods and properties on the request and response objects using prototypes. +menu: guide +order: 4 +--- + +# Overriding the Express API + +The Express API consists of various methods and properties on the request and response objects. These are inherited by prototype. There are two extension points for the Express API: + +1. The global prototypes at `express.request` and `express.response`. +2. App-specific prototypes at `app.request` and `app.response`. + +Altering the global prototypes will affect all loaded Express apps in the same process. If desired, alterations can be made app-specific by only altering the app-specific prototypes after creating a new app. + +## Methods + +You can override the signature and behavior of existing methods with your own, by assigning a custom function. + +Following is an example of overriding the behavior of [res.sendStatus](/4x/api.html#res.sendStatus). + +```js +app.response.sendStatus = function (statusCode, type, message) { + // code is intentionally kept simple for demonstration purpose + return this.contentType(type).status(statusCode).send(message); +}; +``` + +The above implementation completely changes the original signature of `res.sendStatus`. It now accepts a status code, encoding type, and the message to be sent to the client. + +The overridden method may now be used this way: + +```js +res.sendStatus(404, 'application/json', '{"error":"resource not found"}'); +``` + +## Properties + +Properties in the Express API are either: + +1. Assigned properties (ex: `req.baseUrl`, `req.originalUrl`) +2. Defined as getters (ex: `req.secure`, `req.ip`) + +Since properties under category 1 are dynamically assigned on the `request` and `response` objects in the context of the current request-response cycle, their behavior cannot be overridden. + +Properties under category 2 can be overwritten using the Express API extensions API. + +The following code rewrites how the value of `req.ip` is to be derived. Now, it simply returns the value of the `Client-IP` request header. + +```js +Object.defineProperty(app.request, 'ip', { + configurable: true, + enumerable: true, + get() { + return this.get('Client-IP'); + }, +}); +``` + +## Prototype + +In order to provide the Express API, the request/response objects passed to Express (via `app(req, res)`, for example) need to inherit from the same prototype chain. By default, this is `http.IncomingRequest.prototype` for the request and `http.ServerResponse.prototype` for the response. + +Unless necessary, it is recommended that this be done only at the application level, rather than globally. Also, take care that the prototype that is being used matches the functionality as closely as possible to the default prototypes. + +```js +// Use FakeRequest and FakeResponse in place of http.IncomingRequest and http.ServerResponse +// for the given app reference +Object.setPrototypeOf(Object.getPrototypeOf(app.request), FakeRequest.prototype); +Object.setPrototypeOf(Object.getPrototypeOf(app.response), FakeResponse.prototype); +``` diff --git a/astro/src/content/docs/en/guide/routing.md b/astro/src/content/docs/en/guide/routing.md new file mode 100755 index 0000000000..65b6b64d30 --- /dev/null +++ b/astro/src/content/docs/en/guide/routing.md @@ -0,0 +1,419 @@ +--- +title: Express routing +description: Learn how to define and use routes in Express.js applications, including route methods, route paths, parameters, and using Router for modular routing. +menu: guide +order: 1 +--- + +# Routing + +_Routing_ refers to how an application's endpoints (URIs) respond to client requests. +For an introduction to routing, see [Basic routing](/{{ page.lang }}/starter/basic-routing.html). + +You define routing using methods of the Express `app` object that correspond to HTTP methods; +for example, `app.get()` to handle GET requests and `app.post` to handle POST requests. For a full list, +see [app.METHOD](/{{ page.lang }}/5x/api.html#app.METHOD). You can also use [app.all()](/{{ page.lang }}/5x/api.html#app.all) to handle all HTTP methods and [app.use()](/{{ page.lang }}/5x/api.html#app.use) to +specify middleware as the callback function (See [Using middleware](/{{ page.lang }}/guide/using-middleware.html) for details). + +These routing methods specify a callback function (sometimes called "handler functions") called when the application receives a request to the specified route (endpoint) and HTTP method. In other words, the application "listens" for requests that match the specified route(s) and method(s), and when it detects a match, it calls the specified callback function. + +In fact, the routing methods can have more than one callback function as arguments. +With multiple callback functions, it is important to provide `next` as an argument to the callback function and then call `next()` within the body of the function to hand off control +to the next callback. + +The following code is an example of a very basic route. + +```js +const express = require('express'); +const app = express(); + +// respond with "hello world" when a GET request is made to the homepage +app.get('/', (req, res) => { + res.send('hello world'); +}); +``` + +

Route methods

+ +A route method is derived from one of the HTTP methods, and is attached to an instance of the `express` class. + +The following code is an example of routes that are defined for the `GET` and the `POST` methods to the root of the app. + +```js +// GET method route +app.get('/', (req, res) => { + res.send('GET request to the homepage'); +}); + +// POST method route +app.post('/', (req, res) => { + res.send('POST request to the homepage'); +}); +``` + +Express supports methods that correspond to all HTTP request methods: `get`, `post`, and so on. +For a full list, see [app.METHOD](/{{ page.lang }}/5x/api.html#app.METHOD). + +There is a special routing method, `app.all()`, used to load middleware functions at a path for _all_ HTTP request methods. For example, the following handler is executed for requests to the route `"/secret"` whether using `GET`, `POST`, `PUT`, `DELETE`, or any other HTTP request method supported in the [http module](https://nodejs.org/api/http.html#http_http_methods). + +```js +app.all('/secret', (req, res, next) => { + console.log('Accessing the secret section ...'); + next(); // pass control to the next handler +}); +``` + +

Route paths

+ +Route paths, in combination with a request method, define the endpoints at which requests can be made. Route paths can be strings, string patterns, or regular expressions. + +{% capture caution-character %} In express 5, the characters `?`, `+`, `*`, `[]`, and `()` are handled differently than in version 4, please review the [migration guide](/{{ page.lang }}/guide/migrating-5.html#path-syntax) for more information.{% endcapture %} + +{% include admonitions/caution.html content=caution-character %} + +{% capture note-dollar-character %}In express 4, regular expression characters such as `$` need to be escaped with a `\`. +{% endcapture %} + +{% include admonitions/caution.html content=note-dollar-character %} + +{% capture note-path-to-regexp %} + +Express uses [path-to-regexp](https://www.npmjs.com/package/path-to-regexp) for matching the route paths; see the path-to-regexp documentation for all the possibilities in defining route paths. [Express Playground Router](https://bjohansebas.github.io/playground-router/) is a handy tool for testing basic Express routes, although it does not support pattern matching. + +{% endcapture %} + +{% include admonitions/note.html content=note-path-to-regexp %} + +{% capture query-string-note %} + +Query strings are not part of the route path. + +{% endcapture %} + +{% include admonitions/warning.html content=query-string-note %} + +### Route paths based on strings + +This route path will match requests to the root route, `/`. + +```js +app.get('/', (req, res) => { + res.send('root'); +}); +``` + +This route path will match requests to `/about`. + +```js +app.get('/about', (req, res) => { + res.send('about'); +}); +``` + +This route path will match requests to `/random.text`. + +```js +app.get('/random.text', (req, res) => { + res.send('random.text'); +}); +``` + +### Route paths based on string patterns + +{% capture caution-string-patterns %} The string patterns in Express 5 no longer work. Please refer to the [migration guide](/{{ page.lang }}/guide/migrating-5.html#path-syntax) for more information.{% endcapture %} + +{% include admonitions/caution.html content=caution-string-patterns %} + +This route path will match `acd` and `abcd`. + +```js +app.get('/ab?cd', (req, res) => { + res.send('ab?cd'); +}); +``` + +This route path will match `abcd`, `abbcd`, `abbbcd`, and so on. + +```js +app.get('/ab+cd', (req, res) => { + res.send('ab+cd'); +}); +``` + +This route path will match `abcd`, `abxcd`, `abRANDOMcd`, `ab123cd`, and so on. + +```js +app.get('/ab*cd', (req, res) => { + res.send('ab*cd'); +}); +``` + +This route path will match `/abe` and `/abcde`. + +```js +app.get('/ab(cd)?e', (req, res) => { + res.send('ab(cd)?e'); +}); +``` + +### Route paths based on regular expressions + +This route path will match anything with an "a" in it. + +```js +app.get(/a/, (req, res) => { + res.send('/a/'); +}); +``` + +This route path will match `butterfly` and `dragonfly`, but not `butterflyman`, `dragonflyman`, and so on. + +```js +app.get(/.*fly$/, (req, res) => { + res.send('/.*fly$/'); +}); +``` + +

Route parameters

+ +Route parameters are named URL segments that are used to capture the values specified at their position in the URL. The captured values are populated in the `req.params` object, with the name of the route parameter specified in the path as their respective keys. + +``` +Route path: /users/:userId/books/:bookId +Request URL: http://localhost:3000/users/34/books/8989 +req.params: { "userId": "34", "bookId": "8989" } +``` + +To define routes with route parameters, simply specify the route parameters in the path of the route as shown below. + +```js +app.get('/users/:userId/books/:bookId', (req, res) => { + res.send(req.params); +}); +``` + +
+The name of route parameters must be made up of "word characters" ([A-Za-z0-9_]). +
+ +Since the hyphen (`-`) and the dot (`.`) are interpreted literally, they can be used along with route parameters for useful purposes. + +``` +Route path: /flights/:from-:to +Request URL: http://localhost:3000/flights/LAX-SFO +req.params: { "from": "LAX", "to": "SFO" } +``` + +``` +Route path: /plantae/:genus.:species +Request URL: http://localhost:3000/plantae/Prunus.persica +req.params: { "genus": "Prunus", "species": "persica" } +``` + +{% capture warning-regexp %} +In express 5, Regexp characters are not supported in route paths, for more information please refer to the [migration guide](/{{ page.lang }}/guide/migrating-5.html#path-syntax).{% endcapture %} + +{% include admonitions/caution.html content=warning-regexp %} + +To have more control over the exact string that can be matched by a route parameter, you can append a regular expression in parentheses (`()`): + +``` +Route path: /user/:userId(\d+) +Request URL: http://localhost:3000/user/42 +req.params: {"userId": "42"} +``` + +{% capture escape-advisory %} + +Because the regular expression is usually part of a literal string, be sure to escape any `\` characters with an additional backslash, for example `\\d+`. + +{% endcapture %} + +{% include admonitions/warning.html content=escape-advisory %} + +{% capture warning-version %} + +In Express 4.x, the `*` character in regular expressions is not interpreted in the usual way. As a workaround, use `{0,}` instead of `*`. This will likely be fixed in Express 5. + +{% endcapture %} + +{% include admonitions/warning.html content=warning-version %} + +

Route handlers

+ +You can provide multiple callback functions that behave like [middleware](/{{ page.lang }}/guide/using-middleware.html) to handle a request. The only exception is that these callbacks might invoke `next('route')` to bypass the remaining route callbacks. You can use this mechanism to impose pre-conditions on a route, then pass control to subsequent routes if there's no reason to proceed with the current route. + +```js +app.get('/user/:id', (req, res, next) => { + if (req.params.id === '0') { + return next('route'); + } + res.send(`User ${req.params.id}`); +}); + +app.get('/user/:id', (req, res) => { + res.send('Special handler for user ID 0'); +}); +``` + +In this example: + +- `GET /user/5` → handled by first route → sends "User 5" +- `GET /user/0` → first route calls `next('route')`, skipping to the next matching `/user/:id` route + +Route handlers can be in the form of a function, an array of functions, or combinations of both, as shown in the following examples. + +A single callback function can handle a route. For example: + +```js +app.get('/example/a', (req, res) => { + res.send('Hello from A!'); +}); +``` + +More than one callback function can handle a route (make sure you specify the `next` object). For example: + +```js +app.get( + '/example/b', + (req, res, next) => { + console.log('the response will be sent by the next function ...'); + next(); + }, + (req, res) => { + res.send('Hello from B!'); + } +); +``` + +An array of callback functions can handle a route. For example: + +```js +const cb0 = function (req, res, next) { + console.log('CB0'); + next(); +}; + +const cb1 = function (req, res, next) { + console.log('CB1'); + next(); +}; + +const cb2 = function (req, res) { + res.send('Hello from C!'); +}; + +app.get('/example/c', [cb0, cb1, cb2]); +``` + +A combination of independent functions and arrays of functions can handle a route. For example: + +```js +const cb0 = function (req, res, next) { + console.log('CB0'); + next(); +}; + +const cb1 = function (req, res, next) { + console.log('CB1'); + next(); +}; + +app.get( + '/example/d', + [cb0, cb1], + (req, res, next) => { + console.log('the response will be sent by the next function ...'); + next(); + }, + (req, res) => { + res.send('Hello from D!'); + } +); +``` + +

Response methods

+ +The methods on the response object (`res`) in the following table can send a response to the client, and terminate the request-response cycle. If none of these methods are called from a route handler, the client request will be left hanging. + +| Method | Description | +| --------------------------------------------------------------- | ------------------------------------------------------------------------------------- | +| [res.download()](/{{ page.lang }}/5x/api.html#res.download) | Prompt a file to be downloaded. | +| [res.end()](/{{ page.lang }}/5x/api.html#res.end) | End the response process. | +| [res.json()](/{{ page.lang }}/5x/api.html#res.json) | Send a JSON response. | +| [res.jsonp()](/{{ page.lang }}/5x/api.html#res.jsonp) | Send a JSON response with JSONP support. | +| [res.redirect()](/{{ page.lang }}/5x/api.html#res.redirect) | Redirect a request. | +| [res.render()](/{{ page.lang }}/5x/api.html#res.render) | Render a view template. | +| [res.send()](/{{ page.lang }}/5x/api.html#res.send) | Send a response of various types. | +| [res.sendFile()](/{{ page.lang }}/5x/api.html#res.sendFile) | Send a file as an octet stream. | +| [res.sendStatus()](/{{ page.lang }}/5x/api.html#res.sendStatus) | Set the response status code and send its string representation as the response body. | + +

app.route()

+ +You can create chainable route handlers for a route path by using `app.route()`. +Because the path is specified at a single location, creating modular routes is helpful, as is reducing redundancy and typos. For more information about routes, see: [Router() documentation](/{{ page.lang }}/5x/api.html#router). + +Here is an example of chained route handlers that are defined by using `app.route()`. + +```js +app + .route('/book') + .get((req, res) => { + res.send('Get a random book'); + }) + .post((req, res) => { + res.send('Add a book'); + }) + .put((req, res) => { + res.send('Update the book'); + }); +``` + +

express.Router

+ +Use the `express.Router` class to create modular, mountable route handlers. A `Router` instance is a complete middleware and routing system; for this reason, it is often referred to as a "mini-app". + +The following example creates a router as a module, loads a middleware function in it, defines some routes, and mounts the router module on a path in the main app. + +Create a router file named `birds.js` in the app directory, with the following content: + +```js +const express = require('express'); +const router = express.Router(); + +// middleware that is specific to this router +const timeLog = (req, res, next) => { + console.log('Time: ', Date.now()); + next(); +}; +router.use(timeLog); + +// define the home page route +router.get('/', (req, res) => { + res.send('Birds home page'); +}); +// define the about route +router.get('/about', (req, res) => { + res.send('About birds'); +}); + +module.exports = router; +``` + +Then, load the router module in the app: + +```js +const birds = require('./birds'); + +// ... + +app.use('/birds', birds); +``` + +The app will now be able to handle requests to `/birds` and `/birds/about`, as well as call the `timeLog` middleware function that is specific to the route. + +But if the parent route `/birds` has path parameters, it will not be accessible by default from the sub-routes. To make it accessible, you will need to pass the `mergeParams` option to the Router constructor [reference](/{{ page.lang }}/5x/api.html#app.use). + +```js +const router = express.Router({ mergeParams: true }); +``` diff --git a/astro/src/content/docs/en/guide/using-middleware.md b/astro/src/content/docs/en/guide/using-middleware.md new file mode 100644 index 0000000000..1e372172de --- /dev/null +++ b/astro/src/content/docs/en/guide/using-middleware.md @@ -0,0 +1,297 @@ +--- +title: Using Express middleware +description: Learn how to use middleware in Express.js applications, including application-level and router-level middleware, error handling, and integrating third-party middleware. +menu: guide +order: 3 +--- + +# Using middleware + +Express is a routing and middleware web framework that has minimal functionality of its own: An Express application is essentially a series of middleware function calls. + +_Middleware_ functions are functions that have access to the [request object](/{{ page.lang }}/5x/api.html#req) (`req`), the [response object](/{{ page.lang }}/5x/api.html#res) (`res`), and the next middleware function in the application's request-response cycle. The next middleware function is commonly denoted by a variable named `next`. + +Middleware functions can perform the following tasks: + +- Execute any code. +- Make changes to the request and the response objects. +- End the request-response cycle. +- Call the next middleware function in the stack. + +If the current middleware function does not end the request-response cycle, it must call `next()` to pass control to the next middleware function. Otherwise, the request will be left hanging. + +An Express application can use the following types of middleware: + +- [Application-level middleware](#middleware.application) +- [Router-level middleware](#middleware.router) +- [Error-handling middleware](#middleware.error-handling) +- [Built-in middleware](#middleware.built-in) +- [Third-party middleware](#middleware.third-party) + +You can load application-level and router-level middleware with an optional mount path. +You can also load a series of middleware functions together, which creates a sub-stack of the middleware system at a mount point. + +

Application-level middleware

+ +Bind application-level middleware to an instance of the [app object](/{{ page.lang }}/5x/api.html#app) by using the `app.use()` and `app.METHOD()` functions, where `METHOD` is the HTTP method of the request that the middleware function handles (such as GET, PUT, or POST) in lowercase. + +This example shows a middleware function with no mount path. The function is executed every time the app receives a request. + +```js +const express = require('express'); +const app = express(); + +app.use((req, res, next) => { + console.log('Time:', Date.now()); + next(); +}); +``` + +This example shows a middleware function mounted on the `/user/:id` path. The function is executed for any type of +HTTP request on the `/user/:id` path. + +```js +app.use('/user/:id', (req, res, next) => { + console.log('Request Type:', req.method); + next(); +}); +``` + +This example shows a route and its handler function (middleware system). The function handles GET requests to the `/user/:id` path. + +```js +app.get('/user/:id', (req, res, next) => { + res.send('USER'); +}); +``` + +Here is an example of loading a series of middleware functions at a mount point, with a mount path. +It illustrates a middleware sub-stack that prints request info for any type of HTTP request to the `/user/:id` path. + +```js +app.use( + '/user/:id', + (req, res, next) => { + console.log('Request URL:', req.originalUrl); + next(); + }, + (req, res, next) => { + console.log('Request Type:', req.method); + next(); + } +); +``` + +Route handlers enable you to define multiple routes for a path. The example below defines two routes for GET requests to the `/user/:id` path. The second route will not cause any problems, but it will never get called because the first route ends the request-response cycle. + +This example shows a middleware sub-stack that handles GET requests to the `/user/:id` path. + +```js +app.get( + '/user/:id', + (req, res, next) => { + console.log('ID:', req.params.id); + next(); + }, + (req, res, next) => { + res.send('User Info'); + } +); + +// handler for the /user/:id path, which prints the user ID +app.get('/user/:id', (req, res, next) => { + res.send(req.params.id); +}); +``` + +To skip the rest of the middleware functions from a router middleware stack, call `next('route')` to pass control to the next route. + +{% capture next-function %} + +`next('route')` will work only in middleware functions that were loaded by using the `app.METHOD()` or `router.METHOD()` functions. + +{% endcapture %} + +{% include admonitions/note.html content=next-function %} + +This example shows a middleware sub-stack that handles GET requests to the `/user/:id` path. + +```js +app.get( + '/user/:id', + (req, res, next) => { + // if the user ID is 0, skip to the next route + if (req.params.id === '0') next('route'); + // otherwise pass the control to the next middleware function in this stack + else next(); + }, + (req, res, next) => { + // send a regular response + res.send('regular'); + } +); + +// handler for the /user/:id path, which sends a special response +app.get('/user/:id', (req, res, next) => { + res.send('special'); +}); +``` + +Middleware can also be declared in an array for reusability. + +This example shows an array with a middleware sub-stack that handles GET requests to the `/user/:id` path + +```js +function logOriginalUrl(req, res, next) { + console.log('Request URL:', req.originalUrl); + next(); +} + +function logMethod(req, res, next) { + console.log('Request Type:', req.method); + next(); +} + +const logStuff = [logOriginalUrl, logMethod]; +app.get('/user/:id', logStuff, (req, res, next) => { + res.send('User Info'); +}); +``` + +

Router-level middleware

+ +Router-level middleware works in the same way as application-level middleware, except it is bound to an instance of `express.Router()`. + +```js +const router = express.Router(); +``` + +Load router-level middleware by using the `router.use()` and `router.METHOD()` functions. + +The following example code replicates the middleware system that is shown above for application-level middleware, by using router-level middleware: + +```js +const express = require('express'); +const app = express(); +const router = express.Router(); + +// a middleware function with no mount path. This code is executed for every request to the router +router.use((req, res, next) => { + console.log('Time:', Date.now()); + next(); +}); + +// a middleware sub-stack shows request info for any type of HTTP request to the /user/:id path +router.use( + '/user/:id', + (req, res, next) => { + console.log('Request URL:', req.originalUrl); + next(); + }, + (req, res, next) => { + console.log('Request Type:', req.method); + next(); + } +); + +// a middleware sub-stack that handles GET requests to the /user/:id path +router.get( + '/user/:id', + (req, res, next) => { + // if the user ID is 0, skip to the next router + if (req.params.id === '0') next('route'); + // otherwise pass control to the next middleware function in this stack + else next(); + }, + (req, res, next) => { + // render a regular page + res.render('regular'); + } +); + +// handler for the /user/:id path, which renders a special page +router.get('/user/:id', (req, res, next) => { + console.log(req.params.id); + res.render('special'); +}); + +// mount the router on the app +app.use('/', router); +``` + +To skip the rest of the router's middleware functions, call `next('router')` +to pass control back out of the router instance. + +This example shows a middleware sub-stack that handles GET requests to the `/user/:id` path. + +```js +const express = require('express'); +const app = express(); +const router = express.Router(); + +// predicate the router with a check and bail out when needed +router.use((req, res, next) => { + if (!req.headers['x-auth']) return next('router'); + next(); +}); + +router.get('/user/:id', (req, res) => { + res.send('hello, user!'); +}); + +// use the router and 401 anything falling through +app.use('/admin', router, (req, res) => { + res.sendStatus(401); +}); +``` + +

Error-handling middleware

+ +
+Error-handling middleware always takes _four_ arguments. You must provide four arguments to identify it as an error-handling middleware function. Even if you don't need to use the `next` object, you must specify it to maintain the signature. Otherwise, the `next` object will be interpreted as regular middleware and will fail to handle errors. +
+ +Define error-handling middleware functions in the same way as other middleware functions, except with four arguments instead of three, specifically with the signature `(err, req, res, next)`: + +```js +app.use((err, req, res, next) => { + console.error(err.stack); + res.status(500).send('Something broke!'); +}); +``` + +For details about error-handling middleware, see: [Error handling](/{{ page.lang }}/guide/error-handling.html). + +

Built-in middleware

+ +Starting with version 4.x, Express no longer depends on [Connect](https://github.com/senchalabs/connect). The middleware +functions that were previously included with Express are now in separate modules; see [the list of middleware functions](https://github.com/senchalabs/connect#middleware). + +Express has the following built-in middleware functions: + +- [express.static](/en/5x/api.html#express.static) serves static assets such as HTML files, images, and so on. +- [express.json](/en/5x/api.html#express.json) parses incoming requests with JSON payloads. **NOTE: Available with Express 4.16.0+** +- [express.urlencoded](/en/5x/api.html#express.urlencoded) parses incoming requests with URL-encoded payloads. **NOTE: Available with Express 4.16.0+** + +

Third-party middleware

+ +Use third-party middleware to add functionality to Express apps. + +Install the Node.js module for the required functionality, then load it in your app at the application level or at the router level. + +The following example illustrates installing and loading the cookie-parsing middleware function `cookie-parser`. + +```bash +$ npm install cookie-parser +``` + +```js +const express = require('express'); +const app = express(); +const cookieParser = require('cookie-parser'); + +// load the cookie-parsing middleware +app.use(cookieParser()); +``` + +For a partial list of third-party middleware functions that are commonly used with Express, see: [Third-party middleware](../resources/middleware.html). diff --git a/astro/src/content/docs/en/guide/using-template-engines.md b/astro/src/content/docs/en/guide/using-template-engines.md new file mode 100755 index 0000000000..ed31c054cc --- /dev/null +++ b/astro/src/content/docs/en/guide/using-template-engines.md @@ -0,0 +1,65 @@ +--- +title: Using template engines with Express +description: Discover how to integrate and use template engines like Pug, Handlebars, and EJS with Express.js to render dynamic HTML pages efficiently. +menu: guide +order: 5 +--- + +# Using template engines with Express + +A _template engine_ enables you to use static template files in your application. At runtime, the template engine replaces +variables in a template file with actual values, and transforms the template into an HTML file sent to the client. +This approach makes it easier to design an HTML page. + +The [Express application generator](/{{ page.lang }}/starter/generator.html) uses [Pug](https://pugjs.org/api/getting-started.html) as its default, but it also supports [Handlebars](https://www.npmjs.com/package/handlebars), and [EJS](https://www.npmjs.com/package/ejs), among others. + +To render template files, set the following [application setting properties](/{{ page.lang }}/4x/api.html#app.set), in the default `app.js` created by the generator: + +- `views`, the directory where the template files are located. Eg: `app.set('views', './views')`. + This defaults to the `views` directory in the application root directory. +- `view engine`, the template engine to use. For example, to use the Pug template engine: `app.set('view engine', 'pug')`. + +Then install the corresponding template engine npm package; for example to install Pug: + +```bash +$ npm install pug --save +``` + +
+Express-compliant template engines such as Pug export a function named `__express(filePath, options, callback)`, +which `res.render()` calls to render the template code. + +Some template engines do not follow this convention. The [@ladjs/consolidate](https://www.npmjs.com/package/@ladjs/consolidate) +library follows this convention by mapping all of the popular Node.js template engines, and therefore works seamlessly within Express. + +
+ +After the view engine is set, you don't have to specify the engine or load the template engine module in your app; +Express loads the module internally, for example: + +```js +app.set('view engine', 'pug'); +``` + +Then, create a Pug template file named `index.pug` in the `views` directory, with the following content: + +```pug +html + head + title= title + body + h1= message +``` + +Create a route to render the `index.pug` file. If the `view engine` property is not set, +you must specify the extension of the `view` file. Otherwise, you can omit it. + +```js +app.get('/', (req, res) => { + res.render('index', { title: 'Hey', message: 'Hello there!' }); +}); +``` + +When you make a request to the home page, the `index.pug` file will be rendered as HTML. + +The view engine cache does not cache the contents of the template's output, only the underlying template itself. The view is still re-rendered with every request even when the cache is on. diff --git a/astro/src/content/docs/en/guide/writing-middleware.md b/astro/src/content/docs/en/guide/writing-middleware.md new file mode 100755 index 0000000000..3d223aabff --- /dev/null +++ b/astro/src/content/docs/en/guide/writing-middleware.md @@ -0,0 +1,220 @@ +--- +title: Writing middleware for use in Express apps +description: Learn how to write custom middleware functions for Express.js applications, including examples and best practices for enhancing request and response handling. +menu: guide +order: 2 +--- + +# Writing middleware for use in Express apps + +

Overview

+ +_Middleware_ functions are functions that have access to the [request object](/{{ page.lang }}/5x/api.html#req) (`req`), the [response object](/{{ page.lang }}/5x/api.html#res) (`res`), and the `next` function in the application's request-response cycle. The `next` function is a function in the Express router which, when invoked, executes the middleware succeeding the current middleware. + +Middleware functions can perform the following tasks: + +- Execute any code. +- Make changes to the request and the response objects. +- End the request-response cycle. +- Call the next middleware in the stack. + +If the current middleware function does not end the request-response cycle, it must call `next()` to pass control to the next middleware function. Otherwise, the request will be left hanging. + +The following figure shows the elements of a middleware function call: + +
+ + + +
+Elements of a middleware function call + +
HTTP method for which the middleware function applies.
+ +
Path (route) for which the middleware function applies.
+ +
The middleware function.
+ +
Callback argument to the middleware function, called "next" by convention.
+ +
HTTP response argument to the middleware function, called "res" by convention.
+ +
HTTP request argument to the middleware function, called "req" by convention.
+
+
+ +Starting with Express 5, middleware functions that return a Promise will call `next(value)` when they reject or throw an error. `next` will be called with either the rejected value or the thrown Error. + +

Example

+ +Here is an example of a simple "Hello World" Express application. +The remainder of this article will define and add three middleware functions to the application: +one called `myLogger` that prints a simple log message, one called `requestTime` that +displays the timestamp of the HTTP request, and one called `validateCookies` that validates incoming cookies. + +```js +const express = require('express'); +const app = express(); + +app.get('/', (req, res) => { + res.send('Hello World!'); +}); + +app.listen(3000); +``` + +

Middleware function myLogger

+Here is a simple example of a middleware function called "myLogger". This function just prints "LOGGED" when a request to the app passes through it. The middleware function is assigned to a variable named `myLogger`. + +```js +const myLogger = function (req, res, next) { + console.log('LOGGED'); + next(); +}; +``` + +
+Notice the call above to `next()`. Calling this function invokes the next middleware function in the app. +The `next()` function is not a part of the Node.js or Express API, but is the third argument that is passed to the middleware function. The `next()` function could be named anything, but by convention it is always named "next". +To avoid confusion, always use this convention. +
+ +To load the middleware function, call `app.use()`, specifying the middleware function. +For example, the following code loads the `myLogger` middleware function before the route to the root path (/). + +```js +const express = require('express'); +const app = express(); + +const myLogger = function (req, res, next) { + console.log('LOGGED'); + next(); +}; + +app.use(myLogger); + +app.get('/', (req, res) => { + res.send('Hello World!'); +}); + +app.listen(3000); +``` + +Every time the app receives a request, it prints the message "LOGGED" to the terminal. + +The order of middleware loading is important: middleware functions that are loaded first are also executed first. + +If `myLogger` is loaded after the route to the root path, the request never reaches it and the app doesn't print "LOGGED", because the route handler of the root path terminates the request-response cycle. + +The middleware function `myLogger` simply prints a message, then passes on the request to the next middleware function in the stack by calling the `next()` function. + +

Middleware function requestTime

+ +Next, we'll create a middleware function called "requestTime" and add a property called `requestTime` +to the request object. + +```js +const requestTime = function (req, res, next) { + req.requestTime = Date.now(); + next(); +}; +``` + +The app now uses the `requestTime` middleware function. Also, the callback function of the root path route uses the property that the middleware function adds to `req` (the request object). + +```js +const express = require('express'); +const app = express(); + +const requestTime = function (req, res, next) { + req.requestTime = Date.now(); + next(); +}; + +app.use(requestTime); + +app.get('/', (req, res) => { + let responseText = 'Hello World!
'; + responseText += `Requested at: ${req.requestTime}`; + res.send(responseText); +}); + +app.listen(3000); +``` + +When you make a request to the root of the app, the app now displays the timestamp of your request in the browser. + +

Middleware function validateCookies

+ +Finally, we'll create a middleware function that validates incoming cookies and sends a 400 response if cookies are invalid. + +Here's an example function that validates cookies with an external async service. + +```js +async function cookieValidator(cookies) { + try { + await externallyValidateCookie(cookies.testCookie); + } catch { + throw new Error('Invalid cookies'); + } +} +``` + +Here, we use the [`cookie-parser`](/resources/middleware/cookie-parser.html) middleware to parse incoming cookies off the `req` object and pass them to our `cookieValidator` function. The `validateCookies` middleware returns a Promise that upon rejection will automatically trigger our error handler. + +```js +const express = require('express'); +const cookieParser = require('cookie-parser'); +const cookieValidator = require('./cookieValidator'); + +const app = express(); + +async function validateCookies(req, res, next) { + await cookieValidator(req.cookies); + next(); +} + +app.use(cookieParser()); + +app.use(validateCookies); + +// error handler +app.use((err, req, res, next) => { + res.status(400).send(err.message); +}); + +app.listen(3000); +``` + +
+Note how `next()` is called after `await cookieValidator(req.cookies)`. This ensures that if `cookieValidator` resolves, the next middleware in the stack will get called. If you pass anything to the `next()` function (except the string `'route'` or `'router'`), Express regards the current request as being an error and will skip any remaining non-error handling routing and middleware functions. +
+ +Because you have access to the request object, the response object, the next middleware function in the stack, and the whole Node.js API, the possibilities with middleware functions are endless. + +For more information about Express middleware, see: [Using Express middleware](/{{ page.lang }}/guide/using-middleware.html). + +

Configurable middleware

+ +If you need your middleware to be configurable, export a function which accepts an options object or other parameters, which, then returns the middleware implementation based on the input parameters. + +File: `my-middleware.js` + +```js +module.exports = function (options) { + return function (req, res, next) { + // Implement the middleware function based on the options object + next(); + }; +}; +``` + +The middleware can now be used as shown below. + +```js +const mw = require('./my-middleware.js'); + +app.use(mw({ option1: '1', option2: '2' })); +``` + +Refer to [cookie-session](https://github.com/expressjs/cookie-session) and [compression](https://github.com/expressjs/compression) for examples of configurable middleware. diff --git a/astro/src/content/docs/en/resources/community.md b/astro/src/content/docs/en/resources/community.md new file mode 100755 index 0000000000..ca6026be32 --- /dev/null +++ b/astro/src/content/docs/en/resources/community.md @@ -0,0 +1,92 @@ +--- +title: Express community +description: Connect with the Express.js community, learn about the technical committee, find resources, explore community-contributed modules, and get involved in discussions. +menu: resources +order: 1 +--- + +# Community + +## Technical committee + +The Express technical committee meets online every two weeks (as needed) to discuss development and maintenance of Express, +and other issues relevant to the Express project. Each meeting is typically announced in an +[expressjs/discussions issue](https://github.com/expressjs/discussions/issues) with a link to join or view the meeting, which is +open to all observers. + +The meetings are recorded; for a list of the recordings, see the [Express.js YouTube channel](https://www.youtube.com/channel/UCYjxjAeH6TRik9Iwy5nXw7g). + +Members of the Express technical committee are: + +**Active:** + +- [@blakeembrey](https://github.com/blakeembrey) - Blake Embrey +- [@crandmck](https://github.com/crandmck) - Rand McKinney +- [@LinusU](https://github.com/LinusU) - Linus Unnebäck +- [@ulisesgascon](https://github.com/ulisesGascon) - Ulises Gascón +- [@sheplu](https://github.com/sheplu) - Jean Burellier +- [@wesleytodd](https://github.com/wesleytodd) - Wes Todd +- [@jonchurch](https://github.com/jonchurch) - Jon Church +- [@ctcpip](https://github.com/ctcpip/) - Chris de Almeida + +**Inactive:** + +- [@dougwilson](https://github.com/dougwilson) - Douglas Wilson +- [@hacksparrow](https://github.com/hacksparrow) - Hage Yaapa +- [@jonathanong](https://github.com/jonathanong) - jongleberry +- [@niftylettuce](https://github.com/niftylettuce) - niftylettuce +- [@troygoode](https://github.com/troygoode) - Troy Goode + +## Express is made of many modules + +Our vibrant community has created a large variety of extensions, +[middleware modules](/{{ page.lang }}/resources/middleware.html) and higher-level frameworks. + +Additionally, the Express community maintains modules in these two GitHub orgs: + +- [jshttp](https://github.com/jshttp) modules providing useful utility functions; see [Utility modules](/{{ page.lang }}/resources/utils.html). +- [pillarjs](https://github.com/pillarjs): low-level modules that Express uses internally. + +To keep up with what is going on in the whole community, check out the [ExpressJS StatusBoard](https://expressjs.github.io/statusboard/). + +## Issues + +If you've come across what you think is a bug, or just want to make +a feature request open a ticket in the [issue queue](https://github.com/expressjs/express/issues). + +## Examples + +View dozens of Express application [examples](https://github.com/expressjs/express/tree/master/examples) +in the repository covering everything from API design and authentication to template engine integration. + +## Github Discussions + +The [GitHub Discussions](https://github.com/expressjs/discussions) section is an excellent space to engage in conversations about the development and maintenance of Express, as well as to share ideas and discuss topics related to its usage. + +# Branding of Express.js + +## Express.js Logo + +Express is a project of the OpenJS Foundation. Please review the [trademark policy](https://trademark-policy.openjsf.org/) for information about permissible use of Express.js logos and marks. + +
+
+

Logotype

+ + Express.js logo + + + Express.js logo + +
+
+

Logomark

+ + Express.js mark + + + Express.js mark + +
+
+
diff --git a/astro/src/content/docs/en/resources/contributing.md b/astro/src/content/docs/en/resources/contributing.md new file mode 100644 index 0000000000..99b9b92e0b --- /dev/null +++ b/astro/src/content/docs/en/resources/contributing.md @@ -0,0 +1,484 @@ +--- +title: Contributing to Express +description: Find out how to contribute to Express.js, including guidelines for reporting issues, submitting pull requests, becoming a collaborator, and understanding security policies. +menu: resources +order: 5 +--- + +# Contributing to Express + +### Looking to contribute to Expressjs.com? Click [here](#expressjs-website-contributing). + +Express and the other projects in the [expressjs organization on GitHub](https://github.com/expressjs) are projects of the [OpenJs Foundation](https://openjsf.org/). +These projects are governed under the general policies and guidelines of the Node.js Foundation along with the additional guidelines below. + +- [Technical committee](#technical-committee) +- [Community contributing guide](#community-contributing-guide) +- [Collaborator's guide](#collaborators-guide) +- [Security policies and procedures](#security-policies-and-procedures) + +## Technical committee + +The Express technical committee consists of active project members, and guides development and maintenance of the Express project. For more information, see [Express Community - Technical committee](community.html#technical-committee). + +## Community contributing guide + + + +The goal of this document is to create a contribution process that: + +- Encourages new contributions. +- Encourages contributors to remain involved. +- Avoids unnecessary processes and bureaucracy whenever possible. +- Creates a transparent decision making process that makes it clear how + contributors can be involved in decision making. + +### Vocabulary + +- A **Contributor** is any individual creating or commenting on an issue or pull request. +- A **Committer** is a subset of contributors who have been given write access to the repository. +- A **Project Captain** is the lead maintainer of a repository. +- A **TC (Technical Committee)** is a group of committers representing the required technical + expertise to resolve rare disputes. +- A **Triager** is a subset of contributors who have been given triage access to the repository. + +### Logging Issues + +Log an issue for any question or problem you might have. When in doubt, log an issue, and +any additional policies about what to include will be provided in the responses. The only +exception is security disclosures which should be sent privately. + +Committers may direct you to another repository, ask for additional clarifications, and +add appropriate metadata before the issue is addressed. + +Please be courteous and respectful. Every participant is expected to follow the +project's Code of Conduct. + +### Contributions + +Any change to resources in this repository must be through pull requests. This applies to all changes +to documentation, code, binary files, etc. Even long term committers and TC members must use +pull requests. + +No pull request can be merged without being reviewed. + +For non-trivial contributions, pull requests should sit for at least 36 hours to ensure that +contributors in other timezones have time to review. Consideration should also be given to +weekends and other holiday periods to ensure active committers all have reasonable time to +become involved in the discussion and review process if they wish. + +The default for each contribution is that it is accepted once no committer has an objection. +During a review, committers may also request that a specific contributor who is most versed in a +particular area gives a "LGTM" before the PR can be merged. There is no additional "sign off" +process for contributions to land. Once all issues brought by committers are addressed it can +be landed by any committer. + +In the case of an objection being raised in a pull request by another committer, all involved +committers should seek to arrive at a consensus by way of addressing concerns being expressed +by discussion, compromise on the proposed change, or withdrawal of the proposed change. + +If a contribution is controversial and committers cannot agree about how to get it to land +or if it should land then it should be escalated to the TC. TC members should regularly +discuss pending contributions in order to find a resolution. It is expected that only a +small minority of issues be brought to the TC for resolution and that discussion and +compromise among committers be the default resolution mechanism. + +### Becoming a Triager + +Anyone can become a triager! Read more about the process of being a triager in +[the triage process document](https://github.com/expressjs/discussions/blob/master/Triager-Guide.md). + +Currently, any existing [organization member](https://github.com/orgs/expressjs/people) can nominate +a new triager. If you are interested in becoming a triager, our best advice is to actively participate +in the community by helping triaging issues and pull requests. As well we recommend +to engage in other community activities like attending the TC meetings, and participating in the Slack +discussions. If you feel ready and have been helping triage some issues, reach out to an active member of the organization to ask if they'd +be willing to support you. If they agree, they can create a pull request to formalize your nomination. In the case of an objection to the nomination, the triage team is responsible for working with the individuals involved and finding a resolution. + +You can also reach out to any of the [organization members](https://github.com/orgs/expressjs/people) +if you have questions or need guidance. + +### Becoming a Committer + +All contributors who have landed significant and valuable contributions should be onboarded in a timely manner, +and added as a committer, and be given write access to the repository. + +Committers are expected to follow this policy and continue to send pull requests, go through +proper review, and have other committers merge their pull requests. + +### TC Process + +The TC uses a "consensus seeking" process for issues that are escalated to the TC. +The group tries to find a resolution that has no open objections among TC members. +If a consensus cannot be reached that has no objections then a majority wins vote +is called. It is also expected that the majority of decisions made by the TC are via +a consensus seeking process and that voting is only used as a last-resort. + +Resolution may involve returning the issue to project captains with suggestions on +how to move forward towards a consensus. It is not expected that a meeting of the TC +will resolve all issues on its agenda during that meeting and may prefer to continue +the discussion happening among the project captains. + +Members can be added to the TC at any time. Any TC member can nominate another committer +to the TC and the TC uses its standard consensus seeking process to evaluate whether or +not to add this new member. The TC will consist of a minimum of 3 active members and a +maximum of 10. If the TC should drop below 5 members the active TC members should nominate +someone new. If a TC member is stepping down, they are encouraged (but not required) to +nominate someone to take their place. + +TC members will be added as admin's on the Github orgs, npm orgs, and other resources as +necessary to be effective in the role. + +To remain "active" a TC member should have participation within the last 12 months and miss +no more than six consecutive TC meetings. Our goal is to increase participation, not punish +people for any lack of participation, this guideline should be only be used as such +(replace an inactive member with a new active one, for example). Members who do not meet this +are expected to step down. If A TC member does not step down, an issue can be opened in the +discussions repo to move them to inactive status. TC members who step down or are removed due +to inactivity will be moved into inactive status. + +Inactive status members can become active members by self nomination if the TC is not already +larger than the maximum of 10. They will also be given preference if, while at max size, an +active member steps down. + +### Project Captains + +The Express TC can designate captains for individual projects/repos in the +organizations. These captains are responsible for being the primary +day-to-day maintainers of the repo on a technical and community front. +Repo captains are empowered with repo ownership and package publication rights. +When there are conflicts, especially on topics that effect the Express project +at large, captains are responsible to raise it up to the TC and drive +those conflicts to resolution. Captains are also responsible for making sure +community members follow the community guidelines, maintaining the repo +and the published package, as well as in providing user support. + +Like TC members, Repo captains are a subset of committers. + +To become a captain for a project the candidate is expected to participate in that +project for at least 6 months as a committer prior to the request. They should have +helped with code contributions as well as triaging issues. They are also required to +have 2FA enabled on both their GitHub and npm accounts. + +Any TC member or an existing captain on the **same** repo can nominate another committer +to the captain role. To do so, they should submit a PR to this document, updating the +**Active Project Captains** section (while maintaining the sort order) with the project +name, the nominee's GitHub handle, and their npm username (if different). + +- Repos can have as many captains as make sense for the scope of work. +- A TC member or an existing repo captain **on the same project** can nominate a new captain. + Repo captains from other projects should not nominate captains for a different project. + +The PR will require at least 2 approvals from TC members and 2 weeks hold time to allow +for comment and/or dissent. When the PR is merged, a TC member will add them to the +proper GitHub/npm groups. + +#### Active Projects and Captains + +The list can be found at [https://github.com/expressjs/discussions/blob/HEAD/docs/contributing/captains_and_committers.md#active-projects-and-members](https://github.com/expressjs/discussions/blob/HEAD/docs/contributing/captains_and_committers.md#active-projects-and-members) + +#### Current Initiative Captains + +The list can be found at [https://github.com/expressjs/discussions/blob/HEAD/docs/contributing/captains_and_committers.md#current-initiative-captains](https://github.com/expressjs/discussions/blob/HEAD/docs/contributing/captains_and_committers.md#current-initiative-captains) + +### Inactivity and Emeritus Policy for Any Role + +To support the health and continuity of the project, all individuals holding a role within the community (such as Triager, Committer, WG member, Project Captain, or TC member) are encouraged to maintain active participation. + +Inactivity is defined as the absence of meaningful involvement in the project—such as contributions, code reviews, triage, meeting attendance, or discussion participation—for a continuous period of 6 months. + +#### Exceptions + +Anyone may request a temporary leave from active participation due to personal or professional reasons. In such cases, the individual should inform the relevant team or the Technical Committee (TC). During this time, the inactivity policy is paused, and the individual will not be flagged as inactive. + +#### Inactivity Process + +- If someone is deemed inactive, the individual may be transitioned to an emeritus role that reflects their past contributions. A best effort will be made to inform them that this has occurred. They may request to be reinstated when they are ready to be active again. +- The emeritus status helps preserve a clear record of contributors who have meaningfully shaped the project over time. + +#### Accountability + +- The Technical Committee (TC) and the respective captains of each package/team are responsible for assessing activity levels and enacting this policy fairly and transparently, in coordination with other relevant teams. +- In case of disagreement, the situation can be discussed and resolved by consensus within the TC or appropriate team. + +### Developer's Certificate of Origin 1.1 + +```text +By making a contribution to this project, I certify that: + + (a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + + (b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + + (c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + + (d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. +``` + +## Collaborator's guide + + + +### Website Issues + +Open issues for the expressjs.com website in https://github.com/expressjs/expressjs.com. + +For issues in other Express managed repos (everything in `expressjs`, `pillarjs` or `jshttp` other than `expressjs/express`), be sure to check their contributing guide and open issues and PRs in the appropriate repository. + +### PRs and Code contributions + +- Tests must pass. +- Follow the [JavaScript Standard Style](https://standardjs.com/) and `npm run lint`. +- If you fix a bug, add a test. + +### Branches + +Use the `master` branch for bug fixes or minor work that is intended for the +current release stream. + +Use the correspondingly named branch, e.g. `6.x`, for anything intended for +a future release of Express. + +### Steps for contributing + +1. Create an issue for the + bug you want to fix or the feature that you want to add. +2. Create your own fork on GitHub, then + checkout your fork. +3. Write your code in your local copy. It's good practice to create a branch for + each new issue you work on, although not compulsory. +4. To run the test suite, first install the dependencies by running `npm install`, + then run `npm test`. +5. Ensure your code is linted by running `npm run lint` -- fix any issue you + see listed. +6. If the tests pass, you can commit your changes to your fork and then create + a pull request from there. Make sure to reference your issue from the pull + request comments by including the issue number e.g. `#123`. + +### Issues which are questions + +We will typically close any vague issues or questions that are specific to some +app you are writing. Please double check the docs and other references before +being trigger happy with posting a question issue. + +Things that will help get your question issue looked at: + +- Full and runnable JS code. +- Clear description of the problem or unexpected behavior. +- Clear description of the expected result. +- Steps you have taken to debug it yourself. + +If you post a question and do not outline the above items or make it easy for +us to understand and reproduce your issue, it will be closed. + +If your question meets all of the above requirements but you do not believe it needs to be looked at +by the maintainers +(for example, if you are just looking for community input) please open it as a discussion topic instead +of an issue. If you +are unsure and open an issue, we may move it to discussions if we triage them and decide they do +not need high +visibility or maintainer input. + +## Security Policies and Procedures + + + +This document outlines security procedures and general policies for the Express +project. + +- [Reporting a Bug](#reporting-a-bug) +- [Disclosure Policy](#disclosure-policy) +- [Comments on this Policy](#comments-on-this-policy) + +### Reporting a Bug + +The Express team and community take all security bugs in Express seriously. +Thank you for improving the security of Express. We appreciate your efforts and +responsible disclosure and will make every effort to acknowledge your +contributions. + +Report security bugs by emailing `express-security@lists.openjsf.org`. + +To ensure the timely response to your report, please ensure that the entirety +of the report is contained within the email body and not solely behind a web +link or an attachment. + +The lead maintainer will acknowledge your email within 48 hours, and will send a +more detailed response within 48 hours indicating the next steps in handling +your report. After the initial reply to your report, the security team will +endeavor to keep you informed of the progress towards a fix and full +announcement, and may ask for additional information or guidance. + +Report security bugs in third-party modules to the person or team maintaining +the module. + +### Pre-release Versions + +Alpha and Beta releases are unstable and **not suitable for production use**. +Vulnerabilities found in pre-releases should be reported according to the [Reporting a Bug](#reporting-a-bug) section. +Due to the unstable nature of the branch it is not guaranteed that any fixes will be released in the next pre-release. + +### Disclosure Policy + +When the security team receives a security bug report, they will assign it to a +primary handler. This person will coordinate the fix and release process, +involving the following steps: + +- Confirm the problem and determine the affected versions. +- Audit code to find any potential similar problems. +- Prepare fixes for all releases still under maintenance. These fixes will be + released as fast as possible to npm. + +### The Express Threat Model + +We are currently working on a new version of the security model, the most updated version can be found [here](https://github.com/expressjs/security-wg/blob/main/docs/ThreatModel.md) + +### Comments on this Policy + +If you have suggestions on how this process could be improved please submit a +pull request. + +--- + +# Contributing to Expressjs.com {#expressjs-website-contributing} + + + +### The Official Documentation of the Express.js Framework + +This is the contribution documentation for the [expressjs.com](https://github.com/expressjs/expressjs.com) website. + +#### Need some ideas? These are some typical issues. + +1. **Website issues**: If you see anything on the site that could use a tune-up, think about how to fix it. + - Display or screen sizing problems + - Mobile responsiveness issues + - Missing or broken accessibility features + - Website outages + - Broken links + - Page structure or user interface enhancements + +2. **Content Issues**: Fix anything related to site content or typos. + - Spelling errors + - Incorrect/outdated Express.js documentation + - Missing content + +3. **Translation Issues**: Fix any translation errors or contribute new content. + - Fix spelling errors + - Fix incorrect/poorly translated words + - Check out the [Contributing translations](#contributing-translations) section below for a contributing guide. + +#### Want to work on a backlog issue? + +We often have bugs or enhancements that need work. You can find these under our repo's [Issues tab](https://github.com/expressjs/expressjs.com/issues). Check out the tags to find something that's a good match for you. + +#### Have an idea? Found a bug? + +If you've found a bug or a typo, or if you have an idea for an enhancement, you can: + +- Submit a [new issue](https://github.com/expressjs/expressjs.com/issues/new/choose) on our repo. Do this for larger proposals, or if you'd like to discuss or get feedback first. + +- Make a [GitHub pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request). If you have already done work, and it's ready to go, feel free to send it our way. + +## Getting Started + +The steps below will guide you through the Expressjs.com contribution process. + +#### Step 1: (OPTIONAL) Open a New Issue + +So you've found a problem that you want to fix, or have a site enhancement you want to make. + +1. If you want to get feedback or discuss, open a discussion [issue](https://github.com/expressjs/expressjs.com/issues/new/choose) prior to starting work. This is not required, but encouraged for larger proposals. + - While we highly encourage this step, it is only for submissions proposing significant change. It helps us to clarify and focus the work, and ensure it aligns with overall project priorities. + - For submissions proposing minor improvements or corrections, this is not needed. You can skip this step. + - When opening an issue please give it a title and fill in the description section. The more details you provide, the more feedback we can give. + +2. After receiving your issue the Express.js documentation team will respond with feedback. We read every submission and always try to respond quickly with feedback. + - For submissions proposing significant change, we encourage you to follow the review process before starting work. + +#### Step 2: Get the Application Code Base + +Clone the repo and get the code: + +```sh +git clone https://github.com/expressjs/expressjs.com.git +``` + +After you've got the code you're ready to start making your changes! + +But just in case you need a little extra explanation, this section below outlines the main sections of the code base, where most changes are likely to be made. + +**Markdown Page Files**: + +- These files render to html and make up the individual pages of the site. Most of the site's documentation text content is written in `md` files. +- Change these to make changes to individual pages' content/text or markup. +- Each language has its own complete set of pages, located under their respective language directories - all the Spanish markdown content is found in the `es` directory, for example. + +**Includes Partials and Layout Templates** + +- `_includes` are partials that are imported and reused across multiple pages. + - These are used to import text content for reuse across pages, such as the API documentation, e.g., `_includes > api > en > 5x`, which is included in every language. + - These are used to include the page components that make up site-wide user interface and periphery structure, e.g., Header, Footer, etc. +- `_layouts` are the templates used to wrap the site's individual pages. + - These are used to display the structure of the site's periphery, such as the header and footer, and for injecting and displaying individual markdown pages inside the `content` tag. + +**Blog Markdown Files** + +- These files make up the individual blog posts. If you want to contribute a blog post please + follow the specific instructions for [How to write a blog post.](https://expressjs.com/en/blog/write-post.html) +- Located under the `_posts` directory. + +**CSS or Javascript** + +- All css and js files are kept in `css` and `js` folders on the project root. + +The Express.js website is built using [Jekyll](https://jekyllrb.com/) and is hosted on [GitHub Pages](https://pages.github.com/). + +#### Step 3: Running the Application + +Now you'll need a way to see your changes, which means you'll need a running version of the application. You have two options. + +1. **Run Locally**: This gets the local version of the application up and running on your machine. Follow our [Local Setup Guide](https://github.com/expressjs/expressjs.com?tab=readme-ov-file#build-the-website-locally) to use this option. + - This is the recommended option for moderate to complex work. + +2. **Run using Deploy Preview**: Use this option if you don't want to bother with a local installation. Part of our continuous integration pipeline includes [Netlify Deploy Preview](https://docs.netlify.com/deploy/deploy-types/deploy-previews/). + 1. To use this you'll need to get your changes online - after you've made your first commit on your feature branch, make a _draft_ pull request. + 2. After the build steps are complete, you'll have access to a **Deploy Preview** tab that will run your changes on the web, rebuilding after each commit is pushed. + 3. After you are completely done your work, and it's ready for review, remove the draft status on your pull request and submit your work. + +## Contributing translations + +We use Crowdin to manage our translations in multiple languages and achieve automatic translation with artificial intelligence. Since these translations can be inefficient in some cases, we need help from the community to provide accurate and helpful translations. + +The documentation is translated into these languages: + +- Chinese Simplified (`zh-cn`) +- Chinese Traditional (`zh-tw`) +- English (`en`) +- French (`fr`) +- German (`de`) +- Italian (`it`) +- Japanese (`ja`) +- Korean (`ko`) +- Brazilian Portuguese (`pt-br`) +- Spanish (`es`) + +### How to translate + +1. Request to join the Express.js Website project on [Crowdin](https://express.crowdin.com/website) +2. [Select the language you want to translate](https://support.crowdin.com/for-translators/#starting-translation) +3. [Start translating](https://support.crowdin.com/online-editor/) diff --git a/astro/src/content/docs/en/resources/glossary.md b/astro/src/content/docs/en/resources/glossary.md new file mode 100755 index 0000000000..10de90539d --- /dev/null +++ b/astro/src/content/docs/en/resources/glossary.md @@ -0,0 +1,64 @@ +--- +title: Express glossary +description: A comprehensive glossary of terms related to Express.js, Node.js, middleware, routing, and other key concepts to help you understand and use Express effectively. +menu: resources +order: 2 +--- + +# Glossary + +### application + +In general, one or more programs that are designed to carry out operations for a specific purpose. In the context of Express, a program that uses the Express API running on the Node.js platform. Might also refer to an [app object](/{{ page.lang }}/api.html#express). + +### API + +Application programming interface. Spell out the abbreviation when it is first used. + +### Express + +A fast, un-opinionated, minimalist web framework for Node.js applications. In general, "Express" is preferred to "Express.js," though the latter is acceptable. + +### libuv + +A multi-platform support library which focuses on asynchronous I/O, primarily developed for use by Node.js. + +### middleware + +A function that is invoked by the Express routing layer before the final request handler, and thus sits in the middle between a raw request and the final intended route. A few fine points of terminology around middleware: + +- `var foo = require('middleware')` is called _requiring_ or _using_ a Node.js module. Then the statement `var mw = foo()` typically returns the middleware. +- `app.use(mw)` is called _adding the middleware to the global processing stack_. +- `app.get('/foo', mw, function (req, res) { ... })` is called _adding the middleware to the "GET /foo" processing stack_. + +### Node.js + +A software platform that is used to build scalable network applications. Node.js uses JavaScript as its scripting language, and achieves high throughput via non-blocking I/O and a single-threaded event loop. See [nodejs.org](https://nodejs.org/en/). **Usage note**: Initially, "Node.js," thereafter "Node". + +### open-source, open source + +When used as an adjective, hyphenate; for example: "This is open-source software." See [Open-source software on Wikipedia](http://en.wikipedia.org/wiki/Open-source_software). + +{% capture english-rules %} + +Although it is common not to hyphenate this term, we are using the standard English rules for hyphenating a compound adjective. + +{% endcapture %} + +{% include admonitions/note.html content=english-rules %} + +### request + +An HTTP request. A client submits an HTTP request message to a server, which returns a response. The request must use one of several [request methods](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods) such as GET, POST, and so on. + +### response + +An HTTP response. A server returns an HTTP response message to the client. The response contains completion status information about the request and might also contain requested content in its message body. + +### route + +Part of a URL that identifies a resource. For example, in `http://foo.com/products/id`, "/products/id" is the route. + +### router + +See [router](/{{ page.lang }}/api.html#router) in the API reference. diff --git a/astro/src/content/docs/en/resources/middleware.md b/astro/src/content/docs/en/resources/middleware.md new file mode 100755 index 0000000000..3996542b9c --- /dev/null +++ b/astro/src/content/docs/en/resources/middleware.md @@ -0,0 +1,43 @@ +--- +title: Express middleware +description: Explore a list of Express.js middleware modules maintained by the Express team and the community, including built-in middleware and popular third-party modules. +menu: resources +order: 3 +module: mw-home +--- + +## Express middleware + +The Express middleware modules listed here are maintained by the +[Expressjs team](https://github.com/orgs/expressjs/people). + +| Middleware module | Description | +| --------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | +| [body-parser](/{{page.lang}}/resources/middleware/body-parser.html) | Parse HTTP request body. | +| [compression](/{{page.lang}}/resources/middleware/compression.html) | Compress HTTP responses. | +| [connect-rid](/{{page.lang}}/resources/middleware/connect-rid.html) | Generate unique request ID. | +| [cookie-parser](/{{page.lang}}/resources/middleware/cookie-parser.html) | Parse cookie header and populate `req.cookies`. See also [cookies](https://github.com/jed/cookies). | +| [cookie-session](/{{page.lang}}/resources/middleware/cookie-session.html) | Establish cookie-based sessions. | +| [cors](/{{page.lang}}/resources/middleware/cors.html) | Enable cross-origin resource sharing (CORS) with various options. | +| [errorhandler](/{{page.lang}}/resources/middleware/errorhandler.html) | Development error-handling/debugging. | +| [method-override](/{{page.lang}}/resources/middleware/method-override.html) | Override HTTP methods using header. | +| [morgan](/{{page.lang}}/resources/middleware/morgan.html) | HTTP request logger. | +| [multer](/{{page.lang}}/resources/middleware/multer.html) | Handle multi-part form data. | +| [response-time](/{{page.lang}}/resources/middleware/response-time.html) | Record HTTP response time. | +| [serve-favicon](/{{page.lang}}/resources/middleware/serve-favicon.html) | Serve a favicon. | +| [serve-index](/{{page.lang}}/resources/middleware/serve-index.html) | Serve directory listing for a given path. | +| [serve-static](/{{page.lang}}/resources/middleware/serve-static.html) | Serve static files. | +| [session](/{{page.lang}}/resources/middleware/session.html) | Establish server-based sessions (development only). | +| [timeout](/{{page.lang}}/resources/middleware/timeout.html) | Set a timeout perioHTTP request processing. | +| [vhost](/{{page.lang}}/resources/middleware/vhost.html) | Create virtual domains. | + +## Additional middleware modules + +These are some additional popular middleware modules. + +{% include community-caveat.html %} + +| Middleware module | Description | +| --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | +| [helmet](https://github.com/helmetjs/helmet) | Helps secure your apps by setting various HTTP headers. | +| [passport](https://github.com/jaredhanson/passport) | Authentication using "strategies" such as OAuth, OpenID and many others. See [passportjs.org](https://passportjs.org/) for more information. | diff --git a/astro/src/content/docs/en/resources/middleware/body-parser.md b/astro/src/content/docs/en/resources/middleware/body-parser.md new file mode 100644 index 0000000000..f43f7518ea --- /dev/null +++ b/astro/src/content/docs/en/resources/middleware/body-parser.md @@ -0,0 +1,499 @@ +--- +title: Express body-parser middleware +menu: resources +module: body-parser +--- + +# body-parser + +[![NPM Version][npm-version-image]][npm-url] +[![NPM Downloads][npm-downloads-image]][npm-url] +[![Build Status][ci-image]][ci-url] +[![Test Coverage][coveralls-image]][coveralls-url] +[![OpenSSF Scorecard Badge][ossf-scorecard-badge]][ossf-scorecard-visualizer] + +Node.js body parsing middleware. + +Parse incoming request bodies in a middleware before your handlers, available +under the `req.body` property. + +**Note** As `req.body`'s shape is based on user-controlled input, all +properties and values in this object are untrusted and should be validated +before trusting. For example, `req.body.foo.toString()` may fail in multiple +ways, for example the `foo` property may not be there or may not be a string, +and `toString` may not be a function and instead a string or other user input. + +[Learn about the anatomy of an HTTP transaction in Node.js](https://nodejs.org/en/learn/http/anatomy-of-an-http-transaction). + +_This does not handle multipart bodies_, due to their complex and typically +large nature. For multipart bodies, you may be interested in the following +modules: + +- [busboy](https://www.npmjs.com/package/busboy#readme) and + [connect-busboy](https://www.npmjs.com/package/connect-busboy#readme) +- [multiparty](https://www.npmjs.com/package/multiparty#readme) and + [connect-multiparty](https://www.npmjs.com/package/connect-multiparty#readme) +- [formidable](https://www.npmjs.com/package/formidable#readme) +- [multer](https://www.npmjs.com/package/multer#readme) + +This module provides the following parsers: + +- [JSON body parser](#bodyparserjsonoptions) +- [Raw body parser](#bodyparserrawoptions) +- [Text body parser](#bodyparsertextoptions) +- [URL-encoded form body parser](#bodyparserurlencodedoptions) + +Other body parsers you might be interested in: + +- [body](https://www.npmjs.com/package/body#readme) +- [co-body](https://www.npmjs.com/package/co-body#readme) + +## Installation + +```sh +$ npm install body-parser +``` + +## API + +```js +const bodyParser = require('body-parser'); +``` + +The `bodyParser` object exposes various factories to create middlewares. All +middlewares will populate the `req.body` property with the parsed body when +the `Content-Type` request header matches the `type` option. + +The various errors returned by this module are described in the +[errors section](#errors). + +### bodyParser.json([options]) + +Returns middleware that only parses `json` and only looks at requests where +the `Content-Type` header matches the `type` option. This parser accepts any +Unicode encoding of the body and supports automatic inflation of `gzip`, +`br` (brotli) and `deflate` encodings. + +A new `body` object containing the parsed data is populated on the `request` +object after the middleware (i.e. `req.body`). + +#### Options + +The `json` function takes an optional `options` object that may contain any of +the following keys: + +##### defaultCharset + +Specify the default character set for the json content if the charset is not +specified in the `Content-Type` header of the request. Defaults to `utf-8`. + +##### inflate + +When set to `true`, then deflated (compressed) bodies will be inflated; when +`false`, deflated bodies are rejected. Defaults to `true`. + +##### limit + +Controls the maximum request body size. If this is a number, then the value +specifies the number of bytes; if it is a string, the value is passed to the +[bytes](https://www.npmjs.com/package/bytes) library for parsing. Defaults +to `'100kb'`. + +##### reviver + +The `reviver` option is passed directly to `JSON.parse` as the second +argument. You can find more information on this argument +[in the MDN documentation about JSON.parse](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Example.3A_Using_the_reviver_parameter). + +##### strict + +When set to `true`, will only accept arrays and objects; when `false` will +accept anything `JSON.parse` accepts. Defaults to `true`. + +##### type + +The `type` option is used to determine what media type the middleware will +parse. This option can be a string, array of strings, or a function. If not a +function, `type` option is passed directly to the +[type-is](https://www.npmjs.com/package/type-is#readme) library and this can +be an extension name (like `json`), a mime type (like `application/json`), or +a mime type with a wildcard (like `*/*` or `*/json`). If a function, the `type` +option is called as `fn(req)` and the request is parsed if it returns a truthy +value. Defaults to `application/json`. + +##### verify + +The `verify` option, if supplied, is called as `verify(req, res, buf, encoding)`, +where `buf` is a `Buffer` of the raw request body and `encoding` is the +encoding of the request. The parsing can be aborted by throwing an error. + +### bodyParser.raw([options]) + +Returns middleware that parses all bodies as a `Buffer` and only looks at +requests where the `Content-Type` header matches the `type` option. This +parser supports automatic inflation of `gzip`, `br` (brotli) and `deflate` +encodings. + +A new `body` object containing the parsed data is populated on the `request` +object after the middleware (i.e. `req.body`). This will be a `Buffer` object +of the body. + +#### Options + +The `raw` function takes an optional `options` object that may contain any of +the following keys: + +##### inflate + +When set to `true`, then deflated (compressed) bodies will be inflated; when +`false`, deflated bodies are rejected. Defaults to `true`. + +##### limit + +Controls the maximum request body size. If this is a number, then the value +specifies the number of bytes; if it is a string, the value is passed to the +[bytes](https://www.npmjs.com/package/bytes) library for parsing. Defaults +to `'100kb'`. + +##### type + +The `type` option is used to determine what media type the middleware will +parse. This option can be a string, array of strings, or a function. +If not a function, `type` option is passed directly to the +[type-is](https://www.npmjs.com/package/type-is#readme) library and this +can be an extension name (like `bin`), a mime type (like +`application/octet-stream`), or a mime type with a wildcard (like `*/*` or +`application/*`). If a function, the `type` option is called as `fn(req)` +and the request is parsed if it returns a truthy value. Defaults to +`application/octet-stream`. + +##### verify + +The `verify` option, if supplied, is called as `verify(req, res, buf, encoding)`, +where `buf` is a `Buffer` of the raw request body and `encoding` is the +encoding of the request. The parsing can be aborted by throwing an error. + +### bodyParser.text([options]) + +Returns middleware that parses all bodies as a string and only looks at +requests where the `Content-Type` header matches the `type` option. This +parser supports automatic inflation of `gzip`, `br` (brotli) and `deflate` +encodings. + +A new `body` string containing the parsed data is populated on the `request` +object after the middleware (i.e. `req.body`). This will be a string of the +body. + +#### Options + +The `text` function takes an optional `options` object that may contain any of +the following keys: + +##### defaultCharset + +Specify the default character set for the text content if the charset is not +specified in the `Content-Type` header of the request. Defaults to `utf-8`. + +##### inflate + +When set to `true`, then deflated (compressed) bodies will be inflated; when +`false`, deflated bodies are rejected. Defaults to `true`. + +##### limit + +Controls the maximum request body size. If this is a number, then the value +specifies the number of bytes; if it is a string, the value is passed to the +[bytes](https://www.npmjs.com/package/bytes) library for parsing. Defaults +to `'100kb'`. + +##### type + +The `type` option is used to determine what media type the middleware will +parse. This option can be a string, array of strings, or a function. If not +a function, `type` option is passed directly to the +[type-is](https://www.npmjs.com/package/type-is#readme) library and this can +be an extension name (like `txt`), a mime type (like `text/plain`), or a mime +type with a wildcard (like `*/*` or `text/*`). If a function, the `type` +option is called as `fn(req)` and the request is parsed if it returns a +truthy value. Defaults to `text/plain`. + +##### verify + +The `verify` option, if supplied, is called as `verify(req, res, buf, encoding)`, +where `buf` is a `Buffer` of the raw request body and `encoding` is the +encoding of the request. The parsing can be aborted by throwing an error. + +### bodyParser.urlencoded([options]) + +Returns middleware that only parses `urlencoded` bodies and only looks at +requests where the `Content-Type` header matches the `type` option. This +parser accepts only UTF-8 encoding of the body and supports automatic +inflation of `gzip`, `br` (brotli) and `deflate` encodings. + +A new `body` object containing the parsed data is populated on the `request` +object after the middleware (i.e. `req.body`). This object will contain +key-value pairs, where the value can be a string or array (when `extended` is +`false`), or any type (when `extended` is `true`). + +#### Options + +The `urlencoded` function takes an optional `options` object that may contain +any of the following keys: + +##### extended + +The "extended" syntax allows for rich objects and arrays to be encoded into the +URL-encoded format, allowing for a JSON-like experience with URL-encoded. For +more information, please [see the qs +library](https://www.npmjs.com/package/qs#readme). + +Defaults to `false`. + +##### inflate + +When set to `true`, then deflated (compressed) bodies will be inflated; when +`false`, deflated bodies are rejected. Defaults to `true`. + +##### limit + +Controls the maximum request body size. If this is a number, then the value +specifies the number of bytes; if it is a string, the value is passed to the +[bytes](https://www.npmjs.com/package/bytes) library for parsing. Defaults +to `'100kb'`. + +##### parameterLimit + +The `parameterLimit` option controls the maximum number of parameters that +are allowed in the URL-encoded data. If a request contains more parameters +than this value, a 413 will be returned to the client. Defaults to `1000`. + +##### type + +The `type` option is used to determine what media type the middleware will +parse. This option can be a string, array of strings, or a function. If not +a function, `type` option is passed directly to the +[type-is](https://www.npmjs.com/package/type-is#readme) library and this can +be an extension name (like `urlencoded`), a mime type (like +`application/x-www-form-urlencoded`), or a mime type with a wildcard (like +`*/x-www-form-urlencoded`). If a function, the `type` option is called as +`fn(req)` and the request is parsed if it returns a truthy value. Defaults +to `application/x-www-form-urlencoded`. + +##### verify + +The `verify` option, if supplied, is called as `verify(req, res, buf, encoding)`, +where `buf` is a `Buffer` of the raw request body and `encoding` is the +encoding of the request. The parsing can be aborted by throwing an error. + +##### defaultCharset + +The default charset to parse as, if not specified in content-type. Must be +either `utf-8` or `iso-8859-1`. Defaults to `utf-8`. + +##### charsetSentinel + +Whether to let the value of the `utf8` parameter take precedence as the charset +selector. It requires the form to contain a parameter named `utf8` with a value +of `✓`. Defaults to `false`. + +##### interpretNumericEntities + +Whether to decode numeric entities such as `☺` when parsing an iso-8859-1 +form. Defaults to `false`. + +##### depth + +The `depth` option is used to configure the maximum depth of the `qs` library when `extended` is `true`. This allows you to limit the amount of keys that are parsed and can be useful to prevent certain types of abuse. Defaults to `32`. It is recommended to keep this value as low as possible. + +## Errors + +The middlewares provided by this module create errors using the +[`http-errors` module](https://www.npmjs.com/package/http-errors). The errors +will typically have a `status`/`statusCode` property that contains the suggested +HTTP response code, an `expose` property to determine if the `message` property +should be displayed to the client, a `type` property to determine the type of +error without matching against the `message`, and a `body` property containing +the read body, if available. + +The following are the common errors created, though any error can come through +for various reasons. + +### content encoding unsupported + +This error will occur when the request had a `Content-Encoding` header that +contained an encoding but the "inflation" option was set to `false`. The +`status` property is set to `415`, the `type` property is set to +`'encoding.unsupported'`, and the `charset` property will be set to the +encoding that is unsupported. + +### entity parse failed + +This error will occur when the request contained an entity that could not be +parsed by the middleware. The `status` property is set to `400`, the `type` +property is set to `'entity.parse.failed'`, and the `body` property is set to +the entity value that failed parsing. + +### entity verify failed + +This error will occur when the request contained an entity that could not be +failed verification by the defined `verify` option. The `status` property is +set to `403`, the `type` property is set to `'entity.verify.failed'`, and the +`body` property is set to the entity value that failed verification. + +### request aborted + +This error will occur when the request is aborted by the client before reading +the body has finished. The `received` property will be set to the number of +bytes received before the request was aborted and the `expected` property is +set to the number of expected bytes. The `status` property is set to `400` +and `type` property is set to `'request.aborted'`. + +### request entity too large + +This error will occur when the request body's size is larger than the "limit" +option. The `limit` property will be set to the byte limit and the `length` +property will be set to the request body's length. The `status` property is +set to `413` and the `type` property is set to `'entity.too.large'`. + +### request size did not match content length + +This error will occur when the request's length did not match the length from +the `Content-Length` header. This typically occurs when the request is malformed, +typically when the `Content-Length` header was calculated based on characters +instead of bytes. The `status` property is set to `400` and the `type` property +is set to `'request.size.invalid'`. + +### stream encoding should not be set + +This error will occur when something called the `req.setEncoding` method prior +to this middleware. This module operates directly on bytes only and you cannot +call `req.setEncoding` when using this module. The `status` property is set to +`500` and the `type` property is set to `'stream.encoding.set'`. + +### stream is not readable + +This error will occur when the request is no longer readable when this middleware +attempts to read it. This typically means something other than a middleware from +this module read the request body already and the middleware was also configured to +read the same request. The `status` property is set to `500` and the `type` +property is set to `'stream.not.readable'`. + +### too many parameters + +This error will occur when the content of the request exceeds the configured +`parameterLimit` for the `urlencoded` parser. The `status` property is set to +`413` and the `type` property is set to `'parameters.too.many'`. + +### unsupported charset "BOGUS" + +This error will occur when the request had a charset parameter in the +`Content-Type` header, but the `iconv-lite` module does not support it OR the +parser does not support it. The charset is contained in the message as well +as in the `charset` property. The `status` property is set to `415`, the +`type` property is set to `'charset.unsupported'`, and the `charset` property +is set to the charset that is unsupported. + +### unsupported content encoding "bogus" + +This error will occur when the request had a `Content-Encoding` header that +contained an unsupported encoding. The encoding is contained in the message +as well as in the `encoding` property. The `status` property is set to `415`, +the `type` property is set to `'encoding.unsupported'`, and the `encoding` +property is set to the encoding that is unsupported. + +### The input exceeded the depth + +This error occurs when using `bodyParser.urlencoded` with the `extended` property set to `true` and the input exceeds the configured `depth` option. The `status` property is set to `400`. It is recommended to review the `depth` option and evaluate if it requires a higher value. When the `depth` option is set to `32` (default value), the error will not be thrown. + +## Examples + +### Express/Connect top-level generic + +This example demonstrates adding a generic JSON and URL-encoded parser as a +top-level middleware, which will parse the bodies of all incoming requests. +This is the simplest setup. + +```js +const express = require('express'); +const bodyParser = require('body-parser'); + +const app = express(); + +// parse application/x-www-form-urlencoded +app.use(bodyParser.urlencoded()); + +// parse application/json +app.use(bodyParser.json()); + +app.use(function (req, res) { + res.setHeader('Content-Type', 'text/plain'); + res.write('you posted:\n'); + res.end(String(JSON.stringify(req.body, null, 2))); +}); +``` + +### Express route-specific + +This example demonstrates adding body parsers specifically to the routes that +need them. In general, this is the most recommended way to use body-parser with +Express. + +```js +const express = require('express'); +const bodyParser = require('body-parser'); + +const app = express(); + +// create application/json parser +const jsonParser = bodyParser.json(); + +// create application/x-www-form-urlencoded parser +const urlencodedParser = bodyParser.urlencoded(); + +// POST /login gets urlencoded bodies +app.post('/login', urlencodedParser, function (req, res) { + if (!req.body || !req.body.username) res.sendStatus(400); + res.send('welcome, ' + req.body.username); +}); + +// POST /api/users gets JSON bodies +app.post('/api/users', jsonParser, function (req, res) { + if (!req.body) res.sendStatus(400); + // create user in req.body +}); +``` + +### Change accepted type for parsers + +All the parsers accept a `type` option which allows you to change the +`Content-Type` that the middleware will parse. + +```js +const express = require('express'); +const bodyParser = require('body-parser'); + +const app = express(); + +// parse various different custom JSON types as JSON +app.use(bodyParser.json({ type: 'application/*+json' })); + +// parse some custom thing into a Buffer +app.use(bodyParser.raw({ type: 'application/vnd.custom-type' })); + +// parse an HTML body into a string +app.use(bodyParser.text({ type: 'text/html' })); +``` + +## License + +[MIT](LICENSE) + +[ci-image]: https://img.shields.io/github/actions/workflow/status/expressjs/body-parser/ci.yml?branch=master&label=ci +[ci-url]: https://github.com/expressjs/body-parser/actions/workflows/ci.yml +[coveralls-image]: https://img.shields.io/coverallsCoverage/github/expressjs/body-parser?branch=master +[coveralls-url]: https://coveralls.io/r/expressjs/body-parser?branch=master +[npm-downloads-image]: https://img.shields.io/npm/dm/body-parser +[npm-url]: https://npmjs.com/package/body-parser +[npm-version-image]: https://img.shields.io/npm/v/body-parser +[ossf-scorecard-badge]: https://api.scorecard.dev/projects/github.com/expressjs/body-parser/badge +[ossf-scorecard-visualizer]: https://ossf.github.io/scorecard-visualizer/#/projects/github.com/expressjs/body-parser diff --git a/astro/src/content/docs/en/resources/middleware/compression.md b/astro/src/content/docs/en/resources/middleware/compression.md new file mode 100644 index 0000000000..c35004305c --- /dev/null +++ b/astro/src/content/docs/en/resources/middleware/compression.md @@ -0,0 +1,315 @@ +--- +title: Express compression middleware +menu: resources +module: compression +--- + +# compression + +[![NPM Version][npm-image]][npm-url] +[![NPM Downloads][downloads-image]][downloads-url] +[![Build Status][github-actions-ci-image]][github-actions-ci-url] +[![OpenSSF Scorecard Badge][ossf-scorecard-badge]][ossf-scorecard-visualizer] +[![Funding][funding-image]][funding-url] + +Node.js compression middleware. + +The following compression codings are supported: + +- deflate +- gzip +- br (brotli) + +**Note** Brotli is supported only since Node.js versions v11.7.0 and v10.16.0. + +## Install + +This is a [Node.js](https://nodejs.org/en/) module available through the +[npm registry](https://www.npmjs.com/). Installation is done using the +[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally): + +```bash +$ npm install compression +``` + +## API + +```js +var compression = require('compression'); +``` + +### compression([options]) + +Returns the compression middleware using the given `options`. The middleware +will attempt to compress response bodies for all requests that traverse through +the middleware, based on the given `options`. + +This middleware will never compress responses that include a `Cache-Control` +header with the [`no-transform` directive](https://tools.ietf.org/html/rfc7234#section-5.2.2.4), +as compressing will transform the body. + +#### Options + +`compression()` accepts these properties in the options object. In addition to +those listed below, [zlib](https://nodejs.org/api/zlib.html) options may be +passed in to the options object or +[brotli](https://nodejs.org/api/zlib.html#zlib_class_brotlioptions) options. + +##### chunkSize + +Type: `Number`
+Default: `zlib.constants.Z_DEFAULT_CHUNK`, or `16384`. + +See [Node.js documentation](https://nodejs.org/api/zlib.html#zlib_memory_usage_tuning) +regarding the usage. + +##### filter + +Type: `Function` + +A function to decide if the response should be considered for compression. +This function is called as `filter(req, res)` and is expected to return +`true` to consider the response for compression, or `false` to not compress +the response. + +The default filter function uses the [compressible](https://www.npmjs.com/package/compressible) +module to determine if `res.getHeader('Content-Type')` is compressible. + +##### level + +Type: `Number`
+Default: `zlib.constants.Z_DEFAULT_COMPRESSION`, or `-1` + +The level of zlib compression to apply to responses. A higher level will result +in better compression, but will take longer to complete. A lower level will +result in less compression, but will be much faster. + +This is an integer in the range of `0` (no compression) to `9` (maximum +compression). The special value `-1` can be used to mean the "default +compression level", which is a default compromise between speed and +compression (currently equivalent to level 6). + +- `-1` Default compression level (also `zlib.constants.Z_DEFAULT_COMPRESSION`). +- `0` No compression (also `zlib.constants.Z_NO_COMPRESSION`). +- `1` Fastest compression (also `zlib.constants.Z_BEST_SPEED`). +- `2` +- `3` +- `4` +- `5` +- `6` (currently what `zlib.constants.Z_DEFAULT_COMPRESSION` points to). +- `7` +- `8` +- `9` Best compression (also `zlib.constants.Z_BEST_COMPRESSION`). + +**Note** in the list above, `zlib` is from `zlib = require('zlib')`. + +##### memLevel + +Type: `Number`
+Default: `zlib.constants.Z_DEFAULT_MEMLEVEL`, or `8` + +This specifies how much memory should be allocated for the internal compression +state and is an integer in the range of `1` (minimum level) and `9` (maximum +level). + +See [Node.js documentation](https://nodejs.org/api/zlib.html#zlib_memory_usage_tuning) +regarding the usage. + +##### brotli + +Type: `Object` + +This specifies the options for configuring Brotli. See [Node.js documentation](https://nodejs.org/api/zlib.html#class-brotlioptions) for a complete list of available options. + +##### strategy + +Type: `Number`
+Default: `zlib.constants.Z_DEFAULT_STRATEGY` + +This is used to tune the compression algorithm. This value only affects the +compression ratio, not the correctness of the compressed output, even if it +is not set appropriately. + +- `zlib.constants.Z_DEFAULT_STRATEGY` Use for normal data. +- `zlib.constants.Z_FILTERED` Use for data produced by a filter (or predictor). + Filtered data consists mostly of small values with a somewhat random + distribution. In this case, the compression algorithm is tuned to + compress them better. The effect is to force more Huffman coding and less + string matching; it is somewhat intermediate between `zlib.constants.Z_DEFAULT_STRATEGY` + and `zlib.constants.Z_HUFFMAN_ONLY`. +- `zlib.constants.Z_FIXED` Use to prevent the use of dynamic Huffman codes, allowing + for a simpler decoder for special applications. +- `zlib.constants.Z_HUFFMAN_ONLY` Use to force Huffman encoding only (no string match). +- `zlib.constants.Z_RLE` Use to limit match distances to one (run-length encoding). + This is designed to be almost as fast as `zlib.constants.Z_HUFFMAN_ONLY`, but give + better compression for PNG image data. + +**Note** in the list above, `zlib` is from `zlib = require('zlib')`. + +##### threshold + +Type: `Number` or `String`
+Default: `1kb` + +The byte threshold for the response body size before compression is considered +for the response. This is a number of bytes or any string +accepted by the [bytes](https://www.npmjs.com/package/bytes) module. + +**Note** this is only an advisory setting; if the response size cannot be determined +at the time the response headers are written, then it is assumed the response is +_over_ the threshold. To guarantee the response size can be determined, be sure +set a `Content-Length` response header. + +##### windowBits + +Type: `Number`
+Default: `zlib.constants.Z_DEFAULT_WINDOWBITS`, or `15` + +See [Node.js documentation](https://nodejs.org/api/zlib.html#zlib_memory_usage_tuning) +regarding the usage. + +##### enforceEncoding + +Type: `String`
+Default: `identity` + +This is the default encoding to use when the client does not specify an encoding in the request's [Accept-Encoding](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding) header. + +#### .filter + +The default `filter` function. This is used to construct a custom filter +function that is an extension of the default function. + +```js +var compression = require('compression'); +var express = require('express'); + +var app = express(); + +app.use(compression({ filter: shouldCompress })); + +function shouldCompress(req, res) { + if (req.headers['x-no-compression']) { + // don't compress responses with this request header + return false; + } + + // fallback to standard filter function + return compression.filter(req, res); +} +``` + +### res.flush + +This module adds a `res.flush()` method to force the partially-compressed +response to be flushed to the client. + +## Examples + +### express + +When using this module with express, simply `app.use` the module as +high as you like. Requests that pass through the middleware will be compressed. + +```js +var compression = require('compression'); +var express = require('express'); + +var app = express(); + +// compress all responses +app.use(compression()); + +// add all routes +``` + +### Node.js HTTP server + +```js +var compression = require('compression')({ threshold: 0 }); +var http = require('http'); + +function createServer(fn) { + return http.createServer(function (req, res) { + compression(req, res, function (err) { + if (err) { + res.statusCode = err.status || 500; + res.end(err.message); + return; + } + + fn(req, res); + }); + }); +} + +var server = createServer(function (req, res) { + res.setHeader('Content-Type', 'text/plain'); + res.end('hello world!'); +}); + +server.listen(3000, () => { + console.log('> Listening at http://localhost:3000'); +}); +``` + +### Server-Sent Events + +Because of the nature of compression this module does not work out of the box +with server-sent events. To compress content, a window of the output needs to +be buffered up in order to get good compression. Typically when using server-sent +events, there are certain block of data that need to reach the client. + +You can achieve this by calling `res.flush()` when you need the data written to +actually make it to the client. + +```js +var compression = require('compression'); +var express = require('express'); + +var app = express(); + +// compress responses +app.use(compression()); + +// server-sent event stream +app.get('/events', function (req, res) { + res.setHeader('Content-Type', 'text/event-stream'); + res.setHeader('Cache-Control', 'no-cache'); + + // send a ping approx every 2 seconds + var timer = setInterval(function () { + res.write('data: ping\n\n'); + + // !!! this is the important part + res.flush(); + }, 2000); + + res.on('close', function () { + clearInterval(timer); + }); +}); +``` + +## Contributing + +The Express.js project welcomes all constructive contributions. Contributions take many forms, +from code for bug fixes and enhancements, to additions and fixes to documentation, additional +tests, triaging incoming pull requests and issues, and more! + +See the [Contributing Guide](https://github.com/expressjs/express/blob/master/Contributing.md) for more technical details on contributing. + +## License + +[MIT](LICENSE) + +[npm-image]: https://badgen.net/npm/v/compression +[npm-url]: https://npmjs.org/package/compression +[downloads-image]: https://badgen.net/npm/dm/compression +[downloads-url]: https://npmcharts.com/compare/compression?minimal=true +[github-actions-ci-image]: https://badgen.net/github/checks/expressjs/compression/master?label=CI +[github-actions-ci-url]: https://github.com/expressjs/compression/actions?query=workflow%3Aci +[ossf-scorecard-badge]: https://api.scorecard.dev/projects/github.com/expressjs/compression/badge +[ossf-scorecard-visualizer]: https://ossf.github.io/scorecard-visualizer/#/projects/github.com/expressjs/compression +[funding-url]: https://opencollective.com/express +[funding-image]: https://badgen.net/badge/icon/sponsor/pink?icon=github&label=Open%20Collective diff --git a/astro/src/content/docs/en/resources/middleware/connect-rid.md b/astro/src/content/docs/en/resources/middleware/connect-rid.md new file mode 100644 index 0000000000..53aca02427 --- /dev/null +++ b/astro/src/content/docs/en/resources/middleware/connect-rid.md @@ -0,0 +1,64 @@ +--- +title: Express connect-rid middleware +menu: resources +module: connect-rid +--- + +> [!CAUTION] +> **This repository is archived and no longer actively maintained.** +> +> We are no longer accepting issues, feature requests, or pull requests. +> For additional support or questions, please visit the [Express.js Discussions page](https://github.com/expressjs/express/discussions). + +# connect-rid + +[![Build Status](https://secure.travis-ci.org/fengmk2/connect-rid.png)](http://travis-ci.org/fengmk2/connect-rid) [![Coverage Status](https://coveralls.io/repos/fengmk2/connect-rid/badge.png)](https://coveralls.io/r/fengmk2/connect-rid) [![Dependency Status](https://gemnasium.com/fengmk2/connect-rid.png)](https://gemnasium.com/fengmk2/connect-rid) + +[![NPM](https://nodei.co/npm/connect-rid.png?downloads=true&stars=true)](https://nodei.co/npm/connect-rid/) + +![logo](https://raw.github.com/fengmk2/connect-rid/master/logo.png) + +connect request id middleware, base on [rid](https://github.com/fengmk2/rid). + +## Install + +```bash +$ npm install connect-rid +``` + +## Usage + +```js +var rid = require('connect-rid'); + +app.use( + rid({ + // headerName: 'X-RID' + }) +); +``` + +## License + +(The MIT License) + +Copyright (c) 2014 fengmk2 <fengmk2@gmail.com> and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/astro/src/content/docs/en/resources/middleware/cookie-parser.md b/astro/src/content/docs/en/resources/middleware/cookie-parser.md new file mode 100644 index 0000000000..240c943f7e --- /dev/null +++ b/astro/src/content/docs/en/resources/middleware/cookie-parser.md @@ -0,0 +1,125 @@ +--- +title: Express cookie-parser middleware +menu: resources +module: cookie-parser +--- + +# cookie-parser + +[![NPM Version][npm-version-image]][npm-url] +[![NPM Downloads][npm-downloads-image]][npm-url] +[![Build Status][ci-image]][ci-url] +[![Test Coverage][coveralls-image]][coveralls-url] + +Parse `Cookie` header and populate `req.cookies` with an object keyed by the +cookie names. Optionally you may enable signed cookie support by passing a +`secret` string, which assigns `req.secret` so it may be used by other +middleware. + +## Installation + +```sh +$ npm install cookie-parser +``` + +## API + +```js +var cookieParser = require('cookie-parser'); +``` + +### cookieParser(secret, options) + +Create a new cookie parser middleware function using the given `secret` and +`options`. + +- `secret` a string or array used for signing cookies. This is optional and if + not specified, will not parse signed cookies. If a string is provided, this + is used as the secret. If an array is provided, an attempt will be made to + unsign the cookie with each secret in order. +- `options` an object that is passed to `cookie.parse` as the second option. See + [cookie](https://www.npmjs.org/package/cookie) for more information. + - `decode` a function to decode the value of the cookie + +The middleware will parse the `Cookie` header on the request and expose the +cookie data as the property `req.cookies` and, if a `secret` was provided, as +the property `req.signedCookies`. These properties are name value pairs of the +cookie name to cookie value. + +When `secret` is provided, this module will unsign and validate any signed cookie +values and move those name value pairs from `req.cookies` into `req.signedCookies`. +A signed cookie is a cookie that has a value prefixed with `s:`. Signed cookies +that fail signature validation will have the value `false` instead of the tampered +value. + +In addition, this module supports special "JSON cookies". These are cookie where +the value is prefixed with `j:`. When these values are encountered, the value will +be exposed as the result of `JSON.parse`. If parsing fails, the original value will +remain. + +### cookieParser.JSONCookie(str) + +Parse a cookie value as a JSON cookie. This will return the parsed JSON value +if it was a JSON cookie, otherwise, it will return the passed value. + +### cookieParser.JSONCookies(cookies) + +Given an object, this will iterate over the keys and call `JSONCookie` on each +value, replacing the original value with the parsed value. This returns the +same object that was passed in. + +### cookieParser.signedCookie(str, secret) + +Parse a cookie value as a signed cookie. This will return the parsed unsigned +value if it was a signed cookie and the signature was valid. If the value was +not signed, the original value is returned. If the value was signed but the +signature could not be validated, `false` is returned. + +The `secret` argument can be an array or string. If a string is provided, this +is used as the secret. If an array is provided, an attempt will be made to +unsign the cookie with each secret in order. + +### cookieParser.signedCookies(cookies, secret) + +Given an object, this will iterate over the keys and check if any value is a +signed cookie. If it is a signed cookie and the signature is valid, the key +will be deleted from the object and added to the new object that is returned. + +The `secret` argument can be an array or string. If a string is provided, this +is used as the secret. If an array is provided, an attempt will be made to +unsign the cookie with each secret in order. + +## Example + +```js +var express = require('express'); +var cookieParser = require('cookie-parser'); + +var app = express(); +app.use(cookieParser()); + +app.get('/', function (req, res) { + // Cookies that have not been signed + console.log('Cookies: ', req.cookies); + + // Cookies that have been signed + console.log('Signed Cookies: ', req.signedCookies); +}); + +app.listen(8080); + +// curl command that sends an HTTP request with two cookies +// curl http://127.0.0.1:8080 --cookie "Cho=Kim;Greet=Hello" +``` + +## License + +[MIT](LICENSE) + +[ci-image]: https://badgen.net/github/checks/expressjs/cookie-parser/master?label=ci +[ci-url]: https://github.com/expressjs/cookie-parser/actions?query=workflow%3Aci +[coveralls-image]: https://badgen.net/coveralls/c/github/expressjs/cookie-parser/master +[coveralls-url]: https://coveralls.io/r/expressjs/cookie-parser?branch=master +[npm-downloads-image]: https://badgen.net/npm/dm/cookie-parser +[npm-url]: https://npmjs.org/package/cookie-parser +[npm-version-image]: https://badgen.net/npm/v/cookie-parser diff --git a/astro/src/content/docs/en/resources/middleware/cookie-session.md b/astro/src/content/docs/en/resources/middleware/cookie-session.md new file mode 100644 index 0000000000..9993a0f0d5 --- /dev/null +++ b/astro/src/content/docs/en/resources/middleware/cookie-session.md @@ -0,0 +1,125 @@ +--- +title: Express cookie-session middleware +menu: resources +module: cookie-session +--- + +# cookie-parser + +[![NPM Version][npm-version-image]][npm-url] +[![NPM Downloads][npm-downloads-image]][npm-url] +[![Build Status][ci-image]][ci-url] +[![Test Coverage][coveralls-image]][coveralls-url] + +Parse `Cookie` header and populate `req.cookies` with an object keyed by the +cookie names. Optionally you may enable signed cookie support by passing a +`secret` string, which assigns `req.secret` so it may be used by other +middleware. + +## Installation + +```sh +$ npm install cookie-parser +``` + +## API + +```js +var cookieParser = require('cookie-parser'); +``` + +### cookieParser(secret, options) + +Create a new cookie parser middleware function using the given `secret` and +`options`. + +- `secret` a string or array used for signing cookies. This is optional and if + not specified, will not parse signed cookies. If a string is provided, this + is used as the secret. If an array is provided, an attempt will be made to + unsign the cookie with each secret in order. +- `options` an object that is passed to `cookie.parse` as the second option. See + [cookie](https://www.npmjs.org/package/cookie) for more information. + - `decode` a function to decode the value of the cookie + +The middleware will parse the `Cookie` header on the request and expose the +cookie data as the property `req.cookies` and, if a `secret` was provided, as +the property `req.signedCookies`. These properties are name value pairs of the +cookie name to cookie value. + +When `secret` is provided, this module will unsign and validate any signed cookie +values and move those name value pairs from `req.cookies` into `req.signedCookies`. +A signed cookie is a cookie that has a value prefixed with `s:`. Signed cookies +that fail signature validation will have the value `false` instead of the tampered +value. + +In addition, this module supports special "JSON cookies". These are cookie where +the value is prefixed with `j:`. When these values are encountered, the value will +be exposed as the result of `JSON.parse`. If parsing fails, the original value will +remain. + +### cookieParser.JSONCookie(str) + +Parse a cookie value as a JSON cookie. This will return the parsed JSON value +if it was a JSON cookie, otherwise, it will return the passed value. + +### cookieParser.JSONCookies(cookies) + +Given an object, this will iterate over the keys and call `JSONCookie` on each +value, replacing the original value with the parsed value. This returns the +same object that was passed in. + +### cookieParser.signedCookie(str, secret) + +Parse a cookie value as a signed cookie. This will return the parsed unsigned +value if it was a signed cookie and the signature was valid. If the value was +not signed, the original value is returned. If the value was signed but the +signature could not be validated, `false` is returned. + +The `secret` argument can be an array or string. If a string is provided, this +is used as the secret. If an array is provided, an attempt will be made to +unsign the cookie with each secret in order. + +### cookieParser.signedCookies(cookies, secret) + +Given an object, this will iterate over the keys and check if any value is a +signed cookie. If it is a signed cookie and the signature is valid, the key +will be deleted from the object and added to the new object that is returned. + +The `secret` argument can be an array or string. If a string is provided, this +is used as the secret. If an array is provided, an attempt will be made to +unsign the cookie with each secret in order. + +## Example + +```js +var express = require('express'); +var cookieParser = require('cookie-parser'); + +var app = express(); +app.use(cookieParser()); + +app.get('/', function (req, res) { + // Cookies that have not been signed + console.log('Cookies: ', req.cookies); + + // Cookies that have been signed + console.log('Signed Cookies: ', req.signedCookies); +}); + +app.listen(8080); + +// curl command that sends an HTTP request with two cookies +// curl http://127.0.0.1:8080 --cookie "Cho=Kim;Greet=Hello" +``` + +## License + +[MIT](LICENSE) + +[ci-image]: https://badgen.net/github/checks/expressjs/cookie-parser/master?label=ci +[ci-url]: https://github.com/expressjs/cookie-parser/actions?query=workflow%3Aci +[coveralls-image]: https://badgen.net/coveralls/c/github/expressjs/cookie-parser/master +[coveralls-url]: https://coveralls.io/r/expressjs/cookie-parser?branch=master +[npm-downloads-image]: https://badgen.net/npm/dm/cookie-parser +[npm-url]: https://npmjs.org/package/cookie-parser +[npm-version-image]: https://badgen.net/npm/v/cookie-parser diff --git a/astro/src/content/docs/en/resources/middleware/cors.md b/astro/src/content/docs/en/resources/middleware/cors.md new file mode 100644 index 0000000000..d14c1f1154 --- /dev/null +++ b/astro/src/content/docs/en/resources/middleware/cors.md @@ -0,0 +1,262 @@ +--- +title: Express cors middleware +menu: resources +module: cors +--- + +# cors + +[![NPM Version][npm-image]][npm-url] +[![NPM Downloads][downloads-image]][downloads-url] +[![Build Status][github-actions-ci-image]][github-actions-ci-url] +[![Test Coverage][coveralls-image]][coveralls-url] + +CORS is a [Node.js](https://nodejs.org/en/) package for providing a [Connect](https://github.com/senchalabs/connect)/[Express](https://expressjs.com/) middleware that can be used to enable [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS) with various options. + +- [Installation](#installation) +- [Usage](#usage) + - [Simple Usage](#simple-usage-enable-all-cors-requests) + - [Enable CORS for a Single Route](#enable-cors-for-a-single-route) + - [Configuring CORS](#configuring-cors) + - [Configuring CORS w/ Dynamic Origin](#configuring-cors-w-dynamic-origin) + - [Enabling CORS Pre-Flight](#enabling-cors-pre-flight) + - [Customizing CORS Settings Dynamically per Request](#customizing-cors-settings-dynamically-per-request) +- [Configuration Options](#configuration-options) +- [License](#license) +- [Original Author](#original-author) + +## Installation + +This is a [Node.js](https://nodejs.org/en/) module available through the +[npm registry](https://www.npmjs.com/). Installation is done using the +[`npm install` command](https://docs.npmjs.com/downloading-and-installing-packages-locally): + +```sh +$ npm install cors +``` + +## Usage + +### Simple Usage (Enable _All_ CORS Requests) + +```javascript +var express = require('express'); +var cors = require('cors'); +var app = express(); + +app.use(cors()); + +app.get('/products/:id', function (req, res, next) { + res.json({ msg: 'This is CORS-enabled for all origins!' }); +}); + +app.listen(80, function () { + console.log('CORS-enabled web server listening on port 80'); +}); +``` + +### Enable CORS for a Single Route + +```javascript +var express = require('express'); +var cors = require('cors'); +var app = express(); + +app.get('/products/:id', cors(), function (req, res, next) { + res.json({ msg: 'This is CORS-enabled for a Single Route' }); +}); + +app.listen(80, function () { + console.log('CORS-enabled web server listening on port 80'); +}); +``` + +### Configuring CORS + +See the [configuration options](#configuration-options) for details. + +```javascript +var express = require('express'); +var cors = require('cors'); +var app = express(); + +var corsOptions = { + origin: 'http://example.com', + optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204 +}; + +app.get('/products/:id', cors(corsOptions), function (req, res, next) { + res.json({ msg: 'This is CORS-enabled for only example.com.' }); +}); + +app.listen(80, function () { + console.log('CORS-enabled web server listening on port 80'); +}); +``` + +### Configuring CORS w/ Dynamic Origin + +This module supports validating the origin dynamically using a function provided +to the `origin` option. This function will be passed a string that is the origin +(or `undefined` if the request has no origin), and a `callback` with the signature +`callback(error, origin)`. + +The `origin` argument to the callback can be any value allowed for the `origin` +option of the middleware, except a function. See the +[configuration options](#configuration-options) section for more information on all +the possible value types. + +This function is designed to allow the dynamic loading of allowed origin(s) from +a backing datasource, like a database. + +```javascript +var express = require('express'); +var cors = require('cors'); +var app = express(); + +var corsOptions = { + origin: function (origin, callback) { + // db.loadOrigins is an example call to load + // a list of origins from a backing database + db.loadOrigins(function (error, origins) { + callback(error, origins); + }); + }, +}; + +app.get('/products/:id', cors(corsOptions), function (req, res, next) { + res.json({ msg: 'This is CORS-enabled for an allowed domain.' }); +}); + +app.listen(80, function () { + console.log('CORS-enabled web server listening on port 80'); +}); +``` + +### Enabling CORS Pre-Flight + +Certain CORS requests are considered 'complex' and require an initial +`OPTIONS` request (called the "pre-flight request"). An example of a +'complex' CORS request is one that uses an HTTP verb other than +GET/HEAD/POST (such as DELETE) or that uses custom headers. To enable +pre-flighting, you must add a new OPTIONS handler for the route you want +to support: + +```javascript +var express = require('express'); +var cors = require('cors'); +var app = express(); + +app.options('/products/:id', cors()); // enable pre-flight request for DELETE request +app.del('/products/:id', cors(), function (req, res, next) { + res.json({ msg: 'This is CORS-enabled for all origins!' }); +}); + +app.listen(80, function () { + console.log('CORS-enabled web server listening on port 80'); +}); +``` + +You can also enable pre-flight across-the-board like so: + +```javascript +app.options('*', cors()); // include before other routes +``` + +NOTE: When using this middleware as an application level middleware (for +example, `app.use(cors())`), pre-flight requests are already handled for all +routes. + +### Customizing CORS Settings Dynamically per Request + +For APIs that require different CORS configurations for specific routes or requests, you can dynamically generate CORS options based on the incoming request. The `cors` middleware allows you to achieve this by passing a function instead of static options. This function is called for each incoming request and must use the callback pattern to return the appropriate CORS options. + +The function accepts: + +1. **`req`**: + - The incoming request object. + +2. **`callback(error, corsOptions)`**: + - A function used to return the computed CORS options. + - **Arguments**: + - **`error`**: Pass `null` if there’s no error, or an error object to indicate a failure. + - **`corsOptions`**: An object specifying the CORS policy for the current request. + +Here’s an example that handles both public routes and restricted, credential-sensitive routes: + +```javascript +var dynamicCorsOptions = function (req, callback) { + var corsOptions; + if (req.path.startsWith('/auth/connect/')) { + corsOptions = { + origin: 'http://mydomain.com', // Allow only a specific origin + credentials: true, // Enable cookies and credentials + }; + } else { + corsOptions = { origin: '*' }; // Allow all origins for other routes + } + callback(null, corsOptions); +}; + +app.use(cors(dynamicCorsOptions)); + +app.get('/auth/connect/twitter', function (req, res) { + res.send('CORS dynamically applied for Twitter authentication.'); +}); + +app.get('/public', function (req, res) { + res.send('Public data with open CORS.'); +}); + +app.listen(80, function () { + console.log('CORS-enabled web server listening on port 80'); +}); +``` + +## Configuration Options + +- `origin`: Configures the **Access-Control-Allow-Origin** CORS header. Possible values: + - `Boolean` - set `origin` to `true` to reflect the [request origin](https://datatracker.ietf.org/doc/html/draft-abarth-origin-09), as defined by `req.header('Origin')`, or set it to `false` to disable CORS. + - `String` - set `origin` to a specific origin. For example, if you set it to + - `"http://example.com"` only requests from "http://example.com" will be allowed. + - `"*"` for all domains to be allowed. + - `RegExp` - set `origin` to a regular expression pattern which will be used to test the request origin. If it's a match, the request origin will be reflected. For example the pattern `/example\.com$/` will reflect any request that is coming from an origin ending with "example.com". + - `Array` - set `origin` to an array of valid origins. Each origin can be a `String` or a `RegExp`. For example `["http://example1.com", /\.example2\.com$/]` will accept any request from "http://example1.com" or from a subdomain of "example2.com". + - `Function` - set `origin` to a function implementing some custom logic. The function takes the request origin as the first parameter and a callback (called as `callback(err, origin)`, where `origin` is a non-function value of the `origin` option) as the second. +- `methods`: Configures the **Access-Control-Allow-Methods** CORS header. Expects a comma-delimited string (ex: 'GET,PUT,POST') or an array (ex: `['GET', 'PUT', 'POST']`). +- `allowedHeaders`: Configures the **Access-Control-Allow-Headers** CORS header. Expects a comma-delimited string (ex: 'Content-Type,Authorization') or an array (ex: `['Content-Type', 'Authorization']`). If not specified, defaults to reflecting the headers specified in the request's **Access-Control-Request-Headers** header. +- `exposedHeaders`: Configures the **Access-Control-Expose-Headers** CORS header. Expects a comma-delimited string (ex: 'Content-Range,X-Content-Range') or an array (ex: `['Content-Range', 'X-Content-Range']`). If not specified, no custom headers are exposed. +- `credentials`: Configures the **Access-Control-Allow-Credentials** CORS header. Set to `true` to pass the header, otherwise it is omitted. +- `maxAge`: Configures the **Access-Control-Max-Age** CORS header. Set to an integer to pass the header, otherwise it is omitted. +- `preflightContinue`: Pass the CORS preflight response to the next handler. +- `optionsSuccessStatus`: Provides a status code to use for successful `OPTIONS` requests, since some legacy browsers (IE11, various SmartTVs) choke on `204`. + +The default configuration is the equivalent of: + +```json +{ + "origin": "*", + "methods": "GET,HEAD,PUT,PATCH,POST,DELETE", + "preflightContinue": false, + "optionsSuccessStatus": 204 +} +``` + +For details on the effect of each CORS header, read [this](https://web.dev/articles/cross-origin-resource-sharing) article. + +## License + +[MIT License](http://www.opensource.org/licenses/mit-license.php) + +## Original Author + +[Troy Goode](https://github.com/TroyGoode) ([troygoode@gmail.com](mailto:troygoode@gmail.com)) + +[coveralls-image]: https://img.shields.io/coveralls/expressjs/cors/master.svg +[coveralls-url]: https://coveralls.io/r/expressjs/cors?branch=master +[downloads-image]: https://img.shields.io/npm/dm/cors.svg +[downloads-url]: https://npmjs.com/package/cors +[github-actions-ci-image]: https://img.shields.io/github/actions/workflow/status/expressjs/cors/ci.yml?branch=master&label=ci +[github-actions-ci-url]: https://github.com/expressjs/cors?query=workflow%3Aci +[npm-image]: https://img.shields.io/npm/v/cors.svg +[npm-url]: https://npmjs.com/package/cors diff --git a/astro/src/content/docs/en/resources/middleware/errorhandler.md b/astro/src/content/docs/en/resources/middleware/errorhandler.md new file mode 100644 index 0000000000..66bceeddd6 --- /dev/null +++ b/astro/src/content/docs/en/resources/middleware/errorhandler.md @@ -0,0 +1,134 @@ +--- +title: Express errorhandler middleware +menu: resources +module: errorhandler +--- + +# errorhandler + +[![NPM Version][npm-version-image]][npm-url] +[![NPM Downloads][npm-downloads-image]][npm-url] + +[![Test Coverage][coveralls-image]][coveralls-url] + +Development-only error handler middleware. + +This middleware is only intended to be used in a development environment, as +the _full error stack traces and internal details of any object passed to this +module_ will be sent back to the client when an error occurs. + +When an object is provided to Express as an error, this module will display +as much about this object as possible, and will do so by using content negotiation +for the response between HTML, JSON, and plain text. + +- When the object is a standard `Error` object, the string provided by the + `stack` property will be returned in HTML/text responses. +- When the object is a non-`Error` object, the result of + [util.inspect](https://nodejs.org/api/util.html#util_util_inspect_object_options) + will be returned in HTML/text responses. +- For JSON responses, the result will be an object with all enumerable properties + from the object in the response. + +## Install + +This is a [Node.js](https://nodejs.org/en/) module available through the +[npm registry](https://www.npmjs.com/). Installation is done using the +[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally): + +```sh +$ npm install errorhandler +``` + +## API + + + +```js +var errorhandler = require('errorhandler'); +``` + +### errorhandler(options) + +Create new middleware to handle errors and respond with content negotiation. + +#### Options + +Error handler accepts these properties in the options object. + +##### log + +Provide a function to be called with the error and a string representation of +the error. Can be used to write the error to any desired location, or set to +`false` to only send the error back in the response. Called as +`log(err, str, req, res)` where `err` is the `Error` object, `str` is a string +representation of the error, `req` is the request object and `res` is the +response object (note, this function is invoked _after_ the response has been +written). + +The default value for this option is `true` unless `process.env.NODE_ENV === 'test'`. + +Possible values: + +- `true`: Log errors using `console.error(str)`. +- `false`: Only send the error back in the response. +- A function: pass the error to a function for handling. + +## Examples + +### Simple example + +Basic example of adding this middleware as the error handler only in development +with `connect` (`express` also can be used in this example). + +```js +var connect = require('connect'); +var errorhandler = require('errorhandler'); + +var app = connect(); + +// assumes NODE_ENV is set by the user +if (process.env.NODE_ENV === 'development') { + // only use in development + app.use(errorhandler()); +} +``` + +### Custom output location + +Sometimes you may want to output the errors to a different location than STDERR +during development, like a system notification, for example. + + + +```js +var connect = require('connect'); +var errorhandler = require('errorhandler'); +var notifier = require('node-notifier'); + +var app = connect(); + +// assumes NODE_ENV is set by the user +if (process.env.NODE_ENV === 'development') { + // only use in development + app.use(errorhandler({ log: errorNotification })); +} + +function errorNotification(err, str, req) { + var title = 'Error in ' + req.method + ' ' + req.url; + + notifier.notify({ + title: title, + message: str, + }); +} +``` + +## License + +[MIT](LICENSE) + +[coveralls-image]: https://badgen.net/coveralls/c/github/expressjs/errorhandler/master +[coveralls-url]: https://coveralls.io/r/expressjs/errorhandler?branch=master +[npm-downloads-image]: https://badgen.net/npm/dm/errorhandler +[npm-url]: https://npmjs.org/package/errorhandler +[npm-version-image]: https://badgen.net/npm/v/errorhandler diff --git a/astro/src/content/docs/en/resources/middleware/method-override.md b/astro/src/content/docs/en/resources/middleware/method-override.md new file mode 100644 index 0000000000..84be20828d --- /dev/null +++ b/astro/src/content/docs/en/resources/middleware/method-override.md @@ -0,0 +1,188 @@ +--- +title: Express method-override middleware +menu: resources +module: method-override +--- + +# method-override + +[![NPM Version][npm-image]][npm-url] +[![NPM Downloads][downloads-image]][downloads-url] +[![Build Status][travis-image]][travis-url] +[![Test Coverage][coveralls-image]][coveralls-url] + +Lets you use HTTP verbs such as PUT or DELETE in places where the client doesn't support it. + +## Install + +This is a [Node.js](https://nodejs.org/en/) module available through the +[npm registry](https://www.npmjs.com/). Installation is done using the +[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally): + +```sh +$ npm install method-override +``` + +## API + +**NOTE** It is very important that this module is used **before** any module that +needs to know the method of the request (for example, it _must_ be used prior to +the `csurf` module). + +### methodOverride(getter, options) + +Create a new middleware function to override the `req.method` property with a new +value. This value will be pulled from the provided `getter`. + +- `getter` - The getter to use to look up the overridden request method for the request. (default: `X-HTTP-Method-Override`) +- `options.methods` - The allowed methods the original request must be in to check for a method override value. (default: `['POST']`) + +If the found method is supported by node.js core, then `req.method` will be set to +this value, as if it has originally been that value. The previous `req.method` +value will be stored in `req.originalMethod`. + +#### getter + +This is the method of getting the override value from the request. If a function is provided, +the `req` is passed as the first argument, the `res` as the second argument and the method is +expected to be returned. If a string is provided, the string is used to look up the method +with the following rules: + +- If the string starts with `X-`, then it is treated as the name of a header and that header + is used for the method override. If the request contains the same header multiple times, the + first occurrence is used. +- All other strings are treated as a key in the URL query string. + +#### options.methods + +This allows the specification of what methods(s) the request _MUST_ be in in order to check for +the method override value. This defaults to only `POST` methods, which is the only method the +override should arrive in. More methods may be specified here, but it may introduce security +issues and cause weird behavior when requests travel through caches. This value is an array +of methods in upper-case. `null` can be specified to allow all methods. + +## Examples + +### override using a header + +To use a header to override the method, specify the header name +as a string argument to the `methodOverride` function. To then make +the call, send a `POST` request to a URL with the overridden method +as the value of that header. This method of using a header would +typically be used in conjunction with `XMLHttpRequest` on implementations +that do not support the method you are trying to use. + +```js +const express = require('express'); +const methodOverride = require('method-override'); +const app = express(); + +// override with the X-HTTP-Method-Override header in the request +app.use(methodOverride('X-HTTP-Method-Override')); +``` + +Example call with header override using `XMLHttpRequest`: + + + +```js +const xhr = new XMLHttpRequest(); +xhr.onload = onload; +xhr.open('post', '/resource', true); +xhr.setRequestHeader('X-HTTP-Method-Override', 'DELETE'); +xhr.send(); + +function onload() { + alert('got response: ' + this.responseText); +} +``` + +### override using a query value + +To use a query string value to override the method, specify the query +string key as a string argument to the `methodOverride` function. To +then make the call, send a `POST` request to a URL with the overridden +method as the value of that query string key. This method of using a +query value would typically be used in conjunction with plain HTML +`
` elements when trying to support legacy browsers but still use +newer methods. + +```js +const express = require('express'); +const methodOverride = require('method-override'); +const app = express(); + +// override with POST having ?_method=DELETE +app.use(methodOverride('_method')); +``` + +Example call with query override using HTML ``: + +```html + + +
+``` + +### multiple format support + +```js +const express = require('express'); +const methodOverride = require('method-override'); +const app = express(); + +// override with different headers; last one takes precedence +app.use(methodOverride('X-HTTP-Method')); // Microsoft +app.use(methodOverride('X-HTTP-Method-Override')); // Google/GData +app.use(methodOverride('X-Method-Override')); // IBM +``` + +### custom logic + +You can implement any kind of custom logic with a function for the `getter`. The following +implements the logic for looking in `req.body` that was in `method-override@1`: + +```js +const bodyParser = require('body-parser'); +const express = require('express'); +const methodOverride = require('method-override'); +const app = express(); + +// NOTE: when using req.body, you must fully parse the request body +// before you call methodOverride() in your middleware stack, +// otherwise req.body will not be populated. +app.use(bodyParser.urlencoded()); +app.use( + methodOverride(function (req, res) { + if (req.body && typeof req.body === 'object' && '_method' in req.body) { + // look in urlencoded POST bodies and delete it + const method = req.body._method; + delete req.body._method; + return method; + } + }) +); +``` + +Example call with query override using HTML `
`: + +```html + + + + +
+``` + +## License + +[MIT](LICENSE) + +[npm-image]: https://img.shields.io/npm/v/method-override.svg +[npm-url]: https://npmjs.org/package/method-override +[travis-image]: https://img.shields.io/travis/expressjs/method-override/master.svg +[travis-url]: https://travis-ci.org/expressjs/method-override +[coveralls-image]: https://img.shields.io/coveralls/expressjs/method-override/master.svg +[coveralls-url]: https://coveralls.io/r/expressjs/method-override?branch=master +[downloads-image]: https://img.shields.io/npm/dm/method-override.svg +[downloads-url]: https://npmjs.org/package/method-override diff --git a/astro/src/content/docs/en/resources/middleware/morgan.md b/astro/src/content/docs/en/resources/middleware/morgan.md new file mode 100644 index 0000000000..d2227dfc21 --- /dev/null +++ b/astro/src/content/docs/en/resources/middleware/morgan.md @@ -0,0 +1,459 @@ +--- +title: Express morgan middleware +menu: resources +module: morgan +--- + +# morgan + +[![NPM Version][npm-version-image]][npm-url] +[![NPM Downloads][npm-downloads-image]][npm-url] +[![Build Status][ci-image]][ci-url] +[![Coverage Status][coveralls-image]][coveralls-url] + +HTTP request logger middleware for node.js + +> Named after [Dexter](http://en.wikipedia.org/wiki/Dexter_Morgan), a show you should not watch until completion. + +## Installation + +This is a [Node.js](https://nodejs.org/en/) module available through the +[npm registry](https://www.npmjs.com/). Installation is done using the +[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally): + +```sh +$ npm install morgan +``` + +## API + + + +```js +var morgan = require('morgan'); +``` + +### morgan(format, options) + +Create a new morgan logger middleware function using the given `format` and `options`. +The `format` argument may be a string of a predefined name (see below for the names), +a string of a format string, or a function that will produce a log entry. + +The `format` function will be called with three arguments `tokens`, `req`, and `res`, +where `tokens` is an object with all defined tokens, `req` is the HTTP request and `res` +is the HTTP response. The function is expected to return a string that will be the log +line, or `undefined` / `null` to skip logging. + +#### Using a predefined format string + + + +```js +morgan('tiny'); +``` + +#### Using format string of predefined tokens + + + +```js +morgan(':method :url :status :res[content-length] - :response-time ms'); +``` + +#### Using a custom format function + + + +```js +morgan(function (tokens, req, res) { + return [ + tokens.method(req, res), + tokens.url(req, res), + tokens.status(req, res), + tokens.res(req, res, 'content-length'), + '-', + tokens['response-time'](req, res), + 'ms', + ].join(' '); +}); +``` + +#### Options + +Morgan accepts these properties in the options object. + +##### immediate + +Write log line on request instead of response. This means that a requests will +be logged even if the server crashes, _but data from the response (like the +response code, content length, etc.) cannot be logged_. + +##### skip + +Function to determine if logging is skipped, defaults to `false`. This function +will be called as `skip(req, res)`. + + + +```js +// EXAMPLE: only log error responses +morgan('combined', { + skip: function (req, res) { + return res.statusCode < 400; + }, +}); +``` + +##### stream + +Output stream for writing log lines, defaults to `process.stdout`. + +#### Predefined Formats + +There are various pre-defined formats provided: + +##### combined + +Standard Apache combined log output. + +``` +:remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent" +# will output +::1 - - [27/Nov/2024:06:21:42 +0000] "GET /combined HTTP/1.1" 200 2 "-" "curl/8.7.1" +``` + +##### common + +Standard Apache common log output. + +``` +:remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] +# will output +::1 - - [27/Nov/2024:06:21:46 +0000] "GET /common HTTP/1.1" 200 2 +``` + +##### dev + +Concise output colored by response status for development use. The `:status` +token will be colored green for success codes, red for server error codes, +yellow for client error codes, cyan for redirection codes, and uncolored +for information codes. + +``` +:method :url :status :response-time ms - :res[content-length] +# will output +GET /dev 200 0.224 ms - 2 +``` + +##### short + +Shorter than default, also including response time. + +``` +:remote-addr :remote-user :method :url HTTP/:http-version :status :res[content-length] - :response-time ms +# will output +::1 - GET /short HTTP/1.1 200 2 - 0.283 ms +``` + +##### tiny + +The minimal output. + +``` +:method :url :status :res[content-length] - :response-time ms +# will output +GET /tiny 200 2 - 0.188 ms +``` + +#### Tokens + +##### Creating new tokens + +To define a token, simply invoke `morgan.token()` with the name and a callback function. +This callback function is expected to return a string value. The value returned is then +available as ":type" in this case: + + + +```js +morgan.token('type', function (req, res) { + return req.headers['content-type']; +}); +``` + +Calling `morgan.token()` using the same name as an existing token will overwrite that +token definition. + +The token function is expected to be called with the arguments `req` and `res`, representing +the HTTP request and HTTP response. Additionally, the token can accept further arguments of +it's choosing to customize behavior. + +##### :date[format] + +The current date and time in UTC. The available formats are: + +- `clf` for the common log format (`"10/Oct/2000:13:55:36 +0000"`) +- `iso` for the common ISO 8601 date time format (`2000-10-10T13:55:36.000Z`) +- `web` for the common RFC 1123 date time format (`Tue, 10 Oct 2000 13:55:36 GMT`) + +If no format is given, then the default is `web`. + +##### :http-version + +The HTTP version of the request. + +##### :method + +The HTTP method of the request. + +##### :pid + +The process ID of the Node.js process handling the request. + +##### :referrer + +The Referrer header of the request. This will use the standard mis-spelled Referer header if exists, otherwise Referrer. + +##### :remote-addr + +The remote address of the request. This will use `req.ip`, otherwise the standard `req.connection.remoteAddress` value (socket address). + +##### :remote-user + +The user authenticated as part of Basic auth for the request. + +##### :req[header] + +The given `header` of the request. If the header is not present, the +value will be displayed as `"-"` in the log. + +##### :res[header] + +The given `header` of the response. If the header is not present, the +value will be displayed as `"-"` in the log. + +##### :response-time[digits] + +The time between the request coming into `morgan` and when the response +headers are written, in milliseconds. + +The `digits` argument is a number that specifies the number of digits to +include on the number, defaulting to `3`, which provides microsecond precision. + +##### :status + +The status code of the response. + +If the request/response cycle completes before a response was sent to the +client (for example, the TCP socket closed prematurely by a client aborting +the request), then the status will be empty (displayed as `"-"` in the log). + +##### :total-time[digits] + +The time between the request coming into `morgan` and when the response +has finished being written out to the connection, in milliseconds. + +The `digits` argument is a number that specifies the number of digits to +include on the number, defaulting to `3`, which provides microsecond precision. + +##### :url + +The URL of the request. This will use `req.originalUrl` if exists, otherwise `req.url`. + +##### :user-agent + +The contents of the User-Agent header of the request. + +### morgan.compile(format) + +Compile a format string into a `format` function for use by `morgan`. A format string +is a string that represents a single log line and can utilize token syntax. +Tokens are references by `:token-name`. If tokens accept arguments, they can +be passed using `[]`, for example: `:token-name[pretty]` would pass the string +`'pretty'` as an argument to the token `token-name`. + +The function returned from `morgan.compile` takes three arguments `tokens`, `req`, and +`res`, where `tokens` is object with all defined tokens, `req` is the HTTP request and +`res` is the HTTP response. The function will return a string that will be the log line, +or `undefined` / `null` to skip logging. + +Normally formats are defined using `morgan.format(name, format)`, but for certain +advanced uses, this compile function is directly available. + +## Examples + +### express/connect + +Sample app that will log all request in the Apache combined format to STDOUT + +```js +var express = require('express'); +var morgan = require('morgan'); + +var app = express(); + +app.use(morgan('combined')); + +app.get('/', function (req, res) { + res.send('hello, world!'); +}); +``` + +### vanilla http server + +Sample app that will log all request in the Apache combined format to STDOUT + +```js +var finalhandler = require('finalhandler'); +var http = require('http'); +var morgan = require('morgan'); + +// create "middleware" +var logger = morgan('combined'); + +http.createServer(function (req, res) { + var done = finalhandler(req, res); + logger(req, res, function (err) { + if (err) return done(err); + + // respond to request + res.setHeader('content-type', 'text/plain'); + res.end('hello, world!'); + }); +}); +``` + +### write logs to a file + +#### single file + +Sample app that will log all requests in the Apache combined format to the file +`access.log`. + +```js +var express = require('express'); +var fs = require('fs'); +var morgan = require('morgan'); +var path = require('path'); + +var app = express(); + +// create a write stream (in append mode) +var accessLogStream = fs.createWriteStream(path.join(__dirname, 'access.log'), { flags: 'a' }); + +// setup the logger +app.use(morgan('combined', { stream: accessLogStream })); + +app.get('/', function (req, res) { + res.send('hello, world!'); +}); +``` + +#### log file rotation + +Sample app that will log all requests in the Apache combined format to one log +file per day in the `log/` directory using the +[rotating-file-stream module](https://www.npmjs.com/package/rotating-file-stream). + +```js +var express = require('express'); +var morgan = require('morgan'); +var path = require('path'); +var rfs = require('rotating-file-stream'); // version 2.x + +var app = express(); + +// create a rotating write stream +var accessLogStream = rfs.createStream('access.log', { + interval: '1d', // rotate daily + path: path.join(__dirname, 'log'), +}); + +// setup the logger +app.use(morgan('combined', { stream: accessLogStream })); + +app.get('/', function (req, res) { + res.send('hello, world!'); +}); +``` + +### split / dual logging + +The `morgan` middleware can be used as many times as needed, enabling +combinations like: + +- Log entry on request and one on response +- Log all requests to file, but errors to console +- ... and more! + +Sample app that will log all requests to a file using Apache format, but +error responses are logged to the console: + +```js +var express = require('express'); +var fs = require('fs'); +var morgan = require('morgan'); +var path = require('path'); + +var app = express(); + +// log only 4xx and 5xx responses to console +app.use( + morgan('dev', { + skip: function (req, res) { + return res.statusCode < 400; + }, + }) +); + +// log all requests to access.log +app.use( + morgan('common', { + stream: fs.createWriteStream(path.join(__dirname, 'access.log'), { flags: 'a' }), + }) +); + +app.get('/', function (req, res) { + res.send('hello, world!'); +}); +``` + +### use custom token formats + +Sample app that will use custom token formats. This adds an ID to all requests and displays it using the `:id` token. + +```js +var express = require('express'); +var morgan = require('morgan'); +var uuid = require('node-uuid'); + +morgan.token('id', function getId(req) { + return req.id; +}); + +var app = express(); + +app.use(assignId); +app.use(morgan(':id :method :url :response-time')); + +app.get('/', function (req, res) { + res.send('hello, world!'); +}); + +function assignId(req, res, next) { + req.id = uuid.v4(); + next(); +} +``` + +## License + +[MIT](LICENSE) + +[ci-image]: https://badgen.net/github/checks/expressjs/morgan/master?label=ci +[ci-url]: https://github.com/expressjs/morgan/actions/workflows/ci.yml +[coveralls-image]: https://badgen.net/coveralls/c/github/expressjs/morgan/master +[coveralls-url]: https://coveralls.io/r/expressjs/morgan?branch=master +[npm-downloads-image]: https://badgen.net/npm/dm/morgan +[npm-url]: https://npmjs.org/package/morgan +[npm-version-image]: https://badgen.net/npm/v/morgan diff --git a/astro/src/content/docs/en/resources/middleware/multer.md b/astro/src/content/docs/en/resources/middleware/multer.md new file mode 100644 index 0000000000..b8fd6fc4db --- /dev/null +++ b/astro/src/content/docs/en/resources/middleware/multer.md @@ -0,0 +1,353 @@ +--- +title: Express multer middleware +menu: resources +module: multer +--- + +# Multer [![NPM Version][npm-version-image]][npm-url] [![NPM Downloads][npm-downloads-image]][npm-url] [![Build Status][ci-image]][ci-url] [![Test Coverage][test-image]][test-url] [![OpenSSF Scorecard Badge][ossf-scorecard-badge]][ossf-scorecard-visualizer] + +Multer is a node.js middleware for handling `multipart/form-data`, which is primarily used for uploading files. It is written +on top of [busboy](https://github.com/mscdex/busboy) for maximum efficiency. + +**NOTE**: Multer will not process any form which is not multipart (`multipart/form-data`). + +## Translations + +This README is also available in other languages: + +| | | +| ------------------------------------------------------------------------------ | --------------- | +| [العربية](https://github.com/expressjs/multer/blob/main/doc/README-ar.md) | Arabic | +| [简体中文](https://github.com/expressjs/multer/blob/main/doc/README-zh-cn.md) | Chinese | +| [Français](https://github.com/expressjs/multer/blob/main/doc/README-fr.md) | French | +| [한국어](https://github.com/expressjs/multer/blob/main/doc/README-ko.md) | Korean | +| [Português](https://github.com/expressjs/multer/blob/main/doc/README-pt-br.md) | Portuguese (BR) | +| [Русский язык](https://github.com/expressjs/multer/blob/main/doc/README-ru.md) | Russian | +| [Español](https://github.com/expressjs/multer/blob/main/doc/README-es.md) | Spanish | +| [O'zbek tili](https://github.com/expressjs/multer/blob/main/doc/README-uz.md) | Uzbek | +| [Việt Nam](https://github.com/expressjs/multer/blob/main/doc/README-vi.md) | Vietnamese | + +## Installation + +```sh +$ npm install multer +``` + +## Usage + +Multer adds a `body` object and a `file` or `files` object to the `request` object. The `body` object contains the values of the text fields of the form, the `file` or `files` object contains the files uploaded via the form. + +Basic usage example: + +Don't forget the `enctype="multipart/form-data"` in your form. + +```html +
+ +
+``` + +```javascript +const express = require('express'); +const multer = require('multer'); +const upload = multer({ dest: 'uploads/' }); + +const app = express(); + +app.post('/profile', upload.single('avatar'), function (req, res, next) { + // req.file is the `avatar` file + // req.body will hold the text fields, if there were any +}); + +app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) { + // req.files is array of `photos` files + // req.body will contain the text fields, if there were any +}); + +const uploadMiddleware = upload.fields([ + { name: 'avatar', maxCount: 1 }, + { name: 'gallery', maxCount: 8 }, +]); +app.post('/cool-profile', uploadMiddleware, function (req, res, next) { + // req.files is an object (String -> Array) where fieldname is the key, and the value is array of files + // + // e.g. + // req.files['avatar'][0] -> File + // req.files['gallery'] -> Array + // + // req.body will contain the text fields, if there were any +}); +``` + +In case you need to handle a text-only multipart form, you should use the `.none()` method: + +```javascript +const express = require('express'); +const app = express(); +const multer = require('multer'); +const upload = multer(); + +app.post('/profile', upload.none(), function (req, res, next) { + // req.body contains the text fields +}); +``` + +Here's an example on how multer is used in a HTML form. Take special note of the `enctype="multipart/form-data"` and `name="uploaded_file"` fields: + +```html +
+
+ + + +
+
+``` + +Then in your javascript file you would add these lines to access both the file and the body. It is important that you use the `name` field value from the form in your upload function. This tells multer which field on the request it should look for the files in. If these fields aren't the same in the HTML form and on your server, your upload will fail: + +```javascript +const multer = require('multer'); +const upload = multer({ dest: './public/data/uploads/' }); +app.post('/stats', upload.single('uploaded_file'), function (req, res) { + // req.file is the name of your file in the form above, here 'uploaded_file' + // req.body will hold the text fields, if there were any + console.log(req.file, req.body); +}); +``` + +## API + +### File information + +Each file contains the following information: + +| Key | Description | Note | +| -------------- | --------------------------------------------- | --------------- | +| `fieldname` | Field name specified in the form | +| `originalname` | Name of the file on the user's computer | +| `encoding` | Encoding type of the file | +| `mimetype` | Mime type of the file | +| `size` | Size of the file in bytes | +| `destination` | The folder to which the file has been saved | `DiskStorage` | +| `filename` | The name of the file within the `destination` | `DiskStorage` | +| `path` | The full path to the uploaded file | `DiskStorage` | +| `buffer` | A `Buffer` of the entire file | `MemoryStorage` | + +### `multer(opts)` + +Multer accepts an options object, the most basic of which is the `dest` +property, which tells Multer where to upload the files. In case you omit the +options object, the files will be kept in memory and never written to disk. + +By default, Multer will rename the files so as to avoid naming conflicts. The +renaming function can be customized according to your needs. + +The following are the options that can be passed to Multer. + +| Key | Description | +| ------------------- | --------------------------------------------------------- | +| `dest` or `storage` | Where to store the files | +| `fileFilter` | Function to control which files are accepted | +| `limits` | Limits of the uploaded data | +| `preservePath` | Keep the full path of files instead of just the base name | + +In an average web app, only `dest` might be required, and configured as shown in +the following example. + +```javascript +const upload = multer({ dest: 'uploads/' }); +``` + +If you want more control over your uploads, you'll want to use the `storage` +option instead of `dest`. Multer ships with storage engines `DiskStorage` +and `MemoryStorage`; More engines are available from third parties. + +#### `.single(fieldname)` + +Accept a single file with the name `fieldname`. The single file will be stored +in `req.file`. + +#### `.array(fieldname[, maxCount])` + +Accept an array of files, all with the name `fieldname`. Optionally error out if +more than `maxCount` files are uploaded. The array of files will be stored in +`req.files`. + +#### `.fields(fields)` + +Accept a mix of files, specified by `fields`. An object with arrays of files +will be stored in `req.files`. + +`fields` should be an array of objects with `name` and optionally a `maxCount`. +Example: + +```javascript +[ + { name: 'avatar', maxCount: 1 }, + { name: 'gallery', maxCount: 8 }, +]; +``` + +#### `.none()` + +Accept only text fields. If any file upload is made, error with code +"LIMIT_UNEXPECTED_FILE" will be issued. + +#### `.any()` + +Accepts all files that comes over the wire. An array of files will be stored in +`req.files`. + +**WARNING:** Make sure that you always handle the files that a user uploads. +Never add multer as a global middleware since a malicious user could upload +files to a route that you didn't anticipate. Only use this function on routes +where you are handling the uploaded files. + +### `storage` + +#### `DiskStorage` + +The disk storage engine gives you full control on storing files to disk. + +```javascript +const storage = multer.diskStorage({ + destination: function (req, file, cb) { + cb(null, '/tmp/my-uploads'); + }, + filename: function (req, file, cb) { + const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9); + cb(null, file.fieldname + '-' + uniqueSuffix); + }, +}); + +const upload = multer({ storage: storage }); +``` + +There are two options available, `destination` and `filename`. They are both +functions that determine where the file should be stored. + +`destination` is used to determine within which folder the uploaded files should +be stored. This can also be given as a `string` (e.g. `'/tmp/uploads'`). If no +`destination` is given, the operating system's default directory for temporary +files is used. + +**Note:** You are responsible for creating the directory when providing +`destination` as a function. When passing a string, multer will make sure that +the directory is created for you. + +`filename` is used to determine what the file should be named inside the folder. +If no `filename` is given, each file will be given a random name that doesn't +include any file extension. + +**Note:** Multer will not append any file extension for you, your function +should return a filename complete with a file extension. + +Each function gets passed both the request (`req`) and some information about +the file (`file`) to aid with the decision. + +Note that `req.body` might not have been fully populated yet. It depends on the +order that the client transmits fields and files to the server. + +For understanding the calling convention used in the callback (needing to pass +null as the first param), refer to +[Node.js error handling](https://web.archive.org/web/20220417042018/https://www.joyent.com/node-js/production/design/errors) + +#### `MemoryStorage` + +The memory storage engine stores the files in memory as `Buffer` objects. It +doesn't have any options. + +```javascript +const storage = multer.memoryStorage(); +const upload = multer({ storage: storage }); +``` + +When using memory storage, the file info will contain a field called +`buffer` that contains the entire file. + +**WARNING**: Uploading very large files, or relatively small files in large +numbers very quickly, can cause your application to run out of memory when +memory storage is used. + +### `limits` + +An object specifying the size limits of the following optional properties. Multer passes this object into busboy directly, and the details of the properties can be found on [busboy's page](https://github.com/mscdex/busboy#busboy-methods). + +The following integer values are available: + +| Key | Description | Default | +| --------------- | ----------------------------------------------------------------------- | --------- | +| `fieldNameSize` | Max field name size | 100 bytes | +| `fieldSize` | Max field value size (in bytes) | 1MB | +| `fields` | Max number of non-file fields | Infinity | +| `fileSize` | For multipart forms, the max file size (in bytes) | Infinity | +| `files` | For multipart forms, the max number of file fields | Infinity | +| `parts` | For multipart forms, the max number of parts (fields + files) | Infinity | +| `headerPairs` | For multipart forms, the max number of header key=>value pairs to parse | 2000 | + +Specifying the limits can help protect your site against denial of service (DoS) attacks. + +### `fileFilter` + +Set this to a function to control which files should be uploaded and which +should be skipped. The function should look like this: + +```javascript +function fileFilter(req, file, cb) { + // The function should call `cb` with a boolean + // to indicate if the file should be accepted + + // To reject this file pass `false`, like so: + cb(null, false); + + // To accept the file pass `true`, like so: + cb(null, true); + + // You can always pass an error if something goes wrong: + cb(new Error("I don't have a clue!")); +} +``` + +## Error handling + +When encountering an error, Multer will delegate the error to Express. You can +display a nice error page using [the standard express way](http://expressjs.com/guide/error-handling.html). + +If you want to catch errors specifically from Multer, you can call the +middleware function by yourself. Also, if you want to catch only [the Multer errors](https://github.com/expressjs/multer/blob/main/lib/multer-error.js), you can use the `MulterError` class that is attached to the `multer` object itself (e.g. `err instanceof multer.MulterError`). + +```javascript +const multer = require('multer'); +const upload = multer().single('avatar'); + +app.post('/profile', function (req, res) { + upload(req, res, function (err) { + if (err instanceof multer.MulterError) { + // A Multer error occurred when uploading. + } else if (err) { + // An unknown error occurred when uploading. + } + + // Everything went fine. + }); +}); +``` + +## Custom storage engine + +For information on how to build your own storage engine, see [Multer Storage Engine](https://github.com/expressjs/multer/blob/main/StorageEngine.md). + +## License + +[MIT](LICENSE) + +[ci-image]: https://github.com/expressjs/multer/actions/workflows/ci.yml/badge.svg +[ci-url]: https://github.com/expressjs/multer/actions/workflows/ci.yml +[test-url]: https://coveralls.io/r/expressjs/multer?branch=main +[test-image]: https://badgen.net/coveralls/c/github/expressjs/multer/main +[npm-downloads-image]: https://badgen.net/npm/dm/multer +[npm-url]: https://npmjs.org/package/multer +[npm-version-image]: https://badgen.net/npm/v/multer +[ossf-scorecard-badge]: https://api.scorecard.dev/projects/github.com/expressjs/multer/badge +[ossf-scorecard-visualizer]: https://ossf.github.io/scorecard-visualizer/#/projects/github.com/expressjs/multer diff --git a/astro/src/content/docs/en/resources/middleware/response-time.md b/astro/src/content/docs/en/resources/middleware/response-time.md new file mode 100644 index 0000000000..a1447f733c --- /dev/null +++ b/astro/src/content/docs/en/resources/middleware/response-time.md @@ -0,0 +1,315 @@ +--- +title: Express response-time middleware +menu: resources +module: response-time +--- + +# compression + +[![NPM Version][npm-image]][npm-url] +[![NPM Downloads][downloads-image]][downloads-url] +[![Build Status][github-actions-ci-image]][github-actions-ci-url] +[![OpenSSF Scorecard Badge][ossf-scorecard-badge]][ossf-scorecard-visualizer] +[![Funding][funding-image]][funding-url] + +Node.js compression middleware. + +The following compression codings are supported: + +- deflate +- gzip +- br (brotli) + +**Note** Brotli is supported only since Node.js versions v11.7.0 and v10.16.0. + +## Install + +This is a [Node.js](https://nodejs.org/en/) module available through the +[npm registry](https://www.npmjs.com/). Installation is done using the +[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally): + +```bash +$ npm install compression +``` + +## API + +```js +var compression = require('compression'); +``` + +### compression([options]) + +Returns the compression middleware using the given `options`. The middleware +will attempt to compress response bodies for all requests that traverse through +the middleware, based on the given `options`. + +This middleware will never compress responses that include a `Cache-Control` +header with the [`no-transform` directive](https://tools.ietf.org/html/rfc7234#section-5.2.2.4), +as compressing will transform the body. + +#### Options + +`compression()` accepts these properties in the options object. In addition to +those listed below, [zlib](https://nodejs.org/api/zlib.html) options may be +passed in to the options object or +[brotli](https://nodejs.org/api/zlib.html#zlib_class_brotlioptions) options. + +##### chunkSize + +Type: `Number`
+Default: `zlib.constants.Z_DEFAULT_CHUNK`, or `16384`. + +See [Node.js documentation](https://nodejs.org/api/zlib.html#zlib_memory_usage_tuning) +regarding the usage. + +##### filter + +Type: `Function` + +A function to decide if the response should be considered for compression. +This function is called as `filter(req, res)` and is expected to return +`true` to consider the response for compression, or `false` to not compress +the response. + +The default filter function uses the [compressible](https://www.npmjs.com/package/compressible) +module to determine if `res.getHeader('Content-Type')` is compressible. + +##### level + +Type: `Number`
+Default: `zlib.constants.Z_DEFAULT_COMPRESSION`, or `-1` + +The level of zlib compression to apply to responses. A higher level will result +in better compression, but will take longer to complete. A lower level will +result in less compression, but will be much faster. + +This is an integer in the range of `0` (no compression) to `9` (maximum +compression). The special value `-1` can be used to mean the "default +compression level", which is a default compromise between speed and +compression (currently equivalent to level 6). + +- `-1` Default compression level (also `zlib.constants.Z_DEFAULT_COMPRESSION`). +- `0` No compression (also `zlib.constants.Z_NO_COMPRESSION`). +- `1` Fastest compression (also `zlib.constants.Z_BEST_SPEED`). +- `2` +- `3` +- `4` +- `5` +- `6` (currently what `zlib.constants.Z_DEFAULT_COMPRESSION` points to). +- `7` +- `8` +- `9` Best compression (also `zlib.constants.Z_BEST_COMPRESSION`). + +**Note** in the list above, `zlib` is from `zlib = require('zlib')`. + +##### memLevel + +Type: `Number`
+Default: `zlib.constants.Z_DEFAULT_MEMLEVEL`, or `8` + +This specifies how much memory should be allocated for the internal compression +state and is an integer in the range of `1` (minimum level) and `9` (maximum +level). + +See [Node.js documentation](https://nodejs.org/api/zlib.html#zlib_memory_usage_tuning) +regarding the usage. + +##### brotli + +Type: `Object` + +This specifies the options for configuring Brotli. See [Node.js documentation](https://nodejs.org/api/zlib.html#class-brotlioptions) for a complete list of available options. + +##### strategy + +Type: `Number`
+Default: `zlib.constants.Z_DEFAULT_STRATEGY` + +This is used to tune the compression algorithm. This value only affects the +compression ratio, not the correctness of the compressed output, even if it +is not set appropriately. + +- `zlib.constants.Z_DEFAULT_STRATEGY` Use for normal data. +- `zlib.constants.Z_FILTERED` Use for data produced by a filter (or predictor). + Filtered data consists mostly of small values with a somewhat random + distribution. In this case, the compression algorithm is tuned to + compress them better. The effect is to force more Huffman coding and less + string matching; it is somewhat intermediate between `zlib.constants.Z_DEFAULT_STRATEGY` + and `zlib.constants.Z_HUFFMAN_ONLY`. +- `zlib.constants.Z_FIXED` Use to prevent the use of dynamic Huffman codes, allowing + for a simpler decoder for special applications. +- `zlib.constants.Z_HUFFMAN_ONLY` Use to force Huffman encoding only (no string match). +- `zlib.constants.Z_RLE` Use to limit match distances to one (run-length encoding). + This is designed to be almost as fast as `zlib.constants.Z_HUFFMAN_ONLY`, but give + better compression for PNG image data. + +**Note** in the list above, `zlib` is from `zlib = require('zlib')`. + +##### threshold + +Type: `Number` or `String`
+Default: `1kb` + +The byte threshold for the response body size before compression is considered +for the response. This is a number of bytes or any string +accepted by the [bytes](https://www.npmjs.com/package/bytes) module. + +**Note** this is only an advisory setting; if the response size cannot be determined +at the time the response headers are written, then it is assumed the response is +_over_ the threshold. To guarantee the response size can be determined, be sure +set a `Content-Length` response header. + +##### windowBits + +Type: `Number`
+Default: `zlib.constants.Z_DEFAULT_WINDOWBITS`, or `15` + +See [Node.js documentation](https://nodejs.org/api/zlib.html#zlib_memory_usage_tuning) +regarding the usage. + +##### enforceEncoding + +Type: `String`
+Default: `identity` + +This is the default encoding to use when the client does not specify an encoding in the request's [Accept-Encoding](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding) header. + +#### .filter + +The default `filter` function. This is used to construct a custom filter +function that is an extension of the default function. + +```js +var compression = require('compression'); +var express = require('express'); + +var app = express(); + +app.use(compression({ filter: shouldCompress })); + +function shouldCompress(req, res) { + if (req.headers['x-no-compression']) { + // don't compress responses with this request header + return false; + } + + // fallback to standard filter function + return compression.filter(req, res); +} +``` + +### res.flush + +This module adds a `res.flush()` method to force the partially-compressed +response to be flushed to the client. + +## Examples + +### express + +When using this module with express, simply `app.use` the module as +high as you like. Requests that pass through the middleware will be compressed. + +```js +var compression = require('compression'); +var express = require('express'); + +var app = express(); + +// compress all responses +app.use(compression()); + +// add all routes +``` + +### Node.js HTTP server + +```js +var compression = require('compression')({ threshold: 0 }); +var http = require('http'); + +function createServer(fn) { + return http.createServer(function (req, res) { + compression(req, res, function (err) { + if (err) { + res.statusCode = err.status || 500; + res.end(err.message); + return; + } + + fn(req, res); + }); + }); +} + +var server = createServer(function (req, res) { + res.setHeader('Content-Type', 'text/plain'); + res.end('hello world!'); +}); + +server.listen(3000, () => { + console.log('> Listening at http://localhost:3000'); +}); +``` + +### Server-Sent Events + +Because of the nature of compression this module does not work out of the box +with server-sent events. To compress content, a window of the output needs to +be buffered up in order to get good compression. Typically when using server-sent +events, there are certain block of data that need to reach the client. + +You can achieve this by calling `res.flush()` when you need the data written to +actually make it to the client. + +```js +var compression = require('compression'); +var express = require('express'); + +var app = express(); + +// compress responses +app.use(compression()); + +// server-sent event stream +app.get('/events', function (req, res) { + res.setHeader('Content-Type', 'text/event-stream'); + res.setHeader('Cache-Control', 'no-cache'); + + // send a ping approx every 2 seconds + var timer = setInterval(function () { + res.write('data: ping\n\n'); + + // !!! this is the important part + res.flush(); + }, 2000); + + res.on('close', function () { + clearInterval(timer); + }); +}); +``` + +## Contributing + +The Express.js project welcomes all constructive contributions. Contributions take many forms, +from code for bug fixes and enhancements, to additions and fixes to documentation, additional +tests, triaging incoming pull requests and issues, and more! + +See the [Contributing Guide](https://github.com/expressjs/express/blob/master/Contributing.md) for more technical details on contributing. + +## License + +[MIT](LICENSE) + +[npm-image]: https://badgen.net/npm/v/compression +[npm-url]: https://npmjs.org/package/compression +[downloads-image]: https://badgen.net/npm/dm/compression +[downloads-url]: https://npmcharts.com/compare/compression?minimal=true +[github-actions-ci-image]: https://badgen.net/github/checks/expressjs/compression/master?label=CI +[github-actions-ci-url]: https://github.com/expressjs/compression/actions?query=workflow%3Aci +[ossf-scorecard-badge]: https://api.scorecard.dev/projects/github.com/expressjs/compression/badge +[ossf-scorecard-visualizer]: https://ossf.github.io/scorecard-visualizer/#/projects/github.com/expressjs/compression +[funding-url]: https://opencollective.com/express +[funding-image]: https://badgen.net/badge/icon/sponsor/pink?icon=github&label=Open%20Collective diff --git a/astro/src/content/docs/en/resources/middleware/serve-favicon.md b/astro/src/content/docs/en/resources/middleware/serve-favicon.md new file mode 100644 index 0000000000..f002640e47 --- /dev/null +++ b/astro/src/content/docs/en/resources/middleware/serve-favicon.md @@ -0,0 +1,157 @@ +--- +title: Express serve-favicon middleware +menu: resources +module: serve-favicon +--- + +# serve-index + +[![NPM Version][npm-image]][npm-url] +[![NPM Downloads][downloads-image]][downloads-url] +[![Linux Build Status][ci-image]][ci-url] +[![Windows Build][appveyor-image]][appveyor-url] +[![Coverage Status][coveralls-image]][coveralls-url] + +Serves pages that contain directory listings for a given path. + +## Install + +This is a [Node.js](https://nodejs.org/en/) module available through the +[npm registry](https://www.npmjs.com/). Installation is done using the +[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally): + +```sh +$ npm install serve-index +``` + +## API + +```js +var serveIndex = require('serve-index'); +``` + +### serveIndex(path, options) + +Returns middlware that serves an index of the directory in the given `path`. + +The `path` is based off the `req.url` value, so a `req.url` of `'/some/dir` +with a `path` of `'public'` will look at `'public/some/dir'`. If you are using +something like `express`, you can change the URL "base" with `app.use` (see +the express example). + +#### Options + +Serve index accepts these properties in the options object. + +##### filter + +Apply this filter function to files. Defaults to `false`. The `filter` function +is called for each file, with the signature `filter(filename, index, files, dir)` +where `filename` is the name of the file, `index` is the array index, `files` is +the array of files and `dir` is the absolute path the file is located (and thus, +the directory the listing is for). + +##### hidden + +Display hidden (dot) files. Defaults to `false`. + +##### icons + +Display icons. Defaults to `false`. + +##### stylesheet + +Optional path to a CSS stylesheet. Defaults to a built-in stylesheet. + +##### template + +Optional path to an HTML template or a function that will render a HTML +string. Defaults to a built-in template. + +When given a string, the string is used as a file path to load and then the +following tokens are replaced in templates: + +- `{directory}` with the name of the directory. +- `{files}` with the HTML of an unordered list of file links. +- `{linked-path}` with the HTML of a link to the directory. +- `{style}` with the specified stylesheet and embedded images. + +When given as a function, the function is called as `template(locals, callback)` +and it needs to invoke `callback(error, htmlString)`. The following are the +provided locals: + +- `directory` is the directory being displayed (where `/` is the root). +- `displayIcons` is a Boolean for if icons should be rendered or not. +- `fileList` is a sorted array of files in the directory. The array contains + objects with the following properties: + - `name` is the relative name for the file. + - `stat` is a `fs.Stats` object for the file. +- `path` is the full filesystem path to `directory`. +- `style` is the default stylesheet or the contents of the `stylesheet` option. +- `viewName` is the view name provided by the `view` option. + +##### view + +Display mode. `tiles` and `details` are available. Defaults to `tiles`. + +## Examples + +### Serve directory indexes with vanilla node.js http server + +```js +var finalhandler = require('finalhandler'); +var http = require('http'); +var serveIndex = require('serve-index'); +var serveStatic = require('serve-static'); + +// Serve directory indexes for public/ftp folder (with icons) +var index = serveIndex('public/ftp', { icons: true }); + +// Serve up public/ftp folder files +var serve = serveStatic('public/ftp'); + +// Create server +var server = http.createServer(function onRequest(req, res) { + var done = finalhandler(req, res); + serve(req, res, function onNext(err) { + if (err) return done(err); + index(req, res, done); + }); +}); + +// Listen +server.listen(3000); +``` + +### Serve directory indexes with express + +```js +var express = require('express'); +var serveIndex = require('serve-index'); + +var app = express(); + +// Serve URLs like /ftp/thing as public/ftp/thing +// The express.static serves the file contents +// The serveIndex is this module serving the directory +app.use('/ftp', express.static('public/ftp'), serveIndex('public/ftp', { icons: true })); + +// Listen +app.listen(3000); +``` + +## License + +[MIT](LICENSE). The [Silk](http://www.famfamfam.com/lab/icons/silk/) icons +are created by/copyright of [FAMFAMFAM](http://www.famfamfam.com/). + +[appveyor-image]: https://img.shields.io/appveyor/ci/dougwilson/serve-index/master.svg?label=windows +[appveyor-url]: https://ci.appveyor.com/project/dougwilson/serve-index +[ci-image]: https://badgen.net/github/checks/expressjs/serve-index/master?label=ci +[ci-url]: https://github.com/expressjs/serve-index/actions/workflows/ci.yml +[coveralls-image]: https://img.shields.io/coveralls/expressjs/serve-index/master.svg +[coveralls-url]: https://coveralls.io/r/expressjs/serve-index?branch=master +[downloads-image]: https://img.shields.io/npm/dm/serve-index.svg +[downloads-url]: https://npmjs.org/package/serve-index +[npm-image]: https://img.shields.io/npm/v/serve-index.svg +[npm-url]: https://npmjs.org/package/serve-index diff --git a/astro/src/content/docs/en/resources/middleware/serve-index.md b/astro/src/content/docs/en/resources/middleware/serve-index.md new file mode 100644 index 0000000000..79c50e53ff --- /dev/null +++ b/astro/src/content/docs/en/resources/middleware/serve-index.md @@ -0,0 +1,157 @@ +--- +title: Express serve-index middleware +menu: resources +module: serve-index +--- + +# serve-index + +[![NPM Version][npm-image]][npm-url] +[![NPM Downloads][downloads-image]][downloads-url] +[![Linux Build Status][ci-image]][ci-url] +[![Windows Build][appveyor-image]][appveyor-url] +[![Coverage Status][coveralls-image]][coveralls-url] + +Serves pages that contain directory listings for a given path. + +## Install + +This is a [Node.js](https://nodejs.org/en/) module available through the +[npm registry](https://www.npmjs.com/). Installation is done using the +[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally): + +```sh +$ npm install serve-index +``` + +## API + +```js +var serveIndex = require('serve-index'); +``` + +### serveIndex(path, options) + +Returns middlware that serves an index of the directory in the given `path`. + +The `path` is based off the `req.url` value, so a `req.url` of `'/some/dir` +with a `path` of `'public'` will look at `'public/some/dir'`. If you are using +something like `express`, you can change the URL "base" with `app.use` (see +the express example). + +#### Options + +Serve index accepts these properties in the options object. + +##### filter + +Apply this filter function to files. Defaults to `false`. The `filter` function +is called for each file, with the signature `filter(filename, index, files, dir)` +where `filename` is the name of the file, `index` is the array index, `files` is +the array of files and `dir` is the absolute path the file is located (and thus, +the directory the listing is for). + +##### hidden + +Display hidden (dot) files. Defaults to `false`. + +##### icons + +Display icons. Defaults to `false`. + +##### stylesheet + +Optional path to a CSS stylesheet. Defaults to a built-in stylesheet. + +##### template + +Optional path to an HTML template or a function that will render a HTML +string. Defaults to a built-in template. + +When given a string, the string is used as a file path to load and then the +following tokens are replaced in templates: + +- `{directory}` with the name of the directory. +- `{files}` with the HTML of an unordered list of file links. +- `{linked-path}` with the HTML of a link to the directory. +- `{style}` with the specified stylesheet and embedded images. + +When given as a function, the function is called as `template(locals, callback)` +and it needs to invoke `callback(error, htmlString)`. The following are the +provided locals: + +- `directory` is the directory being displayed (where `/` is the root). +- `displayIcons` is a Boolean for if icons should be rendered or not. +- `fileList` is a sorted array of files in the directory. The array contains + objects with the following properties: + - `name` is the relative name for the file. + - `stat` is a `fs.Stats` object for the file. +- `path` is the full filesystem path to `directory`. +- `style` is the default stylesheet or the contents of the `stylesheet` option. +- `viewName` is the view name provided by the `view` option. + +##### view + +Display mode. `tiles` and `details` are available. Defaults to `tiles`. + +## Examples + +### Serve directory indexes with vanilla node.js http server + +```js +var finalhandler = require('finalhandler'); +var http = require('http'); +var serveIndex = require('serve-index'); +var serveStatic = require('serve-static'); + +// Serve directory indexes for public/ftp folder (with icons) +var index = serveIndex('public/ftp', { icons: true }); + +// Serve up public/ftp folder files +var serve = serveStatic('public/ftp'); + +// Create server +var server = http.createServer(function onRequest(req, res) { + var done = finalhandler(req, res); + serve(req, res, function onNext(err) { + if (err) return done(err); + index(req, res, done); + }); +}); + +// Listen +server.listen(3000); +``` + +### Serve directory indexes with express + +```js +var express = require('express'); +var serveIndex = require('serve-index'); + +var app = express(); + +// Serve URLs like /ftp/thing as public/ftp/thing +// The express.static serves the file contents +// The serveIndex is this module serving the directory +app.use('/ftp', express.static('public/ftp'), serveIndex('public/ftp', { icons: true })); + +// Listen +app.listen(3000); +``` + +## License + +[MIT](LICENSE). The [Silk](http://www.famfamfam.com/lab/icons/silk/) icons +are created by/copyright of [FAMFAMFAM](http://www.famfamfam.com/). + +[appveyor-image]: https://img.shields.io/appveyor/ci/dougwilson/serve-index/master.svg?label=windows +[appveyor-url]: https://ci.appveyor.com/project/dougwilson/serve-index +[ci-image]: https://badgen.net/github/checks/expressjs/serve-index/master?label=ci +[ci-url]: https://github.com/expressjs/serve-index/actions/workflows/ci.yml +[coveralls-image]: https://img.shields.io/coveralls/expressjs/serve-index/master.svg +[coveralls-url]: https://coveralls.io/r/expressjs/serve-index?branch=master +[downloads-image]: https://img.shields.io/npm/dm/serve-index.svg +[downloads-url]: https://npmjs.org/package/serve-index +[npm-image]: https://img.shields.io/npm/v/serve-index.svg +[npm-url]: https://npmjs.org/package/serve-index diff --git a/astro/src/content/docs/en/resources/middleware/serve-static.md b/astro/src/content/docs/en/resources/middleware/serve-static.md new file mode 100644 index 0000000000..895f9dc69c --- /dev/null +++ b/astro/src/content/docs/en/resources/middleware/serve-static.md @@ -0,0 +1,261 @@ +--- +title: Express serve-static middleware +menu: resources +module: serve-static +--- + +# serve-static + +[![NPM Version][npm-version-image]][npm-url] +[![NPM Downloads][npm-downloads-image]][npm-url] +[![CI][github-actions-ci-image]][github-actions-ci-url] +[![Test Coverage][coveralls-image]][coveralls-url] + +## Install + +This is a [Node.js](https://nodejs.org/en/) module available through the +[npm registry](https://www.npmjs.com/). Installation is done using the +[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally): + +```sh +$ npm install serve-static +``` + +## API + +```js +const serveStatic = require('serve-static'); +``` + +### serveStatic(root, options) + +Create a new middleware function to serve files from within a given root +directory. The file to serve will be determined by combining `req.url` +with the provided root directory. When a file is not found, instead of +sending a 404 response, this module will instead call `next()` to move on +to the next middleware, allowing for stacking and fall-backs. + +#### Options + +##### acceptRanges + +Enable or disable accepting ranged requests, defaults to true. +Disabling this will not send `Accept-Ranges` and ignore the contents +of the `Range` request header. + +##### cacheControl + +Enable or disable setting `Cache-Control` response header, defaults to +true. Disabling this will ignore the `immutable` and `maxAge` options. + +##### dotfiles + +Set how "dotfiles" are treated when encountered. A dotfile is a file +or directory that begins with a dot ("."). Note this check is done on +the path itself without checking if the path actually exists on the +disk. If `root` is specified, only the dotfiles above the root are +checked (i.e. the root itself can be within a dotfile when set +to "deny"). + +- `'allow'` No special treatment for dotfiles. +- `'deny'` Deny a request for a dotfile and 403/`next()`. +- `'ignore'` Pretend like the dotfile does not exist and 404/`next()`. + +The default value is `'ignore'`. + +##### etag + +Enable or disable etag generation, defaults to true. + +##### extensions + +Set file extension fallbacks. When set, if a file is not found, the given +extensions will be added to the file name and search for. The first that +exists will be served. Example: `['html', 'htm']`. + +The default value is `false`. + +##### fallthrough + +Set the middleware to have client errors fall-through as just unhandled +requests, otherwise forward a client error. The difference is that client +errors like a bad request or a request to a non-existent file will cause +this middleware to simply `next()` to your next middleware when this value +is `true`. When this value is `false`, these errors (even 404s), will invoke +`next(err)`. + +Typically `true` is desired such that multiple physical directories can be +mapped to the same web address or for routes to fill in non-existent files. + +The value `false` can be used if this middleware is mounted at a path that +is designed to be strictly a single file system directory, which allows for +short-circuiting 404s for less overhead. This middleware will also reply to +all methods. + +The default value is `true`. + +##### immutable + +Enable or disable the `immutable` directive in the `Cache-Control` response +header, defaults to `false`. If set to `true`, the `maxAge` option should +also be specified to enable caching. The `immutable` directive will prevent +supported clients from making conditional requests during the life of the +`maxAge` option to check if the file has changed. + +##### index + +By default this module will send "index.html" files in response to a request +on a directory. To disable this set `false` or to supply a new index pass a +string or an array in preferred order. + +##### lastModified + +Enable or disable `Last-Modified` header, defaults to true. Uses the file +system's last modified value. + +##### maxAge + +Provide a max-age in milliseconds for http caching, defaults to 0. This +can also be a string accepted by the [ms](https://www.npmjs.org/package/ms#readme) +module. + +##### redirect + +Redirect to trailing "/" when the pathname is a dir. Defaults to `true`. + +##### setHeaders + +Function to set custom headers on response. Alterations to the headers need to +occur synchronously. The function is called as `fn(res, path, stat)`, where +the arguments are: + +- `res` the response object +- `path` the file path that is being sent +- `stat` the stat object of the file that is being sent + +## Examples + +### Serve files with vanilla node.js http server + +```js +const finalhandler = require('finalhandler'); +const http = require('http'); +const serveStatic = require('serve-static'); + +// Serve up public/ftp folder +const serve = serveStatic('public/ftp', { index: ['index.html', 'index.htm'] }); + +// Create server +const server = http.createServer((req, res) => { + serve(req, res, finalhandler(req, res)); +}); + +// Listen +server.listen(3000); +``` + +### Serve all files as downloads + +```js +const contentDisposition = require('content-disposition'); +const finalhandler = require('finalhandler'); +const http = require('http'); +const serveStatic = require('serve-static'); + +// Serve up public/ftp folder +const serve = serveStatic('public/ftp', { + index: false, + setHeaders: setHeaders, +}); + +// Set header to force download +function setHeaders(res, path) { + res.setHeader('Content-Disposition', contentDisposition(path)); +} + +// Create server +const server = http.createServer((req, res) => { + serve(req, res, finalhandler(req, res)); +}); + +// Listen +server.listen(3000); +``` + +### Serving using express + +#### Simple + +This is a simple example of using Express. + +```js +const express = require('express'); +const serveStatic = require('serve-static'); + +const app = express(); + +app.use(serveStatic('public/ftp', { index: ['default.html', 'default.htm'] })); +app.listen(3000); +``` + +#### Multiple roots + +This example shows a simple way to search through multiple directories. +Files are searched for in `public-optimized/` first, then `public/` second +as a fallback. + +```js +const express = require('express'); +const path = require('path'); +const serveStatic = require('serve-static'); + +const app = express(); + +app.use(serveStatic(path.join(__dirname, 'public-optimized'))); +app.use(serveStatic(path.join(__dirname, 'public'))); +app.listen(3000); +``` + +#### Different settings for paths + +This example shows how to set a different max age depending on the served +file. In this example, HTML files are not cached, while everything else +is for 1 day. + +```js +const express = require('express'); +const path = require('path'); +const serveStatic = require('serve-static'); + +const app = express(); + +app.use( + serveStatic(path.join(__dirname, 'public'), { + maxAge: '1d', + setHeaders: setCustomCacheControl, + }) +); + +app.listen(3000); + +function setCustomCacheControl(res, file) { + if (path.extname(file) === '.html') { + // Custom Cache-Control for HTML files + res.setHeader('Cache-Control', 'public, max-age=0'); + } +} +``` + +## License + +[MIT](LICENSE) + +[coveralls-image]: https://badgen.net/coveralls/c/github/expressjs/serve-static/master +[coveralls-url]: https://coveralls.io/r/expressjs/serve-static?branch=master +[github-actions-ci-image]: https://badgen.net/github/checks/expressjs/serve-static/master?label=linux +[github-actions-ci-url]: https://github.com/expressjs/serve-static/actions/workflows/ci.yml +[node-image]: https://badgen.net/npm/node/serve-static +[node-url]: https://nodejs.org/en/download/ +[npm-downloads-image]: https://badgen.net/npm/dm/serve-static +[npm-url]: https://npmjs.org/package/serve-static +[npm-version-image]: https://badgen.net/npm/v/serve-static diff --git a/astro/src/content/docs/en/resources/middleware/session.md b/astro/src/content/docs/en/resources/middleware/session.md new file mode 100644 index 0000000000..74559b032e --- /dev/null +++ b/astro/src/content/docs/en/resources/middleware/session.md @@ -0,0 +1,1047 @@ +--- +title: Express session middleware +menu: resources +module: session +--- + +# express-session + +[![NPM Version][npm-version-image]][npm-url] +[![NPM Downloads][npm-downloads-image]][node-url] +[![Build Status][ci-image]][ci-url] +[![Test Coverage][coveralls-image]][coveralls-url] + +## Installation + +This is a [Node.js](https://nodejs.org/en/) module available through the +[npm registry](https://www.npmjs.com/). Installation is done using the +[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally): + +```sh +$ npm install express-session +``` + +## API + +```js +var session = require('express-session'); +``` + +### session(options) + +Create a session middleware with the given `options`. + +**Note** Session data is _not_ saved in the cookie itself, just the session ID. +Session data is stored server-side. + +**Note** Since version 1.5.0, the [`cookie-parser` middleware](https://www.npmjs.com/package/cookie-parser) +no longer needs to be used for this module to work. This module now directly reads +and writes cookies on `req`/`res`. Using `cookie-parser` may result in issues +if the `secret` is not the same between this module and `cookie-parser`. + +**Warning** The default server-side session storage, `MemoryStore`, is _purposely_ +not designed for a production environment. It will leak memory under most +conditions, does not scale past a single process, and is meant for debugging and +developing. + +For a list of stores, see [compatible session stores](#compatible-session-stores). + +#### Options + +`express-session` accepts these properties in the options object. + +##### cookie + +Settings object for the session ID cookie. The default value is +`{ path: '/', httpOnly: true, secure: false, maxAge: null }`. + +The following are options that can be set in this object. + +##### cookie.domain + +Specifies the value for the `Domain` `Set-Cookie` attribute. By default, no domain +is set, and most clients will consider the cookie to apply to only the current +domain. + +##### cookie.expires + +Specifies the `Date` object to be the value for the `Expires` `Set-Cookie` attribute. +By default, no expiration is set, and most clients will consider this a +"non-persistent cookie" and will delete it on a condition like exiting a web browser +application. + +**Note** If both `expires` and `maxAge` are set in the options, then the last one +defined in the object is what is used. + +**Note** The `expires` option should not be set directly; instead only use the `maxAge` +option. + +##### cookie.httpOnly + +Specifies the `boolean` value for the `HttpOnly` `Set-Cookie` attribute. When truthy, +the `HttpOnly` attribute is set, otherwise it is not. By default, the `HttpOnly` +attribute is set. + +**Note** be careful when setting this to `true`, as compliant clients will not allow +client-side JavaScript to see the cookie in `document.cookie`. + +##### cookie.maxAge + +Specifies the `number` (in milliseconds) to use when calculating the `Expires` +`Set-Cookie` attribute. This is done by taking the current server time and adding +`maxAge` milliseconds to the value to calculate an `Expires` datetime. By default, +no maximum age is set. + +**Note** If both `expires` and `maxAge` are set in the options, then the last one +defined in the object is what is used. + +##### cookie.partitioned + +Specifies the `boolean` value for the [`Partitioned` `Set-Cookie`](rfc-cutler-httpbis-partitioned-cookies) +attribute. When truthy, the `Partitioned` attribute is set, otherwise it is not. +By default, the `Partitioned` attribute is not set. + +**Note** This is an attribute that has not yet been fully standardized, and may +change in the future. This also means many clients may ignore this attribute until +they understand it. + +More information about can be found in [the proposal](https://github.com/privacycg/CHIPS). + +##### cookie.path + +Specifies the value for the `Path` `Set-Cookie`. By default, this is set to `'/'`, which +is the root path of the domain. + +##### cookie.priority + +Specifies the `string` to be the value for the [`Priority` `Set-Cookie` attribute][rfc-west-cookie-priority-00-4.1]. + +- `'low'` will set the `Priority` attribute to `Low`. +- `'medium'` will set the `Priority` attribute to `Medium`, the default priority when not set. +- `'high'` will set the `Priority` attribute to `High`. + +More information about the different priority levels can be found in +[the specification][rfc-west-cookie-priority-00-4.1]. + +**Note** This is an attribute that has not yet been fully standardized, and may change in the future. +This also means many clients may ignore this attribute until they understand it. + +##### cookie.sameSite + +Specifies the `boolean` or `string` to be the value for the `SameSite` `Set-Cookie` attribute. +By default, this is `false`. + +- `true` will set the `SameSite` attribute to `Strict` for strict same site enforcement. +- `false` will not set the `SameSite` attribute. +- `'lax'` will set the `SameSite` attribute to `Lax` for lax same site enforcement. +- `'none'` will set the `SameSite` attribute to `None` for an explicit cross-site cookie. +- `'strict'` will set the `SameSite` attribute to `Strict` for strict same site enforcement. + +More information about the different enforcement levels can be found in +[the specification][rfc-6265bis-03-4.1.2.7]. + +**Note** This is an attribute that has not yet been fully standardized, and may change in +the future. This also means many clients may ignore this attribute until they understand it. + +**Note** There is a [draft spec](https://tools.ietf.org/html/draft-west-cookie-incrementalism-01) +that requires that the `Secure` attribute be set to `true` when the `SameSite` attribute has been +set to `'none'`. Some web browsers or other clients may be adopting this specification. + +##### cookie.secure + +Specifies the `boolean` value for the `Secure` `Set-Cookie` attribute. When truthy, +the `Secure` attribute is set, otherwise it is not. By default, the `Secure` +attribute is not set. + +**Note** be careful when setting this to `true`, as compliant clients will not send +the cookie back to the server in the future if the browser does not have an HTTPS +connection. + +Please note that `secure: true` is a **recommended** option. However, it requires +an https-enabled website, i.e., HTTPS is necessary for secure cookies. If `secure` +is set, and you access your site over HTTP, the cookie will not be set. If you +have your node.js behind a proxy and are using `secure: true`, you need to set +"trust proxy" in express: + +```js +var app = express(); +app.set('trust proxy', 1); // trust first proxy +app.use( + session({ + secret: 'keyboard cat', + resave: false, + saveUninitialized: true, + cookie: { secure: true }, + }) +); +``` + +For using secure cookies in production, but allowing for testing in development, +the following is an example of enabling this setup based on `NODE_ENV` in express: + +```js +var app = express(); +var sess = { + secret: 'keyboard cat', + cookie: {}, +}; + +if (app.get('env') === 'production') { + app.set('trust proxy', 1); // trust first proxy + sess.cookie.secure = true; // serve secure cookies +} + +app.use(session(sess)); +``` + +The `cookie.secure` option can also be set to the special value `'auto'` to have +this setting automatically match the determined security of the connection. Be +careful when using this setting if the site is available both as HTTP and HTTPS, +as once the cookie is set on HTTPS, it will no longer be visible over HTTP. This +is useful when the Express `"trust proxy"` setting is properly setup to simplify +development vs production configuration. + +##### genid + +Function to call to generate a new session ID. Provide a function that returns +a string that will be used as a session ID. The function is given `req` as the +first argument if you want to use some value attached to `req` when generating +the ID. + +The default value is a function which uses the `uid-safe` library to generate IDs. + +**NOTE** be careful to generate unique IDs so your sessions do not conflict. + +```js +app.use( + session({ + genid: function (req) { + return genuuid(); // use UUIDs for session IDs + }, + secret: 'keyboard cat', + }) +); +``` + +##### name + +The name of the session ID cookie to set in the response (and read from in the +request). + +The default value is `'connect.sid'`. + +**Note** if you have multiple apps running on the same hostname (this is just +the name, i.e. `localhost` or `127.0.0.1`; different schemes and ports do not +name a different hostname), then you need to separate the session cookies from +each other. The simplest method is to simply set different `name`s per app. + +##### proxy + +Trust the reverse proxy when setting secure cookies (via the "X-Forwarded-Proto" +header). + +The default value is `undefined`. + +- `true` The "X-Forwarded-Proto" header will be used. +- `false` All headers are ignored and the connection is considered secure only + if there is a direct TLS/SSL connection. +- `undefined` Uses the "trust proxy" setting from express + +##### resave + +Forces the session to be saved back to the session store, even if the session +was never modified during the request. Depending on your store this may be +necessary, but it can also create race conditions where a client makes two +parallel requests to your server and changes made to the session in one +request may get overwritten when the other request ends, even if it made no +changes (this behavior also depends on what store you're using). + +The default value is `true`, but using the default has been deprecated, +as the default will change in the future. Please research into this setting +and choose what is appropriate to your use-case. Typically, you'll want +`false`. + +How do I know if this is necessary for my store? The best way to know is to +check with your store if it implements the `touch` method. If it does, then +you can safely set `resave: false`. If it does not implement the `touch` +method and your store sets an expiration date on stored sessions, then you +likely need `resave: true`. + +##### rolling + +Force the session identifier cookie to be set on every response. The expiration +is reset to the original [`maxAge`](#cookiemaxage), resetting the expiration +countdown. + +The default value is `false`. + +With this enabled, the session identifier cookie will expire in +[`maxAge`](#cookiemaxage) since the last response was sent instead of in +[`maxAge`](#cookiemaxage) since the session was last modified by the server. + +This is typically used in conjunction with short, non-session-length +[`maxAge`](#cookiemaxage) values to provide a quick timeout of the session data +with reduced potential of it occurring during on going server interactions. + +**Note** When this option is set to `true` but the `saveUninitialized` option is +set to `false`, the cookie will not be set on a response with an uninitialized +session. This option only modifies the behavior when an existing session was +loaded for the request. + +##### saveUninitialized + +Forces a session that is "uninitialized" to be saved to the store. A session is +uninitialized when it is new but not modified. Choosing `false` is useful for +implementing login sessions, reducing server storage usage, or complying with +laws that require permission before setting a cookie. Choosing `false` will also +help with race conditions where a client makes multiple parallel requests +without a session. + +The default value is `true`, but using the default has been deprecated, as the +default will change in the future. Please research into this setting and +choose what is appropriate to your use-case. + +**Note** if you are using Session in conjunction with PassportJS, Passport +will add an empty Passport object to the session for use after a user is +authenticated, which will be treated as a modification to the session, causing +it to be saved. _This has been fixed in PassportJS 0.3.0_ + +##### secret + +**Required option** + +This is the secret used to sign the session ID cookie. The secret can be any type +of value that is supported by Node.js `crypto.createHmac` (like a string or a +`Buffer`). This can be either a single secret, or an array of multiple secrets. If +an array of secrets is provided, only the first element will be used to sign the +session ID cookie, while all the elements will be considered when verifying the +signature in requests. The secret itself should be not easily parsed by a human and +would best be a random set of characters. A best practice may include: + +- The use of environment variables to store the secret, ensuring the secret itself + does not exist in your repository. +- Periodic updates of the secret, while ensuring the previous secret is in the + array. + +Using a secret that cannot be guessed will reduce the ability to hijack a session to +only guessing the session ID (as determined by the `genid` option). + +Changing the secret value will invalidate all existing sessions. In order to rotate +the secret without invalidating sessions, provide an array of secrets, with the new +secret as first element of the array, and including previous secrets as the later +elements. + +**Note** HMAC-256 is used to sign the session ID. For this reason, the secret should +contain at least 32 bytes of entropy. + +##### store + +The session store instance, defaults to a new `MemoryStore` instance. + +##### unset + +Control the result of unsetting `req.session` (through `delete`, setting to `null`, +etc.). + +The default value is `'keep'`. + +- `'destroy'` The session will be destroyed (deleted) when the response ends. +- `'keep'` The session in the store will be kept, but modifications made during + the request are ignored and not saved. + +### req.session + +To store or access session data, simply use the request property `req.session`, +which is (generally) serialized as JSON by the store, so nested objects +are typically fine. For example below is a user-specific view counter: + +```js +// Use the session middleware +app.use(session({ secret: 'keyboard cat', cookie: { maxAge: 60000 } })); + +// Access the session as req.session +app.get('/', function (req, res, next) { + if (req.session.views) { + req.session.views++; + res.setHeader('Content-Type', 'text/html'); + res.write('

views: ' + req.session.views + '

'); + res.write('

expires in: ' + req.session.cookie.maxAge / 1000 + 's

'); + res.end(); + } else { + req.session.views = 1; + res.end('welcome to the session demo. refresh!'); + } +}); +``` + +#### Session.regenerate(callback) + +To regenerate the session simply invoke the method. Once complete, +a new SID and `Session` instance will be initialized at `req.session` +and the `callback` will be invoked. + +```js +req.session.regenerate(function (err) { + // will have a new session here +}); +``` + +#### Session.destroy(callback) + +Destroys the session and will unset the `req.session` property. +Once complete, the `callback` will be invoked. + +```js +req.session.destroy(function (err) { + // cannot access session here +}); +``` + +#### Session.reload(callback) + +Reloads the session data from the store and re-populates the +`req.session` object. Once complete, the `callback` will be invoked. + +```js +req.session.reload(function (err) { + // session updated +}); +``` + +#### Session.save(callback) + +Save the session back to the store, replacing the contents on the store with the +contents in memory (though a store may do something else--consult the store's +documentation for exact behavior). + +This method is automatically called at the end of the HTTP response if the +session data has been altered (though this behavior can be altered with various +options in the middleware constructor). Because of this, typically this method +does not need to be called. + +There are some cases where it is useful to call this method, for example, +redirects, long-lived requests or in WebSockets. + +```js +req.session.save(function (err) { + // session saved +}); +``` + +#### Session.touch() + +Updates the `.maxAge` property. Typically this is +not necessary to call, as the session middleware does this for you. + +### req.session.id + +Each session has a unique ID associated with it. This property is an +alias of [`req.sessionID`](#reqsessionid-1) and cannot be modified. +It has been added to make the session ID accessible from the `session` +object. + +### req.session.cookie + +Each session has a unique cookie object accompany it. This allows +you to alter the session cookie per visitor. For example we can +set `req.session.cookie.expires` to `false` to enable the cookie +to remain for only the duration of the user-agent. + +#### Cookie.maxAge + +Alternatively `req.session.cookie.maxAge` will return the time +remaining in milliseconds, which we may also re-assign a new value +to adjust the `.expires` property appropriately. The following +are essentially equivalent + +```js +var hour = 3600000; +req.session.cookie.expires = new Date(Date.now() + hour); +req.session.cookie.maxAge = hour; +``` + +For example when `maxAge` is set to `60000` (one minute), and 30 seconds +has elapsed it will return `30000` until the current request has completed, +at which time `req.session.touch()` is called to reset +`req.session.cookie.maxAge` to its original value. + +```js +req.session.cookie.maxAge; // => 30000 +``` + +#### Cookie.originalMaxAge + +The `req.session.cookie.originalMaxAge` property returns the original +`maxAge` (time-to-live), in milliseconds, of the session cookie. + +### req.sessionID + +To get the ID of the loaded session, access the request property +`req.sessionID`. This is simply a read-only value set when a session +is loaded/created. + +## Session Store Implementation + +Every session store _must_ be an `EventEmitter` and implement specific +methods. The following methods are the list of **required**, **recommended**, +and **optional**. + +- Required methods are ones that this module will always call on the store. +- Recommended methods are ones that this module will call on the store if + available. +- Optional methods are ones this module does not call at all, but helps + present uniform stores to users. + +For an example implementation view the [connect-redis](http://github.com/visionmedia/connect-redis) repo. + +### store.all(callback) + +**Optional** + +This optional method is used to get all sessions in the store as an array. The +`callback` should be called as `callback(error, sessions)`. + +### store.destroy(sid, callback) + +**Required** + +This required method is used to destroy/delete a session from the store given +a session ID (`sid`). The `callback` should be called as `callback(error)` once +the session is destroyed. + +### store.clear(callback) + +**Optional** + +This optional method is used to delete all sessions from the store. The +`callback` should be called as `callback(error)` once the store is cleared. + +### store.length(callback) + +**Optional** + +This optional method is used to get the count of all sessions in the store. +The `callback` should be called as `callback(error, len)`. + +### store.get(sid, callback) + +**Required** + +This required method is used to get a session from the store given a session +ID (`sid`). The `callback` should be called as `callback(error, session)`. + +The `session` argument should be a session if found, otherwise `null` or +`undefined` if the session was not found (and there was no error). A special +case is made when `error.code === 'ENOENT'` to act like `callback(null, null)`. + +### store.set(sid, session, callback) + +**Required** + +This required method is used to upsert a session into the store given a +session ID (`sid`) and session (`session`) object. The callback should be +called as `callback(error)` once the session has been set in the store. + +### store.touch(sid, session, callback) + +**Recommended** + +This recommended method is used to "touch" a given session given a +session ID (`sid`) and session (`session`) object. The `callback` should be +called as `callback(error)` once the session has been touched. + +This is primarily used when the store will automatically delete idle sessions +and this method is used to signal to the store the given session is active, +potentially resetting the idle timer. + +## Compatible Session Stores + +The following modules implement a session store that is compatible with this +module. Please make a PR to add additional modules :) + +[![★][aerospike-session-store-image] aerospike-session-store][aerospike-session-store-url] A session store using [Aerospike](http://www.aerospike.com/). + +[aerospike-session-store-url]: https://www.npmjs.com/package/aerospike-session-store +[aerospike-session-store-image]: https://badgen.net/github/stars/aerospike/aerospike-session-store-expressjs?label=%E2%98%85 + +[![★][better-sqlite3-session-store-image] better-sqlite3-session-store][better-sqlite3-session-store-url] A session store based on [better-sqlite3](https://github.com/JoshuaWise/better-sqlite3). + +[better-sqlite3-session-store-url]: https://www.npmjs.com/package/better-sqlite3-session-store +[better-sqlite3-session-store-image]: https://badgen.net/github/stars/timdaub/better-sqlite3-session-store?label=%E2%98%85 + +[![★][cassandra-store-image] cassandra-store][cassandra-store-url] An Apache Cassandra-based session store. + +[cassandra-store-url]: https://www.npmjs.com/package/cassandra-store +[cassandra-store-image]: https://badgen.net/github/stars/webcc/cassandra-store?label=%E2%98%85 + +[![★][cluster-store-image] cluster-store][cluster-store-url] A wrapper for using in-process / embedded +stores - such as SQLite (via knex), leveldb, files, or memory - with node cluster (desirable for Raspberry Pi 2 +and other multi-core embedded devices). + +[cluster-store-url]: https://www.npmjs.com/package/cluster-store +[cluster-store-image]: https://badgen.net/github/stars/coolaj86/cluster-store?label=%E2%98%85 + +[![★][connect-arango-image] connect-arango][connect-arango-url] An ArangoDB-based session store. + +[connect-arango-url]: https://www.npmjs.com/package/connect-arango +[connect-arango-image]: https://badgen.net/github/stars/AlexanderArvidsson/connect-arango?label=%E2%98%85 + +[![★][connect-azuretables-image] connect-azuretables][connect-azuretables-url] An [Azure Table Storage](https://azure.microsoft.com/en-gb/services/storage/tables/)-based session store. + +[connect-azuretables-url]: https://www.npmjs.com/package/connect-azuretables +[connect-azuretables-image]: https://badgen.net/github/stars/mike-goodwin/connect-azuretables?label=%E2%98%85 + +[![★][connect-cloudant-store-image] connect-cloudant-store][connect-cloudant-store-url] An [IBM Cloudant](https://cloudant.com/)-based session store. + +[connect-cloudant-store-url]: https://www.npmjs.com/package/connect-cloudant-store +[connect-cloudant-store-image]: https://badgen.net/github/stars/adriantanasa/connect-cloudant-store?label=%E2%98%85 + +[![★][connect-cosmosdb-image] connect-cosmosdb][connect-cosmosdb-url] An Azure [Cosmos DB](https://azure.microsoft.com/en-us/products/cosmos-db/)-based session store. + +[connect-cosmosdb-url]: https://www.npmjs.com/package/connect-cosmosdb +[connect-cosmosdb-image]: https://badgen.net/github/stars/thekillingspree/connect-cosmosdb?label=%E2%98%85 + +[![★][connect-couchbase-image] connect-couchbase][connect-couchbase-url] A [couchbase](http://www.couchbase.com/)-based session store. + +[connect-couchbase-url]: https://www.npmjs.com/package/connect-couchbase +[connect-couchbase-image]: https://badgen.net/github/stars/christophermina/connect-couchbase?label=%E2%98%85 + +[![★][connect-datacache-image] connect-datacache][connect-datacache-url] An [IBM Bluemix Data Cache](http://www.ibm.com/cloud-computing/bluemix/)-based session store. + +[connect-datacache-url]: https://www.npmjs.com/package/connect-datacache +[connect-datacache-image]: https://badgen.net/github/stars/adriantanasa/connect-datacache?label=%E2%98%85 + +[![★][@google-cloud/connect-datastore-image] @google-cloud/connect-datastore][@google-cloud/connect-datastore-url] A [Google Cloud Datastore](https://cloud.google.com/datastore/docs/concepts/overview)-based session store. + +[@google-cloud/connect-datastore-url]: https://www.npmjs.com/package/@google-cloud/connect-datastore +[@google-cloud/connect-datastore-image]: https://badgen.net/github/stars/GoogleCloudPlatform/cloud-datastore-session-node?label=%E2%98%85 + +[![★][connect-db2-image] connect-db2][connect-db2-url] An IBM DB2-based session store built using [ibm_db](https://www.npmjs.com/package/ibm_db) module. + +[connect-db2-url]: https://www.npmjs.com/package/connect-db2 +[connect-db2-image]: https://badgen.net/github/stars/wallali/connect-db2?label=%E2%98%85 + +[![★][connect-dynamodb-image] connect-dynamodb][connect-dynamodb-url] A DynamoDB-based session store. + +[connect-dynamodb-url]: https://www.npmjs.com/package/connect-dynamodb +[connect-dynamodb-image]: https://badgen.net/github/stars/ca98am79/connect-dynamodb?label=%E2%98%85 + +[![★][@google-cloud/connect-firestore-image] @google-cloud/connect-firestore][@google-cloud/connect-firestore-url] A [Google Cloud Firestore](https://cloud.google.com/firestore/docs/overview)-based session store. + +[@google-cloud/connect-firestore-url]: https://www.npmjs.com/package/@google-cloud/connect-firestore +[@google-cloud/connect-firestore-image]: https://badgen.net/github/stars/googleapis/nodejs-firestore-session?label=%E2%98%85 + +[![★][connect-hazelcast-image] connect-hazelcast][connect-hazelcast-url] Hazelcast session store for Connect and Express. + +[connect-hazelcast-url]: https://www.npmjs.com/package/connect-hazelcast +[connect-hazelcast-image]: https://badgen.net/github/stars/huseyinbabal/connect-hazelcast?label=%E2%98%85 + +[![★][connect-loki-image] connect-loki][connect-loki-url] A Loki.js-based session store. + +[connect-loki-url]: https://www.npmjs.com/package/connect-loki +[connect-loki-image]: https://badgen.net/github/stars/Requarks/connect-loki?label=%E2%98%85 + +[![★][connect-lowdb-image] connect-lowdb][connect-lowdb-url] A lowdb-based session store. + +[connect-lowdb-url]: https://www.npmjs.com/package/connect-lowdb +[connect-lowdb-image]: https://badgen.net/github/stars/travishorn/connect-lowdb?label=%E2%98%85 + +[![★][connect-memcached-image] connect-memcached][connect-memcached-url] A memcached-based session store. + +[connect-memcached-url]: https://www.npmjs.com/package/connect-memcached +[connect-memcached-image]: https://badgen.net/github/stars/balor/connect-memcached?label=%E2%98%85 + +[![★][connect-memjs-image] connect-memjs][connect-memjs-url] A memcached-based session store using +[memjs](https://www.npmjs.com/package/memjs) as the memcached client. + +[connect-memjs-url]: https://www.npmjs.com/package/connect-memjs +[connect-memjs-image]: https://badgen.net/github/stars/liamdon/connect-memjs?label=%E2%98%85 + +[![★][connect-ml-image] connect-ml][connect-ml-url] A MarkLogic Server-based session store. + +[connect-ml-url]: https://www.npmjs.com/package/connect-ml +[connect-ml-image]: https://badgen.net/github/stars/bluetorch/connect-ml?label=%E2%98%85 + +[![★][connect-monetdb-image] connect-monetdb][connect-monetdb-url] A MonetDB-based session store. + +[connect-monetdb-url]: https://www.npmjs.com/package/connect-monetdb +[connect-monetdb-image]: https://badgen.net/github/stars/MonetDB/npm-connect-monetdb?label=%E2%98%85 + +[![★][connect-mongo-image] connect-mongo][connect-mongo-url] A MongoDB-based session store. + +[connect-mongo-url]: https://www.npmjs.com/package/connect-mongo +[connect-mongo-image]: https://badgen.net/github/stars/kcbanner/connect-mongo?label=%E2%98%85 + +[![★][connect-mongodb-session-image] connect-mongodb-session][connect-mongodb-session-url] Lightweight MongoDB-based session store built and maintained by MongoDB. + +[connect-mongodb-session-url]: https://www.npmjs.com/package/connect-mongodb-session +[connect-mongodb-session-image]: https://badgen.net/github/stars/mongodb-js/connect-mongodb-session?label=%E2%98%85 + +[![★][connect-mssql-v2-image] connect-mssql-v2][connect-mssql-v2-url] A Microsoft SQL Server-based session store based on [connect-mssql](https://www.npmjs.com/package/connect-mssql). + +[connect-mssql-v2-url]: https://www.npmjs.com/package/connect-mssql-v2 +[connect-mssql-v2-image]: https://badgen.net/github/stars/jluboff/connect-mssql-v2?label=%E2%98%85 + +[![★][connect-neo4j-image] connect-neo4j][connect-neo4j-url] A [Neo4j](https://neo4j.com)-based session store. + +[connect-neo4j-url]: https://www.npmjs.com/package/connect-neo4j +[connect-neo4j-image]: https://badgen.net/github/stars/MaxAndersson/connect-neo4j?label=%E2%98%85 + +[![★][connect-ottoman-image] connect-ottoman][connect-ottoman-url] A [couchbase ottoman](http://www.couchbase.com/)-based session store. + +[connect-ottoman-url]: https://www.npmjs.com/package/connect-ottoman +[connect-ottoman-image]: https://badgen.net/github/stars/noiissyboy/connect-ottoman?label=%E2%98%85 + +[![★][connect-pg-simple-image] connect-pg-simple][connect-pg-simple-url] A PostgreSQL-based session store. + +[connect-pg-simple-url]: https://www.npmjs.com/package/connect-pg-simple +[connect-pg-simple-image]: https://badgen.net/github/stars/voxpelli/node-connect-pg-simple?label=%E2%98%85 + +[![★][connect-redis-image] connect-redis][connect-redis-url] A Redis-based session store. + +[connect-redis-url]: https://www.npmjs.com/package/connect-redis +[connect-redis-image]: https://badgen.net/github/stars/tj/connect-redis?label=%E2%98%85 + +[![★][connect-session-firebase-image] connect-session-firebase][connect-session-firebase-url] A session store based on the [Firebase Realtime Database](https://firebase.google.com/docs/database/) + +[connect-session-firebase-url]: https://www.npmjs.com/package/connect-session-firebase +[connect-session-firebase-image]: https://badgen.net/github/stars/benweier/connect-session-firebase?label=%E2%98%85 + +[![★][connect-session-knex-image] connect-session-knex][connect-session-knex-url] A session store using +[Knex.js](http://knexjs.org/), which is a SQL query builder for PostgreSQL, MySQL, MariaDB, SQLite3, and Oracle. + +[connect-session-knex-url]: https://www.npmjs.com/package/connect-session-knex +[connect-session-knex-image]: https://badgen.net/github/stars/llambda/connect-session-knex?label=%E2%98%85 + +[![★][connect-session-sequelize-image] connect-session-sequelize][connect-session-sequelize-url] A session store using +[Sequelize.js](http://sequelizejs.com/), which is a Node.js / io.js ORM for PostgreSQL, MySQL, SQLite and MSSQL. + +[connect-session-sequelize-url]: https://www.npmjs.com/package/connect-session-sequelize +[connect-session-sequelize-image]: https://badgen.net/github/stars/mweibel/connect-session-sequelize?label=%E2%98%85 + +[![★][connect-sqlite3-image] connect-sqlite3][connect-sqlite3-url] A [SQLite3](https://github.com/mapbox/node-sqlite3) session store modeled after the TJ's `connect-redis` store. + +[connect-sqlite3-url]: https://www.npmjs.com/package/connect-sqlite3 +[connect-sqlite3-image]: https://badgen.net/github/stars/rawberg/connect-sqlite3?label=%E2%98%85 + +[![★][connect-typeorm-image] connect-typeorm][connect-typeorm-url] A [TypeORM](https://github.com/typeorm/typeorm)-based session store. + +[connect-typeorm-url]: https://www.npmjs.com/package/connect-typeorm +[connect-typeorm-image]: https://badgen.net/github/stars/makepost/connect-typeorm?label=%E2%98%85 + +[![★][couchdb-expression-image] couchdb-expression][couchdb-expression-url] A [CouchDB](https://couchdb.apache.org/)-based session store. + +[couchdb-expression-url]: https://www.npmjs.com/package/couchdb-expression +[couchdb-expression-image]: https://badgen.net/github/stars/tkshnwesper/couchdb-expression?label=%E2%98%85 + +[![★][dynamodb-store-image] dynamodb-store][dynamodb-store-url] A DynamoDB-based session store. + +[dynamodb-store-url]: https://www.npmjs.com/package/dynamodb-store +[dynamodb-store-image]: https://badgen.net/github/stars/rafaelrpinto/dynamodb-store?label=%E2%98%85 + +[![★][dynamodb-store-v3-image] dynamodb-store-v3][dynamodb-store-v3-url] Implementation of a session store using DynamoDB backed by the [AWS SDK for JavaScript v3](https://github.com/aws/aws-sdk-js-v3). + +[dynamodb-store-v3-url]: https://www.npmjs.com/package/dynamodb-store-v3 +[dynamodb-store-v3-image]: https://badgen.net/github/stars/FryDay/dynamodb-store-v3?label=%E2%98%85 + +[![★][express-etcd-image] express-etcd][express-etcd-url] An [etcd](https://github.com/stianeikeland/node-etcd) based session store. + +[express-etcd-url]: https://www.npmjs.com/package/express-etcd +[express-etcd-image]: https://badgen.net/github/stars/gildean/express-etcd?label=%E2%98%85 + +[![★][express-mysql-session-image] express-mysql-session][express-mysql-session-url] A session store using native +[MySQL](https://www.mysql.com/) via the [node-mysql](https://github.com/felixge/node-mysql) module. + +[express-mysql-session-url]: https://www.npmjs.com/package/express-mysql-session +[express-mysql-session-image]: https://badgen.net/github/stars/chill117/express-mysql-session?label=%E2%98%85 + +[![★][express-nedb-session-image] express-nedb-session][express-nedb-session-url] A NeDB-based session store. + +[express-nedb-session-url]: https://www.npmjs.com/package/express-nedb-session +[express-nedb-session-image]: https://badgen.net/github/stars/louischatriot/express-nedb-session?label=%E2%98%85 + +[![★][express-oracle-session-image] express-oracle-session][express-oracle-session-url] A session store using native +[oracle](https://www.oracle.com/) via the [node-oracledb](https://www.npmjs.com/package/oracledb) module. + +[express-oracle-session-url]: https://www.npmjs.com/package/express-oracle-session +[express-oracle-session-image]: https://badgen.net/github/stars/slumber86/express-oracle-session?label=%E2%98%85 + +[![★][express-session-cache-manager-image] express-session-cache-manager][express-session-cache-manager-url] +A store that implements [cache-manager](https://www.npmjs.com/package/cache-manager), which supports +a [variety of storage types](https://www.npmjs.com/package/cache-manager#store-engines). + +[express-session-cache-manager-url]: https://www.npmjs.com/package/express-session-cache-manager +[express-session-cache-manager-image]: https://badgen.net/github/stars/theogravity/express-session-cache-manager?label=%E2%98%85 + +[![★][express-session-etcd3-image] express-session-etcd3][express-session-etcd3-url] An [etcd3](https://github.com/mixer/etcd3) based session store. + +[express-session-etcd3-url]: https://www.npmjs.com/package/express-session-etcd3 +[express-session-etcd3-image]: https://badgen.net/github/stars/willgm/express-session-etcd3?label=%E2%98%85 + +[![★][express-session-level-image] express-session-level][express-session-level-url] A [LevelDB](https://github.com/Level/levelup) based session store. + +[express-session-level-url]: https://www.npmjs.com/package/express-session-level +[express-session-level-image]: https://badgen.net/github/stars/tgohn/express-session-level?label=%E2%98%85 + +[![★][express-session-rsdb-image] express-session-rsdb][express-session-rsdb-url] Session store based on Rocket-Store: A very simple, super fast and yet powerful, flat file database. + +[express-session-rsdb-url]: https://www.npmjs.com/package/express-session-rsdb +[express-session-rsdb-image]: https://badgen.net/github/stars/paragi/express-session-rsdb?label=%E2%98%85 + +[![★][express-sessions-image] express-sessions][express-sessions-url] A session store supporting both MongoDB and Redis. + +[express-sessions-url]: https://www.npmjs.com/package/express-sessions +[express-sessions-image]: https://badgen.net/github/stars/konteck/express-sessions?label=%E2%98%85 + +[![★][firestore-store-image] firestore-store][firestore-store-url] A [Firestore](https://github.com/hendrysadrak/firestore-store)-based session store. + +[firestore-store-url]: https://www.npmjs.com/package/firestore-store +[firestore-store-image]: https://badgen.net/github/stars/hendrysadrak/firestore-store?label=%E2%98%85 + +[![★][fortune-session-image] fortune-session][fortune-session-url] A [Fortune.js](https://github.com/fortunejs/fortune) +based session store. Supports all backends supported by Fortune (MongoDB, Redis, Postgres, NeDB). + +[fortune-session-url]: https://www.npmjs.com/package/fortune-session +[fortune-session-image]: https://badgen.net/github/stars/aliceklipper/fortune-session?label=%E2%98%85 + +[![★][hazelcast-store-image] hazelcast-store][hazelcast-store-url] A Hazelcast-based session store built on the [Hazelcast Node Client](https://www.npmjs.com/package/hazelcast-client). + +[hazelcast-store-url]: https://www.npmjs.com/package/hazelcast-store +[hazelcast-store-image]: https://badgen.net/github/stars/jackspaniel/hazelcast-store?label=%E2%98%85 + +[![★][level-session-store-image] level-session-store][level-session-store-url] A LevelDB-based session store. + +[level-session-store-url]: https://www.npmjs.com/package/level-session-store +[level-session-store-image]: https://badgen.net/github/stars/toddself/level-session-store?label=%E2%98%85 + +[![★][lowdb-session-store-image] lowdb-session-store][lowdb-session-store-url] A [lowdb](https://www.npmjs.com/package/lowdb)-based session store. + +[lowdb-session-store-url]: https://www.npmjs.com/package/lowdb-session-store +[lowdb-session-store-image]: https://badgen.net/github/stars/fhellwig/lowdb-session-store?label=%E2%98%85 + +[![★][medea-session-store-image] medea-session-store][medea-session-store-url] A Medea-based session store. + +[medea-session-store-url]: https://www.npmjs.com/package/medea-session-store +[medea-session-store-image]: https://badgen.net/github/stars/BenjaminVadant/medea-session-store?label=%E2%98%85 + +[![★][memorystore-image] memorystore][memorystore-url] A memory session store made for production. + +[memorystore-url]: https://www.npmjs.com/package/memorystore +[memorystore-image]: https://badgen.net/github/stars/roccomuso/memorystore?label=%E2%98%85 + +[![★][mssql-session-store-image] mssql-session-store][mssql-session-store-url] A SQL Server-based session store. + +[mssql-session-store-url]: https://www.npmjs.com/package/mssql-session-store +[mssql-session-store-image]: https://badgen.net/github/stars/jwathen/mssql-session-store?label=%E2%98%85 + +[![★][nedb-session-store-image] nedb-session-store][nedb-session-store-url] An alternate NeDB-based (either in-memory or file-persisted) session store. + +[nedb-session-store-url]: https://www.npmjs.com/package/nedb-session-store +[nedb-session-store-image]: https://badgen.net/github/stars/JamesMGreene/nedb-session-store?label=%E2%98%85 + +[![★][@quixo3/prisma-session-store-image] @quixo3/prisma-session-store][@quixo3/prisma-session-store-url] A session store for the [Prisma Framework](https://www.prisma.io). + +[@quixo3/prisma-session-store-url]: https://www.npmjs.com/package/@quixo3/prisma-session-store +[@quixo3/prisma-session-store-image]: https://badgen.net/github/stars/kleydon/prisma-session-store?label=%E2%98%85 + +[![★][restsession-image] restsession][restsession-url] Store sessions utilizing a RESTful API + +[restsession-url]: https://www.npmjs.com/package/restsession +[restsession-image]: https://badgen.net/github/stars/jankal/restsession?label=%E2%98%85 + +[![★][sequelstore-connect-image] sequelstore-connect][sequelstore-connect-url] A session store using [Sequelize.js](http://sequelizejs.com/). + +[sequelstore-connect-url]: https://www.npmjs.com/package/sequelstore-connect +[sequelstore-connect-image]: https://badgen.net/github/stars/MattMcFarland/sequelstore-connect?label=%E2%98%85 + +[![★][session-file-store-image] session-file-store][session-file-store-url] A file system-based session store. + +[session-file-store-url]: https://www.npmjs.com/package/session-file-store +[session-file-store-image]: https://badgen.net/github/stars/valery-barysok/session-file-store?label=%E2%98%85 + +[![★][session-pouchdb-store-image] session-pouchdb-store][session-pouchdb-store-url] Session store for PouchDB / CouchDB. Accepts embedded, custom, or remote PouchDB instance and realtime synchronization. + +[session-pouchdb-store-url]: https://www.npmjs.com/package/session-pouchdb-store +[session-pouchdb-store-image]: https://badgen.net/github/stars/solzimer/session-pouchdb-store?label=%E2%98%85 + +[![★][@cyclic.sh/session-store-image] @cyclic.sh/session-store][@cyclic.sh/session-store-url] A DynamoDB-based session store for [Cyclic.sh](https://www.cyclic.sh/) apps. + +[@cyclic.sh/session-store-url]: https://www.npmjs.com/package/@cyclic.sh/session-store +[@cyclic.sh/session-store-image]: https://badgen.net/github/stars/cyclic-software/session-store?label=%E2%98%85 + +[![★][@databunker/session-store-image] @databunker/session-store][@databunker/session-store-url] A [Databunker](https://databunker.org/)-based encrypted session store. + +[@databunker/session-store-url]: https://www.npmjs.com/package/@databunker/session-store +[@databunker/session-store-image]: https://badgen.net/github/stars/securitybunker/databunker-session-store?label=%E2%98%85 + +[![★][sessionstore-image] sessionstore][sessionstore-url] A session store that works with various databases. + +[sessionstore-url]: https://www.npmjs.com/package/sessionstore +[sessionstore-image]: https://badgen.net/github/stars/adrai/sessionstore?label=%E2%98%85 + +[![★][tch-nedb-session-image] tch-nedb-session][tch-nedb-session-url] A file system session store based on NeDB. + +[tch-nedb-session-url]: https://www.npmjs.com/package/tch-nedb-session +[tch-nedb-session-image]: https://badgen.net/github/stars/tomaschyly/NeDBSession?label=%E2%98%85 + +## Examples + +### View counter + +A simple example using `express-session` to store page views for a user. + +```js +var express = require('express'); +var parseurl = require('parseurl'); +var session = require('express-session'); + +var app = express(); + +app.use( + session({ + secret: 'keyboard cat', + resave: false, + saveUninitialized: true, + }) +); + +app.use(function (req, res, next) { + if (!req.session.views) { + req.session.views = {}; + } + + // get the url pathname + var pathname = parseurl(req).pathname; + + // count the views + req.session.views[pathname] = (req.session.views[pathname] || 0) + 1; + + next(); +}); + +app.get('/foo', function (req, res, next) { + res.send('you viewed this page ' + req.session.views['/foo'] + ' times'); +}); + +app.get('/bar', function (req, res, next) { + res.send('you viewed this page ' + req.session.views['/bar'] + ' times'); +}); + +app.listen(3000); +``` + +### User login + +A simple example using `express-session` to keep a user log in session. + +```js +var escapeHtml = require('escape-html'); +var express = require('express'); +var session = require('express-session'); + +var app = express(); + +app.use( + session({ + secret: 'keyboard cat', + resave: false, + saveUninitialized: true, + }) +); + +// middleware to test if authenticated +function isAuthenticated(req, res, next) { + if (req.session.user) next(); + else next('route'); +} + +app.get('/', isAuthenticated, function (req, res) { + // this is only called when there is an authentication user due to isAuthenticated + res.send('hello, ' + escapeHtml(req.session.user) + '!' + ' Logout'); +}); + +app.get('/', function (req, res) { + res.send( + '
' + + 'Username:
' + + 'Password:
' + + '
' + ); +}); + +app.post('/login', express.urlencoded({ extended: false }), function (req, res) { + // login logic to validate req.body.user and req.body.pass + // would be implemented here. for this example any combo works + + // regenerate the session, which is good practice to help + // guard against forms of session fixation + req.session.regenerate(function (err) { + if (err) next(err); + + // store user information in session, typically a user id + req.session.user = req.body.user; + + // save the session before redirection to ensure page + // load does not happen before session is saved + req.session.save(function (err) { + if (err) return next(err); + res.redirect('/'); + }); + }); +}); + +app.get('/logout', function (req, res, next) { + // logout logic + + // clear the user from the session object and save. + // this will ensure that re-using the old session id + // does not have a logged in user + req.session.user = null; + req.session.save(function (err) { + if (err) next(err); + + // regenerate the session, which is good practice to help + // guard against forms of session fixation + req.session.regenerate(function (err) { + if (err) next(err); + res.redirect('/'); + }); + }); +}); + +app.listen(3000); +``` + +## Debugging + +This module uses the [debug](https://www.npmjs.com/package/debug) module +internally to log information about session operations. + +To see all the internal logs, set the `DEBUG` environment variable to +`express-session` when launching your app (`npm start`, in this example): + +```sh +$ DEBUG=express-session npm start +``` + +On Windows, use the corresponding command; + +```sh +> set DEBUG=express-session & npm start +``` + +## License + +[MIT](LICENSE) + +[rfc-6265bis-03-4.1.2.7]: https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.7 +[rfc-cutler-httpbis-partitioned-cookies]: https://tools.ietf.org/html/draft-cutler-httpbis-partitioned-cookies/ +[rfc-west-cookie-priority-00-4.1]: https://tools.ietf.org/html/draft-west-cookie-priority-00#section-4.1 +[ci-image]: https://badgen.net/github/checks/expressjs/session/master?label=ci +[ci-url]: https://github.com/expressjs/session/actions?query=workflow%3Aci +[coveralls-image]: https://badgen.net/coveralls/c/github/expressjs/session/master +[coveralls-url]: https://coveralls.io/r/expressjs/session?branch=master +[node-url]: https://nodejs.org/en/download +[npm-downloads-image]: https://badgen.net/npm/dm/express-session +[npm-url]: https://npmjs.org/package/express-session +[npm-version-image]: https://badgen.net/npm/v/express-session diff --git a/astro/src/content/docs/en/resources/middleware/timeout.md b/astro/src/content/docs/en/resources/middleware/timeout.md new file mode 100644 index 0000000000..4ab4b826e1 --- /dev/null +++ b/astro/src/content/docs/en/resources/middleware/timeout.md @@ -0,0 +1,177 @@ +--- +title: Express timeout middleware +menu: resources +module: timeout +--- + +# connect-timeout + +[![NPM Version][npm-image]][npm-url] +[![NPM Downloads][downloads-image]][downloads-url] +[![Build Status][travis-image]][travis-url] +[![Test Coverage][coveralls-image]][coveralls-url] + +Times out a request in the Connect/Express application framework. + +## Install + +This is a [Node.js](https://nodejs.org/en/) module available through the +[npm registry](https://www.npmjs.com/). Installation is done using the +[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally): + +```sh +$ npm install connect-timeout +``` + +## API + +**NOTE** This module is not recommend as a "top-level" middleware (i.e. +`app.use(timeout('5s'))`) unless you take precautions to halt your own +middleware processing. See [as top-level middleware](#as-top-level-middleware) +for how to use as a top-level middleware. + +While the library will emit a 'timeout' event when requests exceed the given +timeout, node will continue processing the slow request until it terminates. +Slow requests will continue to use CPU and memory, even if you are returning +a HTTP response in the timeout callback. For better control over CPU/memory, +you may need to find the events that are taking a long time (3rd party HTTP +requests, disk I/O, database calls) and find a way to cancel them, and/or +close the attached sockets. + +### timeout(time, [options]) + +Returns middleware that times out in `time` milliseconds. `time` can also +be a string accepted by the [ms](https://www.npmjs.org/package/ms#readme) +module. On timeout, `req` will emit `"timeout"`. + +#### Options + +The `timeout` function takes an optional `options` object that may contain +any of the following keys: + +##### respond + +Controls if this module will "respond" in the form of forwarding an error. +If `true`, the timeout error is passed to `next()` so that you may customize +the response behavior. This error has a `.timeout` property as well as +`.status == 503`. This defaults to `true`. + +### req.clearTimeout() + +Clears the timeout on the request. The timeout is completely removed and +will not fire for this request in the future. + +### req.timedout + +`true` if timeout fired; `false` otherwise. + +## Examples + +### as top-level middleware + +Because of the way middleware processing works, once this module +passes the request to the next middleware (which it has to do in order +for you to do work), it can no longer stop the flow, so you must take +care to check if the request has timedout before you continue to act +on the request. + +```javascript +var bodyParser = require('body-parser'); +var cookieParser = require('cookie-parser'); +var express = require('express'); +var timeout = require('connect-timeout'); + +// example of using this top-level; note the use of haltOnTimedout +// after every middleware; it will stop the request flow on a timeout +var app = express(); +app.use(timeout('5s')); +app.use(bodyParser()); +app.use(haltOnTimedout); +app.use(cookieParser()); +app.use(haltOnTimedout); + +// Add your routes here, etc. + +function haltOnTimedout(req, res, next) { + if (!req.timedout) next(); +} + +app.listen(3000); +``` + +### express 3.x + +```javascript +var express = require('express'); +var bodyParser = require('body-parser'); +var timeout = require('connect-timeout'); + +var app = express(); +app.post('/save', timeout('5s'), bodyParser.json(), haltOnTimedout, function (req, res, next) { + savePost(req.body, function (err, id) { + if (err) return next(err); + if (req.timedout) return; + res.send('saved as id ' + id); + }); +}); + +function haltOnTimedout(req, res, next) { + if (!req.timedout) next(); +} + +function savePost(post, cb) { + setTimeout( + function () { + cb(null, (Math.random() * 40000) >>> 0); + }, + (Math.random() * 7000) >>> 0 + ); +} + +app.listen(3000); +``` + +### connect + +```javascript +var bodyParser = require('body-parser'); +var connect = require('connect'); +var timeout = require('connect-timeout'); + +var app = connect(); +app.use('/save', timeout('5s'), bodyParser.json(), haltOnTimedout, function (req, res, next) { + savePost(req.body, function (err, id) { + if (err) return next(err); + if (req.timedout) return; + res.send('saved as id ' + id); + }); +}); + +function haltOnTimedout(req, res, next) { + if (!req.timedout) next(); +} + +function savePost(post, cb) { + setTimeout( + function () { + cb(null, (Math.random() * 40000) >>> 0); + }, + (Math.random() * 7000) >>> 0 + ); +} + +app.listen(3000); +``` + +## License + +[MIT](LICENSE) + +[npm-image]: https://img.shields.io/npm/v/connect-timeout.svg +[npm-url]: https://npmjs.org/package/connect-timeout +[travis-image]: https://img.shields.io/travis/expressjs/timeout/master.svg +[travis-url]: https://travis-ci.org/expressjs/timeout +[coveralls-image]: https://img.shields.io/coveralls/expressjs/timeout/master.svg +[coveralls-url]: https://coveralls.io/r/expressjs/timeout?branch=master +[downloads-image]: https://img.shields.io/npm/dm/connect-timeout.svg +[downloads-url]: https://npmjs.org/package/connect-timeout diff --git a/astro/src/content/docs/en/resources/middleware/vhost.md b/astro/src/content/docs/en/resources/middleware/vhost.md new file mode 100644 index 0000000000..fc3c9cfbcc --- /dev/null +++ b/astro/src/content/docs/en/resources/middleware/vhost.md @@ -0,0 +1,175 @@ +--- +title: Express vhost middleware +menu: resources +module: vhost +--- + +# vhost + +[![NPM Version][npm-image]][npm-url] +[![NPM Downloads][downloads-image]][downloads-url] +[![Build Status][github-actions-ci-image]][github-actions-ci-url] +[![Test Coverage][coveralls-image]][coveralls-url] + +## Install + +```sh +$ npm install vhost +``` + +## API + +```js +var vhost = require('vhost'); +``` + +### vhost(hostname, handle) + +Create a new middleware function to hand off request to `handle` when the incoming +host for the request matches `hostname`. The function is called as +`handle(req, res, next)`, like a standard middleware. + +`hostname` can be a string or a RegExp object. When `hostname` is a string it can +contain `*` to match 1 or more characters in that section of the hostname. When +`hostname` is a RegExp, it will be forced to case-insensitive (since hostnames are) +and will be forced to match based on the start and end of the hostname. + +When host is matched and the request is sent down to a vhost handler, the `req.vhost` +property will be populated with an object. This object will have numeric properties +corresponding to each wildcard (or capture group if RegExp object provided) and the +`hostname` that was matched. + +```js +var connect = require('connect'); +var vhost = require('vhost'); +var app = connect(); + +app.use( + vhost('*.*.example.com', function handle(req, res, next) { + // for match of "foo.bar.example.com:8080" against "*.*.example.com": + console.dir(req.vhost.host); // => 'foo.bar.example.com:8080' + console.dir(req.vhost.hostname); // => 'foo.bar.example.com' + console.dir(req.vhost.length); // => 2 + console.dir(req.vhost[0]); // => 'foo' + console.dir(req.vhost[1]); // => 'bar' + }) +); +``` + +## Examples + +### using with connect for static serving + +```js +var connect = require('connect'); +var serveStatic = require('serve-static'); +var vhost = require('vhost'); + +var mailapp = connect(); + +// add middlewares to mailapp for mail.example.com + +// create app to serve static files on subdomain +var staticapp = connect(); +staticapp.use(serveStatic('public')); + +// create main app +var app = connect(); + +// add vhost routing to main app for mail +app.use(vhost('mail.example.com', mailapp)); + +// route static assets for "assets-*" subdomain to get +// around max host connections limit on browsers +app.use(vhost('assets-*.example.com', staticapp)); + +// add middlewares and main usage to app + +app.listen(3000); +``` + +### using with connect for user subdomains + +```js +var connect = require('connect'); +var serveStatic = require('serve-static'); +var vhost = require('vhost'); + +var mainapp = connect(); + +// add middlewares to mainapp for the main web site + +// create app that will server user content from public/{username}/ +var userapp = connect(); + +userapp.use(function (req, res, next) { + var username = req.vhost[0]; // username is the "*" + + // pretend request was for /{username}/* for file serving + req.originalUrl = req.url; + req.url = '/' + username + req.url; + + next(); +}); +userapp.use(serveStatic('public')); + +// create main app +var app = connect(); + +// add vhost routing for main app +app.use(vhost('userpages.local', mainapp)); +app.use(vhost('www.userpages.local', mainapp)); + +// listen on all subdomains for user pages +app.use(vhost('*.userpages.local', userapp)); + +app.listen(3000); +``` + +### using with any generic request handler + +```js +var connect = require('connect'); +var http = require('http'); +var vhost = require('vhost'); + +// create main app +var app = connect(); + +app.use( + vhost('mail.example.com', function (req, res) { + // handle req + res belonging to mail.example.com + res.setHeader('Content-Type', 'text/plain'); + res.end('hello from mail!'); + }) +); + +// an external api server in any framework +var httpServer = http.createServer(function (req, res) { + res.setHeader('Content-Type', 'text/plain'); + res.end('hello from the api!'); +}); + +app.use( + vhost('api.example.com', function (req, res) { + // handle req + res belonging to api.example.com + // pass the request to a standard Node.js HTTP server + httpServer.emit('request', req, res); + }) +); + +app.listen(3000); +``` + +## License + +[MIT](LICENSE) + +[npm-image]: https://img.shields.io/npm/v/vhost.svg +[npm-url]: https://npmjs.org/package/vhost +[coveralls-image]: https://img.shields.io/coveralls/expressjs/vhost/master.svg +[coveralls-url]: https://coveralls.io/r/expressjs/vhost +[downloads-image]: https://img.shields.io/npm/dm/vhost.svg +[downloads-url]: https://npmjs.org/package/vhost +[github-actions-ci-image]: https://img.shields.io/github/actions/workflow/status/expressjs/vhost/ci.yml?branch=master&label=ci +[github-actions-ci-url]: https://github.com/expressjs/vhost/actions/workflows/ci.yml diff --git a/astro/src/content/docs/en/resources/utils.md b/astro/src/content/docs/en/resources/utils.md new file mode 100644 index 0000000000..27256d6a0b --- /dev/null +++ b/astro/src/content/docs/en/resources/utils.md @@ -0,0 +1,24 @@ +--- +title: Express utilities +description: Discover utility modules related to Express.js and Node.js, including tools for cookies, CSRF protection, URL parsing, routing, and more to enhance your applications. +menu: resources +order: 4 +--- + +## Express utility functions + +The [pillarjs](https://github.com/pillarjs) GitHub organization contains a number of modules +for utility functions that may be generally useful. + +| Utility modules | Description | +| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [cookies](https://www.npmjs.com/package/cookies) | Get and set HTTP(S) cookies that can be signed to prevent tampering, using Keygrip. Can be used with the Node.js HTTP library or as Express middleware. | +| [csrf](https://www.npmjs.com/package/csrf) | Contains the logic behind CSRF token creation and verification. Use this module to create custom CSRF middleware. | +| [finalhandler](https://www.npmjs.com/package/finalhandler) | Function to invoke as the final step to respond to HTTP request. | +| [parseurl](https://www.npmjs.com/package/parseurl) | Parse a URL with caching. | +| [path-to-regexp](https://www.npmjs.com/package/path-to-regexp) | Turn an Express-style path string such as ``/user/:name` into a regular expression. | +| [resolve-path](https://www.npmjs.com/package/resolve-path) | Resolves a relative path against a root path with validation. | +| [router](https://www.npmjs.com/package/router) | Simple middleware-style router. | +| [send](https://www.npmjs.com/package/send) | Library for streaming files as a HTTP response, with support for partial responses (ranges), conditional-GET negotiation, and granular events. | + +For additional low-level HTTP-related modules, see [jshttp](http://jshttp.github.io/). diff --git a/astro/src/content/docs/en/starter/basic-routing.md b/astro/src/content/docs/en/starter/basic-routing.md new file mode 100755 index 0000000000..5039415d21 --- /dev/null +++ b/astro/src/content/docs/en/starter/basic-routing.md @@ -0,0 +1,65 @@ +--- +title: Express basic routing +description: Learn the fundamentals of routing in Express.js applications, including how to define routes, handle HTTP methods, and create route handlers for your web server. +menu: starter +order: 4 +--- + +# Basic routing + +_Routing_ refers to determining how an application responds to a client request to a particular endpoint, which is a URI (or path) and a specific HTTP request method (GET, POST, and so on). + +Each route can have one or more handler functions, which are executed when the route is matched. + +Route definition takes the following structure: + +```js +app.METHOD(PATH, HANDLER); +``` + +Where: + +- `app` is an instance of `express`. +- `METHOD` is an [HTTP request method](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Methods), in lowercase. +- `PATH` is a path on the server. +- `HANDLER` is the function executed when the route is matched. + +
+This tutorial assumes that an instance of `express` named `app` is created and the server is running. If you are not familiar with creating an app and starting it, see the [Hello world example](/{{ page.lang }}/starter/hello-world.html). +
+ +The following examples illustrate defining simple routes. + +Respond with `Hello World!` on the homepage: + +```js +app.get('/', (req, res) => { + res.send('Hello World!'); +}); +``` + +Respond to a POST request on the root route (`/`), the application's home page: + +```js +app.post('/', (req, res) => { + res.send('Got a POST request'); +}); +``` + +Respond to a PUT request to the `/user` route: + +```js +app.put('/user', (req, res) => { + res.send('Got a PUT request at /user'); +}); +``` + +Respond to a DELETE request to the `/user` route: + +```js +app.delete('/user', (req, res) => { + res.send('Got a DELETE request at /user'); +}); +``` + +For more details about routing, see the [routing guide](/{{ page.lang }}/guide/routing.html). diff --git a/astro/src/content/docs/en/starter/examples.md b/astro/src/content/docs/en/starter/examples.md new file mode 100755 index 0000000000..5d4f468f6f --- /dev/null +++ b/astro/src/content/docs/en/starter/examples.md @@ -0,0 +1,18 @@ +--- +title: Express examples +description: Explore a collection of Express.js application examples covering various use cases, integrations, and advanced configurations to help you learn and build your projects. +menu: starter +order: 6 +--- + +{% capture examples %}{% include readmes/express-master/examples.md %}{% endcapture %} +{{ examples | replace: "](.", "](https://github.com/expressjs/express/tree/master/examples" }} + +## Additional examples + +These are some additional examples with more extensive integrations. + +{% include community-caveat.html %} + +- [prisma-fullstack](https://github.com/prisma/prisma-examples/tree/latest/pulse/fullstack-simple-chat) - Fullstack app with Express and Next.js using [Prisma](https://www.npmjs.com/package/prisma) as an ORM +- [prisma-rest-api-ts](https://github.com/prisma/prisma-examples/tree/latest/orm/express) - REST API with Express in TypeScript using [Prisma](https://www.npmjs.com/package/prisma) as an ORM diff --git a/astro/src/content/docs/en/starter/faq.md b/astro/src/content/docs/en/starter/faq.md new file mode 100755 index 0000000000..9b50f95235 --- /dev/null +++ b/astro/src/content/docs/en/starter/faq.md @@ -0,0 +1,94 @@ +--- +title: Express FAQ +description: Find answers to frequently asked questions about Express.js, including topics on application structure, models, authentication, template engines, error handling, and more. +menu: starter +order: 7 +--- + +# FAQ + +## How should I structure my application? + +There is no definitive answer to this question. The answer depends +on the scale of your application and the team that is involved. To be as +flexible as possible, Express makes no assumptions in terms of structure. + +Routes and other application-specific logic can live in as many files +as you wish, in any directory structure you prefer. View the following +examples for inspiration: + +- [Route listings](https://github.com/expressjs/express/blob/4.13.1/examples/route-separation/index.js#L32-L47) +- [Route map](https://github.com/expressjs/express/blob/4.13.1/examples/route-map/index.js#L52-L66) +- [MVC style controllers](https://github.com/expressjs/express/tree/master/examples/mvc) + +Also, there are third-party extensions for Express, which simplify some of these patterns: + +- [Resourceful routing](https://github.com/expressjs/express-resource) + +## How do I define models? + +Express has no notion of a database. This concept is +left up to third-party Node modules, allowing you to +interface with nearly any database. + +See [LoopBack](http://loopback.io) for an Express-based framework that is centered around models. + +## How can I authenticate users? + +Authentication is another opinionated area that Express does not +venture into. You may use any authentication scheme you wish. +For a simple username / password scheme, see [this example](https://github.com/expressjs/express/tree/master/examples/auth). + +## Which template engines does Express support? + +Express supports any template engine that conforms with the `(path, locals, callback)` signature. +To normalize template engine interfaces and caching, see the +[consolidate.js](https://github.com/visionmedia/consolidate.js) +project for support. Unlisted template engines might still support the Express signature. + +For more information, see [Using template engines with Express](/{{page.lang}}/guide/using-template-engines.html). + +## How do I handle 404 responses? + +In Express, 404 responses are not the result of an error, so +the error-handler middleware will not capture them. This behavior is +because a 404 response simply indicates the absence of additional work to do; +in other words, Express has executed all middleware functions and routes, +and found that none of them responded. All you need to +do is add a middleware function at the very bottom of the stack (below all other functions) +to handle a 404 response: + +```js +app.use((req, res, next) => { + res.status(404).send("Sorry can't find that!"); +}); +``` + +Add routes dynamically at runtime on an instance of `express.Router()` +so the routes are not superseded by a middleware function. + +## How do I setup an error handler? + +You define error-handling middleware in the same way as other middleware, +except with four arguments instead of three; specifically with the signature `(err, req, res, next)`: + +```js +app.use((err, req, res, next) => { + console.error(err.stack); + res.status(500).send('Something broke!'); +}); +``` + +For more information, see [Error handling](/{{ page.lang }}/guide/error-handling.html). + +## How do I render plain HTML? + +You don't! There's no need to "render" HTML with the `res.render()` function. +If you have a specific file, use the `res.sendFile()` function. +If you are serving many assets from a directory, use the `express.static()` +middleware function. + +## What version of Node.js does Express require? + +- [Express 4.x](/{{ page.lang }}/4x/api.html) requires Node.js 0.10 or higher. +- [Express 5.x](/{{ page.lang }}/5x/api.html) requires Node.js 18 or higher. diff --git a/astro/src/content/docs/en/starter/generator.md b/astro/src/content/docs/en/starter/generator.md new file mode 100755 index 0000000000..4f50dc5979 --- /dev/null +++ b/astro/src/content/docs/en/starter/generator.md @@ -0,0 +1,124 @@ +--- +title: Express application generator +description: Learn how to use the Express application generator tool to quickly create a skeleton for your Express.js applications, streamlining setup and configuration. +menu: starter +order: 3 +--- + +# Express application generator + +Use the application generator tool, `express-generator`, to quickly create an application skeleton. + +You can run the application generator with the `npx` command (available in Node.js 8.2.0). + +```bash +$ npx express-generator +``` + +For earlier Node versions, install the application generator as a global npm package and then launch it: + +```bash +$ npm install -g express-generator +$ express +``` + +Display the command options with the `-h` option: + +```bash +$ express -h + + Usage: express [options] [dir] + + Options: + + -h, --help output usage information + --version output the version number + -e, --ejs add ejs engine support + --hbs add handlebars engine support + --pug add pug engine support + -H, --hogan add hogan.js engine support + --no-view generate without view engine + -v, --view add view support (ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade) + -c, --css add stylesheet support (less|stylus|compass|sass) (defaults to plain css) + --git add .gitignore + -f, --force force on non-empty directory +``` + +For example, the following creates an Express app named _myapp_. The app will be created in a folder named _myapp_ in the current working directory and the view engine will be set to Pug: + +```bash +$ express --view=pug myapp + + create : myapp + create : myapp/package.json + create : myapp/app.js + create : myapp/public + create : myapp/public/javascripts + create : myapp/public/images + create : myapp/routes + create : myapp/routes/index.js + create : myapp/routes/users.js + create : myapp/public/stylesheets + create : myapp/public/stylesheets/style.css + create : myapp/views + create : myapp/views/index.pug + create : myapp/views/layout.pug + create : myapp/views/error.pug + create : myapp/bin + create : myapp/bin/www +``` + +Then install dependencies: + +```bash +$ cd myapp +$ npm install +``` + +On MacOS or Linux, run the app with this command: + +```bash +$ DEBUG=myapp:* npm start +``` + +On Windows Command Prompt, use this command: + +```bash +> set DEBUG=myapp:* & npm start +``` + +On Windows PowerShell, use this command: + +```bash +PS> $env:DEBUG='myapp:*'; npm start +``` + +Then, load `http://localhost:3000/` in your browser to access the app. + +The generated app has the following directory structure: + +```bash +. +├── app.js +├── bin +│ └── www +├── package.json +├── public +│ ├── images +│ ├── javascripts +│ └── stylesheets +│ └── style.css +├── routes +│ ├── index.js +│ └── users.js +└── views + ├── error.pug + ├── index.pug + └── layout.pug + +7 directories, 9 files +``` + +
+The app structure created by the generator is just one of many ways to structure Express apps. Feel free to use this structure or modify it to best suit your needs. +
diff --git a/astro/src/content/docs/en/starter/hello-world.md b/astro/src/content/docs/en/starter/hello-world.md new file mode 100755 index 0000000000..5a92e97b71 --- /dev/null +++ b/astro/src/content/docs/en/starter/hello-world.md @@ -0,0 +1,48 @@ +--- +title: Express "Hello World" example +description: Get started with Express.js by building a simple 'Hello World' application, demonstrating the basic setup and server creation for beginners. +menu: starter +order: 2 +--- + +# Hello world example + +
+Embedded below is essentially the simplest Express app you can create. It is a single file app — _not_ what you'd get if you use the [Express generator](/en/starter/generator), which creates the scaffolding for a full app with numerous JavaScript files, Jade templates, and sub-directories for various purposes. +
+ +```js +const express = require('express'); +const app = express(); +const port = 3000; + +app.get('/', (req, res) => { + res.send('Hello World!'); +}); + +app.listen(port, () => { + console.log(`Example app listening on port ${port}`); +}); +``` + +This app starts a server and listens on port 3000 for connections. The app responds with "Hello World!" for requests +to the root URL (`/`) or _route_. For every other path, it will respond with a **404 Not Found**. + +### Running Locally + +First create a directory named `myapp`, change to it and run `npm init`. Then, install `express` as a dependency, as per the [installation guide](/en/starter/installing). + +In the `myapp` directory, create a file named `app.js` and copy the code from the example above. + +
+The `req` (request) and `res` (response) are the exact same objects that Node provides, so you can invoke +`req.pipe()`, `req.on('data', callback)`, and anything else you would do without Express involved. +
+ +Run the app with the following command: + +```bash +$ node app.js +``` + +Then, load `http://localhost:3000/` in a browser to see the output. diff --git a/astro/src/content/docs/en/starter/installing.md b/astro/src/content/docs/en/starter/installing.md new file mode 100755 index 0000000000..ff78da6984 --- /dev/null +++ b/astro/src/content/docs/en/starter/installing.md @@ -0,0 +1,50 @@ +--- +title: Installing Express +description: Learn how to install Express.js in your Node.js environment, including setting up your project directory and managing dependencies with npm. +menu: starter +order: 1 +--- + +# Installing + +Assuming you've already installed [Node.js](https://nodejs.org/), create a directory to hold your application, and make that your working directory. + +- [Express 4.x](/en/4x/api) requires Node.js 0.10 or higher. +- [Express 5.x](/en/5x/api) requires Node.js 18 or higher. + +```bash +$ mkdir myapp +$ cd myapp +``` + +Use the `npm init` command to create a `package.json` file for your application. +For more information on how `package.json` works, see [Specifics of npm's package.json handling](https://docs.npmjs.com/files/package.json). + +```bash +$ npm init +``` + +This command prompts you for a number of things, such as the name and version of your application. +For now, you can simply hit RETURN to accept the defaults for most of them, with the following exception: + +``` +entry point: (index.js) +``` + +Enter `app.js`, or whatever you want the name of the main file to be. If you want it to be `index.js`, hit RETURN to accept the suggested default file name. + +Now, install Express in the `myapp` directory and save it in the dependencies list. For example: + +```bash +$ npm install express +``` + +To install Express temporarily and not add it to the dependencies list: + +```bash +$ npm install express --no-save +``` + +
+By default with version npm 5.0+, `npm install` adds the module to the `dependencies` list in the `package.json` file; with earlier versions of npm, you must specify the `--save` option explicitly. Then, afterwards, running `npm install` in the app directory will automatically install modules in the dependencies list. +
diff --git a/astro/src/content/docs/en/starter/static-files.md b/astro/src/content/docs/en/starter/static-files.md new file mode 100755 index 0000000000..8d3c9c2ea3 --- /dev/null +++ b/astro/src/content/docs/en/starter/static-files.md @@ -0,0 +1,78 @@ +--- +title: Serving static files in Express +description: Understand how to serve static files like images, CSS, and JavaScript in Express.js applications using the built-in 'static' middleware. +menu: starter +order: 5 +--- + +# Serving static files in Express + +To serve static files such as images, CSS files, and JavaScript files, use the `express.static` built-in middleware function in Express. + +The function signature is: + +```js +express.static(root, [options]); +``` + +The `root` argument specifies the root directory from which to serve static assets. +For more information on the `options` argument, see [express.static](/{{page.lang}}/5x/api.html#express.static). + +For example, use the following code to serve images, CSS files, and JavaScript files in a directory named `public`: + +```js +app.use(express.static('public')); +``` + +Now, you can load the files that are in the `public` directory: + +```text +http://localhost:3000/images/kitten.jpg +http://localhost:3000/css/style.css +http://localhost:3000/js/app.js +http://localhost:3000/images/bg.png +http://localhost:3000/hello.html +``` + +
+Express looks up the files relative to the static directory, so the name of the static directory is not part of the URL. +
+ +To use multiple static assets directories, call the `express.static` middleware function multiple times: + +```js +app.use(express.static('public')); +app.use(express.static('files')); +``` + +Express looks up the files in the order in which you set the static directories with the `express.static` middleware function. + +{% capture alert_content %} +For best results, [use a reverse proxy](/{{page.lang}}/advanced/best-practice-performance.html#use-a-reverse-proxy) cache to improve performance of serving static assets. +{% endcapture %} +{% include admonitions/note.html content=alert_content %} + +To create a virtual path prefix (where the path does not actually exist in the file system) for files that are served by the `express.static` function, [specify a mount path](/{{ page.lang }}/5x/api.html#app.use) for the static directory, as shown below: + +```js +app.use('/static', express.static('public')); +``` + +Now, you can load the files that are in the `public` directory from the `/static` path prefix. + +```text +http://localhost:3000/static/images/kitten.jpg +http://localhost:3000/static/css/style.css +http://localhost:3000/static/js/app.js +http://localhost:3000/static/images/bg.png +http://localhost:3000/static/hello.html +``` + +However, the path that you provide to the `express.static` function is relative to the directory from where you launch your `node` process. If you run the express app from another directory, it's safer to use the absolute path of the directory that you want to serve: + +```js +const path = require('path'); +app.use('/static', express.static(path.join(__dirname, 'public'))); +``` + +For more details about the `serve-static` function and its options, see [serve-static](/resources/middleware/serve-static.html). diff --git a/astro/src/i18n/ui.ts b/astro/src/i18n/ui.ts new file mode 100644 index 0000000000..0bb540de77 --- /dev/null +++ b/astro/src/i18n/ui.ts @@ -0,0 +1,15 @@ +export const languages = { + en: 'English', + fr: 'Français', +}; + +export const defaultLang = 'en'; + +export const ui = { + en: { + 'home.welcome': 'Welcome', + }, + fr: { + 'home.welcome': 'Bienvenue', + }, +} as const; diff --git a/astro/src/i18n/utils.ts b/astro/src/i18n/utils.ts new file mode 100644 index 0000000000..72ade3c5ba --- /dev/null +++ b/astro/src/i18n/utils.ts @@ -0,0 +1,13 @@ +import { ui, defaultLang } from './ui'; + +export function getLangFromUrl(url: URL) { + const [, lang] = url.pathname.split('/'); + if (lang in ui) return lang as keyof typeof ui; + return defaultLang; +} + +export function useTranslations(lang: keyof typeof ui) { + return function t(key: keyof (typeof ui)[typeof defaultLang]) { + return ui[lang][key] || ui[defaultLang][key]; + }; +} diff --git a/astro/src/layouts/DocLayout.astro b/astro/src/layouts/DocLayout.astro new file mode 100644 index 0000000000..5f4f5e946d --- /dev/null +++ b/astro/src/layouts/DocLayout.astro @@ -0,0 +1,25 @@ +--- +import Layout from './Layout.astro'; +import type { MenuSection } from '@config/menu'; +import type { BreadcrumbItem } from '@utils/breadcrumb'; +import { Breadcrumbs } from '@components/patterns'; + +interface Props { + title: string; + description?: string; + section: MenuSection; + breadcrumbs: BreadcrumbItem[]; +} + +const { title, description, breadcrumbs } = Astro.props; +--- + + +
+ + +
+ +
+
+
diff --git a/astro/src/layouts/Layout.astro b/astro/src/layouts/Layout.astro new file mode 100644 index 0000000000..b7d1c000b0 --- /dev/null +++ b/astro/src/layouts/Layout.astro @@ -0,0 +1,38 @@ +--- +import '@styles/main.css'; +import { Container } from '@components/primitives'; +import { ThemeSwitcher } from '@/components/patterns'; + +interface Props { + title?: string; + description?: string; +} + +const { + title = 'Express - Node.js web application framework', + description = 'Fast, unopinionated, minimalist web framework for Node.js', +} = Astro.props; +--- + + + + + + + + + + + + + + {title} + + + + + + + + + diff --git a/astro/src/pages/[lang]/[...slug].astro b/astro/src/pages/[lang]/[...slug].astro new file mode 100644 index 0000000000..912384dc4b --- /dev/null +++ b/astro/src/pages/[lang]/[...slug].astro @@ -0,0 +1,37 @@ +--- +import { getCollection } from 'astro:content'; +import DocLayout from '@layouts/DocLayout.astro'; +import type { MenuSection } from '@config/menu'; +import { render } from 'astro:content'; +import { buildBreadcrumbs } from '@utils/content'; + +export async function getStaticPaths() { + const pages = await getCollection('docs'); + return pages.map((page) => { + const [lang, ...slugParts] = page.id.split('/'); + + return { + params: { + lang, + slug: slugParts.join('/'), + }, + props: { page }, + }; + }); +} + +const { page } = Astro.props; +const { lang, slug } = Astro.params; +const { Content } = await render(page); +const breadcrumbs = await buildBreadcrumbs(lang, slug, 'docs'); +const { title, description, menu } = page.data; +--- + + + + diff --git a/astro/src/pages/[lang]/docs/index.astro b/astro/src/pages/[lang]/docs/index.astro new file mode 100644 index 0000000000..f18d61fcac --- /dev/null +++ b/astro/src/pages/[lang]/docs/index.astro @@ -0,0 +1,54 @@ +--- +/** + * Express Documentation Index Page + * + * TODO: This is a temporary index page for the Express documentation that lists sections and recent docs. This will be replaced with a proper sidebar navigation layout in the future. + */ +import Layout from '@layouts/Layout.astro'; +import { menuSections, type MenuSection } from '@config/menu'; +import { getDocsBySection } from '@utils/content'; + +const sections = Object.entries(menuSections); + +import { getLangFromUrl } from '@i18n/utils'; +import { languages } from '@i18n/ui'; + +export function getStaticPaths() { + return Object.keys(languages).map((lang) => ({ + params: { lang }, + })); +} + +const lang = getLangFromUrl(Astro.url); +--- + + +

Express Documentation

+

+ This is a temporary entry point page for the Express documentation. Below are some of the + sections and recent docs. +

+

This page will be replaced with a proper sidebar navigation layout soon.

+ { + sections.map(async ([key, label]) => { + const docs = await getDocsBySection(key as MenuSection, lang); + const firstDocs = docs.slice(0, 5); + + return ( +
+

{label}

+
    + {firstDocs.map((doc) => { + const slug = doc.id.replace(`${lang}/${key}/`, '').replace(/\.mdx?$/, ''); + return ( +
  • + {doc.data.title} +
  • + ); + })} +
+
+ ); + }) + } +
diff --git a/astro/src/pages/[lang]/ds-foundations.astro b/astro/src/pages/[lang]/ds-foundations.astro new file mode 100644 index 0000000000..37513f8800 --- /dev/null +++ b/astro/src/pages/[lang]/ds-foundations.astro @@ -0,0 +1,1090 @@ +--- +/** + * Design System Foundations Demo + * + * A single-page demo of all primitive components and tokens. + * TODO: This is a temporary page built to provide a reference for the design system. Can be replaced with a more comprehensive documentation site in the future. + */ +import { Icon } from 'astro-icon/components'; +import Layout from '@layouts/Layout.astro'; +import { + Container, + Grid, + Col, + Flex, + FlexItem, + H1, + H2, + H3, + H4, + H5, + Body, + BodyMd, + BodySm, + BodyXs, + Button, + Code, +} from '@components/primitives'; +import { Code as CodeBlock } from 'astro:components'; +import { getLangFromUrl } from '@i18n/utils'; +import { languages } from '@i18n/ui'; + +export function getStaticPaths() { + return Object.keys(languages).map((lang) => ({ + params: { lang }, + })); +} + +const lang = getLangFromUrl(Astro.url); +--- + + +
+

Design System Foundations

+
+ A living reference of all primitive components, tokens, and patterns. +
+
+ + + + +
+

Typography

+ +
+

Headings

+
+

Heading 1 — Page titles

+

Heading 2 — Section titles

+

Heading 3 — Subsections

+

Heading 4 — Minor headings

+
Heading 5 — Lead/intro paragraph text
+
+
+ +
+

Body Text

+
+ Body — Default paragraph text. This is the standard size for documentation content and + general reading. + Body Medium — Slightly smaller than default body. Good for sidebars and secondary content. +

+ Body Small — Secondary text, captions, and helper text. Used for metadata and less + prominent content. +

+

Body Extra Small — Fine print, legal text, and timestamps.

+
+
+ +
+

Inline Code

+
+ const express = require('express'); + Inline code: Use npm install express to install. +
+
+ +
+

Weights

+ + Light 300 + Normal 400 + Medium 500 + Semibold 600 + Bold 700 + +
+ +
+

Polymorphic Rendering

+
+

H1 styled, rendered as h2

+ Body text rendered as span (inline) +
+
+ +
+

Type Scale

+ +
+
+ Aa + 6xl (54px) +
+
+ Aa + 5xl (45px) +
+
+ Aa + 4xl (36px) +
+
+ Aa + 3xl (30px) +
+
+ Aa + 2xl (24px) +
+
+ Aa + xl (20px) +
+
+ Aa + lg (18px) +
+
+ Aa + base (16px) +
+
+ Aa + sm (14px) +
+
+ Aa + xs (12px) +
+
+
+

Usage

+ + h2 styled as H1 +This is body text. It renders a paragraph by default. +const express = require('express'); + `} + /> +
+ + +
+

Iconography

+ + Icons are provided by astro-icon, a well-supported and officially + recommended package for Astro that gives access to 200,000+ icons from various icon sets. We + primarily use Phosphor Icons (prefix ph:). + + +
+

Examples

+ + + + + + + +
+ +
+

Usage

+ + + `} + /> + + Browse available icons at Phosphor Icons or explore other icon sets at Iconify. + +
+
+ + +
+

Color Tokens

+ +
+

Primitive tokens

+
+
white
+
+ gray-50 +
+
+ gray-100 +
+
+ gray-200 +
+
+ gray-300 +
+
+ gray-400 +
+
+ gray-500 +
+
+ gray-600 +
+
+ gray-700 +
+
+ gray-800 +
+
+ gray-900 +
+
+ gray-950 +
+
black
+
+ +
+
sky-50
+
+ sky-500 +
+
+ sky-700 +
+
+ sky-800 +
+
+ +
+
+ green-50 +
+
+ green-300 +
+
+ green-500 +
+
+ green-700 +
+
+ green-900 +
+
+ +
+
+ amber-50 +
+
+ amber-300 +
+
+ amber-500 +
+
+ amber-600 +
+
+ amber-700 +
+
+ amber-900 +
+
+ +
+
+ red-50 +
+
+ red-300 +
+
+ red-500 +
+
+ red-600 +
+
+ red-700 +
+
+ red-900 +
+
+
+ +
+
+

Semantic tokens

+
+
+ bg-primary +
+
+ bg-secondary +
+
+ bg-tertiary +
+
+ bg-inverse +
+
+ bg-mute +
+
+ bg-success +
+
+ bg-warning +
+
+ bg-error +
+
+
+
+ text-primary +
+
+ text-secondary +
+
+ text-tertiary +
+
+ text-inverse +
+
+ text-mute +
+
+ text-success +
+
+ text-warning +
+
+ text-error +
+
+ +
+
+ border-primary +
+
+ border-secondary +
+
+ border-tertiary +
+
+ border-inverse +
+
+ border-mute +
+
+ border-success +
+
+ border-warning +
+
+ border-error +
+
+
+
+ +

Usage

+ +
+ + +
+

Spacing

+ +
+

Scale

+
+
+
+
+ 0.5 (2px) +
+
+
+ 1 (4px) +
+
+
+ 2 (8px) +
+
+
+ 3 (12px) +
+
+
+ 4 (16px) +
+
+
+ 6 (24px) +
+
+
+ 8 (32px) +
+
+
+
+ 12 (48px) +
+
+
+
+ 16 (64px) +
+
+
+ +

Usage

+ +
+ + +
+

Buttons

+ + Interactive button component with support for variants, sizes, and polymorphic rendering. + + +
+

Variants

+ + + + +
+ +
+

Sizes

+ + + + + +
+ +
+

Ghost Style

+ + + Can be used on light backgrounds + + + + Can be used on dark backgrounds + +
+ +
+

With Icons

+ + + + +
+ +
+

Disabled State

+ + + + +
+ +
+

As Link

+ + + + +
+ +
+

Usage

+ Click me + + + `} + /> +
+
+ + +
+

Grid & Layout

+ + 12-column responsive grid system with Grid, Col, and Flex components. + + +
+

Grid Component

+ + Responsive 12-column grid. Columns cascade from xs → md → lg. + +
+ + +
+ xs=12, md=6, lg=4 +
+ + +
+ xs=12, md=6, lg=4 +
+ + +
+ xs=12, md=12, lg=4 +
+ +
+
+

Usage

+ + Content + Content + Content + + `} + /> +
+ +
+

Flex Component

+ Flexbox layouts for 1D directional content. +
+ +
+ Item 1 +
+
+ Item 2 +
+
+ Item 3 +
+
+
+

Usage

+ +
Item 1
+
Item 2
+ + `} + /> +
+ +
+

FlexItem Component

+ Control flex-grow, flex-shrink, and flex-basis for individual flex children. + +

Equal Columns

+
+ + +
flex="1"
+
+ +
flex="1"
+
+ +
flex="1"
+
+
+
+ +

Different Basis & Grow

+
+ + +
+ FlexItem basis="1/4" +
+
+ +
+ FlexItem (grow="1") +
+
+
+
+ +

Usage

+ + Equal column + Sidebar + Flexible content + + `} + /> +
+ +
+

Container

+ + Centered, responsive content wrapper with max-width and padding. + +
+ +
+ Content centered with max-width: 1440px, width: 90-95% +
+
+
+
+

Usage

+ +
Your content here
+ + `} + /> +
+ + +
+

Breakpoints

+ +
+
+ Current: Mobile (xs) < 768px + Current: Tablet (md) 768px – 1439px + Current: Desktop (lg) ≥ 1440px +
+
+ +
+

Usage

+ +
+
+ + +
diff --git a/astro/src/pages/[lang]/index.astro b/astro/src/pages/[lang]/index.astro new file mode 100644 index 0000000000..f7d5b83267 --- /dev/null +++ b/astro/src/pages/[lang]/index.astro @@ -0,0 +1,30 @@ +--- +import { Body, H1 } from '@components/primitives'; +import Layout from '@layouts/Layout.astro'; +import { getLangFromUrl, useTranslations } from '@i18n/utils'; +import { languages } from '@i18n/ui'; + +export function getStaticPaths() { + return Object.keys(languages).map((lang) => ({ + params: { lang }, + })); +} + +const lang = getLangFromUrl(Astro.url); +const t = useTranslations(lang); +--- + + +

{t('home.welcome')}

+ This is a work-in-progress homepage. + +
diff --git a/astro/src/pages/index.astro b/astro/src/pages/index.astro new file mode 100644 index 0000000000..655eb6cb65 --- /dev/null +++ b/astro/src/pages/index.astro @@ -0,0 +1 @@ + diff --git a/astro/src/styles/base/_fonts.css b/astro/src/styles/base/_fonts.css new file mode 100644 index 0000000000..1101ee226c --- /dev/null +++ b/astro/src/styles/base/_fonts.css @@ -0,0 +1,24 @@ +/** + * Font Face Declarations + * + * Self-hosted JetBrains Mono for code blocks. + * Currently only Light (300) weight is used across the site. + * Using font-display: swap for better performance. + */ + +/* JetBrains Mono - Light */ +@font-face { + font-family: 'JetBrains Mono'; + src: url('/fonts/JetBrainsMono-Light.woff2') format('woff2'); + font-weight: 300; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: 'JetBrains Mono'; + src: url('/fonts/JetBrainsMono-LightItalic.woff2') format('woff2'); + font-weight: 300; + font-style: italic; + font-display: swap; +} diff --git a/astro/src/styles/base/_global.css b/astro/src/styles/base/_global.css new file mode 100644 index 0000000000..fb03010d45 --- /dev/null +++ b/astro/src/styles/base/_global.css @@ -0,0 +1,221 @@ +/** + * Global Base Styles (layer: base) + * + * Applies design tokens to base HTML elements + */ + +html { + font-family: var(--font-family-body); + font-size: 62.5%; + color: var(--color-text-primary); + background-color: var(--color-bg-primary); + scroll-behavior: smooth; + -moz-text-size-adjust: none; + -webkit-text-size-adjust: none; + text-size-adjust: none; + box-sizing: border-box; + + *, + *:before, + *:after { + box-sizing: inherit; + } +} + +body { + font-family: var(--font-family-body); + font-size: var(--font-size-body); + line-height: var(--line-height-body); + background-color: var(--color-bg-primary); + text-rendering: optimizeLegibility; +} + +/* Headings */ +h1, +.h1, +h2, +.h2, +h3, +.h3, +h4, +.h4, +h5, +.h5, +h6, +.h6 { + font-weight: var(--font-weight-medium); + line-height: var(--line-height-tight); + letter-spacing: var(--letter-spacing-tight); + margin: 0; +} + +h1, +.h1 { + font-size: var(--font-size-h1); + margin: var(--space-h1) 0; +} + +h2, +.h2 { + font-size: var(--font-size-h2); + margin: var(--space-h2) 0; +} + +h3, +.h3 { + font-size: var(--font-size-h3); + margin: var(--space-h3) 0; +} + +h4, +.h4 { + font-size: var(--font-size-h4); + margin: var(--space-h4) 0; +} + +h5, +.h5 { + font-size: var(--font-size-lg); + font-weight: var(--font-weight-normal); + line-height: var(--line-height-relaxed); + margin: var(--space-body) 0; +} + +h6, +.h6 { + font-size: var(--font-size-base); + margin: var(--space-body) 0; +} + +p, +.body { + font-family: var(--font-family-body); + font-size: var(--font-size-body); + font-weight: var(--font-weight-normal); + line-height: var(--line-height-body); + letter-spacing: var(--letter-spacing-body); + margin: var(--space-body) 0; +} + +span, +.body-md { + font-family: var(--font-family-body); + font-weight: var(--font-weight-normal); + line-height: var(--line-height-normal); + margin: var(--space-body) 0; +} + +.body-md { + font-size: var(--font-size-sm); +} + +small, +.body-sm { + font-family: var(--font-family-body); + font-weight: var(--font-weight-normal); + line-height: var(--line-height-normal); + margin: var(--space-body) 0; +} + +.body-sm { + font-size: var(--font-size-xs); +} + +.body-xs { + font-family: var(--font-family-body); + font-size: var(--font-size-xxs); + font-weight: var(--font-weight-normal); + line-height: var(--line-height-normal); + margin: var(--space-body) 0; +} + +/* Links */ +a { + color: var(--color-link); + text-decoration: underline; + text-underline-offset: 0.15em; + transition: var(--transition-colors); +} + +a:hover { + color: var(--color-link-hover); +} + +/* Code */ +code, +kbd, +samp, +pre { + font-family: var(--font-family-code); + font-size: var(--font-size-code); + + *, + *:before, + *:after { + font-family: inherit; + } +} + +code, +.code { + font-family: var(--font-family-code); + font-size: var(--font-size-code); + font-weight: var(--font-weight-normal); + line-height: var(--line-height-snug); + background-color: var(--color-bg-tertiary); + padding: var(--space-0-5) var(--space-1); + border-radius: var(--radius-base); + letter-spacing: var(--letter-spacing-normal); +} + +pre { + padding: var(--space-4); + background-color: var(--color-pre-bg); + color: var(--color-pre-fg); + border-radius: var(--radius-lg); + overflow-x: auto; +} + +pre code { + padding: 0; + background: none; + border-radius: 0; +} + +/* Blockquote */ +blockquote { + padding-left: var(--space-4); + border-left: var(--border-width-4) solid var(--color-border-primary); + font-style: italic; +} + +/* Horizontal rule */ +hr { + border: none; + border-top: var(--border-width-1) solid var(--color-border-primary); + margin: var(--space-8) 0; +} + +/* Tables */ +table { + width: 100%; + border-collapse: collapse; +} + +th, +td { + padding: var(--space-3) var(--space-4); + text-align: left; + border-bottom: var(--border-width-1) solid var(--color-border-primary); +} + +th { + font-weight: var(--font-weight-semibold); +} + +/* Lists */ +ul, +ol { + margin: var(--space-body) 0; + padding-left: var(--space-6); +} diff --git a/astro/src/styles/base/_reset.css b/astro/src/styles/base/_reset.css new file mode 100644 index 0000000000..04353be936 --- /dev/null +++ b/astro/src/styles/base/_reset.css @@ -0,0 +1,82 @@ +/** + * CSS Reset (layer: reset) + * + * Modern CSS reset based on Josh Comeau's reset + * https://www.joshwcomeau.com/css/custom-css-reset/ + */ + +/* Box sizing rules */ +*, +*::before, +*::after { + box-sizing: border-box; +} + +/* Remove default margin and padding */ +* { + margin: 0; + padding: 0; +} + +/* Set core body defaults */ +body { + min-height: 100vh; + -webkit-font-smoothing: antialiased; +} + +/* Remove list styles on ul, ol elements with a list role */ +ul[role='list'], +ol[role='list'] { + list-style: none; +} + +/* Set shorter line heights on interactive elements */ +button, +input, +label { + line-height: 1.1; +} + +/* Balance text wrapping on headings */ +h1, +h2, +h3, +h4, +h5, +h6 { + text-wrap: balance; +} + +/* Better text decoration rendering */ +a { + text-decoration-skip-ink: auto; +} + +/* Make images easier to work with */ +img, +picture, +video, +canvas, +svg { + display: block; + max-width: 100%; +} + +/* Inherit fonts for inputs and buttons */ +input, +button, +textarea, +select { + font: inherit; + color: inherit; +} + +/* Make sure textareas without a rows attribute are not tiny */ +textarea:not([rows]) { + min-height: 10em; +} + +/* Anything that has been anchored to should have extra scroll margin */ +:target { + scroll-margin-block: 5ex; +} diff --git a/astro/src/styles/main.css b/astro/src/styles/main.css new file mode 100644 index 0000000000..4ef4b192e6 --- /dev/null +++ b/astro/src/styles/main.css @@ -0,0 +1,18 @@ +/** + * Main Stylesheet + * + * Entry point for all styles + * Import this file in your layout + * + * Layer order (lowest to highest priority): + * 1. reset - CSS reset/normalize + * 2. base - Element defaults (html, body, a, etc.) + * 4. utilities - One-off overrides + */ + +/* Design Tokens - outside layers (global foundation) */ +@import './tokens/index.css'; +@import './base/_reset.css'; +@import './base/_fonts.css'; +@import './base/_global.css'; +@import './utilities/_utilities.css'; diff --git a/astro/src/styles/tokens/_borders.css b/astro/src/styles/tokens/_borders.css new file mode 100644 index 0000000000..80ea81603e --- /dev/null +++ b/astro/src/styles/tokens/_borders.css @@ -0,0 +1,31 @@ +/** + * Border Tokens + * + * Border widths and radius + */ + +:root { + /* Border Widths */ + --border-width-0: 0px; + --border-width-1: 1px; + --border-width-2: 2px; + --border-width-4: 4px; + --border-width-8: 8px; + + /* Border Radius */ + --radius-none: 0; + --radius-sm: 0.2rem; /* 2px */ + --radius-base: 0.4rem; /* 4px */ + --radius-md: 0.6rem; /* 6px */ + --radius-lg: 0.8rem; /* 8px */ + --radius-xl: 1.2rem; /* 12px */ + --radius-2xl: 1.6rem; /* 16px */ + --radius-3xl: 2.4rem; /* 24px */ + --radius-full: 9999px; + + /* Semantic */ + --radius-button: var(--radius-md); + --radius-input: var(--radius-md); + --radius-card: var(--radius-lg); + --radius-badge: var(--radius-full); +} diff --git a/astro/src/styles/tokens/_breakpoints.css b/astro/src/styles/tokens/_breakpoints.css new file mode 100644 index 0000000000..21bcc232a8 --- /dev/null +++ b/astro/src/styles/tokens/_breakpoints.css @@ -0,0 +1,46 @@ +/** + * Breakpoint Tokens + * + * Design breakpoints: + * - Mobile: < 768px + * - Tablet: 768px - 1439px + * - Desktop: >= 1440px + * + * Usage: + * @media (--xs-only) { ... } - Mobile only + * @media (--md-only) { ... } - Tablet only + * @media (--md-up) { ... } - Above Tablet + * @media (--lg-up) { ... } - Above Desktop + * @media (--lg-down) { ... } - Below Desktop + */ + +/* ============================================ + CUSTOM MEDIA QUERIES + ============================================ */ + +/* Device-specific (exclusive) */ +@custom-media --xs-only (width < 768px); +@custom-media --md-up (width >= 768px); +@custom-media --md-only (768px <= width < 1440px); +@custom-media --lg-up (width >= 1440px); +@custom-media --lg-down (width < 1440px); + +/* Range queries (inclusive) */ + +/* ============================================ + BREAKPOINT VALUES (for JavaScript) + + Note: CSS custom properties cannot be used in + @media or @custom-media queries. These are exposed + for documentation (to have a human-readable reference) and + for JavaScript access via getComputedStyle(). + + Example: + const bp = getComputedStyle(document.documentElement) + .getPropertyValue('--breakpoint-md'); + ============================================ */ + +:root { + --breakpoint-md: 768px; + --breakpoint-lg: 1440px; +} diff --git a/astro/src/styles/tokens/_colors.css b/astro/src/styles/tokens/_colors.css new file mode 100644 index 0000000000..9d1115028a --- /dev/null +++ b/astro/src/styles/tokens/_colors.css @@ -0,0 +1,156 @@ +:root { + /** + * Theme behavior: + * - Default: follows system preference (prefers-color-scheme) + * - Override: user can set [data-theme="light|dark"] on + */ + color-scheme: light dark; + + /* ============================================ + PRIMITIVE TOKENS + ============================================ */ + + --white: oklch(100% 0 0); /* #FFFFFF */ + --black: oklch(0% 0 0); /* #000000 */ + + --gray-50: oklch(98% 0 0); /* #FAFAFA */ + --gray-100: oklch(97% 0 0); /* #F6F6F6 */ + --gray-150: oklch(94% 0 0); /* #EEEEEE */ + --gray-200: oklch(92% 0 0); /* #E5E5E5 */ + --gray-300: oklch(87% 0 0); /* #D4D4D4 */ + --gray-400: oklch(70% 0 0); /* #A3A3A3 */ + --gray-500: oklch(55% 0 0); /* #737373 */ + --gray-550: oklch(50% 0 0); /* #626262 */ + --gray-600: oklch(45% 0 0); /* #525252 */ + --gray-700: oklch(35% 0 0); /* #404040 */ + --gray-800: oklch(25% 0 0); /* #262626 */ + --gray-900: oklch(15% 0 0); /* #141414 */ + --gray-950: oklch(13% 0 0); /* #0A0A0A */ + + /* Green */ + --green-50: oklch(97% 0.02 155); /* #F0FDF4 */ + --green-100: oklch(94% 0.04 155); /* #DCFCE7 */ + --green-200: oklch(89% 0.08 155); /* #BBF7D0 */ + --green-300: oklch(81% 0.13 155); /* #86EFAC */ + --green-400: oklch(70% 0.17 155); /* #4ADE80 */ + --green-500: oklch(62% 0.19 155); /* #22C55E */ + --green-600: oklch(53% 0.17 155); /* #16A34A */ + --green-700: oklch(46% 0.14 155); /* #15803D */ + --green-800: oklch(39% 0.11 155); /* #166534 */ + --green-900: oklch(34% 0.09 155); /* #14532D */ + --green-950: oklch(20% 0.06 155); /* #052E16 */ + + /* Blue */ + --blue-50: oklch(97% 0.01 250); /* #EFF6FF */ + --blue-100: oklch(94% 0.03 250); /* #DBEAFE */ + --blue-200: oklch(88% 0.06 250); /* #BFDBFE */ + --blue-300: oklch(79% 0.11 250); /* #93C5FD */ + --blue-400: oklch(69% 0.15 250); /* #60A5FA */ + --blue-500: oklch(60% 0.18 250); /* #3B82F6 */ + --blue-600: oklch(53% 0.2 250); /* #2563EB */ + --blue-700: oklch(47% 0.19 250); /* #1D4ED8 */ + --blue-800: oklch(41% 0.16 250); /* #1E40AF */ + --blue-900: oklch(37% 0.13 250); /* #1E3A8A */ + --blue-950: oklch(26% 0.1 250); /* #172554 */ + + --sky-500: oklch(71% 0.16 237); /* #0EA5E9 */ + --sky-700: oklch(48% 0.22 237); /* #0369A1 */ + + /* Amber */ + --amber-50: oklch(98% 0.03 85); /* #FFFBEB */ + --amber-100: oklch(94% 0.07 85); /* #FEF3C7 */ + --amber-200: oklch(89% 0.12 85); /* #FDE68A */ + --amber-300: oklch(83% 0.16 80); /* #FCD34D */ + --amber-400: oklch(78% 0.17 70); /* #FBBF24 */ + --amber-500: oklch(73% 0.17 60); /* #F59E0B */ + --amber-600: oklch(64% 0.17 50); /* #D97706 */ + --amber-700: oklch(53% 0.15 50); /* #B45309 */ + --amber-800: oklch(45% 0.12 50); /* #92400E */ + --amber-900: oklch(39% 0.1 50); /* #78350F */ + --amber-950: oklch(25% 0.07 50); /* #451A03 */ + + /* Red */ + --red-50: oklch(97% 0.01 25); /* #FEF2F2 */ + --red-100: oklch(94% 0.03 25); /* #FEE2E2 */ + --red-200: oklch(89% 0.06 25); /* #FECACA */ + --red-300: oklch(81% 0.11 25); /* #FCA5A5 */ + --red-400: oklch(70% 0.17 25); /* #F87171 */ + --red-500: oklch(62% 0.21 25); /* #EF4444 */ + --red-600: oklch(54% 0.22 25); /* #DC2626 */ + --red-700: oklch(47% 0.19 25); /* #B91C1C */ + --red-800: oklch(40% 0.16 25); /* #991B1B */ + --red-900: oklch(36% 0.13 25); /* #7F1D1D */ + --red-950: oklch(22% 0.09 25); /* #450A0A */ + + /* ============================================ + SEMANTIC TOKENS + Using light-dark(light-value, dark-value) + ============================================ */ + + /* Backgrounds */ + --color-bg-primary: light-dark(var(--white), var(--black)); + --color-bg-secondary: light-dark(var(--gray-50), var(--gray-900)); + --color-bg-tertiary: light-dark(var(--gray-100), var(--gray-800)); + --color-bg-inverse: light-dark(var(--gray-900), var(--gray-100)); + --color-bg-inverse-secondary: light-dark(var(--gray-800), var(--gray-200)); + --color-bg-mute: light-dark(var(--gray-200), var(--gray-800)); + --color-bg-info: light-dark(var(--blue-50), var(--blue-950)); + --color-bg-success: light-dark(var(--green-50), var(--green-950)); + --color-bg-warning: light-dark(var(--amber-50), var(--amber-950)); + --color-bg-error: light-dark(var(--red-50), var(--red-950)); + + /* Borders */ + --color-border-primary: light-dark(var(--gray-300), var(--gray-500)); + --color-border-secondary: light-dark(var(--gray-200), var(--gray-800)); + --color-border-tertiary: light-dark(var(--gray-400), var(--gray-400)); + --color-border-mute: light-dark(var(--gray-400), var(--gray-600)); + --color-border-inverse: light-dark(var(--gray-700), var(--gray-200)); + --color-border-info: light-dark(var(--blue-200), var(--blue-800)); + --color-border-success: light-dark(var(--green-200), var(--green-800)); + --color-border-warning: light-dark(var(--amber-200), var(--amber-800)); + --color-border-error: light-dark(var(--red-200), var(--red-800)); + + /* Text */ + --color-text-primary: light-dark(var(--gray-900), var(--gray-100)); + --color-text-secondary: light-dark(var(--gray-600), var(--gray-150)); + --color-text-tertiary: var(--gray-500, var(--gray-550)); + --color-text-inverse: light-dark(var(--gray-100), var(--gray-900)); + --color-text-mute: var(--gray-500, var(--gray-550)); + --color-text-info: light-dark(var(--blue-700), var(--blue-400)); + --color-text-success: light-dark(var(--green-700), var(--green-400)); + --color-text-warning: light-dark(var(--amber-700), var(--amber-400)); + --color-text-error: light-dark(var(--red-700), var(--red-400)); + + /* Icons */ + --color-icon-primary: light-dark(var(--gray-900), var(--gray-50)); + --color-icon-secondary: light-dark(var(--gray-500), var(--gray-400)); + + /* ============================================ + COMPONENT TOKENS + ============================================ */ + + /* Buttons */ + --color-button-primary-bg: light-dark(var(--gray-900), var(--white)); + --color-button-primary-text: light-dark(var(--white), var(--black)); + --color-button-primary-bg-hover: light-dark(var(--gray-800), var(--gray-200)); + + /* Links */ + --color-link: light-dark(var(--sky-500), var(--sky-500)); + --color-link-hover: light-dark(var(--sky-500), var(--sky-700)); + --color-link-visited: light-dark(var(--sky-700), var(--sky-700)); + /* Focus */ + --color-focus-ring: light-dark(var(--gray-900), var(--white)); +} + +/* ============================================ + THEME OVERRIDES + Force specific theme via data attribute + ============================================ */ + +[data-theme='light'] { + color-scheme: light; +} + +[data-theme='dark'] { + color-scheme: dark; +} diff --git a/astro/src/styles/tokens/_spacing.css b/astro/src/styles/tokens/_spacing.css new file mode 100644 index 0000000000..11ee180649 --- /dev/null +++ b/astro/src/styles/tokens/_spacing.css @@ -0,0 +1,48 @@ +/** + * Spacing Tokens + * + * Based on a 4px grid system (0.25rem) + * Used for margin, padding, gap, etc. + */ + +:root { + --space-0: 0; + --space-px: 1px; + --space-0-5: 0.2rem; /* 2px */ + --space-1: 0.4rem; /* 4px */ + --space-1-5: 0.6rem; /* 6px */ + --space-2: 0.8rem; /* 8px */ + --space-2-5: 1rem; /* 10px */ + --space-3: 1.2rem; /* 12px */ + --space-3-5: 1.4rem; /* 14px */ + --space-4: 1.6rem; /* 16px */ + --space-5: 2rem; /* 20px */ + --space-6: 2.4rem; /* 24px */ + --space-7: 2.8rem; /* 28px */ + --space-8: 3.2rem; /* 32px */ + --space-9: 3.6rem; /* 36px */ + --space-10: 4rem; /* 40px */ + --space-11: 4.4rem; /* 44px */ + --space-12: 4.8rem; /* 48px */ + --space-14: 5.6rem; /* 56px */ + --space-16: 6.4rem; /* 64px */ + --space-20: 8rem; /* 80px */ + --space-24: 9.6rem; /* 96px */ + --space-28: 11.2rem; /* 112px */ + --space-32: 12.8rem; /* 128px */ + --space-36: 14.4rem; /* 144px */ + --space-40: 16rem; /* 160px */ + --space-44: 17.6rem; /* 176px */ + --space-48: 19.2rem; /* 192px */ + --space-52: 20.8rem; /* 208px */ + --space-56: 22.4rem; /* 224px */ + --space-60: 24rem; /* 240px */ + --space-64: 25.6rem; /* 256px */ + + /* Component specific */ + --space-h1: var(--space-12); + --space-h2: var(--space-6); + --space-h3: var(--space-6); + --space-h4: var(--space-6); + --space-body: var(--space-5); +} diff --git a/astro/src/styles/tokens/_transitions.css b/astro/src/styles/tokens/_transitions.css new file mode 100644 index 0000000000..41c7e739f8 --- /dev/null +++ b/astro/src/styles/tokens/_transitions.css @@ -0,0 +1,47 @@ +/** + * Transition & Animation Tokens + */ + +:root { + /* Durations */ + --duration-75: 75ms; + --duration-100: 100ms; + --duration-150: 150ms; + --duration-200: 200ms; + --duration-300: 300ms; + --duration-500: 500ms; + --duration-700: 700ms; + --duration-1000: 1000ms; + + /* Timing Functions */ + --ease-linear: linear; + --ease-in: cubic-bezier(0.4, 0, 1, 1); + --ease-out: cubic-bezier(0, 0, 0.2, 1); + --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1); + + /* Semantic transitions */ + --transition-fast: var(--duration-150) var(--ease-out); + --transition-base: var(--duration-200) var(--ease-out); + --transition-slow: var(--duration-300) var(--ease-out); + + --transition-colors: + color var(--transition-fast), background-color var(--transition-fast), + border-color var(--transition-fast); + --transition-transform: transform var(--transition-base); + --transition-opacity: opacity var(--transition-base); + --transition-shadow: box-shadow var(--transition-base); +} + +/* Respect reduced motion preference */ +@media (prefers-reduced-motion: reduce) { + :root { + --duration-75: 0ms; + --duration-100: 0ms; + --duration-150: 0ms; + --duration-200: 0ms; + --duration-300: 0ms; + --duration-500: 0ms; + --duration-700: 0ms; + --duration-1000: 0ms; + } +} diff --git a/astro/src/styles/tokens/_typography.css b/astro/src/styles/tokens/_typography.css new file mode 100644 index 0000000000..9097495348 --- /dev/null +++ b/astro/src/styles/tokens/_typography.css @@ -0,0 +1,82 @@ +/** + * Typography Tokens + * + * Primary font: Helvetica Neue + * Code font: JetBrains Mono + */ + +:root { + /* Font Families */ + --font-family-sans: + 'Helvetica Neue', Helvetica, Arial, system-ui, -apple-system, BlinkMacSystemFont, sans-serif; + --font-family-mono: + 'JetBrains Mono', ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, monospace; + + /* Font Sizes - Scale using a 1.2 ratio (Minor Third) */ + --font-size-xxs: 1rem; + --font-size-xs: 1.2rem; + --font-size-sm: 1.4rem; + --font-size-base: 1.6rem; + --font-size-lg: 1.8rem; + --font-size-xl: 2rem; + --font-size-2xl: 2.4rem; + --font-size-3xl: 3rem; + --font-size-4xl: 3.6rem; + --font-size-5xl: 4.5rem; + --font-size-6xl: 5.4rem; + + /* Font Weights */ + --font-weight-light: 300; + --font-weight-normal: 400; + --font-weight-medium: 500; + --font-weight-semibold: 600; + --font-weight-bold: 700; + + /* Line Heights */ + --line-height-none: 1; + --line-height-tight: 1.25; + --line-height-snug: 1.375; + --line-height-normal: 1.5; + --line-height-relaxed: 1.625; + --line-height-loose: 2; + + /* Letter Spacing */ + --letter-spacing-tighter: -0.05em; + --letter-spacing-tight: -0.025em; + --letter-spacing-normal: 0em; + --letter-spacing-wide: 0.025em; + --letter-spacing-wider: 0.05em; + --letter-spacing-widest: 0.1em; + + /* Components tokens */ + --font-family-body: var(--font-family-sans); + --font-size-body: var(--font-size-base); + --line-height-body: var(--line-height-normal); + --letter-spacing-body: var(--letter-spacing-tight); + + --font-family-heading: var(--font-family-sans); + --font-weight-heading: var(--font-weight-bold); + --font-line-height-heading: var(--line-height-tight); + + --font-size-h1: var(--font-size-4xl); + --font-size-h2: var(--font-size-2xl); + --font-size-h3: var(--font-size-lg); + --font-size-h4: var(--font-size-base); + + --font-family-code: var(--font-family-mono); + --font-size-code: 0.9em; + + @media (--md-only) { + --font-size-h1: var(--font-size-5xl); + --font-size-h2: var(--font-size-5xl); + --font-size-h3: var(--font-size-lg); + --font-size-h4: var(--font-size-lg); + } + + @media (--lg-up) { + --font-size-h1: var(--font-size-6xl); + --font-size-h2: var(--font-size-5xl); + --font-size-h3: var(--font-size-2xl); + --font-size-h4: var(--font-size-xl); + } +} diff --git a/astro/src/styles/tokens/index.css b/astro/src/styles/tokens/index.css new file mode 100644 index 0000000000..5d70dd7cfe --- /dev/null +++ b/astro/src/styles/tokens/index.css @@ -0,0 +1,12 @@ +/** + * Design Tokens Index + * + * Import all token files + */ + +@import './_breakpoints.css'; +@import './_colors.css'; +@import './_typography.css'; +@import './_spacing.css'; +@import './_borders.css'; +@import './_transitions.css'; diff --git a/astro/src/styles/utilities/_utilities.css b/astro/src/styles/utilities/_utilities.css new file mode 100644 index 0000000000..5fcb9cc175 --- /dev/null +++ b/astro/src/styles/utilities/_utilities.css @@ -0,0 +1,144 @@ +/** + * Utility Classes (layer: utilities) + * + * High-priority utility classes for one-off overrides. + * Use sparingly - prefer component styles. + */ + +/* Visually hidden but accessible to screen readers */ +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +/* Text alignment */ +.text-left { + text-align: left; +} +.text-center { + text-align: center; +} +.text-right { + text-align: right; +} + +/* Display */ +.hidden { + display: none; +} +.block { + display: block; +} +.inline { + display: inline; +} +.inline-block { + display: inline-block; +} +.flex { + display: flex; +} +.grid { + display: grid; +} + +/* Flex utilities */ +.flex-row { + flex-direction: row; +} +.flex-col { + flex-direction: column; +} +.items-center { + align-items: center; +} +.items-start { + align-items: flex-start; +} +.items-end { + align-items: flex-end; +} +.justify-center { + justify-content: center; +} +.justify-between { + justify-content: space-between; +} +.justify-end { + justify-content: flex-end; +} +.gap-1 { + gap: var(--space-1); +} +.gap-2 { + gap: var(--space-2); +} +.gap-3 { + gap: var(--space-3); +} +.gap-4 { + gap: var(--space-4); +} +.gap-6 { + gap: var(--space-6); +} +.gap-8 { + gap: var(--space-8); +} + +/* Width */ +.w-full { + width: 100%; +} +.max-w-prose { + max-width: var(--content-width); +} + +/* Margin auto */ +.mx-auto { + margin-inline: auto; +} +.my-auto { + margin-block: auto; +} + +/* Padding shortcuts */ +.p-0 { + padding: var(--space-0); +} +.p-2 { + padding: var(--space-2); +} +.p-4 { + padding: var(--space-4); +} +.p-6 { + padding: var(--space-6); +} +.p-8 { + padding: var(--space-8); +} + +/* Margin shortcuts */ +.m-0 { + margin: var(--space-0); +} +.m-2 { + margin: var(--space-2); +} +.m-4 { + margin: var(--space-4); +} +.m-6 { + margin: var(--space-6); +} +.m-8 { + margin: var(--space-8); +} diff --git a/astro/src/utils/content.ts b/astro/src/utils/content.ts new file mode 100644 index 0000000000..7f58c9378d --- /dev/null +++ b/astro/src/utils/content.ts @@ -0,0 +1,84 @@ +import { getCollection, type CollectionEntry } from 'astro:content'; +import type { MenuSection } from '@config/menu'; +import type { collections } from '@/content.config'; + +/** + * Get all documents for a specific language + */ +export async function getDocsByLang(lang: string = 'en') { + const allDocs = await getCollection('docs'); + return allDocs.filter((doc) => doc.id.startsWith(`${lang}/`)); +} + +/** + * Get all documents for a specific section and language + */ +export async function getDocsBySection(section: MenuSection, lang: string = 'en') { + const allDocs = await getDocsByLang(lang); + return allDocs + .filter((doc) => doc.data.menu === section) + .sort((a, b) => (a.data.order ?? 0) - (b.data.order ?? 0)); +} + +/** + * Checks if there is content at the specified path + * @param checkPath - The path to check (e.g., 'en/resources/middleware') + * @param pages - The collection of pages to search within + * @returns True if content exists at the specified path, false otherwise + */ + +export function hasContentAt( + checkPath: string, + pages: CollectionEntry[] +): boolean { + return pages.some((page) => page.id === checkPath); +} + +export interface BreadcrumbItem { + label: string; + href?: string; +} + +/** + * Builds breadcrumb items for a documentation page + * @param lang - The language code (e.g., 'en') + * @param slug - The page slug (e.g., 'resources/middleware/compression') + * @param collection - The collection name to check for existing content + * @returns Array of breadcrumb items with labels and optional hrefs + */ +export async function buildBreadcrumbs( + lang: string, + slug: string, + collection: keyof typeof collections +): Promise { + const pages = await getCollection(collection); + + const breadcrumbs: BreadcrumbItem[] = []; + + breadcrumbs.push({ + label: 'Docs', + href: undefined, + }); + + const slugParts = slug.split('/'); + + slugParts.forEach((part, index) => { + const isLast = index === slugParts.length - 1; + + const pathToSegment = `${lang}/${slugParts.slice(0, index + 1).join('/')}`; + + const label = part + .split('-') + .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) + .join(' '); + + if (!isLast) { + breadcrumbs.push({ + label, + href: hasContentAt(pathToSegment, pages) ? `/${pathToSegment}` : undefined, + }); + } + }); + + return breadcrumbs; +} diff --git a/astro/tsconfig.json b/astro/tsconfig.json new file mode 100644 index 0000000000..b1155e8670 --- /dev/null +++ b/astro/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "astro/tsconfigs/strict", + "include": [".astro/types.d.ts", "**/*"], + "exclude": ["dist"], + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["src/*"], + "@components/*": ["src/components/*"], + "@layouts/*": ["src/layouts/*"], + "@assets/*": ["src/assets/*"], + "@styles/*": ["src/styles/*"], + "@config/*": ["src/config/*"], + "@i18n/*": ["src/i18n/*"], + "@utils/*": ["src/utils/*"] + } + } +} diff --git a/legacy/.github-legacy/CODEOWNERS b/legacy/.github-legacy/CODEOWNERS new file mode 100644 index 0000000000..b983583855 --- /dev/null +++ b/legacy/.github-legacy/CODEOWNERS @@ -0,0 +1,8 @@ +# Website development +* @expressjs/docs-collaborators + +# Codeowners +.github/CODEOWNERS @expressjs/docs-captains + +# Blog +_posts @expressjs/express-tc \ No newline at end of file diff --git a/.github/dependabot.yml b/legacy/.github-legacy/dependabot.yml similarity index 100% rename from .github/dependabot.yml rename to legacy/.github-legacy/dependabot.yml diff --git a/.github/scripts/get-contributing.sh b/legacy/.github-legacy/scripts/get-contributing.sh similarity index 100% rename from .github/scripts/get-contributing.sh rename to legacy/.github-legacy/scripts/get-contributing.sh diff --git a/.github/scripts/get-express-version.mjs b/legacy/.github-legacy/scripts/get-express-version.mjs similarity index 100% rename from .github/scripts/get-express-version.mjs rename to legacy/.github-legacy/scripts/get-express-version.mjs diff --git a/.github/scripts/get-readmes.sh b/legacy/.github-legacy/scripts/get-readmes.sh similarity index 100% rename from .github/scripts/get-readmes.sh rename to legacy/.github-legacy/scripts/get-readmes.sh diff --git a/.github/workflows/ci.yml b/legacy/.github-legacy/workflows/ci.yml similarity index 100% rename from .github/workflows/ci.yml rename to legacy/.github-legacy/workflows/ci.yml diff --git a/legacy/.github-legacy/workflows/codeql.yml b/legacy/.github-legacy/workflows/codeql.yml new file mode 100644 index 0000000000..c01437a44e --- /dev/null +++ b/legacy/.github-legacy/workflows/codeql.yml @@ -0,0 +1,73 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: ["gh-pages"] + pull_request: + # The branches below must be a subset of the branches above + branches: ["gh-pages"] + schedule: + - cron: "0 0 * * 1" + +permissions: + contents: read + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: ["javascript", "actions"] + # CodeQL supports [ $supported-codeql-languages ] + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v4 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v4 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v4 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/crowdin.yml b/legacy/.github-legacy/workflows/crowdin.yml similarity index 100% rename from .github/workflows/crowdin.yml rename to legacy/.github-legacy/workflows/crowdin.yml diff --git a/.github/workflows/deploy.yml b/legacy/.github-legacy/workflows/deploy.yml similarity index 100% rename from .github/workflows/deploy.yml rename to legacy/.github-legacy/workflows/deploy.yml diff --git a/.github/workflows/lighthouse.yml b/legacy/.github-legacy/workflows/lighthouse.yml similarity index 100% rename from .github/workflows/lighthouse.yml rename to legacy/.github-legacy/workflows/lighthouse.yml diff --git a/legacy/.github-legacy/workflows/scorecards.yml b/legacy/.github-legacy/workflows/scorecards.yml new file mode 100644 index 0000000000..59dee089ba --- /dev/null +++ b/legacy/.github-legacy/workflows/scorecards.yml @@ -0,0 +1,76 @@ +# This workflow uses actions that are not certified by GitHub. They are provided +# by a third-party and are governed by separate terms of service, privacy +# policy, and support documentation. + +name: Scorecard supply-chain security +on: + # For Branch-Protection check. Only the default branch is supported. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection + branch_protection_rule: + # To guarantee Maintained check is occasionally updated. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained + schedule: + - cron: '20 7 * * 2' + push: + branches: ["gh-pages"] + +# Declare default permissions as read only. +permissions: read-all + +jobs: + analysis: + name: Scorecard analysis + runs-on: ubuntu-latest + permissions: + # Needed to upload the results to code-scanning dashboard. + security-events: write + # Needed to publish results and get a badge (see publish_results below). + id-token: write + contents: read + actions: read + # To allow GraphQL ListCommits to work + issues: read + pull-requests: read + # To detect SAST tools + checks: read + + steps: + - name: "Checkout code" + uses: actions/checkout@v6 + with: + persist-credentials: false + + - name: "Run analysis" + uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 + with: + results_file: results.sarif + results_format: sarif + # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: + # - you want to enable the Branch-Protection check on a *public* repository, or + # - you are installing Scorecards on a *private* repository + # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat. + # repo_token: ${{ secrets.SCORECARD_TOKEN }} + + # Public repositories: + # - Publish results to OpenSSF REST API for easy access by consumers + # - Allows the repository to include the Scorecard badge. + # - See https://github.com/ossf/scorecard-action#publishing-results. + # For private repositories: + # - `publish_results` will always be set to `false`, regardless + # of the value entered here. + publish_results: true + + # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF + # format to the repository Actions tab. + - name: "Upload artifact" + uses: actions/upload-artifact@v6 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + + # Upload the results to GitHub's code scanning dashboard. + - name: "Upload to code-scanning" + uses: github/codeql-action/upload-sarif@v4 + with: + sarif_file: results.sarif diff --git a/.github/workflows/update-external-docs.yml b/legacy/.github-legacy/workflows/update-external-docs.yml similarity index 100% rename from .github/workflows/update-external-docs.yml rename to legacy/.github-legacy/workflows/update-external-docs.yml diff --git a/.ruby-version b/legacy/.ruby-version similarity index 100% rename from .ruby-version rename to legacy/.ruby-version diff --git a/2x/applications.md b/legacy/2x/applications.md similarity index 100% rename from 2x/applications.md rename to legacy/2x/applications.md diff --git a/2x/contrib.md b/legacy/2x/contrib.md similarity index 100% rename from 2x/contrib.md rename to legacy/2x/contrib.md diff --git a/2x/docs/applications.md b/legacy/2x/docs/applications.md similarity index 100% rename from 2x/docs/applications.md rename to legacy/2x/docs/applications.md diff --git a/2x/docs/contrib.md b/legacy/2x/docs/contrib.md similarity index 100% rename from 2x/docs/contrib.md rename to legacy/2x/docs/contrib.md diff --git a/2x/docs/executable.md b/legacy/2x/docs/executable.md similarity index 100% rename from 2x/docs/executable.md rename to legacy/2x/docs/executable.md diff --git a/2x/docs/guide.md b/legacy/2x/docs/guide.md similarity index 100% rename from 2x/docs/guide.md rename to legacy/2x/docs/guide.md diff --git a/2x/docs/index.md b/legacy/2x/docs/index.md similarity index 100% rename from 2x/docs/index.md rename to legacy/2x/docs/index.md diff --git a/2x/docs/migrate.md b/legacy/2x/docs/migrate.md similarity index 100% rename from 2x/docs/migrate.md rename to legacy/2x/docs/migrate.md diff --git a/2x/docs/screencasts.md b/legacy/2x/docs/screencasts.md similarity index 100% rename from 2x/docs/screencasts.md rename to legacy/2x/docs/screencasts.md diff --git a/2x/executable.md b/legacy/2x/executable.md similarity index 100% rename from 2x/executable.md rename to legacy/2x/executable.md diff --git a/2x/guide.md b/legacy/2x/guide.md similarity index 100% rename from 2x/guide.md rename to legacy/2x/guide.md diff --git a/2x/index.md b/legacy/2x/index.md similarity index 100% rename from 2x/index.md rename to legacy/2x/index.md diff --git a/2x/migrate.md b/legacy/2x/migrate.md similarity index 100% rename from 2x/migrate.md rename to legacy/2x/migrate.md diff --git a/2x/screencasts.md b/legacy/2x/screencasts.md similarity index 100% rename from 2x/screencasts.md rename to legacy/2x/screencasts.md diff --git a/404.md b/legacy/404.md similarity index 100% rename from 404.md rename to legacy/404.md diff --git a/CNAME b/legacy/CNAME similarity index 100% rename from CNAME rename to legacy/CNAME diff --git a/CONTRIBUTING.md b/legacy/CONTRIBUTING.md similarity index 100% rename from CONTRIBUTING.md rename to legacy/CONTRIBUTING.md diff --git a/Dockerfile b/legacy/Dockerfile similarity index 100% rename from Dockerfile rename to legacy/Dockerfile diff --git a/Gemfile b/legacy/Gemfile similarity index 100% rename from Gemfile rename to legacy/Gemfile diff --git a/Gemfile.lock b/legacy/Gemfile.lock similarity index 100% rename from Gemfile.lock rename to legacy/Gemfile.lock diff --git a/Makefile b/legacy/Makefile similarity index 100% rename from Makefile rename to legacy/Makefile diff --git a/README.md b/legacy/README.md similarity index 100% rename from README.md rename to legacy/README.md diff --git a/_config.yml b/legacy/_config.yml similarity index 100% rename from _config.yml rename to legacy/_config.yml diff --git a/_data/de/footer.yml b/legacy/_data/de/footer.yml similarity index 100% rename from _data/de/footer.yml rename to legacy/_data/de/footer.yml diff --git a/_data/de/general.yml b/legacy/_data/de/general.yml similarity index 100% rename from _data/de/general.yml rename to legacy/_data/de/general.yml diff --git a/_data/de/menu.yml b/legacy/_data/de/menu.yml similarity index 100% rename from _data/de/menu.yml rename to legacy/_data/de/menu.yml diff --git a/_data/docsearch.yml b/legacy/_data/docsearch.yml similarity index 100% rename from _data/docsearch.yml rename to legacy/_data/docsearch.yml diff --git a/_data/en/footer.yml b/legacy/_data/en/footer.yml similarity index 100% rename from _data/en/footer.yml rename to legacy/_data/en/footer.yml diff --git a/_data/en/general.yml b/legacy/_data/en/general.yml similarity index 100% rename from _data/en/general.yml rename to legacy/_data/en/general.yml diff --git a/_data/en/menu.yml b/legacy/_data/en/menu.yml similarity index 100% rename from _data/en/menu.yml rename to legacy/_data/en/menu.yml diff --git a/_data/es/footer.yml b/legacy/_data/es/footer.yml similarity index 100% rename from _data/es/footer.yml rename to legacy/_data/es/footer.yml diff --git a/_data/es/general.yml b/legacy/_data/es/general.yml similarity index 100% rename from _data/es/general.yml rename to legacy/_data/es/general.yml diff --git a/_data/es/menu.yml b/legacy/_data/es/menu.yml similarity index 100% rename from _data/es/menu.yml rename to legacy/_data/es/menu.yml diff --git a/_data/express.yml b/legacy/_data/express.yml similarity index 100% rename from _data/express.yml rename to legacy/_data/express.yml diff --git a/_data/fr/footer.yml b/legacy/_data/fr/footer.yml similarity index 100% rename from _data/fr/footer.yml rename to legacy/_data/fr/footer.yml diff --git a/_data/fr/general.yml b/legacy/_data/fr/general.yml similarity index 100% rename from _data/fr/general.yml rename to legacy/_data/fr/general.yml diff --git a/_data/fr/menu.yml b/legacy/_data/fr/menu.yml similarity index 100% rename from _data/fr/menu.yml rename to legacy/_data/fr/menu.yml diff --git a/_data/it/footer.yml b/legacy/_data/it/footer.yml similarity index 100% rename from _data/it/footer.yml rename to legacy/_data/it/footer.yml diff --git a/_data/it/general.yml b/legacy/_data/it/general.yml similarity index 100% rename from _data/it/general.yml rename to legacy/_data/it/general.yml diff --git a/_data/it/menu.yml b/legacy/_data/it/menu.yml similarity index 100% rename from _data/it/menu.yml rename to legacy/_data/it/menu.yml diff --git a/_data/ja/footer.yml b/legacy/_data/ja/footer.yml similarity index 100% rename from _data/ja/footer.yml rename to legacy/_data/ja/footer.yml diff --git a/_data/ja/general.yml b/legacy/_data/ja/general.yml similarity index 100% rename from _data/ja/general.yml rename to legacy/_data/ja/general.yml diff --git a/_data/ja/menu.yml b/legacy/_data/ja/menu.yml similarity index 100% rename from _data/ja/menu.yml rename to legacy/_data/ja/menu.yml diff --git a/_data/ko/footer.yml b/legacy/_data/ko/footer.yml similarity index 100% rename from _data/ko/footer.yml rename to legacy/_data/ko/footer.yml diff --git a/_data/ko/general.yml b/legacy/_data/ko/general.yml similarity index 100% rename from _data/ko/general.yml rename to legacy/_data/ko/general.yml diff --git a/_data/ko/menu.yml b/legacy/_data/ko/menu.yml similarity index 100% rename from _data/ko/menu.yml rename to legacy/_data/ko/menu.yml diff --git a/_data/languages.yml b/legacy/_data/languages.yml similarity index 100% rename from _data/languages.yml rename to legacy/_data/languages.yml diff --git a/_data/pt-br/footer.yml b/legacy/_data/pt-br/footer.yml similarity index 100% rename from _data/pt-br/footer.yml rename to legacy/_data/pt-br/footer.yml diff --git a/_data/pt-br/general.yml b/legacy/_data/pt-br/general.yml similarity index 100% rename from _data/pt-br/general.yml rename to legacy/_data/pt-br/general.yml diff --git a/_data/pt-br/menu.yml b/legacy/_data/pt-br/menu.yml similarity index 100% rename from _data/pt-br/menu.yml rename to legacy/_data/pt-br/menu.yml diff --git a/_data/zh-cn/footer.yml b/legacy/_data/zh-cn/footer.yml similarity index 100% rename from _data/zh-cn/footer.yml rename to legacy/_data/zh-cn/footer.yml diff --git a/_data/zh-cn/general.yml b/legacy/_data/zh-cn/general.yml similarity index 100% rename from _data/zh-cn/general.yml rename to legacy/_data/zh-cn/general.yml diff --git a/_data/zh-cn/menu.yml b/legacy/_data/zh-cn/menu.yml similarity index 100% rename from _data/zh-cn/menu.yml rename to legacy/_data/zh-cn/menu.yml diff --git a/_data/zh-tw/footer.yml b/legacy/_data/zh-tw/footer.yml similarity index 100% rename from _data/zh-tw/footer.yml rename to legacy/_data/zh-tw/footer.yml diff --git a/_data/zh-tw/general.yml b/legacy/_data/zh-tw/general.yml similarity index 100% rename from _data/zh-tw/general.yml rename to legacy/_data/zh-tw/general.yml diff --git a/_data/zh-tw/menu.yml b/legacy/_data/zh-tw/menu.yml similarity index 100% rename from _data/zh-tw/menu.yml rename to legacy/_data/zh-tw/menu.yml diff --git a/_includes/admonitions/caution.html b/legacy/_includes/admonitions/caution.html similarity index 100% rename from _includes/admonitions/caution.html rename to legacy/_includes/admonitions/caution.html diff --git a/_includes/admonitions/note.html b/legacy/_includes/admonitions/note.html similarity index 100% rename from _includes/admonitions/note.html rename to legacy/_includes/admonitions/note.html diff --git a/_includes/admonitions/warning.html b/legacy/_includes/admonitions/warning.html similarity index 100% rename from _includes/admonitions/warning.html rename to legacy/_includes/admonitions/warning.html diff --git a/_includes/announcement.html b/legacy/_includes/announcement.html similarity index 100% rename from _includes/announcement.html rename to legacy/_includes/announcement.html diff --git a/_includes/api/en/3x/app-VERB.md b/legacy/_includes/api/en/3x/app-VERB.md similarity index 100% rename from _includes/api/en/3x/app-VERB.md rename to legacy/_includes/api/en/3x/app-VERB.md diff --git a/_includes/api/en/3x/app-all.md b/legacy/_includes/api/en/3x/app-all.md similarity index 100% rename from _includes/api/en/3x/app-all.md rename to legacy/_includes/api/en/3x/app-all.md diff --git a/_includes/api/en/3x/app-configure.md b/legacy/_includes/api/en/3x/app-configure.md similarity index 100% rename from _includes/api/en/3x/app-configure.md rename to legacy/_includes/api/en/3x/app-configure.md diff --git a/_includes/api/en/3x/app-disable.md b/legacy/_includes/api/en/3x/app-disable.md similarity index 100% rename from _includes/api/en/3x/app-disable.md rename to legacy/_includes/api/en/3x/app-disable.md diff --git a/_includes/api/en/3x/app-disabled.md b/legacy/_includes/api/en/3x/app-disabled.md similarity index 100% rename from _includes/api/en/3x/app-disabled.md rename to legacy/_includes/api/en/3x/app-disabled.md diff --git a/_includes/api/en/3x/app-enable.md b/legacy/_includes/api/en/3x/app-enable.md similarity index 100% rename from _includes/api/en/3x/app-enable.md rename to legacy/_includes/api/en/3x/app-enable.md diff --git a/_includes/api/en/3x/app-enabled.md b/legacy/_includes/api/en/3x/app-enabled.md similarity index 100% rename from _includes/api/en/3x/app-enabled.md rename to legacy/_includes/api/en/3x/app-enabled.md diff --git a/_includes/api/en/3x/app-engine.md b/legacy/_includes/api/en/3x/app-engine.md similarity index 100% rename from _includes/api/en/3x/app-engine.md rename to legacy/_includes/api/en/3x/app-engine.md diff --git a/_includes/api/en/3x/app-get.md b/legacy/_includes/api/en/3x/app-get.md similarity index 100% rename from _includes/api/en/3x/app-get.md rename to legacy/_includes/api/en/3x/app-get.md diff --git a/_includes/api/en/3x/app-listen.md b/legacy/_includes/api/en/3x/app-listen.md similarity index 100% rename from _includes/api/en/3x/app-listen.md rename to legacy/_includes/api/en/3x/app-listen.md diff --git a/_includes/api/en/3x/app-locals.md b/legacy/_includes/api/en/3x/app-locals.md similarity index 100% rename from _includes/api/en/3x/app-locals.md rename to legacy/_includes/api/en/3x/app-locals.md diff --git a/_includes/api/en/3x/app-param.md b/legacy/_includes/api/en/3x/app-param.md similarity index 100% rename from _includes/api/en/3x/app-param.md rename to legacy/_includes/api/en/3x/app-param.md diff --git a/_includes/api/en/3x/app-render.md b/legacy/_includes/api/en/3x/app-render.md similarity index 100% rename from _includes/api/en/3x/app-render.md rename to legacy/_includes/api/en/3x/app-render.md diff --git a/_includes/api/en/3x/app-routes.md b/legacy/_includes/api/en/3x/app-routes.md similarity index 100% rename from _includes/api/en/3x/app-routes.md rename to legacy/_includes/api/en/3x/app-routes.md diff --git a/_includes/api/en/3x/app-set.md b/legacy/_includes/api/en/3x/app-set.md similarity index 100% rename from _includes/api/en/3x/app-set.md rename to legacy/_includes/api/en/3x/app-set.md diff --git a/_includes/api/en/3x/app-settings.md b/legacy/_includes/api/en/3x/app-settings.md similarity index 100% rename from _includes/api/en/3x/app-settings.md rename to legacy/_includes/api/en/3x/app-settings.md diff --git a/_includes/api/en/3x/app-use.md b/legacy/_includes/api/en/3x/app-use.md similarity index 100% rename from _includes/api/en/3x/app-use.md rename to legacy/_includes/api/en/3x/app-use.md diff --git a/_includes/api/en/3x/app.md b/legacy/_includes/api/en/3x/app.md similarity index 100% rename from _includes/api/en/3x/app.md rename to legacy/_includes/api/en/3x/app.md diff --git a/_includes/api/en/3x/express.md b/legacy/_includes/api/en/3x/express.md similarity index 100% rename from _includes/api/en/3x/express.md rename to legacy/_includes/api/en/3x/express.md diff --git a/_includes/api/en/3x/menu.md b/legacy/_includes/api/en/3x/menu.md similarity index 100% rename from _includes/api/en/3x/menu.md rename to legacy/_includes/api/en/3x/menu.md diff --git a/_includes/api/en/3x/middleware.md b/legacy/_includes/api/en/3x/middleware.md similarity index 100% rename from _includes/api/en/3x/middleware.md rename to legacy/_includes/api/en/3x/middleware.md diff --git a/_includes/api/en/3x/mw-basicAuth.md b/legacy/_includes/api/en/3x/mw-basicAuth.md similarity index 100% rename from _includes/api/en/3x/mw-basicAuth.md rename to legacy/_includes/api/en/3x/mw-basicAuth.md diff --git a/_includes/api/en/3x/mw-bodyParser.md b/legacy/_includes/api/en/3x/mw-bodyParser.md similarity index 100% rename from _includes/api/en/3x/mw-bodyParser.md rename to legacy/_includes/api/en/3x/mw-bodyParser.md diff --git a/_includes/api/en/3x/mw-compress.md b/legacy/_includes/api/en/3x/mw-compress.md similarity index 100% rename from _includes/api/en/3x/mw-compress.md rename to legacy/_includes/api/en/3x/mw-compress.md diff --git a/_includes/api/en/3x/mw-cookieParser.md b/legacy/_includes/api/en/3x/mw-cookieParser.md similarity index 100% rename from _includes/api/en/3x/mw-cookieParser.md rename to legacy/_includes/api/en/3x/mw-cookieParser.md diff --git a/_includes/api/en/3x/mw-cookieSession.md b/legacy/_includes/api/en/3x/mw-cookieSession.md similarity index 100% rename from _includes/api/en/3x/mw-cookieSession.md rename to legacy/_includes/api/en/3x/mw-cookieSession.md diff --git a/_includes/api/en/3x/mw-csrf.md b/legacy/_includes/api/en/3x/mw-csrf.md similarity index 100% rename from _includes/api/en/3x/mw-csrf.md rename to legacy/_includes/api/en/3x/mw-csrf.md diff --git a/_includes/api/en/3x/mw-directory.md b/legacy/_includes/api/en/3x/mw-directory.md similarity index 100% rename from _includes/api/en/3x/mw-directory.md rename to legacy/_includes/api/en/3x/mw-directory.md diff --git a/_includes/api/en/3x/req-accepted.md b/legacy/_includes/api/en/3x/req-accepted.md similarity index 100% rename from _includes/api/en/3x/req-accepted.md rename to legacy/_includes/api/en/3x/req-accepted.md diff --git a/_includes/api/en/3x/req-acceptedCharsets.md b/legacy/_includes/api/en/3x/req-acceptedCharsets.md similarity index 100% rename from _includes/api/en/3x/req-acceptedCharsets.md rename to legacy/_includes/api/en/3x/req-acceptedCharsets.md diff --git a/_includes/api/en/3x/req-acceptedLanguages.md b/legacy/_includes/api/en/3x/req-acceptedLanguages.md similarity index 100% rename from _includes/api/en/3x/req-acceptedLanguages.md rename to legacy/_includes/api/en/3x/req-acceptedLanguages.md diff --git a/_includes/api/en/3x/req-accepts.md b/legacy/_includes/api/en/3x/req-accepts.md similarity index 100% rename from _includes/api/en/3x/req-accepts.md rename to legacy/_includes/api/en/3x/req-accepts.md diff --git a/_includes/api/en/3x/req-acceptsCharset.md b/legacy/_includes/api/en/3x/req-acceptsCharset.md similarity index 100% rename from _includes/api/en/3x/req-acceptsCharset.md rename to legacy/_includes/api/en/3x/req-acceptsCharset.md diff --git a/_includes/api/en/3x/req-acceptsLanguage.md b/legacy/_includes/api/en/3x/req-acceptsLanguage.md similarity index 100% rename from _includes/api/en/3x/req-acceptsLanguage.md rename to legacy/_includes/api/en/3x/req-acceptsLanguage.md diff --git a/_includes/api/en/3x/req-body.md b/legacy/_includes/api/en/3x/req-body.md similarity index 100% rename from _includes/api/en/3x/req-body.md rename to legacy/_includes/api/en/3x/req-body.md diff --git a/_includes/api/en/3x/req-cookies.md b/legacy/_includes/api/en/3x/req-cookies.md similarity index 100% rename from _includes/api/en/3x/req-cookies.md rename to legacy/_includes/api/en/3x/req-cookies.md diff --git a/_includes/api/en/3x/req-files.md b/legacy/_includes/api/en/3x/req-files.md similarity index 100% rename from _includes/api/en/3x/req-files.md rename to legacy/_includes/api/en/3x/req-files.md diff --git a/_includes/api/en/3x/req-fresh.md b/legacy/_includes/api/en/3x/req-fresh.md similarity index 100% rename from _includes/api/en/3x/req-fresh.md rename to legacy/_includes/api/en/3x/req-fresh.md diff --git a/_includes/api/en/3x/req-header.md b/legacy/_includes/api/en/3x/req-header.md similarity index 100% rename from _includes/api/en/3x/req-header.md rename to legacy/_includes/api/en/3x/req-header.md diff --git a/_includes/api/en/3x/req-host.md b/legacy/_includes/api/en/3x/req-host.md similarity index 100% rename from _includes/api/en/3x/req-host.md rename to legacy/_includes/api/en/3x/req-host.md diff --git a/_includes/api/en/3x/req-ip.md b/legacy/_includes/api/en/3x/req-ip.md similarity index 100% rename from _includes/api/en/3x/req-ip.md rename to legacy/_includes/api/en/3x/req-ip.md diff --git a/_includes/api/en/3x/req-ips.md b/legacy/_includes/api/en/3x/req-ips.md similarity index 100% rename from _includes/api/en/3x/req-ips.md rename to legacy/_includes/api/en/3x/req-ips.md diff --git a/_includes/api/en/3x/req-is.md b/legacy/_includes/api/en/3x/req-is.md similarity index 100% rename from _includes/api/en/3x/req-is.md rename to legacy/_includes/api/en/3x/req-is.md diff --git a/_includes/api/en/3x/req-originalUrl.md b/legacy/_includes/api/en/3x/req-originalUrl.md similarity index 100% rename from _includes/api/en/3x/req-originalUrl.md rename to legacy/_includes/api/en/3x/req-originalUrl.md diff --git a/_includes/api/en/3x/req-param.md b/legacy/_includes/api/en/3x/req-param.md similarity index 100% rename from _includes/api/en/3x/req-param.md rename to legacy/_includes/api/en/3x/req-param.md diff --git a/_includes/api/en/3x/req-params.md b/legacy/_includes/api/en/3x/req-params.md similarity index 100% rename from _includes/api/en/3x/req-params.md rename to legacy/_includes/api/en/3x/req-params.md diff --git a/_includes/api/en/3x/req-path.md b/legacy/_includes/api/en/3x/req-path.md similarity index 100% rename from _includes/api/en/3x/req-path.md rename to legacy/_includes/api/en/3x/req-path.md diff --git a/_includes/api/en/3x/req-protocol.md b/legacy/_includes/api/en/3x/req-protocol.md similarity index 100% rename from _includes/api/en/3x/req-protocol.md rename to legacy/_includes/api/en/3x/req-protocol.md diff --git a/_includes/api/en/3x/req-query.md b/legacy/_includes/api/en/3x/req-query.md similarity index 100% rename from _includes/api/en/3x/req-query.md rename to legacy/_includes/api/en/3x/req-query.md diff --git a/_includes/api/en/3x/req-res.md b/legacy/_includes/api/en/3x/req-res.md similarity index 100% rename from _includes/api/en/3x/req-res.md rename to legacy/_includes/api/en/3x/req-res.md diff --git a/_includes/api/en/3x/req-route.md b/legacy/_includes/api/en/3x/req-route.md similarity index 100% rename from _includes/api/en/3x/req-route.md rename to legacy/_includes/api/en/3x/req-route.md diff --git a/_includes/api/en/3x/req-secure.md b/legacy/_includes/api/en/3x/req-secure.md similarity index 100% rename from _includes/api/en/3x/req-secure.md rename to legacy/_includes/api/en/3x/req-secure.md diff --git a/_includes/api/en/3x/req-signedCookies.md b/legacy/_includes/api/en/3x/req-signedCookies.md similarity index 100% rename from _includes/api/en/3x/req-signedCookies.md rename to legacy/_includes/api/en/3x/req-signedCookies.md diff --git a/_includes/api/en/3x/req-stale.md b/legacy/_includes/api/en/3x/req-stale.md similarity index 100% rename from _includes/api/en/3x/req-stale.md rename to legacy/_includes/api/en/3x/req-stale.md diff --git a/_includes/api/en/3x/req-subdomains.md b/legacy/_includes/api/en/3x/req-subdomains.md similarity index 100% rename from _includes/api/en/3x/req-subdomains.md rename to legacy/_includes/api/en/3x/req-subdomains.md diff --git a/_includes/api/en/3x/req-xhr.md b/legacy/_includes/api/en/3x/req-xhr.md similarity index 100% rename from _includes/api/en/3x/req-xhr.md rename to legacy/_includes/api/en/3x/req-xhr.md diff --git a/_includes/api/en/3x/req.md b/legacy/_includes/api/en/3x/req.md similarity index 100% rename from _includes/api/en/3x/req.md rename to legacy/_includes/api/en/3x/req.md diff --git a/_includes/api/en/3x/res-attachment.md b/legacy/_includes/api/en/3x/res-attachment.md similarity index 100% rename from _includes/api/en/3x/res-attachment.md rename to legacy/_includes/api/en/3x/res-attachment.md diff --git a/_includes/api/en/3x/res-charset.md b/legacy/_includes/api/en/3x/res-charset.md similarity index 100% rename from _includes/api/en/3x/res-charset.md rename to legacy/_includes/api/en/3x/res-charset.md diff --git a/_includes/api/en/3x/res-clearCookie.md b/legacy/_includes/api/en/3x/res-clearCookie.md similarity index 100% rename from _includes/api/en/3x/res-clearCookie.md rename to legacy/_includes/api/en/3x/res-clearCookie.md diff --git a/_includes/api/en/3x/res-cookie.md b/legacy/_includes/api/en/3x/res-cookie.md similarity index 100% rename from _includes/api/en/3x/res-cookie.md rename to legacy/_includes/api/en/3x/res-cookie.md diff --git a/_includes/api/en/3x/res-download.md b/legacy/_includes/api/en/3x/res-download.md similarity index 100% rename from _includes/api/en/3x/res-download.md rename to legacy/_includes/api/en/3x/res-download.md diff --git a/_includes/api/en/3x/res-format.md b/legacy/_includes/api/en/3x/res-format.md similarity index 100% rename from _includes/api/en/3x/res-format.md rename to legacy/_includes/api/en/3x/res-format.md diff --git a/_includes/api/en/3x/res-get.md b/legacy/_includes/api/en/3x/res-get.md similarity index 100% rename from _includes/api/en/3x/res-get.md rename to legacy/_includes/api/en/3x/res-get.md diff --git a/_includes/api/en/3x/res-json.md b/legacy/_includes/api/en/3x/res-json.md similarity index 100% rename from _includes/api/en/3x/res-json.md rename to legacy/_includes/api/en/3x/res-json.md diff --git a/_includes/api/en/3x/res-jsonp.md b/legacy/_includes/api/en/3x/res-jsonp.md similarity index 100% rename from _includes/api/en/3x/res-jsonp.md rename to legacy/_includes/api/en/3x/res-jsonp.md diff --git a/_includes/api/en/3x/res-links.md b/legacy/_includes/api/en/3x/res-links.md similarity index 100% rename from _includes/api/en/3x/res-links.md rename to legacy/_includes/api/en/3x/res-links.md diff --git a/_includes/api/en/3x/res-locals.md b/legacy/_includes/api/en/3x/res-locals.md similarity index 100% rename from _includes/api/en/3x/res-locals.md rename to legacy/_includes/api/en/3x/res-locals.md diff --git a/_includes/api/en/3x/res-location.md b/legacy/_includes/api/en/3x/res-location.md similarity index 100% rename from _includes/api/en/3x/res-location.md rename to legacy/_includes/api/en/3x/res-location.md diff --git a/_includes/api/en/3x/res-redirect.md b/legacy/_includes/api/en/3x/res-redirect.md similarity index 100% rename from _includes/api/en/3x/res-redirect.md rename to legacy/_includes/api/en/3x/res-redirect.md diff --git a/_includes/api/en/3x/res-render.md b/legacy/_includes/api/en/3x/res-render.md similarity index 100% rename from _includes/api/en/3x/res-render.md rename to legacy/_includes/api/en/3x/res-render.md diff --git a/_includes/api/en/3x/res-req.md b/legacy/_includes/api/en/3x/res-req.md similarity index 100% rename from _includes/api/en/3x/res-req.md rename to legacy/_includes/api/en/3x/res-req.md diff --git a/_includes/api/en/3x/res-send.md b/legacy/_includes/api/en/3x/res-send.md similarity index 100% rename from _includes/api/en/3x/res-send.md rename to legacy/_includes/api/en/3x/res-send.md diff --git a/_includes/api/en/3x/res-sendfile.md b/legacy/_includes/api/en/3x/res-sendfile.md similarity index 100% rename from _includes/api/en/3x/res-sendfile.md rename to legacy/_includes/api/en/3x/res-sendfile.md diff --git a/_includes/api/en/3x/res-set.md b/legacy/_includes/api/en/3x/res-set.md similarity index 100% rename from _includes/api/en/3x/res-set.md rename to legacy/_includes/api/en/3x/res-set.md diff --git a/_includes/api/en/3x/res-status.md b/legacy/_includes/api/en/3x/res-status.md similarity index 100% rename from _includes/api/en/3x/res-status.md rename to legacy/_includes/api/en/3x/res-status.md diff --git a/_includes/api/en/3x/res-type.md b/legacy/_includes/api/en/3x/res-type.md similarity index 100% rename from _includes/api/en/3x/res-type.md rename to legacy/_includes/api/en/3x/res-type.md diff --git a/_includes/api/en/3x/res.md b/legacy/_includes/api/en/3x/res.md similarity index 100% rename from _includes/api/en/3x/res.md rename to legacy/_includes/api/en/3x/res.md diff --git a/_includes/api/en/4x/app-METHOD.md b/legacy/_includes/api/en/4x/app-METHOD.md similarity index 100% rename from _includes/api/en/4x/app-METHOD.md rename to legacy/_includes/api/en/4x/app-METHOD.md diff --git a/_includes/api/en/4x/app-all.md b/legacy/_includes/api/en/4x/app-all.md similarity index 100% rename from _includes/api/en/4x/app-all.md rename to legacy/_includes/api/en/4x/app-all.md diff --git a/_includes/api/en/4x/app-delete-method.md b/legacy/_includes/api/en/4x/app-delete-method.md similarity index 100% rename from _includes/api/en/4x/app-delete-method.md rename to legacy/_includes/api/en/4x/app-delete-method.md diff --git a/_includes/api/en/4x/app-disable.md b/legacy/_includes/api/en/4x/app-disable.md similarity index 100% rename from _includes/api/en/4x/app-disable.md rename to legacy/_includes/api/en/4x/app-disable.md diff --git a/_includes/api/en/4x/app-disabled.md b/legacy/_includes/api/en/4x/app-disabled.md similarity index 100% rename from _includes/api/en/4x/app-disabled.md rename to legacy/_includes/api/en/4x/app-disabled.md diff --git a/_includes/api/en/4x/app-enable.md b/legacy/_includes/api/en/4x/app-enable.md similarity index 100% rename from _includes/api/en/4x/app-enable.md rename to legacy/_includes/api/en/4x/app-enable.md diff --git a/_includes/api/en/4x/app-enabled.md b/legacy/_includes/api/en/4x/app-enabled.md similarity index 100% rename from _includes/api/en/4x/app-enabled.md rename to legacy/_includes/api/en/4x/app-enabled.md diff --git a/_includes/api/en/4x/app-engine.md b/legacy/_includes/api/en/4x/app-engine.md similarity index 100% rename from _includes/api/en/4x/app-engine.md rename to legacy/_includes/api/en/4x/app-engine.md diff --git a/_includes/api/en/4x/app-get-method.md b/legacy/_includes/api/en/4x/app-get-method.md similarity index 100% rename from _includes/api/en/4x/app-get-method.md rename to legacy/_includes/api/en/4x/app-get-method.md diff --git a/_includes/api/en/4x/app-get.md b/legacy/_includes/api/en/4x/app-get.md similarity index 100% rename from _includes/api/en/4x/app-get.md rename to legacy/_includes/api/en/4x/app-get.md diff --git a/_includes/api/en/4x/app-listen.md b/legacy/_includes/api/en/4x/app-listen.md similarity index 100% rename from _includes/api/en/4x/app-listen.md rename to legacy/_includes/api/en/4x/app-listen.md diff --git a/_includes/api/en/4x/app-locals.md b/legacy/_includes/api/en/4x/app-locals.md similarity index 100% rename from _includes/api/en/4x/app-locals.md rename to legacy/_includes/api/en/4x/app-locals.md diff --git a/_includes/api/en/4x/app-mountpath.md b/legacy/_includes/api/en/4x/app-mountpath.md similarity index 100% rename from _includes/api/en/4x/app-mountpath.md rename to legacy/_includes/api/en/4x/app-mountpath.md diff --git a/_includes/api/en/4x/app-onmount.md b/legacy/_includes/api/en/4x/app-onmount.md similarity index 100% rename from _includes/api/en/4x/app-onmount.md rename to legacy/_includes/api/en/4x/app-onmount.md diff --git a/_includes/api/en/4x/app-param.md b/legacy/_includes/api/en/4x/app-param.md similarity index 100% rename from _includes/api/en/4x/app-param.md rename to legacy/_includes/api/en/4x/app-param.md diff --git a/_includes/api/en/4x/app-path.md b/legacy/_includes/api/en/4x/app-path.md similarity index 100% rename from _includes/api/en/4x/app-path.md rename to legacy/_includes/api/en/4x/app-path.md diff --git a/_includes/api/en/4x/app-post-method.md b/legacy/_includes/api/en/4x/app-post-method.md similarity index 100% rename from _includes/api/en/4x/app-post-method.md rename to legacy/_includes/api/en/4x/app-post-method.md diff --git a/_includes/api/en/4x/app-put-method.md b/legacy/_includes/api/en/4x/app-put-method.md similarity index 100% rename from _includes/api/en/4x/app-put-method.md rename to legacy/_includes/api/en/4x/app-put-method.md diff --git a/_includes/api/en/4x/app-render.md b/legacy/_includes/api/en/4x/app-render.md similarity index 100% rename from _includes/api/en/4x/app-render.md rename to legacy/_includes/api/en/4x/app-render.md diff --git a/_includes/api/en/4x/app-route.md b/legacy/_includes/api/en/4x/app-route.md similarity index 100% rename from _includes/api/en/4x/app-route.md rename to legacy/_includes/api/en/4x/app-route.md diff --git a/_includes/api/en/4x/app-set.md b/legacy/_includes/api/en/4x/app-set.md similarity index 100% rename from _includes/api/en/4x/app-set.md rename to legacy/_includes/api/en/4x/app-set.md diff --git a/_includes/api/en/4x/app-settings.md b/legacy/_includes/api/en/4x/app-settings.md similarity index 100% rename from _includes/api/en/4x/app-settings.md rename to legacy/_includes/api/en/4x/app-settings.md diff --git a/_includes/api/en/4x/app-use.md b/legacy/_includes/api/en/4x/app-use.md similarity index 100% rename from _includes/api/en/4x/app-use.md rename to legacy/_includes/api/en/4x/app-use.md diff --git a/_includes/api/en/4x/app.md b/legacy/_includes/api/en/4x/app.md similarity index 100% rename from _includes/api/en/4x/app.md rename to legacy/_includes/api/en/4x/app.md diff --git a/_includes/api/en/4x/express.json.md b/legacy/_includes/api/en/4x/express.json.md similarity index 100% rename from _includes/api/en/4x/express.json.md rename to legacy/_includes/api/en/4x/express.json.md diff --git a/_includes/api/en/4x/express.md b/legacy/_includes/api/en/4x/express.md similarity index 100% rename from _includes/api/en/4x/express.md rename to legacy/_includes/api/en/4x/express.md diff --git a/_includes/api/en/4x/express.raw.md b/legacy/_includes/api/en/4x/express.raw.md similarity index 100% rename from _includes/api/en/4x/express.raw.md rename to legacy/_includes/api/en/4x/express.raw.md diff --git a/_includes/api/en/4x/express.router.md b/legacy/_includes/api/en/4x/express.router.md similarity index 100% rename from _includes/api/en/4x/express.router.md rename to legacy/_includes/api/en/4x/express.router.md diff --git a/_includes/api/en/4x/express.static.md b/legacy/_includes/api/en/4x/express.static.md similarity index 100% rename from _includes/api/en/4x/express.static.md rename to legacy/_includes/api/en/4x/express.static.md diff --git a/_includes/api/en/4x/express.text.md b/legacy/_includes/api/en/4x/express.text.md similarity index 100% rename from _includes/api/en/4x/express.text.md rename to legacy/_includes/api/en/4x/express.text.md diff --git a/_includes/api/en/4x/express.urlencoded.md b/legacy/_includes/api/en/4x/express.urlencoded.md similarity index 100% rename from _includes/api/en/4x/express.urlencoded.md rename to legacy/_includes/api/en/4x/express.urlencoded.md diff --git a/_includes/api/en/4x/menu.md b/legacy/_includes/api/en/4x/menu.md similarity index 100% rename from _includes/api/en/4x/menu.md rename to legacy/_includes/api/en/4x/menu.md diff --git a/_includes/api/en/4x/req-accepts.md b/legacy/_includes/api/en/4x/req-accepts.md similarity index 100% rename from _includes/api/en/4x/req-accepts.md rename to legacy/_includes/api/en/4x/req-accepts.md diff --git a/_includes/api/en/4x/req-acceptsCharsets.md b/legacy/_includes/api/en/4x/req-acceptsCharsets.md similarity index 100% rename from _includes/api/en/4x/req-acceptsCharsets.md rename to legacy/_includes/api/en/4x/req-acceptsCharsets.md diff --git a/_includes/api/en/4x/req-acceptsEncodings.md b/legacy/_includes/api/en/4x/req-acceptsEncodings.md similarity index 100% rename from _includes/api/en/4x/req-acceptsEncodings.md rename to legacy/_includes/api/en/4x/req-acceptsEncodings.md diff --git a/_includes/api/en/4x/req-acceptsLanguages.md b/legacy/_includes/api/en/4x/req-acceptsLanguages.md similarity index 100% rename from _includes/api/en/4x/req-acceptsLanguages.md rename to legacy/_includes/api/en/4x/req-acceptsLanguages.md diff --git a/_includes/api/en/4x/req-app.md b/legacy/_includes/api/en/4x/req-app.md similarity index 100% rename from _includes/api/en/4x/req-app.md rename to legacy/_includes/api/en/4x/req-app.md diff --git a/_includes/api/en/4x/req-baseUrl.md b/legacy/_includes/api/en/4x/req-baseUrl.md similarity index 100% rename from _includes/api/en/4x/req-baseUrl.md rename to legacy/_includes/api/en/4x/req-baseUrl.md diff --git a/_includes/api/en/4x/req-body.md b/legacy/_includes/api/en/4x/req-body.md similarity index 100% rename from _includes/api/en/4x/req-body.md rename to legacy/_includes/api/en/4x/req-body.md diff --git a/_includes/api/en/4x/req-cookies.md b/legacy/_includes/api/en/4x/req-cookies.md similarity index 100% rename from _includes/api/en/4x/req-cookies.md rename to legacy/_includes/api/en/4x/req-cookies.md diff --git a/_includes/api/en/4x/req-fresh.md b/legacy/_includes/api/en/4x/req-fresh.md similarity index 100% rename from _includes/api/en/4x/req-fresh.md rename to legacy/_includes/api/en/4x/req-fresh.md diff --git a/_includes/api/en/4x/req-get.md b/legacy/_includes/api/en/4x/req-get.md similarity index 100% rename from _includes/api/en/4x/req-get.md rename to legacy/_includes/api/en/4x/req-get.md diff --git a/_includes/api/en/4x/req-hostname.md b/legacy/_includes/api/en/4x/req-hostname.md similarity index 100% rename from _includes/api/en/4x/req-hostname.md rename to legacy/_includes/api/en/4x/req-hostname.md diff --git a/_includes/api/en/4x/req-ip.md b/legacy/_includes/api/en/4x/req-ip.md similarity index 100% rename from _includes/api/en/4x/req-ip.md rename to legacy/_includes/api/en/4x/req-ip.md diff --git a/_includes/api/en/4x/req-ips.md b/legacy/_includes/api/en/4x/req-ips.md similarity index 100% rename from _includes/api/en/4x/req-ips.md rename to legacy/_includes/api/en/4x/req-ips.md diff --git a/_includes/api/en/4x/req-is.md b/legacy/_includes/api/en/4x/req-is.md similarity index 100% rename from _includes/api/en/4x/req-is.md rename to legacy/_includes/api/en/4x/req-is.md diff --git a/_includes/api/en/4x/req-method.md b/legacy/_includes/api/en/4x/req-method.md similarity index 100% rename from _includes/api/en/4x/req-method.md rename to legacy/_includes/api/en/4x/req-method.md diff --git a/_includes/api/en/4x/req-originalUrl.md b/legacy/_includes/api/en/4x/req-originalUrl.md similarity index 100% rename from _includes/api/en/4x/req-originalUrl.md rename to legacy/_includes/api/en/4x/req-originalUrl.md diff --git a/_includes/api/en/4x/req-param.md b/legacy/_includes/api/en/4x/req-param.md similarity index 100% rename from _includes/api/en/4x/req-param.md rename to legacy/_includes/api/en/4x/req-param.md diff --git a/_includes/api/en/4x/req-params.md b/legacy/_includes/api/en/4x/req-params.md similarity index 100% rename from _includes/api/en/4x/req-params.md rename to legacy/_includes/api/en/4x/req-params.md diff --git a/_includes/api/en/4x/req-path.md b/legacy/_includes/api/en/4x/req-path.md similarity index 100% rename from _includes/api/en/4x/req-path.md rename to legacy/_includes/api/en/4x/req-path.md diff --git a/_includes/api/en/4x/req-protocol.md b/legacy/_includes/api/en/4x/req-protocol.md similarity index 100% rename from _includes/api/en/4x/req-protocol.md rename to legacy/_includes/api/en/4x/req-protocol.md diff --git a/_includes/api/en/4x/req-query.md b/legacy/_includes/api/en/4x/req-query.md similarity index 100% rename from _includes/api/en/4x/req-query.md rename to legacy/_includes/api/en/4x/req-query.md diff --git a/_includes/api/en/4x/req-range.md b/legacy/_includes/api/en/4x/req-range.md similarity index 100% rename from _includes/api/en/4x/req-range.md rename to legacy/_includes/api/en/4x/req-range.md diff --git a/_includes/api/en/4x/req-res.md b/legacy/_includes/api/en/4x/req-res.md similarity index 100% rename from _includes/api/en/4x/req-res.md rename to legacy/_includes/api/en/4x/req-res.md diff --git a/_includes/api/en/4x/req-route.md b/legacy/_includes/api/en/4x/req-route.md similarity index 100% rename from _includes/api/en/4x/req-route.md rename to legacy/_includes/api/en/4x/req-route.md diff --git a/_includes/api/en/4x/req-secure.md b/legacy/_includes/api/en/4x/req-secure.md similarity index 100% rename from _includes/api/en/4x/req-secure.md rename to legacy/_includes/api/en/4x/req-secure.md diff --git a/_includes/api/en/4x/req-signedCookies.md b/legacy/_includes/api/en/4x/req-signedCookies.md similarity index 100% rename from _includes/api/en/4x/req-signedCookies.md rename to legacy/_includes/api/en/4x/req-signedCookies.md diff --git a/_includes/api/en/4x/req-stale.md b/legacy/_includes/api/en/4x/req-stale.md similarity index 100% rename from _includes/api/en/4x/req-stale.md rename to legacy/_includes/api/en/4x/req-stale.md diff --git a/_includes/api/en/4x/req-subdomains.md b/legacy/_includes/api/en/4x/req-subdomains.md similarity index 100% rename from _includes/api/en/4x/req-subdomains.md rename to legacy/_includes/api/en/4x/req-subdomains.md diff --git a/_includes/api/en/4x/req-xhr.md b/legacy/_includes/api/en/4x/req-xhr.md similarity index 100% rename from _includes/api/en/4x/req-xhr.md rename to legacy/_includes/api/en/4x/req-xhr.md diff --git a/_includes/api/en/4x/req.md b/legacy/_includes/api/en/4x/req.md similarity index 100% rename from _includes/api/en/4x/req.md rename to legacy/_includes/api/en/4x/req.md diff --git a/_includes/api/en/4x/res-app.md b/legacy/_includes/api/en/4x/res-app.md similarity index 100% rename from _includes/api/en/4x/res-app.md rename to legacy/_includes/api/en/4x/res-app.md diff --git a/_includes/api/en/4x/res-append.md b/legacy/_includes/api/en/4x/res-append.md similarity index 100% rename from _includes/api/en/4x/res-append.md rename to legacy/_includes/api/en/4x/res-append.md diff --git a/_includes/api/en/4x/res-attachment.md b/legacy/_includes/api/en/4x/res-attachment.md similarity index 100% rename from _includes/api/en/4x/res-attachment.md rename to legacy/_includes/api/en/4x/res-attachment.md diff --git a/_includes/api/en/4x/res-clearCookie.md b/legacy/_includes/api/en/4x/res-clearCookie.md similarity index 100% rename from _includes/api/en/4x/res-clearCookie.md rename to legacy/_includes/api/en/4x/res-clearCookie.md diff --git a/_includes/api/en/4x/res-cookie.md b/legacy/_includes/api/en/4x/res-cookie.md similarity index 100% rename from _includes/api/en/4x/res-cookie.md rename to legacy/_includes/api/en/4x/res-cookie.md diff --git a/_includes/api/en/4x/res-download.md b/legacy/_includes/api/en/4x/res-download.md similarity index 100% rename from _includes/api/en/4x/res-download.md rename to legacy/_includes/api/en/4x/res-download.md diff --git a/_includes/api/en/4x/res-end.md b/legacy/_includes/api/en/4x/res-end.md similarity index 100% rename from _includes/api/en/4x/res-end.md rename to legacy/_includes/api/en/4x/res-end.md diff --git a/_includes/api/en/4x/res-format.md b/legacy/_includes/api/en/4x/res-format.md similarity index 100% rename from _includes/api/en/4x/res-format.md rename to legacy/_includes/api/en/4x/res-format.md diff --git a/_includes/api/en/4x/res-get.md b/legacy/_includes/api/en/4x/res-get.md similarity index 100% rename from _includes/api/en/4x/res-get.md rename to legacy/_includes/api/en/4x/res-get.md diff --git a/_includes/api/en/4x/res-headersSent.md b/legacy/_includes/api/en/4x/res-headersSent.md similarity index 100% rename from _includes/api/en/4x/res-headersSent.md rename to legacy/_includes/api/en/4x/res-headersSent.md diff --git a/_includes/api/en/4x/res-json.md b/legacy/_includes/api/en/4x/res-json.md similarity index 100% rename from _includes/api/en/4x/res-json.md rename to legacy/_includes/api/en/4x/res-json.md diff --git a/_includes/api/en/4x/res-jsonp.md b/legacy/_includes/api/en/4x/res-jsonp.md similarity index 100% rename from _includes/api/en/4x/res-jsonp.md rename to legacy/_includes/api/en/4x/res-jsonp.md diff --git a/_includes/api/en/4x/res-links.md b/legacy/_includes/api/en/4x/res-links.md similarity index 100% rename from _includes/api/en/4x/res-links.md rename to legacy/_includes/api/en/4x/res-links.md diff --git a/_includes/api/en/4x/res-locals.md b/legacy/_includes/api/en/4x/res-locals.md similarity index 100% rename from _includes/api/en/4x/res-locals.md rename to legacy/_includes/api/en/4x/res-locals.md diff --git a/_includes/api/en/4x/res-location.md b/legacy/_includes/api/en/4x/res-location.md similarity index 100% rename from _includes/api/en/4x/res-location.md rename to legacy/_includes/api/en/4x/res-location.md diff --git a/_includes/api/en/4x/res-redirect.md b/legacy/_includes/api/en/4x/res-redirect.md similarity index 100% rename from _includes/api/en/4x/res-redirect.md rename to legacy/_includes/api/en/4x/res-redirect.md diff --git a/_includes/api/en/4x/res-render.md b/legacy/_includes/api/en/4x/res-render.md similarity index 100% rename from _includes/api/en/4x/res-render.md rename to legacy/_includes/api/en/4x/res-render.md diff --git a/_includes/api/en/4x/res-req.md b/legacy/_includes/api/en/4x/res-req.md similarity index 100% rename from _includes/api/en/4x/res-req.md rename to legacy/_includes/api/en/4x/res-req.md diff --git a/_includes/api/en/4x/res-send.md b/legacy/_includes/api/en/4x/res-send.md similarity index 100% rename from _includes/api/en/4x/res-send.md rename to legacy/_includes/api/en/4x/res-send.md diff --git a/_includes/api/en/4x/res-sendFile.md b/legacy/_includes/api/en/4x/res-sendFile.md similarity index 100% rename from _includes/api/en/4x/res-sendFile.md rename to legacy/_includes/api/en/4x/res-sendFile.md diff --git a/_includes/api/en/4x/res-sendStatus.md b/legacy/_includes/api/en/4x/res-sendStatus.md similarity index 100% rename from _includes/api/en/4x/res-sendStatus.md rename to legacy/_includes/api/en/4x/res-sendStatus.md diff --git a/_includes/api/en/4x/res-set.md b/legacy/_includes/api/en/4x/res-set.md similarity index 100% rename from _includes/api/en/4x/res-set.md rename to legacy/_includes/api/en/4x/res-set.md diff --git a/_includes/api/en/4x/res-status.md b/legacy/_includes/api/en/4x/res-status.md similarity index 100% rename from _includes/api/en/4x/res-status.md rename to legacy/_includes/api/en/4x/res-status.md diff --git a/_includes/api/en/4x/res-type.md b/legacy/_includes/api/en/4x/res-type.md similarity index 100% rename from _includes/api/en/4x/res-type.md rename to legacy/_includes/api/en/4x/res-type.md diff --git a/_includes/api/en/4x/res-vary.md b/legacy/_includes/api/en/4x/res-vary.md similarity index 100% rename from _includes/api/en/4x/res-vary.md rename to legacy/_includes/api/en/4x/res-vary.md diff --git a/_includes/api/en/4x/res.md b/legacy/_includes/api/en/4x/res.md similarity index 100% rename from _includes/api/en/4x/res.md rename to legacy/_includes/api/en/4x/res.md diff --git a/_includes/api/en/4x/router-METHOD.md b/legacy/_includes/api/en/4x/router-METHOD.md similarity index 100% rename from _includes/api/en/4x/router-METHOD.md rename to legacy/_includes/api/en/4x/router-METHOD.md diff --git a/_includes/api/en/4x/router-Router.md b/legacy/_includes/api/en/4x/router-Router.md similarity index 100% rename from _includes/api/en/4x/router-Router.md rename to legacy/_includes/api/en/4x/router-Router.md diff --git a/_includes/api/en/4x/router-all.md b/legacy/_includes/api/en/4x/router-all.md similarity index 100% rename from _includes/api/en/4x/router-all.md rename to legacy/_includes/api/en/4x/router-all.md diff --git a/_includes/api/en/4x/router-param.md b/legacy/_includes/api/en/4x/router-param.md similarity index 100% rename from _includes/api/en/4x/router-param.md rename to legacy/_includes/api/en/4x/router-param.md diff --git a/_includes/api/en/4x/router-route.md b/legacy/_includes/api/en/4x/router-route.md similarity index 100% rename from _includes/api/en/4x/router-route.md rename to legacy/_includes/api/en/4x/router-route.md diff --git a/_includes/api/en/4x/router-use.md b/legacy/_includes/api/en/4x/router-use.md similarity index 100% rename from _includes/api/en/4x/router-use.md rename to legacy/_includes/api/en/4x/router-use.md diff --git a/_includes/api/en/4x/router.md b/legacy/_includes/api/en/4x/router.md similarity index 100% rename from _includes/api/en/4x/router.md rename to legacy/_includes/api/en/4x/router.md diff --git a/_includes/api/en/4x/routing-args.html b/legacy/_includes/api/en/4x/routing-args.html similarity index 100% rename from _includes/api/en/4x/routing-args.html rename to legacy/_includes/api/en/4x/routing-args.html diff --git a/_includes/api/en/5x/app-METHOD.md b/legacy/_includes/api/en/5x/app-METHOD.md similarity index 100% rename from _includes/api/en/5x/app-METHOD.md rename to legacy/_includes/api/en/5x/app-METHOD.md diff --git a/_includes/api/en/5x/app-all.md b/legacy/_includes/api/en/5x/app-all.md similarity index 100% rename from _includes/api/en/5x/app-all.md rename to legacy/_includes/api/en/5x/app-all.md diff --git a/_includes/api/en/5x/app-delete-method.md b/legacy/_includes/api/en/5x/app-delete-method.md similarity index 100% rename from _includes/api/en/5x/app-delete-method.md rename to legacy/_includes/api/en/5x/app-delete-method.md diff --git a/_includes/api/en/5x/app-disable.md b/legacy/_includes/api/en/5x/app-disable.md similarity index 100% rename from _includes/api/en/5x/app-disable.md rename to legacy/_includes/api/en/5x/app-disable.md diff --git a/_includes/api/en/5x/app-disabled.md b/legacy/_includes/api/en/5x/app-disabled.md similarity index 100% rename from _includes/api/en/5x/app-disabled.md rename to legacy/_includes/api/en/5x/app-disabled.md diff --git a/_includes/api/en/5x/app-enable.md b/legacy/_includes/api/en/5x/app-enable.md similarity index 100% rename from _includes/api/en/5x/app-enable.md rename to legacy/_includes/api/en/5x/app-enable.md diff --git a/_includes/api/en/5x/app-enabled.md b/legacy/_includes/api/en/5x/app-enabled.md similarity index 100% rename from _includes/api/en/5x/app-enabled.md rename to legacy/_includes/api/en/5x/app-enabled.md diff --git a/_includes/api/en/5x/app-engine.md b/legacy/_includes/api/en/5x/app-engine.md similarity index 100% rename from _includes/api/en/5x/app-engine.md rename to legacy/_includes/api/en/5x/app-engine.md diff --git a/_includes/api/en/5x/app-get-method.md b/legacy/_includes/api/en/5x/app-get-method.md similarity index 100% rename from _includes/api/en/5x/app-get-method.md rename to legacy/_includes/api/en/5x/app-get-method.md diff --git a/_includes/api/en/5x/app-get.md b/legacy/_includes/api/en/5x/app-get.md similarity index 100% rename from _includes/api/en/5x/app-get.md rename to legacy/_includes/api/en/5x/app-get.md diff --git a/_includes/api/en/5x/app-listen.md b/legacy/_includes/api/en/5x/app-listen.md similarity index 100% rename from _includes/api/en/5x/app-listen.md rename to legacy/_includes/api/en/5x/app-listen.md diff --git a/_includes/api/en/5x/app-locals.md b/legacy/_includes/api/en/5x/app-locals.md similarity index 100% rename from _includes/api/en/5x/app-locals.md rename to legacy/_includes/api/en/5x/app-locals.md diff --git a/_includes/api/en/5x/app-mountpath.md b/legacy/_includes/api/en/5x/app-mountpath.md similarity index 100% rename from _includes/api/en/5x/app-mountpath.md rename to legacy/_includes/api/en/5x/app-mountpath.md diff --git a/_includes/api/en/5x/app-onmount.md b/legacy/_includes/api/en/5x/app-onmount.md similarity index 100% rename from _includes/api/en/5x/app-onmount.md rename to legacy/_includes/api/en/5x/app-onmount.md diff --git a/_includes/api/en/5x/app-param.md b/legacy/_includes/api/en/5x/app-param.md similarity index 100% rename from _includes/api/en/5x/app-param.md rename to legacy/_includes/api/en/5x/app-param.md diff --git a/_includes/api/en/5x/app-path.md b/legacy/_includes/api/en/5x/app-path.md similarity index 100% rename from _includes/api/en/5x/app-path.md rename to legacy/_includes/api/en/5x/app-path.md diff --git a/_includes/api/en/5x/app-post-method.md b/legacy/_includes/api/en/5x/app-post-method.md similarity index 100% rename from _includes/api/en/5x/app-post-method.md rename to legacy/_includes/api/en/5x/app-post-method.md diff --git a/_includes/api/en/5x/app-put-method.md b/legacy/_includes/api/en/5x/app-put-method.md similarity index 100% rename from _includes/api/en/5x/app-put-method.md rename to legacy/_includes/api/en/5x/app-put-method.md diff --git a/_includes/api/en/5x/app-render.md b/legacy/_includes/api/en/5x/app-render.md similarity index 100% rename from _includes/api/en/5x/app-render.md rename to legacy/_includes/api/en/5x/app-render.md diff --git a/_includes/api/en/5x/app-route.md b/legacy/_includes/api/en/5x/app-route.md similarity index 100% rename from _includes/api/en/5x/app-route.md rename to legacy/_includes/api/en/5x/app-route.md diff --git a/_includes/api/en/5x/app-router.md b/legacy/_includes/api/en/5x/app-router.md similarity index 100% rename from _includes/api/en/5x/app-router.md rename to legacy/_includes/api/en/5x/app-router.md diff --git a/_includes/api/en/5x/app-set.md b/legacy/_includes/api/en/5x/app-set.md similarity index 100% rename from _includes/api/en/5x/app-set.md rename to legacy/_includes/api/en/5x/app-set.md diff --git a/_includes/api/en/5x/app-settings.md b/legacy/_includes/api/en/5x/app-settings.md similarity index 100% rename from _includes/api/en/5x/app-settings.md rename to legacy/_includes/api/en/5x/app-settings.md diff --git a/_includes/api/en/5x/app-use.md b/legacy/_includes/api/en/5x/app-use.md similarity index 100% rename from _includes/api/en/5x/app-use.md rename to legacy/_includes/api/en/5x/app-use.md diff --git a/_includes/api/en/5x/app.md b/legacy/_includes/api/en/5x/app.md similarity index 100% rename from _includes/api/en/5x/app.md rename to legacy/_includes/api/en/5x/app.md diff --git a/_includes/api/en/5x/express.json.md b/legacy/_includes/api/en/5x/express.json.md similarity index 100% rename from _includes/api/en/5x/express.json.md rename to legacy/_includes/api/en/5x/express.json.md diff --git a/_includes/api/en/5x/express.md b/legacy/_includes/api/en/5x/express.md similarity index 100% rename from _includes/api/en/5x/express.md rename to legacy/_includes/api/en/5x/express.md diff --git a/_includes/api/en/5x/express.raw.md b/legacy/_includes/api/en/5x/express.raw.md similarity index 100% rename from _includes/api/en/5x/express.raw.md rename to legacy/_includes/api/en/5x/express.raw.md diff --git a/_includes/api/en/5x/express.router.md b/legacy/_includes/api/en/5x/express.router.md similarity index 100% rename from _includes/api/en/5x/express.router.md rename to legacy/_includes/api/en/5x/express.router.md diff --git a/_includes/api/en/5x/express.static.md b/legacy/_includes/api/en/5x/express.static.md similarity index 100% rename from _includes/api/en/5x/express.static.md rename to legacy/_includes/api/en/5x/express.static.md diff --git a/_includes/api/en/5x/express.text.md b/legacy/_includes/api/en/5x/express.text.md similarity index 100% rename from _includes/api/en/5x/express.text.md rename to legacy/_includes/api/en/5x/express.text.md diff --git a/_includes/api/en/5x/express.urlencoded.md b/legacy/_includes/api/en/5x/express.urlencoded.md similarity index 100% rename from _includes/api/en/5x/express.urlencoded.md rename to legacy/_includes/api/en/5x/express.urlencoded.md diff --git a/_includes/api/en/5x/menu.md b/legacy/_includes/api/en/5x/menu.md similarity index 100% rename from _includes/api/en/5x/menu.md rename to legacy/_includes/api/en/5x/menu.md diff --git a/_includes/api/en/5x/req-accepts.md b/legacy/_includes/api/en/5x/req-accepts.md similarity index 100% rename from _includes/api/en/5x/req-accepts.md rename to legacy/_includes/api/en/5x/req-accepts.md diff --git a/_includes/api/en/5x/req-acceptsCharsets.md b/legacy/_includes/api/en/5x/req-acceptsCharsets.md similarity index 100% rename from _includes/api/en/5x/req-acceptsCharsets.md rename to legacy/_includes/api/en/5x/req-acceptsCharsets.md diff --git a/_includes/api/en/5x/req-acceptsEncodings.md b/legacy/_includes/api/en/5x/req-acceptsEncodings.md similarity index 100% rename from _includes/api/en/5x/req-acceptsEncodings.md rename to legacy/_includes/api/en/5x/req-acceptsEncodings.md diff --git a/_includes/api/en/5x/req-acceptsLanguages.md b/legacy/_includes/api/en/5x/req-acceptsLanguages.md similarity index 100% rename from _includes/api/en/5x/req-acceptsLanguages.md rename to legacy/_includes/api/en/5x/req-acceptsLanguages.md diff --git a/_includes/api/en/5x/req-app.md b/legacy/_includes/api/en/5x/req-app.md similarity index 100% rename from _includes/api/en/5x/req-app.md rename to legacy/_includes/api/en/5x/req-app.md diff --git a/_includes/api/en/5x/req-baseUrl.md b/legacy/_includes/api/en/5x/req-baseUrl.md similarity index 100% rename from _includes/api/en/5x/req-baseUrl.md rename to legacy/_includes/api/en/5x/req-baseUrl.md diff --git a/_includes/api/en/5x/req-body.md b/legacy/_includes/api/en/5x/req-body.md similarity index 100% rename from _includes/api/en/5x/req-body.md rename to legacy/_includes/api/en/5x/req-body.md diff --git a/_includes/api/en/5x/req-cookies.md b/legacy/_includes/api/en/5x/req-cookies.md similarity index 100% rename from _includes/api/en/5x/req-cookies.md rename to legacy/_includes/api/en/5x/req-cookies.md diff --git a/_includes/api/en/5x/req-fresh.md b/legacy/_includes/api/en/5x/req-fresh.md similarity index 100% rename from _includes/api/en/5x/req-fresh.md rename to legacy/_includes/api/en/5x/req-fresh.md diff --git a/_includes/api/en/5x/req-get.md b/legacy/_includes/api/en/5x/req-get.md similarity index 100% rename from _includes/api/en/5x/req-get.md rename to legacy/_includes/api/en/5x/req-get.md diff --git a/_includes/api/en/5x/req-host.md b/legacy/_includes/api/en/5x/req-host.md similarity index 100% rename from _includes/api/en/5x/req-host.md rename to legacy/_includes/api/en/5x/req-host.md diff --git a/_includes/api/en/5x/req-hostname.md b/legacy/_includes/api/en/5x/req-hostname.md similarity index 100% rename from _includes/api/en/5x/req-hostname.md rename to legacy/_includes/api/en/5x/req-hostname.md diff --git a/_includes/api/en/5x/req-ip.md b/legacy/_includes/api/en/5x/req-ip.md similarity index 100% rename from _includes/api/en/5x/req-ip.md rename to legacy/_includes/api/en/5x/req-ip.md diff --git a/_includes/api/en/5x/req-ips.md b/legacy/_includes/api/en/5x/req-ips.md similarity index 100% rename from _includes/api/en/5x/req-ips.md rename to legacy/_includes/api/en/5x/req-ips.md diff --git a/_includes/api/en/5x/req-is.md b/legacy/_includes/api/en/5x/req-is.md similarity index 100% rename from _includes/api/en/5x/req-is.md rename to legacy/_includes/api/en/5x/req-is.md diff --git a/_includes/api/en/5x/req-method.md b/legacy/_includes/api/en/5x/req-method.md similarity index 100% rename from _includes/api/en/5x/req-method.md rename to legacy/_includes/api/en/5x/req-method.md diff --git a/_includes/api/en/5x/req-originalUrl.md b/legacy/_includes/api/en/5x/req-originalUrl.md similarity index 100% rename from _includes/api/en/5x/req-originalUrl.md rename to legacy/_includes/api/en/5x/req-originalUrl.md diff --git a/_includes/api/en/5x/req-params.md b/legacy/_includes/api/en/5x/req-params.md similarity index 100% rename from _includes/api/en/5x/req-params.md rename to legacy/_includes/api/en/5x/req-params.md diff --git a/_includes/api/en/5x/req-path.md b/legacy/_includes/api/en/5x/req-path.md similarity index 100% rename from _includes/api/en/5x/req-path.md rename to legacy/_includes/api/en/5x/req-path.md diff --git a/_includes/api/en/5x/req-protocol.md b/legacy/_includes/api/en/5x/req-protocol.md similarity index 100% rename from _includes/api/en/5x/req-protocol.md rename to legacy/_includes/api/en/5x/req-protocol.md diff --git a/_includes/api/en/5x/req-query.md b/legacy/_includes/api/en/5x/req-query.md similarity index 100% rename from _includes/api/en/5x/req-query.md rename to legacy/_includes/api/en/5x/req-query.md diff --git a/_includes/api/en/5x/req-range.md b/legacy/_includes/api/en/5x/req-range.md similarity index 100% rename from _includes/api/en/5x/req-range.md rename to legacy/_includes/api/en/5x/req-range.md diff --git a/_includes/api/en/5x/req-res.md b/legacy/_includes/api/en/5x/req-res.md similarity index 100% rename from _includes/api/en/5x/req-res.md rename to legacy/_includes/api/en/5x/req-res.md diff --git a/_includes/api/en/5x/req-route.md b/legacy/_includes/api/en/5x/req-route.md similarity index 100% rename from _includes/api/en/5x/req-route.md rename to legacy/_includes/api/en/5x/req-route.md diff --git a/_includes/api/en/5x/req-secure.md b/legacy/_includes/api/en/5x/req-secure.md similarity index 100% rename from _includes/api/en/5x/req-secure.md rename to legacy/_includes/api/en/5x/req-secure.md diff --git a/_includes/api/en/5x/req-signedCookies.md b/legacy/_includes/api/en/5x/req-signedCookies.md similarity index 100% rename from _includes/api/en/5x/req-signedCookies.md rename to legacy/_includes/api/en/5x/req-signedCookies.md diff --git a/_includes/api/en/5x/req-stale.md b/legacy/_includes/api/en/5x/req-stale.md similarity index 100% rename from _includes/api/en/5x/req-stale.md rename to legacy/_includes/api/en/5x/req-stale.md diff --git a/_includes/api/en/5x/req-subdomains.md b/legacy/_includes/api/en/5x/req-subdomains.md similarity index 100% rename from _includes/api/en/5x/req-subdomains.md rename to legacy/_includes/api/en/5x/req-subdomains.md diff --git a/_includes/api/en/5x/req-xhr.md b/legacy/_includes/api/en/5x/req-xhr.md similarity index 100% rename from _includes/api/en/5x/req-xhr.md rename to legacy/_includes/api/en/5x/req-xhr.md diff --git a/_includes/api/en/5x/req.md b/legacy/_includes/api/en/5x/req.md similarity index 100% rename from _includes/api/en/5x/req.md rename to legacy/_includes/api/en/5x/req.md diff --git a/_includes/api/en/5x/res-app.md b/legacy/_includes/api/en/5x/res-app.md similarity index 100% rename from _includes/api/en/5x/res-app.md rename to legacy/_includes/api/en/5x/res-app.md diff --git a/_includes/api/en/5x/res-append.md b/legacy/_includes/api/en/5x/res-append.md similarity index 100% rename from _includes/api/en/5x/res-append.md rename to legacy/_includes/api/en/5x/res-append.md diff --git a/_includes/api/en/5x/res-attachment.md b/legacy/_includes/api/en/5x/res-attachment.md similarity index 100% rename from _includes/api/en/5x/res-attachment.md rename to legacy/_includes/api/en/5x/res-attachment.md diff --git a/_includes/api/en/5x/res-clearCookie.md b/legacy/_includes/api/en/5x/res-clearCookie.md similarity index 100% rename from _includes/api/en/5x/res-clearCookie.md rename to legacy/_includes/api/en/5x/res-clearCookie.md diff --git a/_includes/api/en/5x/res-cookie.md b/legacy/_includes/api/en/5x/res-cookie.md similarity index 100% rename from _includes/api/en/5x/res-cookie.md rename to legacy/_includes/api/en/5x/res-cookie.md diff --git a/_includes/api/en/5x/res-download.md b/legacy/_includes/api/en/5x/res-download.md similarity index 100% rename from _includes/api/en/5x/res-download.md rename to legacy/_includes/api/en/5x/res-download.md diff --git a/_includes/api/en/5x/res-end.md b/legacy/_includes/api/en/5x/res-end.md similarity index 100% rename from _includes/api/en/5x/res-end.md rename to legacy/_includes/api/en/5x/res-end.md diff --git a/_includes/api/en/5x/res-format.md b/legacy/_includes/api/en/5x/res-format.md similarity index 100% rename from _includes/api/en/5x/res-format.md rename to legacy/_includes/api/en/5x/res-format.md diff --git a/_includes/api/en/5x/res-get.md b/legacy/_includes/api/en/5x/res-get.md similarity index 100% rename from _includes/api/en/5x/res-get.md rename to legacy/_includes/api/en/5x/res-get.md diff --git a/_includes/api/en/5x/res-headersSent.md b/legacy/_includes/api/en/5x/res-headersSent.md similarity index 100% rename from _includes/api/en/5x/res-headersSent.md rename to legacy/_includes/api/en/5x/res-headersSent.md diff --git a/_includes/api/en/5x/res-json.md b/legacy/_includes/api/en/5x/res-json.md similarity index 100% rename from _includes/api/en/5x/res-json.md rename to legacy/_includes/api/en/5x/res-json.md diff --git a/_includes/api/en/5x/res-jsonp.md b/legacy/_includes/api/en/5x/res-jsonp.md similarity index 100% rename from _includes/api/en/5x/res-jsonp.md rename to legacy/_includes/api/en/5x/res-jsonp.md diff --git a/_includes/api/en/5x/res-links.md b/legacy/_includes/api/en/5x/res-links.md similarity index 100% rename from _includes/api/en/5x/res-links.md rename to legacy/_includes/api/en/5x/res-links.md diff --git a/_includes/api/en/5x/res-locals.md b/legacy/_includes/api/en/5x/res-locals.md similarity index 100% rename from _includes/api/en/5x/res-locals.md rename to legacy/_includes/api/en/5x/res-locals.md diff --git a/_includes/api/en/5x/res-location.md b/legacy/_includes/api/en/5x/res-location.md similarity index 100% rename from _includes/api/en/5x/res-location.md rename to legacy/_includes/api/en/5x/res-location.md diff --git a/_includes/api/en/5x/res-redirect.md b/legacy/_includes/api/en/5x/res-redirect.md similarity index 100% rename from _includes/api/en/5x/res-redirect.md rename to legacy/_includes/api/en/5x/res-redirect.md diff --git a/_includes/api/en/5x/res-render.md b/legacy/_includes/api/en/5x/res-render.md similarity index 100% rename from _includes/api/en/5x/res-render.md rename to legacy/_includes/api/en/5x/res-render.md diff --git a/_includes/api/en/5x/res-req.md b/legacy/_includes/api/en/5x/res-req.md similarity index 100% rename from _includes/api/en/5x/res-req.md rename to legacy/_includes/api/en/5x/res-req.md diff --git a/_includes/api/en/5x/res-send.md b/legacy/_includes/api/en/5x/res-send.md similarity index 100% rename from _includes/api/en/5x/res-send.md rename to legacy/_includes/api/en/5x/res-send.md diff --git a/_includes/api/en/5x/res-sendFile.md b/legacy/_includes/api/en/5x/res-sendFile.md similarity index 100% rename from _includes/api/en/5x/res-sendFile.md rename to legacy/_includes/api/en/5x/res-sendFile.md diff --git a/_includes/api/en/5x/res-sendStatus.md b/legacy/_includes/api/en/5x/res-sendStatus.md similarity index 100% rename from _includes/api/en/5x/res-sendStatus.md rename to legacy/_includes/api/en/5x/res-sendStatus.md diff --git a/_includes/api/en/5x/res-set.md b/legacy/_includes/api/en/5x/res-set.md similarity index 100% rename from _includes/api/en/5x/res-set.md rename to legacy/_includes/api/en/5x/res-set.md diff --git a/_includes/api/en/5x/res-status.md b/legacy/_includes/api/en/5x/res-status.md similarity index 100% rename from _includes/api/en/5x/res-status.md rename to legacy/_includes/api/en/5x/res-status.md diff --git a/_includes/api/en/5x/res-type.md b/legacy/_includes/api/en/5x/res-type.md similarity index 100% rename from _includes/api/en/5x/res-type.md rename to legacy/_includes/api/en/5x/res-type.md diff --git a/_includes/api/en/5x/res-vary.md b/legacy/_includes/api/en/5x/res-vary.md similarity index 100% rename from _includes/api/en/5x/res-vary.md rename to legacy/_includes/api/en/5x/res-vary.md diff --git a/_includes/api/en/5x/res.md b/legacy/_includes/api/en/5x/res.md similarity index 100% rename from _includes/api/en/5x/res.md rename to legacy/_includes/api/en/5x/res.md diff --git a/_includes/api/en/5x/router-METHOD.md b/legacy/_includes/api/en/5x/router-METHOD.md similarity index 100% rename from _includes/api/en/5x/router-METHOD.md rename to legacy/_includes/api/en/5x/router-METHOD.md diff --git a/_includes/api/en/5x/router-Router.md b/legacy/_includes/api/en/5x/router-Router.md similarity index 100% rename from _includes/api/en/5x/router-Router.md rename to legacy/_includes/api/en/5x/router-Router.md diff --git a/_includes/api/en/5x/router-all.md b/legacy/_includes/api/en/5x/router-all.md similarity index 100% rename from _includes/api/en/5x/router-all.md rename to legacy/_includes/api/en/5x/router-all.md diff --git a/_includes/api/en/5x/router-param.md b/legacy/_includes/api/en/5x/router-param.md similarity index 100% rename from _includes/api/en/5x/router-param.md rename to legacy/_includes/api/en/5x/router-param.md diff --git a/_includes/api/en/5x/router-route.md b/legacy/_includes/api/en/5x/router-route.md similarity index 100% rename from _includes/api/en/5x/router-route.md rename to legacy/_includes/api/en/5x/router-route.md diff --git a/_includes/api/en/5x/router-use.md b/legacy/_includes/api/en/5x/router-use.md similarity index 100% rename from _includes/api/en/5x/router-use.md rename to legacy/_includes/api/en/5x/router-use.md diff --git a/_includes/api/en/5x/router.md b/legacy/_includes/api/en/5x/router.md similarity index 100% rename from _includes/api/en/5x/router.md rename to legacy/_includes/api/en/5x/router.md diff --git a/_includes/api/en/5x/routing-args.html b/legacy/_includes/api/en/5x/routing-args.html similarity index 100% rename from _includes/api/en/5x/routing-args.html rename to legacy/_includes/api/en/5x/routing-args.html diff --git a/_includes/blog/authors.html b/legacy/_includes/blog/authors.html similarity index 100% rename from _includes/blog/authors.html rename to legacy/_includes/blog/authors.html diff --git a/_includes/blog/posts-menu.md b/legacy/_includes/blog/posts-menu.md similarity index 100% rename from _includes/blog/posts-menu.md rename to legacy/_includes/blog/posts-menu.md diff --git a/_includes/bottom-navigation.html b/legacy/_includes/bottom-navigation.html similarity index 100% rename from _includes/bottom-navigation.html rename to legacy/_includes/bottom-navigation.html diff --git a/_includes/changelog/menu.md b/legacy/_includes/changelog/menu.md similarity index 100% rename from _includes/changelog/menu.md rename to legacy/_includes/changelog/menu.md diff --git a/_includes/community-caveat.html b/legacy/_includes/community-caveat.html similarity index 100% rename from _includes/community-caveat.html rename to legacy/_includes/community-caveat.html diff --git a/_includes/feed-entry.xml b/legacy/_includes/feed-entry.xml similarity index 100% rename from _includes/feed-entry.xml rename to legacy/_includes/feed-entry.xml diff --git a/_includes/footer.html b/legacy/_includes/footer.html similarity index 100% rename from _includes/footer.html rename to legacy/_includes/footer.html diff --git a/_includes/github-edit-btn.html b/legacy/_includes/github-edit-btn.html similarity index 100% rename from _includes/github-edit-btn.html rename to legacy/_includes/github-edit-btn.html diff --git a/_includes/head.html b/legacy/_includes/head.html similarity index 100% rename from _includes/head.html rename to legacy/_includes/head.html diff --git a/_includes/header.html b/legacy/_includes/header.html similarity index 100% rename from _includes/header.html rename to legacy/_includes/header.html diff --git a/_includes/i18n-notice.html b/legacy/_includes/i18n-notice.html similarity index 100% rename from _includes/i18n-notice.html rename to legacy/_includes/i18n-notice.html diff --git a/_includes/icons/X.svg b/legacy/_includes/icons/X.svg similarity index 100% rename from _includes/icons/X.svg rename to legacy/_includes/icons/X.svg diff --git a/_includes/icons/announcement.svg b/legacy/_includes/icons/announcement.svg similarity index 100% rename from _includes/icons/announcement.svg rename to legacy/_includes/icons/announcement.svg diff --git a/_includes/icons/arrow.svg b/legacy/_includes/icons/arrow.svg similarity index 100% rename from _includes/icons/arrow.svg rename to legacy/_includes/icons/arrow.svg diff --git a/_includes/icons/bluesky.svg b/legacy/_includes/icons/bluesky.svg similarity index 100% rename from _includes/icons/bluesky.svg rename to legacy/_includes/icons/bluesky.svg diff --git a/_includes/icons/caution.svg b/legacy/_includes/icons/caution.svg similarity index 100% rename from _includes/icons/caution.svg rename to legacy/_includes/icons/caution.svg diff --git a/_includes/icons/express-logo.svg b/legacy/_includes/icons/express-logo.svg similarity index 100% rename from _includes/icons/express-logo.svg rename to legacy/_includes/icons/express-logo.svg diff --git a/_includes/icons/github.svg b/legacy/_includes/icons/github.svg similarity index 100% rename from _includes/icons/github.svg rename to legacy/_includes/icons/github.svg diff --git a/_includes/icons/hamburger.svg b/legacy/_includes/icons/hamburger.svg similarity index 100% rename from _includes/icons/hamburger.svg rename to legacy/_includes/icons/hamburger.svg diff --git a/_includes/icons/i18n.svg b/legacy/_includes/icons/i18n.svg similarity index 100% rename from _includes/icons/i18n.svg rename to legacy/_includes/icons/i18n.svg diff --git a/_includes/icons/moon.svg b/legacy/_includes/icons/moon.svg similarity index 100% rename from _includes/icons/moon.svg rename to legacy/_includes/icons/moon.svg diff --git a/_includes/icons/note.svg b/legacy/_includes/icons/note.svg similarity index 100% rename from _includes/icons/note.svg rename to legacy/_includes/icons/note.svg diff --git a/_includes/icons/opencollective.svg b/legacy/_includes/icons/opencollective.svg similarity index 100% rename from _includes/icons/opencollective.svg rename to legacy/_includes/icons/opencollective.svg diff --git a/_includes/icons/openjs_foundation-logo-horizontal-white.svg b/legacy/_includes/icons/openjs_foundation-logo-horizontal-white.svg similarity index 100% rename from _includes/icons/openjs_foundation-logo-horizontal-white.svg rename to legacy/_includes/icons/openjs_foundation-logo-horizontal-white.svg diff --git a/_includes/icons/slack.svg b/legacy/_includes/icons/slack.svg similarity index 100% rename from _includes/icons/slack.svg rename to legacy/_includes/icons/slack.svg diff --git a/_includes/icons/sun.svg b/legacy/_includes/icons/sun.svg similarity index 100% rename from _includes/icons/sun.svg rename to legacy/_includes/icons/sun.svg diff --git a/_includes/icons/warning.svg b/legacy/_includes/icons/warning.svg similarity index 100% rename from _includes/icons/warning.svg rename to legacy/_includes/icons/warning.svg diff --git a/_includes/icons/youtube.svg b/legacy/_includes/icons/youtube.svg similarity index 100% rename from _includes/icons/youtube.svg rename to legacy/_includes/icons/youtube.svg diff --git a/_includes/language-picker.html b/legacy/_includes/language-picker.html similarity index 100% rename from _includes/language-picker.html rename to legacy/_includes/language-picker.html diff --git a/_includes/mw-list.md b/legacy/_includes/mw-list.md similarity index 100% rename from _includes/mw-list.md rename to legacy/_includes/mw-list.md diff --git a/_includes/readmes/body-parser.md b/legacy/_includes/readmes/body-parser.md similarity index 100% rename from _includes/readmes/body-parser.md rename to legacy/_includes/readmes/body-parser.md diff --git a/_includes/readmes/compression.md b/legacy/_includes/readmes/compression.md similarity index 100% rename from _includes/readmes/compression.md rename to legacy/_includes/readmes/compression.md diff --git a/_includes/readmes/connect-rid.md b/legacy/_includes/readmes/connect-rid.md similarity index 100% rename from _includes/readmes/connect-rid.md rename to legacy/_includes/readmes/connect-rid.md diff --git a/_includes/readmes/cookie-parser.md b/legacy/_includes/readmes/cookie-parser.md similarity index 100% rename from _includes/readmes/cookie-parser.md rename to legacy/_includes/readmes/cookie-parser.md diff --git a/_includes/readmes/cookie-session.md b/legacy/_includes/readmes/cookie-session.md similarity index 100% rename from _includes/readmes/cookie-session.md rename to legacy/_includes/readmes/cookie-session.md diff --git a/_includes/readmes/cors.md b/legacy/_includes/readmes/cors.md similarity index 100% rename from _includes/readmes/cors.md rename to legacy/_includes/readmes/cors.md diff --git a/_includes/readmes/errorhandler.md b/legacy/_includes/readmes/errorhandler.md similarity index 100% rename from _includes/readmes/errorhandler.md rename to legacy/_includes/readmes/errorhandler.md diff --git a/_includes/readmes/express-master/examples.md b/legacy/_includes/readmes/express-master/examples.md similarity index 100% rename from _includes/readmes/express-master/examples.md rename to legacy/_includes/readmes/express-master/examples.md diff --git a/_includes/readmes/method-override.md b/legacy/_includes/readmes/method-override.md similarity index 100% rename from _includes/readmes/method-override.md rename to legacy/_includes/readmes/method-override.md diff --git a/_includes/readmes/morgan.md b/legacy/_includes/readmes/morgan.md similarity index 100% rename from _includes/readmes/morgan.md rename to legacy/_includes/readmes/morgan.md diff --git a/_includes/readmes/multer.md b/legacy/_includes/readmes/multer.md similarity index 100% rename from _includes/readmes/multer.md rename to legacy/_includes/readmes/multer.md diff --git a/_includes/readmes/response-time.md b/legacy/_includes/readmes/response-time.md similarity index 100% rename from _includes/readmes/response-time.md rename to legacy/_includes/readmes/response-time.md diff --git a/_includes/readmes/serve-favicon.md b/legacy/_includes/readmes/serve-favicon.md similarity index 100% rename from _includes/readmes/serve-favicon.md rename to legacy/_includes/readmes/serve-favicon.md diff --git a/_includes/readmes/serve-index.md b/legacy/_includes/readmes/serve-index.md similarity index 100% rename from _includes/readmes/serve-index.md rename to legacy/_includes/readmes/serve-index.md diff --git a/_includes/readmes/serve-static.md b/legacy/_includes/readmes/serve-static.md similarity index 100% rename from _includes/readmes/serve-static.md rename to legacy/_includes/readmes/serve-static.md diff --git a/_includes/readmes/session.md b/legacy/_includes/readmes/session.md similarity index 100% rename from _includes/readmes/session.md rename to legacy/_includes/readmes/session.md diff --git a/_includes/readmes/timeout.md b/legacy/_includes/readmes/timeout.md similarity index 100% rename from _includes/readmes/timeout.md rename to legacy/_includes/readmes/timeout.md diff --git a/_includes/readmes/vhost.md b/legacy/_includes/readmes/vhost.md similarity index 100% rename from _includes/readmes/vhost.md rename to legacy/_includes/readmes/vhost.md diff --git a/_includes/util-list.md b/legacy/_includes/util-list.md similarity index 100% rename from _includes/util-list.md rename to legacy/_includes/util-list.md diff --git a/_layouts/404.html b/legacy/_layouts/404.html similarity index 100% rename from _layouts/404.html rename to legacy/_layouts/404.html diff --git a/_layouts/api.html b/legacy/_layouts/api.html similarity index 100% rename from _layouts/api.html rename to legacy/_layouts/api.html diff --git a/_layouts/feed.xml b/legacy/_layouts/feed.xml similarity index 100% rename from _layouts/feed.xml rename to legacy/_layouts/feed.xml diff --git a/_layouts/home.html b/legacy/_layouts/home.html similarity index 100% rename from _layouts/home.html rename to legacy/_layouts/home.html diff --git a/_layouts/middleware.html b/legacy/_layouts/middleware.html similarity index 100% rename from _layouts/middleware.html rename to legacy/_layouts/middleware.html diff --git a/_layouts/page.html b/legacy/_layouts/page.html similarity index 100% rename from _layouts/page.html rename to legacy/_layouts/page.html diff --git a/_layouts/post.html b/legacy/_layouts/post.html similarity index 100% rename from _layouts/post.html rename to legacy/_layouts/post.html diff --git a/_posts/2024-07-16-welcome-post.md b/legacy/_posts/2024-07-16-welcome-post.md similarity index 100% rename from _posts/2024-07-16-welcome-post.md rename to legacy/_posts/2024-07-16-welcome-post.md diff --git a/_posts/2024-09-29-security-releases.md b/legacy/_posts/2024-09-29-security-releases.md similarity index 100% rename from _posts/2024-09-29-security-releases.md rename to legacy/_posts/2024-09-29-security-releases.md diff --git a/_posts/2024-10-01-HeroDevs-partnership-announcement.md b/legacy/_posts/2024-10-01-HeroDevs-partnership-announcement.md similarity index 100% rename from _posts/2024-10-01-HeroDevs-partnership-announcement.md rename to legacy/_posts/2024-10-01-HeroDevs-partnership-announcement.md diff --git a/_posts/2024-10-15-v5-release.md b/legacy/_posts/2024-10-15-v5-release.md similarity index 100% rename from _posts/2024-10-15-v5-release.md rename to legacy/_posts/2024-10-15-v5-release.md diff --git a/_posts/2024-10-22-security-audit-milestone-achievement.md b/legacy/_posts/2024-10-22-security-audit-milestone-achievement.md similarity index 100% rename from _posts/2024-10-22-security-audit-milestone-achievement.md rename to legacy/_posts/2024-10-22-security-audit-milestone-achievement.md diff --git a/_posts/2025-01-09-rewind-2024-triumphs-and-2025-vision.md b/legacy/_posts/2025-01-09-rewind-2024-triumphs-and-2025-vision.md similarity index 100% rename from _posts/2025-01-09-rewind-2024-triumphs-and-2025-vision.md rename to legacy/_posts/2025-01-09-rewind-2024-triumphs-and-2025-vision.md diff --git a/_posts/2025-03-31-v5-1-latest-release.md b/legacy/_posts/2025-03-31-v5-1-latest-release.md similarity index 100% rename from _posts/2025-03-31-v5-1-latest-release.md rename to legacy/_posts/2025-03-31-v5-1-latest-release.md diff --git a/_posts/2025-05-16-express-cleanup-legacy-packages.md b/legacy/_posts/2025-05-16-express-cleanup-legacy-packages.md similarity index 100% rename from _posts/2025-05-16-express-cleanup-legacy-packages.md rename to legacy/_posts/2025-05-16-express-cleanup-legacy-packages.md diff --git a/_posts/2025-05-19-security-releases.md b/legacy/_posts/2025-05-19-security-releases.md similarity index 100% rename from _posts/2025-05-19-security-releases.md rename to legacy/_posts/2025-05-19-security-releases.md diff --git a/_posts/2025-06-05-vulnerability-reporting-process-overhaul.md b/legacy/_posts/2025-06-05-vulnerability-reporting-process-overhaul.md similarity index 100% rename from _posts/2025-06-05-vulnerability-reporting-process-overhaul.md rename to legacy/_posts/2025-06-05-vulnerability-reporting-process-overhaul.md diff --git a/_posts/2025-07-18-security-releases.md b/legacy/_posts/2025-07-18-security-releases.md similarity index 100% rename from _posts/2025-07-18-security-releases.md rename to legacy/_posts/2025-07-18-security-releases.md diff --git a/_posts/2025-07-31-security-releases.md b/legacy/_posts/2025-07-31-security-releases.md similarity index 100% rename from _posts/2025-07-31-security-releases.md rename to legacy/_posts/2025-07-31-security-releases.md diff --git a/_posts/2025-12-01-security-releases.md b/legacy/_posts/2025-12-01-security-releases.md similarity index 100% rename from _posts/2025-12-01-security-releases.md rename to legacy/_posts/2025-12-01-security-releases.md diff --git a/crowdin.yml b/legacy/crowdin.yml similarity index 100% rename from crowdin.yml rename to legacy/crowdin.yml diff --git a/css/langs/de.css b/legacy/css/langs/de.css similarity index 100% rename from css/langs/de.css rename to legacy/css/langs/de.css diff --git a/css/langs/en.css b/legacy/css/langs/en.css similarity index 100% rename from css/langs/en.css rename to legacy/css/langs/en.css diff --git a/css/langs/es.css b/legacy/css/langs/es.css similarity index 100% rename from css/langs/es.css rename to legacy/css/langs/es.css diff --git a/css/langs/fr.css b/legacy/css/langs/fr.css similarity index 100% rename from css/langs/fr.css rename to legacy/css/langs/fr.css diff --git a/css/langs/it.css b/legacy/css/langs/it.css similarity index 100% rename from css/langs/it.css rename to legacy/css/langs/it.css diff --git a/css/langs/ja.css b/legacy/css/langs/ja.css similarity index 100% rename from css/langs/ja.css rename to legacy/css/langs/ja.css diff --git a/css/langs/ko.css b/legacy/css/langs/ko.css similarity index 100% rename from css/langs/ko.css rename to legacy/css/langs/ko.css diff --git a/css/langs/pt-br.css b/legacy/css/langs/pt-br.css similarity index 100% rename from css/langs/pt-br.css rename to legacy/css/langs/pt-br.css diff --git a/css/langs/zh-cn.css b/legacy/css/langs/zh-cn.css similarity index 100% rename from css/langs/zh-cn.css rename to legacy/css/langs/zh-cn.css diff --git a/css/langs/zh-tw.css b/legacy/css/langs/zh-tw.css similarity index 100% rename from css/langs/zh-tw.css rename to legacy/css/langs/zh-tw.css diff --git a/css/search.css b/legacy/css/search.css similarity index 100% rename from css/search.css rename to legacy/css/search.css diff --git a/css/sintax.css b/legacy/css/sintax.css similarity index 100% rename from css/sintax.css rename to legacy/css/sintax.css diff --git a/css/style.css b/legacy/css/style.css similarity index 100% rename from css/style.css rename to legacy/css/style.css diff --git a/css/themes/dark-theme.css b/legacy/css/themes/dark-theme.css similarity index 100% rename from css/themes/dark-theme.css rename to legacy/css/themes/dark-theme.css diff --git a/css/variables.css b/legacy/css/variables.css similarity index 100% rename from css/variables.css rename to legacy/css/variables.css diff --git a/de/3x/api.md b/legacy/de/3x/api.md similarity index 100% rename from de/3x/api.md rename to legacy/de/3x/api.md diff --git a/de/4x/api.md b/legacy/de/4x/api.md similarity index 100% rename from de/4x/api.md rename to legacy/de/4x/api.md diff --git a/de/5x/api.md b/legacy/de/5x/api.md similarity index 100% rename from de/5x/api.md rename to legacy/de/5x/api.md diff --git a/de/advanced/best-practice-performance.md b/legacy/de/advanced/best-practice-performance.md similarity index 100% rename from de/advanced/best-practice-performance.md rename to legacy/de/advanced/best-practice-performance.md diff --git a/de/advanced/best-practice-security.md b/legacy/de/advanced/best-practice-security.md similarity index 100% rename from de/advanced/best-practice-security.md rename to legacy/de/advanced/best-practice-security.md diff --git a/de/advanced/developing-template-engines.md b/legacy/de/advanced/developing-template-engines.md similarity index 100% rename from de/advanced/developing-template-engines.md rename to legacy/de/advanced/developing-template-engines.md diff --git a/de/advanced/healthcheck-graceful-shutdown.md b/legacy/de/advanced/healthcheck-graceful-shutdown.md similarity index 100% rename from de/advanced/healthcheck-graceful-shutdown.md rename to legacy/de/advanced/healthcheck-graceful-shutdown.md diff --git a/de/advanced/security-updates.md b/legacy/de/advanced/security-updates.md similarity index 100% rename from de/advanced/security-updates.md rename to legacy/de/advanced/security-updates.md diff --git a/de/api.md b/legacy/de/api.md similarity index 100% rename from de/api.md rename to legacy/de/api.md diff --git a/de/changelog/index.md b/legacy/de/changelog/index.md similarity index 100% rename from de/changelog/index.md rename to legacy/de/changelog/index.md diff --git a/de/guide/behind-proxies.md b/legacy/de/guide/behind-proxies.md similarity index 100% rename from de/guide/behind-proxies.md rename to legacy/de/guide/behind-proxies.md diff --git a/de/guide/database-integration.md b/legacy/de/guide/database-integration.md similarity index 100% rename from de/guide/database-integration.md rename to legacy/de/guide/database-integration.md diff --git a/de/guide/debugging.md b/legacy/de/guide/debugging.md similarity index 100% rename from de/guide/debugging.md rename to legacy/de/guide/debugging.md diff --git a/de/guide/error-handling.md b/legacy/de/guide/error-handling.md similarity index 100% rename from de/guide/error-handling.md rename to legacy/de/guide/error-handling.md diff --git a/de/guide/migrating-4.md b/legacy/de/guide/migrating-4.md similarity index 100% rename from de/guide/migrating-4.md rename to legacy/de/guide/migrating-4.md diff --git a/de/guide/migrating-5.md b/legacy/de/guide/migrating-5.md similarity index 100% rename from de/guide/migrating-5.md rename to legacy/de/guide/migrating-5.md diff --git a/de/guide/overriding-express-api.md b/legacy/de/guide/overriding-express-api.md similarity index 100% rename from de/guide/overriding-express-api.md rename to legacy/de/guide/overriding-express-api.md diff --git a/de/guide/routing.md b/legacy/de/guide/routing.md similarity index 100% rename from de/guide/routing.md rename to legacy/de/guide/routing.md diff --git a/de/guide/using-middleware.md b/legacy/de/guide/using-middleware.md similarity index 100% rename from de/guide/using-middleware.md rename to legacy/de/guide/using-middleware.md diff --git a/de/guide/using-template-engines.md b/legacy/de/guide/using-template-engines.md similarity index 100% rename from de/guide/using-template-engines.md rename to legacy/de/guide/using-template-engines.md diff --git a/de/guide/writing-middleware.md b/legacy/de/guide/writing-middleware.md similarity index 100% rename from de/guide/writing-middleware.md rename to legacy/de/guide/writing-middleware.md diff --git a/de/index.md b/legacy/de/index.md similarity index 100% rename from de/index.md rename to legacy/de/index.md diff --git a/de/resources/community.md b/legacy/de/resources/community.md similarity index 100% rename from de/resources/community.md rename to legacy/de/resources/community.md diff --git a/de/resources/contributing.md b/legacy/de/resources/contributing.md similarity index 100% rename from de/resources/contributing.md rename to legacy/de/resources/contributing.md diff --git a/de/resources/glossary.md b/legacy/de/resources/glossary.md similarity index 100% rename from de/resources/glossary.md rename to legacy/de/resources/glossary.md diff --git a/de/resources/middleware.md b/legacy/de/resources/middleware.md similarity index 100% rename from de/resources/middleware.md rename to legacy/de/resources/middleware.md diff --git a/de/resources/middleware/body-parser.md b/legacy/de/resources/middleware/body-parser.md similarity index 100% rename from de/resources/middleware/body-parser.md rename to legacy/de/resources/middleware/body-parser.md diff --git a/de/resources/middleware/compression.md b/legacy/de/resources/middleware/compression.md similarity index 100% rename from de/resources/middleware/compression.md rename to legacy/de/resources/middleware/compression.md diff --git a/de/resources/middleware/connect-rid.md b/legacy/de/resources/middleware/connect-rid.md similarity index 100% rename from de/resources/middleware/connect-rid.md rename to legacy/de/resources/middleware/connect-rid.md diff --git a/de/resources/middleware/cookie-parser.md b/legacy/de/resources/middleware/cookie-parser.md similarity index 100% rename from de/resources/middleware/cookie-parser.md rename to legacy/de/resources/middleware/cookie-parser.md diff --git a/de/resources/middleware/cookie-session.md b/legacy/de/resources/middleware/cookie-session.md similarity index 100% rename from de/resources/middleware/cookie-session.md rename to legacy/de/resources/middleware/cookie-session.md diff --git a/de/resources/middleware/cors.md b/legacy/de/resources/middleware/cors.md similarity index 100% rename from de/resources/middleware/cors.md rename to legacy/de/resources/middleware/cors.md diff --git a/de/resources/middleware/errorhandler.md b/legacy/de/resources/middleware/errorhandler.md similarity index 100% rename from de/resources/middleware/errorhandler.md rename to legacy/de/resources/middleware/errorhandler.md diff --git a/de/resources/middleware/method-override.md b/legacy/de/resources/middleware/method-override.md similarity index 100% rename from de/resources/middleware/method-override.md rename to legacy/de/resources/middleware/method-override.md diff --git a/de/resources/middleware/morgan.md b/legacy/de/resources/middleware/morgan.md similarity index 100% rename from de/resources/middleware/morgan.md rename to legacy/de/resources/middleware/morgan.md diff --git a/de/resources/middleware/multer.md b/legacy/de/resources/middleware/multer.md similarity index 100% rename from de/resources/middleware/multer.md rename to legacy/de/resources/middleware/multer.md diff --git a/de/resources/middleware/response-time.md b/legacy/de/resources/middleware/response-time.md similarity index 100% rename from de/resources/middleware/response-time.md rename to legacy/de/resources/middleware/response-time.md diff --git a/de/resources/middleware/serve-favicon.md b/legacy/de/resources/middleware/serve-favicon.md similarity index 100% rename from de/resources/middleware/serve-favicon.md rename to legacy/de/resources/middleware/serve-favicon.md diff --git a/de/resources/middleware/serve-index.md b/legacy/de/resources/middleware/serve-index.md similarity index 100% rename from de/resources/middleware/serve-index.md rename to legacy/de/resources/middleware/serve-index.md diff --git a/de/resources/middleware/serve-static.md b/legacy/de/resources/middleware/serve-static.md similarity index 100% rename from de/resources/middleware/serve-static.md rename to legacy/de/resources/middleware/serve-static.md diff --git a/de/resources/middleware/session.md b/legacy/de/resources/middleware/session.md similarity index 100% rename from de/resources/middleware/session.md rename to legacy/de/resources/middleware/session.md diff --git a/de/resources/middleware/timeout.md b/legacy/de/resources/middleware/timeout.md similarity index 100% rename from de/resources/middleware/timeout.md rename to legacy/de/resources/middleware/timeout.md diff --git a/de/resources/middleware/vhost.md b/legacy/de/resources/middleware/vhost.md similarity index 100% rename from de/resources/middleware/vhost.md rename to legacy/de/resources/middleware/vhost.md diff --git a/de/resources/utils.md b/legacy/de/resources/utils.md similarity index 100% rename from de/resources/utils.md rename to legacy/de/resources/utils.md diff --git a/de/starter/basic-routing.md b/legacy/de/starter/basic-routing.md similarity index 100% rename from de/starter/basic-routing.md rename to legacy/de/starter/basic-routing.md diff --git a/de/starter/examples.md b/legacy/de/starter/examples.md similarity index 100% rename from de/starter/examples.md rename to legacy/de/starter/examples.md diff --git a/de/starter/faq.md b/legacy/de/starter/faq.md similarity index 100% rename from de/starter/faq.md rename to legacy/de/starter/faq.md diff --git a/de/starter/generator.md b/legacy/de/starter/generator.md similarity index 100% rename from de/starter/generator.md rename to legacy/de/starter/generator.md diff --git a/de/starter/hello-world.md b/legacy/de/starter/hello-world.md similarity index 100% rename from de/starter/hello-world.md rename to legacy/de/starter/hello-world.md diff --git a/de/starter/installing.md b/legacy/de/starter/installing.md similarity index 100% rename from de/starter/installing.md rename to legacy/de/starter/installing.md diff --git a/de/starter/static-files.md b/legacy/de/starter/static-files.md similarity index 100% rename from de/starter/static-files.md rename to legacy/de/starter/static-files.md diff --git a/de/support/index.md b/legacy/de/support/index.md similarity index 100% rename from de/support/index.md rename to legacy/de/support/index.md diff --git a/en/3x/api.md b/legacy/en/3x/api.md similarity index 100% rename from en/3x/api.md rename to legacy/en/3x/api.md diff --git a/en/4x/api.md b/legacy/en/4x/api.md similarity index 100% rename from en/4x/api.md rename to legacy/en/4x/api.md diff --git a/en/5x/api.md b/legacy/en/5x/api.md similarity index 100% rename from en/5x/api.md rename to legacy/en/5x/api.md diff --git a/en/advanced/best-practice-performance.md b/legacy/en/advanced/best-practice-performance.md similarity index 100% rename from en/advanced/best-practice-performance.md rename to legacy/en/advanced/best-practice-performance.md diff --git a/en/advanced/best-practice-security.md b/legacy/en/advanced/best-practice-security.md similarity index 100% rename from en/advanced/best-practice-security.md rename to legacy/en/advanced/best-practice-security.md diff --git a/en/advanced/developing-template-engines.md b/legacy/en/advanced/developing-template-engines.md similarity index 100% rename from en/advanced/developing-template-engines.md rename to legacy/en/advanced/developing-template-engines.md diff --git a/en/advanced/healthcheck-graceful-shutdown.md b/legacy/en/advanced/healthcheck-graceful-shutdown.md similarity index 100% rename from en/advanced/healthcheck-graceful-shutdown.md rename to legacy/en/advanced/healthcheck-graceful-shutdown.md diff --git a/en/advanced/security-updates.md b/legacy/en/advanced/security-updates.md similarity index 100% rename from en/advanced/security-updates.md rename to legacy/en/advanced/security-updates.md diff --git a/en/api.md b/legacy/en/api.md similarity index 100% rename from en/api.md rename to legacy/en/api.md diff --git a/en/blog/posts.md b/legacy/en/blog/posts.md similarity index 100% rename from en/blog/posts.md rename to legacy/en/blog/posts.md diff --git a/en/blog/write-post.md b/legacy/en/blog/write-post.md similarity index 100% rename from en/blog/write-post.md rename to legacy/en/blog/write-post.md diff --git a/en/changelog/index.md b/legacy/en/changelog/index.md similarity index 100% rename from en/changelog/index.md rename to legacy/en/changelog/index.md diff --git a/en/guide/behind-proxies.md b/legacy/en/guide/behind-proxies.md similarity index 100% rename from en/guide/behind-proxies.md rename to legacy/en/guide/behind-proxies.md diff --git a/en/guide/database-integration.md b/legacy/en/guide/database-integration.md similarity index 100% rename from en/guide/database-integration.md rename to legacy/en/guide/database-integration.md diff --git a/en/guide/debugging.md b/legacy/en/guide/debugging.md similarity index 100% rename from en/guide/debugging.md rename to legacy/en/guide/debugging.md diff --git a/en/guide/error-handling.md b/legacy/en/guide/error-handling.md similarity index 100% rename from en/guide/error-handling.md rename to legacy/en/guide/error-handling.md diff --git a/en/guide/migrating-4.md b/legacy/en/guide/migrating-4.md similarity index 100% rename from en/guide/migrating-4.md rename to legacy/en/guide/migrating-4.md diff --git a/en/guide/migrating-5.md b/legacy/en/guide/migrating-5.md similarity index 100% rename from en/guide/migrating-5.md rename to legacy/en/guide/migrating-5.md diff --git a/en/guide/overriding-express-api.md b/legacy/en/guide/overriding-express-api.md similarity index 100% rename from en/guide/overriding-express-api.md rename to legacy/en/guide/overriding-express-api.md diff --git a/en/guide/routing.md b/legacy/en/guide/routing.md similarity index 100% rename from en/guide/routing.md rename to legacy/en/guide/routing.md diff --git a/en/guide/using-middleware.md b/legacy/en/guide/using-middleware.md similarity index 100% rename from en/guide/using-middleware.md rename to legacy/en/guide/using-middleware.md diff --git a/en/guide/using-template-engines.md b/legacy/en/guide/using-template-engines.md similarity index 100% rename from en/guide/using-template-engines.md rename to legacy/en/guide/using-template-engines.md diff --git a/en/guide/writing-middleware.md b/legacy/en/guide/writing-middleware.md similarity index 100% rename from en/guide/writing-middleware.md rename to legacy/en/guide/writing-middleware.md diff --git a/en/resources/community.md b/legacy/en/resources/community.md similarity index 100% rename from en/resources/community.md rename to legacy/en/resources/community.md diff --git a/en/resources/contributing.md b/legacy/en/resources/contributing.md similarity index 100% rename from en/resources/contributing.md rename to legacy/en/resources/contributing.md diff --git a/en/resources/glossary.md b/legacy/en/resources/glossary.md similarity index 100% rename from en/resources/glossary.md rename to legacy/en/resources/glossary.md diff --git a/en/resources/middleware.md b/legacy/en/resources/middleware.md similarity index 100% rename from en/resources/middleware.md rename to legacy/en/resources/middleware.md diff --git a/en/resources/middleware/body-parser.md b/legacy/en/resources/middleware/body-parser.md similarity index 100% rename from en/resources/middleware/body-parser.md rename to legacy/en/resources/middleware/body-parser.md diff --git a/en/resources/middleware/compression.md b/legacy/en/resources/middleware/compression.md similarity index 100% rename from en/resources/middleware/compression.md rename to legacy/en/resources/middleware/compression.md diff --git a/en/resources/middleware/connect-rid.md b/legacy/en/resources/middleware/connect-rid.md similarity index 100% rename from en/resources/middleware/connect-rid.md rename to legacy/en/resources/middleware/connect-rid.md diff --git a/en/resources/middleware/cookie-parser.md b/legacy/en/resources/middleware/cookie-parser.md similarity index 100% rename from en/resources/middleware/cookie-parser.md rename to legacy/en/resources/middleware/cookie-parser.md diff --git a/en/resources/middleware/cookie-session.md b/legacy/en/resources/middleware/cookie-session.md similarity index 100% rename from en/resources/middleware/cookie-session.md rename to legacy/en/resources/middleware/cookie-session.md diff --git a/en/resources/middleware/cors.md b/legacy/en/resources/middleware/cors.md similarity index 100% rename from en/resources/middleware/cors.md rename to legacy/en/resources/middleware/cors.md diff --git a/en/resources/middleware/errorhandler.md b/legacy/en/resources/middleware/errorhandler.md similarity index 100% rename from en/resources/middleware/errorhandler.md rename to legacy/en/resources/middleware/errorhandler.md diff --git a/en/resources/middleware/method-override.md b/legacy/en/resources/middleware/method-override.md similarity index 100% rename from en/resources/middleware/method-override.md rename to legacy/en/resources/middleware/method-override.md diff --git a/en/resources/middleware/morgan.md b/legacy/en/resources/middleware/morgan.md similarity index 100% rename from en/resources/middleware/morgan.md rename to legacy/en/resources/middleware/morgan.md diff --git a/en/resources/middleware/multer.md b/legacy/en/resources/middleware/multer.md similarity index 100% rename from en/resources/middleware/multer.md rename to legacy/en/resources/middleware/multer.md diff --git a/en/resources/middleware/response-time.md b/legacy/en/resources/middleware/response-time.md similarity index 100% rename from en/resources/middleware/response-time.md rename to legacy/en/resources/middleware/response-time.md diff --git a/en/resources/middleware/serve-favicon.md b/legacy/en/resources/middleware/serve-favicon.md similarity index 100% rename from en/resources/middleware/serve-favicon.md rename to legacy/en/resources/middleware/serve-favicon.md diff --git a/en/resources/middleware/serve-index.md b/legacy/en/resources/middleware/serve-index.md similarity index 100% rename from en/resources/middleware/serve-index.md rename to legacy/en/resources/middleware/serve-index.md diff --git a/en/resources/middleware/serve-static.md b/legacy/en/resources/middleware/serve-static.md similarity index 100% rename from en/resources/middleware/serve-static.md rename to legacy/en/resources/middleware/serve-static.md diff --git a/en/resources/middleware/session.md b/legacy/en/resources/middleware/session.md similarity index 100% rename from en/resources/middleware/session.md rename to legacy/en/resources/middleware/session.md diff --git a/en/resources/middleware/timeout.md b/legacy/en/resources/middleware/timeout.md similarity index 100% rename from en/resources/middleware/timeout.md rename to legacy/en/resources/middleware/timeout.md diff --git a/en/resources/middleware/vhost.md b/legacy/en/resources/middleware/vhost.md similarity index 100% rename from en/resources/middleware/vhost.md rename to legacy/en/resources/middleware/vhost.md diff --git a/en/resources/utils.md b/legacy/en/resources/utils.md similarity index 100% rename from en/resources/utils.md rename to legacy/en/resources/utils.md diff --git a/en/starter/basic-routing.md b/legacy/en/starter/basic-routing.md similarity index 100% rename from en/starter/basic-routing.md rename to legacy/en/starter/basic-routing.md diff --git a/en/starter/examples.md b/legacy/en/starter/examples.md similarity index 100% rename from en/starter/examples.md rename to legacy/en/starter/examples.md diff --git a/en/starter/faq.md b/legacy/en/starter/faq.md similarity index 100% rename from en/starter/faq.md rename to legacy/en/starter/faq.md diff --git a/en/starter/generator.md b/legacy/en/starter/generator.md similarity index 100% rename from en/starter/generator.md rename to legacy/en/starter/generator.md diff --git a/en/starter/hello-world.md b/legacy/en/starter/hello-world.md similarity index 100% rename from en/starter/hello-world.md rename to legacy/en/starter/hello-world.md diff --git a/en/starter/installing.md b/legacy/en/starter/installing.md similarity index 100% rename from en/starter/installing.md rename to legacy/en/starter/installing.md diff --git a/en/starter/static-files.md b/legacy/en/starter/static-files.md similarity index 100% rename from en/starter/static-files.md rename to legacy/en/starter/static-files.md diff --git a/en/support/index.md b/legacy/en/support/index.md similarity index 100% rename from en/support/index.md rename to legacy/en/support/index.md diff --git a/es/3x/api.md b/legacy/es/3x/api.md similarity index 100% rename from es/3x/api.md rename to legacy/es/3x/api.md diff --git a/es/4x/api.md b/legacy/es/4x/api.md similarity index 100% rename from es/4x/api.md rename to legacy/es/4x/api.md diff --git a/es/5x/api.md b/legacy/es/5x/api.md similarity index 100% rename from es/5x/api.md rename to legacy/es/5x/api.md diff --git a/es/advanced/best-practice-performance.md b/legacy/es/advanced/best-practice-performance.md similarity index 100% rename from es/advanced/best-practice-performance.md rename to legacy/es/advanced/best-practice-performance.md diff --git a/es/advanced/best-practice-security.md b/legacy/es/advanced/best-practice-security.md similarity index 100% rename from es/advanced/best-practice-security.md rename to legacy/es/advanced/best-practice-security.md diff --git a/es/advanced/developing-template-engines.md b/legacy/es/advanced/developing-template-engines.md similarity index 100% rename from es/advanced/developing-template-engines.md rename to legacy/es/advanced/developing-template-engines.md diff --git a/es/advanced/healthcheck-graceful-shutdown.md b/legacy/es/advanced/healthcheck-graceful-shutdown.md similarity index 100% rename from es/advanced/healthcheck-graceful-shutdown.md rename to legacy/es/advanced/healthcheck-graceful-shutdown.md diff --git a/es/advanced/security-updates.md b/legacy/es/advanced/security-updates.md similarity index 100% rename from es/advanced/security-updates.md rename to legacy/es/advanced/security-updates.md diff --git a/es/api.md b/legacy/es/api.md similarity index 100% rename from es/api.md rename to legacy/es/api.md diff --git a/es/changelog/index.md b/legacy/es/changelog/index.md similarity index 100% rename from es/changelog/index.md rename to legacy/es/changelog/index.md diff --git a/es/guide/behind-proxies.md b/legacy/es/guide/behind-proxies.md similarity index 100% rename from es/guide/behind-proxies.md rename to legacy/es/guide/behind-proxies.md diff --git a/es/guide/database-integration.md b/legacy/es/guide/database-integration.md similarity index 100% rename from es/guide/database-integration.md rename to legacy/es/guide/database-integration.md diff --git a/es/guide/debugging.md b/legacy/es/guide/debugging.md similarity index 100% rename from es/guide/debugging.md rename to legacy/es/guide/debugging.md diff --git a/es/guide/error-handling.md b/legacy/es/guide/error-handling.md similarity index 100% rename from es/guide/error-handling.md rename to legacy/es/guide/error-handling.md diff --git a/es/guide/migrating-4.md b/legacy/es/guide/migrating-4.md similarity index 100% rename from es/guide/migrating-4.md rename to legacy/es/guide/migrating-4.md diff --git a/es/guide/migrating-5.md b/legacy/es/guide/migrating-5.md similarity index 100% rename from es/guide/migrating-5.md rename to legacy/es/guide/migrating-5.md diff --git a/es/guide/overriding-express-api.md b/legacy/es/guide/overriding-express-api.md similarity index 100% rename from es/guide/overriding-express-api.md rename to legacy/es/guide/overriding-express-api.md diff --git a/es/guide/routing.md b/legacy/es/guide/routing.md similarity index 100% rename from es/guide/routing.md rename to legacy/es/guide/routing.md diff --git a/es/guide/using-middleware.md b/legacy/es/guide/using-middleware.md similarity index 100% rename from es/guide/using-middleware.md rename to legacy/es/guide/using-middleware.md diff --git a/es/guide/using-template-engines.md b/legacy/es/guide/using-template-engines.md similarity index 100% rename from es/guide/using-template-engines.md rename to legacy/es/guide/using-template-engines.md diff --git a/es/guide/writing-middleware.md b/legacy/es/guide/writing-middleware.md similarity index 100% rename from es/guide/writing-middleware.md rename to legacy/es/guide/writing-middleware.md diff --git a/es/index.md b/legacy/es/index.md similarity index 100% rename from es/index.md rename to legacy/es/index.md diff --git a/es/resources/community.md b/legacy/es/resources/community.md similarity index 100% rename from es/resources/community.md rename to legacy/es/resources/community.md diff --git a/es/resources/contributing.md b/legacy/es/resources/contributing.md similarity index 100% rename from es/resources/contributing.md rename to legacy/es/resources/contributing.md diff --git a/es/resources/glossary.md b/legacy/es/resources/glossary.md similarity index 100% rename from es/resources/glossary.md rename to legacy/es/resources/glossary.md diff --git a/es/resources/middleware.md b/legacy/es/resources/middleware.md similarity index 100% rename from es/resources/middleware.md rename to legacy/es/resources/middleware.md diff --git a/es/resources/middleware/body-parser.md b/legacy/es/resources/middleware/body-parser.md similarity index 100% rename from es/resources/middleware/body-parser.md rename to legacy/es/resources/middleware/body-parser.md diff --git a/es/resources/middleware/compression.md b/legacy/es/resources/middleware/compression.md similarity index 100% rename from es/resources/middleware/compression.md rename to legacy/es/resources/middleware/compression.md diff --git a/es/resources/middleware/connect-rid.md b/legacy/es/resources/middleware/connect-rid.md similarity index 100% rename from es/resources/middleware/connect-rid.md rename to legacy/es/resources/middleware/connect-rid.md diff --git a/es/resources/middleware/cookie-parser.md b/legacy/es/resources/middleware/cookie-parser.md similarity index 100% rename from es/resources/middleware/cookie-parser.md rename to legacy/es/resources/middleware/cookie-parser.md diff --git a/es/resources/middleware/cookie-session.md b/legacy/es/resources/middleware/cookie-session.md similarity index 100% rename from es/resources/middleware/cookie-session.md rename to legacy/es/resources/middleware/cookie-session.md diff --git a/es/resources/middleware/cors.md b/legacy/es/resources/middleware/cors.md similarity index 100% rename from es/resources/middleware/cors.md rename to legacy/es/resources/middleware/cors.md diff --git a/es/resources/middleware/errorhandler.md b/legacy/es/resources/middleware/errorhandler.md similarity index 100% rename from es/resources/middleware/errorhandler.md rename to legacy/es/resources/middleware/errorhandler.md diff --git a/es/resources/middleware/method-override.md b/legacy/es/resources/middleware/method-override.md similarity index 100% rename from es/resources/middleware/method-override.md rename to legacy/es/resources/middleware/method-override.md diff --git a/es/resources/middleware/morgan.md b/legacy/es/resources/middleware/morgan.md similarity index 100% rename from es/resources/middleware/morgan.md rename to legacy/es/resources/middleware/morgan.md diff --git a/es/resources/middleware/multer.md b/legacy/es/resources/middleware/multer.md similarity index 100% rename from es/resources/middleware/multer.md rename to legacy/es/resources/middleware/multer.md diff --git a/es/resources/middleware/response-time.md b/legacy/es/resources/middleware/response-time.md similarity index 100% rename from es/resources/middleware/response-time.md rename to legacy/es/resources/middleware/response-time.md diff --git a/es/resources/middleware/serve-favicon.md b/legacy/es/resources/middleware/serve-favicon.md similarity index 100% rename from es/resources/middleware/serve-favicon.md rename to legacy/es/resources/middleware/serve-favicon.md diff --git a/es/resources/middleware/serve-index.md b/legacy/es/resources/middleware/serve-index.md similarity index 100% rename from es/resources/middleware/serve-index.md rename to legacy/es/resources/middleware/serve-index.md diff --git a/es/resources/middleware/serve-static.md b/legacy/es/resources/middleware/serve-static.md similarity index 100% rename from es/resources/middleware/serve-static.md rename to legacy/es/resources/middleware/serve-static.md diff --git a/es/resources/middleware/session.md b/legacy/es/resources/middleware/session.md similarity index 100% rename from es/resources/middleware/session.md rename to legacy/es/resources/middleware/session.md diff --git a/es/resources/middleware/timeout.md b/legacy/es/resources/middleware/timeout.md similarity index 100% rename from es/resources/middleware/timeout.md rename to legacy/es/resources/middleware/timeout.md diff --git a/es/resources/middleware/vhost.md b/legacy/es/resources/middleware/vhost.md similarity index 100% rename from es/resources/middleware/vhost.md rename to legacy/es/resources/middleware/vhost.md diff --git a/es/resources/utils.md b/legacy/es/resources/utils.md similarity index 100% rename from es/resources/utils.md rename to legacy/es/resources/utils.md diff --git a/es/starter/basic-routing.md b/legacy/es/starter/basic-routing.md similarity index 100% rename from es/starter/basic-routing.md rename to legacy/es/starter/basic-routing.md diff --git a/es/starter/examples.md b/legacy/es/starter/examples.md similarity index 100% rename from es/starter/examples.md rename to legacy/es/starter/examples.md diff --git a/es/starter/faq.md b/legacy/es/starter/faq.md similarity index 100% rename from es/starter/faq.md rename to legacy/es/starter/faq.md diff --git a/es/starter/generator.md b/legacy/es/starter/generator.md similarity index 100% rename from es/starter/generator.md rename to legacy/es/starter/generator.md diff --git a/es/starter/hello-world.md b/legacy/es/starter/hello-world.md similarity index 100% rename from es/starter/hello-world.md rename to legacy/es/starter/hello-world.md diff --git a/es/starter/installing.md b/legacy/es/starter/installing.md similarity index 100% rename from es/starter/installing.md rename to legacy/es/starter/installing.md diff --git a/es/starter/static-files.md b/legacy/es/starter/static-files.md similarity index 100% rename from es/starter/static-files.md rename to legacy/es/starter/static-files.md diff --git a/es/support/index.md b/legacy/es/support/index.md similarity index 100% rename from es/support/index.md rename to legacy/es/support/index.md diff --git a/feed.xml b/legacy/feed.xml similarity index 100% rename from feed.xml rename to legacy/feed.xml diff --git a/fonts/ko/pretendard.css b/legacy/fonts/ko/pretendard.css similarity index 100% rename from fonts/ko/pretendard.css rename to legacy/fonts/ko/pretendard.css diff --git a/fonts/ko/woff/Pretendard-Black.woff b/legacy/fonts/ko/woff/Pretendard-Black.woff similarity index 100% rename from fonts/ko/woff/Pretendard-Black.woff rename to legacy/fonts/ko/woff/Pretendard-Black.woff diff --git a/fonts/ko/woff/Pretendard-Bold.woff b/legacy/fonts/ko/woff/Pretendard-Bold.woff similarity index 100% rename from fonts/ko/woff/Pretendard-Bold.woff rename to legacy/fonts/ko/woff/Pretendard-Bold.woff diff --git a/fonts/ko/woff/Pretendard-ExtraBold.woff b/legacy/fonts/ko/woff/Pretendard-ExtraBold.woff similarity index 100% rename from fonts/ko/woff/Pretendard-ExtraBold.woff rename to legacy/fonts/ko/woff/Pretendard-ExtraBold.woff diff --git a/fonts/ko/woff/Pretendard-ExtraLight.woff b/legacy/fonts/ko/woff/Pretendard-ExtraLight.woff similarity index 100% rename from fonts/ko/woff/Pretendard-ExtraLight.woff rename to legacy/fonts/ko/woff/Pretendard-ExtraLight.woff diff --git a/fonts/ko/woff/Pretendard-Light.woff b/legacy/fonts/ko/woff/Pretendard-Light.woff similarity index 100% rename from fonts/ko/woff/Pretendard-Light.woff rename to legacy/fonts/ko/woff/Pretendard-Light.woff diff --git a/fonts/ko/woff/Pretendard-Medium.woff b/legacy/fonts/ko/woff/Pretendard-Medium.woff similarity index 100% rename from fonts/ko/woff/Pretendard-Medium.woff rename to legacy/fonts/ko/woff/Pretendard-Medium.woff diff --git a/fonts/ko/woff/Pretendard-Regular.woff b/legacy/fonts/ko/woff/Pretendard-Regular.woff similarity index 100% rename from fonts/ko/woff/Pretendard-Regular.woff rename to legacy/fonts/ko/woff/Pretendard-Regular.woff diff --git a/fonts/ko/woff/Pretendard-SemiBold.woff b/legacy/fonts/ko/woff/Pretendard-SemiBold.woff similarity index 100% rename from fonts/ko/woff/Pretendard-SemiBold.woff rename to legacy/fonts/ko/woff/Pretendard-SemiBold.woff diff --git a/fonts/ko/woff/Pretendard-Thin.woff b/legacy/fonts/ko/woff/Pretendard-Thin.woff similarity index 100% rename from fonts/ko/woff/Pretendard-Thin.woff rename to legacy/fonts/ko/woff/Pretendard-Thin.woff diff --git a/fonts/ko/woff2/Pretendard-Black.woff2 b/legacy/fonts/ko/woff2/Pretendard-Black.woff2 similarity index 100% rename from fonts/ko/woff2/Pretendard-Black.woff2 rename to legacy/fonts/ko/woff2/Pretendard-Black.woff2 diff --git a/fonts/ko/woff2/Pretendard-Bold.woff2 b/legacy/fonts/ko/woff2/Pretendard-Bold.woff2 similarity index 100% rename from fonts/ko/woff2/Pretendard-Bold.woff2 rename to legacy/fonts/ko/woff2/Pretendard-Bold.woff2 diff --git a/fonts/ko/woff2/Pretendard-ExtraBold.woff2 b/legacy/fonts/ko/woff2/Pretendard-ExtraBold.woff2 similarity index 100% rename from fonts/ko/woff2/Pretendard-ExtraBold.woff2 rename to legacy/fonts/ko/woff2/Pretendard-ExtraBold.woff2 diff --git a/fonts/ko/woff2/Pretendard-ExtraLight.woff2 b/legacy/fonts/ko/woff2/Pretendard-ExtraLight.woff2 similarity index 100% rename from fonts/ko/woff2/Pretendard-ExtraLight.woff2 rename to legacy/fonts/ko/woff2/Pretendard-ExtraLight.woff2 diff --git a/fonts/ko/woff2/Pretendard-Light.woff2 b/legacy/fonts/ko/woff2/Pretendard-Light.woff2 similarity index 100% rename from fonts/ko/woff2/Pretendard-Light.woff2 rename to legacy/fonts/ko/woff2/Pretendard-Light.woff2 diff --git a/fonts/ko/woff2/Pretendard-Medium.woff2 b/legacy/fonts/ko/woff2/Pretendard-Medium.woff2 similarity index 100% rename from fonts/ko/woff2/Pretendard-Medium.woff2 rename to legacy/fonts/ko/woff2/Pretendard-Medium.woff2 diff --git a/fonts/ko/woff2/Pretendard-Regular.woff2 b/legacy/fonts/ko/woff2/Pretendard-Regular.woff2 similarity index 100% rename from fonts/ko/woff2/Pretendard-Regular.woff2 rename to legacy/fonts/ko/woff2/Pretendard-Regular.woff2 diff --git a/fonts/ko/woff2/Pretendard-SemiBold.woff2 b/legacy/fonts/ko/woff2/Pretendard-SemiBold.woff2 similarity index 100% rename from fonts/ko/woff2/Pretendard-SemiBold.woff2 rename to legacy/fonts/ko/woff2/Pretendard-SemiBold.woff2 diff --git a/fonts/ko/woff2/Pretendard-Thin.woff2 b/legacy/fonts/ko/woff2/Pretendard-Thin.woff2 similarity index 100% rename from fonts/ko/woff2/Pretendard-Thin.woff2 rename to legacy/fonts/ko/woff2/Pretendard-Thin.woff2 diff --git a/fonts/open-sans/fonts.css b/legacy/fonts/open-sans/fonts.css similarity index 100% rename from fonts/open-sans/fonts.css rename to legacy/fonts/open-sans/fonts.css diff --git a/fonts/open-sans/woff/OpenSans-Italic.woff b/legacy/fonts/open-sans/woff/OpenSans-Italic.woff similarity index 100% rename from fonts/open-sans/woff/OpenSans-Italic.woff rename to legacy/fonts/open-sans/woff/OpenSans-Italic.woff diff --git a/fonts/open-sans/woff/OpenSans.woff b/legacy/fonts/open-sans/woff/OpenSans.woff similarity index 100% rename from fonts/open-sans/woff/OpenSans.woff rename to legacy/fonts/open-sans/woff/OpenSans.woff diff --git a/fonts/open-sans/woff2/open-sans-latin-wght-italic.woff2 b/legacy/fonts/open-sans/woff2/open-sans-latin-wght-italic.woff2 similarity index 100% rename from fonts/open-sans/woff2/open-sans-latin-wght-italic.woff2 rename to legacy/fonts/open-sans/woff2/open-sans-latin-wght-italic.woff2 diff --git a/fonts/open-sans/woff2/open-sans-latin-wght-normal.woff2 b/legacy/fonts/open-sans/woff2/open-sans-latin-wght-normal.woff2 similarity index 100% rename from fonts/open-sans/woff2/open-sans-latin-wght-normal.woff2 rename to legacy/fonts/open-sans/woff2/open-sans-latin-wght-normal.woff2 diff --git a/fr/3x/api.md b/legacy/fr/3x/api.md similarity index 100% rename from fr/3x/api.md rename to legacy/fr/3x/api.md diff --git a/fr/4x/api.md b/legacy/fr/4x/api.md similarity index 100% rename from fr/4x/api.md rename to legacy/fr/4x/api.md diff --git a/fr/5x/api.md b/legacy/fr/5x/api.md similarity index 100% rename from fr/5x/api.md rename to legacy/fr/5x/api.md diff --git a/fr/advanced/best-practice-performance.md b/legacy/fr/advanced/best-practice-performance.md similarity index 100% rename from fr/advanced/best-practice-performance.md rename to legacy/fr/advanced/best-practice-performance.md diff --git a/fr/advanced/best-practice-security.md b/legacy/fr/advanced/best-practice-security.md similarity index 100% rename from fr/advanced/best-practice-security.md rename to legacy/fr/advanced/best-practice-security.md diff --git a/fr/advanced/developing-template-engines.md b/legacy/fr/advanced/developing-template-engines.md similarity index 100% rename from fr/advanced/developing-template-engines.md rename to legacy/fr/advanced/developing-template-engines.md diff --git a/fr/advanced/healthcheck-graceful-shutdown.md b/legacy/fr/advanced/healthcheck-graceful-shutdown.md similarity index 100% rename from fr/advanced/healthcheck-graceful-shutdown.md rename to legacy/fr/advanced/healthcheck-graceful-shutdown.md diff --git a/fr/advanced/security-updates.md b/legacy/fr/advanced/security-updates.md similarity index 100% rename from fr/advanced/security-updates.md rename to legacy/fr/advanced/security-updates.md diff --git a/fr/api.md b/legacy/fr/api.md similarity index 100% rename from fr/api.md rename to legacy/fr/api.md diff --git a/fr/changelog/index.md b/legacy/fr/changelog/index.md similarity index 100% rename from fr/changelog/index.md rename to legacy/fr/changelog/index.md diff --git a/fr/guide/behind-proxies.md b/legacy/fr/guide/behind-proxies.md similarity index 100% rename from fr/guide/behind-proxies.md rename to legacy/fr/guide/behind-proxies.md diff --git a/fr/guide/database-integration.md b/legacy/fr/guide/database-integration.md similarity index 100% rename from fr/guide/database-integration.md rename to legacy/fr/guide/database-integration.md diff --git a/fr/guide/debugging.md b/legacy/fr/guide/debugging.md similarity index 100% rename from fr/guide/debugging.md rename to legacy/fr/guide/debugging.md diff --git a/fr/guide/error-handling.md b/legacy/fr/guide/error-handling.md similarity index 100% rename from fr/guide/error-handling.md rename to legacy/fr/guide/error-handling.md diff --git a/fr/guide/migrating-4.md b/legacy/fr/guide/migrating-4.md similarity index 100% rename from fr/guide/migrating-4.md rename to legacy/fr/guide/migrating-4.md diff --git a/fr/guide/migrating-5.md b/legacy/fr/guide/migrating-5.md similarity index 100% rename from fr/guide/migrating-5.md rename to legacy/fr/guide/migrating-5.md diff --git a/fr/guide/overriding-express-api.md b/legacy/fr/guide/overriding-express-api.md similarity index 100% rename from fr/guide/overriding-express-api.md rename to legacy/fr/guide/overriding-express-api.md diff --git a/fr/guide/routing.md b/legacy/fr/guide/routing.md similarity index 100% rename from fr/guide/routing.md rename to legacy/fr/guide/routing.md diff --git a/fr/guide/using-middleware.md b/legacy/fr/guide/using-middleware.md similarity index 100% rename from fr/guide/using-middleware.md rename to legacy/fr/guide/using-middleware.md diff --git a/fr/guide/using-template-engines.md b/legacy/fr/guide/using-template-engines.md similarity index 100% rename from fr/guide/using-template-engines.md rename to legacy/fr/guide/using-template-engines.md diff --git a/fr/guide/writing-middleware.md b/legacy/fr/guide/writing-middleware.md similarity index 100% rename from fr/guide/writing-middleware.md rename to legacy/fr/guide/writing-middleware.md diff --git a/fr/index.md b/legacy/fr/index.md similarity index 100% rename from fr/index.md rename to legacy/fr/index.md diff --git a/fr/resources/community.md b/legacy/fr/resources/community.md similarity index 100% rename from fr/resources/community.md rename to legacy/fr/resources/community.md diff --git a/fr/resources/contributing.md b/legacy/fr/resources/contributing.md similarity index 100% rename from fr/resources/contributing.md rename to legacy/fr/resources/contributing.md diff --git a/fr/resources/glossary.md b/legacy/fr/resources/glossary.md similarity index 100% rename from fr/resources/glossary.md rename to legacy/fr/resources/glossary.md diff --git a/fr/resources/middleware.md b/legacy/fr/resources/middleware.md similarity index 100% rename from fr/resources/middleware.md rename to legacy/fr/resources/middleware.md diff --git a/fr/resources/middleware/body-parser.md b/legacy/fr/resources/middleware/body-parser.md similarity index 100% rename from fr/resources/middleware/body-parser.md rename to legacy/fr/resources/middleware/body-parser.md diff --git a/fr/resources/middleware/compression.md b/legacy/fr/resources/middleware/compression.md similarity index 100% rename from fr/resources/middleware/compression.md rename to legacy/fr/resources/middleware/compression.md diff --git a/fr/resources/middleware/connect-rid.md b/legacy/fr/resources/middleware/connect-rid.md similarity index 100% rename from fr/resources/middleware/connect-rid.md rename to legacy/fr/resources/middleware/connect-rid.md diff --git a/fr/resources/middleware/cookie-parser.md b/legacy/fr/resources/middleware/cookie-parser.md similarity index 100% rename from fr/resources/middleware/cookie-parser.md rename to legacy/fr/resources/middleware/cookie-parser.md diff --git a/fr/resources/middleware/cookie-session.md b/legacy/fr/resources/middleware/cookie-session.md similarity index 100% rename from fr/resources/middleware/cookie-session.md rename to legacy/fr/resources/middleware/cookie-session.md diff --git a/fr/resources/middleware/cors.md b/legacy/fr/resources/middleware/cors.md similarity index 100% rename from fr/resources/middleware/cors.md rename to legacy/fr/resources/middleware/cors.md diff --git a/fr/resources/middleware/errorhandler.md b/legacy/fr/resources/middleware/errorhandler.md similarity index 100% rename from fr/resources/middleware/errorhandler.md rename to legacy/fr/resources/middleware/errorhandler.md diff --git a/fr/resources/middleware/method-override.md b/legacy/fr/resources/middleware/method-override.md similarity index 100% rename from fr/resources/middleware/method-override.md rename to legacy/fr/resources/middleware/method-override.md diff --git a/fr/resources/middleware/morgan.md b/legacy/fr/resources/middleware/morgan.md similarity index 100% rename from fr/resources/middleware/morgan.md rename to legacy/fr/resources/middleware/morgan.md diff --git a/fr/resources/middleware/multer.md b/legacy/fr/resources/middleware/multer.md similarity index 100% rename from fr/resources/middleware/multer.md rename to legacy/fr/resources/middleware/multer.md diff --git a/fr/resources/middleware/response-time.md b/legacy/fr/resources/middleware/response-time.md similarity index 100% rename from fr/resources/middleware/response-time.md rename to legacy/fr/resources/middleware/response-time.md diff --git a/fr/resources/middleware/serve-favicon.md b/legacy/fr/resources/middleware/serve-favicon.md similarity index 100% rename from fr/resources/middleware/serve-favicon.md rename to legacy/fr/resources/middleware/serve-favicon.md diff --git a/fr/resources/middleware/serve-index.md b/legacy/fr/resources/middleware/serve-index.md similarity index 100% rename from fr/resources/middleware/serve-index.md rename to legacy/fr/resources/middleware/serve-index.md diff --git a/fr/resources/middleware/serve-static.md b/legacy/fr/resources/middleware/serve-static.md similarity index 100% rename from fr/resources/middleware/serve-static.md rename to legacy/fr/resources/middleware/serve-static.md diff --git a/fr/resources/middleware/session.md b/legacy/fr/resources/middleware/session.md similarity index 100% rename from fr/resources/middleware/session.md rename to legacy/fr/resources/middleware/session.md diff --git a/fr/resources/middleware/timeout.md b/legacy/fr/resources/middleware/timeout.md similarity index 100% rename from fr/resources/middleware/timeout.md rename to legacy/fr/resources/middleware/timeout.md diff --git a/fr/resources/middleware/vhost.md b/legacy/fr/resources/middleware/vhost.md similarity index 100% rename from fr/resources/middleware/vhost.md rename to legacy/fr/resources/middleware/vhost.md diff --git a/fr/resources/utils.md b/legacy/fr/resources/utils.md similarity index 100% rename from fr/resources/utils.md rename to legacy/fr/resources/utils.md diff --git a/fr/starter/basic-routing.md b/legacy/fr/starter/basic-routing.md similarity index 100% rename from fr/starter/basic-routing.md rename to legacy/fr/starter/basic-routing.md diff --git a/fr/starter/examples.md b/legacy/fr/starter/examples.md similarity index 100% rename from fr/starter/examples.md rename to legacy/fr/starter/examples.md diff --git a/fr/starter/faq.md b/legacy/fr/starter/faq.md similarity index 100% rename from fr/starter/faq.md rename to legacy/fr/starter/faq.md diff --git a/fr/starter/generator.md b/legacy/fr/starter/generator.md similarity index 100% rename from fr/starter/generator.md rename to legacy/fr/starter/generator.md diff --git a/fr/starter/hello-world.md b/legacy/fr/starter/hello-world.md similarity index 100% rename from fr/starter/hello-world.md rename to legacy/fr/starter/hello-world.md diff --git a/fr/starter/installing.md b/legacy/fr/starter/installing.md similarity index 100% rename from fr/starter/installing.md rename to legacy/fr/starter/installing.md diff --git a/fr/starter/static-files.md b/legacy/fr/starter/static-files.md similarity index 100% rename from fr/starter/static-files.md rename to legacy/fr/starter/static-files.md diff --git a/fr/support/index.md b/legacy/fr/support/index.md similarity index 100% rename from fr/support/index.md rename to legacy/fr/support/index.md diff --git a/images/blogger.jpg b/legacy/images/blogger.jpg similarity index 100% rename from images/blogger.jpg rename to legacy/images/blogger.jpg diff --git a/images/brand/logo-dark.svg b/legacy/images/brand/logo-dark.svg similarity index 100% rename from images/brand/logo-dark.svg rename to legacy/images/brand/logo-dark.svg diff --git a/images/brand/logo-light.svg b/legacy/images/brand/logo-light.svg similarity index 100% rename from images/brand/logo-light.svg rename to legacy/images/brand/logo-light.svg diff --git a/images/brand/logotype-dark.svg b/legacy/images/brand/logotype-dark.svg similarity index 100% rename from images/brand/logotype-dark.svg rename to legacy/images/brand/logotype-dark.svg diff --git a/images/brand/logotype-light.svg b/legacy/images/brand/logotype-light.svg similarity index 100% rename from images/brand/logotype-light.svg rename to legacy/images/brand/logotype-light.svg diff --git a/images/clustering.png b/legacy/images/clustering.png similarity index 100% rename from images/clustering.png rename to legacy/images/clustering.png diff --git a/images/copy-btn.svg b/legacy/images/copy-btn.svg similarity index 100% rename from images/copy-btn.svg rename to legacy/images/copy-btn.svg diff --git a/images/express-mw.png b/legacy/images/express-mw.png similarity index 100% rename from images/express-mw.png rename to legacy/images/express-mw.png diff --git a/images/favicon.ico b/legacy/images/favicon.ico similarity index 100% rename from images/favicon.ico rename to legacy/images/favicon.ico diff --git a/images/favicon.png b/legacy/images/favicon.png similarity index 100% rename from images/favicon.png rename to legacy/images/favicon.png diff --git a/images/og.png b/legacy/images/og.png similarity index 100% rename from images/og.png rename to legacy/images/og.png diff --git a/index.md b/legacy/index.md similarity index 100% rename from index.md rename to legacy/index.md diff --git a/it/3x/api.md b/legacy/it/3x/api.md similarity index 100% rename from it/3x/api.md rename to legacy/it/3x/api.md diff --git a/it/4x/api.md b/legacy/it/4x/api.md similarity index 100% rename from it/4x/api.md rename to legacy/it/4x/api.md diff --git a/it/5x/api.md b/legacy/it/5x/api.md similarity index 100% rename from it/5x/api.md rename to legacy/it/5x/api.md diff --git a/it/advanced/best-practice-performance.md b/legacy/it/advanced/best-practice-performance.md similarity index 100% rename from it/advanced/best-practice-performance.md rename to legacy/it/advanced/best-practice-performance.md diff --git a/it/advanced/best-practice-security.md b/legacy/it/advanced/best-practice-security.md similarity index 100% rename from it/advanced/best-practice-security.md rename to legacy/it/advanced/best-practice-security.md diff --git a/it/advanced/developing-template-engines.md b/legacy/it/advanced/developing-template-engines.md similarity index 100% rename from it/advanced/developing-template-engines.md rename to legacy/it/advanced/developing-template-engines.md diff --git a/it/advanced/healthcheck-graceful-shutdown.md b/legacy/it/advanced/healthcheck-graceful-shutdown.md similarity index 100% rename from it/advanced/healthcheck-graceful-shutdown.md rename to legacy/it/advanced/healthcheck-graceful-shutdown.md diff --git a/it/advanced/security-updates.md b/legacy/it/advanced/security-updates.md similarity index 100% rename from it/advanced/security-updates.md rename to legacy/it/advanced/security-updates.md diff --git a/it/api.md b/legacy/it/api.md similarity index 100% rename from it/api.md rename to legacy/it/api.md diff --git a/it/changelog/index.md b/legacy/it/changelog/index.md similarity index 100% rename from it/changelog/index.md rename to legacy/it/changelog/index.md diff --git a/it/guide/behind-proxies.md b/legacy/it/guide/behind-proxies.md similarity index 100% rename from it/guide/behind-proxies.md rename to legacy/it/guide/behind-proxies.md diff --git a/it/guide/database-integration.md b/legacy/it/guide/database-integration.md similarity index 100% rename from it/guide/database-integration.md rename to legacy/it/guide/database-integration.md diff --git a/it/guide/debugging.md b/legacy/it/guide/debugging.md similarity index 100% rename from it/guide/debugging.md rename to legacy/it/guide/debugging.md diff --git a/it/guide/error-handling.md b/legacy/it/guide/error-handling.md similarity index 100% rename from it/guide/error-handling.md rename to legacy/it/guide/error-handling.md diff --git a/it/guide/migrating-4.md b/legacy/it/guide/migrating-4.md similarity index 100% rename from it/guide/migrating-4.md rename to legacy/it/guide/migrating-4.md diff --git a/it/guide/migrating-5.md b/legacy/it/guide/migrating-5.md similarity index 100% rename from it/guide/migrating-5.md rename to legacy/it/guide/migrating-5.md diff --git a/it/guide/overriding-express-api.md b/legacy/it/guide/overriding-express-api.md similarity index 100% rename from it/guide/overriding-express-api.md rename to legacy/it/guide/overriding-express-api.md diff --git a/it/guide/routing.md b/legacy/it/guide/routing.md similarity index 100% rename from it/guide/routing.md rename to legacy/it/guide/routing.md diff --git a/it/guide/using-middleware.md b/legacy/it/guide/using-middleware.md similarity index 100% rename from it/guide/using-middleware.md rename to legacy/it/guide/using-middleware.md diff --git a/it/guide/using-template-engines.md b/legacy/it/guide/using-template-engines.md similarity index 100% rename from it/guide/using-template-engines.md rename to legacy/it/guide/using-template-engines.md diff --git a/it/guide/writing-middleware.md b/legacy/it/guide/writing-middleware.md similarity index 100% rename from it/guide/writing-middleware.md rename to legacy/it/guide/writing-middleware.md diff --git a/it/index.md b/legacy/it/index.md similarity index 100% rename from it/index.md rename to legacy/it/index.md diff --git a/it/resources/community.md b/legacy/it/resources/community.md similarity index 100% rename from it/resources/community.md rename to legacy/it/resources/community.md diff --git a/it/resources/contributing.md b/legacy/it/resources/contributing.md similarity index 100% rename from it/resources/contributing.md rename to legacy/it/resources/contributing.md diff --git a/it/resources/glossary.md b/legacy/it/resources/glossary.md similarity index 100% rename from it/resources/glossary.md rename to legacy/it/resources/glossary.md diff --git a/it/resources/middleware.md b/legacy/it/resources/middleware.md similarity index 100% rename from it/resources/middleware.md rename to legacy/it/resources/middleware.md diff --git a/it/resources/middleware/body-parser.md b/legacy/it/resources/middleware/body-parser.md similarity index 100% rename from it/resources/middleware/body-parser.md rename to legacy/it/resources/middleware/body-parser.md diff --git a/it/resources/middleware/compression.md b/legacy/it/resources/middleware/compression.md similarity index 100% rename from it/resources/middleware/compression.md rename to legacy/it/resources/middleware/compression.md diff --git a/it/resources/middleware/connect-rid.md b/legacy/it/resources/middleware/connect-rid.md similarity index 100% rename from it/resources/middleware/connect-rid.md rename to legacy/it/resources/middleware/connect-rid.md diff --git a/it/resources/middleware/cookie-parser.md b/legacy/it/resources/middleware/cookie-parser.md similarity index 100% rename from it/resources/middleware/cookie-parser.md rename to legacy/it/resources/middleware/cookie-parser.md diff --git a/it/resources/middleware/cookie-session.md b/legacy/it/resources/middleware/cookie-session.md similarity index 100% rename from it/resources/middleware/cookie-session.md rename to legacy/it/resources/middleware/cookie-session.md diff --git a/it/resources/middleware/cors.md b/legacy/it/resources/middleware/cors.md similarity index 100% rename from it/resources/middleware/cors.md rename to legacy/it/resources/middleware/cors.md diff --git a/it/resources/middleware/errorhandler.md b/legacy/it/resources/middleware/errorhandler.md similarity index 100% rename from it/resources/middleware/errorhandler.md rename to legacy/it/resources/middleware/errorhandler.md diff --git a/it/resources/middleware/method-override.md b/legacy/it/resources/middleware/method-override.md similarity index 100% rename from it/resources/middleware/method-override.md rename to legacy/it/resources/middleware/method-override.md diff --git a/it/resources/middleware/morgan.md b/legacy/it/resources/middleware/morgan.md similarity index 100% rename from it/resources/middleware/morgan.md rename to legacy/it/resources/middleware/morgan.md diff --git a/it/resources/middleware/multer.md b/legacy/it/resources/middleware/multer.md similarity index 100% rename from it/resources/middleware/multer.md rename to legacy/it/resources/middleware/multer.md diff --git a/it/resources/middleware/response-time.md b/legacy/it/resources/middleware/response-time.md similarity index 100% rename from it/resources/middleware/response-time.md rename to legacy/it/resources/middleware/response-time.md diff --git a/it/resources/middleware/serve-favicon.md b/legacy/it/resources/middleware/serve-favicon.md similarity index 100% rename from it/resources/middleware/serve-favicon.md rename to legacy/it/resources/middleware/serve-favicon.md diff --git a/it/resources/middleware/serve-index.md b/legacy/it/resources/middleware/serve-index.md similarity index 100% rename from it/resources/middleware/serve-index.md rename to legacy/it/resources/middleware/serve-index.md diff --git a/it/resources/middleware/serve-static.md b/legacy/it/resources/middleware/serve-static.md similarity index 100% rename from it/resources/middleware/serve-static.md rename to legacy/it/resources/middleware/serve-static.md diff --git a/it/resources/middleware/session.md b/legacy/it/resources/middleware/session.md similarity index 100% rename from it/resources/middleware/session.md rename to legacy/it/resources/middleware/session.md diff --git a/it/resources/middleware/timeout.md b/legacy/it/resources/middleware/timeout.md similarity index 100% rename from it/resources/middleware/timeout.md rename to legacy/it/resources/middleware/timeout.md diff --git a/it/resources/middleware/vhost.md b/legacy/it/resources/middleware/vhost.md similarity index 100% rename from it/resources/middleware/vhost.md rename to legacy/it/resources/middleware/vhost.md diff --git a/it/resources/utils.md b/legacy/it/resources/utils.md similarity index 100% rename from it/resources/utils.md rename to legacy/it/resources/utils.md diff --git a/it/starter/basic-routing.md b/legacy/it/starter/basic-routing.md similarity index 100% rename from it/starter/basic-routing.md rename to legacy/it/starter/basic-routing.md diff --git a/it/starter/examples.md b/legacy/it/starter/examples.md similarity index 100% rename from it/starter/examples.md rename to legacy/it/starter/examples.md diff --git a/it/starter/faq.md b/legacy/it/starter/faq.md similarity index 100% rename from it/starter/faq.md rename to legacy/it/starter/faq.md diff --git a/it/starter/generator.md b/legacy/it/starter/generator.md similarity index 100% rename from it/starter/generator.md rename to legacy/it/starter/generator.md diff --git a/it/starter/hello-world.md b/legacy/it/starter/hello-world.md similarity index 100% rename from it/starter/hello-world.md rename to legacy/it/starter/hello-world.md diff --git a/it/starter/installing.md b/legacy/it/starter/installing.md similarity index 100% rename from it/starter/installing.md rename to legacy/it/starter/installing.md diff --git a/it/starter/static-files.md b/legacy/it/starter/static-files.md similarity index 100% rename from it/starter/static-files.md rename to legacy/it/starter/static-files.md diff --git a/it/support/index.md b/legacy/it/support/index.md similarity index 100% rename from it/support/index.md rename to legacy/it/support/index.md diff --git a/ja/3x/api.md b/legacy/ja/3x/api.md similarity index 100% rename from ja/3x/api.md rename to legacy/ja/3x/api.md diff --git a/ja/4x/api.md b/legacy/ja/4x/api.md similarity index 100% rename from ja/4x/api.md rename to legacy/ja/4x/api.md diff --git a/ja/5x/api.md b/legacy/ja/5x/api.md similarity index 100% rename from ja/5x/api.md rename to legacy/ja/5x/api.md diff --git a/ja/advanced/best-practice-performance.md b/legacy/ja/advanced/best-practice-performance.md similarity index 100% rename from ja/advanced/best-practice-performance.md rename to legacy/ja/advanced/best-practice-performance.md diff --git a/ja/advanced/best-practice-security.md b/legacy/ja/advanced/best-practice-security.md similarity index 100% rename from ja/advanced/best-practice-security.md rename to legacy/ja/advanced/best-practice-security.md diff --git a/ja/advanced/developing-template-engines.md b/legacy/ja/advanced/developing-template-engines.md similarity index 100% rename from ja/advanced/developing-template-engines.md rename to legacy/ja/advanced/developing-template-engines.md diff --git a/ja/advanced/healthcheck-graceful-shutdown.md b/legacy/ja/advanced/healthcheck-graceful-shutdown.md similarity index 100% rename from ja/advanced/healthcheck-graceful-shutdown.md rename to legacy/ja/advanced/healthcheck-graceful-shutdown.md diff --git a/ja/advanced/security-updates.md b/legacy/ja/advanced/security-updates.md similarity index 100% rename from ja/advanced/security-updates.md rename to legacy/ja/advanced/security-updates.md diff --git a/ja/api.md b/legacy/ja/api.md similarity index 100% rename from ja/api.md rename to legacy/ja/api.md diff --git a/ja/changelog/index.md b/legacy/ja/changelog/index.md similarity index 100% rename from ja/changelog/index.md rename to legacy/ja/changelog/index.md diff --git a/ja/guide/behind-proxies.md b/legacy/ja/guide/behind-proxies.md similarity index 100% rename from ja/guide/behind-proxies.md rename to legacy/ja/guide/behind-proxies.md diff --git a/ja/guide/database-integration.md b/legacy/ja/guide/database-integration.md similarity index 100% rename from ja/guide/database-integration.md rename to legacy/ja/guide/database-integration.md diff --git a/ja/guide/debugging.md b/legacy/ja/guide/debugging.md similarity index 100% rename from ja/guide/debugging.md rename to legacy/ja/guide/debugging.md diff --git a/ja/guide/error-handling.md b/legacy/ja/guide/error-handling.md similarity index 100% rename from ja/guide/error-handling.md rename to legacy/ja/guide/error-handling.md diff --git a/ja/guide/migrating-4.md b/legacy/ja/guide/migrating-4.md similarity index 100% rename from ja/guide/migrating-4.md rename to legacy/ja/guide/migrating-4.md diff --git a/ja/guide/migrating-5.md b/legacy/ja/guide/migrating-5.md similarity index 100% rename from ja/guide/migrating-5.md rename to legacy/ja/guide/migrating-5.md diff --git a/ja/guide/overriding-express-api.md b/legacy/ja/guide/overriding-express-api.md similarity index 100% rename from ja/guide/overriding-express-api.md rename to legacy/ja/guide/overriding-express-api.md diff --git a/ja/guide/routing.md b/legacy/ja/guide/routing.md similarity index 100% rename from ja/guide/routing.md rename to legacy/ja/guide/routing.md diff --git a/ja/guide/using-middleware.md b/legacy/ja/guide/using-middleware.md similarity index 100% rename from ja/guide/using-middleware.md rename to legacy/ja/guide/using-middleware.md diff --git a/ja/guide/using-template-engines.md b/legacy/ja/guide/using-template-engines.md similarity index 100% rename from ja/guide/using-template-engines.md rename to legacy/ja/guide/using-template-engines.md diff --git a/ja/guide/writing-middleware.md b/legacy/ja/guide/writing-middleware.md similarity index 100% rename from ja/guide/writing-middleware.md rename to legacy/ja/guide/writing-middleware.md diff --git a/ja/index.md b/legacy/ja/index.md similarity index 100% rename from ja/index.md rename to legacy/ja/index.md diff --git a/ja/resources/community.md b/legacy/ja/resources/community.md similarity index 100% rename from ja/resources/community.md rename to legacy/ja/resources/community.md diff --git a/ja/resources/contributing.md b/legacy/ja/resources/contributing.md similarity index 100% rename from ja/resources/contributing.md rename to legacy/ja/resources/contributing.md diff --git a/ja/resources/glossary.md b/legacy/ja/resources/glossary.md similarity index 100% rename from ja/resources/glossary.md rename to legacy/ja/resources/glossary.md diff --git a/ja/resources/middleware.md b/legacy/ja/resources/middleware.md similarity index 100% rename from ja/resources/middleware.md rename to legacy/ja/resources/middleware.md diff --git a/ja/resources/middleware/body-parser.md b/legacy/ja/resources/middleware/body-parser.md similarity index 100% rename from ja/resources/middleware/body-parser.md rename to legacy/ja/resources/middleware/body-parser.md diff --git a/ja/resources/middleware/compression.md b/legacy/ja/resources/middleware/compression.md similarity index 100% rename from ja/resources/middleware/compression.md rename to legacy/ja/resources/middleware/compression.md diff --git a/ja/resources/middleware/connect-rid.md b/legacy/ja/resources/middleware/connect-rid.md similarity index 100% rename from ja/resources/middleware/connect-rid.md rename to legacy/ja/resources/middleware/connect-rid.md diff --git a/ja/resources/middleware/cookie-parser.md b/legacy/ja/resources/middleware/cookie-parser.md similarity index 100% rename from ja/resources/middleware/cookie-parser.md rename to legacy/ja/resources/middleware/cookie-parser.md diff --git a/ja/resources/middleware/cookie-session.md b/legacy/ja/resources/middleware/cookie-session.md similarity index 100% rename from ja/resources/middleware/cookie-session.md rename to legacy/ja/resources/middleware/cookie-session.md diff --git a/ja/resources/middleware/cors.md b/legacy/ja/resources/middleware/cors.md similarity index 100% rename from ja/resources/middleware/cors.md rename to legacy/ja/resources/middleware/cors.md diff --git a/ja/resources/middleware/errorhandler.md b/legacy/ja/resources/middleware/errorhandler.md similarity index 100% rename from ja/resources/middleware/errorhandler.md rename to legacy/ja/resources/middleware/errorhandler.md diff --git a/ja/resources/middleware/method-override.md b/legacy/ja/resources/middleware/method-override.md similarity index 100% rename from ja/resources/middleware/method-override.md rename to legacy/ja/resources/middleware/method-override.md diff --git a/ja/resources/middleware/morgan.md b/legacy/ja/resources/middleware/morgan.md similarity index 100% rename from ja/resources/middleware/morgan.md rename to legacy/ja/resources/middleware/morgan.md diff --git a/ja/resources/middleware/multer.md b/legacy/ja/resources/middleware/multer.md similarity index 100% rename from ja/resources/middleware/multer.md rename to legacy/ja/resources/middleware/multer.md diff --git a/ja/resources/middleware/response-time.md b/legacy/ja/resources/middleware/response-time.md similarity index 100% rename from ja/resources/middleware/response-time.md rename to legacy/ja/resources/middleware/response-time.md diff --git a/ja/resources/middleware/serve-favicon.md b/legacy/ja/resources/middleware/serve-favicon.md similarity index 100% rename from ja/resources/middleware/serve-favicon.md rename to legacy/ja/resources/middleware/serve-favicon.md diff --git a/ja/resources/middleware/serve-index.md b/legacy/ja/resources/middleware/serve-index.md similarity index 100% rename from ja/resources/middleware/serve-index.md rename to legacy/ja/resources/middleware/serve-index.md diff --git a/ja/resources/middleware/serve-static.md b/legacy/ja/resources/middleware/serve-static.md similarity index 100% rename from ja/resources/middleware/serve-static.md rename to legacy/ja/resources/middleware/serve-static.md diff --git a/ja/resources/middleware/session.md b/legacy/ja/resources/middleware/session.md similarity index 100% rename from ja/resources/middleware/session.md rename to legacy/ja/resources/middleware/session.md diff --git a/ja/resources/middleware/timeout.md b/legacy/ja/resources/middleware/timeout.md similarity index 100% rename from ja/resources/middleware/timeout.md rename to legacy/ja/resources/middleware/timeout.md diff --git a/ja/resources/middleware/vhost.md b/legacy/ja/resources/middleware/vhost.md similarity index 100% rename from ja/resources/middleware/vhost.md rename to legacy/ja/resources/middleware/vhost.md diff --git a/ja/resources/utils.md b/legacy/ja/resources/utils.md similarity index 100% rename from ja/resources/utils.md rename to legacy/ja/resources/utils.md diff --git a/ja/starter/basic-routing.md b/legacy/ja/starter/basic-routing.md similarity index 100% rename from ja/starter/basic-routing.md rename to legacy/ja/starter/basic-routing.md diff --git a/ja/starter/examples.md b/legacy/ja/starter/examples.md similarity index 100% rename from ja/starter/examples.md rename to legacy/ja/starter/examples.md diff --git a/ja/starter/faq.md b/legacy/ja/starter/faq.md similarity index 100% rename from ja/starter/faq.md rename to legacy/ja/starter/faq.md diff --git a/ja/starter/generator.md b/legacy/ja/starter/generator.md similarity index 100% rename from ja/starter/generator.md rename to legacy/ja/starter/generator.md diff --git a/ja/starter/hello-world.md b/legacy/ja/starter/hello-world.md similarity index 100% rename from ja/starter/hello-world.md rename to legacy/ja/starter/hello-world.md diff --git a/ja/starter/installing.md b/legacy/ja/starter/installing.md similarity index 100% rename from ja/starter/installing.md rename to legacy/ja/starter/installing.md diff --git a/ja/starter/static-files.md b/legacy/ja/starter/static-files.md similarity index 100% rename from ja/starter/static-files.md rename to legacy/ja/starter/static-files.md diff --git a/ja/support/index.md b/legacy/ja/support/index.md similarity index 100% rename from ja/support/index.md rename to legacy/ja/support/index.md diff --git a/js/app.js b/legacy/js/app.js similarity index 100% rename from js/app.js rename to legacy/js/app.js diff --git a/js/copycode.js b/legacy/js/copycode.js similarity index 100% rename from js/copycode.js rename to legacy/js/copycode.js diff --git a/js/menu.js b/legacy/js/menu.js similarity index 100% rename from js/menu.js rename to legacy/js/menu.js diff --git a/js/theme.js b/legacy/js/theme.js similarity index 100% rename from js/theme.js rename to legacy/js/theme.js diff --git a/ko/3x/api.md b/legacy/ko/3x/api.md similarity index 100% rename from ko/3x/api.md rename to legacy/ko/3x/api.md diff --git a/ko/4x/api.md b/legacy/ko/4x/api.md similarity index 100% rename from ko/4x/api.md rename to legacy/ko/4x/api.md diff --git a/ko/5x/api.md b/legacy/ko/5x/api.md similarity index 100% rename from ko/5x/api.md rename to legacy/ko/5x/api.md diff --git a/ko/advanced/best-practice-performance.md b/legacy/ko/advanced/best-practice-performance.md similarity index 100% rename from ko/advanced/best-practice-performance.md rename to legacy/ko/advanced/best-practice-performance.md diff --git a/ko/advanced/best-practice-security.md b/legacy/ko/advanced/best-practice-security.md similarity index 100% rename from ko/advanced/best-practice-security.md rename to legacy/ko/advanced/best-practice-security.md diff --git a/ko/advanced/developing-template-engines.md b/legacy/ko/advanced/developing-template-engines.md similarity index 100% rename from ko/advanced/developing-template-engines.md rename to legacy/ko/advanced/developing-template-engines.md diff --git a/ko/advanced/healthcheck-graceful-shutdown.md b/legacy/ko/advanced/healthcheck-graceful-shutdown.md similarity index 100% rename from ko/advanced/healthcheck-graceful-shutdown.md rename to legacy/ko/advanced/healthcheck-graceful-shutdown.md diff --git a/ko/advanced/security-updates.md b/legacy/ko/advanced/security-updates.md similarity index 100% rename from ko/advanced/security-updates.md rename to legacy/ko/advanced/security-updates.md diff --git a/ko/api.md b/legacy/ko/api.md similarity index 100% rename from ko/api.md rename to legacy/ko/api.md diff --git a/ko/changelog/4x.md b/legacy/ko/changelog/4x.md similarity index 100% rename from ko/changelog/4x.md rename to legacy/ko/changelog/4x.md diff --git a/ko/changelog/index.md b/legacy/ko/changelog/index.md similarity index 100% rename from ko/changelog/index.md rename to legacy/ko/changelog/index.md diff --git a/ko/guide/behind-proxies.md b/legacy/ko/guide/behind-proxies.md similarity index 100% rename from ko/guide/behind-proxies.md rename to legacy/ko/guide/behind-proxies.md diff --git a/ko/guide/database-integration.md b/legacy/ko/guide/database-integration.md similarity index 100% rename from ko/guide/database-integration.md rename to legacy/ko/guide/database-integration.md diff --git a/ko/guide/debugging.md b/legacy/ko/guide/debugging.md similarity index 100% rename from ko/guide/debugging.md rename to legacy/ko/guide/debugging.md diff --git a/ko/guide/error-handling.md b/legacy/ko/guide/error-handling.md similarity index 100% rename from ko/guide/error-handling.md rename to legacy/ko/guide/error-handling.md diff --git a/ko/guide/migrating-4.md b/legacy/ko/guide/migrating-4.md similarity index 100% rename from ko/guide/migrating-4.md rename to legacy/ko/guide/migrating-4.md diff --git a/ko/guide/migrating-5.md b/legacy/ko/guide/migrating-5.md similarity index 100% rename from ko/guide/migrating-5.md rename to legacy/ko/guide/migrating-5.md diff --git a/ko/guide/overriding-express-api.md b/legacy/ko/guide/overriding-express-api.md similarity index 100% rename from ko/guide/overriding-express-api.md rename to legacy/ko/guide/overriding-express-api.md diff --git a/ko/guide/routing.md b/legacy/ko/guide/routing.md similarity index 100% rename from ko/guide/routing.md rename to legacy/ko/guide/routing.md diff --git a/ko/guide/using-middleware.md b/legacy/ko/guide/using-middleware.md similarity index 100% rename from ko/guide/using-middleware.md rename to legacy/ko/guide/using-middleware.md diff --git a/ko/guide/using-template-engines.md b/legacy/ko/guide/using-template-engines.md similarity index 100% rename from ko/guide/using-template-engines.md rename to legacy/ko/guide/using-template-engines.md diff --git a/ko/guide/writing-middleware.md b/legacy/ko/guide/writing-middleware.md similarity index 100% rename from ko/guide/writing-middleware.md rename to legacy/ko/guide/writing-middleware.md diff --git a/ko/index.md b/legacy/ko/index.md similarity index 100% rename from ko/index.md rename to legacy/ko/index.md diff --git a/ko/resources/community.md b/legacy/ko/resources/community.md similarity index 100% rename from ko/resources/community.md rename to legacy/ko/resources/community.md diff --git a/ko/resources/contributing.md b/legacy/ko/resources/contributing.md similarity index 100% rename from ko/resources/contributing.md rename to legacy/ko/resources/contributing.md diff --git a/ko/resources/glossary.md b/legacy/ko/resources/glossary.md similarity index 100% rename from ko/resources/glossary.md rename to legacy/ko/resources/glossary.md diff --git a/ko/resources/middleware.md b/legacy/ko/resources/middleware.md similarity index 100% rename from ko/resources/middleware.md rename to legacy/ko/resources/middleware.md diff --git a/ko/resources/middleware/body-parser.md b/legacy/ko/resources/middleware/body-parser.md similarity index 100% rename from ko/resources/middleware/body-parser.md rename to legacy/ko/resources/middleware/body-parser.md diff --git a/ko/resources/middleware/compression.md b/legacy/ko/resources/middleware/compression.md similarity index 100% rename from ko/resources/middleware/compression.md rename to legacy/ko/resources/middleware/compression.md diff --git a/ko/resources/middleware/connect-rid.md b/legacy/ko/resources/middleware/connect-rid.md similarity index 100% rename from ko/resources/middleware/connect-rid.md rename to legacy/ko/resources/middleware/connect-rid.md diff --git a/ko/resources/middleware/cookie-parser.md b/legacy/ko/resources/middleware/cookie-parser.md similarity index 100% rename from ko/resources/middleware/cookie-parser.md rename to legacy/ko/resources/middleware/cookie-parser.md diff --git a/ko/resources/middleware/cookie-session.md b/legacy/ko/resources/middleware/cookie-session.md similarity index 100% rename from ko/resources/middleware/cookie-session.md rename to legacy/ko/resources/middleware/cookie-session.md diff --git a/ko/resources/middleware/cors.md b/legacy/ko/resources/middleware/cors.md similarity index 100% rename from ko/resources/middleware/cors.md rename to legacy/ko/resources/middleware/cors.md diff --git a/ko/resources/middleware/errorhandler.md b/legacy/ko/resources/middleware/errorhandler.md similarity index 100% rename from ko/resources/middleware/errorhandler.md rename to legacy/ko/resources/middleware/errorhandler.md diff --git a/ko/resources/middleware/method-override.md b/legacy/ko/resources/middleware/method-override.md similarity index 100% rename from ko/resources/middleware/method-override.md rename to legacy/ko/resources/middleware/method-override.md diff --git a/ko/resources/middleware/morgan.md b/legacy/ko/resources/middleware/morgan.md similarity index 100% rename from ko/resources/middleware/morgan.md rename to legacy/ko/resources/middleware/morgan.md diff --git a/ko/resources/middleware/multer.md b/legacy/ko/resources/middleware/multer.md similarity index 100% rename from ko/resources/middleware/multer.md rename to legacy/ko/resources/middleware/multer.md diff --git a/ko/resources/middleware/response-time.md b/legacy/ko/resources/middleware/response-time.md similarity index 100% rename from ko/resources/middleware/response-time.md rename to legacy/ko/resources/middleware/response-time.md diff --git a/ko/resources/middleware/serve-favicon.md b/legacy/ko/resources/middleware/serve-favicon.md similarity index 100% rename from ko/resources/middleware/serve-favicon.md rename to legacy/ko/resources/middleware/serve-favicon.md diff --git a/ko/resources/middleware/serve-index.md b/legacy/ko/resources/middleware/serve-index.md similarity index 100% rename from ko/resources/middleware/serve-index.md rename to legacy/ko/resources/middleware/serve-index.md diff --git a/ko/resources/middleware/serve-static.md b/legacy/ko/resources/middleware/serve-static.md similarity index 100% rename from ko/resources/middleware/serve-static.md rename to legacy/ko/resources/middleware/serve-static.md diff --git a/ko/resources/middleware/session.md b/legacy/ko/resources/middleware/session.md similarity index 100% rename from ko/resources/middleware/session.md rename to legacy/ko/resources/middleware/session.md diff --git a/ko/resources/middleware/timeout.md b/legacy/ko/resources/middleware/timeout.md similarity index 100% rename from ko/resources/middleware/timeout.md rename to legacy/ko/resources/middleware/timeout.md diff --git a/ko/resources/middleware/vhost.md b/legacy/ko/resources/middleware/vhost.md similarity index 100% rename from ko/resources/middleware/vhost.md rename to legacy/ko/resources/middleware/vhost.md diff --git a/ko/resources/utils.md b/legacy/ko/resources/utils.md similarity index 100% rename from ko/resources/utils.md rename to legacy/ko/resources/utils.md diff --git a/ko/starter/basic-routing.md b/legacy/ko/starter/basic-routing.md similarity index 100% rename from ko/starter/basic-routing.md rename to legacy/ko/starter/basic-routing.md diff --git a/ko/starter/examples.md b/legacy/ko/starter/examples.md similarity index 100% rename from ko/starter/examples.md rename to legacy/ko/starter/examples.md diff --git a/ko/starter/faq.md b/legacy/ko/starter/faq.md similarity index 100% rename from ko/starter/faq.md rename to legacy/ko/starter/faq.md diff --git a/ko/starter/generator.md b/legacy/ko/starter/generator.md similarity index 100% rename from ko/starter/generator.md rename to legacy/ko/starter/generator.md diff --git a/ko/starter/hello-world.md b/legacy/ko/starter/hello-world.md similarity index 100% rename from ko/starter/hello-world.md rename to legacy/ko/starter/hello-world.md diff --git a/ko/starter/installing.md b/legacy/ko/starter/installing.md similarity index 100% rename from ko/starter/installing.md rename to legacy/ko/starter/installing.md diff --git a/ko/starter/static-files.md b/legacy/ko/starter/static-files.md similarity index 100% rename from ko/starter/static-files.md rename to legacy/ko/starter/static-files.md diff --git a/ko/support/index.md b/legacy/ko/support/index.md similarity index 100% rename from ko/support/index.md rename to legacy/ko/support/index.md diff --git a/package-lock.json b/legacy/package-lock.json similarity index 100% rename from package-lock.json rename to legacy/package-lock.json diff --git a/package.json b/legacy/package.json similarity index 100% rename from package.json rename to legacy/package.json diff --git a/pt-br/3x/api.md b/legacy/pt-br/3x/api.md similarity index 100% rename from pt-br/3x/api.md rename to legacy/pt-br/3x/api.md diff --git a/pt-br/4x/api.md b/legacy/pt-br/4x/api.md similarity index 100% rename from pt-br/4x/api.md rename to legacy/pt-br/4x/api.md diff --git a/pt-br/5x/api.md b/legacy/pt-br/5x/api.md similarity index 100% rename from pt-br/5x/api.md rename to legacy/pt-br/5x/api.md diff --git a/pt-br/advanced/best-practice-performance.md b/legacy/pt-br/advanced/best-practice-performance.md similarity index 100% rename from pt-br/advanced/best-practice-performance.md rename to legacy/pt-br/advanced/best-practice-performance.md diff --git a/pt-br/advanced/best-practice-security.md b/legacy/pt-br/advanced/best-practice-security.md similarity index 100% rename from pt-br/advanced/best-practice-security.md rename to legacy/pt-br/advanced/best-practice-security.md diff --git a/pt-br/advanced/developing-template-engines.md b/legacy/pt-br/advanced/developing-template-engines.md similarity index 100% rename from pt-br/advanced/developing-template-engines.md rename to legacy/pt-br/advanced/developing-template-engines.md diff --git a/pt-br/advanced/healthcheck-graceful-shutdown.md b/legacy/pt-br/advanced/healthcheck-graceful-shutdown.md similarity index 100% rename from pt-br/advanced/healthcheck-graceful-shutdown.md rename to legacy/pt-br/advanced/healthcheck-graceful-shutdown.md diff --git a/pt-br/advanced/security-updates.md b/legacy/pt-br/advanced/security-updates.md similarity index 100% rename from pt-br/advanced/security-updates.md rename to legacy/pt-br/advanced/security-updates.md diff --git a/pt-br/api.md b/legacy/pt-br/api.md similarity index 100% rename from pt-br/api.md rename to legacy/pt-br/api.md diff --git a/pt-br/changelog/index.md b/legacy/pt-br/changelog/index.md similarity index 100% rename from pt-br/changelog/index.md rename to legacy/pt-br/changelog/index.md diff --git a/pt-br/guide/behind-proxies.md b/legacy/pt-br/guide/behind-proxies.md similarity index 100% rename from pt-br/guide/behind-proxies.md rename to legacy/pt-br/guide/behind-proxies.md diff --git a/pt-br/guide/database-integration.md b/legacy/pt-br/guide/database-integration.md similarity index 100% rename from pt-br/guide/database-integration.md rename to legacy/pt-br/guide/database-integration.md diff --git a/pt-br/guide/debugging.md b/legacy/pt-br/guide/debugging.md similarity index 100% rename from pt-br/guide/debugging.md rename to legacy/pt-br/guide/debugging.md diff --git a/pt-br/guide/error-handling.md b/legacy/pt-br/guide/error-handling.md similarity index 100% rename from pt-br/guide/error-handling.md rename to legacy/pt-br/guide/error-handling.md diff --git a/pt-br/guide/migrating-4.md b/legacy/pt-br/guide/migrating-4.md similarity index 100% rename from pt-br/guide/migrating-4.md rename to legacy/pt-br/guide/migrating-4.md diff --git a/pt-br/guide/migrating-5.md b/legacy/pt-br/guide/migrating-5.md similarity index 100% rename from pt-br/guide/migrating-5.md rename to legacy/pt-br/guide/migrating-5.md diff --git a/pt-br/guide/overriding-express-api.md b/legacy/pt-br/guide/overriding-express-api.md similarity index 100% rename from pt-br/guide/overriding-express-api.md rename to legacy/pt-br/guide/overriding-express-api.md diff --git a/pt-br/guide/routing.md b/legacy/pt-br/guide/routing.md similarity index 100% rename from pt-br/guide/routing.md rename to legacy/pt-br/guide/routing.md diff --git a/pt-br/guide/using-middleware.md b/legacy/pt-br/guide/using-middleware.md similarity index 100% rename from pt-br/guide/using-middleware.md rename to legacy/pt-br/guide/using-middleware.md diff --git a/pt-br/guide/using-template-engines.md b/legacy/pt-br/guide/using-template-engines.md similarity index 100% rename from pt-br/guide/using-template-engines.md rename to legacy/pt-br/guide/using-template-engines.md diff --git a/pt-br/guide/writing-middleware.md b/legacy/pt-br/guide/writing-middleware.md similarity index 100% rename from pt-br/guide/writing-middleware.md rename to legacy/pt-br/guide/writing-middleware.md diff --git a/pt-br/index.md b/legacy/pt-br/index.md similarity index 100% rename from pt-br/index.md rename to legacy/pt-br/index.md diff --git a/pt-br/resources/community.md b/legacy/pt-br/resources/community.md similarity index 100% rename from pt-br/resources/community.md rename to legacy/pt-br/resources/community.md diff --git a/pt-br/resources/contributing.md b/legacy/pt-br/resources/contributing.md similarity index 100% rename from pt-br/resources/contributing.md rename to legacy/pt-br/resources/contributing.md diff --git a/pt-br/resources/glossary.md b/legacy/pt-br/resources/glossary.md similarity index 100% rename from pt-br/resources/glossary.md rename to legacy/pt-br/resources/glossary.md diff --git a/pt-br/resources/middleware.md b/legacy/pt-br/resources/middleware.md similarity index 100% rename from pt-br/resources/middleware.md rename to legacy/pt-br/resources/middleware.md diff --git a/pt-br/resources/middleware/body-parser.md b/legacy/pt-br/resources/middleware/body-parser.md similarity index 100% rename from pt-br/resources/middleware/body-parser.md rename to legacy/pt-br/resources/middleware/body-parser.md diff --git a/pt-br/resources/middleware/compression.md b/legacy/pt-br/resources/middleware/compression.md similarity index 100% rename from pt-br/resources/middleware/compression.md rename to legacy/pt-br/resources/middleware/compression.md diff --git a/pt-br/resources/middleware/connect-rid.md b/legacy/pt-br/resources/middleware/connect-rid.md similarity index 100% rename from pt-br/resources/middleware/connect-rid.md rename to legacy/pt-br/resources/middleware/connect-rid.md diff --git a/pt-br/resources/middleware/cookie-parser.md b/legacy/pt-br/resources/middleware/cookie-parser.md similarity index 100% rename from pt-br/resources/middleware/cookie-parser.md rename to legacy/pt-br/resources/middleware/cookie-parser.md diff --git a/pt-br/resources/middleware/cookie-session.md b/legacy/pt-br/resources/middleware/cookie-session.md similarity index 100% rename from pt-br/resources/middleware/cookie-session.md rename to legacy/pt-br/resources/middleware/cookie-session.md diff --git a/pt-br/resources/middleware/cors.md b/legacy/pt-br/resources/middleware/cors.md similarity index 100% rename from pt-br/resources/middleware/cors.md rename to legacy/pt-br/resources/middleware/cors.md diff --git a/pt-br/resources/middleware/errorhandler.md b/legacy/pt-br/resources/middleware/errorhandler.md similarity index 100% rename from pt-br/resources/middleware/errorhandler.md rename to legacy/pt-br/resources/middleware/errorhandler.md diff --git a/pt-br/resources/middleware/method-override.md b/legacy/pt-br/resources/middleware/method-override.md similarity index 100% rename from pt-br/resources/middleware/method-override.md rename to legacy/pt-br/resources/middleware/method-override.md diff --git a/pt-br/resources/middleware/morgan.md b/legacy/pt-br/resources/middleware/morgan.md similarity index 100% rename from pt-br/resources/middleware/morgan.md rename to legacy/pt-br/resources/middleware/morgan.md diff --git a/pt-br/resources/middleware/multer.md b/legacy/pt-br/resources/middleware/multer.md similarity index 100% rename from pt-br/resources/middleware/multer.md rename to legacy/pt-br/resources/middleware/multer.md diff --git a/pt-br/resources/middleware/response-time.md b/legacy/pt-br/resources/middleware/response-time.md similarity index 100% rename from pt-br/resources/middleware/response-time.md rename to legacy/pt-br/resources/middleware/response-time.md diff --git a/pt-br/resources/middleware/serve-favicon.md b/legacy/pt-br/resources/middleware/serve-favicon.md similarity index 100% rename from pt-br/resources/middleware/serve-favicon.md rename to legacy/pt-br/resources/middleware/serve-favicon.md diff --git a/pt-br/resources/middleware/serve-index.md b/legacy/pt-br/resources/middleware/serve-index.md similarity index 100% rename from pt-br/resources/middleware/serve-index.md rename to legacy/pt-br/resources/middleware/serve-index.md diff --git a/pt-br/resources/middleware/serve-static.md b/legacy/pt-br/resources/middleware/serve-static.md similarity index 100% rename from pt-br/resources/middleware/serve-static.md rename to legacy/pt-br/resources/middleware/serve-static.md diff --git a/pt-br/resources/middleware/session.md b/legacy/pt-br/resources/middleware/session.md similarity index 100% rename from pt-br/resources/middleware/session.md rename to legacy/pt-br/resources/middleware/session.md diff --git a/pt-br/resources/middleware/timeout.md b/legacy/pt-br/resources/middleware/timeout.md similarity index 100% rename from pt-br/resources/middleware/timeout.md rename to legacy/pt-br/resources/middleware/timeout.md diff --git a/pt-br/resources/middleware/vhost.md b/legacy/pt-br/resources/middleware/vhost.md similarity index 100% rename from pt-br/resources/middleware/vhost.md rename to legacy/pt-br/resources/middleware/vhost.md diff --git a/pt-br/resources/utils.md b/legacy/pt-br/resources/utils.md similarity index 100% rename from pt-br/resources/utils.md rename to legacy/pt-br/resources/utils.md diff --git a/pt-br/starter/basic-routing.md b/legacy/pt-br/starter/basic-routing.md similarity index 100% rename from pt-br/starter/basic-routing.md rename to legacy/pt-br/starter/basic-routing.md diff --git a/pt-br/starter/examples.md b/legacy/pt-br/starter/examples.md similarity index 100% rename from pt-br/starter/examples.md rename to legacy/pt-br/starter/examples.md diff --git a/pt-br/starter/faq.md b/legacy/pt-br/starter/faq.md similarity index 100% rename from pt-br/starter/faq.md rename to legacy/pt-br/starter/faq.md diff --git a/pt-br/starter/generator.md b/legacy/pt-br/starter/generator.md similarity index 100% rename from pt-br/starter/generator.md rename to legacy/pt-br/starter/generator.md diff --git a/pt-br/starter/hello-world.md b/legacy/pt-br/starter/hello-world.md similarity index 100% rename from pt-br/starter/hello-world.md rename to legacy/pt-br/starter/hello-world.md diff --git a/pt-br/starter/installing.md b/legacy/pt-br/starter/installing.md similarity index 100% rename from pt-br/starter/installing.md rename to legacy/pt-br/starter/installing.md diff --git a/pt-br/starter/static-files.md b/legacy/pt-br/starter/static-files.md similarity index 100% rename from pt-br/starter/static-files.md rename to legacy/pt-br/starter/static-files.md diff --git a/pt-br/support/index.md b/legacy/pt-br/support/index.md similarity index 100% rename from pt-br/support/index.md rename to legacy/pt-br/support/index.md diff --git a/sitemap.xml b/legacy/sitemap.xml similarity index 100% rename from sitemap.xml rename to legacy/sitemap.xml diff --git a/vulnerabilities.xml b/legacy/vulnerabilities.xml similarity index 100% rename from vulnerabilities.xml rename to legacy/vulnerabilities.xml diff --git a/zh-cn/3x/api.md b/legacy/zh-cn/3x/api.md similarity index 100% rename from zh-cn/3x/api.md rename to legacy/zh-cn/3x/api.md diff --git a/zh-cn/4x/api.md b/legacy/zh-cn/4x/api.md similarity index 100% rename from zh-cn/4x/api.md rename to legacy/zh-cn/4x/api.md diff --git a/zh-cn/5x/api.md b/legacy/zh-cn/5x/api.md similarity index 100% rename from zh-cn/5x/api.md rename to legacy/zh-cn/5x/api.md diff --git a/zh-cn/advanced/best-practice-performance.md b/legacy/zh-cn/advanced/best-practice-performance.md similarity index 100% rename from zh-cn/advanced/best-practice-performance.md rename to legacy/zh-cn/advanced/best-practice-performance.md diff --git a/zh-cn/advanced/best-practice-security.md b/legacy/zh-cn/advanced/best-practice-security.md similarity index 100% rename from zh-cn/advanced/best-practice-security.md rename to legacy/zh-cn/advanced/best-practice-security.md diff --git a/zh-cn/advanced/developing-template-engines.md b/legacy/zh-cn/advanced/developing-template-engines.md similarity index 100% rename from zh-cn/advanced/developing-template-engines.md rename to legacy/zh-cn/advanced/developing-template-engines.md diff --git a/zh-cn/advanced/healthcheck-graceful-shutdown.md b/legacy/zh-cn/advanced/healthcheck-graceful-shutdown.md similarity index 100% rename from zh-cn/advanced/healthcheck-graceful-shutdown.md rename to legacy/zh-cn/advanced/healthcheck-graceful-shutdown.md diff --git a/zh-cn/advanced/security-updates.md b/legacy/zh-cn/advanced/security-updates.md similarity index 100% rename from zh-cn/advanced/security-updates.md rename to legacy/zh-cn/advanced/security-updates.md diff --git a/zh-cn/api.md b/legacy/zh-cn/api.md similarity index 100% rename from zh-cn/api.md rename to legacy/zh-cn/api.md diff --git a/zh-cn/changelog/index.md b/legacy/zh-cn/changelog/index.md similarity index 100% rename from zh-cn/changelog/index.md rename to legacy/zh-cn/changelog/index.md diff --git a/zh-cn/guide/behind-proxies.md b/legacy/zh-cn/guide/behind-proxies.md similarity index 100% rename from zh-cn/guide/behind-proxies.md rename to legacy/zh-cn/guide/behind-proxies.md diff --git a/zh-cn/guide/database-integration.md b/legacy/zh-cn/guide/database-integration.md similarity index 100% rename from zh-cn/guide/database-integration.md rename to legacy/zh-cn/guide/database-integration.md diff --git a/zh-cn/guide/debugging.md b/legacy/zh-cn/guide/debugging.md similarity index 100% rename from zh-cn/guide/debugging.md rename to legacy/zh-cn/guide/debugging.md diff --git a/zh-cn/guide/error-handling.md b/legacy/zh-cn/guide/error-handling.md similarity index 100% rename from zh-cn/guide/error-handling.md rename to legacy/zh-cn/guide/error-handling.md diff --git a/zh-cn/guide/migrating-4.md b/legacy/zh-cn/guide/migrating-4.md similarity index 100% rename from zh-cn/guide/migrating-4.md rename to legacy/zh-cn/guide/migrating-4.md diff --git a/zh-cn/guide/migrating-5.md b/legacy/zh-cn/guide/migrating-5.md similarity index 100% rename from zh-cn/guide/migrating-5.md rename to legacy/zh-cn/guide/migrating-5.md diff --git a/zh-cn/guide/overriding-express-api.md b/legacy/zh-cn/guide/overriding-express-api.md similarity index 100% rename from zh-cn/guide/overriding-express-api.md rename to legacy/zh-cn/guide/overriding-express-api.md diff --git a/zh-cn/guide/routing.md b/legacy/zh-cn/guide/routing.md similarity index 100% rename from zh-cn/guide/routing.md rename to legacy/zh-cn/guide/routing.md diff --git a/zh-cn/guide/using-middleware.md b/legacy/zh-cn/guide/using-middleware.md similarity index 100% rename from zh-cn/guide/using-middleware.md rename to legacy/zh-cn/guide/using-middleware.md diff --git a/zh-cn/guide/using-template-engines.md b/legacy/zh-cn/guide/using-template-engines.md similarity index 100% rename from zh-cn/guide/using-template-engines.md rename to legacy/zh-cn/guide/using-template-engines.md diff --git a/zh-cn/guide/writing-middleware.md b/legacy/zh-cn/guide/writing-middleware.md similarity index 100% rename from zh-cn/guide/writing-middleware.md rename to legacy/zh-cn/guide/writing-middleware.md diff --git a/zh-cn/index.md b/legacy/zh-cn/index.md similarity index 100% rename from zh-cn/index.md rename to legacy/zh-cn/index.md diff --git a/zh-cn/resources/community.md b/legacy/zh-cn/resources/community.md similarity index 100% rename from zh-cn/resources/community.md rename to legacy/zh-cn/resources/community.md diff --git a/zh-cn/resources/contributing.md b/legacy/zh-cn/resources/contributing.md similarity index 100% rename from zh-cn/resources/contributing.md rename to legacy/zh-cn/resources/contributing.md diff --git a/zh-cn/resources/glossary.md b/legacy/zh-cn/resources/glossary.md similarity index 100% rename from zh-cn/resources/glossary.md rename to legacy/zh-cn/resources/glossary.md diff --git a/zh-cn/resources/middleware.md b/legacy/zh-cn/resources/middleware.md similarity index 100% rename from zh-cn/resources/middleware.md rename to legacy/zh-cn/resources/middleware.md diff --git a/zh-cn/resources/middleware/body-parser.md b/legacy/zh-cn/resources/middleware/body-parser.md similarity index 100% rename from zh-cn/resources/middleware/body-parser.md rename to legacy/zh-cn/resources/middleware/body-parser.md diff --git a/zh-cn/resources/middleware/compression.md b/legacy/zh-cn/resources/middleware/compression.md similarity index 100% rename from zh-cn/resources/middleware/compression.md rename to legacy/zh-cn/resources/middleware/compression.md diff --git a/zh-cn/resources/middleware/connect-rid.md b/legacy/zh-cn/resources/middleware/connect-rid.md similarity index 100% rename from zh-cn/resources/middleware/connect-rid.md rename to legacy/zh-cn/resources/middleware/connect-rid.md diff --git a/zh-cn/resources/middleware/cookie-parser.md b/legacy/zh-cn/resources/middleware/cookie-parser.md similarity index 100% rename from zh-cn/resources/middleware/cookie-parser.md rename to legacy/zh-cn/resources/middleware/cookie-parser.md diff --git a/zh-cn/resources/middleware/cookie-session.md b/legacy/zh-cn/resources/middleware/cookie-session.md similarity index 100% rename from zh-cn/resources/middleware/cookie-session.md rename to legacy/zh-cn/resources/middleware/cookie-session.md diff --git a/zh-cn/resources/middleware/cors.md b/legacy/zh-cn/resources/middleware/cors.md similarity index 100% rename from zh-cn/resources/middleware/cors.md rename to legacy/zh-cn/resources/middleware/cors.md diff --git a/zh-cn/resources/middleware/errorhandler.md b/legacy/zh-cn/resources/middleware/errorhandler.md similarity index 100% rename from zh-cn/resources/middleware/errorhandler.md rename to legacy/zh-cn/resources/middleware/errorhandler.md diff --git a/zh-cn/resources/middleware/method-override.md b/legacy/zh-cn/resources/middleware/method-override.md similarity index 100% rename from zh-cn/resources/middleware/method-override.md rename to legacy/zh-cn/resources/middleware/method-override.md diff --git a/zh-cn/resources/middleware/morgan.md b/legacy/zh-cn/resources/middleware/morgan.md similarity index 100% rename from zh-cn/resources/middleware/morgan.md rename to legacy/zh-cn/resources/middleware/morgan.md diff --git a/zh-cn/resources/middleware/multer.md b/legacy/zh-cn/resources/middleware/multer.md similarity index 100% rename from zh-cn/resources/middleware/multer.md rename to legacy/zh-cn/resources/middleware/multer.md diff --git a/zh-cn/resources/middleware/response-time.md b/legacy/zh-cn/resources/middleware/response-time.md similarity index 100% rename from zh-cn/resources/middleware/response-time.md rename to legacy/zh-cn/resources/middleware/response-time.md diff --git a/zh-cn/resources/middleware/serve-favicon.md b/legacy/zh-cn/resources/middleware/serve-favicon.md similarity index 100% rename from zh-cn/resources/middleware/serve-favicon.md rename to legacy/zh-cn/resources/middleware/serve-favicon.md diff --git a/zh-cn/resources/middleware/serve-index.md b/legacy/zh-cn/resources/middleware/serve-index.md similarity index 100% rename from zh-cn/resources/middleware/serve-index.md rename to legacy/zh-cn/resources/middleware/serve-index.md diff --git a/zh-cn/resources/middleware/serve-static.md b/legacy/zh-cn/resources/middleware/serve-static.md similarity index 100% rename from zh-cn/resources/middleware/serve-static.md rename to legacy/zh-cn/resources/middleware/serve-static.md diff --git a/zh-cn/resources/middleware/session.md b/legacy/zh-cn/resources/middleware/session.md similarity index 100% rename from zh-cn/resources/middleware/session.md rename to legacy/zh-cn/resources/middleware/session.md diff --git a/zh-cn/resources/middleware/timeout.md b/legacy/zh-cn/resources/middleware/timeout.md similarity index 100% rename from zh-cn/resources/middleware/timeout.md rename to legacy/zh-cn/resources/middleware/timeout.md diff --git a/zh-cn/resources/middleware/vhost.md b/legacy/zh-cn/resources/middleware/vhost.md similarity index 100% rename from zh-cn/resources/middleware/vhost.md rename to legacy/zh-cn/resources/middleware/vhost.md diff --git a/zh-cn/resources/utils.md b/legacy/zh-cn/resources/utils.md similarity index 100% rename from zh-cn/resources/utils.md rename to legacy/zh-cn/resources/utils.md diff --git a/zh-cn/starter/basic-routing.md b/legacy/zh-cn/starter/basic-routing.md similarity index 100% rename from zh-cn/starter/basic-routing.md rename to legacy/zh-cn/starter/basic-routing.md diff --git a/zh-cn/starter/examples.md b/legacy/zh-cn/starter/examples.md similarity index 100% rename from zh-cn/starter/examples.md rename to legacy/zh-cn/starter/examples.md diff --git a/zh-cn/starter/faq.md b/legacy/zh-cn/starter/faq.md similarity index 100% rename from zh-cn/starter/faq.md rename to legacy/zh-cn/starter/faq.md diff --git a/zh-cn/starter/generator.md b/legacy/zh-cn/starter/generator.md similarity index 100% rename from zh-cn/starter/generator.md rename to legacy/zh-cn/starter/generator.md diff --git a/zh-cn/starter/hello-world.md b/legacy/zh-cn/starter/hello-world.md similarity index 100% rename from zh-cn/starter/hello-world.md rename to legacy/zh-cn/starter/hello-world.md diff --git a/zh-cn/starter/installing.md b/legacy/zh-cn/starter/installing.md similarity index 100% rename from zh-cn/starter/installing.md rename to legacy/zh-cn/starter/installing.md diff --git a/zh-cn/starter/static-files.md b/legacy/zh-cn/starter/static-files.md similarity index 100% rename from zh-cn/starter/static-files.md rename to legacy/zh-cn/starter/static-files.md diff --git a/zh-cn/support/index.md b/legacy/zh-cn/support/index.md similarity index 100% rename from zh-cn/support/index.md rename to legacy/zh-cn/support/index.md diff --git a/zh-tw/3x/api.md b/legacy/zh-tw/3x/api.md similarity index 100% rename from zh-tw/3x/api.md rename to legacy/zh-tw/3x/api.md diff --git a/zh-tw/4x/api.md b/legacy/zh-tw/4x/api.md similarity index 100% rename from zh-tw/4x/api.md rename to legacy/zh-tw/4x/api.md diff --git a/zh-tw/5x/api.md b/legacy/zh-tw/5x/api.md similarity index 100% rename from zh-tw/5x/api.md rename to legacy/zh-tw/5x/api.md diff --git a/zh-tw/advanced/best-practice-performance.md b/legacy/zh-tw/advanced/best-practice-performance.md similarity index 100% rename from zh-tw/advanced/best-practice-performance.md rename to legacy/zh-tw/advanced/best-practice-performance.md diff --git a/zh-tw/advanced/best-practice-security.md b/legacy/zh-tw/advanced/best-practice-security.md similarity index 100% rename from zh-tw/advanced/best-practice-security.md rename to legacy/zh-tw/advanced/best-practice-security.md diff --git a/zh-tw/advanced/developing-template-engines.md b/legacy/zh-tw/advanced/developing-template-engines.md similarity index 100% rename from zh-tw/advanced/developing-template-engines.md rename to legacy/zh-tw/advanced/developing-template-engines.md diff --git a/zh-tw/advanced/healthcheck-graceful-shutdown.md b/legacy/zh-tw/advanced/healthcheck-graceful-shutdown.md similarity index 100% rename from zh-tw/advanced/healthcheck-graceful-shutdown.md rename to legacy/zh-tw/advanced/healthcheck-graceful-shutdown.md diff --git a/zh-tw/advanced/security-updates.md b/legacy/zh-tw/advanced/security-updates.md similarity index 100% rename from zh-tw/advanced/security-updates.md rename to legacy/zh-tw/advanced/security-updates.md diff --git a/zh-tw/api.md b/legacy/zh-tw/api.md similarity index 100% rename from zh-tw/api.md rename to legacy/zh-tw/api.md diff --git a/zh-tw/changelog/index.md b/legacy/zh-tw/changelog/index.md similarity index 100% rename from zh-tw/changelog/index.md rename to legacy/zh-tw/changelog/index.md diff --git a/zh-tw/guide/behind-proxies.md b/legacy/zh-tw/guide/behind-proxies.md similarity index 100% rename from zh-tw/guide/behind-proxies.md rename to legacy/zh-tw/guide/behind-proxies.md diff --git a/zh-tw/guide/database-integration.md b/legacy/zh-tw/guide/database-integration.md similarity index 100% rename from zh-tw/guide/database-integration.md rename to legacy/zh-tw/guide/database-integration.md diff --git a/zh-tw/guide/debugging.md b/legacy/zh-tw/guide/debugging.md similarity index 100% rename from zh-tw/guide/debugging.md rename to legacy/zh-tw/guide/debugging.md diff --git a/zh-tw/guide/error-handling.md b/legacy/zh-tw/guide/error-handling.md similarity index 100% rename from zh-tw/guide/error-handling.md rename to legacy/zh-tw/guide/error-handling.md diff --git a/zh-tw/guide/migrating-4.md b/legacy/zh-tw/guide/migrating-4.md similarity index 100% rename from zh-tw/guide/migrating-4.md rename to legacy/zh-tw/guide/migrating-4.md diff --git a/zh-tw/guide/migrating-5.md b/legacy/zh-tw/guide/migrating-5.md similarity index 100% rename from zh-tw/guide/migrating-5.md rename to legacy/zh-tw/guide/migrating-5.md diff --git a/zh-tw/guide/overriding-express-api.md b/legacy/zh-tw/guide/overriding-express-api.md similarity index 100% rename from zh-tw/guide/overriding-express-api.md rename to legacy/zh-tw/guide/overriding-express-api.md diff --git a/zh-tw/guide/routing.md b/legacy/zh-tw/guide/routing.md similarity index 100% rename from zh-tw/guide/routing.md rename to legacy/zh-tw/guide/routing.md diff --git a/zh-tw/guide/using-middleware.md b/legacy/zh-tw/guide/using-middleware.md similarity index 100% rename from zh-tw/guide/using-middleware.md rename to legacy/zh-tw/guide/using-middleware.md diff --git a/zh-tw/guide/using-template-engines.md b/legacy/zh-tw/guide/using-template-engines.md similarity index 100% rename from zh-tw/guide/using-template-engines.md rename to legacy/zh-tw/guide/using-template-engines.md diff --git a/zh-tw/guide/writing-middleware.md b/legacy/zh-tw/guide/writing-middleware.md similarity index 100% rename from zh-tw/guide/writing-middleware.md rename to legacy/zh-tw/guide/writing-middleware.md diff --git a/zh-tw/index.md b/legacy/zh-tw/index.md similarity index 100% rename from zh-tw/index.md rename to legacy/zh-tw/index.md diff --git a/zh-tw/resources/community.md b/legacy/zh-tw/resources/community.md similarity index 100% rename from zh-tw/resources/community.md rename to legacy/zh-tw/resources/community.md diff --git a/zh-tw/resources/contributing.md b/legacy/zh-tw/resources/contributing.md similarity index 100% rename from zh-tw/resources/contributing.md rename to legacy/zh-tw/resources/contributing.md diff --git a/zh-tw/resources/glossary.md b/legacy/zh-tw/resources/glossary.md similarity index 100% rename from zh-tw/resources/glossary.md rename to legacy/zh-tw/resources/glossary.md diff --git a/zh-tw/resources/middleware.md b/legacy/zh-tw/resources/middleware.md similarity index 100% rename from zh-tw/resources/middleware.md rename to legacy/zh-tw/resources/middleware.md diff --git a/zh-tw/resources/middleware/body-parser.md b/legacy/zh-tw/resources/middleware/body-parser.md similarity index 100% rename from zh-tw/resources/middleware/body-parser.md rename to legacy/zh-tw/resources/middleware/body-parser.md diff --git a/zh-tw/resources/middleware/compression.md b/legacy/zh-tw/resources/middleware/compression.md similarity index 100% rename from zh-tw/resources/middleware/compression.md rename to legacy/zh-tw/resources/middleware/compression.md diff --git a/zh-tw/resources/middleware/connect-rid.md b/legacy/zh-tw/resources/middleware/connect-rid.md similarity index 100% rename from zh-tw/resources/middleware/connect-rid.md rename to legacy/zh-tw/resources/middleware/connect-rid.md diff --git a/zh-tw/resources/middleware/cookie-parser.md b/legacy/zh-tw/resources/middleware/cookie-parser.md similarity index 100% rename from zh-tw/resources/middleware/cookie-parser.md rename to legacy/zh-tw/resources/middleware/cookie-parser.md diff --git a/zh-tw/resources/middleware/cookie-session.md b/legacy/zh-tw/resources/middleware/cookie-session.md similarity index 100% rename from zh-tw/resources/middleware/cookie-session.md rename to legacy/zh-tw/resources/middleware/cookie-session.md diff --git a/zh-tw/resources/middleware/cors.md b/legacy/zh-tw/resources/middleware/cors.md similarity index 100% rename from zh-tw/resources/middleware/cors.md rename to legacy/zh-tw/resources/middleware/cors.md diff --git a/zh-tw/resources/middleware/errorhandler.md b/legacy/zh-tw/resources/middleware/errorhandler.md similarity index 100% rename from zh-tw/resources/middleware/errorhandler.md rename to legacy/zh-tw/resources/middleware/errorhandler.md diff --git a/zh-tw/resources/middleware/method-override.md b/legacy/zh-tw/resources/middleware/method-override.md similarity index 100% rename from zh-tw/resources/middleware/method-override.md rename to legacy/zh-tw/resources/middleware/method-override.md diff --git a/zh-tw/resources/middleware/morgan.md b/legacy/zh-tw/resources/middleware/morgan.md similarity index 100% rename from zh-tw/resources/middleware/morgan.md rename to legacy/zh-tw/resources/middleware/morgan.md diff --git a/zh-tw/resources/middleware/multer.md b/legacy/zh-tw/resources/middleware/multer.md similarity index 100% rename from zh-tw/resources/middleware/multer.md rename to legacy/zh-tw/resources/middleware/multer.md diff --git a/zh-tw/resources/middleware/response-time.md b/legacy/zh-tw/resources/middleware/response-time.md similarity index 100% rename from zh-tw/resources/middleware/response-time.md rename to legacy/zh-tw/resources/middleware/response-time.md diff --git a/zh-tw/resources/middleware/serve-favicon.md b/legacy/zh-tw/resources/middleware/serve-favicon.md similarity index 100% rename from zh-tw/resources/middleware/serve-favicon.md rename to legacy/zh-tw/resources/middleware/serve-favicon.md diff --git a/zh-tw/resources/middleware/serve-index.md b/legacy/zh-tw/resources/middleware/serve-index.md similarity index 100% rename from zh-tw/resources/middleware/serve-index.md rename to legacy/zh-tw/resources/middleware/serve-index.md diff --git a/zh-tw/resources/middleware/serve-static.md b/legacy/zh-tw/resources/middleware/serve-static.md similarity index 100% rename from zh-tw/resources/middleware/serve-static.md rename to legacy/zh-tw/resources/middleware/serve-static.md diff --git a/zh-tw/resources/middleware/session.md b/legacy/zh-tw/resources/middleware/session.md similarity index 100% rename from zh-tw/resources/middleware/session.md rename to legacy/zh-tw/resources/middleware/session.md diff --git a/zh-tw/resources/middleware/timeout.md b/legacy/zh-tw/resources/middleware/timeout.md similarity index 100% rename from zh-tw/resources/middleware/timeout.md rename to legacy/zh-tw/resources/middleware/timeout.md diff --git a/zh-tw/resources/middleware/vhost.md b/legacy/zh-tw/resources/middleware/vhost.md similarity index 100% rename from zh-tw/resources/middleware/vhost.md rename to legacy/zh-tw/resources/middleware/vhost.md diff --git a/zh-tw/resources/utils.md b/legacy/zh-tw/resources/utils.md similarity index 100% rename from zh-tw/resources/utils.md rename to legacy/zh-tw/resources/utils.md diff --git a/zh-tw/starter/basic-routing.md b/legacy/zh-tw/starter/basic-routing.md similarity index 100% rename from zh-tw/starter/basic-routing.md rename to legacy/zh-tw/starter/basic-routing.md diff --git a/zh-tw/starter/examples.md b/legacy/zh-tw/starter/examples.md similarity index 100% rename from zh-tw/starter/examples.md rename to legacy/zh-tw/starter/examples.md diff --git a/zh-tw/starter/faq.md b/legacy/zh-tw/starter/faq.md similarity index 100% rename from zh-tw/starter/faq.md rename to legacy/zh-tw/starter/faq.md diff --git a/zh-tw/starter/generator.md b/legacy/zh-tw/starter/generator.md similarity index 100% rename from zh-tw/starter/generator.md rename to legacy/zh-tw/starter/generator.md diff --git a/zh-tw/starter/hello-world.md b/legacy/zh-tw/starter/hello-world.md similarity index 100% rename from zh-tw/starter/hello-world.md rename to legacy/zh-tw/starter/hello-world.md diff --git a/zh-tw/starter/installing.md b/legacy/zh-tw/starter/installing.md similarity index 100% rename from zh-tw/starter/installing.md rename to legacy/zh-tw/starter/installing.md diff --git a/zh-tw/starter/static-files.md b/legacy/zh-tw/starter/static-files.md similarity index 100% rename from zh-tw/starter/static-files.md rename to legacy/zh-tw/starter/static-files.md diff --git a/zh-tw/support/index.md b/legacy/zh-tw/support/index.md similarity index 100% rename from zh-tw/support/index.md rename to legacy/zh-tw/support/index.md diff --git a/netlify.toml b/netlify.toml new file mode 100644 index 0000000000..b177eceedb --- /dev/null +++ b/netlify.toml @@ -0,0 +1,4 @@ +[build] + base = astro + command = "npm run build" + publish = "astro/dist" From 31e70948df310a0a1c6bb6e79681d7b24f3b53e5 Mon Sep 17 00:00:00 2001 From: Sebastian Beltran Date: Thu, 29 Jan 2026 10:33:26 -0500 Subject: [PATCH 02/17] ci: add workflow for Astro site build and linting (#2168) --- .github/workflows/build.yml | 77 +++++++++++++++++++ .../components/primitives/Button/Button.astro | 2 +- .../primitives/Typography/Typography.astro | 8 +- 3 files changed, 79 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000000..3d80fcb424 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,77 @@ +name: ci + +on: + pull_request: + branches: + - redesign + pull_request_review: + types: [submitted] + push: + branches: + - redesign + +# Cancel in progress workflows +# in the scenario where we already had a run going for that PR/branch/tag but then triggered a new run +concurrency: + group: "${{ github.workflow }} ✨ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}" + cancel-in-progress: true + +permissions: + contents: read + +jobs: + lint: + runs-on: ubuntu-latest + if: | + github.event.pull_request.draft != true && + (github.event_name == 'pull_request_review' && github.event.review.state == 'approved') || + github.event_name != 'pull_request_review' + + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + + - name: Set up Node.js + uses: actions/setup-node@v6 + with: + # node-version-file: ".nvmrc" use when .nvmrc is on root of the repo + node-version: "24.13" + # cache: "npm" use when package-lock.json is on root of the repo + + - name: Install Node.js dependencies + working-directory: astro + run: npm ci + + - name: Run tests + working-directory: astro + shell: bash + run: npm run check + + build: + name: build + runs-on: ubuntu-latest + if: | + github.event.pull_request.draft != true && + (github.event_name == 'pull_request_review' && github.event.review.state == 'approved') || + github.event_name != 'pull_request_review' + + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + + - name: Set up Node.js + uses: actions/setup-node@v6 + with: + # node-version-file: ".nvmrc" use when .nvmrc is on root of the repo + node-version: "24.13" + # cache: "npm" use when package-lock.json is on root of the repo + + - name: Install Node.js dependencies + working-directory: astro + run: npm ci + + - name: Build Astro site + working-directory: astro + run: npm run build diff --git a/astro/src/components/primitives/Button/Button.astro b/astro/src/components/primitives/Button/Button.astro index 8e1e2481d7..700d07edc6 100644 --- a/astro/src/components/primitives/Button/Button.astro +++ b/astro/src/components/primitives/Button/Button.astro @@ -15,7 +15,7 @@ */ import type { HTMLAttributes } from 'astro/types'; -import type { ButtonSize, ButtonVariant, ButtonHTMLTag, ButtonBaseProps } from './types'; +import type { ButtonBaseProps } from './types'; import './Button.css'; type Props = diff --git a/astro/src/components/primitives/Typography/Typography.astro b/astro/src/components/primitives/Typography/Typography.astro index 2e1713aa06..5e2f129798 100644 --- a/astro/src/components/primitives/Typography/Typography.astro +++ b/astro/src/components/primitives/Typography/Typography.astro @@ -15,13 +15,7 @@ */ import type { HTMLAttributes } from 'astro/types'; -import type { - TypographyVariant, - TypographyHTMLTag, - TypographyColor, - TypographyWeight, - TypographyBaseProps, -} from './types'; +import type { TypographyBaseProps } from './types'; import './Typography.css'; type Props = TypographyBaseProps & HTMLAttributes<'p'>; From 474d485d298131b1e2b5cbc372a52e03369467d6 Mon Sep 17 00:00:00 2001 From: Jon Church Date: Thu, 29 Jan 2026 13:33:20 -0500 Subject: [PATCH 03/17] fix: point netlify to astro dir (#2170) --- netlify.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/netlify.toml b/netlify.toml index b177eceedb..ae93185a99 100644 --- a/netlify.toml +++ b/netlify.toml @@ -1,4 +1,4 @@ [build] - base = astro + base = "astro" command = "npm run build" - publish = "astro/dist" + publish = "dist" From e8dbc453a1701ad8f302069870b67dc0b4935dc2 Mon Sep 17 00:00:00 2001 From: Francesca Giannino Date: Wed, 18 Feb 2026 14:36:17 +0100 Subject: [PATCH 04/17] feat: mobile header and sidebar navigation (#2180) Co-authored-by: shubham oulkar <91728992+ShubhamOulkar@users.noreply.github.com> Co-authored-by: Sebastian Beltran Co-authored-by: Shubham Oulkar --- astro/CONTRIBUTING.md | 316 +++- astro/package-lock.json | 41 +- astro/package.json | 9 +- astro/postcss.config.mjs | 2 + astro/public/logo-dark.svg | 1 + astro/public/logo-white.svg | 1 + .../patterns/Breadcrumbs/Breadcrumbs.astro | 6 +- .../components/patterns/Header/Header.astro | 75 + .../src/components/patterns/Header/Header.css | 132 ++ .../components/patterns/Sidebar/Sidebar.astro | 65 + .../components/patterns/Sidebar/Sidebar.css | 290 ++++ .../patterns/Sidebar/SidebarController.ts | 253 +++ .../patterns/Sidebar/SidebarFocusTrap.ts | 70 + .../patterns/Sidebar/SidebarItemsList.astro | 65 + .../patterns/Sidebar/SidebarMenu.astro | 219 +++ .../patterns/Sidebar/SidebarNavItem.astro | 87 + .../patterns/Sidebar/SidebarVersionManager.ts | 145 ++ .../src/components/patterns/Sidebar/utils.ts | 258 +++ .../ThemeSwitcher/ThemeSwitcher.astro | 80 +- .../patterns/ThemeSwitcher/ThemeSwitcher.css | 45 + .../VersionSwitcher/VersionSwitcher.astro | 71 + .../VersionSwitcher/VersionSwitcher.css | 12 + .../patterns/VersionSwitcher/index.ts | 6 + .../patterns/VersionSwitcher/types.ts | 19 + astro/src/components/patterns/index.ts | 3 + .../components/primitives/Button/Button.astro | 26 +- .../components/primitives/Button/Button.css | 128 +- .../src/components/primitives/Button/index.ts | 8 +- .../src/components/primitives/Button/types.ts | 19 +- .../primitives/Container/Container.astro | 2 +- .../primitives/Container/Container.css | 14 +- .../src/components/primitives/Grid/Col.astro | 2 +- .../src/components/primitives/Grid/Flex.astro | 2 +- .../components/primitives/Grid/FlexItem.astro | 2 +- .../src/components/primitives/Grid/Grid.astro | 2 +- astro/src/components/primitives/Grid/Grid.css | 896 +++++----- .../components/primitives/Select/Select.astro | 77 + .../components/primitives/Select/Select.css | 101 ++ .../src/components/primitives/Select/index.ts | 6 + .../src/components/primitives/Select/types.ts | 32 + .../primitives/Typography/Body.astro | 4 +- .../primitives/Typography/BodyMd.astro | 4 +- .../primitives/Typography/BodySm.astro | 4 +- .../primitives/Typography/BodyXs.astro | 4 +- .../primitives/Typography/Code.astro | 4 +- .../components/primitives/Typography/H1.astro | 2 +- .../components/primitives/Typography/H2.astro | 2 +- .../components/primitives/Typography/H3.astro | 2 +- .../components/primitives/Typography/H4.astro | 2 +- .../components/primitives/Typography/H5.astro | 18 +- .../primitives/Typography/Typography.astro | 5 +- .../primitives/Typography/Typography.css | 104 +- .../components/primitives/Typography/types.ts | 2 + astro/src/components/primitives/index.ts | 8 +- astro/src/config/menu.ts | 8 - astro/src/config/menu/api.ts | 293 ++++ astro/src/config/menu/docs.ts | 40 + astro/src/config/menu/main.ts | 42 + astro/src/config/menu/middleware.ts | 26 + astro/src/config/menu/resources.ts | 19 + astro/src/config/types.ts | 33 + astro/src/content.config.ts | 11 +- astro/src/content/docs/en/3x/api.md | 25 + .../docs/en/3x/api/application/app-VERB.md | 62 + .../docs/en/3x/api/application/app-all.md | 37 + .../en/3x/api/application/app-configure.md | 45 + .../docs/en/3x/api/application/app-disable.md | 14 + .../en/3x/api/application/app-disabled.md | 17 + .../docs/en/3x/api/application/app-enable.md | 14 + .../docs/en/3x/api/application/app-enabled.md | 17 + .../docs/en/3x/api/application/app-engine.md | 44 + .../docs/en/3x/api/application/app-get.md | 17 + .../docs/en/3x/api/application/app-listen.md | 41 + .../docs/en/3x/api/application/app-locals.md | 52 + .../docs/en/3x/api/application/app-param.md | 75 + .../docs/en/3x/api/application/app-render.md | 20 + .../docs/en/3x/api/application/app-routes.md | 34 + .../docs/en/3x/api/application/app-set.md | 14 + .../en/3x/api/application/app-settings.md | 19 + .../docs/en/3x/api/application/app-use.md | 94 + .../docs/en/3x/api/application/overview.md | 20 + astro/src/content/docs/en/3x/api/express.md | 19 + .../docs/en/3x/api/middleware/middleware.md | 34 + .../docs/en/3x/api/middleware/mw-basicAuth.md | 36 + .../en/3x/api/middleware/mw-bodyParser.md | 32 + .../docs/en/3x/api/middleware/mw-compress.md | 17 + .../en/3x/api/middleware/mw-cookieParser.md | 15 + .../en/3x/api/middleware/mw-cookieSession.md | 24 + .../docs/en/3x/api/middleware/mw-csrf.md | 20 + .../docs/en/3x/api/middleware/mw-directory.md | 21 + .../docs/en/3x/api/request/overview.md | 121 ++ .../docs/en/3x/api/request/req-accepted.md | 19 + .../en/3x/api/request/req-acceptedCharsets.md | 13 + .../3x/api/request/req-acceptedLanguages.md | 13 + .../docs/en/3x/api/request/req-accepts.md | 41 + .../en/3x/api/request/req-acceptsCharset.md | 8 + .../en/3x/api/request/req-acceptsLanguage.md | 8 + .../docs/en/3x/api/request/req-body.md | 24 + .../docs/en/3x/api/request/req-cookies.md | 16 + .../docs/en/3x/api/request/req-files.md | 50 + .../docs/en/3x/api/request/req-fresh.md | 14 + .../docs/en/3x/api/request/req-header.md | 21 + .../docs/en/3x/api/request/req-host.md | 14 + .../content/docs/en/3x/api/request/req-ip.md | 14 + .../content/docs/en/3x/api/request/req-ips.md | 15 + .../content/docs/en/3x/api/request/req-is.md | 26 + .../docs/en/3x/api/request/req-originalUrl.md | 18 + .../docs/en/3x/api/request/req-param.md | 32 + .../docs/en/3x/api/request/req-params.md | 27 + .../docs/en/3x/api/request/req-path.md | 14 + .../docs/en/3x/api/request/req-protocol.md | 18 + .../docs/en/3x/api/request/req-query.md | 25 + .../content/docs/en/3x/api/request/req-res.md | 9 + .../docs/en/3x/api/request/req-route.md | 27 + .../docs/en/3x/api/request/req-secure.md | 13 + .../en/3x/api/request/req-signedCookies.md | 20 + .../docs/en/3x/api/request/req-stale.md | 14 + .../docs/en/3x/api/request/req-subdomains.md | 14 + .../content/docs/en/3x/api/request/req-xhr.md | 14 + .../docs/en/3x/api/response/res-attachment.md | 20 + .../docs/en/3x/api/response/res-charset.md | 14 + .../en/3x/api/response/res-clearCookie.md | 13 + .../docs/en/3x/api/response/res-cookie.md | 42 + .../docs/en/3x/api/response/res-download.md | 31 + .../docs/en/3x/api/response/res-format.md | 57 + .../docs/en/3x/api/response/res-get.md | 13 + .../docs/en/3x/api/response/res-json.md | 18 + .../docs/en/3x/api/response/res-jsonp.md | 38 + .../docs/en/3x/api/response/res-links.md | 22 + .../docs/en/3x/api/response/res-locals.md | 21 + .../docs/en/3x/api/response/res-location.md | 26 + .../docs/en/3x/api/response/res-redirect.md | 56 + .../docs/en/3x/api/response/res-render.md | 21 + .../docs/en/3x/api/response/res-req.md | 9 + .../docs/en/3x/api/response/res-send.md | 58 + .../docs/en/3x/api/response/res-sendfile.md | 35 + .../docs/en/3x/api/response/res-set.md | 20 + .../docs/en/3x/api/response/res-status.md | 12 + .../docs/en/3x/api/response/res-type.md | 20 + .../docs/en/3x/api/response/response.md | 89 + .../advanced/best-practice-performance.md | 2 - .../advanced/best-practice-security.md | 2 - .../advanced/developing-template-engines.md | 2 - .../advanced/healthcheck-graceful-shutdown.md | 2 - .../en/{ => 4x}/advanced/security-updates.md | 2 - astro/src/content/docs/en/4x/api.md | 8 + .../docs/en/4x/api/application/app-METHOD.md | 65 + .../docs/en/4x/api/application/app-all.md | 49 + .../4x/api/application/app-delete-method.md | 19 + .../docs/en/4x/api/application/app-disable.md | 17 + .../en/4x/api/application/app-disabled.md | 18 + .../docs/en/4x/api/application/app-enable.md | 15 + .../docs/en/4x/api/application/app-enabled.md | 18 + .../docs/en/4x/api/application/app-engine.md | 41 + .../en/4x/api/application/app-get-method.md | 20 + .../docs/en/4x/api/application/app-get.md | 18 + .../docs/en/4x/api/application/app-listen.md | 58 + .../docs/en/4x/api/application/app-locals.md | 39 + .../en/4x/api/application/app-mountpath.md | 50 + .../docs/en/4x/api/application/app-onmount.md | 35 + .../docs/en/4x/api/application/app-param.md | 165 ++ .../docs/en/4x/api/application/app-path.md | 24 + .../en/4x/api/application/app-post-method.md | 19 + .../en/4x/api/application/app-put-method.md | 18 + .../docs/en/4x/api/application/app-render.md | 44 + .../docs/en/4x/api/application/app-route.md | 26 + .../docs/en/4x/api/application/app-set.md | 25 + .../en/4x/api/application/app-settings.md | 341 ++++ .../docs/en/4x/api/application/app-use.md | 333 ++++ .../docs/en/4x/api/application/overview.md | 128 ++ .../docs/en/4x/api/express/express.json.md | 47 + .../content/docs/en/4x/api/express/express.md | 39 + .../docs/en/4x/api/express/express.raw.md | 45 + .../docs/en/4x/api/express/express.router.md | 29 + .../docs/en/4x/api/express/express.static.md | 102 ++ .../docs/en/4x/api/express/express.text.md | 46 + .../en/4x/api/express/express.urlencoded.md | 53 + .../docs/en/4x/api/request/overview.md | 160 ++ .../docs/en/4x/api/request/req-accepts.md | 41 + .../en/4x/api/request/req-acceptsCharsets.md | 12 + .../en/4x/api/request/req-acceptsEncodings.md | 12 + .../en/4x/api/request/req-acceptsLanguages.md | 20 + .../content/docs/en/4x/api/request/req-app.md | 25 + .../docs/en/4x/api/request/req-base-url.md | 35 + .../docs/en/4x/api/request/req-body.md | 30 + .../docs/en/4x/api/request/req-cookies.md | 19 + .../docs/en/4x/api/request/req-fresh.md | 18 + .../content/docs/en/4x/api/request/req-get.md | 22 + .../docs/en/4x/api/request/req-hostname.md | 28 + .../content/docs/en/4x/api/request/req-ip.md | 17 + .../content/docs/en/4x/api/request/req-ips.md | 14 + .../content/docs/en/4x/api/request/req-is.md | 47 + .../docs/en/4x/api/request/req-method.md | 9 + .../docs/en/4x/api/request/req-originalUrl.md | 33 + .../docs/en/4x/api/request/req-param.md | 41 + .../docs/en/4x/api/request/req-params.md | 30 + .../docs/en/4x/api/request/req-path.md | 18 + .../docs/en/4x/api/request/req-protocol.md | 17 + .../docs/en/4x/api/request/req-query.md | 26 + .../docs/en/4x/api/request/req-range.md | 38 + .../content/docs/en/4x/api/request/req-res.md | 9 + .../docs/en/4x/api/request/req-route.md | 30 + .../docs/en/4x/api/request/req-secure.md | 13 + .../en/4x/api/request/req-signedCookies.md | 22 + .../docs/en/4x/api/request/req-stale.md | 14 + .../docs/en/4x/api/request/req-subdomains.md | 18 + .../content/docs/en/4x/api/request/req-xhr.md | 14 + .../docs/en/4x/api/response/overview.md | 135 ++ .../docs/en/4x/api/response/res-app.md | 10 + .../docs/en/4x/api/response/res-append.md | 18 + .../docs/en/4x/api/response/res-attachment.md | 19 + .../en/4x/api/response/res-clearCookie.md | 27 + .../docs/en/4x/api/response/res-cookie.md | 95 + .../docs/en/4x/api/response/res-download.md | 62 + .../docs/en/4x/api/response/res-end.md | 15 + .../docs/en/4x/api/response/res-format.md | 57 + .../docs/en/4x/api/response/res-get.md | 14 + .../en/4x/api/response/res-headersSent.md | 16 + .../docs/en/4x/api/response/res-json.md | 18 + .../docs/en/4x/api/response/res-jsonp.md | 37 + .../docs/en/4x/api/response/res-links.md | 25 + .../docs/en/4x/api/response/res-locals.md | 33 + .../docs/en/4x/api/response/res-location.md | 30 + .../docs/en/4x/api/response/res-redirect.md | 65 + .../docs/en/4x/api/response/res-render.md | 50 + .../docs/en/4x/api/response/res-req.md | 9 + .../docs/en/4x/api/response/res-send.md | 44 + .../docs/en/4x/api/response/res-sendFile.md | 91 + .../docs/en/4x/api/response/res-sendStatus.md | 20 + .../docs/en/4x/api/response/res-set.md | 21 + .../docs/en/4x/api/response/res-status.md | 15 + .../docs/en/4x/api/response/res-type.md | 23 + .../docs/en/4x/api/response/res-vary.md | 12 + .../content/docs/en/4x/api/router/overview.md | 66 + .../docs/en/4x/api/router/router-METHOD.md | 47 + .../docs/en/4x/api/router/router-Router.md | 5 + .../docs/en/4x/api/router/router-all.md | 36 + .../docs/en/4x/api/router/router-param.md | 128 ++ .../docs/en/4x/api/router/router-route.md | 54 + .../docs/en/4x/api/router/router-use.md | 112 ++ .../docs/en/4x/api/router/routing-args.html | 58 + .../docs/en/{ => 4x}/guide/behind-proxies.md | 2 - .../en/{ => 4x}/guide/database-integration.md | 2 - .../docs/en/{ => 4x}/guide/debugging.md | 2 - .../docs/en/{ => 4x}/guide/error-handling.md | 2 - .../docs/en/{ => 4x}/guide/migrating-4.md | 2 - .../docs/en/{ => 4x}/guide/migrating-5.md | 16 +- .../{ => 4x}/guide/overriding-express-api.md | 2 - .../content/docs/en/{ => 4x}/guide/routing.md | 2 - .../en/{ => 4x}/guide/using-middleware.md | 2 - .../{ => 4x}/guide/using-template-engines.md | 2 - .../en/{ => 4x}/guide/writing-middleware.md | 2 - .../docs/en/{ => 4x}/starter/basic-routing.md | 2 - .../docs/en/{ => 4x}/starter/examples.md | 2 - .../content/docs/en/{ => 4x}/starter/faq.md | 2 - .../docs/en/{ => 4x}/starter/generator.md | 2 - .../docs/en/{ => 4x}/starter/hello-world.md | 2 - .../docs/en/{ => 4x}/starter/installing.md | 2 - .../docs/en/{ => 4x}/starter/static-files.md | 2 - .../5x/advanced/best-practice-performance.md | 307 ++++ .../en/5x/advanced/best-practice-security.md | 283 +++ .../advanced/developing-template-engines.md | 45 + .../advanced/healthcheck-graceful-shutdown.md | 30 + .../docs/en/5x/advanced/security-updates.md | 83 + astro/src/content/docs/en/5x/api.md | 8 + .../docs/en/5x/api/application/app-METHOD.md | 65 + .../docs/en/5x/api/application/app-all.md | 49 + .../5x/api/application/app-delete-method.md | 19 + .../docs/en/5x/api/application/app-disable.md | 17 + .../en/5x/api/application/app-disabled.md | 18 + .../docs/en/5x/api/application/app-enable.md | 15 + .../docs/en/5x/api/application/app-enabled.md | 18 + .../docs/en/5x/api/application/app-engine.md | 41 + .../en/5x/api/application/app-get-method.md | 20 + .../docs/en/5x/api/application/app-get.md | 18 + .../docs/en/5x/api/application/app-listen.md | 56 + .../docs/en/5x/api/application/app-locals.md | 39 + .../en/5x/api/application/app-mountpath.md | 50 + .../docs/en/5x/api/application/app-onmount.md | 35 + .../docs/en/5x/api/application/app-param.md | 83 + .../docs/en/5x/api/application/app-path.md | 24 + .../en/5x/api/application/app-post-method.md | 19 + .../en/5x/api/application/app-put-method.md | 18 + .../docs/en/5x/api/application/app-render.md | 44 + .../docs/en/5x/api/application/app-route.md | 26 + .../docs/en/5x/api/application/app-router.md | 24 + .../docs/en/5x/api/application/app-set.md | 25 + .../en/5x/api/application/app-settings.md | 335 ++++ .../docs/en/5x/api/application/app-use.md | 310 ++++ .../docs/en/5x/api/application/overview.md | 132 ++ .../docs/en/5x/api/express/express.json.md | 43 + .../content/docs/en/5x/api/express/express.md | 39 + .../docs/en/5x/api/express/express.raw.md | 41 + .../docs/en/5x/api/express/express.router.md | 29 + .../docs/en/5x/api/express/express.static.md | 99 ++ .../docs/en/5x/api/express/express.text.md | 42 + .../en/5x/api/express/express.urlencoded.md | 45 + .../docs/en/5x/api/request/overview.md | 160 ++ .../docs/en/5x/api/request/req-accepts.md | 41 + .../en/5x/api/request/req-acceptsCharsets.md | 12 + .../en/5x/api/request/req-acceptsEncodings.md | 12 + .../en/5x/api/request/req-acceptsLanguages.md | 20 + .../content/docs/en/5x/api/request/req-app.md | 25 + .../docs/en/5x/api/request/req-base-url.md | 35 + .../docs/en/5x/api/request/req-body.md | 30 + .../docs/en/5x/api/request/req-cookies.md | 19 + .../docs/en/5x/api/request/req-fresh.md | 18 + .../content/docs/en/5x/api/request/req-get.md | 22 + .../docs/en/5x/api/request/req-host.md | 27 + .../docs/en/5x/api/request/req-hostname.md | 28 + .../content/docs/en/5x/api/request/req-ip.md | 17 + .../content/docs/en/5x/api/request/req-ips.md | 14 + .../content/docs/en/5x/api/request/req-is.md | 36 + .../docs/en/5x/api/request/req-method.md | 9 + .../docs/en/5x/api/request/req-originalUrl.md | 33 + .../docs/en/5x/api/request/req-params.md | 44 + .../docs/en/5x/api/request/req-path.md | 18 + .../docs/en/5x/api/request/req-protocol.md | 17 + .../docs/en/5x/api/request/req-query.md | 26 + .../docs/en/5x/api/request/req-range.md | 38 + .../content/docs/en/5x/api/request/req-res.md | 9 + .../docs/en/5x/api/request/req-route.md | 36 + .../docs/en/5x/api/request/req-secure.md | 14 + .../en/5x/api/request/req-signedCookies.md | 22 + .../docs/en/5x/api/request/req-stale.md | 14 + .../docs/en/5x/api/request/req-subdomains.md | 18 + .../content/docs/en/5x/api/request/req-xhr.md | 14 + .../docs/en/5x/api/response/res-app.md | 10 + .../docs/en/5x/api/response/res-append.md | 21 + .../docs/en/5x/api/response/res-attachment.md | 19 + .../en/5x/api/response/res-clearCookie.md | 24 + .../docs/en/5x/api/response/res-cookie.md | 95 + .../docs/en/5x/api/response/res-download.md | 66 + .../docs/en/5x/api/response/res-end.md | 15 + .../docs/en/5x/api/response/res-format.md | 57 + .../docs/en/5x/api/response/res-get.md | 14 + .../en/5x/api/response/res-headersSent.md | 16 + .../docs/en/5x/api/response/res-json.md | 18 + .../docs/en/5x/api/response/res-jsonp.md | 37 + .../docs/en/5x/api/response/res-links.md | 25 + .../docs/en/5x/api/response/res-locals.md | 33 + .../docs/en/5x/api/response/res-location.md | 22 + .../docs/en/5x/api/response/res-redirect.md | 56 + .../docs/en/5x/api/response/res-render.md | 42 + .../docs/en/5x/api/response/res-req.md | 9 + .../docs/en/5x/api/response/res-send.md | 44 + .../docs/en/5x/api/response/res-sendFile.md | 91 + .../docs/en/5x/api/response/res-sendStatus.md | 20 + .../docs/en/5x/api/response/res-set.md | 21 + .../docs/en/5x/api/response/res-status.md | 15 + .../docs/en/5x/api/response/res-type.md | 18 + .../docs/en/5x/api/response/res-vary.md | 12 + .../docs/en/5x/api/response/response.md | 135 ++ .../docs/en/5x/api/router/router-METHOD.md | 71 + .../docs/en/5x/api/router/router-Router.md | 5 + .../docs/en/5x/api/router/router-all.md | 36 + .../docs/en/5x/api/router/router-param.md | 67 + .../docs/en/5x/api/router/router-route.md | 54 + .../docs/en/5x/api/router/router-use.md | 111 ++ .../content/docs/en/5x/api/router/router.md | 66 + .../docs/en/5x/guide/behind-proxies.md | 92 + .../docs/en/5x/guide/database-integration.md | 501 ++++++ .../src/content/docs/en/5x/guide/debugging.md | 127 ++ .../docs/en/5x/guide/error-handling.md | 306 ++++ .../content/docs/en/5x/guide/migrating-4.md | 613 +++++++ .../content/docs/en/5x/guide/migrating-5.md | 614 +++++++ .../en/5x/guide/overriding-express-api.md | 70 + astro/src/content/docs/en/5x/guide/routing.md | 417 +++++ .../docs/en/5x/guide/using-middleware.md | 295 ++++ .../en/5x/guide/using-template-engines.md | 63 + .../docs/en/5x/guide/writing-middleware.md | 218 +++ .../docs/en/5x/starter/basic-routing.md | 63 + .../content/docs/en/5x/starter/examples.md | 16 + astro/src/content/docs/en/5x/starter/faq.md | 92 + .../content/docs/en/5x/starter/generator.md | 122 ++ .../content/docs/en/5x/starter/hello-world.md | 46 + .../content/docs/en/5x/starter/installing.md | 48 + .../docs/en/5x/starter/static-files.md | 76 + .../resources => resources/en}/community.md | 19 +- .../en}/contributing.md | 2 - .../en/resources => resources/en}/glossary.md | 2 - .../en}/middleware/body-parser.md | 1 - .../en}/middleware/compression.md | 1 - .../en}/middleware/connect-rid.md | 1 - .../en}/middleware/cookie-parser.md | 1 - .../en}/middleware/cookie-session.md | 1 - .../en}/middleware/cors.md | 1 - .../en}/middleware/errorhandler.md | 1 - .../en}/middleware/method-override.md | 1 - .../en}/middleware/morgan.md | 1 - .../en}/middleware/multer.md | 1 - .../en/middleware/overview.md} | 2 - .../en}/middleware/response-time.md | 1 - .../en}/middleware/serve-favicon.md | 1 - .../en}/middleware/serve-index.md | 1 - .../en}/middleware/serve-static.md | 1 - .../en}/middleware/session.md | 1 - .../en}/middleware/timeout.md | 1 - .../en}/middleware/vhost.md | 1 - .../en/resources => resources/en}/utils.md | 2 - astro/src/layouts/DocLayout.astro | 4 +- astro/src/layouts/Layout.astro | 11 +- astro/src/pages/[lang]/[...slug].astro | 60 +- astro/src/pages/[lang]/blog/index.astro | 21 + astro/src/pages/[lang]/docs/index.astro | 54 - astro/src/pages/[lang]/ds-foundations.astro | 1534 +++++++++-------- .../pages/[lang]/resources/[...slug].astro | 31 + astro/src/pages/[lang]/support/index.astro | 21 + astro/src/styles/base/_global.css | 10 + astro/src/styles/main.css | 23 +- astro/src/styles/tokens/_colors.css | 8 +- astro/src/styles/tokens/_sizing.css | 45 + astro/src/styles/tokens/_spacing.css | 1 + astro/src/styles/tokens/_zindex.css | 11 + astro/src/styles/tokens/index.css | 2 + astro/src/styles/utilities/_utilities.css | 7 +- astro/src/utils/content.ts | 193 ++- legacy/de/guide/migrating-5.md | 239 +-- legacy/en/guide/migrating-5.md | 256 +-- legacy/es/guide/migrating-5.md | 233 +-- legacy/fr/guide/migrating-5.md | 233 +-- legacy/it/guide/migrating-5.md | 233 +-- legacy/ja/guide/migrating-5.md | 233 +-- legacy/ko/guide/migrating-5.md | 233 +-- legacy/pt-br/guide/migrating-5.md | 239 +-- legacy/zh-cn/guide/migrating-5.md | 233 +-- legacy/zh-tw/guide/migrating-5.md | 233 +-- 427 files changed, 20852 insertions(+), 2853 deletions(-) create mode 100644 astro/public/logo-dark.svg create mode 100644 astro/public/logo-white.svg create mode 100644 astro/src/components/patterns/Header/Header.astro create mode 100644 astro/src/components/patterns/Header/Header.css create mode 100644 astro/src/components/patterns/Sidebar/Sidebar.astro create mode 100644 astro/src/components/patterns/Sidebar/Sidebar.css create mode 100644 astro/src/components/patterns/Sidebar/SidebarController.ts create mode 100644 astro/src/components/patterns/Sidebar/SidebarFocusTrap.ts create mode 100644 astro/src/components/patterns/Sidebar/SidebarItemsList.astro create mode 100644 astro/src/components/patterns/Sidebar/SidebarMenu.astro create mode 100644 astro/src/components/patterns/Sidebar/SidebarNavItem.astro create mode 100644 astro/src/components/patterns/Sidebar/SidebarVersionManager.ts create mode 100644 astro/src/components/patterns/Sidebar/utils.ts create mode 100644 astro/src/components/patterns/ThemeSwitcher/ThemeSwitcher.css create mode 100644 astro/src/components/patterns/VersionSwitcher/VersionSwitcher.astro create mode 100644 astro/src/components/patterns/VersionSwitcher/VersionSwitcher.css create mode 100644 astro/src/components/patterns/VersionSwitcher/index.ts create mode 100644 astro/src/components/patterns/VersionSwitcher/types.ts create mode 100644 astro/src/components/primitives/Select/Select.astro create mode 100644 astro/src/components/primitives/Select/Select.css create mode 100644 astro/src/components/primitives/Select/index.ts create mode 100644 astro/src/components/primitives/Select/types.ts delete mode 100644 astro/src/config/menu.ts create mode 100644 astro/src/config/menu/api.ts create mode 100644 astro/src/config/menu/docs.ts create mode 100644 astro/src/config/menu/main.ts create mode 100644 astro/src/config/menu/middleware.ts create mode 100644 astro/src/config/menu/resources.ts create mode 100644 astro/src/config/types.ts create mode 100644 astro/src/content/docs/en/3x/api.md create mode 100644 astro/src/content/docs/en/3x/api/application/app-VERB.md create mode 100644 astro/src/content/docs/en/3x/api/application/app-all.md create mode 100644 astro/src/content/docs/en/3x/api/application/app-configure.md create mode 100644 astro/src/content/docs/en/3x/api/application/app-disable.md create mode 100644 astro/src/content/docs/en/3x/api/application/app-disabled.md create mode 100644 astro/src/content/docs/en/3x/api/application/app-enable.md create mode 100644 astro/src/content/docs/en/3x/api/application/app-enabled.md create mode 100644 astro/src/content/docs/en/3x/api/application/app-engine.md create mode 100644 astro/src/content/docs/en/3x/api/application/app-get.md create mode 100644 astro/src/content/docs/en/3x/api/application/app-listen.md create mode 100644 astro/src/content/docs/en/3x/api/application/app-locals.md create mode 100644 astro/src/content/docs/en/3x/api/application/app-param.md create mode 100644 astro/src/content/docs/en/3x/api/application/app-render.md create mode 100644 astro/src/content/docs/en/3x/api/application/app-routes.md create mode 100644 astro/src/content/docs/en/3x/api/application/app-set.md create mode 100644 astro/src/content/docs/en/3x/api/application/app-settings.md create mode 100644 astro/src/content/docs/en/3x/api/application/app-use.md create mode 100644 astro/src/content/docs/en/3x/api/application/overview.md create mode 100644 astro/src/content/docs/en/3x/api/express.md create mode 100644 astro/src/content/docs/en/3x/api/middleware/middleware.md create mode 100644 astro/src/content/docs/en/3x/api/middleware/mw-basicAuth.md create mode 100644 astro/src/content/docs/en/3x/api/middleware/mw-bodyParser.md create mode 100644 astro/src/content/docs/en/3x/api/middleware/mw-compress.md create mode 100644 astro/src/content/docs/en/3x/api/middleware/mw-cookieParser.md create mode 100644 astro/src/content/docs/en/3x/api/middleware/mw-cookieSession.md create mode 100644 astro/src/content/docs/en/3x/api/middleware/mw-csrf.md create mode 100644 astro/src/content/docs/en/3x/api/middleware/mw-directory.md create mode 100644 astro/src/content/docs/en/3x/api/request/overview.md create mode 100644 astro/src/content/docs/en/3x/api/request/req-accepted.md create mode 100644 astro/src/content/docs/en/3x/api/request/req-acceptedCharsets.md create mode 100644 astro/src/content/docs/en/3x/api/request/req-acceptedLanguages.md create mode 100644 astro/src/content/docs/en/3x/api/request/req-accepts.md create mode 100644 astro/src/content/docs/en/3x/api/request/req-acceptsCharset.md create mode 100644 astro/src/content/docs/en/3x/api/request/req-acceptsLanguage.md create mode 100644 astro/src/content/docs/en/3x/api/request/req-body.md create mode 100644 astro/src/content/docs/en/3x/api/request/req-cookies.md create mode 100644 astro/src/content/docs/en/3x/api/request/req-files.md create mode 100644 astro/src/content/docs/en/3x/api/request/req-fresh.md create mode 100644 astro/src/content/docs/en/3x/api/request/req-header.md create mode 100644 astro/src/content/docs/en/3x/api/request/req-host.md create mode 100644 astro/src/content/docs/en/3x/api/request/req-ip.md create mode 100644 astro/src/content/docs/en/3x/api/request/req-ips.md create mode 100644 astro/src/content/docs/en/3x/api/request/req-is.md create mode 100644 astro/src/content/docs/en/3x/api/request/req-originalUrl.md create mode 100644 astro/src/content/docs/en/3x/api/request/req-param.md create mode 100644 astro/src/content/docs/en/3x/api/request/req-params.md create mode 100644 astro/src/content/docs/en/3x/api/request/req-path.md create mode 100644 astro/src/content/docs/en/3x/api/request/req-protocol.md create mode 100644 astro/src/content/docs/en/3x/api/request/req-query.md create mode 100644 astro/src/content/docs/en/3x/api/request/req-res.md create mode 100644 astro/src/content/docs/en/3x/api/request/req-route.md create mode 100644 astro/src/content/docs/en/3x/api/request/req-secure.md create mode 100644 astro/src/content/docs/en/3x/api/request/req-signedCookies.md create mode 100644 astro/src/content/docs/en/3x/api/request/req-stale.md create mode 100644 astro/src/content/docs/en/3x/api/request/req-subdomains.md create mode 100644 astro/src/content/docs/en/3x/api/request/req-xhr.md create mode 100644 astro/src/content/docs/en/3x/api/response/res-attachment.md create mode 100644 astro/src/content/docs/en/3x/api/response/res-charset.md create mode 100644 astro/src/content/docs/en/3x/api/response/res-clearCookie.md create mode 100644 astro/src/content/docs/en/3x/api/response/res-cookie.md create mode 100644 astro/src/content/docs/en/3x/api/response/res-download.md create mode 100644 astro/src/content/docs/en/3x/api/response/res-format.md create mode 100644 astro/src/content/docs/en/3x/api/response/res-get.md create mode 100644 astro/src/content/docs/en/3x/api/response/res-json.md create mode 100644 astro/src/content/docs/en/3x/api/response/res-jsonp.md create mode 100644 astro/src/content/docs/en/3x/api/response/res-links.md create mode 100644 astro/src/content/docs/en/3x/api/response/res-locals.md create mode 100644 astro/src/content/docs/en/3x/api/response/res-location.md create mode 100644 astro/src/content/docs/en/3x/api/response/res-redirect.md create mode 100644 astro/src/content/docs/en/3x/api/response/res-render.md create mode 100644 astro/src/content/docs/en/3x/api/response/res-req.md create mode 100644 astro/src/content/docs/en/3x/api/response/res-send.md create mode 100644 astro/src/content/docs/en/3x/api/response/res-sendfile.md create mode 100644 astro/src/content/docs/en/3x/api/response/res-set.md create mode 100644 astro/src/content/docs/en/3x/api/response/res-status.md create mode 100644 astro/src/content/docs/en/3x/api/response/res-type.md create mode 100644 astro/src/content/docs/en/3x/api/response/response.md rename astro/src/content/docs/en/{ => 4x}/advanced/best-practice-performance.md (99%) rename astro/src/content/docs/en/{ => 4x}/advanced/best-practice-security.md (99%) rename astro/src/content/docs/en/{ => 4x}/advanced/developing-template-engines.md (98%) rename astro/src/content/docs/en/{ => 4x}/advanced/healthcheck-graceful-shutdown.md (98%) rename astro/src/content/docs/en/{ => 4x}/advanced/security-updates.md (99%) create mode 100644 astro/src/content/docs/en/4x/api.md create mode 100644 astro/src/content/docs/en/4x/api/application/app-METHOD.md create mode 100644 astro/src/content/docs/en/4x/api/application/app-all.md create mode 100644 astro/src/content/docs/en/4x/api/application/app-delete-method.md create mode 100644 astro/src/content/docs/en/4x/api/application/app-disable.md create mode 100644 astro/src/content/docs/en/4x/api/application/app-disabled.md create mode 100644 astro/src/content/docs/en/4x/api/application/app-enable.md create mode 100644 astro/src/content/docs/en/4x/api/application/app-enabled.md create mode 100644 astro/src/content/docs/en/4x/api/application/app-engine.md create mode 100644 astro/src/content/docs/en/4x/api/application/app-get-method.md create mode 100644 astro/src/content/docs/en/4x/api/application/app-get.md create mode 100644 astro/src/content/docs/en/4x/api/application/app-listen.md create mode 100644 astro/src/content/docs/en/4x/api/application/app-locals.md create mode 100644 astro/src/content/docs/en/4x/api/application/app-mountpath.md create mode 100644 astro/src/content/docs/en/4x/api/application/app-onmount.md create mode 100644 astro/src/content/docs/en/4x/api/application/app-param.md create mode 100644 astro/src/content/docs/en/4x/api/application/app-path.md create mode 100644 astro/src/content/docs/en/4x/api/application/app-post-method.md create mode 100644 astro/src/content/docs/en/4x/api/application/app-put-method.md create mode 100644 astro/src/content/docs/en/4x/api/application/app-render.md create mode 100644 astro/src/content/docs/en/4x/api/application/app-route.md create mode 100644 astro/src/content/docs/en/4x/api/application/app-set.md create mode 100644 astro/src/content/docs/en/4x/api/application/app-settings.md create mode 100644 astro/src/content/docs/en/4x/api/application/app-use.md create mode 100644 astro/src/content/docs/en/4x/api/application/overview.md create mode 100644 astro/src/content/docs/en/4x/api/express/express.json.md create mode 100644 astro/src/content/docs/en/4x/api/express/express.md create mode 100644 astro/src/content/docs/en/4x/api/express/express.raw.md create mode 100644 astro/src/content/docs/en/4x/api/express/express.router.md create mode 100644 astro/src/content/docs/en/4x/api/express/express.static.md create mode 100644 astro/src/content/docs/en/4x/api/express/express.text.md create mode 100644 astro/src/content/docs/en/4x/api/express/express.urlencoded.md create mode 100644 astro/src/content/docs/en/4x/api/request/overview.md create mode 100644 astro/src/content/docs/en/4x/api/request/req-accepts.md create mode 100644 astro/src/content/docs/en/4x/api/request/req-acceptsCharsets.md create mode 100644 astro/src/content/docs/en/4x/api/request/req-acceptsEncodings.md create mode 100644 astro/src/content/docs/en/4x/api/request/req-acceptsLanguages.md create mode 100644 astro/src/content/docs/en/4x/api/request/req-app.md create mode 100644 astro/src/content/docs/en/4x/api/request/req-base-url.md create mode 100644 astro/src/content/docs/en/4x/api/request/req-body.md create mode 100644 astro/src/content/docs/en/4x/api/request/req-cookies.md create mode 100644 astro/src/content/docs/en/4x/api/request/req-fresh.md create mode 100644 astro/src/content/docs/en/4x/api/request/req-get.md create mode 100644 astro/src/content/docs/en/4x/api/request/req-hostname.md create mode 100644 astro/src/content/docs/en/4x/api/request/req-ip.md create mode 100644 astro/src/content/docs/en/4x/api/request/req-ips.md create mode 100644 astro/src/content/docs/en/4x/api/request/req-is.md create mode 100644 astro/src/content/docs/en/4x/api/request/req-method.md create mode 100644 astro/src/content/docs/en/4x/api/request/req-originalUrl.md create mode 100644 astro/src/content/docs/en/4x/api/request/req-param.md create mode 100644 astro/src/content/docs/en/4x/api/request/req-params.md create mode 100644 astro/src/content/docs/en/4x/api/request/req-path.md create mode 100644 astro/src/content/docs/en/4x/api/request/req-protocol.md create mode 100644 astro/src/content/docs/en/4x/api/request/req-query.md create mode 100644 astro/src/content/docs/en/4x/api/request/req-range.md create mode 100644 astro/src/content/docs/en/4x/api/request/req-res.md create mode 100644 astro/src/content/docs/en/4x/api/request/req-route.md create mode 100644 astro/src/content/docs/en/4x/api/request/req-secure.md create mode 100644 astro/src/content/docs/en/4x/api/request/req-signedCookies.md create mode 100644 astro/src/content/docs/en/4x/api/request/req-stale.md create mode 100644 astro/src/content/docs/en/4x/api/request/req-subdomains.md create mode 100644 astro/src/content/docs/en/4x/api/request/req-xhr.md create mode 100644 astro/src/content/docs/en/4x/api/response/overview.md create mode 100644 astro/src/content/docs/en/4x/api/response/res-app.md create mode 100644 astro/src/content/docs/en/4x/api/response/res-append.md create mode 100644 astro/src/content/docs/en/4x/api/response/res-attachment.md create mode 100644 astro/src/content/docs/en/4x/api/response/res-clearCookie.md create mode 100644 astro/src/content/docs/en/4x/api/response/res-cookie.md create mode 100644 astro/src/content/docs/en/4x/api/response/res-download.md create mode 100644 astro/src/content/docs/en/4x/api/response/res-end.md create mode 100644 astro/src/content/docs/en/4x/api/response/res-format.md create mode 100644 astro/src/content/docs/en/4x/api/response/res-get.md create mode 100644 astro/src/content/docs/en/4x/api/response/res-headersSent.md create mode 100644 astro/src/content/docs/en/4x/api/response/res-json.md create mode 100644 astro/src/content/docs/en/4x/api/response/res-jsonp.md create mode 100644 astro/src/content/docs/en/4x/api/response/res-links.md create mode 100644 astro/src/content/docs/en/4x/api/response/res-locals.md create mode 100644 astro/src/content/docs/en/4x/api/response/res-location.md create mode 100644 astro/src/content/docs/en/4x/api/response/res-redirect.md create mode 100644 astro/src/content/docs/en/4x/api/response/res-render.md create mode 100644 astro/src/content/docs/en/4x/api/response/res-req.md create mode 100644 astro/src/content/docs/en/4x/api/response/res-send.md create mode 100644 astro/src/content/docs/en/4x/api/response/res-sendFile.md create mode 100644 astro/src/content/docs/en/4x/api/response/res-sendStatus.md create mode 100644 astro/src/content/docs/en/4x/api/response/res-set.md create mode 100644 astro/src/content/docs/en/4x/api/response/res-status.md create mode 100644 astro/src/content/docs/en/4x/api/response/res-type.md create mode 100644 astro/src/content/docs/en/4x/api/response/res-vary.md create mode 100644 astro/src/content/docs/en/4x/api/router/overview.md create mode 100644 astro/src/content/docs/en/4x/api/router/router-METHOD.md create mode 100644 astro/src/content/docs/en/4x/api/router/router-Router.md create mode 100644 astro/src/content/docs/en/4x/api/router/router-all.md create mode 100644 astro/src/content/docs/en/4x/api/router/router-param.md create mode 100644 astro/src/content/docs/en/4x/api/router/router-route.md create mode 100644 astro/src/content/docs/en/4x/api/router/router-use.md create mode 100644 astro/src/content/docs/en/4x/api/router/routing-args.html rename astro/src/content/docs/en/{ => 4x}/guide/behind-proxies.md (99%) rename astro/src/content/docs/en/{ => 4x}/guide/database-integration.md (99%) rename astro/src/content/docs/en/{ => 4x}/guide/debugging.md (99%) rename astro/src/content/docs/en/{ => 4x}/guide/error-handling.md (99%) rename astro/src/content/docs/en/{ => 4x}/guide/migrating-4.md (99%) rename astro/src/content/docs/en/{ => 4x}/guide/migrating-5.md (99%) rename astro/src/content/docs/en/{ => 4x}/guide/overriding-express-api.md (99%) rename astro/src/content/docs/en/{ => 4x}/guide/routing.md (99%) rename astro/src/content/docs/en/{ => 4x}/guide/using-middleware.md (99%) rename astro/src/content/docs/en/{ => 4x}/guide/using-template-engines.md (99%) rename astro/src/content/docs/en/{ => 4x}/guide/writing-middleware.md (99%) rename astro/src/content/docs/en/{ => 4x}/starter/basic-routing.md (98%) rename astro/src/content/docs/en/{ => 4x}/starter/examples.md (97%) rename astro/src/content/docs/en/{ => 4x}/starter/faq.md (99%) rename astro/src/content/docs/en/{ => 4x}/starter/generator.md (99%) rename astro/src/content/docs/en/{ => 4x}/starter/hello-world.md (98%) rename astro/src/content/docs/en/{ => 4x}/starter/installing.md (98%) rename astro/src/content/docs/en/{ => 4x}/starter/static-files.md (99%) create mode 100644 astro/src/content/docs/en/5x/advanced/best-practice-performance.md create mode 100644 astro/src/content/docs/en/5x/advanced/best-practice-security.md create mode 100755 astro/src/content/docs/en/5x/advanced/developing-template-engines.md create mode 100644 astro/src/content/docs/en/5x/advanced/healthcheck-graceful-shutdown.md create mode 100755 astro/src/content/docs/en/5x/advanced/security-updates.md create mode 100644 astro/src/content/docs/en/5x/api.md create mode 100644 astro/src/content/docs/en/5x/api/application/app-METHOD.md create mode 100644 astro/src/content/docs/en/5x/api/application/app-all.md create mode 100644 astro/src/content/docs/en/5x/api/application/app-delete-method.md create mode 100644 astro/src/content/docs/en/5x/api/application/app-disable.md create mode 100644 astro/src/content/docs/en/5x/api/application/app-disabled.md create mode 100644 astro/src/content/docs/en/5x/api/application/app-enable.md create mode 100644 astro/src/content/docs/en/5x/api/application/app-enabled.md create mode 100644 astro/src/content/docs/en/5x/api/application/app-engine.md create mode 100644 astro/src/content/docs/en/5x/api/application/app-get-method.md create mode 100644 astro/src/content/docs/en/5x/api/application/app-get.md create mode 100644 astro/src/content/docs/en/5x/api/application/app-listen.md create mode 100644 astro/src/content/docs/en/5x/api/application/app-locals.md create mode 100644 astro/src/content/docs/en/5x/api/application/app-mountpath.md create mode 100644 astro/src/content/docs/en/5x/api/application/app-onmount.md create mode 100644 astro/src/content/docs/en/5x/api/application/app-param.md create mode 100644 astro/src/content/docs/en/5x/api/application/app-path.md create mode 100644 astro/src/content/docs/en/5x/api/application/app-post-method.md create mode 100644 astro/src/content/docs/en/5x/api/application/app-put-method.md create mode 100644 astro/src/content/docs/en/5x/api/application/app-render.md create mode 100644 astro/src/content/docs/en/5x/api/application/app-route.md create mode 100644 astro/src/content/docs/en/5x/api/application/app-router.md create mode 100644 astro/src/content/docs/en/5x/api/application/app-set.md create mode 100644 astro/src/content/docs/en/5x/api/application/app-settings.md create mode 100644 astro/src/content/docs/en/5x/api/application/app-use.md create mode 100644 astro/src/content/docs/en/5x/api/application/overview.md create mode 100644 astro/src/content/docs/en/5x/api/express/express.json.md create mode 100644 astro/src/content/docs/en/5x/api/express/express.md create mode 100644 astro/src/content/docs/en/5x/api/express/express.raw.md create mode 100644 astro/src/content/docs/en/5x/api/express/express.router.md create mode 100644 astro/src/content/docs/en/5x/api/express/express.static.md create mode 100644 astro/src/content/docs/en/5x/api/express/express.text.md create mode 100644 astro/src/content/docs/en/5x/api/express/express.urlencoded.md create mode 100644 astro/src/content/docs/en/5x/api/request/overview.md create mode 100644 astro/src/content/docs/en/5x/api/request/req-accepts.md create mode 100644 astro/src/content/docs/en/5x/api/request/req-acceptsCharsets.md create mode 100644 astro/src/content/docs/en/5x/api/request/req-acceptsEncodings.md create mode 100644 astro/src/content/docs/en/5x/api/request/req-acceptsLanguages.md create mode 100644 astro/src/content/docs/en/5x/api/request/req-app.md create mode 100644 astro/src/content/docs/en/5x/api/request/req-base-url.md create mode 100644 astro/src/content/docs/en/5x/api/request/req-body.md create mode 100644 astro/src/content/docs/en/5x/api/request/req-cookies.md create mode 100644 astro/src/content/docs/en/5x/api/request/req-fresh.md create mode 100644 astro/src/content/docs/en/5x/api/request/req-get.md create mode 100644 astro/src/content/docs/en/5x/api/request/req-host.md create mode 100644 astro/src/content/docs/en/5x/api/request/req-hostname.md create mode 100644 astro/src/content/docs/en/5x/api/request/req-ip.md create mode 100644 astro/src/content/docs/en/5x/api/request/req-ips.md create mode 100644 astro/src/content/docs/en/5x/api/request/req-is.md create mode 100644 astro/src/content/docs/en/5x/api/request/req-method.md create mode 100644 astro/src/content/docs/en/5x/api/request/req-originalUrl.md create mode 100644 astro/src/content/docs/en/5x/api/request/req-params.md create mode 100644 astro/src/content/docs/en/5x/api/request/req-path.md create mode 100644 astro/src/content/docs/en/5x/api/request/req-protocol.md create mode 100644 astro/src/content/docs/en/5x/api/request/req-query.md create mode 100644 astro/src/content/docs/en/5x/api/request/req-range.md create mode 100644 astro/src/content/docs/en/5x/api/request/req-res.md create mode 100644 astro/src/content/docs/en/5x/api/request/req-route.md create mode 100644 astro/src/content/docs/en/5x/api/request/req-secure.md create mode 100644 astro/src/content/docs/en/5x/api/request/req-signedCookies.md create mode 100644 astro/src/content/docs/en/5x/api/request/req-stale.md create mode 100644 astro/src/content/docs/en/5x/api/request/req-subdomains.md create mode 100644 astro/src/content/docs/en/5x/api/request/req-xhr.md create mode 100644 astro/src/content/docs/en/5x/api/response/res-app.md create mode 100644 astro/src/content/docs/en/5x/api/response/res-append.md create mode 100644 astro/src/content/docs/en/5x/api/response/res-attachment.md create mode 100644 astro/src/content/docs/en/5x/api/response/res-clearCookie.md create mode 100644 astro/src/content/docs/en/5x/api/response/res-cookie.md create mode 100644 astro/src/content/docs/en/5x/api/response/res-download.md create mode 100644 astro/src/content/docs/en/5x/api/response/res-end.md create mode 100644 astro/src/content/docs/en/5x/api/response/res-format.md create mode 100644 astro/src/content/docs/en/5x/api/response/res-get.md create mode 100644 astro/src/content/docs/en/5x/api/response/res-headersSent.md create mode 100644 astro/src/content/docs/en/5x/api/response/res-json.md create mode 100644 astro/src/content/docs/en/5x/api/response/res-jsonp.md create mode 100644 astro/src/content/docs/en/5x/api/response/res-links.md create mode 100644 astro/src/content/docs/en/5x/api/response/res-locals.md create mode 100644 astro/src/content/docs/en/5x/api/response/res-location.md create mode 100644 astro/src/content/docs/en/5x/api/response/res-redirect.md create mode 100644 astro/src/content/docs/en/5x/api/response/res-render.md create mode 100644 astro/src/content/docs/en/5x/api/response/res-req.md create mode 100644 astro/src/content/docs/en/5x/api/response/res-send.md create mode 100644 astro/src/content/docs/en/5x/api/response/res-sendFile.md create mode 100644 astro/src/content/docs/en/5x/api/response/res-sendStatus.md create mode 100644 astro/src/content/docs/en/5x/api/response/res-set.md create mode 100644 astro/src/content/docs/en/5x/api/response/res-status.md create mode 100644 astro/src/content/docs/en/5x/api/response/res-type.md create mode 100644 astro/src/content/docs/en/5x/api/response/res-vary.md create mode 100644 astro/src/content/docs/en/5x/api/response/response.md create mode 100644 astro/src/content/docs/en/5x/api/router/router-METHOD.md create mode 100644 astro/src/content/docs/en/5x/api/router/router-Router.md create mode 100644 astro/src/content/docs/en/5x/api/router/router-all.md create mode 100644 astro/src/content/docs/en/5x/api/router/router-param.md create mode 100644 astro/src/content/docs/en/5x/api/router/router-route.md create mode 100644 astro/src/content/docs/en/5x/api/router/router-use.md create mode 100644 astro/src/content/docs/en/5x/api/router/router.md create mode 100755 astro/src/content/docs/en/5x/guide/behind-proxies.md create mode 100644 astro/src/content/docs/en/5x/guide/database-integration.md create mode 100755 astro/src/content/docs/en/5x/guide/debugging.md create mode 100755 astro/src/content/docs/en/5x/guide/error-handling.md create mode 100755 astro/src/content/docs/en/5x/guide/migrating-4.md create mode 100755 astro/src/content/docs/en/5x/guide/migrating-5.md create mode 100644 astro/src/content/docs/en/5x/guide/overriding-express-api.md create mode 100755 astro/src/content/docs/en/5x/guide/routing.md create mode 100644 astro/src/content/docs/en/5x/guide/using-middleware.md create mode 100755 astro/src/content/docs/en/5x/guide/using-template-engines.md create mode 100755 astro/src/content/docs/en/5x/guide/writing-middleware.md create mode 100755 astro/src/content/docs/en/5x/starter/basic-routing.md create mode 100755 astro/src/content/docs/en/5x/starter/examples.md create mode 100755 astro/src/content/docs/en/5x/starter/faq.md create mode 100755 astro/src/content/docs/en/5x/starter/generator.md create mode 100755 astro/src/content/docs/en/5x/starter/hello-world.md create mode 100755 astro/src/content/docs/en/5x/starter/installing.md create mode 100755 astro/src/content/docs/en/5x/starter/static-files.md rename astro/src/content/{docs/en/resources => resources/en}/community.md (82%) rename astro/src/content/{docs/en/resources => resources/en}/contributing.md (99%) rename astro/src/content/{docs/en/resources => resources/en}/glossary.md (99%) rename astro/src/content/{docs/en/resources => resources/en}/middleware/body-parser.md (99%) rename astro/src/content/{docs/en/resources => resources/en}/middleware/compression.md (99%) rename astro/src/content/{docs/en/resources => resources/en}/middleware/connect-rid.md (99%) rename astro/src/content/{docs/en/resources => resources/en}/middleware/cookie-parser.md (99%) rename astro/src/content/{docs/en/resources => resources/en}/middleware/cookie-session.md (99%) rename astro/src/content/{docs/en/resources => resources/en}/middleware/cors.md (99%) rename astro/src/content/{docs/en/resources => resources/en}/middleware/errorhandler.md (99%) rename astro/src/content/{docs/en/resources => resources/en}/middleware/method-override.md (99%) rename astro/src/content/{docs/en/resources => resources/en}/middleware/morgan.md (99%) rename astro/src/content/{docs/en/resources => resources/en}/middleware/multer.md (99%) rename astro/src/content/{docs/en/resources/middleware.md => resources/en/middleware/overview.md} (99%) rename astro/src/content/{docs/en/resources => resources/en}/middleware/response-time.md (99%) rename astro/src/content/{docs/en/resources => resources/en}/middleware/serve-favicon.md (99%) rename astro/src/content/{docs/en/resources => resources/en}/middleware/serve-index.md (99%) rename astro/src/content/{docs/en/resources => resources/en}/middleware/serve-static.md (99%) rename astro/src/content/{docs/en/resources => resources/en}/middleware/session.md (99%) rename astro/src/content/{docs/en/resources => resources/en}/middleware/timeout.md (99%) rename astro/src/content/{docs/en/resources => resources/en}/middleware/vhost.md (99%) rename astro/src/content/{docs/en/resources => resources/en}/utils.md (99%) create mode 100644 astro/src/pages/[lang]/blog/index.astro delete mode 100644 astro/src/pages/[lang]/docs/index.astro create mode 100644 astro/src/pages/[lang]/resources/[...slug].astro create mode 100644 astro/src/pages/[lang]/support/index.astro create mode 100644 astro/src/styles/tokens/_sizing.css create mode 100644 astro/src/styles/tokens/_zindex.css diff --git a/astro/CONTRIBUTING.md b/astro/CONTRIBUTING.md index af56697819..53f9d64fee 100644 --- a/astro/CONTRIBUTING.md +++ b/astro/CONTRIBUTING.md @@ -1,15 +1,13 @@ -# Contributing to Expressjs.com - -### The Official Documentation of the Express.js Framework +# Contributing to the expressjs.com website This is the contribution documentation for the [expressjs.com](https://github.com/expressjs/expressjs.com) website. > [!NOTE] > This is not the repo for Express.js framework. To contribute to the _[Express.js framework](https://github.com/expressjs/express)_, check out the [GitHub repo contributing page](https://github.com/expressjs/express?tab=contributing-ov-file) or the website's [Contributing to Express](https://expressjs.com/en/resources/contributing.html) page. -#### Need some ideas? These are some typical issues. +### Common contributions -1. **Website issues**: If you see anything on the site that could use a tune-up, think about how to fix it. +1. **Website Issues**: Improvements to the site's functionality, design, or accessibility. - Display or screen sizing problems - Mobile responsiveness issues - Missing or broken accessibility features @@ -27,13 +25,13 @@ This is the contribution documentation for the [expressjs.com](https://github.co - Fix incorrect/poorly translated words - Check out the [Contributing translations](#contributing-translations) section below for a contributing guide. -#### Want to work on a backlog issue? +### Working on existing issues -We often have bugs or enhancements that need work. You can find these under our repo's [Issues tab](https://github.com/expressjs/expressjs.com/issues). Check out the tags to find something that's a good match for you. +We welcome contributions to existing bugs or enhancements. You can find these under our repo's [Issues tab](https://github.com/expressjs/expressjs.com/issues). Check out the tags to find something that matches your interests. Look for issues labeled `good first issue` or `help wanted` to get started. -#### Have an idea? Found a bug? +### Reporting bugs & requesting features -If you've found a bug or a typo, or if you have an idea for an enhancement, you can: +If you have found a bug, a typo, or have an idea for an enhancement, you can: - Submit a [new issue](https://github.com/expressjs/expressjs.com/issues/new/choose) on our repo. Do this for larger proposals, or if you'd like to discuss or get feedback first. @@ -41,31 +39,41 @@ If you've found a bug or a typo, or if you have an idea for an enhancement, you ## Getting Started -The steps below will guide you through the Expressjs.com contribution process. +The steps below will guide you through the expressjs.com contribution process. -#### Step 1: (OPTIONAL) Open a New Issue +#### Step 1: Open an Issue (Optional) -So you've found a problem that you want to fix, or have a site enhancement you want to make. +If you have identified a problem or an enhancement: 1. If you want to get feedback or discuss, open a discussion [issue](https://github.com/expressjs/expressjs.com/issues/new/choose) prior to starting work. This is not required, but encouraged for larger proposals. - While we highly encourage this step, it is only for submissions proposing significant change. It helps us to clarify and focus the work, and ensure it aligns with overall project priorities. - For submissions proposing minor improvements or corrections, this is not needed. You can skip this step. - - When opening an issue please give it a title and fill in the description section. The more details you provide, the more feedback we can give. + - When opening an issue, please provide a clear title and complete description. The more details you provide, the more feedback we can give. -2. After receiving your issue the Express.js documentation team will respond with feedback. We read every submission and always try to respond quickly with feedback. +2. After receiving your issue, the Express.js documentation team will respond with feedback. We review all submissions and aim to respond as soon as possible. - For submissions proposing significant change, we encourage you to follow the review process before starting work. -#### Step 2: Get the Application Code Base +#### Step 2: Get the project codebase ## Prerequisites -- **Node.js**: v24.13.0 or higher +### Development stack + +This project uses: + +- **Astro** for site generation +- **TypeScript** for type safety +- **ESLint** for linting +- **Prettier** for formatting + + +### Tooling + +- **Node.js**: v24.x or higher - **npm**: v11.0.0 or higher (comes with Node 24) > We recommend using [nvm](https://github.com/nvm-sh/nvm) to manage Node.js versions. This project includes an `.nvmrc` file for automatic version switching. -## Getting Started - 1. **Clone the repository:** ```bash @@ -96,13 +104,58 @@ So you've found a problem that you want to fix, or have a site enhancement you w ## Available Scripts -| Command | Description | -| ----------------- | ---------------------------------------- | -| `npm run dev` | Start development server with hot reload | -| `npm run build` | Build production site to `./dist` | -| `npm run preview` | Preview production build locally | +| Command | Description | +| ----------------- | ----------------------------------------- | +| `npm run dev` | Start development server with hot reload | +| `npm run build` | Build production site to `./dist` | +| `npm run preview` | Preview production build locally | +| `npm run lint` | Run ESLint to check for issues | +| `npm run check` | Run type checking and format verification | + +## Submitting a pull request + +1. Create a new branch from `redesign` +2. Make your changes +3. Run `npm run check` to verify code style and types +4. Commit with a clear message +5. Push to your fork +6. Open a PR against `redesign` + +> Ensure all checks pass and your branch is up to date with `redesign` before opening a PR. + +## Architecture policy + +Although Astro supports integrations with frameworks such as React or Vue, this project intentionally avoids additional frontend frameworks. + +The expressjs.com website is designed to use: + +- HTML +- CSS +- TypeScript + +This decision helps keep the codebase lightweight, easier to maintain, and accessible to a broader range of contributors. + +### Do not introduce new frontend frameworks + +Please do not introduce React, Vue, or other client-side frameworks without prior discussion and approval. + +If a proposed feature appears to require a framework integration: + +1. Open an issue first. +2. Explain the use case and why the existing stack (HTML, CSS, and TypeScript) is insufficient. +3. Wait for approval from the maintainers before proceeding. + +Pull requests that introduce new framework dependencies without prior discussion may be closed. + +### Existing exception -## Project Structure +> The search component is implemented using React to support the Orama-powered search experience. +> This is a limited, isolated integration and does not indicate that React (or other frameworks) should be used elsewhere in the project. + +> [!IMPORTANT] +> Pull requests that introduce new framework dependencies without prior discussion may not be accepted. + +## Project structure ``` astro/ @@ -112,8 +165,10 @@ astro/ │ │ ├── patterns/ # Complex UI patterns │ │ └── primitives/ # Base UI primitives │ ├── config/ # Configuration files +│ │ ├── menu/ # Menu configuration files (sidebars) │ ├── content/ # Content collections -│ │ └── docs/ # Documentation content +│ │ ├── docs/ # Documentation content +│ │ └── resources/ # Resource pages │ ├── i18n/ # Internationalization │ ├── layouts/ # Page layouts │ ├── pages/ # Route pages @@ -125,5 +180,214 @@ astro/ │ └── utils/ # Utility functions ├── public/ # Static assets │ └── fonts/ # Font files -└── astro.config.mjs # Astro configuration +├── astro.config.mjs # Astro configuration +``` + +## Content configuration + +The site uses Astro's [Content Collections](https://docs.astro.build/en/guides/content-collections/) to manage documentation and resources. The configuration is defined in `src/content.config.ts`. + +### Collections + +| Collection | Location | Description | +| ----------- | ------------------------ | --------------------------------- | +| `docs` | `src/content/docs/` | Documentation pages (guides, API) | +| `resources` | `src/content/resources/` | Resource pages (community, tools) | + +### Frontmatter schema + +Each content file requires frontmatter with the following properties: + +```yaml +--- +title: 'Page Title' # Required: The page title +description: 'Description' # Optional: Page description for SEO +--- +``` + +## Versioning + +The Express.js documentation supports multiple versions. Content is organized by version in the `src/content/docs/` directory. + +### Version structure + +``` +src/content/docs/ +└── en/ + ├── 3x/ # Express 3.x documentation + ├── 4x/ # Express 4.x documentation + └── 5x/ # Express 5.x documentation (default) +``` + +### How versioning works + +- **Default Version**: `5x` is the current default version +- **Supported Versions**: `5x`, `4x`, `3x` +- **URL Patterns**: + - Versioned: `/en/5x/api/` → Express 5.x API docs + - Non-versioned: `/en/api/` → Defaults to Express 5.x + +### Adding version specific content + +1. Create your content file in the appropriate version directory: + + ``` + src/content/docs/en/5x/guide/my-new-page.md + ``` + +2. The versioning system (configured in `src/pages/[lang]/[...slug].astro`) will automatically: + - Serve the page at `/en/5x/guide/my-new-page` + - Create non-versioned aliases for default version content + +### Menu configuration + +The navigation menus are configured in `src/config/menu/`. The type definitions are in `src/config/types.ts`. + +#### Menu structure + +Menus are composed of **sections** and **items**: + +``` +Menu +├── sections[] # Groups of menu items +│ ├── title? # Optional section header +│ ├── basePath? # Base path prepended to all item hrefs +│ ├── omitFrom? # Versions to exclude this section from +│ └── items[] # Menu items in this section +└── items[] # Alternative: flat list of items (no sections) ``` + +#### Configuration files + +| File | Purpose | +| --------------- | ------------------------------------------- | +| `main.ts` | Top-level navigation (Docs, API, Resources) | +| `docs.ts` | Documentation sidebar menu | +| `api.ts` | API reference sidebar menu | +| `resources.ts` | Resources section menu | +| `middleware.ts` | Middleware submenu | + +#### Adding menu items + +Basic menu item with a link: + +```typescript +{ href: `/guide/routing`, label: 'Routing', ariaLabel: 'Routing guide' } +``` + +Menu item with a submenu: + +```typescript +{ + label: 'Properties', + ariaLabel: 'Application properties', + submenu: { + items: [ + { href: `/api/application/app-locals`, label: 'app.locals' }, + { href: `/api/application/app-mountpath`, label: 'app.mountpath' }, + ], + }, +} +``` + +#### Adding sections + +Sections group related menu items with an optional title: + +```typescript +{ + title: 'Getting started', + items: [ + { href: `/starter/installing`, label: 'Installing' }, + { href: `/starter/hello-world`, label: 'Hello world' }, + ], +} +``` + +#### Version specific menus + +**Enabling versioning on a submenu** — Use `versioned` to specify which versions the menu supports. The version prefix will be automatically prepended to URLs: + +```typescript +{ + label: 'API Reference', + submenu: { + versioned: ['5x', '4x', '3x'], // Supports all three versions + sections: apiMenu.sections, + }, +} +``` + +**Omitting items from specific versions** — Use `omitFrom` to hide an item in certain versions: + +```typescript +{ + href: `/api/application/app-mountpath`, + label: 'app.mountpath', + omitFrom: ['3x'], // Not available in Express 3.x +} +``` + +**Omitting entire sections from specific versions**: + +```typescript +{ + title: 'Router', + omitFrom: ['3x'], // Router section doesn't exist in 3.x + items: [ + { href: `/api/router/overview`, label: 'Overview' }, + ], +} +``` + +#### Type reference + +```typescript +type VersionPrefix = '5x' | '4x' | '3x'; + +type Menu = { + sections?: MenuSection[]; + items?: MenuItem[]; + basePath?: string; + versioned?: VersionPrefix[]; +}; + +type MenuSection = { + title?: string; // Section header text + basePath?: string; // Prepended to all item hrefs + items: MenuItem[]; + omitFrom?: VersionPrefix[]; // Versions to exclude this section from +}; + +type MenuItem = { + label: string; + ariaLabel?: string; + icon?: string; + href?: string; // Link destination (omit if using submenu) + submenu?: Menu; // Nested menu (omit if using href) + omitFrom?: VersionPrefix[]; // Versions to exclude this item from +}; +``` + +## Contributing translations + +We use Crowdin to manage our translations in multiple languages and achieve automatic translation with artificial intelligence. Since these translations can be inefficient in some cases, we need help from the community to provide accurate and helpful translations. + +The documentation is translated into these languages: + +- Chinese Simplified (`zh-cn`) +- Chinese Traditional (`zh-tw`) +- English (`en`) +- French (`fr`) +- German (`de`) +- Italian (`it`) +- Japanese (`ja`) +- Korean (`ko`) +- Brazilian Portuguese (`pt-br`) +- Spanish (`es`) + +### How to translate + +1. Request to join the Express.js Website project on [Crowdin](https://express.crowdin.com/website) +2. [Select the language you want to translate](https://support.crowdin.com/for-translators/#starting-translation) +3. [Start translating](https://support.crowdin.com/online-editor/) diff --git a/astro/package-lock.json b/astro/package-lock.json index 8e15e1a4ba..dc551f40c1 100644 --- a/astro/package-lock.json +++ b/astro/package-lock.json @@ -15,21 +15,18 @@ "devDependencies": { "@csstools/postcss-global-data": "^4.0.0", "@eslint/js": "^9.39.2", - "@iconify-json/ph": "^1.2.2", + "@iconify-json/fluent": "^1.2.38", "eslint": "^9.39.2", "eslint-config-prettier": "^10.1.8", "eslint-plugin-astro": "^1.5.0", "eslint-plugin-jsx-a11y": "^6.10.2", "lint-staged": "^16.2.7", "postcss-custom-media": "^12.0.0", + "postcss-nested": "^7.0.2", "prettier": "^3.8.1", "prettier-plugin-astro": "^0.14.1", "typescript": "^5.9.3", "typescript-eslint": "^8.53.1" - }, - "engines": { - "node": ">=24.13.0", - "npm": ">=11.0.0" } }, "node_modules/@antfu/install-pkg": { @@ -945,10 +942,10 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@iconify-json/ph": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@iconify-json/ph/-/ph-1.2.2.tgz", - "integrity": "sha512-PgkEZNtqa8hBGjHXQa4pMwZa93hmfu8FUSjs/nv4oUU6yLsgv+gh9nu28Kqi8Fz9CCVu4hj1MZs9/60J57IzFw==", + "node_modules/@iconify-json/fluent": { + "version": "1.2.38", + "resolved": "https://registry.npmjs.org/@iconify-json/fluent/-/fluent-1.2.38.tgz", + "integrity": "sha512-5+MsS9aePYHoxMO5+/kXkhSYRhctvgSyxt/7r0Xc3CHpOq4Rcu8x7GSfIzxOwP16T0Y8M471ykRe5xmU4MzBPQ==", "dev": true, "license": "MIT", "dependencies": { @@ -7950,6 +7947,32 @@ "postcss": "^8.4" } }, + "node_modules/postcss-nested": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-7.0.2.tgz", + "integrity": "sha512-5osppouFc0VR9/VYzYxO03VaDa3e8F23Kfd6/9qcZTUI8P58GIYlArOET2Wq0ywSl2o2PjELhYOFI4W7l5QHKw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, "node_modules/postcss-selector-parser": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", diff --git a/astro/package.json b/astro/package.json index 5e4a3d8d52..eaefd53e88 100644 --- a/astro/package.json +++ b/astro/package.json @@ -22,7 +22,7 @@ "devEngines": { "runtime": { "name": "node", - "version": ">=24.13.0", + "version": "24.x", "onFail": "error" }, "packageManager": { @@ -31,20 +31,17 @@ "onFail": "error" } }, - "engines": { - "node": ">=24.13.0", - "npm": ">=11.0.0" - }, "devDependencies": { "@csstools/postcss-global-data": "^4.0.0", "@eslint/js": "^9.39.2", - "@iconify-json/ph": "^1.2.2", + "@iconify-json/fluent": "^1.2.38", "eslint": "^9.39.2", "eslint-config-prettier": "^10.1.8", "eslint-plugin-astro": "^1.5.0", "eslint-plugin-jsx-a11y": "^6.10.2", "lint-staged": "^16.2.7", "postcss-custom-media": "^12.0.0", + "postcss-nested": "^7.0.2", "prettier": "^3.8.1", "prettier-plugin-astro": "^0.14.1", "typescript": "^5.9.3", diff --git a/astro/postcss.config.mjs b/astro/postcss.config.mjs index ef00bed1ed..febcf2f575 100644 --- a/astro/postcss.config.mjs +++ b/astro/postcss.config.mjs @@ -1,5 +1,6 @@ import postcssGlobalData from '@csstools/postcss-global-data'; import postcssCustomMedia from 'postcss-custom-media'; +import postcssNested from 'postcss-nested'; export default { plugins: [ @@ -7,5 +8,6 @@ export default { files: ['./src/styles/tokens/_breakpoints.css'], }), postcssCustomMedia(), + postcssNested(), ], }; diff --git a/astro/public/logo-dark.svg b/astro/public/logo-dark.svg new file mode 100644 index 0000000000..0dc200a93c --- /dev/null +++ b/astro/public/logo-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/astro/public/logo-white.svg b/astro/public/logo-white.svg new file mode 100644 index 0000000000..1ba7920fd9 --- /dev/null +++ b/astro/public/logo-white.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/astro/src/components/patterns/Breadcrumbs/Breadcrumbs.astro b/astro/src/components/patterns/Breadcrumbs/Breadcrumbs.astro index 220e6db0b3..bf57300f14 100644 --- a/astro/src/components/patterns/Breadcrumbs/Breadcrumbs.astro +++ b/astro/src/components/patterns/Breadcrumbs/Breadcrumbs.astro @@ -6,7 +6,7 @@ */ import { Body } from '@components/primitives'; import { Icon } from 'astro-icon/components'; -import type { BreadcrumbItem } from '@utils/breadcrumb'; +import type { BreadcrumbItem } from '@utils/content'; interface Props { items: BreadcrumbItem[]; @@ -27,7 +27,9 @@ const { items } = Astro.props; ) : ( {item.label} )} - {index < items.length - 1 &&
+ +Following are some examples of using the [express.static](/{{page.lang}}/guide/using-middleware.html#middleware.built-in) +middleware in an Express app. + +Serve static content for the app from the "public" directory in the application directory: + +```js +// GET /style.css etc +app.use(express.static(path.join(__dirname, 'public'))); +``` + +Mount the middleware at "/static" to serve static content only when their request path is prefixed with "/static": + +```js +// GET /static/style.css etc. +app.use('/static', express.static(path.join(__dirname, 'public'))); +``` + +Disable logging for static content requests by loading the logger middleware after the static middleware: + +```js +app.use(express.static(path.join(__dirname, 'public'))); +app.use(logger()); +``` + +Serve static files from multiple directories, but give precedence to "./public" over the others: + +```js +app.use(express.static(path.join(__dirname, 'public'))); +app.use(express.static(path.join(__dirname, 'files'))); +app.use(express.static(path.join(__dirname, 'uploads'))); +``` diff --git a/astro/src/content/docs/en/4x/api/application/overview.md b/astro/src/content/docs/en/4x/api/application/overview.md new file mode 100644 index 0000000000..93a2e52c4c --- /dev/null +++ b/astro/src/content/docs/en/4x/api/application/overview.md @@ -0,0 +1,128 @@ +--- +title: Properties +description: section markdown="1"> +--- + +

Application

+ +The `app` object conventionally denotes the Express application. +Create it by calling the top-level `express()` function exported by the Express module: + +```js +var express = require('express'); +var app = express(); + +app.get('/', function (req, res) { + res.send('hello world'); +}); + +app.listen(3000); +``` + +The `app` object has methods for + +- Routing HTTP requests; see for example, [app.METHOD](#app.METHOD) and [app.param](#app.param). +- Configuring middleware; see [app.route](#app.route). +- Rendering HTML views; see [app.render](#app.render). +- Registering a template engine; see [app.engine](#app.engine). + +It also has settings (properties) that affect how the application behaves; +for more information, see [Application settings](#app.settings.table). + +
+The Express application object can be referred from the [request object](#req) and the [response object](#res) as `req.app`, and `res.app`, respectively. +
+ +

Properties

+ +
+ {% include api/en/4x/app-locals.md %} +
+ +
+ {% include api/en/4x/app-mountpath.md %} +
+ +

Events

+ +
+ {% include api/en/4x/app-onmount.md %} +
+ +

Methods

+ +
+ {% include api/en/4x/app-all.md %} +
+ +
+ {% include api/en/4x/app-delete-method.md %} +
+ +
+ {% include api/en/4x/app-disable.md %} +
+ +
+ {% include api/en/4x/app-disabled.md %} +
+ +
+ {% include api/en/4x/app-enable.md %} +
+ +
+ {% include api/en/4x/app-enabled.md %} +
+ +
+ {% include api/en/4x/app-engine.md %} +
+ +
+ {% include api/en/4x/app-get.md %} +
+ +
+ {% include api/en/4x/app-get-method.md %} +
+ +
+ {% include api/en/4x/app-listen.md %} +
+ +
+ {% include api/en/4x/app-METHOD.md %} +
+ +
+ {% include api/en/4x/app-param.md %} +
+ +
+ {% include api/en/4x/app-path.md %} +
+ +
+ {% include api/en/4x/app-post-method.md %} +
+ +
+ {% include api/en/4x/app-put-method.md %} +
+ +
+ {% include api/en/4x/app-render.md %} +
+ +
+ {% include api/en/4x/app-route.md %} +
+ +
+ {% include api/en/4x/app-set.md %} +
+ +
+ {% include api/en/4x/app-use.md %} +
diff --git a/astro/src/content/docs/en/4x/api/express/express.json.md b/astro/src/content/docs/en/4x/api/express/express.json.md new file mode 100644 index 0000000000..f313870335 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/express/express.json.md @@ -0,0 +1,47 @@ +--- +title: express.json +description: This middleware is available in Express v4.16.0 onwards. +--- + +

express.json([options])

+ +
+This middleware is available in Express v4.16.0 onwards. +
+ +This is a built-in middleware function in Express. It parses incoming requests +with JSON payloads and is based on +[body-parser](/resources/middleware/body-parser.html). + +Returns middleware that only parses JSON and only looks at requests where +the `Content-Type` header matches the `type` option. This parser accepts any +Unicode encoding of the body and supports automatic inflation of `gzip` and +`deflate` encodings. + +A new `body` object containing the parsed data is populated on the `request` +object after the middleware (i.e. `req.body`), or an empty object (`{}`) if +there was no body to parse, the `Content-Type` was not matched, or an error +occurred. + +
+As `req.body`'s shape is based on user-controlled input, all properties and +values in this object are untrusted and should be validated before trusting. +For example, `req.body.foo.toString()` may fail in multiple ways, for example +`foo` may not be there or may not be a string, and `toString` may not be a +function and instead a string or other user-input. +
+ +
+ +The following table describes the properties of the optional `options` object. + +| Property | Description | Type | Default | +| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | -------------------- | +| `inflate` | Enables or disables handling deflated (compressed) bodies; when disabled, deflated bodies are rejected. | Boolean | `true` | +| `limit` | Controls the maximum request body size. If this is a number, then the value specifies the number of bytes; if it is a string, the value is passed to the [bytes](https://www.npmjs.com/package/bytes) library for parsing. | Mixed | `"100kb"` | +| `reviver` | The `reviver` option is passed directly to `JSON.parse` as the second argument. You can find more information on this argument [in the MDN documentation about JSON.parse](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Example.3A_Using_the_reviver_parameter). | Function | `null` | +| `strict` | Enables or disables only accepting arrays and objects; when disabled will accept anything `JSON.parse` accepts. | Boolean | `true` | +| `type` | This is used to determine what media type the middleware will parse. This option can be a string, array of strings, or a function. If not a function, `type` option is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme) library and this can be an extension name (like `json`), a mime type (like `application/json`), or a mime type with a wildcard (like `*/*` or `*/json`). If a function, the `type` option is called as `fn(req)` and the request is parsed if it returns a truthy value. | Mixed | `"application/json"` | +| `verify` | This option, if supplied, is called as `verify(req, res, buf, encoding)`, where `buf` is a `Buffer` of the raw request body and `encoding` is the encoding of the request. The parsing can be aborted by throwing an error. | Function | `undefined` | + +
diff --git a/astro/src/content/docs/en/4x/api/express/express.md b/astro/src/content/docs/en/4x/api/express/express.md new file mode 100644 index 0000000000..7aac38f370 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/express/express.md @@ -0,0 +1,39 @@ +--- +title: Methods +description: section markdown="1"> +--- + +

express()

+ +Creates an Express application. The `express()` function is a top-level function exported by the `express` module. + +```js +var express = require('express'); +var app = express(); +``` + +

Methods

+ +
+ {% include api/en/4x/express.json.md %} +
+ +
+ {% include api/en/4x/express.raw.md %} +
+ +
+ {% include api/en/4x/express.router.md %} +
+ +
+ {% include api/en/4x/express.static.md %} +
+ +
+ {% include api/en/4x/express.text.md %} +
+ +
+ {% include api/en/4x/express.urlencoded.md %} +
diff --git a/astro/src/content/docs/en/4x/api/express/express.raw.md b/astro/src/content/docs/en/4x/api/express/express.raw.md new file mode 100644 index 0000000000..cc6626e71a --- /dev/null +++ b/astro/src/content/docs/en/4x/api/express/express.raw.md @@ -0,0 +1,45 @@ +--- +title: express.raw +description: This middleware is available in Express v4.17.0 onwards. +--- + +

express.raw([options])

+ +
+This middleware is available in Express v4.17.0 onwards. +
+ +This is a built-in middleware function in Express. It parses incoming request +payloads into a `Buffer` and is based on +[body-parser](/resources/middleware/body-parser.html). + +Returns middleware that parses all bodies as a `Buffer` and only looks at requests +where the `Content-Type` header matches the `type` option. This parser accepts +any Unicode encoding of the body and supports automatic inflation of `gzip` and +`deflate` encodings. + +A new `body` `Buffer` containing the parsed data is populated on the `request` +object after the middleware (i.e. `req.body`), or an empty object (`{}`) if +there was no body to parse, the `Content-Type` was not matched, or an error +occurred. + +
+As `req.body`'s shape is based on user-controlled input, all properties and +values in this object are untrusted and should be validated before trusting. +For example, `req.body.toString()` may fail in multiple ways, for example +stacking multiple parsers `req.body` may be from a different parser. Testing +that `req.body` is a `Buffer` before calling buffer methods is recommended. +
+ +The following table describes the properties of the optional `options` object. + +
+ +| Property | Description | Type | Default | +| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ---------------------------- | +| `inflate` | Enables or disables handling deflated (compressed) bodies; when disabled, deflated bodies are rejected. | Boolean | `true` | +| `limit` | Controls the maximum request body size. If this is a number, then the value specifies the number of bytes; if it is a string, the value is passed to the [bytes](https://www.npmjs.com/package/bytes) library for parsing. | Mixed | `"100kb"` | +| `type` | This is used to determine what media type the middleware will parse. This option can be a string, array of strings, or a function. If not a function, `type` option is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme) library and this can be an extension name (like `bin`), a mime type (like `application/octet-stream`), or a mime type with a wildcard (like `*/*` or `application/*`). If a function, the `type` option is called as `fn(req)` and the request is parsed if it returns a truthy value. | Mixed | `"application/octet-stream"` | +| `verify` | This option, if supplied, is called as `verify(req, res, buf, encoding)`, where `buf` is a `Buffer` of the raw request body and `encoding` is the encoding of the request. The parsing can be aborted by throwing an error. | Function | `undefined` | + +
diff --git a/astro/src/content/docs/en/4x/api/express/express.router.md b/astro/src/content/docs/en/4x/api/express/express.router.md new file mode 100644 index 0000000000..baf1b889fd --- /dev/null +++ b/astro/src/content/docs/en/4x/api/express/express.router.md @@ -0,0 +1,29 @@ +--- +title: express.Router +description: Creates a new [router](#router) object. +--- + +

express.Router([options])

+ +Creates a new [router](#router) object. + +```js +var router = express.Router([options]); +``` + +The optional `options` parameter specifies the behavior of the router. + +
+ +| Property | Description | Default | Availability | +| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | ------------ | +| `caseSensitive` | Enable case sensitivity. | Disabled by default, treating "/Foo" and "/foo" as the same. | | +| `mergeParams` | Preserve the `req.params` values from the parent router. If the parent and the child have conflicting param names, the child's value take precedence. | `false` | 4.5.0+ | +| `strict` | Enable strict routing. | Disabled by default, "/foo" and "/foo/" are treated the same by the router. |   | + +
+ +You can add middleware and HTTP method routes (such as `get`, `put`, `post`, and +so on) to `router` just like an application. + +For more information, see [Router](#router). diff --git a/astro/src/content/docs/en/4x/api/express/express.static.md b/astro/src/content/docs/en/4x/api/express/express.static.md new file mode 100644 index 0000000000..9e34d55ad2 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/express/express.static.md @@ -0,0 +1,102 @@ +--- +title: express.static +description: This is a built-in middleware function in Express. +--- + +

express.static(root, [options])

+ +This is a built-in middleware function in Express. +It serves static files and is based on [serve-static](/resources/middleware/serve-static.html). + +{% capture alert_content %} +For best results, [use a reverse proxy](/{{page.lang}}/advanced/best-practice-performance.html#use-a-reverse-proxy) cache to improve performance of serving static assets. +{% endcapture %} +{% include admonitions/note.html content=alert_content %} + +The `root` argument specifies the root directory from which to serve static assets. +The function determines the file to serve by combining `req.url` with the provided `root` directory. +When a file is not found, instead of sending a 404 response, it calls `next()` +to move on to the next middleware, allowing for stacking and fall-backs. + +The following table describes the properties of the `options` object. +See also the [example below](#example.of.express.static). + +
+ +| Property | Description | Type | Default | +| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------ | +| `dotfiles` | Determines how dotfiles (files or directories that begin with a dot ".") are treated.

See [dotfiles](#dotfiles) below. | String | `undefined` | +| `etag` | Enable or disable etag generation

NOTE: `express.static` always sends weak ETags. | Boolean | `true` | +| `extensions` | Sets file extension fallbacks: If a file is not found, search for files with the specified extensions and serve the first one found. Example: `['html', 'htm']`. | Mixed | `false` | +| `fallthrough` | Let client errors fall-through as unhandled requests, otherwise forward a client error.

See [fallthrough](#fallthrough) below. | Boolean | `true` | +| `immutable` | Enable or disable the `immutable` directive in the `Cache-Control` response header. If enabled, the `maxAge` option should also be specified to enable caching. The `immutable` directive will prevent supported clients from making conditional requests during the life of the `maxAge` option to check if the file has changed. | Boolean | `false` | +| `index` | Sends the specified directory index file. Set to `false` to disable directory indexing. | Mixed | "index.html" | +| `lastModified` | Set the `Last-Modified` header to the last modified date of the file on the OS. | Boolean | `true` | +| `maxAge` | Set the max-age property of the Cache-Control header in milliseconds or a string in [ms format](https://www.npmjs.org/package/ms). | Number | 0 | +| `redirect` | Redirect to trailing "/" when the pathname is a directory. | Boolean | `true` | +| `setHeaders` | Function for setting HTTP headers to serve with the file.

See [setHeaders](#setHeaders) below. | Function | | +| `acceptRanges` | Enable or disable accepting ranged requests. Disabling this will not send the `Accept-Ranges` header and will ignore the contents of the Range request header. | Boolean | true | +| `cacheControl` | Enable or disable setting the `Cache-Control` response header. Disabling this will ignore the immutable and maxAge options. | Boolean | true | + +
+ +For more information, see [Serving static files in Express](/starter/static-files.html). +and [Using middleware - Built-in middleware](/{{page.lang}}/guide/using-middleware.html#middleware.built-in). + +
dotfiles
+ +Possible values for this option are: + +- "allow" - No special treatment for dotfiles. +- "deny" - Deny a request for a dotfile, respond with `403`, then call `next()`. +- "ignore" - Act as if the dotfile does not exist, respond with `404`, then call `next()`. +- `undefined` - Act as ignore, except that files in a directory that begins with a dot are **NOT** ignored. + +
fallthrough
+ +When this option is `true`, client errors such as a bad request or a request to a non-existent +file will cause this middleware to simply call `next()` to invoke the next middleware in the stack. +When false, these errors (even 404s), will invoke `next(err)`. + +Set this option to `true` so you can map multiple physical directories +to the same web address or for routes to fill in non-existent files. + +Use `false` if you have mounted this middleware at a path designed +to be strictly a single file system directory, which allows for short-circuiting 404s +for less overhead. This middleware will also reply to all methods. + +
setHeaders
+ +For this option, specify a function to set custom response headers. Alterations to the headers must occur synchronously. + +The signature of the function is: + +```js +fn(res, path, stat); +``` + +Arguments: + +- `res`, the [response object](#res). +- `path`, the file path that is being sent. +- `stat`, the `stat` object of the file that is being sent. + +

Example of express.static

+ +Here is an example of using the `express.static` middleware function with an elaborate options object: + +```js +var options = { + dotfiles: 'ignore', + etag: false, + extensions: ['htm', 'html'], + index: false, + maxAge: '1d', + redirect: false, + setHeaders: function (res, path, stat) { + res.set('x-timestamp', Date.now()); + }, +}; + +app.use(express.static('public', options)); +``` diff --git a/astro/src/content/docs/en/4x/api/express/express.text.md b/astro/src/content/docs/en/4x/api/express/express.text.md new file mode 100644 index 0000000000..76aa3033fc --- /dev/null +++ b/astro/src/content/docs/en/4x/api/express/express.text.md @@ -0,0 +1,46 @@ +--- +title: express.text +description: This middleware is available in Express v4.17.0 onwards. +--- + +

express.text([options])

+ +
+This middleware is available in Express v4.17.0 onwards. +
+ +This is a built-in middleware function in Express. It parses incoming request +payloads into a string and is based on +[body-parser](/resources/middleware/body-parser.html). + +Returns middleware that parses all bodies as a string and only looks at requests +where the `Content-Type` header matches the `type` option. This parser accepts +any Unicode encoding of the body and supports automatic inflation of `gzip` and +`deflate` encodings. + +A new `body` string containing the parsed data is populated on the `request` +object after the middleware (i.e. `req.body`), or an empty object (`{}`) if +there was no body to parse, the `Content-Type` was not matched, or an error +occurred. + +
+As `req.body`'s shape is based on user-controlled input, all properties and +values in this object are untrusted and should be validated before trusting. +For example, `req.body.trim()` may fail in multiple ways, for example +stacking multiple parsers `req.body` may be from a different parser. Testing +that `req.body` is a string before calling string methods is recommended. +
+ +The following table describes the properties of the optional `options` object. + +
+ +| Property | Description | Type | Default | +| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | -------------- | +| `defaultCharset` | Specify the default character set for the text content if the charset is not specified in the `Content-Type` header of the request. | String | `"utf-8"` | +| `inflate` | Enables or disables handling deflated (compressed) bodies; when disabled, deflated bodies are rejected. | Boolean | `true` | +| `limit` | Controls the maximum request body size. If this is a number, then the value specifies the number of bytes; if it is a string, the value is passed to the [bytes](https://www.npmjs.com/package/bytes) library for parsing. | Mixed | `"100kb"` | +| `type` | This is used to determine what media type the middleware will parse. This option can be a string, array of strings, or a function. If not a function, `type` option is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme) library and this can be an extension name (like `txt`), a mime type (like `text/plain`), or a mime type with a wildcard (like `*/*` or `text/*`). If a function, the `type` option is called as `fn(req)` and the request is parsed if it returns a truthy value. | Mixed | `"text/plain"` | +| `verify` | This option, if supplied, is called as `verify(req, res, buf, encoding)`, where `buf` is a `Buffer` of the raw request body and `encoding` is the encoding of the request. The parsing can be aborted by throwing an error. | Function | `undefined` | + +
diff --git a/astro/src/content/docs/en/4x/api/express/express.urlencoded.md b/astro/src/content/docs/en/4x/api/express/express.urlencoded.md new file mode 100644 index 0000000000..6fd9fad1eb --- /dev/null +++ b/astro/src/content/docs/en/4x/api/express/express.urlencoded.md @@ -0,0 +1,53 @@ +--- +title: express.urlencoded +description: This middleware is available in Express v4.16.0 onwards. +--- + +

express.urlencoded([options])

+ +
+This middleware is available in Express v4.16.0 onwards. +
+ +This is a built-in middleware function in Express. It parses incoming requests +with urlencoded payloads and is based on [body-parser](/resources/middleware/body-parser.html). + +Returns middleware that only parses urlencoded bodies and only looks at +requests where the `Content-Type` header matches the `type` option. This +parser accepts only UTF-8 encoding of the body and supports automatic +inflation of `gzip` and `deflate` encodings. + +A new `body` object containing the parsed data is populated on the `request` +object after the middleware (i.e. `req.body`), or an empty object (`{}`) if +there was no body to parse, the `Content-Type` was not matched, or an error +occurred. This object will contain key-value pairs, where the value can be +a string or array (when `extended` is `false`), or any type (when `extended` +is `true`). + +
+As `req.body`'s shape is based on user-controlled input, all properties and +values in this object are untrusted and should be validated before trusting. +For example, `req.body.foo.toString()` may fail in multiple ways, for example +`foo` may not be there or may not be a string, and `toString` may not be a +function and instead a string or other user-input. +
+ +The following table describes the properties of the optional `options` object. + +
+ +| Property | Description | Type | Default | +| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------------------------------- | +| `extended` | This option allows to choose between parsing the URL-encoded data with the `querystring` library (when `false`) or the `qs` library (when `true`). The "extended" syntax allows for rich objects and arrays to be encoded into the URL-encoded format, allowing for a JSON-like experience with URL-encoded. For more information, please [see the qs library](https://www.npmjs.org/package/qs#readme). | Boolean | `true` | +| `inflate` | Enables or disables handling deflated (compressed) bodies; when disabled, deflated bodies are rejected. | Boolean | `true` | +| `limit` | Controls the maximum request body size. If this is a number, then the value specifies the number of bytes; if it is a string, the value is passed to the [bytes](https://www.npmjs.com/package/bytes) library for parsing. | Mixed | `"100kb"` | +| `parameterLimit` | This option controls the maximum number of parameters that are allowed in the URL-encoded data. If a request contains more parameters than this value, an error will be raised. | Number | `1000` | +| `type` | This is used to determine what media type the middleware will parse. This option can be a string, array of strings, or a function. If not a function, `type` option is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme) library and this can be an extension name (like `urlencoded`), a mime type (like `application/x-www-form-urlencoded`), or a mime type with a wildcard (like `*/x-www-form-urlencoded`). If a function, the `type` option is called as `fn(req)` and the request is parsed if it returns a truthy value. | Mixed | `"application/x-www-form-urlencoded"` | +| `verify` | This option, if supplied, is called as `verify(req, res, buf, encoding)`, where `buf` is a `Buffer` of the raw request body and `encoding` is the encoding of the request. The parsing can be aborted by throwing an error. | Function | `undefined` | +| `depth` | Configure the maximum depth of the `qs` library when `extended` is `true`. This allows you to limit the amount of keys that are parsed and can be useful to prevent certain types of abuse. Defaults to `32`. It is recommended to keep this value as low as possible. | Number | `32` | + +
+ +
+The `depth` option was added in Express v4.20.0. If you are using an earlier version, this option will not be available. +
diff --git a/astro/src/content/docs/en/4x/api/request/overview.md b/astro/src/content/docs/en/4x/api/request/overview.md new file mode 100644 index 0000000000..8e850398bf --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/overview.md @@ -0,0 +1,160 @@ +--- +title: Properties +description: The req object represents the HTTP request and has properties for the request query string, parameters, body, HTTP headers, and so on +--- + +

Request

+ +The `req` object represents the HTTP request and has properties for the +request query string, parameters, body, HTTP headers, and so on. In this documentation and by convention, +the object is always referred to as `req` (and the HTTP response is `res`) but its actual name is determined +by the parameters to the callback function in which you're working. + +For example: + +```js +app.get('/user/:id', function (req, res) { + res.send('user ' + req.params.id); +}); +``` + +But you could just as well have: + +```js +app.get('/user/:id', function (request, response) { + response.send('user ' + request.params.id); +}); +``` + +The `req` object is an enhanced version of Node's own request object +and supports all [built-in fields and methods](https://nodejs.org/api/http.html#http_class_http_incomingmessage). + +

Properties

+ +
+In Express 4, `req.files` is no longer available on the `req` object by default. To access uploaded files +on the `req.files` object, use multipart-handling middleware like [busboy](https://www.npmjs. +com/package/busboy), [multer](https://www.npmjs.com/package/multer), +[formidable](https://www.npmjs.com/package/formidable), +[multiparty](https://www.npmjs.com/package/multiparty), +[connect-multiparty](https://www.npmjs.com/package/connect-multiparty), +or [pez](https://www.npmjs.com/package/pez). +
+ +
+ {% include api/en/4x/req-app.md %} +
+ +
+ {% include api/en/4x/req-baseUrl.md %} +
+ +
+ {% include api/en/4x/req-body.md %} +
+ +
+ {% include api/en/4x/req-cookies.md %} +
+ +
+ {% include api/en/4x/req-fresh.md %} +
+ +
+ {% include api/en/4x/req-hostname.md %} +
+ +
+ {% include api/en/4x/req-ip.md %} +
+ +
+ {% include api/en/4x/req-ips.md %} +
+ +
+ {% include api/en/4x/req-method.md %} +
+ +
+ {% include api/en/4x/req-originalUrl.md %} +
+ +
+ {% include api/en/4x/req-params.md %} +
+ +
+ {% include api/en/4x/req-path.md %} +
+ +
+ {% include api/en/4x/req-protocol.md %} +
+ +
+ {% include api/en/4x/req-query.md %} +
+ +
+ {% include api/en/4x/req-res.md %} +
+ +
+ {% include api/en/4x/req-route.md %} +
+ +
+ {% include api/en/4x/req-secure.md %} +
+ +
+ {% include api/en/4x/req-signedCookies.md %} +
+ +
+ {% include api/en/4x/req-stale.md %} +
+ +
+ {% include api/en/4x/req-subdomains.md %} +
+ +
+ {% include api/en/4x/req-xhr.md %} +
+ +

Methods

+ +
+ {% include api/en/4x/req-accepts.md %} +
+ +
+ {% include api/en/4x/req-acceptsCharsets.md %} +
+ +
+ {% include api/en/4x/req-acceptsEncodings.md %} +
+ +
+ {% include api/en/4x/req-acceptsLanguages.md %} +
+ +
+ {% include api/en/4x/req-get.md %} +
+ +
+ {% include api/en/4x/req-is.md %} +
+ +
+ {% include api/en/4x/req-param.md %} +
+ +
+ {% include api/en/4x/req-range.md %} +
diff --git a/astro/src/content/docs/en/4x/api/request/req-accepts.md b/astro/src/content/docs/en/4x/api/request/req-accepts.md new file mode 100644 index 0000000000..763c6c6ab7 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/req-accepts.md @@ -0,0 +1,41 @@ +--- +title: req.accepts +description: Checks if the specified content types are acceptable, based on the request Accept HTTP header field. +--- + +

req.accepts(types)

+ +Checks if the specified content types are acceptable, based on the request's `Accept` HTTP header field. +The method returns the best match, or if none of the specified content types is acceptable, returns +`false` (in which case, the application should respond with `406 "Not Acceptable"`). + +The `type` value may be a single MIME type string (such as "application/json"), +an extension name such as "json", a comma-delimited list, or an array. For a +list or array, the method returns the _best_ match (if any). + +```js +// Accept: text/html +req.accepts('html'); +// => "html" + +// Accept: text/*, application/json +req.accepts('html'); +// => "html" +req.accepts('text/html'); +// => "text/html" +req.accepts(['json', 'text']); +// => "json" +req.accepts('application/json'); +// => "application/json" + +// Accept: text/*, application/json +req.accepts('image/png'); +req.accepts('png'); +// => false + +// Accept: text/*;q=.5, application/json +req.accepts(['html', 'json']); +// => "json" +``` + +For more information, or if you have issues or concerns, see [accepts](https://github.com/expressjs/accepts). diff --git a/astro/src/content/docs/en/4x/api/request/req-acceptsCharsets.md b/astro/src/content/docs/en/4x/api/request/req-acceptsCharsets.md new file mode 100644 index 0000000000..69bed2797b --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/req-acceptsCharsets.md @@ -0,0 +1,12 @@ +--- +title: req.acceptsCharsets +description: Returns the first accepted charset of the specified character sets, +--- + +

req.acceptsCharsets(charset [, ...])

+ +Returns the first accepted charset of the specified character sets, +based on the request's `Accept-Charset` HTTP header field. +If none of the specified charsets is accepted, returns `false`. + +For more information, or if you have issues or concerns, see [accepts](https://github.com/expressjs/accepts). diff --git a/astro/src/content/docs/en/4x/api/request/req-acceptsEncodings.md b/astro/src/content/docs/en/4x/api/request/req-acceptsEncodings.md new file mode 100644 index 0000000000..384e10bb6a --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/req-acceptsEncodings.md @@ -0,0 +1,12 @@ +--- +title: req.acceptsEncodings +description: Returns the first accepted encoding of the specified encodings, +--- + +

req.acceptsEncodings(encoding [, ...])

+ +Returns the first accepted encoding of the specified encodings, +based on the request's `Accept-Encoding` HTTP header field. +If none of the specified encodings is accepted, returns `false`. + +For more information, or if you have issues or concerns, see [accepts](https://github.com/expressjs/accepts). diff --git a/astro/src/content/docs/en/4x/api/request/req-acceptsLanguages.md b/astro/src/content/docs/en/4x/api/request/req-acceptsLanguages.md new file mode 100644 index 0000000000..0674eaa689 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/req-acceptsLanguages.md @@ -0,0 +1,20 @@ +--- +title: req.acceptsLanguages +description: Returns the first accepted language of the specified languages, +--- + +

req.acceptsLanguages([lang, ...])

+ +Returns the first accepted language of the specified languages, +based on the request's `Accept-Language` HTTP header field. +If none of the specified languages is accepted, returns `false`. + +If no `lang` argument is given, then `req.acceptsLanguages()` +returns all languages from the HTTP `Accept-Language` header +as an `Array`. + +For more information, or if you have issues or concerns, see [accepts](https://github.com/expressjs/accepts). + +Express (4.x) source: [request.js line 179](https://github.com/expressjs/express/blob/4.x/lib/request.js#L179) + +Accepts (1.3) source: [index.js line 195](https://github.com/jshttp/accepts/blob/f69c19e459bd501e59fb0b1a40b7471bb578113a/index.js#L195) diff --git a/astro/src/content/docs/en/4x/api/request/req-app.md b/astro/src/content/docs/en/4x/api/request/req-app.md new file mode 100644 index 0000000000..f776c3e8ad --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/req-app.md @@ -0,0 +1,25 @@ +--- +title: req.app +description: This property holds a reference to the instance of the Express application that is using the middleware. +--- + +

req.app

+ +This property holds a reference to the instance of the Express application that is using the middleware. + +If you follow the pattern in which you create a module that just exports a middleware function +and `require()` it in your main file, then the middleware can access the Express instance via `req.app` + +For example: + +```js +// index.js +app.get('/viewdirectory', require('./mymiddleware.js')); +``` + +```js +// mymiddleware.js +module.exports = function (req, res) { + res.send('The views directory is ' + req.app.get('views')); +}; +``` diff --git a/astro/src/content/docs/en/4x/api/request/req-base-url.md b/astro/src/content/docs/en/4x/api/request/req-base-url.md new file mode 100644 index 0000000000..0100ff6db6 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/req-base-url.md @@ -0,0 +1,35 @@ +--- +title: req.baseUrl +description: The URL path on which a router instance was mounted. +--- + +

req.baseUrl

+ +The URL path on which a router instance was mounted. + +The `req.baseUrl` property is similar to the [mountpath](#app.mountpath) property of the `app` object, +except `app.mountpath` returns the matched path pattern(s). + +For example: + +```js +var greet = express.Router(); + +greet.get('/jp', function (req, res) { + console.log(req.baseUrl); // /greet + res.send('Konnichiwa!'); +}); + +app.use('/greet', greet); // load the router on '/greet' +``` + +Even if you use a path pattern or a set of path patterns to load the router, +the `baseUrl` property returns the matched string, not the pattern(s). In the +following example, the `greet` router is loaded on two path patterns. + +```js +app.use(['/gre+t', '/hel{2}o'], greet); // load the router on '/gre+t' and '/hel{2}o' +``` + +When a request is made to `/greet/jp`, `req.baseUrl` is "/greet". When a request is +made to `/hello/jp`, `req.baseUrl` is "/hello". diff --git a/astro/src/content/docs/en/4x/api/request/req-body.md b/astro/src/content/docs/en/4x/api/request/req-body.md new file mode 100644 index 0000000000..18b8eb861c --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/req-body.md @@ -0,0 +1,30 @@ +--- +title: req.body +description: Contains key-value pairs of data submitted in the request body. +--- + +

req.body

+ +Contains key-value pairs of data submitted in the request body. +By default, it is `undefined`, and is populated when you use body-parsing middleware such +as [`express.json()`](#express.json) or [`express.urlencoded()`](#express.urlencoded). + +
+As `req.body`'s shape is based on user-controlled input, all properties and values in this object are untrusted and should be validated before trusting. For example, `req.body.foo.toString()` may fail in multiple ways, for example `foo` may not be there or may not be a string, and `toString` may not be a function and instead a string or other user-input. +
+ +The following example shows how to use body-parsing middleware to populate `req.body`. + +```js +var express = require('express'); + +var app = express(); + +app.use(express.json()); // for parsing application/json +app.use(express.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded + +app.post('/profile', function (req, res, next) { + console.log(req.body); + res.json(req.body); +}); +``` diff --git a/astro/src/content/docs/en/4x/api/request/req-cookies.md b/astro/src/content/docs/en/4x/api/request/req-cookies.md new file mode 100644 index 0000000000..63ac2a74b4 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/req-cookies.md @@ -0,0 +1,19 @@ +--- +title: req.cookies +description: When using cookie-parser middleware, this property is an object that +--- + +

req.cookies

+ +When using [cookie-parser](https://www.npmjs.com/package/cookie-parser) middleware, this property is an object that +contains cookies sent by the request. If the request contains no cookies, it defaults to `{}`. + +```js +// Cookie: name=tj +console.dir(req.cookies.name); +// => 'tj' +``` + +If the cookie has been signed, you have to use [req.signedCookies](#req.signedCookies). + +For more information, issues, or concerns, see [cookie-parser](https://github.com/expressjs/cookie-parser). diff --git a/astro/src/content/docs/en/4x/api/request/req-fresh.md b/astro/src/content/docs/en/4x/api/request/req-fresh.md new file mode 100644 index 0000000000..293c12e898 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/req-fresh.md @@ -0,0 +1,18 @@ +--- +title: req.fresh +description: When the response is still fresh in the client cache true is returned, otherwise false is returned to indicate that the client cache is now stale. +--- + +

req.fresh

+ +When the response is still "fresh" in the client's cache `true` is returned, otherwise `false` is returned to indicate that the client cache is now stale and the full response should be sent. + +When a client sends the `Cache-Control: no-cache` request header to indicate an end-to-end reload request, this module will return `false` to make handling these requests transparent. + +Further details for how cache validation works can be found in the +[HTTP/1.1 Caching Specification](https://tools.ietf.org/html/rfc7234). + +```js +console.dir(req.fresh); +// => true +``` diff --git a/astro/src/content/docs/en/4x/api/request/req-get.md b/astro/src/content/docs/en/4x/api/request/req-get.md new file mode 100644 index 0000000000..ad116d8421 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/req-get.md @@ -0,0 +1,22 @@ +--- +title: req.get +description: Returns the specified HTTP request header field (case-insensitive match). +--- + +

req.get(field)

+ +Returns the specified HTTP request header field (case-insensitive match). +The `Referrer` and `Referer` fields are interchangeable. + +```js +req.get('Content-Type'); +// => "text/plain" + +req.get('content-type'); +// => "text/plain" + +req.get('Something'); +// => undefined +``` + +Aliased as `req.header(field)`. diff --git a/astro/src/content/docs/en/4x/api/request/req-hostname.md b/astro/src/content/docs/en/4x/api/request/req-hostname.md new file mode 100644 index 0000000000..04a2833e0e --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/req-hostname.md @@ -0,0 +1,28 @@ +--- +title: req.hostname +description: Contains the hostname derived from the Host HTTP header. +--- + +

req.hostname

+ +Contains the hostname derived from the `Host` HTTP header. + +When the [`trust proxy` setting](/4x/api.html#trust.proxy.options.table) +does not evaluate to `false`, this property will instead get the value +from the `X-Forwarded-Host` header field. This header can be set by +the client or by the proxy. + +If there is more than one `X-Forwarded-Host` header in the request, the +value of the first header is used. This includes a single header with +comma-separated values, in which the first value is used. + +
+Prior to Express v4.17.0, the `X-Forwarded-Host` could not contain multiple +values or be present more than once. +
+ +```js +// Host: "example.com:3000" +console.dir(req.hostname); +// => 'example.com' +``` diff --git a/astro/src/content/docs/en/4x/api/request/req-ip.md b/astro/src/content/docs/en/4x/api/request/req-ip.md new file mode 100644 index 0000000000..1f03406847 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/req-ip.md @@ -0,0 +1,17 @@ +--- +title: req.ip +description: Contains the remote IP address of the request. +--- + +

req.ip

+ +Contains the remote IP address of the request. + +When the [`trust proxy` setting](/4x/api.html#trust.proxy.options.table) does not evaluate to `false`, +the value of this property is derived from the left-most entry in the +`X-Forwarded-For` header. This header can be set by the client or by the proxy. + +```js +console.dir(req.ip); +// => '127.0.0.1' +``` diff --git a/astro/src/content/docs/en/4x/api/request/req-ips.md b/astro/src/content/docs/en/4x/api/request/req-ips.md new file mode 100644 index 0000000000..1d632da216 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/req-ips.md @@ -0,0 +1,14 @@ +--- +title: req.ips +description: When the trust proxy setting does not evaluate to false, +--- + +

req.ips

+ +When the [`trust proxy` setting](/4x/api.html#trust.proxy.options.table) does not evaluate to `false`, +this property contains an array of IP addresses +specified in the `X-Forwarded-For` request header. Otherwise, it contains an +empty array. This header can be set by the client or by the proxy. + +For example, if `X-Forwarded-For` is `client, proxy1, proxy2`, `req.ips` would be +`["client", "proxy1", "proxy2"]`, where `proxy2` is the furthest downstream. diff --git a/astro/src/content/docs/en/4x/api/request/req-is.md b/astro/src/content/docs/en/4x/api/request/req-is.md new file mode 100644 index 0000000000..944dba091d --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/req-is.md @@ -0,0 +1,47 @@ +--- +title: req.is +description: Returns the matching content type if the incoming request's "Content-Type" HTTP header field +--- + +

req.is(type)

+ +Returns the matching content type if the incoming request's "Content-Type" HTTP header field +matches the MIME type specified by the `type` parameter. If the request has no body, returns `null`. +Returns `false` otherwise. + +```js +// With Content-Type: text/html; charset=utf-8 +req.is('html'); +// => 'html' +req.is('text/html'); +// => 'text/html' +req.is('text/*'); +// => 'text/*' + +// When Content-Type is application/json +req.is('json'); +// => 'json' +req.is('application/json'); +// => 'application/json' +req.is('application/*'); +// => 'application/*' + +// Using arrays +// When Content-Type is application/json +req.is(['json', 'html']); +// => 'json' + +// Using multiple arguments +// When Content-Type is application/json +req.is('json', 'html'); +// => 'json' + +req.is('html'); +// => false +req.is(['xml', 'yaml']); +// => false +req.is('xml', 'yaml'); +// => false +``` + +For more information, or if you have issues or concerns, see [type-is](https://github.com/expressjs/type-is). diff --git a/astro/src/content/docs/en/4x/api/request/req-method.md b/astro/src/content/docs/en/4x/api/request/req-method.md new file mode 100644 index 0000000000..92b683bcfd --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/req-method.md @@ -0,0 +1,9 @@ +--- +title: req.method +description: Contains a string corresponding to the HTTP method of the request +--- + +

req.method

+ +Contains a string corresponding to the HTTP method of the request: +`GET`, `POST`, `PUT`, and so on. diff --git a/astro/src/content/docs/en/4x/api/request/req-originalUrl.md b/astro/src/content/docs/en/4x/api/request/req-originalUrl.md new file mode 100644 index 0000000000..5d0b88a5a7 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/req-originalUrl.md @@ -0,0 +1,33 @@ +--- +title: req.originalUrl +description: req.url retains the original request URL, allowing you to rewrite req.url freely for internal routing purposes +--- + +

req.originalUrl

+ +
+`req.url` is not a native Express property, it is inherited from Node's [http module](https://nodejs.org/api/http.html#http_message_url). +
+ +This property is much like `req.url`; however, it retains the original request URL, +allowing you to rewrite `req.url` freely for internal routing purposes. For example, +the "mounting" feature of [app.use()](#app.use) will rewrite `req.url` to strip the mount point. + +```js +// GET /search?q=something +console.dir(req.originalUrl); +// => '/search?q=something' +``` + +`req.originalUrl` is available both in middleware and router objects, and is a +combination of `req.baseUrl` and `req.url`. Consider following example: + +```js +app.use('/admin', function (req, res, next) { + // GET 'http://www.example.com/admin/new?sort=desc' + console.dir(req.originalUrl); // '/admin/new?sort=desc' + console.dir(req.baseUrl); // '/admin' + console.dir(req.path); // '/new' + next(); +}); +``` diff --git a/astro/src/content/docs/en/4x/api/request/req-param.md b/astro/src/content/docs/en/4x/api/request/req-param.md new file mode 100644 index 0000000000..0dda6b4f5a --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/req-param.md @@ -0,0 +1,41 @@ +--- +title: req.param +description: Deprecated. Use either req.params, req.body or req.query, as applicable. +--- + +

req.param(name [, defaultValue])

+ +
+Deprecated. Use either `req.params`, `req.body` or `req.query`, as applicable. +
+ +Returns the value of param `name` when present. + +```js +// ?name=tobi +req.param('name'); +// => "tobi" + +// POST name=tobi +req.param('name'); +// => "tobi" + +// /user/tobi for /user/:name +req.param('name'); +// => "tobi" +``` + +Lookup is performed in the following order: + +- `req.params` +- `req.body` +- `req.query` + +Optionally, you can specify `defaultValue` to set a default value if the parameter is not found in any of the request objects. + +
+Direct access to `req.body`, `req.params`, and `req.query` should be favoured for clarity - unless you truly accept input from each object. + +Body-parsing middleware must be loaded for `req.param()` to work predictably. Refer [req.body](#req.body) for details. + +
diff --git a/astro/src/content/docs/en/4x/api/request/req-params.md b/astro/src/content/docs/en/4x/api/request/req-params.md new file mode 100644 index 0000000000..e915644e31 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/req-params.md @@ -0,0 +1,30 @@ +--- +title: req.params +description: This property is an object containing properties mapped to the [named route "parameters"](/{{ page.lang }}/guide/routing.html#route-parameters). Fo... +--- + +

req.params

+ +This property is an object containing properties mapped to the [named route "parameters"](/{{ page.lang }}/guide/routing.html#route-parameters). For example, if you have the route `/user/:name`, then the "name" property is available as `req.params.name`. This object defaults to `{}`. + +```js +// GET /user/tj +console.dir(req.params.name); +// => 'tj' +``` + +When you use a regular expression for the route definition, capture groups are provided as integer keys using `req.params[n]`, where `n` is the nth capture group. This rule is applied to unnamed wild card matches with string routes such as `/file/*`: + +```js +// GET /file/javascripts/jquery.js +console.dir(req.params[0]); +// => 'javascripts/jquery.js' +``` + +Named capturing groups in regular expressions behave like named route parameters. For example the group from `/^\/file\/(?.*)$/` expression is available as `req.params.path`. + +If you need to make changes to a key in `req.params`, use the [app.param](/{{ page.lang }}/4x/api.html#app.param) handler. Changes are applicable only to [parameters](/{{ page.lang }}/guide/routing.html#route-parameters) already defined in the route path. + +Any changes made to the `req.params` object in a middleware or route handler will be reset. + +{% include admonitions/note.html content="Express automatically decodes the values in `req.params` (using `decodeURIComponent`)." %} diff --git a/astro/src/content/docs/en/4x/api/request/req-path.md b/astro/src/content/docs/en/4x/api/request/req-path.md new file mode 100644 index 0000000000..6c86493204 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/req-path.md @@ -0,0 +1,18 @@ +--- +title: req.path +description: Contains the path part of the request URL. +--- + +

req.path

+ +Contains the path part of the request URL. + +```js +// example.com/users?sort=desc +console.dir(req.path); +// => '/users' +``` + +
+When called from a middleware, the mount point is not included in `req.path`. See [app.use()](/4x/api.html#app.use) for more details. +
diff --git a/astro/src/content/docs/en/4x/api/request/req-protocol.md b/astro/src/content/docs/en/4x/api/request/req-protocol.md new file mode 100644 index 0000000000..569431fe0f --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/req-protocol.md @@ -0,0 +1,17 @@ +--- +title: req.protocol +description: Contains the request protocol string either http or (for TLS requests) https. +--- + +

req.protocol

+ +Contains the request protocol string: either `http` or (for TLS requests) `https`. + +When the [`trust proxy` setting](#trust.proxy.options.table) does not evaluate to `false`, +this property will use the value of the `X-Forwarded-Proto` header field if present. +This header can be set by the client or by the proxy. + +```js +console.dir(req.protocol); +// => 'http' +``` diff --git a/astro/src/content/docs/en/4x/api/request/req-query.md b/astro/src/content/docs/en/4x/api/request/req-query.md new file mode 100644 index 0000000000..d1027d8da3 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/req-query.md @@ -0,0 +1,26 @@ +--- +title: req.query +description: This property is an object containing a property for each query string parameter in the route. +--- + +

req.query

+ +This property is an object containing a property for each query string parameter in the route. +When [query parser](#app.settings.table) is set to disabled, it is an empty object `{}`, otherwise it is the result of the configured query parser. + +
+As `req.query`'s shape is based on user-controlled input, all properties and values in this object are untrusted and should be validated before trusting. For example, `req.query.foo.toString()` may fail in multiple ways, for example `foo` may not be there or may not be a string, and `toString` may not be a function and instead a string or other user-input. +
+ +The value of this property can be configured with the [query parser application setting](#app.settings.table) to work how your application needs it. A very popular query string parser is the [`qs` module](https://www.npmjs.org/package/qs), and this is used by default. The `qs` module is very configurable with many settings, and it may be desirable to use different settings than the default to populate `req.query`: + +```js +var qs = require('qs'); +app.set('query parser', function (str) { + return qs.parse(str, { + /* custom options */ + }); +}); +``` + +Check out the [query parser application setting](#app.settings.table) documentation for other customization options. diff --git a/astro/src/content/docs/en/4x/api/request/req-range.md b/astro/src/content/docs/en/4x/api/request/req-range.md new file mode 100644 index 0000000000..d2b908f7f3 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/req-range.md @@ -0,0 +1,38 @@ +--- +title: req.range +description: Range header parser +--- + +

req.range(size[, options])

+ +`Range` header parser. + +The `size` parameter is the maximum size of the resource. + +The `options` parameter is an object that can have the following properties. + +
+ +| Property | Type | Description | +| --------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `combine` | Boolean | Specify if overlapping & adjacent ranges should be combined, defaults to `false`. When `true`, ranges will be combined and returned as if they were specified that way in the header. | + +
+ +An array of ranges will be returned or negative numbers indicating an error parsing. + +- `-2` signals a malformed header string +- `-1` signals an unsatisfiable range + +```js +// parse header from request +var range = req.range(1000); + +// the type of the range +if (range.type === 'bytes') { + // the ranges + range.forEach(function (r) { + // do something with r.start and r.end + }); +} +``` diff --git a/astro/src/content/docs/en/4x/api/request/req-res.md b/astro/src/content/docs/en/4x/api/request/req-res.md new file mode 100644 index 0000000000..94e5554756 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/req-res.md @@ -0,0 +1,9 @@ +--- +title: req.res +description: This property holds a reference to the +--- + +

req.res

+ +This property holds a reference to the response object +that relates to this request object. diff --git a/astro/src/content/docs/en/4x/api/request/req-route.md b/astro/src/content/docs/en/4x/api/request/req-route.md new file mode 100644 index 0000000000..57f8548968 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/req-route.md @@ -0,0 +1,30 @@ +--- +title: req.route +description: Contains the currently-matched route, a string +--- + +

req.route

+ +Contains the currently-matched route, a string. For example: + +```js +app.get('/user/:id?', function userIdHandler(req, res) { + console.log(req.route); + res.send('GET'); +}); +``` + +Example output from the previous snippet: + +``` +{ path: '/user/:id?', + stack: + [ { handle: [Function: userIdHandler], + name: 'userIdHandler', + params: undefined, + path: undefined, + keys: [], + regexp: /^\/?$/i, + method: 'get' } ], + methods: { get: true } } +``` diff --git a/astro/src/content/docs/en/4x/api/request/req-secure.md b/astro/src/content/docs/en/4x/api/request/req-secure.md new file mode 100644 index 0000000000..aaee9e1a9d --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/req-secure.md @@ -0,0 +1,13 @@ +--- +title: req.secure +description: A Boolean property that is true if a TLS connection is established +--- + +

req.secure

+ +A Boolean property that is true if a TLS connection is established. Equivalent to: + +```js +console.dir(req.protocol === 'https'); +// => true +``` diff --git a/astro/src/content/docs/en/4x/api/request/req-signedCookies.md b/astro/src/content/docs/en/4x/api/request/req-signedCookies.md new file mode 100644 index 0000000000..73750e60b0 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/req-signedCookies.md @@ -0,0 +1,22 @@ +--- +title: req.signedCookies +description: When using cookie-parser middleware, this property +--- + +

req.signedCookies

+ +When using [cookie-parser](https://www.npmjs.com/package/cookie-parser) middleware, this property +contains signed cookies sent by the request, unsigned and ready for use. Signed cookies reside +in a different object to show developer intent; otherwise, a malicious attack could be placed on +`req.cookie` values (which are easy to spoof). Note that signing a cookie does not make it "hidden" +or encrypted; but simply prevents tampering (because the secret used to sign is private). + +If no signed cookies are sent, the property defaults to `{}`. + +```js +// Cookie: user=tobi.CP7AWaXDfAKIRfH49dQzKJx7sKzzSoPq7/AcBBRVwlI3 +console.dir(req.signedCookies.user); +// => 'tobi' +``` + +For more information, issues, or concerns, see [cookie-parser](https://github.com/expressjs/cookie-parser). diff --git a/astro/src/content/docs/en/4x/api/request/req-stale.md b/astro/src/content/docs/en/4x/api/request/req-stale.md new file mode 100644 index 0000000000..b39f5cb5ef --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/req-stale.md @@ -0,0 +1,14 @@ +--- +title: req.stale +description: Indicates whether the request is stale, and is the opposite of req.fresh. +--- + +

req.stale

+ +Indicates whether the request is "stale," and is the opposite of `req.fresh`. +For more information, see [req.fresh](#req.fresh). + +```js +console.dir(req.stale); +// => true +``` diff --git a/astro/src/content/docs/en/4x/api/request/req-subdomains.md b/astro/src/content/docs/en/4x/api/request/req-subdomains.md new file mode 100644 index 0000000000..894143f8d1 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/req-subdomains.md @@ -0,0 +1,18 @@ +--- +title: req.subdomains +description: An array of subdomains in the domain name of the request. +--- + +

req.subdomains

+ +An array of subdomains in the domain name of the request. + +```js +// Host: "tobi.ferrets.example.com" +console.dir(req.subdomains); +// => ['ferrets', 'tobi'] +``` + +The application property `subdomain offset`, which defaults to 2, is used for determining the +beginning of the subdomain segments. To change this behavior, change its value +using [app.set](/{{ page.lang }}/4x/api.html#app.set). diff --git a/astro/src/content/docs/en/4x/api/request/req-xhr.md b/astro/src/content/docs/en/4x/api/request/req-xhr.md new file mode 100644 index 0000000000..f247d20b05 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/request/req-xhr.md @@ -0,0 +1,14 @@ +--- +title: req.xhr +description: A Boolean property that is true if the request X-Requested-With header field is "XMLHttpRequest" +--- + +

req.xhr

+ +A Boolean property that is `true` if the request's `X-Requested-With` header field is +"XMLHttpRequest", indicating that the request was issued by a client library such as jQuery. + +```js +console.dir(req.xhr); +// => true +``` diff --git a/astro/src/content/docs/en/4x/api/response/overview.md b/astro/src/content/docs/en/4x/api/response/overview.md new file mode 100644 index 0000000000..ba3d4a8050 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/response/overview.md @@ -0,0 +1,135 @@ +--- +title: Properties +description: section markdown="1"> +--- + +

Response

+ +The `res` object represents the HTTP response that an Express app sends when it gets an HTTP request. + +In this documentation and by convention, +the object is always referred to as `res` (and the HTTP request is `req`) but its actual name is determined +by the parameters to the callback function in which you're working. + +For example: + +```js +app.get('/user/:id', function (req, res) { + res.send('user ' + req.params.id); +}); +``` + +But you could just as well have: + +```js +app.get('/user/:id', function (request, response) { + response.send('user ' + request.params.id); +}); +``` + +The `res` object is an enhanced version of Node's own response object +and supports all [built-in fields and methods](https://nodejs.org/api/http.html#http_class_http_serverresponse). + +

Properties

+ +
+ {% include api/en/4x/res-app.md %} +
+ +
+ {% include api/en/4x/res-headersSent.md %} +
+ +
+ {% include api/en/4x/res-locals.md %} +
+ +

Methods

+ +
+ {% include api/en/4x/res-append.md %} +
+ +
+ {% include api/en/4x/res-attachment.md %} +
+ +
+ {% include api/en/4x/res-cookie.md %} +
+ +
+ {% include api/en/4x/res-clearCookie.md %} +
+ +
+ {% include api/en/4x/res-download.md %} +
+ +
+ {% include api/en/4x/res-end.md %} +
+ +
+ {% include api/en/4x/res-format.md %} +
+ +
+ {% include api/en/4x/res-get.md %} +
+ +
+ {% include api/en/4x/res-json.md %} +
+ +
+ {% include api/en/4x/res-jsonp.md %} +
+ +
+ {% include api/en/4x/res-links.md %} +
+ +
+ {% include api/en/4x/res-location.md %} +
+ +
+ {% include api/en/4x/res-redirect.md %} +
+ +
+ {% include api/en/4x/res-render.md %} +
+ +
+ {% include api/en/4x/res-req.md %} +
+ +
+ {% include api/en/4x/res-send.md %} +
+ +
+ {% include api/en/4x/res-sendFile.md %} +
+ +
+ {% include api/en/4x/res-sendStatus.md %} +
+ +
+ {% include api/en/4x/res-set.md %} +
+ +
+ {% include api/en/4x/res-status.md %} +
+ +
+ {% include api/en/4x/res-type.md %} +
+ +
+ {% include api/en/4x/res-vary.md %} +
diff --git a/astro/src/content/docs/en/4x/api/response/res-app.md b/astro/src/content/docs/en/4x/api/response/res-app.md new file mode 100644 index 0000000000..b853d54dd3 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/response/res-app.md @@ -0,0 +1,10 @@ +--- +title: res.app +description: This property holds a reference to the instance of the Express application that is using the middleware. +--- + +

res.app

+ +This property holds a reference to the instance of the Express application that is using the middleware. + +`res.app` is identical to the [req.app](#req.app) property in the request object. diff --git a/astro/src/content/docs/en/4x/api/response/res-append.md b/astro/src/content/docs/en/4x/api/response/res-append.md new file mode 100644 index 0000000000..ecbc596f1e --- /dev/null +++ b/astro/src/content/docs/en/4x/api/response/res-append.md @@ -0,0 +1,18 @@ +--- +title: res.append +description: Appends the specified value to the HTTP response header field +--- + +

res.append(field [, value])

+ +{% include admonitions/note.html content="`res.append()` is supported by Express v4.11.0+" %} +Appends the specified `value` to the HTTP response header `field`. If the header is not already set, +it creates the header with the specified value. The `value` parameter can be a string or an array. + +{% include admonitions/note.html content="calling `res.set()` after `res.append()` will reset the previously-set header value." %} + +```js +res.append('Link', ['', '']); +res.append('Set-Cookie', 'foo=bar; Path=/; HttpOnly'); +res.append('Warning', '199 Miscellaneous warning'); +``` diff --git a/astro/src/content/docs/en/4x/api/response/res-attachment.md b/astro/src/content/docs/en/4x/api/response/res-attachment.md new file mode 100644 index 0000000000..6d1eed1ff3 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/response/res-attachment.md @@ -0,0 +1,19 @@ +--- +title: res.attachment +description: Sets the HTTP response Content-Disposition header field to attachment. +--- + +

res.attachment([filename])

+ +Sets the HTTP response `Content-Disposition` header field to "attachment". If a `filename` is given, +then it sets the Content-Type based on the extension name via `res.type()`, +and sets the `Content-Disposition` "filename=" parameter. + +```js +res.attachment(); +// Content-Disposition: attachment + +res.attachment('path/to/logo.png'); +// Content-Disposition: attachment; filename="logo.png" +// Content-Type: image/png +``` diff --git a/astro/src/content/docs/en/4x/api/response/res-clearCookie.md b/astro/src/content/docs/en/4x/api/response/res-clearCookie.md new file mode 100644 index 0000000000..fbe206b2f7 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/response/res-clearCookie.md @@ -0,0 +1,27 @@ +--- +title: res.clearCookie +description: Clears the cookie with the specified name by sending a Set-Cookie header that sets its expiration date in the past. +--- + +

res.clearCookie(name [, options])

+ +Clears the cookie with the specified `name` by sending a `Set-Cookie` header that sets its expiration date in the past. +This instructs the client that the cookie has expired and is no longer valid. For more information +about available `options`, see [res.cookie()](#res.cookie). + +
+If the `maxAge` or `expires` options are set, the cookie may not be cleared depending on the time values provided, +as Express does not ignore these options. It is therefore recommended to omit these options when calling this +method. Passing these two options has been deprecated since Express v4.20.0. +
+ +
+Web browsers and other compliant clients will only clear the cookie if the given +`options` is identical to those given to [res.cookie()](#res.cookie), excluding +`expires` and `maxAge`. +
+ +```js +res.cookie('name', 'tobi', { path: '/admin' }); +res.clearCookie('name', { path: '/admin' }); +``` diff --git a/astro/src/content/docs/en/4x/api/response/res-cookie.md b/astro/src/content/docs/en/4x/api/response/res-cookie.md new file mode 100644 index 0000000000..340ef94962 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/response/res-cookie.md @@ -0,0 +1,95 @@ +--- +title: res.cookie +description: Sets cookie name to value. The value parameter may be a string or object converted to JSON. +--- + +

res.cookie(name, value [, options])

+ +Sets cookie `name` to `value`. The `value` parameter may be a string or object converted to JSON. + +The `options` parameter is an object that can have the following properties. + +
+ +| Property | Type | Description | +| ------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `domain` | String | Domain name for the cookie. Defaults to the domain name of the app. | +| `encode` | Function | A synchronous function used for cookie value encoding. Defaults to `encodeURIComponent`. | +| `expires` | Date | Expiry date of the cookie in GMT. If not specified or set to 0, creates a session cookie. | +| `httpOnly` | Boolean | Flags the cookie to be accessible only by the web server. | +| `maxAge` | Number | Convenient option for setting the expiry time relative to the current time in milliseconds. | +| `path` | String | Path for the cookie. Defaults to "/". | +| `partitioned` | Boolean | Indicates that the cookie should be stored using partitioned storage. See [Cookies Having Independent Partitioned State (CHIPS)](https://developer.mozilla.org/en-US/docs/Web/Privacy/Partitioned_cookies) for more details. | +| `priority` | String | Value of the "Priority" **Set-Cookie** attribute. | +| `secure` | Boolean | Marks the cookie to be used with HTTPS only. | +| `signed` | Boolean | Indicates if the cookie should be signed. | +| `sameSite` | Boolean or String | Value of the "SameSite" **Set-Cookie** attribute. More information at [https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00#section-4.1.1](https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00#section-4.1.1). | + +
+ +
+All `res.cookie()` does is set the HTTP `Set-Cookie` header with the options provided. +Any option not specified defaults to the value stated in [RFC 6265](http://tools.ietf.org/html/rfc6265). +
+ +For example: + +```js +res.cookie('name', 'tobi', { domain: '.example.com', path: '/admin', secure: true }); +res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true }); +``` + +You can set multiple cookies in a single response by calling `res.cookie` multiple times, for example: + +```js +res + .status(201) + .cookie('access_token', 'Bearer ' + token, { + expires: new Date(Date.now() + 8 * 3600000), // cookie will be removed after 8 hours + }) + .cookie('test', 'test') + .redirect(301, '/admin'); +``` + +The `encode` option allows you to choose the function used for cookie value encoding. +Does not support asynchronous functions. + +Example use case: You need to set a domain-wide cookie for another site in your organization. +This other site (not under your administrative control) does not use URI-encoded cookie values. + +```js +// Default encoding +res.cookie('some_cross_domain_cookie', 'http://mysubdomain.example.com', { domain: 'example.com' }); +// Result: 'some_cross_domain_cookie=http%3A%2F%2Fmysubdomain.example.com; Domain=example.com; Path=/' + +// Custom encoding +res.cookie('some_cross_domain_cookie', 'http://mysubdomain.example.com', { + domain: 'example.com', + encode: String, +}); +// Result: 'some_cross_domain_cookie=http://mysubdomain.example.com; Domain=example.com; Path=/;' +``` + +The `maxAge` option is a convenience option for setting "expires" relative to the current time in milliseconds. +The following is equivalent to the second example above. + +```js +res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true }); +``` + +You can pass an object as the `value` parameter; it is then serialized as JSON and parsed by `bodyParser()` middleware. + +```js +res.cookie('cart', { items: [1, 2, 3] }); +res.cookie('cart', { items: [1, 2, 3] }, { maxAge: 900000 }); +``` + +When using [cookie-parser](https://www.npmjs.com/package/cookie-parser) middleware, this method also +supports signed cookies. Simply include the `signed` option set to `true`. +Then `res.cookie()` will use the secret passed to `cookieParser(secret)` to sign the value. + +```js +res.cookie('name', 'tobi', { signed: true }); +``` + +Later you may access this value through the [req.signedCookie](#req.signedCookies) object. diff --git a/astro/src/content/docs/en/4x/api/response/res-download.md b/astro/src/content/docs/en/4x/api/response/res-download.md new file mode 100644 index 0000000000..08b6f43cd6 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/response/res-download.md @@ -0,0 +1,62 @@ +--- +title: res.download +description: Transfers the file at path as an attachment. Typically, browsers will prompt the user for download. +--- + +

res.download(path [, filename] [, options] [, fn])

+ +Transfers the file at `path` as an "attachment". Typically, browsers will prompt the user for download. +By default, the `Content-Disposition` header "filename=" parameter is derived from the `path` argument, but can be overridden with the `filename` parameter. +If `path` is relative, then it will be based on the current working directory of the process or +the `root` option, if provided. + +
+This API provides access to data on the running file system. Ensure that either (a) the way in +which the `path` argument was constructed is secure if it contains user input or (b) set the `root` +option to the absolute path of a directory to contain access within. + +When the `root` option is provided, Express will validate that the relative path provided as +`path` will resolve within the given `root` option. + +
+ +The following table provides details on the `options` parameter. + +
+The optional `options` argument is supported by Express v4.16.0 onwards. +
+ +
+ +| Property | Description | Default | Availability | +| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------ | +| `maxAge` | Sets the max-age property of the `Cache-Control` header in milliseconds or a string in [ms format](https://www.npmjs.org/package/ms) | 0 | 4.16+ | +| `root` | Root directory for relative filenames. | | 4.18+ | +| `lastModified` | Sets the `Last-Modified` header to the last modified date of the file on the OS. Set `false` to disable it. | Enabled | 4.16+ | +| `headers` | Object containing HTTP headers to serve with the file. The header `Content-Disposition` will be overridden by the `filename` argument. | | 4.16+ | +| `dotfiles` | Option for serving dotfiles. Possible values are "allow", "deny", "ignore". | "ignore" | 4.16+ | +| `acceptRanges` | Enable or disable accepting ranged requests. | `true` | 4.16+ | +| `cacheControl` | Enable or disable setting `Cache-Control` response header. | `true` | 4.16+ | +| `immutable` | Enable or disable the `immutable` directive in the `Cache-Control` response header. If enabled, the `maxAge` option should also be specified to enable caching. The `immutable` directive will prevent supported clients from making conditional requests during the life of the `maxAge` option to check if the file has changed. | `false` | 4.16+ | + +
+ +The method invokes the callback function `fn(err)` when the transfer is complete +or when an error occurs. If the callback function is specified and an error occurs, +the callback function must explicitly handle the response process either by +ending the request-response cycle, or by passing control to the next route. + +```js +res.download('/report-12345.pdf'); + +res.download('/report-12345.pdf', 'report.pdf'); + +res.download('/report-12345.pdf', 'report.pdf', function (err) { + if (err) { + // Handle error, but keep in mind the response may be partially-sent + // so check res.headersSent + } else { + // decrement a download credit, etc. + } +}); +``` diff --git a/astro/src/content/docs/en/4x/api/response/res-end.md b/astro/src/content/docs/en/4x/api/response/res-end.md new file mode 100644 index 0000000000..1d59764120 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/response/res-end.md @@ -0,0 +1,15 @@ +--- +title: res.end +description: Ends the response process. This method actually comes from Node core, specifically the response.end method of http.ServerResponse. +--- + +

res.end([data[, encoding]][, callback])

+ +Ends the response process. This method actually comes from Node core, specifically the [response.end() method of http.ServerResponse](https://nodejs.org/api/http.html#responseenddata-encoding-callback). + +Use to quickly end the response without any data. If you need to respond with data, instead use methods such as [res.send()](#res.send) and [res.json()](#res.json). + +```js +res.end(); +res.status(404).end(); +``` diff --git a/astro/src/content/docs/en/4x/api/response/res-format.md b/astro/src/content/docs/en/4x/api/response/res-format.md new file mode 100644 index 0000000000..570d6222dd --- /dev/null +++ b/astro/src/content/docs/en/4x/api/response/res-format.md @@ -0,0 +1,57 @@ +--- +title: res.format +description: Performs content-negotiation on the Accept HTTP header on the request object, when present. +--- + +

res.format(object)

+ +Performs content-negotiation on the `Accept` HTTP header on the request object, when present. +It uses [req.accepts()](#req.accepts) to select a handler for the request, based on the acceptable +types ordered by their quality values. If the header is not specified, the first callback is invoked. +When no match is found, the server responds with 406 "Not Acceptable", or invokes the `default` callback. + +The `Content-Type` response header is set when a callback is selected. However, you may alter +this within the callback using methods such as `res.set()` or `res.type()`. + +The following example would respond with `{ "message": "hey" }` when the `Accept` header field is set +to "application/json" or "\*/json" (however if it is "\*/\*", then the response will be "hey"). + +```js +res.format({ + 'text/plain': function () { + res.send('hey'); + }, + + 'text/html': function () { + res.send('

hey

'); + }, + + 'application/json': function () { + res.send({ message: 'hey' }); + }, + + default: function () { + // log the request and respond with 406 + res.status(406).send('Not Acceptable'); + }, +}); +``` + +In addition to canonicalized MIME types, you may also use extension names mapped +to these types for a slightly less verbose implementation: + +```js +res.format({ + text: function () { + res.send('hey'); + }, + + html: function () { + res.send('

hey

'); + }, + + json: function () { + res.send({ message: 'hey' }); + }, +}); +``` diff --git a/astro/src/content/docs/en/4x/api/response/res-get.md b/astro/src/content/docs/en/4x/api/response/res-get.md new file mode 100644 index 0000000000..300dd9d1a9 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/response/res-get.md @@ -0,0 +1,14 @@ +--- +title: res.get +description: Returns the HTTP response header specified by field. +--- + +

res.get(field)

+ +Returns the HTTP response header specified by `field`. +The match is case-insensitive. + +```js +res.get('Content-Type'); +// => "text/plain" +``` diff --git a/astro/src/content/docs/en/4x/api/response/res-headersSent.md b/astro/src/content/docs/en/4x/api/response/res-headersSent.md new file mode 100644 index 0000000000..7eaca46914 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/response/res-headersSent.md @@ -0,0 +1,16 @@ +--- +title: res.headersSent +description: Boolean property that indicates if the app sent HTTP headers for the response. +--- + +

res.headersSent

+ +Boolean property that indicates if the app sent HTTP headers for the response. + +```js +app.get('/', function (req, res) { + console.dir(res.headersSent); // false + res.send('OK'); + console.dir(res.headersSent); // true +}); +``` diff --git a/astro/src/content/docs/en/4x/api/response/res-json.md b/astro/src/content/docs/en/4x/api/response/res-json.md new file mode 100644 index 0000000000..40d6c0c083 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/response/res-json.md @@ -0,0 +1,18 @@ +--- +title: res.json +description: Sends a JSON response. This method sends a response (with the correct content-type) that is the parameter converted to a +--- + +

res.json([body])

+ +Sends a JSON response. This method sends a response (with the correct content-type) that is the parameter converted to a +JSON string using [JSON.stringify()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify). + +The parameter can be any JSON type, including object, array, string, Boolean, number, or null, +and you can also use it to convert other values to JSON. + +```js +res.json(null); +res.json({ user: 'tobi' }); +res.status(500).json({ error: 'message' }); +``` diff --git a/astro/src/content/docs/en/4x/api/response/res-jsonp.md b/astro/src/content/docs/en/4x/api/response/res-jsonp.md new file mode 100644 index 0000000000..7dad964a15 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/response/res-jsonp.md @@ -0,0 +1,37 @@ +--- +title: res.jsonp +description: Sends a JSON response with JSONP support. This method is identical to res.json, +--- + +

res.jsonp([body])

+ +Sends a JSON response with JSONP support. This method is identical to `res.json()`, +except that it opts-in to JSONP callback support. + +```js +res.jsonp(null); +// => callback(null) + +res.jsonp({ user: 'tobi' }); +// => callback({ "user": "tobi" }) + +res.status(500).jsonp({ error: 'message' }); +// => callback({ "error": "message" }) +``` + +By default, the JSONP callback name is simply `callback`. Override this with the +jsonp callback name setting. + +The following are some examples of JSONP responses using the same code: + +```js +// ?callback=foo +res.jsonp({ user: 'tobi' }); +// => foo({ "user": "tobi" }) + +app.set('jsonp callback name', 'cb'); + +// ?cb=foo +res.status(500).jsonp({ error: 'message' }); +// => foo({ "error": "message" }) +``` diff --git a/astro/src/content/docs/en/4x/api/response/res-links.md b/astro/src/content/docs/en/4x/api/response/res-links.md new file mode 100644 index 0000000000..a3c2b12004 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/response/res-links.md @@ -0,0 +1,25 @@ +--- +title: res.links +description: Joins the links provided as properties of the parameter to populate the response Link HTTP header field. +--- + + + +Joins the `links` provided as properties of the parameter to populate the response's +`Link` HTTP header field. + +For example, the following call: + +```js +res.links({ + next: 'http://api.example.com/users?page=2', + last: 'http://api.example.com/users?page=5', +}); +``` + +Yields the following results: + +``` +Link: ; rel="next", + ; rel="last" +``` diff --git a/astro/src/content/docs/en/4x/api/response/res-locals.md b/astro/src/content/docs/en/4x/api/response/res-locals.md new file mode 100644 index 0000000000..b15e2558c9 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/response/res-locals.md @@ -0,0 +1,33 @@ +--- +title: res.locals +description: Use this property to set variables accessible in templates rendered with [res.render](#res.render). +--- + +

res.locals

+ +Use this property to set variables accessible in templates rendered with [res.render](#res.render). +The variables set on `res.locals` are available within a single request-response cycle, and will not +be shared between requests. + +
+The `locals` object is used by view engines to render a response. The object +keys may be particularly sensitive and should not contain user-controlled +input, as it may affect the operation of the view engine or provide a path to +cross-site scripting. Consult the documentation for the used view engine for +additional considerations. +
+ +In order to keep local variables for use in template rendering between requests, use +[app.locals](#app.locals) instead. + +This property is useful for exposing request-level information such as the request path name, +authenticated user, user settings, and so on to templates rendered within the application. + +```js +app.use(function (req, res, next) { + // Make `user` and `authenticated` available in templates + res.locals.user = req.user; + res.locals.authenticated = !req.user.anonymous; + next(); +}); +``` diff --git a/astro/src/content/docs/en/4x/api/response/res-location.md b/astro/src/content/docs/en/4x/api/response/res-location.md new file mode 100644 index 0000000000..5211174c2e --- /dev/null +++ b/astro/src/content/docs/en/4x/api/response/res-location.md @@ -0,0 +1,30 @@ +--- +title: res.location +description: Sets the response Location HTTP header to the specified path parameter. +--- + +

res.location(path)

+ +Sets the response `Location` HTTP header to the specified `path` parameter. + +```js +res.location('/foo/bar'); +res.location('http://example.com'); +res.location('back'); +``` + +{% include admonitions/note.html content="`'back'` was deprecated in 4.21.0, use `req.get('Referrer') || '/'` as an argument instead." %} + +A `path` value of "back" has a special meaning, it refers to the URL specified in the `Referer` header of the request. If the `Referer` header was not specified, it refers to "/". + +See also [Security best practices: Prevent open redirect +vulnerabilities](http://expressjs.com/en/advanced/best-practice-security.html#prevent-open-redirects). + +
+After encoding the URL, if not encoded already, Express passes the specified URL to the browser in the `Location` header, +without any validation. + +Browsers take the responsibility of deriving the intended URL from the current URL +or the referring URL, and the URL specified in the `Location` header; and redirect the user accordingly. + +
diff --git a/astro/src/content/docs/en/4x/api/response/res-redirect.md b/astro/src/content/docs/en/4x/api/response/res-redirect.md new file mode 100644 index 0000000000..7271794017 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/response/res-redirect.md @@ -0,0 +1,65 @@ +--- +title: res.redirect +description: Redirects to the URL derived from the specified path, with specified status, a positive integer +--- + +

res.redirect([status,] path)

+ +Redirects to the URL derived from the specified `path`, with specified `status`, a positive integer +that corresponds to an [HTTP status code](https://www.rfc-editor.org/rfc/rfc9110.html#name-status-codes) . +If not specified, `status` defaults to "302 "Found". + +```js +res.redirect('/foo/bar'); +res.redirect('http://example.com'); +res.redirect(301, 'http://example.com'); +res.redirect('../login'); +``` + +Redirects can be a fully-qualified URL for redirecting to a different site: + +```js +res.redirect('http://google.com'); +``` + +Redirects can be relative to the root of the host name. For example, if the +application is on `http://example.com/admin/post/new`, the following +would redirect to the URL `http://example.com/admin`: + +```js +res.redirect('/admin'); +``` + +Redirects can be relative to the current URL. For example, +from `http://example.com/blog/admin/` (notice the trailing slash), the following +would redirect to the URL `http://example.com/blog/admin/post/new`. + +```js +res.redirect('post/new'); +``` + +Redirecting to `post/new` from `http://example.com/blog/admin` (no trailing slash), +will redirect to `http://example.com/blog/post/new`. + +If you found the above behavior confusing, think of path segments as directories +(with trailing slashes) and files, it will start to make sense. + +Path-relative redirects are also possible. If you were on +`http://example.com/admin/post/new`, the following would redirect to +`http://example.com/admin/post`: + +```js +res.redirect('..'); +``` + +A `back` redirection redirects the request back to the [referer](http://en.wikipedia.org/wiki/HTTP_referer), +defaulting to `/` when the referer is missing. + +```js +res.redirect('back'); +``` + +{% include admonitions/note.html content="`back` redirect was deprecated in 4.21.0, use `req.get('Referrer') || '/'` as an argument instead." %} + +See also [Security best practices: Prevent open redirect +vulnerabilities](http://expressjs.com/en/advanced/best-practice-security.html#prevent-open-redirects). diff --git a/astro/src/content/docs/en/4x/api/response/res-render.md b/astro/src/content/docs/en/4x/api/response/res-render.md new file mode 100644 index 0000000000..0fe6e14cc6 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/response/res-render.md @@ -0,0 +1,50 @@ +--- +title: res.render +description: Renders a view and sends the rendered HTML string to the client. +--- + +

res.render(view [, locals] [, callback])

+ +Renders a `view` and sends the rendered HTML string to the client. +Optional parameters: + +- `locals`, an object whose properties define local variables for the view. +- `callback`, a callback function. If provided, the method returns both the possible error and rendered string, but does not perform an automated response. When an error occurs, the method invokes `next(err)` internally. + +The `view` argument is a string that is the file path of the view file to render. This can be an absolute path, or a path relative to the `views` setting. If the path does not contain a file extension, then the `view engine` setting determines the file extension. If the path does contain a file extension, then Express will load the module for the specified template engine (via `require()`) and render it using the loaded module's `__express` function. + +For more information, see [Using template engines with Express](/{{page.lang}}/guide/using-template-engines.html). + +
+The `view` argument performs file system operations like reading a file from +disk and evaluating Node.js modules, and as so for security reasons should not +contain input from the end-user. +
+ +
+The `locals` object is used by view engines to render a response. The object +keys may be particularly sensitive and should not contain user-controlled +input, as it may affect the operation of the view engine or provide a path to +cross-site scripting. Consult the documentation for the used view engine for +additional considerations. +
+ +
+The local variable `cache` enables view caching. Set it to `true`, +to cache the view during development; view caching is enabled in production by default. +
+ +```js +// send the rendered view to the client +res.render('index'); + +// if a callback is specified, the rendered HTML string has to be sent explicitly +res.render('index', function (err, html) { + res.send(html); +}); + +// pass a local variable to the view +res.render('user', { name: 'Tobi' }, function (err, html) { + // ... +}); +``` diff --git a/astro/src/content/docs/en/4x/api/response/res-req.md b/astro/src/content/docs/en/4x/api/response/res-req.md new file mode 100644 index 0000000000..f20548a045 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/response/res-req.md @@ -0,0 +1,9 @@ +--- +title: res.req +description: This property holds a reference to the +--- + +

res.req

+ +This property holds a reference to the request object +that relates to this response object. diff --git a/astro/src/content/docs/en/4x/api/response/res-send.md b/astro/src/content/docs/en/4x/api/response/res-send.md new file mode 100644 index 0000000000..c7fc23dff6 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/response/res-send.md @@ -0,0 +1,44 @@ +--- +title: res.send +description: Sends the HTTP response. +--- + +

res.send([body])

+ +Sends the HTTP response. + +The `body` parameter can be a `Buffer` object, a `String`, an object, `Boolean`, or an `Array`. +For example: + +```js +res.send(Buffer.from('whoop')); +res.send({ some: 'json' }); +res.send('

some html

'); +res.status(404).send('Sorry, we cannot find that!'); +res.status(500).send({ error: 'something blew up' }); +``` + +This method performs many useful tasks for simple non-streaming responses: +For example, it automatically assigns the `Content-Length` HTTP response header field +(unless previously defined) and provides automatic HEAD and HTTP cache freshness support. + +When the parameter is a `Buffer` object, the method sets the `Content-Type` +response header field to "application/octet-stream", unless previously defined as shown below: + +```js +res.set('Content-Type', 'text/html'); +res.send(Buffer.from('

some html

')); +``` + +When the parameter is a `String`, the method sets the `Content-Type` to "text/html": + +```js +res.send('

some html

'); +``` + +When the parameter is an `Array` or `Object`, Express responds with the JSON representation: + +```js +res.send({ user: 'tobi' }); +res.send([1, 2, 3]); +``` diff --git a/astro/src/content/docs/en/4x/api/response/res-sendFile.md b/astro/src/content/docs/en/4x/api/response/res-sendFile.md new file mode 100644 index 0000000000..65c5ca3627 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/response/res-sendFile.md @@ -0,0 +1,91 @@ +--- +title: res.sendFile +description: Transfers the file at the given path. Sets the Content-Type response HTTP header field based on the filename extension +--- + +

res.sendFile(path [, options] [, fn])

+ +
+`res.sendFile()` is supported by Express v4.8.0 onwards. +
+ +Transfers the file at the given `path`. Sets the `Content-Type` response HTTP header field +based on the filename's extension. Unless the `root` option is set in +the options object, `path` must be an absolute path to the file. + +
+This API provides access to data on the running file system. Ensure that either (a) the way in +which the `path` argument was constructed into an absolute path is secure if it contains user +input or (b) set the `root` option to the absolute path of a directory to contain access within. + +When the `root` option is provided, the `path` argument is allowed to be a relative path, +including containing `..`. Express will validate that the relative path provided as `path` will +resolve within the given `root` option. + +
+ +The following table provides details on the `options` parameter. + +
+ +| Property | Description | Default | Availability | +| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------ | +| `maxAge` | Sets the max-age property of the `Cache-Control` header in milliseconds or a string in [ms format](https://www.npmjs.org/package/ms) | 0 | | +| `root` | Root directory for relative filenames. | | | +| `lastModified` | Sets the `Last-Modified` header to the last modified date of the file on the OS. Set `false` to disable it. | Enabled | 4.9.0+ | +| `headers` | Object containing HTTP headers to serve with the file. | | | +| `dotfiles` | Option for serving dotfiles. Possible values are "allow", "deny", "ignore". | "ignore" |   | +| `acceptRanges` | Enable or disable accepting ranged requests. | `true` | 4.14+ | +| `cacheControl` | Enable or disable setting `Cache-Control` response header. | `true` | 4.14+ | +| `immutable` | Enable or disable the `immutable` directive in the `Cache-Control` response header. If enabled, the `maxAge` option should also be specified to enable caching. The `immutable` directive will prevent supported clients from making conditional requests during the life of the `maxAge` option to check if the file has changed. | `false` | 4.16+ | + +
+ +The method invokes the callback function `fn(err)` when the transfer is complete +or when an error occurs. If the callback function is specified and an error occurs, +the callback function must explicitly handle the response process either by +ending the request-response cycle, or by passing control to the next route. + +Here is an example of using `res.sendFile` with all its arguments. + +```js +app.get('/file/:name', function (req, res, next) { + var options = { + root: path.join(__dirname, 'public'), + dotfiles: 'deny', + headers: { + 'x-timestamp': Date.now(), + 'x-sent': true, + }, + }; + + var fileName = req.params.name; + res.sendFile(fileName, options, function (err) { + if (err) { + next(err); + } else { + console.log('Sent:', fileName); + } + }); +}); +``` + +The following example illustrates using +`res.sendFile` to provide fine-grained support for serving files: + +```js +app.get('/user/:uid/photos/:file', function (req, res) { + var uid = req.params.uid; + var file = req.params.file; + + req.user.mayViewFilesFrom(uid, function (yes) { + if (yes) { + res.sendFile('/uploads/' + uid + '/' + file); + } else { + res.status(403).send("Sorry! You can't see that."); + } + }); +}); +``` + +For more information, or if you have issues or concerns, see [send](https://github.com/pillarjs/send). diff --git a/astro/src/content/docs/en/4x/api/response/res-sendStatus.md b/astro/src/content/docs/en/4x/api/response/res-sendStatus.md new file mode 100644 index 0000000000..eef217cd82 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/response/res-sendStatus.md @@ -0,0 +1,20 @@ +--- +title: res.sendStatus +description: Sets the response HTTP status code to statusCode and sends the registered status message as the text response body. If an unknown status code is specified, the response body will be just the code number. +--- + +

res.sendStatus(statusCode)

+ +Sets the response HTTP status code to `statusCode` and sends the registered status message as the text response body. If an unknown status code is specified, the response body will just be the code number. + +```js +res.sendStatus(404); +``` + +
+Some versions of Node.js will throw when `res.statusCode` is set to an +invalid HTTP status code (outside of the range `100` to `599`). Consult +the HTTP server documentation for the Node.js version being used. +
+ +[More about HTTP Status Codes](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes) diff --git a/astro/src/content/docs/en/4x/api/response/res-set.md b/astro/src/content/docs/en/4x/api/response/res-set.md new file mode 100644 index 0000000000..6d2b01e63e --- /dev/null +++ b/astro/src/content/docs/en/4x/api/response/res-set.md @@ -0,0 +1,21 @@ +--- +title: res.set +description: Sets the response HTTP header field to value. +--- + +

res.set(field [, value])

+ +Sets the response's HTTP header `field` to `value`. +To set multiple fields at once, pass an object as the parameter. + +```js +res.set('Content-Type', 'text/plain'); + +res.set({ + 'Content-Type': 'text/plain', + 'Content-Length': '123', + ETag: '12345', +}); +``` + +Aliased as `res.header(field [, value])`. diff --git a/astro/src/content/docs/en/4x/api/response/res-status.md b/astro/src/content/docs/en/4x/api/response/res-status.md new file mode 100644 index 0000000000..4969cd4ff9 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/response/res-status.md @@ -0,0 +1,15 @@ +--- +title: res.status +description: Sets the HTTP status for the response. +--- + +

res.status(code)

+ +Sets the HTTP status for the response. +It is a chainable alias of Node's [response.statusCode](http://nodejs.org/api/http.html#http_response_statuscode). + +```js +res.status(403).end(); +res.status(400).send('Bad Request'); +res.status(404).sendFile('/absolute/path/to/404.png'); +``` diff --git a/astro/src/content/docs/en/4x/api/response/res-type.md b/astro/src/content/docs/en/4x/api/response/res-type.md new file mode 100644 index 0000000000..615ffb3c6a --- /dev/null +++ b/astro/src/content/docs/en/4x/api/response/res-type.md @@ -0,0 +1,23 @@ +--- +title: res.type +description: Sets the Content-Type HTTP header to the MIME type as determined by the specified type. If type contains the slash character, then it sets the Content-Type to the exact value. +--- + +

res.type(type)

+ +Sets the `Content-Type` HTTP header to the MIME type as determined by the specified `type`. If `type` contains the "/" character, then it sets the `Content-Type` to the exact value of `type`, otherwise it is assumed to be a file extension and the MIME type is looked up in a mapping using the `express.static.mime.lookup()` method. + +```js +res.type('.html'); +// => 'text/html' +res.type('html'); +// => 'text/html' +res.type('json'); +// => 'application/json' +res.type('application/json'); +// => 'application/json' +res.type('png'); +// => 'image/png' +``` + +Aliased as `res.contentType(type)`. diff --git a/astro/src/content/docs/en/4x/api/response/res-vary.md b/astro/src/content/docs/en/4x/api/response/res-vary.md new file mode 100644 index 0000000000..164bed9285 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/response/res-vary.md @@ -0,0 +1,12 @@ +--- +title: res.vary +description: Adds the field to the Vary response header, if it is not there already. +--- + +

res.vary(field)

+ +Adds the field to the `Vary` response header, if it is not there already. + +```js +res.vary('User-Agent').render('docs'); +``` diff --git a/astro/src/content/docs/en/4x/api/router/overview.md b/astro/src/content/docs/en/4x/api/router/overview.md new file mode 100644 index 0000000000..9d1ec07241 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/router/overview.md @@ -0,0 +1,66 @@ +--- +title: Methods +description: section markdown="1"> +--- + +

Router

+ +
+A `router` object is an instance of middleware and routes. You can think of it +as a "mini-application," capable only of performing middleware and routing +functions. Every Express application has a built-in app router. + +A router behaves like middleware itself, so you can use it as an argument to +[app.use()](#app.use) or as the argument to another router's [use()](#router.use) method. + +The top-level `express` object has a [Router()](#express.router) method that creates a new `router` object. + +Once you've created a router object, you can add middleware and HTTP method routes (such as `get`, `put`, `post`, +and so on) to it just like an application. For example: + +```js +// invoked for any requests passed to this router +router.use(function (req, res, next) { + // .. some logic here .. like any other middleware + next(); +}); + +// will handle any request that ends in /events +// depends on where the router is "use()'d" +router.get('/events', function (req, res, next) { + // .. +}); +``` + +You can then use a router for a particular root URL in this way separating your routes into files or even mini-apps. + +```js +// only requests to /calendar/* will be sent to our "router" +app.use('/calendar', router); +``` + +Keep in mind that any middleware applied to a router will run for all requests on that router's path, even those that aren't part of the router. + +
+ +

Methods

+ +
+ {% include api/en/4x/router-all.md %} +
+ +
+ {% include api/en/4x/router-METHOD.md %} +
+ +
+ {% include api/en/4x/router-param.md %} +
+ +
+ {% include api/en/4x/router-route.md %} +
+ +
+ {% include api/en/4x/router-use.md %} +
diff --git a/astro/src/content/docs/en/4x/api/router/router-METHOD.md b/astro/src/content/docs/en/4x/api/router/router-METHOD.md new file mode 100644 index 0000000000..2c6ea555f4 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/router/router-METHOD.md @@ -0,0 +1,47 @@ +--- +title: router.METHOD +description: The router.METHOD methods provide the routing functionality in Express, +--- + +

router.METHOD(path, [callback, ...] callback)

+ +The `router.METHOD()` methods provide the routing functionality in Express, +where METHOD is one of the HTTP methods, such as GET, PUT, POST, and so on, +in lowercase. Thus, the actual methods are `router.get()`, `router.post()`, +`router.put()`, and so on. + +
+ The `router.get()` function is automatically called for the HTTP `HEAD` method in + addition to the `GET` method if `router.head()` was not called for the + path before `router.get()`. +
+ +You can provide multiple callbacks, and all are treated equally, and behave just +like middleware, except that these callbacks may invoke `next('route')` +to bypass the remaining route callback(s). You can use this mechanism to perform +pre-conditions on a route then pass control to subsequent routes when there is no +reason to proceed with the route matched. + +The following snippet illustrates the most simple route definition possible. +Express translates the path strings to regular expressions, used internally +to match incoming requests. Query strings are _not_ considered when performing +these matches, for example "GET /" would match the following route, as would +"GET /?name=tobi". + +```js +router.get('/', function (req, res) { + res.send('hello world'); +}); +``` + +You can also use regular expressions—useful if you have very specific +constraints, for example the following would match "GET /commits/71dbb9c" as well +as "GET /commits/71dbb9c..4c084f9". + +```js +router.get(/^\/commits\/(\w+)(?:\.\.(\w+))?$/, function (req, res) { + var from = req.params[0]; + var to = req.params[1] || 'HEAD'; + res.send('commit range ' + from + '..' + to); +}); +``` diff --git a/astro/src/content/docs/en/4x/api/router/router-Router.md b/astro/src/content/docs/en/4x/api/router/router-Router.md new file mode 100644 index 0000000000..de2867f15c --- /dev/null +++ b/astro/src/content/docs/en/4x/api/router/router-Router.md @@ -0,0 +1,5 @@ +--- +title: Router +--- + +

Router([options])

diff --git a/astro/src/content/docs/en/4x/api/router/router-all.md b/astro/src/content/docs/en/4x/api/router/router-all.md new file mode 100644 index 0000000000..cda8e9c21b --- /dev/null +++ b/astro/src/content/docs/en/4x/api/router/router-all.md @@ -0,0 +1,36 @@ +--- +title: router.all +description: This method is just like the router.METHOD methods, except that it matches all HTTP methods (verbs). +--- + +

router.all(path, [callback, ...] callback)

+ +This method is just like the `router.METHOD()` methods, except that it matches all HTTP methods (verbs). + +This method is extremely useful for +mapping "global" logic for specific path prefixes or arbitrary matches. +For example, if you placed the following route at the top of all other +route definitions, it would require that all routes from that point on +would require authentication, and automatically load a user. Keep in mind +that these callbacks do not have to act as end points; `loadUser` +can perform a task, then call `next()` to continue matching subsequent +routes. + +```js +router.all('*', requireAuthentication, loadUser); +``` + +Or the equivalent: + +```js +router.all('*', requireAuthentication); +router.all('*', loadUser); +``` + +Another example of this is white-listed "global" functionality. Here +the example is much like before, but it only restricts paths prefixed with +"/api": + +```js +router.all('/api/*', requireAuthentication); +``` diff --git a/astro/src/content/docs/en/4x/api/router/router-param.md b/astro/src/content/docs/en/4x/api/router/router-param.md new file mode 100644 index 0000000000..cb82308fb4 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/router/router-param.md @@ -0,0 +1,128 @@ +--- +title: router.param +description: Adds callback triggers to route parameters, where name is the name of the parameter and callback is the callback function. Although name is technically optional, it is required. +--- + +

router.param(name, callback)

+ +Adds callback triggers to route parameters, where `name` is the name of the parameter and `callback` is the callback function. Although `name` is technically optional, using this method without it is deprecated starting with Express v4.11.0 (see below). + +The parameters of the callback function are: + +- `req`, the request object. +- `res`, the response object. +- `next`, indicating the next middleware function. +- The value of the `name` parameter. +- The name of the parameter. + +
+Unlike `app.param()`, `router.param()` does not accept an array of route parameters. +
+ +For example, when `:user` is present in a route path, you may map user loading logic to automatically provide `req.user` to the route, or perform validations on the parameter input. + +```js +router.param('user', function (req, res, next, id) { + // try to get the user details from the User model and attach it to the request object + User.find(id, function (err, user) { + if (err) { + next(err); + } else if (user) { + req.user = user; + next(); + } else { + next(new Error('failed to load user')); + } + }); +}); +``` + +Param callback functions are local to the router on which they are defined. They are not inherited by mounted apps or routers, nor are they triggered for route parameters inherited from parent routers. Hence, param callbacks defined on `router` will be triggered only by route parameters defined on `router` routes. + +A param callback will be called only once in a request-response cycle, even if the parameter is matched in multiple routes, as shown in the following examples. + +```js +router.param('id', function (req, res, next, id) { + console.log('CALLED ONLY ONCE'); + next(); +}); + +router.get('/user/:id', function (req, res, next) { + console.log('although this matches'); + next(); +}); + +router.get('/user/:id', function (req, res) { + console.log('and this matches too'); + res.end(); +}); +``` + +On `GET /user/42`, the following is printed: + +``` +CALLED ONLY ONCE +although this matches +and this matches too +``` + +
+The following section describes `router.param(callback)`, which is deprecated as of v4.11.0. +
+ +The behavior of the `router.param(name, callback)` method can be altered entirely by passing only a function to `router.param()`. This function is a custom implementation of how `router.param(name, callback)` should behave - it accepts two parameters and must return a middleware. + +The first parameter of this function is the name of the URL parameter that should be captured, the second parameter can be any JavaScript object which might be used for returning the middleware implementation. + +The middleware returned by the function decides the behavior of what happens when a URL parameter is captured. + +In this example, the `router.param(name, callback)` signature is modified to `router.param(name, accessId)`. Instead of accepting a name and a callback, `router.param()` will now accept a name and a number. + +```js +var express = require('express'); +var app = express(); +var router = express.Router(); + +// customizing the behavior of router.param() +router.param(function (param, option) { + return function (req, res, next, val) { + if (val === option) { + next(); + } else { + res.sendStatus(403); + } + }; +}); + +// using the customized router.param() +router.param('id', '1337'); + +// route to trigger the capture +router.get('/user/:id', function (req, res) { + res.send('OK'); +}); + +app.use(router); + +app.listen(3000, function () { + console.log('Ready'); +}); +``` + +In this example, the `router.param(name, callback)` signature remains the same, but instead of a middleware callback, a custom data type checking function has been defined to validate the data type of the user id. + +```js +router.param(function (param, validator) { + return function (req, res, next, val) { + if (validator(val)) { + next(); + } else { + res.sendStatus(403); + } + }; +}); + +router.param('id', function (candidate) { + return !isNaN(parseFloat(candidate)) && isFinite(candidate); +}); +``` diff --git a/astro/src/content/docs/en/4x/api/router/router-route.md b/astro/src/content/docs/en/4x/api/router/router-route.md new file mode 100644 index 0000000000..89dd15bbcb --- /dev/null +++ b/astro/src/content/docs/en/4x/api/router/router-route.md @@ -0,0 +1,54 @@ +--- +title: router.route +description: Returns an instance of a single route which you can then use to handle HTTP verbs +--- + +

router.route(path)

+ +Returns an instance of a single route which you can then use to handle HTTP verbs +with optional middleware. Use `router.route()` to avoid duplicate route naming and +thus typing errors. + +Building on the `router.param()` example above, the following code shows how to use +`router.route()` to specify various HTTP method handlers. + +```js +var router = express.Router(); + +router.param('user_id', function (req, res, next, id) { + // sample user, would actually fetch from DB, etc... + req.user = { + id: id, + name: 'TJ', + }; + next(); +}); + +router + .route('/users/:user_id') + .all(function (req, res, next) { + // runs for all HTTP verbs first + // think of it as route specific middleware! + next(); + }) + .get(function (req, res, next) { + res.json(req.user); + }) + .put(function (req, res, next) { + // just an example of maybe updating the user + req.user.name = req.params.name; + // save user ... etc + res.json(req.user); + }) + .post(function (req, res, next) { + next(new Error('not implemented')); + }) + .delete(function (req, res, next) { + next(new Error('not implemented')); + }); +``` + +This approach re-uses the single `/users/:user_id` path and adds handlers for +various HTTP methods. + +{% include admonitions/note.html content="When you use `router.route()`, middleware ordering is based on when the _route_ is created, not when method handlers are added to the route. For this purpose, you can consider method handlers to belong to the route to which they were added." %} diff --git a/astro/src/content/docs/en/4x/api/router/router-use.md b/astro/src/content/docs/en/4x/api/router/router-use.md new file mode 100644 index 0000000000..b6f3929a32 --- /dev/null +++ b/astro/src/content/docs/en/4x/api/router/router-use.md @@ -0,0 +1,112 @@ +--- +title: router.use +description: Uses the specified middleware function or functions, with optional mount path that defaults to slash. +--- + +

router.use([path], [function, ...] function)

+ +Uses the specified middleware function or functions, with optional mount path `path`, that defaults to "/". + +This method is similar to [app.use()](#app.use). A simple example and use case is described below. +See [app.use()](#app.use) for more information. + +Middleware is like a plumbing pipe: requests start at the first middleware function defined +and work their way "down" the middleware stack processing for each path they match. + +```js +var express = require('express'); +var app = express(); +var router = express.Router(); + +// simple logger for this router's requests +// all requests to this router will first hit this middleware +router.use(function (req, res, next) { + console.log('%s %s %s', req.method, req.url, req.path); + next(); +}); + +// this will only be invoked if the path starts with /bar from the mount point +router.use('/bar', function (req, res, next) { + // ... maybe some additional /bar logging ... + next(); +}); + +// always invoked +router.use(function (req, res, next) { + res.send('Hello World'); +}); + +app.use('/foo', router); + +app.listen(3000); +``` + +The "mount" path is stripped and is _not_ visible to the middleware function. +The main effect of this feature is that a mounted middleware function may operate without +code changes regardless of its "prefix" pathname. + +The order in which you define middleware with `router.use()` is very important. +They are invoked sequentially, thus the order defines middleware precedence. For example, +usually a logger is the very first middleware you would use, so that every request gets logged. + +```js +var logger = require('morgan'); +var path = require('path'); + +router.use(logger()); +router.use(express.static(path.join(__dirname, 'public'))); +router.use(function (req, res) { + res.send('Hello'); +}); +``` + +Now suppose you wanted to ignore logging requests for static files, but to continue +logging routes and middleware defined after `logger()`. You would simply move the call to `express.static()` to the top, +before adding the logger middleware: + +```js +router.use(express.static(path.join(__dirname, 'public'))); +router.use(logger()); +router.use(function (req, res) { + res.send('Hello'); +}); +``` + +Another example is serving files from multiple directories, +giving precedence to "./public" over the others: + +```js +router.use(express.static(path.join(__dirname, 'public'))); +router.use(express.static(path.join(__dirname, 'files'))); +router.use(express.static(path.join(__dirname, 'uploads'))); +``` + +The `router.use()` method also supports named parameters so that your mount points +for other routers can benefit from preloading using named parameters. + +**NOTE**: Although these middleware functions are added via a particular router, _when_ +they run is defined by the path they are attached to (not the router). Therefore, +middleware added via one router may run for other routers if its routes +match. For example, this code shows two different routers mounted on the same path: + +```js +var authRouter = express.Router(); +var openRouter = express.Router(); + +authRouter.use(require('./authenticate').basic(usersdb)); + +authRouter.get('/:user_id/edit', function (req, res, next) { + // ... Edit user UI ... +}); +openRouter.get('/', function (req, res, next) { + // ... List users ... +}); +openRouter.get('/:user_id', function (req, res, next) { + // ... View user ... +}); + +app.use('/users', authRouter); +app.use('/users', openRouter); +``` + +Even though the authentication middleware was added via the `authRouter` it will run on the routes defined by the `openRouter` as well since both routers were mounted on `/users`. To avoid this behavior, use different paths for each router. diff --git a/astro/src/content/docs/en/4x/api/router/routing-args.html b/astro/src/content/docs/en/4x/api/router/routing-args.html new file mode 100644 index 0000000000..cbf0dd027a --- /dev/null +++ b/astro/src/content/docs/en/4x/api/router/routing-args.html @@ -0,0 +1,58 @@ +

Arguments

+ +
+ + + + + + + + + + + + + + + + + + + + +
ArgumentDescriptionDefault
path + The path for which the middleware function is invoked; can be any of: +
    +
  • A string representing a path.
  • +
  • A path pattern.
  • +
  • A regular expression pattern to match paths.
  • +
  • An array of combinations of any of the above.
  • +
+ For examples, see Path examples. +
'/' (root path)
callback + Callback functions; can be: +
    +
  • A middleware function.
  • +
  • A series of middleware functions (separated by commas).
  • +
  • An array of middleware functions.
  • +
  • A combination of all of the above.
  • +
+

+ You can provide multiple callback functions that behave just like middleware, except + that these callbacks can invoke next('route') to bypass the remaining route + callback(s). You can use this mechanism to impose pre-conditions on a route, then pass + control to subsequent routes if there is no reason to proceed with the current route. +

+

+ Since router and app implement the + middleware interface, you can use them as you would any other middleware function. +

+

+ For examples, see + Middleware callback function examples. +

+
None
+
diff --git a/astro/src/content/docs/en/guide/behind-proxies.md b/astro/src/content/docs/en/4x/guide/behind-proxies.md similarity index 99% rename from astro/src/content/docs/en/guide/behind-proxies.md rename to astro/src/content/docs/en/4x/guide/behind-proxies.md index bbd812a043..a9e4921603 100755 --- a/astro/src/content/docs/en/guide/behind-proxies.md +++ b/astro/src/content/docs/en/4x/guide/behind-proxies.md @@ -1,8 +1,6 @@ --- title: Express behind proxies description: Learn how to configure Express.js applications to work correctly behind reverse proxies, including using the trust proxy setting to handle client IP addresses. -menu: guide -order: 8 --- # Express behind proxies diff --git a/astro/src/content/docs/en/guide/database-integration.md b/astro/src/content/docs/en/4x/guide/database-integration.md similarity index 99% rename from astro/src/content/docs/en/guide/database-integration.md rename to astro/src/content/docs/en/4x/guide/database-integration.md index 3383a7eccc..3c653355ad 100644 --- a/astro/src/content/docs/en/guide/database-integration.md +++ b/astro/src/content/docs/en/4x/guide/database-integration.md @@ -1,8 +1,6 @@ --- title: Express database integration description: Discover how to integrate various databases with Express.js applications, including setup examples for MongoDB, MySQL, PostgreSQL, and more. -menu: guide -order: 11 --- # Database integration diff --git a/astro/src/content/docs/en/guide/debugging.md b/astro/src/content/docs/en/4x/guide/debugging.md similarity index 99% rename from astro/src/content/docs/en/guide/debugging.md rename to astro/src/content/docs/en/4x/guide/debugging.md index 27be4d5134..9aabe80876 100755 --- a/astro/src/content/docs/en/guide/debugging.md +++ b/astro/src/content/docs/en/4x/guide/debugging.md @@ -1,8 +1,6 @@ --- title: Debugging Express description: Learn how to enable and use debugging logs in Express.js applications by setting the DEBUG environment variable for enhanced troubleshooting. -menu: guide -order: 7 --- # Debugging Express diff --git a/astro/src/content/docs/en/guide/error-handling.md b/astro/src/content/docs/en/4x/guide/error-handling.md similarity index 99% rename from astro/src/content/docs/en/guide/error-handling.md rename to astro/src/content/docs/en/4x/guide/error-handling.md index 3d09588c9a..3c81881742 100755 --- a/astro/src/content/docs/en/guide/error-handling.md +++ b/astro/src/content/docs/en/4x/guide/error-handling.md @@ -1,8 +1,6 @@ --- title: Express error handling description: Understand how Express.js handles errors in synchronous and asynchronous code, and learn to implement custom error handling middleware for your applications. -menu: guide -order: 6 --- # Error Handling diff --git a/astro/src/content/docs/en/guide/migrating-4.md b/astro/src/content/docs/en/4x/guide/migrating-4.md similarity index 99% rename from astro/src/content/docs/en/guide/migrating-4.md rename to astro/src/content/docs/en/4x/guide/migrating-4.md index ba06664382..bc463dea44 100755 --- a/astro/src/content/docs/en/guide/migrating-4.md +++ b/astro/src/content/docs/en/4x/guide/migrating-4.md @@ -1,8 +1,6 @@ --- title: Migrating to Express 4 description: A guide to migrating your Express.js applications from version 3 to 4, covering changes in middleware, routing, and how to update your codebase effectively. -menu: guide -order: 9 --- # Moving to Express 4 diff --git a/astro/src/content/docs/en/guide/migrating-5.md b/astro/src/content/docs/en/4x/guide/migrating-5.md similarity index 99% rename from astro/src/content/docs/en/guide/migrating-5.md rename to astro/src/content/docs/en/4x/guide/migrating-5.md index 95a1576fe3..3d959ed7dd 100755 --- a/astro/src/content/docs/en/guide/migrating-5.md +++ b/astro/src/content/docs/en/4x/guide/migrating-5.md @@ -1,8 +1,6 @@ --- title: Migrating to Express 5 description: A comprehensive guide to migrating your Express.js applications from version 4 to 5, detailing breaking changes, deprecated methods, and new improvements. -menu: guide -order: 10 --- # Moving to Express 5 @@ -97,7 +95,7 @@ Initially, `del` was used instead of `delete`, because `delete` is a reserved ke {% capture codemod-route-del-to-delete %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx codemod@latest @expressjs/route-del-to-delete ``` @@ -134,7 +132,7 @@ The following method names have been pluralized. In Express 4, using the old met {% capture codemod-pluralized-methods %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx codemod@latest @expressjs/pluralize-method-names ``` @@ -175,7 +173,7 @@ This potentially confusing and dangerous method of retrieving form data has been {% capture codemod-req-param %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx codemod@latest @expressjs/explicit-request-params ``` @@ -210,7 +208,7 @@ Express 5 no longer supports the signature `res.json(obj, status)`. Instead, set {% capture codemod-status-send-order %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx codemod@latest @expressjs/status-send-order ``` @@ -255,7 +253,7 @@ Express 5 no longer supports the signature `res.redirect(url, status)`. Instead, {% capture codemod-redirect-arg-order %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx codemod@latest @expressjs/redirect-arg-order ``` @@ -282,7 +280,7 @@ Express 5 no longer supports the magic string `back` in the `res.redirect()` and {% capture codemod-back-redirect-deprecated %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx codemod@latest @expressjs/back-redirect-deprecated ``` @@ -355,7 +353,7 @@ The `res.sendfile()` function has been replaced by a camel-cased version `res.se {% capture codemod-camelcase-sendfile %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx codemod@latest @expressjs/camelcase-sendfile ``` diff --git a/astro/src/content/docs/en/guide/overriding-express-api.md b/astro/src/content/docs/en/4x/guide/overriding-express-api.md similarity index 99% rename from astro/src/content/docs/en/guide/overriding-express-api.md rename to astro/src/content/docs/en/4x/guide/overriding-express-api.md index 33e3bcf83f..db65ce792f 100644 --- a/astro/src/content/docs/en/guide/overriding-express-api.md +++ b/astro/src/content/docs/en/4x/guide/overriding-express-api.md @@ -1,8 +1,6 @@ --- title: Overriding the Express API description: Discover how to customize and extend the Express.js API by overriding methods and properties on the request and response objects using prototypes. -menu: guide -order: 4 --- # Overriding the Express API diff --git a/astro/src/content/docs/en/guide/routing.md b/astro/src/content/docs/en/4x/guide/routing.md similarity index 99% rename from astro/src/content/docs/en/guide/routing.md rename to astro/src/content/docs/en/4x/guide/routing.md index 65b6b64d30..cd1f1db834 100755 --- a/astro/src/content/docs/en/guide/routing.md +++ b/astro/src/content/docs/en/4x/guide/routing.md @@ -1,8 +1,6 @@ --- title: Express routing description: Learn how to define and use routes in Express.js applications, including route methods, route paths, parameters, and using Router for modular routing. -menu: guide -order: 1 --- # Routing diff --git a/astro/src/content/docs/en/guide/using-middleware.md b/astro/src/content/docs/en/4x/guide/using-middleware.md similarity index 99% rename from astro/src/content/docs/en/guide/using-middleware.md rename to astro/src/content/docs/en/4x/guide/using-middleware.md index 1e372172de..c202096171 100644 --- a/astro/src/content/docs/en/guide/using-middleware.md +++ b/astro/src/content/docs/en/4x/guide/using-middleware.md @@ -1,8 +1,6 @@ --- title: Using Express middleware description: Learn how to use middleware in Express.js applications, including application-level and router-level middleware, error handling, and integrating third-party middleware. -menu: guide -order: 3 --- # Using middleware diff --git a/astro/src/content/docs/en/guide/using-template-engines.md b/astro/src/content/docs/en/4x/guide/using-template-engines.md similarity index 99% rename from astro/src/content/docs/en/guide/using-template-engines.md rename to astro/src/content/docs/en/4x/guide/using-template-engines.md index ed31c054cc..4255702117 100755 --- a/astro/src/content/docs/en/guide/using-template-engines.md +++ b/astro/src/content/docs/en/4x/guide/using-template-engines.md @@ -1,8 +1,6 @@ --- title: Using template engines with Express description: Discover how to integrate and use template engines like Pug, Handlebars, and EJS with Express.js to render dynamic HTML pages efficiently. -menu: guide -order: 5 --- # Using template engines with Express diff --git a/astro/src/content/docs/en/guide/writing-middleware.md b/astro/src/content/docs/en/4x/guide/writing-middleware.md similarity index 99% rename from astro/src/content/docs/en/guide/writing-middleware.md rename to astro/src/content/docs/en/4x/guide/writing-middleware.md index 3d223aabff..5676253444 100755 --- a/astro/src/content/docs/en/guide/writing-middleware.md +++ b/astro/src/content/docs/en/4x/guide/writing-middleware.md @@ -1,8 +1,6 @@ --- title: Writing middleware for use in Express apps description: Learn how to write custom middleware functions for Express.js applications, including examples and best practices for enhancing request and response handling. -menu: guide -order: 2 --- # Writing middleware for use in Express apps diff --git a/astro/src/content/docs/en/starter/basic-routing.md b/astro/src/content/docs/en/4x/starter/basic-routing.md similarity index 98% rename from astro/src/content/docs/en/starter/basic-routing.md rename to astro/src/content/docs/en/4x/starter/basic-routing.md index 5039415d21..e699ef3f72 100755 --- a/astro/src/content/docs/en/starter/basic-routing.md +++ b/astro/src/content/docs/en/4x/starter/basic-routing.md @@ -1,8 +1,6 @@ --- title: Express basic routing description: Learn the fundamentals of routing in Express.js applications, including how to define routes, handle HTTP methods, and create route handlers for your web server. -menu: starter -order: 4 --- # Basic routing diff --git a/astro/src/content/docs/en/starter/examples.md b/astro/src/content/docs/en/4x/starter/examples.md similarity index 97% rename from astro/src/content/docs/en/starter/examples.md rename to astro/src/content/docs/en/4x/starter/examples.md index 5d4f468f6f..a25a6d9834 100755 --- a/astro/src/content/docs/en/starter/examples.md +++ b/astro/src/content/docs/en/4x/starter/examples.md @@ -1,8 +1,6 @@ --- title: Express examples description: Explore a collection of Express.js application examples covering various use cases, integrations, and advanced configurations to help you learn and build your projects. -menu: starter -order: 6 --- {% capture examples %}{% include readmes/express-master/examples.md %}{% endcapture %} diff --git a/astro/src/content/docs/en/starter/faq.md b/astro/src/content/docs/en/4x/starter/faq.md similarity index 99% rename from astro/src/content/docs/en/starter/faq.md rename to astro/src/content/docs/en/4x/starter/faq.md index 9b50f95235..397591ad28 100755 --- a/astro/src/content/docs/en/starter/faq.md +++ b/astro/src/content/docs/en/4x/starter/faq.md @@ -1,8 +1,6 @@ --- title: Express FAQ description: Find answers to frequently asked questions about Express.js, including topics on application structure, models, authentication, template engines, error handling, and more. -menu: starter -order: 7 --- # FAQ diff --git a/astro/src/content/docs/en/starter/generator.md b/astro/src/content/docs/en/4x/starter/generator.md similarity index 99% rename from astro/src/content/docs/en/starter/generator.md rename to astro/src/content/docs/en/4x/starter/generator.md index 4f50dc5979..4ee5058a18 100755 --- a/astro/src/content/docs/en/starter/generator.md +++ b/astro/src/content/docs/en/4x/starter/generator.md @@ -1,8 +1,6 @@ --- title: Express application generator description: Learn how to use the Express application generator tool to quickly create a skeleton for your Express.js applications, streamlining setup and configuration. -menu: starter -order: 3 --- # Express application generator diff --git a/astro/src/content/docs/en/starter/hello-world.md b/astro/src/content/docs/en/4x/starter/hello-world.md similarity index 98% rename from astro/src/content/docs/en/starter/hello-world.md rename to astro/src/content/docs/en/4x/starter/hello-world.md index 5a92e97b71..97da56d686 100755 --- a/astro/src/content/docs/en/starter/hello-world.md +++ b/astro/src/content/docs/en/4x/starter/hello-world.md @@ -1,8 +1,6 @@ --- title: Express "Hello World" example description: Get started with Express.js by building a simple 'Hello World' application, demonstrating the basic setup and server creation for beginners. -menu: starter -order: 2 --- # Hello world example diff --git a/astro/src/content/docs/en/starter/installing.md b/astro/src/content/docs/en/4x/starter/installing.md similarity index 98% rename from astro/src/content/docs/en/starter/installing.md rename to astro/src/content/docs/en/4x/starter/installing.md index ff78da6984..74b1d3ef6f 100755 --- a/astro/src/content/docs/en/starter/installing.md +++ b/astro/src/content/docs/en/4x/starter/installing.md @@ -1,8 +1,6 @@ --- title: Installing Express description: Learn how to install Express.js in your Node.js environment, including setting up your project directory and managing dependencies with npm. -menu: starter -order: 1 --- # Installing diff --git a/astro/src/content/docs/en/starter/static-files.md b/astro/src/content/docs/en/4x/starter/static-files.md similarity index 99% rename from astro/src/content/docs/en/starter/static-files.md rename to astro/src/content/docs/en/4x/starter/static-files.md index 8d3c9c2ea3..52a21fdecc 100755 --- a/astro/src/content/docs/en/starter/static-files.md +++ b/astro/src/content/docs/en/4x/starter/static-files.md @@ -1,8 +1,6 @@ --- title: Serving static files in Express description: Understand how to serve static files like images, CSS, and JavaScript in Express.js applications using the built-in 'static' middleware. -menu: starter -order: 5 --- # Serving static files in Express diff --git a/astro/src/content/docs/en/5x/advanced/best-practice-performance.md b/astro/src/content/docs/en/5x/advanced/best-practice-performance.md new file mode 100644 index 0000000000..b67e10a94b --- /dev/null +++ b/astro/src/content/docs/en/5x/advanced/best-practice-performance.md @@ -0,0 +1,307 @@ +--- +title: Performance Best Practices Using Express in Production +description: Discover performance and reliability best practices for Express apps in production, covering code optimizations and environment setups for optimal performance. +--- + +# Production best practices: performance and reliability + +This article discusses performance and reliability best practices for Express applications deployed to production. + +This topic clearly falls into the "devops" world, spanning both traditional development and operations. Accordingly, the information is divided into two parts: + +- Things to do in your code (the dev part): + - [Use gzip compression](#use-gzip-compression) + - [Don't use synchronous functions](#dont-use-synchronous-functions) + - [Do logging correctly](#do-logging-correctly) + - [Handle exceptions properly](#handle-exceptions-properly) +- Things to do in your environment / setup (the ops part): + - [Set NODE_ENV to "production"](#set-node_env-to-production) + - [Ensure your app automatically restarts](#ensure-your-app-automatically-restarts) + - [Run your app in a cluster](#run-your-app-in-a-cluster) + - [Cache request results](#cache-request-results) + - [Use a load balancer](#use-a-load-balancer) + - [Use a reverse proxy](#use-a-reverse-proxy) + +## Things to do in your code {#in-code} + +Here are some things you can do in your code to improve your application's performance: + +- [Use gzip compression](#use-gzip-compression) +- [Don't use synchronous functions](#dont-use-synchronous-functions) +- [Do logging correctly](#do-logging-correctly) +- [Handle exceptions properly](#handle-exceptions-properly) + +### Use gzip compression + +Gzip compressing can greatly decrease the size of the response body and hence increase the speed of a web app. Use the [compression](https://www.npmjs.com/package/compression) middleware for gzip compression in your Express app. For example: + +```js +const compression = require('compression'); +const express = require('express'); +const app = express(); + +app.use(compression()); +``` + +For a high-traffic website in production, the best way to put compression in place is to implement it at a reverse proxy level (see [Use a reverse proxy](#use-a-reverse-proxy)). In that case, you do not need to use compression middleware. For details on enabling gzip compression in Nginx, see [Module ngx_http_gzip_module](http://nginx.org/en/docs/http/ngx_http_gzip_module.html) in the Nginx documentation. + +### Don't use synchronous functions + +Synchronous functions and methods tie up the executing process until they return. A single call to a synchronous function might return in a few microseconds or milliseconds, however in high-traffic websites, these calls add up and reduce the performance of the app. Avoid their use in production. + +Although Node and many modules provide synchronous and asynchronous versions of their functions, always use the asynchronous version in production. The only time when a synchronous function can be justified is upon initial startup. + +You can use the `--trace-sync-io` command-line flag to print a warning and a stack trace whenever your application uses a synchronous API. Of course, you wouldn't want to use this in production, but rather to ensure that your code is ready for production. See the [node command-line options documentation](https://nodejs.org/api/cli.html#cli_trace_sync_io) for more information. + +### Do logging correctly + +In general, there are two reasons for logging from your app: For debugging and for logging app activity (essentially, everything else). Using `console.log()` or `console.error()` to print log messages to the terminal is common practice in development. But [these functions are synchronous](https://nodejs.org/api/console.html#console) when the destination is a terminal or a file, so they are not suitable for production, unless you pipe the output to another program. + +#### For debugging + +If you're logging for purposes of debugging, then instead of using `console.log()`, use a special debugging module like [debug](https://www.npmjs.com/package/debug). This module enables you to use the DEBUG environment variable to control what debug messages are sent to `console.error()`, if any. To keep your app purely asynchronous, you'd still want to pipe `console.error()` to another program. But then, you're not really going to debug in production, are you? + +#### For app activity + +If you're logging app activity (for example, tracking traffic or API calls), instead of using `console.log()`, use a logging library like [Pino](https://www.npmjs.com/package/pino), which is the fastest and most efficient option available. + +### Handle exceptions properly + +Node apps crash when they encounter an uncaught exception. Not handling exceptions and taking appropriate actions will make your Express app crash and go offline. If you follow the advice in [Ensure your app automatically restarts](#ensure-your-app-automatically-restarts) below, then your app will recover from a crash. Fortunately, Express apps typically have a short startup time. Nevertheless, you want to avoid crashing in the first place, and to do that, you need to handle exceptions properly. + +To ensure you handle all exceptions, use the following techniques: + +- [Use try-catch](#use-try-catch) +- [Use promises](#use-promises) + +Before diving into these topics, you should have a basic understanding of Node/Express error handling: using error-first callbacks, and propagating errors in middleware. Node uses an "error-first callback" convention for returning errors from asynchronous functions, where the first parameter to the callback function is the error object, followed by result data in succeeding parameters. To indicate no error, pass null as the first parameter. The callback function must correspondingly follow the error-first callback convention to meaningfully handle the error. And in Express, the best practice is to use the next() function to propagate errors through the middleware chain. + +For more on the fundamentals of error handling, see: + +- [Error Handling in Node.js](https://www.tritondatacenter.com/node-js/production/design/errors) + +#### Use try-catch + +Try-catch is a JavaScript language construct that you can use to catch exceptions in synchronous code. Use try-catch, for example, to handle JSON parsing errors as shown below. + +Here is an example of using try-catch to handle a potential process-crashing exception. +This middleware function accepts a query field parameter named "params" that is a JSON object. + +```js +app.get('/search', (req, res) => { + // Simulating async operation + setImmediate(() => { + const jsonStr = req.query.params; + try { + const jsonObj = JSON.parse(jsonStr); + res.send('Success'); + } catch (e) { + res.status(400).send('Invalid JSON string'); + } + }); +}); +``` + +However, try-catch works only for synchronous code. Because the Node platform is primarily asynchronous (particularly in a production environment), try-catch won't catch a lot of exceptions. + +#### Use promises + +When an error is thrown in an `async` function or a rejected promise is awaited inside an `async` function, those errors will be passed to the error handler as if calling `next(err)` + +```js +app.get('/', async (req, res, next) => { + const data = await userData(); // If this promise fails, it will automatically call `next(err)` to handle the error. + + res.send(data); +}); + +app.use((err, req, res, next) => { + res.status(err.status ?? 500).send({ error: err.message }); +}); +``` + +Also, you can use asynchronous functions for your middleware, and the router will handle errors if the promise fails, for example: + +```js +app.use(async (req, res, next) => { + req.locals.user = await getUser(req); + + next(); // This will be called if the promise does not throw an error. +}); +``` + +Best practice is to handle errors as close to the site as possible. So while this is now handled in the router, it’s best to catch the error in the middleware and handle it without relying on separate error-handling middleware. + +#### What not to do + +One thing you should _not_ do is to listen for the `uncaughtException` event, emitted when an exception bubbles all the way back to the event loop. Adding an event listener for `uncaughtException` will change the default behavior of the process that is encountering an exception; the process will continue to run despite the exception. This might sound like a good way of preventing your app from crashing, but continuing to run the app after an uncaught exception is a dangerous practice and is not recommended, because the state of the process becomes unreliable and unpredictable. + +Additionally, using `uncaughtException` is officially recognized as [crude](https://nodejs.org/api/process.html#process_event_uncaughtexception). So listening for `uncaughtException` is just a bad idea. This is why we recommend things like multiple processes and supervisors: crashing and restarting is often the most reliable way to recover from an error. + +We also don't recommend using [domains](https://nodejs.org/api/domain.html). It generally doesn't solve the problem and is a deprecated module. + +## Things to do in your environment / setup {#in-environment} + +Here are some things you can do in your system environment to improve your app's performance: + +- [Set NODE_ENV to "production"](#set-node_env-to-production) +- [Ensure your app automatically restarts](#ensure-your-app-automatically-restarts) +- [Run your app in a cluster](#run-your-app-in-a-cluster) +- [Cache request results](#cache-request-results) +- [Use a load balancer](#use-a-load-balancer) +- [Use a reverse proxy](#use-a-reverse-proxy) + +### Set NODE_ENV to "production" + +The NODE_ENV environment variable specifies the environment in which an application is running (usually, development or production). One of the simplest things you can do to improve performance is to set NODE_ENV to `production`. + +Setting NODE_ENV to "production" makes Express: + +- Cache view templates. +- Cache CSS files generated from CSS extensions. +- Generate less verbose error messages. + +[Tests indicate](https://www.dynatrace.com/news/blog/the-drastic-effects-of-omitting-node-env-in-your-express-js-applications/) that just doing this can improve app performance by a factor of three! + +If you need to write environment-specific code, you can check the value of NODE_ENV with `process.env.NODE_ENV`. Be aware that checking the value of any environment variable incurs a performance penalty, and so should be done sparingly. + +In development, you typically set environment variables in your interactive shell, for example by using `export` or your `.bash_profile` file. But in general, you shouldn't do that on a production server; instead, use your OS's init system (systemd). The next section provides more details about using your init system in general, but setting `NODE_ENV` is so important for performance (and easy to do), that it's highlighted here. + +With systemd, use the `Environment` directive in your unit file. For example: + +```sh +# /etc/systemd/system/myservice.service +Environment=NODE_ENV=production +``` + +For more information, see [Using Environment Variables In systemd Units](https://www.flatcar.org/docs/latest/setup/systemd/environment-variables/). + +### Ensure your app automatically restarts + +In production, you don't want your application to be offline, ever. This means you need to make sure it restarts both if the app crashes and if the server itself crashes. Although you hope that neither of those events occurs, realistically you must account for both eventualities by: + +- Using a process manager to restart the app (and Node) when it crashes. +- Using the init system provided by your OS to restart the process manager when the OS crashes. It's also possible to use the init system without a process manager. + +Node applications crash if they encounter an uncaught exception. The foremost thing you need to do is to ensure your app is well-tested and handles all exceptions (see [handle exceptions properly](#handle-exceptions-properly) for details). But as a fail-safe, put a mechanism in place to ensure that if and when your app crashes, it will automatically restart. + +#### Use a process manager + +In development, you started your app simply from the command line with `node server.js` or something similar. But doing this in production is a recipe for disaster. If the app crashes, it will be offline until you restart it. To ensure your app restarts if it crashes, use a process manager. A process manager is a "container" for applications that facilitates deployment, provides high availability, and enables you to manage the application at runtime. + +In addition to restarting your app when it crashes, a process manager can enable you to: + +- Gain insights into runtime performance and resource consumption. +- Modify settings dynamically to improve performance. +- Control clustering (pm2). + +Historically, it was popular to use a Node.js process manager like [PM2](https://github.com/Unitech/pm2). See their documentation if you wish to do this. However, we recommend using your init system for process management. + +#### Use an init system + +The next layer of reliability is to ensure that your app restarts when the server restarts. Systems can still go down for a variety of reasons. To ensure that your app restarts if the server crashes, use the init system built into your OS. The main init system in use today is [systemd](https://wiki.debian.org/systemd). + +There are two ways to use init systems with your Express app: + +- Run your app in a process manager, and install the process manager as a service with the init system. The process manager will restart your app when the app crashes, and the init system will restart the process manager when the OS restarts. This is the recommended approach. +- Run your app (and Node) directly with the init system. This is somewhat simpler, but you don't get the additional advantages of using a process manager. + +##### Systemd + +Systemd is a Linux system and service manager. Most major Linux distributions have adopted systemd as their default init system. + +A systemd service configuration file is called a _unit file_, with a filename ending in `.service`. Here's an example unit file to manage a Node app directly. Replace the values enclosed in `` for your system and app: + +```sh +[Unit] +Description= + +[Service] +Type=simple +ExecStart=/usr/local/bin/node +WorkingDirectory= + +User=nobody +Group=nogroup + +# Environment variables: +Environment=NODE_ENV=production + +# Allow many incoming connections +LimitNOFILE=infinity + +# Allow core dumps for debugging +LimitCORE=infinity + +StandardInput=null +StandardOutput=syslog +StandardError=syslog +Restart=always + +[Install] +WantedBy=multi-user.target +``` + +For more information on systemd, see the [systemd reference (man page)](http://www.freedesktop.org/software/systemd/man/systemd.unit.html). + +### Run your app in a cluster + +In a multi-core system, you can increase the performance of a Node app by many times by launching a cluster of processes. A cluster runs multiple instances of the app, ideally one instance on each CPU core, thereby distributing the load and tasks among the instances. + +![Balancing between application instances using the cluster API](/images/clustering.png) + +IMPORTANT: Since the app instances run as separate processes, they do not share the same memory space. That is, objects are local to each instance of the app. Therefore, you cannot maintain state in the application code. However, you can use an in-memory datastore like [Redis](http://redis.io/) to store session-related data and state. This caveat applies to essentially all forms of horizontal scaling, whether clustering with multiple processes or multiple physical servers. + +In clustered apps, worker processes can crash individually without affecting the rest of the processes. Apart from performance advantages, failure isolation is another reason to run a cluster of app processes. Whenever a worker process crashes, always make sure to log the event and spawn a new process using cluster.fork(). + +#### Using Node's cluster module + +Clustering is made possible with Node's [cluster module](https://nodejs.org/api/cluster.html). This enables a master process to spawn worker processes and distribute incoming connections among the workers. + +#### Using PM2 + +If you deploy your application with PM2, then you can take advantage of clustering _without_ modifying your application code. You should ensure your [application is stateless](https://pm2.keymetrics.io/docs/usage/specifics/#stateless-apps) first, meaning no local data is stored in the process (such as sessions, websocket connections and the like). + +When running an application with PM2, you can enable **cluster mode** to run it in a cluster with a number of instances of your choosing, such as the matching the number of available CPUs on the machine. You can manually change the number of processes in the cluster using the `pm2` command line tool without stopping the app. + +To enable cluster mode, start your application like so: + +```bash +# Start 4 worker processes +$ pm2 start npm --name my-app -i 4 -- start +# Auto-detect number of available CPUs and start that many worker processes +$ pm2 start npm --name my-app -i max -- start +``` + +This can also be configured within a PM2 process file (`ecosystem.config.js` or similar) by setting `exec_mode` to `cluster` and `instances` to the number of workers to start. + +Once running, the application can be scaled like so: + +```bash +# Add 3 more workers +$ pm2 scale my-app +3 +# Scale to a specific number of workers +$ pm2 scale my-app 2 +``` + +For more information on clustering with PM2, see [Cluster Mode](https://pm2.keymetrics.io/docs/usage/cluster-mode/) in the PM2 documentation. + +### Cache request results + +Another strategy to improve the performance in production is to cache the result of requests, so that your app does not repeat the operation to serve the same request repeatedly. + +Use a caching server like [Varnish](https://www.varnish-cache.org/) or [Nginx](https://blog.nginx.org/blog/nginx-caching-guide) (see also [Nginx Caching](https://serversforhackers.com/nginx-caching/)) to greatly improve the speed and performance of your app. + +### Use a load balancer + +No matter how optimized an app is, a single instance can handle only a limited amount of load and traffic. One way to scale an app is to run multiple instances of it and distribute the traffic via a load balancer. Setting up a load balancer can improve your app's performance and speed, and enable it to scale more than is possible with a single instance. + +A load balancer is usually a reverse proxy that orchestrates traffic to and from multiple application instances and servers. You can easily set up a load balancer for your app by using [Nginx](https://nginx.org/en/docs/http/load_balancing.html) or [HAProxy](https://www.digitalocean.com/community/tutorials/an-introduction-to-haproxy-and-load-balancing-concepts). + +With load balancing, you might have to ensure that requests that are associated with a particular session ID connect to the process that originated them. This is known as _session affinity_, or _sticky sessions_, and may be addressed by the suggestion above to use a data store such as Redis for session data (depending on your application). For a discussion, see [Using multiple nodes](https://socket.io/docs/v4/using-multiple-nodes/). + +### Use a reverse proxy + +A reverse proxy sits in front of a web app and performs supporting operations on the requests, apart from directing requests to the app. It can handle error pages, compression, caching, serving files, and load balancing among other things. + +Handing over tasks that do not require knowledge of application state to a reverse proxy frees up Express to perform specialized application tasks. For this reason, it is recommended to run Express behind a reverse proxy like [Nginx](https://www.nginx.org/) or [HAProxy](https://www.haproxy.org/) in production. diff --git a/astro/src/content/docs/en/5x/advanced/best-practice-security.md b/astro/src/content/docs/en/5x/advanced/best-practice-security.md new file mode 100644 index 0000000000..b7836981a2 --- /dev/null +++ b/astro/src/content/docs/en/5x/advanced/best-practice-security.md @@ -0,0 +1,283 @@ +--- +title: Security Best Practices for Express in Production +description: Discover crucial security best practices for Express apps in production, including using TLS, input validation, secure cookies, and preventing vulnerabilities. +--- + +# Production Best Practices: Security + +## Overview + +The term _"production"_ refers to the stage in the software lifecycle when an application or API is generally available to its end-users or consumers. In contrast, in the _"development"_ stage, you're still actively writing and testing code, and the application is not open to external access. The corresponding system environments are known as _production_ and _development_ environments, respectively. + +Development and production environments are usually set up differently and have vastly different requirements. What's fine in development may not be acceptable in production. For example, in a development environment you may want verbose logging of errors for debugging, while the same behavior can become a security concern in a production environment. And in development, you don't need to worry about scalability, reliability, and performance, while those concerns become critical in production. + +{% capture security-note %} + +If you believe you have discovered a security vulnerability in Express, please see +[Security Policies and Procedures](/en/resources/contributing.html#security-policies-and-procedures). + +{% endcapture %} + +{% include admonitions/note.html content=security-note %} + +Security best practices for Express applications in production include: + +- [Production Best Practices: Security](#production-best-practices-security) + - [Overview](#overview) + - [Don't use deprecated or vulnerable versions of Express](#dont-use-deprecated-or-vulnerable-versions-of-express) + - [Use TLS](#use-tls) + - [Do not trust user input](#do-not-trust-user-input) + - [Prevent open redirects](#prevent-open-redirects) + - [Use Helmet](#use-helmet) + - [Reduce fingerprinting](#reduce-fingerprinting) + - [Use cookies securely](#use-cookies-securely) + - [Don't use the default session cookie name](#dont-use-the-default-session-cookie-name) + - [Set cookie security options](#set-cookie-security-options) + - [Prevent brute-force attacks against authorization](#prevent-brute-force-attacks-against-authorization) + - [Ensure your dependencies are secure](#ensure-your-dependencies-are-secure) + - [Avoid other known vulnerabilities](#avoid-other-known-vulnerabilities) + - [Additional considerations](#additional-considerations) + +## Don't use deprecated or vulnerable versions of Express + +Express 2.x and 3.x are no longer maintained. Security and performance issues in these versions won't be fixed. Do not use them! If you haven't moved to version 4, follow the [migration guide](/{{ page.lang }}/guide/migrating-4.html) or consider [Commercial Support Options](/{{ page.lang }}/support#commercial-support-options). + +Also ensure you are not using any of the vulnerable Express versions listed on the [Security updates page](/{{ page.lang }}/advanced/security-updates.html). If you are, update to one of the stable releases, preferably the latest. + +## Use TLS + +If your app deals with or transmits sensitive data, use [Transport Layer Security](https://en.wikipedia.org/wiki/Transport_Layer_Security) (TLS) to secure the connection and the data. This technology encrypts data before it is sent from the client to the server, thus preventing some common (and easy) hacks. Although Ajax and POST requests might not be visibly obvious and seem "hidden" in browsers, their network traffic is vulnerable to [packet sniffing](https://en.wikipedia.org/wiki/Packet_analyzer) and [man-in-the-middle attacks](https://en.wikipedia.org/wiki/Man-in-the-middle_attack). + +You may be familiar with Secure Socket Layer (SSL) encryption. [TLS is simply the next progression of SSL](). In other words, if you were using SSL before, consider upgrading to TLS. In general, we recommend Nginx to handle TLS. For a good reference to configure TLS on Nginx (and other servers), see [Recommended Server Configurations (Mozilla Wiki)](https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_Server_Configurations). + +Also, a handy tool to get a free TLS certificate is [Let's Encrypt](https://letsencrypt.org/about/), a free, automated, and open certificate authority (CA) provided by the [Internet Security Research Group (ISRG)](https://www.abetterinternet.org/). + +## Do not trust user input + +For web applications, one of the most critical security requirements is proper user input validation and handling. This comes in many forms and we will not cover all of them here. +Ultimately, the responsibility for validating and correctly handling the types of user input your application accepts is yours. + +### Prevent open redirects + +An example of potentially dangerous user input is an _open redirect_, where an application accepts a URL as user input (often in the URL query, for example `?url=https://example.com`) and uses `res.redirect` to set the `location` header and +return a 3xx status. + +An application must validate that it supports redirecting to the incoming URL to avoid sending users to malicious links such as phishing websites, among other risks. + +Here is an example of checking URLs before using `res.redirect` or `res.location`: + +```js +app.use((req, res) => { + try { + if (new Url(req.query.url).host !== 'example.com') { + return res.status(400).end(`Unsupported redirect to host: ${req.query.url}`); + } + } catch (e) { + return res.status(400).end(`Invalid url: ${req.query.url}`); + } + res.redirect(req.query.url); +}); +``` + +## Use Helmet + +[Helmet][helmet] can help protect your app from some well-known web vulnerabilities by setting HTTP headers appropriately. + +Helmet is a middleware function that sets security-related HTTP response headers. Helmet sets the following headers by default: + +- `Content-Security-Policy`: A powerful allow-list of what can happen on your page which mitigates many attacks +- `Cross-Origin-Opener-Policy`: Helps process-isolate your page +- `Cross-Origin-Resource-Policy`: Blocks others from loading your resources cross-origin +- `Origin-Agent-Cluster`: Changes process isolation to be origin-based +- `Referrer-Policy`: Controls the [`Referer`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referer) header +- `Strict-Transport-Security`: Tells browsers to prefer HTTPS +- `X-Content-Type-Options`: Avoids [MIME sniffing](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#mime_sniffing) +- `X-DNS-Prefetch-Control`: Controls DNS prefetching +- `X-Download-Options`: Forces downloads to be saved (Internet Explorer only) +- `X-Frame-Options`: Legacy header that mitigates [Clickjacking](https://en.wikipedia.org/wiki/Clickjacking) attacks +- `X-Permitted-Cross-Domain-Policies`: Controls cross-domain behavior for Adobe products, like Acrobat +- `X-Powered-By`: Info about the web server. Removed because it could be used in simple attacks +- `X-XSS-Protection`: Legacy header that tries to mitigate [XSS attacks](https://developer.mozilla.org/en-US/docs/Glossary/Cross-site_scripting), but makes things worse, so Helmet disables it + +Each header can be configured or disabled. To read more about it please go to [its documentation website][helmet]. + +Install Helmet like any other module: + +```bash +$ npm install helmet +``` + +Then to use it in your code: + +```js +// ... + +const helmet = require('helmet'); +app.use(helmet()); + +// ... +``` + +## Reduce fingerprinting + +It can help to provide an extra layer of security to reduce the ability of attackers to determine +the software that a server uses, known as "fingerprinting." Though not a security issue itself, +reducing the ability to fingerprint an application improves its overall security posture. +Server software can be fingerprinted by quirks in how it responds to specific requests, for example in +the HTTP response headers. + +By default, Express sends the `X-Powered-By` response header that you can +disable using the `app.disable()` method: + +```js +app.disable('x-powered-by'); +``` + +{% capture powered-advisory %} + +Disabling the `X-Powered-By header` does not prevent +a sophisticated attacker from determining that an app is running Express. It may +discourage a casual exploit, but there are other ways to determine an app is running +Express. + +{% endcapture %} + +{% include admonitions/note.html content=powered-advisory %} + +Express also sends its own formatted "404 Not Found" messages and formatter error +response messages. These can be changed by +[adding your own not found handler](/en/starter/faq.html#how-do-i-handle-404-responses) +and +[writing your own error handler](/en/guide/error-handling.html#writing-error-handlers): + +```js +// last app.use calls right before app.listen(): + +// custom 404 +app.use((req, res, next) => { + res.status(404).send("Sorry can't find that!"); +}); + +// custom error handler +app.use((err, req, res, next) => { + console.error(err.stack); + res.status(500).send('Something broke!'); +}); +``` + +## Use cookies securely + +To ensure cookies don't open your app to exploits, don't use the default session cookie name and set cookie security options appropriately. + +There are two main middleware cookie session modules: + +- [express-session](https://www.npmjs.com/package/express-session) that replaces `express.session` middleware built-in to Express 3.x. +- [cookie-session](https://www.npmjs.com/package/cookie-session) that replaces `express.cookieSession` middleware built-in to Express 3.x. + +The main difference between these two modules is how they save cookie session data. The [express-session](https://www.npmjs.com/package/express-session) middleware stores session data on the server; it only saves the session ID in the cookie itself, not session data. By default, it uses in-memory storage and is not designed for a production environment. In production, you'll need to set up a scalable session-store; see the list of [compatible session stores](https://github.com/expressjs/session#compatible-session-stores). + +In contrast, [cookie-session](https://www.npmjs.com/package/cookie-session) middleware implements cookie-backed storage: it serializes the entire session to the cookie, rather than just a session key. Only use it when session data is relatively small and easily encoded as primitive values (rather than objects). Although browsers are supposed to support at least 4096 bytes per cookie, to ensure you don't exceed the limit, don't exceed a size of 4093 bytes per domain. Also, be aware that the cookie data will be visible to the client, so if there is any reason to keep it secure or obscure, then `express-session` may be a better choice. + +### Don't use the default session cookie name + +Using the default session cookie name can open your app to attacks. The security issue posed is similar to `X-Powered-By`: a potential attacker can use it to fingerprint the server and target attacks accordingly. + +To avoid this problem, use generic cookie names; for example using [express-session](https://www.npmjs.com/package/express-session) middleware: + +```js +const session = require('express-session'); +app.set('trust proxy', 1); // trust first proxy +app.use( + session({ + secret: 's3Cur3', + name: 'sessionId', + }) +); +``` + +### Set cookie security options + +Set the following cookie options to enhance security: + +- `secure` - Ensures the browser only sends the cookie over HTTPS. +- `httpOnly` - Ensures the cookie is sent only over HTTP(S), not client JavaScript, helping to protect against cross-site scripting attacks. +- `domain` - indicates the domain of the cookie; use it to compare against the domain of the server in which the URL is being requested. If they match, then check the path attribute next. +- `path` - indicates the path of the cookie; use it to compare against the request path. If this and domain match, then send the cookie in the request. +- `expires` - use to set expiration date for persistent cookies. + +Here is an example using [cookie-session](https://www.npmjs.com/package/cookie-session) middleware: + +```js +const session = require('cookie-session'); +const express = require('express'); +const app = express(); + +const expiryDate = new Date(Date.now() + 60 * 60 * 1000); // 1 hour +app.use( + session({ + name: 'session', + keys: ['key1', 'key2'], + cookie: { + secure: true, + httpOnly: true, + domain: 'example.com', + path: 'foo/bar', + expires: expiryDate, + }, + }) +); +``` + +## Prevent brute-force attacks against authorization + +Make sure login endpoints are protected to make private data more secure. + +A simple and powerful technique is to block authorization attempts using two metrics: + +1. The number of consecutive failed attempts by the same user name and IP address. +1. The number of failed attempts from an IP address over some long period of time. For example, block an IP address if it makes 100 failed attempts in one day. + +[rate-limiter-flexible](https://github.com/animir/node-rate-limiter-flexible) package provides tools to make this technique easy and fast. You can find [an example of brute-force protection in the documentation](https://github.com/animir/node-rate-limiter-flexible/wiki/Overall-example#login-endpoint-protection) + +## Ensure your dependencies are secure + +Using npm to manage your application's dependencies is powerful and convenient. But the packages that you use may contain critical security vulnerabilities that could also affect your application. The security of your app is only as strong as the "weakest link" in your dependencies. + +Since npm@6, npm automatically reviews every install request. Also, you can use `npm audit` to analyze your dependency tree. + +```bash +$ npm audit +``` + +If you want to stay more secure, consider [Snyk](https://snyk.io/). + +Snyk offers both a [command-line tool](https://www.npmjs.com/package/snyk) and a [Github integration](https://snyk.io/docs/github) that checks your application against [Snyk's open source vulnerability database](https://snyk.io/vuln/) for any known vulnerabilities in your dependencies. Install the CLI as follows: + +```bash +$ npm install -g snyk +$ cd your-app +``` + +Use this command to test your application for vulnerabilities: + +```bash +$ snyk test +``` + +### Avoid other known vulnerabilities + +Keep an eye out for [Node Security Project](https://npmjs.com/advisories) or [Snyk](https://snyk.io/vuln/) advisories that may affect Express or other modules that your app uses. In general, these databases are excellent resources for knowledge and tools about Node security. + +Finally, Express apps—like any other web apps—can be vulnerable to a variety of web-based attacks. Familiarize yourself with known [web vulnerabilities](https://www.owasp.org/www-project-top-ten/) and take precautions to avoid them. + +## Additional considerations + +Here are some further recommendations from the excellent [Node.js Security Checklist](https://blog.risingstack.com/node-js-security-checklist/). Refer to that blog post for all the details on these recommendations: + +- Always filter and sanitize user input to protect against cross-site scripting (XSS) and command injection attacks. +- Defend against SQL injection attacks by using parameterized queries or prepared statements. +- Use the open-source [sqlmap](http://sqlmap.org/) tool to detect SQL injection vulnerabilities in your app. +- Use the [nmap](https://nmap.org/) and [sslyze](https://github.com/nabla-c0d3/sslyze) tools to test the configuration of your SSL ciphers, keys, and renegotiation as well as the validity of your certificate. +- Use [safe-regex](https://www.npmjs.com/package/safe-regex) to ensure your regular expressions are not susceptible to [regular expression denial of service](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS) attacks. + +[helmet]: https://helmetjs.github.io/ diff --git a/astro/src/content/docs/en/5x/advanced/developing-template-engines.md b/astro/src/content/docs/en/5x/advanced/developing-template-engines.md new file mode 100755 index 0000000000..80e28ba8c9 --- /dev/null +++ b/astro/src/content/docs/en/5x/advanced/developing-template-engines.md @@ -0,0 +1,45 @@ +--- +title: Developing template engines for Express +description: Learn how to develop custom template engines for Express.js using app.engine(), with examples on creating and integrating your own template rendering logic. +--- + +# Developing template engines for Express + +Use the `app.engine(ext, callback)` method to create your own template engine. `ext` refers to the file extension, and `callback` is the template engine function, which accepts the following items as parameters: the location of the file, the options object, and the callback function. + +The following code is an example of implementing a very simple template engine for rendering `.ntl` files. + +```js +const fs = require('fs'); // this engine requires the fs module +app.engine('ntl', (filePath, options, callback) => { + // define the template engine + fs.readFile(filePath, (err, content) => { + if (err) return callback(err); + // this is an extremely simple template engine + const rendered = content + .toString() + .replace('#title#', `${options.title}`) + .replace('#message#', `

${options.message}

`); + return callback(null, rendered); + }); +}); +app.set('views', './views'); // specify the views directory +app.set('view engine', 'ntl'); // register the template engine +``` + +Your app will now be able to render `.ntl` files. Create a file named `index.ntl` in the `views` directory with the following content. + +```pug +#title# +#message# +``` + +Then, create the following route in your app. + +```js +app.get('/', (req, res) => { + res.render('index', { title: 'Hey', message: 'Hello there!' }); +}); +``` + +When you make a request to the home page, `index.ntl` will be rendered as HTML. diff --git a/astro/src/content/docs/en/5x/advanced/healthcheck-graceful-shutdown.md b/astro/src/content/docs/en/5x/advanced/healthcheck-graceful-shutdown.md new file mode 100644 index 0000000000..1018345076 --- /dev/null +++ b/astro/src/content/docs/en/5x/advanced/healthcheck-graceful-shutdown.md @@ -0,0 +1,30 @@ +--- +title: Health Checks and Graceful Shutdown +description: Learn how to implement health checks and graceful shutdown in Express apps to enhance reliability, manage deployments, and integrate with load balancers like Kubernetes. +--- + +# Health Checks and Graceful Shutdown + +## Graceful shutdown + +When you deploy a new version of your application, you must replace the previous version. The process manager you're using will first send a SIGTERM signal to the application to notify it that it will be killed. Once the application gets this signal, it should stop accepting new requests, finish all the ongoing requests, clean up the resources it used, including database connections and file locks then exit. + +### Example + +```js +const server = app.listen(port); + +process.on('SIGTERM', () => { + debug('SIGTERM signal received: closing HTTP server'); + server.close(() => { + debug('HTTP server closed'); + }); +}); +``` + +## Health checks + +A load balancer uses health checks to determine if an application instance is healthy and can accept requests. For example, [Kubernetes has two health checks](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/): + +- `liveness`, that determines when to restart a container. +- `readiness`, that determines when a container is ready to start accepting traffic. When a pod is not ready, it is removed from the service load balancers. diff --git a/astro/src/content/docs/en/5x/advanced/security-updates.md b/astro/src/content/docs/en/5x/advanced/security-updates.md new file mode 100755 index 0000000000..a727ab32d3 --- /dev/null +++ b/astro/src/content/docs/en/5x/advanced/security-updates.md @@ -0,0 +1,83 @@ +--- +title: Express security updates +description: Review the latest security updates and patches for Express.js, including detailed vulnerability lists for different versions to help maintain a secure application. +--- + +# Security updates + +
+Node.js vulnerabilities directly affect Express. Therefore, [keep a watch on Node.js vulnerabilities](https://nodejs.org/en/blog/vulnerability/) and make sure you are using the latest stable version of Node.js. +
+ +The list below enumerates the Express vulnerabilities that were fixed in the specified version update. + +{% capture security-policy %} +If you believe you have discovered a security vulnerability in Express, please see +[Security Policies and Procedures](/{{page.lang}}/resources/contributing.html#security-policies-and-procedures). +{% endcapture %} + +{% include admonitions/note.html content=security-policy %} + +## 4.x + +- 4.21.2 + - The dependency `path-to-regexp` has been updated to address a [vulnerability](https://github.com/pillarjs/path-to-regexp/security/advisories/GHSA-rhx6-c78j-4q9w). +- 4.21.1 + - The dependency `cookie` has been updated to address a [vulnerability](https://github.com/jshttp/cookie/security/advisories/GHSA-pxg6-pf52-xh8x), This may affect your application if you use `res.cookie`. +- 4.20.0 + - Fixed XSS vulnerability in `res.redirect` ([advisory](https://github.com/expressjs/express/security/advisories/GHSA-qw6h-vgh9-j6wx), [CVE-2024-43796](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-43796)). + - The dependency `serve-static` has been updated to address a [vulnerability](https://github.com/advisories/GHSA-cm22-4g7w-348p). + - The dependency `send` has been updated to address a [vulnerability](https://github.com/advisories/GHSA-m6fv-jmcg-4jfg). + - The dependency `path-to-regexp` has been updated to address a [vulnerability](https://github.com/pillarjs/path-to-regexp/security/advisories/GHSA-9wv6-86v2-598j). + - The dependency `body-parser` has been updated to addres a [vulnerability](https://github.com/advisories/GHSA-qwcr-r2fm-qrc7), This may affect your application if you had url enconding activated. +- 4.19.0, 4.19.1 + - Fixed open redirect vulnerability in `res.location` and `res.redirect` ([advisory](https://github.com/expressjs/express/security/advisories/GHSA-rv95-896h-c2vc), [CVE-2024-29041](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-29041)). +- 4.17.3 + - The dependency `qs` has been updated to address a [vulnerability](https://github.com/advisories/GHSA-hrpp-h998-j3pp). This may affect your application if the following APIs are used: `req.query`, `req.body`, `req.param`. +- 4.16.0 + - The dependency `forwarded` has been updated to address a [vulnerability](https://npmjs.com/advisories/527). This may affect your application if the following APIs are used: `req.host`, `req.hostname`, `req.ip`, `req.ips`, `req.protocol`. + - The dependency `mime` has been updated to address a [vulnerability](https://npmjs.com/advisories/535), but this issue does not impact Express. + - The dependency `send` has been updated to provide a protection against a [Node.js 8.5.0 vulnerability](https://nodejs.org/en/blog/vulnerability/september-2017-path-validation/). This only impacts running Express on the specific Node.js version 8.5.0. +- 4.15.5 + - The dependency `debug` has been updated to address a [vulnerability](https://snyk.io/vuln/npm:debug:20170905), but this issue does not impact Express. + - The dependency `fresh` has been updated to address a [vulnerability](https://npmjs.com/advisories/526). This will affect your application if the following APIs are used: `express.static`, `req.fresh`, `res.json`, `res.jsonp`, `res.send`, `res.sendfile` `res.sendFile`, `res.sendStatus`. +- 4.15.3 + - The dependency `ms` has been updated to address a [vulnerability](https://snyk.io/vuln/npm:ms:20170412). This may affect your application if untrusted string input is passed to the `maxAge` option in the following APIs: `express.static`, `res.sendfile`, and `res.sendFile`. +- 4.15.2 + - The dependency `qs` has been updated to address a [vulnerability](https://snyk.io/vuln/npm:qs:20170213), but this issue does not impact Express. Updating to 4.15.2 is a good practice, but not required to address the vulnerability. +- 4.11.1 + - Fixed root path disclosure vulnerability in `express.static`, `res.sendfile`, and `res.sendFile` +- 4.10.7 + - Fixed open redirect vulnerability in `express.static` ([advisory](https://npmjs.com/advisories/35), [CVE-2015-1164](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-1164)). +- 4.8.8 + - Fixed directory traversal vulnerabilities in `express.static` ([advisory](http://npmjs.com/advisories/32) , [CVE-2014-6394](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-6394)). +- 4.8.4 + - Node.js 0.10 can leak `fd`s in certain situations that affect `express.static` and `res.sendfile`. Malicious requests could cause `fd`s to leak and eventually lead to `EMFILE` errors and server unresponsiveness. +- 4.8.0 + - Sparse arrays that have extremely high indexes in the query string could cause the process to run out of memory and crash the server. + - Extremely nested query string objects could cause the process to block and make the server unresponsive temporarily. + +## 3.x + +
+ **Express 3.x IS END-OF-LIFE AND NO LONGER MAINTAINED** + +Known and unknown security and performance issues in 3.x have not been addressed since the last update (1 August, 2015). It is highly recommended to use the latest version of Express. + +If you are unable to upgrade past 3.x, please consider [Commercial Support Options](/{{ page.lang }}/support#commercial-support-options). + +
+ +- 3.19.1 + - Fixed root path disclosure vulnerability in `express.static`, `res.sendfile`, and `res.sendFile` +- 3.19.0 + - Fixed open redirect vulnerability in `express.static` ([advisory](https://npmjs.com/advisories/35), [CVE-2015-1164](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-1164)). +- 3.16.10 + - Fixed directory traversal vulnerabilities in `express.static`. +- 3.16.6 + - Node.js 0.10 can leak `fd`s in certain situations that affect `express.static` and `res.sendfile`. Malicious requests could cause `fd`s to leak and eventually lead to `EMFILE` errors and server unresponsiveness. +- 3.16.0 + - Sparse arrays that have extremely high indexes in query string could cause the process to run out of memory and crash the server. + - Extremely nested query string objects could cause the process to block and make the server unresponsive temporarily. +- 3.3.0 + - The 404 response of an unsupported method override attempt was susceptible to cross-site scripting attacks. diff --git a/astro/src/content/docs/en/5x/api.md b/astro/src/content/docs/en/5x/api.md new file mode 100644 index 0000000000..d0c66d19c3 --- /dev/null +++ b/astro/src/content/docs/en/5x/api.md @@ -0,0 +1,8 @@ +--- +title: 5x API Reference +description: API Reference for version 5.x +--- + +# 5.x API + +Some content here... diff --git a/astro/src/content/docs/en/5x/api/application/app-METHOD.md b/astro/src/content/docs/en/5x/api/application/app-METHOD.md new file mode 100644 index 0000000000..5251777667 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/application/app-METHOD.md @@ -0,0 +1,65 @@ +--- +title: app.METHOD +description: Routes an HTTP request, where METHOD is the HTTP method of the request, such as GET, +--- + +

app.METHOD(path, callback [, callback ...])

+ +Routes an HTTP request, where METHOD is the HTTP method of the request, such as GET, +PUT, POST, and so on, in lowercase. Thus, the actual methods are `app.get()`, +`app.post()`, `app.put()`, and so on. See [Routing methods](#routing-methods) below for the complete list. + +{% include api/en/5x/routing-args.html %} + +#### Routing methods + +Express supports the following routing methods corresponding to the HTTP methods of the same names: + +
+
    +
  • checkout
  • +
  • copy
  • +
  • delete
  • +
  • get
  • +
  • head
  • +
  • lock
  • +
  • merge
  • +
  • mkactivity
  • +
+
    +
  • mkcol
  • +
  • move
  • +
  • m-search
  • +
  • notify
  • +
  • options
  • +
  • patch
  • +
  • post
  • +
+
    +
  • purge
  • +
  • put
  • +
  • report
  • +
  • search
  • +
  • subscribe
  • +
  • trace
  • +
  • unlock
  • +
  • unsubscribe
  • +
+
+ +The API documentation has explicit entries only for the most popular HTTP methods `app.get()`, +`app.post()`, `app.put()`, and `app.delete()`. +However, the other methods listed above work in exactly the same way. + +To route methods that translate to invalid JavaScript variable names, use the bracket notation. For example, `app['m-search']('/', function ...`. + +
+ The `app.get()` function is automatically called for the HTTP `HEAD` method in addition to the `GET` + method if `app.head()` was not called for the path before `app.get()`. +
+ +The method, `app.all()`, is not derived from any HTTP method and loads middleware at +the specified path for _all_ HTTP request methods. +For more information, see [app.all](#app.all). + +For more information on routing, see the [routing guide](/{{page.lang}}/guide/routing.html). diff --git a/astro/src/content/docs/en/5x/api/application/app-all.md b/astro/src/content/docs/en/5x/api/application/app-all.md new file mode 100644 index 0000000000..62daf475b3 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/application/app-all.md @@ -0,0 +1,49 @@ +--- +title: app.all +description: This method is like the standard [app.METHOD()](#app.METHOD) methods, +--- + +

app.all(path, callback [, callback ...])

+ +This method is like the standard [app.METHOD()](#app.METHOD) methods, +except it matches all HTTP verbs. + +{% include api/en/5x/routing-args.html %} + +#### Examples + +The following callback is executed for requests to `/secret` whether using +GET, POST, PUT, DELETE, or any other HTTP request method: + +```js +app.all('/secret', (req, res, next) => { + console.log('Accessing the secret section ...'); + next(); // pass control to the next handler +}); +``` + +The `app.all()` method is useful for mapping "global" logic for specific path prefixes or arbitrary matches. For example, if you put the following at the top of all other +route definitions, it requires that all routes from that point on +require authentication, and automatically load a user. Keep in mind +that these callbacks do not have to act as end-points: `loadUser` +can perform a task, then call `next()` to continue matching subsequent +routes. + +```js +app.all('{*splat}', requireAuthentication, loadUser); +``` + +Or the equivalent: + +```js +app.all('{*splat}', requireAuthentication); +app.all('{*splat}', loadUser); +``` + +Another example is white-listed "global" functionality. +The example is similar to the ones above, but it only restricts paths that start with +"/api": + +```js +app.all('/api/{*splat}', requireAuthentication); +``` diff --git a/astro/src/content/docs/en/5x/api/application/app-delete-method.md b/astro/src/content/docs/en/5x/api/application/app-delete-method.md new file mode 100644 index 0000000000..bbc76ab702 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/application/app-delete-method.md @@ -0,0 +1,19 @@ +--- +title: app.delete +description: Routes HTTP DELETE requests to the specified path with the specified callback functions. +--- + +

app.delete(path, callback [, callback ...])

+ +Routes HTTP DELETE requests to the specified path with the specified callback functions. +For more information, see the [routing guide](/{{page.lang}}/guide/routing.html). + +{% include api/en/5x/routing-args.html %} + +#### Example + +```js +app.delete('/', (req, res) => { + res.send('DELETE request to homepage'); +}); +``` diff --git a/astro/src/content/docs/en/5x/api/application/app-disable.md b/astro/src/content/docs/en/5x/api/application/app-disable.md new file mode 100644 index 0000000000..3c269bf4f6 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/application/app-disable.md @@ -0,0 +1,17 @@ +--- +title: app.disable +description: Sets the Boolean setting name to false, where name is one of the properties from the app settings table. +--- + +

app.disable(name)

+ +Sets the Boolean setting `name` to `false`, where `name` is one of the properties from the [app settings table](#app.settings.table). +Calling `app.set('foo', false)` for a Boolean property is the same as calling `app.disable('foo')`. + +For example: + +```js +app.disable('trust proxy'); +app.get('trust proxy'); +// => false +``` diff --git a/astro/src/content/docs/en/5x/api/application/app-disabled.md b/astro/src/content/docs/en/5x/api/application/app-disabled.md new file mode 100644 index 0000000000..8183edb278 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/application/app-disabled.md @@ -0,0 +1,18 @@ +--- +title: app.disabled +description: Returns true if the Boolean setting name is disabled (false), where name is one of the properties from +--- + +

app.disabled(name)

+ +Returns `true` if the Boolean setting `name` is disabled (`false`), where `name` is one of the properties from +the [app settings table](#app.settings.table). + +```js +app.disabled('trust proxy'); +// => true + +app.enable('trust proxy'); +app.disabled('trust proxy'); +// => false +``` diff --git a/astro/src/content/docs/en/5x/api/application/app-enable.md b/astro/src/content/docs/en/5x/api/application/app-enable.md new file mode 100644 index 0000000000..209d3364a8 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/application/app-enable.md @@ -0,0 +1,15 @@ +--- +title: app.enable +description: Sets the Boolean setting name to true, where name is one of the properties from the app settings table. +--- + +

app.enable(name)

+ +Sets the Boolean setting `name` to `true`, where `name` is one of the properties from the [app settings table](#app.settings.table). +Calling `app.set('foo', true)` for a Boolean property is the same as calling `app.enable('foo')`. + +```js +app.enable('trust proxy'); +app.get('trust proxy'); +// => true +``` diff --git a/astro/src/content/docs/en/5x/api/application/app-enabled.md b/astro/src/content/docs/en/5x/api/application/app-enabled.md new file mode 100644 index 0000000000..d63c469d48 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/application/app-enabled.md @@ -0,0 +1,18 @@ +--- +title: app.enabled +description: Returns true if the setting name is enabled (true), where name is one of the properties from the app settings table +--- + +

app.enabled(name)

+ +Returns `true` if the setting `name` is enabled (`true`), where `name` is one of the +properties from the [app settings table](#app.settings.table). + +```js +app.enabled('trust proxy'); +// => false + +app.enable('trust proxy'); +app.enabled('trust proxy'); +// => true +``` diff --git a/astro/src/content/docs/en/5x/api/application/app-engine.md b/astro/src/content/docs/en/5x/api/application/app-engine.md new file mode 100644 index 0000000000..7096d556f2 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/application/app-engine.md @@ -0,0 +1,41 @@ +--- +title: app.engine +description: Registers the given template engine callback as ext. +--- + +

app.engine(ext, callback)

+ +Registers the given template engine `callback` as `ext`. + +By default, Express will `require()` the engine based on the file extension. +For example, if you try to render a "foo.pug" file, Express invokes the +following internally, and caches the `require()` on subsequent calls to increase +performance. + +```js +app.engine('pug', require('pug').__express); +``` + +Use this method for engines that do not provide `.__express` out of the box, +or if you wish to "map" a different extension to the template engine. + +For example, to map the EJS template engine to ".html" files: + +```js +app.engine('html', require('ejs').renderFile); +``` + +In this case, EJS provides a `.renderFile()` method with +the same signature that Express expects: `(path, options, callback)`, +though note that it aliases this method as `ejs.__express` internally +so if you're using ".ejs" extensions you don't need to do anything. + +Some template engines do not follow this convention. The +[consolidate.js](https://github.com/tj/consolidate.js) library maps Node template engines to follow this convention, +so they work seamlessly with Express. + +```js +const engines = require('consolidate'); +app.engine('haml', engines.haml); +app.engine('html', engines.hogan); +``` diff --git a/astro/src/content/docs/en/5x/api/application/app-get-method.md b/astro/src/content/docs/en/5x/api/application/app-get-method.md new file mode 100644 index 0000000000..8ad8b292d4 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/application/app-get-method.md @@ -0,0 +1,20 @@ +--- +title: app.get +description: Routes HTTP GET requests to the specified path with the specified callback functions. +--- + +

app.get(path, callback [, callback ...])

+ +Routes HTTP GET requests to the specified path with the specified callback functions. + +{% include api/en/5x/routing-args.html %} + +For more information, see the [routing guide](/{{page.lang}}/guide/routing.html). + +#### Example + +```js +app.get('/', (req, res) => { + res.send('GET request to homepage'); +}); +``` diff --git a/astro/src/content/docs/en/5x/api/application/app-get.md b/astro/src/content/docs/en/5x/api/application/app-get.md new file mode 100644 index 0000000000..f385b1bfb9 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/application/app-get.md @@ -0,0 +1,18 @@ +--- +title: app.get +description: Returns the value of name app setting, where name is one of the strings in the app settings table +--- + +

app.get(name)

+ +Returns the value of `name` app setting, where `name` is one of the strings in the +[app settings table](#app.settings.table). For example: + +```js +app.get('title'); +// => undefined + +app.set('title', 'My Site'); +app.get('title'); +// => "My Site" +``` diff --git a/astro/src/content/docs/en/5x/api/application/app-listen.md b/astro/src/content/docs/en/5x/api/application/app-listen.md new file mode 100644 index 0000000000..b7845a8c3c --- /dev/null +++ b/astro/src/content/docs/en/5x/api/application/app-listen.md @@ -0,0 +1,56 @@ +--- +title: app.listen +description: Starts a UNIX socket and listens for connections on the given path. +--- + +

app.listen(path, [callback])

+ +Starts a UNIX socket and listens for connections on the given path. +This method is identical to Node's [http.Server.listen()](https://nodejs.org/api/http.html#http_server_listen). + +```js +const express = require('express'); +const app = express(); +app.listen('/tmp/sock'); +``` + +

app.listen([port[, host[, backlog]]][, callback])

+ +Binds and listens for connections on the specified host and port. +This method is identical to Node's [http.Server.listen()](https://nodejs.org/api/http.html#http_server_listen). + +If port is omitted or is 0, the operating system will assign an arbitrary unused +port, which is useful for cases like automated tasks (tests, etc.). + +```js +const express = require('express'); +const app = express(); +app.listen(3000); +``` + +The `app` returned by `express()` is in fact a JavaScript +`Function`, designed to be passed to Node's HTTP servers as a callback +to handle requests. This makes it easy to provide both HTTP and HTTPS versions of +your app with the same code base, as the app does not inherit from these +(it is simply a callback): + +```js +const express = require('express'); +const https = require('https'); +const http = require('http'); +const app = express(); + +http.createServer(app).listen(80); +https.createServer(options, app).listen(443); +``` + +The `app.listen()` method returns an [http.Server](https://nodejs.org/api/http.html#http_class_http_server) object and (for HTTP) is a convenience method for the following: + +```js +app.listen = function () { + const server = http.createServer(this); + return server.listen.apply(server, arguments); +}; +``` + +{% include admonitions/note.html content="All the forms of Node's [http.Server.listen()](https://nodejs.org/api/http.html#http_server_listen) method are in fact actually supported." %} diff --git a/astro/src/content/docs/en/5x/api/application/app-locals.md b/astro/src/content/docs/en/5x/api/application/app-locals.md new file mode 100644 index 0000000000..f3718bc1a6 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/application/app-locals.md @@ -0,0 +1,39 @@ +--- +title: app.locals +description: The app.locals object has properties that are local variables within the application, +--- + +

app.locals

+ +The `app.locals` object has properties that are local variables within the application, +and will be available in templates rendered with [res.render](#res.render). + +
+The `locals` object is used by view engines to render a response. The object +keys may be particularly sensitive and should not contain user-controlled +input, as it may affect the operation of the view engine or provide a path to +cross-site scripting. Consult the documentation for the used view engine for +additional considerations. +
+ +```js +console.dir(app.locals.title); +// => 'My App' + +console.dir(app.locals.email); +// => 'me@myapp.com' +``` + +Once set, the value of `app.locals` properties persist throughout the life of the application, +in contrast with [res.locals](#res.locals) properties that +are valid only for the lifetime of the request. + +You can access local variables in templates rendered within the application. +This is useful for providing helper functions to templates, as well as application-level data. +Local variables are available in middleware via `req.app.locals` (see [req.app](#req.app)) + +```js +app.locals.title = 'My App'; +app.locals.strftime = require('strftime'); +app.locals.email = 'me@myapp.com'; +``` diff --git a/astro/src/content/docs/en/5x/api/application/app-mountpath.md b/astro/src/content/docs/en/5x/api/application/app-mountpath.md new file mode 100644 index 0000000000..1b0b530f69 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/application/app-mountpath.md @@ -0,0 +1,50 @@ +--- +title: app.mountpath +description: The app.mountpath property contains one or more path patterns on which a sub-app was mounted. +--- + +

app.mountpath

+ +The `app.mountpath` property contains one or more path patterns on which a sub-app was mounted. + +
+ A sub-app is an instance of `express` that may be used for handling the request to a route. +
+ +```js +const express = require('express'); + +const app = express(); // the main app +const admin = express(); // the sub app + +admin.get('/', (req, res) => { + console.log(admin.mountpath); // /admin + res.send('Admin Homepage'); +}); + +app.use('/admin', admin); // mount the sub app +``` + +It is similar to the [baseUrl](#req.baseUrl) property of the `req` object, except `req.baseUrl` +returns the matched URL path, instead of the matched patterns. + +If a sub-app is mounted on multiple path patterns, `app.mountpath` returns the list of +patterns it is mounted on, as shown in the following example. + +```js +const admin = express(); + +admin.get('/', (req, res) => { + console.log(admin.mountpath); // [ '/adm{*splat}n', '/manager' ] + res.send('Admin Homepage'); +}); + +const secret = express(); +secret.get('/', (req, res) => { + console.log(secret.mountpath); // /secr{*splat}t + res.send('Admin Secret'); +}); + +admin.use('/secr{*splat}t', secret); // load the 'secret' router on '/secr{*splat}t', on the 'admin' sub app +app.use(['/adm{*splat}n', '/manager'], admin); // load the 'admin' router on '/adm{*splat}n' and '/manager', on the parent app +``` diff --git a/astro/src/content/docs/en/5x/api/application/app-onmount.md b/astro/src/content/docs/en/5x/api/application/app-onmount.md new file mode 100644 index 0000000000..0ca99b82e0 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/application/app-onmount.md @@ -0,0 +1,35 @@ +--- +title: app.on +description: The mount event is fired on a sub-app, when it is mounted on a parent app. The parent app is passed to the callback function. +--- + +

app.on('mount', callback(parent))

+ +The `mount` event is fired on a sub-app, when it is mounted on a parent app. The parent app is passed to the callback function. + +
+**NOTE** + +Sub-apps will: + +- Not inherit the value of settings that have a default value. You must set the value in the sub-app. +- Inherit the value of settings with no default value. + +For details, see [Application settings](/en/5x/api.html#app.settings.table). + +
+ +```js +const admin = express(); + +admin.on('mount', (parent) => { + console.log('Admin Mounted'); + console.log(parent); // refers to the parent app +}); + +admin.get('/', (req, res) => { + res.send('Admin Homepage'); +}); + +app.use('/admin', admin); +``` diff --git a/astro/src/content/docs/en/5x/api/application/app-param.md b/astro/src/content/docs/en/5x/api/application/app-param.md new file mode 100644 index 0000000000..b3ca5ccd89 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/application/app-param.md @@ -0,0 +1,83 @@ +--- +title: app.param +description: Add callback triggers to route parameters, where name is the name of the parameter or an array of parameter names, and callback is the callback function. +--- + +

app.param(name, callback)

+ +Add callback triggers to [route parameters](/{{ page.lang }}/guide/routing.html#route-parameters), where `name` is the name of the parameter or an array of them, and `callback` is the callback function. The parameters of the callback function are the request object, the response object, the next middleware, the value of the parameter and the name of the parameter, in that order. + +If `name` is an array, the `callback` trigger is registered for each parameter declared in it, in the order in which they are declared. Furthermore, for each declared parameter except the last one, a call to `next` inside the callback will call the callback for the next declared parameter. For the last parameter, a call to `next` will call the next middleware in place for the route currently being processed, just like it would if `name` were just a string. + +For example, when `:user` is present in a route path, you may map user loading logic to automatically provide `req.user` to the route, or perform validations on the parameter input. + +```js +app.param('user', (req, res, next, id) => { + // try to get the user details from the User model and attach it to the request object + User.find(id, (err, user) => { + if (err) { + next(err); + } else if (user) { + req.user = user; + next(); + } else { + next(new Error('failed to load user')); + } + }); +}); +``` + +Param callback functions are local to the router on which they are defined. They are not inherited by mounted apps or routers, nor are they triggered for route parameters inherited from parent routers. Hence, param callbacks defined on `app` will be triggered only by route parameters defined on `app` routes. + +All param callbacks will be called before any handler of any route in which the param occurs, and they will each be called only once in a request-response cycle, even if the parameter is matched in multiple routes, as shown in the following examples. + +```js +app.param('id', (req, res, next, id) => { + console.log('CALLED ONLY ONCE'); + next(); +}); + +app.get('/user/:id', (req, res, next) => { + console.log('although this matches'); + next(); +}); + +app.get('/user/:id', (req, res) => { + console.log('and this matches too'); + res.end(); +}); +``` + +On `GET /user/42`, the following is printed: + +``` +CALLED ONLY ONCE +although this matches +and this matches too +``` + +```js +app.param(['id', 'page'], (req, res, next, value) => { + console.log('CALLED ONLY ONCE with', value); + next(); +}); + +app.get('/user/:id/:page', (req, res, next) => { + console.log('although this matches'); + next(); +}); + +app.get('/user/:id/:page', (req, res) => { + console.log('and this matches too'); + res.end(); +}); +``` + +On `GET /user/42/3`, the following is printed: + +``` +CALLED ONLY ONCE with 42 +CALLED ONLY ONCE with 3 +although this matches +and this matches too +``` diff --git a/astro/src/content/docs/en/5x/api/application/app-path.md b/astro/src/content/docs/en/5x/api/application/app-path.md new file mode 100644 index 0000000000..78c6885667 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/application/app-path.md @@ -0,0 +1,24 @@ +--- +title: app.path +description: Returns the canonical path of the app, a string. +--- + +

app.path()

+ +Returns the canonical path of the app, a string. + +```js +const app = express(); +const blog = express(); +const blogAdmin = express(); + +app.use('/blog', blog); +blog.use('/admin', blogAdmin); + +console.log(app.path()); // '' +console.log(blog.path()); // '/blog' +console.log(blogAdmin.path()); // '/blog/admin' +``` + +The behavior of this method can become very complicated in complex cases of mounted apps: +it is usually better to use [req.baseUrl](#req.baseUrl) to get the canonical path of the app. diff --git a/astro/src/content/docs/en/5x/api/application/app-post-method.md b/astro/src/content/docs/en/5x/api/application/app-post-method.md new file mode 100644 index 0000000000..e961081239 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/application/app-post-method.md @@ -0,0 +1,19 @@ +--- +title: app.post +description: Routes HTTP POST requests to the specified path with the specified callback functions. +--- + +

app.post(path, callback [, callback ...])

+ +Routes HTTP POST requests to the specified path with the specified callback functions. +For more information, see the [routing guide](/{{page.lang}}/guide/routing.html). + +{% include api/en/5x/routing-args.html %} + +#### Example + +```js +app.post('/', (req, res) => { + res.send('POST request to homepage'); +}); +``` diff --git a/astro/src/content/docs/en/5x/api/application/app-put-method.md b/astro/src/content/docs/en/5x/api/application/app-put-method.md new file mode 100644 index 0000000000..2eb53a77eb --- /dev/null +++ b/astro/src/content/docs/en/5x/api/application/app-put-method.md @@ -0,0 +1,18 @@ +--- +title: app.put +description: Routes HTTP PUT requests to the specified path with the specified callback functions. +--- + +

app.put(path, callback [, callback ...])

+ +Routes HTTP PUT requests to the specified path with the specified callback functions. + +{% include api/en/5x/routing-args.html %} + +#### Example + +```js +app.put('/', (req, res) => { + res.send('PUT request to homepage'); +}); +``` diff --git a/astro/src/content/docs/en/5x/api/application/app-render.md b/astro/src/content/docs/en/5x/api/application/app-render.md new file mode 100644 index 0000000000..d5f65bf258 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/application/app-render.md @@ -0,0 +1,44 @@ +--- +title: app.render +description: Returns the rendered HTML of a view via the callback function. It accepts an optional parameter that is an object containing local variables for the vie +--- + +

app.render(view, [locals], callback)

+ +Returns the rendered HTML of a view via the `callback` function. It accepts an optional parameter +that is an object containing local variables for the view. It is like [res.render()](#res.render), +except it cannot send the rendered view to the client on its own. + +
+Think of `app.render()` as a utility function for generating rendered view strings. +Internally `res.render()` uses `app.render()` to render views. +
+ +
+The `view` argument performs file system operations like reading a file from +disk and evaluating Node.js modules, and as so for security reasons should not +contain input from the end-user. +
+ +
+The `locals` object is used by view engines to render a response. The object +keys may be particularly sensitive and should not contain user-controlled +input, as it may affect the operation of the view engine or provide a path to +cross-site scripting. Consult the documentation for the used view engine for +additional considerations. +
+ +
+The local variable `cache` is reserved for enabling view cache. Set it to `true`, if you want to +cache view during development; view caching is enabled in production by default. +
+ +```js +app.render('email', (err, html) => { + // ... +}); + +app.render('email', { name: 'Tobi' }, (err, html) => { + // ... +}); +``` diff --git a/astro/src/content/docs/en/5x/api/application/app-route.md b/astro/src/content/docs/en/5x/api/application/app-route.md new file mode 100644 index 0000000000..a0f9816d5d --- /dev/null +++ b/astro/src/content/docs/en/5x/api/application/app-route.md @@ -0,0 +1,26 @@ +--- +title: app.route +description: Returns an instance of a single route, which you can then use to handle HTTP verbs with optional middleware. +--- + +

app.route(path)

+ +Returns an instance of a single route, which you can then use to handle HTTP verbs with optional middleware. +Use `app.route()` to avoid duplicate route names (and thus typo errors). + +```js +const app = express(); + +app + .route('/events') + .all((req, res, next) => { + // runs for all HTTP verbs first + // think of it as route specific middleware! + }) + .get((req, res, next) => { + res.json({}); + }) + .post((req, res, next) => { + // maybe add a new event... + }); +``` diff --git a/astro/src/content/docs/en/5x/api/application/app-router.md b/astro/src/content/docs/en/5x/api/application/app-router.md new file mode 100644 index 0000000000..6bd664d291 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/application/app-router.md @@ -0,0 +1,24 @@ +--- +title: app.router +description: The application's in-built instance of router. This is created lazily, on first access. +--- + +

app.router

+ +The application's in-built instance of router. This is created lazily, on first access. + +```js +const express = require('express'); +const app = express(); +const router = app.router; + +router.get('/', (req, res) => { + res.send('hello world'); +}); + +app.listen(3000); +``` + +You can add middleware and HTTP method routes to the `router` just like an application. + +For more information, see [Router](#router). diff --git a/astro/src/content/docs/en/5x/api/application/app-set.md b/astro/src/content/docs/en/5x/api/application/app-set.md new file mode 100644 index 0000000000..87302a6b81 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/application/app-set.md @@ -0,0 +1,25 @@ +--- +title: app.set +description: Assigns setting name to value +--- + +

app.set(name, value)

+ +Assigns setting `name` to `value`. You may store any value that you want, +but certain names can be used to configure the behavior of the server. These +special names are listed in the [app settings table](#app.settings.table). + +Calling `app.set('foo', true)` for a Boolean property is the same as calling +`app.enable('foo')`. Similarly, calling `app.set('foo', false)` for a Boolean +property is the same as calling `app.disable('foo')`. + +Retrieve the value of a setting with [`app.get()`](#app.get). + +```js +app.set('title', 'My Site'); +app.get('title'); // "My Site" +``` + +

Application Settings

+ +{% include api/en/5x/app-settings.md %} diff --git a/astro/src/content/docs/en/5x/api/application/app-settings.md b/astro/src/content/docs/en/5x/api/application/app-settings.md new file mode 100644 index 0000000000..5443d70d77 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/application/app-settings.md @@ -0,0 +1,335 @@ +--- +title: App.Settings +description: The following table lists application settings. +--- + +The following table lists application settings. + +Note that sub-apps will: + +- Not inherit the value of settings that have a default value. You must set the value in the sub-app. +- Inherit the value of settings with no default value; these are explicitly noted in the table below. + +Exceptions: Sub-apps will inherit the value of `trust proxy` even though it has a default value (for backward-compatibility); +Sub-apps will not inherit the value of `view cache` in production (when `NODE_ENV` is "production"). + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyTypeDescriptionDefault
+ `case sensitive routing` + Boolean

Enable case sensitivity. + When enabled, "/Foo" and "/foo" are different routes. + When disabled, "/Foo" and "/foo" are treated the same.

+

NOTE: Sub-apps will inherit the value of this setting.

+
N/A (undefined) +
+ `env` + StringEnvironment mode. + Be sure to set to "production" in a production environment; + see Production best practices: performance and reliability. + + `process.env.NODE_ENV` (`NODE_ENV` environment variable) or "development" if `NODE_ENV` is not set. +
+ `etag` + Varied + Set the ETag response header. For possible values, see the [`etag` options table](#etag.options.table). + +[More about the HTTP ETag header](http://en.wikipedia.org/wiki/HTTP_ETag). + + + `weak` +
+ `jsonp callback name` + StringSpecifies the default JSONP callback name. + "callback" +
+ `json escape` + Boolean + Enable escaping JSON responses from the `res.json`, `res.jsonp`, and `res.send` APIs. This will escape the characters `<`, `>`, and `&` as Unicode escape sequences in JSON. The purpose of this is to assist with [mitigating certain types of persistent XSS attacks](https://blog.mozilla.org/security/2017/07/18/web-service-audits-firefox-accounts/) when clients sniff responses for HTML. +

NOTE: Sub-apps will inherit the value of this setting.

+
N/A (undefined)
+ `json replacer` + VariedThe 'replacer' argument used by `JSON.stringify`. +

NOTE: Sub-apps will inherit the value of this setting.

+
N/A (undefined) +
+ `json spaces` + VariedThe 'space' argument used by `JSON.stringify`. +This is typically set to the number of spaces to use to indent prettified JSON. +

NOTE: Sub-apps will inherit the value of this setting.

+
N/A (undefined)
+ `query parser` + Varied +Disable query parsing by setting the value to `false`, or set the query parser to use either "simple" or "extended" or a custom query string parsing function. + +The simple query parser is based on Node's native query parser, [querystring](http://nodejs.org/api/querystring.html). + +The extended query parser is based on [qs](https://www.npmjs.org/package/qs). + +A custom query string parsing function will receive the complete query string, and must return an object of query keys and their values. + + "simple"
+ `strict routing` + Boolean

Enable strict routing. + When enabled, the router treats "/foo" and "/foo/" as different. + Otherwise, the router treats "/foo" and "/foo/" as the same.

+

NOTE: Sub-apps will inherit the value of this setting.

+
N/A (undefined)
+ `subdomain offset` + NumberThe number of dot-separated parts of the host to remove to access subdomain.2
+ `trust proxy` + Varied + Indicates the app is behind a front-facing proxy, and to use the `X-Forwarded-*` headers to determine the connection and the IP address of the client. NOTE: `X-Forwarded-*` headers are easily spoofed and the detected IP addresses are unreliable. +

+ When enabled, Express attempts to determine the IP address of the client connected through the front-facing proxy, or series of proxies. The `req.ips` property, then contains an array of IP addresses the client is connected through. To enable it, use the values described in the trust proxy options table. +

+ The `trust proxy` setting is implemented using the proxy-addr package. For more information, see its documentation. +

+NOTE: Sub-apps will inherit the value of this setting, even though it has a default value. +

+
+ `false` (disabled) +
+ `views` + String or ArrayA directory or an array of directories for the application's views. If an array, the views are looked up in the order they occur in the array. + `process.cwd() + '/views'` +
+ `view cache` + Boolean

Enables view template compilation caching.

+

NOTE: Sub-apps will not inherit the value of this setting in production (when `NODE_ENV` is "production").

+
+ `true` in production, otherwise undefined. +
+ `view engine` + StringThe default engine extension to use when omitted. +

NOTE: Sub-apps will inherit the value of this setting.

+
N/A (undefined)
+ `x-powered-by` + BooleanEnables the "X-Powered-By: Express" HTTP header. + `true` +
+
+ +
Options for `trust proxy` setting
+ +

+ Read [Express behind proxies](/{{page.lang}}/guide/behind-proxies.html) for more + information. +

+ +
+ + + + + + + + + + + + + + + + + + + + +
TypeValue
Boolean + If `true`, the client's IP address is understood as the left-most entry in the `X-Forwarded-*` header. + +If `false`, the app is understood as directly facing the Internet and the client's IP address is derived from `req.connection.remoteAddress`. This is the default setting. + +
String
String containing comma-separated values
Array of strings
+ An IP address, subnet, or an array of IP addresses, and subnets to trust. Pre-configured subnet names are: + +- loopback - `127.0.0.1/8`, `::1/128` +- linklocal - `169.254.0.0/16`, `fe80::/10` +- uniquelocal - `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `fc00::/7` + +Set IP addresses in any of the following ways: + +Specify a single subnet: + +```js +app.set('trust proxy', 'loopback'); +``` + +Specify a subnet and an address: + +```js +app.set('trust proxy', 'loopback, 123.123.123.123'); +``` + +Specify multiple subnets as CSV: + +```js +app.set('trust proxy', 'loopback, linklocal, uniquelocal'); +``` + +Specify multiple subnets as an array: + +```js +app.set('trust proxy', ['loopback', 'linklocal', 'uniquelocal']); +``` + +When specified, the IP addresses or the subnets are excluded from the address determination process, and the untrusted IP address nearest to the application server is determined as the client's IP address. + +
Number + Trust the nth hop from the front-facing proxy server as the client. +
Function + Custom trust implementation. Use this only if you know what you are doing. + +```js +app.set('trust proxy', (ip) => { + if (ip === '127.0.0.1' || ip === '123.123.123.123') + return true; // trusted IPs + else return false; +}); +``` + +
+
+ +
Options for `etag` setting
+ +

+**NOTE**: These settings apply only to dynamic files, not static files. +The [express.static](#express.static) middleware ignores these settings. +

+ +

+ The ETag functionality is implemented using the + [etag](https://www.npmjs.org/package/etag) package. + For more information, see its documentation. +

+ +
+ + + + + + + + + + + + + + + + +
TypeValue
Boolean + `true` enables weak ETag. This is the default setting.
+ `false` disables ETag altogether. +
String + If "strong", enables strong ETag.
+ If "weak", enables weak ETag. +
FunctionCustom ETag function implementation. Use this only if you know what you are doing. + +```js +app.set('etag', (body, encoding) => { + return generateHash(body, encoding); // consider the function is defined +}); +``` + +
+
diff --git a/astro/src/content/docs/en/5x/api/application/app-use.md b/astro/src/content/docs/en/5x/api/application/app-use.md new file mode 100644 index 0000000000..8a16a4e339 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/application/app-use.md @@ -0,0 +1,310 @@ +--- +title: app.use +description: Mounts the specified [middleware](/{{page.lang}}/guide/using-middleware.html) function or functions +--- + +

app.use([path,] callback [, callback...])

+ +Mounts the specified [middleware](/{{page.lang}}/guide/using-middleware.html) function or functions +at the specified path: +the middleware function is executed when the base of the requested path matches `path`. + +{% include api/en/5x/routing-args.html %} + +#### Description + +A route will match any path that follows its path immediately with a "`/`". +For example: `app.use('/apple', ...)` will match "/apple", "/apple/images", +"/apple/images/news", and so on. + +Since `path` defaults to "/", middleware mounted without a path will be executed for every request to the app. +For example, this middleware function will be executed for _every_ request to the app: + +```js +app.use((req, res, next) => { + console.log('Time: %d', Date.now()); + next(); +}); +``` + +
+**NOTE** + +Sub-apps will: + +- Not inherit the value of settings that have a default value. You must set the value in the sub-app. +- Inherit the value of settings with no default value. + +For details, see [Application settings](/en/5x/api.html#app.settings.table). + +
+ +Middleware functions are executed sequentially, therefore the order of middleware inclusion is important. + +```js +// this middleware will not allow the request to go beyond it +app.use((req, res, next) => { + res.send('Hello World'); +}); + +// requests will never reach this route +app.get('/', (req, res) => { + res.send('Welcome'); +}); +``` + +**Error-handling middleware** + +Error-handling middleware always takes _four_ arguments. You must provide four arguments to identify it as an error-handling middleware function. Even if you don't need to use the `next` object, you must specify it to maintain the signature. Otherwise, the `next` object will be interpreted as regular middleware and will fail to handle errors. For details about error-handling middleware, see: [Error handling](/{{ page.lang }}/guide/error-handling.html). + +Define error-handling middleware functions in the same way as other middleware functions, except with four arguments instead of three, specifically with the signature `(err, req, res, next)`): + +```js +app.use((err, req, res, next) => { + console.error(err.stack); + res.status(500).send('Something broke!'); +}); +``` + +#### Path examples + +The following table provides some simple examples of valid `path` values for +mounting middleware. + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeExample
Path +Matches the exact path `/abcd` and any sub-paths starting with `/abcd/` (for example, `/abcd/foo`): + +```js +app.use('/abcd', (req, res, next) => { + next(); +}); +``` + +
Path Pattern +This will match paths starting with `/abcd` and `/abd`: + +```js +app.use('/ab{c}d', (req, res, next) => { + next(); +}); +``` + +
Regular Expression +This will match paths starting with `/abc` and `/xyz`: + +```js +app.use(/\/abc|\/xyz/, (req, res, next) => { + next(); +}); +``` + +
Array +This will match paths starting with `/abcd`, `/xyza`, `/lmn`, and `/pqr`: + +```js +app.use(['/abcd', '/xyza', /\/lmn|\/pqr/], (req, res, next) => { + next(); +}); +``` + +
+
+ +#### Middleware callback function examples + +The following table provides some simple examples of middleware functions that +can be used as the `callback` argument to `app.use()`, `app.METHOD()`, and `app.all()`. + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
UsageExample
Single Middleware +You can define and mount a middleware function locally. + +```js +app.use((req, res, next) => { + next(); +}); +``` + +A router is valid middleware. + +```js +const router = express.Router(); +router.get('/', (req, res, next) => { + next(); +}); +app.use(router); +``` + +An Express app is valid middleware. + +```js +const subApp = express(); +subApp.get('/', (req, res, next) => { + next(); +}); +app.use(subApp); +``` + +
Series of Middleware +You can specify more than one middleware function at the same mount path. + +```js +const r1 = express.Router(); +r1.get('/', (req, res, next) => { + next(); +}); + +const r2 = express.Router(); +r2.get('/', (req, res, next) => { + next(); +}); + +app.use(r1, r2); +``` + +
Array +Use an array to group middleware logically. + +```js +const r1 = express.Router(); +r1.get('/', (req, res, next) => { + next(); +}); + +const r2 = express.Router(); +r2.get('/', (req, res, next) => { + next(); +}); + +app.use([r1, r2]); +``` + +
Combination +You can combine all the above ways of mounting middleware. + +```js +function mw1(req, res, next) { + next(); +} +function mw2(req, res, next) { + next(); +} + +const r1 = express.Router(); +r1.get('/', (req, res, next) => { + next(); +}); + +const r2 = express.Router(); +r2.get('/', (req, res, next) => { + next(); +}); + +const subApp = express(); +subApp.get('/', (req, res, next) => { + next(); +}); + +app.use(mw1, [mw2, r1, r2], subApp); +``` + +
+
+ +Following are some examples of using the [express.static](/{{page.lang}}/guide/using-middleware.html#middleware.built-in) +middleware in an Express app. + +Serve static content for the app from the "public" directory in the application directory: + +```js +// GET /style.css etc +app.use(express.static(path.join(__dirname, 'public'))); +``` + +Mount the middleware at "/static" to serve static content only when their request path is prefixed with "/static": + +```js +// GET /static/style.css etc. +app.use('/static', express.static(path.join(__dirname, 'public'))); +``` + +Disable logging for static content requests by loading the logger middleware after the static middleware: + +```js +app.use(express.static(path.join(__dirname, 'public'))); +app.use(logger()); +``` + +Serve static files from multiple directories, but give precedence to "./public" over the others: + +```js +app.use(express.static(path.join(__dirname, 'public'))); +app.use(express.static(path.join(__dirname, 'files'))); +app.use(express.static(path.join(__dirname, 'uploads'))); +``` diff --git a/astro/src/content/docs/en/5x/api/application/overview.md b/astro/src/content/docs/en/5x/api/application/overview.md new file mode 100644 index 0000000000..ee9b6ab334 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/application/overview.md @@ -0,0 +1,132 @@ +--- +title: Properties +description: section markdown="1"> +--- + +

Application

+ +The `app` object conventionally denotes the Express application. +Create it by calling the top-level `express()` function exported by the Express module: + +```js +const express = require('express'); +const app = express(); + +app.get('/', (req, res) => { + res.send('hello world'); +}); + +app.listen(3000); +``` + +The `app` object has methods for + +- Routing HTTP requests; see for example, [app.METHOD](#app.METHOD) and [app.param](#app.param). +- Configuring middleware; see [app.route](#app.route). +- Rendering HTML views; see [app.render](#app.render). +- Registering a template engine; see [app.engine](#app.engine). + +It also has settings (properties) that affect how the application behaves; +for more information, see [Application settings](#app.settings.table). + +
+The Express application object can be referred from the [request object](#req) and the [response object](#res) as `req.app`, and `res.app`, respectively. +
+ +

Properties

+ +
+ {% include api/en/5x/app-locals.md %} +
+ +
+ {% include api/en/5x/app-mountpath.md %} +
+ +
+ {% include api/en/5x/app-router.md %} +
+ +

Events

+ +
+ {% include api/en/5x/app-onmount.md %} +
+ +

Methods

+ +
+ {% include api/en/5x/app-all.md %} +
+ +
+ {% include api/en/5x/app-delete-method.md %} +
+ +
+ {% include api/en/5x/app-disable.md %} +
+ +
+ {% include api/en/5x/app-disabled.md %} +
+ +
+ {% include api/en/5x/app-enable.md %} +
+ +
+ {% include api/en/5x/app-enabled.md %} +
+ +
+ {% include api/en/5x/app-engine.md %} +
+ +
+ {% include api/en/5x/app-get.md %} +
+ +
+ {% include api/en/5x/app-get-method.md %} +
+ +
+ {% include api/en/5x/app-listen.md %} +
+ +
+ {% include api/en/5x/app-METHOD.md %} +
+ +
+ {% include api/en/5x/app-param.md %} +
+ +
+ {% include api/en/5x/app-path.md %} +
+ +
+ {% include api/en/5x/app-post-method.md %} +
+ +
+ {% include api/en/5x/app-put-method.md %} +
+ +
+ {% include api/en/5x/app-render.md %} +
+ +
+ {% include api/en/5x/app-route.md %} +
+ +
+ {% include api/en/5x/app-set.md %} +
+ +
+ {% include api/en/5x/app-use.md %} +
diff --git a/astro/src/content/docs/en/5x/api/express/express.json.md b/astro/src/content/docs/en/5x/api/express/express.json.md new file mode 100644 index 0000000000..a905bf45ed --- /dev/null +++ b/astro/src/content/docs/en/5x/api/express/express.json.md @@ -0,0 +1,43 @@ +--- +title: express.json +description: This is a built-in middleware function in Express. It parses incoming requests +--- + +

express.json([options])

+ +This is a built-in middleware function in Express. It parses incoming requests +with JSON payloads and is based on +[body-parser](/resources/middleware/body-parser.html). + +Returns middleware that only parses JSON and only looks at requests where +the `Content-Type` header matches the `type` option. This parser accepts any +Unicode encoding of the body and supports automatic inflation of `gzip` and +`deflate` encodings. + +A new `body` object containing the parsed data is populated on the `request` +object after the middleware (i.e. `req.body`), or `undefined` if +there was no body to parse, the `Content-Type` was not matched, or an error +occurred. + +
+As `req.body`'s shape is based on user-controlled input, all properties and +values in this object are untrusted and should be validated before trusting. +For example, `req.body.foo.toString()` may fail in multiple ways, for example +`foo` may not be there or may not be a string, and `toString` may not be a +function and instead a string or other user-input. +
+ +The following table describes the properties of the optional `options` object. + +
+ +| Property | Description | Type | Default | +| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | -------------------- | +| `inflate` | Enables or disables handling deflated (compressed) bodies; when disabled, deflated bodies are rejected. | Boolean | `true` | +| `limit` | Controls the maximum request body size. If this is a number, then the value specifies the number of bytes; if it is a string, the value is passed to the [bytes](https://www.npmjs.com/package/bytes) library for parsing. | Mixed | `"100kb"` | +| `reviver` | The `reviver` option is passed directly to `JSON.parse` as the second argument. You can find more information on this argument [in the MDN documentation about JSON.parse](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Example.3A_Using_the_reviver_parameter). | Function | `null` | +| `strict` | Enables or disables only accepting arrays and objects; when disabled will accept anything `JSON.parse` accepts. | Boolean | `true` | +| `type` | This is used to determine what media type the middleware will parse. This option can be a string, array of strings, or a function. If not a function, `type` option is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme) library and this can be an extension name (like `json`), a mime type (like `application/json`), or a mime type with a wildcard (like `*/*` or `*/json`). If a function, the `type` option is called as `fn(req)` and the request is parsed if it returns a truthy value. | Mixed | `"application/json"` | +| `verify` | This option, if supplied, is called as `verify(req, res, buf, encoding)`, where `buf` is a `Buffer` of the raw request body and `encoding` is the encoding of the request. The parsing can be aborted by throwing an error. | Function | `undefined` | + +
diff --git a/astro/src/content/docs/en/5x/api/express/express.md b/astro/src/content/docs/en/5x/api/express/express.md new file mode 100644 index 0000000000..163c1c3f1f --- /dev/null +++ b/astro/src/content/docs/en/5x/api/express/express.md @@ -0,0 +1,39 @@ +--- +title: Methods +description: section markdown="1"> +--- + +

express()

+ +Creates an Express application. The `express()` function is a top-level function exported by the `express` module. + +```js +const express = require('express'); +const app = express(); +``` + +

Methods

+ +
+ {% include api/en/5x/express.json.md %} +
+ +
+ {% include api/en/5x/express.raw.md %} +
+ +
+ {% include api/en/5x/express.router.md %} +
+ +
+ {% include api/en/5x/express.static.md %} +
+ +
+ {% include api/en/5x/express.text.md %} +
+ +
+ {% include api/en/5x/express.urlencoded.md %} +
diff --git a/astro/src/content/docs/en/5x/api/express/express.raw.md b/astro/src/content/docs/en/5x/api/express/express.raw.md new file mode 100644 index 0000000000..04011354a5 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/express/express.raw.md @@ -0,0 +1,41 @@ +--- +title: express.raw +description: This is a built-in middleware function in Express. It parses incoming request +--- + +

express.raw([options])

+ +This is a built-in middleware function in Express. It parses incoming request +payloads into a `Buffer` and is based on +[body-parser](/resources/middleware/body-parser.html). + +Returns middleware that parses all bodies as a `Buffer` and only looks at requests +where the `Content-Type` header matches the `type` option. This parser accepts +any Unicode encoding of the body and supports automatic inflation of `gzip` and +`deflate` encodings. + +A new `body` `Buffer` containing the parsed data is populated on the `request` +object after the middleware (i.e. `req.body`), or `undefined` if +there was no body to parse, the `Content-Type` was not matched, or an error +occurred. + +
+As `req.body`'s shape is based on user-controlled input, all properties and +values in this object are untrusted and should be validated before trusting. +For example, `req.body.toString()` may fail in multiple ways, for example +stacking multiple parsers `req.body` may be from a different parser. Testing +that `req.body` is a `Buffer` before calling buffer methods is recommended. +
+ +The following table describes the properties of the optional `options` object. + +
+ +| Property | Description | Type | Default | +| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ---------------------------- | +| `inflate` | Enables or disables handling deflated (compressed) bodies; when disabled, deflated bodies are rejected. | Boolean | `true` | +| `limit` | Controls the maximum request body size. If this is a number, then the value specifies the number of bytes; if it is a string, the value is passed to the [bytes](https://www.npmjs.com/package/bytes) library for parsing. | Mixed | `"100kb"` | +| `type` | This is used to determine what media type the middleware will parse. This option can be a string, array of strings, or a function. If not a function, `type` option is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme) library and this can be an extension name (like `bin`), a mime type (like `application/octet-stream`), or a mime type with a wildcard (like `*/*` or `application/*`). If a function, the `type` option is called as `fn(req)` and the request is parsed if it returns a truthy value. | Mixed | `"application/octet-stream"` | +| `verify` | This option, if supplied, is called as `verify(req, res, buf, encoding)`, where `buf` is a `Buffer` of the raw request body and `encoding` is the encoding of the request. The parsing can be aborted by throwing an error. | Function | `undefined` | + +
diff --git a/astro/src/content/docs/en/5x/api/express/express.router.md b/astro/src/content/docs/en/5x/api/express/express.router.md new file mode 100644 index 0000000000..2474bc3fa0 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/express/express.router.md @@ -0,0 +1,29 @@ +--- +title: express.Router +description: Creates a new [router](#router) object. +--- + +

express.Router([options])

+ +Creates a new [router](#router) object. + +```js +const router = express.Router([options]); +``` + +The optional `options` parameter specifies the behavior of the router. + +
+ +| Property | Description | Default | Availability | +| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | ------------ | +| `caseSensitive` | Enable case sensitivity. | Disabled by default, treating "/Foo" and "/foo" as the same. | | +| `mergeParams` | Preserve the `req.params` values from the parent router. If the parent and the child have conflicting param names, the child's value take precedence. | `false` | 4.5.0+ | +| `strict` | Enable strict routing. | Disabled by default, "/foo" and "/foo/" are treated the same by the router. |   | + +
+ +You can add middleware and HTTP method routes (such as `get`, `put`, `post`, and +so on) to `router` just like an application. + +For more information, see [Router](#router). diff --git a/astro/src/content/docs/en/5x/api/express/express.static.md b/astro/src/content/docs/en/5x/api/express/express.static.md new file mode 100644 index 0000000000..cb16475ae6 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/express/express.static.md @@ -0,0 +1,99 @@ +--- +title: express.static +description: This is a built-in middleware function in Express. +--- + +

express.static(root, [options])

+ +This is a built-in middleware function in Express. +It serves static files and is based on [serve-static](/resources/middleware/serve-static.html). + +
NOTE: For best results, [use a reverse proxy](/{{page.lang}}/advanced/best-practice-performance.html#use-a-reverse-proxy) cache to improve performance of serving static assets. +
+ +The `root` argument specifies the root directory from which to serve static assets. +The function determines the file to serve by combining `req.url` with the provided `root` directory. +When a file is not found, instead of sending a 404 response, it instead calls `next()` +to move on to the next middleware, allowing for stacking and fall-backs. + +The following table describes the properties of the `options` object. +See also the [example below](#example.of.express.static). + +
+ +| Property | Description | Type | Default | +| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------ | +| `dotfiles` | Determines how dotfiles (files or directories that begin with a dot ".") are treated.

See [dotfiles](#dotfiles) below. | String | "ignore" | +| `etag` | Enable or disable etag generation

NOTE: `express.static` always sends weak ETags. | Boolean | `true` | +| `extensions` | Sets file extension fallbacks: If a file is not found, search for files with the specified extensions and serve the first one found. Example: `['html', 'htm']`. | Mixed | `false` | +| `fallthrough` | Let client errors fall-through as unhandled requests, otherwise forward a client error.

See [fallthrough](#fallthrough) below. | Boolean | `true` | +| `immutable` | Enable or disable the `immutable` directive in the `Cache-Control` response header. If enabled, the `maxAge` option should also be specified to enable caching. The `immutable` directive will prevent supported clients from making conditional requests during the life of the `maxAge` option to check if the file has changed. | Boolean | `false` | +| `index` | Sends the specified directory index file. Set to `false` to disable directory indexing. | Mixed | "index.html" | +| `lastModified` | Set the `Last-Modified` header to the last modified date of the file on the OS. | Boolean | `true` | +| `maxAge` | Set the max-age property of the Cache-Control header in milliseconds or a string in [ms format](https://www.npmjs.org/package/ms). | Number | 0 | +| `redirect` | Redirect to trailing "/" when the pathname is a directory. | Boolean | `true` | +| `setHeaders` | Function for setting HTTP headers to serve with the file.

See [setHeaders](#setHeaders) below. | Function | | +| `acceptRanges` | Enable or disable accepting ranged requests. Disabling this will not send the Accept-Ranges header and will ignore the contents of the Range request header. | Boolean | true | +| `cacheControl` | Enable or disable setting the Cache-Control response header. Disabling this will ignore the immutable and maxAge options. | Boolean | true | + +
+ +For more information, see [Serving static files in Express](/starter/static-files.html). +and [Using middleware - Built-in middleware](/{{page.lang}}/guide/using-middleware.html#middleware.built-in). + +
dotfiles
+ +Possible values for this option are: + +- "allow" - No special treatment for dotfiles. +- "deny" - Deny a request for a dotfile, respond with `403`, then call `next()`. +- "ignore" - Act as if the dotfile does not exist, respond with `404`, then call `next()`. + +
fallthrough
+ +When this option is `true`, client errors such as a bad request or a request to a non-existent +file will cause this middleware to simply call `next()` to invoke the next middleware in the stack. +When false, these errors (even 404s), will invoke `next(err)`. + +Set this option to `true` so you can map multiple physical directories +to the same web address or for routes to fill in non-existent files. + +Use `false` if you have mounted this middleware at a path designed +to be strictly a single file system directory, which allows for short-circuiting 404s +for less overhead. This middleware will also reply to all methods. + +
setHeaders
+ +For this option, specify a function to set custom response headers. Alterations to the headers must occur synchronously. + +The signature of the function is: + +```js +fn(res, path, stat); +``` + +Arguments: + +- `res`, the [response object](#res). +- `path`, the file path that is being sent. +- `stat`, the `stat` object of the file that is being sent. + +

Example of express.static

+ +Here is an example of using the `express.static` middleware function with an elaborate options object: + +```js +const options = { + dotfiles: 'ignore', + etag: false, + extensions: ['htm', 'html'], + index: false, + maxAge: '1d', + redirect: false, + setHeaders(res, path, stat) { + res.set('x-timestamp', Date.now()); + }, +}; + +app.use(express.static('public', options)); +``` diff --git a/astro/src/content/docs/en/5x/api/express/express.text.md b/astro/src/content/docs/en/5x/api/express/express.text.md new file mode 100644 index 0000000000..10647ca41c --- /dev/null +++ b/astro/src/content/docs/en/5x/api/express/express.text.md @@ -0,0 +1,42 @@ +--- +title: express.text +description: This is a built-in middleware function in Express. It parses incoming request +--- + +

express.text([options])

+ +This is a built-in middleware function in Express. It parses incoming request +payloads into a string and is based on +[body-parser](/resources/middleware/body-parser.html). + +Returns middleware that parses all bodies as a string and only looks at requests +where the `Content-Type` header matches the `type` option. This parser accepts +any Unicode encoding of the body and supports automatic inflation of `gzip` and +`deflate` encodings. + +A new `body` string containing the parsed data is populated on the `request` +object after the middleware (i.e. `req.body`), or `undefined` if +there was no body to parse, the `Content-Type` was not matched, or an error +occurred. + +
+As `req.body`'s shape is based on user-controlled input, all properties and +values in this object are untrusted and should be validated before trusting. +For example, `req.body.trim()` may fail in multiple ways, for example +stacking multiple parsers `req.body` may be from a different parser. Testing +that `req.body` is a string before calling string methods is recommended. +
+ +The following table describes the properties of the optional `options` object. + +
+ +| Property | Description | Type | Default | +| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | -------------- | +| `defaultCharset` | Specify the default character set for the text content if the charset is not specified in the `Content-Type` header of the request. | String | `"utf-8"` | +| `inflate` | Enables or disables handling deflated (compressed) bodies; when disabled, deflated bodies are rejected. | Boolean | `true` | +| `limit` | Controls the maximum request body size. If this is a number, then the value specifies the number of bytes; if it is a string, the value is passed to the [bytes](https://www.npmjs.com/package/bytes) library for parsing. | Mixed | `"100kb"` | +| `type` | This is used to determine what media type the middleware will parse. This option can be a string, array of strings, or a function. If not a function, `type` option is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme) library and this can be an extension name (like `txt`), a mime type (like `text/plain`), or a mime type with a wildcard (like `*/*` or `text/*`). If a function, the `type` option is called as `fn(req)` and the request is parsed if it returns a truthy value. | Mixed | `"text/plain"` | +| `verify` | This option, if supplied, is called as `verify(req, res, buf, encoding)`, where `buf` is a `Buffer` of the raw request body and `encoding` is the encoding of the request. The parsing can be aborted by throwing an error. | Function | `undefined` | + +
diff --git a/astro/src/content/docs/en/5x/api/express/express.urlencoded.md b/astro/src/content/docs/en/5x/api/express/express.urlencoded.md new file mode 100644 index 0000000000..6da362522b --- /dev/null +++ b/astro/src/content/docs/en/5x/api/express/express.urlencoded.md @@ -0,0 +1,45 @@ +--- +title: express.urlencoded +description: This is a built-in middleware function in Express. It parses incoming requests +--- + +

express.urlencoded([options])

+ +This is a built-in middleware function in Express. It parses incoming requests +with urlencoded payloads and is based on [body-parser](/resources/middleware/body-parser.html). + +Returns middleware that only parses urlencoded bodies and only looks at +requests where the `Content-Type` header matches the `type` option. This +parser accepts only UTF-8 encoding of the body and supports automatic +inflation of `gzip` and `deflate` encodings. + +A new `body` object containing the parsed data is populated on the `request` +object after the middleware (i.e. `req.body`), or `undefined` if +there was no body to parse, the `Content-Type` was not matched, or an error +occurred. This object will contain key-value pairs, where the value can be +a string or array (when `extended` is `false`), or any type (when `extended` +is `true`). + +
+As `req.body`'s shape is based on user-controlled input, all properties and +values in this object are untrusted and should be validated before trusting. +For example, `req.body.foo.toString()` may fail in multiple ways, for example +`foo` may not be there or may not be a string, and `toString` may not be a +function and instead a string or other user-input. +
+ +The following table describes the properties of the optional `options` object. + +
+ +| Property | Description | Type | Default | +| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------------------------------- | +| `extended` | This option allows to choose between parsing the URL-encoded data with the `querystring` library (when `false`) or the `qs` library (when `true`). The "extended" syntax allows for rich objects and arrays to be encoded into the URL-encoded format, allowing for a JSON-like experience with URL-encoded. For more information, please [see the qs library](https://www.npmjs.org/package/qs#readme). | Boolean | `false` | +| `inflate` | Enables or disables handling deflated (compressed) bodies; when disabled, deflated bodies are rejected. | Boolean | `true` | +| `limit` | Controls the maximum request body size. If this is a number, then the value specifies the number of bytes; if it is a string, the value is passed to the [bytes](https://www.npmjs.com/package/bytes) library for parsing. | Mixed | `"100kb"` | +| `parameterLimit` | This option controls the maximum number of parameters that are allowed in the URL-encoded data. If a request contains more parameters than this value, an error will be raised. | Number | `1000` | +| `type` | This is used to determine what media type the middleware will parse. This option can be a string, array of strings, or a function. If not a function, `type` option is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme) library and this can be an extension name (like `urlencoded`), a mime type (like `application/x-www-form-urlencoded`), or a mime type with a wildcard (like `*/x-www-form-urlencoded`). If a function, the `type` option is called as `fn(req)` and the request is parsed if it returns a truthy value. | Mixed | `"application/x-www-form-urlencoded"` | +| `verify` | This option, if supplied, is called as `verify(req, res, buf, encoding)`, where `buf` is a `Buffer` of the raw request body and `encoding` is the encoding of the request. The parsing can be aborted by throwing an error. | Function | `undefined` | +| `depth` | Configure the maximum depth of the `qs` library when `extended` is `true`. This allows you to limit the amount of keys that are parsed and can be useful to prevent certain types of abuse. Defaults to `32`. It is recommended to keep this value as low as possible. | Number | `32` | + +
diff --git a/astro/src/content/docs/en/5x/api/request/overview.md b/astro/src/content/docs/en/5x/api/request/overview.md new file mode 100644 index 0000000000..203654e039 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/overview.md @@ -0,0 +1,160 @@ +--- +title: Properties +description: The req object represents the HTTP request and has properties for the request query string, parameters, body, HTTP headers, and so on +--- + +

Request

+ +The `req` object represents the HTTP request and has properties for the +request query string, parameters, body, HTTP headers, and so on. In this documentation and by convention, +the object is always referred to as `req` (and the HTTP response is `res`) but its actual name is determined +by the parameters to the callback function in which you're working. + +For example: + +```js +app.get('/user/:id', (req, res) => { + res.send(`user ${req.params.id}`); +}); +``` + +But you could just as well have: + +```js +app.get('/user/:id', (request, response) => { + response.send(`user ${request.params.id}`); +}); +``` + +The `req` object is an enhanced version of Node's own request object +and supports all [built-in fields and methods](https://nodejs.org/api/http.html#http_class_http_incomingmessage). + +

Properties

+ +
+In Express 4, `req.files` is no longer available on the `req` object by default. To access uploaded files +on the `req.files` object, use multipart-handling middleware like [busboy](https://www.npmjs. +com/package/busboy), [multer](https://www.npmjs.com/package/multer), +[formidable](https://www.npmjs.com/package/formidable), +[multiparty](https://www.npmjs.com/package/multiparty), +[connect-multiparty](https://www.npmjs.com/package/connect-multiparty), +or [pez](https://www.npmjs.com/package/pez). +
+ +
+ {% include api/en/5x/req-app.md %} +
+ +
+ {% include api/en/5x/req-baseUrl.md %} +
+ +
+ {% include api/en/5x/req-body.md %} +
+ +
+ {% include api/en/5x/req-cookies.md %} +
+ +
+ {% include api/en/5x/req-fresh.md %} +
+ +
+ {% include api/en/5x/req-host.md %} +
+ +
+ {% include api/en/5x/req-hostname.md %} +
+ +
+ {% include api/en/5x/req-ip.md %} +
+ +
+ {% include api/en/5x/req-ips.md %} +
+ +
+ {% include api/en/5x/req-method.md %} +
+ +
+ {% include api/en/5x/req-originalUrl.md %} +
+ +
+ {% include api/en/5x/req-params.md %} +
+ +
+ {% include api/en/5x/req-path.md %} +
+ +
+ {% include api/en/5x/req-protocol.md %} +
+ +
+ {% include api/en/5x/req-query.md %} +
+ +
+ {% include api/en/5x/req-res.md %} +
+ +
+ {% include api/en/5x/req-route.md %} +
+ +
+ {% include api/en/5x/req-secure.md %} +
+ +
+ {% include api/en/5x/req-signedCookies.md %} +
+ +
+ {% include api/en/5x/req-stale.md %} +
+ +
+ {% include api/en/5x/req-subdomains.md %} +
+ +
+ {% include api/en/5x/req-xhr.md %} +
+ +

Methods

+ +
+ {% include api/en/5x/req-accepts.md %} +
+ +
+ {% include api/en/5x/req-acceptsCharsets.md %} +
+ +
+ {% include api/en/5x/req-acceptsEncodings.md %} +
+ +
+ {% include api/en/5x/req-acceptsLanguages.md %} +
+ +
+ {% include api/en/5x/req-get.md %} +
+ +
+ {% include api/en/5x/req-is.md %} +
+ +
+ {% include api/en/5x/req-range.md %} +
diff --git a/astro/src/content/docs/en/5x/api/request/req-accepts.md b/astro/src/content/docs/en/5x/api/request/req-accepts.md new file mode 100644 index 0000000000..763c6c6ab7 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/req-accepts.md @@ -0,0 +1,41 @@ +--- +title: req.accepts +description: Checks if the specified content types are acceptable, based on the request Accept HTTP header field. +--- + +

req.accepts(types)

+ +Checks if the specified content types are acceptable, based on the request's `Accept` HTTP header field. +The method returns the best match, or if none of the specified content types is acceptable, returns +`false` (in which case, the application should respond with `406 "Not Acceptable"`). + +The `type` value may be a single MIME type string (such as "application/json"), +an extension name such as "json", a comma-delimited list, or an array. For a +list or array, the method returns the _best_ match (if any). + +```js +// Accept: text/html +req.accepts('html'); +// => "html" + +// Accept: text/*, application/json +req.accepts('html'); +// => "html" +req.accepts('text/html'); +// => "text/html" +req.accepts(['json', 'text']); +// => "json" +req.accepts('application/json'); +// => "application/json" + +// Accept: text/*, application/json +req.accepts('image/png'); +req.accepts('png'); +// => false + +// Accept: text/*;q=.5, application/json +req.accepts(['html', 'json']); +// => "json" +``` + +For more information, or if you have issues or concerns, see [accepts](https://github.com/expressjs/accepts). diff --git a/astro/src/content/docs/en/5x/api/request/req-acceptsCharsets.md b/astro/src/content/docs/en/5x/api/request/req-acceptsCharsets.md new file mode 100644 index 0000000000..69bed2797b --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/req-acceptsCharsets.md @@ -0,0 +1,12 @@ +--- +title: req.acceptsCharsets +description: Returns the first accepted charset of the specified character sets, +--- + +

req.acceptsCharsets(charset [, ...])

+ +Returns the first accepted charset of the specified character sets, +based on the request's `Accept-Charset` HTTP header field. +If none of the specified charsets is accepted, returns `false`. + +For more information, or if you have issues or concerns, see [accepts](https://github.com/expressjs/accepts). diff --git a/astro/src/content/docs/en/5x/api/request/req-acceptsEncodings.md b/astro/src/content/docs/en/5x/api/request/req-acceptsEncodings.md new file mode 100644 index 0000000000..384e10bb6a --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/req-acceptsEncodings.md @@ -0,0 +1,12 @@ +--- +title: req.acceptsEncodings +description: Returns the first accepted encoding of the specified encodings, +--- + +

req.acceptsEncodings(encoding [, ...])

+ +Returns the first accepted encoding of the specified encodings, +based on the request's `Accept-Encoding` HTTP header field. +If none of the specified encodings is accepted, returns `false`. + +For more information, or if you have issues or concerns, see [accepts](https://github.com/expressjs/accepts). diff --git a/astro/src/content/docs/en/5x/api/request/req-acceptsLanguages.md b/astro/src/content/docs/en/5x/api/request/req-acceptsLanguages.md new file mode 100644 index 0000000000..998805fa9e --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/req-acceptsLanguages.md @@ -0,0 +1,20 @@ +--- +title: req.acceptsLanguages +description: Returns the first accepted language of the specified languages, +--- + +

req.acceptsLanguages([lang, ...])

+ +Returns the first accepted language of the specified languages, +based on the request's `Accept-Language` HTTP header field. +If none of the specified languages is accepted, returns `false`. + +If no `lang` argument is given, then `req.acceptsLanguages()` +returns all languages from the HTTP `Accept-Language` header +as an `Array`. + +For more information, or if you have issues or concerns, see [accepts](https://github.com/expressjs/accepts). + +Express (5.x) source: [request.js line 172](https://github.com/expressjs/express/blob/v5.1.0/lib/request.js#L172) + +Accepts (2.0) source: [index.js line 195](https://github.com/jshttp/accepts/blob/2.0.0/index.js#L195) diff --git a/astro/src/content/docs/en/5x/api/request/req-app.md b/astro/src/content/docs/en/5x/api/request/req-app.md new file mode 100644 index 0000000000..6594a0142a --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/req-app.md @@ -0,0 +1,25 @@ +--- +title: req.app +description: This property holds a reference to the instance of the Express application that is using the middleware. +--- + +

req.app

+ +This property holds a reference to the instance of the Express application that is using the middleware. + +If you follow the pattern in which you create a module that just exports a middleware function +and `require()` it in your main file, then the middleware can access the Express instance via `req.app` + +For example: + +```js +// index.js +app.get('/viewdirectory', require('./mymiddleware.js')); +``` + +```js +// mymiddleware.js +module.exports = (req, res) => { + res.send(`The views directory is ${req.app.get('views')}`); +}; +``` diff --git a/astro/src/content/docs/en/5x/api/request/req-base-url.md b/astro/src/content/docs/en/5x/api/request/req-base-url.md new file mode 100644 index 0000000000..a49e6912ca --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/req-base-url.md @@ -0,0 +1,35 @@ +--- +title: req.baseUrl +description: The URL path on which a router instance was mounted. +--- + +

req.baseUrl

+ +The URL path on which a router instance was mounted. + +The `req.baseUrl` property is similar to the [mountpath](#app.mountpath) property of the `app` object, +except `app.mountpath` returns the matched path pattern(s). + +For example: + +```js +const greet = express.Router(); + +greet.get('/jp', (req, res) => { + console.log(req.baseUrl); // /greet + res.send('Konichiwa!'); +}); + +app.use('/greet', greet); // load the router on '/greet' +``` + +Even if you use a path pattern or a set of path patterns to load the router, +the `baseUrl` property returns the matched string, not the pattern(s). In the +following example, the `greet` router is loaded on two path patterns. + +```js +app.use(['/gre:"param"t', '/hel{l}o'], greet); // load the router on '/gre:"param"t' and '/hel{l}o' +``` + +When a request is made to `/greet/jp`, `req.baseUrl` is "/greet". When a request is +made to `/hello/jp`, `req.baseUrl` is "/hello". diff --git a/astro/src/content/docs/en/5x/api/request/req-body.md b/astro/src/content/docs/en/5x/api/request/req-body.md new file mode 100644 index 0000000000..a921f3c624 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/req-body.md @@ -0,0 +1,30 @@ +--- +title: req.body +description: Contains key-value pairs of data submitted in the request body. +--- + +

req.body

+ +Contains key-value pairs of data submitted in the request body. +By default, it is `undefined`, and is populated when you use body-parsing middleware such +as [`express.json()`](#express.json) or [`express.urlencoded()`](#express.urlencoded). + +
+As `req.body`'s shape is based on user-controlled input, all properties and values in this object are untrusted and should be validated before trusting. For example, `req.body.foo.toString()` may fail in multiple ways, for example `foo` may not be there or may not be a string, and `toString` may not be a function and instead a string or other user-input. +
+ +The following example shows how to use body-parsing middleware to populate `req.body`. + +```js +const express = require('express'); + +const app = express(); + +app.use(express.json()); // for parsing application/json +app.use(express.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded + +app.post('/profile', (req, res, next) => { + console.log(req.body); + res.json(req.body); +}); +``` diff --git a/astro/src/content/docs/en/5x/api/request/req-cookies.md b/astro/src/content/docs/en/5x/api/request/req-cookies.md new file mode 100644 index 0000000000..806b6dc5ab --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/req-cookies.md @@ -0,0 +1,19 @@ +--- +title: req.cookies +description: When using cookie-parser middleware, this property is an object that contains cookies sent by the request +--- + +

req.cookies

+ +When using [cookie-parser](https://www.npmjs.com/package/cookie-parser) middleware, this property is an object that +contains cookies sent by the request. If the request contains no cookies, it defaults to `{}`. + +```js +// Cookie: name=tj +console.dir(req.cookies.name); +// => "tj" +``` + +If the cookie has been signed, you have to use [req.signedCookies](#req.signedCookies). + +For more information, issues, or concerns, see [cookie-parser](https://github.com/expressjs/cookie-parser). diff --git a/astro/src/content/docs/en/5x/api/request/req-fresh.md b/astro/src/content/docs/en/5x/api/request/req-fresh.md new file mode 100644 index 0000000000..293c12e898 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/req-fresh.md @@ -0,0 +1,18 @@ +--- +title: req.fresh +description: When the response is still fresh in the client cache true is returned, otherwise false is returned to indicate that the client cache is now stale. +--- + +

req.fresh

+ +When the response is still "fresh" in the client's cache `true` is returned, otherwise `false` is returned to indicate that the client cache is now stale and the full response should be sent. + +When a client sends the `Cache-Control: no-cache` request header to indicate an end-to-end reload request, this module will return `false` to make handling these requests transparent. + +Further details for how cache validation works can be found in the +[HTTP/1.1 Caching Specification](https://tools.ietf.org/html/rfc7234). + +```js +console.dir(req.fresh); +// => true +``` diff --git a/astro/src/content/docs/en/5x/api/request/req-get.md b/astro/src/content/docs/en/5x/api/request/req-get.md new file mode 100644 index 0000000000..ad116d8421 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/req-get.md @@ -0,0 +1,22 @@ +--- +title: req.get +description: Returns the specified HTTP request header field (case-insensitive match). +--- + +

req.get(field)

+ +Returns the specified HTTP request header field (case-insensitive match). +The `Referrer` and `Referer` fields are interchangeable. + +```js +req.get('Content-Type'); +// => "text/plain" + +req.get('content-type'); +// => "text/plain" + +req.get('Something'); +// => undefined +``` + +Aliased as `req.header(field)`. diff --git a/astro/src/content/docs/en/5x/api/request/req-host.md b/astro/src/content/docs/en/5x/api/request/req-host.md new file mode 100644 index 0000000000..6b1191eb31 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/req-host.md @@ -0,0 +1,27 @@ +--- +title: req.host +description: Contains the host derived from the Host HTTP header. +--- + +

req.host

+ +Contains the host derived from the `Host` HTTP header. + +When the [`trust proxy` setting](api.html#app.settings.table) +does not evaluate to `false`, this property will instead get the value +from the `X-Forwarded-Host` header field. This header can be set by +the client or by the proxy. + +If there is more than one `X-Forwarded-Host` header in the request, the +value of the first header is used. This includes a single header with +comma-separated values, in which the first value is used. + +```js +// Host: "example.com:3000" +console.dir(req.host); +// => 'example.com:3000' + +// Host: "[::1]:3000" +console.dir(req.host); +// => '[::1]:3000' +``` diff --git a/astro/src/content/docs/en/5x/api/request/req-hostname.md b/astro/src/content/docs/en/5x/api/request/req-hostname.md new file mode 100644 index 0000000000..94477d42ef --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/req-hostname.md @@ -0,0 +1,28 @@ +--- +title: req.hostname +description: Contains the hostname derived from the Host HTTP header. +--- + +

req.hostname

+ +Contains the hostname derived from the `Host` HTTP header. + +When the [`trust proxy` setting](/5x/api.html#trust.proxy.options.table) +does not evaluate to `false`, this property will instead get the value +from the `X-Forwarded-Host` header field. This header can be set by +the client or by the proxy. + +If there is more than one `X-Forwarded-Host` header in the request, the +value of the first header is used. This includes a single header with +comma-separated values, in which the first value is used. + +
+Prior to Express v4.17.0, the `X-Forwarded-Host` could not contain multiple +values or be present more than once. +
+ +```js +// Host: "example.com:3000" +console.dir(req.hostname); +// => 'example.com' +``` diff --git a/astro/src/content/docs/en/5x/api/request/req-ip.md b/astro/src/content/docs/en/5x/api/request/req-ip.md new file mode 100644 index 0000000000..dec38033cc --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/req-ip.md @@ -0,0 +1,17 @@ +--- +title: req.ip +description: Contains the remote IP address of the request. +--- + +

req.ip

+ +Contains the remote IP address of the request. + +When the [`trust proxy` setting](/5x/api.html#trust.proxy.options.table) does not evaluate to `false`, +the value of this property is derived from the left-most entry in the +`X-Forwarded-For` header. This header can be set by the client or by the proxy. + +```js +console.dir(req.ip); +// => "127.0.0.1" +``` diff --git a/astro/src/content/docs/en/5x/api/request/req-ips.md b/astro/src/content/docs/en/5x/api/request/req-ips.md new file mode 100644 index 0000000000..424fcd28f0 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/req-ips.md @@ -0,0 +1,14 @@ +--- +title: req.ips +description: When the trust proxy setting does not evaluate to false, this property contains an array of IP addresses specified in the X-Forwarded-For request header +--- + +

req.ips

+ +When the [`trust proxy` setting](/5x/api.html#trust.proxy.options.table) does not evaluate to `false`, +this property contains an array of IP addresses +specified in the `X-Forwarded-For` request header. Otherwise, it contains an +empty array. This header can be set by the client or by the proxy. + +For example, if `X-Forwarded-For` is `client, proxy1, proxy2`, `req.ips` would be +`["client", "proxy1", "proxy2"]`, where `proxy2` is the furthest downstream. diff --git a/astro/src/content/docs/en/5x/api/request/req-is.md b/astro/src/content/docs/en/5x/api/request/req-is.md new file mode 100644 index 0000000000..3c9b22623d --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/req-is.md @@ -0,0 +1,36 @@ +--- +title: req.is +description: Returns the matching content type if the incoming request's "Content-Type" HTTP header field +--- + +

req.is(type)

+ +Returns the matching content type if the incoming request's "Content-Type" HTTP header field +matches the MIME type specified by the `type` parameter. If the request has no body, returns `null`. +Returns `false` otherwise. + +```js +// With Content-Type: text/html; charset=utf-8 +req.is('html'); // => 'html' +req.is('text/html'); // => 'text/html' +req.is('text/*'); // => 'text/*' + +// When Content-Type is application/json +req.is('json'); // => 'json' +req.is('application/json'); // => 'application/json' +req.is('application/*'); // => 'application/*' + +// Using arrays +// When Content-Type is application/json +req.is(['json', 'html']); // => 'json' + +// Using multiple arguments +// When Content-Type is application/json +req.is('json', 'html'); // => 'json' + +req.is('html'); // => false +req.is(['xml', 'yaml']); // => false +req.is('xml', 'yaml'); // => false +``` + +For more information, or if you have issues or concerns, see [type-is](https://github.com/expressjs/type-is). diff --git a/astro/src/content/docs/en/5x/api/request/req-method.md b/astro/src/content/docs/en/5x/api/request/req-method.md new file mode 100644 index 0000000000..92b683bcfd --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/req-method.md @@ -0,0 +1,9 @@ +--- +title: req.method +description: Contains a string corresponding to the HTTP method of the request +--- + +

req.method

+ +Contains a string corresponding to the HTTP method of the request: +`GET`, `POST`, `PUT`, and so on. diff --git a/astro/src/content/docs/en/5x/api/request/req-originalUrl.md b/astro/src/content/docs/en/5x/api/request/req-originalUrl.md new file mode 100644 index 0000000000..c7d4b142ed --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/req-originalUrl.md @@ -0,0 +1,33 @@ +--- +title: req.originalUrl +description: req.url is not a native Express property, it is inherited from Node http module +--- + +

req.originalUrl

+ +
+`req.url` is not a native Express property, it is inherited from Node's [http module](https://nodejs.org/api/http.html#http_message_url). +
+ +This property is much like `req.url`; however, it retains the original request URL, +allowing you to rewrite `req.url` freely for internal routing purposes. For example, +the "mounting" feature of [app.use()](#app.use) will rewrite `req.url` to strip the mount point. + +```js +// GET /search?q=something +console.dir(req.originalUrl); +// => "/search?q=something" +``` + +`req.originalUrl` is available both in middleware and router objects, and is a +combination of `req.baseUrl` and `req.url`. Consider following example: + +```js +// GET 'http://www.example.com/admin/new?sort=desc' +app.use('/admin', (req, res, next) => { + console.dir(req.originalUrl); // '/admin/new?sort=desc' + console.dir(req.baseUrl); // '/admin' + console.dir(req.path); // '/new' + next(); +}); +``` diff --git a/astro/src/content/docs/en/5x/api/request/req-params.md b/astro/src/content/docs/en/5x/api/request/req-params.md new file mode 100644 index 0000000000..b87d9a66d3 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/req-params.md @@ -0,0 +1,44 @@ +--- +title: req.params +description: This property is an object containing properties mapped to the [named route "parameters"](/{{ page.lang }}/guide/routing.html#route-parameters). Fo... +--- + +

req.params

+ +This property is an object containing properties mapped to the [named route "parameters"](/{{ page.lang }}/guide/routing.html#route-parameters). For example, if you have the route `/user/:name`, then the "name" property is available as `req.params.name`. This object defaults to `Object.create(null)` when using string paths, but remains a standard object with a normal prototype when the path is defined with a regular expression. + +```js +// GET /user/tj +console.dir(req.params.name); +// => "tj" +``` + +Properties corresponding to wildcard parameters are arrays containing separate path segments split on `/`: + +```js +app.get('/files/*file', (req, res) => { + console.dir(req.params.file); + // GET /files/note.txt + // => [ 'note.txt' ] + // GET /files/images/image.png + // => [ 'images', 'image.png' ] +}); +``` + +When you use a regular expression for the route definition, capture groups are provided as integer keys using `req.params[n]`, where `n` is the nth capture group. + +```js +app.use(/^\/file\/(.*)$/, (req, res) => { + // GET /file/javascripts/jquery.js + console.dir(req.params[0]); + // => "javascripts/jquery.js" +}); +``` + +Named capturing groups in regular expressions behave like named route parameters. For example the group from `/^\/file\/(?.*)$/` expression is available as `req.params.path`. + +If you need to make changes to a key in `req.params`, use the [app.param](/{{ page.lang }}/5x/api.html#app.param) handler. Changes are applicable only to [parameters](/{{ page.lang }}/guide/routing.html#route-parameters) already defined in the route path. + +Any changes made to the `req.params` object in a middleware or route handler will be reset. + +{% include admonitions/note.html content="Express automatically decodes the values in `req.params` (using `decodeURIComponent`)." %} diff --git a/astro/src/content/docs/en/5x/api/request/req-path.md b/astro/src/content/docs/en/5x/api/request/req-path.md new file mode 100644 index 0000000000..36341283a5 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/req-path.md @@ -0,0 +1,18 @@ +--- +title: req.path +description: Contains the path part of the request URL. +--- + +

req.path

+ +Contains the path part of the request URL. + +```js +// example.com/users?sort=desc +console.dir(req.path); +// => "/users" +``` + +
+When called from a middleware, the mount point is not included in `req.path`. See [app.use()](/5x/api.html#app.use) for more details. +
diff --git a/astro/src/content/docs/en/5x/api/request/req-protocol.md b/astro/src/content/docs/en/5x/api/request/req-protocol.md new file mode 100644 index 0000000000..082e784b47 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/req-protocol.md @@ -0,0 +1,17 @@ +--- +title: req.protocol +description: Contains the request protocol string either http or (for TLS requests) https. +--- + +

req.protocol

+ +Contains the request protocol string: either `http` or (for TLS requests) `https`. + +When the [`trust proxy` setting](#trust.proxy.options.table) does not evaluate to `false`, +this property will use the value of the `X-Forwarded-Proto` header field if present. +This header can be set by the client or by the proxy. + +```js +console.dir(req.protocol); +// => "http" +``` diff --git a/astro/src/content/docs/en/5x/api/request/req-query.md b/astro/src/content/docs/en/5x/api/request/req-query.md new file mode 100644 index 0000000000..98697eaa7e --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/req-query.md @@ -0,0 +1,26 @@ +--- +title: req.query +description: This property is an object containing a property for each query string parameter in the route. +--- + +

req.query

+ +This property is an object containing a property for each query string parameter in the route. +When [query parser](#app.settings.table) is set to disabled, it is an empty object `{}`, otherwise it is the result of the configured query parser. + +
+As `req.query`'s shape is based on user-controlled input, all properties and values in this object are untrusted and should be validated before trusting. For example, `req.query.foo.toString()` may fail in multiple ways, for example `foo` may not be there or may not be a string, and `toString` may not be a function and instead a string or other user-input. +
+ +The value of this property can be configured with the [query parser application setting](#app.settings.table) to work how your application needs it. A very popular query string parser is the [`qs` module](https://www.npmjs.org/package/qs), and this is used by default. The `qs` module is very configurable with many settings, and it may be desirable to use different settings than the default to populate `req.query`: + +```js +const qs = require('qs'); +app.set('query parser', (str) => + qs.parse(str, { + /* custom options */ + }) +); +``` + +Check out the [query parser application setting](#app.settings.table) documentation for other customization options. diff --git a/astro/src/content/docs/en/5x/api/request/req-range.md b/astro/src/content/docs/en/5x/api/request/req-range.md new file mode 100644 index 0000000000..6c103987a2 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/req-range.md @@ -0,0 +1,38 @@ +--- +title: req.range +description: Range header parser +--- + +

req.range(size[, options])

+ +`Range` header parser. + +The `size` parameter is the maximum size of the resource. + +The `options` parameter is an object that can have the following properties. + +
+ +| Property | Type | Description | +| --------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `combine` | Boolean | Specify if overlapping & adjacent ranges should be combined, defaults to `false`. When `true`, ranges will be combined and returned as if they were specified that way in the header. | + +
+ +An array of ranges will be returned or negative numbers indicating an error parsing. + +- `-2` signals a malformed header string +- `-1` signals an unsatisfiable range + +```js +// parse header from request +const range = req.range(1000); + +// the type of the range +if (range.type === 'bytes') { + // the ranges + range.forEach((r) => { + // do something with r.start and r.end + }); +} +``` diff --git a/astro/src/content/docs/en/5x/api/request/req-res.md b/astro/src/content/docs/en/5x/api/request/req-res.md new file mode 100644 index 0000000000..94e5554756 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/req-res.md @@ -0,0 +1,9 @@ +--- +title: req.res +description: This property holds a reference to the +--- + +

req.res

+ +This property holds a reference to the response object +that relates to this request object. diff --git a/astro/src/content/docs/en/5x/api/request/req-route.md b/astro/src/content/docs/en/5x/api/request/req-route.md new file mode 100644 index 0000000000..d2a3159b3b --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/req-route.md @@ -0,0 +1,36 @@ +--- +title: req.route +description: Contains the currently-matched route, a string +--- + +

req.route

+ +Contains the currently-matched route, a string. For example: + +```js +app.get('/user/{:id}', (req, res) => { + console.dir(req.route, { depth: null }); + res.send('GET'); +}); +``` + +Example output from the previous snippet: + +``` +Route { + path: '/user/{:id}', + stack: [ + Layer { + handle: [Function (anonymous)], + keys: [], + name: '', + params: undefined, + path: undefined, + slash: false, + matchers: [ [Function: match] ], + method: 'get' + } + ], + methods: [Object: null prototype] { get: true } +} +``` diff --git a/astro/src/content/docs/en/5x/api/request/req-secure.md b/astro/src/content/docs/en/5x/api/request/req-secure.md new file mode 100644 index 0000000000..d3f86bdcd2 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/req-secure.md @@ -0,0 +1,14 @@ +--- +title: req.secure +description: A Boolean property that is true if a TLS connection is established. Equivalent to the following code. +--- + +

req.secure

+ +A Boolean property that is true if a TLS connection is established. Equivalent to the following: + + + +```js +req.protocol === 'https'; +``` diff --git a/astro/src/content/docs/en/5x/api/request/req-signedCookies.md b/astro/src/content/docs/en/5x/api/request/req-signedCookies.md new file mode 100644 index 0000000000..b573fc082e --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/req-signedCookies.md @@ -0,0 +1,22 @@ +--- +title: req.signedCookies +description: When using cookie-parser middleware, this property contains signed cookies sent by the request +--- + +

req.signedCookies

+ +When using [cookie-parser](https://www.npmjs.com/package/cookie-parser) middleware, this property +contains signed cookies sent by the request, unsigned and ready for use. Signed cookies reside +in a different object to show developer intent; otherwise, a malicious attack could be placed on +`req.cookie` values (which are easy to spoof). Note that signing a cookie does not make it "hidden" +or encrypted; but simply prevents tampering (because the secret used to sign is private). + +If no signed cookies are sent, the property defaults to `{}`. + +```js +// Cookie: user=tobi.CP7AWaXDfAKIRfH49dQzKJx7sKzzSoPq7/AcBBRVwlI3 +console.dir(req.signedCookies.user); +// => "tobi" +``` + +For more information, issues, or concerns, see [cookie-parser](https://github.com/expressjs/cookie-parser). diff --git a/astro/src/content/docs/en/5x/api/request/req-stale.md b/astro/src/content/docs/en/5x/api/request/req-stale.md new file mode 100644 index 0000000000..b39f5cb5ef --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/req-stale.md @@ -0,0 +1,14 @@ +--- +title: req.stale +description: Indicates whether the request is stale, and is the opposite of req.fresh. +--- + +

req.stale

+ +Indicates whether the request is "stale," and is the opposite of `req.fresh`. +For more information, see [req.fresh](#req.fresh). + +```js +console.dir(req.stale); +// => true +``` diff --git a/astro/src/content/docs/en/5x/api/request/req-subdomains.md b/astro/src/content/docs/en/5x/api/request/req-subdomains.md new file mode 100644 index 0000000000..9395377b47 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/req-subdomains.md @@ -0,0 +1,18 @@ +--- +title: req.subdomains +description: An array of subdomains in the domain name of the request. +--- + +

req.subdomains

+ +An array of subdomains in the domain name of the request. + +```js +// Host: "tobi.ferrets.example.com" +console.dir(req.subdomains); +// => ["ferrets", "tobi"] +``` + +The application property `subdomain offset`, which defaults to 2, is used for determining the +beginning of the subdomain segments. To change this behavior, change its value +using [app.set](/{{ page.lang }}/5x/api.html#app.set). diff --git a/astro/src/content/docs/en/5x/api/request/req-xhr.md b/astro/src/content/docs/en/5x/api/request/req-xhr.md new file mode 100644 index 0000000000..f247d20b05 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/request/req-xhr.md @@ -0,0 +1,14 @@ +--- +title: req.xhr +description: A Boolean property that is true if the request X-Requested-With header field is "XMLHttpRequest" +--- + +

req.xhr

+ +A Boolean property that is `true` if the request's `X-Requested-With` header field is +"XMLHttpRequest", indicating that the request was issued by a client library such as jQuery. + +```js +console.dir(req.xhr); +// => true +``` diff --git a/astro/src/content/docs/en/5x/api/response/res-app.md b/astro/src/content/docs/en/5x/api/response/res-app.md new file mode 100644 index 0000000000..b853d54dd3 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/response/res-app.md @@ -0,0 +1,10 @@ +--- +title: res.app +description: This property holds a reference to the instance of the Express application that is using the middleware. +--- + +

res.app

+ +This property holds a reference to the instance of the Express application that is using the middleware. + +`res.app` is identical to the [req.app](#req.app) property in the request object. diff --git a/astro/src/content/docs/en/5x/api/response/res-append.md b/astro/src/content/docs/en/5x/api/response/res-append.md new file mode 100644 index 0000000000..abda903e81 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/response/res-append.md @@ -0,0 +1,21 @@ +--- +title: res.append +description: res.append appends the specified value to the HTTP response header field +--- + +

res.append(field [, value])

+ +
+`res.append()` is supported by Express v4.11.0+ +
+ +Appends the specified `value` to the HTTP response header `field`. If the header is not already set, +it creates the header with the specified value. The `value` parameter can be a string or an array. + +{% include admonitions/note.html content="calling `res.set()` after `res.append()` will reset the previously-set header value." %} + +```js +res.append('Link', ['', '']); +res.append('Set-Cookie', 'foo=bar; Path=/; HttpOnly'); +res.append('Warning', '199 Miscellaneous warning'); +``` diff --git a/astro/src/content/docs/en/5x/api/response/res-attachment.md b/astro/src/content/docs/en/5x/api/response/res-attachment.md new file mode 100644 index 0000000000..7d667eedd4 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/response/res-attachment.md @@ -0,0 +1,19 @@ +--- +title: res.attachment +description: Sets the HTTP response Content-Disposition header field to attachment +--- + +

res.attachment([filename])

+ +Sets the HTTP response `Content-Disposition` header field to "attachment". If a `filename` is given, +then it sets the `Content-Type` based on the extension name via `res.type()`, +and sets the `Content-Disposition` "filename=" parameter. + +```js +res.attachment(); +// Content-Disposition: attachment + +res.attachment('path/to/logo.png'); +// Content-Disposition: attachment; filename="logo.png" +// Content-Type: image/png +``` diff --git a/astro/src/content/docs/en/5x/api/response/res-clearCookie.md b/astro/src/content/docs/en/5x/api/response/res-clearCookie.md new file mode 100644 index 0000000000..f2738bf189 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/response/res-clearCookie.md @@ -0,0 +1,24 @@ +--- +title: res.clearCookie +description: Clears the cookie with the specified name by sending a Set-Cookie header that sets its expiration date in the past. +--- + +

res.clearCookie(name [, options])

+ +Clears the cookie with the specified `name` by sending a `Set-Cookie` header that sets its expiration date in the past. +This instructs the client that the cookie has expired and is no longer valid. For more information +about available `options`, see [res.cookie()](#res.cookie). + +
+The `expires` and `max-age` options are being ignored completely. +
+ +
+Web browsers and other compliant clients will only clear the cookie if the given +`options` is identical to those given to [res.cookie()](#res.cookie) +
+ +```js +res.cookie('name', 'tobi', { path: '/admin' }); +res.clearCookie('name', { path: '/admin' }); +``` diff --git a/astro/src/content/docs/en/5x/api/response/res-cookie.md b/astro/src/content/docs/en/5x/api/response/res-cookie.md new file mode 100644 index 0000000000..ab7e81de34 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/response/res-cookie.md @@ -0,0 +1,95 @@ +--- +title: res.cookie +description: Sets cookie name to value. The value parameter may be a string or object converted to JSON. +--- + +

res.cookie(name, value [, options])

+ +Sets cookie `name` to `value`. The `value` parameter may be a string or object converted to JSON. + +The `options` parameter is an object that can have the following properties. + +
+ +| Property | Type | Description | +| ------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `domain` | String | Domain name for the cookie. Defaults to the domain name of the app. | +| `encode` | Function | A synchronous function used for cookie value encoding. Defaults to `encodeURIComponent`. | +| `expires` | Date | Expiry date of the cookie in GMT. If not specified or set to 0, creates a session cookie. | +| `httpOnly` | Boolean | Flags the cookie to be accessible only by the web server. | +| `maxAge` | Number | Convenient option for setting the expiry time relative to the current time in milliseconds. | +| `path` | String | Path for the cookie. Defaults to "/". | +| `partitioned` | Boolean | Indicates that the cookie should be stored using partitioned storage. See [Cookies Having Independent Partitioned State (CHIPS)](https://developer.mozilla.org/en-US/docs/Web/Privacy/Partitioned_cookies) for more details. | +| `priority` | String | Value of the "Priority" **Set-Cookie** attribute. | +| `secure` | Boolean | Marks the cookie to be used with HTTPS only. | +| `signed` | Boolean | Indicates if the cookie should be signed. | +| `sameSite` | Boolean or String | Value of the "SameSite" **Set-Cookie** attribute. More information at [https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00#section-4.1.1](https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00#section-4.1.1). | + +
+ +
+All `res.cookie()` does is set the HTTP `Set-Cookie` header with the options provided. +Any option not specified defaults to the value stated in [RFC 6265](http://tools.ietf.org/html/rfc6265). +
+ +For example: + +```js +res.cookie('name', 'tobi', { domain: '.example.com', path: '/admin', secure: true }); +res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true }); +``` + +You can set multiple cookies in a single response by calling `res.cookie` multiple times, for example: + +```js +res + .status(201) + .cookie('access_token', `Bearer ${token}`, { + expires: new Date(Date.now() + 8 * 3600000), // cookie will be removed after 8 hours + }) + .cookie('test', 'test') + .redirect(301, '/admin'); +``` + +The `encode` option allows you to choose the function used for cookie value encoding. +Does not support asynchronous functions. + +Example use case: You need to set a domain-wide cookie for another site in your organization. +This other site (not under your administrative control) does not use URI-encoded cookie values. + +```js +// Default encoding +res.cookie('some_cross_domain_cookie', 'http://mysubdomain.example.com', { domain: 'example.com' }); +// Result: 'some_cross_domain_cookie=http%3A%2F%2Fmysubdomain.example.com; Domain=example.com; Path=/' + +// Custom encoding +res.cookie('some_cross_domain_cookie', 'http://mysubdomain.example.com', { + domain: 'example.com', + encode: String, +}); +// Result: 'some_cross_domain_cookie=http://mysubdomain.example.com; Domain=example.com; Path=/;' +``` + +The `maxAge` option is a convenience option for setting "expires" relative to the current time in milliseconds. +The following is equivalent to the second example above. + +```js +res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true }); +``` + +You can pass an object as the `value` parameter; it is then serialized as JSON and parsed by `bodyParser()` middleware. + +```js +res.cookie('cart', { items: [1, 2, 3] }); +res.cookie('cart', { items: [1, 2, 3] }, { maxAge: 900000 }); +``` + +When using [cookie-parser](https://www.npmjs.com/package/cookie-parser) middleware, this method also +supports signed cookies. Simply include the `signed` option set to `true`. +Then, `res.cookie()` will use the secret passed to `cookieParser(secret)` to sign the value. + +```js +res.cookie('name', 'tobi', { signed: true }); +``` + +Later, you may access this value through the [req.signedCookies](#req.signedCookies) object. diff --git a/astro/src/content/docs/en/5x/api/response/res-download.md b/astro/src/content/docs/en/5x/api/response/res-download.md new file mode 100644 index 0000000000..42eb6db49f --- /dev/null +++ b/astro/src/content/docs/en/5x/api/response/res-download.md @@ -0,0 +1,66 @@ +--- +title: res.download +description: res.download provides access to data on the running file system +--- + +

res.download(path [, filename] [, options] [, fn])

+ +
+The optional `options` argument is supported by Express v4.16.0 onwards. +
+ +Transfers the file at `path` as an "attachment". Typically, browsers will prompt the user for download. +By default, the `Content-Disposition` header "filename=" parameter is derived from the `path` argument, but can be overridden with the `filename` parameter. +If `path` is relative, then it will be based on the current working directory of the process or +the `root` option, if provided. + +
+This API provides access to data on the running file system. Ensure that either (a) the way in +which the `path` argument was constructed is secure if it contains user input or (b) set the `root` +option to the absolute path of a directory to contain access within. + +When the `root` option is provided, Express will validate that the relative path provided as +`path` will resolve within the given `root` option. + +
+ +The following table provides details on the `options` parameter. + +
+The optional `options` argument is supported by Express v4.16.0 onwards. +
+ +
+ +| Property | Description | Default | Availability | +| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------ | +| `maxAge` | Sets the max-age property of the `Cache-Control` header in milliseconds or a string in [ms format](https://www.npmjs.org/package/ms) | 0 | 4.16+ | +| `root` | Root directory for relative filenames. | | 4.18+ | +| `lastModified` | Sets the `Last-Modified` header to the last modified date of the file on the OS. Set `false` to disable it. | Enabled | 4.16+ | +| `headers` | Object containing HTTP headers to serve with the file. The header `Content-Disposition` will be overridden by the `filename` argument. | | 4.16+ | +| `dotfiles` | Option for serving dotfiles. Possible values are "allow", "deny", "ignore". | "ignore" | 4.16+ | +| `acceptRanges` | Enable or disable accepting ranged requests. | `true` | 4.16+ | +| `cacheControl` | Enable or disable setting `Cache-Control` response header. | `true` | 4.16+ | +| `immutable` | Enable or disable the `immutable` directive in the `Cache-Control` response header. If enabled, the `maxAge` option should also be specified to enable caching. The `immutable` directive will prevent supported clients from making conditional requests during the life of the `maxAge` option to check if the file has changed. | `false` | 4.16+ | + +
+ +The method invokes the callback function `fn(err)` when the transfer is complete +or when an error occurs. If the callback function is specified and an error occurs, +the callback function must explicitly handle the response process either by +ending the request-response cycle, or by passing control to the next route. + +```js +res.download('/report-12345.pdf'); + +res.download('/report-12345.pdf', 'report.pdf'); + +res.download('/report-12345.pdf', 'report.pdf', (err) => { + if (err) { + // Handle error, but keep in mind the response may be partially-sent + // so check res.headersSent + } else { + // decrement a download credit, etc. + } +}); +``` diff --git a/astro/src/content/docs/en/5x/api/response/res-end.md b/astro/src/content/docs/en/5x/api/response/res-end.md new file mode 100644 index 0000000000..1d59764120 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/response/res-end.md @@ -0,0 +1,15 @@ +--- +title: res.end +description: Ends the response process. This method actually comes from Node core, specifically the response.end method of http.ServerResponse. +--- + +

res.end([data[, encoding]][, callback])

+ +Ends the response process. This method actually comes from Node core, specifically the [response.end() method of http.ServerResponse](https://nodejs.org/api/http.html#responseenddata-encoding-callback). + +Use to quickly end the response without any data. If you need to respond with data, instead use methods such as [res.send()](#res.send) and [res.json()](#res.json). + +```js +res.end(); +res.status(404).end(); +``` diff --git a/astro/src/content/docs/en/5x/api/response/res-format.md b/astro/src/content/docs/en/5x/api/response/res-format.md new file mode 100644 index 0000000000..92e7c40e45 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/response/res-format.md @@ -0,0 +1,57 @@ +--- +title: res.format +description: Performs content-negotiation on the Accept HTTP header on the request object, when present. +--- + +

res.format(object)

+ +Performs content-negotiation on the `Accept` HTTP header on the request object, when present. +It uses [req.accepts()](#req.accepts) to select a handler for the request, based on the acceptable +types ordered by their quality values. If the header is not specified, the first callback is invoked. +When no match is found, the server responds with 406 "Not Acceptable", or invokes the `default` callback. + +The `Content-Type` response header is set when a callback is selected. However, you may alter +this within the callback using methods such as `res.set()` or `res.type()`. + +The following example would respond with `{ "message": "hey" }` when the `Accept` header field is set +to "application/json" or "\*/json" (however, if it is "\*/\*", then the response will be "hey"). + +```js +res.format({ + 'text/plain'() { + res.send('hey'); + }, + + 'text/html'() { + res.send('

hey

'); + }, + + 'application/json'() { + res.send({ message: 'hey' }); + }, + + default() { + // log the request and respond with 406 + res.status(406).send('Not Acceptable'); + }, +}); +``` + +In addition to canonicalized MIME types, you may also use extension names mapped +to these types for a slightly less verbose implementation: + +```js +res.format({ + text() { + res.send('hey'); + }, + + html() { + res.send('

hey

'); + }, + + json() { + res.send({ message: 'hey' }); + }, +}); +``` diff --git a/astro/src/content/docs/en/5x/api/response/res-get.md b/astro/src/content/docs/en/5x/api/response/res-get.md new file mode 100644 index 0000000000..300dd9d1a9 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/response/res-get.md @@ -0,0 +1,14 @@ +--- +title: res.get +description: Returns the HTTP response header specified by field. +--- + +

res.get(field)

+ +Returns the HTTP response header specified by `field`. +The match is case-insensitive. + +```js +res.get('Content-Type'); +// => "text/plain" +``` diff --git a/astro/src/content/docs/en/5x/api/response/res-headersSent.md b/astro/src/content/docs/en/5x/api/response/res-headersSent.md new file mode 100644 index 0000000000..ed9b41069e --- /dev/null +++ b/astro/src/content/docs/en/5x/api/response/res-headersSent.md @@ -0,0 +1,16 @@ +--- +title: res.headersSent +description: Boolean property that indicates if the app sent HTTP headers for the response. +--- + +

res.headersSent

+ +Boolean property that indicates if the app sent HTTP headers for the response. + +```js +app.get('/', (req, res) => { + console.log(res.headersSent); // false + res.send('OK'); + console.log(res.headersSent); // true +}); +``` diff --git a/astro/src/content/docs/en/5x/api/response/res-json.md b/astro/src/content/docs/en/5x/api/response/res-json.md new file mode 100644 index 0000000000..40d6c0c083 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/response/res-json.md @@ -0,0 +1,18 @@ +--- +title: res.json +description: Sends a JSON response. This method sends a response (with the correct content-type) that is the parameter converted to a +--- + +

res.json([body])

+ +Sends a JSON response. This method sends a response (with the correct content-type) that is the parameter converted to a +JSON string using [JSON.stringify()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify). + +The parameter can be any JSON type, including object, array, string, Boolean, number, or null, +and you can also use it to convert other values to JSON. + +```js +res.json(null); +res.json({ user: 'tobi' }); +res.status(500).json({ error: 'message' }); +``` diff --git a/astro/src/content/docs/en/5x/api/response/res-jsonp.md b/astro/src/content/docs/en/5x/api/response/res-jsonp.md new file mode 100644 index 0000000000..7dad964a15 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/response/res-jsonp.md @@ -0,0 +1,37 @@ +--- +title: res.jsonp +description: Sends a JSON response with JSONP support. This method is identical to res.json, +--- + +

res.jsonp([body])

+ +Sends a JSON response with JSONP support. This method is identical to `res.json()`, +except that it opts-in to JSONP callback support. + +```js +res.jsonp(null); +// => callback(null) + +res.jsonp({ user: 'tobi' }); +// => callback({ "user": "tobi" }) + +res.status(500).jsonp({ error: 'message' }); +// => callback({ "error": "message" }) +``` + +By default, the JSONP callback name is simply `callback`. Override this with the +jsonp callback name setting. + +The following are some examples of JSONP responses using the same code: + +```js +// ?callback=foo +res.jsonp({ user: 'tobi' }); +// => foo({ "user": "tobi" }) + +app.set('jsonp callback name', 'cb'); + +// ?cb=foo +res.status(500).jsonp({ error: 'message' }); +// => foo({ "error": "message" }) +``` diff --git a/astro/src/content/docs/en/5x/api/response/res-links.md b/astro/src/content/docs/en/5x/api/response/res-links.md new file mode 100644 index 0000000000..db6aaba927 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/response/res-links.md @@ -0,0 +1,25 @@ +--- +title: res.links +description: Joins the links provided as properties of the parameter to populate the response Link HTTP header field +--- + + + +Joins the `links` provided as properties of the parameter to populate the response's +`Link` HTTP header field. + +For example, the following call: + +```js +res.links({ + next: 'http://api.example.com/users?page=2', + last: 'http://api.example.com/users?page=5', +}); +``` + +Yields the following results: + +``` +Link: ; rel="next", + ; rel="last" +``` diff --git a/astro/src/content/docs/en/5x/api/response/res-locals.md b/astro/src/content/docs/en/5x/api/response/res-locals.md new file mode 100644 index 0000000000..d2cf8c9b85 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/response/res-locals.md @@ -0,0 +1,33 @@ +--- +title: res.locals +description: Use this property to set variables accessible in templates rendered with [res.render](#res.render). +--- + +

res.locals

+ +Use this property to set variables accessible in templates rendered with [res.render](#res.render). +The variables set on `res.locals` are available within a single request-response cycle, and will not +be shared between requests. + +
+The `locals` object is used by view engines to render a response. The object +keys may be particularly sensitive and should not contain user-controlled +input, as it may affect the operation of the view engine or provide a path to +cross-site scripting. Consult the documentation for the used view engine for +additional considerations. +
+ +In order to keep local variables for use in template rendering between requests, use +[app.locals](#app.locals) instead. + +This property is useful for exposing request-level information such as the request path name, +authenticated user, user settings, and so on to templates rendered within the application. + +```js +app.use((req, res, next) => { + // Make `user` and `authenticated` available in templates + res.locals.user = req.user; + res.locals.authenticated = !req.user.anonymous; + next(); +}); +``` diff --git a/astro/src/content/docs/en/5x/api/response/res-location.md b/astro/src/content/docs/en/5x/api/response/res-location.md new file mode 100644 index 0000000000..37104a0eb3 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/response/res-location.md @@ -0,0 +1,22 @@ +--- +title: res.location +description: Sets the response Location HTTP header to the specified path parameter. +--- + +

res.location(path)

+ +Sets the response `Location` HTTP header to the specified `path` parameter. + +```js +res.location('/foo/bar'); +res.location('http://example.com'); +``` + +
+After encoding the URL, if not encoded already, Express passes the specified URL to the browser in the `Location` header, +without any validation. + +Browsers take the responsibility of deriving the intended URL from the current URL +or the referring URL, and the URL specified in the `Location` header; and redirect the user accordingly. + +
diff --git a/astro/src/content/docs/en/5x/api/response/res-redirect.md b/astro/src/content/docs/en/5x/api/response/res-redirect.md new file mode 100644 index 0000000000..86932014ca --- /dev/null +++ b/astro/src/content/docs/en/5x/api/response/res-redirect.md @@ -0,0 +1,56 @@ +--- +title: res.redirect +description: Redirects to the URL derived from the specified path, with specified status, a positive integer +--- + +

res.redirect([status,] path)

+ +Redirects to the URL derived from the specified `path`, with specified `status`, a positive integer +that corresponds to an [HTTP status code](https://www.rfc-editor.org/rfc/rfc9110.html#name-status-codes). +If not specified, `status` defaults to `302 "Found"`. + +```js +res.redirect('/foo/bar'); +res.redirect('http://example.com'); +res.redirect(301, 'http://example.com'); +res.redirect('../login'); +``` + +Redirects can be a fully-qualified URL for redirecting to a different site: + +```js +res.redirect('http://google.com'); +``` + +Redirects can be relative to the root of the host name. For example, if the +application is on `http://example.com/admin/post/new`, the following +would redirect to the URL `http://example.com/admin`: + +```js +res.redirect('/admin'); +``` + +Redirects can be relative to the current URL. For example, +from `http://example.com/blog/admin/` (notice the trailing slash), the following +would redirect to the URL `http://example.com/blog/admin/post/new`. + +```js +res.redirect('post/new'); +``` + +Redirecting to `post/new` from `http://example.com/blog/admin` (no trailing slash), +will redirect to `http://example.com/blog/post/new`. + +If you found the above behavior confusing, think of path segments as directories +(with trailing slashes) and files, it will start to make sense. + +Path-relative redirects are also possible. If you were on +`http://example.com/admin/post/new`, the following would redirect to +`http://example.com/admin/post`: + +```js +res.redirect('..'); +``` + +See also [Security best practices: Prevent open redirect +vulnerabilities](http://expressjs.com/en/advanced/best-practice-security.html#prevent-open-redirects). diff --git a/astro/src/content/docs/en/5x/api/response/res-render.md b/astro/src/content/docs/en/5x/api/response/res-render.md new file mode 100644 index 0000000000..c9a4cad9f9 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/response/res-render.md @@ -0,0 +1,42 @@ +--- +title: res.render +description: Renders a view and sends the rendered HTML string to the client. +--- + +

res.render(view [, locals] [, callback])

+ +Renders a `view` and sends the rendered HTML string to the client. +Optional parameters: + +- `locals`, an object whose properties define local variables for the view. +- `callback`, a callback function. If provided, the method returns both the possible error and rendered string, but does not perform an automated response. When an error occurs, the method invokes `next(err)` internally. + +The `view` argument is a string that is the file path of the view file to render. This can be an absolute path, or a path relative to the `views` setting. If the path does not contain a file extension, then the `view engine` setting determines the file extension. If the path does contain a file extension, then Express will load the module for the specified template engine (via `require()`) and render it using the loaded module's `__express` function. + +For more information, see [Using template engines with Express](/{{page.lang}}/guide/using-template-engines.html). + +{% include admonitions/warning.html content="The `view` argument performs file system operations like reading a file from disk and evaluating Node.js modules, and as so for security reasons should not contain input from the end-user." %} + +{% include admonitions/warning.html content="The `locals` object is used by view engines to render a response. The object +keys may be particularly sensitive and should not contain user-controlled +input, as it may affect the operation of the view engine or provide a path to +cross-site scripting. Consult the documentation for the used view engine for +additional considerations." %} + +{% include admonitions/caution.html content="The local variable `cache` enables view caching. Set it to `true`, +to cache the view during development; view caching is enabled in production by default." %} + +```js +// send the rendered view to the client +res.render('index'); + +// if a callback is specified, the rendered HTML string has to be sent explicitly +res.render('index', (err, html) => { + res.send(html); +}); + +// pass a local variable to the view +res.render('user', { name: 'Tobi' }, (err, html) => { + // ... +}); +``` diff --git a/astro/src/content/docs/en/5x/api/response/res-req.md b/astro/src/content/docs/en/5x/api/response/res-req.md new file mode 100644 index 0000000000..f20548a045 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/response/res-req.md @@ -0,0 +1,9 @@ +--- +title: res.req +description: This property holds a reference to the +--- + +

res.req

+ +This property holds a reference to the request object +that relates to this response object. diff --git a/astro/src/content/docs/en/5x/api/response/res-send.md b/astro/src/content/docs/en/5x/api/response/res-send.md new file mode 100644 index 0000000000..dd1797ff42 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/response/res-send.md @@ -0,0 +1,44 @@ +--- +title: res.send +description: Sends the HTTP response. +--- + +

res.send([body])

+ +Sends the HTTP response. + +The `body` parameter can be a `Buffer` object, a `String`, an object, `Boolean`, or an `Array`. +For example: + +```js +res.send(Buffer.from('whoop')); +res.send({ some: 'json' }); +res.send('

some html

'); +res.status(404).send('Sorry, we cannot find that!'); +res.status(500).send({ error: 'something blew up' }); +``` + +This method performs many useful tasks for simple non-streaming responses: +For example, it automatically assigns the `Content-Length` HTTP response header field +and provides automatic HEAD and HTTP cache freshness support. + +When the parameter is a `Buffer` object, the method sets the `Content-Type` +response header field to "application/octet-stream", unless previously defined as shown below: + +```js +res.set('Content-Type', 'text/html'); +res.send(Buffer.from('

some html

')); +``` + +When the parameter is a `String`, the method sets the `Content-Type` to "text/html": + +```js +res.send('

some html

'); +``` + +When the parameter is an `Array` or `Object`, Express responds with the JSON representation: + +```js +res.send({ user: 'tobi' }); +res.send([1, 2, 3]); +``` diff --git a/astro/src/content/docs/en/5x/api/response/res-sendFile.md b/astro/src/content/docs/en/5x/api/response/res-sendFile.md new file mode 100644 index 0000000000..750532497f --- /dev/null +++ b/astro/src/content/docs/en/5x/api/response/res-sendFile.md @@ -0,0 +1,91 @@ +--- +title: res.sendFile +description: res.sendFile transfers the file at the given path. Sets the Content-Type response HTTP header field based on the filename extension +--- + +

res.sendFile(path [, options] [, fn])

+ +
+`res.sendFile()` is supported by Express v4.8.0 onwards. +
+ +Transfers the file at the given `path`. Sets the `Content-Type` response HTTP header field +based on the filename's extension. Unless the `root` option is set in +the options object, `path` must be an absolute path to the file. + +
+This API provides access to data on the running file system. Ensure that either (a) the way in +which the `path` argument was constructed into an absolute path is secure if it contains user +input or (b) set the `root` option to the absolute path of a directory to contain access within. + +When the `root` option is provided, the `path` argument is allowed to be a relative path, +including containing `..`. Express will validate that the relative path provided as `path` will +resolve within the given `root` option. + +
+ +The following table provides details on the `options` parameter. + +
+ +| Property | Description | Default | Availability | +| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------ | +| `maxAge` | Sets the max-age property of the `Cache-Control` header in milliseconds or a string in [ms format](https://www.npmjs.org/package/ms) | 0 | | +| `root` | Root directory for relative filenames. | | | +| `lastModified` | Sets the `Last-Modified` header to the last modified date of the file on the OS. Set `false` to disable it. | Enabled | 4.9.0+ | +| `headers` | Object containing HTTP headers to serve with the file. | | | +| `dotfiles` | Option for serving dotfiles. Possible values are "allow", "deny", "ignore". | "ignore" |   | +| `acceptRanges` | Enable or disable accepting ranged requests. | `true` | 4.14+ | +| `cacheControl` | Enable or disable setting `Cache-Control` response header. | `true` | 4.14+ | +| `immutable` | Enable or disable the `immutable` directive in the `Cache-Control` response header. If enabled, the `maxAge` option should also be specified to enable caching. The `immutable` directive will prevent supported clients from making conditional requests during the life of the `maxAge` option to check if the file has changed. | `false` | 4.16+ | + +
+ +The method invokes the callback function `fn(err)` when the transfer is complete +or when an error occurs. If the callback function is specified and an error occurs, +the callback function must explicitly handle the response process either by +ending the request-response cycle, or by passing control to the next route. + +Here is an example of using `res.sendFile` with all its arguments. + +```js +app.get('/file/:name', (req, res, next) => { + const options = { + root: path.join(__dirname, 'public'), + dotfiles: 'deny', + headers: { + 'x-timestamp': Date.now(), + 'x-sent': true, + }, + }; + + const fileName = req.params.name; + res.sendFile(fileName, options, (err) => { + if (err) { + next(err); + } else { + console.log('Sent:', fileName); + } + }); +}); +``` + +The following example illustrates using +`res.sendFile` to provide fine-grained support for serving files: + +```js +app.get('/user/:uid/photos/:file', (req, res) => { + const uid = req.params.uid; + const file = req.params.file; + + req.user.mayViewFilesFrom(uid, (yes) => { + if (yes) { + res.sendFile(`/uploads/${uid}/${file}`); + } else { + res.status(403).send("Sorry! You can't see that."); + } + }); +}); +``` + +For more information, or if you have issues or concerns, see [send](https://github.com/pillarjs/send). diff --git a/astro/src/content/docs/en/5x/api/response/res-sendStatus.md b/astro/src/content/docs/en/5x/api/response/res-sendStatus.md new file mode 100644 index 0000000000..ae77bd6f46 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/response/res-sendStatus.md @@ -0,0 +1,20 @@ +--- +title: res.sendStatus +description: Sets the response HTTP status code to statusCode and sends the registered status message as the text response body. If an unknown status code is specified, the response body will be just the code number. +--- + +

res.sendStatus(statusCode)

+ +Sets the response HTTP status code to `statusCode` and sends the registered status message as the text response body. If an unknown status code is specified, the response body will just be the code number. + +```js +res.sendStatus(404); +``` + +
+Some versions of Node.js will throw when `res.statusCode` is set to an +invalid HTTP status code (outside of the range `100` to `599`). Consult +the HTTP server documentation for the Node.js version being used. +
+ +[More about HTTP Status Codes](http://en.wikipedia.org/wiki/List_of_HTTP_status_codes) diff --git a/astro/src/content/docs/en/5x/api/response/res-set.md b/astro/src/content/docs/en/5x/api/response/res-set.md new file mode 100644 index 0000000000..6d2b01e63e --- /dev/null +++ b/astro/src/content/docs/en/5x/api/response/res-set.md @@ -0,0 +1,21 @@ +--- +title: res.set +description: Sets the response HTTP header field to value. +--- + +

res.set(field [, value])

+ +Sets the response's HTTP header `field` to `value`. +To set multiple fields at once, pass an object as the parameter. + +```js +res.set('Content-Type', 'text/plain'); + +res.set({ + 'Content-Type': 'text/plain', + 'Content-Length': '123', + ETag: '12345', +}); +``` + +Aliased as `res.header(field [, value])`. diff --git a/astro/src/content/docs/en/5x/api/response/res-status.md b/astro/src/content/docs/en/5x/api/response/res-status.md new file mode 100644 index 0000000000..4969cd4ff9 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/response/res-status.md @@ -0,0 +1,15 @@ +--- +title: res.status +description: Sets the HTTP status for the response. +--- + +

res.status(code)

+ +Sets the HTTP status for the response. +It is a chainable alias of Node's [response.statusCode](http://nodejs.org/api/http.html#http_response_statuscode). + +```js +res.status(403).end(); +res.status(400).send('Bad Request'); +res.status(404).sendFile('/absolute/path/to/404.png'); +``` diff --git a/astro/src/content/docs/en/5x/api/response/res-type.md b/astro/src/content/docs/en/5x/api/response/res-type.md new file mode 100644 index 0000000000..b566a8d143 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/response/res-type.md @@ -0,0 +1,18 @@ +--- +title: res.type +description: Sets the Content-Type HTTP header to the MIME type as determined by the specified type. If type contains the slash character, then it sets the Content-Type to the exact value. +--- + +

res.type(type)

+ +Sets the `Content-Type` HTTP header to the MIME type as determined by the specified `type`. If `type` contains the "/" character, then it sets the `Content-Type` to the exact value of `type`, otherwise it is assumed to be a file extension and the MIME type is looked up using the `contentType()` method of the `mime-types` package. + +```js +res.type('.html'); // => 'text/html' +res.type('html'); // => 'text/html' +res.type('json'); // => 'application/json' +res.type('application/json'); // => 'application/json' +res.type('png'); // => image/png: +``` + +Aliased as `res.contentType(type)`. diff --git a/astro/src/content/docs/en/5x/api/response/res-vary.md b/astro/src/content/docs/en/5x/api/response/res-vary.md new file mode 100644 index 0000000000..164bed9285 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/response/res-vary.md @@ -0,0 +1,12 @@ +--- +title: res.vary +description: Adds the field to the Vary response header, if it is not there already. +--- + +

res.vary(field)

+ +Adds the field to the `Vary` response header, if it is not there already. + +```js +res.vary('User-Agent').render('docs'); +``` diff --git a/astro/src/content/docs/en/5x/api/response/response.md b/astro/src/content/docs/en/5x/api/response/response.md new file mode 100644 index 0000000000..ac989a33d8 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/response/response.md @@ -0,0 +1,135 @@ +--- +title: Properties +description: section markdown="1"> +--- + +

Response

+ +The `res` object represents the HTTP response that an Express app sends when it gets an HTTP request. + +In this documentation and by convention, +the object is always referred to as `res` (and the HTTP request is `req`) but its actual name is determined +by the parameters to the callback function in which you're working. + +For example: + +```js +app.get('/user/:id', (req, res) => { + res.send(`user ${req.params.id}`); +}); +``` + +But you could just as well have: + +```js +app.get('/user/:id', (request, response) => { + response.send(`user ${request.params.id}`); +}); +``` + +The `res` object is an enhanced version of Node's own response object +and supports all [built-in fields and methods](https://nodejs.org/api/http.html#http_class_http_serverresponse). + +

Properties

+ +
+ {% include api/en/5x/res-app.md %} +
+ +
+ {% include api/en/5x/res-headersSent.md %} +
+ +
+ {% include api/en/5x/res-locals.md %} +
+ +
+ {% include api/en/5x/res-req.md %} +
+ +

Methods

+ +
+ {% include api/en/5x/res-append.md %} +
+ +
+ {% include api/en/5x/res-attachment.md %} +
+ +
+ {% include api/en/5x/res-cookie.md %} +
+ +
+ {% include api/en/5x/res-clearCookie.md %} +
+ +
+ {% include api/en/5x/res-download.md %} +
+ +
+ {% include api/en/5x/res-end.md %} +
+ +
+ {% include api/en/5x/res-format.md %} +
+ +
+ {% include api/en/5x/res-get.md %} +
+ +
+ {% include api/en/5x/res-json.md %} +
+ +
+ {% include api/en/5x/res-jsonp.md %} +
+ +
+ {% include api/en/5x/res-links.md %} +
+ +
+ {% include api/en/5x/res-location.md %} +
+ +
+ {% include api/en/5x/res-redirect.md %} +
+ +
+ {% include api/en/5x/res-render.md %} +
+ +
+ {% include api/en/5x/res-send.md %} +
+ +
+ {% include api/en/5x/res-sendFile.md %} +
+ +
+ {% include api/en/5x/res-sendStatus.md %} +
+ +
+ {% include api/en/5x/res-set.md %} +
+ +
+ {% include api/en/5x/res-status.md %} +
+ +
+ {% include api/en/5x/res-type.md %} +
+ +
+ {% include api/en/5x/res-vary.md %} +
diff --git a/astro/src/content/docs/en/5x/api/router/router-METHOD.md b/astro/src/content/docs/en/5x/api/router/router-METHOD.md new file mode 100644 index 0000000000..a4eb343c90 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/router/router-METHOD.md @@ -0,0 +1,71 @@ +--- +title: router.METHOD +description: The router.METHOD methods provide the routing functionality in Express, where METHOD is one of the HTTP methods, such as GET, PUT, POST, and so on, in lowercase +--- + +

router.METHOD(path, [callback, ...] callback)

+ +The `router.METHOD()` methods provide the routing functionality in Express, +where METHOD is one of the HTTP methods, such as GET, PUT, POST, and so on, +in lowercase. Thus, the actual methods are `router.get()`, `router.post()`, +`router.put()`, and so on. + +
+ The `router.get()` function is automatically called for the HTTP `HEAD` method in + addition to the `GET` method if `router.head()` was not called for the + path before `router.get()`. +
+ +You can provide multiple callbacks, and all are treated equally, and behave just +like middleware, except that these callbacks may invoke `next('route')` +to bypass the remaining route callback(s). You can use this mechanism to perform +pre-conditions on a route then pass control to subsequent routes when there is no +reason to proceed with the route matched. + +The following snippet illustrates the most simple route definition possible. +Express translates the path strings to regular expressions, used internally +to match incoming requests. Query strings are _not_ considered when performing +these matches, for example "GET /" would match the following route, as would +"GET /?name=tobi". + +```js +router.get('/', (req, res) => { + res.send('hello world'); +}); +``` + +You can also use regular expressions—useful if you have very specific +constraints, for example the following would match "GET /commits/71dbb9c" as well +as "GET /commits/71dbb9c..4c084f9". + +```js +router.get(/^\/commits\/(\w+)(?:\.\.(\w+))?$/, (req, res) => { + const from = req.params[0]; + const to = req.params[1] || 'HEAD'; + res.send(`commit range ${from}..${to}`); +}); +``` + +You can use `next` primitive to implement a flow control between different +middleware functions, based on a specific program state. Invoking `next` with +the string `'router'` will cause all the remaining route callbacks on that router +to be bypassed. + +The following example illustrates `next('router')` usage. + +```js +function fn(req, res, next) { + console.log('I come here'); + next('router'); +} +router.get('/foo', fn, (req, res, next) => { + console.log('I dont come here'); +}); +router.get('/foo', (req, res, next) => { + console.log('I dont come here'); +}); +app.get('/foo', (req, res) => { + console.log(' I come here too'); + res.end('good'); +}); +``` diff --git a/astro/src/content/docs/en/5x/api/router/router-Router.md b/astro/src/content/docs/en/5x/api/router/router-Router.md new file mode 100644 index 0000000000..de2867f15c --- /dev/null +++ b/astro/src/content/docs/en/5x/api/router/router-Router.md @@ -0,0 +1,5 @@ +--- +title: Router +--- + +

Router([options])

diff --git a/astro/src/content/docs/en/5x/api/router/router-all.md b/astro/src/content/docs/en/5x/api/router/router-all.md new file mode 100644 index 0000000000..6a0461bc82 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/router/router-all.md @@ -0,0 +1,36 @@ +--- +title: router.all +description: This method is just like the router.METHOD methods, except that it matches all HTTP methods (verbs). +--- + +

router.all(path, [callback, ...] callback)

+ +This method is just like the `router.METHOD()` methods, except that it matches all HTTP methods (verbs). + +This method is extremely useful for +mapping "global" logic for specific path prefixes or arbitrary matches. +For example, if you placed the following route at the top of all other +route definitions, it would require that all routes from that point on +would require authentication, and automatically load a user. Keep in mind +that these callbacks do not have to act as end points; `loadUser` +can perform a task, then call `next()` to continue matching subsequent +routes. + +```js +router.all('{*splat}', requireAuthentication, loadUser); +``` + +Or the equivalent: + +```js +router.all('{*splat}', requireAuthentication); +router.all('{*splat}', loadUser); +``` + +Another example of this is white-listed "global" functionality. Here, +the example is much like before, but it only restricts paths prefixed with +"/api": + +```js +router.all('/api/{*splat}', requireAuthentication); +``` diff --git a/astro/src/content/docs/en/5x/api/router/router-param.md b/astro/src/content/docs/en/5x/api/router/router-param.md new file mode 100644 index 0000000000..184e0792e4 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/router/router-param.md @@ -0,0 +1,67 @@ +--- +title: router.param +description: Adds callback triggers to route parameters, where name is the name of the parameter and callback is the callback function. Although name is technically optional, it is required. +--- + +

router.param(name, callback)

+ +Adds callback triggers to route parameters, where `name` is the name of the parameter and `callback` is the callback function. Although `name` is technically optional, using this method without it is deprecated starting with Express v4.11.0 (see below). + +The parameters of the callback function are: + +- `req`, the request object. +- `res`, the response object. +- `next`, indicating the next middleware function. +- The value of the `name` parameter. +- The name of the parameter. + +
+Unlike `app.param()`, `router.param()` does not accept an array of route parameters. +
+ +For example, when `:user` is present in a route path, you may map user loading logic to automatically provide `req.user` to the route, or perform validations on the parameter input. + +```js +router.param('user', (req, res, next, id) => { + // try to get the user details from the User model and attach it to the request object + User.find(id, (err, user) => { + if (err) { + next(err); + } else if (user) { + req.user = user; + next(); + } else { + next(new Error('failed to load user')); + } + }); +}); +``` + +Param callback functions are local to the router on which they are defined. They are not inherited by mounted apps or routers, nor are they triggered for route parameters inherited from parent routers. Hence, param callbacks defined on `router` will be triggered only by route parameters defined on `router` routes. + +A param callback will be called only once in a request-response cycle, even if the parameter is matched in multiple routes, as shown in the following examples. + +```js +router.param('id', (req, res, next, id) => { + console.log('CALLED ONLY ONCE'); + next(); +}); + +router.get('/user/:id', (req, res, next) => { + console.log('although this matches'); + next(); +}); + +router.get('/user/:id', (req, res) => { + console.log('and this matches too'); + res.end(); +}); +``` + +On `GET /user/42`, the following is printed: + +``` +CALLED ONLY ONCE +although this matches +and this matches too +``` diff --git a/astro/src/content/docs/en/5x/api/router/router-route.md b/astro/src/content/docs/en/5x/api/router/router-route.md new file mode 100644 index 0000000000..f3d9d42075 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/router/router-route.md @@ -0,0 +1,54 @@ +--- +title: router.route +description: Returns an instance of a single route which you can then use to handle HTTP verbs +--- + +

router.route(path)

+ +Returns an instance of a single route which you can then use to handle HTTP verbs +with optional middleware. Use `router.route()` to avoid duplicate route naming and +thus typing errors. + +Building on the `router.param()` example above, the following code shows how to use +`router.route()` to specify various HTTP method handlers. + +```js +const router = express.Router(); + +router.param('user_id', (req, res, next, id) => { + // sample user, would actually fetch from DB, etc... + req.user = { + id, + name: 'TJ', + }; + next(); +}); + +router + .route('/users/:user_id') + .all((req, res, next) => { + // runs for all HTTP verbs first + // think of it as route specific middleware! + next(); + }) + .get((req, res, next) => { + res.json(req.user); + }) + .put((req, res, next) => { + // just an example of maybe updating the user + req.user.name = req.params.name; + // save user ... etc + res.json(req.user); + }) + .post((req, res, next) => { + next(new Error('not implemented')); + }) + .delete((req, res, next) => { + next(new Error('not implemented')); + }); +``` + +This approach re-uses the single `/users/:user_id` path and adds handlers for +various HTTP methods. + +{% include admonitions/note.html content="When you use `router.route()`, middleware ordering is based on when the _route_ is created, not when method handlers are added to the route. For this purpose, you can consider method handlers to belong to the route to which they were added." %} diff --git a/astro/src/content/docs/en/5x/api/router/router-use.md b/astro/src/content/docs/en/5x/api/router/router-use.md new file mode 100644 index 0000000000..6e31cf7f22 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/router/router-use.md @@ -0,0 +1,111 @@ +--- +title: router.use +description: Uses the specified middleware function or functions, with optional mount path that defaults to slash. +--- + +

router.use([path], [function, ...] function)

+ +Uses the specified middleware function or functions, with optional mount path `path`, that defaults to "/". + +This method is similar to [app.use()](#app.use). A simple example and use case is described below. +See [app.use()](#app.use) for more information. + +Middleware is like a plumbing pipe: requests start at the first middleware function defined +and work their way "down" the middleware stack processing for each path they match. + +```js +const express = require('express'); +const app = express(); +const router = express.Router(); + +// simple logger for this router's requests +// all requests to this router will first hit this middleware +router.use((req, res, next) => { + console.log('%s %s %s', req.method, req.url, req.path); + next(); +}); + +// this will only be invoked if the path starts with /bar from the mount point +router.use('/bar', (req, res, next) => { + // ... maybe some additional /bar logging ... + next(); +}); + +// always invoked +router.use((req, res, next) => { + res.send('Hello World'); +}); + +app.use('/foo', router); + +app.listen(3000); +``` + +The "mount" path is stripped and is _not_ visible to the middleware function. +The main effect of this feature is that a mounted middleware function may operate without +code changes regardless of its "prefix" pathname. + +The order in which you define middleware with `router.use()` is very important. +They are invoked sequentially, thus the order defines middleware precedence. For example, +usually a logger is the very first middleware you would use, so that every request gets logged. + +```js +const logger = require('morgan'); + +router.use(logger()); +router.use(express.static(path.join(__dirname, 'public'))); +router.use((req, res) => { + res.send('Hello'); +}); +``` + +Now suppose you wanted to ignore logging requests for static files, but to continue +logging routes and middleware defined after `logger()`. You would simply move the call to `express.static()` to the top, +before adding the logger middleware: + +```js +router.use(express.static(path.join(__dirname, 'public'))); +router.use(logger()); +router.use((req, res) => { + res.send('Hello'); +}); +``` + +Another example is serving files from multiple directories, +giving precedence to "./public" over the others: + +```js +app.use(express.static(path.join(__dirname, 'public'))); +app.use(express.static(path.join(__dirname, 'files'))); +app.use(express.static(path.join(__dirname, 'uploads'))); +``` + +The `router.use()` method also supports named parameters so that your mount points +for other routers can benefit from preloading using named parameters. + +**NOTE**: Although these middleware functions are added via a particular router, _when_ +they run is defined by the path they are attached to (not the router). Therefore, +middleware added via one router may run for other routers if its routes +match. For example, this code shows two different routers mounted on the same path: + +```js +const authRouter = express.Router(); +const openRouter = express.Router(); + +authRouter.use(require('./authenticate').basic(usersdb)); + +authRouter.get('/:user_id/edit', (req, res, next) => { + // ... Edit user UI ... +}); +openRouter.get('/', (req, res, next) => { + // ... List users ... +}); +openRouter.get('/:user_id', (req, res, next) => { + // ... View user ... +}); + +app.use('/users', authRouter); +app.use('/users', openRouter); +``` + +Even though the authentication middleware was added via the `authRouter` it will run on the routes defined by the `openRouter` as well since both routers were mounted on `/users`. To avoid this behavior, use different paths for each router. diff --git a/astro/src/content/docs/en/5x/api/router/router.md b/astro/src/content/docs/en/5x/api/router/router.md new file mode 100644 index 0000000000..e961fa8eb6 --- /dev/null +++ b/astro/src/content/docs/en/5x/api/router/router.md @@ -0,0 +1,66 @@ +--- +title: Methods +description: section markdown="1"> +--- + +

Router

+ +
+A `router` object is an instance of middleware and routes. You can think of it +as a "mini-application," capable only of performing middleware and routing +functions. Every Express application has a built-in app router. + +A router behaves like middleware itself, so you can use it as an argument to +[app.use()](#app.use) or as the argument to another router's [use()](#router.use) method. + +The top-level `express` object has a [Router()](#express.router) method that creates a new `router` object. + +Once you've created a router object, you can add middleware and HTTP method routes (such as `get`, `put`, `post`, +and so on) to it just like an application. For example: + +```js +// invoked for any requests passed to this router +router.use((req, res, next) => { + // .. some logic here .. like any other middleware + next(); +}); + +// will handle any request that ends in /events +// depends on where the router is "use()'d" +router.get('/events', (req, res, next) => { + // .. +}); +``` + +You can then use a router for a particular root URL in this way separating your routes into files or even mini-apps. + +```js +// only requests to /calendar/* will be sent to our "router" +app.use('/calendar', router); +``` + +Keep in mind that any middleware applied to a router will run for all requests on that router's path, even those that aren't part of the router. + +
+ +

Methods

+ +
+ {% include api/en/5x/router-all.md %} +
+ +
+ {% include api/en/5x/router-METHOD.md %} +
+ +
+ {% include api/en/5x/router-param.md %} +
+ +
+ {% include api/en/5x/router-route.md %} +
+ +
+ {% include api/en/5x/router-use.md %} +
diff --git a/astro/src/content/docs/en/5x/guide/behind-proxies.md b/astro/src/content/docs/en/5x/guide/behind-proxies.md new file mode 100755 index 0000000000..a9e4921603 --- /dev/null +++ b/astro/src/content/docs/en/5x/guide/behind-proxies.md @@ -0,0 +1,92 @@ +--- +title: Express behind proxies +description: Learn how to configure Express.js applications to work correctly behind reverse proxies, including using the trust proxy setting to handle client IP addresses. +--- + +# Express behind proxies + +When running an Express app behind a reverse proxy, some of the Express APIs may return different values than expected. In order to adjust for this, the `trust proxy` application setting may be used to expose information provided by the reverse proxy in the Express APIs. The most common issue is express APIs that expose the client's IP address may instead show an internal IP address of the reverse proxy. + +
+When configuring the `trust proxy` setting, it is important to understand the exact setup of the reverse proxy. Since this setting will trust values provided in the request, it is important that the combination of the setting in Express matches how the reverse proxy operates. +
+ +The application setting `trust proxy` may be set to one of the values listed in the following table. + + + + + + + + + + + + + + + + + + + + + +
TypeValue
Boolean +If `true`, the client's IP address is understood as the left-most entry in the `X-Forwarded-For` header. + +If `false`, the app is understood as directly facing the client and the client's IP address is derived from `req.socket.remoteAddress`. This is the default setting. + +
+When setting to `true`, it is important to ensure that the last reverse proxy trusted is removing/overwriting all of the following HTTP headers: `X-Forwarded-For`, `X-Forwarded-Host`, and `X-Forwarded-Proto`, otherwise it may be possible for the client to provide any value. +
+
IP addresses +An IP address, subnet, or an array of IP addresses and subnets to trust as being a reverse proxy. The following list shows the pre-configured subnet names: + +- loopback - `127.0.0.1/8`, `::1/128` +- linklocal - `169.254.0.0/16`, `fe80::/10` +- uniquelocal - `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `fc00::/7` + +You can set IP addresses in any of the following ways: + +```js +app.set('trust proxy', 'loopback'); // specify a single subnet +app.set('trust proxy', 'loopback, 123.123.123.123'); // specify a subnet and an address +app.set('trust proxy', 'loopback, linklocal, uniquelocal'); // specify multiple subnets as CSV +app.set('trust proxy', ['loopback', 'linklocal', 'uniquelocal']); // specify multiple subnets as an array +``` + +When specified, the IP addresses or the subnets are excluded from the address determination process, and the untrusted IP address nearest to the application server is determined as the client's IP address. This works by checking if `req.socket.remoteAddress` is trusted. If so, then each address in `X-Forwarded-For` is checked from right to left until the first non-trusted address. + +
Number +Use the address that is at most `n` number of hops away from the Express application. `req.socket.remoteAddress` is the first hop, and the rest are looked for in the `X-Forwarded-For` header from right to left. A value of `0` means that the first untrusted address would be `req.socket.remoteAddress`, i.e. there is no reverse proxy. + +
+When using this setting, it is important to ensure there are not multiple, different-length paths to the Express application such that the client can be less than the configured number of hops away, otherwise it may be possible for the client to provide any value. +
+
Function +Custom trust implementation. + +```js +app.set('trust proxy', (ip) => { + if (ip === '127.0.0.1' || ip === '123.123.123.123') + return true; // trusted IPs + else return false; +}); +``` + +
+ +Enabling `trust proxy` will have the following impact: + +
    +
  • The value of [req.hostname](/{{ page.lang }}/api.html#req.hostname) is derived from the value set in the `X-Forwarded-Host` header, which can be set by the client or by the proxy. +
  • +
  • `X-Forwarded-Proto` can be set by the reverse proxy to tell the app whether it is `https` or `http` or even an invalid name. This value is reflected by [req.protocol](/{{ page.lang }}/api.html#req.protocol). +
  • +
  • The [req.ip](/{{ page.lang }}/api.html#req.ip) and [req.ips](/{{ page.lang }}/api.html#req.ips) values are populated based on the socket address and `X-Forwarded-For` header, starting at the first untrusted address. +
  • +
+ +The `trust proxy` setting is implemented using the [proxy-addr](https://www.npmjs.com/package/proxy-addr) package. For more information, see its documentation. diff --git a/astro/src/content/docs/en/5x/guide/database-integration.md b/astro/src/content/docs/en/5x/guide/database-integration.md new file mode 100644 index 0000000000..3c653355ad --- /dev/null +++ b/astro/src/content/docs/en/5x/guide/database-integration.md @@ -0,0 +1,501 @@ +--- +title: Express database integration +description: Discover how to integrate various databases with Express.js applications, including setup examples for MongoDB, MySQL, PostgreSQL, and more. +--- + +# Database integration + +Adding the capability to connect databases to Express apps is just a matter of loading an appropriate Node.js driver for the database in your app. This document briefly explains how to add and use some of the most popular Node.js modules for database systems in your Express app: + +- [Cassandra](#cassandra) +- [Couchbase](#couchbase) +- [CouchDB](#couchdb) +- [LevelDB](#leveldb) +- [MySQL](#mysql) +- [MongoDB](#mongodb) +- [Neo4j](#neo4j) +- [Oracle](#oracle) +- [PostgreSQL](#postgresql) +- [Redis](#redis) +- [SQL Server](#sql-server) +- [SQLite](#sqlite) +- [Elasticsearch](#elasticsearch) + +
+These database drivers are among many that are available. For other options, +search on the [npm](https://www.npmjs.com/) site. +
+ +## Cassandra + +**Module**: [cassandra-driver](https://github.com/datastax/nodejs-driver) + +### Installation + +```bash +$ npm install cassandra-driver +``` + +### Example + +```js +const cassandra = require('cassandra-driver'); +const client = new cassandra.Client({ contactPoints: ['localhost'] }); + +client.execute('select key from system.local', (err, result) => { + if (err) throw err; + console.log(result.rows[0]); +}); +``` + +## Couchbase + +**Module**: [couchnode](https://github.com/couchbase/couchnode) + +### Installation + +```bash +$ npm install couchbase +``` + +### Example + +```js +const couchbase = require('couchbase'); +const bucket = new couchbase.Cluster('http://localhost:8091').openBucket('bucketName'); + +// add a document to a bucket +bucket.insert('document-key', { name: 'Matt', shoeSize: 13 }, (err, result) => { + if (err) { + console.log(err); + } else { + console.log(result); + } +}); + +// get all documents with shoe size 13 +const n1ql = 'SELECT d.* FROM `bucketName` d WHERE shoeSize = $1'; +const query = N1qlQuery.fromString(n1ql); +bucket.query(query, [13], (err, result) => { + if (err) { + console.log(err); + } else { + console.log(result); + } +}); +``` + +## CouchDB + +**Module**: [nano](https://github.com/dscape/nano) + +### Installation + +```bash +$ npm install nano +``` + +### Example + +```js +const nano = require('nano')('http://localhost:5984'); +nano.db.create('books'); +const books = nano.db.use('books'); + +// Insert a book document in the books database +books.insert({ name: 'The Art of war' }, null, (err, body) => { + if (err) { + console.log(err); + } else { + console.log(body); + } +}); + +// Get a list of all books +books.list((err, body) => { + if (err) { + console.log(err); + } else { + console.log(body.rows); + } +}); +``` + +## LevelDB + +**Module**: [levelup](https://github.com/rvagg/node-levelup) + +### Installation + +```bash +$ npm install level levelup leveldown +``` + +### Example + +```js +const levelup = require('levelup'); +const db = levelup('./mydb'); + +db.put('name', 'LevelUP', (err) => { + if (err) return console.log('Ooops!', err); + + db.get('name', (err, value) => { + if (err) return console.log('Ooops!', err); + + console.log(`name=${value}`); + }); +}); +``` + +## MySQL + +**Module**: [mysql](https://github.com/felixge/node-mysql/) + +### Installation + +```bash +$ npm install mysql +``` + +### Example + +```js +const mysql = require('mysql'); +const connection = mysql.createConnection({ + host: 'localhost', + user: 'dbuser', + password: 's3kreee7', + database: 'my_db', +}); + +connection.connect(); + +connection.query('SELECT 1 + 1 AS solution', (err, rows, fields) => { + if (err) throw err; + + console.log('The solution is: ', rows[0].solution); +}); + +connection.end(); +``` + +## MongoDB + +**Module**: [mongodb](https://github.com/mongodb/node-mongodb-native) + +### Installation + +```bash +$ npm install mongodb +``` + +### Example (v2.\*) + +```js +const MongoClient = require('mongodb').MongoClient; + +MongoClient.connect('mongodb://localhost:27017/animals', (err, db) => { + if (err) throw err; + + db.collection('mammals') + .find() + .toArray((err, result) => { + if (err) throw err; + + console.log(result); + }); +}); +``` + +### Example (v3.\*) + +```js +const MongoClient = require('mongodb').MongoClient; + +MongoClient.connect('mongodb://localhost:27017/animals', (err, client) => { + if (err) throw err; + + const db = client.db('animals'); + + db.collection('mammals') + .find() + .toArray((err, result) => { + if (err) throw err; + + console.log(result); + }); +}); +``` + +If you want an object model driver for MongoDB, look at [Mongoose](https://github.com/LearnBoost/mongoose). + +## Neo4j + +**Module**: [neo4j-driver](https://github.com/neo4j/neo4j-javascript-driver) + +### Installation + +```bash +$ npm install neo4j-driver +``` + +### Example + +```js +const neo4j = require('neo4j-driver'); +const driver = neo4j.driver('neo4j://localhost:7687', neo4j.auth.basic('neo4j', 'letmein')); + +const session = driver.session(); + +session.readTransaction((tx) => { + return tx + .run('MATCH (n) RETURN count(n) AS count') + .then((res) => { + console.log(res.records[0].get('count')); + }) + .catch((error) => { + console.log(error); + }); +}); +``` + +## Oracle + +**Module**: [oracledb](https://github.com/oracle/node-oracledb) + +### Installation + +NOTE: [See installation prerequisites](https://github.com/oracle/node-oracledb#-installation). + +```bash +$ npm install oracledb +``` + +### Example + +```js +const oracledb = require('oracledb'); +const config = { + user: '', + password: '', + connectString: 'localhost:1521/orcl', +}; + +async function getEmployee(empId) { + let conn; + + try { + conn = await oracledb.getConnection(config); + + const result = await conn.execute('select * from employees where employee_id = :id', [empId]); + + console.log(result.rows[0]); + } catch (err) { + console.log('Ouch!', err); + } finally { + if (conn) { + // conn assignment worked, need to close + await conn.close(); + } + } +} + +getEmployee(101); +``` + +## PostgreSQL + +**Module**: [pg-promise](https://github.com/vitaly-t/pg-promise) + +### Installation + +```bash +$ npm install pg-promise +``` + +### Example + +```js +const pgp = require('pg-promise')(/* options */); +const db = pgp('postgres://username:password@host:port/database'); + +db.one('SELECT $1 AS value', 123) + .then((data) => { + console.log('DATA:', data.value); + }) + .catch((error) => { + console.log('ERROR:', error); + }); +``` + +## Redis + +**Module**: [redis](https://github.com/mranney/node_redis) + +### Installation + +```bash +$ npm install redis +``` + +### Example + +```js +const redis = require('redis'); +const client = redis.createClient(); + +client.on('error', (err) => { + console.log(`Error ${err}`); +}); + +client.set('string key', 'string val', redis.print); +client.hset('hash key', 'hashtest 1', 'some value', redis.print); +client.hset(['hash key', 'hashtest 2', 'some other value'], redis.print); + +client.hkeys('hash key', (err, replies) => { + console.log(`${replies.length} replies:`); + + replies.forEach((reply, i) => { + console.log(` ${i}: ${reply}`); + }); + + client.quit(); +}); +``` + +## SQL Server + +**Module**: [tedious](https://github.com/tediousjs/tedious) + +### Installation + +```bash +$ npm install tedious +``` + +### Example + +```js +const Connection = require('tedious').Connection; +const Request = require('tedious').Request; + +const config = { + server: 'localhost', + authentication: { + type: 'default', + options: { + userName: 'your_username', // update me + password: 'your_password', // update me + }, + }, +}; + +const connection = new Connection(config); + +connection.on('connect', (err) => { + if (err) { + console.log(err); + } else { + executeStatement(); + } +}); + +function executeStatement() { + request = new Request("select 123, 'hello world'", (err, rowCount) => { + if (err) { + console.log(err); + } else { + console.log(`${rowCount} rows`); + } + connection.close(); + }); + + request.on('row', (columns) => { + columns.forEach((column) => { + if (column.value === null) { + console.log('NULL'); + } else { + console.log(column.value); + } + }); + }); + + connection.execSql(request); +} +``` + +## SQLite + +**Module**: [sqlite3](https://github.com/mapbox/node-sqlite3) + +### Installation + +```bash +$ npm install sqlite3 +``` + +### Example + +```js +const sqlite3 = require('sqlite3').verbose(); +const db = new sqlite3.Database(':memory:'); + +db.serialize(() => { + db.run('CREATE TABLE lorem (info TEXT)'); + const stmt = db.prepare('INSERT INTO lorem VALUES (?)'); + + for (let i = 0; i < 10; i++) { + stmt.run(`Ipsum ${i}`); + } + + stmt.finalize(); + + db.each('SELECT rowid AS id, info FROM lorem', (err, row) => { + console.log(`${row.id}: ${row.info}`); + }); +}); + +db.close(); +``` + +## Elasticsearch + +**Module**: [elasticsearch](https://github.com/elastic/elasticsearch-js) + +### Installation + +```bash +$ npm install elasticsearch +``` + +### Example + +```js +const elasticsearch = require('elasticsearch'); +const client = elasticsearch.Client({ + host: 'localhost:9200', +}); + +client + .search({ + index: 'books', + type: 'book', + body: { + query: { + multi_match: { + query: 'express js', + fields: ['title', 'description'], + }, + }, + }, + }) + .then( + (response) => { + const hits = response.hits.hits; + }, + (error) => { + console.trace(error.message); + } + ); +``` diff --git a/astro/src/content/docs/en/5x/guide/debugging.md b/astro/src/content/docs/en/5x/guide/debugging.md new file mode 100755 index 0000000000..9aabe80876 --- /dev/null +++ b/astro/src/content/docs/en/5x/guide/debugging.md @@ -0,0 +1,127 @@ +--- +title: Debugging Express +description: Learn how to enable and use debugging logs in Express.js applications by setting the DEBUG environment variable for enhanced troubleshooting. +--- + +# Debugging Express + +To see all the internal logs used in Express, set the `DEBUG` environment variable to +`express:*` when launching your app. + +```bash +$ DEBUG=express:* node index.js +``` + +On Windows, use the corresponding command. + +```bash +> $env:DEBUG = "express:*"; node index.js +``` + +Running this command on the default app generated by the [express generator](/{{ page.lang }}/starter/generator.html) prints the following output: + +```bash +$ DEBUG=express:* node ./bin/www + express:router:route new / +0ms + express:router:layer new / +1ms + express:router:route get / +1ms + express:router:layer new / +0ms + express:router:route new / +1ms + express:router:layer new / +0ms + express:router:route get / +0ms + express:router:layer new / +0ms + express:application compile etag weak +1ms + express:application compile query parser extended +0ms + express:application compile trust proxy false +0ms + express:application booting in development mode +1ms + express:router use / query +0ms + express:router:layer new / +0ms + express:router use / expressInit +0ms + express:router:layer new / +0ms + express:router use / favicon +1ms + express:router:layer new / +0ms + express:router use / logger +0ms + express:router:layer new / +0ms + express:router use / jsonParser +0ms + express:router:layer new / +1ms + express:router use / urlencodedParser +0ms + express:router:layer new / +0ms + express:router use / cookieParser +0ms + express:router:layer new / +0ms + express:router use / stylus +90ms + express:router:layer new / +0ms + express:router use / serveStatic +0ms + express:router:layer new / +0ms + express:router use / router +0ms + express:router:layer new / +1ms + express:router use /users router +0ms + express:router:layer new /users +0ms + express:router use / <anonymous> +0ms + express:router:layer new / +0ms + express:router use / <anonymous> +0ms + express:router:layer new / +0ms + express:router use / <anonymous> +0ms + express:router:layer new / +0ms +``` + +When a request is then made to the app, you will see the logs specified in the Express code: + +```bash + express:router dispatching GET / +4h + express:router query : / +2ms + express:router expressInit : / +0ms + express:router favicon : / +0ms + express:router logger : / +1ms + express:router jsonParser : / +0ms + express:router urlencodedParser : / +1ms + express:router cookieParser : / +0ms + express:router stylus : / +0ms + express:router serveStatic : / +2ms + express:router router : / +2ms + express:router dispatching GET / +1ms + express:view lookup "index.pug" +338ms + express:view stat "/projects/example/views/index.pug" +0ms + express:view render "/projects/example/views/index.pug" +1ms +``` + +To see the logs only from the router implementation, set the value of `DEBUG` to `express:router`. Likewise, to see logs only from the application implementation, set the value of `DEBUG` to `express:application`, and so on. + +## Applications generated by `express` + +An application generated by the `express` command uses the `debug` module and its debug namespace is scoped to the name of the application. + +For example, if you generated the app with `$ express sample-app`, you can enable the debug statements with the following command: + +```bash +$ DEBUG=sample-app:* node ./bin/www +``` + +You can specify more than one debug namespace by assigning a comma-separated list of names: + +```bash +$ DEBUG=http,mail,express:* node index.js +``` + +## Advanced options + +When running through Node.js, you can set a few environment variables that will change the behavior of the debug logging: + +| Name | Purpose | +| ------------------- | ------------------------------------------------- | +| `DEBUG` | Enables/disables specific debugging namespaces. | +| `DEBUG_COLORS` | Whether or not to use colors in the debug output. | +| `DEBUG_DEPTH` | Object inspection depth. | +| `DEBUG_FD` | File descriptor to write debug output to. | +| `DEBUG_SHOW_HIDDEN` | Shows hidden properties on inspected objects. | + +{% capture debug-text %} + +The environment variables beginning with `DEBUG_` end up being +converted into an Options object that gets used with `%o`/`%O` formatters. +See the Node.js documentation for +[`util.inspect()`](https://nodejs.org/api/util.html#util_util_inspect_object_options) +for the complete list. + +{% endcapture %} + +{% include admonitions/note.html content=debug-text %} diff --git a/astro/src/content/docs/en/5x/guide/error-handling.md b/astro/src/content/docs/en/5x/guide/error-handling.md new file mode 100755 index 0000000000..3c81881742 --- /dev/null +++ b/astro/src/content/docs/en/5x/guide/error-handling.md @@ -0,0 +1,306 @@ +--- +title: Express error handling +description: Understand how Express.js handles errors in synchronous and asynchronous code, and learn to implement custom error handling middleware for your applications. +--- + +# Error Handling + +_Error Handling_ refers to how Express catches and processes errors that +occur both synchronously and asynchronously. Express comes with a default error +handler so you don't need to write your own to get started. + +## Catching Errors + +It's important to ensure that Express catches all errors that occur while +running route handlers and middleware. + +Errors that occur in synchronous code inside route handlers and middleware +require no extra work. If synchronous code throws an error, then Express will +catch and process it. For example: + +```js +app.get('/', (req, res) => { + throw new Error('BROKEN'); // Express will catch this on its own. +}); +``` + +For errors returned from asynchronous functions invoked by route handlers +and middleware, you must pass them to the `next()` function, where Express will +catch and process them. For example: + +```js +app.get('/', (req, res, next) => { + fs.readFile('/file-does-not-exist', (err, data) => { + if (err) { + next(err); // Pass errors to Express. + } else { + res.send(data); + } + }); +}); +``` + +Starting with Express 5, route handlers and middleware that return a Promise +will call `next(value)` automatically when they reject or throw an error. +For example: + +```js +app.get('/user/:id', async (req, res, next) => { + const user = await getUserById(req.params.id); + res.send(user); +}); +``` + +If `getUserById` throws an error or rejects, `next` will be called with either +the thrown error or the rejected value. If no rejected value is provided, `next` +will be called with a default Error object provided by the Express router. + +If you pass anything to the `next()` function (except the string `'route'`), +Express regards the current request as being an error and will skip any +remaining non-error handling routing and middleware functions. + +If the callback in a sequence provides no data, only errors, you can simplify +this code as follows: + +```js +app.get('/', [ + function (req, res, next) { + fs.writeFile('/inaccessible-path', 'data', next); + }, + function (req, res) { + res.send('OK'); + }, +]); +``` + +In the above example, `next` is provided as the callback for `fs.writeFile`, +which is called with or without errors. If there is no error, the second +handler is executed, otherwise Express catches and processes the error. + +You must catch errors that occur in asynchronous code invoked by route handlers or +middleware and pass them to Express for processing. For example: + +```js +app.get('/', (req, res, next) => { + setTimeout(() => { + try { + throw new Error('BROKEN'); + } catch (err) { + next(err); + } + }, 100); +}); +``` + +The above example uses a `try...catch` block to catch errors in the +asynchronous code and pass them to Express. If the `try...catch` +block were omitted, Express would not catch the error since it is not part of the synchronous +handler code. + +Use promises to avoid the overhead of the `try...catch` block or when using functions +that return promises. For example: + +```js +app.get('/', (req, res, next) => { + Promise.resolve() + .then(() => { + throw new Error('BROKEN'); + }) + .catch(next); // Errors will be passed to Express. +}); +``` + +Since promises automatically catch both synchronous errors and rejected promises, +you can simply provide `next` as the final catch handler and Express will catch errors, +because the catch handler is given the error as the first argument. + +You could also use a chain of handlers to rely on synchronous error +catching, by reducing the asynchronous code to something trivial. For example: + +```js +app.get('/', [ + function (req, res, next) { + fs.readFile('/maybe-valid-file', 'utf-8', (err, data) => { + res.locals.data = data; + next(err); + }); + }, + function (req, res) { + res.locals.data = res.locals.data.split(',')[1]; + res.send(res.locals.data); + }, +]); +``` + +The above example has a couple of trivial statements from the `readFile` +call. If `readFile` causes an error, then it passes the error to Express, otherwise you +quickly return to the world of synchronous error handling in the next handler +in the chain. Then, the example above tries to process the data. If this fails, then the +synchronous error handler will catch it. If you had done this processing inside +the `readFile` callback, then the application might exit and the Express error +handlers would not run. + +Whichever method you use, if you want Express error handlers to be called in and the +application to survive, you must ensure that Express receives the error. + +## The default error handler + +Express comes with a built-in error handler that takes care of any errors that might be encountered in the app. This default error-handling middleware function is added at the end of the middleware function stack. + +If you pass an error to `next()` and you do not handle it in a custom error +handler, it will be handled by the built-in error handler; the error will be +written to the client with the stack trace. The stack trace is not included +in the production environment. + +
+Set the environment variable `NODE_ENV` to `production`, to run the app in production mode. +
+ +When an error is written, the following information is added to the +response: + +- The `res.statusCode` is set from `err.status` (or `err.statusCode`). If + this value is outside the 4xx or 5xx range, it will be set to 500. +- The `res.statusMessage` is set according to the status code. +- The body will be the HTML of the status code message when in production + environment, otherwise will be `err.stack`. +- Any headers specified in an `err.headers` object. + +If you call `next()` with an error after you have started writing the +response (for example, if you encounter an error while streaming the +response to the client), the Express default error handler closes the +connection and fails the request. + +So when you add a custom error handler, you must delegate to +the default Express error handler, when the headers +have already been sent to the client: + +```js +function errorHandler(err, req, res, next) { + if (res.headersSent) { + return next(err); + } + res.status(500); + res.render('error', { error: err }); +} +``` + +Note that the default error handler can get triggered if you call `next()` with an error +in your code more than once, even if custom error handling middleware is in place. + +Other error handling middleware can be found at [Express middleware](/{{ page.lang }}/resources/middleware.html). + +## Writing error handlers + +Define error-handling middleware functions in the same way as other middleware functions, +except error-handling functions have four arguments instead of three: +`(err, req, res, next)`. For example: + +```js +app.use((err, req, res, next) => { + console.error(err.stack); + res.status(500).send('Something broke!'); +}); +``` + +You define error-handling middleware last, after other `app.use()` and routes calls; for example: + +```js +const bodyParser = require('body-parser'); +const methodOverride = require('method-override'); + +app.use( + bodyParser.urlencoded({ + extended: true, + }) +); +app.use(bodyParser.json()); +app.use(methodOverride()); +app.use((err, req, res, next) => { + // logic +}); +``` + +Responses from within a middleware function can be in any format, such as an HTML error page, a simple message, or a JSON string. + +For organizational (and higher-level framework) purposes, you can define +several error-handling middleware functions, much as you would with +regular middleware functions. For example, to define an error-handler +for requests made by using `XHR` and those without: + +```js +const bodyParser = require('body-parser'); +const methodOverride = require('method-override'); + +app.use( + bodyParser.urlencoded({ + extended: true, + }) +); +app.use(bodyParser.json()); +app.use(methodOverride()); +app.use(logErrors); +app.use(clientErrorHandler); +app.use(errorHandler); +``` + +In this example, the generic `logErrors` might write request and +error information to `stderr`, for example: + +```js +function logErrors(err, req, res, next) { + console.error(err.stack); + next(err); +} +``` + +Also in this example, `clientErrorHandler` is defined as follows; in this case, the error is explicitly passed along to the next one. + +Notice that when _not_ calling "next" in an error-handling function, you are responsible for writing (and ending) the response. Otherwise, those requests will "hang" and will not be eligible for garbage collection. + +```js +function clientErrorHandler(err, req, res, next) { + if (req.xhr) { + res.status(500).send({ error: 'Something failed!' }); + } else { + next(err); + } +} +``` + +Implement the "catch-all" `errorHandler` function as follows (for example): + +```js +function errorHandler(err, req, res, next) { + res.status(500); + res.render('error', { error: err }); +} +``` + +If you have a route handler with multiple callback functions, you can use the `route` parameter to skip to the next route handler. For example: + +```js +app.get( + '/a_route_behind_paywall', + (req, res, next) => { + if (!req.user.hasPaid) { + // continue handling this request + next('route'); + } else { + next(); + } + }, + (req, res, next) => { + PaidContent.find((err, doc) => { + if (err) return next(err); + res.json(doc); + }); + } +); +``` + +In this example, the `getPaidContent` handler will be skipped but any remaining handlers in `app` for `/a_route_behind_paywall` would continue to be executed. + +
+Calls to `next()` and `next(err)` indicate that the current handler is complete and in what state. `next(err)` will skip all remaining handlers in the chain except for those that are set up to handle errors as described above. +
diff --git a/astro/src/content/docs/en/5x/guide/migrating-4.md b/astro/src/content/docs/en/5x/guide/migrating-4.md new file mode 100755 index 0000000000..bc463dea44 --- /dev/null +++ b/astro/src/content/docs/en/5x/guide/migrating-4.md @@ -0,0 +1,613 @@ +--- +title: Migrating to Express 4 +description: A guide to migrating your Express.js applications from version 3 to 4, covering changes in middleware, routing, and how to update your codebase effectively. +--- + +# Moving to Express 4 + +

Overview

+ +Express 4 is a breaking change from Express 3. That means an existing Express 3 app will _not_ work if you update the Express version in its dependencies. + +This article covers: + + + +

Changes in Express 4

+ +There are several significant changes in Express 4: + + + +See also: + +- [New features in 4.x.](https://github.com/expressjs/express/wiki/New-features-in-4.x) +- [Migrating from 3.x to 4.x.](https://github.com/expressjs/express/wiki/Migrating-from-3.x-to-4.x) + +

+Changes to Express core and middleware system +

+ +Express 4 no longer depends on Connect, and removes all built-in +middleware from its core, except for the `express.static` function. This means that +Express is now an independent routing and middleware web framework, and +Express versioning and releases are not affected by middleware updates. + +Without built-in middleware, you must explicitly add all the +middleware that is required to run your app. Simply follow these steps: + +1. Install the module: `npm install --save ` +2. In your app, require the module: `require('module-name')` +3. Use the module according to its documentation: `app.use( ... )` + +The following table lists Express 3 middleware and their counterparts in Express 4. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Express 3Express 4
express.bodyParserbody-parser + +multer
express.compresscompression
express.cookieSessioncookie-session
express.cookieParsercookie-parser
express.loggermorgan
express.sessionexpress-session
express.faviconserve-favicon
express.responseTimeresponse-time
express.errorHandlererrorhandler
express.methodOverridemethod-override
express.timeoutconnect-timeout
express.vhostvhost
express.csrfcsurf
express.directoryserve-index
express.staticserve-static
+ +Here is the [complete list](https://github.com/senchalabs/connect#middleware) of Express 4 middleware. + +In most cases, you can simply replace the old version 3 middleware with +its Express 4 counterpart. For details, see the module documentation in +GitHub. + +

app.use accepts parameters

+ +In version 4 you can use a variable parameter to define the path where middleware functions are loaded, then read the value of the parameter from the route handler. +For example: + +```js +app.use('/book/:id', (req, res, next) => { + console.log('ID:', req.params.id); + next(); +}); +``` + +

+The routing system +

+ +Apps now implicitly load routing middleware, so you no longer have to +worry about the order in which middleware is loaded with respect to +the `router` middleware. + +The way you define routes is unchanged, but the routing system has two +new features to help organize your routes: + +{: .doclist } + +- A new method, `app.route()`, to create chainable route handlers for a route path. +- A new class, `express.Router`, to create modular mountable route handlers. + +

app.route() method

+ +The new `app.route()` method enables you to create chainable route handlers +for a route path. Because the path is specified in a single location, creating modular routes is helpful, as is reducing redundancy and typos. For more +information about routes, see [`Router()` documentation](/{{ page.lang }}/4x/api.html#router). + +Here is an example of chained route handlers that are defined by using the `app.route()` function. + +```js +app + .route('/book') + .get((req, res) => { + res.send('Get a random book'); + }) + .post((req, res) => { + res.send('Add a book'); + }) + .put((req, res) => { + res.send('Update the book'); + }); +``` + +

express.Router class

+ +The other feature that helps to organize routes is a new class, +`express.Router`, that you can use to create modular mountable +route handlers. A `Router` instance is a complete middleware and +routing system; for this reason it is often referred to as a "mini-app". + +The following example creates a router as a module, loads middleware in +it, defines some routes, and mounts it on a path on the main app. + +For example, create a router file named `birds.js` in the app directory, +with the following content: + +```js +var express = require('express'); +var router = express.Router(); + +// middleware specific to this router +router.use((req, res, next) => { + console.log('Time: ', Date.now()); + next(); +}); +// define the home page route +router.get('/', (req, res) => { + res.send('Birds home page'); +}); +// define the about route +router.get('/about', (req, res) => { + res.send('About birds'); +}); + +module.exports = router; +``` + +Then, load the router module in the app: + +```js +var birds = require('./birds'); + +// ... + +app.use('/birds', birds); +``` + +The app will now be able to handle requests to the `/birds` and +`/birds/about` paths, and will call the `timeLog` +middleware that is specific to the route. + +

+Other changes +

+ +The following table lists other small but important changes in Express 4: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ObjectDescription
Node.jsExpress 4 requires Node.js 0.10.x or later and has dropped support for +Node.js 0.8.x.
+`http.createServer()` + +The `http` module is no longer needed, unless you need to directly work with it (socket.io/SPDY/HTTPS). The app can be started by using the +`app.listen()` function. +
+`app.configure()` + +The `app.configure()` function has been removed. Use the +`process.env.NODE_ENV` or +`app.get('env')` function to detect the environment and configure the app accordingly. +
+`json spaces` + +The `json spaces` application property is disabled by default in Express 4. +
+`req.accepted()` + +Use `req.accepts()`, `req.acceptsEncodings()`, +`req.acceptsCharsets()`, and `req.acceptsLanguages()`. +
+`res.location()` + +No longer resolves relative URLs. +
+`req.params` + +Was an array; now an object. +
+`res.locals` + +Was a function; now an object. +
+`res.headerSent` + +Changed to `res.headersSent`. +
+`app.route` + +Now available as `app.mountpath`. +
+`res.on('header')` + +Removed. +
+`res.charset` + +Removed. +
+`res.setHeader('Set-Cookie', val)` + +Functionality is now limited to setting the basic cookie value. Use +`res.cookie()` for added functionality. +
+ +

Example app migration

+ +Here is an example of migrating an Express 3 application to Express 4. +The files of interest are `app.js` and `package.json`. + +

+Version 3 app +

+ +

app.js

+ +Consider an Express v.3 application with the following `app.js` file: + +```js +var express = require('express'); +var routes = require('./routes'); +var user = require('./routes/user'); +var http = require('http'); +var path = require('path'); + +var app = express(); + +// all environments +app.set('port', process.env.PORT || 3000); +app.set('views', path.join(__dirname, 'views')); +app.set('view engine', 'pug'); +app.use(express.favicon()); +app.use(express.logger('dev')); +app.use(express.methodOverride()); +app.use(express.session({ secret: 'your secret here' })); +app.use(express.bodyParser()); +app.use(app.router); +app.use(express.static(path.join(__dirname, 'public'))); + +// development only +if (app.get('env') === 'development') { + app.use(express.errorHandler()); +} + +app.get('/', routes.index); +app.get('/users', user.list); + +http.createServer(app).listen(app.get('port'), () => { + console.log('Express server listening on port ' + app.get('port')); +}); +``` + +

package.json

+ +The accompanying version 3 `package.json` file might look +something like this: + +```json +{ + "name": "application-name", + "version": "0.0.1", + "private": true, + "scripts": { + "start": "node app.js" + }, + "dependencies": { + "express": "3.12.0", + "pug": "*" + } +} +``` + +

+Process +

+ +Begin the migration process by installing the required middleware for the +Express 4 app and updating Express and Pug to their respective latest +version with the following command: + +```bash +$ npm install serve-favicon morgan method-override express-session body-parser multer errorhandler express@latest pug@latest --save +``` + +Make the following changes to `app.js`: + +1. The built-in Express middleware functions `express.favicon`, + `express.logger`, `express.methodOverride`, + `express.session`, `express.bodyParser` and + `express.errorHandler` are no longer available on the + `express` object. You must install their alternatives + manually and load them in the app. + +2. You no longer need to load the `app.router` function. + It is not a valid Express 4 app object, so remove the + `app.use(app.router);` code. + +3. Make sure that the middleware functions are loaded in the correct order - load `errorHandler` after loading the app routes. + +

Version 4 app

+ +

package.json

+ +Running the above `npm` command will update `package.json` as follows: + +```json +{ + "name": "application-name", + "version": "0.0.1", + "private": true, + "scripts": { + "start": "node app.js" + }, + "dependencies": { + "body-parser": "^1.5.2", + "errorhandler": "^1.1.1", + "express": "^4.8.0", + "express-session": "^1.7.2", + "pug": "^2.0.0", + "method-override": "^2.1.2", + "morgan": "^1.2.2", + "multer": "^0.1.3", + "serve-favicon": "^2.0.1" + } +} +``` + +

app.js

+ +Then, remove invalid code, load the required middleware, and make other +changes as necessary. The `app.js` file will look like this: + +```js +var http = require('http'); +var express = require('express'); +var routes = require('./routes'); +var user = require('./routes/user'); +var path = require('path'); + +var favicon = require('serve-favicon'); +var logger = require('morgan'); +var methodOverride = require('method-override'); +var session = require('express-session'); +var bodyParser = require('body-parser'); +var multer = require('multer'); +var errorHandler = require('errorhandler'); + +var app = express(); + +// all environments +app.set('port', process.env.PORT || 3000); +app.set('views', path.join(__dirname, 'views')); +app.set('view engine', 'pug'); +app.use(favicon(path.join(__dirname, '/public/favicon.ico'))); +app.use(logger('dev')); +app.use(methodOverride()); +app.use( + session({ + resave: true, + saveUninitialized: true, + secret: 'uwotm8', + }) +); +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: true })); +app.use(multer()); +app.use(express.static(path.join(__dirname, 'public'))); + +app.get('/', routes.index); +app.get('/users', user.list); + +// error handling middleware should be loaded after the loading the routes +if (app.get('env') === 'development') { + app.use(errorHandler()); +} + +var server = http.createServer(app); +server.listen(app.get('port'), () => { + console.log('Express server listening on port ' + app.get('port')); +}); +``` + +
+Unless you need to work directly with the `http` module (socket.io/SPDY/HTTPS), loading it is not required, and the app can be simply started this way: + +```js +app.listen(app.get('port'), () => { + console.log('Express server listening on port ' + app.get('port')); +}); +``` + +
+ +

Run the app

+ +The migration process is complete, and the app is now an +Express 4 app. To confirm, start the app by using the following command: + +```bash +$ node . +``` + +Load [http://localhost:3000](http://localhost:3000) +and see the home page being rendered by Express 4. + +

Upgrading to the Express 4 app generator

+ +The command-line tool to generate an Express app is still +`express`, but to upgrade to the new version, you must uninstall +the Express 3 app generator and then install the new +`express-generator`. + +

Installing

+ +If you already have the Express 3 app generator installed on your system, +you must uninstall it: + +```bash +$ npm uninstall -g express +``` + +Depending on how your file and directory privileges are configured, +you might need to run this command with `sudo`. + +Now install the new generator: + +```bash +$ npm install -g express-generator +``` + +Depending on how your file and directory privileges are configured, +you might need to run this command with `sudo`. + +Now the `express` command on your system is updated to the +Express 4 generator. + +

Changes to the app generator

+ +Command options and use largely remain the same, with the following exceptions: + +{: .doclist } + +- Removed the `--sessions` option. +- Removed the `--jshtml` option. +- Added the `--hogan` option to support [Hogan.js](http://twitter.github.io/hogan.js/). + +

Example

+ +Execute the following command to create an Express 4 app: + +```bash +$ express app4 +``` + +If you look at the contents of the `app4/app.js` file, you will notice +that all the middleware functions (except `express.static`) that are required for +the app are loaded as independent modules, and the `router` middleware +is no longer explicitly loaded in the app. + +You will also notice that the `app.js` file is now a Node.js module, in contrast to the standalone app that was generated by the old generator. + +After installing the dependencies, start the app by using the following command: + +```bash +$ npm start +``` + +If you look at the `npm start` script in the `package.json` file, +you will notice that the actual command that starts the app is +`node ./bin/www`, which used to be `node app.js` +in Express 3. + +Because the `app.js` file that was generated by the Express 4 generator +is now a Node.js module, it can no longer be started independently as an app +(unless you modify the code). The module must be loaded in a Node.js file +and started via the Node.js file. The Node.js file is `./bin/www` +in this case. + +Neither the `bin` directory nor the extensionless `www` +file is mandatory for creating an Express app or starting the app. They are +just suggestions made by the generator, so feel free to modify them to suit your +needs. + +To get rid of the `www` directory and keep things the "Express 3 way", +delete the line that says `module.exports = app;` at the end of the +`app.js` file, then paste the following code in its place: + +```js +app.set('port', process.env.PORT || 3000); + +var server = app.listen(app.get('port'), () => { + debug('Express server listening on port ' + server.address().port); +}); +``` + +Ensure that you load the `debug` module at the top of the `app.js` file by using the following code: + +```js +var debug = require('debug')('app4'); +``` + +Next, change `"start": "node ./bin/www"` in the `package.json` file to `"start": "node app.js"`. + +You have now moved the functionality of `./bin/www` back to +`app.js`. This change is not recommended, but the exercise helps you +to understand how the `./bin/www` file works, and why the `app.js` file +no longer starts on its own. diff --git a/astro/src/content/docs/en/5x/guide/migrating-5.md b/astro/src/content/docs/en/5x/guide/migrating-5.md new file mode 100755 index 0000000000..3d959ed7dd --- /dev/null +++ b/astro/src/content/docs/en/5x/guide/migrating-5.md @@ -0,0 +1,614 @@ +--- +title: Migrating to Express 5 +description: A comprehensive guide to migrating your Express.js applications from version 4 to 5, detailing breaking changes, deprecated methods, and new improvements. +--- + +# Moving to Express 5 + +

Overview

+ +Express 5 is not very different from Express 4; although it maintains the same basic API, there are still changes that break compatibility with the previous version. Therefore, an application built with Express 4 might not work if you update it to use Express 5. + +To install this version, you need to have a Node.js version 18 or higher. Then, execute the following command in your application directory: + +```sh +npm install "express@5" +``` + +You can then run your automated tests to see what fails, and fix problems according to the updates listed below. After addressing test failures, run your app to see what errors occur. You'll find out right away if the app uses any methods or properties that are not supported. + +## Express 5 Codemods + +To help you migrate your express server, we have created a set of codemods that will help you automatically update your code to the latest version of Express. + +Run the following command for run all the codemods available: + +```sh +npx codemod@latest @expressjs/v5-migration-recipe +``` + +If you want to run a specific codemod, you can run the following command: + +```sh +npx codemod@latest @expressjs/name-of-the-codemod +``` + +You can find the list of available codemods [here](https://codemod.link/express). + +

Changes in Express 5

+ +**Removed methods and properties** + + + +**Changed** + + + +**Improvements** + + + +## Removed methods and properties + +If you use any of these methods or properties in your app, it will crash. So, you'll need to change your app after you update to version 5. + +

app.del()

+ +Express 5 no longer supports the `app.del()` function. If you use this function, an error is thrown. For registering HTTP DELETE routes, use the `app.delete()` function instead. + +Initially, `del` was used instead of `delete`, because `delete` is a reserved keyword in JavaScript. However, as of ECMAScript 6, `delete` and other reserved keywords can legally be used as property names. + +{% capture codemod-route-del-to-delete %} +You can replace the deprecated signatures with the following command: + +```plaintext +npx codemod@latest @expressjs/route-del-to-delete +``` + +{% endcapture %} + +{% include admonitions/note.html content=codemod-route-del-to-delete %} + +```js +// v4 +app.del('/user/:id', (req, res) => { + res.send(`DELETE /user/${req.params.id}`); +}); + +// v5 +app.delete('/user/:id', (req, res) => { + res.send(`DELETE /user/${req.params.id}`); +}); +``` + +

app.param(fn)

+ +The `app.param(fn)` signature was used for modifying the behavior of the `app.param(name, fn)` function. It has been deprecated since v4.11.0, and Express 5 no longer supports it at all. + +

Pluralized method names

+ +The following method names have been pluralized. In Express 4, using the old methods resulted in a deprecation warning. Express 5 no longer supports them at all: + +`req.acceptsCharset()` is replaced by `req.acceptsCharsets()`. + +`req.acceptsEncoding()` is replaced by `req.acceptsEncodings()`. + +`req.acceptsLanguage()` is replaced by `req.acceptsLanguages()`. + +{% capture codemod-pluralized-methods %} +You can replace the deprecated signatures with the following command: + +```plaintext +npx codemod@latest @expressjs/pluralize-method-names +``` + +{% endcapture %} + +{% include admonitions/note.html content=codemod-pluralized-methods %} + +```js +// v4 +app.all('/', (req, res) => { + req.acceptsCharset('utf-8'); + req.acceptsEncoding('br'); + req.acceptsLanguage('en'); + + // ... +}); + +// v5 +app.all('/', (req, res) => { + req.acceptsCharsets('utf-8'); + req.acceptsEncodings('br'); + req.acceptsLanguages('en'); + + // ... +}); +``` + +

Leading colon (:) in the name for app.param(name, fn)

+ +A leading colon character (:) in the name for the `app.param(name, fn)` function is a remnant of Express 3, and for the sake of backwards compatibility, Express 4 supported it with a deprecation notice. Express 5 will silently ignore it and use the name parameter without prefixing it with a colon. + +This should not affect your code if you follow the Express 4 documentation of [app.param](/{{ page.lang }}/4x/api.html#app.param), as it makes no mention of the leading colon. + +

req.param(name)

+ +This potentially confusing and dangerous method of retrieving form data has been removed. You will now need to specifically look for the submitted parameter name in the `req.params`, `req.body`, or `req.query` object. + +{% capture codemod-req-param %} +You can replace the deprecated signatures with the following command: + +```plaintext +npx codemod@latest @expressjs/explicit-request-params +``` + +{% endcapture %} + +{% include admonitions/note.html content=codemod-req-param %} + +```js +// v4 +app.post('/user', (req, res) => { + const id = req.param('id'); + const body = req.param('body'); + const query = req.param('query'); + + // ... +}); + +// v5 +app.post('/user', (req, res) => { + const id = req.params.id; + const body = req.body; + const query = req.query; + + // ... +}); +``` + +

res.json(obj, status)

+ +Express 5 no longer supports the signature `res.json(obj, status)`. Instead, set the status and then chain it to the `res.json()` method like this: `res.status(status).json(obj)`. + +{% capture codemod-status-send-order %} +You can replace the deprecated signatures with the following command: + +```plaintext +npx codemod@latest @expressjs/status-send-order +``` + +{% endcapture %} + +{% include admonitions/note.html content=codemod-status-send-order %} + +```js +// v4 +app.post('/user', (req, res) => { + res.json({ name: 'Ruben' }, 201); +}); + +// v5 +app.post('/user', (req, res) => { + res.status(201).json({ name: 'Ruben' }); +}); +``` + +

res.jsonp(obj, status)

+ +Express 5 no longer supports the signature `res.jsonp(obj, status)`. Instead, set the status and then chain it to the `res.jsonp()` method like this: `res.status(status).jsonp(obj)`. + +{% include admonitions/note.html content=codemod-status-send-order %} + +```js +// v4 +app.post('/user', (req, res) => { + res.jsonp({ name: 'Ruben' }, 201); +}); + +// v5 +app.post('/user', (req, res) => { + res.status(201).jsonp({ name: 'Ruben' }); +}); +``` + +

res.redirect(url, status)

+ +Express 5 no longer supports the signature `res.redirect(url, status)`. Instead, use the following signature: `res.redirect(status, url)`. + +{% capture codemod-redirect-arg-order %} +You can replace the deprecated signatures with the following command: + +```plaintext +npx codemod@latest @expressjs/redirect-arg-order +``` + +{% endcapture %} + +{% include admonitions/note.html content=codemod-redirect-arg-order %} + +```js +// v4 +app.get('/user', (req, res) => { + res.redirect('/users', 301); +}); + +// v5 +app.get('/user', (req, res) => { + res.redirect(301, '/users'); +}); +``` + +

res.redirect('back') and res.location('back')

+ +Express 5 no longer supports the magic string `back` in the `res.redirect()` and `res.location()` methods. Instead, use the `req.get('Referrer') || '/'` value to redirect back to the previous page. In Express 4, the `res.redirect('back')` and `res.location('back')` methods were deprecated. + +{% capture codemod-back-redirect-deprecated %} +You can replace the deprecated signatures with the following command: + +```plaintext +npx codemod@latest @expressjs/back-redirect-deprecated +``` + +{% endcapture %} + +{% include admonitions/note.html content=codemod-back-redirect-deprecated %} + +```js +// v4 +app.get('/user', (req, res) => { + res.redirect('back'); +}); + +// v5 +app.get('/user', (req, res) => { + res.redirect(req.get('Referrer') || '/'); +}); +``` + +

res.send(body, status)

+ +Express 5 no longer supports the signature `res.send(obj, status)`. Instead, set the status and then chain it to the `res.send()` method like this: `res.status(status).send(obj)`. + +{% include admonitions/note.html content=codemod-status-send-order %} + +```js +// v4 +app.get('/user', (req, res) => { + res.send({ name: 'Ruben' }, 200); +}); + +// v5 +app.get('/user', (req, res) => { + res.status(200).send({ name: 'Ruben' }); +}); +``` + +

res.send(status)

+ +Express 5 no longer supports the signature `res.send(status)`, where `status` is a number. Instead, use the `res.sendStatus(statusCode)` function, which sets the HTTP response header status code and sends the text version of the code: "Not Found", "Internal Server Error", and so on. +If you need to send a number by using the `res.send()` function, quote the number to convert it to a string, so that Express does not interpret it as an attempt to use the unsupported old signature. + +{% include admonitions/note.html content=codemod-status-send-order %} + +```js +// v4 +app.get('/user', (req, res) => { + res.send(200); +}); + +// v5 +app.get('/user', (req, res) => { + res.sendStatus(200); +}); +``` + +

res.sendfile()

+ +The `res.sendfile()` function has been replaced by a camel-cased version `res.sendFile()` in Express 5. + +**Note:** In Express 5, `res.sendFile()` uses the `mime-types` package for MIME type detection, which returns different Content-Type values than Express 4 for several common file types: + +- JavaScript files (.js): now "text/javascript" instead of "application/javascript" +- JSON files (.json): now "application/json" instead of "text/json" +- CSS files (.css): now "text/css" instead of "text/plain" +- XML files (.xml): now "application/xml" instead of "text/xml" +- Font files (.woff): now "font/woff" instead of "application/font-woff" +- SVG files (.svg): now "image/svg+xml" instead of "application/svg+xml" + +{% capture codemod-camelcase-sendfile %} +You can replace the deprecated signatures with the following command: + +```plaintext +npx codemod@latest @expressjs/camelcase-sendfile +``` + +{% endcapture %} + +{% include admonitions/note.html content=codemod-camelcase-sendfile %} + +```js +// v4 +app.get('/user', (req, res) => { + res.sendfile('/path/to/file'); +}); + +// v5 +app.get('/user', (req, res) => { + res.sendFile('/path/to/file'); +}); +``` + +

router.param(fn)

+ +The `router.param(fn)` signature was used for modifying the behavior of the `router.param(name, fn)` function. It has been deprecated since v4.11.0, and Express 5 no longer supports it at all. + +

express.static.mime

+ +In Express 5, `mime` is no longer an exported property of the `static` field. +Use the [`mime-types` package](https://github.com/jshttp/mime-types) to work with MIME type values. + +**Important:** This change affects not only direct usage of `express.static.mime` but also other Express methods that rely on MIME type detection, such as `res.sendFile()`. The following MIME types have changed from Express 4: + +- JavaScript files (.js): now served as "text/javascript" instead of "application/javascript" +- JSON files (.json): now served as "application/json" instead of "text/json" +- CSS files (.css): now served as "text/css" instead of "text/plain" +- HTML files (.html): now served as "text/html; charset=utf-8" instead of just "text/html" +- XML files (.xml): now served as "application/xml" instead of "text/xml" +- Font files (.woff): now served as "font/woff" instead of "application/font-woff" + +```js +// v4 +express.static.mime.lookup('json'); + +// v5 +const mime = require('mime-types'); +mime.lookup('json'); +``` + +

express:router debug logs

+ +In Express 5, router handling logic is performed by a dependency. Therefore, the +debug logs for the router are no longer available under the `express:` namespace. +In v4, the logs were available under the namespaces `express:router`, `express:router:layer`, +and `express:router:route`. All of these were included under the namespace `express:*`. +In v5.1+, the logs are available under the namespaces `router`, `router:layer`, and `router:route`. +The logs from `router:layer` and `router:route` are included in the namespace `router:*`. +To achieve the same detail of debug logging when using `express:*` in v4, use a conjunction of +`express:*`, `router`, and `router:*`. + +```sh +# v4 +DEBUG=express:* node index.js + +# v5 +DEBUG=express:*,router,router:* node index.js +``` + +## Changed + +

Path route matching syntax

+ +Path route matching syntax is when a string is supplied as the first parameter to the `app.all()`, `app.use()`, `app.METHOD()`, `router.all()`, `router.METHOD()`, and `router.use()` APIs. The following changes have been made to how the path string is matched to an incoming request: + +- The wildcard `*` must have a name, matching the behavior of parameters `:`, use `/*splat` instead of `/*` + +```js +// v4 +app.get('/*', async (req, res) => { + res.send('ok'); +}); + +// v5 +app.get('/*splat', async (req, res) => { + res.send('ok'); +}); +``` + +{% capture note_wildcard %} +`*splat` matches any path without the root path. If you need to match the root path as well `/`, you can use `/{*splat}`, wrapping the wildcard in braces. + +```js +// v5 +app.get('/{*splat}', async (req, res) => { + res.send('ok'); +}); +``` + +{% endcapture %} +{% include admonitions/note.html content=note_wildcard %} + +- The optional character `?` is no longer supported, use braces instead. + +```js +// v4 +app.get('/:file.:ext?', async (req, res) => { + res.send('ok'); +}); + +// v5 +app.get('/:file{.:ext}', async (req, res) => { + res.send('ok'); +}); +``` + +- Regexp characters are not supported. For example: + +```js +app.get('/[discussion|page]/:slug', async (req, res) => { + res.status(200).send('ok'); +}); +``` + +should be changed to: + +```js +app.get(['/discussion/:slug', '/page/:slug'], async (req, res) => { + res.status(200).send('ok'); +}); +``` + +- Some characters have been reserved to avoid confusion during upgrade (`()[]?+!`), use `\` to escape them. +- Parameter names now support valid JavaScript identifiers, or quoted like `:"this"`. + +

Rejected promises handled from middleware and handlers

+ +Request middleware and handlers that return rejected promises are now handled by forwarding the rejected value as an `Error` to the error handling middleware. This means that using `async` functions as middleware and handlers are easier than ever. When an error is thrown in an `async` function or a rejected promise is `await`ed inside an async function, those errors will be passed to the error handler as if calling `next(err)`. + +Details of how Express handles errors is covered in the [error handling documentation](/en/guide/error-handling.html). + +

express.urlencoded

+ +The `express.urlencoded` method makes the `extended` option `false` by default. + +

express.static dotfiles

+ +In Express 5, the `express.static` middleware's `dotfiles` option now defaults to `"ignore"`. This is a change from Express 4, where dotfiles were served by default. As a result, files inside a directory that starts with a dot (`.`), such as `.well-known`, will no longer be accessible and will return a **404 Not Found** error. This can break functionality that depends on serving dot-directories, such as Android App Links, and Apple Universal Links. + +Example of breaking code: + +```js +// v4 +app.use(express.static('public')); +``` + +After migrating to Express 5, a request to `/.well-known/assetlinks.json` will result in a **404 Not Found**. + +To fix this, serve specific dot-directories explicitly using the `dotfiles: "allow"` option: + +```js +// v5 +app.use('/.well-known', express.static('public/.well-known', { dotfiles: 'allow' })); +app.use(express.static('public')); +``` + +This approach allows you to safely serve only the intended dot-directories while keeping the default secure behavior for other dotfiles, which remain inaccessible. + +

app.listen

+ +In Express 5, the `app.listen` method will invoke the user-provided callback function (if provided) when the server receives an error event. In Express 4, such errors would be thrown. This change shifts error-handling responsibility to the callback function in Express 5. If there is an error, it will be passed to the callback as an argument. +For example: + +```js +const server = app.listen(8080, '0.0.0.0', (error) => { + if (error) { + throw error; // e.g. EADDRINUSE + } + console.log(`Listening on ${JSON.stringify(server.address())}`); +}); +``` + +

app.router

+ +The `app.router` object, which was removed in Express 4, has made a comeback in Express 5. In the new version, this object is a just a reference to the base Express router, unlike in Express 3, where an app had to explicitly load it. + +

req.body

+ +The `req.body` property returns `undefined` when the body has not been parsed. In Express 4, it returns `{}` by default. + +

req.host

+ +In Express 4, the `req.host` function incorrectly stripped off the port number if it was present. In Express 5, the port number is maintained. + +

req.params

+ +The `req.params` object now has a **null prototype** when using string paths. However, if the path is defined with a regular expression, `req.params` remains a standard object with a normal prototype. Additionally, there are two important behavioral changes: + +**Wildcard parameters are now arrays:** + +Wildcards (e.g., `/*splat`) capture path segments as an array instead of a single string. + +```js +app.get('/*splat', (req, res) => { + // GET /foo/bar + console.dir(req.params); + // => [Object: null prototype] { splat: [ 'foo', 'bar' ] } +}); +``` + +**Unmatched parameters are omitted:** + +In Express 4, unmatched wildcards were empty strings (`''`) and optional `:` parameters (using `?`) had a key with value `undefined`. In Express 5, unmatched parameters are completely omitted from `req.params`. + +```js +// v4: unmatched wildcard is empty string +app.get('/*', (req, res) => { + // GET / + console.dir(req.params); + // => { '0': '' } +}); + +// v4: unmatched optional param is undefined +app.get('/:file.:ext?', (req, res) => { + // GET /image + console.dir(req.params); + // => { file: 'image', ext: undefined } +}); + +// v5: unmatched optional param is omitted +app.get('/:file{.:ext}', (req, res) => { + // GET /image + console.dir(req.params); + // => [Object: null prototype] { file: 'image' } +}); +``` + +

req.query

+ +The `req.query` property is no longer a writable property and is instead a getter. The default query parser has been changed from "extended" to "simple". + +

res.clearCookie

+ +The `res.clearCookie` method ignores the `maxAge` and `expires` options provided by the user. + +

res.status

+ +The `res.status` method only accepts integers in the range of `100` to `999`, following the behavior defined by Node.js, and it returns an error when the status code is not an integer. + +

res.vary

+ +The `res.vary` throws an error when the `field` argument is missing. In Express 4, if the argument was omitted, it gave a warning in the console + +## Improvements + +

res.render()

+ +This method now enforces asynchronous behavior for all view engines, avoiding bugs caused by view engines that had a synchronous implementation and that violated the recommended interface. + +

Brotli encoding support

+ +Express 5 supports Brotli encoding for requests received from clients that support it. diff --git a/astro/src/content/docs/en/5x/guide/overriding-express-api.md b/astro/src/content/docs/en/5x/guide/overriding-express-api.md new file mode 100644 index 0000000000..db65ce792f --- /dev/null +++ b/astro/src/content/docs/en/5x/guide/overriding-express-api.md @@ -0,0 +1,70 @@ +--- +title: Overriding the Express API +description: Discover how to customize and extend the Express.js API by overriding methods and properties on the request and response objects using prototypes. +--- + +# Overriding the Express API + +The Express API consists of various methods and properties on the request and response objects. These are inherited by prototype. There are two extension points for the Express API: + +1. The global prototypes at `express.request` and `express.response`. +2. App-specific prototypes at `app.request` and `app.response`. + +Altering the global prototypes will affect all loaded Express apps in the same process. If desired, alterations can be made app-specific by only altering the app-specific prototypes after creating a new app. + +## Methods + +You can override the signature and behavior of existing methods with your own, by assigning a custom function. + +Following is an example of overriding the behavior of [res.sendStatus](/4x/api.html#res.sendStatus). + +```js +app.response.sendStatus = function (statusCode, type, message) { + // code is intentionally kept simple for demonstration purpose + return this.contentType(type).status(statusCode).send(message); +}; +``` + +The above implementation completely changes the original signature of `res.sendStatus`. It now accepts a status code, encoding type, and the message to be sent to the client. + +The overridden method may now be used this way: + +```js +res.sendStatus(404, 'application/json', '{"error":"resource not found"}'); +``` + +## Properties + +Properties in the Express API are either: + +1. Assigned properties (ex: `req.baseUrl`, `req.originalUrl`) +2. Defined as getters (ex: `req.secure`, `req.ip`) + +Since properties under category 1 are dynamically assigned on the `request` and `response` objects in the context of the current request-response cycle, their behavior cannot be overridden. + +Properties under category 2 can be overwritten using the Express API extensions API. + +The following code rewrites how the value of `req.ip` is to be derived. Now, it simply returns the value of the `Client-IP` request header. + +```js +Object.defineProperty(app.request, 'ip', { + configurable: true, + enumerable: true, + get() { + return this.get('Client-IP'); + }, +}); +``` + +## Prototype + +In order to provide the Express API, the request/response objects passed to Express (via `app(req, res)`, for example) need to inherit from the same prototype chain. By default, this is `http.IncomingRequest.prototype` for the request and `http.ServerResponse.prototype` for the response. + +Unless necessary, it is recommended that this be done only at the application level, rather than globally. Also, take care that the prototype that is being used matches the functionality as closely as possible to the default prototypes. + +```js +// Use FakeRequest and FakeResponse in place of http.IncomingRequest and http.ServerResponse +// for the given app reference +Object.setPrototypeOf(Object.getPrototypeOf(app.request), FakeRequest.prototype); +Object.setPrototypeOf(Object.getPrototypeOf(app.response), FakeResponse.prototype); +``` diff --git a/astro/src/content/docs/en/5x/guide/routing.md b/astro/src/content/docs/en/5x/guide/routing.md new file mode 100755 index 0000000000..cd1f1db834 --- /dev/null +++ b/astro/src/content/docs/en/5x/guide/routing.md @@ -0,0 +1,417 @@ +--- +title: Express routing +description: Learn how to define and use routes in Express.js applications, including route methods, route paths, parameters, and using Router for modular routing. +--- + +# Routing + +_Routing_ refers to how an application's endpoints (URIs) respond to client requests. +For an introduction to routing, see [Basic routing](/{{ page.lang }}/starter/basic-routing.html). + +You define routing using methods of the Express `app` object that correspond to HTTP methods; +for example, `app.get()` to handle GET requests and `app.post` to handle POST requests. For a full list, +see [app.METHOD](/{{ page.lang }}/5x/api.html#app.METHOD). You can also use [app.all()](/{{ page.lang }}/5x/api.html#app.all) to handle all HTTP methods and [app.use()](/{{ page.lang }}/5x/api.html#app.use) to +specify middleware as the callback function (See [Using middleware](/{{ page.lang }}/guide/using-middleware.html) for details). + +These routing methods specify a callback function (sometimes called "handler functions") called when the application receives a request to the specified route (endpoint) and HTTP method. In other words, the application "listens" for requests that match the specified route(s) and method(s), and when it detects a match, it calls the specified callback function. + +In fact, the routing methods can have more than one callback function as arguments. +With multiple callback functions, it is important to provide `next` as an argument to the callback function and then call `next()` within the body of the function to hand off control +to the next callback. + +The following code is an example of a very basic route. + +```js +const express = require('express'); +const app = express(); + +// respond with "hello world" when a GET request is made to the homepage +app.get('/', (req, res) => { + res.send('hello world'); +}); +``` + +

Route methods

+ +A route method is derived from one of the HTTP methods, and is attached to an instance of the `express` class. + +The following code is an example of routes that are defined for the `GET` and the `POST` methods to the root of the app. + +```js +// GET method route +app.get('/', (req, res) => { + res.send('GET request to the homepage'); +}); + +// POST method route +app.post('/', (req, res) => { + res.send('POST request to the homepage'); +}); +``` + +Express supports methods that correspond to all HTTP request methods: `get`, `post`, and so on. +For a full list, see [app.METHOD](/{{ page.lang }}/5x/api.html#app.METHOD). + +There is a special routing method, `app.all()`, used to load middleware functions at a path for _all_ HTTP request methods. For example, the following handler is executed for requests to the route `"/secret"` whether using `GET`, `POST`, `PUT`, `DELETE`, or any other HTTP request method supported in the [http module](https://nodejs.org/api/http.html#http_http_methods). + +```js +app.all('/secret', (req, res, next) => { + console.log('Accessing the secret section ...'); + next(); // pass control to the next handler +}); +``` + +

Route paths

+ +Route paths, in combination with a request method, define the endpoints at which requests can be made. Route paths can be strings, string patterns, or regular expressions. + +{% capture caution-character %} In express 5, the characters `?`, `+`, `*`, `[]`, and `()` are handled differently than in version 4, please review the [migration guide](/{{ page.lang }}/guide/migrating-5.html#path-syntax) for more information.{% endcapture %} + +{% include admonitions/caution.html content=caution-character %} + +{% capture note-dollar-character %}In express 4, regular expression characters such as `$` need to be escaped with a `\`. +{% endcapture %} + +{% include admonitions/caution.html content=note-dollar-character %} + +{% capture note-path-to-regexp %} + +Express uses [path-to-regexp](https://www.npmjs.com/package/path-to-regexp) for matching the route paths; see the path-to-regexp documentation for all the possibilities in defining route paths. [Express Playground Router](https://bjohansebas.github.io/playground-router/) is a handy tool for testing basic Express routes, although it does not support pattern matching. + +{% endcapture %} + +{% include admonitions/note.html content=note-path-to-regexp %} + +{% capture query-string-note %} + +Query strings are not part of the route path. + +{% endcapture %} + +{% include admonitions/warning.html content=query-string-note %} + +### Route paths based on strings + +This route path will match requests to the root route, `/`. + +```js +app.get('/', (req, res) => { + res.send('root'); +}); +``` + +This route path will match requests to `/about`. + +```js +app.get('/about', (req, res) => { + res.send('about'); +}); +``` + +This route path will match requests to `/random.text`. + +```js +app.get('/random.text', (req, res) => { + res.send('random.text'); +}); +``` + +### Route paths based on string patterns + +{% capture caution-string-patterns %} The string patterns in Express 5 no longer work. Please refer to the [migration guide](/{{ page.lang }}/guide/migrating-5.html#path-syntax) for more information.{% endcapture %} + +{% include admonitions/caution.html content=caution-string-patterns %} + +This route path will match `acd` and `abcd`. + +```js +app.get('/ab?cd', (req, res) => { + res.send('ab?cd'); +}); +``` + +This route path will match `abcd`, `abbcd`, `abbbcd`, and so on. + +```js +app.get('/ab+cd', (req, res) => { + res.send('ab+cd'); +}); +``` + +This route path will match `abcd`, `abxcd`, `abRANDOMcd`, `ab123cd`, and so on. + +```js +app.get('/ab*cd', (req, res) => { + res.send('ab*cd'); +}); +``` + +This route path will match `/abe` and `/abcde`. + +```js +app.get('/ab(cd)?e', (req, res) => { + res.send('ab(cd)?e'); +}); +``` + +### Route paths based on regular expressions + +This route path will match anything with an "a" in it. + +```js +app.get(/a/, (req, res) => { + res.send('/a/'); +}); +``` + +This route path will match `butterfly` and `dragonfly`, but not `butterflyman`, `dragonflyman`, and so on. + +```js +app.get(/.*fly$/, (req, res) => { + res.send('/.*fly$/'); +}); +``` + +

Route parameters

+ +Route parameters are named URL segments that are used to capture the values specified at their position in the URL. The captured values are populated in the `req.params` object, with the name of the route parameter specified in the path as their respective keys. + +``` +Route path: /users/:userId/books/:bookId +Request URL: http://localhost:3000/users/34/books/8989 +req.params: { "userId": "34", "bookId": "8989" } +``` + +To define routes with route parameters, simply specify the route parameters in the path of the route as shown below. + +```js +app.get('/users/:userId/books/:bookId', (req, res) => { + res.send(req.params); +}); +``` + +
+The name of route parameters must be made up of "word characters" ([A-Za-z0-9_]). +
+ +Since the hyphen (`-`) and the dot (`.`) are interpreted literally, they can be used along with route parameters for useful purposes. + +``` +Route path: /flights/:from-:to +Request URL: http://localhost:3000/flights/LAX-SFO +req.params: { "from": "LAX", "to": "SFO" } +``` + +``` +Route path: /plantae/:genus.:species +Request URL: http://localhost:3000/plantae/Prunus.persica +req.params: { "genus": "Prunus", "species": "persica" } +``` + +{% capture warning-regexp %} +In express 5, Regexp characters are not supported in route paths, for more information please refer to the [migration guide](/{{ page.lang }}/guide/migrating-5.html#path-syntax).{% endcapture %} + +{% include admonitions/caution.html content=warning-regexp %} + +To have more control over the exact string that can be matched by a route parameter, you can append a regular expression in parentheses (`()`): + +``` +Route path: /user/:userId(\d+) +Request URL: http://localhost:3000/user/42 +req.params: {"userId": "42"} +``` + +{% capture escape-advisory %} + +Because the regular expression is usually part of a literal string, be sure to escape any `\` characters with an additional backslash, for example `\\d+`. + +{% endcapture %} + +{% include admonitions/warning.html content=escape-advisory %} + +{% capture warning-version %} + +In Express 4.x, the `*` character in regular expressions is not interpreted in the usual way. As a workaround, use `{0,}` instead of `*`. This will likely be fixed in Express 5. + +{% endcapture %} + +{% include admonitions/warning.html content=warning-version %} + +

Route handlers

+ +You can provide multiple callback functions that behave like [middleware](/{{ page.lang }}/guide/using-middleware.html) to handle a request. The only exception is that these callbacks might invoke `next('route')` to bypass the remaining route callbacks. You can use this mechanism to impose pre-conditions on a route, then pass control to subsequent routes if there's no reason to proceed with the current route. + +```js +app.get('/user/:id', (req, res, next) => { + if (req.params.id === '0') { + return next('route'); + } + res.send(`User ${req.params.id}`); +}); + +app.get('/user/:id', (req, res) => { + res.send('Special handler for user ID 0'); +}); +``` + +In this example: + +- `GET /user/5` → handled by first route → sends "User 5" +- `GET /user/0` → first route calls `next('route')`, skipping to the next matching `/user/:id` route + +Route handlers can be in the form of a function, an array of functions, or combinations of both, as shown in the following examples. + +A single callback function can handle a route. For example: + +```js +app.get('/example/a', (req, res) => { + res.send('Hello from A!'); +}); +``` + +More than one callback function can handle a route (make sure you specify the `next` object). For example: + +```js +app.get( + '/example/b', + (req, res, next) => { + console.log('the response will be sent by the next function ...'); + next(); + }, + (req, res) => { + res.send('Hello from B!'); + } +); +``` + +An array of callback functions can handle a route. For example: + +```js +const cb0 = function (req, res, next) { + console.log('CB0'); + next(); +}; + +const cb1 = function (req, res, next) { + console.log('CB1'); + next(); +}; + +const cb2 = function (req, res) { + res.send('Hello from C!'); +}; + +app.get('/example/c', [cb0, cb1, cb2]); +``` + +A combination of independent functions and arrays of functions can handle a route. For example: + +```js +const cb0 = function (req, res, next) { + console.log('CB0'); + next(); +}; + +const cb1 = function (req, res, next) { + console.log('CB1'); + next(); +}; + +app.get( + '/example/d', + [cb0, cb1], + (req, res, next) => { + console.log('the response will be sent by the next function ...'); + next(); + }, + (req, res) => { + res.send('Hello from D!'); + } +); +``` + +

Response methods

+ +The methods on the response object (`res`) in the following table can send a response to the client, and terminate the request-response cycle. If none of these methods are called from a route handler, the client request will be left hanging. + +| Method | Description | +| --------------------------------------------------------------- | ------------------------------------------------------------------------------------- | +| [res.download()](/{{ page.lang }}/5x/api.html#res.download) | Prompt a file to be downloaded. | +| [res.end()](/{{ page.lang }}/5x/api.html#res.end) | End the response process. | +| [res.json()](/{{ page.lang }}/5x/api.html#res.json) | Send a JSON response. | +| [res.jsonp()](/{{ page.lang }}/5x/api.html#res.jsonp) | Send a JSON response with JSONP support. | +| [res.redirect()](/{{ page.lang }}/5x/api.html#res.redirect) | Redirect a request. | +| [res.render()](/{{ page.lang }}/5x/api.html#res.render) | Render a view template. | +| [res.send()](/{{ page.lang }}/5x/api.html#res.send) | Send a response of various types. | +| [res.sendFile()](/{{ page.lang }}/5x/api.html#res.sendFile) | Send a file as an octet stream. | +| [res.sendStatus()](/{{ page.lang }}/5x/api.html#res.sendStatus) | Set the response status code and send its string representation as the response body. | + +

app.route()

+ +You can create chainable route handlers for a route path by using `app.route()`. +Because the path is specified at a single location, creating modular routes is helpful, as is reducing redundancy and typos. For more information about routes, see: [Router() documentation](/{{ page.lang }}/5x/api.html#router). + +Here is an example of chained route handlers that are defined by using `app.route()`. + +```js +app + .route('/book') + .get((req, res) => { + res.send('Get a random book'); + }) + .post((req, res) => { + res.send('Add a book'); + }) + .put((req, res) => { + res.send('Update the book'); + }); +``` + +

express.Router

+ +Use the `express.Router` class to create modular, mountable route handlers. A `Router` instance is a complete middleware and routing system; for this reason, it is often referred to as a "mini-app". + +The following example creates a router as a module, loads a middleware function in it, defines some routes, and mounts the router module on a path in the main app. + +Create a router file named `birds.js` in the app directory, with the following content: + +```js +const express = require('express'); +const router = express.Router(); + +// middleware that is specific to this router +const timeLog = (req, res, next) => { + console.log('Time: ', Date.now()); + next(); +}; +router.use(timeLog); + +// define the home page route +router.get('/', (req, res) => { + res.send('Birds home page'); +}); +// define the about route +router.get('/about', (req, res) => { + res.send('About birds'); +}); + +module.exports = router; +``` + +Then, load the router module in the app: + +```js +const birds = require('./birds'); + +// ... + +app.use('/birds', birds); +``` + +The app will now be able to handle requests to `/birds` and `/birds/about`, as well as call the `timeLog` middleware function that is specific to the route. + +But if the parent route `/birds` has path parameters, it will not be accessible by default from the sub-routes. To make it accessible, you will need to pass the `mergeParams` option to the Router constructor [reference](/{{ page.lang }}/5x/api.html#app.use). + +```js +const router = express.Router({ mergeParams: true }); +``` diff --git a/astro/src/content/docs/en/5x/guide/using-middleware.md b/astro/src/content/docs/en/5x/guide/using-middleware.md new file mode 100644 index 0000000000..c202096171 --- /dev/null +++ b/astro/src/content/docs/en/5x/guide/using-middleware.md @@ -0,0 +1,295 @@ +--- +title: Using Express middleware +description: Learn how to use middleware in Express.js applications, including application-level and router-level middleware, error handling, and integrating third-party middleware. +--- + +# Using middleware + +Express is a routing and middleware web framework that has minimal functionality of its own: An Express application is essentially a series of middleware function calls. + +_Middleware_ functions are functions that have access to the [request object](/{{ page.lang }}/5x/api.html#req) (`req`), the [response object](/{{ page.lang }}/5x/api.html#res) (`res`), and the next middleware function in the application's request-response cycle. The next middleware function is commonly denoted by a variable named `next`. + +Middleware functions can perform the following tasks: + +- Execute any code. +- Make changes to the request and the response objects. +- End the request-response cycle. +- Call the next middleware function in the stack. + +If the current middleware function does not end the request-response cycle, it must call `next()` to pass control to the next middleware function. Otherwise, the request will be left hanging. + +An Express application can use the following types of middleware: + +- [Application-level middleware](#middleware.application) +- [Router-level middleware](#middleware.router) +- [Error-handling middleware](#middleware.error-handling) +- [Built-in middleware](#middleware.built-in) +- [Third-party middleware](#middleware.third-party) + +You can load application-level and router-level middleware with an optional mount path. +You can also load a series of middleware functions together, which creates a sub-stack of the middleware system at a mount point. + +

Application-level middleware

+ +Bind application-level middleware to an instance of the [app object](/{{ page.lang }}/5x/api.html#app) by using the `app.use()` and `app.METHOD()` functions, where `METHOD` is the HTTP method of the request that the middleware function handles (such as GET, PUT, or POST) in lowercase. + +This example shows a middleware function with no mount path. The function is executed every time the app receives a request. + +```js +const express = require('express'); +const app = express(); + +app.use((req, res, next) => { + console.log('Time:', Date.now()); + next(); +}); +``` + +This example shows a middleware function mounted on the `/user/:id` path. The function is executed for any type of +HTTP request on the `/user/:id` path. + +```js +app.use('/user/:id', (req, res, next) => { + console.log('Request Type:', req.method); + next(); +}); +``` + +This example shows a route and its handler function (middleware system). The function handles GET requests to the `/user/:id` path. + +```js +app.get('/user/:id', (req, res, next) => { + res.send('USER'); +}); +``` + +Here is an example of loading a series of middleware functions at a mount point, with a mount path. +It illustrates a middleware sub-stack that prints request info for any type of HTTP request to the `/user/:id` path. + +```js +app.use( + '/user/:id', + (req, res, next) => { + console.log('Request URL:', req.originalUrl); + next(); + }, + (req, res, next) => { + console.log('Request Type:', req.method); + next(); + } +); +``` + +Route handlers enable you to define multiple routes for a path. The example below defines two routes for GET requests to the `/user/:id` path. The second route will not cause any problems, but it will never get called because the first route ends the request-response cycle. + +This example shows a middleware sub-stack that handles GET requests to the `/user/:id` path. + +```js +app.get( + '/user/:id', + (req, res, next) => { + console.log('ID:', req.params.id); + next(); + }, + (req, res, next) => { + res.send('User Info'); + } +); + +// handler for the /user/:id path, which prints the user ID +app.get('/user/:id', (req, res, next) => { + res.send(req.params.id); +}); +``` + +To skip the rest of the middleware functions from a router middleware stack, call `next('route')` to pass control to the next route. + +{% capture next-function %} + +`next('route')` will work only in middleware functions that were loaded by using the `app.METHOD()` or `router.METHOD()` functions. + +{% endcapture %} + +{% include admonitions/note.html content=next-function %} + +This example shows a middleware sub-stack that handles GET requests to the `/user/:id` path. + +```js +app.get( + '/user/:id', + (req, res, next) => { + // if the user ID is 0, skip to the next route + if (req.params.id === '0') next('route'); + // otherwise pass the control to the next middleware function in this stack + else next(); + }, + (req, res, next) => { + // send a regular response + res.send('regular'); + } +); + +// handler for the /user/:id path, which sends a special response +app.get('/user/:id', (req, res, next) => { + res.send('special'); +}); +``` + +Middleware can also be declared in an array for reusability. + +This example shows an array with a middleware sub-stack that handles GET requests to the `/user/:id` path + +```js +function logOriginalUrl(req, res, next) { + console.log('Request URL:', req.originalUrl); + next(); +} + +function logMethod(req, res, next) { + console.log('Request Type:', req.method); + next(); +} + +const logStuff = [logOriginalUrl, logMethod]; +app.get('/user/:id', logStuff, (req, res, next) => { + res.send('User Info'); +}); +``` + +

Router-level middleware

+ +Router-level middleware works in the same way as application-level middleware, except it is bound to an instance of `express.Router()`. + +```js +const router = express.Router(); +``` + +Load router-level middleware by using the `router.use()` and `router.METHOD()` functions. + +The following example code replicates the middleware system that is shown above for application-level middleware, by using router-level middleware: + +```js +const express = require('express'); +const app = express(); +const router = express.Router(); + +// a middleware function with no mount path. This code is executed for every request to the router +router.use((req, res, next) => { + console.log('Time:', Date.now()); + next(); +}); + +// a middleware sub-stack shows request info for any type of HTTP request to the /user/:id path +router.use( + '/user/:id', + (req, res, next) => { + console.log('Request URL:', req.originalUrl); + next(); + }, + (req, res, next) => { + console.log('Request Type:', req.method); + next(); + } +); + +// a middleware sub-stack that handles GET requests to the /user/:id path +router.get( + '/user/:id', + (req, res, next) => { + // if the user ID is 0, skip to the next router + if (req.params.id === '0') next('route'); + // otherwise pass control to the next middleware function in this stack + else next(); + }, + (req, res, next) => { + // render a regular page + res.render('regular'); + } +); + +// handler for the /user/:id path, which renders a special page +router.get('/user/:id', (req, res, next) => { + console.log(req.params.id); + res.render('special'); +}); + +// mount the router on the app +app.use('/', router); +``` + +To skip the rest of the router's middleware functions, call `next('router')` +to pass control back out of the router instance. + +This example shows a middleware sub-stack that handles GET requests to the `/user/:id` path. + +```js +const express = require('express'); +const app = express(); +const router = express.Router(); + +// predicate the router with a check and bail out when needed +router.use((req, res, next) => { + if (!req.headers['x-auth']) return next('router'); + next(); +}); + +router.get('/user/:id', (req, res) => { + res.send('hello, user!'); +}); + +// use the router and 401 anything falling through +app.use('/admin', router, (req, res) => { + res.sendStatus(401); +}); +``` + +

Error-handling middleware

+ +
+Error-handling middleware always takes _four_ arguments. You must provide four arguments to identify it as an error-handling middleware function. Even if you don't need to use the `next` object, you must specify it to maintain the signature. Otherwise, the `next` object will be interpreted as regular middleware and will fail to handle errors. +
+ +Define error-handling middleware functions in the same way as other middleware functions, except with four arguments instead of three, specifically with the signature `(err, req, res, next)`: + +```js +app.use((err, req, res, next) => { + console.error(err.stack); + res.status(500).send('Something broke!'); +}); +``` + +For details about error-handling middleware, see: [Error handling](/{{ page.lang }}/guide/error-handling.html). + +

Built-in middleware

+ +Starting with version 4.x, Express no longer depends on [Connect](https://github.com/senchalabs/connect). The middleware +functions that were previously included with Express are now in separate modules; see [the list of middleware functions](https://github.com/senchalabs/connect#middleware). + +Express has the following built-in middleware functions: + +- [express.static](/en/5x/api.html#express.static) serves static assets such as HTML files, images, and so on. +- [express.json](/en/5x/api.html#express.json) parses incoming requests with JSON payloads. **NOTE: Available with Express 4.16.0+** +- [express.urlencoded](/en/5x/api.html#express.urlencoded) parses incoming requests with URL-encoded payloads. **NOTE: Available with Express 4.16.0+** + +

Third-party middleware

+ +Use third-party middleware to add functionality to Express apps. + +Install the Node.js module for the required functionality, then load it in your app at the application level or at the router level. + +The following example illustrates installing and loading the cookie-parsing middleware function `cookie-parser`. + +```bash +$ npm install cookie-parser +``` + +```js +const express = require('express'); +const app = express(); +const cookieParser = require('cookie-parser'); + +// load the cookie-parsing middleware +app.use(cookieParser()); +``` + +For a partial list of third-party middleware functions that are commonly used with Express, see: [Third-party middleware](../resources/middleware.html). diff --git a/astro/src/content/docs/en/5x/guide/using-template-engines.md b/astro/src/content/docs/en/5x/guide/using-template-engines.md new file mode 100755 index 0000000000..4255702117 --- /dev/null +++ b/astro/src/content/docs/en/5x/guide/using-template-engines.md @@ -0,0 +1,63 @@ +--- +title: Using template engines with Express +description: Discover how to integrate and use template engines like Pug, Handlebars, and EJS with Express.js to render dynamic HTML pages efficiently. +--- + +# Using template engines with Express + +A _template engine_ enables you to use static template files in your application. At runtime, the template engine replaces +variables in a template file with actual values, and transforms the template into an HTML file sent to the client. +This approach makes it easier to design an HTML page. + +The [Express application generator](/{{ page.lang }}/starter/generator.html) uses [Pug](https://pugjs.org/api/getting-started.html) as its default, but it also supports [Handlebars](https://www.npmjs.com/package/handlebars), and [EJS](https://www.npmjs.com/package/ejs), among others. + +To render template files, set the following [application setting properties](/{{ page.lang }}/4x/api.html#app.set), in the default `app.js` created by the generator: + +- `views`, the directory where the template files are located. Eg: `app.set('views', './views')`. + This defaults to the `views` directory in the application root directory. +- `view engine`, the template engine to use. For example, to use the Pug template engine: `app.set('view engine', 'pug')`. + +Then install the corresponding template engine npm package; for example to install Pug: + +```bash +$ npm install pug --save +``` + +
+Express-compliant template engines such as Pug export a function named `__express(filePath, options, callback)`, +which `res.render()` calls to render the template code. + +Some template engines do not follow this convention. The [@ladjs/consolidate](https://www.npmjs.com/package/@ladjs/consolidate) +library follows this convention by mapping all of the popular Node.js template engines, and therefore works seamlessly within Express. + +
+ +After the view engine is set, you don't have to specify the engine or load the template engine module in your app; +Express loads the module internally, for example: + +```js +app.set('view engine', 'pug'); +``` + +Then, create a Pug template file named `index.pug` in the `views` directory, with the following content: + +```pug +html + head + title= title + body + h1= message +``` + +Create a route to render the `index.pug` file. If the `view engine` property is not set, +you must specify the extension of the `view` file. Otherwise, you can omit it. + +```js +app.get('/', (req, res) => { + res.render('index', { title: 'Hey', message: 'Hello there!' }); +}); +``` + +When you make a request to the home page, the `index.pug` file will be rendered as HTML. + +The view engine cache does not cache the contents of the template's output, only the underlying template itself. The view is still re-rendered with every request even when the cache is on. diff --git a/astro/src/content/docs/en/5x/guide/writing-middleware.md b/astro/src/content/docs/en/5x/guide/writing-middleware.md new file mode 100755 index 0000000000..5676253444 --- /dev/null +++ b/astro/src/content/docs/en/5x/guide/writing-middleware.md @@ -0,0 +1,218 @@ +--- +title: Writing middleware for use in Express apps +description: Learn how to write custom middleware functions for Express.js applications, including examples and best practices for enhancing request and response handling. +--- + +# Writing middleware for use in Express apps + +

Overview

+ +_Middleware_ functions are functions that have access to the [request object](/{{ page.lang }}/5x/api.html#req) (`req`), the [response object](/{{ page.lang }}/5x/api.html#res) (`res`), and the `next` function in the application's request-response cycle. The `next` function is a function in the Express router which, when invoked, executes the middleware succeeding the current middleware. + +Middleware functions can perform the following tasks: + +- Execute any code. +- Make changes to the request and the response objects. +- End the request-response cycle. +- Call the next middleware in the stack. + +If the current middleware function does not end the request-response cycle, it must call `next()` to pass control to the next middleware function. Otherwise, the request will be left hanging. + +The following figure shows the elements of a middleware function call: + +
+ + + +
+Elements of a middleware function call + +
HTTP method for which the middleware function applies.
+ +
Path (route) for which the middleware function applies.
+ +
The middleware function.
+ +
Callback argument to the middleware function, called "next" by convention.
+ +
HTTP response argument to the middleware function, called "res" by convention.
+ +
HTTP request argument to the middleware function, called "req" by convention.
+
+
+ +Starting with Express 5, middleware functions that return a Promise will call `next(value)` when they reject or throw an error. `next` will be called with either the rejected value or the thrown Error. + +

Example

+ +Here is an example of a simple "Hello World" Express application. +The remainder of this article will define and add three middleware functions to the application: +one called `myLogger` that prints a simple log message, one called `requestTime` that +displays the timestamp of the HTTP request, and one called `validateCookies` that validates incoming cookies. + +```js +const express = require('express'); +const app = express(); + +app.get('/', (req, res) => { + res.send('Hello World!'); +}); + +app.listen(3000); +``` + +

Middleware function myLogger

+Here is a simple example of a middleware function called "myLogger". This function just prints "LOGGED" when a request to the app passes through it. The middleware function is assigned to a variable named `myLogger`. + +```js +const myLogger = function (req, res, next) { + console.log('LOGGED'); + next(); +}; +``` + +
+Notice the call above to `next()`. Calling this function invokes the next middleware function in the app. +The `next()` function is not a part of the Node.js or Express API, but is the third argument that is passed to the middleware function. The `next()` function could be named anything, but by convention it is always named "next". +To avoid confusion, always use this convention. +
+ +To load the middleware function, call `app.use()`, specifying the middleware function. +For example, the following code loads the `myLogger` middleware function before the route to the root path (/). + +```js +const express = require('express'); +const app = express(); + +const myLogger = function (req, res, next) { + console.log('LOGGED'); + next(); +}; + +app.use(myLogger); + +app.get('/', (req, res) => { + res.send('Hello World!'); +}); + +app.listen(3000); +``` + +Every time the app receives a request, it prints the message "LOGGED" to the terminal. + +The order of middleware loading is important: middleware functions that are loaded first are also executed first. + +If `myLogger` is loaded after the route to the root path, the request never reaches it and the app doesn't print "LOGGED", because the route handler of the root path terminates the request-response cycle. + +The middleware function `myLogger` simply prints a message, then passes on the request to the next middleware function in the stack by calling the `next()` function. + +

Middleware function requestTime

+ +Next, we'll create a middleware function called "requestTime" and add a property called `requestTime` +to the request object. + +```js +const requestTime = function (req, res, next) { + req.requestTime = Date.now(); + next(); +}; +``` + +The app now uses the `requestTime` middleware function. Also, the callback function of the root path route uses the property that the middleware function adds to `req` (the request object). + +```js +const express = require('express'); +const app = express(); + +const requestTime = function (req, res, next) { + req.requestTime = Date.now(); + next(); +}; + +app.use(requestTime); + +app.get('/', (req, res) => { + let responseText = 'Hello World!
'; + responseText += `Requested at: ${req.requestTime}`; + res.send(responseText); +}); + +app.listen(3000); +``` + +When you make a request to the root of the app, the app now displays the timestamp of your request in the browser. + +

Middleware function validateCookies

+ +Finally, we'll create a middleware function that validates incoming cookies and sends a 400 response if cookies are invalid. + +Here's an example function that validates cookies with an external async service. + +```js +async function cookieValidator(cookies) { + try { + await externallyValidateCookie(cookies.testCookie); + } catch { + throw new Error('Invalid cookies'); + } +} +``` + +Here, we use the [`cookie-parser`](/resources/middleware/cookie-parser.html) middleware to parse incoming cookies off the `req` object and pass them to our `cookieValidator` function. The `validateCookies` middleware returns a Promise that upon rejection will automatically trigger our error handler. + +```js +const express = require('express'); +const cookieParser = require('cookie-parser'); +const cookieValidator = require('./cookieValidator'); + +const app = express(); + +async function validateCookies(req, res, next) { + await cookieValidator(req.cookies); + next(); +} + +app.use(cookieParser()); + +app.use(validateCookies); + +// error handler +app.use((err, req, res, next) => { + res.status(400).send(err.message); +}); + +app.listen(3000); +``` + +
+Note how `next()` is called after `await cookieValidator(req.cookies)`. This ensures that if `cookieValidator` resolves, the next middleware in the stack will get called. If you pass anything to the `next()` function (except the string `'route'` or `'router'`), Express regards the current request as being an error and will skip any remaining non-error handling routing and middleware functions. +
+ +Because you have access to the request object, the response object, the next middleware function in the stack, and the whole Node.js API, the possibilities with middleware functions are endless. + +For more information about Express middleware, see: [Using Express middleware](/{{ page.lang }}/guide/using-middleware.html). + +

Configurable middleware

+ +If you need your middleware to be configurable, export a function which accepts an options object or other parameters, which, then returns the middleware implementation based on the input parameters. + +File: `my-middleware.js` + +```js +module.exports = function (options) { + return function (req, res, next) { + // Implement the middleware function based on the options object + next(); + }; +}; +``` + +The middleware can now be used as shown below. + +```js +const mw = require('./my-middleware.js'); + +app.use(mw({ option1: '1', option2: '2' })); +``` + +Refer to [cookie-session](https://github.com/expressjs/cookie-session) and [compression](https://github.com/expressjs/compression) for examples of configurable middleware. diff --git a/astro/src/content/docs/en/5x/starter/basic-routing.md b/astro/src/content/docs/en/5x/starter/basic-routing.md new file mode 100755 index 0000000000..e699ef3f72 --- /dev/null +++ b/astro/src/content/docs/en/5x/starter/basic-routing.md @@ -0,0 +1,63 @@ +--- +title: Express basic routing +description: Learn the fundamentals of routing in Express.js applications, including how to define routes, handle HTTP methods, and create route handlers for your web server. +--- + +# Basic routing + +_Routing_ refers to determining how an application responds to a client request to a particular endpoint, which is a URI (or path) and a specific HTTP request method (GET, POST, and so on). + +Each route can have one or more handler functions, which are executed when the route is matched. + +Route definition takes the following structure: + +```js +app.METHOD(PATH, HANDLER); +``` + +Where: + +- `app` is an instance of `express`. +- `METHOD` is an [HTTP request method](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Methods), in lowercase. +- `PATH` is a path on the server. +- `HANDLER` is the function executed when the route is matched. + +
+This tutorial assumes that an instance of `express` named `app` is created and the server is running. If you are not familiar with creating an app and starting it, see the [Hello world example](/{{ page.lang }}/starter/hello-world.html). +
+ +The following examples illustrate defining simple routes. + +Respond with `Hello World!` on the homepage: + +```js +app.get('/', (req, res) => { + res.send('Hello World!'); +}); +``` + +Respond to a POST request on the root route (`/`), the application's home page: + +```js +app.post('/', (req, res) => { + res.send('Got a POST request'); +}); +``` + +Respond to a PUT request to the `/user` route: + +```js +app.put('/user', (req, res) => { + res.send('Got a PUT request at /user'); +}); +``` + +Respond to a DELETE request to the `/user` route: + +```js +app.delete('/user', (req, res) => { + res.send('Got a DELETE request at /user'); +}); +``` + +For more details about routing, see the [routing guide](/{{ page.lang }}/guide/routing.html). diff --git a/astro/src/content/docs/en/5x/starter/examples.md b/astro/src/content/docs/en/5x/starter/examples.md new file mode 100755 index 0000000000..a25a6d9834 --- /dev/null +++ b/astro/src/content/docs/en/5x/starter/examples.md @@ -0,0 +1,16 @@ +--- +title: Express examples +description: Explore a collection of Express.js application examples covering various use cases, integrations, and advanced configurations to help you learn and build your projects. +--- + +{% capture examples %}{% include readmes/express-master/examples.md %}{% endcapture %} +{{ examples | replace: "](.", "](https://github.com/expressjs/express/tree/master/examples" }} + +## Additional examples + +These are some additional examples with more extensive integrations. + +{% include community-caveat.html %} + +- [prisma-fullstack](https://github.com/prisma/prisma-examples/tree/latest/pulse/fullstack-simple-chat) - Fullstack app with Express and Next.js using [Prisma](https://www.npmjs.com/package/prisma) as an ORM +- [prisma-rest-api-ts](https://github.com/prisma/prisma-examples/tree/latest/orm/express) - REST API with Express in TypeScript using [Prisma](https://www.npmjs.com/package/prisma) as an ORM diff --git a/astro/src/content/docs/en/5x/starter/faq.md b/astro/src/content/docs/en/5x/starter/faq.md new file mode 100755 index 0000000000..397591ad28 --- /dev/null +++ b/astro/src/content/docs/en/5x/starter/faq.md @@ -0,0 +1,92 @@ +--- +title: Express FAQ +description: Find answers to frequently asked questions about Express.js, including topics on application structure, models, authentication, template engines, error handling, and more. +--- + +# FAQ + +## How should I structure my application? + +There is no definitive answer to this question. The answer depends +on the scale of your application and the team that is involved. To be as +flexible as possible, Express makes no assumptions in terms of structure. + +Routes and other application-specific logic can live in as many files +as you wish, in any directory structure you prefer. View the following +examples for inspiration: + +- [Route listings](https://github.com/expressjs/express/blob/4.13.1/examples/route-separation/index.js#L32-L47) +- [Route map](https://github.com/expressjs/express/blob/4.13.1/examples/route-map/index.js#L52-L66) +- [MVC style controllers](https://github.com/expressjs/express/tree/master/examples/mvc) + +Also, there are third-party extensions for Express, which simplify some of these patterns: + +- [Resourceful routing](https://github.com/expressjs/express-resource) + +## How do I define models? + +Express has no notion of a database. This concept is +left up to third-party Node modules, allowing you to +interface with nearly any database. + +See [LoopBack](http://loopback.io) for an Express-based framework that is centered around models. + +## How can I authenticate users? + +Authentication is another opinionated area that Express does not +venture into. You may use any authentication scheme you wish. +For a simple username / password scheme, see [this example](https://github.com/expressjs/express/tree/master/examples/auth). + +## Which template engines does Express support? + +Express supports any template engine that conforms with the `(path, locals, callback)` signature. +To normalize template engine interfaces and caching, see the +[consolidate.js](https://github.com/visionmedia/consolidate.js) +project for support. Unlisted template engines might still support the Express signature. + +For more information, see [Using template engines with Express](/{{page.lang}}/guide/using-template-engines.html). + +## How do I handle 404 responses? + +In Express, 404 responses are not the result of an error, so +the error-handler middleware will not capture them. This behavior is +because a 404 response simply indicates the absence of additional work to do; +in other words, Express has executed all middleware functions and routes, +and found that none of them responded. All you need to +do is add a middleware function at the very bottom of the stack (below all other functions) +to handle a 404 response: + +```js +app.use((req, res, next) => { + res.status(404).send("Sorry can't find that!"); +}); +``` + +Add routes dynamically at runtime on an instance of `express.Router()` +so the routes are not superseded by a middleware function. + +## How do I setup an error handler? + +You define error-handling middleware in the same way as other middleware, +except with four arguments instead of three; specifically with the signature `(err, req, res, next)`: + +```js +app.use((err, req, res, next) => { + console.error(err.stack); + res.status(500).send('Something broke!'); +}); +``` + +For more information, see [Error handling](/{{ page.lang }}/guide/error-handling.html). + +## How do I render plain HTML? + +You don't! There's no need to "render" HTML with the `res.render()` function. +If you have a specific file, use the `res.sendFile()` function. +If you are serving many assets from a directory, use the `express.static()` +middleware function. + +## What version of Node.js does Express require? + +- [Express 4.x](/{{ page.lang }}/4x/api.html) requires Node.js 0.10 or higher. +- [Express 5.x](/{{ page.lang }}/5x/api.html) requires Node.js 18 or higher. diff --git a/astro/src/content/docs/en/5x/starter/generator.md b/astro/src/content/docs/en/5x/starter/generator.md new file mode 100755 index 0000000000..4ee5058a18 --- /dev/null +++ b/astro/src/content/docs/en/5x/starter/generator.md @@ -0,0 +1,122 @@ +--- +title: Express application generator +description: Learn how to use the Express application generator tool to quickly create a skeleton for your Express.js applications, streamlining setup and configuration. +--- + +# Express application generator + +Use the application generator tool, `express-generator`, to quickly create an application skeleton. + +You can run the application generator with the `npx` command (available in Node.js 8.2.0). + +```bash +$ npx express-generator +``` + +For earlier Node versions, install the application generator as a global npm package and then launch it: + +```bash +$ npm install -g express-generator +$ express +``` + +Display the command options with the `-h` option: + +```bash +$ express -h + + Usage: express [options] [dir] + + Options: + + -h, --help output usage information + --version output the version number + -e, --ejs add ejs engine support + --hbs add handlebars engine support + --pug add pug engine support + -H, --hogan add hogan.js engine support + --no-view generate without view engine + -v, --view add view support (ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade) + -c, --css add stylesheet support (less|stylus|compass|sass) (defaults to plain css) + --git add .gitignore + -f, --force force on non-empty directory +``` + +For example, the following creates an Express app named _myapp_. The app will be created in a folder named _myapp_ in the current working directory and the view engine will be set to Pug: + +```bash +$ express --view=pug myapp + + create : myapp + create : myapp/package.json + create : myapp/app.js + create : myapp/public + create : myapp/public/javascripts + create : myapp/public/images + create : myapp/routes + create : myapp/routes/index.js + create : myapp/routes/users.js + create : myapp/public/stylesheets + create : myapp/public/stylesheets/style.css + create : myapp/views + create : myapp/views/index.pug + create : myapp/views/layout.pug + create : myapp/views/error.pug + create : myapp/bin + create : myapp/bin/www +``` + +Then install dependencies: + +```bash +$ cd myapp +$ npm install +``` + +On MacOS or Linux, run the app with this command: + +```bash +$ DEBUG=myapp:* npm start +``` + +On Windows Command Prompt, use this command: + +```bash +> set DEBUG=myapp:* & npm start +``` + +On Windows PowerShell, use this command: + +```bash +PS> $env:DEBUG='myapp:*'; npm start +``` + +Then, load `http://localhost:3000/` in your browser to access the app. + +The generated app has the following directory structure: + +```bash +. +├── app.js +├── bin +│ └── www +├── package.json +├── public +│ ├── images +│ ├── javascripts +│ └── stylesheets +│ └── style.css +├── routes +│ ├── index.js +│ └── users.js +└── views + ├── error.pug + ├── index.pug + └── layout.pug + +7 directories, 9 files +``` + +
+The app structure created by the generator is just one of many ways to structure Express apps. Feel free to use this structure or modify it to best suit your needs. +
diff --git a/astro/src/content/docs/en/5x/starter/hello-world.md b/astro/src/content/docs/en/5x/starter/hello-world.md new file mode 100755 index 0000000000..97da56d686 --- /dev/null +++ b/astro/src/content/docs/en/5x/starter/hello-world.md @@ -0,0 +1,46 @@ +--- +title: Express "Hello World" example +description: Get started with Express.js by building a simple 'Hello World' application, demonstrating the basic setup and server creation for beginners. +--- + +# Hello world example + +
+Embedded below is essentially the simplest Express app you can create. It is a single file app — _not_ what you'd get if you use the [Express generator](/en/starter/generator), which creates the scaffolding for a full app with numerous JavaScript files, Jade templates, and sub-directories for various purposes. +
+ +```js +const express = require('express'); +const app = express(); +const port = 3000; + +app.get('/', (req, res) => { + res.send('Hello World!'); +}); + +app.listen(port, () => { + console.log(`Example app listening on port ${port}`); +}); +``` + +This app starts a server and listens on port 3000 for connections. The app responds with "Hello World!" for requests +to the root URL (`/`) or _route_. For every other path, it will respond with a **404 Not Found**. + +### Running Locally + +First create a directory named `myapp`, change to it and run `npm init`. Then, install `express` as a dependency, as per the [installation guide](/en/starter/installing). + +In the `myapp` directory, create a file named `app.js` and copy the code from the example above. + +
+The `req` (request) and `res` (response) are the exact same objects that Node provides, so you can invoke +`req.pipe()`, `req.on('data', callback)`, and anything else you would do without Express involved. +
+ +Run the app with the following command: + +```bash +$ node app.js +``` + +Then, load `http://localhost:3000/` in a browser to see the output. diff --git a/astro/src/content/docs/en/5x/starter/installing.md b/astro/src/content/docs/en/5x/starter/installing.md new file mode 100755 index 0000000000..74b1d3ef6f --- /dev/null +++ b/astro/src/content/docs/en/5x/starter/installing.md @@ -0,0 +1,48 @@ +--- +title: Installing Express +description: Learn how to install Express.js in your Node.js environment, including setting up your project directory and managing dependencies with npm. +--- + +# Installing + +Assuming you've already installed [Node.js](https://nodejs.org/), create a directory to hold your application, and make that your working directory. + +- [Express 4.x](/en/4x/api) requires Node.js 0.10 or higher. +- [Express 5.x](/en/5x/api) requires Node.js 18 or higher. + +```bash +$ mkdir myapp +$ cd myapp +``` + +Use the `npm init` command to create a `package.json` file for your application. +For more information on how `package.json` works, see [Specifics of npm's package.json handling](https://docs.npmjs.com/files/package.json). + +```bash +$ npm init +``` + +This command prompts you for a number of things, such as the name and version of your application. +For now, you can simply hit RETURN to accept the defaults for most of them, with the following exception: + +``` +entry point: (index.js) +``` + +Enter `app.js`, or whatever you want the name of the main file to be. If you want it to be `index.js`, hit RETURN to accept the suggested default file name. + +Now, install Express in the `myapp` directory and save it in the dependencies list. For example: + +```bash +$ npm install express +``` + +To install Express temporarily and not add it to the dependencies list: + +```bash +$ npm install express --no-save +``` + +
+By default with version npm 5.0+, `npm install` adds the module to the `dependencies` list in the `package.json` file; with earlier versions of npm, you must specify the `--save` option explicitly. Then, afterwards, running `npm install` in the app directory will automatically install modules in the dependencies list. +
diff --git a/astro/src/content/docs/en/5x/starter/static-files.md b/astro/src/content/docs/en/5x/starter/static-files.md new file mode 100755 index 0000000000..52a21fdecc --- /dev/null +++ b/astro/src/content/docs/en/5x/starter/static-files.md @@ -0,0 +1,76 @@ +--- +title: Serving static files in Express +description: Understand how to serve static files like images, CSS, and JavaScript in Express.js applications using the built-in 'static' middleware. +--- + +# Serving static files in Express + +To serve static files such as images, CSS files, and JavaScript files, use the `express.static` built-in middleware function in Express. + +The function signature is: + +```js +express.static(root, [options]); +``` + +The `root` argument specifies the root directory from which to serve static assets. +For more information on the `options` argument, see [express.static](/{{page.lang}}/5x/api.html#express.static). + +For example, use the following code to serve images, CSS files, and JavaScript files in a directory named `public`: + +```js +app.use(express.static('public')); +``` + +Now, you can load the files that are in the `public` directory: + +```text +http://localhost:3000/images/kitten.jpg +http://localhost:3000/css/style.css +http://localhost:3000/js/app.js +http://localhost:3000/images/bg.png +http://localhost:3000/hello.html +``` + +
+Express looks up the files relative to the static directory, so the name of the static directory is not part of the URL. +
+ +To use multiple static assets directories, call the `express.static` middleware function multiple times: + +```js +app.use(express.static('public')); +app.use(express.static('files')); +``` + +Express looks up the files in the order in which you set the static directories with the `express.static` middleware function. + +{% capture alert_content %} +For best results, [use a reverse proxy](/{{page.lang}}/advanced/best-practice-performance.html#use-a-reverse-proxy) cache to improve performance of serving static assets. +{% endcapture %} +{% include admonitions/note.html content=alert_content %} + +To create a virtual path prefix (where the path does not actually exist in the file system) for files that are served by the `express.static` function, [specify a mount path](/{{ page.lang }}/5x/api.html#app.use) for the static directory, as shown below: + +```js +app.use('/static', express.static('public')); +``` + +Now, you can load the files that are in the `public` directory from the `/static` path prefix. + +```text +http://localhost:3000/static/images/kitten.jpg +http://localhost:3000/static/css/style.css +http://localhost:3000/static/js/app.js +http://localhost:3000/static/images/bg.png +http://localhost:3000/static/hello.html +``` + +However, the path that you provide to the `express.static` function is relative to the directory from where you launch your `node` process. If you run the express app from another directory, it's safer to use the absolute path of the directory that you want to serve: + +```js +const path = require('path'); +app.use('/static', express.static(path.join(__dirname, 'public'))); +``` + +For more details about the `serve-static` function and its options, see [serve-static](/resources/middleware/serve-static.html). diff --git a/astro/src/content/docs/en/resources/community.md b/astro/src/content/resources/en/community.md similarity index 82% rename from astro/src/content/docs/en/resources/community.md rename to astro/src/content/resources/en/community.md index ca6026be32..71635ce043 100755 --- a/astro/src/content/docs/en/resources/community.md +++ b/astro/src/content/resources/en/community.md @@ -1,8 +1,6 @@ --- title: Express community description: Connect with the Express.js community, learn about the technical committee, find resources, explore community-contributed modules, and get involved in discussions. -menu: resources -order: 1 --- # Community @@ -72,20 +70,21 @@ Express is a project of the OpenJS Foundation. Please review the [trademark poli
diff --git a/astro/src/content/docs/en/resources/contributing.md b/astro/src/content/resources/en/contributing.md similarity index 99% rename from astro/src/content/docs/en/resources/contributing.md rename to astro/src/content/resources/en/contributing.md index 99b9b92e0b..d473cf0ef9 100644 --- a/astro/src/content/docs/en/resources/contributing.md +++ b/astro/src/content/resources/en/contributing.md @@ -1,8 +1,6 @@ --- title: Contributing to Express description: Find out how to contribute to Express.js, including guidelines for reporting issues, submitting pull requests, becoming a collaborator, and understanding security policies. -menu: resources -order: 5 --- # Contributing to Express diff --git a/astro/src/content/docs/en/resources/glossary.md b/astro/src/content/resources/en/glossary.md similarity index 99% rename from astro/src/content/docs/en/resources/glossary.md rename to astro/src/content/resources/en/glossary.md index 10de90539d..e441b1a5e8 100755 --- a/astro/src/content/docs/en/resources/glossary.md +++ b/astro/src/content/resources/en/glossary.md @@ -1,8 +1,6 @@ --- title: Express glossary description: A comprehensive glossary of terms related to Express.js, Node.js, middleware, routing, and other key concepts to help you understand and use Express effectively. -menu: resources -order: 2 --- # Glossary diff --git a/astro/src/content/docs/en/resources/middleware/body-parser.md b/astro/src/content/resources/en/middleware/body-parser.md similarity index 99% rename from astro/src/content/docs/en/resources/middleware/body-parser.md rename to astro/src/content/resources/en/middleware/body-parser.md index f43f7518ea..e82649a95c 100644 --- a/astro/src/content/docs/en/resources/middleware/body-parser.md +++ b/astro/src/content/resources/en/middleware/body-parser.md @@ -1,6 +1,5 @@ --- title: Express body-parser middleware -menu: resources module: body-parser --- diff --git a/astro/src/content/docs/en/resources/middleware/compression.md b/astro/src/content/resources/en/middleware/compression.md similarity index 99% rename from astro/src/content/docs/en/resources/middleware/compression.md rename to astro/src/content/resources/en/middleware/compression.md index c35004305c..6ac63fcb7a 100644 --- a/astro/src/content/docs/en/resources/middleware/compression.md +++ b/astro/src/content/resources/en/middleware/compression.md @@ -1,6 +1,5 @@ --- title: Express compression middleware -menu: resources module: compression --- diff --git a/astro/src/content/docs/en/resources/middleware/connect-rid.md b/astro/src/content/resources/en/middleware/connect-rid.md similarity index 99% rename from astro/src/content/docs/en/resources/middleware/connect-rid.md rename to astro/src/content/resources/en/middleware/connect-rid.md index 53aca02427..4eef16c6d6 100644 --- a/astro/src/content/docs/en/resources/middleware/connect-rid.md +++ b/astro/src/content/resources/en/middleware/connect-rid.md @@ -1,6 +1,5 @@ --- title: Express connect-rid middleware -menu: resources module: connect-rid --- diff --git a/astro/src/content/docs/en/resources/middleware/cookie-parser.md b/astro/src/content/resources/en/middleware/cookie-parser.md similarity index 99% rename from astro/src/content/docs/en/resources/middleware/cookie-parser.md rename to astro/src/content/resources/en/middleware/cookie-parser.md index 240c943f7e..2a59496387 100644 --- a/astro/src/content/docs/en/resources/middleware/cookie-parser.md +++ b/astro/src/content/resources/en/middleware/cookie-parser.md @@ -1,6 +1,5 @@ --- title: Express cookie-parser middleware -menu: resources module: cookie-parser --- diff --git a/astro/src/content/docs/en/resources/middleware/cookie-session.md b/astro/src/content/resources/en/middleware/cookie-session.md similarity index 99% rename from astro/src/content/docs/en/resources/middleware/cookie-session.md rename to astro/src/content/resources/en/middleware/cookie-session.md index 9993a0f0d5..2d6d1f885b 100644 --- a/astro/src/content/docs/en/resources/middleware/cookie-session.md +++ b/astro/src/content/resources/en/middleware/cookie-session.md @@ -1,6 +1,5 @@ --- title: Express cookie-session middleware -menu: resources module: cookie-session --- diff --git a/astro/src/content/docs/en/resources/middleware/cors.md b/astro/src/content/resources/en/middleware/cors.md similarity index 99% rename from astro/src/content/docs/en/resources/middleware/cors.md rename to astro/src/content/resources/en/middleware/cors.md index d14c1f1154..55d70922cb 100644 --- a/astro/src/content/docs/en/resources/middleware/cors.md +++ b/astro/src/content/resources/en/middleware/cors.md @@ -1,6 +1,5 @@ --- title: Express cors middleware -menu: resources module: cors --- diff --git a/astro/src/content/docs/en/resources/middleware/errorhandler.md b/astro/src/content/resources/en/middleware/errorhandler.md similarity index 99% rename from astro/src/content/docs/en/resources/middleware/errorhandler.md rename to astro/src/content/resources/en/middleware/errorhandler.md index 66bceeddd6..20df618320 100644 --- a/astro/src/content/docs/en/resources/middleware/errorhandler.md +++ b/astro/src/content/resources/en/middleware/errorhandler.md @@ -1,6 +1,5 @@ --- title: Express errorhandler middleware -menu: resources module: errorhandler --- diff --git a/astro/src/content/docs/en/resources/middleware/method-override.md b/astro/src/content/resources/en/middleware/method-override.md similarity index 99% rename from astro/src/content/docs/en/resources/middleware/method-override.md rename to astro/src/content/resources/en/middleware/method-override.md index 84be20828d..7b97ab855e 100644 --- a/astro/src/content/docs/en/resources/middleware/method-override.md +++ b/astro/src/content/resources/en/middleware/method-override.md @@ -1,6 +1,5 @@ --- title: Express method-override middleware -menu: resources module: method-override --- diff --git a/astro/src/content/docs/en/resources/middleware/morgan.md b/astro/src/content/resources/en/middleware/morgan.md similarity index 99% rename from astro/src/content/docs/en/resources/middleware/morgan.md rename to astro/src/content/resources/en/middleware/morgan.md index d2227dfc21..5319d93d57 100644 --- a/astro/src/content/docs/en/resources/middleware/morgan.md +++ b/astro/src/content/resources/en/middleware/morgan.md @@ -1,6 +1,5 @@ --- title: Express morgan middleware -menu: resources module: morgan --- diff --git a/astro/src/content/docs/en/resources/middleware/multer.md b/astro/src/content/resources/en/middleware/multer.md similarity index 99% rename from astro/src/content/docs/en/resources/middleware/multer.md rename to astro/src/content/resources/en/middleware/multer.md index b8fd6fc4db..326786ab3d 100644 --- a/astro/src/content/docs/en/resources/middleware/multer.md +++ b/astro/src/content/resources/en/middleware/multer.md @@ -1,6 +1,5 @@ --- title: Express multer middleware -menu: resources module: multer --- diff --git a/astro/src/content/docs/en/resources/middleware.md b/astro/src/content/resources/en/middleware/overview.md similarity index 99% rename from astro/src/content/docs/en/resources/middleware.md rename to astro/src/content/resources/en/middleware/overview.md index 3996542b9c..ca3ef817b2 100755 --- a/astro/src/content/docs/en/resources/middleware.md +++ b/astro/src/content/resources/en/middleware/overview.md @@ -1,8 +1,6 @@ --- title: Express middleware description: Explore a list of Express.js middleware modules maintained by the Express team and the community, including built-in middleware and popular third-party modules. -menu: resources -order: 3 module: mw-home --- diff --git a/astro/src/content/docs/en/resources/middleware/response-time.md b/astro/src/content/resources/en/middleware/response-time.md similarity index 99% rename from astro/src/content/docs/en/resources/middleware/response-time.md rename to astro/src/content/resources/en/middleware/response-time.md index a1447f733c..f911f480f5 100644 --- a/astro/src/content/docs/en/resources/middleware/response-time.md +++ b/astro/src/content/resources/en/middleware/response-time.md @@ -1,6 +1,5 @@ --- title: Express response-time middleware -menu: resources module: response-time --- diff --git a/astro/src/content/docs/en/resources/middleware/serve-favicon.md b/astro/src/content/resources/en/middleware/serve-favicon.md similarity index 99% rename from astro/src/content/docs/en/resources/middleware/serve-favicon.md rename to astro/src/content/resources/en/middleware/serve-favicon.md index f002640e47..7a77865c6b 100644 --- a/astro/src/content/docs/en/resources/middleware/serve-favicon.md +++ b/astro/src/content/resources/en/middleware/serve-favicon.md @@ -1,6 +1,5 @@ --- title: Express serve-favicon middleware -menu: resources module: serve-favicon --- diff --git a/astro/src/content/docs/en/resources/middleware/serve-index.md b/astro/src/content/resources/en/middleware/serve-index.md similarity index 99% rename from astro/src/content/docs/en/resources/middleware/serve-index.md rename to astro/src/content/resources/en/middleware/serve-index.md index 79c50e53ff..da03cf94b2 100644 --- a/astro/src/content/docs/en/resources/middleware/serve-index.md +++ b/astro/src/content/resources/en/middleware/serve-index.md @@ -1,6 +1,5 @@ --- title: Express serve-index middleware -menu: resources module: serve-index --- diff --git a/astro/src/content/docs/en/resources/middleware/serve-static.md b/astro/src/content/resources/en/middleware/serve-static.md similarity index 99% rename from astro/src/content/docs/en/resources/middleware/serve-static.md rename to astro/src/content/resources/en/middleware/serve-static.md index 895f9dc69c..b048165d7b 100644 --- a/astro/src/content/docs/en/resources/middleware/serve-static.md +++ b/astro/src/content/resources/en/middleware/serve-static.md @@ -1,6 +1,5 @@ --- title: Express serve-static middleware -menu: resources module: serve-static --- diff --git a/astro/src/content/docs/en/resources/middleware/session.md b/astro/src/content/resources/en/middleware/session.md similarity index 99% rename from astro/src/content/docs/en/resources/middleware/session.md rename to astro/src/content/resources/en/middleware/session.md index 74559b032e..90f3837a42 100644 --- a/astro/src/content/docs/en/resources/middleware/session.md +++ b/astro/src/content/resources/en/middleware/session.md @@ -1,6 +1,5 @@ --- title: Express session middleware -menu: resources module: session --- diff --git a/astro/src/content/docs/en/resources/middleware/timeout.md b/astro/src/content/resources/en/middleware/timeout.md similarity index 99% rename from astro/src/content/docs/en/resources/middleware/timeout.md rename to astro/src/content/resources/en/middleware/timeout.md index 4ab4b826e1..f6057aedfd 100644 --- a/astro/src/content/docs/en/resources/middleware/timeout.md +++ b/astro/src/content/resources/en/middleware/timeout.md @@ -1,6 +1,5 @@ --- title: Express timeout middleware -menu: resources module: timeout --- diff --git a/astro/src/content/docs/en/resources/middleware/vhost.md b/astro/src/content/resources/en/middleware/vhost.md similarity index 99% rename from astro/src/content/docs/en/resources/middleware/vhost.md rename to astro/src/content/resources/en/middleware/vhost.md index fc3c9cfbcc..72f49d7f93 100644 --- a/astro/src/content/docs/en/resources/middleware/vhost.md +++ b/astro/src/content/resources/en/middleware/vhost.md @@ -1,6 +1,5 @@ --- title: Express vhost middleware -menu: resources module: vhost --- diff --git a/astro/src/content/docs/en/resources/utils.md b/astro/src/content/resources/en/utils.md similarity index 99% rename from astro/src/content/docs/en/resources/utils.md rename to astro/src/content/resources/en/utils.md index 27256d6a0b..010f83664f 100644 --- a/astro/src/content/docs/en/resources/utils.md +++ b/astro/src/content/resources/en/utils.md @@ -1,8 +1,6 @@ --- title: Express utilities description: Discover utility modules related to Express.js and Node.js, including tools for cookies, CSRF protection, URL parsing, routing, and more to enhance your applications. -menu: resources -order: 4 --- ## Express utility functions diff --git a/astro/src/layouts/DocLayout.astro b/astro/src/layouts/DocLayout.astro index 5f4f5e946d..5f2f04b090 100644 --- a/astro/src/layouts/DocLayout.astro +++ b/astro/src/layouts/DocLayout.astro @@ -1,13 +1,11 @@ --- import Layout from './Layout.astro'; -import type { MenuSection } from '@config/menu'; -import type { BreadcrumbItem } from '@utils/breadcrumb'; +import type { BreadcrumbItem } from '@utils/content'; import { Breadcrumbs } from '@components/patterns'; interface Props { title: string; description?: string; - section: MenuSection; breadcrumbs: BreadcrumbItem[]; } diff --git a/astro/src/layouts/Layout.astro b/astro/src/layouts/Layout.astro index b7d1c000b0..d4127e95b0 100644 --- a/astro/src/layouts/Layout.astro +++ b/astro/src/layouts/Layout.astro @@ -1,7 +1,8 @@ --- import '@styles/main.css'; import { Container } from '@components/primitives'; -import { ThemeSwitcher } from '@/components/patterns'; +import { Sidebar } from '@/components/patterns'; +import { Header } from '@/components/patterns'; interface Props { title?: string; @@ -27,11 +28,15 @@ const { {title} + + + +
- - diff --git a/astro/src/pages/[lang]/[...slug].astro b/astro/src/pages/[lang]/[...slug].astro index 912384dc4b..a52f75b9cc 100644 --- a/astro/src/pages/[lang]/[...slug].astro +++ b/astro/src/pages/[lang]/[...slug].astro @@ -1,37 +1,61 @@ --- import { getCollection } from 'astro:content'; import DocLayout from '@layouts/DocLayout.astro'; -import type { MenuSection } from '@config/menu'; import { render } from 'astro:content'; import { buildBreadcrumbs } from '@utils/content'; export async function getStaticPaths() { + const DEFAULT_VERSION = '5x'; + const VERSION_PREFIXES = ['5x', '4x', '3x']; + const pages = await getCollection('docs'); - return pages.map((page) => { + + const paths: Array<{ + params: { lang: string; slug: string }; + props: { page: (typeof pages)[0]; version: string }; + }> = []; + + pages.forEach((page) => { const [lang, ...slugParts] = page.id.split('/'); + const fullSlug = slugParts.join('/'); + + const isVersioned = VERSION_PREFIXES.some((v) => fullSlug.startsWith(`${v}/`)); + + paths.push({ + params: { lang, slug: fullSlug }, + props: { page, version: isVersioned ? slugParts[0] : DEFAULT_VERSION }, + }); + }); - return { - params: { - lang, - slug: slugParts.join('/'), - }, - props: { page }, - }; + const defaultVersionPages = pages.filter((page) => { + const [, ...slugParts] = page.id.split('/'); + return slugParts[0] === DEFAULT_VERSION; }); + + defaultVersionPages.forEach((page) => { + const [lang, , ...restSlugParts] = page.id.split('/'); + const nonVersionedSlug = restSlugParts.join('/'); + + const exists = paths.some((p) => p.params.lang === lang && p.params.slug === nonVersionedSlug); + + if (!exists && nonVersionedSlug) { + paths.push({ + params: { lang, slug: nonVersionedSlug }, + props: { page, version: DEFAULT_VERSION }, + }); + } + }); + + return paths; } -const { page } = Astro.props; +const { page, version } = Astro.props; const { lang, slug } = Astro.params; const { Content } = await render(page); -const breadcrumbs = await buildBreadcrumbs(lang, slug, 'docs'); -const { title, description, menu } = page.data; +const breadcrumbs = await buildBreadcrumbs(lang, slug, 'docs', version); +const { title, description } = page.data; --- - + diff --git a/astro/src/pages/[lang]/blog/index.astro b/astro/src/pages/[lang]/blog/index.astro new file mode 100644 index 0000000000..429a130612 --- /dev/null +++ b/astro/src/pages/[lang]/blog/index.astro @@ -0,0 +1,21 @@ +--- +/** + * Express Documentation Index Page + * + * TODO: This is a temporary index page for the blog listing recent posts. This will be replaced with a proper blog layout in the future. + */ +import Layout from '@layouts/Layout.astro'; +import { languages } from '@i18n/ui'; + +export function getStaticPaths() { + return Object.keys(languages).map((lang) => ({ + params: { lang }, + })); +} +--- + + +

Express Blog

+

This is a temporary entry point page for the Express blog.

+

This page will be replaced with a proper blog layout soon.

+
diff --git a/astro/src/pages/[lang]/docs/index.astro b/astro/src/pages/[lang]/docs/index.astro deleted file mode 100644 index f18d61fcac..0000000000 --- a/astro/src/pages/[lang]/docs/index.astro +++ /dev/null @@ -1,54 +0,0 @@ ---- -/** - * Express Documentation Index Page - * - * TODO: This is a temporary index page for the Express documentation that lists sections and recent docs. This will be replaced with a proper sidebar navigation layout in the future. - */ -import Layout from '@layouts/Layout.astro'; -import { menuSections, type MenuSection } from '@config/menu'; -import { getDocsBySection } from '@utils/content'; - -const sections = Object.entries(menuSections); - -import { getLangFromUrl } from '@i18n/utils'; -import { languages } from '@i18n/ui'; - -export function getStaticPaths() { - return Object.keys(languages).map((lang) => ({ - params: { lang }, - })); -} - -const lang = getLangFromUrl(Astro.url); ---- - - -

Express Documentation

-

- This is a temporary entry point page for the Express documentation. Below are some of the - sections and recent docs. -

-

This page will be replaced with a proper sidebar navigation layout soon.

- { - sections.map(async ([key, label]) => { - const docs = await getDocsBySection(key as MenuSection, lang); - const firstDocs = docs.slice(0, 5); - - return ( -
-

{label}

-
    - {firstDocs.map((doc) => { - const slug = doc.id.replace(`${lang}/${key}/`, '').replace(/\.mdx?$/, ''); - return ( -
  • - {doc.data.title} -
  • - ); - })} -
-
- ); - }) - } -
diff --git a/astro/src/pages/[lang]/ds-foundations.astro b/astro/src/pages/[lang]/ds-foundations.astro index 37513f8800..fed0dd64c5 100644 --- a/astro/src/pages/[lang]/ds-foundations.astro +++ b/astro/src/pages/[lang]/ds-foundations.astro @@ -188,530 +188,544 @@ import { H1, Body, Code } from '@components/primitives'; Icons are provided by astro-icon, a well-supported and officially recommended package for Astro that gives access to 200,000+ icons from various icon sets. We - primarily use Phosphor Icons (prefix ph:). - + primarily use Fluent Icons (prefix fluent:). + -
-

Examples

- - - - - - - -
+
+

Examples

+ + + + + + + +
-
-

Usage

- +

Usage

+ - + + `} - /> - - Browse available icons at Phosphor Icons or explore other icon sets at Iconify. - -
- - - -
-

Color Tokens

- -
-

Primitive tokens

-
-
white
-
- gray-50 -
-
- gray-100 -
-
- gray-200 -
-
- gray-300 -
-
- gray-400 -
-
- gray-500 -
-
- gray-600 -
-
- gray-700 -
-
- gray-800 -
-
- gray-900 -
-
- gray-950 -
-
black
-
- -
-
sky-50
-
- sky-500 -
-
- sky-700 -
-
- sky-800 -
-
- -
-
- green-50 -
-
- green-300 -
-
- green-500 -
-
- green-700 -
-
- green-900 -
-
- -
-
- amber-50 -
-
- amber-300 -
-
- amber-500 -
-
- amber-600 -
-
- amber-700 -
-
- amber-900 -
+ /> + + Browse available icons at Phosphor Icons or explore other icon sets at Iconify. +
+ -
-
- red-50 -
-
- red-300 -
-
- red-500 -
-
- red-600 -
-
- red-700 -
-
- red-900 -
-
-
+ +
+

Color Tokens

-
-

Semantic tokens

-
-
- bg-primary +

Primitive tokens

+
+
white
+
+ gray-50
-
- bg-secondary +
+ gray-100
-
- bg-tertiary +
+ gray-200
-
- bg-inverse +
+ gray-300
-
- bg-mute +
+ gray-400
-
- bg-success +
+ gray-500
-
- bg-warning +
+ gray-600
-
- bg-error +
+ gray-700
+
+ gray-800 +
+
+ gray-900 +
+
+ gray-950 +
+
black
-
-
- text-primary + +
+
sky-50
+
+ sky-500
-
- text-secondary +
+ sky-700
-
- text-tertiary +
+ sky-800
-
- text-inverse +
+ +
+
+ green-50
-
- text-mute +
+ green-300
-
- text-success +
+ green-500
-
- text-warning +
+ green-700
-
- text-error +
+ green-900
- -
-
- border-primary + +
+
+ amber-50
-
- border-secondary +
+ amber-300
-
- border-tertiary +
+ amber-500
-
- border-inverse +
+ amber-600
-
- border-mute +
+ amber-700
-
- border-success +
+ amber-900
-
- border-warning +
+ +
+
+ red-50
-
- border-error +
+ red-300 +
+
+ red-500 +
+
+ red-600 +
+
+ red-700 +
+
+ red-900
-
-

Usage

- +
+

Semantic tokens

+
+
+ bg-primary +
+
+ bg-secondary +
+
+ bg-tertiary +
+
+ bg-inverse +
+
+ bg-mute +
+
+ bg-success +
+
+ bg-warning +
+
+ bg-error +
+
+
+
+ text-primary +
+
+ text-secondary +
+
+ text-tertiary +
+
+ text-inverse +
+
+ text-mute +
+
+ text-success +
+
+ text-warning +
+
+ text-error +
+
+ +
+
+ border-primary +
+
+ border-secondary +
+
+ border-tertiary +
+
+ border-inverse +
+
+ border-mute +
+
+ border-success +
+
+ border-warning +
+
+ border-error +
+
+
+
+ +

Usage

+ -
+ /> +
- -
-

Spacing

+ +
+

Spacing

-
-

Scale

-
-
-
+
+

Scale

+
+
+
+
+ 0.5 (2px)
- 0.5 (2px) -
-
-
- 1 (4px) -
-
-
- 2 (8px) -
-
-
- 3 (12px) -
-
-
- 4 (16px) -
-
-
- 6 (24px) -
-
-
- 8 (32px) -
-
-
+
+
+
+ 1 (4px)
- 12 (48px) -
-
-
+
+
+
+ 2 (8px) +
+
+
+
+ 3 (12px) +
+
+
+
+ 4 (16px) +
+
+
+
+ 6 (24px) +
+
+
+
+ 8 (32px) +
+
+
+
+ 12 (48px) +
+
+
+
+ 16 (64px)
- 16 (64px)
-
-

Usage

- Usage + -
+ /> +
- -
-

Buttons

- - Interactive button component with support for variants, sizes, and polymorphic rendering. - + +
+

Buttons

+ + Interactive button component with support for variants, sizes, and polymorphic rendering. + -
-

Variants

- - - - -
+
+

Variants

+ + + + +
-
-

Sizes

- - - - - -
+
+

Sizes

+ + + + + +
-
-

Ghost Style

- - - Can be used on light backgrounds - - - - Can be used on dark backgrounds - -
+
+

Ghost Style

+ + + Can be used on light backgrounds + + + + Can be used on dark backgrounds + +
-
-

With Icons

- - - - -
+
+

With Icons

+ + + + +
-
-

Disabled State

- - - - -
+
+

Disabled State

+ + + + +
-
-

As Link

- - - - -
+
+

As Link

+ + + + +
-
-

Usage

- +

Usage

+ Click me `} - /> -
-
- - -
-

Grid & Layout

- - 12-column responsive grid system with Grid, Col, and Flex components. - + /> +
+ -
-

Grid Component

+ +
+

Grid & Layout

- Responsive 12-column grid. Columns cascade from xs → md → lg. + 12-column responsive grid system with Grid, Col, and Flex components. -
- - -
- xs=12, md=6, lg=4 -
- - -
- xs=12, md=6, lg=4 -
- - -
- xs=12, md=12, lg=4 -
- -
-
-

Usage

- +

Grid Component

+ + Responsive 12-column grid. Columns cascade from xs → md → lg. + +
+ + +
+ xs=12, md=6, lg=4 +
+ + +
+ xs=12, md=6, lg=4 +
+ + +
+ xs=12, md=12, lg=4 +
+ +
+
+

Usage

+ @@ -720,30 +734,30 @@ import { Grid, Col } from "@components/primitives"; Content `} - /> -
- -
-

Flex Component

- Flexbox layouts for 1D directional content. -
- -
- Item 1 -
-
- Item 2 -
-
- Item 3 -
-
+ />
-

Usage

- +

Flex Component

+ Flexbox layouts for 1D directional content. +
+ +
+ Item 1 +
+
+ Item 2 +
+
+ Item 3 +
+
+
+

Usage

+ @@ -751,51 +765,51 @@ import { Flex } from "@components/primitives";
Item 2
`} - /> -
- -
-

FlexItem Component

- Control flex-grow, flex-shrink, and flex-basis for individual flex children. - -

Equal Columns

-
- - -
flex="1"
-
- -
flex="1"
-
- -
flex="1"
-
-
+ />
-

Different Basis & Grow

-
- - -
- FlexItem basis="1/4" -
-
- -
- FlexItem (grow="1") -
-
-
-
+
+

FlexItem Component

+ Control flex-grow, flex-shrink, and flex-basis for individual flex children. -

Usage

- Equal Columns +
+ + +
flex="1"
+
+ +
flex="1"
+
+ +
flex="1"
+
+
+
+ +

Different Basis & Grow

+
+ + +
+ FlexItem basis="1/4" +
+
+ +
+ FlexItem (grow="1") +
+
+
+
+ +

Usage

+ @@ -804,54 +818,54 @@ import { Flex, FlexItem } from "@components/primitives"; Flexible content `} - /> -
+ /> +
-
-

Container

- - Centered, responsive content wrapper with max-width and padding. - -
- -
- Content centered with max-width: 1440px, width: 90-95% -
-
+
+

Container

+ + Centered, responsive content wrapper with max-width and padding. + +
+ +
+ Content centered with max-width: 1440px, width: 90-95% +
+
+
-
-

Usage

- Usage +
Your content here
`} - /> - + /> + - -
-

Breakpoints

+ +
+

Breakpoints

-
-
- Current: Mobile (xs) < 768px - Current: Tablet (md) 768px – 1439px - Current: Desktop (lg) ≥ 1440px +
+
+ Current: Mobile (xs) < 768px + Current: Tablet (md) 768px – 1439px + Current: Desktop (lg) ≥ 1440px +
-
-
-

Usage

- +

Usage

+ -
-
+ /> +
+ + + + + @media (--lg-up) { + .ds-breakpoint--lg { + display: block; + } + } + + diff --git a/astro/src/pages/[lang]/resources/[...slug].astro b/astro/src/pages/[lang]/resources/[...slug].astro new file mode 100644 index 0000000000..2b92154f92 --- /dev/null +++ b/astro/src/pages/[lang]/resources/[...slug].astro @@ -0,0 +1,31 @@ +--- +import { getCollection } from 'astro:content'; +import DocLayout from '@layouts/DocLayout.astro'; +import { render } from 'astro:content'; +import { buildBreadcrumbs } from '@utils/content'; + +export async function getStaticPaths() { + const pages = await getCollection('resources'); + return pages.map((page) => { + const [lang, ...slugParts] = page.id.split('/'); + + return { + params: { + lang, + slug: slugParts.join('/'), + }, + props: { page }, + }; + }); +} + +const { page } = Astro.props; +const { lang, slug } = Astro.params; +const { Content } = await render(page); +const breadcrumbs = await buildBreadcrumbs(lang, slug, 'resources'); +const { title, description } = page.data; +--- + + + + diff --git a/astro/src/pages/[lang]/support/index.astro b/astro/src/pages/[lang]/support/index.astro new file mode 100644 index 0000000000..2e6528dd12 --- /dev/null +++ b/astro/src/pages/[lang]/support/index.astro @@ -0,0 +1,21 @@ +--- +/** + * Express Documentation Index Page + * + * TODO: This is a temporary index page for support page. This will be replaced with a proper support layout in the future. + */ +import Layout from '@layouts/Layout.astro'; +import { languages } from '@i18n/ui'; + +export function getStaticPaths() { + return Object.keys(languages).map((lang) => ({ + params: { lang }, + })); +} +--- + + +

Express Version Support

+

This is a temporary entry point page for the Express support.

+

This page will be replaced with a proper support layout soon.

+
diff --git a/astro/src/styles/base/_global.css b/astro/src/styles/base/_global.css index fb03010d45..8fbc8c092f 100644 --- a/astro/src/styles/base/_global.css +++ b/astro/src/styles/base/_global.css @@ -141,6 +141,16 @@ a:hover { color: var(--color-link-hover); } +a:focus-visible, +button:focus-visible, +input:focus-visible, +select:focus-visible, +textarea:focus-visible, +[tabindex]:focus-visible { + outline: 1px solid var(--color-focus-ring); + outline-offset: -2px; +} + /* Code */ code, kbd, diff --git a/astro/src/styles/main.css b/astro/src/styles/main.css index 4ef4b192e6..d06f8a5ced 100644 --- a/astro/src/styles/main.css +++ b/astro/src/styles/main.css @@ -4,15 +4,20 @@ * Entry point for all styles * Import this file in your layout * - * Layer order (lowest to highest priority): - * 1. reset - CSS reset/normalize - * 2. base - Element defaults (html, body, a, etc.) - * 4. utilities - One-off overrides + * CSS Cascade Layers order (lowest to highest priority): + * 1. base - Global styles (reset, fonts, global, utilities) + * 2. primitives - Primitive component styles + * 3. patterns - Pattern component styles + * + * Layer order is defined in Layout.astro + * Layers ensure correct specificity order regardless of bundle order */ -/* Design Tokens - outside layers (global foundation) */ +/* Design Tokens - CSS custom properties (OUTSIDE layers for global access) */ @import './tokens/index.css'; -@import './base/_reset.css'; -@import './base/_fonts.css'; -@import './base/_global.css'; -@import './utilities/_utilities.css'; + +/* Import base styles into the base layer */ +@import './base/_reset.css' layer(base); +@import './base/_fonts.css' layer(base); +@import './base/_global.css' layer(base); +@import './utilities/_utilities.css' layer(base); diff --git a/astro/src/styles/tokens/_colors.css b/astro/src/styles/tokens/_colors.css index 9d1115028a..fc45e4bd93 100644 --- a/astro/src/styles/tokens/_colors.css +++ b/astro/src/styles/tokens/_colors.css @@ -24,7 +24,7 @@ --gray-600: oklch(45% 0 0); /* #525252 */ --gray-700: oklch(35% 0 0); /* #404040 */ --gray-800: oklch(25% 0 0); /* #262626 */ - --gray-900: oklch(15% 0 0); /* #141414 */ + --gray-900: oklch(19% 0 1); /* #141414 */ --gray-950: oklch(13% 0 0); /* #0A0A0A */ /* Green */ @@ -90,10 +90,10 @@ /* Backgrounds */ --color-bg-primary: light-dark(var(--white), var(--black)); --color-bg-secondary: light-dark(var(--gray-50), var(--gray-900)); - --color-bg-tertiary: light-dark(var(--gray-100), var(--gray-800)); + --color-bg-tertiary: light-dark(var(--gray-150), var(--gray-800)); --color-bg-inverse: light-dark(var(--gray-900), var(--gray-100)); --color-bg-inverse-secondary: light-dark(var(--gray-800), var(--gray-200)); - --color-bg-mute: light-dark(var(--gray-200), var(--gray-800)); + --color-bg-mute: light-dark(var(--gray-200), var(--gray-600)); --color-bg-info: light-dark(var(--blue-50), var(--blue-950)); --color-bg-success: light-dark(var(--green-50), var(--green-950)); --color-bg-warning: light-dark(var(--amber-50), var(--amber-950)); @@ -103,7 +103,7 @@ --color-border-primary: light-dark(var(--gray-300), var(--gray-500)); --color-border-secondary: light-dark(var(--gray-200), var(--gray-800)); --color-border-tertiary: light-dark(var(--gray-400), var(--gray-400)); - --color-border-mute: light-dark(var(--gray-400), var(--gray-600)); + --color-border-mute: light-dark(var(--gray-300), var(--gray-700)); --color-border-inverse: light-dark(var(--gray-700), var(--gray-200)); --color-border-info: light-dark(var(--blue-200), var(--blue-800)); --color-border-success: light-dark(var(--green-200), var(--green-800)); diff --git a/astro/src/styles/tokens/_sizing.css b/astro/src/styles/tokens/_sizing.css new file mode 100644 index 0000000000..999ddbac0e --- /dev/null +++ b/astro/src/styles/tokens/_sizing.css @@ -0,0 +1,45 @@ +/** + * Sizing tokens + * + * Based on a 4px grid system (0.25rem) + * Used for width, height, max-width, max-height, etc. + */ + +:root { + --size-0: 0; + --size-px: 1px; + --size-0-5: 0.2rem; /* 2px */ + --size-1: 0.4rem; /* 4px */ + --size-1-5: 0.6rem; /* 6px */ + --size-2: 0.8rem; /* 8px */ + --size-2-5: 1rem; /* 10px */ + --size-3: 1.2rem; /* 12px */ + --size-3-5: 1.4rem; /* 14px */ + --size-4: 1.6rem; /* 16px */ + --size-5: 2rem; /* 20px */ + --size-6: 2.4rem; /* 24px */ + --size-7: 2.8rem; /* 28px */ + --size-8: 3.2rem; /* 32px */ + --size-9: 3.6rem; /* 36px */ + --size-10: 4rem; /* 40px */ + --size-11: 4.4rem; /* 44px */ + --size-12: 4.8rem; /* 48px */ + --size-14: 5.6rem; /* 56px */ + --size-16: 6.4rem; /* 64px */ + --size-20: 8rem; /* 80px */ + --size-24: 9.6rem; /* 96px */ + --size-28: 11.2rem; /* 112px */ + --size-32: 12.8rem; /* 128px */ + --size-36: 14.4rem; /* 144px */ + --size-40: 16rem; /* 160px */ + --size-44: 17.6rem; /* 176px */ + --size-48: 19.2rem; /* 192px */ + --size-52: 20.8rem; /* 208px */ + --size-56: 22.4rem; /* 224px */ + --size-60: 24rem; /* 240px */ + --size-64: 25.6rem; /* 256px */ + --size-68: 27.2rem; /* 272px */ + --size-72: 28.8rem; /* 288px */ + --size-76: 30.4rem; /* 304px */ + --size-80: 32rem; /* 320px */ +} diff --git a/astro/src/styles/tokens/_spacing.css b/astro/src/styles/tokens/_spacing.css index 11ee180649..6b492f6114 100644 --- a/astro/src/styles/tokens/_spacing.css +++ b/astro/src/styles/tokens/_spacing.css @@ -26,6 +26,7 @@ --space-12: 4.8rem; /* 48px */ --space-14: 5.6rem; /* 56px */ --space-16: 6.4rem; /* 64px */ + --space-18: 7.2rem; /* 72px */ --space-20: 8rem; /* 80px */ --space-24: 9.6rem; /* 96px */ --space-28: 11.2rem; /* 112px */ diff --git a/astro/src/styles/tokens/_zindex.css b/astro/src/styles/tokens/_zindex.css new file mode 100644 index 0000000000..74c24f9d6e --- /dev/null +++ b/astro/src/styles/tokens/_zindex.css @@ -0,0 +1,11 @@ +/** + * Z-Index Scale + * Values are ordered from lowest to highest. + * Each layer is spaced by 10 to allow for intermediate values if needed. + */ + +:root { + --z-index-sidebar-backdrop: 10; + --z-index-sidebar: 20; + --z-index-header: 20; +} diff --git a/astro/src/styles/tokens/index.css b/astro/src/styles/tokens/index.css index 5d70dd7cfe..ab1b427a2e 100644 --- a/astro/src/styles/tokens/index.css +++ b/astro/src/styles/tokens/index.css @@ -8,5 +8,7 @@ @import './_colors.css'; @import './_typography.css'; @import './_spacing.css'; +@import './_sizing.css'; +@import './_zindex.css'; @import './_borders.css'; @import './_transitions.css'; diff --git a/astro/src/styles/utilities/_utilities.css b/astro/src/styles/utilities/_utilities.css index 5fcb9cc175..dce775e580 100644 --- a/astro/src/styles/utilities/_utilities.css +++ b/astro/src/styles/utilities/_utilities.css @@ -93,15 +93,18 @@ gap: var(--space-8); } -/* Width */ .w-full { width: 100%; } + +.h-full { + height: 100%; +} + .max-w-prose { max-width: var(--content-width); } -/* Margin auto */ .mx-auto { margin-inline: auto; } diff --git a/astro/src/utils/content.ts b/astro/src/utils/content.ts index 7f58c9378d..b5b6557948 100644 --- a/astro/src/utils/content.ts +++ b/astro/src/utils/content.ts @@ -1,24 +1,8 @@ import { getCollection, type CollectionEntry } from 'astro:content'; -import type { MenuSection } from '@config/menu'; +import { mainMenu } from '@/config/menu/main'; +import { apiMenu } from '@/config/menu/api'; import type { collections } from '@/content.config'; - -/** - * Get all documents for a specific language - */ -export async function getDocsByLang(lang: string = 'en') { - const allDocs = await getCollection('docs'); - return allDocs.filter((doc) => doc.id.startsWith(`${lang}/`)); -} - -/** - * Get all documents for a specific section and language - */ -export async function getDocsBySection(section: MenuSection, lang: string = 'en') { - const allDocs = await getDocsByLang(lang); - return allDocs - .filter((doc) => doc.data.menu === section) - .sort((a, b) => (a.data.order ?? 0) - (b.data.order ?? 0)); -} +import type { Menu } from '@/config/types'; /** * Checks if there is content at the specified path @@ -26,7 +10,6 @@ export async function getDocsBySection(section: MenuSection, lang: string = 'en' * @param pages - The collection of pages to search within * @returns True if content exists at the specified path, false otherwise */ - export function hasContentAt( checkPath: string, pages: CollectionEntry[] @@ -39,46 +22,182 @@ export interface BreadcrumbItem { href?: string; } +/** + * Find the label for a collection from the main menu + */ +function getCollectionLabel(collection: string): string { + for (const section of mainMenu.sections || []) { + for (const item of section.items) { + if ('submenu' in item && item.submenu?.basePath === `/${collection}`) { + return item.label; + } + } + } + // Fallback: capitalize the collection name + return collection.charAt(0).toUpperCase() + collection.slice(1); +} + +/** + * Format a slug segment into a readable label + */ +function formatLabel(segment: string): string { + return segment + .split('-') + .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) + .join(' '); +} + +/** + * Find breadcrumb labels by traversing the menu structure + * Returns an array of labels representing the path to the href in the menu + */ +function findInMenu(href: string, menu: Menu, path: string[] = []): string[] | null { + // Check sections + if (menu.sections) { + for (const section of menu.sections) { + // Add section title to path if it exists + const currentPath = section.title ? [...path, section.title] : path; + + // Check items in this section + for (const item of section.items) { + if ('href' in item && item.href) { + // Normalize hrefs for comparison (remove leading slash and version) + const normalizedItemHref = item.href.replace(/^\//, ''); + const normalizedSearchHref = href.replace(/^\//, '').replace(/^\d+x\//, ''); + + if (normalizedItemHref === normalizedSearchHref) { + return currentPath; + } + } + + // Check submenu if it exists + if ('submenu' in item && item.submenu) { + const submenuPath = [...currentPath, item.label]; + const result = findInMenu(href, item.submenu, submenuPath); + if (result) { + return result; + } + } + } + } + } + + // Check items at menu root level + if (menu.items) { + for (const item of menu.items) { + if ('href' in item && item.href) { + const normalizedItemHref = item.href.replace(/^\//, ''); + const normalizedSearchHref = href.replace(/^\//, '').replace(/^\d+x\//, ''); + + if (normalizedItemHref === normalizedSearchHref) { + return path; + } + } + + if ('submenu' in item && item.submenu) { + const submenuPath = [...path, item.label]; + const result = findInMenu(href, item.submenu, submenuPath); + if (result) { + return result; + } + } + } + } + + return null; +} + /** * Builds breadcrumb items for a documentation page * @param lang - The language code (e.g., 'en') * @param slug - The page slug (e.g., 'resources/middleware/compression') * @param collection - The collection name to check for existing content + * @param version - The version to display in breadcrumbs (e.g., '5x') * @returns Array of breadcrumb items with labels and optional hrefs */ export async function buildBreadcrumbs( lang: string, slug: string, - collection: keyof typeof collections + collection: keyof typeof collections, + version?: string ): Promise { const pages = await getCollection(collection); const breadcrumbs: BreadcrumbItem[] = []; - breadcrumbs.push({ - label: 'Docs', - href: undefined, - }); - const slugParts = slug.split('/'); + const startIndex = slugParts[0] === version ? 1 : 0; - slugParts.forEach((part, index) => { - const isLast = index === slugParts.length - 1; + // Check if this is an API page + const isApiPage = slugParts.includes('api'); - const pathToSegment = `${lang}/${slugParts.slice(0, index + 1).join('/')}`; + if (isApiPage) { + // For API pages: version > API > category > subsection (e.g., "5x > API > Application > Properties") + if (version) { + breadcrumbs.push({ + label: version, + href: undefined, + }); + } + + breadcrumbs.push({ + label: 'API', + href: undefined, + }); + + // Try to find the page in the API menu structure to get proper labels + const apiIndex = slugParts.indexOf('api'); + const apiPath = slugParts.slice(apiIndex).join('/'); + const menuPath = findInMenu(apiPath, apiMenu); + + if (menuPath && menuPath.length > 0) { + // Use labels from menu structure + menuPath.forEach((label) => { + breadcrumbs.push({ + label, + href: undefined, + }); + }); + } else { + // Fallback: use formatted path segments + slugParts.slice(apiIndex + 1).forEach((part, index) => { + const isLast = index === slugParts.slice(apiIndex + 1).length - 1; + const pathToSegment = `${lang}/${slugParts.slice(0, apiIndex + index + 2).join('/')}`; - const label = part - .split('-') - .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) - .join(' '); + if (!isLast) { + breadcrumbs.push({ + label: formatLabel(part), + href: hasContentAt(pathToSegment, pages) ? `/${pathToSegment}` : undefined, + }); + } + }); + } + } else { + // For non-API pages: use the original structure + breadcrumbs.push({ + label: getCollectionLabel(collection), + href: undefined, + }); - if (!isLast) { + if (version) { breadcrumbs.push({ - label, - href: hasContentAt(pathToSegment, pages) ? `/${pathToSegment}` : undefined, + label: version, + href: undefined, }); } - }); + + slugParts.slice(startIndex).forEach((part, index) => { + const isLast = index === slugParts.slice(startIndex).length - 1; + const pathToSegment = `${lang}/${slugParts.slice(0, startIndex + index + 1).join('/')}`; + + if (!isLast) { + breadcrumbs.push({ + label: formatLabel(part), + href: hasContentAt(pathToSegment, pages) ? `/${pathToSegment}` : undefined, + }); + } + }); + } return breadcrumbs; } diff --git a/legacy/de/guide/migrating-5.md b/legacy/de/guide/migrating-5.md index 2b2e8f031f..8dcd0cd461 100644 --- a/legacy/de/guide/migrating-5.md +++ b/legacy/de/guide/migrating-5.md @@ -99,7 +99,7 @@ Anfänglich wurde `del` statt `delete` verwendet, weil `delete` in JavaScript ei {% capture codemod-deprecated-signatures %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod v4-deprecated-signatures ``` @@ -109,14 +109,14 @@ npx @expressjs/codemod v4-deprecated-signatures ```js // v4 -app.del('/user/:id', (req, res) => { - res.send(`DELETE /user/${req.params.id}`) -}) +app.del("/user/:id", (req, res) => { + res.send(`DELETE /user/${req.params.id}`); +}); // v5 -app.delete('/user/:id', (req, res) => { - res.send(`DELETE /user/${req.params.id}`) -}) +app.delete("/user/:id", (req, res) => { + res.send(`DELETE /user/${req.params.id}`); +}); ```

app.param(fn)

@@ -136,7 +136,7 @@ Die folgenden Methodennamen wurden pluralisiert. In Express 4 wurde bei Verwendu {% capture codemod-pluralized-methods %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod pluralized-methods ``` @@ -146,22 +146,22 @@ npx @expressjs/codemod pluralized-methods ```js // v4 -app.all('/', (req, res) => { - req.acceptsCharset('utf-8') - req.acceptsEncoding('br') - req.acceptsLanguage('en') +app.all("/", (req, res) => { + req.acceptsCharset("utf-8"); + req.acceptsEncoding("br"); + req.acceptsLanguage("en"); // ... -}) +}); // v5 -app.all('/', (req, res) => { - req.acceptsCharsets('utf-8') - req.acceptsEncodings('br') - req.acceptsLanguages('en') +app.all("/", (req, res) => { + req.acceptsCharsets("utf-8"); + req.acceptsEncodings("br"); + req.acceptsLanguages("en"); // ... -}) +}); ```

Führender Doppelpunkt (:) im Namen für app.param(name, fn)

@@ -177,7 +177,7 @@ Dieses potenziell verwirrende und durchaus riskante Verfahren des Abrufens von F {% capture codemod-req-param %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod req-param ``` @@ -187,76 +187,76 @@ npx @expressjs/codemod req-param ```js // v4 -app.post('/user', (req, res) => { - const id = req.param('id') - const body = req.param('body') - const query = req.param('query') +app.post("/user", (req, res) => { + const id = req.param("id"); + const body = req.param("body"); + const query = req.param("query"); // ... -}) +}); // v5 -app.post('/user', (req, res) => { - const id = req.params.id - const body = req.body - const query = req.query +app.post("/user", (req, res) => { + const id = req.params.id; + const body = req.body; + const query = req.query; // ... -}) +}); ```

res.json(obj, status)

-Express 5 unterstützt die Signatur `res.json(obj, status)` nicht mehr. Stattdessen müssen Sie den Status festlegen und diesen dann mit `res.json()`-Methoden wie dieser verketten: `res.status(status).json(obj)`. +Express 5 unterstützt die Signatur `res.json(obj, status)` nicht mehr. Stattdessen müssen Sie den Status festlegen und diesen dann mit `res.json()`-Methoden wie dieser verketten: `res.status(status).json(obj)`. {% include admonitions/note.html content=codemod-deprecated-signatures %} ```js // v4 -app.post('/user', (req, res) => { - res.json({ name: 'Ruben' }, 201) -}) +app.post("/user", (req, res) => { + res.json({ name: "Ruben" }, 201); +}); // v5 -app.post('/user', (req, res) => { - res.status(201).json({ name: 'Ruben' }) -}) +app.post("/user", (req, res) => { + res.status(201).json({ name: "Ruben" }); +}); ```

res.jsonp(obj, status)

-Express 5 unterstützt die Signatur `res.jsonp(obj, status)` nicht mehr. Stattdessen müssen Sie den Status festlegen und diesen dann mit `res.jsonp()`-Methoden wie dieser verketten: `res.status(status).jsonp(obj)`. +Express 5 unterstützt die Signatur `res.jsonp(obj, status)` nicht mehr. Stattdessen müssen Sie den Status festlegen und diesen dann mit `res.jsonp()`-Methoden wie dieser verketten: `res.status(status).jsonp(obj)`. {% include admonitions/note.html content=codemod-deprecated-signatures %} ```js // v4 -app.post('/user', (req, res) => { - res.jsonp({ name: 'Ruben' }, 201) -}) +app.post("/user", (req, res) => { + res.jsonp({ name: "Ruben" }, 201); +}); // v5 -app.post('/user', (req, res) => { - res.status(201).jsonp({ name: 'Ruben' }) -}) +app.post("/user", (req, res) => { + res.status(201).jsonp({ name: "Ruben" }); +}); ```

res.redirect(url, status)

-Express 5 unterstützt die Signatur `res.send(obj, status)` nicht mehr. Stattdessen müssen Sie den Status festlegen und diesen dann mit `res.send()`-Methoden wie dieser verketten: `res.status(status).send(obj)`. +Express 5 unterstützt die Signatur `res.send(obj, status)` nicht mehr. Stattdessen müssen Sie den Status festlegen und diesen dann mit `res.send()`-Methoden wie dieser verketten: `res.status(status).send(obj)`. {% include admonitions/note.html content=codemod-deprecated-signatures %} ```js // v4 -app.get('/user', (req, res) => { - res.redirect('/users', 301) -}) +app.get("/user", (req, res) => { + res.redirect("/users", 301); +}); // v5 -app.get('/user', (req, res) => { - res.redirect(301, '/users') -}) +app.get("/user", (req, res) => { + res.redirect(301, "/users"); +}); ```

res.redirect('back') and res.location('back')

@@ -266,7 +266,7 @@ Express 5 no longer supports the magic string `back` in the `res.redirect()` and {% capture codemod-magic-redirect %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod magic-redirect ``` @@ -276,14 +276,14 @@ npx @expressjs/codemod magic-redirect ```js // v4 -app.get('/user', (req, res) => { - res.redirect('back') -}) +app.get("/user", (req, res) => { + res.redirect("back"); +}); // v5 -app.get('/user', (req, res) => { - res.redirect(req.get('Referrer') || '/') -}) +app.get("/user", (req, res) => { + res.redirect(req.get("Referrer") || "/"); +}); ```

res.send(body, status)

@@ -294,14 +294,14 @@ Express 5 no longer supports the signature `res.send(obj, status)`. Instead, set ```js // v4 -app.get('/user', (req, res) => { - res.send({ name: 'Ruben' }, 200) -}) +app.get("/user", (req, res) => { + res.send({ name: "Ruben" }, 200); +}); // v5 -app.get('/user', (req, res) => { - res.status(200).send({ name: 'Ruben' }) -}) +app.get("/user", (req, res) => { + res.status(200).send({ name: "Ruben" }); +}); ```

res.send(status)

@@ -313,14 +313,14 @@ Wenn Sie eine Zahl senden und hierfür die Funktion `res.send()` verwenden müss ```js // v4 -app.get('/user', (req, res) => { - res.send(200) -}) +app.get("/user", (req, res) => { + res.send(200); +}); // v5 -app.get('/user', (req, res) => { - res.sendStatus(200) -}) +app.get("/user", (req, res) => { + res.sendStatus(200); +}); ```

res.sendfile()

@@ -340,14 +340,14 @@ Die Funktion `res.sendfile()` wurde durch eine Version in Camel-Schreibweise von ```js // v4 -app.get('/user', (req, res) => { - res.sendfile('/path/to/file') -}) +app.get("/user", (req, res) => { + res.sendfile("/path/to/file"); +}); // v5 -app.get('/user', (req, res) => { - res.sendFile('/path/to/file') -}) +app.get("/user", (req, res) => { + res.sendFile("/path/to/file"); +}); ```

router.param(fn)

@@ -370,11 +370,11 @@ Use the [`mime-types` package](https://github.com/jshttp/mime-types) to work wit ```js // v4 -express.static.mime.lookup('json') +express.static.mime.lookup("json"); // v5 -const mime = require('mime-types') -mime.lookup('json') +const mime = require("mime-types"); +mime.lookup("json"); ```

express:router debug logs

@@ -406,14 +406,14 @@ Path route matching syntax is when a string is supplied as the first parameter t ```js // v4 -app.get('/*', async (req, res) => { - res.send('ok') -}) +app.get("/*", async (req, res) => { + res.send("ok"); +}); // v5 -app.get('/*splat', async (req, res) => { - res.send('ok') -}) +app.get("/*splat", async (req, res) => { + res.send("ok"); +}); ``` {% capture note_wildcard %} @@ -421,9 +421,9 @@ app.get('/*splat', async (req, res) => { ```js // v5 -app.get('/{*splat}', async (req, res) => { - res.send('ok') -}) +app.get("/{*splat}", async (req, res) => { + res.send("ok"); +}); ``` {% endcapture %} @@ -433,30 +433,30 @@ app.get('/{*splat}', async (req, res) => { ```js // v4 -app.get('/:file.:ext?', async (req, res) => { - res.send('ok') -}) +app.get("/:file.:ext?", async (req, res) => { + res.send("ok"); +}); // v5 -app.get('/:file{.:ext}', async (req, res) => { - res.send('ok') -}) +app.get("/:file{.:ext}", async (req, res) => { + res.send("ok"); +}); ``` - Regexp characters are not supported. Beispiel: ```js -app.get('/[discussion|page]/:slug', async (req, res) => { - res.status(200).send('ok') -}) +app.get("/[discussion|page]/:slug", async (req, res) => { + res.status(200).send("ok"); +}); ``` should be changed to: ```js -app.get(['/discussion/:slug', '/page/:slug'], async (req, res) => { - res.status(200).send('ok') -}) +app.get(["/discussion/:slug", "/page/:slug"], async (req, res) => { + res.status(200).send("ok"); +}); ``` - Some characters have been reserved to avoid confusion during upgrade (`()[]?+!`), use `\` to escape them. @@ -480,7 +480,7 @@ Example of breaking code: ```js // v4 -app.use(express.static('public')) +app.use(express.static("public")); ``` After migrating to Express 5, a request to `/.well-known/assetlinks.json` will result in a **404 Not Found**. @@ -489,8 +489,11 @@ To fix this, serve specific dot-directories explicitly using the `dotfiles: "all ```js // v5 -app.use('/.well-known', express.static('public/.well-known', { dotfiles: 'allow' })) -app.use(express.static('public')) +app.use( + "/.well-known", + express.static("public/.well-known", { dotfiles: "allow" }), +); +app.use(express.static("public")); ``` This approach allows you to safely serve only the intended dot-directories while keeping the default secure behavior for other dotfiles, which remain inaccessible. @@ -501,12 +504,12 @@ In Express 5, the `app.listen` method will invoke the user-provided callback fun Beispiel: ```js -const server = app.listen(8080, '0.0.0.0', (error) => { +const server = app.listen(8080, "0.0.0.0", (error) => { if (error) { - throw error // e.g. EADDRINUSE + throw error; // e.g. EADDRINUSE } - console.log(`Listening on ${JSON.stringify(server.address())}`) -}) + console.log(`Listening on ${JSON.stringify(server.address())}`); +}); ```

app.router

@@ -530,11 +533,11 @@ The `req.params` object now has a **null prototype** when using string paths. Ho Wildcards (e.g., `/*splat`) capture path segments as an array instead of a single string. ```js -app.get('/*splat', (req, res) => { +app.get("/*splat", (req, res) => { // GET /foo/bar - console.dir(req.params) + console.dir(req.params); // => [Object: null prototype] { splat: [ 'foo', 'bar' ] } -}) +}); ``` **Unmatched parameters are omitted:** @@ -543,25 +546,25 @@ In Express 4, unmatched wildcards were empty strings (`''`) and optional `:` par ```js // v4: unmatched wildcard is empty string -app.get('/*', (req, res) => { +app.get("/*", (req, res) => { // GET / - console.dir(req.params) + console.dir(req.params); // => { '0': '' } -}) +}); // v4: unmatched optional param is undefined -app.get('/:file.:ext?', (req, res) => { +app.get("/:file.:ext?", (req, res) => { // GET /image - console.dir(req.params) + console.dir(req.params); // => { file: 'image', ext: undefined } -}) +}); // v5: unmatched optional param is omitted -app.get('/:file{.:ext}', (req, res) => { +app.get("/:file{.:ext}", (req, res) => { // GET /image - console.dir(req.params) + console.dir(req.params); // => [Object: null prototype] { file: 'image' } -}) +}); ```

req.query

diff --git a/legacy/en/guide/migrating-5.md b/legacy/en/guide/migrating-5.md index 4541a282c9..d12c829af8 100755 --- a/legacy/en/guide/migrating-5.md +++ b/legacy/en/guide/migrating-5.md @@ -79,7 +79,6 @@ You can find the list of available codemods [here](https://codemod.link/express)
  • res.vary
  • - **Improvements**
      @@ -100,23 +99,24 @@ Initially, `del` was used instead of `delete`, because `delete` is a reserved ke {% capture codemod-route-del-to-delete %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx codemod@latest @expressjs/route-del-to-delete ``` + {% endcapture %} {% include admonitions/note.html content=codemod-route-del-to-delete %} ```js // v4 -app.del('/user/:id', (req, res) => { - res.send(`DELETE /user/${req.params.id}`) -}) +app.del("/user/:id", (req, res) => { + res.send(`DELETE /user/${req.params.id}`); +}); // v5 -app.delete('/user/:id', (req, res) => { - res.send(`DELETE /user/${req.params.id}`) -}) +app.delete("/user/:id", (req, res) => { + res.send(`DELETE /user/${req.params.id}`); +}); ```

      app.param(fn)

      @@ -136,31 +136,32 @@ The following method names have been pluralized. In Express 4, using the old met {% capture codemod-pluralized-methods %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx codemod@latest @expressjs/pluralize-method-names ``` + {% endcapture %} {% include admonitions/note.html content=codemod-pluralized-methods %} ```js // v4 -app.all('/', (req, res) => { - req.acceptsCharset('utf-8') - req.acceptsEncoding('br') - req.acceptsLanguage('en') +app.all("/", (req, res) => { + req.acceptsCharset("utf-8"); + req.acceptsEncoding("br"); + req.acceptsLanguage("en"); // ... -}) +}); // v5 -app.all('/', (req, res) => { - req.acceptsCharsets('utf-8') - req.acceptsEncodings('br') - req.acceptsLanguages('en') +app.all("/", (req, res) => { + req.acceptsCharsets("utf-8"); + req.acceptsEncodings("br"); + req.acceptsLanguages("en"); // ... -}) +}); ```

      Leading colon (:) in the name for app.param(name, fn)

      @@ -176,31 +177,32 @@ This potentially confusing and dangerous method of retrieving form data has been {% capture codemod-req-param %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx codemod@latest @expressjs/explicit-request-params ``` + {% endcapture %} {% include admonitions/note.html content=codemod-req-param %} ```js // v4 -app.post('/user', (req, res) => { - const id = req.param('id') - const body = req.param('body') - const query = req.param('query') +app.post("/user", (req, res) => { + const id = req.param("id"); + const body = req.param("body"); + const query = req.param("query"); // ... -}) +}); // v5 -app.post('/user', (req, res) => { - const id = req.params.id - const body = req.body - const query = req.query +app.post("/user", (req, res) => { + const id = req.params.id; + const body = req.body; + const query = req.query; // ... -}) +}); ```

      res.json(obj, status)

      @@ -210,23 +212,24 @@ Express 5 no longer supports the signature `res.json(obj, status)`. Instead, set {% capture codemod-status-send-order %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx codemod@latest @expressjs/status-send-order ``` + {% endcapture %} {% include admonitions/note.html content=codemod-status-send-order %} ```js // v4 -app.post('/user', (req, res) => { - res.json({ name: 'Ruben' }, 201) -}) +app.post("/user", (req, res) => { + res.json({ name: "Ruben" }, 201); +}); // v5 -app.post('/user', (req, res) => { - res.status(201).json({ name: 'Ruben' }) -}) +app.post("/user", (req, res) => { + res.status(201).json({ name: "Ruben" }); +}); ```

      res.jsonp(obj, status)

      @@ -235,17 +238,16 @@ Express 5 no longer supports the signature `res.jsonp(obj, status)`. Instead, se {% include admonitions/note.html content=codemod-status-send-order %} - ```js // v4 -app.post('/user', (req, res) => { - res.jsonp({ name: 'Ruben' }, 201) -}) +app.post("/user", (req, res) => { + res.jsonp({ name: "Ruben" }, 201); +}); // v5 -app.post('/user', (req, res) => { - res.status(201).jsonp({ name: 'Ruben' }) -}) +app.post("/user", (req, res) => { + res.status(201).jsonp({ name: "Ruben" }); +}); ```

      res.redirect(url, status)

      @@ -255,26 +257,26 @@ Express 5 no longer supports the signature `res.redirect(url, status)`. Instead, {% capture codemod-redirect-arg-order %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx codemod@latest @expressjs/redirect-arg-order ``` + {% endcapture %} {% include admonitions/note.html content=codemod-redirect-arg-order %} ```js // v4 -app.get('/user', (req, res) => { - res.redirect('/users', 301) -}) +app.get("/user", (req, res) => { + res.redirect("/users", 301); +}); // v5 -app.get('/user', (req, res) => { - res.redirect(301, '/users') -}) +app.get("/user", (req, res) => { + res.redirect(301, "/users"); +}); ``` -

      res.redirect('back') and res.location('back')

      Express 5 no longer supports the magic string `back` in the `res.redirect()` and `res.location()` methods. Instead, use the `req.get('Referrer') || '/'` value to redirect back to the previous page. In Express 4, the `res.redirect('back')` and `res.location('back')` methods were deprecated. @@ -282,23 +284,24 @@ Express 5 no longer supports the magic string `back` in the `res.redirect()` and {% capture codemod-back-redirect-deprecated %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx codemod@latest @expressjs/back-redirect-deprecated ``` + {% endcapture %} {% include admonitions/note.html content=codemod-back-redirect-deprecated %} ```js // v4 -app.get('/user', (req, res) => { - res.redirect('back') -}) +app.get("/user", (req, res) => { + res.redirect("back"); +}); // v5 -app.get('/user', (req, res) => { - res.redirect(req.get('Referrer') || '/') -}) +app.get("/user", (req, res) => { + res.redirect(req.get("Referrer") || "/"); +}); ```

      res.send(body, status)

      @@ -307,17 +310,16 @@ Express 5 no longer supports the signature `res.send(obj, status)`. Instead, set {% include admonitions/note.html content=codemod-status-send-order %} - ```js // v4 -app.get('/user', (req, res) => { - res.send({ name: 'Ruben' }, 200) -}) +app.get("/user", (req, res) => { + res.send({ name: "Ruben" }, 200); +}); // v5 -app.get('/user', (req, res) => { - res.status(200).send({ name: 'Ruben' }) -}) +app.get("/user", (req, res) => { + res.status(200).send({ name: "Ruben" }); +}); ```

      res.send(status)

      @@ -327,17 +329,16 @@ If you need to send a number by using the `res.send()` function, quote the numbe {% include admonitions/note.html content=codemod-status-send-order %} - ```js // v4 -app.get('/user', (req, res) => { - res.send(200) -}) +app.get("/user", (req, res) => { + res.send(200); +}); // v5 -app.get('/user', (req, res) => { - res.sendStatus(200) -}) +app.get("/user", (req, res) => { + res.sendStatus(200); +}); ```

      res.sendfile()

      @@ -356,23 +357,24 @@ The `res.sendfile()` function has been replaced by a camel-cased version `res.se {% capture codemod-camelcase-sendfile %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx codemod@latest @expressjs/camelcase-sendfile ``` + {% endcapture %} {% include admonitions/note.html content=codemod-camelcase-sendfile %} ```js // v4 -app.get('/user', (req, res) => { - res.sendfile('/path/to/file') -}) +app.get("/user", (req, res) => { + res.sendfile("/path/to/file"); +}); // v5 -app.get('/user', (req, res) => { - res.sendFile('/path/to/file') -}) +app.get("/user", (req, res) => { + res.sendFile("/path/to/file"); +}); ```

      router.param(fn)

      @@ -395,11 +397,11 @@ Use the [`mime-types` package](https://github.com/jshttp/mime-types) to work wit ```js // v4 -express.static.mime.lookup('json') +express.static.mime.lookup("json"); // v5 -const mime = require('mime-types') -mime.lookup('json') +const mime = require("mime-types"); +mime.lookup("json"); ```

      express:router debug logs

      @@ -431,14 +433,14 @@ Path route matching syntax is when a string is supplied as the first parameter t ```js // v4 -app.get('/*', async (req, res) => { - res.send('ok') -}) +app.get("/*", async (req, res) => { + res.send("ok"); +}); // v5 -app.get('/*splat', async (req, res) => { - res.send('ok') -}) +app.get("/*splat", async (req, res) => { + res.send("ok"); +}); ``` {% capture note_wildcard %} @@ -446,10 +448,11 @@ app.get('/*splat', async (req, res) => { ```js // v5 -app.get('/{*splat}', async (req, res) => { - res.send('ok') -}) +app.get("/{*splat}", async (req, res) => { + res.send("ok"); +}); ``` + {% endcapture %} {% include admonitions/note.html content=note_wildcard %} @@ -457,27 +460,30 @@ app.get('/{*splat}', async (req, res) => { ```js // v4 -app.get('/:file.:ext?', async (req, res) => { - res.send('ok') -}) +app.get("/:file.:ext?", async (req, res) => { + res.send("ok"); +}); // v5 -app.get('/:file{.:ext}', async (req, res) => { - res.send('ok') -}) +app.get("/:file{.:ext}", async (req, res) => { + res.send("ok"); +}); ``` - Regexp characters are not supported. For example: + ```js -app.get('/[discussion|page]/:slug', async (req, res) => { - res.status(200).send('ok') -}) +app.get("/[discussion|page]/:slug", async (req, res) => { + res.status(200).send("ok"); +}); ``` + should be changed to: + ```js -app.get(['/discussion/:slug', '/page/:slug'], async (req, res) => { - res.status(200).send('ok') -}) +app.get(["/discussion/:slug", "/page/:slug"], async (req, res) => { + res.status(200).send("ok"); +}); ``` - Some characters have been reserved to avoid confusion during upgrade (`()[]?+!`), use `\` to escape them. @@ -501,7 +507,7 @@ Example of breaking code: ```js // v4 -app.use(express.static('public')) +app.use(express.static("public")); ``` After migrating to Express 5, a request to `/.well-known/assetlinks.json` will result in a **404 Not Found**. @@ -510,25 +516,27 @@ To fix this, serve specific dot-directories explicitly using the `dotfiles: "all ```js // v5 -app.use('/.well-known', express.static('public/.well-known', { dotfiles: 'allow' })) -app.use(express.static('public')) +app.use( + "/.well-known", + express.static("public/.well-known", { dotfiles: "allow" }), +); +app.use(express.static("public")); ``` This approach allows you to safely serve only the intended dot-directories while keeping the default secure behavior for other dotfiles, which remain inaccessible. -

      app.listen

      In Express 5, the `app.listen` method will invoke the user-provided callback function (if provided) when the server receives an error event. In Express 4, such errors would be thrown. This change shifts error-handling responsibility to the callback function in Express 5. If there is an error, it will be passed to the callback as an argument. For example: ```js -const server = app.listen(8080, '0.0.0.0', (error) => { +const server = app.listen(8080, "0.0.0.0", (error) => { if (error) { - throw error // e.g. EADDRINUSE + throw error; // e.g. EADDRINUSE } - console.log(`Listening on ${JSON.stringify(server.address())}`) -}) + console.log(`Listening on ${JSON.stringify(server.address())}`); +}); ```

      app.router

      @@ -552,11 +560,11 @@ The `req.params` object now has a **null prototype** when using string paths. Ho Wildcards (e.g., `/*splat`) capture path segments as an array instead of a single string. ```js -app.get('/*splat', (req, res) => { +app.get("/*splat", (req, res) => { // GET /foo/bar - console.dir(req.params) + console.dir(req.params); // => [Object: null prototype] { splat: [ 'foo', 'bar' ] } -}) +}); ``` **Unmatched parameters are omitted:** @@ -565,25 +573,25 @@ In Express 4, unmatched wildcards were empty strings (`''`) and optional `:` par ```js // v4: unmatched wildcard is empty string -app.get('/*', (req, res) => { +app.get("/*", (req, res) => { // GET / - console.dir(req.params) + console.dir(req.params); // => { '0': '' } -}) +}); // v4: unmatched optional param is undefined -app.get('/:file.:ext?', (req, res) => { +app.get("/:file.:ext?", (req, res) => { // GET /image - console.dir(req.params) + console.dir(req.params); // => { file: 'image', ext: undefined } -}) +}); // v5: unmatched optional param is omitted -app.get('/:file{.:ext}', (req, res) => { +app.get("/:file{.:ext}", (req, res) => { // GET /image - console.dir(req.params) + console.dir(req.params); // => [Object: null prototype] { file: 'image' } -}) +}); ```

      req.query

      diff --git a/legacy/es/guide/migrating-5.md b/legacy/es/guide/migrating-5.md index 889c0a18db..40c2316b91 100644 --- a/legacy/es/guide/migrating-5.md +++ b/legacy/es/guide/migrating-5.md @@ -99,7 +99,7 @@ Inicialmente, se utilizaba `del` en lugar de `delete`, porque `delete` es una pa {% capture codemod-deprecated-signatures %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod v4-deprecated-signatures ``` @@ -109,14 +109,14 @@ npx @expressjs/codemod v4-deprecated-signatures ```js // v4 -app.del('/user/:id', (req, res) => { - res.send(`DELETE /user/${req.params.id}`) -}) +app.del("/user/:id", (req, res) => { + res.send(`DELETE /user/${req.params.id}`); +}); // v5 -app.delete('/user/:id', (req, res) => { - res.send(`DELETE /user/${req.params.id}`) -}) +app.delete("/user/:id", (req, res) => { + res.send(`DELETE /user/${req.params.id}`); +}); ```

      app.param(fn)

      @@ -136,7 +136,7 @@ Los siguientes nombres de métodos se han pluralizado. En Express 4, el uso de l {% capture codemod-pluralized-methods %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod pluralized-methods ``` @@ -146,22 +146,22 @@ npx @expressjs/codemod pluralized-methods ```js // v4 -app.all('/', (req, res) => { - req.acceptsCharset('utf-8') - req.acceptsEncoding('br') - req.acceptsLanguage('en') +app.all("/", (req, res) => { + req.acceptsCharset("utf-8"); + req.acceptsEncoding("br"); + req.acceptsLanguage("en"); // ... -}) +}); // v5 -app.all('/', (req, res) => { - req.acceptsCharsets('utf-8') - req.acceptsEncodings('br') - req.acceptsLanguages('en') +app.all("/", (req, res) => { + req.acceptsCharsets("utf-8"); + req.acceptsEncodings("br"); + req.acceptsLanguages("en"); // ... -}) +}); ```

      Dos puntos (:) delanteros en el nombre de app.param(name, fn)

      @@ -177,7 +177,7 @@ Este método potencialmente confuso y peligroso de recuperar datos de formulario {% capture codemod-req-param %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod req-param ``` @@ -187,22 +187,22 @@ npx @expressjs/codemod req-param ```js // v4 -app.post('/user', (req, res) => { - const id = req.param('id') - const body = req.param('body') - const query = req.param('query') +app.post("/user", (req, res) => { + const id = req.param("id"); + const body = req.param("body"); + const query = req.param("query"); // ... -}) +}); // v5 -app.post('/user', (req, res) => { - const id = req.params.id - const body = req.body - const query = req.query +app.post("/user", (req, res) => { + const id = req.params.id; + const body = req.body; + const query = req.query; // ... -}) +}); ```

      res.json(obj, status)

      @@ -213,14 +213,14 @@ Express 5 ya no da soporte a la firma `res.json(obj, status)`. En su lugar, esta ```js // v4 -app.post('/user', (req, res) => { - res.json({ name: 'Ruben' }, 201) -}) +app.post("/user", (req, res) => { + res.json({ name: "Ruben" }, 201); +}); // v5 -app.post('/user', (req, res) => { - res.status(201).json({ name: 'Ruben' }) -}) +app.post("/user", (req, res) => { + res.status(201).json({ name: "Ruben" }); +}); ```

      res.jsonp(obj, status)

      @@ -231,14 +231,14 @@ Express 5 ya no da soporte a la firma `res.jsonp(obj, status)`. En su lugar, est ```js // v4 -app.post('/user', (req, res) => { - res.jsonp({ name: 'Ruben' }, 201) -}) +app.post("/user", (req, res) => { + res.jsonp({ name: "Ruben" }, 201); +}); // v5 -app.post('/user', (req, res) => { - res.status(201).jsonp({ name: 'Ruben' }) -}) +app.post("/user", (req, res) => { + res.status(201).jsonp({ name: "Ruben" }); +}); ```

      res.redirect(url, status)

      @@ -249,14 +249,14 @@ Express 5 ya no da soporte a la firma `res.send(obj, status)`. En su lugar, esta ```js // v4 -app.get('/user', (req, res) => { - res.redirect('/users', 301) -}) +app.get("/user", (req, res) => { + res.redirect("/users", 301); +}); // v5 -app.get('/user', (req, res) => { - res.redirect(301, '/users') -}) +app.get("/user", (req, res) => { + res.redirect(301, "/users"); +}); ```

      res.redirect('back') and res.location('back')

      @@ -266,7 +266,7 @@ Express 5 no longer supports the magic string `back` in the `res.redirect()` and {% capture codemod-magic-redirect %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod magic-redirect ``` @@ -276,14 +276,14 @@ npx @expressjs/codemod magic-redirect ```js // v4 -app.get('/user', (req, res) => { - res.redirect('back') -}) +app.get("/user", (req, res) => { + res.redirect("back"); +}); // v5 -app.get('/user', (req, res) => { - res.redirect(req.get('Referrer') || '/') -}) +app.get("/user", (req, res) => { + res.redirect(req.get("Referrer") || "/"); +}); ```

      res.send(body, status)

      @@ -294,14 +294,14 @@ Express 5 no longer supports the signature `res.send(obj, status)`. Instead, set ```js // v4 -app.get('/user', (req, res) => { - res.send({ name: 'Ruben' }, 200) -}) +app.get("/user", (req, res) => { + res.send({ name: "Ruben" }, 200); +}); // v5 -app.get('/user', (req, res) => { - res.status(200).send({ name: 'Ruben' }) -}) +app.get("/user", (req, res) => { + res.status(200).send({ name: "Ruben" }); +}); ```

      res.send(status)

      @@ -313,14 +313,14 @@ Si necesita enviar un número utilizando la función `res.send()`, escríbalo en ```js // v4 -app.get('/user', (req, res) => { - res.send(200) -}) +app.get("/user", (req, res) => { + res.send(200); +}); // v5 -app.get('/user', (req, res) => { - res.sendStatus(200) -}) +app.get("/user", (req, res) => { + res.sendStatus(200); +}); ```

      res.sendfile()

      @@ -340,14 +340,14 @@ La función `res.sendfile()` se ha sustituido por una versión de la función `r ```js // v4 -app.get('/user', (req, res) => { - res.sendfile('/path/to/file') -}) +app.get("/user", (req, res) => { + res.sendfile("/path/to/file"); +}); // v5 -app.get('/user', (req, res) => { - res.sendFile('/path/to/file') -}) +app.get("/user", (req, res) => { + res.sendFile("/path/to/file"); +}); ```

      router.param(fn)

      @@ -370,11 +370,11 @@ Use the [`mime-types` package](https://github.com/jshttp/mime-types) to work wit ```js // v4 -express.static.mime.lookup('json') +express.static.mime.lookup("json"); // v5 -const mime = require('mime-types') -mime.lookup('json') +const mime = require("mime-types"); +mime.lookup("json"); ```

      express:router debug logs

      @@ -406,14 +406,14 @@ Path route matching syntax is when a string is supplied as the first parameter t ```js // v4 -app.get('/*', async (req, res) => { - res.send('ok') -}) +app.get("/*", async (req, res) => { + res.send("ok"); +}); // v5 -app.get('/*splat', async (req, res) => { - res.send('ok') -}) +app.get("/*splat", async (req, res) => { + res.send("ok"); +}); ``` {% capture note_wildcard %} @@ -421,9 +421,9 @@ app.get('/*splat', async (req, res) => { ```js // v5 -app.get('/{*splat}', async (req, res) => { - res.send('ok') -}) +app.get("/{*splat}", async (req, res) => { + res.send("ok"); +}); ``` {% endcapture %} @@ -433,30 +433,30 @@ app.get('/{*splat}', async (req, res) => { ```js // v4 -app.get('/:file.:ext?', async (req, res) => { - res.send('ok') -}) +app.get("/:file.:ext?", async (req, res) => { + res.send("ok"); +}); // v5 -app.get('/:file{.:ext}', async (req, res) => { - res.send('ok') -}) +app.get("/:file{.:ext}", async (req, res) => { + res.send("ok"); +}); ``` - Regexp characters are not supported. For example: ```js -app.get('/[discussion|page]/:slug', async (req, res) => { - res.status(200).send('ok') -}) +app.get("/[discussion|page]/:slug", async (req, res) => { + res.status(200).send("ok"); +}); ``` should be changed to: ```js -app.get(['/discussion/:slug', '/page/:slug'], async (req, res) => { - res.status(200).send('ok') -}) +app.get(["/discussion/:slug", "/page/:slug"], async (req, res) => { + res.status(200).send("ok"); +}); ``` - Some characters have been reserved to avoid confusion during upgrade (`()[]?+!`), use `\` to escape them. @@ -480,7 +480,7 @@ Example of breaking code: ```js // v4 -app.use(express.static('public')) +app.use(express.static("public")); ``` After migrating to Express 5, a request to `/.well-known/assetlinks.json` will result in a **404 Not Found**. @@ -489,8 +489,11 @@ To fix this, serve specific dot-directories explicitly using the `dotfiles: "all ```js // v5 -app.use('/.well-known', express.static('public/.well-known', { dotfiles: 'allow' })) -app.use(express.static('public')) +app.use( + "/.well-known", + express.static("public/.well-known", { dotfiles: "allow" }), +); +app.use(express.static("public")); ``` This approach allows you to safely serve only the intended dot-directories while keeping the default secure behavior for other dotfiles, which remain inaccessible. @@ -501,12 +504,12 @@ In Express 5, the `app.listen` method will invoke the user-provided callback fun For example: ```js -const server = app.listen(8080, '0.0.0.0', (error) => { +const server = app.listen(8080, "0.0.0.0", (error) => { if (error) { - throw error // e.g. EADDRINUSE + throw error; // e.g. EADDRINUSE } - console.log(`Listening on ${JSON.stringify(server.address())}`) -}) + console.log(`Listening on ${JSON.stringify(server.address())}`); +}); ```

      app.router

      @@ -530,11 +533,11 @@ The `req.params` object now has a **null prototype** when using string paths. Ho Wildcards (e.g., `/*splat`) capture path segments as an array instead of a single string. ```js -app.get('/*splat', (req, res) => { +app.get("/*splat", (req, res) => { // GET /foo/bar - console.dir(req.params) + console.dir(req.params); // => [Object: null prototype] { splat: [ 'foo', 'bar' ] } -}) +}); ``` **Unmatched parameters are omitted:** @@ -543,25 +546,25 @@ In Express 4, unmatched wildcards were empty strings (`''`) and optional `:` par ```js // v4: unmatched wildcard is empty string -app.get('/*', (req, res) => { +app.get("/*", (req, res) => { // GET / - console.dir(req.params) + console.dir(req.params); // => { '0': '' } -}) +}); // v4: unmatched optional param is undefined -app.get('/:file.:ext?', (req, res) => { +app.get("/:file.:ext?", (req, res) => { // GET /image - console.dir(req.params) + console.dir(req.params); // => { file: 'image', ext: undefined } -}) +}); // v5: unmatched optional param is omitted -app.get('/:file{.:ext}', (req, res) => { +app.get("/:file{.:ext}", (req, res) => { // GET /image - console.dir(req.params) + console.dir(req.params); // => [Object: null prototype] { file: 'image' } -}) +}); ```

      req.query

      diff --git a/legacy/fr/guide/migrating-5.md b/legacy/fr/guide/migrating-5.md index 67db811e24..a035f09ea8 100644 --- a/legacy/fr/guide/migrating-5.md +++ b/legacy/fr/guide/migrating-5.md @@ -117,7 +117,7 @@ clé réservé dans JavaScript. Cependant, à partir d'ECMAScript 6, {% capture codemod-deprecated-signatures %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod v4-deprecated-signatures ``` @@ -127,14 +127,14 @@ npx @expressjs/codemod v4-deprecated-signatures ```js // v4 -app.del('/user/:id', (req, res) => { - res.send(`DELETE /user/${req.params.id}`) -}) +app.del("/user/:id", (req, res) => { + res.send(`DELETE /user/${req.params.id}`); +}); // v5 -app.delete('/user/:id', (req, res) => { - res.send(`DELETE /user/${req.params.id}`) -}) +app.delete("/user/:id", (req, res) => { + res.send(`DELETE /user/${req.params.id}`); +}); ```

      app.param(fn)

      @@ -161,7 +161,7 @@ d'obsolescence. Express 5 ne les prend plus du tout en charge : {% capture codemod-pluralized-methods %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod pluralized-methods ``` @@ -171,22 +171,22 @@ npx @expressjs/codemod pluralized-methods ```js // v4 -app.all('/', (req, res) => { - req.acceptsCharset('utf-8') - req.acceptsEncoding('br') - req.acceptsLanguage('en') +app.all("/", (req, res) => { + req.acceptsCharset("utf-8"); + req.acceptsEncoding("br"); + req.acceptsLanguage("en"); // ... -}) +}); // v5 -app.all('/', (req, res) => { - req.acceptsCharsets('utf-8') - req.acceptsEncodings('br') - req.acceptsLanguages('en') +app.all("/", (req, res) => { + req.acceptsCharsets("utf-8"); + req.acceptsEncodings("br"); + req.acceptsLanguages("en"); // ... -}) +}); ```

      Signe deux-points (:) de tête dans le nom de la @@ -212,7 +212,7 @@ l'objet `req.params`, `req.body` ou `req.query`. {% capture codemod-req-param %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod req-param ``` @@ -222,22 +222,22 @@ npx @expressjs/codemod req-param ```js // v4 -app.post('/user', (req, res) => { - const id = req.param('id') - const body = req.param('body') - const query = req.param('query') +app.post("/user", (req, res) => { + const id = req.param("id"); + const body = req.param("body"); + const query = req.param("query"); // ... -}) +}); // v5 -app.post('/user', (req, res) => { - const id = req.params.id - const body = req.body - const query = req.query +app.post("/user", (req, res) => { + const id = req.params.id; + const body = req.body; + const query = req.query; // ... -}) +}); ```

      res.json(obj, status)

      @@ -252,14 +252,14 @@ statut et enchaînez-le à la méthode ```js // v4 -app.post('/user', (req, res) => { - res.json({ name: 'Ruben' }, 201) -}) +app.post("/user", (req, res) => { + res.json({ name: "Ruben" }, 201); +}); // v5 -app.post('/user', (req, res) => { - res.status(201).json({ name: 'Ruben' }) -}) +app.post("/user", (req, res) => { + res.status(201).json({ name: "Ruben" }); +}); ```

      res.jsonp(obj, status)

      @@ -273,14 +273,14 @@ comme suit : `res.status(status).jsonp(obj)`. ```js // v4 -app.post('/user', (req, res) => { - res.jsonp({ name: 'Ruben' }, 201) -}) +app.post("/user", (req, res) => { + res.jsonp({ name: "Ruben" }, 201); +}); // v5 -app.post('/user', (req, res) => { - res.status(201).jsonp({ name: 'Ruben' }) -}) +app.post("/user", (req, res) => { + res.status(201).jsonp({ name: "Ruben" }); +}); ```

      res.redirect(url, status)

      @@ -294,14 +294,14 @@ comme suit : `res.status(status).send(obj)`. ```js // v4 -app.get('/user', (req, res) => { - res.redirect('/users', 301) -}) +app.get("/user", (req, res) => { + res.redirect("/users", 301); +}); // v5 -app.get('/user', (req, res) => { - res.redirect(301, '/users') -}) +app.get("/user", (req, res) => { + res.redirect(301, "/users"); +}); ```

      res.redirect('back') and res.location('back')

      @@ -311,7 +311,7 @@ Express 5 no longer supports the magic string `back` in the `res.redirect()` and {% capture codemod-magic-redirect %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod magic-redirect ``` @@ -321,14 +321,14 @@ npx @expressjs/codemod magic-redirect ```js // v4 -app.get('/user', (req, res) => { - res.redirect('back') -}) +app.get("/user", (req, res) => { + res.redirect("back"); +}); // v5 -app.get('/user', (req, res) => { - res.redirect(req.get('Referrer') || '/') -}) +app.get("/user", (req, res) => { + res.redirect(req.get("Referrer") || "/"); +}); ```

      res.send(body, status)

      @@ -339,14 +339,14 @@ Express 5 no longer supports the signature `res.send(obj, status)`. Instead, set ```js // v4 -app.get('/user', (req, res) => { - res.send({ name: 'Ruben' }, 200) -}) +app.get("/user", (req, res) => { + res.send({ name: "Ruben" }, 200); +}); // v5 -app.get('/user', (req, res) => { - res.status(200).send({ name: 'Ruben' }) -}) +app.get("/user", (req, res) => { + res.status(200).send({ name: "Ruben" }); +}); ```

      res.send(status)

      @@ -364,14 +364,14 @@ comme une tentative d'utilisation de l'ancienne signature non prise en charge. ```js // v4 -app.get('/user', (req, res) => { - res.send(200) -}) +app.get("/user", (req, res) => { + res.send(200); +}); // v5 -app.get('/user', (req, res) => { - res.sendStatus(200) -}) +app.get("/user", (req, res) => { + res.sendStatus(200); +}); ```

      res.sendfile()

      @@ -393,14 +393,14 @@ version CamelCase `res.sendFile()` dans Express 5. ```js // v4 -app.get('/user', (req, res) => { - res.sendfile('/path/to/file') -}) +app.get("/user", (req, res) => { + res.sendfile("/path/to/file"); +}); // v5 -app.get('/user', (req, res) => { - res.sendFile('/path/to/file') -}) +app.get("/user", (req, res) => { + res.sendFile("/path/to/file"); +}); ```

      router.param(fn)

      @@ -424,11 +424,11 @@ Use the [`mime-types` package](https://github.com/jshttp/mime-types) to work wit ```js // v4 -express.static.mime.lookup('json') +express.static.mime.lookup("json"); // v5 -const mime = require('mime-types') -mime.lookup('json') +const mime = require("mime-types"); +mime.lookup("json"); ```

      express:router debug logs

      @@ -460,14 +460,14 @@ Path route matching syntax is when a string is supplied as the first parameter t ```js // v4 -app.get('/*', async (req, res) => { - res.send('ok') -}) +app.get("/*", async (req, res) => { + res.send("ok"); +}); // v5 -app.get('/*splat', async (req, res) => { - res.send('ok') -}) +app.get("/*splat", async (req, res) => { + res.send("ok"); +}); ``` {% capture note_wildcard %} @@ -475,9 +475,9 @@ app.get('/*splat', async (req, res) => { ```js // v5 -app.get('/{*splat}', async (req, res) => { - res.send('ok') -}) +app.get("/{*splat}", async (req, res) => { + res.send("ok"); +}); ``` {% endcapture %} @@ -487,30 +487,30 @@ app.get('/{*splat}', async (req, res) => { ```js // v4 -app.get('/:file.:ext?', async (req, res) => { - res.send('ok') -}) +app.get("/:file.:ext?", async (req, res) => { + res.send("ok"); +}); // v5 -app.get('/:file{.:ext}', async (req, res) => { - res.send('ok') -}) +app.get("/:file{.:ext}", async (req, res) => { + res.send("ok"); +}); ``` - Regexp characters are not supported. Par exemple : ```js -app.get('/[discussion|page]/:slug', async (req, res) => { - res.status(200).send('ok') -}) +app.get("/[discussion|page]/:slug", async (req, res) => { + res.status(200).send("ok"); +}); ``` should be changed to: ```js -app.get(['/discussion/:slug', '/page/:slug'], async (req, res) => { - res.status(200).send('ok') -}) +app.get(["/discussion/:slug", "/page/:slug"], async (req, res) => { + res.status(200).send("ok"); +}); ``` - Some characters have been reserved to avoid confusion during upgrade (`()[]?+!`), use `\` to escape them. @@ -534,7 +534,7 @@ Example of breaking code: ```js // v4 -app.use(express.static('public')) +app.use(express.static("public")); ``` After migrating to Express 5, a request to `/.well-known/assetlinks.json` will result in a **404 Not Found**. @@ -543,8 +543,11 @@ To fix this, serve specific dot-directories explicitly using the `dotfiles: "all ```js // v5 -app.use('/.well-known', express.static('public/.well-known', { dotfiles: 'allow' })) -app.use(express.static('public')) +app.use( + "/.well-known", + express.static("public/.well-known", { dotfiles: "allow" }), +); +app.use(express.static("public")); ``` This approach allows you to safely serve only the intended dot-directories while keeping the default secure behavior for other dotfiles, which remain inaccessible. @@ -555,12 +558,12 @@ In Express 5, the `app.listen` method will invoke the user-provided callback fun Par exemple : ```js -const server = app.listen(8080, '0.0.0.0', (error) => { +const server = app.listen(8080, "0.0.0.0", (error) => { if (error) { - throw error // e.g. EADDRINUSE + throw error; // e.g. EADDRINUSE } - console.log(`Listening on ${JSON.stringify(server.address())}`) -}) + console.log(`Listening on ${JSON.stringify(server.address())}`); +}); ```

      app.router

      @@ -586,11 +589,11 @@ The `req.params` object now has a **null prototype** when using string paths. Ho Wildcards (e.g., `/*splat`) capture path segments as an array instead of a single string. ```js -app.get('/*splat', (req, res) => { +app.get("/*splat", (req, res) => { // GET /foo/bar - console.dir(req.params) + console.dir(req.params); // => [Object: null prototype] { splat: [ 'foo', 'bar' ] } -}) +}); ``` **Unmatched parameters are omitted:** @@ -599,25 +602,25 @@ In Express 4, unmatched wildcards were empty strings (`''`) and optional `:` par ```js // v4: unmatched wildcard is empty string -app.get('/*', (req, res) => { +app.get("/*", (req, res) => { // GET / - console.dir(req.params) + console.dir(req.params); // => { '0': '' } -}) +}); // v4: unmatched optional param is undefined -app.get('/:file.:ext?', (req, res) => { +app.get("/:file.:ext?", (req, res) => { // GET /image - console.dir(req.params) + console.dir(req.params); // => { file: 'image', ext: undefined } -}) +}); // v5: unmatched optional param is omitted -app.get('/:file{.:ext}', (req, res) => { +app.get("/:file{.:ext}", (req, res) => { // GET /image - console.dir(req.params) + console.dir(req.params); // => [Object: null prototype] { file: 'image' } -}) +}); ```

      req.query

      diff --git a/legacy/it/guide/migrating-5.md b/legacy/it/guide/migrating-5.md index 40d09e379f..91eef72d1f 100644 --- a/legacy/it/guide/migrating-5.md +++ b/legacy/it/guide/migrating-5.md @@ -99,7 +99,7 @@ Inizialmente era stato utilizzato il comando `del` al posto di `delete`, perché {% capture codemod-deprecated-signatures %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod v4-deprecated-signatures ``` @@ -109,14 +109,14 @@ npx @expressjs/codemod v4-deprecated-signatures ```js // v4 -app.del('/user/:id', (req, res) => { - res.send(`DELETE /user/${req.params.id}`) -}) +app.del("/user/:id", (req, res) => { + res.send(`DELETE /user/${req.params.id}`); +}); // v5 -app.delete('/user/:id', (req, res) => { - res.send(`DELETE /user/${req.params.id}`) -}) +app.delete("/user/:id", (req, res) => { + res.send(`DELETE /user/${req.params.id}`); +}); ```

      app.param(fn)

      @@ -136,7 +136,7 @@ I seguenti nomi di metodi sono stati messi al plurale. In Express 4, l'utilizzo {% capture codemod-pluralized-methods %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod pluralized-methods ``` @@ -146,22 +146,22 @@ npx @expressjs/codemod pluralized-methods ```js // v4 -app.all('/', (req, res) => { - req.acceptsCharset('utf-8') - req.acceptsEncoding('br') - req.acceptsLanguage('en') +app.all("/", (req, res) => { + req.acceptsCharset("utf-8"); + req.acceptsEncoding("br"); + req.acceptsLanguage("en"); // ... -}) +}); // v5 -app.all('/', (req, res) => { - req.acceptsCharsets('utf-8') - req.acceptsEncodings('br') - req.acceptsLanguages('en') +app.all("/", (req, res) => { + req.acceptsCharsets("utf-8"); + req.acceptsEncodings("br"); + req.acceptsLanguages("en"); // ... -}) +}); ```

      Due punti (:) nel nome per app.param(name, fn)

      @@ -177,7 +177,7 @@ Questo metodo poco chiaro e molto pericoloso che si utilizzava per richiamare i {% capture codemod-req-param %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod req-param ``` @@ -187,22 +187,22 @@ npx @expressjs/codemod req-param ```js // v4 -app.post('/user', (req, res) => { - const id = req.param('id') - const body = req.param('body') - const query = req.param('query') +app.post("/user", (req, res) => { + const id = req.param("id"); + const body = req.param("body"); + const query = req.param("query"); // ... -}) +}); // v5 -app.post('/user', (req, res) => { - const id = req.params.id - const body = req.body - const query = req.query +app.post("/user", (req, res) => { + const id = req.params.id; + const body = req.body; + const query = req.query; // ... -}) +}); ```

      res.json(obj, status)

      @@ -213,14 +213,14 @@ Express 5 non supporta più la firma `res.json(obj, status)`. Al contrario, impo ```js // v4 -app.post('/user', (req, res) => { - res.json({ name: 'Ruben' }, 201) -}) +app.post("/user", (req, res) => { + res.json({ name: "Ruben" }, 201); +}); // v5 -app.post('/user', (req, res) => { - res.status(201).json({ name: 'Ruben' }) -}) +app.post("/user", (req, res) => { + res.status(201).json({ name: "Ruben" }); +}); ```

      res.jsonp(obj, status)

      @@ -231,14 +231,14 @@ Express 5 non supporta più la firma `res.jsonp(obj, status)`. Al contrario, imp ```js // v4 -app.post('/user', (req, res) => { - res.jsonp({ name: 'Ruben' }, 201) -}) +app.post("/user", (req, res) => { + res.jsonp({ name: "Ruben" }, 201); +}); // v5 -app.post('/user', (req, res) => { - res.status(201).jsonp({ name: 'Ruben' }) -}) +app.post("/user", (req, res) => { + res.status(201).jsonp({ name: "Ruben" }); +}); ```

      res.redirect(url, status)

      @@ -249,14 +249,14 @@ Express 5 non supporta più la firma `res.send(obj, status)`. Al contrario, impo ```js // v4 -app.get('/user', (req, res) => { - res.redirect('/users', 301) -}) +app.get("/user", (req, res) => { + res.redirect("/users", 301); +}); // v5 -app.get('/user', (req, res) => { - res.redirect(301, '/users') -}) +app.get("/user", (req, res) => { + res.redirect(301, "/users"); +}); ```

      res.redirect('back') and res.location('back')

      @@ -266,7 +266,7 @@ Express 5 no longer supports the magic string `back` in the `res.redirect()` and {% capture codemod-magic-redirect %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod magic-redirect ``` @@ -276,14 +276,14 @@ npx @expressjs/codemod magic-redirect ```js // v4 -app.get('/user', (req, res) => { - res.redirect('back') -}) +app.get("/user", (req, res) => { + res.redirect("back"); +}); // v5 -app.get('/user', (req, res) => { - res.redirect(req.get('Referrer') || '/') -}) +app.get("/user", (req, res) => { + res.redirect(req.get("Referrer") || "/"); +}); ```

      res.send(body, status)

      @@ -294,14 +294,14 @@ Express 5 no longer supports the signature `res.send(obj, status)`. Instead, set ```js // v4 -app.get('/user', (req, res) => { - res.send({ name: 'Ruben' }, 200) -}) +app.get("/user", (req, res) => { + res.send({ name: "Ruben" }, 200); +}); // v5 -app.get('/user', (req, res) => { - res.status(200).send({ name: 'Ruben' }) -}) +app.get("/user", (req, res) => { + res.status(200).send({ name: "Ruben" }); +}); ```

      res.send(status)

      @@ -313,14 +313,14 @@ Se è necessario inviare un numero utilizzando la funzione `res.send()`, citare ```js // v4 -app.get('/user', (req, res) => { - res.send(200) -}) +app.get("/user", (req, res) => { + res.send(200); +}); // v5 -app.get('/user', (req, res) => { - res.sendStatus(200) -}) +app.get("/user", (req, res) => { + res.sendStatus(200); +}); ```

      res.sendfile()

      @@ -340,14 +340,14 @@ La funzione `res.sendfile()` è stata sostituita da una versione in cui ogni fra ```js // v4 -app.get('/user', (req, res) => { - res.sendfile('/path/to/file') -}) +app.get("/user", (req, res) => { + res.sendfile("/path/to/file"); +}); // v5 -app.get('/user', (req, res) => { - res.sendFile('/path/to/file') -}) +app.get("/user", (req, res) => { + res.sendFile("/path/to/file"); +}); ```

      router.param(fn)

      @@ -370,11 +370,11 @@ Use the [`mime-types` package](https://github.com/jshttp/mime-types) to work wit ```js // v4 -express.static.mime.lookup('json') +express.static.mime.lookup("json"); // v5 -const mime = require('mime-types') -mime.lookup('json') +const mime = require("mime-types"); +mime.lookup("json"); ```

      express:router debug logs

      @@ -406,14 +406,14 @@ Path route matching syntax is when a string is supplied as the first parameter t ```js // v4 -app.get('/*', async (req, res) => { - res.send('ok') -}) +app.get("/*", async (req, res) => { + res.send("ok"); +}); // v5 -app.get('/*splat', async (req, res) => { - res.send('ok') -}) +app.get("/*splat", async (req, res) => { + res.send("ok"); +}); ``` {% capture note_wildcard %} @@ -421,9 +421,9 @@ app.get('/*splat', async (req, res) => { ```js // v5 -app.get('/{*splat}', async (req, res) => { - res.send('ok') -}) +app.get("/{*splat}", async (req, res) => { + res.send("ok"); +}); ``` {% endcapture %} @@ -433,30 +433,30 @@ app.get('/{*splat}', async (req, res) => { ```js // v4 -app.get('/:file.:ext?', async (req, res) => { - res.send('ok') -}) +app.get("/:file.:ext?", async (req, res) => { + res.send("ok"); +}); // v5 -app.get('/:file{.:ext}', async (req, res) => { - res.send('ok') -}) +app.get("/:file{.:ext}", async (req, res) => { + res.send("ok"); +}); ``` - Regexp characters are not supported. Ad esempio: ```js -app.get('/[discussion|page]/:slug', async (req, res) => { - res.status(200).send('ok') -}) +app.get("/[discussion|page]/:slug", async (req, res) => { + res.status(200).send("ok"); +}); ``` should be changed to: ```js -app.get(['/discussion/:slug', '/page/:slug'], async (req, res) => { - res.status(200).send('ok') -}) +app.get(["/discussion/:slug", "/page/:slug"], async (req, res) => { + res.status(200).send("ok"); +}); ``` - Some characters have been reserved to avoid confusion during upgrade (`()[]?+!`), use `\` to escape them. @@ -480,7 +480,7 @@ Example of breaking code: ```js // v4 -app.use(express.static('public')) +app.use(express.static("public")); ``` After migrating to Express 5, a request to `/.well-known/assetlinks.json` will result in a **404 Not Found**. @@ -489,8 +489,11 @@ To fix this, serve specific dot-directories explicitly using the `dotfiles: "all ```js // v5 -app.use('/.well-known', express.static('public/.well-known', { dotfiles: 'allow' })) -app.use(express.static('public')) +app.use( + "/.well-known", + express.static("public/.well-known", { dotfiles: "allow" }), +); +app.use(express.static("public")); ``` This approach allows you to safely serve only the intended dot-directories while keeping the default secure behavior for other dotfiles, which remain inaccessible. @@ -501,12 +504,12 @@ In Express 5, the `app.listen` method will invoke the user-provided callback fun Ad esempio: ```js -const server = app.listen(8080, '0.0.0.0', (error) => { +const server = app.listen(8080, "0.0.0.0", (error) => { if (error) { - throw error // e.g. EADDRINUSE + throw error; // e.g. EADDRINUSE } - console.log(`Listening on ${JSON.stringify(server.address())}`) -}) + console.log(`Listening on ${JSON.stringify(server.address())}`); +}); ```

      app.router

      @@ -530,11 +533,11 @@ The `req.params` object now has a **null prototype** when using string paths. Ho Wildcards (e.g., `/*splat`) capture path segments as an array instead of a single string. ```js -app.get('/*splat', (req, res) => { +app.get("/*splat", (req, res) => { // GET /foo/bar - console.dir(req.params) + console.dir(req.params); // => [Object: null prototype] { splat: [ 'foo', 'bar' ] } -}) +}); ``` **Unmatched parameters are omitted:** @@ -543,25 +546,25 @@ In Express 4, unmatched wildcards were empty strings (`''`) and optional `:` par ```js // v4: unmatched wildcard is empty string -app.get('/*', (req, res) => { +app.get("/*", (req, res) => { // GET / - console.dir(req.params) + console.dir(req.params); // => { '0': '' } -}) +}); // v4: unmatched optional param is undefined -app.get('/:file.:ext?', (req, res) => { +app.get("/:file.:ext?", (req, res) => { // GET /image - console.dir(req.params) + console.dir(req.params); // => { file: 'image', ext: undefined } -}) +}); // v5: unmatched optional param is omitted -app.get('/:file{.:ext}', (req, res) => { +app.get("/:file{.:ext}", (req, res) => { // GET /image - console.dir(req.params) + console.dir(req.params); // => [Object: null prototype] { file: 'image' } -}) +}); ```

      req.query

      diff --git a/legacy/ja/guide/migrating-5.md b/legacy/ja/guide/migrating-5.md index 21b7e81bcf..d60ff7df77 100644 --- a/legacy/ja/guide/migrating-5.md +++ b/legacy/ja/guide/migrating-5.md @@ -99,7 +99,7 @@ Express 5 は、`app.del()` 関数をサポートしなくなりました。こ {% capture codemod-deprecated-signatures %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod v4-deprecated-signatures ``` @@ -109,14 +109,14 @@ npx @expressjs/codemod v4-deprecated-signatures ```js // v4 -app.del('/user/:id', (req, res) => { - res.send(`DELETE /user/${req.params.id}`) -}) +app.del("/user/:id", (req, res) => { + res.send(`DELETE /user/${req.params.id}`); +}); // v5 -app.delete('/user/:id', (req, res) => { - res.send(`DELETE /user/${req.params.id}`) -}) +app.delete("/user/:id", (req, res) => { + res.send(`DELETE /user/${req.params.id}`); +}); ```

      app.param(fn)

      @@ -136,7 +136,7 @@ The following method names have been pluralized. In Express 4, using the old met {% capture codemod-pluralized-methods %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod pluralized-methods ``` @@ -146,22 +146,22 @@ npx @expressjs/codemod pluralized-methods ```js // v4 -app.all('/', (req, res) => { - req.acceptsCharset('utf-8') - req.acceptsEncoding('br') - req.acceptsLanguage('en') +app.all("/", (req, res) => { + req.acceptsCharset("utf-8"); + req.acceptsEncoding("br"); + req.acceptsLanguage("en"); // ... -}) +}); // v5 -app.all('/', (req, res) => { - req.acceptsCharsets('utf-8') - req.acceptsEncodings('br') - req.acceptsLanguages('en') +app.all("/", (req, res) => { + req.acceptsCharsets("utf-8"); + req.acceptsEncodings("br"); + req.acceptsLanguages("en"); // ... -}) +}); ```

      app.param(name, fn) の name の先頭コロン (:)

      @@ -177,7 +177,7 @@ This potentially confusing and dangerous method of retrieving form data has been {% capture codemod-req-param %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod req-param ``` @@ -187,22 +187,22 @@ npx @expressjs/codemod req-param ```js // v4 -app.post('/user', (req, res) => { - const id = req.param('id') - const body = req.param('body') - const query = req.param('query') +app.post("/user", (req, res) => { + const id = req.param("id"); + const body = req.param("body"); + const query = req.param("query"); // ... -}) +}); // v5 -app.post('/user', (req, res) => { - const id = req.params.id - const body = req.body - const query = req.query +app.post("/user", (req, res) => { + const id = req.params.id; + const body = req.body; + const query = req.query; // ... -}) +}); ```

      res.json(obj, status)

      @@ -213,14 +213,14 @@ Express 5 は、シグニチャー `res.json(obj, status)` をサポートしな ```js // v4 -app.post('/user', (req, res) => { - res.json({ name: 'Ruben' }, 201) -}) +app.post("/user", (req, res) => { + res.json({ name: "Ruben" }, 201); +}); // v5 -app.post('/user', (req, res) => { - res.status(201).json({ name: 'Ruben' }) -}) +app.post("/user", (req, res) => { + res.status(201).json({ name: "Ruben" }); +}); ```

      res.jsonp(obj, status)

      @@ -231,14 +231,14 @@ Express 5 は、シグニチャー `res.jsonp(obj, status)` をサポートし ```js // v4 -app.post('/user', (req, res) => { - res.jsonp({ name: 'Ruben' }, 201) -}) +app.post("/user", (req, res) => { + res.jsonp({ name: "Ruben" }, 201); +}); // v5 -app.post('/user', (req, res) => { - res.status(201).jsonp({ name: 'Ruben' }) -}) +app.post("/user", (req, res) => { + res.status(201).jsonp({ name: "Ruben" }); +}); ```

      res.redirect(url, status)

      @@ -249,14 +249,14 @@ Express 5 no longer supports the signature `res.redirect(url, status)`. Instead, ```js // v4 -app.get('/user', (req, res) => { - res.redirect('/users', 301) -}) +app.get("/user", (req, res) => { + res.redirect("/users", 301); +}); // v5 -app.get('/user', (req, res) => { - res.redirect(301, '/users') -}) +app.get("/user", (req, res) => { + res.redirect(301, "/users"); +}); ```

      res.redirect('back') and res.location('back')

      @@ -266,7 +266,7 @@ Express 5 no longer supports the magic string `back` in the `res.redirect()` and {% capture codemod-magic-redirect %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod magic-redirect ``` @@ -276,14 +276,14 @@ npx @expressjs/codemod magic-redirect ```js // v4 -app.get('/user', (req, res) => { - res.redirect('back') -}) +app.get("/user", (req, res) => { + res.redirect("back"); +}); // v5 -app.get('/user', (req, res) => { - res.redirect(req.get('Referrer') || '/') -}) +app.get("/user", (req, res) => { + res.redirect(req.get("Referrer") || "/"); +}); ```

      res.send(body, status)

      @@ -294,14 +294,14 @@ Express 5 は、シグニチャー `res.send(obj, status)` をサポートしな ```js // v4 -app.get('/user', (req, res) => { - res.send({ name: 'Ruben' }, 200) -}) +app.get("/user", (req, res) => { + res.send({ name: "Ruben" }, 200); +}); // v5 -app.get('/user', (req, res) => { - res.status(200).send({ name: 'Ruben' }) -}) +app.get("/user", (req, res) => { + res.status(200).send({ name: "Ruben" }); +}); ```

      res.send(status)

      @@ -313,14 +313,14 @@ If you need to send a number by using the `res.send()` function, quote the numbe ```js // v4 -app.get('/user', (req, res) => { - res.send(200) -}) +app.get("/user", (req, res) => { + res.send(200); +}); // v5 -app.get('/user', (req, res) => { - res.sendStatus(200) -}) +app.get("/user", (req, res) => { + res.sendStatus(200); +}); ```

      res.sendfile()

      @@ -340,14 +340,14 @@ app.get('/user', (req, res) => { ```js // v4 -app.get('/user', (req, res) => { - res.sendfile('/path/to/file') -}) +app.get("/user", (req, res) => { + res.sendfile("/path/to/file"); +}); // v5 -app.get('/user', (req, res) => { - res.sendFile('/path/to/file') -}) +app.get("/user", (req, res) => { + res.sendFile("/path/to/file"); +}); ```

      router.param(fn)

      @@ -370,11 +370,11 @@ Use the [`mime-types` package](https://github.com/jshttp/mime-types) to work wit ```js // v4 -express.static.mime.lookup('json') +express.static.mime.lookup("json"); // v5 -const mime = require('mime-types') -mime.lookup('json') +const mime = require("mime-types"); +mime.lookup("json"); ```

      express:router debug logs

      @@ -406,14 +406,14 @@ Path route matching syntax is when a string is supplied as the first parameter t ```js // v4 -app.get('/*', async (req, res) => { - res.send('ok') -}) +app.get("/*", async (req, res) => { + res.send("ok"); +}); // v5 -app.get('/*splat', async (req, res) => { - res.send('ok') -}) +app.get("/*splat", async (req, res) => { + res.send("ok"); +}); ``` {% capture note_wildcard %} @@ -421,9 +421,9 @@ app.get('/*splat', async (req, res) => { ```js // v5 -app.get('/{*splat}', async (req, res) => { - res.send('ok') -}) +app.get("/{*splat}", async (req, res) => { + res.send("ok"); +}); ``` {% endcapture %} @@ -433,30 +433,30 @@ app.get('/{*splat}', async (req, res) => { ```js // v4 -app.get('/:file.:ext?', async (req, res) => { - res.send('ok') -}) +app.get("/:file.:ext?", async (req, res) => { + res.send("ok"); +}); // v5 -app.get('/:file{.:ext}', async (req, res) => { - res.send('ok') -}) +app.get("/:file{.:ext}", async (req, res) => { + res.send("ok"); +}); ``` - Regexp characters are not supported. For example: ```js -app.get('/[discussion|page]/:slug', async (req, res) => { - res.status(200).send('ok') -}) +app.get("/[discussion|page]/:slug", async (req, res) => { + res.status(200).send("ok"); +}); ``` should be changed to: ```js -app.get(['/discussion/:slug', '/page/:slug'], async (req, res) => { - res.status(200).send('ok') -}) +app.get(["/discussion/:slug", "/page/:slug"], async (req, res) => { + res.status(200).send("ok"); +}); ``` - Some characters have been reserved to avoid confusion during upgrade (`()[]?+!`), use `\` to escape them. @@ -480,7 +480,7 @@ Example of breaking code: ```js // v4 -app.use(express.static('public')) +app.use(express.static("public")); ``` After migrating to Express 5, a request to `/.well-known/assetlinks.json` will result in a **404 Not Found**. @@ -489,8 +489,11 @@ To fix this, serve specific dot-directories explicitly using the `dotfiles: "all ```js // v5 -app.use('/.well-known', express.static('public/.well-known', { dotfiles: 'allow' })) -app.use(express.static('public')) +app.use( + "/.well-known", + express.static("public/.well-known", { dotfiles: "allow" }), +); +app.use(express.static("public")); ``` This approach allows you to safely serve only the intended dot-directories while keeping the default secure behavior for other dotfiles, which remain inaccessible. @@ -501,12 +504,12 @@ In Express 5, the `app.listen` method will invoke the user-provided callback fun For example: ```js -const server = app.listen(8080, '0.0.0.0', (error) => { +const server = app.listen(8080, "0.0.0.0", (error) => { if (error) { - throw error // e.g. EADDRINUSE + throw error; // e.g. EADDRINUSE } - console.log(`Listening on ${JSON.stringify(server.address())}`) -}) + console.log(`Listening on ${JSON.stringify(server.address())}`); +}); ```

      app.router

      @@ -530,11 +533,11 @@ The `req.params` object now has a **null prototype** when using string paths. Ho Wildcards (e.g., `/*splat`) capture path segments as an array instead of a single string. ```js -app.get('/*splat', (req, res) => { +app.get("/*splat", (req, res) => { // GET /foo/bar - console.dir(req.params) + console.dir(req.params); // => [Object: null prototype] { splat: [ 'foo', 'bar' ] } -}) +}); ``` **Unmatched parameters are omitted:** @@ -543,25 +546,25 @@ In Express 4, unmatched wildcards were empty strings (`''`) and optional `:` par ```js // v4: unmatched wildcard is empty string -app.get('/*', (req, res) => { +app.get("/*", (req, res) => { // GET / - console.dir(req.params) + console.dir(req.params); // => { '0': '' } -}) +}); // v4: unmatched optional param is undefined -app.get('/:file.:ext?', (req, res) => { +app.get("/:file.:ext?", (req, res) => { // GET /image - console.dir(req.params) + console.dir(req.params); // => { file: 'image', ext: undefined } -}) +}); // v5: unmatched optional param is omitted -app.get('/:file{.:ext}', (req, res) => { +app.get("/:file{.:ext}", (req, res) => { // GET /image - console.dir(req.params) + console.dir(req.params); // => [Object: null prototype] { file: 'image' } -}) +}); ```

      req.query

      diff --git a/legacy/ko/guide/migrating-5.md b/legacy/ko/guide/migrating-5.md index fedcfe82ee..2d94712214 100644 --- a/legacy/ko/guide/migrating-5.md +++ b/legacy/ko/guide/migrating-5.md @@ -99,7 +99,7 @@ Express 5는 `app.del()` 함수를 더 이상 지원하지 않습니다. 이 함 {% capture codemod-deprecated-signatures %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod v4-deprecated-signatures ``` @@ -109,14 +109,14 @@ npx @expressjs/codemod v4-deprecated-signatures ```js // v4 -app.del('/user/:id', (req, res) => { - res.send(`DELETE /user/${req.params.id}`) -}) +app.del("/user/:id", (req, res) => { + res.send(`DELETE /user/${req.params.id}`); +}); // v5 -app.delete('/user/:id', (req, res) => { - res.send(`DELETE /user/${req.params.id}`) -}) +app.delete("/user/:id", (req, res) => { + res.send(`DELETE /user/${req.params.id}`); +}); ```

      app.param(fn)

      @@ -136,7 +136,7 @@ app.delete('/user/:id', (req, res) => { {% capture codemod-pluralized-methods %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod pluralized-methods ``` @@ -146,22 +146,22 @@ npx @expressjs/codemod pluralized-methods ```js // v4 -app.all('/', (req, res) => { - req.acceptsCharset('utf-8') - req.acceptsEncoding('br') - req.acceptsLanguage('en') +app.all("/", (req, res) => { + req.acceptsCharset("utf-8"); + req.acceptsEncoding("br"); + req.acceptsLanguage("en"); // ... -}) +}); // v5 -app.all('/', (req, res) => { - req.acceptsCharsets('utf-8') - req.acceptsEncodings('br') - req.acceptsLanguages('en') +app.all("/", (req, res) => { + req.acceptsCharsets("utf-8"); + req.acceptsEncodings("br"); + req.acceptsLanguages("en"); // ... -}) +}); ```

      app.param(name, fn)에 대한 이름(name)의 첫머리 콜론(:)

      @@ -177,7 +177,7 @@ app.all('/', (req, res) => { {% capture codemod-req-param %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod req-param ``` @@ -187,22 +187,22 @@ npx @expressjs/codemod req-param ```js // v4 -app.post('/user', (req, res) => { - const id = req.param('id') - const body = req.param('body') - const query = req.param('query') +app.post("/user", (req, res) => { + const id = req.param("id"); + const body = req.param("body"); + const query = req.param("query"); // ... -}) +}); // v5 -app.post('/user', (req, res) => { - const id = req.params.id - const body = req.body - const query = req.query +app.post("/user", (req, res) => { + const id = req.params.id; + const body = req.body; + const query = req.query; // ... -}) +}); ```

      res.json(obj, status)

      @@ -213,14 +213,14 @@ Express 5는 `res.json(obj, status)` 시그니처를 더 이상 지원하지 않 ```js // v4 -app.post('/user', (req, res) => { - res.json({ name: 'Ruben' }, 201) -}) +app.post("/user", (req, res) => { + res.json({ name: "Ruben" }, 201); +}); // v5 -app.post('/user', (req, res) => { - res.status(201).json({ name: 'Ruben' }) -}) +app.post("/user", (req, res) => { + res.status(201).json({ name: "Ruben" }); +}); ```

      res.jsonp(obj, status)

      @@ -231,14 +231,14 @@ Express 5는 `res.jsonp(obj, status)` 시그니처를 더 이상 지원하지 ```js // v4 -app.post('/user', (req, res) => { - res.jsonp({ name: 'Ruben' }, 201) -}) +app.post("/user", (req, res) => { + res.jsonp({ name: "Ruben" }, 201); +}); // v5 -app.post('/user', (req, res) => { - res.status(201).jsonp({ name: 'Ruben' }) -}) +app.post("/user", (req, res) => { + res.status(201).jsonp({ name: "Ruben" }); +}); ```

      res.redirect(url, status)

      @@ -249,14 +249,14 @@ Express 5는 `res.send(obj, status)` 시그니처를 더 이상 지원하지 않 ```js // v4 -app.get('/user', (req, res) => { - res.redirect('/users', 301) -}) +app.get("/user", (req, res) => { + res.redirect("/users", 301); +}); // v5 -app.get('/user', (req, res) => { - res.redirect(301, '/users') -}) +app.get("/user", (req, res) => { + res.redirect(301, "/users"); +}); ```

      res.redirect('back') and res.location('back')

      @@ -266,7 +266,7 @@ Express 5 no longer supports the magic string `back` in the `res.redirect()` and {% capture codemod-magic-redirect %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod magic-redirect ``` @@ -276,14 +276,14 @@ npx @expressjs/codemod magic-redirect ```js // v4 -app.get('/user', (req, res) => { - res.redirect('back') -}) +app.get("/user", (req, res) => { + res.redirect("back"); +}); // v5 -app.get('/user', (req, res) => { - res.redirect(req.get('Referrer') || '/') -}) +app.get("/user", (req, res) => { + res.redirect(req.get("Referrer") || "/"); +}); ```

      res.send(body, status)

      @@ -294,14 +294,14 @@ Express 5 no longer supports the signature `res.send(obj, status)`. Instead, set ```js // v4 -app.get('/user', (req, res) => { - res.send({ name: 'Ruben' }, 200) -}) +app.get("/user", (req, res) => { + res.send({ name: "Ruben" }, 200); +}); // v5 -app.get('/user', (req, res) => { - res.status(200).send({ name: 'Ruben' }) -}) +app.get("/user", (req, res) => { + res.status(200).send({ name: "Ruben" }); +}); ```

      res.send(status)

      @@ -313,14 +313,14 @@ Express 5는 \*`status`\*가 숫자인 res.send(status) ```js // v4 -app.get('/user', (req, res) => { - res.send(200) -}) +app.get("/user", (req, res) => { + res.send(200); +}); // v5 -app.get('/user', (req, res) => { - res.sendStatus(200) -}) +app.get("/user", (req, res) => { + res.sendStatus(200); +}); ```

      res.sendfile()

      @@ -340,14 +340,14 @@ Express 5에서 `res.sendfile()` 함수는 낙타 대문자(camel-cased) 버전 ```js // v4 -app.get('/user', (req, res) => { - res.sendfile('/path/to/file') -}) +app.get("/user", (req, res) => { + res.sendfile("/path/to/file"); +}); // v5 -app.get('/user', (req, res) => { - res.sendFile('/path/to/file') -}) +app.get("/user", (req, res) => { + res.sendFile("/path/to/file"); +}); ```

      router.param(fn)

      @@ -370,11 +370,11 @@ Use the [`mime-types` package](https://github.com/jshttp/mime-types) to work wit ```js // v4 -express.static.mime.lookup('json') +express.static.mime.lookup("json"); // v5 -const mime = require('mime-types') -mime.lookup('json') +const mime = require("mime-types"); +mime.lookup("json"); ```

      express:router debug logs

      @@ -406,14 +406,14 @@ Path route matching syntax is when a string is supplied as the first parameter t ```js // v4 -app.get('/*', async (req, res) => { - res.send('ok') -}) +app.get("/*", async (req, res) => { + res.send("ok"); +}); // v5 -app.get('/*splat', async (req, res) => { - res.send('ok') -}) +app.get("/*splat", async (req, res) => { + res.send("ok"); +}); ``` {% capture note_wildcard %} @@ -421,9 +421,9 @@ app.get('/*splat', async (req, res) => { ```js // v5 -app.get('/{*splat}', async (req, res) => { - res.send('ok') -}) +app.get("/{*splat}", async (req, res) => { + res.send("ok"); +}); ``` {% endcapture %} @@ -433,30 +433,30 @@ app.get('/{*splat}', async (req, res) => { ```js // v4 -app.get('/:file.:ext?', async (req, res) => { - res.send('ok') -}) +app.get("/:file.:ext?", async (req, res) => { + res.send("ok"); +}); // v5 -app.get('/:file{.:ext}', async (req, res) => { - res.send('ok') -}) +app.get("/:file{.:ext}", async (req, res) => { + res.send("ok"); +}); ``` - Regexp characters are not supported. 예를 들면 다음과 같습니다. ```js -app.get('/[discussion|page]/:slug', async (req, res) => { - res.status(200).send('ok') -}) +app.get("/[discussion|page]/:slug", async (req, res) => { + res.status(200).send("ok"); +}); ``` should be changed to: ```js -app.get(['/discussion/:slug', '/page/:slug'], async (req, res) => { - res.status(200).send('ok') -}) +app.get(["/discussion/:slug", "/page/:slug"], async (req, res) => { + res.status(200).send("ok"); +}); ``` - Some characters have been reserved to avoid confusion during upgrade (`()[]?+!`), use `\` to escape them. @@ -480,7 +480,7 @@ Example of breaking code: ```js // v4 -app.use(express.static('public')) +app.use(express.static("public")); ``` After migrating to Express 5, a request to `/.well-known/assetlinks.json` will result in a **404 Not Found**. @@ -489,8 +489,11 @@ To fix this, serve specific dot-directories explicitly using the `dotfiles: "all ```js // v5 -app.use('/.well-known', express.static('public/.well-known', { dotfiles: 'allow' })) -app.use(express.static('public')) +app.use( + "/.well-known", + express.static("public/.well-known", { dotfiles: "allow" }), +); +app.use(express.static("public")); ``` This approach allows you to safely serve only the intended dot-directories while keeping the default secure behavior for other dotfiles, which remain inaccessible. @@ -501,12 +504,12 @@ In Express 5, the `app.listen` method will invoke the user-provided callback fun 예를 들면 다음과 같습니다. ```js -const server = app.listen(8080, '0.0.0.0', (error) => { +const server = app.listen(8080, "0.0.0.0", (error) => { if (error) { - throw error // e.g. EADDRINUSE + throw error; // e.g. EADDRINUSE } - console.log(`Listening on ${JSON.stringify(server.address())}`) -}) + console.log(`Listening on ${JSON.stringify(server.address())}`); +}); ```

      app.router

      @@ -530,11 +533,11 @@ The `req.params` object now has a **null prototype** when using string paths. Ho Wildcards (e.g., `/*splat`) capture path segments as an array instead of a single string. ```js -app.get('/*splat', (req, res) => { +app.get("/*splat", (req, res) => { // GET /foo/bar - console.dir(req.params) + console.dir(req.params); // => [Object: null prototype] { splat: [ 'foo', 'bar' ] } -}) +}); ``` **Unmatched parameters are omitted:** @@ -543,25 +546,25 @@ In Express 4, unmatched wildcards were empty strings (`''`) and optional `:` par ```js // v4: unmatched wildcard is empty string -app.get('/*', (req, res) => { +app.get("/*", (req, res) => { // GET / - console.dir(req.params) + console.dir(req.params); // => { '0': '' } -}) +}); // v4: unmatched optional param is undefined -app.get('/:file.:ext?', (req, res) => { +app.get("/:file.:ext?", (req, res) => { // GET /image - console.dir(req.params) + console.dir(req.params); // => { file: 'image', ext: undefined } -}) +}); // v5: unmatched optional param is omitted -app.get('/:file{.:ext}', (req, res) => { +app.get("/:file{.:ext}", (req, res) => { // GET /image - console.dir(req.params) + console.dir(req.params); // => [Object: null prototype] { file: 'image' } -}) +}); ```

      req.query

      diff --git a/legacy/pt-br/guide/migrating-5.md b/legacy/pt-br/guide/migrating-5.md index 3279493188..e4a65d899d 100644 --- a/legacy/pt-br/guide/migrating-5.md +++ b/legacy/pt-br/guide/migrating-5.md @@ -115,7 +115,7 @@ legalmente ser usadas como nomes de propriedades. {% capture codemod-deprecated-signatures %} Você pode substituir as assinaturas obsoletas pelo seguinte comando: -```plain-text +```plaintext npx @expressjs/codemod v4-deprecated-signatures ``` @@ -125,14 +125,14 @@ npx @expressjs/codemod v4-deprecated-signatures ```js // v4 -app.del('/user/:id', (req, res) => { - res.send(`DELETE /user/${req.params.id}`) -}) +app.del("/user/:id", (req, res) => { + res.send(`DELETE /user/${req.params.id}`); +}); // v5 -app.delete('/user/:id', (req, res) => { - res.send(`DELETE /user/${req.params.id}`) -}) +app.delete("/user/:id", (req, res) => { + res.send(`DELETE /user/${req.params.id}`); +}); ```

      app.param(fn)

      @@ -145,7 +145,7 @@ foi descontinuada desde a v4.11.0, e o Express 5 não a suporta mais de nenhuma Os seguintes nomes de métodos podem ser pluralizados. No Express 4, o uso dos métodos antigos resultava em um aviso de -descontinuação. O Express 5 não os suporta mais de forma nenhuma: Express 5 no longer supports them at all: +descontinuação. O Express 5 não os suporta mais de forma nenhuma: Express 5 no longer supports them at all: `req.acceptsLanguage()` é substituído por `req.acceptsLanguages()`. @@ -156,7 +156,7 @@ descontinuação. O Express 5 não os suporta mais de forma nenhuma: Express 5 {% capture codemod-pluralized-methods %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod pluralized-methods ``` @@ -166,22 +166,22 @@ npx @expressjs/codemod pluralized-methods ```js // v4 -app.all('/', (req, res) => { - req.acceptsCharset('utf-8') - req.acceptsEncoding('br') - req.acceptsLanguage('en') +app.all("/", (req, res) => { + req.acceptsCharset("utf-8"); + req.acceptsEncoding("br"); + req.acceptsLanguage("en"); // ... -}) +}); // v5 -app.all('/', (req, res) => { - req.acceptsCharsets('utf-8') - req.acceptsEncodings('br') - req.acceptsLanguages('en') +app.all("/", (req, res) => { + req.acceptsCharsets("utf-8"); + req.acceptsEncodings("br"); + req.acceptsLanguages("en"); // ... -}) +}); ```

      Dois pontos no começo (:) do nome do app.param(name, fn)

      @@ -205,7 +205,7 @@ Este é um método potencialmente confuso e perigoso de recuperação de dados d {% capture codemod-req-param %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod req-param ``` @@ -215,22 +215,22 @@ npx @expressjs/codemod req-param ```js // v4 -app.post('/user', (req, res) => { - const id = req.param('id') - const body = req.param('body') - const query = req.param('query') +app.post("/user", (req, res) => { + const id = req.param("id"); + const body = req.param("body"); + const query = req.param("query"); // ... -}) +}); // v5 -app.post('/user', (req, res) => { - const id = req.params.id - const body = req.body - const query = req.query +app.post("/user", (req, res) => { + const id = req.params.id; + const body = req.body; + const query = req.query; // ... -}) +}); ```

      res.json(obj, status)

      @@ -243,14 +243,14 @@ invés disso, configure o status e então encadeie-o ao método `res.json()` ass ```js // v4 -app.post('/user', (req, res) => { - res.json({ name: 'Ruben' }, 201) -}) +app.post("/user", (req, res) => { + res.json({ name: "Ruben" }, 201); +}); // v5 -app.post('/user', (req, res) => { - res.status(201).json({ name: 'Ruben' }) -}) +app.post("/user", (req, res) => { + res.status(201).json({ name: "Ruben" }); +}); ```

      res.jsonp(obj, status)

      @@ -262,14 +262,14 @@ O Express 5 não suporta mais a assinatura `res.jsonp(obj, status)`. Ao invés d ```js // v4 -app.post('/user', (req, res) => { - res.jsonp({ name: 'Ruben' }, 201) -}) +app.post("/user", (req, res) => { + res.jsonp({ name: "Ruben" }, 201); +}); // v5 -app.post('/user', (req, res) => { - res.status(201).jsonp({ name: 'Ruben' }) -}) +app.post("/user", (req, res) => { + res.status(201).jsonp({ name: "Ruben" }); +}); ```

      res.redirect(url, status)

      @@ -281,14 +281,14 @@ O Express 5 não suporta mais a assinatura `res.send(obj, status)`. Ao invés di ```js // v4 -app.get('/user', (req, res) => { - res.redirect('/users', 301) -}) +app.get("/user", (req, res) => { + res.redirect("/users", 301); +}); // v5 -app.get('/user', (req, res) => { - res.redirect(301, '/users') -}) +app.get("/user", (req, res) => { + res.redirect(301, "/users"); +}); ```

      res.redirect('back') and res.location('back')

      @@ -298,7 +298,7 @@ Express 5 no longer supports the magic string `back` in the `res.redirect()` and {% capture codemod-magic-redirect %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod magic-redirect ``` @@ -308,14 +308,14 @@ npx @expressjs/codemod magic-redirect ```js // v4 -app.get('/user', (req, res) => { - res.redirect('back') -}) +app.get("/user", (req, res) => { + res.redirect("back"); +}); // v5 -app.get('/user', (req, res) => { - res.redirect(req.get('Referrer') || '/') -}) +app.get("/user", (req, res) => { + res.redirect(req.get("Referrer") || "/"); +}); ```

      res.send(body, status)

      @@ -326,14 +326,14 @@ Express 5 no longer supports the signature `res.send(obj, status)`. Instead, set ```js // v4 -app.get('/user', (req, res) => { - res.send({ name: 'Ruben' }, 200) -}) +app.get("/user", (req, res) => { + res.send({ name: "Ruben" }, 200); +}); // v5 -app.get('/user', (req, res) => { - res.status(200).send({ name: 'Ruben' }) -}) +app.get("/user", (req, res) => { + res.status(200).send({ name: "Ruben" }); +}); ```

      res.send(status)

      @@ -341,7 +341,7 @@ app.get('/user', (req, res) => { O Express 5 não suporta mais a assinatura res.send(status), onde _`status`_ é um número. Ao invés disso, use a função `res.sendStatus(statusCode)`, que configura o código -do status do cabeçalho de resposta HTTP e envia a versão de texto do +do status do cabeçalho de resposta HTTP e envia a versão de texto do código: "Não Encontrado", "Erro Interno de Servidor", e assim por diante. Se precisar enviar um número usando a função @@ -354,14 +354,14 @@ suportada. ```js // v4 -app.get('/user', (req, res) => { - res.send(200) -}) +app.get("/user", (req, res) => { + res.send(200); +}); // v5 -app.get('/user', (req, res) => { - res.sendStatus(200) -}) +app.get("/user", (req, res) => { + res.sendStatus(200); +}); ```

      res.sendfile()

      @@ -383,14 +383,14 @@ Express 5. ```js // v4 -app.get('/user', (req, res) => { - res.sendfile('/path/to/file') -}) +app.get("/user", (req, res) => { + res.sendfile("/path/to/file"); +}); // v5 -app.get('/user', (req, res) => { - res.sendFile('/path/to/file') -}) +app.get("/user", (req, res) => { + res.sendFile("/path/to/file"); +}); ```

      router.param(fn)

      @@ -414,11 +414,11 @@ Use the [`mime-types` package](https://github.com/jshttp/mime-types) to work wit ```js // v4 -express.static.mime.lookup('json') +express.static.mime.lookup("json"); // v5 -const mime = require('mime-types') -mime.lookup('json') +const mime = require("mime-types"); +mime.lookup("json"); ```

      express:router debug logs

      @@ -450,14 +450,14 @@ Path route matching syntax is when a string is supplied as the first parameter t ```js // v4 -app.get('/*', async (req, res) => { - res.send('ok') -}) +app.get("/*", async (req, res) => { + res.send("ok"); +}); // v5 -app.get('/*splat', async (req, res) => { - res.send('ok') -}) +app.get("/*splat", async (req, res) => { + res.send("ok"); +}); ``` {% capture note_wildcard %} @@ -465,9 +465,9 @@ app.get('/*splat', async (req, res) => { ```js // v5 -app.get('/{*splat}', async (req, res) => { - res.send('ok') -}) +app.get("/{*splat}", async (req, res) => { + res.send("ok"); +}); ``` {% endcapture %} @@ -477,30 +477,30 @@ app.get('/{*splat}', async (req, res) => { ```js // v4 -app.get('/:file.:ext?', async (req, res) => { - res.send('ok') -}) +app.get("/:file.:ext?", async (req, res) => { + res.send("ok"); +}); // v5 -app.get('/:file{.:ext}', async (req, res) => { - res.send('ok') -}) +app.get("/:file{.:ext}", async (req, res) => { + res.send("ok"); +}); ``` - Regexp characters are not supported. Por exemplo: ```js -app.get('/[discussion|page]/:slug', async (req, res) => { - res.status(200).send('ok') -}) +app.get("/[discussion|page]/:slug", async (req, res) => { + res.status(200).send("ok"); +}); ``` should be changed to: ```js -app.get(['/discussion/:slug', '/page/:slug'], async (req, res) => { - res.status(200).send('ok') -}) +app.get(["/discussion/:slug", "/page/:slug"], async (req, res) => { + res.status(200).send("ok"); +}); ``` - Some characters have been reserved to avoid confusion during upgrade (`()[]?+!`), use `\` to escape them. @@ -524,7 +524,7 @@ Example of breaking code: ```js // v4 -app.use(express.static('public')) +app.use(express.static("public")); ``` After migrating to Express 5, a request to `/.well-known/assetlinks.json` will result in a **404 Not Found**. @@ -533,8 +533,11 @@ To fix this, serve specific dot-directories explicitly using the `dotfiles: "all ```js // v5 -app.use('/.well-known', express.static('public/.well-known', { dotfiles: 'allow' })) -app.use(express.static('public')) +app.use( + "/.well-known", + express.static("public/.well-known", { dotfiles: "allow" }), +); +app.use(express.static("public")); ``` This approach allows you to safely serve only the intended dot-directories while keeping the default secure behavior for other dotfiles, which remain inaccessible. @@ -545,12 +548,12 @@ In Express 5, the `app.listen` method will invoke the user-provided callback fun Por exemplo: ```js -const server = app.listen(8080, '0.0.0.0', (error) => { +const server = app.listen(8080, "0.0.0.0", (error) => { if (error) { - throw error // e.g. EADDRINUSE + throw error; // e.g. EADDRINUSE } - console.log(`Listening on ${JSON.stringify(server.address())}`) -}) + console.log(`Listening on ${JSON.stringify(server.address())}`); +}); ```

      app.router

      @@ -579,11 +582,11 @@ The `req.params` object now has a **null prototype** when using string paths. Ho Wildcards (e.g., `/*splat`) capture path segments as an array instead of a single string. ```js -app.get('/*splat', (req, res) => { +app.get("/*splat", (req, res) => { // GET /foo/bar - console.dir(req.params) + console.dir(req.params); // => [Object: null prototype] { splat: [ 'foo', 'bar' ] } -}) +}); ``` **Unmatched parameters are omitted:** @@ -592,25 +595,25 @@ In Express 4, unmatched wildcards were empty strings (`''`) and optional `:` par ```js // v4: unmatched wildcard is empty string -app.get('/*', (req, res) => { +app.get("/*", (req, res) => { // GET / - console.dir(req.params) + console.dir(req.params); // => { '0': '' } -}) +}); // v4: unmatched optional param is undefined -app.get('/:file.:ext?', (req, res) => { +app.get("/:file.:ext?", (req, res) => { // GET /image - console.dir(req.params) + console.dir(req.params); // => { file: 'image', ext: undefined } -}) +}); // v5: unmatched optional param is omitted -app.get('/:file{.:ext}', (req, res) => { +app.get("/:file{.:ext}", (req, res) => { // GET /image - console.dir(req.params) + console.dir(req.params); // => [Object: null prototype] { file: 'image' } -}) +}); ```

      req.query

      @@ -633,7 +636,7 @@ The `res.vary` throws an error when the `field` argument is missing. In Express

      res.render()

      -Este método agora impinge comportamento assíncrono para todos +Este método agora impinge comportamento assíncrono para todos os mecanismos de visualização, evitando erros causados pelos mecanismos de visualização que tinham uma implementação síncrona e que violavam a interface recomendada. diff --git a/legacy/zh-cn/guide/migrating-5.md b/legacy/zh-cn/guide/migrating-5.md index 02d36227fe..161452eb57 100644 --- a/legacy/zh-cn/guide/migrating-5.md +++ b/legacy/zh-cn/guide/migrating-5.md @@ -99,7 +99,7 @@ Express 5 不再支持 `app.del()` 函数。如果使用此函数,将抛出错 {% capture codemod-deprecated-signatures %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod v4-deprecated-signatures ``` @@ -109,14 +109,14 @@ npx @expressjs/codemod v4-deprecated-signatures ```js // v4 -app.del('/user/:id', (req, res) => { - res.send(`DELETE /user/${req.params.id}`) -}) +app.del("/user/:id", (req, res) => { + res.send(`DELETE /user/${req.params.id}`); +}); // v5 -app.delete('/user/:id', (req, res) => { - res.send(`DELETE /user/${req.params.id}`) -}) +app.delete("/user/:id", (req, res) => { + res.send(`DELETE /user/${req.params.id}`); +}); ```

      app.param(fn)

      @@ -136,7 +136,7 @@ The following method names have been pluralized. In Express 4, using the old met {% capture codemod-pluralized-methods %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod pluralized-methods ``` @@ -146,22 +146,22 @@ npx @expressjs/codemod pluralized-methods ```js // v4 -app.all('/', (req, res) => { - req.acceptsCharset('utf-8') - req.acceptsEncoding('br') - req.acceptsLanguage('en') +app.all("/", (req, res) => { + req.acceptsCharset("utf-8"); + req.acceptsEncoding("br"); + req.acceptsLanguage("en"); // ... -}) +}); // v5 -app.all('/', (req, res) => { - req.acceptsCharsets('utf-8') - req.acceptsEncodings('br') - req.acceptsLanguages('en') +app.all("/", (req, res) => { + req.acceptsCharsets("utf-8"); + req.acceptsEncodings("br"); + req.acceptsLanguages("en"); // ... -}) +}); ```

      app.param(name, fn) 的名称中的前置冒号 (:)

      @@ -177,7 +177,7 @@ This potentially confusing and dangerous method of retrieving form data has been {% capture codemod-req-param %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod req-param ``` @@ -187,22 +187,22 @@ npx @expressjs/codemod req-param ```js // v4 -app.post('/user', (req, res) => { - const id = req.param('id') - const body = req.param('body') - const query = req.param('query') +app.post("/user", (req, res) => { + const id = req.param("id"); + const body = req.param("body"); + const query = req.param("query"); // ... -}) +}); // v5 -app.post('/user', (req, res) => { - const id = req.params.id - const body = req.body - const query = req.query +app.post("/user", (req, res) => { + const id = req.params.id; + const body = req.body; + const query = req.query; // ... -}) +}); ```

      res.json(obj, status)

      @@ -213,14 +213,14 @@ Express 5 不再支持特征符 `res.json(obj, status)`。而是设置状态, ```js // v4 -app.post('/user', (req, res) => { - res.json({ name: 'Ruben' }, 201) -}) +app.post("/user", (req, res) => { + res.json({ name: "Ruben" }, 201); +}); // v5 -app.post('/user', (req, res) => { - res.status(201).json({ name: 'Ruben' }) -}) +app.post("/user", (req, res) => { + res.status(201).json({ name: "Ruben" }); +}); ```

      res.jsonp(obj, status)

      @@ -231,14 +231,14 @@ Express 5 不再支持特征符 `res.jsonp(obj, status)`。而是设置状态, ```js // v4 -app.post('/user', (req, res) => { - res.jsonp({ name: 'Ruben' }, 201) -}) +app.post("/user", (req, res) => { + res.jsonp({ name: "Ruben" }, 201); +}); // v5 -app.post('/user', (req, res) => { - res.status(201).jsonp({ name: 'Ruben' }) -}) +app.post("/user", (req, res) => { + res.status(201).jsonp({ name: "Ruben" }); +}); ```

      res.redirect(url, status)

      @@ -249,14 +249,14 @@ Express 5 no longer supports the signature `res.redirect(url, status)`. Instead, ```js // v4 -app.get('/user', (req, res) => { - res.redirect('/users', 301) -}) +app.get("/user", (req, res) => { + res.redirect("/users", 301); +}); // v5 -app.get('/user', (req, res) => { - res.redirect(301, '/users') -}) +app.get("/user", (req, res) => { + res.redirect(301, "/users"); +}); ```

      res.redirect('back') and res.location('back')

      @@ -266,7 +266,7 @@ Express 5 no longer supports the magic string `back` in the `res.redirect()` and {% capture codemod-magic-redirect %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod magic-redirect ``` @@ -276,14 +276,14 @@ npx @expressjs/codemod magic-redirect ```js // v4 -app.get('/user', (req, res) => { - res.redirect('back') -}) +app.get("/user", (req, res) => { + res.redirect("back"); +}); // v5 -app.get('/user', (req, res) => { - res.redirect(req.get('Referrer') || '/') -}) +app.get("/user", (req, res) => { + res.redirect(req.get("Referrer") || "/"); +}); ```

      res.send(body, status)

      @@ -294,14 +294,14 @@ Express 5 不再支持特征符 `res.send(obj, status)`。而是设置状态, ```js // v4 -app.get('/user', (req, res) => { - res.send({ name: 'Ruben' }, 200) -}) +app.get("/user", (req, res) => { + res.send({ name: "Ruben" }, 200); +}); // v5 -app.get('/user', (req, res) => { - res.status(200).send({ name: 'Ruben' }) -}) +app.get("/user", (req, res) => { + res.status(200).send({ name: "Ruben" }); +}); ```

      res.send(status)

      @@ -313,14 +313,14 @@ If you need to send a number by using the `res.send()` function, quote the numbe ```js // v4 -app.get('/user', (req, res) => { - res.send(200) -}) +app.get("/user", (req, res) => { + res.send(200); +}); // v5 -app.get('/user', (req, res) => { - res.sendStatus(200) -}) +app.get("/user", (req, res) => { + res.sendStatus(200); +}); ```

      res.sendfile()

      @@ -340,14 +340,14 @@ app.get('/user', (req, res) => { ```js // v4 -app.get('/user', (req, res) => { - res.sendfile('/path/to/file') -}) +app.get("/user", (req, res) => { + res.sendfile("/path/to/file"); +}); // v5 -app.get('/user', (req, res) => { - res.sendFile('/path/to/file') -}) +app.get("/user", (req, res) => { + res.sendFile("/path/to/file"); +}); ```

      router.param(fn)

      @@ -370,11 +370,11 @@ Use the [`mime-types` package](https://github.com/jshttp/mime-types) to work wit ```js // v4 -express.static.mime.lookup('json') +express.static.mime.lookup("json"); // v5 -const mime = require('mime-types') -mime.lookup('json') +const mime = require("mime-types"); +mime.lookup("json"); ```

      express:router debug logs

      @@ -406,14 +406,14 @@ Path route matching syntax is when a string is supplied as the first parameter t ```js // v4 -app.get('/*', async (req, res) => { - res.send('ok') -}) +app.get("/*", async (req, res) => { + res.send("ok"); +}); // v5 -app.get('/*splat', async (req, res) => { - res.send('ok') -}) +app.get("/*splat", async (req, res) => { + res.send("ok"); +}); ``` {% capture note_wildcard %} @@ -421,9 +421,9 @@ app.get('/*splat', async (req, res) => { ```js // v5 -app.get('/{*splat}', async (req, res) => { - res.send('ok') -}) +app.get("/{*splat}", async (req, res) => { + res.send("ok"); +}); ``` {% endcapture %} @@ -433,30 +433,30 @@ app.get('/{*splat}', async (req, res) => { ```js // v4 -app.get('/:file.:ext?', async (req, res) => { - res.send('ok') -}) +app.get("/:file.:ext?", async (req, res) => { + res.send("ok"); +}); // v5 -app.get('/:file{.:ext}', async (req, res) => { - res.send('ok') -}) +app.get("/:file{.:ext}", async (req, res) => { + res.send("ok"); +}); ``` - Regexp characters are not supported. For example: ```js -app.get('/[discussion|page]/:slug', async (req, res) => { - res.status(200).send('ok') -}) +app.get("/[discussion|page]/:slug", async (req, res) => { + res.status(200).send("ok"); +}); ``` should be changed to: ```js -app.get(['/discussion/:slug', '/page/:slug'], async (req, res) => { - res.status(200).send('ok') -}) +app.get(["/discussion/:slug", "/page/:slug"], async (req, res) => { + res.status(200).send("ok"); +}); ``` - Some characters have been reserved to avoid confusion during upgrade (`()[]?+!`), use `\` to escape them. @@ -480,7 +480,7 @@ Example of breaking code: ```js // v4 -app.use(express.static('public')) +app.use(express.static("public")); ``` After migrating to Express 5, a request to `/.well-known/assetlinks.json` will result in a **404 Not Found**. @@ -489,8 +489,11 @@ To fix this, serve specific dot-directories explicitly using the `dotfiles: "all ```js // v5 -app.use('/.well-known', express.static('public/.well-known', { dotfiles: 'allow' })) -app.use(express.static('public')) +app.use( + "/.well-known", + express.static("public/.well-known", { dotfiles: "allow" }), +); +app.use(express.static("public")); ``` This approach allows you to safely serve only the intended dot-directories while keeping the default secure behavior for other dotfiles, which remain inaccessible. @@ -501,12 +504,12 @@ In Express 5, the `app.listen` method will invoke the user-provided callback fun For example: ```js -const server = app.listen(8080, '0.0.0.0', (error) => { +const server = app.listen(8080, "0.0.0.0", (error) => { if (error) { - throw error // e.g. EADDRINUSE + throw error; // e.g. EADDRINUSE } - console.log(`Listening on ${JSON.stringify(server.address())}`) -}) + console.log(`Listening on ${JSON.stringify(server.address())}`); +}); ```

      app.router

      @@ -530,11 +533,11 @@ The `req.params` object now has a **null prototype** when using string paths. Ho Wildcards (e.g., `/*splat`) capture path segments as an array instead of a single string. ```js -app.get('/*splat', (req, res) => { +app.get("/*splat", (req, res) => { // GET /foo/bar - console.dir(req.params) + console.dir(req.params); // => [Object: null prototype] { splat: [ 'foo', 'bar' ] } -}) +}); ``` **Unmatched parameters are omitted:** @@ -543,25 +546,25 @@ In Express 4, unmatched wildcards were empty strings (`''`) and optional `:` par ```js // v4: unmatched wildcard is empty string -app.get('/*', (req, res) => { +app.get("/*", (req, res) => { // GET / - console.dir(req.params) + console.dir(req.params); // => { '0': '' } -}) +}); // v4: unmatched optional param is undefined -app.get('/:file.:ext?', (req, res) => { +app.get("/:file.:ext?", (req, res) => { // GET /image - console.dir(req.params) + console.dir(req.params); // => { file: 'image', ext: undefined } -}) +}); // v5: unmatched optional param is omitted -app.get('/:file{.:ext}', (req, res) => { +app.get("/:file{.:ext}", (req, res) => { // GET /image - console.dir(req.params) + console.dir(req.params); // => [Object: null prototype] { file: 'image' } -}) +}); ```

      req.query

      diff --git a/legacy/zh-tw/guide/migrating-5.md b/legacy/zh-tw/guide/migrating-5.md index a85c65abb3..ab4f440e7b 100644 --- a/legacy/zh-tw/guide/migrating-5.md +++ b/legacy/zh-tw/guide/migrating-5.md @@ -99,7 +99,7 @@ Express 5 no longer supports the `app.del()` function. If you use this function, {% capture codemod-deprecated-signatures %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod v4-deprecated-signatures ``` @@ -109,14 +109,14 @@ npx @expressjs/codemod v4-deprecated-signatures ```js // v4 -app.del('/user/:id', (req, res) => { - res.send(`DELETE /user/${req.params.id}`) -}) +app.del("/user/:id", (req, res) => { + res.send(`DELETE /user/${req.params.id}`); +}); // v5 -app.delete('/user/:id', (req, res) => { - res.send(`DELETE /user/${req.params.id}`) -}) +app.delete("/user/:id", (req, res) => { + res.send(`DELETE /user/${req.params.id}`); +}); ```

      app.param(fn)

      @@ -136,7 +136,7 @@ The following method names have been pluralized. In Express 4, using the old met {% capture codemod-pluralized-methods %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod pluralized-methods ``` @@ -146,22 +146,22 @@ npx @expressjs/codemod pluralized-methods ```js // v4 -app.all('/', (req, res) => { - req.acceptsCharset('utf-8') - req.acceptsEncoding('br') - req.acceptsLanguage('en') +app.all("/", (req, res) => { + req.acceptsCharset("utf-8"); + req.acceptsEncoding("br"); + req.acceptsLanguage("en"); // ... -}) +}); // v5 -app.all('/', (req, res) => { - req.acceptsCharsets('utf-8') - req.acceptsEncodings('br') - req.acceptsLanguages('en') +app.all("/", (req, res) => { + req.acceptsCharsets("utf-8"); + req.acceptsEncodings("br"); + req.acceptsLanguages("en"); // ... -}) +}); ```

      app.param(name, fn) 名稱中的前導冒號 (:)

      @@ -177,7 +177,7 @@ This potentially confusing and dangerous method of retrieving form data has been {% capture codemod-req-param %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod req-param ``` @@ -187,22 +187,22 @@ npx @expressjs/codemod req-param ```js // v4 -app.post('/user', (req, res) => { - const id = req.param('id') - const body = req.param('body') - const query = req.param('query') +app.post("/user", (req, res) => { + const id = req.param("id"); + const body = req.param("body"); + const query = req.param("query"); // ... -}) +}); // v5 -app.post('/user', (req, res) => { - const id = req.params.id - const body = req.body - const query = req.query +app.post("/user", (req, res) => { + const id = req.params.id; + const body = req.body; + const query = req.query; // ... -}) +}); ```

      res.json(obj, status)

      @@ -213,14 +213,14 @@ Express 5 不再支援 `res.json(obj, status)` 簽章。請改以設定狀態, ```js // v4 -app.post('/user', (req, res) => { - res.json({ name: 'Ruben' }, 201) -}) +app.post("/user", (req, res) => { + res.json({ name: "Ruben" }, 201); +}); // v5 -app.post('/user', (req, res) => { - res.status(201).json({ name: 'Ruben' }) -}) +app.post("/user", (req, res) => { + res.status(201).json({ name: "Ruben" }); +}); ```

      res.jsonp(obj, status)

      @@ -231,14 +231,14 @@ Express 5 不再支援 `res.jsonp(obj, status)` 簽章。請改以設定狀態 ```js // v4 -app.post('/user', (req, res) => { - res.jsonp({ name: 'Ruben' }, 201) -}) +app.post("/user", (req, res) => { + res.jsonp({ name: "Ruben" }, 201); +}); // v5 -app.post('/user', (req, res) => { - res.status(201).jsonp({ name: 'Ruben' }) -}) +app.post("/user", (req, res) => { + res.status(201).jsonp({ name: "Ruben" }); +}); ```

      res.redirect(url, status)

      @@ -249,14 +249,14 @@ Express 5 no longer supports the signature `res.redirect(url, status)`. Instead, ```js // v4 -app.get('/user', (req, res) => { - res.redirect('/users', 301) -}) +app.get("/user", (req, res) => { + res.redirect("/users", 301); +}); // v5 -app.get('/user', (req, res) => { - res.redirect(301, '/users') -}) +app.get("/user", (req, res) => { + res.redirect(301, "/users"); +}); ```

      res.redirect('back') and res.location('back')

      @@ -266,7 +266,7 @@ Express 5 no longer supports the magic string `back` in the `res.redirect()` and {% capture codemod-magic-redirect %} You can replace the deprecated signatures with the following command: -```plain-text +```plaintext npx @expressjs/codemod magic-redirect ``` @@ -276,14 +276,14 @@ npx @expressjs/codemod magic-redirect ```js // v4 -app.get('/user', (req, res) => { - res.redirect('back') -}) +app.get("/user", (req, res) => { + res.redirect("back"); +}); // v5 -app.get('/user', (req, res) => { - res.redirect(req.get('Referrer') || '/') -}) +app.get("/user", (req, res) => { + res.redirect(req.get("Referrer") || "/"); +}); ```

      res.send(body, status)

      @@ -294,14 +294,14 @@ Express 5 不再支援 `res.send(obj, status)` 簽章。請改以設定狀態, ```js // v4 -app.get('/user', (req, res) => { - res.send({ name: 'Ruben' }, 200) -}) +app.get("/user", (req, res) => { + res.send({ name: "Ruben" }, 200); +}); // v5 -app.get('/user', (req, res) => { - res.status(200).send({ name: 'Ruben' }) -}) +app.get("/user", (req, res) => { + res.status(200).send({ name: "Ruben" }); +}); ```

      res.send(status)

      @@ -314,14 +314,14 @@ If you need to send a number by using the `res.send()` function, quote the numbe ```js // v4 -app.get('/user', (req, res) => { - res.send(200) -}) +app.get("/user", (req, res) => { + res.send(200); +}); // v5 -app.get('/user', (req, res) => { - res.sendStatus(200) -}) +app.get("/user", (req, res) => { + res.sendStatus(200); +}); ```

      res.sendfile()

      @@ -341,14 +341,14 @@ app.get('/user', (req, res) => { ```js // v4 -app.get('/user', (req, res) => { - res.sendfile('/path/to/file') -}) +app.get("/user", (req, res) => { + res.sendfile("/path/to/file"); +}); // v5 -app.get('/user', (req, res) => { - res.sendFile('/path/to/file') -}) +app.get("/user", (req, res) => { + res.sendFile("/path/to/file"); +}); ```

      router.param(fn)

      @@ -371,11 +371,11 @@ Use the [`mime-types` package](https://github.com/jshttp/mime-types) to work wit ```js // v4 -express.static.mime.lookup('json') +express.static.mime.lookup("json"); // v5 -const mime = require('mime-types') -mime.lookup('json') +const mime = require("mime-types"); +mime.lookup("json"); ```

      express:router debug logs

      @@ -407,14 +407,14 @@ Path route matching syntax is when a string is supplied as the first parameter t ```js // v4 -app.get('/*', async (req, res) => { - res.send('ok') -}) +app.get("/*", async (req, res) => { + res.send("ok"); +}); // v5 -app.get('/*splat', async (req, res) => { - res.send('ok') -}) +app.get("/*splat", async (req, res) => { + res.send("ok"); +}); ``` {% capture note_wildcard %} @@ -422,9 +422,9 @@ app.get('/*splat', async (req, res) => { ```js // v5 -app.get('/{*splat}', async (req, res) => { - res.send('ok') -}) +app.get("/{*splat}", async (req, res) => { + res.send("ok"); +}); ``` {% endcapture %} @@ -434,30 +434,30 @@ app.get('/{*splat}', async (req, res) => { ```js // v4 -app.get('/:file.:ext?', async (req, res) => { - res.send('ok') -}) +app.get("/:file.:ext?", async (req, res) => { + res.send("ok"); +}); // v5 -app.get('/:file{.:ext}', async (req, res) => { - res.send('ok') -}) +app.get("/:file{.:ext}", async (req, res) => { + res.send("ok"); +}); ``` - Regexp characters are not supported. For example: ```js -app.get('/[discussion|page]/:slug', async (req, res) => { - res.status(200).send('ok') -}) +app.get("/[discussion|page]/:slug", async (req, res) => { + res.status(200).send("ok"); +}); ``` should be changed to: ```js -app.get(['/discussion/:slug', '/page/:slug'], async (req, res) => { - res.status(200).send('ok') -}) +app.get(["/discussion/:slug", "/page/:slug"], async (req, res) => { + res.status(200).send("ok"); +}); ``` - Some characters have been reserved to avoid confusion during upgrade (`()[]?+!`), use `\` to escape them. @@ -481,7 +481,7 @@ Example of breaking code: ```js // v4 -app.use(express.static('public')) +app.use(express.static("public")); ``` After migrating to Express 5, a request to `/.well-known/assetlinks.json` will result in a **404 Not Found**. @@ -490,8 +490,11 @@ To fix this, serve specific dot-directories explicitly using the `dotfiles: "all ```js // v5 -app.use('/.well-known', express.static('public/.well-known', { dotfiles: 'allow' })) -app.use(express.static('public')) +app.use( + "/.well-known", + express.static("public/.well-known", { dotfiles: "allow" }), +); +app.use(express.static("public")); ``` This approach allows you to safely serve only the intended dot-directories while keeping the default secure behavior for other dotfiles, which remain inaccessible. @@ -502,12 +505,12 @@ In Express 5, the `app.listen` method will invoke the user-provided callback fun For example: ```js -const server = app.listen(8080, '0.0.0.0', (error) => { +const server = app.listen(8080, "0.0.0.0", (error) => { if (error) { - throw error // e.g. EADDRINUSE + throw error; // e.g. EADDRINUSE } - console.log(`Listening on ${JSON.stringify(server.address())}`) -}) + console.log(`Listening on ${JSON.stringify(server.address())}`); +}); ```

      app.router

      @@ -532,11 +535,11 @@ The `req.params` object now has a **null prototype** when using string paths. Ho Wildcards (e.g., `/*splat`) capture path segments as an array instead of a single string. ```js -app.get('/*splat', (req, res) => { +app.get("/*splat", (req, res) => { // GET /foo/bar - console.dir(req.params) + console.dir(req.params); // => [Object: null prototype] { splat: [ 'foo', 'bar' ] } -}) +}); ``` **Unmatched parameters are omitted:** @@ -545,25 +548,25 @@ In Express 4, unmatched wildcards were empty strings (`''`) and optional `:` par ```js // v4: unmatched wildcard is empty string -app.get('/*', (req, res) => { +app.get("/*", (req, res) => { // GET / - console.dir(req.params) + console.dir(req.params); // => { '0': '' } -}) +}); // v4: unmatched optional param is undefined -app.get('/:file.:ext?', (req, res) => { +app.get("/:file.:ext?", (req, res) => { // GET /image - console.dir(req.params) + console.dir(req.params); // => { file: 'image', ext: undefined } -}) +}); // v5: unmatched optional param is omitted -app.get('/:file{.:ext}', (req, res) => { +app.get("/:file{.:ext}", (req, res) => { // GET /image - console.dir(req.params) + console.dir(req.params); // => [Object: null prototype] { file: 'image' } -}) +}); ```

      req.query

      From 7f8829d1bb371f5cc327b91ae93e3b7faba3b596 Mon Sep 17 00:00:00 2001 From: Francesca Giannino Date: Tue, 24 Feb 2026 14:27:47 +0100 Subject: [PATCH 05/17] feat: tablet/desktop header and sidebar navigation (#2185) Co-authored-by: shubham oulkar <91728992+ShubhamOulkar@users.noreply.github.com> --- astro/package-lock.json | 30 +- .../components/patterns/Header/Header.astro | 23 +- .../src/components/patterns/Header/Header.css | 45 +- .../SearchTrigger/SearchTrigger.astro | 33 + .../patterns/SearchTrigger/SearchTrigger.css | 70 + .../components/patterns/Sidebar/Sidebar.astro | 29 +- .../components/patterns/Sidebar/Sidebar.css | 213 +- .../patterns/Sidebar/SidebarController.ts | 256 ++- .../patterns/Sidebar/SidebarFocusTrap.ts | 5 - .../patterns/Sidebar/SidebarItemsList.astro | 88 +- .../patterns/Sidebar/SidebarMenu.astro | 296 +-- .../patterns/Sidebar/SidebarNavItem.astro | 11 +- .../src/components/patterns/Sidebar/utils.ts | 220 +- .../ThemeSwitcher/ThemeSwitcher.astro | 25 - .../patterns/ThemeSwitcher/ThemeSwitcher.css | 1 - .../VersionSwitcher/VersionSwitcher.css | 6 + astro/src/components/patterns/index.ts | 1 + .../components/primitives/Select/Select.css | 1 + astro/src/config/menu/main.ts | 2 +- .../docs/en/5x/api/response/overview.md | 135 ++ .../content/docs/en/5x/api/router/overview.md | 66 + astro/src/icons/logo-dark.svg | 1 + astro/src/icons/logo-light.svg | 1 + astro/src/layouts/DocLayout.astro | 5 +- astro/src/layouts/Layout.astro | 33 +- astro/src/pages/[lang]/blog/index.astro | 9 +- astro/src/pages/[lang]/ds-foundations.astro | 1792 +++++++++-------- astro/src/pages/[lang]/index.astro | 24 +- astro/src/pages/[lang]/support/index.astro | 9 +- astro/src/styles/base/_global.css | 6 + astro/src/styles/tokens/_sizing.css | 5 + astro/src/styles/tokens/_zindex.css | 2 +- 32 files changed, 2100 insertions(+), 1343 deletions(-) create mode 100644 astro/src/components/patterns/SearchTrigger/SearchTrigger.astro create mode 100644 astro/src/components/patterns/SearchTrigger/SearchTrigger.css create mode 100644 astro/src/content/docs/en/5x/api/response/overview.md create mode 100644 astro/src/content/docs/en/5x/api/router/overview.md create mode 100644 astro/src/icons/logo-dark.svg create mode 100644 astro/src/icons/logo-light.svg diff --git a/astro/package-lock.json b/astro/package-lock.json index dc551f40c1..a45dd6bdfc 100644 --- a/astro/package-lock.json +++ b/astro/package-lock.json @@ -55,8 +55,7 @@ "version": "2.13.0", "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-2.13.0.tgz", "integrity": "sha512-mqVORhUJViA28fwHYaWmsXSzLO9osbdZ5ImUfxBarqsYdMlPbqAqGJCxsNzvppp1BEzc1mJNjOVvQqeDN8Vspw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@astrojs/internal-helpers": { "version": "0.7.5", @@ -246,7 +245,6 @@ "url": "https://opencollective.com/csstools" } ], - "peer": true, "engines": { "node": ">=20.19.0" }, @@ -269,7 +267,6 @@ "url": "https://opencollective.com/csstools" } ], - "peer": true, "engines": { "node": ">=20.19.0" } @@ -2133,6 +2130,15 @@ "@types/unist": "*" } }, + "node_modules/@types/node": { + "version": "25.3.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.0.tgz", + "integrity": "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A==", + "optional": true, + "dependencies": { + "undici-types": "~7.18.0" + } + }, "node_modules/@types/unist": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", @@ -2194,7 +2200,6 @@ "integrity": "sha512-nm3cvFN9SqZGXjmw5bZ6cGmvJSyJPn0wU9gHAZZHDnZl2wF9PhHv78Xf06E0MaNk4zLVHL8hb2/c32XvyJOLQg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.53.1", "@typescript-eslint/types": "8.53.1", @@ -2417,7 +2422,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2712,7 +2716,6 @@ "resolved": "https://registry.npmjs.org/astro/-/astro-5.16.11.tgz", "integrity": "sha512-Z7kvkTTT5n6Hn5lCm6T3WU6pkxx84Hn25dtQ6dR7ATrBGq9eVa8EuB/h1S8xvaoVyCMZnIESu99Z9RJfdLRLDA==", "license": "MIT", - "peer": true, "dependencies": { "@astrojs/compiler": "^2.13.0", "@astrojs/internal-helpers": "0.7.5", @@ -4071,7 +4074,6 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -7909,7 +7911,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -8553,7 +8554,6 @@ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.55.3.tgz", "integrity": "sha512-y9yUpfQvetAjiDLtNMf1hL9NXchIJgWt6zIKeoB+tCd3npX08Eqfzg60V9DhIGVMtQ0AlMkFw5xa+AQ37zxnAA==", "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -9484,7 +9484,6 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -9564,9 +9563,9 @@ } }, "node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", "license": "MIT", "optional": true }, @@ -9896,7 +9895,6 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", @@ -10200,7 +10198,6 @@ "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", "devOptional": true, "license": "ISC", - "peer": true, "bin": { "yaml": "bin.mjs" }, @@ -10274,7 +10271,6 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/astro/src/components/patterns/Header/Header.astro b/astro/src/components/patterns/Header/Header.astro index 1c80bd4e87..3238f405b6 100644 --- a/astro/src/components/patterns/Header/Header.astro +++ b/astro/src/components/patterns/Header/Header.astro @@ -4,10 +4,10 @@ * * Main site header with logo and navigation menu */ -import { Icon } from 'astro-icon/components'; import './Header.css'; +import { Icon } from 'astro-icon/components'; import { BodyMd, Flex } from '@/components/primitives'; -import ThemeSwitcher from '../ThemeSwitcher/ThemeSwitcher.astro'; +import { ThemeSwitcher, SearchTrigger } from '@components/patterns'; ---
      @@ -24,24 +24,15 @@ import ThemeSwitcher from '../ThemeSwitcher/ThemeSwitcher.astro'; - - - + - - + + + + + diff --git a/astro/src/components/patterns/SearchTrigger/SearchTrigger.css b/astro/src/components/patterns/SearchTrigger/SearchTrigger.css new file mode 100644 index 0000000000..0e0f61330b --- /dev/null +++ b/astro/src/components/patterns/SearchTrigger/SearchTrigger.css @@ -0,0 +1,70 @@ +@layer patterns { + .search-trigger { + display: flex; + align-items: center; + gap: var(--space-6); + background-color: transparent; + border-radius: var(--radius-base); + border: 0; + color: var(--color-text-tertiary); + cursor: pointer; + transition: + background-color 0.2s, + border-color 0.2s; + + &:hover { + background-color: var(--color-bg-secondary); + border-color: var(--color-border-secondary); + outline: none; + } + + &:focus-visible { + outline: 1px solid var(--color-focus-ring); + } + + span { + line-height: var(--line-height-snug); + + @media (--xs-only) { + display: none; + } + } + + svg { + color: var(--color-icon-primary); + } + + @media (--md-up) { + border: 1px solid var(--color-border-secondary); + padding: var(--space-1-5) var(--space-1-5) var(--space-1-5) var(--space-2); + } + } + + .search-trigger-icon { + border-radius: var(--radius-base); + transition: background-color var(--duration-200) var(--ease-in-out); + flex-shrink: 0; + + @media (--xs-only) { + background-color: var(--color-bg-secondary); + padding: var(--space-2); + + &:hover { + background-color: var(--color-bg-mute); + } + } + } + + .search-trigger-shortcut { + margin-left: auto; + font-size: var(--font-size-xs); + color: var(--color-text-secondary); + background-color: var(--color-bg-secondary); + padding: var(--space-1) var(--space-2); + border-radius: var(--radius-base); + + @media (--xs-only) { + display: none; + } + } +} diff --git a/astro/src/components/patterns/Sidebar/Sidebar.astro b/astro/src/components/patterns/Sidebar/Sidebar.astro index c36fa295bd..d1148774a5 100644 --- a/astro/src/components/patterns/Sidebar/Sidebar.astro +++ b/astro/src/components/patterns/Sidebar/Sidebar.astro @@ -5,8 +5,14 @@ import { getLangFromUrl } from '@/i18n/utils'; import { mainMenu } from '@/config/menu/main'; import type { VersionConfig } from '@/components/patterns/VersionSwitcher/types'; import type { Menu } from '@/config/types'; +import { Icon } from 'astro-icon/components'; import SidebarMenu from './SidebarMenu.astro'; -import { detectVersionFromUrl } from './utils'; +import { + detectVersionFromUrl, + collectAllSubmenus, + calculateInitialActiveLevel, + type SubmenuData, +} from './utils'; type Props = HTMLAttributes<'div'> & { menu?: Menu; @@ -28,6 +34,10 @@ const { const lang = getLangFromUrl(Astro.url); const currentPath = Astro.url.pathname; const currentVersion = detectVersionFromUrl(currentPath, versions, defaultVersion); + +const submenus: SubmenuData[] = []; +collectAllSubmenus(menu, 0, 'root', '', [], currentVersion, submenus); +const initialActiveLevel = calculateInitialActiveLevel(submenus, currentPath, lang, currentVersion); --- @@ -46,7 +56,22 @@ const currentVersion = detectVersionFromUrl(currentPath, versions, defaultVersio > -
    ))} - {submenu.menu.items && submenu.menu.items.length > 0 && ( - - )} - - - - ); - })} - - ))} + {(submenu.menu.items?.length ?? 0) > 0 && ( + + )} + + + + ); + })} + + ))} + ) } diff --git a/astro/src/components/patterns/Sidebar/SidebarNavItem.astro b/astro/src/components/patterns/Sidebar/SidebarNavItem.astro index 23b7cff635..dfcd2a017e 100644 --- a/astro/src/components/patterns/Sidebar/SidebarNavItem.astro +++ b/astro/src/components/patterns/Sidebar/SidebarNavItem.astro @@ -24,6 +24,9 @@ const { targetLevel, showIcon = false, } = Astro.props; + +const isNested = variant === 'nested'; +const isRootSubmenu = variant === 'root'; --- { @@ -33,7 +36,7 @@ const { href={href} class:list={[ 'sidebar-nav-item', - variant === 'nested' && 'sidebar-nav-item--nested', + isNested && 'sidebar-nav-item--nested', isActive && 'sidebar-nav-item--active', ]} aria-label={item.ariaLabel} @@ -55,8 +58,10 @@ const { - - + @@ -34,10 +53,14 @@ const { -
    - - - + + + +
    + +
    +
    +
    diff --git a/astro/src/pages/[lang]/blog/index.astro b/astro/src/pages/[lang]/blog/index.astro index 429a130612..99e9d72b90 100644 --- a/astro/src/pages/[lang]/blog/index.astro +++ b/astro/src/pages/[lang]/blog/index.astro @@ -6,6 +6,7 @@ */ import Layout from '@layouts/Layout.astro'; import { languages } from '@i18n/ui'; +import { Container } from '@/components/primitives'; export function getStaticPaths() { return Object.keys(languages).map((lang) => ({ @@ -15,7 +16,9 @@ export function getStaticPaths() { --- -

    Express Blog

    -

    This is a temporary entry point page for the Express blog.

    -

    This page will be replaced with a proper blog layout soon.

    + +

    Express Blog

    +

    This is a temporary entry point page for the Express blog.

    +

    This page will be replaced with a proper blog layout soon.

    +
    diff --git a/astro/src/pages/[lang]/ds-foundations.astro b/astro/src/pages/[lang]/ds-foundations.astro index fed0dd64c5..67fc08fa5c 100644 --- a/astro/src/pages/[lang]/ds-foundations.astro +++ b/astro/src/pages/[lang]/ds-foundations.astro @@ -39,693 +39,700 @@ const lang = getLangFromUrl(Astro.url); --- -
    -

    Design System Foundations

    -
    - A living reference of all primitive components, tokens, and patterns. -
    -
    - - - - -
    -

    Typography

    - -
    -

    Headings

    -
    -

    Heading 1 — Page titles

    -

    Heading 2 — Section titles

    -

    Heading 3 — Subsections

    -

    Heading 4 — Minor headings

    -
    Heading 5 — Lead/intro paragraph text
    -
    -
    - -
    -

    Body Text

    -
    - Body — Default paragraph text. This is the standard size for documentation content and - general reading. - Body Medium — Slightly smaller than default body. Good for sidebars and secondary content. -

    - Body Small — Secondary text, captions, and helper text. Used for metadata and less - prominent content. -

    -

    Body Extra Small — Fine print, legal text, and timestamps.

    -
    -
    + +
    +

    Design System Foundations

    +
    + A living reference of all primitive components, tokens, and patterns. +
    +
    + + + + +
    +

    Typography

    -
    -

    Inline Code

    -
    - const express = require('express'); - Inline code: Use npm install express to install. -
    -
    - -
    -

    Weights

    - - Light 300 - Normal 400 - Medium 500 - Semibold 600 - Bold 700 - -
    - -
    -

    Polymorphic Rendering

    -
    -

    H1 styled, rendered as h2

    - Body text rendered as span (inline) +
    +

    Headings

    +
    +

    Heading 1 — Page titles

    +

    Heading 2 — Section titles

    +

    Heading 3 — Subsections

    +

    Heading 4 — Minor headings

    +
    Heading 5 — Lead/intro paragraph text
    +
    -
    - -
    -

    Type Scale

    -
    -
    - Aa - 6xl (54px) -
    -
    - Aa - 5xl (45px) -
    -
    - Aa - 4xl (36px) -
    -
    - Aa - 3xl (30px) -
    -
    - Aa - 2xl (24px) -
    -
    - Aa - xl (20px) -
    -
    - Aa - lg (18px) -
    -
    - Aa - base (16px) -
    -
    - Aa - sm (14px) -
    -
    - Aa - xs (12px) +
    +

    Body Text

    +
    + Body — Default paragraph text. This is the standard size for documentation content + and general reading. + Body Medium — Slightly smaller than default body. Good for sidebars and secondary + content. +

    + Body Small — Secondary text, captions, and helper text. Used for metadata and less + prominent content. +

    +

    Body Extra Small — Fine print, legal text, and timestamps.

    -
    -

    Usage

    - h2 styled as H1 -This is body text. It renders a paragraph by default. -const express = require('express'); - `} - /> -
    - - -
    -

    Iconography

    - - Icons are provided by astro-icon, a well-supported and officially - recommended package for Astro that gives access to 200,000+ icons from various icon sets. We - primarily use Fluent Icons (prefix fluent:). - +
    +

    Inline Code

    +
    + const express = require('express'); + Inline code: Use npm install express to install. +
    +
    -

    Examples

    - - - - - - +

    Weights

    + + Light 300 + Normal 400 + Medium 500 + Semibold 600 + Bold 700
    -

    Usage

    - - - `} - /> - - Browse available icons at Phosphor Icons or explore other icon sets at Iconify. - +

    Polymorphic Rendering

    +
    +

    H1 styled, rendered as h2

    + Body text rendered as span (inline) +
    -
    - - -
    -

    Color Tokens

    -

    Primitive tokens

    -
    -
    white
    -
    - gray-50 -
    -
    - gray-100 +

    Type Scale

    + +
    +
    + Aa + 6xl (54px)
    -
    - gray-200 +
    + Aa + 5xl (45px)
    -
    - gray-300 +
    + Aa + 4xl (36px)
    -
    - gray-400 +
    + Aa + 3xl (30px)
    -
    - gray-500 +
    + Aa + 2xl (24px)
    -
    - gray-600 +
    + Aa + xl (20px)
    -
    - gray-700 +
    + Aa + lg (18px)
    -
    - gray-800 +
    + Aa + base (16px)
    -
    - gray-900 +
    + Aa + sm (14px)
    -
    - gray-950 +
    + Aa + xs (12px)
    -
    black
    +
    +

    Usage

    -
    -
    sky-50
    -
    - sky-500 -
    -
    - sky-700 -
    -
    - sky-800 -
    -
    + -
    - green-50 -
    -
    - green-300 -
    -
    - green-500 -
    -
    - green-700 -
    -
    - green-900 -
    -
    +

    h2 styled as H1

    +This is body text. It renders a paragraph by default. +const express = require('express'); + `} + /> +
    -
    -
    - amber-50 -
    -
    - amber-300 -
    -
    - amber-500 -
    -
    - amber-600 -
    -
    - amber-700 -
    -
    - amber-900 -
    + +
    +

    Iconography

    + + Icons are provided by astro-icon, a well-supported and officially + recommended package for Astro that gives access to 200,000+ icons from various icon sets. We + primarily use Fluent Icons (prefix fluent:). + + +
    +

    Examples

    + + + + + + +
    -
    -
    - red-50 -
    -
    - red-300 -
    -
    - red-500 -
    -
    - red-600 -
    -
    - red-700 -
    -
    - red-900 -
    +
    +

    Usage

    + + + `} + /> + + Browse available icons at Phosphor Icons or explore other icon sets at Iconify. +
    -
    +
    + + +
    +

    Color Tokens

    -
    -

    Semantic tokens

    -
    -
    - bg-primary +

    Primitive tokens

    +
    +
    white
    +
    + gray-50
    -
    - bg-secondary +
    + gray-100
    -
    - bg-tertiary +
    + gray-200
    -
    - bg-inverse +
    + gray-300
    -
    - bg-mute +
    + gray-400
    -
    - bg-success +
    + gray-500
    -
    - bg-warning +
    + gray-600
    -
    - bg-error +
    + gray-700 +
    +
    + gray-800
    +
    + gray-900 +
    +
    + gray-950 +
    +
    black
    -
    -
    - text-primary + +
    +
    + sky-50
    -
    - text-secondary +
    + sky-500
    -
    - text-tertiary +
    + sky-700
    -
    - text-inverse +
    + sky-800
    -
    - text-mute +
    + +
    +
    + green-50
    -
    - text-success +
    + green-300
    -
    - text-warning +
    + green-500
    -
    - text-error +
    + green-700 +
    +
    + green-900
    - -
    -
    - border-primary + +
    +
    + amber-50
    -
    - border-secondary +
    + amber-300
    -
    - border-tertiary +
    + amber-500
    -
    - border-inverse +
    + amber-600
    -
    - border-mute +
    + amber-700
    -
    - border-success +
    + amber-900
    -
    - border-warning +
    + +
    +
    + red-50
    -
    - border-error +
    + red-300 +
    +
    + red-500 +
    +
    + red-600 +
    +
    + red-700 +
    +
    + red-900
    -
    -

    Usage

    - +
    +

    Semantic tokens

    +
    +
    + bg-primary +
    +
    + bg-secondary +
    +
    + bg-tertiary +
    +
    + bg-inverse +
    +
    + bg-mute +
    +
    + bg-success +
    +
    + bg-warning +
    +
    + bg-error +
    +
    +
    +
    + text-primary +
    +
    + text-secondary +
    +
    + text-tertiary +
    +
    + text-inverse +
    +
    + text-mute +
    +
    + text-success +
    +
    + text-warning +
    +
    + text-error +
    +
    + +
    +
    + border-primary +
    +
    + border-secondary +
    +
    + border-tertiary +
    +
    + border-inverse +
    +
    + border-mute +
    +
    + border-success +
    +
    + border-warning +
    +
    + border-error +
    +
    +
    +
    + +

    Usage

    + -
    + /> +
    - -
    -

    Spacing

    + +
    +

    Spacing

    -
    -

    Scale

    -
    -
    -
    +
    +

    Scale

    +
    +
    +
    +
    + 0.5 (2px)
    - 0.5 (2px) -
    -
    -
    +
    +
    +
    + 1 (4px)
    - 1 (4px) -
    -
    -
    +
    +
    +
    + 2 (8px)
    - 2 (8px) -
    -
    -
    +
    +
    +
    + 3 (12px)
    - 3 (12px) -
    -
    -
    +
    +
    +
    + 4 (16px)
    - 4 (16px) -
    -
    -
    +
    +
    +
    + 6 (24px)
    - 6 (24px) -
    -
    -
    +
    +
    +
    + 8 (32px)
    - 8 (32px) -
    -
    -
    +
    +
    +
    + 12 (48px)
    - 12 (48px) -
    -
    -
    +
    +
    +
    + 16 (64px)
    - 16 (64px)
    -
    -

    Usage

    - Usage + -
    + /> +
    - -
    -

    Buttons

    - - Interactive button component with support for variants, sizes, and polymorphic rendering. - + +
    +

    Buttons

    + + Interactive button component with support for variants, sizes, and polymorphic rendering. + -
    -

    Variants

    - - - - -
    +
    +

    Variants

    + + + + +
    -
    -

    Sizes

    - - - - - -
    +
    +

    Sizes

    + + + + + +
    -
    -

    Ghost Style

    - - - Can be used on light backgrounds - - - - Can be used on dark backgrounds - -
    +
    +

    Ghost Style

    + + + Can be used on light backgrounds + + + + Can be used on dark backgrounds + +
    -
    -

    With Icons

    - - - - -
    +
    +

    With Icons

    + + + + +
    -
    -

    Disabled State

    - - - - -
    +
    +

    Disabled State

    + + + + +
    -
    -

    As Link

    - - - - -
    +
    +

    As Link

    + + + + +
    -
    -

    Usage

    - +

    Usage

    + Click me `} - /> -
    -
    - - -
    -

    Grid & Layout

    - - 12-column responsive grid system with Grid, Col, and Flex components. - + /> +
    +
    -
    -

    Grid Component

    + +
    +

    Grid & Layout

    - Responsive 12-column grid. Columns cascade from xs → md → lg. + 12-column responsive grid system with Grid, Col, and Flex components. -
    - - -
    - xs=12, md=6, lg=4 -
    - - -
    - xs=12, md=6, lg=4 -
    - - -
    - xs=12, md=12, lg=4 -
    - -
    -
    -

    Usage

    - +

    Grid Component

    + + Responsive 12-column grid. Columns cascade from xs → md → lg. + +
    + + +
    + xs=12, md=6, lg=4 +
    + + +
    + xs=12, md=6, lg=4 +
    + + +
    + xs=12, md=12, lg=4 +
    + +
    +
    +

    Usage

    + @@ -734,30 +741,30 @@ import { Grid, Col } from "@components/primitives"; Content `} - /> -
    - -
    -

    Flex Component

    - Flexbox layouts for 1D directional content. -
    - -
    - Item 1 -
    -
    - Item 2 -
    -
    - Item 3 -
    -
    + />
    -

    Usage

    - +

    Flex Component

    + Flexbox layouts for 1D directional content. +
    + +
    + Item 1 +
    +
    + Item 2 +
    +
    + Item 3 +
    +
    +
    +

    Usage

    + @@ -765,51 +772,51 @@ import { Flex } from "@components/primitives";
    Item 2
    `} - /> -
    - -
    -

    FlexItem Component

    - Control flex-grow, flex-shrink, and flex-basis for individual flex children. - -

    Equal Columns

    -
    - - -
    flex="1"
    -
    - -
    flex="1"
    -
    - -
    flex="1"
    -
    -
    + />
    -

    Different Basis & Grow

    -
    - - -
    - FlexItem basis="1/4" -
    -
    - -
    - FlexItem (grow="1") -
    -
    -
    -
    +
    +

    FlexItem Component

    + Control flex-grow, flex-shrink, and flex-basis for individual flex children. -

    Usage

    - Equal Columns +
    + + +
    flex="1"
    +
    + +
    flex="1"
    +
    + +
    flex="1"
    +
    +
    +
    + +

    Different Basis & Grow

    +
    + + +
    + FlexItem basis="1/4" +
    +
    + +
    + FlexItem (grow="1") +
    +
    +
    +
    + +

    Usage

    + @@ -818,54 +825,54 @@ import { Flex, FlexItem } from "@components/primitives"; Flexible content `} - /> -
    + /> +
    -
    -

    Container

    - - Centered, responsive content wrapper with max-width and padding. - -
    - -
    - Content centered with max-width: 1440px, width: 90-95% -
    -
    +
    +

    Container

    + + Centered, responsive content wrapper with max-width and padding. + +
    + +
    + Content centered with max-width: 1440px, width: 90-95% +
    +
    +
    -
    -

    Usage

    - Usage +
    Your content here
    `} - /> -
    + /> + - -
    -

    Breakpoints

    + +
    +

    Breakpoints

    -
    -
    - Current: Mobile (xs) < 768px - Current: Tablet (md) 768px – 1439px - Current: Desktop (lg) ≥ 1440px +
    +
    + Current: Mobile (xs) < 768px + Current: Tablet (md) 768px – 1439px + Current: Desktop (lg) ≥ 1440px +
    -
    -
    -

    Usage

    - +

    Usage

    + -
    -
    + /> + +
    + + - + + @media (--xs-only) { + .ds-breakpoint--xs { + display: block; + } + } + + @media (--md-up) { + .ds-breakpoint--md { + display: block; + } + } + + @media (--lg-up) { + .ds-breakpoint--lg { + display: block; + } + } + + +
    diff --git a/astro/src/pages/[lang]/index.astro b/astro/src/pages/[lang]/index.astro index f7d5b83267..010d9dd988 100644 --- a/astro/src/pages/[lang]/index.astro +++ b/astro/src/pages/[lang]/index.astro @@ -1,5 +1,5 @@ --- -import { Body, H1 } from '@components/primitives'; +import { Body, Container, H1 } from '@components/primitives'; import Layout from '@layouts/Layout.astro'; import { getLangFromUrl, useTranslations } from '@i18n/utils'; import { languages } from '@i18n/ui'; @@ -15,16 +15,14 @@ const t = useTranslations(lang); --- -

    {t('home.welcome')}

    - This is a work-in-progress homepage. - + +

    {t('home.welcome')}

    + This is a work-in-progress homepage. + +
    diff --git a/astro/src/pages/[lang]/support/index.astro b/astro/src/pages/[lang]/support/index.astro index 2e6528dd12..30b6055d12 100644 --- a/astro/src/pages/[lang]/support/index.astro +++ b/astro/src/pages/[lang]/support/index.astro @@ -6,6 +6,7 @@ */ import Layout from '@layouts/Layout.astro'; import { languages } from '@i18n/ui'; +import { Container } from '@/components/primitives'; export function getStaticPaths() { return Object.keys(languages).map((lang) => ({ @@ -15,7 +16,9 @@ export function getStaticPaths() { --- -

    Express Version Support

    -

    This is a temporary entry point page for the Express support.

    -

    This page will be replaced with a proper support layout soon.

    + +

    Express Version Support

    +

    This is a temporary entry point page for the Express support.

    +

    This page will be replaced with a proper support layout soon.

    +
    diff --git a/astro/src/styles/base/_global.css b/astro/src/styles/base/_global.css index 8fbc8c092f..7aeb69293f 100644 --- a/astro/src/styles/base/_global.css +++ b/astro/src/styles/base/_global.css @@ -229,3 +229,9 @@ ol { margin: var(--space-body) 0; padding-left: var(--space-6); } + +main { + @media (--md-up) { + padding-top: var(--space-16); + } +} diff --git a/astro/src/styles/tokens/_sizing.css b/astro/src/styles/tokens/_sizing.css index 999ddbac0e..d0eaadb528 100644 --- a/astro/src/styles/tokens/_sizing.css +++ b/astro/src/styles/tokens/_sizing.css @@ -42,4 +42,9 @@ --size-72: 28.8rem; /* 288px */ --size-76: 30.4rem; /* 304px */ --size-80: 32rem; /* 320px */ + --size-84: 33.6rem; /* 336px */ + --size-88: 35.2rem; /* 352px */ + --size-92: 36.8rem; /* 368px */ + --size-96: 38.4rem; /* 384px */ + --size-100: 40rem; /* 400px */ } diff --git a/astro/src/styles/tokens/_zindex.css b/astro/src/styles/tokens/_zindex.css index 74c24f9d6e..931d16766f 100644 --- a/astro/src/styles/tokens/_zindex.css +++ b/astro/src/styles/tokens/_zindex.css @@ -6,6 +6,6 @@ :root { --z-index-sidebar-backdrop: 10; - --z-index-sidebar: 20; --z-index-header: 20; + --z-index-sidebar: 30; } From c927948416a391d276263cf23ce21837fed70fed Mon Sep 17 00:00:00 2001 From: Francesca Giannino Date: Wed, 25 Feb 2026 09:32:18 +0100 Subject: [PATCH 06/17] feat: redesign footer (#2196) Co-authored-by: shubham oulkar <91728992+ShubhamOulkar@users.noreply.github.com> --- astro/public/netlify-logo.svg | 1 + astro/public/openjs-logo-black.svg | 57 ++++++++ astro/public/openjs-logo-white.svg | 61 +++++++++ .../components/patterns/Footer/Footer.astro | 128 ++++++++++++++++++ .../src/components/patterns/Footer/Footer.css | 126 +++++++++++++++++ astro/src/components/patterns/index.ts | 1 + .../src/components/primitives/Grid/Grid.astro | 6 +- astro/src/components/primitives/Grid/Grid.css | 37 +++++ astro/src/components/primitives/Grid/types.ts | 4 + astro/src/icons/bsky.svg | 3 + astro/src/icons/github.svg | 3 + astro/src/icons/open-collective.svg | 4 + astro/src/icons/slack.svg | 6 + astro/src/icons/x.svg | 3 + astro/src/icons/youtube.svg | 3 + astro/src/layouts/Layout.astro | 13 +- astro/src/styles/base/_global.css | 4 + 17 files changed, 453 insertions(+), 7 deletions(-) create mode 100644 astro/public/netlify-logo.svg create mode 100644 astro/public/openjs-logo-black.svg create mode 100644 astro/public/openjs-logo-white.svg create mode 100644 astro/src/components/patterns/Footer/Footer.astro create mode 100644 astro/src/components/patterns/Footer/Footer.css create mode 100644 astro/src/icons/bsky.svg create mode 100644 astro/src/icons/github.svg create mode 100644 astro/src/icons/open-collective.svg create mode 100644 astro/src/icons/slack.svg create mode 100644 astro/src/icons/x.svg create mode 100644 astro/src/icons/youtube.svg diff --git a/astro/public/netlify-logo.svg b/astro/public/netlify-logo.svg new file mode 100644 index 0000000000..2edda22502 --- /dev/null +++ b/astro/public/netlify-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/astro/public/openjs-logo-black.svg b/astro/public/openjs-logo-black.svg new file mode 100644 index 0000000000..2c30e009a4 --- /dev/null +++ b/astro/public/openjs-logo-black.svg @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/astro/public/openjs-logo-white.svg b/astro/public/openjs-logo-white.svg new file mode 100644 index 0000000000..1a4436d3ea --- /dev/null +++ b/astro/public/openjs-logo-white.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/astro/src/components/patterns/Footer/Footer.astro b/astro/src/components/patterns/Footer/Footer.astro new file mode 100644 index 0000000000..0dd70b2d29 --- /dev/null +++ b/astro/src/components/patterns/Footer/Footer.astro @@ -0,0 +1,128 @@ +--- +/** + * Footer Component + * + * Main site footer with copyright and additional information + */ +import './Footer.css'; +import { Icon } from 'astro-icon/components'; +import { BodyMd, Col, Container, Grid } from '@/components/primitives'; +--- + + diff --git a/astro/src/components/patterns/Footer/Footer.css b/astro/src/components/patterns/Footer/Footer.css new file mode 100644 index 0000000000..45d8e292a5 --- /dev/null +++ b/astro/src/components/patterns/Footer/Footer.css @@ -0,0 +1,126 @@ +@layer patterns { + .footer { + background-color: var(--color-bg-primary); + text-align: center; + color: var(--color-text-secondary); + border-top: 1px solid var(--color-border-secondary); + + a { + text-decoration: none; + + &:hover { + text-decoration: underline; + } + } + } + + .footer__links { + list-style: none; + padding: 0; + margin: var(--space-4) 0; + + li { + display: inline; + margin: 0 var(--space-2); + } + + a { + color: var(--color-text-secondary); + font-size: var(--font-size-sm); + } + } + + .footer-top { + padding: var(--space-6) 0; + } + + .footer-bottom { + background-color: var(--color-bg-secondary); + padding: var(--space-6) 0; + } + + .footer__logo { + list-style: none; + padding: 0; + margin: 0; + + @media (--xs-only) { + li { + display: block; + text-align: center; + + a { + display: inline-block; + padding: var(--space-4) 0; + } + } + } + + @media (--md-up) { + display: flex; + align-items: center; + gap: var(--space-8); + } + } + + .footer__socials { + list-style: none; + padding: 0; + margin: 0; + display: flex; + align-items: center; + justify-content: center; + gap: var(--space-8); + + li { + display: inline; + } + + svg { + color: var(--color-icon-primary); + } + + svg path { + fill: currentColor; + } + + @media (--xs-only) { + padding: var(--space-4) 0 var(--space-6); + } + + @media (--md-up) { + justify-content: right; + gap: var(--space-10); + } + } + + .footer-logo-dark { + display: none; + } + + @media (prefers-color-scheme: dark) { + .footer-logo-light { + display: none; + } + + .footer-logo-dark { + display: block; + } + } + + [data-theme='dark'] .footer-logo-light { + display: none; + } + + [data-theme='dark'] .footer-logo-dark { + display: block; + } + + [data-theme='light'] .footer-logo-light { + display: block; + } + + [data-theme='light'] .footer-logo-dark { + display: none; + } +} diff --git a/astro/src/components/patterns/index.ts b/astro/src/components/patterns/index.ts index bdd36920a3..7c727f53e9 100644 --- a/astro/src/components/patterns/index.ts +++ b/astro/src/components/patterns/index.ts @@ -10,3 +10,4 @@ export { default as Sidebar } from './Sidebar/Sidebar.astro'; export { default as ThemeSwitcher } from './ThemeSwitcher/ThemeSwitcher.astro'; export { default as VersionSwitcher } from './VersionSwitcher/VersionSwitcher.astro'; export { default as SearchTrigger } from './SearchTrigger/SearchTrigger.astro'; +export { default as Footer } from './Footer/Footer.astro'; diff --git a/astro/src/components/primitives/Grid/Grid.astro b/astro/src/components/primitives/Grid/Grid.astro index dcc2da52c9..4a76cc8412 100644 --- a/astro/src/components/primitives/Grid/Grid.astro +++ b/astro/src/components/primitives/Grid/Grid.astro @@ -6,7 +6,7 @@ * Use with children for responsive column layouts. * * @example - * + * * Content * */ @@ -17,7 +17,7 @@ import type { GridProps } from './types'; type Props = GridProps & HTMLAttributes<'div'>; -const { gap, rowGap, columnGap, class: className, ...rest } = Astro.props; +const { gap, rowGap, columnGap, align, justify, class: className, ...rest } = Astro.props; ---
    + + diff --git a/astro/src/icons/github.svg b/astro/src/icons/github.svg new file mode 100644 index 0000000000..e5c5a6896e --- /dev/null +++ b/astro/src/icons/github.svg @@ -0,0 +1,3 @@ + + + diff --git a/astro/src/icons/open-collective.svg b/astro/src/icons/open-collective.svg new file mode 100644 index 0000000000..250d734a1f --- /dev/null +++ b/astro/src/icons/open-collective.svg @@ -0,0 +1,4 @@ + + + + diff --git a/astro/src/icons/slack.svg b/astro/src/icons/slack.svg new file mode 100644 index 0000000000..c0b1f1156a --- /dev/null +++ b/astro/src/icons/slack.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/astro/src/icons/x.svg b/astro/src/icons/x.svg new file mode 100644 index 0000000000..780ab6a346 --- /dev/null +++ b/astro/src/icons/x.svg @@ -0,0 +1,3 @@ + + + diff --git a/astro/src/icons/youtube.svg b/astro/src/icons/youtube.svg new file mode 100644 index 0000000000..e8db9ce050 --- /dev/null +++ b/astro/src/icons/youtube.svg @@ -0,0 +1,3 @@ + + + diff --git a/astro/src/layouts/Layout.astro b/astro/src/layouts/Layout.astro index da74eb59a8..5f6c5c2511 100644 --- a/astro/src/layouts/Layout.astro +++ b/astro/src/layouts/Layout.astro @@ -1,7 +1,7 @@ --- import '@styles/main.css'; import { Flex, FlexItem } from '@components/primitives'; -import { Sidebar } from '@/components/patterns'; +import { Footer, Sidebar } from '@/components/patterns'; import { Header } from '@/components/patterns'; interface Props { @@ -54,12 +54,15 @@ const {
    - + -
    - -
    + +
    + +
    +
    + diff --git a/astro/src/styles/base/_global.css b/astro/src/styles/base/_global.css index 7aeb69293f..b71b6c0478 100644 --- a/astro/src/styles/base/_global.css +++ b/astro/src/styles/base/_global.css @@ -231,7 +231,11 @@ ol { } main { + flex-grow: 1; + padding-bottom: var(--space-16); + @media (--md-up) { padding-top: var(--space-16); + padding-bottom: var(--space-32); } } From d8ed488febe25fa9b7478a4468e7282ed15a4dcf Mon Sep 17 00:00:00 2001 From: Francesca Giannino Date: Mon, 2 Mar 2026 10:15:41 +0100 Subject: [PATCH 07/17] feat(redesign): i18n language selection (#2197) Co-authored-by: shubham oulkar <91728992+ShubhamOulkar@users.noreply.github.com> Co-authored-by: Shubham Oulkar Co-authored-by: Sebastian Beltran --- .github/workflows/crowdin.yml | 30 + astro/CONTRIBUTING.md | 158 ++++- astro/astro.config.mjs | 1 + astro/crowdin.yml | 11 + astro/package-lock.json | 503 ++++++++++++++- astro/package.json | 3 +- .../patterns/Breadcrumbs/Breadcrumbs.astro | 5 +- .../components/patterns/Header/Header.astro | 20 +- .../src/components/patterns/Header/Header.css | 33 - .../LanguageSelect/LanguageSelect.astro | 65 ++ .../patterns/LanguageSelect/types.ts | 16 + .../SearchTrigger/SearchTrigger.astro | 8 +- .../components/patterns/Sidebar/Sidebar.astro | 8 +- .../patterns/Sidebar/SidebarItemsList.astro | 5 +- .../patterns/Sidebar/SidebarMenu.astro | 22 +- .../patterns/Sidebar/SidebarNavItem.astro | 13 +- .../src/components/patterns/Sidebar/utils.ts | 9 +- .../ThemeSwitcher/ThemeSwitcher.astro | 9 +- .../VersionSwitcher/VersionSwitcher.astro | 50 +- astro/src/components/patterns/index.ts | 1 + .../components/primitives/Select/Select.astro | 301 ++++++++- .../components/primitives/Select/Select.css | 182 ++++-- .../src/components/primitives/Select/types.ts | 30 +- .../primitives/Typography/BodyMd.astro | 7 +- astro/src/config/menu/api.ts | 209 +------ astro/src/config/menu/docs.ts | 34 +- astro/src/config/menu/main.ts | 21 +- astro/src/config/menu/middleware.ts | 4 +- astro/src/config/menu/resources.ts | 4 +- astro/src/content/docs/de/3x/api.md | 22 + .../docs/de/3x/api/application/app-VERB.md | 62 ++ .../docs/de/3x/api/application/app-all.md | 37 ++ .../de/3x/api/application/app-configure.md | 45 ++ .../docs/de/3x/api/application/app-disable.md | 14 + .../de/3x/api/application/app-disabled.md | 17 + .../docs/de/3x/api/application/app-enable.md | 14 + .../docs/de/3x/api/application/app-enabled.md | 17 + .../docs/de/3x/api/application/app-engine.md | 44 ++ .../docs/de/3x/api/application/app-get.md | 17 + .../docs/de/3x/api/application/app-listen.md | 41 ++ .../docs/de/3x/api/application/app-locals.md | 52 ++ .../docs/de/3x/api/application/app-param.md | 75 +++ .../docs/de/3x/api/application/app-render.md | 20 + .../docs/de/3x/api/application/app-routes.md | 34 + .../docs/de/3x/api/application/app-set.md | 14 + .../de/3x/api/application/app-settings.md | 19 + .../docs/de/3x/api/application/app-use.md | 94 +++ .../docs/de/3x/api/application/overview.md | 20 + astro/src/content/docs/de/3x/api/express.md | 19 + .../docs/de/3x/api/middleware/middleware.md | 34 + .../docs/de/3x/api/middleware/mw-basicAuth.md | 36 ++ .../de/3x/api/middleware/mw-bodyParser.md | 32 + .../docs/de/3x/api/middleware/mw-compress.md | 17 + .../de/3x/api/middleware/mw-cookieParser.md | 15 + .../de/3x/api/middleware/mw-cookieSession.md | 24 + .../docs/de/3x/api/middleware/mw-csrf.md | 20 + .../docs/de/3x/api/middleware/mw-directory.md | 21 + .../docs/de/3x/api/request/overview.md | 121 ++++ .../docs/de/3x/api/request/req-accepted.md | 19 + .../de/3x/api/request/req-acceptedCharsets.md | 13 + .../3x/api/request/req-acceptedLanguages.md | 13 + .../docs/de/3x/api/request/req-accepts.md | 41 ++ .../de/3x/api/request/req-acceptsCharset.md | 8 + .../de/3x/api/request/req-acceptsLanguage.md | 8 + .../docs/de/3x/api/request/req-body.md | 24 + .../docs/de/3x/api/request/req-cookies.md | 16 + .../docs/de/3x/api/request/req-files.md | 50 ++ .../docs/de/3x/api/request/req-fresh.md | 14 + .../docs/de/3x/api/request/req-header.md | 21 + .../docs/de/3x/api/request/req-host.md | 14 + .../content/docs/de/3x/api/request/req-ip.md | 14 + .../content/docs/de/3x/api/request/req-ips.md | 15 + .../content/docs/de/3x/api/request/req-is.md | 26 + .../docs/de/3x/api/request/req-originalUrl.md | 18 + .../docs/de/3x/api/request/req-param.md | 32 + .../docs/de/3x/api/request/req-params.md | 27 + .../docs/de/3x/api/request/req-path.md | 14 + .../docs/de/3x/api/request/req-protocol.md | 18 + .../docs/de/3x/api/request/req-query.md | 25 + .../content/docs/de/3x/api/request/req-res.md | 9 + .../docs/de/3x/api/request/req-route.md | 27 + .../docs/de/3x/api/request/req-secure.md | 13 + .../de/3x/api/request/req-signedCookies.md | 20 + .../docs/de/3x/api/request/req-stale.md | 14 + .../docs/de/3x/api/request/req-subdomains.md | 14 + .../content/docs/de/3x/api/request/req-xhr.md | 14 + .../docs/de/3x/api/response/res-attachment.md | 20 + .../docs/de/3x/api/response/res-charset.md | 14 + .../de/3x/api/response/res-clearCookie.md | 13 + .../docs/de/3x/api/response/res-cookie.md | 42 ++ .../docs/de/3x/api/response/res-download.md | 31 + .../docs/de/3x/api/response/res-format.md | 57 ++ .../docs/de/3x/api/response/res-get.md | 13 + .../docs/de/3x/api/response/res-json.md | 18 + .../docs/de/3x/api/response/res-jsonp.md | 38 ++ .../docs/de/3x/api/response/res-links.md | 22 + .../docs/de/3x/api/response/res-locals.md | 21 + .../docs/de/3x/api/response/res-location.md | 26 + .../docs/de/3x/api/response/res-redirect.md | 56 ++ .../docs/de/3x/api/response/res-render.md | 21 + .../docs/de/3x/api/response/res-req.md | 9 + .../docs/de/3x/api/response/res-send.md | 58 ++ .../docs/de/3x/api/response/res-sendfile.md | 35 ++ .../docs/de/3x/api/response/res-set.md | 20 + .../docs/de/3x/api/response/res-status.md | 12 + .../docs/de/3x/api/response/res-type.md | 20 + .../docs/de/3x/api/response/response.md | 89 +++ .../4x/advanced/best-practice-performance.md | 307 +++++++++ .../de/4x/advanced/best-practice-security.md | 282 +++++++++ .../advanced/developing-template-engines.md | 45 ++ .../advanced/healthcheck-graceful-shutdown.md | 30 + .../docs/de/4x/advanced/security-updates.md | 84 +++ astro/src/content/docs/de/4x/api.md | 26 + .../docs/de/4x/api/application/app-METHOD.md | 65 ++ .../docs/de/4x/api/application/app-all.md | 49 ++ .../4x/api/application/app-delete-method.md | 19 + .../docs/de/4x/api/application/app-disable.md | 17 + .../de/4x/api/application/app-disabled.md | 18 + .../docs/de/4x/api/application/app-enable.md | 15 + .../docs/de/4x/api/application/app-enabled.md | 18 + .../docs/de/4x/api/application/app-engine.md | 41 ++ .../de/4x/api/application/app-get-method.md | 20 + .../docs/de/4x/api/application/app-get.md | 18 + .../docs/de/4x/api/application/app-listen.md | 58 ++ .../docs/de/4x/api/application/app-locals.md | 39 ++ .../de/4x/api/application/app-mountpath.md | 50 ++ .../docs/de/4x/api/application/app-onmount.md | 35 ++ .../docs/de/4x/api/application/app-param.md | 165 +++++ .../docs/de/4x/api/application/app-path.md | 24 + .../de/4x/api/application/app-post-method.md | 19 + .../de/4x/api/application/app-put-method.md | 18 + .../docs/de/4x/api/application/app-render.md | 44 ++ .../docs/de/4x/api/application/app-route.md | 26 + .../docs/de/4x/api/application/app-set.md | 25 + .../de/4x/api/application/app-settings.md | 341 ++++++++++ .../docs/de/4x/api/application/app-use.md | 333 ++++++++++ .../docs/de/4x/api/application/overview.md | 128 ++++ .../docs/de/4x/api/express/express.json.md | 47 ++ .../content/docs/de/4x/api/express/express.md | 39 ++ .../docs/de/4x/api/express/express.raw.md | 45 ++ .../docs/de/4x/api/express/express.router.md | 29 + .../docs/de/4x/api/express/express.static.md | 102 +++ .../docs/de/4x/api/express/express.text.md | 46 ++ .../de/4x/api/express/express.urlencoded.md | 53 ++ .../docs/de/4x/api/request/overview.md | 160 +++++ .../docs/de/4x/api/request/req-accepts.md | 41 ++ .../de/4x/api/request/req-acceptsCharsets.md | 12 + .../de/4x/api/request/req-acceptsEncodings.md | 12 + .../de/4x/api/request/req-acceptsLanguages.md | 20 + .../content/docs/de/4x/api/request/req-app.md | 25 + .../docs/de/4x/api/request/req-base-url.md | 35 ++ .../docs/de/4x/api/request/req-body.md | 30 + .../docs/de/4x/api/request/req-cookies.md | 19 + .../docs/de/4x/api/request/req-fresh.md | 18 + .../content/docs/de/4x/api/request/req-get.md | 22 + .../docs/de/4x/api/request/req-hostname.md | 28 + .../content/docs/de/4x/api/request/req-ip.md | 17 + .../content/docs/de/4x/api/request/req-ips.md | 14 + .../content/docs/de/4x/api/request/req-is.md | 47 ++ .../docs/de/4x/api/request/req-method.md | 9 + .../docs/de/4x/api/request/req-originalUrl.md | 33 + .../docs/de/4x/api/request/req-param.md | 41 ++ .../docs/de/4x/api/request/req-params.md | 30 + .../docs/de/4x/api/request/req-path.md | 18 + .../docs/de/4x/api/request/req-protocol.md | 17 + .../docs/de/4x/api/request/req-query.md | 26 + .../docs/de/4x/api/request/req-range.md | 38 ++ .../content/docs/de/4x/api/request/req-res.md | 9 + .../docs/de/4x/api/request/req-route.md | 30 + .../docs/de/4x/api/request/req-secure.md | 13 + .../de/4x/api/request/req-signedCookies.md | 22 + .../docs/de/4x/api/request/req-stale.md | 14 + .../docs/de/4x/api/request/req-subdomains.md | 18 + .../content/docs/de/4x/api/request/req-xhr.md | 14 + .../docs/de/4x/api/response/overview.md | 135 ++++ .../docs/de/4x/api/response/res-app.md | 10 + .../docs/de/4x/api/response/res-append.md | 18 + .../docs/de/4x/api/response/res-attachment.md | 19 + .../de/4x/api/response/res-clearCookie.md | 27 + .../docs/de/4x/api/response/res-cookie.md | 95 +++ .../docs/de/4x/api/response/res-download.md | 62 ++ .../docs/de/4x/api/response/res-end.md | 15 + .../docs/de/4x/api/response/res-format.md | 57 ++ .../docs/de/4x/api/response/res-get.md | 14 + .../de/4x/api/response/res-headersSent.md | 16 + .../docs/de/4x/api/response/res-json.md | 18 + .../docs/de/4x/api/response/res-jsonp.md | 37 ++ .../docs/de/4x/api/response/res-links.md | 25 + .../docs/de/4x/api/response/res-locals.md | 33 + .../docs/de/4x/api/response/res-location.md | 30 + .../docs/de/4x/api/response/res-redirect.md | 65 ++ .../docs/de/4x/api/response/res-render.md | 50 ++ .../docs/de/4x/api/response/res-req.md | 9 + .../docs/de/4x/api/response/res-send.md | 44 ++ .../docs/de/4x/api/response/res-sendFile.md | 91 +++ .../docs/de/4x/api/response/res-sendStatus.md | 20 + .../docs/de/4x/api/response/res-set.md | 21 + .../docs/de/4x/api/response/res-status.md | 15 + .../docs/de/4x/api/response/res-type.md | 23 + .../docs/de/4x/api/response/res-vary.md | 12 + .../content/docs/de/4x/api/router/overview.md | 66 ++ .../docs/de/4x/api/router/router-METHOD.md | 47 ++ .../docs/de/4x/api/router/router-Router.md | 5 + .../docs/de/4x/api/router/router-all.md | 36 ++ .../docs/de/4x/api/router/router-param.md | 128 ++++ .../docs/de/4x/api/router/router-route.md | 54 ++ .../docs/de/4x/api/router/router-use.md | 112 ++++ .../docs/de/4x/api/router/routing-args.html | 58 ++ .../docs/de/4x/guide/behind-proxies.md | 90 +++ .../docs/de/4x/guide/database-integration.md | 509 +++++++++++++++ .../src/content/docs/de/4x/guide/debugging.md | 126 ++++ .../docs/de/4x/guide/error-handling.md | 289 +++++++++ .../content/docs/de/4x/guide/migrating-4.md | 554 +++++++++++++++++ .../content/docs/de/4x/guide/migrating-5.md | 587 ++++++++++++++++++ .../de/4x/guide/overriding-express-api.md | 70 +++ astro/src/content/docs/de/4x/guide/routing.md | 417 +++++++++++++ .../docs/de/4x/guide/using-middleware.md | 293 +++++++++ .../de/4x/guide/using-template-engines.md | 58 ++ .../docs/de/4x/guide/writing-middleware.md | 217 +++++++ .../docs/de/4x/starter/basic-routing.md | 63 ++ .../content/docs/de/4x/starter/examples.md | 16 + astro/src/content/docs/de/4x/starter/faq.md | 75 +++ .../content/docs/de/4x/starter/generator.md | 122 ++++ .../content/docs/de/4x/starter/hello-world.md | 42 ++ .../content/docs/de/4x/starter/installing.md | 48 ++ .../docs/de/4x/starter/static-files.md | 74 +++ .../5x/advanced/best-practice-performance.md | 307 +++++++++ .../de/5x/advanced/best-practice-security.md | 282 +++++++++ .../advanced/developing-template-engines.md | 45 ++ .../advanced/healthcheck-graceful-shutdown.md | 30 + .../docs/de/5x/advanced/security-updates.md | 84 +++ astro/src/content/docs/de/5x/api.md | 26 + .../docs/de/5x/api/application/app-METHOD.md | 65 ++ .../docs/de/5x/api/application/app-all.md | 49 ++ .../5x/api/application/app-delete-method.md | 19 + .../docs/de/5x/api/application/app-disable.md | 17 + .../de/5x/api/application/app-disabled.md | 18 + .../docs/de/5x/api/application/app-enable.md | 15 + .../docs/de/5x/api/application/app-enabled.md | 18 + .../docs/de/5x/api/application/app-engine.md | 41 ++ .../de/5x/api/application/app-get-method.md | 20 + .../docs/de/5x/api/application/app-get.md | 18 + .../docs/de/5x/api/application/app-listen.md | 56 ++ .../docs/de/5x/api/application/app-locals.md | 39 ++ .../de/5x/api/application/app-mountpath.md | 50 ++ .../docs/de/5x/api/application/app-onmount.md | 35 ++ .../docs/de/5x/api/application/app-param.md | 83 +++ .../docs/de/5x/api/application/app-path.md | 24 + .../de/5x/api/application/app-post-method.md | 19 + .../de/5x/api/application/app-put-method.md | 18 + .../docs/de/5x/api/application/app-render.md | 44 ++ .../docs/de/5x/api/application/app-route.md | 26 + .../docs/de/5x/api/application/app-router.md | 24 + .../docs/de/5x/api/application/app-set.md | 25 + .../de/5x/api/application/app-settings.md | 335 ++++++++++ .../docs/de/5x/api/application/app-use.md | 310 +++++++++ .../docs/de/5x/api/application/overview.md | 132 ++++ .../docs/de/5x/api/express/express.json.md | 43 ++ .../content/docs/de/5x/api/express/express.md | 39 ++ .../docs/de/5x/api/express/express.raw.md | 41 ++ .../docs/de/5x/api/express/express.router.md | 29 + .../docs/de/5x/api/express/express.static.md | 99 +++ .../docs/de/5x/api/express/express.text.md | 42 ++ .../de/5x/api/express/express.urlencoded.md | 45 ++ .../docs/de/5x/api/request/overview.md | 160 +++++ .../docs/de/5x/api/request/req-accepts.md | 41 ++ .../de/5x/api/request/req-acceptsCharsets.md | 12 + .../de/5x/api/request/req-acceptsEncodings.md | 12 + .../de/5x/api/request/req-acceptsLanguages.md | 20 + .../content/docs/de/5x/api/request/req-app.md | 25 + .../docs/de/5x/api/request/req-base-url.md | 35 ++ .../docs/de/5x/api/request/req-body.md | 30 + .../docs/de/5x/api/request/req-cookies.md | 19 + .../docs/de/5x/api/request/req-fresh.md | 18 + .../content/docs/de/5x/api/request/req-get.md | 22 + .../docs/de/5x/api/request/req-host.md | 27 + .../docs/de/5x/api/request/req-hostname.md | 28 + .../content/docs/de/5x/api/request/req-ip.md | 17 + .../content/docs/de/5x/api/request/req-ips.md | 14 + .../content/docs/de/5x/api/request/req-is.md | 36 ++ .../docs/de/5x/api/request/req-method.md | 9 + .../docs/de/5x/api/request/req-originalUrl.md | 33 + .../docs/de/5x/api/request/req-params.md | 44 ++ .../docs/de/5x/api/request/req-path.md | 18 + .../docs/de/5x/api/request/req-protocol.md | 17 + .../docs/de/5x/api/request/req-query.md | 26 + .../docs/de/5x/api/request/req-range.md | 38 ++ .../content/docs/de/5x/api/request/req-res.md | 9 + .../docs/de/5x/api/request/req-route.md | 36 ++ .../docs/de/5x/api/request/req-secure.md | 14 + .../de/5x/api/request/req-signedCookies.md | 22 + .../docs/de/5x/api/request/req-stale.md | 14 + .../docs/de/5x/api/request/req-subdomains.md | 18 + .../content/docs/de/5x/api/request/req-xhr.md | 14 + .../docs/de/5x/api/response/overview.md | 135 ++++ .../docs/de/5x/api/response/res-app.md | 10 + .../docs/de/5x/api/response/res-append.md | 21 + .../docs/de/5x/api/response/res-attachment.md | 19 + .../de/5x/api/response/res-clearCookie.md | 24 + .../docs/de/5x/api/response/res-cookie.md | 95 +++ .../docs/de/5x/api/response/res-download.md | 66 ++ .../docs/de/5x/api/response/res-end.md | 15 + .../docs/de/5x/api/response/res-format.md | 57 ++ .../docs/de/5x/api/response/res-get.md | 14 + .../de/5x/api/response/res-headersSent.md | 16 + .../docs/de/5x/api/response/res-json.md | 18 + .../docs/de/5x/api/response/res-jsonp.md | 37 ++ .../docs/de/5x/api/response/res-links.md | 25 + .../docs/de/5x/api/response/res-locals.md | 33 + .../docs/de/5x/api/response/res-location.md | 22 + .../docs/de/5x/api/response/res-redirect.md | 56 ++ .../docs/de/5x/api/response/res-render.md | 42 ++ .../docs/de/5x/api/response/res-req.md | 9 + .../docs/de/5x/api/response/res-send.md | 44 ++ .../docs/de/5x/api/response/res-sendFile.md | 91 +++ .../docs/de/5x/api/response/res-sendStatus.md | 20 + .../docs/de/5x/api/response/res-set.md | 21 + .../docs/de/5x/api/response/res-status.md | 15 + .../docs/de/5x/api/response/res-type.md | 18 + .../docs/de/5x/api/response/res-vary.md | 12 + .../content/docs/de/5x/api/router/overview.md | 66 ++ .../docs/de/5x/api/router/router-METHOD.md | 71 +++ .../docs/de/5x/api/router/router-Router.md | 5 + .../docs/de/5x/api/router/router-all.md | 36 ++ .../docs/de/5x/api/router/router-param.md | 67 ++ .../docs/de/5x/api/router/router-route.md | 54 ++ .../docs/de/5x/api/router/router-use.md | 111 ++++ .../docs/de/5x/guide/behind-proxies.md | 90 +++ .../docs/de/5x/guide/database-integration.md | 509 +++++++++++++++ .../src/content/docs/de/5x/guide/debugging.md | 126 ++++ .../docs/de/5x/guide/error-handling.md | 289 +++++++++ .../content/docs/de/5x/guide/migrating-4.md | 554 +++++++++++++++++ .../content/docs/de/5x/guide/migrating-5.md | 587 ++++++++++++++++++ .../de/5x/guide/overriding-express-api.md | 70 +++ astro/src/content/docs/de/5x/guide/routing.md | 417 +++++++++++++ .../docs/de/5x/guide/using-middleware.md | 293 +++++++++ .../de/5x/guide/using-template-engines.md | 58 ++ .../docs/de/5x/guide/writing-middleware.md | 217 +++++++ .../docs/de/5x/starter/basic-routing.md | 63 ++ .../content/docs/de/5x/starter/examples.md | 16 + astro/src/content/docs/de/5x/starter/faq.md | 75 +++ .../content/docs/de/5x/starter/generator.md | 122 ++++ .../content/docs/de/5x/starter/hello-world.md | 42 ++ .../content/docs/de/5x/starter/installing.md | 48 ++ .../docs/de/5x/starter/static-files.md | 74 +++ astro/src/content/docs/es/3x/api.md | 23 + astro/src/content/docs/es/4x/api.md | 26 + astro/src/content/docs/es/5x/api.md | 26 + astro/src/content/docs/fr/3x/api.md | 23 + astro/src/content/docs/fr/4x/api.md | 26 + astro/src/content/docs/fr/5x/api.md | 26 + astro/src/content/docs/it/3x/api.md | 23 + astro/src/content/docs/it/4x/api.md | 26 + astro/src/content/docs/it/5x/api.md | 26 + astro/src/content/docs/ja/3x/api.md | 23 + astro/src/content/docs/ja/4x/api.md | 26 + astro/src/content/docs/ja/5x/api.md | 26 + astro/src/content/docs/ko/3x/api.md | 26 + astro/src/content/docs/ko/4x/api.md | 26 + astro/src/content/docs/ko/5x/api.md | 26 + astro/src/content/docs/pt-br/3x/api.md | 23 + astro/src/content/docs/pt-br/4x/api.md | 26 + astro/src/content/docs/pt-br/5x/api.md | 26 + astro/src/content/docs/zh-cn/3x/api.md | 23 + astro/src/content/docs/zh-cn/4x/api.md | 26 + astro/src/content/docs/zh-cn/5x/api.md | 26 + astro/src/content/docs/zh-tw/3x/api.md | 23 + astro/src/content/docs/zh-tw/4x/api.md | 26 + astro/src/content/docs/zh-tw/5x/api.md | 26 + astro/src/i18n/locales.ts | 45 ++ astro/src/i18n/ui.ts | 15 - astro/src/i18n/ui/de.json | 75 +++ astro/src/i18n/ui/en.json | 75 +++ astro/src/i18n/ui/es.json | 75 +++ astro/src/i18n/ui/fr.json | 75 +++ astro/src/i18n/ui/it.json | 75 +++ astro/src/i18n/ui/ja.json | 75 +++ astro/src/i18n/ui/ko.json | 75 +++ astro/src/i18n/ui/pt-br.json | 75 +++ astro/src/i18n/ui/zh-cn.json | 75 +++ astro/src/i18n/ui/zh-tw.json | 75 +++ astro/src/i18n/utils.ts | 38 +- astro/src/layouts/Layout.astro | 24 +- astro/src/pages/404.astro | 27 + astro/src/pages/[lang]/blog/index.astro | 2 +- astro/src/pages/[lang]/ds-foundations.astro | 239 ++++++- astro/src/pages/[lang]/index.astro | 9 +- astro/src/pages/[lang]/support/index.astro | 2 +- 388 files changed, 22378 insertions(+), 415 deletions(-) create mode 100644 .github/workflows/crowdin.yml create mode 100644 astro/crowdin.yml create mode 100644 astro/src/components/patterns/LanguageSelect/LanguageSelect.astro create mode 100644 astro/src/components/patterns/LanguageSelect/types.ts create mode 100644 astro/src/content/docs/de/3x/api.md create mode 100644 astro/src/content/docs/de/3x/api/application/app-VERB.md create mode 100644 astro/src/content/docs/de/3x/api/application/app-all.md create mode 100644 astro/src/content/docs/de/3x/api/application/app-configure.md create mode 100644 astro/src/content/docs/de/3x/api/application/app-disable.md create mode 100644 astro/src/content/docs/de/3x/api/application/app-disabled.md create mode 100644 astro/src/content/docs/de/3x/api/application/app-enable.md create mode 100644 astro/src/content/docs/de/3x/api/application/app-enabled.md create mode 100644 astro/src/content/docs/de/3x/api/application/app-engine.md create mode 100644 astro/src/content/docs/de/3x/api/application/app-get.md create mode 100644 astro/src/content/docs/de/3x/api/application/app-listen.md create mode 100644 astro/src/content/docs/de/3x/api/application/app-locals.md create mode 100644 astro/src/content/docs/de/3x/api/application/app-param.md create mode 100644 astro/src/content/docs/de/3x/api/application/app-render.md create mode 100644 astro/src/content/docs/de/3x/api/application/app-routes.md create mode 100644 astro/src/content/docs/de/3x/api/application/app-set.md create mode 100644 astro/src/content/docs/de/3x/api/application/app-settings.md create mode 100644 astro/src/content/docs/de/3x/api/application/app-use.md create mode 100644 astro/src/content/docs/de/3x/api/application/overview.md create mode 100644 astro/src/content/docs/de/3x/api/express.md create mode 100644 astro/src/content/docs/de/3x/api/middleware/middleware.md create mode 100644 astro/src/content/docs/de/3x/api/middleware/mw-basicAuth.md create mode 100644 astro/src/content/docs/de/3x/api/middleware/mw-bodyParser.md create mode 100644 astro/src/content/docs/de/3x/api/middleware/mw-compress.md create mode 100644 astro/src/content/docs/de/3x/api/middleware/mw-cookieParser.md create mode 100644 astro/src/content/docs/de/3x/api/middleware/mw-cookieSession.md create mode 100644 astro/src/content/docs/de/3x/api/middleware/mw-csrf.md create mode 100644 astro/src/content/docs/de/3x/api/middleware/mw-directory.md create mode 100644 astro/src/content/docs/de/3x/api/request/overview.md create mode 100644 astro/src/content/docs/de/3x/api/request/req-accepted.md create mode 100644 astro/src/content/docs/de/3x/api/request/req-acceptedCharsets.md create mode 100644 astro/src/content/docs/de/3x/api/request/req-acceptedLanguages.md create mode 100644 astro/src/content/docs/de/3x/api/request/req-accepts.md create mode 100644 astro/src/content/docs/de/3x/api/request/req-acceptsCharset.md create mode 100644 astro/src/content/docs/de/3x/api/request/req-acceptsLanguage.md create mode 100644 astro/src/content/docs/de/3x/api/request/req-body.md create mode 100644 astro/src/content/docs/de/3x/api/request/req-cookies.md create mode 100644 astro/src/content/docs/de/3x/api/request/req-files.md create mode 100644 astro/src/content/docs/de/3x/api/request/req-fresh.md create mode 100644 astro/src/content/docs/de/3x/api/request/req-header.md create mode 100644 astro/src/content/docs/de/3x/api/request/req-host.md create mode 100644 astro/src/content/docs/de/3x/api/request/req-ip.md create mode 100644 astro/src/content/docs/de/3x/api/request/req-ips.md create mode 100644 astro/src/content/docs/de/3x/api/request/req-is.md create mode 100644 astro/src/content/docs/de/3x/api/request/req-originalUrl.md create mode 100644 astro/src/content/docs/de/3x/api/request/req-param.md create mode 100644 astro/src/content/docs/de/3x/api/request/req-params.md create mode 100644 astro/src/content/docs/de/3x/api/request/req-path.md create mode 100644 astro/src/content/docs/de/3x/api/request/req-protocol.md create mode 100644 astro/src/content/docs/de/3x/api/request/req-query.md create mode 100644 astro/src/content/docs/de/3x/api/request/req-res.md create mode 100644 astro/src/content/docs/de/3x/api/request/req-route.md create mode 100644 astro/src/content/docs/de/3x/api/request/req-secure.md create mode 100644 astro/src/content/docs/de/3x/api/request/req-signedCookies.md create mode 100644 astro/src/content/docs/de/3x/api/request/req-stale.md create mode 100644 astro/src/content/docs/de/3x/api/request/req-subdomains.md create mode 100644 astro/src/content/docs/de/3x/api/request/req-xhr.md create mode 100644 astro/src/content/docs/de/3x/api/response/res-attachment.md create mode 100644 astro/src/content/docs/de/3x/api/response/res-charset.md create mode 100644 astro/src/content/docs/de/3x/api/response/res-clearCookie.md create mode 100644 astro/src/content/docs/de/3x/api/response/res-cookie.md create mode 100644 astro/src/content/docs/de/3x/api/response/res-download.md create mode 100644 astro/src/content/docs/de/3x/api/response/res-format.md create mode 100644 astro/src/content/docs/de/3x/api/response/res-get.md create mode 100644 astro/src/content/docs/de/3x/api/response/res-json.md create mode 100644 astro/src/content/docs/de/3x/api/response/res-jsonp.md create mode 100644 astro/src/content/docs/de/3x/api/response/res-links.md create mode 100644 astro/src/content/docs/de/3x/api/response/res-locals.md create mode 100644 astro/src/content/docs/de/3x/api/response/res-location.md create mode 100644 astro/src/content/docs/de/3x/api/response/res-redirect.md create mode 100644 astro/src/content/docs/de/3x/api/response/res-render.md create mode 100644 astro/src/content/docs/de/3x/api/response/res-req.md create mode 100644 astro/src/content/docs/de/3x/api/response/res-send.md create mode 100644 astro/src/content/docs/de/3x/api/response/res-sendfile.md create mode 100644 astro/src/content/docs/de/3x/api/response/res-set.md create mode 100644 astro/src/content/docs/de/3x/api/response/res-status.md create mode 100644 astro/src/content/docs/de/3x/api/response/res-type.md create mode 100644 astro/src/content/docs/de/3x/api/response/response.md create mode 100644 astro/src/content/docs/de/4x/advanced/best-practice-performance.md create mode 100644 astro/src/content/docs/de/4x/advanced/best-practice-security.md create mode 100644 astro/src/content/docs/de/4x/advanced/developing-template-engines.md create mode 100644 astro/src/content/docs/de/4x/advanced/healthcheck-graceful-shutdown.md create mode 100644 astro/src/content/docs/de/4x/advanced/security-updates.md create mode 100644 astro/src/content/docs/de/4x/api.md create mode 100644 astro/src/content/docs/de/4x/api/application/app-METHOD.md create mode 100644 astro/src/content/docs/de/4x/api/application/app-all.md create mode 100644 astro/src/content/docs/de/4x/api/application/app-delete-method.md create mode 100644 astro/src/content/docs/de/4x/api/application/app-disable.md create mode 100644 astro/src/content/docs/de/4x/api/application/app-disabled.md create mode 100644 astro/src/content/docs/de/4x/api/application/app-enable.md create mode 100644 astro/src/content/docs/de/4x/api/application/app-enabled.md create mode 100644 astro/src/content/docs/de/4x/api/application/app-engine.md create mode 100644 astro/src/content/docs/de/4x/api/application/app-get-method.md create mode 100644 astro/src/content/docs/de/4x/api/application/app-get.md create mode 100644 astro/src/content/docs/de/4x/api/application/app-listen.md create mode 100644 astro/src/content/docs/de/4x/api/application/app-locals.md create mode 100644 astro/src/content/docs/de/4x/api/application/app-mountpath.md create mode 100644 astro/src/content/docs/de/4x/api/application/app-onmount.md create mode 100644 astro/src/content/docs/de/4x/api/application/app-param.md create mode 100644 astro/src/content/docs/de/4x/api/application/app-path.md create mode 100644 astro/src/content/docs/de/4x/api/application/app-post-method.md create mode 100644 astro/src/content/docs/de/4x/api/application/app-put-method.md create mode 100644 astro/src/content/docs/de/4x/api/application/app-render.md create mode 100644 astro/src/content/docs/de/4x/api/application/app-route.md create mode 100644 astro/src/content/docs/de/4x/api/application/app-set.md create mode 100644 astro/src/content/docs/de/4x/api/application/app-settings.md create mode 100644 astro/src/content/docs/de/4x/api/application/app-use.md create mode 100644 astro/src/content/docs/de/4x/api/application/overview.md create mode 100644 astro/src/content/docs/de/4x/api/express/express.json.md create mode 100644 astro/src/content/docs/de/4x/api/express/express.md create mode 100644 astro/src/content/docs/de/4x/api/express/express.raw.md create mode 100644 astro/src/content/docs/de/4x/api/express/express.router.md create mode 100644 astro/src/content/docs/de/4x/api/express/express.static.md create mode 100644 astro/src/content/docs/de/4x/api/express/express.text.md create mode 100644 astro/src/content/docs/de/4x/api/express/express.urlencoded.md create mode 100644 astro/src/content/docs/de/4x/api/request/overview.md create mode 100644 astro/src/content/docs/de/4x/api/request/req-accepts.md create mode 100644 astro/src/content/docs/de/4x/api/request/req-acceptsCharsets.md create mode 100644 astro/src/content/docs/de/4x/api/request/req-acceptsEncodings.md create mode 100644 astro/src/content/docs/de/4x/api/request/req-acceptsLanguages.md create mode 100644 astro/src/content/docs/de/4x/api/request/req-app.md create mode 100644 astro/src/content/docs/de/4x/api/request/req-base-url.md create mode 100644 astro/src/content/docs/de/4x/api/request/req-body.md create mode 100644 astro/src/content/docs/de/4x/api/request/req-cookies.md create mode 100644 astro/src/content/docs/de/4x/api/request/req-fresh.md create mode 100644 astro/src/content/docs/de/4x/api/request/req-get.md create mode 100644 astro/src/content/docs/de/4x/api/request/req-hostname.md create mode 100644 astro/src/content/docs/de/4x/api/request/req-ip.md create mode 100644 astro/src/content/docs/de/4x/api/request/req-ips.md create mode 100644 astro/src/content/docs/de/4x/api/request/req-is.md create mode 100644 astro/src/content/docs/de/4x/api/request/req-method.md create mode 100644 astro/src/content/docs/de/4x/api/request/req-originalUrl.md create mode 100644 astro/src/content/docs/de/4x/api/request/req-param.md create mode 100644 astro/src/content/docs/de/4x/api/request/req-params.md create mode 100644 astro/src/content/docs/de/4x/api/request/req-path.md create mode 100644 astro/src/content/docs/de/4x/api/request/req-protocol.md create mode 100644 astro/src/content/docs/de/4x/api/request/req-query.md create mode 100644 astro/src/content/docs/de/4x/api/request/req-range.md create mode 100644 astro/src/content/docs/de/4x/api/request/req-res.md create mode 100644 astro/src/content/docs/de/4x/api/request/req-route.md create mode 100644 astro/src/content/docs/de/4x/api/request/req-secure.md create mode 100644 astro/src/content/docs/de/4x/api/request/req-signedCookies.md create mode 100644 astro/src/content/docs/de/4x/api/request/req-stale.md create mode 100644 astro/src/content/docs/de/4x/api/request/req-subdomains.md create mode 100644 astro/src/content/docs/de/4x/api/request/req-xhr.md create mode 100644 astro/src/content/docs/de/4x/api/response/overview.md create mode 100644 astro/src/content/docs/de/4x/api/response/res-app.md create mode 100644 astro/src/content/docs/de/4x/api/response/res-append.md create mode 100644 astro/src/content/docs/de/4x/api/response/res-attachment.md create mode 100644 astro/src/content/docs/de/4x/api/response/res-clearCookie.md create mode 100644 astro/src/content/docs/de/4x/api/response/res-cookie.md create mode 100644 astro/src/content/docs/de/4x/api/response/res-download.md create mode 100644 astro/src/content/docs/de/4x/api/response/res-end.md create mode 100644 astro/src/content/docs/de/4x/api/response/res-format.md create mode 100644 astro/src/content/docs/de/4x/api/response/res-get.md create mode 100644 astro/src/content/docs/de/4x/api/response/res-headersSent.md create mode 100644 astro/src/content/docs/de/4x/api/response/res-json.md create mode 100644 astro/src/content/docs/de/4x/api/response/res-jsonp.md create mode 100644 astro/src/content/docs/de/4x/api/response/res-links.md create mode 100644 astro/src/content/docs/de/4x/api/response/res-locals.md create mode 100644 astro/src/content/docs/de/4x/api/response/res-location.md create mode 100644 astro/src/content/docs/de/4x/api/response/res-redirect.md create mode 100644 astro/src/content/docs/de/4x/api/response/res-render.md create mode 100644 astro/src/content/docs/de/4x/api/response/res-req.md create mode 100644 astro/src/content/docs/de/4x/api/response/res-send.md create mode 100644 astro/src/content/docs/de/4x/api/response/res-sendFile.md create mode 100644 astro/src/content/docs/de/4x/api/response/res-sendStatus.md create mode 100644 astro/src/content/docs/de/4x/api/response/res-set.md create mode 100644 astro/src/content/docs/de/4x/api/response/res-status.md create mode 100644 astro/src/content/docs/de/4x/api/response/res-type.md create mode 100644 astro/src/content/docs/de/4x/api/response/res-vary.md create mode 100644 astro/src/content/docs/de/4x/api/router/overview.md create mode 100644 astro/src/content/docs/de/4x/api/router/router-METHOD.md create mode 100644 astro/src/content/docs/de/4x/api/router/router-Router.md create mode 100644 astro/src/content/docs/de/4x/api/router/router-all.md create mode 100644 astro/src/content/docs/de/4x/api/router/router-param.md create mode 100644 astro/src/content/docs/de/4x/api/router/router-route.md create mode 100644 astro/src/content/docs/de/4x/api/router/router-use.md create mode 100644 astro/src/content/docs/de/4x/api/router/routing-args.html create mode 100644 astro/src/content/docs/de/4x/guide/behind-proxies.md create mode 100644 astro/src/content/docs/de/4x/guide/database-integration.md create mode 100644 astro/src/content/docs/de/4x/guide/debugging.md create mode 100644 astro/src/content/docs/de/4x/guide/error-handling.md create mode 100644 astro/src/content/docs/de/4x/guide/migrating-4.md create mode 100644 astro/src/content/docs/de/4x/guide/migrating-5.md create mode 100644 astro/src/content/docs/de/4x/guide/overriding-express-api.md create mode 100644 astro/src/content/docs/de/4x/guide/routing.md create mode 100644 astro/src/content/docs/de/4x/guide/using-middleware.md create mode 100644 astro/src/content/docs/de/4x/guide/using-template-engines.md create mode 100644 astro/src/content/docs/de/4x/guide/writing-middleware.md create mode 100644 astro/src/content/docs/de/4x/starter/basic-routing.md create mode 100644 astro/src/content/docs/de/4x/starter/examples.md create mode 100644 astro/src/content/docs/de/4x/starter/faq.md create mode 100644 astro/src/content/docs/de/4x/starter/generator.md create mode 100644 astro/src/content/docs/de/4x/starter/hello-world.md create mode 100644 astro/src/content/docs/de/4x/starter/installing.md create mode 100644 astro/src/content/docs/de/4x/starter/static-files.md create mode 100644 astro/src/content/docs/de/5x/advanced/best-practice-performance.md create mode 100644 astro/src/content/docs/de/5x/advanced/best-practice-security.md create mode 100644 astro/src/content/docs/de/5x/advanced/developing-template-engines.md create mode 100644 astro/src/content/docs/de/5x/advanced/healthcheck-graceful-shutdown.md create mode 100644 astro/src/content/docs/de/5x/advanced/security-updates.md create mode 100644 astro/src/content/docs/de/5x/api.md create mode 100644 astro/src/content/docs/de/5x/api/application/app-METHOD.md create mode 100644 astro/src/content/docs/de/5x/api/application/app-all.md create mode 100644 astro/src/content/docs/de/5x/api/application/app-delete-method.md create mode 100644 astro/src/content/docs/de/5x/api/application/app-disable.md create mode 100644 astro/src/content/docs/de/5x/api/application/app-disabled.md create mode 100644 astro/src/content/docs/de/5x/api/application/app-enable.md create mode 100644 astro/src/content/docs/de/5x/api/application/app-enabled.md create mode 100644 astro/src/content/docs/de/5x/api/application/app-engine.md create mode 100644 astro/src/content/docs/de/5x/api/application/app-get-method.md create mode 100644 astro/src/content/docs/de/5x/api/application/app-get.md create mode 100644 astro/src/content/docs/de/5x/api/application/app-listen.md create mode 100644 astro/src/content/docs/de/5x/api/application/app-locals.md create mode 100644 astro/src/content/docs/de/5x/api/application/app-mountpath.md create mode 100644 astro/src/content/docs/de/5x/api/application/app-onmount.md create mode 100644 astro/src/content/docs/de/5x/api/application/app-param.md create mode 100644 astro/src/content/docs/de/5x/api/application/app-path.md create mode 100644 astro/src/content/docs/de/5x/api/application/app-post-method.md create mode 100644 astro/src/content/docs/de/5x/api/application/app-put-method.md create mode 100644 astro/src/content/docs/de/5x/api/application/app-render.md create mode 100644 astro/src/content/docs/de/5x/api/application/app-route.md create mode 100644 astro/src/content/docs/de/5x/api/application/app-router.md create mode 100644 astro/src/content/docs/de/5x/api/application/app-set.md create mode 100644 astro/src/content/docs/de/5x/api/application/app-settings.md create mode 100644 astro/src/content/docs/de/5x/api/application/app-use.md create mode 100644 astro/src/content/docs/de/5x/api/application/overview.md create mode 100644 astro/src/content/docs/de/5x/api/express/express.json.md create mode 100644 astro/src/content/docs/de/5x/api/express/express.md create mode 100644 astro/src/content/docs/de/5x/api/express/express.raw.md create mode 100644 astro/src/content/docs/de/5x/api/express/express.router.md create mode 100644 astro/src/content/docs/de/5x/api/express/express.static.md create mode 100644 astro/src/content/docs/de/5x/api/express/express.text.md create mode 100644 astro/src/content/docs/de/5x/api/express/express.urlencoded.md create mode 100644 astro/src/content/docs/de/5x/api/request/overview.md create mode 100644 astro/src/content/docs/de/5x/api/request/req-accepts.md create mode 100644 astro/src/content/docs/de/5x/api/request/req-acceptsCharsets.md create mode 100644 astro/src/content/docs/de/5x/api/request/req-acceptsEncodings.md create mode 100644 astro/src/content/docs/de/5x/api/request/req-acceptsLanguages.md create mode 100644 astro/src/content/docs/de/5x/api/request/req-app.md create mode 100644 astro/src/content/docs/de/5x/api/request/req-base-url.md create mode 100644 astro/src/content/docs/de/5x/api/request/req-body.md create mode 100644 astro/src/content/docs/de/5x/api/request/req-cookies.md create mode 100644 astro/src/content/docs/de/5x/api/request/req-fresh.md create mode 100644 astro/src/content/docs/de/5x/api/request/req-get.md create mode 100644 astro/src/content/docs/de/5x/api/request/req-host.md create mode 100644 astro/src/content/docs/de/5x/api/request/req-hostname.md create mode 100644 astro/src/content/docs/de/5x/api/request/req-ip.md create mode 100644 astro/src/content/docs/de/5x/api/request/req-ips.md create mode 100644 astro/src/content/docs/de/5x/api/request/req-is.md create mode 100644 astro/src/content/docs/de/5x/api/request/req-method.md create mode 100644 astro/src/content/docs/de/5x/api/request/req-originalUrl.md create mode 100644 astro/src/content/docs/de/5x/api/request/req-params.md create mode 100644 astro/src/content/docs/de/5x/api/request/req-path.md create mode 100644 astro/src/content/docs/de/5x/api/request/req-protocol.md create mode 100644 astro/src/content/docs/de/5x/api/request/req-query.md create mode 100644 astro/src/content/docs/de/5x/api/request/req-range.md create mode 100644 astro/src/content/docs/de/5x/api/request/req-res.md create mode 100644 astro/src/content/docs/de/5x/api/request/req-route.md create mode 100644 astro/src/content/docs/de/5x/api/request/req-secure.md create mode 100644 astro/src/content/docs/de/5x/api/request/req-signedCookies.md create mode 100644 astro/src/content/docs/de/5x/api/request/req-stale.md create mode 100644 astro/src/content/docs/de/5x/api/request/req-subdomains.md create mode 100644 astro/src/content/docs/de/5x/api/request/req-xhr.md create mode 100644 astro/src/content/docs/de/5x/api/response/overview.md create mode 100644 astro/src/content/docs/de/5x/api/response/res-app.md create mode 100644 astro/src/content/docs/de/5x/api/response/res-append.md create mode 100644 astro/src/content/docs/de/5x/api/response/res-attachment.md create mode 100644 astro/src/content/docs/de/5x/api/response/res-clearCookie.md create mode 100644 astro/src/content/docs/de/5x/api/response/res-cookie.md create mode 100644 astro/src/content/docs/de/5x/api/response/res-download.md create mode 100644 astro/src/content/docs/de/5x/api/response/res-end.md create mode 100644 astro/src/content/docs/de/5x/api/response/res-format.md create mode 100644 astro/src/content/docs/de/5x/api/response/res-get.md create mode 100644 astro/src/content/docs/de/5x/api/response/res-headersSent.md create mode 100644 astro/src/content/docs/de/5x/api/response/res-json.md create mode 100644 astro/src/content/docs/de/5x/api/response/res-jsonp.md create mode 100644 astro/src/content/docs/de/5x/api/response/res-links.md create mode 100644 astro/src/content/docs/de/5x/api/response/res-locals.md create mode 100644 astro/src/content/docs/de/5x/api/response/res-location.md create mode 100644 astro/src/content/docs/de/5x/api/response/res-redirect.md create mode 100644 astro/src/content/docs/de/5x/api/response/res-render.md create mode 100644 astro/src/content/docs/de/5x/api/response/res-req.md create mode 100644 astro/src/content/docs/de/5x/api/response/res-send.md create mode 100644 astro/src/content/docs/de/5x/api/response/res-sendFile.md create mode 100644 astro/src/content/docs/de/5x/api/response/res-sendStatus.md create mode 100644 astro/src/content/docs/de/5x/api/response/res-set.md create mode 100644 astro/src/content/docs/de/5x/api/response/res-status.md create mode 100644 astro/src/content/docs/de/5x/api/response/res-type.md create mode 100644 astro/src/content/docs/de/5x/api/response/res-vary.md create mode 100644 astro/src/content/docs/de/5x/api/router/overview.md create mode 100644 astro/src/content/docs/de/5x/api/router/router-METHOD.md create mode 100644 astro/src/content/docs/de/5x/api/router/router-Router.md create mode 100644 astro/src/content/docs/de/5x/api/router/router-all.md create mode 100644 astro/src/content/docs/de/5x/api/router/router-param.md create mode 100644 astro/src/content/docs/de/5x/api/router/router-route.md create mode 100644 astro/src/content/docs/de/5x/api/router/router-use.md create mode 100644 astro/src/content/docs/de/5x/guide/behind-proxies.md create mode 100644 astro/src/content/docs/de/5x/guide/database-integration.md create mode 100644 astro/src/content/docs/de/5x/guide/debugging.md create mode 100644 astro/src/content/docs/de/5x/guide/error-handling.md create mode 100644 astro/src/content/docs/de/5x/guide/migrating-4.md create mode 100644 astro/src/content/docs/de/5x/guide/migrating-5.md create mode 100644 astro/src/content/docs/de/5x/guide/overriding-express-api.md create mode 100644 astro/src/content/docs/de/5x/guide/routing.md create mode 100644 astro/src/content/docs/de/5x/guide/using-middleware.md create mode 100644 astro/src/content/docs/de/5x/guide/using-template-engines.md create mode 100644 astro/src/content/docs/de/5x/guide/writing-middleware.md create mode 100644 astro/src/content/docs/de/5x/starter/basic-routing.md create mode 100644 astro/src/content/docs/de/5x/starter/examples.md create mode 100644 astro/src/content/docs/de/5x/starter/faq.md create mode 100644 astro/src/content/docs/de/5x/starter/generator.md create mode 100644 astro/src/content/docs/de/5x/starter/hello-world.md create mode 100644 astro/src/content/docs/de/5x/starter/installing.md create mode 100644 astro/src/content/docs/de/5x/starter/static-files.md create mode 100644 astro/src/content/docs/es/3x/api.md create mode 100644 astro/src/content/docs/es/4x/api.md create mode 100644 astro/src/content/docs/es/5x/api.md create mode 100644 astro/src/content/docs/fr/3x/api.md create mode 100644 astro/src/content/docs/fr/4x/api.md create mode 100644 astro/src/content/docs/fr/5x/api.md create mode 100644 astro/src/content/docs/it/3x/api.md create mode 100644 astro/src/content/docs/it/4x/api.md create mode 100644 astro/src/content/docs/it/5x/api.md create mode 100644 astro/src/content/docs/ja/3x/api.md create mode 100644 astro/src/content/docs/ja/4x/api.md create mode 100644 astro/src/content/docs/ja/5x/api.md create mode 100644 astro/src/content/docs/ko/3x/api.md create mode 100644 astro/src/content/docs/ko/4x/api.md create mode 100644 astro/src/content/docs/ko/5x/api.md create mode 100644 astro/src/content/docs/pt-br/3x/api.md create mode 100644 astro/src/content/docs/pt-br/4x/api.md create mode 100644 astro/src/content/docs/pt-br/5x/api.md create mode 100644 astro/src/content/docs/zh-cn/3x/api.md create mode 100644 astro/src/content/docs/zh-cn/4x/api.md create mode 100644 astro/src/content/docs/zh-cn/5x/api.md create mode 100644 astro/src/content/docs/zh-tw/3x/api.md create mode 100644 astro/src/content/docs/zh-tw/4x/api.md create mode 100644 astro/src/content/docs/zh-tw/5x/api.md create mode 100644 astro/src/i18n/locales.ts delete mode 100644 astro/src/i18n/ui.ts create mode 100644 astro/src/i18n/ui/de.json create mode 100644 astro/src/i18n/ui/en.json create mode 100644 astro/src/i18n/ui/es.json create mode 100644 astro/src/i18n/ui/fr.json create mode 100644 astro/src/i18n/ui/it.json create mode 100644 astro/src/i18n/ui/ja.json create mode 100644 astro/src/i18n/ui/ko.json create mode 100644 astro/src/i18n/ui/pt-br.json create mode 100644 astro/src/i18n/ui/zh-cn.json create mode 100644 astro/src/i18n/ui/zh-tw.json create mode 100644 astro/src/pages/404.astro diff --git a/.github/workflows/crowdin.yml b/.github/workflows/crowdin.yml new file mode 100644 index 0000000000..b0be632134 --- /dev/null +++ b/.github/workflows/crowdin.yml @@ -0,0 +1,30 @@ +name: Crowdin Upload + +on: + push: + branches: [gh-pages] + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + synchronize-with-crowdin: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + persist-credentials: false + + - name: crowdin action + uses: crowdin/github-action@60debf382ee245b21794321190ad0501db89d8c1 # https://github.com/crowdin/github-action/releases/tag/v2.13.0 + with: + upload_sources: true + upload_translations: false + download_translations: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} + CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} diff --git a/astro/CONTRIBUTING.md b/astro/CONTRIBUTING.md index 53f9d64fee..40e6fc4fd5 100644 --- a/astro/CONTRIBUTING.md +++ b/astro/CONTRIBUTING.md @@ -369,25 +369,151 @@ type MenuItem = { }; ``` -## Contributing translations +## Internationalization (i18n) -We use Crowdin to manage our translations in multiple languages and achieve automatic translation with artificial intelligence. Since these translations can be inefficient in some cases, we need help from the community to provide accurate and helpful translations. +The expressjs.com website supports multiple languages through a combination of Astro routing, TypeScript utilities, and Crowdin integration. -The documentation is translated into these languages: +### Contributing translations -- Chinese Simplified (`zh-cn`) -- Chinese Traditional (`zh-tw`) -- English (`en`) -- French (`fr`) -- German (`de`) -- Italian (`it`) -- Japanese (`ja`) -- Korean (`ko`) -- Brazilian Portuguese (`pt-br`) -- Spanish (`es`) +We use Crowdin to manage our translations in multiple languages and to enable automatic translation with artificial intelligence. Since AI translations can be imperfect, we welcome community contributions to improve translation accuracy and quality. -### How to translate +#### How to contribute translations -1. Request to join the Express.js Website project on [Crowdin](https://express.crowdin.com/website) +1. Request to join the [Express.js Website project on Crowdin](https://express.crowdin.com/website) 2. [Select the language you want to translate](https://support.crowdin.com/for-translators/#starting-translation) -3. [Start translating](https://support.crowdin.com/online-editor/) +3. [Start translating in the Crowdin editor](https://support.crowdin.com/online-editor/) + +> Translation contributions must be made through Crowdin, not directly to the repository. Direct edits to translation files will be overwritten by Crowdin syncs. + +### Adding a new language + +To add a new language to the website, follow this process: + +1. **Request language support** - Contact a website captain to request a new language in Crowdin. Only website maintainers can add new languages to the Crowdin project. + +2. **Crowdin will generate files** - Once approved in Crowdin, translation files will be automatically created: + - `src/i18n/ui/[lang-code].json` - UI strings + - Content files in `src/content/docs/[lang-code]/` + +3. **Update `src/i18n/locales.ts`** - Once files are created by Crowdin: + - Add the language to the `languages` object + - Import the new language's JSON file from `src/i18n/ui/` + +### How i18n works (Technical Details) + +For developers who want to understand the technical architecture of the i18n system: + +### Architecture overview + +The i18n system is built on these key components: + +1. **Locales Configuration** (`src/i18n/locales.ts`): + - Defines all supported languages and their metadata + - Imports UI translation strings from JSON files + - Exports types for type-safe translations + +2. **i18n Utilities** (`src/i18n/utils.ts`): + - `getLangFromUrl()` - Extracts the language code from the URL + - `useTranslations()` - Returns a translation function for the current language + - Helper functions for language path manipulation + +3. **Routing** (`src/pages/[lang]/[...slug].astro`): + - Dynamic routing with the `[lang]` parameter for language selection + - Supports URLs like `/en/api/`, `/fr/api/`, `/de/api/`, etc. + +4. **UI Translations** (`src/i18n/ui/`): + - JSON files for each supported language (e.g., `en.json`, `fr.json`) + - Contains UI strings like navigation labels, buttons, and UI elements + - Managed through Crowdin for easier translation + +### Supported languages + +The website is available in the following languages: + +- `en` - English +- `de` - German (Deutsch) +- `es` - Spanish (Español) +- `fr` - French (Français) +- `it` - Italian (Italiano) +- `ja` - Japanese (日本語) +- `ko` - Korean (한국어) +- `pt-br` - Brazilian Portuguese (Português) +- `zh-cn` - Chinese Simplified (简体中文) +- `zh-tw` - Chinese Traditional (繁體中文) + +### Using translations in components + +To use translations in your Astro components, import the utility functions and extract the language from the current URL: + +```astro +--- +import { getLangFromUrl, useTranslations } from '@/i18n/utils'; + +const lang = getLangFromUrl(Astro.url); +const t = useTranslations(lang); +--- + + +

    {t('common.welcome')}

    +``` + +The `Astro.url` object automatically provides the current page URL, making it easy to extract the language code and get the appropriate translations. + +### Content organization + +#### UI translations + +UI strings are stored in JSON files in `src/i18n/ui/`. For example, `src/i18n/ui/en.json`: + +```json +{ + "common": { + "home": "Home", + "about": "About", + "contact": "Contact" + }, + "navigation": { + "docs": "Documentation", + "api": "API Reference" + } +} +``` + +#### Content translations + +Documentation content is stored separately from UI translations: + +- **Docs**: `src/content/docs/[lang-code]/[version]/` - Documentation pages +- **Resources**: `src/content/resources/[lang-code]/` - Resource pages + +The following content is currently not translated: + +- **API reference** +- **Blog posts** + +### Adding UI translations + +When adding new UI strings: + +1. Add the string to `src/i18n/ui/en.json` first +2. The structure will be synced to Crowdin +3. Translators will translate it through Crowdin +4. Updated translations will be synced back + +### Crowdin integration + +The `crowdin.yml` configuration file defines: + +- Source files and their Crowdin translation targets +- Directory structure for translations +- API configuration for automation + +When translations are completed in Crowdin: + +- Files are automatically synced to the repository +- A bot automatically creates pull requests with the translation updates + +> [!WARNING] +> **Do not manually create or edit translation files** (`src/i18n/ui/*.json` and `src/content/docs/[lang-code]/*.*`) +> These files are automatically managed by Crowdin and will be overwritten if you make manual changes. +> All translation updates must go through the Crowdin workflow. diff --git a/astro/astro.config.mjs b/astro/astro.config.mjs index 095044e693..3441315e48 100644 --- a/astro/astro.config.mjs +++ b/astro/astro.config.mjs @@ -5,6 +5,7 @@ import icon from 'astro-icon'; // https://astro.build/config export default defineConfig({ + site: 'https://expressjs.com', integrations: [mdx(), icon()], markdown: { shikiConfig: { diff --git a/astro/crowdin.yml b/astro/crowdin.yml new file mode 100644 index 0000000000..3575ea36cf --- /dev/null +++ b/astro/crowdin.yml @@ -0,0 +1,11 @@ +files: + - source: /src/content/docs/en/**/*.* + translation: /src/content/docs/%two_letters_code%/**/%original_file_name% + - source: /src/content/resources/en/**/*.* + translation: /src/resources/docs/%two_letters_code%/**/%original_file_name% + - source: /src/i18n/ui/en/en.json + translation: /src/i18n/ui/%two_letters_code%/%two_letters_code%.json +preserve_hierarchy: true +project_id_env: CROWDIN_PROJECT_ID +base_url: 'https://express.api.crowdin.com' +api_token_env: CROWDIN_PERSONAL_TOKEN diff --git a/astro/package-lock.json b/astro/package-lock.json index a45dd6bdfc..aa3d7adfca 100644 --- a/astro/package-lock.json +++ b/astro/package-lock.json @@ -9,13 +9,14 @@ "version": "0.0.1", "dependencies": { "@astrojs/mdx": "^4.3.13", - "astro": "^5.16.11", + "astro": "^5.18.0", "astro-icon": "^1.1.5" }, "devDependencies": { "@csstools/postcss-global-data": "^4.0.0", "@eslint/js": "^9.39.2", "@iconify-json/fluent": "^1.2.38", + "@types/node": "^25.3.2", "eslint": "^9.39.2", "eslint-config-prettier": "^10.1.8", "eslint-plugin-astro": "^1.5.0", @@ -55,7 +56,8 @@ "version": "2.13.0", "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-2.13.0.tgz", "integrity": "sha512-mqVORhUJViA28fwHYaWmsXSzLO9osbdZ5ImUfxBarqsYdMlPbqAqGJCxsNzvppp1BEzc1mJNjOVvQqeDN8Vspw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@astrojs/internal-helpers": { "version": "0.7.5", @@ -245,6 +247,7 @@ "url": "https://opencollective.com/csstools" } ], + "peer": true, "engines": { "node": ">=20.19.0" }, @@ -267,6 +270,7 @@ "url": "https://opencollective.com/csstools" } ], + "peer": true, "engines": { "node": ">=20.19.0" } @@ -2131,10 +2135,12 @@ } }, "node_modules/@types/node": { - "version": "25.3.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.0.tgz", - "integrity": "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A==", - "optional": true, + "version": "25.3.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.2.tgz", + "integrity": "sha512-RpV6r/ij22zRRdyBPcxDeKAzH43phWVKEjL2iksqo1Vz3CuBUrgmPpPhALKiRfU7OMCmeeO9vECBMsV0hMTG8Q==", + "devOptional": true, + "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~7.18.0" } @@ -2200,6 +2206,7 @@ "integrity": "sha512-nm3cvFN9SqZGXjmw5bZ6cGmvJSyJPn0wU9gHAZZHDnZl2wF9PhHv78Xf06E0MaNk4zLVHL8hb2/c32XvyJOLQg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.53.1", "@typescript-eslint/types": "8.53.1", @@ -2422,6 +2429,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2712,10 +2720,11 @@ } }, "node_modules/astro": { - "version": "5.16.11", - "resolved": "https://registry.npmjs.org/astro/-/astro-5.16.11.tgz", - "integrity": "sha512-Z7kvkTTT5n6Hn5lCm6T3WU6pkxx84Hn25dtQ6dR7ATrBGq9eVa8EuB/h1S8xvaoVyCMZnIESu99Z9RJfdLRLDA==", + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/astro/-/astro-5.18.0.tgz", + "integrity": "sha512-CHiohwJIS4L0G6/IzE1Fx3dgWqXBCXus/od0eGUfxrZJD2um2pE7ehclMmgL/fXqbU7NfE1Ze2pq34h2QaA6iQ==", "license": "MIT", + "peer": true, "dependencies": { "@astrojs/compiler": "^2.13.0", "@astrojs/internal-helpers": "0.7.5", @@ -2740,7 +2749,7 @@ "dlv": "^1.1.3", "dset": "^3.1.4", "es-module-lexer": "^1.7.0", - "esbuild": "^0.25.0", + "esbuild": "^0.27.3", "estree-walker": "^3.0.3", "flattie": "^1.1.1", "fontace": "~0.4.0", @@ -2761,16 +2770,16 @@ "prompts": "^2.4.2", "rehype": "^13.0.2", "semver": "^7.7.3", - "shiki": "^3.20.0", + "shiki": "^3.21.0", "smol-toml": "^1.6.0", "svgo": "^4.0.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tsconfck": "^3.1.6", "ultrahtml": "^1.6.0", - "unifont": "~0.7.1", + "unifont": "~0.7.3", "unist-util-visit": "^5.0.0", - "unstorage": "^1.17.3", + "unstorage": "^1.17.4", "vfile": "^6.0.3", "vite": "^6.4.1", "vitefu": "^1.1.1", @@ -2835,6 +2844,463 @@ "@iconify/utils": "^2.1.30" } }, + "node_modules/astro/node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/astro/node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, "node_modules/astrojs-compiler-sync": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/astrojs-compiler-sync/-/astrojs-compiler-sync-1.1.1.tgz", @@ -4074,6 +4540,7 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -7911,6 +8378,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -8554,6 +9022,7 @@ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.55.3.tgz", "integrity": "sha512-y9yUpfQvetAjiDLtNMf1hL9NXchIJgWt6zIKeoB+tCd3npX08Eqfzg60V9DhIGVMtQ0AlMkFw5xa+AQ37zxnAA==", "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -9484,6 +9953,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -9566,8 +10036,8 @@ "version": "7.18.2", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", - "license": "MIT", - "optional": true + "devOptional": true, + "license": "MIT" }, "node_modules/unified": { "version": "11.0.5", @@ -9895,6 +10365,7 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", @@ -10198,6 +10669,7 @@ "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", "devOptional": true, "license": "ISC", + "peer": true, "bin": { "yaml": "bin.mjs" }, @@ -10271,6 +10743,7 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/astro/package.json b/astro/package.json index eaefd53e88..fec4a06e30 100644 --- a/astro/package.json +++ b/astro/package.json @@ -16,7 +16,7 @@ }, "dependencies": { "@astrojs/mdx": "^4.3.13", - "astro": "^5.16.11", + "astro": "^5.18.0", "astro-icon": "^1.1.5" }, "devEngines": { @@ -35,6 +35,7 @@ "@csstools/postcss-global-data": "^4.0.0", "@eslint/js": "^9.39.2", "@iconify-json/fluent": "^1.2.38", + "@types/node": "^25.3.2", "eslint": "^9.39.2", "eslint-config-prettier": "^10.1.8", "eslint-plugin-astro": "^1.5.0", diff --git a/astro/src/components/patterns/Breadcrumbs/Breadcrumbs.astro b/astro/src/components/patterns/Breadcrumbs/Breadcrumbs.astro index bf57300f14..c863f7144c 100644 --- a/astro/src/components/patterns/Breadcrumbs/Breadcrumbs.astro +++ b/astro/src/components/patterns/Breadcrumbs/Breadcrumbs.astro @@ -7,15 +7,18 @@ import { Body } from '@components/primitives'; import { Icon } from 'astro-icon/components'; import type { BreadcrumbItem } from '@utils/content'; +import { getLangFromUrl, useTranslations } from '@/i18n/utils'; interface Props { items: BreadcrumbItem[]; } const { items } = Astro.props; +const lang = getLangFromUrl(Astro.url); +const t = useTranslations(lang); --- -
    + + diff --git a/astro/src/components/primitives/Select/Select.css b/astro/src/components/primitives/Select/Select.css index 7281e0d76e..22c3786bdf 100644 --- a/astro/src/components/primitives/Select/Select.css +++ b/astro/src/components/primitives/Select/Select.css @@ -3,100 +3,204 @@ */ @layer primitives { - .select-wrapper { + .select-container { position: relative; display: inline-flex; align-items: center; } - .select-wrapper--full-width { + .select-container--full-width { width: 100%; } - .select-caret { - position: absolute; - right: var(--space-2); - pointer-events: none; - color: var(--color-icon-secondary); - width: 16px; - height: 16px; - } - - .select { + .select-button { cursor: pointer; position: relative; display: inline-flex; align-items: center; + gap: var(--space-2); background-color: var(--color-bg-secondary); border: 1px solid var(--color-border-mute); border-radius: var(--radius-base); - cursor: pointer; - appearance: none; transition: border-color 0.2s ease, - box-shadow 0.2s ease; + background-color 0.2s ease; + font-family: inherit; + color: var(--color-text-primary); + width: 100%; } - /* Sizes */ - .select--size-sm { - padding: var(--space-1) var(--space-6) var(--space-1) var(--space-2); + .select-button--size-sm { + padding: var(--space-1) var(--space-2); font-size: var(--font-size-xs); } - .select--size-md { - padding: var(--space-2) var(--space-6) var(--space-2) var(--space-3); + .select-button--size-md { + padding: var(--space-2) var(--space-3); font-size: var(--font-size-sm); font-weight: var(--font-weight-medium); } - .select--size-lg { - padding: var(--space-3) var(--space-8) var(--space-3) var(--space-4); + .select-button--size-lg { + padding: var(--space-3) var(--space-4); font-size: var(--font-size-base); } - /* Variants */ - .select--variant-default { + .select-button--variant-default { background-color: var(--color-bg-secondary); border-color: var(--color-border-mute); } - .select--variant-ghost { + .select-button--variant-ghost { background-color: transparent; border-color: transparent; } - .select--variant-ghost:hover { + .select-button--variant-ghost:hover { background-color: var(--color-bg-hover); } - .select--variant-minimal { + .select-button--variant-minimal { background-color: transparent; border: none; padding-left: 0; } - /* Full width */ - .select--full-width { - width: 100%; + .select-button--variant-icon { + background-color: transparent; + border: none; + padding: 0; + width: auto; } - /* States */ - .select:hover { - border-color: var(--color-border-primary); + .select-icon { + padding: var(--space-2); + border-radius: var(--radius-base); + background-color: var(--color-bg-secondary); + transition: background-color var(--duration-200) var(--ease-in-out); + flex-shrink: 0; + display: flex; + align-items: center; + justify-content: center; + } + + .select-button--variant-icon:hover .select-icon { + background-color: var(--color-bg-mute); } - .select:focus-visible { - outline-offset: -1px; + .select-button:hover:not(:disabled) { border-color: var(--color-border-primary); } - .select:disabled { + .select-button:focus-visible { + outline: 2px solid var(--color-focus-ring); + outline-offset: 2px; + } + + .select-button:disabled { + opacity: 0.5; + cursor: not-allowed; + } + + .select-caret { + margin-left: auto; + color: var(--color-icon-secondary); + width: 16px; + height: 16px; + flex-shrink: 0; + transition: transform 0.2s ease; + } + + .select-container[data-open='true'] .select-caret { + transform: rotate(180deg); + } + + .select-dropdown { + position: absolute; + top: calc(100% + var(--space-1)); + width: 100%; + min-width: var(--size-24); + background-color: var(--color-bg-primary); + border: 1px solid var(--color-border-secondary); + border-radius: var(--radius-lg); + z-index: 100; + padding: 0; + opacity: 0; + visibility: hidden; + transform: translateY(calc(-1 * var(--space-2))); + transition: + opacity 0.2s, + transform 0.2s, + visibility 0.2s; + max-height: var(--size-96); + overflow-y: auto; + } + + .select-dropdown--align-left { + left: 0; + right: auto; + } + + .select-dropdown--align-right { + right: 0; + left: auto; + } + + .select-container[data-open='true'] .select-dropdown { + opacity: 1; + visibility: visible; + transform: translateY(0); + } + + /* Option Styles */ + .select-option { + display: flex; + align-items: center; + width: 100%; + padding: var(--space-2) var(--space-3); + background-color: transparent; + border: none; + cursor: pointer; + font: inherit; + color: var(--color-text-primary); + text-align: left; + transition: background-color 0.2s; + + &:first-child { + border-top-left-radius: var(--radius-lg); + border-top-right-radius: var(--radius-lg); + } + + &:last-child { + border-bottom-left-radius: var(--radius-lg); + border-bottom-right-radius: var(--radius-lg); + } + } + + .select-option:focus-visible { + outline: 2px solid var(--color-focus-ring); + outline-offset: -2px; + background-color: var(--color-bg-tertiary); + } + + .select-option:hover { + background-color: var(--color-bg-tertiary); + } + + .select-option[aria-selected='true'] { + background: var(--color-bg-secondary); + } + + .select-option:disabled { opacity: 0.5; cursor: not-allowed; } - /* Disabled options */ - .select option:disabled { - color: var(--color-text-mute); + .select-label { + flex: 1; + text-align: left; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } } diff --git a/astro/src/components/primitives/Select/types.ts b/astro/src/components/primitives/Select/types.ts index 886dc77e63..6be4b26d03 100644 --- a/astro/src/components/primitives/Select/types.ts +++ b/astro/src/components/primitives/Select/types.ts @@ -2,31 +2,49 @@ * Select Primitive Types */ -export interface SelectOption { +export interface SelectOption { /** Value of the option */ - value: string; + value: T; /** Display label */ label: string; /** Whether the option is selected */ selected?: boolean; /** Whether the option is disabled */ disabled?: boolean; + /** Optional data to pass to custom renderers */ + data?: Record; } export type SelectSize = 'sm' | 'md' | 'lg'; -export type SelectVariant = 'default' | 'ghost' | 'minimal'; +export type SelectVariant = 'default' | 'ghost' | 'minimal' | 'icon'; -export interface SelectBaseProps { +export interface SelectBaseProps { /** Size variant */ size?: SelectSize; /** Style variant */ variant?: SelectVariant; /** Options for the select */ - options?: SelectOption[]; + options: SelectOption[]; /** Currently selected value */ - value?: string; + value?: T; /** Placeholder text when no value is selected */ placeholder?: string; /** Full width select */ fullWidth?: boolean; + /** Aria label for the select button */ + ariaLabel?: string; + /** ID for the select container */ + id?: string; + /** Name attribute for form submission */ + name?: string; + /** Whether the select is disabled */ + disabled?: boolean; + /** Callback when selection changes */ + onChange?: (value: T) => void; + /** Icon name to display (for icon variant) */ + icon?: string; + /** Whether to hide the label (icon-only mode) */ + hideLabel?: boolean; + /** Dropdown alignment relative to the button */ + dropdownAlign?: 'left' | 'right'; } diff --git a/astro/src/components/primitives/Typography/BodyMd.astro b/astro/src/components/primitives/Typography/BodyMd.astro index 9338c7ebd6..71ec281940 100644 --- a/astro/src/components/primitives/Typography/BodyMd.astro +++ b/astro/src/components/primitives/Typography/BodyMd.astro @@ -9,12 +9,9 @@ import type { HTMLAttributes } from 'astro/types'; import Typography from './Typography.astro'; -import type { TypographyColor, TypographyWeight } from './types.ts'; +import type { TypographyBaseProps } from './types.ts'; -type BaseProps = { - color?: TypographyColor; - weight?: TypographyWeight; -}; +type BaseProps = Omit; type Props = | ({ as?: 'span' } & BaseProps & HTMLAttributes<'span'>) diff --git a/astro/src/config/menu/api.ts b/astro/src/config/menu/api.ts index 9d695291c1..a7dcf6b3ae 100644 --- a/astro/src/config/menu/api.ts +++ b/astro/src/config/menu/api.ts @@ -6,63 +6,22 @@ export const apiMenu: Menu = { items: [ { href: '/api', - label: 'Overview', - ariaLabel: 'Overview', + label: 'menu.overview', + ariaLabel: 'menu.overview', }, ], }, { - title: 'Express', + title: 'menu.application', items: [ - { href: `/api/express/overview`, label: 'Overview', ariaLabel: 'Express overview' }, { - label: 'Methods', - ariaLabel: 'Express methods', - omitFrom: ['3x'], - submenu: { - items: [ - { - href: `/api/express/expressjson`, - label: 'express.json()', - ariaLabel: 'express.json method', - }, - { - href: `/api/express/expressraw`, - label: 'express.raw()', - ariaLabel: 'express.raw method', - }, - { - href: '/api/express/expressrouter', - label: 'express.Router()', - ariaLabel: 'express.Router method', - }, - { - href: '/api/express/expressstatic', - label: 'express.static()', - ariaLabel: 'express.static method', - }, - { - href: `/api/express/expresstext`, - label: 'express.text()', - ariaLabel: 'express.text method', - }, - { - href: `/api/express/expressurlencoded`, - label: 'express.urlencoded()', - ariaLabel: 'express.urlencoded method', - }, - ], - }, + href: `/api/application/overview`, + label: 'menu.overview', + ariaLabel: 'menu.applicationOverviewAria', }, - ], - }, - { - title: 'Application', - items: [ - { href: `/api/application/overview`, label: 'Overview', ariaLabel: 'Application overview' }, { - label: 'Properties', - ariaLabel: 'Application properties', + label: 'menu.properties', + ariaLabel: 'menu.applicationPropertiesAria', submenu: { items: [ { @@ -76,38 +35,12 @@ export const apiMenu: Menu = { ariaLabel: 'app.mountpath property', omitFrom: ['3x'], }, - { - href: `/api/application/app-router`, - label: 'app.router', - ariaLabel: 'app.router property', - omitFrom: ['3x', '4x'], - }, - { - href: `/api/application/app-routes`, - label: 'app.routes', - ariaLabel: 'app.routes property', - omitFrom: ['4x', '5x'], - }, ], }, }, { - label: 'Events', - ariaLabel: 'Application events', - omitFrom: ['3x'], - submenu: { - items: [ - { - href: `/api/application/app-event-mount`, - label: 'mount', - ariaLabel: 'app mount event', - }, - ], - }, - }, - { - label: 'Methods', - ariaLabel: 'Application methods', + label: 'menu.methods', + ariaLabel: 'menu.applicationMethodsAria', submenu: { items: [ { @@ -121,104 +54,22 @@ export const apiMenu: Menu = { ariaLabel: 'app.delete method', omitFrom: ['3x'], }, - { - href: '/api/application/app-disable', - label: 'app.disable()', - ariaLabel: 'app.disable method', - }, - { - href: '/api/application/app-disabled', - label: 'app.disabled()', - ariaLabel: 'app.disabled method', - }, - { - href: '/api/application/app-enable', - label: 'app.enable()', - ariaLabel: 'app.enable method', - }, - { - href: '/api/application/app-enabled', - label: 'app.enabled()', - ariaLabel: 'app.enabled method', - }, - { - href: '/api/application/app-engine', - label: 'app.engine()', - ariaLabel: 'app.engine method', - }, - { - href: '/api/application/app-get', - label: 'app.get()', - ariaLabel: 'app.get method', - }, - { - href: '/api/application/app-get-method', - label: 'app.get()', - ariaLabel: 'app.get method', - omitFrom: ['3x'], - }, - { - href: '/api/application/app-listen', - label: 'app.listen()', - ariaLabel: 'app.listen method', - }, - { - href: '/api/application/app-param', - label: 'app.param()', - ariaLabel: 'app.param method', - }, - { - href: '/api/application/app-method', - label: 'app.METHOD()', - ariaLabel: 'app.METHOD method', - omitFrom: ['3x'], - }, - { - href: '/api/application/app-path', - label: 'app.path()', - ariaLabel: 'app.path method', - omitFrom: ['3x'], - }, - { - href: '/api/application/app-post', - label: 'app.post()', - ariaLabel: 'app.post method', - omitFrom: ['3x'], - }, - { - href: '/api/application/app-put', - label: 'app.put()', - ariaLabel: 'app.put method', - omitFrom: ['3x'], - }, - { - href: '/api/application/app-render', - label: 'app.render()', - ariaLabel: 'app.render method', - }, - { - href: '/api/application/app-route', - label: 'app.route()', - ariaLabel: 'app.route method', - omitFrom: ['3x'], - }, - { - href: '/api/application/app-use', - label: 'app.use()', - ariaLabel: 'app.use method', - }, ], }, }, ], }, { - title: 'Request', + title: 'menu.request', items: [ - { href: `/api/request/overview`, label: 'Overview', ariaLabel: 'Request overview' }, { - label: 'Properties', - ariaLabel: 'Request properties', + href: `/api/request/overview`, + label: 'menu.overview', + ariaLabel: 'menu.requestOverviewAria', + }, + { + label: 'menu.properties', + ariaLabel: 'menu.requestPropertiesAria', submenu: { items: [ { @@ -245,12 +96,16 @@ export const apiMenu: Menu = { ], }, { - title: 'Response', + title: 'menu.response', items: [ - { href: `/api/response/overview`, label: 'Overview', ariaLabel: 'Response overview' }, { - label: 'Properties', - ariaLabel: 'Response properties', + href: `/api/response/overview`, + label: 'menu.overview', + ariaLabel: 'menu.responseOverviewAria', + }, + { + label: 'menu.properties', + ariaLabel: 'menu.responsePropertiesAria', submenu: { items: [ { @@ -270,13 +125,17 @@ export const apiMenu: Menu = { ], }, { - title: 'Router', + title: 'menu.router', omitFrom: ['3x'], items: [ - { href: `/api/router/overview`, label: 'Overview', ariaLabel: 'Router overview' }, { - label: 'Methods', - ariaLabel: 'Router methods', + href: `/api/router/overview`, + label: 'menu.overview', + ariaLabel: 'menu.routerOverviewAria', + }, + { + label: 'menu.methods', + ariaLabel: 'menu.routerMethodsAria', submenu: { items: [ { diff --git a/astro/src/config/menu/docs.ts b/astro/src/config/menu/docs.ts index 39e9b80dab..6207df5c80 100644 --- a/astro/src/config/menu/docs.ts +++ b/astro/src/config/menu/docs.ts @@ -3,36 +3,44 @@ import type { Menu } from '../types'; export const docsMenu: Menu = { sections: [ { - title: 'Getting started', + title: 'menu.gettingStarted', items: [ - { href: `/starter/installing`, label: 'Installing', ariaLabel: 'Installing Express' }, - { href: `/starter/hello-world`, label: 'Hello world', ariaLabel: 'Hello world example' }, - { href: `/starter/generator`, label: 'Express generator', ariaLabel: 'Express generator' }, + { href: `/starter/installing`, label: 'menu.installing', ariaLabel: 'menu.installingAria' }, + { + href: `/starter/hello-world`, + label: 'menu.helloWorld', + ariaLabel: 'menu.helloWorldAria', + }, + { + href: `/starter/generator`, + label: 'menu.expressGenerator', + ariaLabel: 'menu.expressGeneratorAria', + }, ], }, { - title: 'Guide', + title: 'menu.guide', items: [ - { href: `/guide/routing`, label: 'Routing', ariaLabel: 'Routing guide' }, + { href: `/guide/routing`, label: 'menu.routing', ariaLabel: 'menu.routingAria' }, { href: `/guide/writing-middleware`, - label: 'Writing middleware', - ariaLabel: 'Writing middleware guide', + label: 'menu.writingMiddleware', + ariaLabel: 'menu.writingMiddlewareAria', }, { href: `/guide/using-middleware`, - label: 'Using middleware', - ariaLabel: 'Using middleware guide', + label: 'menu.usingMiddleware', + ariaLabel: 'menu.usingMiddlewareAria', }, ], }, { - title: 'Advanced topics', + title: 'menu.advancedTopics', items: [ { href: `/advanced/developing-template-engines`, - label: 'Building template engines', - ariaLabel: 'Building template engines guide', + label: 'menu.buildingTemplateEngines', + ariaLabel: 'menu.buildingTemplateEnginesAria', }, ], }, diff --git a/astro/src/config/menu/main.ts b/astro/src/config/menu/main.ts index dd79fab297..ac6e15cac9 100644 --- a/astro/src/config/menu/main.ts +++ b/astro/src/config/menu/main.ts @@ -8,8 +8,8 @@ export const mainMenu: Menu = { { items: [ { - label: 'Docs', - ariaLabel: 'Documentation', + label: 'menu.docs', + ariaLabel: 'menu.docsAria', icon: 'document-bullet-list-multiple-20-regular', submenu: { versioned: ['5x', '4x'], @@ -17,8 +17,8 @@ export const mainMenu: Menu = { }, }, { - label: 'API', - ariaLabel: 'API Reference', + label: 'menu.api', + ariaLabel: 'menu.apiAria', icon: 'code-20-regular', submenu: { versioned: ['5x', '4x', '3x'], @@ -26,16 +26,21 @@ export const mainMenu: Menu = { }, }, { - label: 'Resources', - ariaLabel: 'Resources', + label: 'menu.resources', + ariaLabel: 'menu.resourcesAria', icon: 'folder-20-regular', submenu: { basePath: '/resources', items: resourcesMenu.items, }, }, - { href: `/blog`, label: 'Blog', icon: 'news-20-regular', ariaLabel: 'Blog' }, - { href: `/support`, label: 'Support', icon: 'info-20-regular', ariaLabel: 'Support' }, + { href: `/blog`, label: 'menu.blog', icon: 'news-20-regular', ariaLabel: 'menu.blogAria' }, + { + href: `/support`, + label: 'menu.support', + icon: 'info-20-regular', + ariaLabel: 'menu.supportAria', + }, ], }, ], diff --git a/astro/src/config/menu/middleware.ts b/astro/src/config/menu/middleware.ts index 0d07f57879..2933d86664 100644 --- a/astro/src/config/menu/middleware.ts +++ b/astro/src/config/menu/middleware.ts @@ -4,8 +4,8 @@ export const middlewareMenu: Menu = { items: [ { href: `/overview`, - label: 'Overview', - ariaLabel: 'Middleware overview', + label: 'menu.overview', + ariaLabel: 'menu.middlewareOverviewAria', }, { href: `/body-parser`, diff --git a/astro/src/config/menu/resources.ts b/astro/src/config/menu/resources.ts index fda00a5341..53e9e5d253 100644 --- a/astro/src/config/menu/resources.ts +++ b/astro/src/config/menu/resources.ts @@ -3,8 +3,8 @@ import { middlewareMenu } from './middleware'; export const resourcesMenu: Menu = { items: [ - { href: `/community`, label: 'Community', ariaLabel: 'Community resources' }, - { href: `/glossary`, label: 'Glossary', ariaLabel: 'Glossary of terms' }, + { href: `/community`, label: 'menu.community', ariaLabel: 'menu.communityAria' }, + { href: `/glossary`, label: 'menu.glossary', ariaLabel: 'menu.glossaryAria' }, { href: `/contributing`, label: 'Express community' }, { href: `/utils`, label: 'Express utilities' }, { diff --git a/astro/src/content/docs/de/3x/api.md b/astro/src/content/docs/de/3x/api.md new file mode 100644 index 0000000000..24b74d9ba3 --- /dev/null +++ b/astro/src/content/docs/de/3x/api.md @@ -0,0 +1,22 @@ +--- +title: Express 3.x - API-Referenz +description: Access the API reference for Express.js version 3.x, noting that this version is end-of-life and no longer maintained - includes details on modules and methods. +--- + +
    + +
    + **Express 3.x WIRD NICHT MEHR GEWARTET** + +Bekannte und unbekannte Probleme bei Sicherheit und Leistung in 3.x wurden seit dem letzten Update (1. August 2015) noch nicht behoben. Es wird dringend empfohlen, die aktuelle Version von Express zu verwenden. + +If you are unable to upgrade past 3.x, please consider [Commercial Support Options](/{{ page.lang }}/support#commercial-support-options). + +
    + +

    3.x-API

    + + +{% include api/en/3x/app.md %} + +
    diff --git a/astro/src/content/docs/de/3x/api/application/app-VERB.md b/astro/src/content/docs/de/3x/api/application/app-VERB.md new file mode 100644 index 0000000000..a007c0d02c --- /dev/null +++ b/astro/src/content/docs/de/3x/api/application/app-VERB.md @@ -0,0 +1,62 @@ +--- +title: app.VERB +description: The app.VERB methods provide the routing functionality +--- + +

    app.VERB(path, [callback...], callback)

    + +The `app.VERB()` methods provide the routing functionality +in Express, where VERB is one of the HTTP verbs, such +as `app.post()`. Multiple callbacks may be given, all are treated +equally, and behave just like middleware, with the one exception that +these callbacks may invoke `next('route')` to bypass the +remaining route callback(s). This mechanism can be used to perform pre-conditions +on a route then pass control to subsequent routes when there is no reason to proceed +with the route matched. + +The following snippet illustrates the most simple route definition possible. Express +translates the path strings to regular expressions, used internally to match incoming requests. +Query strings are not considered when peforming these matches, for example "GET /" +would match the following route, as would "GET /?name=tobi". + +```js +app.get('/', function (req, res) { + res.send('hello world'); +}); +``` + +Regular expressions may also be used, and can be useful +if you have very specific restraints, for example the following +would match "GET /commits/71dbb9c" as well as "GET /commits/71dbb9c..4c084f9". + +```js +app.get(/^\/commits\/(\w+)(?:\.\.(\w+))?$/, function (req, res) { + var from = req.params[0]; + var to = req.params[1] || 'HEAD'; + res.send('commit range ' + from + '..' + to); +}); +``` + +Several callbacks may also be passed, useful for re-using middleware +that load resources, perform validations, etc. + +```js +app.get('/user/:id', user.load, function () { + // ... +}); +``` + +These callbacks may be passed within arrays as well, these arrays are +simply flattened when passed: + +```js +var middleware = [loadForum, loadThread]; + +app.get('/forum/:fid/thread/:tid', middleware, function () { + // ... +}); + +app.post('/forum/:fid/thread/:tid', middleware, function () { + // ... +}); +``` diff --git a/astro/src/content/docs/de/3x/api/application/app-all.md b/astro/src/content/docs/de/3x/api/application/app-all.md new file mode 100644 index 0000000000..9fd9675018 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/application/app-all.md @@ -0,0 +1,37 @@ +--- +title: app.all +description: This method functions just like the app.VERB methods, +--- + +

    app.all(path, [callback...], callback)

    + +This method functions just like the `app.VERB()` methods, +however it matches all HTTP verbs. + +This method is extremely useful for +mapping "global" logic for specific path prefixes or arbitrary matches. +For example if you placed the following route at the top of all other +route definitions, it would require that all routes from that point on +would require authentication, and automatically load a user. Keep in mind +that these callbacks do not have to act as end points, `loadUser` +can perform a task, then `next()` to continue matching subsequent +routes. + +```js +app.all('*', requireAuthentication, loadUser); +``` + +Or the equivalent: + +```js +app.all('*', requireAuthentication); +app.all('*', loadUser); +``` + +Another great example of this is white-listed "global" functionality. Here +the example is much like before, however only restricting paths prefixed with +"/api": + +```js +app.all('/api/*', requireAuthentication); +``` diff --git a/astro/src/content/docs/de/3x/api/application/app-configure.md b/astro/src/content/docs/de/3x/api/application/app-configure.md new file mode 100644 index 0000000000..0287bf44a8 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/application/app-configure.md @@ -0,0 +1,45 @@ +--- +title: app.configure +description: Conditionally invoke callback when env matches app.get env, +--- + +

    app.configure([env], callback)

    + +Conditionally invoke `callback` when `env` matches `app.get('env')`, +aka `process.env.NODE_ENV`. This method remains for legacy reasons, and is effectively +an `if` statement as illustrated in the following snippets. These functions are not +required in order to use `app.set()` and other configuration methods. + +```js +// all environments +app.configure(function () { + app.set('title', 'My Application'); +}); + +// development only +app.configure('development', function () { + app.set('db uri', 'localhost/dev'); +}); + +// production only +app.configure('production', function () { + app.set('db uri', 'n.n.n.n/prod'); +}); +``` + +Is effectively sugar for: + +```js +// all environments +app.set('title', 'My Application'); + +// development only +if (app.get('env') === 'development') { + app.set('db uri', 'localhost/dev'); +} + +// production only +if (app.get('env') === 'production') { + app.set('db uri', 'n.n.n.n/prod'); +} +``` diff --git a/astro/src/content/docs/de/3x/api/application/app-disable.md b/astro/src/content/docs/de/3x/api/application/app-disable.md new file mode 100644 index 0000000000..e2ba96c1dd --- /dev/null +++ b/astro/src/content/docs/de/3x/api/application/app-disable.md @@ -0,0 +1,14 @@ +--- +title: app.disable +description: Set setting name to false. +--- + +

    app.disable(name)

    + +Set setting `name` to `false`. + +```js +app.disable('trust proxy'); +app.get('trust proxy'); +// => false +``` diff --git a/astro/src/content/docs/de/3x/api/application/app-disabled.md b/astro/src/content/docs/de/3x/api/application/app-disabled.md new file mode 100644 index 0000000000..0c7d092cf4 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/application/app-disabled.md @@ -0,0 +1,17 @@ +--- +title: app.disabled +description: Check if setting name is disabled. +--- + +

    app.disabled(name)

    + +Check if setting `name` is disabled. + +```js +app.disabled('trust proxy'); +// => true + +app.enable('trust proxy'); +app.disabled('trust proxy'); +// => false +``` diff --git a/astro/src/content/docs/de/3x/api/application/app-enable.md b/astro/src/content/docs/de/3x/api/application/app-enable.md new file mode 100644 index 0000000000..35534cb3ad --- /dev/null +++ b/astro/src/content/docs/de/3x/api/application/app-enable.md @@ -0,0 +1,14 @@ +--- +title: app.enable +description: Set setting name to true. +--- + +

    app.enable(name)

    + +Set setting `name` to `true`. + +```js +app.enable('trust proxy'); +app.get('trust proxy'); +// => true +``` diff --git a/astro/src/content/docs/de/3x/api/application/app-enabled.md b/astro/src/content/docs/de/3x/api/application/app-enabled.md new file mode 100644 index 0000000000..a19432d554 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/application/app-enabled.md @@ -0,0 +1,17 @@ +--- +title: app.enabled +description: Check if setting name is enabled. +--- + +

    app.enabled(name)

    + +Check if setting `name` is enabled. + +```js +app.enabled('trust proxy'); +// => false + +app.enable('trust proxy'); +app.enabled('trust proxy'); +// => true +``` diff --git a/astro/src/content/docs/de/3x/api/application/app-engine.md b/astro/src/content/docs/de/3x/api/application/app-engine.md new file mode 100644 index 0000000000..9ff0a8778b --- /dev/null +++ b/astro/src/content/docs/de/3x/api/application/app-engine.md @@ -0,0 +1,44 @@ +--- +title: app.engine +description: Register the given template engine callback as ext +--- + +

    app.engine(ext, callback)

    + +Register the given template engine `callback` as `ext` + +By default will `require()` the engine based on the +file extension. For example if you try to render +a "foo.jade" file Express will invoke the following internally, +and cache the `require()` on subsequent calls to increase +performance. + +```js +app.engine('jade', require('jade').__express); +``` + +For engines that do not provide `.__express` out of the box - +or if you wish to "map" a different extension to the template engine +you may use this method. For example mapping the EJS template engine to +".html" files: + +```js +app.engine('html', require('ejs').renderFile); +``` + +In this case EJS provides a `.renderFile()` method with +the same signature that Express expects: `(path, options, callback)`, +though note that it aliases this method as `ejs.__express` internally +so if you're using ".ejs" extensions you dont need to do anything. + +Some template engines do not follow this convention, the +consolidate.js +library was created to map all of node's popular template +engines to follow this convention, thus allowing them to +work seemlessly within Express. + +```js +var engines = require('consolidate'); +app.engine('haml', engines.haml); +app.engine('html', engines.hogan); +``` diff --git a/astro/src/content/docs/de/3x/api/application/app-get.md b/astro/src/content/docs/de/3x/api/application/app-get.md new file mode 100644 index 0000000000..767117eda9 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/application/app-get.md @@ -0,0 +1,17 @@ +--- +title: app.get +description: Get setting name value. +--- + +

    app.get(name)

    + +Get setting `name` value. + +```js +app.get('title'); +// => undefined + +app.set('title', 'My Site'); +app.get('title'); +// => "My Site" +``` diff --git a/astro/src/content/docs/de/3x/api/application/app-listen.md b/astro/src/content/docs/de/3x/api/application/app-listen.md new file mode 100644 index 0000000000..242d429aeb --- /dev/null +++ b/astro/src/content/docs/de/3x/api/application/app-listen.md @@ -0,0 +1,41 @@ +--- +title: app.listen +description: Bind and listen for connections on the given host and port, +--- + +

    app.listen()

    + +Bind and listen for connections on the given host and port, +this method is identical to node's http.Server#listen(). + +```js +var express = require('express'); +var app = express(); +app.listen(3000); +``` + +The `app` returned by `express()` is in fact a JavaScript +`Function`, designed to be passed to node's http servers as a callback +to handle requests. This allows you to provide both HTTP and HTTPS versions of +your app with the same codebase easily, as the app does not inherit from these, +it is simply a callback: + +```js +var express = require('express'); +var https = require('https'); +var http = require('http'); +var app = express(); + +http.createServer(app).listen(80); +https.createServer(options, app).listen(443); +``` + +The `app.listen()` method is simply a convenience method defined as, +if you wish to use HTTPS or provide both, use the technique above. + +```js +app.listen = function () { + var server = http.createServer(this); + return server.listen.apply(server, arguments); +}; +``` diff --git a/astro/src/content/docs/de/3x/api/application/app-locals.md b/astro/src/content/docs/de/3x/api/application/app-locals.md new file mode 100644 index 0000000000..4436b537f8 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/application/app-locals.md @@ -0,0 +1,52 @@ +--- +title: app.locals +description: Application local variables are provided to all templates +--- + +

    app.locals

    + +Application local variables are provided to all templates +rendered within the application. This is useful for providing +helper functions to templates, as well as app-level data. + +```js +app.locals.title = 'My App'; +app.locals.strftime = require('strftime'); +``` + +The `app.locals` object is a JavaScript `Function`, +which when invoked with an object will merge properties into itself, providing +a simple way to expose existing objects as local variables. + +```js +app.locals({ + title: 'My App', + phone: '1-250-858-9990', + email: 'me@myapp.com', +}); + +console.log(app.locals.title); +// => 'My App' + +console.log(app.locals.email); +// => 'me@myapp.com' +``` + +A consequence of the `app.locals` Object being ultimately a Javascript Function Object is that you must not reuse existing (native) named properties for your own variable names, such as `name, apply, bind, call, arguments, length, constructor`. + +```js +app.locals({ name: 'My App' }); + +console.log(app.locals.name); +// => return 'app.locals' in place of 'My App' (app.locals is a Function !) +// => if name's variable is used in a template, a ReferenceError will be returned. +``` + +The full list of native named properties can be found in many specifications. The JavaScript specification introduced original properties, some of which still recognized by modern engines, and the EcmaScript specification then built on it and normalized the set of properties, adding new ones and removing deprecated ones. Check out properties for Functions and Objects if interested. + +By default Express exposes only a single app-level local variable, `settings`. + +```js +app.set('title', 'My App'); +// use settings.title in a view +``` diff --git a/astro/src/content/docs/de/3x/api/application/app-param.md b/astro/src/content/docs/de/3x/api/application/app-param.md new file mode 100644 index 0000000000..97d935d169 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/application/app-param.md @@ -0,0 +1,75 @@ +--- +title: app.param +description: Map logic to route parameters. For example when user +--- + +

    app.param([name], callback)

    + +Map logic to route parameters. For example when `:user` +is present in a route path you may map user loading logic to automatically +provide `req.user` to the route, or perform validations +on the parameter input. + +The following snippet illustrates how the `callback` +is much like middleware, thus supporting async operations, however +providing the additional value of the parameter, here named as `id`. +An attempt to load the user is then performed, assigning `req.user`, +otherwise passing an error to `next(err)`. + +```js +app.param('user', function (req, res, next, id) { + User.find(id, function (err, user) { + if (err) { + next(err); + } else if (user) { + req.user = user; + next(); + } else { + next(new Error('failed to load user')); + } + }); +}); +``` + +Alternatively you may pass only a `callback`, in which +case you have the opportunity to alter the `app.param()` API. +For example the express-params +defines the following callback which allows you to restrict parameters to a given +regular expression. + +This example is a bit more advanced, checking if the second argument is a regular +expression, returning the callback which acts much like the "user" param example. + +```js +app.param(function (name, fn) { + if (fn instanceof RegExp) { + return function (req, res, next, val) { + var captures; + if ((captures = fn.exec(String(val)))) { + req.params[name] = captures; + next(); + } else { + next('route'); + } + }; + } +}); +``` + +The method could now be used to effectively validate parameters, or also +parse them to provide capture groups: + +```js +app.param('id', /^\d+$/); + +app.get('/user/:id', function (req, res) { + res.send('user ' + req.params.id); +}); + +app.param('range', /^(\w+)\.\.(\w+)?$/); + +app.get('/range/:range', function (req, res) { + var range = req.params.range; + res.send('from ' + range[1] + ' to ' + range[2]); +}); +``` diff --git a/astro/src/content/docs/de/3x/api/application/app-render.md b/astro/src/content/docs/de/3x/api/application/app-render.md new file mode 100644 index 0000000000..58e286aa46 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/application/app-render.md @@ -0,0 +1,20 @@ +--- +title: app.render +description: Render a view with a callback responding with +--- + +

    app.render(view, [options], callback)

    + +Render a `view` with a callback responding with +the rendered string. This is the app-level variant of `res.render()`, +and otherwise behaves the same way. + +```js +app.render('email', function (err, html) { + // ... +}); + +app.render('email', { name: 'Tobi' }, function (err, html) { + // ... +}); +``` diff --git a/astro/src/content/docs/de/3x/api/application/app-routes.md b/astro/src/content/docs/de/3x/api/application/app-routes.md new file mode 100644 index 0000000000..c60979174f --- /dev/null +++ b/astro/src/content/docs/de/3x/api/application/app-routes.md @@ -0,0 +1,34 @@ +--- +title: app.routes +description: The app.routes object houses all of the routes defined mapped +--- + +

    app.routes

    + +The `app.routes` object houses all of the routes defined mapped +by the associated HTTP verb. This object may be used for introspection capabilities, +for example Express uses this internally not only for routing but to provide default +OPTIONS behaviour unless `app.options()` is used. Your application +or framework may also remove routes by simply by removing them from this object. + +The output of `console.log(app.routes)`: + +``` +{ get: + [ { path: '/', + method: 'get', + callbacks: [Object], + keys: [], + regexp: /^\/\/?$/i }, + { path: '/user/:id', + method: 'get', + callbacks: [Object], + keys: [{ name: 'id', optional: false }], + regexp: /^\/user\/(?:([^\/]+?))\/?$/i } ], + delete: + [ { path: '/user/:id', + method: 'delete', + callbacks: [Object], + keys: [Object], + regexp: /^\/user\/(?:([^\/]+?))\/?$/i } ] } +``` diff --git a/astro/src/content/docs/de/3x/api/application/app-set.md b/astro/src/content/docs/de/3x/api/application/app-set.md new file mode 100644 index 0000000000..62ee6ac565 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/application/app-set.md @@ -0,0 +1,14 @@ +--- +title: app.set +description: Assigns setting name to value. +--- + +

    app.set(name, value)

    + +Assigns setting `name` to `value`. + +```js +app.set('title', 'My Site'); +app.get('title'); +// => "My Site" +``` diff --git a/astro/src/content/docs/de/3x/api/application/app-settings.md b/astro/src/content/docs/de/3x/api/application/app-settings.md new file mode 100644 index 0000000000..65dc18f6b8 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/application/app-settings.md @@ -0,0 +1,19 @@ +--- +title: settings +description: The following settings are provided to alter how Express will behave +--- + +

    settings

    + +The following settings are provided to alter how Express will behave: + +- `env` Environment mode, defaults to process.env.NODE_ENV or "development" +- `trust proxy` Enables reverse proxy support, disabled by default +- `jsonp callback name` Changes the default callback name of ?callback= +- `json replacer` JSON replacer callback, null by default +- `json spaces` JSON response spaces for formatting, defaults to 2 in development, 0 in production +- `case sensitive routing` Enable case sensitivity, disabled by default, treating "/Foo" and "/foo" as the same +- `strict routing` Enable strict routing, by default "/foo" and "/foo/" are treated the same by the router +- `view cache` Enables view template compilation caching, enabled in production by default +- `view engine` The default engine extension to use when omitted +- `views` The view directory path, defaulting to "process.cwd() + '/views'" diff --git a/astro/src/content/docs/de/3x/api/application/app-use.md b/astro/src/content/docs/de/3x/api/application/app-use.md new file mode 100644 index 0000000000..ee0ca34392 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/application/app-use.md @@ -0,0 +1,94 @@ +--- +title: app.use +description: Use the given middleware function, with optional mount path, +--- + +

    app.use([path], function)

    + +Use the given middleware `function`, with optional mount `path`, +defaulting to "/". + +```js +var express = require('express'); +var app = express(); + +// simple logger +app.use(function (req, res, next) { + console.log('%s %s', req.method, req.url); + next(); +}); + +// respond +app.use(function (req, res, next) { + res.send('Hello World'); +}); + +app.listen(3000); +``` + +The "mount" path is stripped and is not visible +to the middleware `function`. The main effect of this feature is that +mounted middleware may operate without code changes regardless of its "prefix" +pathname. + +
    +A route will match any path that follows its path immediately with either a "`/`" or a "`.`". For example: `app.use('/apple', ...)` will match _/apple_, _/apple/images_, _/apple/images/news_, _/apple.html_, _/apple.html.txt_, and so on. +
    + +Here's a concrete example, take the typical use-case of serving files in ./public +using the `express.static()` middleware: + +```js +// GET /javascripts/jquery.js +// GET /style.css +// GET /favicon.ico +app.use(express.static(path.join(__dirname, 'public'))); +``` + +Say for example you wanted to prefix all static files with "/static", you could +use the "mounting" feature to support this. Mounted middleware functions are _not_ +invoked unless the `req.url` contains this prefix, at which point +it is stripped when the function is invoked. This affects this function only, +subsequent middleware will see `req.url` with "/static" included +unless they are mounted as well. + +```js +// GET /static/javascripts/jquery.js +// GET /static/style.css +// GET /static/favicon.ico +app.use('/static', express.static(path.join(__dirname, 'public'))); +``` + +The order of which middleware are "defined" using `app.use()` is +very important, they are invoked sequentially, thus this defines middleware +precedence. For example usually `express.logger()` is the very +first middleware you would use, logging every request: + +```js +app.use(express.logger()); +app.use(express.static(path.join(__dirname, 'public'))); +app.use(function (req, res) { + res.send('Hello'); +}); +``` + +Now suppose you wanted to ignore logging requests for static files, but to +continue logging routes and middleware defined after `logger()`, +you would simply move `static()` above: + +```js +app.use(express.static(path.join(__dirname, 'public'))); +app.use(express.logger()); +app.use(function (req, res) { + res.send('Hello'); +}); +``` + +Another concrete example would be serving files from multiple directories, +giving precedence to "./public" over the others: + +```js +app.use(express.static(path.join(__dirname, 'public'))); +app.use(express.static(path.join(__dirname, 'files'))); +app.use(express.static(path.join(__dirname, 'uploads'))); +``` diff --git a/astro/src/content/docs/de/3x/api/application/overview.md b/astro/src/content/docs/de/3x/api/application/overview.md new file mode 100644 index 0000000000..3b5dc69334 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/application/overview.md @@ -0,0 +1,20 @@ +--- +title: Properties +description: section markdown="1"> +--- + +

    Application

    + +The `app` object conventionally denotes the Express application. +Create it by calling the top-level `express()` function exported by the Express module: + +```js +var express = require('express'); +var app = express(); + +app.get('/', function (req, res) { + res.send('hello world'); +}); + +app.listen(3000); +``` diff --git a/astro/src/content/docs/de/3x/api/express.md b/astro/src/content/docs/de/3x/api/express.md new file mode 100644 index 0000000000..e04222a0d0 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/express.md @@ -0,0 +1,19 @@ +--- +title: Express +description: h2 id="express">express() +--- + +

    express()

    + +Creates an Express application. The `express()` function is a top-level function exported by the _express_ module. + +```js +var express = require('express'); +var app = express(); + +app.get('/', function (req, res) { + res.send('hello world'); +}); + +app.listen(3000); +``` diff --git a/astro/src/content/docs/de/3x/api/middleware/middleware.md b/astro/src/content/docs/de/3x/api/middleware/middleware.md new file mode 100644 index 0000000000..596e3d76cb --- /dev/null +++ b/astro/src/content/docs/de/3x/api/middleware/middleware.md @@ -0,0 +1,34 @@ +--- +title: Middleware +description: h2 id="middleware">Middleware +--- + +

    Middleware

    + +
    + {% include api/en/3x/mw-basicAuth.md %} +
    + +
    + {% include api/en/3x/mw-bodyParser.md %} +
    + +
    + {% include api/en/3x/mw-compress.md %} +
    + +
    + {% include api/en/3x/mw-cookieParser.md %} +
    + +
    + {% include api/en/3x/mw-cookieSession.md %} +
    + +
    + {% include api/en/3x/mw-csrf.md %} +
    + +
    + {% include api/en/3x/mw-directory.md %} +
    diff --git a/astro/src/content/docs/de/3x/api/middleware/mw-basicAuth.md b/astro/src/content/docs/de/3x/api/middleware/mw-basicAuth.md new file mode 100644 index 0000000000..7d4f7fe3ed --- /dev/null +++ b/astro/src/content/docs/de/3x/api/middleware/mw-basicAuth.md @@ -0,0 +1,36 @@ +--- +title: basicAuth +description: Basic Authentication middleware, populating req.user +--- + +

    basicAuth()

    + +Basic Authentication middleware, populating `req.user` +with the username. + +Simple username and password: + +```js +app.use(express.basicAuth('username', 'password')); +``` + +Callback verification: + +```js +app.use( + express.basicAuth(function (user, pass) { + return user === 'tj' && pass === 'wahoo'; + }) +); +``` + +Async callback verification, accepting `fn(err, user)`, +in this case `req.user` will be the user object passed. + +```js +app.use( + express.basicAuth(function (user, pass, fn) { + User.authenticate({ user: user, pass: pass }, fn); + }) +); +``` diff --git a/astro/src/content/docs/de/3x/api/middleware/mw-bodyParser.md b/astro/src/content/docs/de/3x/api/middleware/mw-bodyParser.md new file mode 100644 index 0000000000..3388e4d605 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/middleware/mw-bodyParser.md @@ -0,0 +1,32 @@ +--- +title: bodyParser +description: Request body parsing middleware supporting JSON, urlencoded, +--- + +

    bodyParser()

    + +Request body parsing middleware supporting JSON, urlencoded, +and multipart requests. This middleware is simply a wrapper +for the `json()`, `urlencoded()`, and +`multipart()` middleware. + +```js +app.use(express.bodyParser()); + +// is equivalent to: +app.use(express.json()); +app.use(express.urlencoded()); +app.use(express.multipart()); +``` + +For security sake, it's better to disable file upload if your application +doesn't need it. To do this, use only the needed middleware, i.e. don't use +the `bodyParser` and `multipart()` middleware: + +```js +app.use(express.json()); +app.use(express.urlencoded()); +``` + +If your application needs file upload you should set up +a strategy for dealing with those files. diff --git a/astro/src/content/docs/de/3x/api/middleware/mw-compress.md b/astro/src/content/docs/de/3x/api/middleware/mw-compress.md new file mode 100644 index 0000000000..03ccb87b75 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/middleware/mw-compress.md @@ -0,0 +1,17 @@ +--- +title: compress +description: Compress response data with gzip / deflate. This middleware +--- + +

    compress()

    + +Compress response data with gzip / deflate. This middleware +should be placed "high" within the stack to ensure all +responses may be compressed. + +```js +app.use(express.logger()); +app.use(express.compress()); +app.use(express.methodOverride()); +app.use(express.bodyParser()); +``` diff --git a/astro/src/content/docs/de/3x/api/middleware/mw-cookieParser.md b/astro/src/content/docs/de/3x/api/middleware/mw-cookieParser.md new file mode 100644 index 0000000000..32990bccef --- /dev/null +++ b/astro/src/content/docs/de/3x/api/middleware/mw-cookieParser.md @@ -0,0 +1,15 @@ +--- +title: cookieParser +description: Parses the Cookie header field and populates req.cookies +--- + +

    cookieParser()

    + +Parses the Cookie header field and populates `req.cookies` +with an object keyed by the cookie names. Optionally you may enabled +signed cookie support by passing a `secret` string. + +```js +app.use(express.cookieParser()); +app.use(express.cookieParser('some secret')); +``` diff --git a/astro/src/content/docs/de/3x/api/middleware/mw-cookieSession.md b/astro/src/content/docs/de/3x/api/middleware/mw-cookieSession.md new file mode 100644 index 0000000000..0e984f5172 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/middleware/mw-cookieSession.md @@ -0,0 +1,24 @@ +--- +title: cookieSession +description: Provides cookie-based sessions, and populates req.session. +--- + +

    cookieSession()

    + +Provides cookie-based sessions, and populates `req.session`. +This middleware takes the following options: + +- `key` cookie name defaulting to `connect.sess` +- `secret` prevents cookie tampering +- `cookie` session cookie settings, defaulting to `{ path: '/', httpOnly: true, maxAge: null }` +- `proxy` trust the reverse proxy when setting secure cookies (via "x-forwarded-proto") + +```js +app.use(express.cookieSession()); +``` + +To clear a cookie simply assign the session to null before responding: + +```js +req.session = null; +``` diff --git a/astro/src/content/docs/de/3x/api/middleware/mw-csrf.md b/astro/src/content/docs/de/3x/api/middleware/mw-csrf.md new file mode 100644 index 0000000000..83a5f6598c --- /dev/null +++ b/astro/src/content/docs/de/3x/api/middleware/mw-csrf.md @@ -0,0 +1,20 @@ +--- +title: csrf +description: CSRF protection middleware. +--- + +

    csrf()

    + +CSRF protection middleware. + +By default this middleware generates a token named "\_csrf" +which should be added to requests which mutate +state, within a hidden form field, query-string etc. This +token is validated against `req.csrfToken()`. + +The default `value` function checks `req.body` generated +by the `bodyParser()` middleware, `req.query` generated +by `query()`, and the "X-CSRF-Token" header field. + +This middleware requires session support, thus should be added +somewhere below `session()`. diff --git a/astro/src/content/docs/de/3x/api/middleware/mw-directory.md b/astro/src/content/docs/de/3x/api/middleware/mw-directory.md new file mode 100644 index 0000000000..fe1219ff55 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/middleware/mw-directory.md @@ -0,0 +1,21 @@ +--- +title: directory +description: Directory serving middleware, serves the given path. +--- + +

    directory()

    + +Directory serving middleware, serves the given `path`. +This middleware may be paired with `static()` to serve +files, providing a full-featured file browser. + +```js +app.use(express.directory('public')); +app.use(express.static('public')); +``` + +This middleware accepts the following options: + +- `hidden` display hidden (dot) files. Defaults to false. +- `icons` display icons. Defaults to false. +- `filter` Apply this filter function to files. Defaults to false. diff --git a/astro/src/content/docs/de/3x/api/request/overview.md b/astro/src/content/docs/de/3x/api/request/overview.md new file mode 100644 index 0000000000..fc7e96b47d --- /dev/null +++ b/astro/src/content/docs/de/3x/api/request/overview.md @@ -0,0 +1,121 @@ +--- +title: Req +description: h2 id="request">Request +--- + +

    Request

    + +The `req` object is an enhanced version of Node's own request object +and supports all [built-in fields and methods](https://nodejs.org/api/http.html#http_class_http_incomingmessage). + +
    + {% include api/en/3x/req-params.md %} +
    + +
    + {% include api/en/3x/req-query.md %} +
    + +
    + {% include api/en/3x/req-body.md %} +
    + +
    + {% include api/en/3x/req-files.md %} +
    + +
    + {% include api/en/3x/req-param.md %} +
    + +
    + {% include api/en/3x/req-route.md %} +
    + +
    + {% include api/en/3x/req-cookies.md %} +
    + +
    + {% include api/en/3x/req-signedCookies.md %} +
    + +
    + {% include api/en/3x/req-header.md %} +
    + +
    + {% include api/en/3x/req-accepts.md %} +
    + +
    + {% include api/en/3x/req-accepted.md %} +
    + +
    + {% include api/en/3x/req-is.md %} +
    + +
    + {% include api/en/3x/req-ip.md %} +
    + +
    + {% include api/en/3x/req-ips.md %} +
    + +
    + {% include api/en/3x/req-path.md %} +
    + +
    + {% include api/en/3x/req-host.md %} +
    + +
    + {% include api/en/3x/req-fresh.md %} +
    + +
    + {% include api/en/3x/req-stale.md %} +
    + +
    + {% include api/en/3x/req-xhr.md %} +
    + +
    + {% include api/en/3x/req-protocol.md %} +
    + +
    + {% include api/en/3x/req-secure.md %} +
    + +
    + {% include api/en/3x/req-subdomains.md %} +
    + +
    + {% include api/en/3x/req-originalUrl.md %} +
    + +
    + {% include api/en/3x/req-acceptedLanguages.md %} +
    + +
    + {% include api/en/3x/req-acceptedCharsets.md %} +
    + +
    + {% include api/en/3x/req-acceptsCharset.md %} +
    + +
    + {% include api/en/3x/req-acceptsLanguage.md %} +
    + +
    + {% include api/en/3x/req-res.md %} +
    diff --git a/astro/src/content/docs/de/3x/api/request/req-accepted.md b/astro/src/content/docs/de/3x/api/request/req-accepted.md new file mode 100644 index 0000000000..54e1c42558 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/request/req-accepted.md @@ -0,0 +1,19 @@ +--- +title: req.accepted +description: Return an array of Accepted media types ordered from highest quality to lowest. +--- + +

    req.accepted

    + +Return an array of Accepted media types ordered from highest quality to lowest. + +``` +[ { value: 'application/json', + quality: 1, + type: 'application', + subtype: 'json' }, + { value: 'text/html', + quality: 0.5, + type: 'text', + subtype: 'html' } ] +``` diff --git a/astro/src/content/docs/de/3x/api/request/req-acceptedCharsets.md b/astro/src/content/docs/de/3x/api/request/req-acceptedCharsets.md new file mode 100644 index 0000000000..91e693c493 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/request/req-acceptedCharsets.md @@ -0,0 +1,13 @@ +--- +title: req.acceptedCharsets +description: Return an array of Accepted charsets ordered from highest quality to lowest. +--- + +

    req.acceptedCharsets

    + +Return an array of Accepted charsets ordered from highest quality to lowest. + +``` +Accept-Charset: iso-8859-5;q=.2, unicode-1-1;q=0.8 +// => ['unicode-1-1', 'iso-8859-5'] +``` diff --git a/astro/src/content/docs/de/3x/api/request/req-acceptedLanguages.md b/astro/src/content/docs/de/3x/api/request/req-acceptedLanguages.md new file mode 100644 index 0000000000..d7b70d4b32 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/request/req-acceptedLanguages.md @@ -0,0 +1,13 @@ +--- +title: req.acceptedLanguages +description: Return an array of Accepted languages ordered from highest quality to lowest. +--- + +

    req.acceptedLanguages

    + +Return an array of Accepted languages ordered from highest quality to lowest. + +``` +Accept-Language: en;q=.5, en-us +// => ['en-us', 'en'] +``` diff --git a/astro/src/content/docs/de/3x/api/request/req-accepts.md b/astro/src/content/docs/de/3x/api/request/req-accepts.md new file mode 100644 index 0000000000..e74a39a426 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/request/req-accepts.md @@ -0,0 +1,41 @@ +--- +title: req.accepts +description: Check if the given types are acceptable, returning +--- + +

    req.accepts(types)

    + +Check if the given `types` are acceptable, returning +the best match when true, otherwise `undefined` - in which +case you should respond with 406 "Not Acceptable". + +The `type` value may be a single mime type string +such as "application/json", the extension name +such as "json", a comma-delimited list or an array. When a list +or array is given the best match, if any is returned. + +```js +// Accept: text/html +req.accepts('html'); +// => "html" + +// Accept: text/*, application/json +req.accepts('html'); +// => "html" +req.accepts('text/html'); +// => "text/html" +req.accepts('json, text'); +// => "json" +req.accepts('application/json'); +// => "application/json" + +// Accept: text/*, application/json +req.accepts('image/png'); +req.accepts('png'); +// => undefined + +// Accept: text/*;q=.5, application/json +req.accepts(['html', 'json']); +req.accepts('html, json'); +// => "json" +``` diff --git a/astro/src/content/docs/de/3x/api/request/req-acceptsCharset.md b/astro/src/content/docs/de/3x/api/request/req-acceptsCharset.md new file mode 100644 index 0000000000..d210b4fd0b --- /dev/null +++ b/astro/src/content/docs/de/3x/api/request/req-acceptsCharset.md @@ -0,0 +1,8 @@ +--- +title: req.acceptsCharset +description: Check if the given charset are acceptable. +--- + +

    req.acceptsCharset(charset)

    + +Check if the given `charset` are acceptable. diff --git a/astro/src/content/docs/de/3x/api/request/req-acceptsLanguage.md b/astro/src/content/docs/de/3x/api/request/req-acceptsLanguage.md new file mode 100644 index 0000000000..4ab1331f28 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/request/req-acceptsLanguage.md @@ -0,0 +1,8 @@ +--- +title: req.acceptsLanguage +description: Check if the given lang are acceptable. +--- + +

    req.acceptsLanguage(lang)

    + +Check if the given `lang` are acceptable. diff --git a/astro/src/content/docs/de/3x/api/request/req-body.md b/astro/src/content/docs/de/3x/api/request/req-body.md new file mode 100644 index 0000000000..2d49e5e41f --- /dev/null +++ b/astro/src/content/docs/de/3x/api/request/req-body.md @@ -0,0 +1,24 @@ +--- +title: req.body +description: This property is an object containing the parsed request body. This feature +--- + +

    req.body

    + +This property is an object containing the parsed request body. This feature +is provided by the `bodyParser()` middleware, though other body +parsing middleware may follow this convention as well. This property +defaults to `{}` when `bodyParser()` is used. + +```js +// POST user[name]=tobi&user[email]=tobi@learnboost.com +console.log(req.body.user.name); +// => "tobi" + +console.log(req.body.user.email); +// => "tobi@learnboost.com" + +// POST { "name": "tobi" } +console.log(req.body.name); +// => "tobi" +``` diff --git a/astro/src/content/docs/de/3x/api/request/req-cookies.md b/astro/src/content/docs/de/3x/api/request/req-cookies.md new file mode 100644 index 0000000000..2bbd590d30 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/request/req-cookies.md @@ -0,0 +1,16 @@ +--- +title: req.cookies +description: This object requires the cookieParser middleware for use. +--- + +

    req.cookies

    + +This object requires the `cookieParser()` middleware for use. +It contains cookies sent by the user-agent. If no cookies are sent, it +defaults to `{}`. + +```js +// Cookie: name=tj +console.log(req.cookies.name); +// => "tj" +``` diff --git a/astro/src/content/docs/de/3x/api/request/req-files.md b/astro/src/content/docs/de/3x/api/request/req-files.md new file mode 100644 index 0000000000..f81cd53501 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/request/req-files.md @@ -0,0 +1,50 @@ +--- +title: req.files +description: This property is an object of the files uploaded. This feature +--- + +

    req.files

    + +This property is an object of the files uploaded. This feature +is provided by the `bodyParser()` middleware, though other body +parsing middleware may follow this convention as well. This property +defaults to `{}` when `bodyParser()` is used. + +For example if a file field was named "image", +and a file was uploaded, `req.files.image` would contain +the following `File` object: + +``` +{ size: 74643, + path: '/tmp/8ef9c52abe857867fd0a4e9a819d1876', + name: 'edge.png', + type: 'image/png', + hash: false, + lastModifiedDate: Thu Aug 09 2012 20:07:51 GMT-0700 (PDT), + _writeStream: + { path: '/tmp/8ef9c52abe857867fd0a4e9a819d1876', + fd: 13, + writable: false, + flags: 'w', + encoding: 'binary', + mode: 438, + bytesWritten: 74643, + busy: false, + _queue: [], + _open: [Function], + drainable: true }, + length: [Getter], + filename: [Getter], + mime: [Getter] } +``` + +The `bodyParser()` middleware utilizes the +node-formidable +module internally, and accepts the same options. An example of this +is the `keepExtensions` formidable option, defaulting to false +which in this case gives you the filename "/tmp/8ef9c52abe857867fd0a4e9a819d1876" void of +the ".png" extension. To enable this, and others you may pass them to `bodyParser()`: + +```js +app.use(express.bodyParser({ keepExtensions: true, uploadDir: '/my/files' })); +``` diff --git a/astro/src/content/docs/de/3x/api/request/req-fresh.md b/astro/src/content/docs/de/3x/api/request/req-fresh.md new file mode 100644 index 0000000000..ecbeb9ce53 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/request/req-fresh.md @@ -0,0 +1,14 @@ +--- +title: req.fresh +description: Check if the request is fresh - aka Last-Modified and/or the ETag still match, +--- + +

    req.fresh

    + +Check if the request is fresh - aka Last-Modified and/or the ETag still match, +indicating that the resource is "fresh". + +```js +console.dir(req.fresh); +// => true +``` diff --git a/astro/src/content/docs/de/3x/api/request/req-header.md b/astro/src/content/docs/de/3x/api/request/req-header.md new file mode 100644 index 0000000000..0c7facfd73 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/request/req-header.md @@ -0,0 +1,21 @@ +--- +title: req.get +description: Get the case-insensitive request header field. The Referrer and Referer fields are interchangeable. +--- + +

    req.get(field)

    + +Get the case-insensitive request header `field`. The "Referrer" and "Referer" fields are interchangeable. + +```js +req.get('Content-Type'); +// => "text/plain" + +req.get('content-type'); +// => "text/plain" + +req.get('Something'); +// => undefined +``` + +p Aliased as `req.header(field)`. diff --git a/astro/src/content/docs/de/3x/api/request/req-host.md b/astro/src/content/docs/de/3x/api/request/req-host.md new file mode 100644 index 0000000000..37701792b5 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/request/req-host.md @@ -0,0 +1,14 @@ +--- +title: req.host +description: Returns the hostname from the "Host" header field (void of portno). +--- + +

    req.host

    + +Returns the hostname from the "Host" header field (void of portno). + +```js +// Host: "example.com:3000" +console.dir(req.host); +// => 'example.com' +``` diff --git a/astro/src/content/docs/de/3x/api/request/req-ip.md b/astro/src/content/docs/de/3x/api/request/req-ip.md new file mode 100644 index 0000000000..871a48f6c7 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/request/req-ip.md @@ -0,0 +1,14 @@ +--- +title: req.ip +description: Return the remote address, or when "trust proxy" +--- + +

    req.ip

    + +Return the remote address, or when "trust proxy" +is enabled - the upstream address. + +```js +console.dir(req.ip); +// => '127.0.0.1' +``` diff --git a/astro/src/content/docs/de/3x/api/request/req-ips.md b/astro/src/content/docs/de/3x/api/request/req-ips.md new file mode 100644 index 0000000000..ca99131757 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/request/req-ips.md @@ -0,0 +1,15 @@ +--- +title: req.ips +description: When trust proxy is true, parse +--- + +

    req.ips

    + +When "trust proxy" is `true`, parse +the "X-Forwarded-For" ip address list +and return an array, otherwise an empty +array is returned. + +For example if the value were "client, proxy1, proxy2" +you would receive the array `["client", "proxy1", "proxy2"]` +where "proxy2" is the furthest down-stream. diff --git a/astro/src/content/docs/de/3x/api/request/req-is.md b/astro/src/content/docs/de/3x/api/request/req-is.md new file mode 100644 index 0000000000..5f5ce21e77 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/request/req-is.md @@ -0,0 +1,26 @@ +--- +title: req.is +description: Check if the incoming request contains the "Content-Type" +--- + +

    req.is(type)

    + +Check if the incoming request contains the "Content-Type" +header field, and it matches the give mime `type`. + +```js +// With Content-Type: text/html; charset=utf-8 +req.is('html'); +req.is('text/html'); +req.is('text/*'); +// => true + +// When Content-Type is application/json +req.is('json'); +req.is('application/json'); +req.is('application/*'); +// => true + +req.is('html'); +// => false +``` diff --git a/astro/src/content/docs/de/3x/api/request/req-originalUrl.md b/astro/src/content/docs/de/3x/api/request/req-originalUrl.md new file mode 100644 index 0000000000..6f84143c80 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/request/req-originalUrl.md @@ -0,0 +1,18 @@ +--- +title: req.originalUrl +description: This property is much like req.url, however it retains +--- + +

    req.originalUrl

    + +This property is much like `req.url`, however it retains +the original request url, allowing you to rewrite `req.url` +freely for internal routing purposes. For example the "mounting" feature +of app.use() will rewrite `req.url` to +strip the mount point. + +```js +// GET /search?q=something +console.log(req.originalUrl); +// => "/search?q=something" +``` diff --git a/astro/src/content/docs/de/3x/api/request/req-param.md b/astro/src/content/docs/de/3x/api/request/req-param.md new file mode 100644 index 0000000000..f2eb23c60d --- /dev/null +++ b/astro/src/content/docs/de/3x/api/request/req-param.md @@ -0,0 +1,32 @@ +--- +title: req.param +description: Return the value of param name when present. +--- + +

    req.param(name)

    + +Return the value of param `name` when present. + +```js +// ?name=tobi +req.param('name'); +// => "tobi" + +// POST name=tobi +req.param('name'); +// => "tobi" + +// /user/tobi for /user/:name +req.param('name'); +// => "tobi" +``` + +Lookup is performed in the following order: + +- `req.params` +- `req.body` +- `req.query` + +Direct access to `req.body`, `req.params`, +and `req.query` should be favoured for clarity - unless +you truly accept input from each object. diff --git a/astro/src/content/docs/de/3x/api/request/req-params.md b/astro/src/content/docs/de/3x/api/request/req-params.md new file mode 100644 index 0000000000..045271e181 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/request/req-params.md @@ -0,0 +1,27 @@ +--- +title: req.params +description: This property is an array containing properties mapped to the named route "parameters". +--- + +

    req.params

    + +This property is an array containing properties mapped to the named route "parameters". +For example if you have the route `/user/:name`, then the "name" property +is available to you as `req.params.name`. This object defaults to `{}`. + +```js +// GET /user/tj +console.dir(req.params.name); +// => 'tj' +``` + +When a regular expression is used for the route definition, capture groups +are provided in the array using `req.params[N]`, where `N` +is the nth capture group. This rule is applied to unnamed wild-card matches +with string routes such as `/file/*`: + +```js +// GET /file/javascripts/jquery.js +console.dir(req.params[0]); +// => 'javascripts/jquery.js' +``` diff --git a/astro/src/content/docs/de/3x/api/request/req-path.md b/astro/src/content/docs/de/3x/api/request/req-path.md new file mode 100644 index 0000000000..cf82ffe4bf --- /dev/null +++ b/astro/src/content/docs/de/3x/api/request/req-path.md @@ -0,0 +1,14 @@ +--- +title: req.path +description: Returns the request URL pathname. +--- + +

    req.path

    + +Returns the request URL pathname. + +```js +// example.com/users?sort=desc +console.dir(req.path); +// => '/users' +``` diff --git a/astro/src/content/docs/de/3x/api/request/req-protocol.md b/astro/src/content/docs/de/3x/api/request/req-protocol.md new file mode 100644 index 0000000000..c67e210d37 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/request/req-protocol.md @@ -0,0 +1,18 @@ +--- +title: req.protocol +description: Return the protocol string "http" or "https" +--- + +

    req.protocol

    + +Return the protocol string "http" or "https" +when requested with TLS. When the "trust proxy" +setting is enabled the "X-Forwarded-Proto" header +field will be trusted. If you're running behind +a reverse proxy that supplies https for you this +may be enabled. + +```js +console.dir(req.protocol); +// => 'http' +``` diff --git a/astro/src/content/docs/de/3x/api/request/req-query.md b/astro/src/content/docs/de/3x/api/request/req-query.md new file mode 100644 index 0000000000..c4e4d99758 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/request/req-query.md @@ -0,0 +1,25 @@ +--- +title: req.query +description: This property is an object containing the parsed query-string, +--- + +

    req.query

    + +This property is an object containing the parsed query-string, +defaulting to `{}`. + +```js +// GET /search?q=tobi+ferret +console.dir(req.query.q); +// => 'tobi ferret' + +// GET /shoes?order=desc&shoe[color]=blue&shoe[type]=converse +console.dir(req.query.order); +// => 'desc' + +console.dir(req.query.shoe.color); +// => 'blue' + +console.dir(req.query.shoe.type); +// => 'converse' +``` diff --git a/astro/src/content/docs/de/3x/api/request/req-res.md b/astro/src/content/docs/de/3x/api/request/req-res.md new file mode 100644 index 0000000000..c3c87d2601 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/request/req-res.md @@ -0,0 +1,9 @@ +--- +title: req.res +description: This property holds a reference to the +--- + +

    req.res

    + +This property holds a reference to the response object +that relates to this request object. diff --git a/astro/src/content/docs/de/3x/api/request/req-route.md b/astro/src/content/docs/de/3x/api/request/req-route.md new file mode 100644 index 0000000000..416da6cb89 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/request/req-route.md @@ -0,0 +1,27 @@ +--- +title: req.route +description: The currently matched Route containing +--- + +

    req.route

    + +The currently matched `Route` containing +several properties such as the route's original path +string, the regexp generated, and so on. + +```js +app.get('/user/:id?', function (req, res) { + console.dir(req.route); +}); +``` + +Example output from the previous snippet: + +``` +{ path: '/user/:id?', + method: 'get', + callbacks: [ [Function] ], + keys: [ { name: 'id', optional: true } ], + regexp: /^\/user(?:\/([^\/]+?))?\/?$/i, + params: [ id: '12' ] } +``` diff --git a/astro/src/content/docs/de/3x/api/request/req-secure.md b/astro/src/content/docs/de/3x/api/request/req-secure.md new file mode 100644 index 0000000000..b118f239a4 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/request/req-secure.md @@ -0,0 +1,13 @@ +--- +title: req.secure +description: Check if a TLS connection is established. This is a short-hand for +--- + +

    req.secure

    + +Check if a TLS connection is established. This is a short-hand for: + +```js +console.dir(req.protocol === 'https'); +// => true +``` diff --git a/astro/src/content/docs/de/3x/api/request/req-signedCookies.md b/astro/src/content/docs/de/3x/api/request/req-signedCookies.md new file mode 100644 index 0000000000..36a51e94df --- /dev/null +++ b/astro/src/content/docs/de/3x/api/request/req-signedCookies.md @@ -0,0 +1,20 @@ +--- +title: req.signedCookies +description: This object requires the cookieParser secret middleware for use. +--- + +

    req.signedCookies

    + +This object requires the `cookieParser(secret)` middleware for use. +It contains signed cookies sent by the user-agent, unsigned and ready for use. +Signed cookies reside in a different object to show developer intent; otherwise, +a malicious attack could be placed on `req.cookie` values (which are easy to spoof). +Note that signing a cookie does not make it "hidden" or encrypted; this simply +prevents tampering (because the secret used to sign is private). If no signed +cookies are sent, it defaults to `{}`. + +```js +// Cookie: user=tobi.CP7AWaXDfAKIRfH49dQzKJx7sKzzSoPq7/AcBBRVwlI3 +console.dir(req.signedCookies.user); +// => 'tobi' +``` diff --git a/astro/src/content/docs/de/3x/api/request/req-stale.md b/astro/src/content/docs/de/3x/api/request/req-stale.md new file mode 100644 index 0000000000..2a05d51b3b --- /dev/null +++ b/astro/src/content/docs/de/3x/api/request/req-stale.md @@ -0,0 +1,14 @@ +--- +title: req.stale +description: Check if the request is stale - aka Last-Modified and/or the ETag do not match, +--- + +

    req.stale

    + +Check if the request is stale - aka Last-Modified and/or the ETag do not match, +indicating that the resource is "stale". + +```js +console.dir(req.stale); +// => true +``` diff --git a/astro/src/content/docs/de/3x/api/request/req-subdomains.md b/astro/src/content/docs/de/3x/api/request/req-subdomains.md new file mode 100644 index 0000000000..5d52e1c719 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/request/req-subdomains.md @@ -0,0 +1,14 @@ +--- +title: req.subdomains +description: Return subdomains as an array. +--- + +

    req.subdomains

    + +Return subdomains as an array. + +```js +// Host: "tobi.ferrets.example.com" +console.dir(req.subdomains); +// => ['ferrets', 'tobi'] +``` diff --git a/astro/src/content/docs/de/3x/api/request/req-xhr.md b/astro/src/content/docs/de/3x/api/request/req-xhr.md new file mode 100644 index 0000000000..b29cda85d1 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/request/req-xhr.md @@ -0,0 +1,14 @@ +--- +title: req.xhr +description: Check if the request was issued with the "X-Requested-With" +--- + +

    req.xhr

    + +Check if the request was issued with the "X-Requested-With" +header field set to "XMLHttpRequest" (jQuery etc). + +```js +console.dir(req.xhr); +// => true +``` diff --git a/astro/src/content/docs/de/3x/api/response/res-attachment.md b/astro/src/content/docs/de/3x/api/response/res-attachment.md new file mode 100644 index 0000000000..b3d31d0201 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/response/res-attachment.md @@ -0,0 +1,20 @@ +--- +title: res.attachment +description: Sets the Content-Disposition header field to "attachment". If +--- + +

    res.attachment([filename])

    + +Sets the Content-Disposition header field to "attachment". If +a `filename` is given then the Content-Type will be +automatically set based on the extname via `res.type()`, +and the Content-Disposition's "filename=" parameter will be set. + +```js +res.attachment(); +// Content-Disposition: attachment + +res.attachment('path/to/logo.png'); +// Content-Disposition: attachment; filename="logo.png" +// Content-Type: image/png +``` diff --git a/astro/src/content/docs/de/3x/api/response/res-charset.md b/astro/src/content/docs/de/3x/api/response/res-charset.md new file mode 100644 index 0000000000..e75892c3d4 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/response/res-charset.md @@ -0,0 +1,14 @@ +--- +title: res.charset +description: Assign the charset. Defaults to "utf-8". +--- + +

    res.charset

    + +Assign the charset. Defaults to "utf-8". + +```js +res.charset = 'value'; +res.send('

    some html

    '); +// => Content-Type: text/html; charset=value +``` diff --git a/astro/src/content/docs/de/3x/api/response/res-clearCookie.md b/astro/src/content/docs/de/3x/api/response/res-clearCookie.md new file mode 100644 index 0000000000..6754dd61d3 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/response/res-clearCookie.md @@ -0,0 +1,13 @@ +--- +title: res.clearCookie +description: Clear cookie name. The path option defaults to slash. +--- + +

    res.clearCookie(name, [options])

    + +Clear cookie `name`. The `path` option defaults to "/". + +```js +res.cookie('name', 'tobi', { path: '/admin' }); +res.clearCookie('name', { path: '/admin' }); +``` diff --git a/astro/src/content/docs/de/3x/api/response/res-cookie.md b/astro/src/content/docs/de/3x/api/response/res-cookie.md new file mode 100644 index 0000000000..7cd5e29114 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/response/res-cookie.md @@ -0,0 +1,42 @@ +--- +title: res.cookie +description: Set cookie name to value, which may be a string or object converted to JSON. The path +--- + +

    res.cookie(name, value, [options])

    + +Set cookie `name` to `value`, which may be a string or object converted to JSON. The `path` +option defaults to "/". + +```js +res.cookie('name', 'tobi', { domain: '.example.com', path: '/admin', secure: true }); +res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true }); +``` + +The `maxAge` option is a convenience option for setting "expires" +relative to the current time in milliseconds. The following is equivalent to +the previous example. + +```js +res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true }); +``` + +An object may be passed which is then serialized as JSON, which is +automatically parsed by the `bodyParser()` middleware. + +```js +res.cookie('cart', { items: [1, 2, 3] }); +res.cookie('cart', { items: [1, 2, 3] }, { maxAge: 900000 }); +``` + +Signed cookies are also supported through this method. Simply +pass the `signed` option. When given `res.cookie()` +will use the secret passed to `express.cookieParser(secret)` +to sign the value. + +```js +res.cookie('name', 'tobi', { signed: true }); +``` + +Later you may access this value through the req.signedCookie +object. diff --git a/astro/src/content/docs/de/3x/api/response/res-download.md b/astro/src/content/docs/de/3x/api/response/res-download.md new file mode 100644 index 0000000000..1706bb83c7 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/response/res-download.md @@ -0,0 +1,31 @@ +--- +title: res.download +description: Transfer the file at path as an attachment, +--- + +

    res.download(path, [filename], [fn])

    + +Transfer the file at `path` as an "attachment", +typically browsers will prompt the user for download. The +Content-Disposition "filename=" parameter, aka the one +that will appear in the brower dialog is set to `path` +by default, however you may provide an override `filename`. + +When an error has ocurred or transfer is complete the optional +callback `fn` is invoked. This method uses res.sendfile() +to transfer the file. + +```js +res.download('/report-12345.pdf'); + +res.download('/report-12345.pdf', 'report.pdf'); + +res.download('/report-12345.pdf', 'report.pdf', function (err) { + if (err) { + // handle error, keep in mind the response may be partially-sent + // so check res.headerSent + } else { + // decrement a download credit etc + } +}); +``` diff --git a/astro/src/content/docs/de/3x/api/response/res-format.md b/astro/src/content/docs/de/3x/api/response/res-format.md new file mode 100644 index 0000000000..4e537981f2 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/response/res-format.md @@ -0,0 +1,57 @@ +--- +title: res.format +description: Performs content-negotiation on the request Accept header +--- + +

    res.format(object)

    + +Performs content-negotiation on the request Accept header +field when present. This method uses `req.accepted`, an array of +acceptable types ordered by their quality values, otherwise the +first callback is invoked. When no match is performed the server +responds with 406 "Not Acceptable", or invokes the `default` +callback. + +The Content-Type is set for you when a callback is selected, +however you may alter this within the callback using `res.set()` +or `res.type()` etcetera. + +The following example would respond with `{ "message": "hey" }` +when the Accept header field is set to "application/json" or "_/json", +however if "_/\*" is given then "hey" will be the response. + +```js +res.format({ + 'text/plain': function () { + res.send('hey'); + }, + + 'text/html': function () { + res.send('

    hey

    '); + }, + + 'application/json': function () { + res.send({ message: 'hey' }); + }, +}); +``` + +In addition to canonicalized MIME types you may also +use extnames mapped to these types, providing a slightly +less verbose implementation: + +```js +res.format({ + text: function () { + res.send('hey'); + }, + + html: function () { + res.send('

    hey

    '); + }, + + json: function () { + res.send({ message: 'hey' }); + }, +}); +``` diff --git a/astro/src/content/docs/de/3x/api/response/res-get.md b/astro/src/content/docs/de/3x/api/response/res-get.md new file mode 100644 index 0000000000..342b90714c --- /dev/null +++ b/astro/src/content/docs/de/3x/api/response/res-get.md @@ -0,0 +1,13 @@ +--- +title: res.get +description: Get the case-insensitive response header field. +--- + +

    res.get(field)

    + +Get the case-insensitive response header `field`. + +```js +res.get('Content-Type'); +// => "text/plain" +``` diff --git a/astro/src/content/docs/de/3x/api/response/res-json.md b/astro/src/content/docs/de/3x/api/response/res-json.md new file mode 100644 index 0000000000..6780b3f7f1 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/response/res-json.md @@ -0,0 +1,18 @@ +--- +title: res.json +description: Send a JSON response. This method is identical +--- + +

    res.json([status|body], [body])

    + +Send a JSON response. This method is identical +to `res.send()` when an object or +array is passed, however it may be used for +explicit JSON conversion of non-objects (null, undefined, etc), +though these are technically not valid JSON. + +```js +res.json(null); +res.json({ user: 'tobi' }); +res.json(500, { error: 'message' }); +``` diff --git a/astro/src/content/docs/de/3x/api/response/res-jsonp.md b/astro/src/content/docs/de/3x/api/response/res-jsonp.md new file mode 100644 index 0000000000..fe0944c80d --- /dev/null +++ b/astro/src/content/docs/de/3x/api/response/res-jsonp.md @@ -0,0 +1,38 @@ +--- +title: res.jsonp +description: Send a JSON response with JSONP support. This method is identical +--- + +

    res.jsonp([status|body], [body])

    + +Send a JSON response with JSONP support. This method is identical +to `res.json()` however opts-in to JSONP callback +support. + +```js +res.jsonp(null); +// => null + +res.jsonp({ user: 'tobi' }); +// => { "user": "tobi" } + +res.jsonp(500, { error: 'message' }); +// => { "error": "message" } +``` + +By default the JSONP callback name is simply `callback`, +however you may alter this with the jsonp callback name +setting. The following are some examples of JSONP responses using the same +code: + +```js +// ?callback=foo +res.jsonp({ user: 'tobi' }); +// => foo({ "user": "tobi" }) + +app.set('jsonp callback name', 'cb'); + +// ?cb=foo +res.jsonp(500, { error: 'message' }); +// => foo({ "error": "message" }) +``` diff --git a/astro/src/content/docs/de/3x/api/response/res-links.md b/astro/src/content/docs/de/3x/api/response/res-links.md new file mode 100644 index 0000000000..62744d116f --- /dev/null +++ b/astro/src/content/docs/de/3x/api/response/res-links.md @@ -0,0 +1,22 @@ +--- +title: res.links +description: Join the given links to populate the Link response header field. +--- + + + +Join the given `links` to populate the "Link" response header field. + +```js +res.links({ + next: 'http://api.example.com/users?page=2', + last: 'http://api.example.com/users?page=5', +}); +``` + +p yields: + +``` +Link: rel="next", + rel="last" +``` diff --git a/astro/src/content/docs/de/3x/api/response/res-locals.md b/astro/src/content/docs/de/3x/api/response/res-locals.md new file mode 100644 index 0000000000..039a69e780 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/response/res-locals.md @@ -0,0 +1,21 @@ +--- +title: res.locals +description: Response local variables are scoped to the request, thus only +--- + +

    res.locals

    + +Response local variables are scoped to the request, thus only +available to the view(s) rendered during that request / response +cycle, if any. Otherwise this API is identical to app.locals. + +This object is useful for exposing request-level information such as the +request pathname, authenticated user, user settings etcetera. + +```js +app.use(function (req, res, next) { + res.locals.user = req.user; + res.locals.authenticated = !req.user.anonymous; + next(); +}); +``` diff --git a/astro/src/content/docs/de/3x/api/response/res-location.md b/astro/src/content/docs/de/3x/api/response/res-location.md new file mode 100644 index 0000000000..44fac2fc16 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/response/res-location.md @@ -0,0 +1,26 @@ +--- +title: res.location +description: Set the location header. +--- + +

    res.location

    + +Set the location header. + +```js +res.location('/foo/bar'); +res.location('foo/bar'); +res.location('http://example.com'); +res.location('../login'); +res.location('back'); +``` + +You can use the same kind of `urls` as in `res.redirect()`. + +For example, if your application is mounted at `/blog`, +the following would set the `location` header to +`/blog/admin`: + +```js +res.location('admin'); +``` diff --git a/astro/src/content/docs/de/3x/api/response/res-redirect.md b/astro/src/content/docs/de/3x/api/response/res-redirect.md new file mode 100644 index 0000000000..81cf723bcf --- /dev/null +++ b/astro/src/content/docs/de/3x/api/response/res-redirect.md @@ -0,0 +1,56 @@ +--- +title: res.redirect +description: Redirect to the given url with optional status code +--- + +

    res.redirect([status], url)

    + +Redirect to the given `url` with optional `status` code +defaulting to 302 "Found". + +```js +res.redirect('/foo/bar'); +res.redirect('http://example.com'); +res.redirect(301, 'http://example.com'); +res.redirect('../login'); +``` + +Express supports a few forms of redirection, first being +a fully qualified URI for redirecting to a different site: + +```js +res.redirect('http://google.com'); +``` + +The second form is the pathname-relative redirect, for example +if you were on `http://example.com/admin/post/new`, the +following redirect to `/admin` would land you at `http://example.com/admin`: + +```js +res.redirect('/admin'); +``` + +This next redirect is relative to the `mount` point of the application. For example +if you have a blog application mounted at `/blog`, ideally it has no knowledge of +where it was mounted, so where a redirect of `/admin/post/new` would simply give you +`http://example.com/admin/post/new`, the following mount-relative redirect would give +you `http://example.com/blog/admin/post/new`: + +```js +res.redirect('admin/post/new'); +``` + +Pathname relative redirects are also possible. If you were +on `http://example.com/admin/post/new`, the following redirect +would land you at `http//example.com/admin/post`: + +```js +res.redirect('..'); +``` + +The final special-case is a `back` redirect, redirecting back to +the Referer (or Referrer), defaulting to `/` when missing. + +```js +res.redirect('back'); +``` diff --git a/astro/src/content/docs/de/3x/api/response/res-render.md b/astro/src/content/docs/de/3x/api/response/res-render.md new file mode 100644 index 0000000000..b00b585286 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/response/res-render.md @@ -0,0 +1,21 @@ +--- +title: res.render +description: Render a view with a callback responding with +--- + +

    res.render(view, [locals], callback)

    + +Render a `view` with a callback responding with +the rendered string. When an error occurs `next(err)` +is invoked internally. When a callback is provided both the possible error +and rendered string are passed, and no automated response is performed. + +```js +res.render('index', function (err, html) { + // ... +}); + +res.render('user', { name: 'Tobi' }, function (err, html) { + // ... +}); +``` diff --git a/astro/src/content/docs/de/3x/api/response/res-req.md b/astro/src/content/docs/de/3x/api/response/res-req.md new file mode 100644 index 0000000000..2abec18cca --- /dev/null +++ b/astro/src/content/docs/de/3x/api/response/res-req.md @@ -0,0 +1,9 @@ +--- +title: res.req +description: This property holds a reference to the +--- + +

    res.req

    + +This property holds a reference to the request object +that relates to this response object. diff --git a/astro/src/content/docs/de/3x/api/response/res-send.md b/astro/src/content/docs/de/3x/api/response/res-send.md new file mode 100644 index 0000000000..c03e53c936 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/response/res-send.md @@ -0,0 +1,58 @@ +--- +title: res.send +description: Send a response. +--- + +

    res.send([body|status], [body])

    + +Send a response. + +```js +res.send(Buffer.from('whoop')); +res.send({ some: 'json' }); +res.send('

    some html

    '); +res.send(404, 'Sorry, we cannot find that!'); +res.send(500, { error: 'something blew up' }); +res.send(200); +``` + +This method performs a myriad of +useful tasks for simple non-streaming responses such +as automatically assigning the Content-Length unless +previously defined and providing automatic HEAD and +HTTP cache freshness support. + +When a `Buffer` is given +the Content-Type is set to "application/octet-stream" +unless previously defined as shown below: + +```js +res.set('Content-Type', 'text/html'); +res.send(Buffer.from('

    some html

    ')); +``` + +When a `String` is given the +Content-Type is set defaulted to "text/html": + +```js +res.send('

    some html

    '); +``` + +When an `Array` or `Object` is +given Express will respond with the JSON representation: + +```js +res.send({ user: 'tobi' }); +res.send([1, 2, 3]); +``` + +Finally when a `Number` is given without +any of the previously mentioned bodies, then a response +body string is assigned for you. For example 200 will +respond will the text "OK", and 404 "Not Found" and so on. + +```js +res.send(200); +res.send(404); +res.send(500); +``` diff --git a/astro/src/content/docs/de/3x/api/response/res-sendfile.md b/astro/src/content/docs/de/3x/api/response/res-sendfile.md new file mode 100644 index 0000000000..619038305a --- /dev/null +++ b/astro/src/content/docs/de/3x/api/response/res-sendfile.md @@ -0,0 +1,35 @@ +--- +title: res.sendfile +description: Transfer the file at the given path. +--- + +

    res.sendfile(path, [options], [fn]])

    + +Transfer the file at the given `path`. + +Automatically defaults the Content-Type response header field based +on the filename's extension. The callback `fn(err)` is +invoked when the transfer is complete or when an error occurs. + +Options: + +- `maxAge` in milliseconds defaulting to 0 +- `root` root directory for relative filenames + +This method provides fine-grained support for file serving +as illustrated in the following example: + +```js +app.get('/user/:uid/photos/:file', function (req, res) { + var uid = req.params.uid; + var file = req.params.file; + + req.user.mayViewFilesFrom(uid, function (yes) { + if (yes) { + res.sendfile('/uploads/' + uid + '/' + file); + } else { + res.send(403, 'Sorry! you cant see that.'); + } + }); +}); +``` diff --git a/astro/src/content/docs/de/3x/api/response/res-set.md b/astro/src/content/docs/de/3x/api/response/res-set.md new file mode 100644 index 0000000000..4e1a1177d3 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/response/res-set.md @@ -0,0 +1,20 @@ +--- +title: res.set +description: Set header field to value, or pass an object to set multiple fields at once. +--- + +

    res.set(field, [value])

    + +Set header `field` to `value`, or pass an object to set multiple fields at once. + +```js +res.set('Content-Type', 'text/plain'); + +res.set({ + 'Content-Type': 'text/plain', + 'Content-Length': '123', + ETag: '12345', +}); +``` + +Aliased as `res.header(field, [value])`. diff --git a/astro/src/content/docs/de/3x/api/response/res-status.md b/astro/src/content/docs/de/3x/api/response/res-status.md new file mode 100644 index 0000000000..b0cbe2bd79 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/response/res-status.md @@ -0,0 +1,12 @@ +--- +title: res.status +description: Chainable alias of node res.statusCode property. +--- + +

    res.status(code)

    + +Chainable alias of node's `res.statusCode=`. + +```js +res.status(404).sendfile('path/to/404.png'); +``` diff --git a/astro/src/content/docs/de/3x/api/response/res-type.md b/astro/src/content/docs/de/3x/api/response/res-type.md new file mode 100644 index 0000000000..157a2ed6ad --- /dev/null +++ b/astro/src/content/docs/de/3x/api/response/res-type.md @@ -0,0 +1,20 @@ +--- +title: res.type +description: Sets the Content-Type to the mime lookup of type, +--- + +

    res.type(type)

    + +Sets the Content-Type to the mime lookup of `type`, +or when "/" is present the Content-Type is simply set to this +literal value. + +```js +res.type('.html'); +res.type('html'); +res.type('json'); +res.type('application/json'); +res.type('png'); +``` + +p Aliased as `res.contentType(type)`. diff --git a/astro/src/content/docs/de/3x/api/response/response.md b/astro/src/content/docs/de/3x/api/response/response.md new file mode 100644 index 0000000000..722423f376 --- /dev/null +++ b/astro/src/content/docs/de/3x/api/response/response.md @@ -0,0 +1,89 @@ +--- +title: Res +description: h2 id="response">Response +--- + +

    Response

    + +The `res` object is an enhanced version of Node's own response object +and supports all [built-in fields and methods](https://nodejs.org/api/http.html#http_class_http_serverresponse). + +
    + {% include api/en/3x/res-status.md %} +
    + +
    + {% include api/en/3x/res-set.md %} +
    + +
    + {% include api/en/3x/res-get.md %} +
    + +
    + {% include api/en/3x/res-cookie.md %} +
    + +
    + {% include api/en/3x/res-clearCookie.md %} +
    + +
    + {% include api/en/3x/res-redirect.md %} +
    + +
    + {% include api/en/3x/res-location.md %} +
    + +
    + {% include api/en/3x/res-charset.md %} +
    + +
    + {% include api/en/3x/res-send.md %} +
    + +
    + {% include api/en/3x/res-json.md %} +
    + +
    + {% include api/en/3x/res-jsonp.md %} +
    + +
    + {% include api/en/3x/res-type.md %} +
    + +
    + {% include api/en/3x/res-format.md %} +
    + +
    + {% include api/en/3x/res-attachment.md %} +
    + +
    + {% include api/en/3x/res-sendfile.md %} +
    + +
    + {% include api/en/3x/res-download.md %} +
    + +
    + {% include api/en/3x/res-links.md %} +
    + +
    + {% include api/en/3x/res-locals.md %} +
    + +
    + {% include api/en/3x/res-render.md %} +
    + +
    + {% include api/en/3x/res-req.md %} +
    diff --git a/astro/src/content/docs/de/4x/advanced/best-practice-performance.md b/astro/src/content/docs/de/4x/advanced/best-practice-performance.md new file mode 100644 index 0000000000..b1c5c672aa --- /dev/null +++ b/astro/src/content/docs/de/4x/advanced/best-practice-performance.md @@ -0,0 +1,307 @@ +--- +title: Leistungsspezifische Best Practices für Express-Anwendungen in Produktionsumgebungen +description: Discover performance and reliability best practices for Express apps in production, covering code optimizations and environment setups for optimal performance. +--- + +# Best Practices in Produktionsumgebungen: Leistung und Zuverlässigkeit + +In diesem Beitrag werden Best Practices in Bezug auf Leistung und Zuverlässigkeit für Express-Anwendungen behandelt, die in der Produktionsumgebung bereitgestellt werden. + +Dieses Thema gehört sicherlich zur "DevOps"-Welt und deckt traditionelle Entwicklungs- und Betriebsprozesse ab. Entsprechend sind die Informationen hier in zwei Teile unterteilt: + +- Things to do in your code (the dev part): + - Für statische Dateien Middleware verwenden + - Keine synchronen Funktionen verwenden + - [Do logging correctly](#do-logging-correctly) + - [Handle exceptions properly](#handle-exceptions-properly) +- Things to do in your environment / setup (the ops part): + - NODE_ENV auf "production" festlegen + - Automatischen Neustart Ihrer Anwendung sicherstellen + - Anwendung in einem Cluster ausführen + - Anforderungsergebnisse im Cache speichern + - Load Balancer verwenden + - Reverse Proxy verwenden + +## Things to do in your code {#in-code} + +Dies sind einige Beispiele für Maßnahmen, die Sie an Ihrem Code vornehmen können, um die Anwendungsleistung zu verbessern: + +- Für statische Dateien Middleware verwenden +- Keine synchronen Funktionen verwenden +- [Do logging correctly](#do-logging-correctly) +- [Handle exceptions properly](#handle-exceptions-properly) + +### GZIP-Komprimierung verwenden + +Mit der GZIP-Komprimierung lässt sich die Größe des Antworthauptteils deutlich verringern und somit die Geschwindigkeit der Webanwendung erhöhen. Verwenden Sie die Middleware [compression](https://www.npmjs.com/package/compression) für die GZIP-Komprimierung in Ihrer Express-Anwendung. Beispiel: + +```js +const compression = require('compression'); +const express = require('express'); +const app = express(); + +app.use(compression()); +``` + +Bei Websites mit hohem Datenverkehr in Produktionsumgebungen lässt sich die Komprimierung am besten installieren, indem sie auf Reverse Proxy-Ebene implementiert wird (siehe [Reverse Proxy verwenden](#proxy)). In diesem Fall wird die Middleware "compression" nicht benötigt. Details zur Aktivierung der GZIP-Komprimierung in Nginx siehe [Modul ngx_http_gzip_module](http://nginx.org/en/docs/http/ngx_http_gzip_module.html) in der Nginx-Dokumentation. + +### Keine synchronen Funktionen verwenden + +Synchrone Funktionen und Methoden belasten den Ausführungsprozess, bis sie zurückgegeben werden. Ein einzelner Aufruf für eine synchrone Funktion kann in wenigen Mikrosekunden oder Millisekunden zurückgegeben werden. Bei Websites mit hohem Datenverkehr hingegen summieren sich diese Aufrufe und verringern die Leistung der Anwendung. Sie sollten also deren Verwendung in Produktionsumgebungen vermeiden. + +Auch wenn Node und viele andere Module synchrone und asynchrone Versionen ihrer Funktionen bieten, sollten Sie in Produktionsumgebungen immer die asynchrone Version verwenden. Nur beim ersten Systemstart ist die Verwendung einer synchronen Funktion begründet. + +You can use the `--trace-sync-io` command-line flag to print a warning and a stack trace whenever your application uses a synchronous API. Auch wenn Sie diese natürlich nicht in der Produktionsumgebung verwenden werden, soll dadurch trotzdem sichergestellt werden, dass Ihr Code in der Produktionsumgebung eingesetzt werden kann. Weitere Informationen hierzu siehe [Wöchentliches Update für io.js 2.1.0](https://nodejs.org/en/blog/weekly-updates/weekly-update.2015-05-22/#2-1-0). + +### Do logging correctly + +Im Allgemeinen gibt es für die Protokollierung Ihrer Anwendung zwei Gründe: 1) Debugging und 2) Protokollierung von Anwendungsaktivitäten (im Wesentlichen alles andere, außer Debugging). Die Verwendung von`console.log()` oder `console.err()` zur Ausgabe von Protokollnachrichten an das Terminal ist in der Entwicklung gängige Praxis. But [these functions are synchronous](https://nodejs.org/api/console.html#console) when the destination is a terminal or a file, so they are not suitable for production, unless you pipe the output to another program. + +#### Für Debuggingzwecke + +Wenn Sie die Protokollierung für Debuggingzwecke nutzen, sollten Sie statt `console.log()` besser ein spezielles Debuggingmodul wie [debug](https://www.npmjs.com/package/debug) verwenden. Mit einem solchen Modul können Sie über die Umgebungsvariable DEBUG steuern, welche Debugnachrichten an `console.err()` gesendet werden (falls vorhanden). Um Ihre Anwendung rein asynchron zu halten, können Sie trotzdem `console.err()` per Pipe zu einem anderen Programm umleiten. Sie nehmen dann aber kein Debugging in der Produktionsumgebung vor, richtig? + +#### Für Anwendungsaktivitäten + +If you're logging app activity (for example, tracking traffic or API calls), instead of using `console.log()`, use a logging library like [Pino](https://www.npmjs.com/package/pino), which is the fastest and most efficient option available. + +### Ausnahmebedingungen ordnungsgemäß handhaben + +Node-Anwendungen stürzen ab, wenn eine nicht abgefangene Ausnahmebedingung vorkommt. Wenn diese Ausnahmebedingungen nicht behandelt und entsprechende Maßnahmen eingeleitet werden, stürzt Ihre Express-Anwendung ab und geht offline. Wenn Sie dem nachfolgenden Rat in [Sicherstellen, dass Ihre Anwendung automatisch neu gestartet wird](#restart) folgen, wird Ihre Anwendung nach einem Absturz wiederhergestellt. Glücklicherweise haben Express-Anwendungen nur eine kurze Initialisierungszeit. Nevertheless, you want to avoid crashing in the first place, and to do that, you need to handle exceptions properly. + +Mit folgenden Verfahren stellen Sie sicher, dass alle Ausnahmebedingungen gehandhabt werden: + +- ["try-catch" verwenden](#try-catch) +- ["Promises" verwenden](#promises) + +Um näher auf diese Themen eingehen zu können, müssen Sie sich ein grundlegendes Verständnis der Fehlerbehandlung in Node und Express aneignen: Verwendung von Error-first-Callbacks und Propagieren von Fehlern in Middleware. Node verwendet die Konvention "Error-first-Callback" für die Rückgabe von Fehlern von asynchronen Funktionen, bei denen der erste Parameter zur Callback-Funktion das Fehlerobjekt ist, gefolgt von Ergebnisdaten in den nachfolgenden Parametern. Um anzugeben, dass kein Fehler vorliegt, müssen Sie "null" als ersten Parameter übergeben. Die Callback-Funktion muss der Konvention "Error-first-Callback" folgen, um den Fehler sinnvoll bearbeiten zu können. In Express hat sich bewährt, die Funktion "next()" zu verwenden, um Fehler über die Middleware-Chain zu propagieren. + +Weitere Informationen zu den Grundlagen der Fehlerbehandlung siehe: + +- [Fehlerbehandlung in Node.js](https://www.tritondatacenter.com/node-js/production/design/errors) + +#### "try-catch" verwenden + +"try-catch" ist ein JavaScript-Sprachkonstrukt, mit dem Sie Ausnahmebedingungen in synchronem Code abfangen können. Verwenden Sie "try-catch" beispielsweise, um JSON-Parsing-Fehler wie unten gezeigt zu bearbeiten. + +Dies ist ein Beispiel zur Verwendung von "try-catch", um eine potenzielle "process-crashing"-Ausnahmebedingung zu handhaben. +Diese Middlewarefunktion akzeptiert einen Abfragefeldparameter mit dem Namen "params", der ein JSON-Objekt ist. + +```js +app.get('/search', (req, res) => { + // Simulating async operation + setImmediate(() => { + const jsonStr = req.query.params; + try { + const jsonObj = JSON.parse(jsonStr); + res.send('Success'); + } catch (e) { + res.status(400).send('Invalid JSON string'); + } + }); +}); +``` + +"try-catch" funktioniert jedoch nur in synchronem Code. Da die Node-Plattform primär asynchron ist (insbesondere in einer Produktionsumgebung), lassen sich mit "try-catch" nicht besonders viele Ausnahmebedingungen abfangen. + +#### "Promises" verwenden + +When an error is thrown in an `async` function or a rejected promise is awaited inside an `async` function, those errors will be passed to the error handler as if calling `next(err)` + +```js +app.get('/', async (req, res, next) => { + const data = await userData(); // If this promise fails, it will automatically call `next(err)` to handle the error. + + res.send(data); +}); + +app.use((err, req, res, next) => { + res.status(err.status ?? 500).send({ error: err.message }); +}); +``` + +Also, you can use asynchronous functions for your middleware, and the router will handle errors if the promise fails, for example: + +```js +app.use(async (req, res, next) => { + req.locals.user = await getUser(req); + + next(); // This will be called if the promise does not throw an error. +}); +``` + +Best practice is to handle errors as close to the site as possible. So while this is now handled in the router, it’s best to catch the error in the middleware and handle it without relying on separate error-handling middleware. + +#### What not to do + +Sie sollten _auf keinen_ Fall per Listener das Ereignis `uncaughtException` überwachen, das ausgegeben wird, wenn eine Ausnahmebedingung bis zurück zur Ereignisschleife bestehen bleibt. Durch das Hinzufügen eines Ereignislisteners für `uncaughtException` verändert sich das Standardverhalten des Prozesses, über das eine Ausnahmebedingung festgestellt wird. Das Ausführen einer Anwendung nach einer nicht abgefangenen Ausnahmebedingung ist aber eine durchaus riskante Vorgehensweise und wird nicht empfohlen, da der Prozessstatus störanfällig und unvorhersehbar wird. + +Außerdem wird die Verwendung von `uncaughtException` offiziell als [grobes Vorgehen](https://nodejs.org/api/process.html#process_event_uncaughtexception) angesehen, sodass es den [Vorschlag](https://github.com/nodejs/node-v0.x-archive/issues/2582) gibt, die Funktion aus dem Kern zu entfernen. Das Überwachen von `uncaughtException` per Listener ist also keine gute Idee. Daher empfehlen wir Dinge wie Mehrfachprozesse und Supervisoren: Ein Absturz und anschließender Neustart ist häufig die zuverlässigste Art der Fehlerbehebung. + +Zudem empfehlen wir, [domains](https://nodejs.org/api/domain.html) nicht zu verwenden. Mit diesem Modul, das zudem veraltet ist, lässt sich das Problem in der Regel nicht lösen. + +## Things to do in your environment / setup {#in-environment} + +Dies sind einige Beispiele für Maßnahmen, die Sie an Ihrer Systemumgebung vornehmen können, um die Anwendungsleistung zu verbessern: + +- NODE_ENV auf "production" festlegen +- Automatischen Neustart Ihrer Anwendung sicherstellen +- Anwendung in einem Cluster ausführen +- Anforderungsergebnisse im Cache speichern +- Load Balancer verwenden +- Reverse Proxy verwenden + +### NODE_ENV auf "production" festlegen + +In der Umgebungsvariablen NODE_ENV wird die Umgebung angegeben, in der eine Anwendung ausgeführt wird (in der Regel ist dies die Entwicklungs- oder Produktionsumgebung). One of the simplest things you can do to improve performance is to set NODE_ENV to `production`. + +Durch das Festlegen von NODE_ENV auf "production" führt Express Folgendes aus: + +- Speichern von Anzeigevorlagen im Cache. +- Speichern von CSS-Dateien, die aus CSS-Erweiterungen generiert wurden, im Cache. +- Generieren von weniger ausführlichen Fehlernachrichten. + +[Tests indicate](https://www.dynatrace.com/news/blog/the-drastic-effects-of-omitting-node-env-in-your-express-js-applications/) that just doing this can improve app performance by a factor of three! + +Wenn Sie umgebungsspezifischen Code schreiben müssen, können Sie den Wert von NODE_ENV mit `process.env.NODE_ENV` überprüfen. Beachten Sie, dass die Überprüfung des Werts seiner Umgebungsvariablen eine leistungsbezogene Penalisierung nach sich zieht. + +In einer Entwicklungsumgebung wird die Umgebungsvariable in der Regel in Ihrer interaktiven Shell festgelegt, indem Sie beispielsweise `export` oder Ihre Datei `.bash_profile` verwenden. But in general, you shouldn't do that on a production server; instead, use your OS's init system (systemd). Der nächste Abschnitt enthält weitere Details zur Verwendung des Init-Systems im Allgemeinen. Die Festlegung von NODE_ENV ist jedoch für das Leistungsverhalten so wichtig (und so einfach durchzuführen), dass hier besonders darauf eingegangen wird. + +Verwenden Sie bei systemd die Anweisung `Environment` in Ihrer Einheitendatei. Beispiel: + +```sh +# /etc/systemd/system/myservice.service +Environment=NODE_ENV=production +``` + +For more information, see [Using Environment Variables In systemd Units](https://www.flatcar.org/docs/latest/setup/systemd/environment-variables/). + +### Automatischen Neustart Ihrer Anwendung sicherstellen + +In der Produktionsumgebung sollte die Anwendung nie offline sein. Das bedeutet, dass Sie sicherstellen müssen, dass die Anwendung bei einem Absturz der Anwendung oder des Servers immer wieder neu gestartet wird. Auch wenn man hofft, das keines dieser Ereignisse jemals eintritt, muss man doch mit beiden Möglichkeiten rechnen und: + +- einen Prozessmanager verwenden, um die Anwendung (und Node) bei einem Absturz neu zu starten. +- das Init-System Ihres Betriebssystems verwenden, um den Prozessmanager bei einem Absturz des Betriebssystems neu zu starten. Außerdem kann das Init-System auch ohne einen Prozessmanager verwendet werden. + +Node-Anwendungen stürzen ab, wenn eine nicht abgefangene Ausnahmebedingung auftritt. Als Erstes müssen Sie in einem solchen Fall sicherstellen, dass Ihre Anwendung ausreichend getestet wurde und in der Lage ist, alle Ausnahmebedingungen zu handhaben (weitere Informationen siehe [Ausnahmebedingungen ordnungsgemäß handhaben](#exceptions)). Die sicherste Maßnahme ist jedoch, einen Mechanismus zu implementieren, über den bei einem Absturz der Anwendung ein automatischer Neustart der Anwendung ausgeführt wird. + +#### Prozessmanager verwenden + +In Entwicklungumgebungen wird die Anwendung einfach über die Befehlszeile mit `node server.js` oder einer vergleichbaren Datei gestartet. In der Produktionsumgebung hingegen ist durch diese Vorgehensweise die Katastrophe bereits vorprogrammiert. Wenn die Anwendung abstürzt, ist sie solange offline, bis Sie sie erneut starten. Um sicherzustellen, dass Ihre Anwendung nach einem Absturz neu gestartet wird, sollten Sie einen Prozessmanager verwenden. Ein Prozessmanager ist ein "Container" für Anwendungen, der die Bereitstellung erleichtert, eine hohe Verfügbarkeit sicherstellt und die Verwaltung der Anwendung zur Laufzeit ermöglicht. + +Neben einem Neustart der Anwendung nach einem Absturz bietet ein Prozessmanager noch weitere Möglichkeiten: + +- Einblicke in die Laufzeitleistung und die Ressourcennutzung +- Dynamische Änderung der Einstellungen zur Verbesserung des Leistungsverhaltens +- Control clustering (pm2). + +Historically, it was popular to use a Node.js process manager like [PM2](https://github.com/Unitech/pm2). See their documentation if you wish to do this. However, we recommend using your init system for process management. + +#### Init-System verwenden + +Als nächste Ebene der Zuverlässigkeit müssen Sie sicherstellen, dass Ihre Anwendung bei einem Serverneustart neu gestartet wird. Systeme können immer wieder aus verschiedenen Gründen abstürzen. Um sicherzustellen, dass Ihre Anwendung bei einem Serverabsturz neu gestartet wird, können Sie das in Ihr Betriebssystem integrierte Init-System verwenden. The main init system in use today is [systemd](https://wiki.debian.org/systemd). + +Es gibt zwei Möglichkeiten, Init-Systeme mit Ihrer Express-Anwendung zu verwenden: + +- Ausführung Ihrer Anwendung in einem Prozessmanager und Installation des Prozessmanagers als Service mit dem Init-System. Der Prozessmanager wird neu gestartet, wenn Ihre Anwendung abstürzt. Dies ist die empfohlene Vorgehensweise. +- Ausführung Ihrer Anwendung (und von Node) direkt mit dem Init-System. Diese Vorgehensweise ist zwar etwas einfacher, Sie profitieren jedoch nicht von den zusätzlichen Vorteilen des Einsatzes eines Prozessmanagers. + +##### systemd + +"systemd" ist ein Linux-System und Service-Manager. Die meisten wichtigen Linux-Distributionen haben "systemd" als Init-Standardsystem übernommen. + +Eine "systemd"-Servicekonfigurationsdatei wird als _Einheitendatei_ bezeichnet, die die Endung ".service" hat. Dies ist ein Beispiel für eine Einheitendatei zur direkten Verwaltung einer Node-Anwendung (ersetzen Sie den Text in Fettdruck durch Werte für Ihr System und Ihre Anwendung): Replace the values enclosed in `` for your system and app: + +```sh +[Unit] +Description= + +[Service] +Type=simple +ExecStart=/usr/local/bin/node +WorkingDirectory= + +User=nobody +Group=nogroup + +# Environment variables: +Environment=NODE_ENV=production + +# Allow many incoming connections +LimitNOFILE=infinity + +# Allow core dumps for debugging +LimitCORE=infinity + +StandardInput=null +StandardOutput=syslog +StandardError=syslog +Restart=always + +[Install] +WantedBy=multi-user.target +``` + +Weitere Informationen zu "systemd" siehe [systemd-Referenz (Man-Page)](http://www.freedesktop.org/software/systemd/man/systemd.unit.html). + +### Anwendung in einem Cluster ausführen + +In einem Multi-Core-System können Sie die Leistung einer Node-Anwendung mehrmals erhöhen, indem Sie einen Cluster von Prozessen starten. Ein Cluster führt mehrere Instanzen der Anwendung aus, idealerweise eine Instanz auf jedem CPU-Core. + +![Balancing between application instances using the cluster API](/images/clustering.png) + +Wichtig. Da die Anwendungsinstanzen als separate Prozesse ausgeführt werden, nutzen sie nicht dieselbe Hauptspeicherkapazität gemeinsam. Das heißt, Objekte befinden sich für jede Instanz der Anwendung auf lokaler Ebene. Daher kann der Status im Anwendungscode nicht beibehalten werden. Sie können jedoch einen speicherinternen Datenspeicher wie [Redis](http://redis.io/) verwenden, um sitzungsrelevante Daten und Statusinformationen zu speichern. Diese Einschränkung trifft im Wesentlichen auf alle Formen der horizontalen Skalierung zu, unabhängig davon, ob es sich um Clustering mit mehreren Prozessen oder mehreren physischen Servern handelt. + +Bei in Gruppen zusammengefassten Anwendungen (geclusterte Anwendungen) können Verarbeitungsprozesse einzeln ausfallen, ohne dass sich dies auf die restlichen Prozesse auswirkt. Neben den Leistungsvorteilen ist die Fehlerisolierung ein weiterer Grund, einen Cluster von Anwendungsprozessen auszuführen. Wenn ein Verarbeitungsprozess abstürzt, müssen Sie sicherstellen, dass das Ereignis protokolliert und ein neuer Prozess mithilfe von "cluster.fork()" gestartet wird. + +#### Clustermodule von Node verwenden + +Clustering is made possible with Node's [cluster module](https://nodejs.org/api/cluster.html). Dadurch wird ein Masterprozess eingeleitet, um Verarbeitungsprozesse zu starten und eingehende Verbindungen auf die Verarbeitungsprozesse zu verteilen. + +#### Using PM2 + +If you deploy your application with PM2, then you can take advantage of clustering _without_ modifying your application code. You should ensure your [application is stateless](https://pm2.keymetrics.io/docs/usage/specifics/#stateless-apps) first, meaning no local data is stored in the process (such as sessions, websocket connections and the like). + +When running an application with PM2, you can enable **cluster mode** to run it in a cluster with a number of instances of your choosing, such as the matching the number of available CPUs on the machine. You can manually change the number of processes in the cluster using the `pm2` command line tool without stopping the app. + +To enable cluster mode, start your application like so: + +```bash +# Start 4 worker processes +$ pm2 start npm --name my-app -i 4 -- start +# Auto-detect number of available CPUs and start that many worker processes +$ pm2 start npm --name my-app -i max -- start +``` + +This can also be configured within a PM2 process file (`ecosystem.config.js` or similar) by setting `exec_mode` to `cluster` and `instances` to the number of workers to start. + +Once running, the application can be scaled like so: + +```bash +# Add 3 more workers +$ pm2 scale my-app +3 +# Scale to a specific number of workers +$ pm2 scale my-app 2 +``` + +For more information on clustering with PM2, see [Cluster Mode](https://pm2.keymetrics.io/docs/usage/cluster-mode/) in the PM2 documentation. + +### Anforderungsergebnisse im Cache speichern + +Eine weitere Strategie zur Verbesserung des Leistungsverhaltens in Produktionsumgebungen ist das Speichern von Anforderungergebnissen im Cache. Ihre Anwendung muss also diese Operation nicht wiederholt ausführen, um dieselbe Anforderung wiederholt zu bedienen. + +Use a caching server like [Varnish](https://www.varnish-cache.org/) or [Nginx](https://blog.nginx.org/blog/nginx-caching-guide) (see also [Nginx Caching](https://serversforhackers.com/nginx-caching/)) to greatly improve the speed and performance of your app. + +### Load Balancer verwenden + +Unabhängig davon, wie gut eine Anwendung optimiert wurde, kann eine Einzelinstanz nur eine begrenzte Arbeitslast oder einen begrenzten Datenverkehr handhaben. Eine Möglichkeit, eine Anwendung zu skalieren, ist die Ausführung mehrerer Instanzen dieser Anwendung und die Verteilung des Datenverkehrs über eine Lastausgleichsfunktion (Load Balancer) vorzunehmen. Die Einrichtung eines solchen Load Balancer kann helfen, Leistung und Geschwindigkeit Ihrer Anwendung zu verbessern. + +Ein Load Balancer ist in der Regel ein Reverse Proxy, der den Datenverkehr zu und von mehreren Anwendungsinstanzen und Servern koordiniert. You can easily set up a load balancer for your app by using [Nginx](https://nginx.org/en/docs/http/load_balancing.html) or [HAProxy](https://www.digitalocean.com/community/tutorials/an-introduction-to-haproxy-and-load-balancing-concepts). + +Bei einer solchen Lastverteilung müssen Sie sicherstellen, dass Anforderungen, die einer bestimmten Sitzungs-ID zugeordnet sind, mit dem Prozess verbunden sind, von dem sie ursprünglich stammen. Dies wird auch als _Sitzungsaffinität_ oder _Affine Sitzungen_ bezeichnet und kann durch den obigen Vorschlag, einen Datenspeicher wie Redis für Sitzungsdaten zu verwenden (je nach Anwendung), umgesetzt werden. Eine Beschreibung hierzu siehe [Mehrere Knoten verwenden](https://socket.io/docs/v4/using-multiple-nodes/). + +### Reverse Proxy verwenden + +Ein Reverse Proxy befindet sich vor einer Webanwendung und führt Unterstützungsoperationen für die Anforderungen aus (außer das Weiterleiten von Anforderungen an die Anwendung). Fehlerseiten, Komprimierungen und Caching bearbeiten, Dateien bereitstellen und Lastverteilungen vornehmen. + +Durch die Übergabe von Tasks, die keine Kenntnis des Anwendungsstatus erfordern, an einen Reverse Proxy muss Express keine speziellen Anwendungstasks mehr ausführen. For this reason, it is recommended to run Express behind a reverse proxy like [Nginx](https://www.nginx.org/) or [HAProxy](https://www.haproxy.org/) in production. diff --git a/astro/src/content/docs/de/4x/advanced/best-practice-security.md b/astro/src/content/docs/de/4x/advanced/best-practice-security.md new file mode 100644 index 0000000000..374a1f98b2 --- /dev/null +++ b/astro/src/content/docs/de/4x/advanced/best-practice-security.md @@ -0,0 +1,282 @@ +--- +title: Sicherheitsspezifische Best Practices für Express-Anwendungen in Produktionsumgebungen +description: Discover crucial security best practices for Express apps in production, including using TLS, input validation, secure cookies, and preventing vulnerabilities. +--- + +# Best Practices in Produktionsumgebungen: Sicherheit + +## Überblick + +Der Begriff _"Produktion"_ bezieht sich auf die Phase im Softwarelebenszyklus, in der eine Anwendung oder API für Endbenutzer oder Verbraucher allgemein verfügbar ist. Im Gegensatz dazu wird in der Phase _"Entwicklung"_ noch aktiv Code geschrieben und getestet. Die Anwendung ist in dieser Phase noch nicht für externen Zugriff verfügbar. Die entsprechenden Systemumgebungen werden als _Produktionsumgebungen_ und _Entwicklungsumgebungen_ bezeichnet. + +Entwicklungs- und Produktionsumgebungen werden in der Regel unterschiedlich konfiguriert und weisen deutliche Unterschiede bei den Anforderungen auf. Was in der Entwicklung funktioniert, muss in der Produktion nicht unbedingt akzeptabel sein. Beispiel: In einer Entwicklungsumgebung ist eine ausführliche Protokollierung von Fehlern für Debuggingzwecke sinnvoll. Dieselbe Vorgehensweise kann in einer Produktionsumgebung jedoch zu einem Sicherheitsproblem führen. In einer Entwicklungsumgebung müssen Sie sich keine Gedanken zu Themen wie Skalierbarkeit, Zuverlässigkeit und Leistung machen, während dies in einer Produktionsumgebung kritische Faktoren sind. + +{% capture security-note %} + +If you believe you have discovered a security vulnerability in Express, please see +[Security Policies and Procedures](/en/resources/contributing.html#security-policies-and-procedures). + +{% endcapture %} + +{% include admonitions/note.html content=security-note %} + +In diesem Beitrag werden einige der Best Practices in Bezug auf das Thema Sicherheit für Express-Anwendungen behandelt, die in der Produktionsumgebung bereitgestellt werden. + +- [Production Best Practices: Security](#production-best-practices-security) + - [Overview](#overview) + - [Don't use deprecated or vulnerable versions of Express](#dont-use-deprecated-or-vulnerable-versions-of-express) + - Über [hsts](https://github.com/helmetjs/hsts) werden `Strict-Transport-Security`-Header festgelegt, über die sichere (HTTP over SSL/TLS) Verbindungen zum Server durchgesetzt werden. + - [Do not trust user input](#do-not-trust-user-input) + - [Prevent open redirects](#prevent-open-redirects) + - "Helmet" ist eine Ansammlung von neun kleineren Middlewarefunktionen, über die sicherheitsrelevante HTTP-Header festgelegt werden. + - [Reduce fingerprinting](#reduce-fingerprinting) + - Über [xssFilter](https://github.com/helmetjs/x-xss-protection) werden `X-XSS-Protection`-Header festgelegt, um XSS-Filter (Cross-site Scripting) in den meisten aktuellen Web-Browsern zu aktivieren. + - Über [noCache](https://github.com/helmetjs/nocache) werden `Cache-Control`- und Pragma-Header festgelegt, um clientseitiges Caching zu deaktivieren. + - Über [ieNoOpen](https://github.com/helmetjs/ienoopen) werden `X-Download-Options`-Header für IE8+ festgelegt. + - [Prevent brute-force attacks against authorization](#prevent-brute-force-attacks-against-authorization) + - [Ensure your dependencies are secure](#ensure-your-dependencies-are-secure) + - [Avoid other known vulnerabilities](#avoid-other-known-vulnerabilities) + - [Additional considerations](#additional-considerations) + +## Verwenden Sie keine veralteten oder anfälligen Versionen von Express + +Express 2.x und 3.x werden nicht mehr gepflegt. Sicherheits- und Leistungsprobleme in diesen Versionen werden nicht mehr behoben. Verwenden Sie diese Versionen nicht! Wenn Sie noch nicht auf Version 4 umgestellt haben, befolgen Sie die Anweisungen im [Migrationshandbuch](/{{ page.lang }}/guide/migrating-4.html). + +Stellen Sie außerdem sicher, dass Sie keine anfälligen Express-Versionen verwenden, die auf der [Seite mit den Sicherheitsupdates](/{{ page.lang }}/advanced/security-updates.html) aufgelistet sind. Falls doch, führen Sie ein Update auf eines der stabileren Releases durch, bevorzugt das aktuelle Release. + +## TLS verwenden + +Wenn über Ihre Anwendung vertrauliche Daten bearbeitet oder übertragen werden, sollten Sie [Transport Layer Security](https://en.wikipedia.org/wiki/Transport_Layer_Security) (TLS) verwenden, um die Verbindung und die Daten zu schützen. Diese Technologie verschlüsselt Daten, bevor sie vom Client zum Server gesendet werden. Dadurch lassen sich einige gängige (und einfache) Hackerattacken vermeiden. Auch wenn Ajax- und POST-Anforderungen nicht sofort offensichtlich und in Browsern "versteckt" zu sein scheinen, ist deren Netzverkehr anfällig für das [Ausspionieren von Paketen](https://en.wikipedia.org/wiki/Packet_analyzer) und [Man-in-the-Middle-Attacken](https://en.wikipedia.org/wiki/Man-in-the-middle_attack). + +Möglicherweise sind Sie mit SSL-Verschlüsselung (Secure Socket Layer) bereits vertraut. [TLS ist einfach der nächste Entwicklungsschritt bei SSL](). In anderen Worten: Wenn Sie bisher SSL verwendet haben, sollten Sie ein Upgrade auf TLS in Erwägung ziehen. Generell empfehlen wir für TLS den Nginx-Server. Eine gute Referenz zum Konfigurieren von TLS auf Nginx (und anderen Servern) ist [Empfohlene Serverkonfigurationen (Mozilla Wiki)](https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_Server_Configurations). + +Ein handliches Tool zum Abrufen eines kostenloses TLS-Zertifikats ist außerdem [Let's Encrypt](https://letsencrypt.org/about/), eine kostenlose, automatisierte und offene Zertifizierungsstelle der [Internet Security Research Group (ISRG)](https://letsencrypt.org/isrg/). + +## Do not trust user input + +For web applications, one of the most critical security requirements is proper user input validation and handling. This comes in many forms and we will not cover all of them here. +Ultimately, the responsibility for validating and correctly handling the types of user input your application accepts is yours. + +### Prevent open redirects + +An example of potentially dangerous user input is an _open redirect_, where an application accepts a URL as user input (often in the URL query, for example `?url=https://example.com`) and uses `res.redirect` to set the `location` header and +return a 3xx status. + +An application must validate that it supports redirecting to the incoming URL to avoid sending users to malicious links such as phishing websites, among other risks. + +Here is an example of checking URLs before using `res.redirect` or `res.location`: + +```js +app.use((req, res) => { + try { + if (new Url(req.query.url).host !== 'example.com') { + return res.status(400).end(`Unsupported redirect to host: ${req.query.url}`); + } + } catch (e) { + return res.status(400).end(`Invalid url: ${req.query.url}`); + } + res.redirect(req.query.url); +}); +``` + +## "Helmet" verwenden + +[Helmet](https://www.npmjs.com/package/helmet) kann beim Schutz Ihrer Anwendung gegen einige gängige Schwachstellen hilfreiche Dienste leisten, indem die HTTP-Header entsprechend konfiguriert werden. + +Helmet is a middleware function that sets security-related HTTP response headers. Helmet sets the following headers by default: + +- `Content-Security-Policy`: A powerful allow-list of what can happen on your page which mitigates many attacks +- `Cross-Origin-Opener-Policy`: Helps process-isolate your page +- `Cross-Origin-Resource-Policy`: Blocks others from loading your resources cross-origin +- `Origin-Agent-Cluster`: Changes process isolation to be origin-based +- `Referrer-Policy`: Controls the [`Referer`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referer) header +- `Strict-Transport-Security`: Tells browsers to prefer HTTPS +- `X-Content-Type-Options`: Avoids [MIME sniffing](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#mime_sniffing) +- `X-DNS-Prefetch-Control`: Controls DNS prefetching +- `X-Download-Options`: Forces downloads to be saved (Internet Explorer only) +- `X-Frame-Options`: Legacy header that mitigates [Clickjacking](https://en.wikipedia.org/wiki/Clickjacking) attacks +- `X-Permitted-Cross-Domain-Policies`: Controls cross-domain behavior for Adobe products, like Acrobat +- `X-Powered-By`: Info about the web server. Removed because it could be used in simple attacks +- `X-XSS-Protection`: Legacy header that tries to mitigate [XSS attacks](https://developer.mozilla.org/en-US/docs/Glossary/Cross-site_scripting), but makes things worse, so Helmet disables it + +Each header can be configured or disabled. To read more about it please go to [its documentation website][helmet]. + +Installieren Sie "Helmet" wie alle anderen Module: + +```bash +$ npm install helmet +``` + +So verwenden Sie "Helmet" in Ihrem Code: + +```js +// ... + +const helmet = require('helmet'); +app.use(helmet()); + +// ... +``` + +## Reduce fingerprinting + +It can help to provide an extra layer of security to reduce the ability of attackers to determine +the software that a server uses, known as "fingerprinting." Though not a security issue itself, +reducing the ability to fingerprint an application improves its overall security posture. +Server software can be fingerprinted by quirks in how it responds to specific requests, for example in +the HTTP response headers. + +Ein bewährtes Verfahren ist also, diesen Header mit der Methode `app.disable()` zu deaktivieren: + +```js +app.disable('x-powered-by'); +``` + +{% capture powered-advisory %} + +Disabling the `X-Powered-By header` does not prevent +a sophisticated attacker from determining that an app is running Express. It may +discourage a casual exploit, but there are other ways to determine an app is running +Express. + +{% endcapture %} + +{% include admonitions/note.html content=powered-advisory %} + +Express also sends its own formatted "404 Not Found" messages and formatter error +response messages. These can be changed by +[adding your own not found handler](/en/starter/faq.html#how-do-i-handle-404-responses) +and +[writing your own error handler](/en/guide/error-handling.html#writing-error-handlers): + +```js +// last app.use calls right before app.listen(): + +// custom 404 +app.use((req, res, next) => { + res.status(404).send("Sorry can't find that!"); +}); + +// custom error handler +app.use((err, req, res, next) => { + console.error(err.stack); + res.status(500).send('Something broke!'); +}); +``` + +## Cookies sicher verwenden + +Um sicherzustellen, dass Cookies Ihre Anwendung nicht für Angriffsmöglichkeiten öffnen, sollten Sie den standardmäßigen Namen des Sitzungscookies nicht verwenden und die Cookie-Sicherheitsoptionen entsprechend festlegen. + +Es gibt zwei wesentliche Middleware-Cookie-Sitzungsmodule: + +- [express-session](https://www.npmjs.com/package/express-session), das in Express 3.x integrierte `express.session`-Middleware ersetzt. +- [cookie-session](https://www.npmjs.com/package/cookie-session), das in Express 3.x integrierte `express.cookieSession`-Middleware ersetzt. + +Der Hauptunterschied zwischen diesen beiden Modulen liegt darin, wie die Cookie-Sitzungsdaten gespeichert werden. Die [express-session](https://www.npmjs.com/package/express-session)-Middleware speichert Sitzungsdaten auf dem Server. Sie speichert nur die Sitzungs-ID im Cookie und nicht die Sitzungsdaten. Standardmäßig wird dabei der speicherinterne Speicher verwendet. Eine Verwendung der Middleware in der Produktionsumgebung ist nicht vorgesehen. In der Produktionsumgebung müssen Sie einen skalierbaren "Session-Store" einrichten. Siehe hierzu die Liste der [kompatiblen Session-Stores](https://github.com/expressjs/session#compatible-session-stores). + +Im Gegensatz dazu implementiert die [cookie-session](https://www.npmjs.com/package/cookie-session)-Middleware cookiegestützten Speicher: Sie serialisiert die gesamte Sitzung zum Cookie und nicht nur einen Sitzungsschlüssel. Diese Middleware sollten Sie nur verwenden, wenn Sitzungsdaten relativ klein sind und einfach als primitive Werte (und nicht als Objekte) codiert sind. Auch wenn Browser mindestens 4096 Byte pro Cookie unterstützen sollten, müssen Sie sicherstellen, dass dieses Limit nicht überschritten wird. Überschreiten Sie auf keinen Fall die Größe von 4093 Byte pro Domäne. Achten Sie zudem darauf, dass die Cookiedaten für den Client sichtbar sind. Wenn also ein Grund vorliegt, die Daten sicher oder unkenntlich zu machen, ist "express-session" möglicherweise die bessere Wahl. + +### Verwenden Sie nicht den standardmäßigen Namen des Sitzungscookies + +Die Verwendung des standardmäßigen Namens des Sitzungscookies kann Ihre Anwendung anfällig für Attacken machen. Das mögliche Sicherheitsproblem ist vergleichbar mit `X-Powered-By`: ein potenzieller Angreifer kann diesen Header verwenden, um einen elektronischen Fingerabdruck des Servers zu erstellen und Attacken entsprechend zu platzieren. + +Über [noSniff](https://github.com/helmetjs/dont-sniff-mimetype) werden `X-Content-Type-Options`-Header festgelegt, um bei Browsern MIME-Sniffing von Antworten weg vom deklarierten Inhaltstyp (declared content-type) vorzubeugen. + +```js +const session = require('express-session'); +app.set('trust proxy', 1); // trust first proxy +app.use( + session({ + secret: 's3Cur3', + name: 'sessionId', + }) +); +``` + +### Cookie-Sicherheitsoptionen festlegen + +Legen Sie die folgenden Cookieoptionen fest, um die Sicherheit zu erhöhen: + +- `secure` - Stellt sicher, dass der Browser das Cookie nur über HTTPS sendet. +- `httpOnly` - Stellt sicher, dass das Cookie nur über HTTP(S) und nicht über das Client-JavaScript gesendet wird und dadurch Schutz gegen Cross-Site Scripting-Attacken besteht. +- `domain` - Gibt die Domäne des Cookies an, die für den Vergleich mit der Domäne des Servers verwendet wird, in der die URL angefordert wird. Stimmen diese beiden überein, müssen Sie das Pfadattribut überprüfen. +- `path` - Gibt den Pfad des Cookies an, der für den Vergleich mit dem Anforderungspfad verwendet wird. Wenn dieser Pfad und die Domäne übereinstimmen, können Sie das Cookie in der Anforderung senden. +- `expires` - Wird verwendet, um das Ablaufdatum für persistente Cookies festzulegen. + +Dies ist ein Beispiel zur Verwendung der [cookie-session](https://www.npmjs.com/package/cookie-session)-Middleware: + +```js +const session = require('cookie-session'); +const express = require('express'); +const app = express(); + +const expiryDate = new Date(Date.now() + 60 * 60 * 1000); // 1 hour +app.use( + session({ + name: 'session', + keys: ['key1', 'key2'], + cookie: { + secure: true, + httpOnly: true, + domain: 'example.com', + path: 'foo/bar', + expires: expiryDate, + }, + }) +); +``` + +## Prevent brute-force attacks against authorization + +Make sure login endpoints are protected to make private data more secure. + +A simple and powerful technique is to block authorization attempts using two metrics: + +1. The number of consecutive failed attempts by the same user name and IP address. +2. The number of failed attempts from an IP address over some long period of time. For example, block an IP address if it makes 100 failed attempts in one day. + +[rate-limiter-flexible](https://github.com/animir/node-rate-limiter-flexible) package provides tools to make this technique easy and fast. You can find [an example of brute-force protection in the documentation](https://github.com/animir/node-rate-limiter-flexible/wiki/Overall-example#login-endpoint-protection) + +## Ensure your dependencies are secure + +Using npm to manage your application's dependencies is powerful and convenient. But the packages that you use may contain critical security vulnerabilities that could also affect your application. The security of your app is only as strong as the "weakest link" in your dependencies. + +Since npm@6, npm automatically reviews every install request. Also, you can use `npm audit` to analyze your dependency tree. + +```bash +$ npm audit +``` + +If you want to stay more secure, consider [Snyk](https://snyk.io/). + +Snyk offers both a [command-line tool](https://www.npmjs.com/package/snyk) and a [Github integration](https://snyk.io/docs/github) that checks your application against [Snyk's open source vulnerability database](https://snyk.io/vuln/) for any known vulnerabilities in your dependencies. Install the CLI as follows: + +```bash +$ npm install -g snyk +$ cd your-app +``` + +Use this command to test your application for vulnerabilities: + +```bash +$ snyk test +``` + +### Vermeiden Sie andere Schwachstellen + +Achten Sie auf [Node Security Project](https://npmjs.com/advisories)-Empfehlungen, die Express oder andere Module, die Ihre Anwendung nutzt, beeinträchtigen können. Im Allgemeinen ist Node Security Project aber eine exzellente Ressource mit Wissen und Tools zur Sicherheit von Node. + +Letztendlich können Express-Anwendungen – wie viele andere Webanwendungen auch – anfällig für eine Vielzahl webbasierter Attacken sein. Machen Sie sich deshalb mit bekannten [webspezifischen Schwachstellen](https://www.owasp.org/www-project-top-ten/) vertraut und treffen Sie die geeigneten Vorkehrungen, um diese zu vermeiden. + +## Weitere Überlegungen + +Dies sind einige weitere Empfehlungen aus der hervorragenden [Node.js Security Checklist](https://blog.risingstack.com/node-js-security-checklist/). In diesem Blogbeitrag finden Sie alle Details zu diesen Empfehlungen: + +- Filtern und bereinigen Sie immer Benutzereingaben, um sich gegen XS-Angriffe (Cross-Site Scripting) und Befehlsinjektionsattacken zu schützen. +- Implementieren Sie Verteidungsmaßnahmen gegen SQL-Injection-Attacken, indem sie parametrisierte Abfragen oder vorbereitete Anweisungen einsetzen. +- Nutzen Sie das Open-Source-Tool [sqlmap](http://sqlmap.org/), um SQL-Injection-Schwachstellen in Ihrer Anwendung zu erkennen. +- Verwenden Sie die Tools [nmap](https://nmap.org/) und [sslyze](https://github.com/nabla-c0d3/sslyze), um die Konfiguration Ihrer SSL-Verschlüsselungen, -Schlüssel und Neuvereinbarungen sowie die Gültigkeit Ihres Zertifikats zu testen. +- Verwenden Sie [safe-regex](https://www.npmjs.com/package/safe-regex), um sicherzustellen, dass Ihre regulären Ausdrücke nicht für [Denial-of-Service-Attacken](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS) anfällig sind. + +[helmet]: diff --git a/astro/src/content/docs/de/4x/advanced/developing-template-engines.md b/astro/src/content/docs/de/4x/advanced/developing-template-engines.md new file mode 100644 index 0000000000..354927776d --- /dev/null +++ b/astro/src/content/docs/de/4x/advanced/developing-template-engines.md @@ -0,0 +1,45 @@ +--- +title: Template-Engines für Express entwickeln +description: Learn how to develop custom template engines for Express.js using app.engine(), with examples on creating and integrating your own template rendering logic. +--- + +# Template-Engines für Express entwickeln + +Verwenden Sie die Methode `app.engine(ext, callback)`, um Ihre eigene Template-Engine zu erstellen. `ext` bezieht sich auf die Dateierweiterung, `callback` ist die Template-Engine-Funktion, die die folgenden Elemente als Parameter akzeptiert: die Position der Datei, das Optionsobjekt und die Callback-Funktion. + +Der folgende Code ist ein Beispiel für die Implementierung einer sehr einfachen Template-Engine für die Ausgabe von `.ntl`-Dateien. + +```js +const fs = require('fs'); // this engine requires the fs module +app.engine('ntl', (filePath, options, callback) => { + // define the template engine + fs.readFile(filePath, (err, content) => { + if (err) return callback(err); + // this is an extremely simple template engine + const rendered = content + .toString() + .replace('#title#', `${options.title}`) + .replace('#message#', `

    ${options.message}

    `); + return callback(null, rendered); + }); +}); +app.set('views', './views'); // specify the views directory +app.set('view engine', 'ntl'); // register the template engine +``` + +Ihre Anwendung ist jetzt in der Lage, `.ntl`-Dateien auszugeben. Erstellen Sie im Verzeichnis `views` eine Datei namens `index.ntl` mit dem folgenden Inhalt. + +```pug +#title# +#message# +``` + +Erstellen Sie dann in Ihrer Anwendung die folgende Route. + +```js +app.get('/', (req, res) => { + res.render('index', { title: 'Hey', message: 'Hello there!' }); +}); +``` + +Wenn Sie eine Anforderung zur Homepage einleiten, wird `index.ntl` im HTML-Format ausgegeben. diff --git a/astro/src/content/docs/de/4x/advanced/healthcheck-graceful-shutdown.md b/astro/src/content/docs/de/4x/advanced/healthcheck-graceful-shutdown.md new file mode 100644 index 0000000000..545baf7174 --- /dev/null +++ b/astro/src/content/docs/de/4x/advanced/healthcheck-graceful-shutdown.md @@ -0,0 +1,30 @@ +--- +title: Health Checks and Graceful Shutdown +description: Learn how to implement health checks and graceful shutdown in Express apps to enhance reliability, manage deployments, and integrate with load balancers like Kubernetes. +--- + +# Health Checks and Graceful Shutdown + +## Graceful shutdown + +When you deploy a new version of your application, you must replace the previous version. The process manager you're using will first send a SIGTERM signal to the application to notify it that it will be killed. Once the application gets this signal, it should stop accepting new requests, finish all the ongoing requests, clean up the resources it used, including database connections and file locks then exit. + +### Beispiel + +```js +const server = app.listen(port); + +process.on('SIGTERM', () => { + debug('SIGTERM signal received: closing HTTP server'); + server.close(() => { + debug('HTTP server closed'); + }); +}); +``` + +## Health checks + +A load balancer uses health checks to determine if an application instance is healthy and can accept requests. For example, [Kubernetes has two health checks](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/): + +- `liveness`, that determines when to restart a container. +- `readiness`, that determines when a container is ready to start accepting traffic. When a pod is not ready, it is removed from the service load balancers. diff --git a/astro/src/content/docs/de/4x/advanced/security-updates.md b/astro/src/content/docs/de/4x/advanced/security-updates.md new file mode 100644 index 0000000000..c4c6733905 --- /dev/null +++ b/astro/src/content/docs/de/4x/advanced/security-updates.md @@ -0,0 +1,84 @@ +--- +title: Express-Sicherheitsupdates +description: Review the latest security updates and patches for Express.js, including detailed vulnerability lists for different versions to help maintain a secure application. +--- + +# Sicherheitsupdates + +
    +Schwachstellen bei Node.js wirken sich direkt auf Express aus. Daher sollten Sie [ein Auge auf Schwachstellen bei Node.js haben](https://nodejs.org +/en/blog/vulnerability/) und sicherstellen, dass Sie die aktuelle stabile Version von Node.js haben. +
    + +Die folgende Liste enthält die Express-Schwachstellen, die im angegebenen Versionsupdate behoben wurden. + +{% capture security-policy %} +If you believe you have discovered a security vulnerability in Express, please see +[Security Policies and Procedures](/{{page.lang}}/resources/contributing.html#security-policies-and-procedures). +{% endcapture %} + +{% include admonitions/note.html content=security-policy %} + +## 4.x + +- 4.21.2 + - The dependency `path-to-regexp` has been updated to address a [vulnerability](https://github.com/pillarjs/path-to-regexp/security/advisories/GHSA-rhx6-c78j-4q9w). +- 4.21.1 + - The dependency `cookie` has been updated to address a [vulnerability](https://github.com/jshttp/cookie/security/advisories/GHSA-pxg6-pf52-xh8x), This may affect your application if you use `res.cookie`. +- 4.20.0 + - Fixed XSS vulnerability in `res.redirect` ([advisory](https://github.com/expressjs/express/security/advisories/GHSA-qw6h-vgh9-j6wx), [CVE-2024-43796](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-43796)). + - The dependency `serve-static` has been updated to address a [vulnerability](https://github.com/advisories/GHSA-cm22-4g7w-348p). + - The dependency `send` has been updated to address a [vulnerability](https://github.com/advisories/GHSA-m6fv-jmcg-4jfg). + - The dependency `path-to-regexp` has been updated to address a [vulnerability](https://github.com/pillarjs/path-to-regexp/security/advisories/GHSA-9wv6-86v2-598j). + - The dependency `body-parser` has been updated to addres a [vulnerability](https://github.com/advisories/GHSA-qwcr-r2fm-qrc7), This may affect your application if you had url enconding activated. +- 4.19.0, 4.19.1 + - Fixed open redirect vulnerability in `res.location` and `res.redirect` ([advisory](https://github.com/expressjs/express/security/advisories/GHSA-rv95-896h-c2vc), [CVE-2024-29041](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-29041)). +- 4.17.3 + - The dependency `qs` has been updated to address a [vulnerability](https://github.com/advisories/GHSA-hrpp-h998-j3pp). This may affect your application if the following APIs are used: `req.query`, `req.body`, `req.param`. +- 4.16.0 + - The dependency `forwarded` has been updated to address a [vulnerability](https://npmjs.com/advisories/527). This may affect your application if the following APIs are used: `req.host`, `req.hostname`, `req.ip`, `req.ips`, `req.protocol`. + - The dependency `mime` has been updated to address a [vulnerability](https://npmjs.com/advisories/535), but this issue does not impact Express. + - The dependency `send` has been updated to provide a protection against a [Node.js 8.5.0 vulnerability](https://nodejs.org/en/blog/vulnerability/september-2017-path-validation/). This only impacts running Express on the specific Node.js version 8.5.0. +- 4.15.5 + - The dependency `debug` has been updated to address a [vulnerability](https://snyk.io/vuln/npm:debug:20170905), but this issue does not impact Express. + - The dependency `fresh` has been updated to address a [vulnerability](https://npmjs.com/advisories/526). This will affect your application if the following APIs are used: `express.static`, `req.fresh`, `res.json`, `res.jsonp`, `res.send`, `res.sendfile` `res.sendFile`, `res.sendStatus`. +- 4.15.3 + - The dependency `ms` has been updated to address a [vulnerability](https://snyk.io/vuln/npm:ms:20170412). This may affect your application if untrusted string input is passed to the `maxAge` option in the following APIs: `express.static`, `res.sendfile`, and `res.sendFile`. +- 4.15.2 + - The dependency `qs` has been updated to address a [vulnerability](https://snyk.io/vuln/npm:qs:20170213), but this issue does not impact Express. Updating to 4.15.2 is a good practice, but not required to address the vulnerability. +- 4.11.1 + - Offenlegungsgefahr beim Rootpfad in `express.static`, `res.sendfile` und `res.sendFile` behoben. +- 4.10.7 + - Offene Umadressierungsschwachstelle in `express.static` ([Empfehlung](https://npmjs.com/advisories/35), [CVE-2015-1164](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-1164)) behoben. +- 4.8.8 + - Schwachstellen durch Directory-Traversal-Technik in `express.static` ([Empfehlung](http://npmjs.com/advisories/32) , [CVE-2014-6394](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-6394)) behoben. +- 4.8.4 + - Node.js 0.10 kann in bestimmten Situationen Lecks bei `fd` aufweisen, die sich auf `express.static` und `res.sendfile` auswirken. Böswillige Anforderungen können zu Lecks bei `fd` führen und letztendlich `EMFILE`-Fehler nach sich ziehen und bewirken, dass Server nicht antworten. +- 4.8.0 + - Sparse-Arrays mit extrem hohen Indizes in der Abfragezeichenfolge können bewirken, dass für die Prozessausführung nicht genügend Arbeitsspeicher zur Verfügung steht und es zu einem Serverabsturz kommt. + - Extrem verschachtelte Abfragezeichenfolgenobjekte können bewirken, dass der Prozess blockiert und der Server dadurch vorübergehend nicht antwortet. + +## 3.x + +
    + **Express 3.x WIRD NICHT MEHR GEWARTET** + +Bekannte und unbekannte Probleme bei Sicherheit und Leistung in 3.x wurden seit dem letzten Update (1. August 2015) noch nicht behoben. Es wird dringend empfohlen, die aktuelle Version von Express zu verwenden. + +If you are unable to upgrade past 3.x, please consider [Commercial Support Options](/{{ page.lang }}/support#commercial-support-options). + +
    + +- 3.19.1 + - Offenlegungsgefahr beim Rootpfad in `express.static`, `res.sendfile` und `res.sendFile` behoben. +- 3.19.0 + - Offene Umadressierungsschwachstelle in `express.static` ([Empfehlung](https://npmjs.com/advisories/35), [CVE-2015-1164](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-1164)) behoben. +- 3.16.10 + - Schwachstellen durch Directory-Traversal-Technik in `express.static` behoben. +- 3.16.6 + - Node.js 0.10 kann in bestimmten Situationen Lecks bei `fd` aufweisen, die sich auf `express.static` und `res.sendfile` auswirken. Böswillige Anforderungen können zu Lecks bei `fd` führen und letztendlich `EMFILE`-Fehler nach sich ziehen und bewirken, dass Server nicht antworten. +- 3.16.0 + - Sparse-Arrays mit extrem hohen Indizes in der Abfragezeichenfolge können bewirken, dass für die Prozessausführung nicht genügend Arbeitsspeicher zur Verfügung steht und es zu einem Serverabsturz kommt. + - Extrem verschachtelte Abfragezeichenfolgenobjekte können bewirken, dass der Prozess blockiert und der Server dadurch vorübergehend nicht antwortet. +- 3.3.0 + - Die Antwort 404 bei einem nicht unterstützten Überschreibungsversuch war anfällig gegen Cross-Site Scripting-Attacken. diff --git a/astro/src/content/docs/de/4x/api.md b/astro/src/content/docs/de/4x/api.md new file mode 100644 index 0000000000..4ec463d229 --- /dev/null +++ b/astro/src/content/docs/de/4x/api.md @@ -0,0 +1,26 @@ +--- +version: 4x +title: Express 4.x - API-Referenz +description: Access the API reference for Express.js 4.x, detailing all modules, methods, and properties for building web applications with this version. +--- + +
    + +

    4.x-API

    + +{% capture node-version %} + +Express 4.0 requires Node.js 0.10 or higher. + +{% endcapture %} + +{% include admonitions/note.html content=node-version %} + + +{% include api/en/4x/express.md %} +{% include api/en/4x/app.md %} +{% include api/en/4x/req.md %} +{% include api/en/4x/res.md %} +{% include api/en/4x/router.md %} + +
    diff --git a/astro/src/content/docs/de/4x/api/application/app-METHOD.md b/astro/src/content/docs/de/4x/api/application/app-METHOD.md new file mode 100644 index 0000000000..54d1b4a39e --- /dev/null +++ b/astro/src/content/docs/de/4x/api/application/app-METHOD.md @@ -0,0 +1,65 @@ +--- +title: app.METHOD +description: Routes an HTTP request, where METHOD is the HTTP method of the request, such as GET, +--- + +

    app.METHOD(path, callback [, callback ...])

    + +Routes an HTTP request, where METHOD is the HTTP method of the request, such as GET, +PUT, POST, and so on, in lowercase. Thus, the actual methods are `app.get()`, +`app.post()`, `app.put()`, and so on. See [Routing methods](#routing-methods) below for the complete list. + +{% include api/en/4x/routing-args.html %} + +#### Routing methods + +Express supports the following routing methods corresponding to the HTTP methods of the same names: + +
    +
      +
    • checkout
    • +
    • copy
    • +
    • delete
    • +
    • get
    • +
    • head
    • +
    • lock
    • +
    • merge
    • +
    • mkactivity
    • +
    +
      +
    • mkcol
    • +
    • move
    • +
    • m-search
    • +
    • notify
    • +
    • options
    • +
    • patch
    • +
    • post
    • +
    +
      +
    • purge
    • +
    • put
    • +
    • report
    • +
    • search
    • +
    • subscribe
    • +
    • trace
    • +
    • unlock
    • +
    • unsubscribe
    • +
    +
    + +The API documentation has explicit entries only for the most popular HTTP methods `app.get()`, +`app.post()`, `app.put()`, and `app.delete()`. +However, the other methods listed above work in exactly the same way. + +To route methods that translate to invalid JavaScript variable names, use the bracket notation. For example, `app['m-search']('/', function ...`. + +
    + The `app.get()` function is automatically called for the HTTP `HEAD` method in addition to the `GET` + method if `app.head()` was not called for the path before `app.get()`. +
    + +The method, `app.all()`, is not derived from any HTTP method and loads middleware at +the specified path for _all_ HTTP request methods. +For more information, see [app.all](#app.all). + +For more information on routing, see the [routing guide](/{{page.lang}}/guide/routing.html). diff --git a/astro/src/content/docs/de/4x/api/application/app-all.md b/astro/src/content/docs/de/4x/api/application/app-all.md new file mode 100644 index 0000000000..806726c679 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/application/app-all.md @@ -0,0 +1,49 @@ +--- +title: app.all +description: This method is like the standard [app.METHOD()](#app.METHOD) methods, +--- + +

    app.all(path, callback [, callback ...])

    + +This method is like the standard [app.METHOD()](#app.METHOD) methods, +except it matches all HTTP verbs. + +{% include api/en/4x/routing-args.html %} + +#### Examples + +The following callback is executed for requests to `/secret` whether using +GET, POST, PUT, DELETE, or any other HTTP request method: + +```js +app.all('/secret', function (req, res, next) { + console.log('Accessing the secret section ...'); + next(); // pass control to the next handler +}); +``` + +The `app.all()` method is useful for mapping "global" logic for specific path prefixes or arbitrary matches. For example, if you put the following at the top of all other +route definitions, it requires that all routes from that point on +require authentication, and automatically load a user. Keep in mind +that these callbacks do not have to act as end-points: `loadUser` +can perform a task, then call `next()` to continue matching subsequent +routes. + +```js +app.all('*', requireAuthentication, loadUser); +``` + +Or the equivalent: + +```js +app.all('*', requireAuthentication); +app.all('*', loadUser); +``` + +Another example is white-listed "global" functionality. +The example is similar to the ones above, but it only restricts paths that start with +"/api": + +```js +app.all('/api/*', requireAuthentication); +``` diff --git a/astro/src/content/docs/de/4x/api/application/app-delete-method.md b/astro/src/content/docs/de/4x/api/application/app-delete-method.md new file mode 100644 index 0000000000..9f120c22c5 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/application/app-delete-method.md @@ -0,0 +1,19 @@ +--- +title: app.delete +description: Routes HTTP DELETE requests to the specified path with the specified callback functions. +--- + +

    app.delete(path, callback [, callback ...])

    + +Routes HTTP DELETE requests to the specified path with the specified callback functions. +For more information, see the [routing guide](/{{page.lang}}/guide/routing.html). + +{% include api/en/4x/routing-args.html %} + +#### Example + +```js +app.delete('/', function (req, res) { + res.send('DELETE request to homepage'); +}); +``` diff --git a/astro/src/content/docs/de/4x/api/application/app-disable.md b/astro/src/content/docs/de/4x/api/application/app-disable.md new file mode 100644 index 0000000000..3c269bf4f6 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/application/app-disable.md @@ -0,0 +1,17 @@ +--- +title: app.disable +description: Sets the Boolean setting name to false, where name is one of the properties from the app settings table. +--- + +

    app.disable(name)

    + +Sets the Boolean setting `name` to `false`, where `name` is one of the properties from the [app settings table](#app.settings.table). +Calling `app.set('foo', false)` for a Boolean property is the same as calling `app.disable('foo')`. + +For example: + +```js +app.disable('trust proxy'); +app.get('trust proxy'); +// => false +``` diff --git a/astro/src/content/docs/de/4x/api/application/app-disabled.md b/astro/src/content/docs/de/4x/api/application/app-disabled.md new file mode 100644 index 0000000000..8183edb278 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/application/app-disabled.md @@ -0,0 +1,18 @@ +--- +title: app.disabled +description: Returns true if the Boolean setting name is disabled (false), where name is one of the properties from +--- + +

    app.disabled(name)

    + +Returns `true` if the Boolean setting `name` is disabled (`false`), where `name` is one of the properties from +the [app settings table](#app.settings.table). + +```js +app.disabled('trust proxy'); +// => true + +app.enable('trust proxy'); +app.disabled('trust proxy'); +// => false +``` diff --git a/astro/src/content/docs/de/4x/api/application/app-enable.md b/astro/src/content/docs/de/4x/api/application/app-enable.md new file mode 100644 index 0000000000..209d3364a8 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/application/app-enable.md @@ -0,0 +1,15 @@ +--- +title: app.enable +description: Sets the Boolean setting name to true, where name is one of the properties from the app settings table. +--- + +

    app.enable(name)

    + +Sets the Boolean setting `name` to `true`, where `name` is one of the properties from the [app settings table](#app.settings.table). +Calling `app.set('foo', true)` for a Boolean property is the same as calling `app.enable('foo')`. + +```js +app.enable('trust proxy'); +app.get('trust proxy'); +// => true +``` diff --git a/astro/src/content/docs/de/4x/api/application/app-enabled.md b/astro/src/content/docs/de/4x/api/application/app-enabled.md new file mode 100644 index 0000000000..9eb17158fe --- /dev/null +++ b/astro/src/content/docs/de/4x/api/application/app-enabled.md @@ -0,0 +1,18 @@ +--- +title: app.enabled +description: Returns true if the setting name is enabled (true), where name is one of the +--- + +

    app.enabled(name)

    + +Returns `true` if the setting `name` is enabled (`true`), where `name` is one of the +properties from the [app settings table](#app.settings.table). + +```js +app.enabled('trust proxy'); +// => false + +app.enable('trust proxy'); +app.enabled('trust proxy'); +// => true +``` diff --git a/astro/src/content/docs/de/4x/api/application/app-engine.md b/astro/src/content/docs/de/4x/api/application/app-engine.md new file mode 100644 index 0000000000..1d4b13a797 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/application/app-engine.md @@ -0,0 +1,41 @@ +--- +title: app.engine +description: Registers the given template engine callback as ext. +--- + +

    app.engine(ext, callback)

    + +Registers the given template engine `callback` as `ext`. + +By default, Express will `require()` the engine based on the file extension. +For example, if you try to render a "foo.pug" file, Express invokes the +following internally, and caches the `require()` on subsequent calls to increase +performance. + +```js +app.engine('pug', require('pug').__express); +``` + +Use this method for engines that do not provide `.__express` out of the box, +or if you wish to "map" a different extension to the template engine. + +For example, to map the EJS template engine to ".html" files: + +```js +app.engine('html', require('ejs').renderFile); +``` + +In this case, EJS provides a `.renderFile()` method with +the same signature that Express expects: `(path, options, callback)`, +though note that it aliases this method as `ejs.__express` internally +so if you're using ".ejs" extensions you don't need to do anything. + +Some template engines do not follow this convention. The +[consolidate.js](https://github.com/tj/consolidate.js) library maps Node template engines to follow this convention, +so they work seamlessly with Express. + +```js +var engines = require('consolidate'); +app.engine('haml', engines.haml); +app.engine('html', engines.hogan); +``` diff --git a/astro/src/content/docs/de/4x/api/application/app-get-method.md b/astro/src/content/docs/de/4x/api/application/app-get-method.md new file mode 100644 index 0000000000..0268ed1ac6 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/application/app-get-method.md @@ -0,0 +1,20 @@ +--- +title: app.get +description: Routes HTTP GET requests to the specified path with the specified callback functions. +--- + +

    app.get(path, callback [, callback ...])

    + +Routes HTTP GET requests to the specified path with the specified callback functions. + +{% include api/en/4x/routing-args.html %} + +For more information, see the [routing guide](/{{page.lang}}/guide/routing.html). + +#### Example + +```js +app.get('/', function (req, res) { + res.send('GET request to homepage'); +}); +``` diff --git a/astro/src/content/docs/de/4x/api/application/app-get.md b/astro/src/content/docs/de/4x/api/application/app-get.md new file mode 100644 index 0000000000..a2d43b52d0 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/application/app-get.md @@ -0,0 +1,18 @@ +--- +title: app.get +description: Returns the value of name app setting, where name is one of the strings in the +--- + +

    app.get(name)

    + +Returns the value of `name` app setting, where `name` is one of the strings in the +[app settings table](#app.settings.table). For example: + +```js +app.get('title'); +// => undefined + +app.set('title', 'My Site'); +app.get('title'); +// => "My Site" +``` diff --git a/astro/src/content/docs/de/4x/api/application/app-listen.md b/astro/src/content/docs/de/4x/api/application/app-listen.md new file mode 100644 index 0000000000..c68faebbb2 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/application/app-listen.md @@ -0,0 +1,58 @@ +--- +title: app.listen +description: Starts a UNIX socket and listens for connections on the given path. +--- + +

    app.listen(path, [callback])

    + +Starts a UNIX socket and listens for connections on the given path. +This method is identical to Node's [http.Server.listen()](https://nodejs.org/api/http.html#http_server_listen). + +```js +var express = require('express'); +var app = express(); +app.listen('/tmp/sock'); +``` + +

    app.listen([port[, host[, backlog]]][, callback])

    + +Binds and listens for connections on the specified host and port. +This method is identical to Node's [http.Server.listen()](https://nodejs.org/api/http.html#http_server_listen). + +If port is omitted or is 0, the operating system will assign an arbitrary unused +port, which is useful for cases like automated tasks (tests, etc.). + +```js +var express = require('express'); +var app = express(); +app.listen(3000); +``` + +The `app` returned by `express()` is in fact a JavaScript +`Function`, designed to be passed to Node's HTTP servers as a callback +to handle requests. This makes it easy to provide both HTTP and HTTPS versions of +your app with the same code base, as the app does not inherit from these +(it is simply a callback): + +```js +var express = require('express'); +var https = require('https'); +var http = require('http'); +var app = express(); + +http.createServer(app).listen(80); +https.createServer(options, app).listen(443); +``` + +The `app.listen()` method returns an [http.Server](https://nodejs.org/api/http.html#http_class_http_server) object and (for HTTP) is a convenience method for the following: + +```js +app.listen = function () { + var server = http.createServer(this); + return server.listen.apply(server, arguments); +}; +``` + +{% include admonitions/note.html content="All the forms of Node's +[http.Server.listen()](https://nodejs.org/api/http.html#http_server_listen) +method are in fact actually supported." %} diff --git a/astro/src/content/docs/de/4x/api/application/app-locals.md b/astro/src/content/docs/de/4x/api/application/app-locals.md new file mode 100644 index 0000000000..f3718bc1a6 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/application/app-locals.md @@ -0,0 +1,39 @@ +--- +title: app.locals +description: The app.locals object has properties that are local variables within the application, +--- + +

    app.locals

    + +The `app.locals` object has properties that are local variables within the application, +and will be available in templates rendered with [res.render](#res.render). + +
    +The `locals` object is used by view engines to render a response. The object +keys may be particularly sensitive and should not contain user-controlled +input, as it may affect the operation of the view engine or provide a path to +cross-site scripting. Consult the documentation for the used view engine for +additional considerations. +
    + +```js +console.dir(app.locals.title); +// => 'My App' + +console.dir(app.locals.email); +// => 'me@myapp.com' +``` + +Once set, the value of `app.locals` properties persist throughout the life of the application, +in contrast with [res.locals](#res.locals) properties that +are valid only for the lifetime of the request. + +You can access local variables in templates rendered within the application. +This is useful for providing helper functions to templates, as well as application-level data. +Local variables are available in middleware via `req.app.locals` (see [req.app](#req.app)) + +```js +app.locals.title = 'My App'; +app.locals.strftime = require('strftime'); +app.locals.email = 'me@myapp.com'; +``` diff --git a/astro/src/content/docs/de/4x/api/application/app-mountpath.md b/astro/src/content/docs/de/4x/api/application/app-mountpath.md new file mode 100644 index 0000000000..b81f5858a8 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/application/app-mountpath.md @@ -0,0 +1,50 @@ +--- +title: app.mountpath +description: The app.mountpath property contains one or more path patterns on which a sub-app was mounted. +--- + +

    app.mountpath

    + +The `app.mountpath` property contains one or more path patterns on which a sub-app was mounted. + +
    + A sub-app is an instance of `express` that may be used for handling the request to a route. +
    + +```js +var express = require('express'); + +var app = express(); // the main app +var admin = express(); // the sub app + +admin.get('/', function (req, res) { + console.log(admin.mountpath); // /admin + res.send('Admin Homepage'); +}); + +app.use('/admin', admin); // mount the sub app +``` + +It is similar to the [baseUrl](#req.baseUrl) property of the `req` object, except `req.baseUrl` +returns the matched URL path, instead of the matched patterns. + +If a sub-app is mounted on multiple path patterns, `app.mountpath` returns the list of +patterns it is mounted on, as shown in the following example. + +```js +var admin = express(); + +admin.get('/', function (req, res) { + console.dir(admin.mountpath); // [ '/adm*n', '/manager' ] + res.send('Admin Homepage'); +}); + +var secret = express(); +secret.get('/', function (req, res) { + console.log(secret.mountpath); // /secr*t + res.send('Admin Secret'); +}); + +admin.use('/secr*t', secret); // load the 'secret' router on '/secr*t', on the 'admin' sub app +app.use(['/adm*n', '/manager'], admin); // load the 'admin' router on '/adm*n' and '/manager', on the parent app +``` diff --git a/astro/src/content/docs/de/4x/api/application/app-onmount.md b/astro/src/content/docs/de/4x/api/application/app-onmount.md new file mode 100644 index 0000000000..699db4fafa --- /dev/null +++ b/astro/src/content/docs/de/4x/api/application/app-onmount.md @@ -0,0 +1,35 @@ +--- +title: app.on +description: The mount event is fired on a sub-app, when it is mounted on a parent app. The parent app is passed to the callback function. +--- + +

    app.on('mount', callback(parent))

    + +The `mount` event is fired on a sub-app, when it is mounted on a parent app. The parent app is passed to the callback function. + +
    +**NOTE** + +Sub-apps will: + +- Not inherit the value of settings that have a default value. You must set the value in the sub-app. +- Inherit the value of settings with no default value. + +For details, see [Application settings](/en/4x/api.html#app.settings.table). + +
    + +```js +var admin = express(); + +admin.on('mount', function (parent) { + console.log('Admin Mounted'); + console.log(parent); // refers to the parent app +}); + +admin.get('/', function (req, res) { + res.send('Admin Homepage'); +}); + +app.use('/admin', admin); +``` diff --git a/astro/src/content/docs/de/4x/api/application/app-param.md b/astro/src/content/docs/de/4x/api/application/app-param.md new file mode 100644 index 0000000000..6ef8819e35 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/application/app-param.md @@ -0,0 +1,165 @@ +--- +title: app.param +description: Add callback triggers to route parameters, where name is the name of the parameter or an array of parameter names, and callback is the callback function. +--- + +

    app.param([name], callback)

    + +Add callback triggers to [route parameters](/{{ page.lang }}/guide/routing.html#route-parameters), where `name` is the name of the parameter or an array of them, and `callback` is the callback function. The parameters of the callback function are the request object, the response object, the next middleware, the value of the parameter and the name of the parameter, in that order. + +If `name` is an array, the `callback` trigger is registered for each parameter declared in it, in the order in which they are declared. Furthermore, for each declared parameter except the last one, a call to `next` inside the callback will call the callback for the next declared parameter. For the last parameter, a call to `next` will call the next middleware in place for the route currently being processed, just like it would if `name` were just a string. + +For example, when `:user` is present in a route path, you may map user loading logic to automatically provide `req.user` to the route, or perform validations on the parameter input. + +```js +app.param('user', function (req, res, next, id) { + // try to get the user details from the User model and attach it to the request object + User.find(id, function (err, user) { + if (err) { + next(err); + } else if (user) { + req.user = user; + next(); + } else { + next(new Error('failed to load user')); + } + }); +}); +``` + +Param callback functions are local to the router on which they are defined. They are not inherited by mounted apps or routers, nor are they triggered for route parameters inherited from parent routers. Hence, param callbacks defined on `app` will be triggered only by route parameters defined on `app` routes. + +All param callbacks will be called before any handler of any route in which the param occurs, and they will each be called only once in a request-response cycle, even if the parameter is matched in multiple routes, as shown in the following examples. + +```js +app.param('id', function (req, res, next, id) { + console.log('CALLED ONLY ONCE'); + next(); +}); + +app.get('/user/:id', function (req, res, next) { + console.log('although this matches'); + next(); +}); + +app.get('/user/:id', function (req, res) { + console.log('and this matches too'); + res.end(); +}); +``` + +On `GET /user/42`, the following is printed: + +``` +CALLED ONLY ONCE +although this matches +and this matches too +``` + +```js +app.param(['id', 'page'], function (req, res, next, value) { + console.log('CALLED ONLY ONCE with', value); + next(); +}); + +app.get('/user/:id/:page', function (req, res, next) { + console.log('although this matches'); + next(); +}); + +app.get('/user/:id/:page', function (req, res) { + console.log('and this matches too'); + res.end(); +}); +``` + +On `GET /user/42/3`, the following is printed: + +``` +CALLED ONLY ONCE with 42 +CALLED ONLY ONCE with 3 +although this matches +and this matches too +``` + +
    +The following section describes `app.param(callback)`, which is deprecated as of v4.11.0. +
    + +The behavior of the `app.param(name, callback)` method can be altered entirely by passing only a function to `app.param()`. This function is a custom implementation of how `app.param(name, callback)` should behave - it accepts two parameters and must return a middleware. + +The first parameter of this function is the name of the URL parameter that should be captured, the second parameter can be any JavaScript object which might be used for returning the middleware implementation. + +The middleware returned by the function decides the behavior of what happens when a URL parameter is captured. + +In this example, the `app.param(name, callback)` signature is modified to `app.param(name, accessId)`. Instead of accepting a name and a callback, `app.param()` will now accept a name and a number. + +```js +var express = require('express'); +var app = express(); + +// customizing the behavior of app.param() +app.param(function (param, option) { + return function (req, res, next, val) { + if (val === option) { + next(); + } else { + next('route'); + } + }; +}); + +// using the customized app.param() +app.param('id', 1337); + +// route to trigger the capture +app.get('/user/:id', function (req, res) { + res.send('OK'); +}); + +app.listen(3000, function () { + console.log('Ready'); +}); +``` + +In this example, the `app.param(name, callback)` signature remains the same, but instead of a middleware callback, a custom data type checking function has been defined to validate the data type of the user id. + +```js +app.param(function (param, validator) { + return function (req, res, next, val) { + if (validator(val)) { + next(); + } else { + next('route'); + } + }; +}); + +app.param('id', function (candidate) { + return !isNaN(parseFloat(candidate)) && isFinite(candidate); +}); +``` + +
    +The '`.`' character can't be used to capture a character in your capturing regexp. For example you can't use `'/user-.+/'` to capture `'users-gami'`, use `[\\s\\S]` or `[\\w\\W]` instead (as in `'/user-[\\s\\S]+/'`. + +Examples: + +```js +// captures '1-a_6' but not '543-azser-sder' +router.get('/[0-9]+-[[\\w]]*', function (req, res, next) { + next(); +}); + +// captures '1-a_6' and '543-az(ser"-sder' but not '5-a s' +router.get('/[0-9]+-[[\\S]]*', function (req, res, next) { + next(); +}); + +// captures all (equivalent to '.*') +router.get('[[\\s\\S]]*', function (req, res, next) { + next(); +}); +``` + +
    diff --git a/astro/src/content/docs/de/4x/api/application/app-path.md b/astro/src/content/docs/de/4x/api/application/app-path.md new file mode 100644 index 0000000000..25538ad337 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/application/app-path.md @@ -0,0 +1,24 @@ +--- +title: app.path +description: Returns the canonical path of the app, a string. +--- + +

    app.path()

    + +Returns the canonical path of the app, a string. + +```js +var app = express(); +var blog = express(); +var blogAdmin = express(); + +app.use('/blog', blog); +blog.use('/admin', blogAdmin); + +console.dir(app.path()); // '' +console.dir(blog.path()); // '/blog' +console.dir(blogAdmin.path()); // '/blog/admin' +``` + +The behavior of this method can become very complicated in complex cases of mounted apps: +it is usually better to use [req.baseUrl](#req.baseUrl) to get the canonical path of the app. diff --git a/astro/src/content/docs/de/4x/api/application/app-post-method.md b/astro/src/content/docs/de/4x/api/application/app-post-method.md new file mode 100644 index 0000000000..1a81494c32 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/application/app-post-method.md @@ -0,0 +1,19 @@ +--- +title: app.post +description: Routes HTTP POST requests to the specified path with the specified callback functions. +--- + +

    app.post(path, callback [, callback ...])

    + +Routes HTTP POST requests to the specified path with the specified callback functions. +For more information, see the [routing guide](/{{page.lang}}/guide/routing.html). + +{% include api/en/4x/routing-args.html %} + +#### Example + +```js +app.post('/', function (req, res) { + res.send('POST request to homepage'); +}); +``` diff --git a/astro/src/content/docs/de/4x/api/application/app-put-method.md b/astro/src/content/docs/de/4x/api/application/app-put-method.md new file mode 100644 index 0000000000..33051b8806 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/application/app-put-method.md @@ -0,0 +1,18 @@ +--- +title: app.put +description: Routes HTTP PUT requests to the specified path with the specified callback functions. +--- + +

    app.put(path, callback [, callback ...])

    + +Routes HTTP PUT requests to the specified path with the specified callback functions. + +{% include api/en/4x/routing-args.html %} + +#### Example + +```js +app.put('/', function (req, res) { + res.send('PUT request to homepage'); +}); +``` diff --git a/astro/src/content/docs/de/4x/api/application/app-render.md b/astro/src/content/docs/de/4x/api/application/app-render.md new file mode 100644 index 0000000000..2703d1436b --- /dev/null +++ b/astro/src/content/docs/de/4x/api/application/app-render.md @@ -0,0 +1,44 @@ +--- +title: app.render +description: Returns the rendered HTML of a view via the callback function. It accepts an optional parameter +--- + +

    app.render(view, [locals], callback)

    + +Returns the rendered HTML of a view via the `callback` function. It accepts an optional parameter +that is an object containing local variables for the view. It is like [res.render()](#res.render), +except it cannot send the rendered view to the client on its own. + +
    +Think of `app.render()` as a utility function for generating rendered view strings. +Internally `res.render()` uses `app.render()` to render views. +
    + +
    +The `view` argument performs file system operations like reading a file from +disk and evaluating Node.js modules, and as so for security reasons should not +contain input from the end-user. +
    + +
    +The `locals` object is used by view engines to render a response. The object +keys may be particularly sensitive and should not contain user-controlled +input, as it may affect the operation of the view engine or provide a path to +cross-site scripting. Consult the documentation for the used view engine for +additional considerations. +
    + +
    +The local variable `cache` is reserved for enabling view cache. Set it to `true`, if you want to +cache view during development; view caching is enabled in production by default. +
    + +```js +app.render('email', function (err, html) { + // ... +}); + +app.render('email', { name: 'Tobi' }, function (err, html) { + // ... +}); +``` diff --git a/astro/src/content/docs/de/4x/api/application/app-route.md b/astro/src/content/docs/de/4x/api/application/app-route.md new file mode 100644 index 0000000000..e4576e6b54 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/application/app-route.md @@ -0,0 +1,26 @@ +--- +title: app.route +description: Returns an instance of a single route, which you can then use to handle HTTP verbs with optional middleware. +--- + +

    app.route(path)

    + +Returns an instance of a single route, which you can then use to handle HTTP verbs with optional middleware. +Use `app.route()` to avoid duplicate route names (and thus typo errors). + +```js +var app = express(); + +app + .route('/events') + .all(function (req, res, next) { + // runs for all HTTP verbs first + // think of it as route specific middleware! + }) + .get(function (req, res, next) { + res.json({}); + }) + .post(function (req, res, next) { + // maybe add a new event... + }); +``` diff --git a/astro/src/content/docs/de/4x/api/application/app-set.md b/astro/src/content/docs/de/4x/api/application/app-set.md new file mode 100644 index 0000000000..e2f10bd0fb --- /dev/null +++ b/astro/src/content/docs/de/4x/api/application/app-set.md @@ -0,0 +1,25 @@ +--- +title: app.set +description: Assigns setting name to value. You may store any value that you want, +--- + +

    app.set(name, value)

    + +Assigns setting `name` to `value`. You may store any value that you want, +but certain names can be used to configure the behavior of the server. These +special names are listed in the [app settings table](#app.settings.table). + +Calling `app.set('foo', true)` for a Boolean property is the same as calling +`app.enable('foo')`. Similarly, calling `app.set('foo', false)` for a Boolean +property is the same as calling `app.disable('foo')`. + +Retrieve the value of a setting with [`app.get()`](#app.get). + +```js +app.set('title', 'My Site'); +app.get('title'); // "My Site" +``` + +

    Application Settings

    + +{% include api/en/4x/app-settings.md %} diff --git a/astro/src/content/docs/de/4x/api/application/app-settings.md b/astro/src/content/docs/de/4x/api/application/app-settings.md new file mode 100644 index 0000000000..219f66966e --- /dev/null +++ b/astro/src/content/docs/de/4x/api/application/app-settings.md @@ -0,0 +1,341 @@ +--- +title: App.Settings +description: The following table lists application settings. +--- + +The following table lists application settings. + +Note that sub-apps will: + +- Not inherit the value of settings that have a default value. You must set the value in the sub-app. +- Inherit the value of settings with no default value; these are explicitly noted in the table below. + +Exceptions: Sub-apps will inherit the value of `trust proxy` even though it has a default value (for backward-compatibility); +Sub-apps will not inherit the value of `view cache` in production (when `NODE_ENV` is "production"). + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    PropertyTypeDescriptionDefault
    + `case sensitive routing` + Boolean

    Enable case sensitivity. + When enabled, "/Foo" and "/foo" are different routes. + When disabled, "/Foo" and "/foo" are treated the same.

    +

    NOTE: Sub-apps will inherit the value of this setting.

    +
    N/A (undefined) +
    + `env` + String + Environment mode. Be sure to set to "production" in a production environment; see [Production best practices: performance and reliability](/{{page.lang}}/advanced/best-practice-performance.html#env). + + `process.env.NODE_ENV` (`NODE_ENV` environment variable) or "development" if `NODE_ENV` is not set. +
    + `etag` + Varied + Set the ETag response header. For possible values, see the [`etag` options table](#etag.options.table). + +[More about the HTTP ETag header](http://en.wikipedia.org/wiki/HTTP_ETag). + + + `weak` +
    + `jsonp callback name` + StringSpecifies the default JSONP callback name. + "callback" +
    + `json escape` + Boolean + Enable escaping JSON responses from the `res.json`, `res.jsonp`, and `res.send` APIs. This will escape the characters `<`, `>`, and `&` as Unicode escape sequences in JSON. The purpose of this it to assist with [mitigating certain types of persistent XSS attacks](https://blog.mozilla.org/security/2017/07/18/web-service-audits-firefox-accounts/) when clients sniff responses for HTML. +

    NOTE: Sub-apps will inherit the value of this setting.

    +
    N/A (undefined)
    + `json replacer` + VariedThe 'replacer' argument used by `JSON.stringify`. +

    NOTE: Sub-apps will inherit the value of this setting.

    +
    N/A (undefined) +
    + `json spaces` + VariedThe 'space' argument used by `JSON.stringify`. +This is typically set to the number of spaces to use to indent prettified JSON. +

    NOTE: Sub-apps will inherit the value of this setting.

    +
    N/A (undefined)
    + `query parser` + Varied +Disable query parsing by setting the value to `false`, or set the query parser to use either "simple" or "extended" or a custom query string parsing function. + +The simple query parser is based on Node's native query parser, [querystring](http://nodejs.org/api/querystring.html). + +The extended query parser is based on [qs](https://www.npmjs.org/package/qs). + +A custom query string parsing function will receive the complete query string, and must return an object of query keys and their values. + + "extended"
    + `strict routing` + Boolean

    Enable strict routing. + When enabled, the router treats "/foo" and "/foo/" as different. + Otherwise, the router treats "/foo" and "/foo/" as the same.

    +

    NOTE: Sub-apps will inherit the value of this setting.

    +
    N/A (undefined)
    + `subdomain offset` + NumberThe number of dot-separated parts of the host to remove to access subdomain.2
    + `trust proxy` + Varied + Indicates the app is behind a front-facing proxy, and to use the `X-Forwarded-*` headers to determine the connection and the IP address of the client. NOTE: `X-Forwarded-*` headers are easily spoofed and the detected IP addresses are unreliable. +

    + When enabled, Express attempts to determine the IP address of the client connected through the front-facing proxy, or series of proxies. The `req.ips` property, then contains an array of IP addresses the client is connected through. To enable it, use the values described in the trust proxy options table. +

    + The `trust proxy` setting is implemented using the proxy-addr package. For more information, see its documentation. +

    +NOTE: Sub-apps will inherit the value of this setting, even though it has a default value. +

    +
    + `false` (disabled) +
    + `views` + String or ArrayA directory or an array of directories for the application's views. If an array, the views are looked up in the order they occur in the array. + `process.cwd() + '/views'` +
    + `view cache` + Boolean

    Enables view template compilation caching.

    +

    NOTE: Sub-apps will not inherit the value of this setting in production (when `NODE_ENV` is "production").

    +
    + `true` in production, otherwise undefined. +
    + `view engine` + StringThe default engine extension to use when omitted. +

    NOTE: Sub-apps will inherit the value of this setting.

    +
    N/A (undefined)
    + `x-powered-by` + BooleanEnables the "X-Powered-By: Express" HTTP header. + `true` +
    +
    + +
    Options for `trust proxy` setting
    + +

    + Read [Express behind proxies](/{{page.lang}}/guide/behind-proxies.html) for more + information. +

    + +
    + + + + + + + + + + + + + + + + + + + + +
    TypeValue
    Boolean + If `true`, the client's IP address is understood as the left-most entry in the `X-Forwarded-*` header. + +If `false`, the app is understood as directly facing the Internet and the client's IP address is derived from `req.connection.remoteAddress`. This is the default setting. + +
    String
    String containing comma-separated values
    Array of strings
    + An IP address, subnet, or an array of IP addresses, and subnets to trust. Pre-configured subnet names are: + +- loopback - `127.0.0.1/8`, `::1/128` +- linklocal - `169.254.0.0/16`, `fe80::/10` +- uniquelocal - `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `fc00::/7` + +Set IP addresses in any of the following ways: + +Specify a single subnet: + +```js +app.set('trust proxy', 'loopback'); +``` + +Specify a subnet and an address: + +```js +app.set('trust proxy', 'loopback, 123.123.123.123'); +``` + +Specify multiple subnets as CSV: + +```js +app.set('trust proxy', 'loopback, linklocal, uniquelocal'); +``` + +Specify multiple subnets as an array: + +```js +app.set('trust proxy', ['loopback', 'linklocal', 'uniquelocal']); +``` + +When specified, the IP addresses or the subnets are excluded from the address determination process, and the untrusted IP address nearest to the application server is determined as the client's IP address. + +
    Number + Trust the nth hop from the front-facing proxy server as the client. +
    Function + Custom trust implementation. Use this only if you know what you are doing. + +```js +app.set('trust proxy', function (ip) { + if (ip === '127.0.0.1' || ip === '123.123.123.123') + return true; // trusted IPs + else return false; +}); +``` + +
    +
    + +
    Options for `etag` setting
    + +

    +**NOTE**: These settings apply only to dynamic files, not static files. +The [express.static](#express.static) middleware ignores these settings. +

    + +

    + The ETag functionality is implemented using the + [etag](https://www.npmjs.org/package/etag) package. + For more information, see its documentation. +

    + +
    + + + + + + + + + + + + + + + + +
    TypeValue
    Boolean + `true` enables weak ETag. This is the default setting.
    + `false` disables ETag altogether. +
    String + If "strong", enables strong ETag.
    + If "weak", enables weak ETag. +
    FunctionCustom ETag function implementation. Use this only if you know what you are doing. + +```js +app.set('etag', function (body, encoding) { + return generateHash(body, encoding); // consider the function is defined +}); +``` + +
    +
    diff --git a/astro/src/content/docs/de/4x/api/application/app-use.md b/astro/src/content/docs/de/4x/api/application/app-use.md new file mode 100644 index 0000000000..5b7ec424b6 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/application/app-use.md @@ -0,0 +1,333 @@ +--- +title: app.use +description: Mounts the specified [middleware](/{{page.lang}}/guide/using-middleware.html) function or functions +--- + +

    app.use([path,] callback [, callback...])

    + +Mounts the specified [middleware](/{{page.lang}}/guide/using-middleware.html) function or functions +at the specified path: +the middleware function is executed when the base of the requested path matches `path`. + +{% include api/en/4x/routing-args.html %} + +#### Description + +A route will match any path that follows its path immediately with a "`/`". +For example: `app.use('/apple', ...)` will match "/apple", "/apple/images", +"/apple/images/news", and so on. + +Since `path` defaults to "/", middleware mounted without a path will be executed for every request to the app. +For example, this middleware function will be executed for _every_ request to the app: + +```js +app.use(function (req, res, next) { + console.log('Time: %d', Date.now()); + next(); +}); +``` + +
    +**NOTE** + +Sub-apps will: + +- Not inherit the value of settings that have a default value. You must set the value in the sub-app. +- Inherit the value of settings with no default value. + +For details, see [Application settings](/en/4x/api.html#app.settings.table). + +
    + +Middleware functions are executed sequentially, therefore the order of middleware inclusion is important. + +```js +// this middleware will not allow the request to go beyond it +app.use(function (req, res, next) { + res.send('Hello World'); +}); + +// requests will never reach this route +app.get('/', function (req, res) { + res.send('Welcome'); +}); +``` + +**Error-handling middleware** + +Error-handling middleware always takes _four_ arguments. You must provide four arguments to identify it as an error-handling middleware function. Even if you don't need to use the `next` object, you must specify it to maintain the signature. Otherwise, the `next` object will be interpreted as regular middleware and will fail to handle errors. For details about error-handling middleware, see: [Error handling](/{{ page.lang }}/guide/error-handling.html). + +Define error-handling middleware functions in the same way as other middleware functions, except with four arguments instead of three, specifically with the signature `(err, req, res, next)`): + +```js +app.use(function (err, req, res, next) { + console.error(err.stack); + res.status(500).send('Something broke!'); +}); +``` + +#### Path examples + +The following table provides some simple examples of valid `path` values for +mounting middleware. + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeExample
    Path +Matches the exact path `/abcd` and any sub-paths starting with `/abcd/` (for example, `/abcd/foo`): + +```js +app.use('/abcd', function (req, res, next) { + next(); +}); +``` + +
    Path Pattern +This will match paths starting with `/abcd` and `/abd`: + +```js +app.use('/abc?d', function (req, res, next) { + next(); +}); +``` + +This will match paths starting with `/abcd`, `/abbcd`, `/abbbbbcd`, and so on: + +```js +app.use('/ab+cd', function (req, res, next) { + next(); +}); +``` + +This will match paths starting with `/abcd`, `/abxcd`, `/abFOOcd`, `/abbArcd`, and so on: + +```js +app.use('/ab*cd', function (req, res, next) { + next(); +}); +``` + +This will match paths starting with `/ad` and `/abcd`: + +```js +app.use('/a(bc)?d', function (req, res, next) { + next(); +}); +``` + +
    Regular Expression +This will match paths starting with `/abc` and `/xyz`: + +```js +app.use(/\/abc|\/xyz/, function (req, res, next) { + next(); +}); +``` + +
    Array +This will match paths starting with `/abcd`, `/xyza`, `/lmn`, and `/pqr`: + +```js +app.use(['/abcd', '/xyza', /\/lmn|\/pqr/], function (req, res, next) { + next(); +}); +``` + +
    +
    + +#### Middleware callback function examples + +The following table provides some simple examples of middleware functions that +can be used as the `callback` argument to `app.use()`, `app.METHOD()`, and `app.all()`. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    UsageExample
    Single Middleware +You can define and mount a middleware function locally. + +```js +app.use(function (req, res, next) { + next(); +}); +``` + +A router is valid middleware. + +```js +var router = express.Router(); +router.get('/', function (req, res, next) { + next(); +}); +app.use(router); +``` + +An Express app is valid middleware. + +```js +var subApp = express(); +subApp.get('/', function (req, res, next) { + next(); +}); +app.use(subApp); +``` + +
    Series of Middleware +You can specify more than one middleware function at the same mount path. + +```js +var r1 = express.Router(); +r1.get('/', function (req, res, next) { + next(); +}); + +var r2 = express.Router(); +r2.get('/', function (req, res, next) { + next(); +}); + +app.use(r1, r2); +``` + +
    Array +Use an array to group middleware logically. + +```js +var r1 = express.Router(); +r1.get('/', function (req, res, next) { + next(); +}); + +var r2 = express.Router(); +r2.get('/', function (req, res, next) { + next(); +}); + +app.use([r1, r2]); +``` + +
    Combination +You can combine all the above ways of mounting middleware. + +```js +function mw1(req, res, next) { + next(); +} +function mw2(req, res, next) { + next(); +} + +var r1 = express.Router(); +r1.get('/', function (req, res, next) { + next(); +}); + +var r2 = express.Router(); +r2.get('/', function (req, res, next) { + next(); +}); + +var subApp = express(); +subApp.get('/', function (req, res, next) { + next(); +}); + +app.use(mw1, [mw2, r1, r2], subApp); +``` + +
    + + +Following are some examples of using the [express.static](/{{page.lang}}/guide/using-middleware.html#middleware.built-in) +middleware in an Express app. + +Serve static content for the app from the "public" directory in the application directory: + +```js +// GET /style.css etc +app.use(express.static(path.join(__dirname, 'public'))); +``` + +Mount the middleware at "/static" to serve static content only when their request path is prefixed with "/static": + +```js +// GET /static/style.css etc. +app.use('/static', express.static(path.join(__dirname, 'public'))); +``` + +Disable logging for static content requests by loading the logger middleware after the static middleware: + +```js +app.use(express.static(path.join(__dirname, 'public'))); +app.use(logger()); +``` + +Serve static files from multiple directories, but give precedence to "./public" over the others: + +```js +app.use(express.static(path.join(__dirname, 'public'))); +app.use(express.static(path.join(__dirname, 'files'))); +app.use(express.static(path.join(__dirname, 'uploads'))); +``` diff --git a/astro/src/content/docs/de/4x/api/application/overview.md b/astro/src/content/docs/de/4x/api/application/overview.md new file mode 100644 index 0000000000..93a2e52c4c --- /dev/null +++ b/astro/src/content/docs/de/4x/api/application/overview.md @@ -0,0 +1,128 @@ +--- +title: Properties +description: section markdown="1"> +--- + +

    Application

    + +The `app` object conventionally denotes the Express application. +Create it by calling the top-level `express()` function exported by the Express module: + +```js +var express = require('express'); +var app = express(); + +app.get('/', function (req, res) { + res.send('hello world'); +}); + +app.listen(3000); +``` + +The `app` object has methods for + +- Routing HTTP requests; see for example, [app.METHOD](#app.METHOD) and [app.param](#app.param). +- Configuring middleware; see [app.route](#app.route). +- Rendering HTML views; see [app.render](#app.render). +- Registering a template engine; see [app.engine](#app.engine). + +It also has settings (properties) that affect how the application behaves; +for more information, see [Application settings](#app.settings.table). + +
    +The Express application object can be referred from the [request object](#req) and the [response object](#res) as `req.app`, and `res.app`, respectively. +
    + +

    Properties

    + +
    + {% include api/en/4x/app-locals.md %} +
    + +
    + {% include api/en/4x/app-mountpath.md %} +
    + +

    Events

    + +
    + {% include api/en/4x/app-onmount.md %} +
    + +

    Methods

    + +
    + {% include api/en/4x/app-all.md %} +
    + +
    + {% include api/en/4x/app-delete-method.md %} +
    + +
    + {% include api/en/4x/app-disable.md %} +
    + +
    + {% include api/en/4x/app-disabled.md %} +
    + +
    + {% include api/en/4x/app-enable.md %} +
    + +
    + {% include api/en/4x/app-enabled.md %} +
    + +
    + {% include api/en/4x/app-engine.md %} +
    + +
    + {% include api/en/4x/app-get.md %} +
    + +
    + {% include api/en/4x/app-get-method.md %} +
    + +
    + {% include api/en/4x/app-listen.md %} +
    + +
    + {% include api/en/4x/app-METHOD.md %} +
    + +
    + {% include api/en/4x/app-param.md %} +
    + +
    + {% include api/en/4x/app-path.md %} +
    + +
    + {% include api/en/4x/app-post-method.md %} +
    + +
    + {% include api/en/4x/app-put-method.md %} +
    + +
    + {% include api/en/4x/app-render.md %} +
    + +
    + {% include api/en/4x/app-route.md %} +
    + +
    + {% include api/en/4x/app-set.md %} +
    + +
    + {% include api/en/4x/app-use.md %} +
    diff --git a/astro/src/content/docs/de/4x/api/express/express.json.md b/astro/src/content/docs/de/4x/api/express/express.json.md new file mode 100644 index 0000000000..f313870335 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/express/express.json.md @@ -0,0 +1,47 @@ +--- +title: express.json +description: This middleware is available in Express v4.16.0 onwards. +--- + +

    express.json([options])

    + +
    +This middleware is available in Express v4.16.0 onwards. +
    + +This is a built-in middleware function in Express. It parses incoming requests +with JSON payloads and is based on +[body-parser](/resources/middleware/body-parser.html). + +Returns middleware that only parses JSON and only looks at requests where +the `Content-Type` header matches the `type` option. This parser accepts any +Unicode encoding of the body and supports automatic inflation of `gzip` and +`deflate` encodings. + +A new `body` object containing the parsed data is populated on the `request` +object after the middleware (i.e. `req.body`), or an empty object (`{}`) if +there was no body to parse, the `Content-Type` was not matched, or an error +occurred. + +
    +As `req.body`'s shape is based on user-controlled input, all properties and +values in this object are untrusted and should be validated before trusting. +For example, `req.body.foo.toString()` may fail in multiple ways, for example +`foo` may not be there or may not be a string, and `toString` may not be a +function and instead a string or other user-input. +
    + +
    + +The following table describes the properties of the optional `options` object. + +| Property | Description | Type | Default | +| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | -------------------- | +| `inflate` | Enables or disables handling deflated (compressed) bodies; when disabled, deflated bodies are rejected. | Boolean | `true` | +| `limit` | Controls the maximum request body size. If this is a number, then the value specifies the number of bytes; if it is a string, the value is passed to the [bytes](https://www.npmjs.com/package/bytes) library for parsing. | Mixed | `"100kb"` | +| `reviver` | The `reviver` option is passed directly to `JSON.parse` as the second argument. You can find more information on this argument [in the MDN documentation about JSON.parse](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Example.3A_Using_the_reviver_parameter). | Function | `null` | +| `strict` | Enables or disables only accepting arrays and objects; when disabled will accept anything `JSON.parse` accepts. | Boolean | `true` | +| `type` | This is used to determine what media type the middleware will parse. This option can be a string, array of strings, or a function. If not a function, `type` option is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme) library and this can be an extension name (like `json`), a mime type (like `application/json`), or a mime type with a wildcard (like `*/*` or `*/json`). If a function, the `type` option is called as `fn(req)` and the request is parsed if it returns a truthy value. | Mixed | `"application/json"` | +| `verify` | This option, if supplied, is called as `verify(req, res, buf, encoding)`, where `buf` is a `Buffer` of the raw request body and `encoding` is the encoding of the request. The parsing can be aborted by throwing an error. | Function | `undefined` | + +
    diff --git a/astro/src/content/docs/de/4x/api/express/express.md b/astro/src/content/docs/de/4x/api/express/express.md new file mode 100644 index 0000000000..7aac38f370 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/express/express.md @@ -0,0 +1,39 @@ +--- +title: Methods +description: section markdown="1"> +--- + +

    express()

    + +Creates an Express application. The `express()` function is a top-level function exported by the `express` module. + +```js +var express = require('express'); +var app = express(); +``` + +

    Methods

    + +
    + {% include api/en/4x/express.json.md %} +
    + +
    + {% include api/en/4x/express.raw.md %} +
    + +
    + {% include api/en/4x/express.router.md %} +
    + +
    + {% include api/en/4x/express.static.md %} +
    + +
    + {% include api/en/4x/express.text.md %} +
    + +
    + {% include api/en/4x/express.urlencoded.md %} +
    diff --git a/astro/src/content/docs/de/4x/api/express/express.raw.md b/astro/src/content/docs/de/4x/api/express/express.raw.md new file mode 100644 index 0000000000..cc6626e71a --- /dev/null +++ b/astro/src/content/docs/de/4x/api/express/express.raw.md @@ -0,0 +1,45 @@ +--- +title: express.raw +description: This middleware is available in Express v4.17.0 onwards. +--- + +

    express.raw([options])

    + +
    +This middleware is available in Express v4.17.0 onwards. +
    + +This is a built-in middleware function in Express. It parses incoming request +payloads into a `Buffer` and is based on +[body-parser](/resources/middleware/body-parser.html). + +Returns middleware that parses all bodies as a `Buffer` and only looks at requests +where the `Content-Type` header matches the `type` option. This parser accepts +any Unicode encoding of the body and supports automatic inflation of `gzip` and +`deflate` encodings. + +A new `body` `Buffer` containing the parsed data is populated on the `request` +object after the middleware (i.e. `req.body`), or an empty object (`{}`) if +there was no body to parse, the `Content-Type` was not matched, or an error +occurred. + +
    +As `req.body`'s shape is based on user-controlled input, all properties and +values in this object are untrusted and should be validated before trusting. +For example, `req.body.toString()` may fail in multiple ways, for example +stacking multiple parsers `req.body` may be from a different parser. Testing +that `req.body` is a `Buffer` before calling buffer methods is recommended. +
    + +The following table describes the properties of the optional `options` object. + +
    + +| Property | Description | Type | Default | +| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ---------------------------- | +| `inflate` | Enables or disables handling deflated (compressed) bodies; when disabled, deflated bodies are rejected. | Boolean | `true` | +| `limit` | Controls the maximum request body size. If this is a number, then the value specifies the number of bytes; if it is a string, the value is passed to the [bytes](https://www.npmjs.com/package/bytes) library for parsing. | Mixed | `"100kb"` | +| `type` | This is used to determine what media type the middleware will parse. This option can be a string, array of strings, or a function. If not a function, `type` option is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme) library and this can be an extension name (like `bin`), a mime type (like `application/octet-stream`), or a mime type with a wildcard (like `*/*` or `application/*`). If a function, the `type` option is called as `fn(req)` and the request is parsed if it returns a truthy value. | Mixed | `"application/octet-stream"` | +| `verify` | This option, if supplied, is called as `verify(req, res, buf, encoding)`, where `buf` is a `Buffer` of the raw request body and `encoding` is the encoding of the request. The parsing can be aborted by throwing an error. | Function | `undefined` | + +
    diff --git a/astro/src/content/docs/de/4x/api/express/express.router.md b/astro/src/content/docs/de/4x/api/express/express.router.md new file mode 100644 index 0000000000..baf1b889fd --- /dev/null +++ b/astro/src/content/docs/de/4x/api/express/express.router.md @@ -0,0 +1,29 @@ +--- +title: express.Router +description: Creates a new [router](#router) object. +--- + +

    express.Router([options])

    + +Creates a new [router](#router) object. + +```js +var router = express.Router([options]); +``` + +The optional `options` parameter specifies the behavior of the router. + +
    + +| Property | Description | Default | Availability | +| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | ------------ | +| `caseSensitive` | Enable case sensitivity. | Disabled by default, treating "/Foo" and "/foo" as the same. | | +| `mergeParams` | Preserve the `req.params` values from the parent router. If the parent and the child have conflicting param names, the child's value take precedence. | `false` | 4.5.0+ | +| `strict` | Enable strict routing. | Disabled by default, "/foo" and "/foo/" are treated the same by the router. |   | + +
    + +You can add middleware and HTTP method routes (such as `get`, `put`, `post`, and +so on) to `router` just like an application. + +For more information, see [Router](#router). diff --git a/astro/src/content/docs/de/4x/api/express/express.static.md b/astro/src/content/docs/de/4x/api/express/express.static.md new file mode 100644 index 0000000000..9e34d55ad2 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/express/express.static.md @@ -0,0 +1,102 @@ +--- +title: express.static +description: This is a built-in middleware function in Express. +--- + +

    express.static(root, [options])

    + +This is a built-in middleware function in Express. +It serves static files and is based on [serve-static](/resources/middleware/serve-static.html). + +{% capture alert_content %} +For best results, [use a reverse proxy](/{{page.lang}}/advanced/best-practice-performance.html#use-a-reverse-proxy) cache to improve performance of serving static assets. +{% endcapture %} +{% include admonitions/note.html content=alert_content %} + +The `root` argument specifies the root directory from which to serve static assets. +The function determines the file to serve by combining `req.url` with the provided `root` directory. +When a file is not found, instead of sending a 404 response, it calls `next()` +to move on to the next middleware, allowing for stacking and fall-backs. + +The following table describes the properties of the `options` object. +See also the [example below](#example.of.express.static). + +
    + +| Property | Description | Type | Default | +| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------ | +| `dotfiles` | Determines how dotfiles (files or directories that begin with a dot ".") are treated.

    See [dotfiles](#dotfiles) below. | String | `undefined` | +| `etag` | Enable or disable etag generation

    NOTE: `express.static` always sends weak ETags. | Boolean | `true` | +| `extensions` | Sets file extension fallbacks: If a file is not found, search for files with the specified extensions and serve the first one found. Example: `['html', 'htm']`. | Mixed | `false` | +| `fallthrough` | Let client errors fall-through as unhandled requests, otherwise forward a client error.

    See [fallthrough](#fallthrough) below. | Boolean | `true` | +| `immutable` | Enable or disable the `immutable` directive in the `Cache-Control` response header. If enabled, the `maxAge` option should also be specified to enable caching. The `immutable` directive will prevent supported clients from making conditional requests during the life of the `maxAge` option to check if the file has changed. | Boolean | `false` | +| `index` | Sends the specified directory index file. Set to `false` to disable directory indexing. | Mixed | "index.html" | +| `lastModified` | Set the `Last-Modified` header to the last modified date of the file on the OS. | Boolean | `true` | +| `maxAge` | Set the max-age property of the Cache-Control header in milliseconds or a string in [ms format](https://www.npmjs.org/package/ms). | Number | 0 | +| `redirect` | Redirect to trailing "/" when the pathname is a directory. | Boolean | `true` | +| `setHeaders` | Function for setting HTTP headers to serve with the file.

    See [setHeaders](#setHeaders) below. | Function | | +| `acceptRanges` | Enable or disable accepting ranged requests. Disabling this will not send the `Accept-Ranges` header and will ignore the contents of the Range request header. | Boolean | true | +| `cacheControl` | Enable or disable setting the `Cache-Control` response header. Disabling this will ignore the immutable and maxAge options. | Boolean | true | + +
    + +For more information, see [Serving static files in Express](/starter/static-files.html). +and [Using middleware - Built-in middleware](/{{page.lang}}/guide/using-middleware.html#middleware.built-in). + +
    dotfiles
    + +Possible values for this option are: + +- "allow" - No special treatment for dotfiles. +- "deny" - Deny a request for a dotfile, respond with `403`, then call `next()`. +- "ignore" - Act as if the dotfile does not exist, respond with `404`, then call `next()`. +- `undefined` - Act as ignore, except that files in a directory that begins with a dot are **NOT** ignored. + +
    fallthrough
    + +When this option is `true`, client errors such as a bad request or a request to a non-existent +file will cause this middleware to simply call `next()` to invoke the next middleware in the stack. +When false, these errors (even 404s), will invoke `next(err)`. + +Set this option to `true` so you can map multiple physical directories +to the same web address or for routes to fill in non-existent files. + +Use `false` if you have mounted this middleware at a path designed +to be strictly a single file system directory, which allows for short-circuiting 404s +for less overhead. This middleware will also reply to all methods. + +
    setHeaders
    + +For this option, specify a function to set custom response headers. Alterations to the headers must occur synchronously. + +The signature of the function is: + +```js +fn(res, path, stat); +``` + +Arguments: + +- `res`, the [response object](#res). +- `path`, the file path that is being sent. +- `stat`, the `stat` object of the file that is being sent. + +

    Example of express.static

    + +Here is an example of using the `express.static` middleware function with an elaborate options object: + +```js +var options = { + dotfiles: 'ignore', + etag: false, + extensions: ['htm', 'html'], + index: false, + maxAge: '1d', + redirect: false, + setHeaders: function (res, path, stat) { + res.set('x-timestamp', Date.now()); + }, +}; + +app.use(express.static('public', options)); +``` diff --git a/astro/src/content/docs/de/4x/api/express/express.text.md b/astro/src/content/docs/de/4x/api/express/express.text.md new file mode 100644 index 0000000000..76aa3033fc --- /dev/null +++ b/astro/src/content/docs/de/4x/api/express/express.text.md @@ -0,0 +1,46 @@ +--- +title: express.text +description: This middleware is available in Express v4.17.0 onwards. +--- + +

    express.text([options])

    + +
    +This middleware is available in Express v4.17.0 onwards. +
    + +This is a built-in middleware function in Express. It parses incoming request +payloads into a string and is based on +[body-parser](/resources/middleware/body-parser.html). + +Returns middleware that parses all bodies as a string and only looks at requests +where the `Content-Type` header matches the `type` option. This parser accepts +any Unicode encoding of the body and supports automatic inflation of `gzip` and +`deflate` encodings. + +A new `body` string containing the parsed data is populated on the `request` +object after the middleware (i.e. `req.body`), or an empty object (`{}`) if +there was no body to parse, the `Content-Type` was not matched, or an error +occurred. + +
    +As `req.body`'s shape is based on user-controlled input, all properties and +values in this object are untrusted and should be validated before trusting. +For example, `req.body.trim()` may fail in multiple ways, for example +stacking multiple parsers `req.body` may be from a different parser. Testing +that `req.body` is a string before calling string methods is recommended. +
    + +The following table describes the properties of the optional `options` object. + +
    + +| Property | Description | Type | Default | +| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | -------------- | +| `defaultCharset` | Specify the default character set for the text content if the charset is not specified in the `Content-Type` header of the request. | String | `"utf-8"` | +| `inflate` | Enables or disables handling deflated (compressed) bodies; when disabled, deflated bodies are rejected. | Boolean | `true` | +| `limit` | Controls the maximum request body size. If this is a number, then the value specifies the number of bytes; if it is a string, the value is passed to the [bytes](https://www.npmjs.com/package/bytes) library for parsing. | Mixed | `"100kb"` | +| `type` | This is used to determine what media type the middleware will parse. This option can be a string, array of strings, or a function. If not a function, `type` option is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme) library and this can be an extension name (like `txt`), a mime type (like `text/plain`), or a mime type with a wildcard (like `*/*` or `text/*`). If a function, the `type` option is called as `fn(req)` and the request is parsed if it returns a truthy value. | Mixed | `"text/plain"` | +| `verify` | This option, if supplied, is called as `verify(req, res, buf, encoding)`, where `buf` is a `Buffer` of the raw request body and `encoding` is the encoding of the request. The parsing can be aborted by throwing an error. | Function | `undefined` | + +
    diff --git a/astro/src/content/docs/de/4x/api/express/express.urlencoded.md b/astro/src/content/docs/de/4x/api/express/express.urlencoded.md new file mode 100644 index 0000000000..6fd9fad1eb --- /dev/null +++ b/astro/src/content/docs/de/4x/api/express/express.urlencoded.md @@ -0,0 +1,53 @@ +--- +title: express.urlencoded +description: This middleware is available in Express v4.16.0 onwards. +--- + +

    express.urlencoded([options])

    + +
    +This middleware is available in Express v4.16.0 onwards. +
    + +This is a built-in middleware function in Express. It parses incoming requests +with urlencoded payloads and is based on [body-parser](/resources/middleware/body-parser.html). + +Returns middleware that only parses urlencoded bodies and only looks at +requests where the `Content-Type` header matches the `type` option. This +parser accepts only UTF-8 encoding of the body and supports automatic +inflation of `gzip` and `deflate` encodings. + +A new `body` object containing the parsed data is populated on the `request` +object after the middleware (i.e. `req.body`), or an empty object (`{}`) if +there was no body to parse, the `Content-Type` was not matched, or an error +occurred. This object will contain key-value pairs, where the value can be +a string or array (when `extended` is `false`), or any type (when `extended` +is `true`). + +
    +As `req.body`'s shape is based on user-controlled input, all properties and +values in this object are untrusted and should be validated before trusting. +For example, `req.body.foo.toString()` may fail in multiple ways, for example +`foo` may not be there or may not be a string, and `toString` may not be a +function and instead a string or other user-input. +
    + +The following table describes the properties of the optional `options` object. + +
    + +| Property | Description | Type | Default | +| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------------------------------- | +| `extended` | This option allows to choose between parsing the URL-encoded data with the `querystring` library (when `false`) or the `qs` library (when `true`). The "extended" syntax allows for rich objects and arrays to be encoded into the URL-encoded format, allowing for a JSON-like experience with URL-encoded. For more information, please [see the qs library](https://www.npmjs.org/package/qs#readme). | Boolean | `true` | +| `inflate` | Enables or disables handling deflated (compressed) bodies; when disabled, deflated bodies are rejected. | Boolean | `true` | +| `limit` | Controls the maximum request body size. If this is a number, then the value specifies the number of bytes; if it is a string, the value is passed to the [bytes](https://www.npmjs.com/package/bytes) library for parsing. | Mixed | `"100kb"` | +| `parameterLimit` | This option controls the maximum number of parameters that are allowed in the URL-encoded data. If a request contains more parameters than this value, an error will be raised. | Number | `1000` | +| `type` | This is used to determine what media type the middleware will parse. This option can be a string, array of strings, or a function. If not a function, `type` option is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme) library and this can be an extension name (like `urlencoded`), a mime type (like `application/x-www-form-urlencoded`), or a mime type with a wildcard (like `*/x-www-form-urlencoded`). If a function, the `type` option is called as `fn(req)` and the request is parsed if it returns a truthy value. | Mixed | `"application/x-www-form-urlencoded"` | +| `verify` | This option, if supplied, is called as `verify(req, res, buf, encoding)`, where `buf` is a `Buffer` of the raw request body and `encoding` is the encoding of the request. The parsing can be aborted by throwing an error. | Function | `undefined` | +| `depth` | Configure the maximum depth of the `qs` library when `extended` is `true`. This allows you to limit the amount of keys that are parsed and can be useful to prevent certain types of abuse. Defaults to `32`. It is recommended to keep this value as low as possible. | Number | `32` | + +
    + +
    +The `depth` option was added in Express v4.20.0. If you are using an earlier version, this option will not be available. +
    diff --git a/astro/src/content/docs/de/4x/api/request/overview.md b/astro/src/content/docs/de/4x/api/request/overview.md new file mode 100644 index 0000000000..8e850398bf --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/overview.md @@ -0,0 +1,160 @@ +--- +title: Properties +description: The req object represents the HTTP request and has properties for the request query string, parameters, body, HTTP headers, and so on +--- + +

    Request

    + +The `req` object represents the HTTP request and has properties for the +request query string, parameters, body, HTTP headers, and so on. In this documentation and by convention, +the object is always referred to as `req` (and the HTTP response is `res`) but its actual name is determined +by the parameters to the callback function in which you're working. + +For example: + +```js +app.get('/user/:id', function (req, res) { + res.send('user ' + req.params.id); +}); +``` + +But you could just as well have: + +```js +app.get('/user/:id', function (request, response) { + response.send('user ' + request.params.id); +}); +``` + +The `req` object is an enhanced version of Node's own request object +and supports all [built-in fields and methods](https://nodejs.org/api/http.html#http_class_http_incomingmessage). + +

    Properties

    + +
    +In Express 4, `req.files` is no longer available on the `req` object by default. To access uploaded files +on the `req.files` object, use multipart-handling middleware like [busboy](https://www.npmjs. +com/package/busboy), [multer](https://www.npmjs.com/package/multer), +[formidable](https://www.npmjs.com/package/formidable), +[multiparty](https://www.npmjs.com/package/multiparty), +[connect-multiparty](https://www.npmjs.com/package/connect-multiparty), +or [pez](https://www.npmjs.com/package/pez). +
    + +
    + {% include api/en/4x/req-app.md %} +
    + +
    + {% include api/en/4x/req-baseUrl.md %} +
    + +
    + {% include api/en/4x/req-body.md %} +
    + +
    + {% include api/en/4x/req-cookies.md %} +
    + +
    + {% include api/en/4x/req-fresh.md %} +
    + +
    + {% include api/en/4x/req-hostname.md %} +
    + +
    + {% include api/en/4x/req-ip.md %} +
    + +
    + {% include api/en/4x/req-ips.md %} +
    + +
    + {% include api/en/4x/req-method.md %} +
    + +
    + {% include api/en/4x/req-originalUrl.md %} +
    + +
    + {% include api/en/4x/req-params.md %} +
    + +
    + {% include api/en/4x/req-path.md %} +
    + +
    + {% include api/en/4x/req-protocol.md %} +
    + +
    + {% include api/en/4x/req-query.md %} +
    + +
    + {% include api/en/4x/req-res.md %} +
    + +
    + {% include api/en/4x/req-route.md %} +
    + +
    + {% include api/en/4x/req-secure.md %} +
    + +
    + {% include api/en/4x/req-signedCookies.md %} +
    + +
    + {% include api/en/4x/req-stale.md %} +
    + +
    + {% include api/en/4x/req-subdomains.md %} +
    + +
    + {% include api/en/4x/req-xhr.md %} +
    + +

    Methods

    + +
    + {% include api/en/4x/req-accepts.md %} +
    + +
    + {% include api/en/4x/req-acceptsCharsets.md %} +
    + +
    + {% include api/en/4x/req-acceptsEncodings.md %} +
    + +
    + {% include api/en/4x/req-acceptsLanguages.md %} +
    + +
    + {% include api/en/4x/req-get.md %} +
    + +
    + {% include api/en/4x/req-is.md %} +
    + +
    + {% include api/en/4x/req-param.md %} +
    + +
    + {% include api/en/4x/req-range.md %} +
    diff --git a/astro/src/content/docs/de/4x/api/request/req-accepts.md b/astro/src/content/docs/de/4x/api/request/req-accepts.md new file mode 100644 index 0000000000..763c6c6ab7 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/req-accepts.md @@ -0,0 +1,41 @@ +--- +title: req.accepts +description: Checks if the specified content types are acceptable, based on the request Accept HTTP header field. +--- + +

    req.accepts(types)

    + +Checks if the specified content types are acceptable, based on the request's `Accept` HTTP header field. +The method returns the best match, or if none of the specified content types is acceptable, returns +`false` (in which case, the application should respond with `406 "Not Acceptable"`). + +The `type` value may be a single MIME type string (such as "application/json"), +an extension name such as "json", a comma-delimited list, or an array. For a +list or array, the method returns the _best_ match (if any). + +```js +// Accept: text/html +req.accepts('html'); +// => "html" + +// Accept: text/*, application/json +req.accepts('html'); +// => "html" +req.accepts('text/html'); +// => "text/html" +req.accepts(['json', 'text']); +// => "json" +req.accepts('application/json'); +// => "application/json" + +// Accept: text/*, application/json +req.accepts('image/png'); +req.accepts('png'); +// => false + +// Accept: text/*;q=.5, application/json +req.accepts(['html', 'json']); +// => "json" +``` + +For more information, or if you have issues or concerns, see [accepts](https://github.com/expressjs/accepts). diff --git a/astro/src/content/docs/de/4x/api/request/req-acceptsCharsets.md b/astro/src/content/docs/de/4x/api/request/req-acceptsCharsets.md new file mode 100644 index 0000000000..69bed2797b --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/req-acceptsCharsets.md @@ -0,0 +1,12 @@ +--- +title: req.acceptsCharsets +description: Returns the first accepted charset of the specified character sets, +--- + +

    req.acceptsCharsets(charset [, ...])

    + +Returns the first accepted charset of the specified character sets, +based on the request's `Accept-Charset` HTTP header field. +If none of the specified charsets is accepted, returns `false`. + +For more information, or if you have issues or concerns, see [accepts](https://github.com/expressjs/accepts). diff --git a/astro/src/content/docs/de/4x/api/request/req-acceptsEncodings.md b/astro/src/content/docs/de/4x/api/request/req-acceptsEncodings.md new file mode 100644 index 0000000000..384e10bb6a --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/req-acceptsEncodings.md @@ -0,0 +1,12 @@ +--- +title: req.acceptsEncodings +description: Returns the first accepted encoding of the specified encodings, +--- + +

    req.acceptsEncodings(encoding [, ...])

    + +Returns the first accepted encoding of the specified encodings, +based on the request's `Accept-Encoding` HTTP header field. +If none of the specified encodings is accepted, returns `false`. + +For more information, or if you have issues or concerns, see [accepts](https://github.com/expressjs/accepts). diff --git a/astro/src/content/docs/de/4x/api/request/req-acceptsLanguages.md b/astro/src/content/docs/de/4x/api/request/req-acceptsLanguages.md new file mode 100644 index 0000000000..0674eaa689 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/req-acceptsLanguages.md @@ -0,0 +1,20 @@ +--- +title: req.acceptsLanguages +description: Returns the first accepted language of the specified languages, +--- + +

    req.acceptsLanguages([lang, ...])

    + +Returns the first accepted language of the specified languages, +based on the request's `Accept-Language` HTTP header field. +If none of the specified languages is accepted, returns `false`. + +If no `lang` argument is given, then `req.acceptsLanguages()` +returns all languages from the HTTP `Accept-Language` header +as an `Array`. + +For more information, or if you have issues or concerns, see [accepts](https://github.com/expressjs/accepts). + +Express (4.x) source: [request.js line 179](https://github.com/expressjs/express/blob/4.x/lib/request.js#L179) + +Accepts (1.3) source: [index.js line 195](https://github.com/jshttp/accepts/blob/f69c19e459bd501e59fb0b1a40b7471bb578113a/index.js#L195) diff --git a/astro/src/content/docs/de/4x/api/request/req-app.md b/astro/src/content/docs/de/4x/api/request/req-app.md new file mode 100644 index 0000000000..f776c3e8ad --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/req-app.md @@ -0,0 +1,25 @@ +--- +title: req.app +description: This property holds a reference to the instance of the Express application that is using the middleware. +--- + +

    req.app

    + +This property holds a reference to the instance of the Express application that is using the middleware. + +If you follow the pattern in which you create a module that just exports a middleware function +and `require()` it in your main file, then the middleware can access the Express instance via `req.app` + +For example: + +```js +// index.js +app.get('/viewdirectory', require('./mymiddleware.js')); +``` + +```js +// mymiddleware.js +module.exports = function (req, res) { + res.send('The views directory is ' + req.app.get('views')); +}; +``` diff --git a/astro/src/content/docs/de/4x/api/request/req-base-url.md b/astro/src/content/docs/de/4x/api/request/req-base-url.md new file mode 100644 index 0000000000..0100ff6db6 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/req-base-url.md @@ -0,0 +1,35 @@ +--- +title: req.baseUrl +description: The URL path on which a router instance was mounted. +--- + +

    req.baseUrl

    + +The URL path on which a router instance was mounted. + +The `req.baseUrl` property is similar to the [mountpath](#app.mountpath) property of the `app` object, +except `app.mountpath` returns the matched path pattern(s). + +For example: + +```js +var greet = express.Router(); + +greet.get('/jp', function (req, res) { + console.log(req.baseUrl); // /greet + res.send('Konnichiwa!'); +}); + +app.use('/greet', greet); // load the router on '/greet' +``` + +Even if you use a path pattern or a set of path patterns to load the router, +the `baseUrl` property returns the matched string, not the pattern(s). In the +following example, the `greet` router is loaded on two path patterns. + +```js +app.use(['/gre+t', '/hel{2}o'], greet); // load the router on '/gre+t' and '/hel{2}o' +``` + +When a request is made to `/greet/jp`, `req.baseUrl` is "/greet". When a request is +made to `/hello/jp`, `req.baseUrl` is "/hello". diff --git a/astro/src/content/docs/de/4x/api/request/req-body.md b/astro/src/content/docs/de/4x/api/request/req-body.md new file mode 100644 index 0000000000..18b8eb861c --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/req-body.md @@ -0,0 +1,30 @@ +--- +title: req.body +description: Contains key-value pairs of data submitted in the request body. +--- + +

    req.body

    + +Contains key-value pairs of data submitted in the request body. +By default, it is `undefined`, and is populated when you use body-parsing middleware such +as [`express.json()`](#express.json) or [`express.urlencoded()`](#express.urlencoded). + +
    +As `req.body`'s shape is based on user-controlled input, all properties and values in this object are untrusted and should be validated before trusting. For example, `req.body.foo.toString()` may fail in multiple ways, for example `foo` may not be there or may not be a string, and `toString` may not be a function and instead a string or other user-input. +
    + +The following example shows how to use body-parsing middleware to populate `req.body`. + +```js +var express = require('express'); + +var app = express(); + +app.use(express.json()); // for parsing application/json +app.use(express.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded + +app.post('/profile', function (req, res, next) { + console.log(req.body); + res.json(req.body); +}); +``` diff --git a/astro/src/content/docs/de/4x/api/request/req-cookies.md b/astro/src/content/docs/de/4x/api/request/req-cookies.md new file mode 100644 index 0000000000..63ac2a74b4 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/req-cookies.md @@ -0,0 +1,19 @@ +--- +title: req.cookies +description: When using cookie-parser middleware, this property is an object that +--- + +

    req.cookies

    + +When using [cookie-parser](https://www.npmjs.com/package/cookie-parser) middleware, this property is an object that +contains cookies sent by the request. If the request contains no cookies, it defaults to `{}`. + +```js +// Cookie: name=tj +console.dir(req.cookies.name); +// => 'tj' +``` + +If the cookie has been signed, you have to use [req.signedCookies](#req.signedCookies). + +For more information, issues, or concerns, see [cookie-parser](https://github.com/expressjs/cookie-parser). diff --git a/astro/src/content/docs/de/4x/api/request/req-fresh.md b/astro/src/content/docs/de/4x/api/request/req-fresh.md new file mode 100644 index 0000000000..293c12e898 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/req-fresh.md @@ -0,0 +1,18 @@ +--- +title: req.fresh +description: When the response is still fresh in the client cache true is returned, otherwise false is returned to indicate that the client cache is now stale. +--- + +

    req.fresh

    + +When the response is still "fresh" in the client's cache `true` is returned, otherwise `false` is returned to indicate that the client cache is now stale and the full response should be sent. + +When a client sends the `Cache-Control: no-cache` request header to indicate an end-to-end reload request, this module will return `false` to make handling these requests transparent. + +Further details for how cache validation works can be found in the +[HTTP/1.1 Caching Specification](https://tools.ietf.org/html/rfc7234). + +```js +console.dir(req.fresh); +// => true +``` diff --git a/astro/src/content/docs/de/4x/api/request/req-get.md b/astro/src/content/docs/de/4x/api/request/req-get.md new file mode 100644 index 0000000000..ad116d8421 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/req-get.md @@ -0,0 +1,22 @@ +--- +title: req.get +description: Returns the specified HTTP request header field (case-insensitive match). +--- + +

    req.get(field)

    + +Returns the specified HTTP request header field (case-insensitive match). +The `Referrer` and `Referer` fields are interchangeable. + +```js +req.get('Content-Type'); +// => "text/plain" + +req.get('content-type'); +// => "text/plain" + +req.get('Something'); +// => undefined +``` + +Aliased as `req.header(field)`. diff --git a/astro/src/content/docs/de/4x/api/request/req-hostname.md b/astro/src/content/docs/de/4x/api/request/req-hostname.md new file mode 100644 index 0000000000..04a2833e0e --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/req-hostname.md @@ -0,0 +1,28 @@ +--- +title: req.hostname +description: Contains the hostname derived from the Host HTTP header. +--- + +

    req.hostname

    + +Contains the hostname derived from the `Host` HTTP header. + +When the [`trust proxy` setting](/4x/api.html#trust.proxy.options.table) +does not evaluate to `false`, this property will instead get the value +from the `X-Forwarded-Host` header field. This header can be set by +the client or by the proxy. + +If there is more than one `X-Forwarded-Host` header in the request, the +value of the first header is used. This includes a single header with +comma-separated values, in which the first value is used. + +
    +Prior to Express v4.17.0, the `X-Forwarded-Host` could not contain multiple +values or be present more than once. +
    + +```js +// Host: "example.com:3000" +console.dir(req.hostname); +// => 'example.com' +``` diff --git a/astro/src/content/docs/de/4x/api/request/req-ip.md b/astro/src/content/docs/de/4x/api/request/req-ip.md new file mode 100644 index 0000000000..1f03406847 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/req-ip.md @@ -0,0 +1,17 @@ +--- +title: req.ip +description: Contains the remote IP address of the request. +--- + +

    req.ip

    + +Contains the remote IP address of the request. + +When the [`trust proxy` setting](/4x/api.html#trust.proxy.options.table) does not evaluate to `false`, +the value of this property is derived from the left-most entry in the +`X-Forwarded-For` header. This header can be set by the client or by the proxy. + +```js +console.dir(req.ip); +// => '127.0.0.1' +``` diff --git a/astro/src/content/docs/de/4x/api/request/req-ips.md b/astro/src/content/docs/de/4x/api/request/req-ips.md new file mode 100644 index 0000000000..1d632da216 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/req-ips.md @@ -0,0 +1,14 @@ +--- +title: req.ips +description: When the trust proxy setting does not evaluate to false, +--- + +

    req.ips

    + +When the [`trust proxy` setting](/4x/api.html#trust.proxy.options.table) does not evaluate to `false`, +this property contains an array of IP addresses +specified in the `X-Forwarded-For` request header. Otherwise, it contains an +empty array. This header can be set by the client or by the proxy. + +For example, if `X-Forwarded-For` is `client, proxy1, proxy2`, `req.ips` would be +`["client", "proxy1", "proxy2"]`, where `proxy2` is the furthest downstream. diff --git a/astro/src/content/docs/de/4x/api/request/req-is.md b/astro/src/content/docs/de/4x/api/request/req-is.md new file mode 100644 index 0000000000..944dba091d --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/req-is.md @@ -0,0 +1,47 @@ +--- +title: req.is +description: Returns the matching content type if the incoming request's "Content-Type" HTTP header field +--- + +

    req.is(type)

    + +Returns the matching content type if the incoming request's "Content-Type" HTTP header field +matches the MIME type specified by the `type` parameter. If the request has no body, returns `null`. +Returns `false` otherwise. + +```js +// With Content-Type: text/html; charset=utf-8 +req.is('html'); +// => 'html' +req.is('text/html'); +// => 'text/html' +req.is('text/*'); +// => 'text/*' + +// When Content-Type is application/json +req.is('json'); +// => 'json' +req.is('application/json'); +// => 'application/json' +req.is('application/*'); +// => 'application/*' + +// Using arrays +// When Content-Type is application/json +req.is(['json', 'html']); +// => 'json' + +// Using multiple arguments +// When Content-Type is application/json +req.is('json', 'html'); +// => 'json' + +req.is('html'); +// => false +req.is(['xml', 'yaml']); +// => false +req.is('xml', 'yaml'); +// => false +``` + +For more information, or if you have issues or concerns, see [type-is](https://github.com/expressjs/type-is). diff --git a/astro/src/content/docs/de/4x/api/request/req-method.md b/astro/src/content/docs/de/4x/api/request/req-method.md new file mode 100644 index 0000000000..92b683bcfd --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/req-method.md @@ -0,0 +1,9 @@ +--- +title: req.method +description: Contains a string corresponding to the HTTP method of the request +--- + +

    req.method

    + +Contains a string corresponding to the HTTP method of the request: +`GET`, `POST`, `PUT`, and so on. diff --git a/astro/src/content/docs/de/4x/api/request/req-originalUrl.md b/astro/src/content/docs/de/4x/api/request/req-originalUrl.md new file mode 100644 index 0000000000..5d0b88a5a7 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/req-originalUrl.md @@ -0,0 +1,33 @@ +--- +title: req.originalUrl +description: req.url retains the original request URL, allowing you to rewrite req.url freely for internal routing purposes +--- + +

    req.originalUrl

    + +
    +`req.url` is not a native Express property, it is inherited from Node's [http module](https://nodejs.org/api/http.html#http_message_url). +
    + +This property is much like `req.url`; however, it retains the original request URL, +allowing you to rewrite `req.url` freely for internal routing purposes. For example, +the "mounting" feature of [app.use()](#app.use) will rewrite `req.url` to strip the mount point. + +```js +// GET /search?q=something +console.dir(req.originalUrl); +// => '/search?q=something' +``` + +`req.originalUrl` is available both in middleware and router objects, and is a +combination of `req.baseUrl` and `req.url`. Consider following example: + +```js +app.use('/admin', function (req, res, next) { + // GET 'http://www.example.com/admin/new?sort=desc' + console.dir(req.originalUrl); // '/admin/new?sort=desc' + console.dir(req.baseUrl); // '/admin' + console.dir(req.path); // '/new' + next(); +}); +``` diff --git a/astro/src/content/docs/de/4x/api/request/req-param.md b/astro/src/content/docs/de/4x/api/request/req-param.md new file mode 100644 index 0000000000..0dda6b4f5a --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/req-param.md @@ -0,0 +1,41 @@ +--- +title: req.param +description: Deprecated. Use either req.params, req.body or req.query, as applicable. +--- + +

    req.param(name [, defaultValue])

    + +
    +Deprecated. Use either `req.params`, `req.body` or `req.query`, as applicable. +
    + +Returns the value of param `name` when present. + +```js +// ?name=tobi +req.param('name'); +// => "tobi" + +// POST name=tobi +req.param('name'); +// => "tobi" + +// /user/tobi for /user/:name +req.param('name'); +// => "tobi" +``` + +Lookup is performed in the following order: + +- `req.params` +- `req.body` +- `req.query` + +Optionally, you can specify `defaultValue` to set a default value if the parameter is not found in any of the request objects. + +
    +Direct access to `req.body`, `req.params`, and `req.query` should be favoured for clarity - unless you truly accept input from each object. + +Body-parsing middleware must be loaded for `req.param()` to work predictably. Refer [req.body](#req.body) for details. + +
    diff --git a/astro/src/content/docs/de/4x/api/request/req-params.md b/astro/src/content/docs/de/4x/api/request/req-params.md new file mode 100644 index 0000000000..e915644e31 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/req-params.md @@ -0,0 +1,30 @@ +--- +title: req.params +description: This property is an object containing properties mapped to the [named route "parameters"](/{{ page.lang }}/guide/routing.html#route-parameters). Fo... +--- + +

    req.params

    + +This property is an object containing properties mapped to the [named route "parameters"](/{{ page.lang }}/guide/routing.html#route-parameters). For example, if you have the route `/user/:name`, then the "name" property is available as `req.params.name`. This object defaults to `{}`. + +```js +// GET /user/tj +console.dir(req.params.name); +// => 'tj' +``` + +When you use a regular expression for the route definition, capture groups are provided as integer keys using `req.params[n]`, where `n` is the nth capture group. This rule is applied to unnamed wild card matches with string routes such as `/file/*`: + +```js +// GET /file/javascripts/jquery.js +console.dir(req.params[0]); +// => 'javascripts/jquery.js' +``` + +Named capturing groups in regular expressions behave like named route parameters. For example the group from `/^\/file\/(?.*)$/` expression is available as `req.params.path`. + +If you need to make changes to a key in `req.params`, use the [app.param](/{{ page.lang }}/4x/api.html#app.param) handler. Changes are applicable only to [parameters](/{{ page.lang }}/guide/routing.html#route-parameters) already defined in the route path. + +Any changes made to the `req.params` object in a middleware or route handler will be reset. + +{% include admonitions/note.html content="Express automatically decodes the values in `req.params` (using `decodeURIComponent`)." %} diff --git a/astro/src/content/docs/de/4x/api/request/req-path.md b/astro/src/content/docs/de/4x/api/request/req-path.md new file mode 100644 index 0000000000..6c86493204 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/req-path.md @@ -0,0 +1,18 @@ +--- +title: req.path +description: Contains the path part of the request URL. +--- + +

    req.path

    + +Contains the path part of the request URL. + +```js +// example.com/users?sort=desc +console.dir(req.path); +// => '/users' +``` + +
    +When called from a middleware, the mount point is not included in `req.path`. See [app.use()](/4x/api.html#app.use) for more details. +
    diff --git a/astro/src/content/docs/de/4x/api/request/req-protocol.md b/astro/src/content/docs/de/4x/api/request/req-protocol.md new file mode 100644 index 0000000000..569431fe0f --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/req-protocol.md @@ -0,0 +1,17 @@ +--- +title: req.protocol +description: Contains the request protocol string either http or (for TLS requests) https. +--- + +

    req.protocol

    + +Contains the request protocol string: either `http` or (for TLS requests) `https`. + +When the [`trust proxy` setting](#trust.proxy.options.table) does not evaluate to `false`, +this property will use the value of the `X-Forwarded-Proto` header field if present. +This header can be set by the client or by the proxy. + +```js +console.dir(req.protocol); +// => 'http' +``` diff --git a/astro/src/content/docs/de/4x/api/request/req-query.md b/astro/src/content/docs/de/4x/api/request/req-query.md new file mode 100644 index 0000000000..d1027d8da3 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/req-query.md @@ -0,0 +1,26 @@ +--- +title: req.query +description: This property is an object containing a property for each query string parameter in the route. +--- + +

    req.query

    + +This property is an object containing a property for each query string parameter in the route. +When [query parser](#app.settings.table) is set to disabled, it is an empty object `{}`, otherwise it is the result of the configured query parser. + +
    +As `req.query`'s shape is based on user-controlled input, all properties and values in this object are untrusted and should be validated before trusting. For example, `req.query.foo.toString()` may fail in multiple ways, for example `foo` may not be there or may not be a string, and `toString` may not be a function and instead a string or other user-input. +
    + +The value of this property can be configured with the [query parser application setting](#app.settings.table) to work how your application needs it. A very popular query string parser is the [`qs` module](https://www.npmjs.org/package/qs), and this is used by default. The `qs` module is very configurable with many settings, and it may be desirable to use different settings than the default to populate `req.query`: + +```js +var qs = require('qs'); +app.set('query parser', function (str) { + return qs.parse(str, { + /* custom options */ + }); +}); +``` + +Check out the [query parser application setting](#app.settings.table) documentation for other customization options. diff --git a/astro/src/content/docs/de/4x/api/request/req-range.md b/astro/src/content/docs/de/4x/api/request/req-range.md new file mode 100644 index 0000000000..d2b908f7f3 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/req-range.md @@ -0,0 +1,38 @@ +--- +title: req.range +description: Range header parser +--- + +

    req.range(size[, options])

    + +`Range` header parser. + +The `size` parameter is the maximum size of the resource. + +The `options` parameter is an object that can have the following properties. + +
    + +| Property | Type | Description | +| --------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `combine` | Boolean | Specify if overlapping & adjacent ranges should be combined, defaults to `false`. When `true`, ranges will be combined and returned as if they were specified that way in the header. | + +
    + +An array of ranges will be returned or negative numbers indicating an error parsing. + +- `-2` signals a malformed header string +- `-1` signals an unsatisfiable range + +```js +// parse header from request +var range = req.range(1000); + +// the type of the range +if (range.type === 'bytes') { + // the ranges + range.forEach(function (r) { + // do something with r.start and r.end + }); +} +``` diff --git a/astro/src/content/docs/de/4x/api/request/req-res.md b/astro/src/content/docs/de/4x/api/request/req-res.md new file mode 100644 index 0000000000..94e5554756 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/req-res.md @@ -0,0 +1,9 @@ +--- +title: req.res +description: This property holds a reference to the +--- + +

    req.res

    + +This property holds a reference to the response object +that relates to this request object. diff --git a/astro/src/content/docs/de/4x/api/request/req-route.md b/astro/src/content/docs/de/4x/api/request/req-route.md new file mode 100644 index 0000000000..57f8548968 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/req-route.md @@ -0,0 +1,30 @@ +--- +title: req.route +description: Contains the currently-matched route, a string +--- + +

    req.route

    + +Contains the currently-matched route, a string. For example: + +```js +app.get('/user/:id?', function userIdHandler(req, res) { + console.log(req.route); + res.send('GET'); +}); +``` + +Example output from the previous snippet: + +``` +{ path: '/user/:id?', + stack: + [ { handle: [Function: userIdHandler], + name: 'userIdHandler', + params: undefined, + path: undefined, + keys: [], + regexp: /^\/?$/i, + method: 'get' } ], + methods: { get: true } } +``` diff --git a/astro/src/content/docs/de/4x/api/request/req-secure.md b/astro/src/content/docs/de/4x/api/request/req-secure.md new file mode 100644 index 0000000000..aaee9e1a9d --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/req-secure.md @@ -0,0 +1,13 @@ +--- +title: req.secure +description: A Boolean property that is true if a TLS connection is established +--- + +

    req.secure

    + +A Boolean property that is true if a TLS connection is established. Equivalent to: + +```js +console.dir(req.protocol === 'https'); +// => true +``` diff --git a/astro/src/content/docs/de/4x/api/request/req-signedCookies.md b/astro/src/content/docs/de/4x/api/request/req-signedCookies.md new file mode 100644 index 0000000000..73750e60b0 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/req-signedCookies.md @@ -0,0 +1,22 @@ +--- +title: req.signedCookies +description: When using cookie-parser middleware, this property +--- + +

    req.signedCookies

    + +When using [cookie-parser](https://www.npmjs.com/package/cookie-parser) middleware, this property +contains signed cookies sent by the request, unsigned and ready for use. Signed cookies reside +in a different object to show developer intent; otherwise, a malicious attack could be placed on +`req.cookie` values (which are easy to spoof). Note that signing a cookie does not make it "hidden" +or encrypted; but simply prevents tampering (because the secret used to sign is private). + +If no signed cookies are sent, the property defaults to `{}`. + +```js +// Cookie: user=tobi.CP7AWaXDfAKIRfH49dQzKJx7sKzzSoPq7/AcBBRVwlI3 +console.dir(req.signedCookies.user); +// => 'tobi' +``` + +For more information, issues, or concerns, see [cookie-parser](https://github.com/expressjs/cookie-parser). diff --git a/astro/src/content/docs/de/4x/api/request/req-stale.md b/astro/src/content/docs/de/4x/api/request/req-stale.md new file mode 100644 index 0000000000..b39f5cb5ef --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/req-stale.md @@ -0,0 +1,14 @@ +--- +title: req.stale +description: Indicates whether the request is stale, and is the opposite of req.fresh. +--- + +

    req.stale

    + +Indicates whether the request is "stale," and is the opposite of `req.fresh`. +For more information, see [req.fresh](#req.fresh). + +```js +console.dir(req.stale); +// => true +``` diff --git a/astro/src/content/docs/de/4x/api/request/req-subdomains.md b/astro/src/content/docs/de/4x/api/request/req-subdomains.md new file mode 100644 index 0000000000..894143f8d1 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/req-subdomains.md @@ -0,0 +1,18 @@ +--- +title: req.subdomains +description: An array of subdomains in the domain name of the request. +--- + +

    req.subdomains

    + +An array of subdomains in the domain name of the request. + +```js +// Host: "tobi.ferrets.example.com" +console.dir(req.subdomains); +// => ['ferrets', 'tobi'] +``` + +The application property `subdomain offset`, which defaults to 2, is used for determining the +beginning of the subdomain segments. To change this behavior, change its value +using [app.set](/{{ page.lang }}/4x/api.html#app.set). diff --git a/astro/src/content/docs/de/4x/api/request/req-xhr.md b/astro/src/content/docs/de/4x/api/request/req-xhr.md new file mode 100644 index 0000000000..f247d20b05 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/request/req-xhr.md @@ -0,0 +1,14 @@ +--- +title: req.xhr +description: A Boolean property that is true if the request X-Requested-With header field is "XMLHttpRequest" +--- + +

    req.xhr

    + +A Boolean property that is `true` if the request's `X-Requested-With` header field is +"XMLHttpRequest", indicating that the request was issued by a client library such as jQuery. + +```js +console.dir(req.xhr); +// => true +``` diff --git a/astro/src/content/docs/de/4x/api/response/overview.md b/astro/src/content/docs/de/4x/api/response/overview.md new file mode 100644 index 0000000000..ba3d4a8050 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/response/overview.md @@ -0,0 +1,135 @@ +--- +title: Properties +description: section markdown="1"> +--- + +

    Response

    + +The `res` object represents the HTTP response that an Express app sends when it gets an HTTP request. + +In this documentation and by convention, +the object is always referred to as `res` (and the HTTP request is `req`) but its actual name is determined +by the parameters to the callback function in which you're working. + +For example: + +```js +app.get('/user/:id', function (req, res) { + res.send('user ' + req.params.id); +}); +``` + +But you could just as well have: + +```js +app.get('/user/:id', function (request, response) { + response.send('user ' + request.params.id); +}); +``` + +The `res` object is an enhanced version of Node's own response object +and supports all [built-in fields and methods](https://nodejs.org/api/http.html#http_class_http_serverresponse). + +

    Properties

    + +
    + {% include api/en/4x/res-app.md %} +
    + +
    + {% include api/en/4x/res-headersSent.md %} +
    + +
    + {% include api/en/4x/res-locals.md %} +
    + +

    Methods

    + +
    + {% include api/en/4x/res-append.md %} +
    + +
    + {% include api/en/4x/res-attachment.md %} +
    + +
    + {% include api/en/4x/res-cookie.md %} +
    + +
    + {% include api/en/4x/res-clearCookie.md %} +
    + +
    + {% include api/en/4x/res-download.md %} +
    + +
    + {% include api/en/4x/res-end.md %} +
    + +
    + {% include api/en/4x/res-format.md %} +
    + +
    + {% include api/en/4x/res-get.md %} +
    + +
    + {% include api/en/4x/res-json.md %} +
    + +
    + {% include api/en/4x/res-jsonp.md %} +
    + +
    + {% include api/en/4x/res-links.md %} +
    + +
    + {% include api/en/4x/res-location.md %} +
    + +
    + {% include api/en/4x/res-redirect.md %} +
    + +
    + {% include api/en/4x/res-render.md %} +
    + +
    + {% include api/en/4x/res-req.md %} +
    + +
    + {% include api/en/4x/res-send.md %} +
    + +
    + {% include api/en/4x/res-sendFile.md %} +
    + +
    + {% include api/en/4x/res-sendStatus.md %} +
    + +
    + {% include api/en/4x/res-set.md %} +
    + +
    + {% include api/en/4x/res-status.md %} +
    + +
    + {% include api/en/4x/res-type.md %} +
    + +
    + {% include api/en/4x/res-vary.md %} +
    diff --git a/astro/src/content/docs/de/4x/api/response/res-app.md b/astro/src/content/docs/de/4x/api/response/res-app.md new file mode 100644 index 0000000000..b853d54dd3 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/response/res-app.md @@ -0,0 +1,10 @@ +--- +title: res.app +description: This property holds a reference to the instance of the Express application that is using the middleware. +--- + +

    res.app

    + +This property holds a reference to the instance of the Express application that is using the middleware. + +`res.app` is identical to the [req.app](#req.app) property in the request object. diff --git a/astro/src/content/docs/de/4x/api/response/res-append.md b/astro/src/content/docs/de/4x/api/response/res-append.md new file mode 100644 index 0000000000..ecbc596f1e --- /dev/null +++ b/astro/src/content/docs/de/4x/api/response/res-append.md @@ -0,0 +1,18 @@ +--- +title: res.append +description: Appends the specified value to the HTTP response header field +--- + +

    res.append(field [, value])

    + +{% include admonitions/note.html content="`res.append()` is supported by Express v4.11.0+" %} +Appends the specified `value` to the HTTP response header `field`. If the header is not already set, +it creates the header with the specified value. The `value` parameter can be a string or an array. + +{% include admonitions/note.html content="calling `res.set()` after `res.append()` will reset the previously-set header value." %} + +```js +res.append('Link', ['', '']); +res.append('Set-Cookie', 'foo=bar; Path=/; HttpOnly'); +res.append('Warning', '199 Miscellaneous warning'); +``` diff --git a/astro/src/content/docs/de/4x/api/response/res-attachment.md b/astro/src/content/docs/de/4x/api/response/res-attachment.md new file mode 100644 index 0000000000..6d1eed1ff3 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/response/res-attachment.md @@ -0,0 +1,19 @@ +--- +title: res.attachment +description: Sets the HTTP response Content-Disposition header field to attachment. +--- + +

    res.attachment([filename])

    + +Sets the HTTP response `Content-Disposition` header field to "attachment". If a `filename` is given, +then it sets the Content-Type based on the extension name via `res.type()`, +and sets the `Content-Disposition` "filename=" parameter. + +```js +res.attachment(); +// Content-Disposition: attachment + +res.attachment('path/to/logo.png'); +// Content-Disposition: attachment; filename="logo.png" +// Content-Type: image/png +``` diff --git a/astro/src/content/docs/de/4x/api/response/res-clearCookie.md b/astro/src/content/docs/de/4x/api/response/res-clearCookie.md new file mode 100644 index 0000000000..fbe206b2f7 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/response/res-clearCookie.md @@ -0,0 +1,27 @@ +--- +title: res.clearCookie +description: Clears the cookie with the specified name by sending a Set-Cookie header that sets its expiration date in the past. +--- + +

    res.clearCookie(name [, options])

    + +Clears the cookie with the specified `name` by sending a `Set-Cookie` header that sets its expiration date in the past. +This instructs the client that the cookie has expired and is no longer valid. For more information +about available `options`, see [res.cookie()](#res.cookie). + +
    +If the `maxAge` or `expires` options are set, the cookie may not be cleared depending on the time values provided, +as Express does not ignore these options. It is therefore recommended to omit these options when calling this +method. Passing these two options has been deprecated since Express v4.20.0. +
    + +
    +Web browsers and other compliant clients will only clear the cookie if the given +`options` is identical to those given to [res.cookie()](#res.cookie), excluding +`expires` and `maxAge`. +
    + +```js +res.cookie('name', 'tobi', { path: '/admin' }); +res.clearCookie('name', { path: '/admin' }); +``` diff --git a/astro/src/content/docs/de/4x/api/response/res-cookie.md b/astro/src/content/docs/de/4x/api/response/res-cookie.md new file mode 100644 index 0000000000..340ef94962 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/response/res-cookie.md @@ -0,0 +1,95 @@ +--- +title: res.cookie +description: Sets cookie name to value. The value parameter may be a string or object converted to JSON. +--- + +

    res.cookie(name, value [, options])

    + +Sets cookie `name` to `value`. The `value` parameter may be a string or object converted to JSON. + +The `options` parameter is an object that can have the following properties. + +
    + +| Property | Type | Description | +| ------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `domain` | String | Domain name for the cookie. Defaults to the domain name of the app. | +| `encode` | Function | A synchronous function used for cookie value encoding. Defaults to `encodeURIComponent`. | +| `expires` | Date | Expiry date of the cookie in GMT. If not specified or set to 0, creates a session cookie. | +| `httpOnly` | Boolean | Flags the cookie to be accessible only by the web server. | +| `maxAge` | Number | Convenient option for setting the expiry time relative to the current time in milliseconds. | +| `path` | String | Path for the cookie. Defaults to "/". | +| `partitioned` | Boolean | Indicates that the cookie should be stored using partitioned storage. See [Cookies Having Independent Partitioned State (CHIPS)](https://developer.mozilla.org/en-US/docs/Web/Privacy/Partitioned_cookies) for more details. | +| `priority` | String | Value of the "Priority" **Set-Cookie** attribute. | +| `secure` | Boolean | Marks the cookie to be used with HTTPS only. | +| `signed` | Boolean | Indicates if the cookie should be signed. | +| `sameSite` | Boolean or String | Value of the "SameSite" **Set-Cookie** attribute. More information at [https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00#section-4.1.1](https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00#section-4.1.1). | + +
    + +
    +All `res.cookie()` does is set the HTTP `Set-Cookie` header with the options provided. +Any option not specified defaults to the value stated in [RFC 6265](http://tools.ietf.org/html/rfc6265). +
    + +For example: + +```js +res.cookie('name', 'tobi', { domain: '.example.com', path: '/admin', secure: true }); +res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true }); +``` + +You can set multiple cookies in a single response by calling `res.cookie` multiple times, for example: + +```js +res + .status(201) + .cookie('access_token', 'Bearer ' + token, { + expires: new Date(Date.now() + 8 * 3600000), // cookie will be removed after 8 hours + }) + .cookie('test', 'test') + .redirect(301, '/admin'); +``` + +The `encode` option allows you to choose the function used for cookie value encoding. +Does not support asynchronous functions. + +Example use case: You need to set a domain-wide cookie for another site in your organization. +This other site (not under your administrative control) does not use URI-encoded cookie values. + +```js +// Default encoding +res.cookie('some_cross_domain_cookie', 'http://mysubdomain.example.com', { domain: 'example.com' }); +// Result: 'some_cross_domain_cookie=http%3A%2F%2Fmysubdomain.example.com; Domain=example.com; Path=/' + +// Custom encoding +res.cookie('some_cross_domain_cookie', 'http://mysubdomain.example.com', { + domain: 'example.com', + encode: String, +}); +// Result: 'some_cross_domain_cookie=http://mysubdomain.example.com; Domain=example.com; Path=/;' +``` + +The `maxAge` option is a convenience option for setting "expires" relative to the current time in milliseconds. +The following is equivalent to the second example above. + +```js +res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true }); +``` + +You can pass an object as the `value` parameter; it is then serialized as JSON and parsed by `bodyParser()` middleware. + +```js +res.cookie('cart', { items: [1, 2, 3] }); +res.cookie('cart', { items: [1, 2, 3] }, { maxAge: 900000 }); +``` + +When using [cookie-parser](https://www.npmjs.com/package/cookie-parser) middleware, this method also +supports signed cookies. Simply include the `signed` option set to `true`. +Then `res.cookie()` will use the secret passed to `cookieParser(secret)` to sign the value. + +```js +res.cookie('name', 'tobi', { signed: true }); +``` + +Later you may access this value through the [req.signedCookie](#req.signedCookies) object. diff --git a/astro/src/content/docs/de/4x/api/response/res-download.md b/astro/src/content/docs/de/4x/api/response/res-download.md new file mode 100644 index 0000000000..08b6f43cd6 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/response/res-download.md @@ -0,0 +1,62 @@ +--- +title: res.download +description: Transfers the file at path as an attachment. Typically, browsers will prompt the user for download. +--- + +

    res.download(path [, filename] [, options] [, fn])

    + +Transfers the file at `path` as an "attachment". Typically, browsers will prompt the user for download. +By default, the `Content-Disposition` header "filename=" parameter is derived from the `path` argument, but can be overridden with the `filename` parameter. +If `path` is relative, then it will be based on the current working directory of the process or +the `root` option, if provided. + +
    +This API provides access to data on the running file system. Ensure that either (a) the way in +which the `path` argument was constructed is secure if it contains user input or (b) set the `root` +option to the absolute path of a directory to contain access within. + +When the `root` option is provided, Express will validate that the relative path provided as +`path` will resolve within the given `root` option. + +
    + +The following table provides details on the `options` parameter. + +
    +The optional `options` argument is supported by Express v4.16.0 onwards. +
    + +
    + +| Property | Description | Default | Availability | +| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------ | +| `maxAge` | Sets the max-age property of the `Cache-Control` header in milliseconds or a string in [ms format](https://www.npmjs.org/package/ms) | 0 | 4.16+ | +| `root` | Root directory for relative filenames. | | 4.18+ | +| `lastModified` | Sets the `Last-Modified` header to the last modified date of the file on the OS. Set `false` to disable it. | Enabled | 4.16+ | +| `headers` | Object containing HTTP headers to serve with the file. The header `Content-Disposition` will be overridden by the `filename` argument. | | 4.16+ | +| `dotfiles` | Option for serving dotfiles. Possible values are "allow", "deny", "ignore". | "ignore" | 4.16+ | +| `acceptRanges` | Enable or disable accepting ranged requests. | `true` | 4.16+ | +| `cacheControl` | Enable or disable setting `Cache-Control` response header. | `true` | 4.16+ | +| `immutable` | Enable or disable the `immutable` directive in the `Cache-Control` response header. If enabled, the `maxAge` option should also be specified to enable caching. The `immutable` directive will prevent supported clients from making conditional requests during the life of the `maxAge` option to check if the file has changed. | `false` | 4.16+ | + +
    + +The method invokes the callback function `fn(err)` when the transfer is complete +or when an error occurs. If the callback function is specified and an error occurs, +the callback function must explicitly handle the response process either by +ending the request-response cycle, or by passing control to the next route. + +```js +res.download('/report-12345.pdf'); + +res.download('/report-12345.pdf', 'report.pdf'); + +res.download('/report-12345.pdf', 'report.pdf', function (err) { + if (err) { + // Handle error, but keep in mind the response may be partially-sent + // so check res.headersSent + } else { + // decrement a download credit, etc. + } +}); +``` diff --git a/astro/src/content/docs/de/4x/api/response/res-end.md b/astro/src/content/docs/de/4x/api/response/res-end.md new file mode 100644 index 0000000000..1d59764120 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/response/res-end.md @@ -0,0 +1,15 @@ +--- +title: res.end +description: Ends the response process. This method actually comes from Node core, specifically the response.end method of http.ServerResponse. +--- + +

    res.end([data[, encoding]][, callback])

    + +Ends the response process. This method actually comes from Node core, specifically the [response.end() method of http.ServerResponse](https://nodejs.org/api/http.html#responseenddata-encoding-callback). + +Use to quickly end the response without any data. If you need to respond with data, instead use methods such as [res.send()](#res.send) and [res.json()](#res.json). + +```js +res.end(); +res.status(404).end(); +``` diff --git a/astro/src/content/docs/de/4x/api/response/res-format.md b/astro/src/content/docs/de/4x/api/response/res-format.md new file mode 100644 index 0000000000..570d6222dd --- /dev/null +++ b/astro/src/content/docs/de/4x/api/response/res-format.md @@ -0,0 +1,57 @@ +--- +title: res.format +description: Performs content-negotiation on the Accept HTTP header on the request object, when present. +--- + +

    res.format(object)

    + +Performs content-negotiation on the `Accept` HTTP header on the request object, when present. +It uses [req.accepts()](#req.accepts) to select a handler for the request, based on the acceptable +types ordered by their quality values. If the header is not specified, the first callback is invoked. +When no match is found, the server responds with 406 "Not Acceptable", or invokes the `default` callback. + +The `Content-Type` response header is set when a callback is selected. However, you may alter +this within the callback using methods such as `res.set()` or `res.type()`. + +The following example would respond with `{ "message": "hey" }` when the `Accept` header field is set +to "application/json" or "\*/json" (however if it is "\*/\*", then the response will be "hey"). + +```js +res.format({ + 'text/plain': function () { + res.send('hey'); + }, + + 'text/html': function () { + res.send('

    hey

    '); + }, + + 'application/json': function () { + res.send({ message: 'hey' }); + }, + + default: function () { + // log the request and respond with 406 + res.status(406).send('Not Acceptable'); + }, +}); +``` + +In addition to canonicalized MIME types, you may also use extension names mapped +to these types for a slightly less verbose implementation: + +```js +res.format({ + text: function () { + res.send('hey'); + }, + + html: function () { + res.send('

    hey

    '); + }, + + json: function () { + res.send({ message: 'hey' }); + }, +}); +``` diff --git a/astro/src/content/docs/de/4x/api/response/res-get.md b/astro/src/content/docs/de/4x/api/response/res-get.md new file mode 100644 index 0000000000..300dd9d1a9 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/response/res-get.md @@ -0,0 +1,14 @@ +--- +title: res.get +description: Returns the HTTP response header specified by field. +--- + +

    res.get(field)

    + +Returns the HTTP response header specified by `field`. +The match is case-insensitive. + +```js +res.get('Content-Type'); +// => "text/plain" +``` diff --git a/astro/src/content/docs/de/4x/api/response/res-headersSent.md b/astro/src/content/docs/de/4x/api/response/res-headersSent.md new file mode 100644 index 0000000000..7eaca46914 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/response/res-headersSent.md @@ -0,0 +1,16 @@ +--- +title: res.headersSent +description: Boolean property that indicates if the app sent HTTP headers for the response. +--- + +

    res.headersSent

    + +Boolean property that indicates if the app sent HTTP headers for the response. + +```js +app.get('/', function (req, res) { + console.dir(res.headersSent); // false + res.send('OK'); + console.dir(res.headersSent); // true +}); +``` diff --git a/astro/src/content/docs/de/4x/api/response/res-json.md b/astro/src/content/docs/de/4x/api/response/res-json.md new file mode 100644 index 0000000000..40d6c0c083 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/response/res-json.md @@ -0,0 +1,18 @@ +--- +title: res.json +description: Sends a JSON response. This method sends a response (with the correct content-type) that is the parameter converted to a +--- + +

    res.json([body])

    + +Sends a JSON response. This method sends a response (with the correct content-type) that is the parameter converted to a +JSON string using [JSON.stringify()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify). + +The parameter can be any JSON type, including object, array, string, Boolean, number, or null, +and you can also use it to convert other values to JSON. + +```js +res.json(null); +res.json({ user: 'tobi' }); +res.status(500).json({ error: 'message' }); +``` diff --git a/astro/src/content/docs/de/4x/api/response/res-jsonp.md b/astro/src/content/docs/de/4x/api/response/res-jsonp.md new file mode 100644 index 0000000000..7dad964a15 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/response/res-jsonp.md @@ -0,0 +1,37 @@ +--- +title: res.jsonp +description: Sends a JSON response with JSONP support. This method is identical to res.json, +--- + +

    res.jsonp([body])

    + +Sends a JSON response with JSONP support. This method is identical to `res.json()`, +except that it opts-in to JSONP callback support. + +```js +res.jsonp(null); +// => callback(null) + +res.jsonp({ user: 'tobi' }); +// => callback({ "user": "tobi" }) + +res.status(500).jsonp({ error: 'message' }); +// => callback({ "error": "message" }) +``` + +By default, the JSONP callback name is simply `callback`. Override this with the +jsonp callback name setting. + +The following are some examples of JSONP responses using the same code: + +```js +// ?callback=foo +res.jsonp({ user: 'tobi' }); +// => foo({ "user": "tobi" }) + +app.set('jsonp callback name', 'cb'); + +// ?cb=foo +res.status(500).jsonp({ error: 'message' }); +// => foo({ "error": "message" }) +``` diff --git a/astro/src/content/docs/de/4x/api/response/res-links.md b/astro/src/content/docs/de/4x/api/response/res-links.md new file mode 100644 index 0000000000..a3c2b12004 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/response/res-links.md @@ -0,0 +1,25 @@ +--- +title: res.links +description: Joins the links provided as properties of the parameter to populate the response Link HTTP header field. +--- + + + +Joins the `links` provided as properties of the parameter to populate the response's +`Link` HTTP header field. + +For example, the following call: + +```js +res.links({ + next: 'http://api.example.com/users?page=2', + last: 'http://api.example.com/users?page=5', +}); +``` + +Yields the following results: + +``` +Link: ; rel="next", + ; rel="last" +``` diff --git a/astro/src/content/docs/de/4x/api/response/res-locals.md b/astro/src/content/docs/de/4x/api/response/res-locals.md new file mode 100644 index 0000000000..b15e2558c9 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/response/res-locals.md @@ -0,0 +1,33 @@ +--- +title: res.locals +description: Use this property to set variables accessible in templates rendered with [res.render](#res.render). +--- + +

    res.locals

    + +Use this property to set variables accessible in templates rendered with [res.render](#res.render). +The variables set on `res.locals` are available within a single request-response cycle, and will not +be shared between requests. + +
    +The `locals` object is used by view engines to render a response. The object +keys may be particularly sensitive and should not contain user-controlled +input, as it may affect the operation of the view engine or provide a path to +cross-site scripting. Consult the documentation for the used view engine for +additional considerations. +
    + +In order to keep local variables for use in template rendering between requests, use +[app.locals](#app.locals) instead. + +This property is useful for exposing request-level information such as the request path name, +authenticated user, user settings, and so on to templates rendered within the application. + +```js +app.use(function (req, res, next) { + // Make `user` and `authenticated` available in templates + res.locals.user = req.user; + res.locals.authenticated = !req.user.anonymous; + next(); +}); +``` diff --git a/astro/src/content/docs/de/4x/api/response/res-location.md b/astro/src/content/docs/de/4x/api/response/res-location.md new file mode 100644 index 0000000000..5211174c2e --- /dev/null +++ b/astro/src/content/docs/de/4x/api/response/res-location.md @@ -0,0 +1,30 @@ +--- +title: res.location +description: Sets the response Location HTTP header to the specified path parameter. +--- + +

    res.location(path)

    + +Sets the response `Location` HTTP header to the specified `path` parameter. + +```js +res.location('/foo/bar'); +res.location('http://example.com'); +res.location('back'); +``` + +{% include admonitions/note.html content="`'back'` was deprecated in 4.21.0, use `req.get('Referrer') || '/'` as an argument instead." %} + +A `path` value of "back" has a special meaning, it refers to the URL specified in the `Referer` header of the request. If the `Referer` header was not specified, it refers to "/". + +See also [Security best practices: Prevent open redirect +vulnerabilities](http://expressjs.com/en/advanced/best-practice-security.html#prevent-open-redirects). + +
    +After encoding the URL, if not encoded already, Express passes the specified URL to the browser in the `Location` header, +without any validation. + +Browsers take the responsibility of deriving the intended URL from the current URL +or the referring URL, and the URL specified in the `Location` header; and redirect the user accordingly. + +
    diff --git a/astro/src/content/docs/de/4x/api/response/res-redirect.md b/astro/src/content/docs/de/4x/api/response/res-redirect.md new file mode 100644 index 0000000000..7271794017 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/response/res-redirect.md @@ -0,0 +1,65 @@ +--- +title: res.redirect +description: Redirects to the URL derived from the specified path, with specified status, a positive integer +--- + +

    res.redirect([status,] path)

    + +Redirects to the URL derived from the specified `path`, with specified `status`, a positive integer +that corresponds to an [HTTP status code](https://www.rfc-editor.org/rfc/rfc9110.html#name-status-codes) . +If not specified, `status` defaults to "302 "Found". + +```js +res.redirect('/foo/bar'); +res.redirect('http://example.com'); +res.redirect(301, 'http://example.com'); +res.redirect('../login'); +``` + +Redirects can be a fully-qualified URL for redirecting to a different site: + +```js +res.redirect('http://google.com'); +``` + +Redirects can be relative to the root of the host name. For example, if the +application is on `http://example.com/admin/post/new`, the following +would redirect to the URL `http://example.com/admin`: + +```js +res.redirect('/admin'); +``` + +Redirects can be relative to the current URL. For example, +from `http://example.com/blog/admin/` (notice the trailing slash), the following +would redirect to the URL `http://example.com/blog/admin/post/new`. + +```js +res.redirect('post/new'); +``` + +Redirecting to `post/new` from `http://example.com/blog/admin` (no trailing slash), +will redirect to `http://example.com/blog/post/new`. + +If you found the above behavior confusing, think of path segments as directories +(with trailing slashes) and files, it will start to make sense. + +Path-relative redirects are also possible. If you were on +`http://example.com/admin/post/new`, the following would redirect to +`http://example.com/admin/post`: + +```js +res.redirect('..'); +``` + +A `back` redirection redirects the request back to the [referer](http://en.wikipedia.org/wiki/HTTP_referer), +defaulting to `/` when the referer is missing. + +```js +res.redirect('back'); +``` + +{% include admonitions/note.html content="`back` redirect was deprecated in 4.21.0, use `req.get('Referrer') || '/'` as an argument instead." %} + +See also [Security best practices: Prevent open redirect +vulnerabilities](http://expressjs.com/en/advanced/best-practice-security.html#prevent-open-redirects). diff --git a/astro/src/content/docs/de/4x/api/response/res-render.md b/astro/src/content/docs/de/4x/api/response/res-render.md new file mode 100644 index 0000000000..0fe6e14cc6 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/response/res-render.md @@ -0,0 +1,50 @@ +--- +title: res.render +description: Renders a view and sends the rendered HTML string to the client. +--- + +

    res.render(view [, locals] [, callback])

    + +Renders a `view` and sends the rendered HTML string to the client. +Optional parameters: + +- `locals`, an object whose properties define local variables for the view. +- `callback`, a callback function. If provided, the method returns both the possible error and rendered string, but does not perform an automated response. When an error occurs, the method invokes `next(err)` internally. + +The `view` argument is a string that is the file path of the view file to render. This can be an absolute path, or a path relative to the `views` setting. If the path does not contain a file extension, then the `view engine` setting determines the file extension. If the path does contain a file extension, then Express will load the module for the specified template engine (via `require()`) and render it using the loaded module's `__express` function. + +For more information, see [Using template engines with Express](/{{page.lang}}/guide/using-template-engines.html). + +
    +The `view` argument performs file system operations like reading a file from +disk and evaluating Node.js modules, and as so for security reasons should not +contain input from the end-user. +
    + +
    +The `locals` object is used by view engines to render a response. The object +keys may be particularly sensitive and should not contain user-controlled +input, as it may affect the operation of the view engine or provide a path to +cross-site scripting. Consult the documentation for the used view engine for +additional considerations. +
    + +
    +The local variable `cache` enables view caching. Set it to `true`, +to cache the view during development; view caching is enabled in production by default. +
    + +```js +// send the rendered view to the client +res.render('index'); + +// if a callback is specified, the rendered HTML string has to be sent explicitly +res.render('index', function (err, html) { + res.send(html); +}); + +// pass a local variable to the view +res.render('user', { name: 'Tobi' }, function (err, html) { + // ... +}); +``` diff --git a/astro/src/content/docs/de/4x/api/response/res-req.md b/astro/src/content/docs/de/4x/api/response/res-req.md new file mode 100644 index 0000000000..f20548a045 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/response/res-req.md @@ -0,0 +1,9 @@ +--- +title: res.req +description: This property holds a reference to the +--- + +

    res.req

    + +This property holds a reference to the request object +that relates to this response object. diff --git a/astro/src/content/docs/de/4x/api/response/res-send.md b/astro/src/content/docs/de/4x/api/response/res-send.md new file mode 100644 index 0000000000..c7fc23dff6 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/response/res-send.md @@ -0,0 +1,44 @@ +--- +title: res.send +description: Sends the HTTP response. +--- + +

    res.send([body])

    + +Sends the HTTP response. + +The `body` parameter can be a `Buffer` object, a `String`, an object, `Boolean`, or an `Array`. +For example: + +```js +res.send(Buffer.from('whoop')); +res.send({ some: 'json' }); +res.send('

    some html

    '); +res.status(404).send('Sorry, we cannot find that!'); +res.status(500).send({ error: 'something blew up' }); +``` + +This method performs many useful tasks for simple non-streaming responses: +For example, it automatically assigns the `Content-Length` HTTP response header field +(unless previously defined) and provides automatic HEAD and HTTP cache freshness support. + +When the parameter is a `Buffer` object, the method sets the `Content-Type` +response header field to "application/octet-stream", unless previously defined as shown below: + +```js +res.set('Content-Type', 'text/html'); +res.send(Buffer.from('

    some html

    ')); +``` + +When the parameter is a `String`, the method sets the `Content-Type` to "text/html": + +```js +res.send('

    some html

    '); +``` + +When the parameter is an `Array` or `Object`, Express responds with the JSON representation: + +```js +res.send({ user: 'tobi' }); +res.send([1, 2, 3]); +``` diff --git a/astro/src/content/docs/de/4x/api/response/res-sendFile.md b/astro/src/content/docs/de/4x/api/response/res-sendFile.md new file mode 100644 index 0000000000..65c5ca3627 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/response/res-sendFile.md @@ -0,0 +1,91 @@ +--- +title: res.sendFile +description: Transfers the file at the given path. Sets the Content-Type response HTTP header field based on the filename extension +--- + +

    res.sendFile(path [, options] [, fn])

    + +
    +`res.sendFile()` is supported by Express v4.8.0 onwards. +
    + +Transfers the file at the given `path`. Sets the `Content-Type` response HTTP header field +based on the filename's extension. Unless the `root` option is set in +the options object, `path` must be an absolute path to the file. + +
    +This API provides access to data on the running file system. Ensure that either (a) the way in +which the `path` argument was constructed into an absolute path is secure if it contains user +input or (b) set the `root` option to the absolute path of a directory to contain access within. + +When the `root` option is provided, the `path` argument is allowed to be a relative path, +including containing `..`. Express will validate that the relative path provided as `path` will +resolve within the given `root` option. + +
    + +The following table provides details on the `options` parameter. + +
    + +| Property | Description | Default | Availability | +| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------ | +| `maxAge` | Sets the max-age property of the `Cache-Control` header in milliseconds or a string in [ms format](https://www.npmjs.org/package/ms) | 0 | | +| `root` | Root directory for relative filenames. | | | +| `lastModified` | Sets the `Last-Modified` header to the last modified date of the file on the OS. Set `false` to disable it. | Enabled | 4.9.0+ | +| `headers` | Object containing HTTP headers to serve with the file. | | | +| `dotfiles` | Option for serving dotfiles. Possible values are "allow", "deny", "ignore". | "ignore" |   | +| `acceptRanges` | Enable or disable accepting ranged requests. | `true` | 4.14+ | +| `cacheControl` | Enable or disable setting `Cache-Control` response header. | `true` | 4.14+ | +| `immutable` | Enable or disable the `immutable` directive in the `Cache-Control` response header. If enabled, the `maxAge` option should also be specified to enable caching. The `immutable` directive will prevent supported clients from making conditional requests during the life of the `maxAge` option to check if the file has changed. | `false` | 4.16+ | + +
    + +The method invokes the callback function `fn(err)` when the transfer is complete +or when an error occurs. If the callback function is specified and an error occurs, +the callback function must explicitly handle the response process either by +ending the request-response cycle, or by passing control to the next route. + +Here is an example of using `res.sendFile` with all its arguments. + +```js +app.get('/file/:name', function (req, res, next) { + var options = { + root: path.join(__dirname, 'public'), + dotfiles: 'deny', + headers: { + 'x-timestamp': Date.now(), + 'x-sent': true, + }, + }; + + var fileName = req.params.name; + res.sendFile(fileName, options, function (err) { + if (err) { + next(err); + } else { + console.log('Sent:', fileName); + } + }); +}); +``` + +The following example illustrates using +`res.sendFile` to provide fine-grained support for serving files: + +```js +app.get('/user/:uid/photos/:file', function (req, res) { + var uid = req.params.uid; + var file = req.params.file; + + req.user.mayViewFilesFrom(uid, function (yes) { + if (yes) { + res.sendFile('/uploads/' + uid + '/' + file); + } else { + res.status(403).send("Sorry! You can't see that."); + } + }); +}); +``` + +For more information, or if you have issues or concerns, see [send](https://github.com/pillarjs/send). diff --git a/astro/src/content/docs/de/4x/api/response/res-sendStatus.md b/astro/src/content/docs/de/4x/api/response/res-sendStatus.md new file mode 100644 index 0000000000..eef217cd82 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/response/res-sendStatus.md @@ -0,0 +1,20 @@ +--- +title: res.sendStatus +description: Sets the response HTTP status code to statusCode and sends the registered status message as the text response body. If an unknown status code is specified, the response body will be just the code number. +--- + +

    res.sendStatus(statusCode)

    + +Sets the response HTTP status code to `statusCode` and sends the registered status message as the text response body. If an unknown status code is specified, the response body will just be the code number. + +```js +res.sendStatus(404); +``` + +
    +Some versions of Node.js will throw when `res.statusCode` is set to an +invalid HTTP status code (outside of the range `100` to `599`). Consult +the HTTP server documentation for the Node.js version being used. +
    + +[More about HTTP Status Codes](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes) diff --git a/astro/src/content/docs/de/4x/api/response/res-set.md b/astro/src/content/docs/de/4x/api/response/res-set.md new file mode 100644 index 0000000000..6d2b01e63e --- /dev/null +++ b/astro/src/content/docs/de/4x/api/response/res-set.md @@ -0,0 +1,21 @@ +--- +title: res.set +description: Sets the response HTTP header field to value. +--- + +

    res.set(field [, value])

    + +Sets the response's HTTP header `field` to `value`. +To set multiple fields at once, pass an object as the parameter. + +```js +res.set('Content-Type', 'text/plain'); + +res.set({ + 'Content-Type': 'text/plain', + 'Content-Length': '123', + ETag: '12345', +}); +``` + +Aliased as `res.header(field [, value])`. diff --git a/astro/src/content/docs/de/4x/api/response/res-status.md b/astro/src/content/docs/de/4x/api/response/res-status.md new file mode 100644 index 0000000000..4969cd4ff9 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/response/res-status.md @@ -0,0 +1,15 @@ +--- +title: res.status +description: Sets the HTTP status for the response. +--- + +

    res.status(code)

    + +Sets the HTTP status for the response. +It is a chainable alias of Node's [response.statusCode](http://nodejs.org/api/http.html#http_response_statuscode). + +```js +res.status(403).end(); +res.status(400).send('Bad Request'); +res.status(404).sendFile('/absolute/path/to/404.png'); +``` diff --git a/astro/src/content/docs/de/4x/api/response/res-type.md b/astro/src/content/docs/de/4x/api/response/res-type.md new file mode 100644 index 0000000000..615ffb3c6a --- /dev/null +++ b/astro/src/content/docs/de/4x/api/response/res-type.md @@ -0,0 +1,23 @@ +--- +title: res.type +description: Sets the Content-Type HTTP header to the MIME type as determined by the specified type. If type contains the slash character, then it sets the Content-Type to the exact value. +--- + +

    res.type(type)

    + +Sets the `Content-Type` HTTP header to the MIME type as determined by the specified `type`. If `type` contains the "/" character, then it sets the `Content-Type` to the exact value of `type`, otherwise it is assumed to be a file extension and the MIME type is looked up in a mapping using the `express.static.mime.lookup()` method. + +```js +res.type('.html'); +// => 'text/html' +res.type('html'); +// => 'text/html' +res.type('json'); +// => 'application/json' +res.type('application/json'); +// => 'application/json' +res.type('png'); +// => 'image/png' +``` + +Aliased as `res.contentType(type)`. diff --git a/astro/src/content/docs/de/4x/api/response/res-vary.md b/astro/src/content/docs/de/4x/api/response/res-vary.md new file mode 100644 index 0000000000..164bed9285 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/response/res-vary.md @@ -0,0 +1,12 @@ +--- +title: res.vary +description: Adds the field to the Vary response header, if it is not there already. +--- + +

    res.vary(field)

    + +Adds the field to the `Vary` response header, if it is not there already. + +```js +res.vary('User-Agent').render('docs'); +``` diff --git a/astro/src/content/docs/de/4x/api/router/overview.md b/astro/src/content/docs/de/4x/api/router/overview.md new file mode 100644 index 0000000000..9d1ec07241 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/router/overview.md @@ -0,0 +1,66 @@ +--- +title: Methods +description: section markdown="1"> +--- + +

    Router

    + +
    +A `router` object is an instance of middleware and routes. You can think of it +as a "mini-application," capable only of performing middleware and routing +functions. Every Express application has a built-in app router. + +A router behaves like middleware itself, so you can use it as an argument to +[app.use()](#app.use) or as the argument to another router's [use()](#router.use) method. + +The top-level `express` object has a [Router()](#express.router) method that creates a new `router` object. + +Once you've created a router object, you can add middleware and HTTP method routes (such as `get`, `put`, `post`, +and so on) to it just like an application. For example: + +```js +// invoked for any requests passed to this router +router.use(function (req, res, next) { + // .. some logic here .. like any other middleware + next(); +}); + +// will handle any request that ends in /events +// depends on where the router is "use()'d" +router.get('/events', function (req, res, next) { + // .. +}); +``` + +You can then use a router for a particular root URL in this way separating your routes into files or even mini-apps. + +```js +// only requests to /calendar/* will be sent to our "router" +app.use('/calendar', router); +``` + +Keep in mind that any middleware applied to a router will run for all requests on that router's path, even those that aren't part of the router. + +
    + +

    Methods

    + +
    + {% include api/en/4x/router-all.md %} +
    + +
    + {% include api/en/4x/router-METHOD.md %} +
    + +
    + {% include api/en/4x/router-param.md %} +
    + +
    + {% include api/en/4x/router-route.md %} +
    + +
    + {% include api/en/4x/router-use.md %} +
    diff --git a/astro/src/content/docs/de/4x/api/router/router-METHOD.md b/astro/src/content/docs/de/4x/api/router/router-METHOD.md new file mode 100644 index 0000000000..2c6ea555f4 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/router/router-METHOD.md @@ -0,0 +1,47 @@ +--- +title: router.METHOD +description: The router.METHOD methods provide the routing functionality in Express, +--- + +

    router.METHOD(path, [callback, ...] callback)

    + +The `router.METHOD()` methods provide the routing functionality in Express, +where METHOD is one of the HTTP methods, such as GET, PUT, POST, and so on, +in lowercase. Thus, the actual methods are `router.get()`, `router.post()`, +`router.put()`, and so on. + +
    + The `router.get()` function is automatically called for the HTTP `HEAD` method in + addition to the `GET` method if `router.head()` was not called for the + path before `router.get()`. +
    + +You can provide multiple callbacks, and all are treated equally, and behave just +like middleware, except that these callbacks may invoke `next('route')` +to bypass the remaining route callback(s). You can use this mechanism to perform +pre-conditions on a route then pass control to subsequent routes when there is no +reason to proceed with the route matched. + +The following snippet illustrates the most simple route definition possible. +Express translates the path strings to regular expressions, used internally +to match incoming requests. Query strings are _not_ considered when performing +these matches, for example "GET /" would match the following route, as would +"GET /?name=tobi". + +```js +router.get('/', function (req, res) { + res.send('hello world'); +}); +``` + +You can also use regular expressions—useful if you have very specific +constraints, for example the following would match "GET /commits/71dbb9c" as well +as "GET /commits/71dbb9c..4c084f9". + +```js +router.get(/^\/commits\/(\w+)(?:\.\.(\w+))?$/, function (req, res) { + var from = req.params[0]; + var to = req.params[1] || 'HEAD'; + res.send('commit range ' + from + '..' + to); +}); +``` diff --git a/astro/src/content/docs/de/4x/api/router/router-Router.md b/astro/src/content/docs/de/4x/api/router/router-Router.md new file mode 100644 index 0000000000..de2867f15c --- /dev/null +++ b/astro/src/content/docs/de/4x/api/router/router-Router.md @@ -0,0 +1,5 @@ +--- +title: Router +--- + +

    Router([options])

    diff --git a/astro/src/content/docs/de/4x/api/router/router-all.md b/astro/src/content/docs/de/4x/api/router/router-all.md new file mode 100644 index 0000000000..cda8e9c21b --- /dev/null +++ b/astro/src/content/docs/de/4x/api/router/router-all.md @@ -0,0 +1,36 @@ +--- +title: router.all +description: This method is just like the router.METHOD methods, except that it matches all HTTP methods (verbs). +--- + +

    router.all(path, [callback, ...] callback)

    + +This method is just like the `router.METHOD()` methods, except that it matches all HTTP methods (verbs). + +This method is extremely useful for +mapping "global" logic for specific path prefixes or arbitrary matches. +For example, if you placed the following route at the top of all other +route definitions, it would require that all routes from that point on +would require authentication, and automatically load a user. Keep in mind +that these callbacks do not have to act as end points; `loadUser` +can perform a task, then call `next()` to continue matching subsequent +routes. + +```js +router.all('*', requireAuthentication, loadUser); +``` + +Or the equivalent: + +```js +router.all('*', requireAuthentication); +router.all('*', loadUser); +``` + +Another example of this is white-listed "global" functionality. Here +the example is much like before, but it only restricts paths prefixed with +"/api": + +```js +router.all('/api/*', requireAuthentication); +``` diff --git a/astro/src/content/docs/de/4x/api/router/router-param.md b/astro/src/content/docs/de/4x/api/router/router-param.md new file mode 100644 index 0000000000..cb82308fb4 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/router/router-param.md @@ -0,0 +1,128 @@ +--- +title: router.param +description: Adds callback triggers to route parameters, where name is the name of the parameter and callback is the callback function. Although name is technically optional, it is required. +--- + +

    router.param(name, callback)

    + +Adds callback triggers to route parameters, where `name` is the name of the parameter and `callback` is the callback function. Although `name` is technically optional, using this method without it is deprecated starting with Express v4.11.0 (see below). + +The parameters of the callback function are: + +- `req`, the request object. +- `res`, the response object. +- `next`, indicating the next middleware function. +- The value of the `name` parameter. +- The name of the parameter. + +
    +Unlike `app.param()`, `router.param()` does not accept an array of route parameters. +
    + +For example, when `:user` is present in a route path, you may map user loading logic to automatically provide `req.user` to the route, or perform validations on the parameter input. + +```js +router.param('user', function (req, res, next, id) { + // try to get the user details from the User model and attach it to the request object + User.find(id, function (err, user) { + if (err) { + next(err); + } else if (user) { + req.user = user; + next(); + } else { + next(new Error('failed to load user')); + } + }); +}); +``` + +Param callback functions are local to the router on which they are defined. They are not inherited by mounted apps or routers, nor are they triggered for route parameters inherited from parent routers. Hence, param callbacks defined on `router` will be triggered only by route parameters defined on `router` routes. + +A param callback will be called only once in a request-response cycle, even if the parameter is matched in multiple routes, as shown in the following examples. + +```js +router.param('id', function (req, res, next, id) { + console.log('CALLED ONLY ONCE'); + next(); +}); + +router.get('/user/:id', function (req, res, next) { + console.log('although this matches'); + next(); +}); + +router.get('/user/:id', function (req, res) { + console.log('and this matches too'); + res.end(); +}); +``` + +On `GET /user/42`, the following is printed: + +``` +CALLED ONLY ONCE +although this matches +and this matches too +``` + +
    +The following section describes `router.param(callback)`, which is deprecated as of v4.11.0. +
    + +The behavior of the `router.param(name, callback)` method can be altered entirely by passing only a function to `router.param()`. This function is a custom implementation of how `router.param(name, callback)` should behave - it accepts two parameters and must return a middleware. + +The first parameter of this function is the name of the URL parameter that should be captured, the second parameter can be any JavaScript object which might be used for returning the middleware implementation. + +The middleware returned by the function decides the behavior of what happens when a URL parameter is captured. + +In this example, the `router.param(name, callback)` signature is modified to `router.param(name, accessId)`. Instead of accepting a name and a callback, `router.param()` will now accept a name and a number. + +```js +var express = require('express'); +var app = express(); +var router = express.Router(); + +// customizing the behavior of router.param() +router.param(function (param, option) { + return function (req, res, next, val) { + if (val === option) { + next(); + } else { + res.sendStatus(403); + } + }; +}); + +// using the customized router.param() +router.param('id', '1337'); + +// route to trigger the capture +router.get('/user/:id', function (req, res) { + res.send('OK'); +}); + +app.use(router); + +app.listen(3000, function () { + console.log('Ready'); +}); +``` + +In this example, the `router.param(name, callback)` signature remains the same, but instead of a middleware callback, a custom data type checking function has been defined to validate the data type of the user id. + +```js +router.param(function (param, validator) { + return function (req, res, next, val) { + if (validator(val)) { + next(); + } else { + res.sendStatus(403); + } + }; +}); + +router.param('id', function (candidate) { + return !isNaN(parseFloat(candidate)) && isFinite(candidate); +}); +``` diff --git a/astro/src/content/docs/de/4x/api/router/router-route.md b/astro/src/content/docs/de/4x/api/router/router-route.md new file mode 100644 index 0000000000..89dd15bbcb --- /dev/null +++ b/astro/src/content/docs/de/4x/api/router/router-route.md @@ -0,0 +1,54 @@ +--- +title: router.route +description: Returns an instance of a single route which you can then use to handle HTTP verbs +--- + +

    router.route(path)

    + +Returns an instance of a single route which you can then use to handle HTTP verbs +with optional middleware. Use `router.route()` to avoid duplicate route naming and +thus typing errors. + +Building on the `router.param()` example above, the following code shows how to use +`router.route()` to specify various HTTP method handlers. + +```js +var router = express.Router(); + +router.param('user_id', function (req, res, next, id) { + // sample user, would actually fetch from DB, etc... + req.user = { + id: id, + name: 'TJ', + }; + next(); +}); + +router + .route('/users/:user_id') + .all(function (req, res, next) { + // runs for all HTTP verbs first + // think of it as route specific middleware! + next(); + }) + .get(function (req, res, next) { + res.json(req.user); + }) + .put(function (req, res, next) { + // just an example of maybe updating the user + req.user.name = req.params.name; + // save user ... etc + res.json(req.user); + }) + .post(function (req, res, next) { + next(new Error('not implemented')); + }) + .delete(function (req, res, next) { + next(new Error('not implemented')); + }); +``` + +This approach re-uses the single `/users/:user_id` path and adds handlers for +various HTTP methods. + +{% include admonitions/note.html content="When you use `router.route()`, middleware ordering is based on when the _route_ is created, not when method handlers are added to the route. For this purpose, you can consider method handlers to belong to the route to which they were added." %} diff --git a/astro/src/content/docs/de/4x/api/router/router-use.md b/astro/src/content/docs/de/4x/api/router/router-use.md new file mode 100644 index 0000000000..b6f3929a32 --- /dev/null +++ b/astro/src/content/docs/de/4x/api/router/router-use.md @@ -0,0 +1,112 @@ +--- +title: router.use +description: Uses the specified middleware function or functions, with optional mount path that defaults to slash. +--- + +

    router.use([path], [function, ...] function)

    + +Uses the specified middleware function or functions, with optional mount path `path`, that defaults to "/". + +This method is similar to [app.use()](#app.use). A simple example and use case is described below. +See [app.use()](#app.use) for more information. + +Middleware is like a plumbing pipe: requests start at the first middleware function defined +and work their way "down" the middleware stack processing for each path they match. + +```js +var express = require('express'); +var app = express(); +var router = express.Router(); + +// simple logger for this router's requests +// all requests to this router will first hit this middleware +router.use(function (req, res, next) { + console.log('%s %s %s', req.method, req.url, req.path); + next(); +}); + +// this will only be invoked if the path starts with /bar from the mount point +router.use('/bar', function (req, res, next) { + // ... maybe some additional /bar logging ... + next(); +}); + +// always invoked +router.use(function (req, res, next) { + res.send('Hello World'); +}); + +app.use('/foo', router); + +app.listen(3000); +``` + +The "mount" path is stripped and is _not_ visible to the middleware function. +The main effect of this feature is that a mounted middleware function may operate without +code changes regardless of its "prefix" pathname. + +The order in which you define middleware with `router.use()` is very important. +They are invoked sequentially, thus the order defines middleware precedence. For example, +usually a logger is the very first middleware you would use, so that every request gets logged. + +```js +var logger = require('morgan'); +var path = require('path'); + +router.use(logger()); +router.use(express.static(path.join(__dirname, 'public'))); +router.use(function (req, res) { + res.send('Hello'); +}); +``` + +Now suppose you wanted to ignore logging requests for static files, but to continue +logging routes and middleware defined after `logger()`. You would simply move the call to `express.static()` to the top, +before adding the logger middleware: + +```js +router.use(express.static(path.join(__dirname, 'public'))); +router.use(logger()); +router.use(function (req, res) { + res.send('Hello'); +}); +``` + +Another example is serving files from multiple directories, +giving precedence to "./public" over the others: + +```js +router.use(express.static(path.join(__dirname, 'public'))); +router.use(express.static(path.join(__dirname, 'files'))); +router.use(express.static(path.join(__dirname, 'uploads'))); +``` + +The `router.use()` method also supports named parameters so that your mount points +for other routers can benefit from preloading using named parameters. + +**NOTE**: Although these middleware functions are added via a particular router, _when_ +they run is defined by the path they are attached to (not the router). Therefore, +middleware added via one router may run for other routers if its routes +match. For example, this code shows two different routers mounted on the same path: + +```js +var authRouter = express.Router(); +var openRouter = express.Router(); + +authRouter.use(require('./authenticate').basic(usersdb)); + +authRouter.get('/:user_id/edit', function (req, res, next) { + // ... Edit user UI ... +}); +openRouter.get('/', function (req, res, next) { + // ... List users ... +}); +openRouter.get('/:user_id', function (req, res, next) { + // ... View user ... +}); + +app.use('/users', authRouter); +app.use('/users', openRouter); +``` + +Even though the authentication middleware was added via the `authRouter` it will run on the routes defined by the `openRouter` as well since both routers were mounted on `/users`. To avoid this behavior, use different paths for each router. diff --git a/astro/src/content/docs/de/4x/api/router/routing-args.html b/astro/src/content/docs/de/4x/api/router/routing-args.html new file mode 100644 index 0000000000..cbf0dd027a --- /dev/null +++ b/astro/src/content/docs/de/4x/api/router/routing-args.html @@ -0,0 +1,58 @@ +

    Arguments

    + +
    + + + + + + + + + + + + + + + + + + + + +
    ArgumentDescriptionDefault
    path + The path for which the middleware function is invoked; can be any of: +
      +
    • A string representing a path.
    • +
    • A path pattern.
    • +
    • A regular expression pattern to match paths.
    • +
    • An array of combinations of any of the above.
    • +
    + For examples, see Path examples. +
    '/' (root path)
    callback + Callback functions; can be: +
      +
    • A middleware function.
    • +
    • A series of middleware functions (separated by commas).
    • +
    • An array of middleware functions.
    • +
    • A combination of all of the above.
    • +
    +

    + You can provide multiple callback functions that behave just like middleware, except + that these callbacks can invoke next('route') to bypass the remaining route + callback(s). You can use this mechanism to impose pre-conditions on a route, then pass + control to subsequent routes if there is no reason to proceed with the current route. +

    +

    + Since router and app implement the + middleware interface, you can use them as you would any other middleware function. +

    +

    + For examples, see + Middleware callback function examples. +

    +
    None
    +
    diff --git a/astro/src/content/docs/de/4x/guide/behind-proxies.md b/astro/src/content/docs/de/4x/guide/behind-proxies.md new file mode 100644 index 0000000000..b56026a0d2 --- /dev/null +++ b/astro/src/content/docs/de/4x/guide/behind-proxies.md @@ -0,0 +1,90 @@ +--- +title: Express hinter Proxys +description: Learn how to configure Express.js applications to work correctly behind reverse proxies, including using the trust proxy setting to handle client IP addresses. +--- + +# Express hinter Proxys + +When running an Express app behind a reverse proxy, some of the Express APIs may return different values than expected. In order to adjust for this, the `trust proxy` application setting may be used to expose information provided by the reverse proxy in the Express APIs. The most common issue is express APIs that expose the client's IP address may instead show an internal IP address of the reverse proxy. + +
    +When configuring the `trust proxy` setting, it is important to understand the exact setup of the reverse proxy. Since this setting will trust values provided in the request, it is important that the combination of the setting in Express matches how the reverse proxy operates. +
    + +Bei der Ausführung einer Express-Anwendung hinter einem Proxy legen Sie die Anwendungsvariable `trust proxy` (mithilfe von [app.set()](/{{ page.lang }}/4x/api.html#app.set)) auf einen der in der folgenden Tabelle enthaltenen Werte fest: + + + + + + + + + + + + + + + + + + + + + +
    TypWert
    BooleschWenn `true` angegeben wird, wird die IP-Adresse des Clients als der äußerst rechte Eintrag im Header `X-Forwarded-*` interpretiert. + +Wenn `false` angegeben wird, wird die Anwendung als direkte Verbindung zum Internet gesehen. Die IP-Adresse des Clients wird dann von `req.connection.remoteAddress` abgeleitet. Dies ist die Standardeinstellung. + +
    +When setting to `true`, it is important to ensure that the last reverse proxy trusted is removing/overwriting all of the following HTTP headers: `X-Forwarded-For`, `X-Forwarded-Host`, and `X-Forwarded-Proto`, otherwise it may be possible for the client to provide any value. +
    +
    IP addresses +An IP address, subnet, or an array of IP addresses and subnets to trust as being a reverse proxy. The following list shows the pre-configured subnet names: + +- loopback - `127.0.0.1/8`, `::1/128` +- linklocal - `169.254.0.0/16`, `fe80::/10` +- uniquelocal - `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `fc00::/7` + +Sie können IP-Adressen wie folgt festlegen: + +```js +app.set('trust proxy', 'loopback'); // specify a single subnet +app.set('trust proxy', 'loopback, 123.123.123.123'); // specify a subnet and an address +app.set('trust proxy', 'loopback, linklocal, uniquelocal'); // specify multiple subnets as CSV +app.set('trust proxy', ['loopback', 'linklocal', 'uniquelocal']); // specify multiple subnets as an array +``` + +Sobald die Werte angegeben wurden, werden die betreffenden IP-Adressen und Teilnetze aus dem Adressfeststellungsprozess ausgeschlossen. Die nicht vertrauenswürdige IP-Adresse, die am nächsten zum Anwendungsserver liegt, wird als IP-Adresse des Clients festgelegt. This works by checking if `req.socket.remoteAddress` is trusted. If so, then each address in `X-Forwarded-For` is checked from right to left until the first non-trusted address. + +
    Zahl +Use the address that is at most `n` number of hops away from the Express application. `req.socket.remoteAddress` is the first hop, and the rest are looked for in the `X-Forwarded-For` header from right to left. A value of `0` means that the first untrusted address would be `req.socket.remoteAddress`, i.e. there is no reverse proxy. + +
    +When using this setting, it is important to ensure there are not multiple, different-length paths to the Express application such that the client can be less than the configured number of hops away, otherwise it may be possible for the client to provide any value. +
    +
    Function +Custom trust implementation. + +```js +app.set('trust proxy', (ip) => { + if (ip === '127.0.0.1' || ip === '123.123.123.123') + return true; // trusted IPs + else return false; +}); +``` + +
    + +Enabling `trust proxy` will have the following impact: + +
      +
    • Der Wert für [req.hostname](/{{ page.lang }}/api.html#req.hostname) wird vom Wert abgeleitet, der im Header `X-Forwarded-Host` festgelegt wurde. Dieser Wert kann vom Client oder Proxy festgelegt werden.
    • +
    • `X-Forwarded-Proto` kann vom Reverse Proxy festgelegt werden, um der Anwendung mitzuteilen, ob es sich um `https` oder `http` oder sogar um einen ungültigen Namen handelt. Dieser Wert wird durch [req.protocol](/{{ page.lang }}/api.html#req.protocol) abgebildet. +
    • +
    • Als Werte für [req.ip](/{{ page.lang }}/api.html#req.ip) und [req.ips](/{{ page.lang }}/api.html#req.ips) wird die Liste der Adressen aus `X-Forwarded-For` herangezogen. +
    • +
    + +Die Einstellung für `trust proxy` wird mithilfe des [proxy-addr](https://www.npmjs.com/package/proxy-addr)-Pakets implementiert. Weitere Informationen finden Sie in der zugehörigen Dokumentation. diff --git a/astro/src/content/docs/de/4x/guide/database-integration.md b/astro/src/content/docs/de/4x/guide/database-integration.md new file mode 100644 index 0000000000..fcd6291fc1 --- /dev/null +++ b/astro/src/content/docs/de/4x/guide/database-integration.md @@ -0,0 +1,509 @@ +--- +title: Datenbankintegration in Express +description: Discover how to integrate various databases with Express.js applications, including setup examples for MongoDB, MySQL, PostgreSQL, and more. +--- + +# Datenbankintegration + +Die Herstellung einer Verbindung zwischen Datenbanken und Express-Anwendungen erfolgt einfach durch Laden eines geeigneten Node.js-Treibers für die Datenbank in Ihre Anwendung. In diesem Dokument wird in Kurzform beschrieben, wie einige der gängigsten Node.js-Module für Datenbanksysteme Ihrer Express-Anwendung hinzugefügt und verwendet werden: + +- [Cassandra](#cassandra) +- [Couchbase](#couchbase) +- [CouchDB](#couchdb) +- [LevelDB](#leveldb) +- [MySQL](#mysql) +- [MongoDB](#mongo) +- [Neo4j](#neo4j) +- [Oracle](#oracle) +- [PostgreSQL](#postgres) +- [Redis](#redis) +- +- [SQLite](#sqlite) +- [ElasticSearch](#elasticsearch) + +
    +Diese Datenbanktreiber sind neben zahlreichen anderen Treibern verfügbar. Weitere Optionen finden Sie auf der [npm](https://www.npmjs.com/)-Site. +
    + +## Cassandra + +**Modul**: [cassandra-driver](https://github.com/datastax/nodejs-driver) +**Installation** + +### Installation + +```bash +$ npm install cassandra-driver +``` + +### Beispiel + +```js +const cassandra = require('cassandra-driver'); +const client = new cassandra.Client({ contactPoints: ['localhost'] }); + +client.execute('select key from system.local', (err, result) => { + if (err) throw err; + console.log(result.rows[0]); +}); +``` + +## Couchbase + +**Module**: [couchnode](https://github.com/couchbase/couchnode) + +### Installation + +```bash +$ npm install couchbase +``` + +### Beispiel + +```js +const couchbase = require('couchbase'); +const bucket = new couchbase.Cluster('http://localhost:8091').openBucket('bucketName'); + +// add a document to a bucket +bucket.insert('document-key', { name: 'Matt', shoeSize: 13 }, (err, result) => { + if (err) { + console.log(err); + } else { + console.log(result); + } +}); + +// get all documents with shoe size 13 +const n1ql = 'SELECT d.* FROM `bucketName` d WHERE shoeSize = $1'; +const query = N1qlQuery.fromString(n1ql); +bucket.query(query, [13], (err, result) => { + if (err) { + console.log(err); + } else { + console.log(result); + } +}); +``` + +## CouchDB + +**Modul**: [nano](https://github.com/dscape/nano) +**Installation** + +### Installation + +```bash +$ npm install nano +``` + +### Beispiel + +```js +const nano = require('nano')('http://localhost:5984'); +nano.db.create('books'); +const books = nano.db.use('books'); + +// Insert a book document in the books database +books.insert({ name: 'The Art of war' }, null, (err, body) => { + if (err) { + console.log(err); + } else { + console.log(body); + } +}); + +// Get a list of all books +books.list((err, body) => { + if (err) { + console.log(err); + } else { + console.log(body.rows); + } +}); +``` + +## LevelDB + +**Modul**: [levelup](https://github.com/rvagg/node-levelup) +**Installation** + +### Installation + +```bash +$ npm install level levelup leveldown +``` + +### Beispiel + +```js +const levelup = require('levelup'); +const db = levelup('./mydb'); + +db.put('name', 'LevelUP', (err) => { + if (err) return console.log('Ooops!', err); + + db.get('name', (err, value) => { + if (err) return console.log('Ooops!', err); + + console.log(`name=${value}`); + }); +}); +``` + +## MySQL + +**Modul**: [mysql](https://github.com/felixge/node-mysql/) +**Installation** + +### Installation + +```bash +$ npm install mysql +``` + +### Beispiel + +```js +const mysql = require('mysql'); +const connection = mysql.createConnection({ + host: 'localhost', + user: 'dbuser', + password: 's3kreee7', + database: 'my_db', +}); + +connection.connect(); + +connection.query('SELECT 1 + 1 AS solution', (err, rows, fields) => { + if (err) throw err; + + console.log('The solution is: ', rows[0].solution); +}); + +connection.end(); +``` + +## MongoDB + +**Modul**: [mongodb](https://github.com/mongodb/node-mongodb-native) +**Installation** + +### Installation + +```bash +$ npm install mongodb +``` + +### Example (v2.\*) + +```js +const MongoClient = require('mongodb').MongoClient; + +MongoClient.connect('mongodb://localhost:27017/animals', (err, db) => { + if (err) throw err; + + db.collection('mammals') + .find() + .toArray((err, result) => { + if (err) throw err; + + console.log(result); + }); +}); +``` + +### Example (v3.\*) + +```js +const MongoClient = require('mongodb').MongoClient; + +MongoClient.connect('mongodb://localhost:27017/animals', (err, client) => { + if (err) throw err; + + const db = client.db('animals'); + + db.collection('mammals') + .find() + .toArray((err, result) => { + if (err) throw err; + + console.log(result); + }); +}); +``` + +Wenn Sie nach einem Objektmodelltreiber für MongoDB suchen, schauen Sie unter [Mongoose](https://github.com/LearnBoost/mongoose) nach. + +## Neo4j + +**Module**: [neo4j-driver](https://github.com/neo4j/neo4j-javascript-driver) + +### Installation + +```bash +$ npm install neo4j-driver +``` + +### Beispiel + +```js +const neo4j = require('neo4j-driver'); +const driver = neo4j.driver('neo4j://localhost:7687', neo4j.auth.basic('neo4j', 'letmein')); + +const session = driver.session(); + +session.readTransaction((tx) => { + return tx + .run('MATCH (n) RETURN count(n) AS count') + .then((res) => { + console.log(res.records[0].get('count')); + }) + .catch((error) => { + console.log(error); + }); +}); +``` + +## Oracle + +**Modul**: [oracledb](https://github.com/oracle/node-oracledb) + +### Installation + +Anmerkung: [Siehe Installations-Voraussetzungen](https://github.com/oracle/node-oracledb#-installation). + +```bash +$ npm install oracledb +``` + +### Beispiel + +```js +const oracledb = require('oracledb'); +const config = { + user: '', + password: '', + connectString: 'localhost:1521/orcl', +}; + +async function getEmployee(empId) { + let conn; + + try { + conn = await oracledb.getConnection(config); + + const result = await conn.execute('select * from employees where employee_id = :id', [empId]); + + console.log(result.rows[0]); + } catch (err) { + console.log('Ouch!', err); + } finally { + if (conn) { + // conn assignment worked, need to close + await conn.close(); + } + } +} + +getEmployee(101); +``` + +## PostgreSQL + +**Modul**: [pg-promise](https://github.com/vitaly-t/pg-promise) +**Installation** + +### Installation + +```bash +$ npm install pg-promise +``` + +### Beispiel + +```js +const pgp = require('pg-promise')(/* options */); +const db = pgp('postgres://username:password@host:port/database'); + +db.one('SELECT $1 AS value', 123) + .then((data) => { + console.log('DATA:', data.value); + }) + .catch((error) => { + console.log('ERROR:', error); + }); +``` + +## Redis + +**Modul**: [redis](https://github.com/mranney/node_redis) +**Installation** + +### Installation + +```bash +$ npm install redis +``` + +### Beispiel + +```js +const redis = require('redis'); +const client = redis.createClient(); + +client.on('error', (err) => { + console.log(`Error ${err}`); +}); + +client.set('string key', 'string val', redis.print); +client.hset('hash key', 'hashtest 1', 'some value', redis.print); +client.hset(['hash key', 'hashtest 2', 'some other value'], redis.print); + +client.hkeys('hash key', (err, replies) => { + console.log(`${replies.length} replies:`); + + replies.forEach((reply, i) => { + console.log(` ${i}: ${reply}`); + }); + + client.quit(); +}); +``` + +## SQL Server + +**Module**: [tedious](https://github.com/tediousjs/tedious) + +### Installation + +```bash +$ npm install tedious +``` + +### Beispiel + +```js +const Connection = require('tedious').Connection; +const Request = require('tedious').Request; + +const config = { + server: 'localhost', + authentication: { + type: 'default', + options: { + userName: 'your_username', // update me + password: 'your_password', // update me + }, + }, +}; + +const connection = new Connection(config); + +connection.on('connect', (err) => { + if (err) { + console.log(err); + } else { + executeStatement(); + } +}); + +function executeStatement() { + request = new Request("select 123, 'hello world'", (err, rowCount) => { + if (err) { + console.log(err); + } else { + console.log(`${rowCount} rows`); + } + connection.close(); + }); + + request.on('row', (columns) => { + columns.forEach((column) => { + if (column.value === null) { + console.log('NULL'); + } else { + console.log(column.value); + } + }); + }); + + connection.execSql(request); +} +``` + +## SQLite + +**Modul**: [sqlite3](https://github.com/mapbox/node-sqlite3) +**Installation** + +### Installation + +```bash +$ npm install sqlite3 +``` + +### Beispiel + +```js +const sqlite3 = require('sqlite3').verbose(); +const db = new sqlite3.Database(':memory:'); + +db.serialize(() => { + db.run('CREATE TABLE lorem (info TEXT)'); + const stmt = db.prepare('INSERT INTO lorem VALUES (?)'); + + for (let i = 0; i < 10; i++) { + stmt.run(`Ipsum ${i}`); + } + + stmt.finalize(); + + db.each('SELECT rowid AS id, info FROM lorem', (err, row) => { + console.log(`${row.id}: ${row.info}`); + }); +}); + +db.close(); +``` + +## ElasticSearch + +**Modul**: [elasticsearch](https://github.com/elastic/elasticsearch-js) +**Installation** + +### Installation + +```bash +$ npm install elasticsearch +``` + +### Beispiel + +```js +const elasticsearch = require('elasticsearch'); +const client = elasticsearch.Client({ + host: 'localhost:9200', +}); + +client + .search({ + index: 'books', + type: 'book', + body: { + query: { + multi_match: { + query: 'express js', + fields: ['title', 'description'], + }, + }, + }, + }) + .then( + (response) => { + const hits = response.hits.hits; + }, + (error) => { + console.trace(error.message); + } + ); +``` diff --git a/astro/src/content/docs/de/4x/guide/debugging.md b/astro/src/content/docs/de/4x/guide/debugging.md new file mode 100644 index 0000000000..573b701338 --- /dev/null +++ b/astro/src/content/docs/de/4x/guide/debugging.md @@ -0,0 +1,126 @@ +--- +title: Debugging bei Express +description: Learn how to enable and use debugging logs in Express.js applications by setting the DEBUG environment variable for enhanced troubleshooting. +--- + +# Debugging bei Express + +Wenn Sie alle in Express verwendeten internen Protokolle anzeigen wollen, legen Sie beim Starten Ihrer Anwendung die Umgebungsvariable `DEBUG` auf `express:*` fest. + +```bash +$ DEBUG=express:* node index.js +``` + +Verwenden Sie unter Windows den entsprechenden Befehl. + +```bash +> $env:DEBUG = "express:*"; node index.js +``` + +Die Ausführung dieses Befehls für die durch [express generator](/{{ page.lang }}/starter/generator.html) generierte Standardanwendung resultiert in folgender Ausgabe: + +```bash +$ DEBUG=express:* node ./bin/www + express:router:route new / +0ms + express:router:layer new / +1ms + express:router:route get / +1ms + express:router:layer new / +0ms + express:router:route new / +1ms + express:router:layer new / +0ms + express:router:route get / +0ms + express:router:layer new / +0ms + express:application compile etag weak +1ms + express:application compile query parser extended +0ms + express:application compile trust proxy false +0ms + express:application booting in development mode +1ms + express:router use / query +0ms + express:router:layer new / +0ms + express:router use / expressInit +0ms + express:router:layer new / +0ms + express:router use / favicon +1ms + express:router:layer new / +0ms + express:router use / logger +0ms + express:router:layer new / +0ms + express:router use / jsonParser +0ms + express:router:layer new / +1ms + express:router use / urlencodedParser +0ms + express:router:layer new / +0ms + express:router use / cookieParser +0ms + express:router:layer new / +0ms + express:router use / stylus +90ms + express:router:layer new / +0ms + express:router use / serveStatic +0ms + express:router:layer new / +0ms + express:router use / router +0ms + express:router:layer new / +1ms + express:router use /users router +0ms + express:router:layer new /users +0ms + express:router use / &lt;anonymous&gt; +0ms + express:router:layer new / +0ms + express:router use / &lt;anonymous&gt; +0ms + express:router:layer new / +0ms + express:router use / &lt;anonymous&gt; +0ms + express:router:layer new / +0ms +``` + +Bei einer Anforderung an die Anwendung sind die Protokolle im Express-Code angegeben: + +```bash + express:router dispatching GET / +4h + express:router query : / +2ms + express:router expressInit : / +0ms + express:router favicon : / +0ms + express:router logger : / +1ms + express:router jsonParser : / +0ms + express:router urlencodedParser : / +1ms + express:router cookieParser : / +0ms + express:router stylus : / +0ms + express:router serveStatic : / +2ms + express:router router : / +2ms + express:router dispatching GET / +1ms + express:view lookup "index.pug" +338ms + express:view stat "/projects/example/views/index.pug" +0ms + express:view render "/projects/example/views/index.pug" +1ms +``` + +Wenn Sie nur die Protokolle von der Routerimplementierung sehen wollen, legen Sie den Wert für `DEBUG` auf `express:router` fest. Gleichermaßen gilt: Wenn Sie nur die Protokolle von der Anwendungsimplementierung sehen wollen, legen Sie den Wert für `DEBUG` auf `express:application` fest, usw. + +## Von `express` generierte Anwendungen + +An application generated by the `express` command uses the `debug` module and its debug namespace is scoped to the name of the application. + +Beispiel: Wenn Sie die Anwendung mit `$ express sample-app` generiert haben, können Sie die Debuganweisungen mit dem folgenden Befehl aktivieren: + +```bash +$ DEBUG=sample-app:* node ./bin/www +``` + +Sie können mehrere Debug-Namespaces in einer durch Kommas getrennten Namensliste angeben: + +```bash +$ DEBUG=http,mail,express:* node index.js +``` + +## Advanced options + +When running through Node.js, you can set a few environment variables that will change the behavior of the debug logging: + +| Name | Purpose | +| ------------------- | ------------------------------------------------- | +| `DEBUG` | Enables/disables specific debugging namespaces. | +| `DEBUG_COLORS` | Whether or not to use colors in the debug output. | +| `DEBUG_DEPTH` | Object inspection depth. | +| `DEBUG_FD` | File descriptor to write debug output to. | +| `DEBUG_SHOW_HIDDEN` | Shows hidden properties on inspected objects. | + +{% capture debug-text %} + +The environment variables beginning with `DEBUG_` end up being +converted into an Options object that gets used with `%o`/`%O` formatters. +See the Node.js documentation for +[`util.inspect()`](https://nodejs.org/api/util.html#util_util_inspect_object_options) +for the complete list. + +{% endcapture %} + +{% include admonitions/note.html content=debug-text %} diff --git a/astro/src/content/docs/de/4x/guide/error-handling.md b/astro/src/content/docs/de/4x/guide/error-handling.md new file mode 100644 index 0000000000..9b7c30e8d3 --- /dev/null +++ b/astro/src/content/docs/de/4x/guide/error-handling.md @@ -0,0 +1,289 @@ +--- +title: Fehlerbehandlung in Express +description: Understand how Express.js handles errors in synchronous and asynchronous code, and learn to implement custom error handling middleware for your applications. +--- + +# Fehlerbehandlung + +_Error Handling_ refers to how Express catches and processes errors that +occur both synchronously and asynchronously. Express comes with a default error +handler so you don't need to write your own to get started. + +## Catching Errors + +It's important to ensure that Express catches all errors that occur while +running route handlers and middleware. + +Errors that occur in synchronous code inside route handlers and middleware +require no extra work. If synchronous code throws an error, then Express will +catch and process it. Beispiel: + +```js +app.get('/', (req, res) => { + throw new Error('BROKEN'); // Express will catch this on its own. +}); +``` + +Middlewarefunktionen für die Fehlerbehandlung werden in derselben Weise definiert wie andere Middlewarefunktionen, nur, dass Fehlerbehandlungsfunktionen vier anstatt drei Argumente aufweisen: +`(err, req, res, next)`. Beispiel: + +```js +app.get('/', (req, res, next) => { + fs.readFile('/file-does-not-exist', (err, data) => { + if (err) { + next(err); // Pass errors to Express. + } else { + res.send(data); + } + }); +}); +``` + +Middleware für die Fehlerbehandlung wird ganz zuletzt nach allen anderen `app.use()`- und Weiterleitungsaufrufen definiert. +Beispiel: + +```js +app.get('/user/:id', async (req, res, next) => { + const user = await getUserById(req.params.id); + res.send(user); +}); +``` + +If `getUserById` throws an error or rejects, `next` will be called with either +the thrown error or the rejected value. If no rejected value is provided, `next` +will be called with a default Error object provided by the Express router. + +Wenn Sie Übergaben an die Funktion `next()` vornehmen (außer die Zeichenfolge `'route'`), sieht Express die aktuelle Anforderung als Fehler an und überspringt alle verbleibenden fehlerfreien Behandlungsroutinen und Middlewarefunktionen. + +If the callback in a sequence provides no data, only errors, you can simplify +this code as follows: + +```js +app.get('/', [ + function (req, res, next) { + fs.writeFile('/inaccessible-path', 'data', next); + }, + function (req, res) { + res.send('OK'); + }, +]); +``` + +In the above example, `next` is provided as the callback for `fs.writeFile`, +which is called with or without errors. If there is no error, the second +handler is executed, otherwise Express catches and processes the error. + +Bei einem Routenhandler mit mehreren Callback-Funktionen können Sie den Parameter `route` verwenden, um den nächsten Routenhandler zu überspringen. Beispiel: + +```js +app.get('/', (req, res, next) => { + setTimeout(() => { + try { + throw new Error('BROKEN'); + } catch (err) { + next(err); + } + }, 100); +}); +``` + +The above example uses a `try...catch` block to catch errors in the +asynchronous code and pass them to Express. If the `try...catch` +block were omitted, Express would not catch the error since it is not part of the synchronous +handler code. + +Use promises to avoid the overhead of the `try...catch` block or when using functions +that return promises. Beispiel: + +```js +app.get('/', (req, res, next) => { + Promise.resolve() + .then(() => { + throw new Error('BROKEN'); + }) + .catch(next); // Errors will be passed to Express. +}); +``` + +Since promises automatically catch both synchronous errors and rejected promises, +you can simply provide `next` as the final catch handler and Express will catch errors, +because the catch handler is given the error as the first argument. + +You could also use a chain of handlers to rely on synchronous error +catching, by reducing the asynchronous code to something trivial. Beispiel: + +```js +app.get('/', [ + function (req, res, next) { + fs.readFile('/maybe-valid-file', 'utf-8', (err, data) => { + res.locals.data = data; + next(err); + }); + }, + function (req, res) { + res.locals.data = res.locals.data.split(',')[1]; + res.send(res.locals.data); + }, +]); +``` + +The above example has a couple of trivial statements from the `readFile` +call. If `readFile` causes an error, then it passes the error to Express, otherwise you +quickly return to the world of synchronous error handling in the next handler +in the chain. Then, the example above tries to process the data. If this fails, then the +synchronous error handler will catch it. If you had done this processing inside +the `readFile` callback, then the application might exit and the Express error +handlers would not run. + +Whichever method you use, if you want Express error handlers to be called in and the +application to survive, you must ensure that Express receives the error. + +## Die Standardfehlerbehandlungsroutine (Default Error Handler) + +Express ist bereits mit einer integrierten Fehlerbehandlungsroutine ausgestattet, mit der alle in der Anwendung festgestellten Fehler gehandhabt werden können. Diese Middleware für die Fehlerbehandlung wird am Ende des Middleware-Funktionsstack hinzugefügt. + +Wenn Sie einen Fehler an `next()` übergeben und diesen nicht mit einem Error-Handler bearbeiten, wird dieser über den integrierten Error-Handler bearbeitet. Der Fehler wird mit dem Stack-Trace zum Client geschrieben. Der Stack-Trace ist in der Produktionsumgebung nicht verfügbar. + +
    +Legen Sie die Umgebungsvariable `NODE_ENV` auf `production` fest, um die Anwendung im Produktionsmodus auszuführen. +
    + +When an error is written, the following information is added to the +response: + +- The `res.statusCode` is set from `err.status` (or `err.statusCode`). If + this value is outside the 4xx or 5xx range, it will be set to 500. +- The `res.statusMessage` is set according to the status code. +- The body will be the HTML of the status code message when in production + environment, otherwise will be `err.stack`. +- Any headers specified in an `err.headers` object. + +Wenn `next()` mit einem Fehler aufgerufen wird, nachdem Sie mit dem Schreiben der Antwort begonnen haben (z. B., wenn Sie beim Streamen der Antwort zum Client einen Fehler feststellen), schließt die Standardfehlerbehandlungsroutine in Express die Verbindung, und die Anforderung schlägt fehl. + +Wenn Sie also einen angepassten Error-Handler hinzufügen, empfiehlt es sich, eine Delegierung zur Standardfehlerbehandlungsroutine in Express vorzunehmen, wenn die Header bereits an den Client gesendet wurden: + +```js +function errorHandler(err, req, res, next) { + if (res.headersSent) { + return next(err); + } + res.status(500); + res.render('error', { error: err }); +} +``` + +Note that the default error handler can get triggered if you call `next()` with an error +in your code more than once, even if custom error handling middleware is in place. + +Other error handling middleware can be found at [Express middleware](/{{ page.lang }}/resources/middleware.html). + +## Writing error handlers + +Define error-handling middleware functions in the same way as other middleware functions, +except error-handling functions have four arguments instead of three: +`(err, req, res, next)`. Beispiel: + +```js +app.use((err, req, res, next) => { + console.error(err.stack); + res.status(500).send('Something broke!'); +}); +``` + +You define error-handling middleware last, after other `app.use()` and routes calls; for example: + +```js +const bodyParser = require('body-parser'); +const methodOverride = require('method-override'); + +app.use( + bodyParser.urlencoded({ + extended: true, + }) +); +app.use(bodyParser.json()); +app.use(methodOverride()); +app.use((err, req, res, next) => { + // logic +}); +``` + +Antworten von der Middlewarefunktion können das von Ihnen gewünschte Format aufweisen wie beispielsweise eine Fehlerseite im HTML-Format, eine einfache Nachricht oder eine JSON-Zeichenfolge. + +Für organisatorische Zwecke (und Frameworks der höheren Ebene) können Sie mehrere Middlewarefunktionen für die Fehlerbehandlung definieren, wie Sie dies bei regulären Middlewarefunktionen auch tun würden. Wenn Sie beispielsweise eine Fehlerbehandlungsroutine (Error-Handler) für Anforderungen über `XHR` und andere Anforderungen definieren wollen, können Sie die folgenden Befehle verwenden: + +```js +const bodyParser = require('body-parser'); +const methodOverride = require('method-override'); + +app.use( + bodyParser.urlencoded({ + extended: true, + }) +); +app.use(bodyParser.json()); +app.use(methodOverride()); +app.use(logErrors); +app.use(clientErrorHandler); +app.use(errorHandler); +``` + +In diesem Beispiel kann die generische `logErrors`-Funktion Anforderungs- und Fehlerinformationen in `stderr` schreiben: + +```js +function logErrors(err, req, res, next) { + console.error(err.stack); + next(err); +} +``` + +In diesem Beispiel wird `clientErrorHandler` wie folgt definiert. In diesem Fall wird der Fehler explizit an den nächsten Error-Handler übergeben: + +Notice that when _not_ calling "next" in an error-handling function, you are responsible for writing (and ending) the response. Otherwise, those requests will "hang" and will not be eligible for garbage collection. + +```js +function clientErrorHandler(err, req, res, next) { + if (req.xhr) { + res.status(500).send({ error: 'Something failed!' }); + } else { + next(err); + } +} +``` + +Die `errorHandler`-Funktion "catch-all" kann wie folgt implementiert werden: + +```js +function errorHandler(err, req, res, next) { + res.status(500); + res.render('error', { error: err }); +} +``` + +If you have a route handler with multiple callback functions, you can use the `route` parameter to skip to the next route handler. Beispiel: + +```js +app.get( + '/a_route_behind_paywall', + (req, res, next) => { + if (!req.user.hasPaid) { + // continue handling this request + next('route'); + } else { + next(); + } + }, + (req, res, next) => { + PaidContent.find((err, doc) => { + if (err) return next(err); + res.json(doc); + }); + } +); +``` + +In diesem Beispiel wird der Handler `getPaidContent` übersprungen. Alle verbleibenden Handler in `app` für `/a_route_behind_paywall` werden jedoch weiter ausgeführt. + +
    +Aufrufe zu `next()` und `next(err)` geben an, dass der aktuelle Handler abgeschlossen ist und welchen Status er aufweist. Durch `next(err)` werden alle verbleibenden Handler in der Kette übersprungen. Ausgenommen hiervor sind die Handler, die konfiguriert sind, um Fehler wie oben beschrieben zu behandeln. +
    diff --git a/astro/src/content/docs/de/4x/guide/migrating-4.md b/astro/src/content/docs/de/4x/guide/migrating-4.md new file mode 100644 index 0000000000..7846241979 --- /dev/null +++ b/astro/src/content/docs/de/4x/guide/migrating-4.md @@ -0,0 +1,554 @@ +--- +title: Migration auf Express 4 +description: A guide to migrating your Express.js applications from version 3 to 4, covering changes in middleware, routing, and how to update your codebase effectively. +--- + +# Wechsel zu Express 4 + +

    Überblick

    + +Express 4 bietet grundlegende Veränderungen im Vergleich zu Express 3. Das bedeutet, dass eine Express 3-Anwendung nicht funktioniert, wenn Sie die Express-Version in ihren Abhängigkeiten aktualisieren. + +In diesem Beitrag werden folgende Themen behandelt: + + + +

    Änderungen in Express 4

    + +In Express 4 wurden einige signifikante Änderungen vorgenommen: + + + +Siehe hierzu auch: + +- [Neue Features/Funktionen in 4.x.](https://github.com/expressjs/express/wiki/New-features-in-4.x) +- [Migration von 3.x auf 4.x.](https://github.com/expressjs/express/wiki/Migrating-from-3.x-to-4.x) + +

    +Änderungen am Express-Core- und Middlewaresystem

    + +In Express 4 bestehen keine Abhängigkeiten mehr zu Connect. Alle integrierten Middlewarefunktionen werden aus dem Core entfernt. Ausgenommen hiervon ist die Funktion `express.static`. Das bedeutet, dass Express nun ein unabhängiges Routing- und Middleware-Web-Framework ist und Express-Versionierung und -Releases von Middleware-Updates nicht betroffen sind. + +Ohne integrierte Middleware müssen Sie explizit alle Middlewarefunktionen hinzufügen, die für die Ausführung Ihrer Anwendung erforderlich sind. Befolgen Sie einfach diese Schritte: + +1. Installieren des Moduls: `npm install --save ` +2. Anfordern des Moduls in Ihrer Anwendung: `require('modulname')` +3. Verwendung des Moduls gemäß Dokumentation: `app.use( ... )` + +In der folgenden Tabelle sind Express 3-Middlewarefunktionen und deren Entsprechungen in Express 4 aufgelistet. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Express 3Express 4
    express.bodyParserbody-parser + +multer
    express.compresscompression
    express.cookieSessioncookie-session
    express.cookieParsercookie-parser
    express.loggermorgan
    express.sessionexpress-session
    express.faviconserve-favicon
    express.responseTimeresponse-time
    express.errorHandlererrorhandler
    express.methodOverridemethod-override
    express.timeoutconnect-timeout
    express.vhostvhost
    express.csrfcsurf
    express.directoryserve-index
    express.staticserve-static
    + +Hier finden Sie die [komplette Liste](https://github.com/senchalabs/connect#middleware) der Express 4-Middleware. + +In den meisten Fällen können Sie einfach nur die Middleware der alten Version 3 durch deren Entsprechung in Express 4 ersetzen. Details hierzu finden Sie in der modulspezifischen Dokumentation in GitHub. + +

    app.use akzeptiert Parameter.

    + +In Version 4 können Sie über einen Variablenparameter den Pfad definieren, in den Middlewarefunktionen geladen werden. Dann können Sie den Wert des Parameters aus dem Routenhandler laden. +Beispiel: + +```js +app.use('/book/:id', (req, res, next) => { + console.log('ID:', req.params.id); + next(); +}); +``` + +

    +Das Routingsystem +

    + +Anwendungen laden nun implizit Routing-Middleware. Sie müssen sich also keine Gedanken mehr über die Reihenfolge machen, in der die Middleware in Bezug auf die `router`-Middleware geladen wird. + +Das Routingsystem verfügt jedoch über zwei neue Funktionen, die beim Organisieren Ihrer Weiterleitungen helfen: + +{: .doclist } + +- Die neue Methode `app.route()` zum Erstellen verkettbarer Routenhandler für einen Weiterleitungspfad +- Die neue Klasse `express.Router` zum Erstellen modular einbindbarer Routenhandler + +

    Die Methode app.route()

    + +Die neue Methode `app.route()` hilft beim Erstellen verkettbarer Routenhandler für einen Weiterleitungspfad. Da der Pfad an einer einzelnen Position angegeben wird, ist das Erstellen modularer Weiterleitungen hilfreich, da Redundanzen und Schreibfehler reduziert werden. Weitere Informationen zu Weiterleitungen finden Sie in der Dokumentation zu [`Router()`](/{{ page.lang }}/4x/api.html#router). + +Dies ist ein Beispiel für verkettete Routenhandler, die mit der Funktion `app.route()` definiert werden. + +```js +app + .route('/book') + .get((req, res) => { + res.send('Get a random book'); + }) + .post((req, res) => { + res.send('Add a book'); + }) + .put((req, res) => { + res.send('Update the book'); + }); +``` + +

    Die Klasse express.Router

    + +Eine weitere Funktion, die beim Organisieren von Weiterleitungen hilft, ist die neue Klasse `express.Router`. Über diese Klasse können Sie modular einbindbare Routenhandler erstellen. Eine `Router`-Instanz ist ein vollständiges Middleware- und Routingsystem. Aus diesem Grund wird diese Instanz oft auch als "Mini-App" bezeichnet. + +Im folgenden Beispiel wird ein Router als Modul erstellt, Middleware in das Modul geladen, es werden Weiterleitungen definiert und das Modul letztendlich in einen Pfad in der Hauptanwendung eingebunden. + +Beispiel: Erstellen Sie eine Routerdatei namens `birds.js` mit dem folgenden Inhalt im Anwendungsverzeichnis: + +```js +var express = require('express'); +var router = express.Router(); + +// middleware specific to this router +router.use((req, res, next) => { + console.log('Time: ', Date.now()); + next(); +}); +// define the home page route +router.get('/', (req, res) => { + res.send('Birds home page'); +}); +// define the about route +router.get('/about', (req, res) => { + res.send('About birds'); +}); + +module.exports = router; +``` + +Laden Sie dann das Routermodul in die Anwendung: + +```js +var birds = require('./birds'); + +// ... + +app.use('/birds', birds); +``` + +Die Anwendung kann nun Anforderungen an die Pfade `/birds` und `/birds/about` bearbeiten und ruft die Middleware `timeLog` auf, die speziell für diese Weiterleitung bestimmt ist. + +

    +Weitere Änderungen

    + +In der folgenden Tabelle sind andere kleinere, aber trotzdem wichtige Änderungen in Express 4 aufgeführt: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ObjektBeschreibung
    Node.js +Express 4 erfordert Node.js 0.10.x oder höher und unterstützt nicht mehr Node.js 0.8.x. +
    +`http.createServer()` + +Das Modul `http` wird nicht mehr benötigt, es sei denn, Sie müssen direkt mit dem Modul arbeiten (socket.io/SPDY/HTTPS). Die Anwendung kann mithilfe der Funktion `app.listen()` gestartet werden. +
    +`app.configure()` + +Die Funktion `app.configure()` wurde entfernt. Verwenden Sie die Funktion `process.env.NODE_ENV` oder `app.get('env')`, um die Umgebung zu erkennen und die Anwendung entsprechend zu konfigurieren. +
    +`json spaces` + +Die Anwendungseigenschaft `json spaces` ist in Express 4 standardmäßig inaktiviert. +
    +`req.accepted()` + +Verwenden Sie `req.accepts()`, `req.acceptsEncodings()`, `req.acceptsCharsets()` und `req.acceptsLanguages()`. +
    +`res.location()` + +Löst keine relativen URLs mehr auf. +
    +`req.params` + +War bisher ein Array, ist nun ein Objekt. +
    +`res.locals` + +War bisher eine Funktion, ist nun ein Objekt. +
    +`res.headerSent` + +Geändert in `res.headersSent`. +
    +`app.route` + +Nun verfügbar als `app.mountpath`. +
    +`res.on('header')` + +Entfernt. +
    +`res.charset` + +Entfernt. +
    +`res.setHeader('Set-Cookie', val)` + +Die Funktionalität ist nun auf die Einstellung des Basis-Cookiewerts begrenzt. Verwenden Sie `res.cookie()`, um weitere Funktionalität zu erhalten. +
    + +

    Beispiel für eine Anwendungsmigration

    + +Dies ist ein Beispiel für die Migration einer Express 3-Anwendung auf Express 4. +Die dabei interessanten Dateien sind `app.js` und `package.json`. + +

    +Anwendung der Version 3 +

    + +

    app.js

    + +Es wird eine Express v.3-Anwendung mit der folgenden Datei `app.js` angenommen: + +```js +var express = require('express'); +var routes = require('./routes'); +var user = require('./routes/user'); +var http = require('http'); +var path = require('path'); + +var app = express(); + +// all environments +app.set('port', process.env.PORT || 3000); +app.set('views', path.join(__dirname, 'views')); +app.set('view engine', 'pug'); +app.use(express.favicon()); +app.use(express.logger('dev')); +app.use(express.methodOverride()); +app.use(express.session({ secret: 'your secret here' })); +app.use(express.bodyParser()); +app.use(app.router); +app.use(express.static(path.join(__dirname, 'public'))); + +// development only +if (app.get('env') === 'development') { + app.use(express.errorHandler()); +} + +app.get('/', routes.index); +app.get('/users', user.list); + +http.createServer(app).listen(app.get('port'), () => { + console.log('Express server listening on port ' + app.get('port')); +}); +``` + +

    package.json

    + +Die zugehörige `package.json`-Datei der Version 3 sieht in etwa wie folgt aus: + +```json +{ + "name": "application-name", + "version": "0.0.1", + "private": true, + "scripts": { + "start": "node app.js" + }, + "dependencies": { + "express": "3.12.0", + "pug": "*" + } +} +``` + +

    +Prozess +

    + +Beginnen Sie den Migrationsprozess mit der Installation der erforderlichen Middleware für die Express 4-Anwendung und der Aktualisierung von Express und Pug auf die aktuellen Versionen. Verwenden Sie hierzu den folgenden Befehl: + +```bash +$ npm install serve-favicon morgan method-override express-session body-parser multer errorhandler express@latest pug@latest --save +``` + +Nehmen Sie an `app.js` die folgenden Änderungen vor: + +1. Die integrierten Express-Middlewarefunktionen `express.favicon`, + `express.logger`, `express.methodOverride`, + `express.session`, `express.bodyParser` und + `express.errorHandler` sind im Objekt `express` nicht mehr verfügbar. Sie müssen deren Alternativen manuell installieren und in die Anwendung laden. + +2. Sie müssen die Funktion `app.router` nicht mehr laden. + Sie ist kein gültiges Express 4-Anwendungsobjekt. Entfernen Sie also den Code `app.use(app.router);`. + +3. Stellen Sie sicher, dass die Middlewarefunktionen in der richtigen Reihenfolge geladen werden – laden Sie `errorHandler` nach dem Laden der Anwendungsweiterleitungen. + +

    Anwendung der Version 4

    + +

    package.json

    + +Durch Ausführung des Befehls `npm` wird `package.json` wie folgt aktualisiert: + +```json +{ + "name": "application-name", + "version": "0.0.1", + "private": true, + "scripts": { + "start": "node app.js" + }, + "dependencies": { + "body-parser": "^1.5.2", + "errorhandler": "^1.1.1", + "express": "^4.8.0", + "express-session": "^1.7.2", + "pug": "^2.0.0", + "method-override": "^2.1.2", + "morgan": "^1.2.2", + "multer": "^0.1.3", + "serve-favicon": "^2.0.1" + } +} +``` + +

    app.js

    + +Entfernen Sie dann ungültigen Code, laden Sie die erforderliche Middleware und nehmen Sie andere Änderungen nach Bedarf vor. Die Datei `app.js` sieht dann wie folgt aus: + +```js +var http = require('http'); +var express = require('express'); +var routes = require('./routes'); +var user = require('./routes/user'); +var path = require('path'); + +var favicon = require('serve-favicon'); +var logger = require('morgan'); +var methodOverride = require('method-override'); +var session = require('express-session'); +var bodyParser = require('body-parser'); +var multer = require('multer'); +var errorHandler = require('errorhandler'); + +var app = express(); + +// all environments +app.set('port', process.env.PORT || 3000); +app.set('views', path.join(__dirname, 'views')); +app.set('view engine', 'pug'); +app.use(favicon(path.join(__dirname, '/public/favicon.ico'))); +app.use(logger('dev')); +app.use(methodOverride()); +app.use( + session({ + resave: true, + saveUninitialized: true, + secret: 'uwotm8', + }) +); +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: true })); +app.use(multer()); +app.use(express.static(path.join(__dirname, 'public'))); + +app.get('/', routes.index); +app.get('/users', user.list); + +// error handling middleware should be loaded after the loading the routes +if (app.get('env') === 'development') { + app.use(errorHandler()); +} + +var server = http.createServer(app); +server.listen(app.get('port'), () => { + console.log('Express server listening on port ' + app.get('port')); +}); +``` + +
    Wenn Sie nicht direkt mit dem Modul `http` arbeiten müssen (socket.io/SPDY/HTTPS), ist das Laden des Moduls nicht erforderlich. Die Anwendung kann dann einfach wie folgt gestartet werden: + +```js +app.listen(app.get('port'), () => { + console.log('Express server listening on port ' + app.get('port')); +}); +``` + +
    + +

    Anwendung ausführen

    + +Der Migrationsprozess ist abgeschlossen und die Anwendung ist nun eine Express 4-Anwendung. Zum Bestätigen starten Sie die Anwendung mit dem folgenden Befehl: + +```bash +$ node . +``` + +Laden Sie [http://localhost:3000](http://localhost:3000) und sehen Sie, wie die Homepage von Express 4 wiedergegeben wird. + +

    Upgrade auf den Express 4 App Generator

    + +Das Befehlszeilentool zum Generieren einer Express-Anwendung ist nach wie vor `express`. Für ein Upgrade auf die neue Version müssen Sie jedoch den Express 3 App Generator deinstallieren und dann den neuen Generator `express-generator` installieren. + +

    Installation

    + +Wenn der Express 3 App Generator bereits auf Ihrem System installiert ist, müssen Sie diesen deinstallieren: + +```bash +$ npm uninstall -g express +``` + +Abhängig davon, wie Ihre Datei- und Verzeichnissberechtigungen konfiguriert sind, müssen Sie diesen Befehl möglicherweise mit `sudo` ausführen. + +Installieren Sie nun den neuen Generator: + +```bash +$ npm install -g express-generator +``` + +Abhängig davon, wie Ihre Datei- und Verzeichnissberechtigungen konfiguriert sind, müssen Sie diesen Befehl möglicherweise mit `sudo` ausführen. + +Nun wird der Befehl `express` auf Ihrem System auf den Express 4 App Generator aktualisiert. + +

    Änderungen am App Generator

    + +Befehlsoptionen und -nutzung bleiben größtenteils unverändert. Es gelten jedoch folgende Ausnahmen: + +{: .doclist } + +- Option `--sessions` wurde entfernt. +- Option `--jshtml` wurde entfernt. +- Option `--hogan` wurde hinzugefügt, um [Hogan.js](http://twitter.github.io/hogan.js/) zu unterstützen. + +

    Beispiel

    + +Führen Sie den folgenden Befehl aus, um eine Express 4-Anwendung zu erstellen: + +```bash +$ express app4 +``` + +Wenn Sie sich den Inhalt der Datei `app4/app.js` ansehen, werden Sie feststellen, dass alle Middlewarefunktionen (außer `express.static`), die für die Anwendung erforderlich sind, als unabhängige Module geladen werden und die Middleware `router` nicht mehr explizit in die Anwendung geladen wird. + +Sie werden auch feststellen, dass die Datei `app.js` nun ein Node.js-Modul ist – im Gegensatz zur eigenständigen Anwendung, die vom bisherigen Generator generiert wurde. + +Starten Sie nach der Installation der Abhängigkeiten die Anwendung mit dem folgenden Befehl: + +```bash +$ npm start +``` + +Wenn Sie sich das npm-Startscript in der Datei `package.json` näher ansehen, werden Sie feststellen, dass der eigentliche Befehl, der die Anwendung startet, `node ./bin/www` heißt. Dieser Befehl lautete in Express 3 `node app.js`. + +Da die Datei `app.js`, die vom Express 4 Generator erstellt wurde, nun ein Node.js-Modul ist, kann dieses nicht mehr wie bisher unabhängig als Anwendung gestartet werden (es sei denn, Sie ändern den Code). Das Modul muss in eine Node.js-Datei geladen und über die Node.js-Datei gestartet werden. Die Node.js-Datei ist in diesem Fall `./bin/www`. + +Weder das Verzeichnis `bin` noch die erweiterungslose Datei `www` ist für das Erstellen einer Express-Anwendung oder das Starten der Anwendung zwingend erforderlich. Dies sind lediglich Vorschläge des Generators. Sie können diese also je nach Ihren Anforderungen ändern. + +Um das Verzeichnis `www` zu löschen und alles im "Express 3-Stil" zu belassen, löschen Sie die Zeile mit dem Eintrag `module.exports = app;` am Ende der Datei `app.js`. Fügen Sie dann stattdessen den folgenden Code an derselben Position ein: + +```js +app.set('port', process.env.PORT || 3000); + +var server = app.listen(app.get('port'), () => { + debug('Express server listening on port ' + server.address().port); +}); +``` + +Stellen Sie sicher, dass Sie das Modul `debug` am Anfang der Datei `app.js` laden. Verwenden Sie dazu den folgenden Code: + +```js +var debug = require('debug')('app4'); +``` + +Ändern Sie als Nächstes `"start": "node ./bin/www"` in der Datei `package.json` in `"start": "node app.js"`. + +Sie haben nun die Funktionalität von `./bin/www` wieder in `app.js` verschoben. Diese Änderung wird nicht empfohlen. Die Übung hat Ihnen jedoch geholfen, zu verstehen, wie die Datei `./bin/www` funktioniert und warum die Datei `app.js` nicht mehr automatisch gestartet wird. diff --git a/astro/src/content/docs/de/4x/guide/migrating-5.md b/astro/src/content/docs/de/4x/guide/migrating-5.md new file mode 100644 index 0000000000..fd4ff016c8 --- /dev/null +++ b/astro/src/content/docs/de/4x/guide/migrating-5.md @@ -0,0 +1,587 @@ +--- +title: Migration auf Express 5 +description: A comprehensive guide to migrating your Express.js applications from version 4 to 5, detailing breaking changes, deprecated methods, and new improvements. +--- + +# Wechsel zu Express 5 + +

    Überblick

    + +Express 5.0 befindet sich noch in der Beta-Release-Phase. Hier finden Sie jedoch bereits eine Vorschau zu den Änderungen in diesem Release und zur Migration Ihrer Express 4-Anwendung auf Express 5. + +To install this version, you need to have a Node.js version 18 or higher. Then, execute the following command in your application directory: + +```sh +npm install "express@5" +``` + +Sie können Ihre automatisierten Tests ausführen, um zu sehen, was fehlschlägt, und Probleme gemäß den folgenden Updates beheben. Nachdem Sie alle Testfehler behoben haben, führen Sie Ihre Anwendung aus, um zu sehen, welche Fehler noch auftreten. Sie werden sofort feststellen, ob die Anwendung Methoden oder Eigenschaften verwendet, die nicht unterstützt werden. + +## Express 5 Codemods + +To help you migrate your express server, we have created a set of codemods that will help you automatically update your code to the latest version of Express. + +Run the following command for run all the codemods available: + +```sh +npx @expressjs/codemod upgrade +``` + +If you want to run a specific codemod, you can run the following command: + +```sh +npx @expressjs/codemod name-of-the-codemod +``` + +You can find the list of available codemods [here](https://github.com/expressjs/codemod?tab=readme-ov-file#available-codemods). + +

    Änderungen in Express 5

    + +**Entfernte Methoden und Eigenschaften** + + + +**Verbesserungen** + + + +**Geändert** + + + +## Entfernte Methoden und Eigenschaften + +Wenn Sie eine dieser Methoden oder Eigenschaften in Ihrer Anwendung verwenden, stürzt die Anwendung ab. Sie müssen also Ihre Anwendung ändern, wenn Sie auf Version 5 umgestellt haben. + +

    app.del()

    + +Express 5 unterstützt die Funktion `app.del()` nicht mehr. Wenn Sie diese Funktion verwenden, wird ein Fehler ausgelöst. Für die Registrierung von HTTP DELETE-Weiterleitungen verwenden Sie stattdessen die Funktion `app.delete()`. + +Anfänglich wurde `del` statt `delete` verwendet, weil `delete` in JavaScript ein reserviertes Schlüsselwort ist. Ab ECMAScript 6 jedoch können `delete` und andere reservierte Schlüsselwörter legal als Eigenschaftsnamen verwendet werden. + +{% capture codemod-deprecated-signatures %} +You can replace the deprecated signatures with the following command: + +```plaintext +npx @expressjs/codemod v4-deprecated-signatures +``` + +{% endcapture %} + +{% include admonitions/note.html content=codemod-deprecated-signatures %} + +```js +// v4 +app.del('/user/:id', (req, res) => { + res.send(`DELETE /user/${req.params.id}`); +}); + +// v5 +app.delete('/user/:id', (req, res) => { + res.send(`DELETE /user/${req.params.id}`); +}); +``` + +

    app.param(fn)

    + +Die Signatur `app.param(fn)` wurde für die Änderung der Verhaltensweise der Funktion `app.param(name, fn)` verwendet. Seit v4.11.0 wurde sie nicht mehr verwendet. In Express 5 wird sie überhaupt nicht mehr unterstützt. + +

    Pluralisierte Methodennamen

    + +Die folgenden Methodennamen wurden pluralisiert. In Express 4 wurde bei Verwendung der alten Methoden eine Warnung zur Einstellung der Unterstützung ausgegeben. Express 5 unterstützt diese Methoden nicht mehr. + +`req.acceptsLanguage()` wird durch `req.acceptsLanguages()` ersetzt. + +`req.acceptsCharset()` wird durch `req.acceptsCharsets()` ersetzt. + +`req.acceptsEncoding()` wird durch `req.acceptsEncodings()` ersetzt. + +{% capture codemod-pluralized-methods %} +You can replace the deprecated signatures with the following command: + +```plaintext +npx @expressjs/codemod pluralized-methods +``` + +{% endcapture %} + +{% include admonitions/note.html content=codemod-pluralized-methods %} + +```js +// v4 +app.all('/', (req, res) => { + req.acceptsCharset('utf-8'); + req.acceptsEncoding('br'); + req.acceptsLanguage('en'); + + // ... +}); + +// v5 +app.all('/', (req, res) => { + req.acceptsCharsets('utf-8'); + req.acceptsEncodings('br'); + req.acceptsLanguages('en'); + + // ... +}); +``` + +

    Führender Doppelpunkt (:) im Namen für app.param(name, fn)

    + +Ein führendes Doppelpunktzeichen (:) im Namen für die Funktion `app.param(name, fn)` ist ein Überbleibsel aus Express 3. Aus Gründen der Abwärtskompatibilität wurde dieser Name in Express 4 mit einem Hinweis zu veralteten Versionen weiter unterstützt. In Express 5 wird dieser Name stillschwiegend ignoriert und der Namensparameter ohne einen vorangestellten Doppelpunkt verwendet. + +Dies dürfte keine Auswirkungen auf Ihren Code haben, wenn Sie die Express 4-Dokumentation zu [app.param](/{{ page.lang }}/4x/api.html#app.param) befolgen, da dort der führende Doppelpunkt nicht erwähnt wird. + +

    req.param(name)

    + +Dieses potenziell verwirrende und durchaus riskante Verfahren des Abrufens von Formulardaten wurde entfernt. Sie müssen nun ganz speziell nach dem übergebenen Parameternamen im Objekt `req.params`, `req.body` oder `req.query` suchen. + +{% capture codemod-req-param %} +You can replace the deprecated signatures with the following command: + +```plaintext +npx @expressjs/codemod req-param +``` + +{% endcapture %} + +{% include admonitions/note.html content=codemod-req-param %} + +```js +// v4 +app.post('/user', (req, res) => { + const id = req.param('id'); + const body = req.param('body'); + const query = req.param('query'); + + // ... +}); + +// v5 +app.post('/user', (req, res) => { + const id = req.params.id; + const body = req.body; + const query = req.query; + + // ... +}); +``` + +

    res.json(obj, status)

    + +Express 5 unterstützt die Signatur `res.json(obj, status)` nicht mehr. Stattdessen müssen Sie den Status festlegen und diesen dann mit `res.json()`-Methoden wie dieser verketten: `res.status(status).json(obj)`. + +{% include admonitions/note.html content=codemod-deprecated-signatures %} + +```js +// v4 +app.post('/user', (req, res) => { + res.json({ name: 'Ruben' }, 201); +}); + +// v5 +app.post('/user', (req, res) => { + res.status(201).json({ name: 'Ruben' }); +}); +``` + +

    res.jsonp(obj, status)

    + +Express 5 unterstützt die Signatur `res.jsonp(obj, status)` nicht mehr. Stattdessen müssen Sie den Status festlegen und diesen dann mit `res.jsonp()`-Methoden wie dieser verketten: `res.status(status).jsonp(obj)`. + +{% include admonitions/note.html content=codemod-deprecated-signatures %} + +```js +// v4 +app.post('/user', (req, res) => { + res.jsonp({ name: 'Ruben' }, 201); +}); + +// v5 +app.post('/user', (req, res) => { + res.status(201).jsonp({ name: 'Ruben' }); +}); +``` + +

    res.redirect(url, status)

    + +Express 5 unterstützt die Signatur `res.send(obj, status)` nicht mehr. Stattdessen müssen Sie den Status festlegen und diesen dann mit `res.send()`-Methoden wie dieser verketten: `res.status(status).send(obj)`. + +{% include admonitions/note.html content=codemod-deprecated-signatures %} + +```js +// v4 +app.get('/user', (req, res) => { + res.redirect('/users', 301); +}); + +// v5 +app.get('/user', (req, res) => { + res.redirect(301, '/users'); +}); +``` + +

    res.redirect('back') and res.location('back')

    + +Express 5 no longer supports the magic string `back` in the `res.redirect()` and `res.location()` methods. Instead, use the `req.get('Referrer') || '/'` value to redirect back to the previous page. In Express 4, the `res.redirect('back')` and `res.location('back')` methods were deprecated. + +{% capture codemod-magic-redirect %} +You can replace the deprecated signatures with the following command: + +```plaintext +npx @expressjs/codemod magic-redirect +``` + +{% endcapture %} + +{% include admonitions/note.html content=codemod-magic-redirect %} + +```js +// v4 +app.get('/user', (req, res) => { + res.redirect('back'); +}); + +// v5 +app.get('/user', (req, res) => { + res.redirect(req.get('Referrer') || '/'); +}); +``` + +

    res.send(body, status)

    + +Express 5 no longer supports the signature `res.send(obj, status)`. Instead, set the status and then chain it to the `res.send()` method like this: `res.status(status).send(obj)`. + +{% include admonitions/note.html content=codemod-deprecated-signatures %} + +```js +// v4 +app.get('/user', (req, res) => { + res.send({ name: 'Ruben' }, 200); +}); + +// v5 +app.get('/user', (req, res) => { + res.status(200).send({ name: 'Ruben' }); +}); +``` + +

    res.send(status)

    + +Express 5 unterstützt die Signatur res.send(status), nicht mehr, wobei _`status`_ für eine Zahl steht. Verwenden Sie stattdessen die Funktion `res.sendStatus(statusCode)`, mit der der Statuscode für den HTTP-Antwort-Header festgelegt und die Textversion des Codes gesendet wird: "Not Found" (Nicht gefunden), "Internal Server Error" (Interner Serverfehler) usw. +Wenn Sie eine Zahl senden und hierfür die Funktion `res.send()` verwenden müssen, müssen Sie die Zahl in Anführungszeichen setzen, um diese in eine Zeichenfolge zu konvertieren. Dadurch interpretiert Express diese Zahl nicht als Versuch, die nicht mehr unterstützte alte Signatur zu verwenden. + +{% include admonitions/note.html content=codemod-deprecated-signatures %} + +```js +// v4 +app.get('/user', (req, res) => { + res.send(200); +}); + +// v5 +app.get('/user', (req, res) => { + res.sendStatus(200); +}); +``` + +

    res.sendfile()

    + +Die Funktion `res.sendfile()` wurde durch eine Version in Camel-Schreibweise von `res.sendFile()` in Express 5 ersetzt. + +**Note:** In Express 5, `res.sendFile()` uses the `mime-types` package for MIME type detection, which returns different Content-Type values than Express 4 for several common file types: + +- JavaScript files (.js): now "text/javascript" instead of "application/javascript" +- JSON files (.json): now "application/json" instead of "text/json" +- CSS files (.css): now "text/css" instead of "text/plain" +- XML files (.xml): now "application/xml" instead of "text/xml" +- Font files (.woff): now "font/woff" instead of "application/font-woff" +- SVG files (.svg): now "image/svg+xml" instead of "application/svg+xml" + +{% include admonitions/note.html content=codemod-deprecated-signatures %} + +```js +// v4 +app.get('/user', (req, res) => { + res.sendfile('/path/to/file'); +}); + +// v5 +app.get('/user', (req, res) => { + res.sendFile('/path/to/file'); +}); +``` + +

    router.param(fn)

    + +The `router.param(fn)` signature was used for modifying the behavior of the `router.param(name, fn)` function. Seit v4.11.0 wurde sie nicht mehr verwendet. In Express 5 wird sie überhaupt nicht mehr unterstützt. + +

    express.static.mime

    + +In Express 5, `mime` is no longer an exported property of the `static` field. +Use the [`mime-types` package](https://github.com/jshttp/mime-types) to work with MIME type values. + +**Important:** This change affects not only direct usage of `express.static.mime` but also other Express methods that rely on MIME type detection, such as `res.sendFile()`. The following MIME types have changed from Express 4: + +- JavaScript files (.js): now served as "text/javascript" instead of "application/javascript" +- JSON files (.json): now served as "application/json" instead of "text/json" +- CSS files (.css): now served as "text/css" instead of "text/plain" +- HTML files (.html): now served as "text/html; charset=utf-8" instead of just "text/html" +- XML files (.xml): now served as "application/xml" instead of "text/xml" +- Font files (.woff): now served as "font/woff" instead of "application/font-woff" + +```js +// v4 +express.static.mime.lookup('json'); + +// v5 +const mime = require('mime-types'); +mime.lookup('json'); +``` + +

    express:router debug logs

    + +In Express 5, router handling logic is performed by a dependency. Therefore, the +debug logs for the router are no longer available under the `express:` namespace. +In v4, the logs were available under the namespaces `express:router`, `express:router:layer`, +and `express:router:route`. All of these were included under the namespace `express:*`. +In v5.1+, the logs are available under the namespaces `router`, `router:layer`, and `router:route`. +The logs from `router:layer` and `router:route` are included in the namespace `router:*`. +To achieve the same detail of debug logging when using `express:*` in v4, use a conjunction of +`express:*`, `router`, and `router:*`. + +```sh +# v4 +DEBUG=express:* node index.js + +# v5 +DEBUG=express:*,router,router:* node index.js +``` + +## Geändert + +

    Path route matching syntax

    + +Path route matching syntax is when a string is supplied as the first parameter to the `app.all()`, `app.use()`, `app.METHOD()`, `router.all()`, `router.METHOD()`, and `router.use()` APIs. The following changes have been made to how the path string is matched to an incoming request: + +- The wildcard `*` must have a name, matching the behavior of parameters `:`, use `/*splat` instead of `/*` + +```js +// v4 +app.get('/*', async (req, res) => { + res.send('ok'); +}); + +// v5 +app.get('/*splat', async (req, res) => { + res.send('ok'); +}); +``` + +{% capture note_wildcard %} +`*splat` matches any path without the root path. If you need to match the root path as well `/`, you can use `/{*splat}`, wrapping the wildcard in braces. + +```js +// v5 +app.get('/{*splat}', async (req, res) => { + res.send('ok'); +}); +``` + +{% endcapture %} +{% include admonitions/note.html content=note_wildcard %} + +- The optional character `?` is no longer supported, use braces instead. + +```js +// v4 +app.get('/:file.:ext?', async (req, res) => { + res.send('ok'); +}); + +// v5 +app.get('/:file{.:ext}', async (req, res) => { + res.send('ok'); +}); +``` + +- Regexp characters are not supported. Beispiel: + +```js +app.get('/[discussion|page]/:slug', async (req, res) => { + res.status(200).send('ok'); +}); +``` + +should be changed to: + +```js +app.get(['/discussion/:slug', '/page/:slug'], async (req, res) => { + res.status(200).send('ok'); +}); +``` + +- Some characters have been reserved to avoid confusion during upgrade (`()[]?+!`), use `\` to escape them. +- Parameter names now support valid JavaScript identifiers, or quoted like `:"this"`. + +

    Rejected promises handled from middleware and handlers

    + +Request middleware and handlers that return rejected promises are now handled by forwarding the rejected value as an `Error` to the error handling middleware. This means that using `async` functions as middleware and handlers are easier than ever. When an error is thrown in an `async` function or a rejected promise is `await`ed inside an async function, those errors will be passed to the error handler as if calling `next(err)`. + +Details of how Express handles errors is covered in the [error handling documentation](/en/guide/error-handling.html). + +

    express.urlencoded

    + +The `express.urlencoded` method makes the `extended` option `false` by default. + +

    express.static dotfiles

    + +In Express 5, the `express.static` middleware's `dotfiles` option now defaults to `"ignore"`. This is a change from Express 4, where dotfiles were served by default. As a result, files inside a directory that starts with a dot (`.`), such as `.well-known`, will no longer be accessible and will return a **404 Not Found** error. This can break functionality that depends on serving dot-directories, such as Android App Links, and Apple Universal Links. + +Example of breaking code: + +```js +// v4 +app.use(express.static('public')); +``` + +After migrating to Express 5, a request to `/.well-known/assetlinks.json` will result in a **404 Not Found**. + +To fix this, serve specific dot-directories explicitly using the `dotfiles: "allow"` option: + +```js +// v5 +app.use('/.well-known', express.static('public/.well-known', { dotfiles: 'allow' })); +app.use(express.static('public')); +``` + +This approach allows you to safely serve only the intended dot-directories while keeping the default secure behavior for other dotfiles, which remain inaccessible. + +

    app.listen

    + +In Express 5, the `app.listen` method will invoke the user-provided callback function (if provided) when the server receives an error event. In Express 4, such errors would be thrown. This change shifts error-handling responsibility to the callback function in Express 5. If there is an error, it will be passed to the callback as an argument. +Beispiel: + +```js +const server = app.listen(8080, '0.0.0.0', (error) => { + if (error) { + throw error; // e.g. EADDRINUSE + } + console.log(`Listening on ${JSON.stringify(server.address())}`); +}); +``` + +

    app.router

    + +Das Objekt `app.router`, das in Express 4 entfernt wurde, ist in Express 5 wieder verfügbar. In der neuen Version fungiert dieses Objekt nur als Referenz zum Express-Basisrouter – im Gegensatz zu Express 3, wo die Anwendung dieses Objekt explizit laden musste. + +

    req.body

    + +The `req.body` property returns `undefined` when the body has not been parsed. In Express 4, it returns `{}` by default. + +

    req.host

    + +In Express 4 übergab die Funktion `req.host` nicht ordnungsgemäß eine eventuell vorhandene Portnummer. In Express 5 wird die Portnummer beibehalten. + +

    req.params

    + +The `req.params` object now has a **null prototype** when using string paths. However, if the path is defined with a regular expression, `req.params` remains a standard object with a normal prototype. Additionally, there are two important behavioral changes: + +**Wildcard parameters are now arrays:** + +Wildcards (e.g., `/*splat`) capture path segments as an array instead of a single string. + +```js +app.get('/*splat', (req, res) => { + // GET /foo/bar + console.dir(req.params); + // => [Object: null prototype] { splat: [ 'foo', 'bar' ] } +}); +``` + +**Unmatched parameters are omitted:** + +In Express 4, unmatched wildcards were empty strings (`''`) and optional `:` parameters (using `?`) had a key with value `undefined`. In Express 5, unmatched parameters are completely omitted from `req.params`. + +```js +// v4: unmatched wildcard is empty string +app.get('/*', (req, res) => { + // GET / + console.dir(req.params); + // => { '0': '' } +}); + +// v4: unmatched optional param is undefined +app.get('/:file.:ext?', (req, res) => { + // GET /image + console.dir(req.params); + // => { file: 'image', ext: undefined } +}); + +// v5: unmatched optional param is omitted +app.get('/:file{.:ext}', (req, res) => { + // GET /image + console.dir(req.params); + // => [Object: null prototype] { file: 'image' } +}); +``` + +

    req.query

    + +The `req.query` property is no longer a writable property and is instead a getter. The default query parser has been changed from "extended" to "simple". + +

    res.clearCookie

    + +The `res.clearCookie` method ignores the `maxAge` and `expires` options provided by the user. + +

    res.status

    + +The `res.status` method only accepts integers in the range of `100` to `999`, following the behavior defined by Node.js, and it returns an error when the status code is not an integer. + +

    res.vary

    + +The `res.vary` throws an error when the `field` argument is missing. In Express 4, if the argument was omitted, it gave a warning in the console + +## Verbesserungen + +

    res.render()

    + +Diese Methode erzwingt nun asynchrones Verhalten für alle View-Engines, sodass durch View-Engines mit synchroner Implementierung verursachte Fehler vermieden werden, durch die die empfohlene Schnittstelle nicht verwendet werden konnte. + +

    Brotli encoding support

    + +Express 5 supports Brotli encoding for requests received from clients that support it. diff --git a/astro/src/content/docs/de/4x/guide/overriding-express-api.md b/astro/src/content/docs/de/4x/guide/overriding-express-api.md new file mode 100644 index 0000000000..db65ce792f --- /dev/null +++ b/astro/src/content/docs/de/4x/guide/overriding-express-api.md @@ -0,0 +1,70 @@ +--- +title: Overriding the Express API +description: Discover how to customize and extend the Express.js API by overriding methods and properties on the request and response objects using prototypes. +--- + +# Overriding the Express API + +The Express API consists of various methods and properties on the request and response objects. These are inherited by prototype. There are two extension points for the Express API: + +1. The global prototypes at `express.request` and `express.response`. +2. App-specific prototypes at `app.request` and `app.response`. + +Altering the global prototypes will affect all loaded Express apps in the same process. If desired, alterations can be made app-specific by only altering the app-specific prototypes after creating a new app. + +## Methods + +You can override the signature and behavior of existing methods with your own, by assigning a custom function. + +Following is an example of overriding the behavior of [res.sendStatus](/4x/api.html#res.sendStatus). + +```js +app.response.sendStatus = function (statusCode, type, message) { + // code is intentionally kept simple for demonstration purpose + return this.contentType(type).status(statusCode).send(message); +}; +``` + +The above implementation completely changes the original signature of `res.sendStatus`. It now accepts a status code, encoding type, and the message to be sent to the client. + +The overridden method may now be used this way: + +```js +res.sendStatus(404, 'application/json', '{"error":"resource not found"}'); +``` + +## Properties + +Properties in the Express API are either: + +1. Assigned properties (ex: `req.baseUrl`, `req.originalUrl`) +2. Defined as getters (ex: `req.secure`, `req.ip`) + +Since properties under category 1 are dynamically assigned on the `request` and `response` objects in the context of the current request-response cycle, their behavior cannot be overridden. + +Properties under category 2 can be overwritten using the Express API extensions API. + +The following code rewrites how the value of `req.ip` is to be derived. Now, it simply returns the value of the `Client-IP` request header. + +```js +Object.defineProperty(app.request, 'ip', { + configurable: true, + enumerable: true, + get() { + return this.get('Client-IP'); + }, +}); +``` + +## Prototype + +In order to provide the Express API, the request/response objects passed to Express (via `app(req, res)`, for example) need to inherit from the same prototype chain. By default, this is `http.IncomingRequest.prototype` for the request and `http.ServerResponse.prototype` for the response. + +Unless necessary, it is recommended that this be done only at the application level, rather than globally. Also, take care that the prototype that is being used matches the functionality as closely as possible to the default prototypes. + +```js +// Use FakeRequest and FakeResponse in place of http.IncomingRequest and http.ServerResponse +// for the given app reference +Object.setPrototypeOf(Object.getPrototypeOf(app.request), FakeRequest.prototype); +Object.setPrototypeOf(Object.getPrototypeOf(app.response), FakeResponse.prototype); +``` diff --git a/astro/src/content/docs/de/4x/guide/routing.md b/astro/src/content/docs/de/4x/guide/routing.md new file mode 100644 index 0000000000..f365b137f3 --- /dev/null +++ b/astro/src/content/docs/de/4x/guide/routing.md @@ -0,0 +1,417 @@ +--- +title: Weiterleitung in Express +description: Learn how to define and use routes in Express.js applications, including route methods, route paths, parameters, and using Router for modular routing. +--- + +# Weiterleitung (Routing) + +Der Begriff _Weiterleitung_ (Routing) bezieht sich auf die Definition von Anwendungsendpunkten (URIs) und deren Antworten auf Clientanforderungen. +Eine Einführung in dieses Routing siehe [Basisrouting](/{{ page.lang }}/starter/basic-routing.html). + +You define routing using methods of the Express `app` object that correspond to HTTP methods; +for example, `app.get()` to handle GET requests and `app.post` to handle POST requests. For a full list, +see [app.METHOD](/{{ page.lang }}/5x/api.html#app.METHOD). You can also use [app.all()](/{{ page.lang }}/5x/api.html#app.all) to handle all HTTP methods and [app.use()](/{{ page.lang }}/5x/api.html#app.use) to +specify middleware as the callback function (See [Using middleware](/{{ page.lang }}/guide/using-middleware.html) for details). + +These routing methods specify a callback function (sometimes called "handler functions") called when the application receives a request to the specified route (endpoint) and HTTP method. In other words, the application "listens" for requests that match the specified route(s) and method(s), and when it detects a match, it calls the specified callback function. + +In fact, the routing methods can have more than one callback function as arguments. +With multiple callback functions, it is important to provide `next` as an argument to the callback function and then call `next()` within the body of the function to hand off control +to the next callback. + +Der folgende Code ist ein Beispiel für ein sehr einfaches Basisrouting. + +```js +const express = require('express'); +const app = express(); + +// respond with "hello world" when a GET request is made to the homepage +app.get('/', (req, res) => { + res.send('hello world'); +}); +``` + +

    Weiterleitungsmethoden

    + +Eine Weiterleitungsmethode wird von einer HTTP-Methode abgeleitet und an eine Instanz der Klasse `express` angehängt. + +Der folgende Code ist ein Beispiel für Weiterleitungen, die für die Methoden GET und POST zum Stamm (Root) der Anwendung definiert werden. + +```js +// GET method route +app.get('/', (req, res) => { + res.send('GET request to the homepage'); +}); + +// POST method route +app.post('/', (req, res) => { + res.send('POST request to the homepage'); +}); +``` + +Express supports methods that correspond to all HTTP request methods: `get`, `post`, and so on. +For a full list, see [app.METHOD](/{{ page.lang }}/5x/api.html#app.METHOD). + +Es gibt eine spezielle Weiterleitungsmethode, `app.all()`, die nicht von einer HTTP-Methode abgeleitet wird. Diese Methode wird zum Laden von Middlewarefunktionen bei einem Pfad für alle Anforderungsmethoden verwendet. Im folgenden Beispiel wird der Handler für Anforderungen zur Weiterleitung "/secret" ausgeführt, um herauszufinden, ob Sie GET-, POST-, PUT-, DELETE- oder andere HTTP-Anforderungsmethoden verwenden, die im [HTTP-Modul](https://nodejs.org/api/http.html#http_http_methods) unterstützt werden. + +```js +app.all('/secret', (req, res, next) => { + console.log('Accessing the secret section ...'); + next(); // pass control to the next handler +}); +``` + +

    Weiterleitungspfade

    + +Über Weiterleitungspfade werden in Kombination mit einer Anforderungsmethode die Endpunkte definiert, bei denen Anforderungen erfolgen können. Weiterleitungspfade können Zeichenfolgen, Zeichenfolgemuster oder reguläre Ausdrücke sein. + +{% capture caution-character %} In express 5, the characters `?`, `+`, `*`, `[]`, and `()` are handled differently than in version 4, please review the [migration guide](/{{ page.lang }}/guide/migrating-5.html#path-syntax) for more information.{% endcapture %} + +{% include admonitions/caution.html content=caution-character %} + +{% capture note-dollar-character %}In express 4, regular expression characters such as `$` need to be escaped with a `\`. +{% endcapture %} + +{% include admonitions/caution.html content=note-dollar-character %} + +{% capture note-path-to-regexp %} + +Express uses [path-to-regexp](https://www.npmjs.com/package/path-to-regexp) for matching the route paths; see the path-to-regexp documentation for all the possibilities in defining route paths. [Express Route Tester](http://forbeslindesay.github.io/express-route-tester/) ist ein handliches Tool zum Testen von Express-Basisweiterleitungen, auch wenn dieses Tool keine Musterabgleiche unterstützt. + +{% endcapture %} + +{% include admonitions/note.html content=note-path-to-regexp %} + +{% capture query-string-note %} + +Query strings are not part of the route path. + +{% endcapture %} + +{% include admonitions/warning.html content=query-string-note %} + +### Route paths based on strings + +Dieser Weiterleitungspfad gleicht Weiterleitungsanforderungen zum Stammverzeichnis (`/`) ab. + +```js +app.get('/', (req, res) => { + res.send('root'); +}); +``` + +Dieser Weiterleitungspfad gleicht Anforderungen mit `/about` ab. + +```js +app.get('/about', (req, res) => { + res.send('about'); +}); +``` + +Dieser Weiterleitungspfad gleicht Anforderungen mit `/random.text` ab. + +```js +app.get('/random.text', (req, res) => { + res.send('random.text'); +}); +``` + +### Route paths based on string patterns + +{% capture caution-string-patterns %} The string patterns in Express 5 no longer work. Please refer to the [migration guide](/{{ page.lang }}/guide/migrating-5.html#path-syntax) for more information.{% endcapture %} + +{% include admonitions/caution.html content=caution-string-patterns %} + +Dieser Weiterleitungspfad gleicht `acd` und `abcd` ab. + +```js +app.get('/ab?cd', (req, res) => { + res.send('ab?cd'); +}); +``` + +Dies sind einige Beispiele für Weiterleitungspfade auf Basis von Zeichenfolgemustern. + +```js +app.get('/ab+cd', (req, res) => { + res.send('ab+cd'); +}); +``` + +Dies sind einige Beispiele für Weiterleitungspfade auf Basis von Zeichenfolgen. + +```js +app.get('/ab*cd', (req, res) => { + res.send('ab*cd'); +}); +``` + +Dieser Weiterleitungspfad gleicht `/abe` und `/abcde` ab. + +```js +app.get('/ab(cd)?e', (req, res) => { + res.send('ab(cd)?e'); +}); +``` + +### Route paths based on regular expressions + +Dieser Weiterleitungspfad gleicht alle Weiterleitungsnamen ab, die den Buchstaben "a" enthalten. + +```js +app.get(/a/, (req, res) => { + res.send('/a/'); +}); +``` + +Dieser Weiterleitungspfad gleicht `butterfly` und `dragonfly`, jedoch nicht `butterflyman`, `dragonfly man` usw. + +```js +app.get(/.*fly$/, (req, res) => { + res.send('/.*fly$/'); +}); +``` + +

    Route parameters

    + +Route parameters are named URL segments that are used to capture the values specified at their position in the URL. The captured values are populated in the `req.params` object, with the name of the route parameter specified in the path as their respective keys. + +``` +Route path: /users/:userId/books/:bookId +Request URL: http://localhost:3000/users/34/books/8989 +req.params: { "userId": "34", "bookId": "8989" } +``` + +To define routes with route parameters, simply specify the route parameters in the path of the route as shown below. + +```js +app.get('/users/:userId/books/:bookId', (req, res) => { + res.send(req.params); +}); +``` + +
    +The name of route parameters must be made up of "word characters" ([A-Za-z0-9_]). +
    + +Since the hyphen (`-`) and the dot (`.`) are interpreted literally, they can be used along with route parameters for useful purposes. + +``` +Route path: /flights/:from-:to +Request URL: http://localhost:3000/flights/LAX-SFO +req.params: { "from": "LAX", "to": "SFO" } +``` + +``` +Route path: /plantae/:genus.:species +Request URL: http://localhost:3000/plantae/Prunus.persica +req.params: { "genus": "Prunus", "species": "persica" } +``` + +{% capture warning-regexp %} +In express 5, Regexp characters are not supported in route paths, for more information please refer to the [migration guide](/{{ page.lang }}/guide/migrating-5.html#path-syntax).{% endcapture %} + +{% include admonitions/caution.html content=warning-regexp %} + +To have more control over the exact string that can be matched by a route parameter, you can append a regular expression in parentheses (`()`): + +``` +Route path: /user/:userId(\d+) +Request URL: http://localhost:3000/user/42 +req.params: {"userId": "42"} +``` + +{% capture escape-advisory %} + +Because the regular expression is usually part of a literal string, be sure to escape any `\` characters with an additional backslash, for example `\\d+`. + +{% endcapture %} + +{% include admonitions/warning.html content=escape-advisory %} + +{% capture warning-version %} + +In Express 4.x, the `*` character in regular expressions is not interpreted in the usual way. As a workaround, use `{0,}` instead of `*`. This will likely be fixed in Express 5. + +{% endcapture %} + +{% include admonitions/warning.html content=warning-version %} + +

    Routenhandler (Weiterleitungsroutinen)

    + +Sie können mehrere Callback-Funktionen angeben, die sich wie [Middleware](/{{ page.lang }}/guide/using-middleware.html) verhalten, um eine Anforderung zu verarbeiten. Die einzige Ausnahme hierbei ist, dass diese Callbacks möglicherweise `next('route')` aufrufen, um die verbleibenden Weiterleitungs-Callbacks zu umgehen. Mit diesem Verfahren können Sie Vorabbedingungen für eine Weiterleitung festlegen und dann die Steuerung an nachfolgende Weiterleitungen übergeben, wenn kein Grund vorliegt, mit der aktuellen Weiterleitung fortzufahren. + +```js +app.get('/user/:id', (req, res, next) => { + if (req.params.id === '0') { + return next('route'); + } + res.send(`User ${req.params.id}`); +}); + +app.get('/user/:id', (req, res) => { + res.send('Special handler for user ID 0'); +}); +``` + +In this example: + +- `GET /user/5` → handled by first route → sends "User 5" +- `GET /user/0` → first route calls `next('route')`, skipping to the next matching `/user/:id` route + +Routenhandler können eine Funktion und/oder ein Funktionsarray sein, wie in den folgenden Beispielen zu sehen ist. + +Eine einzelne Callback-Funktion kann eine Weiterleitung verarbeiten. Beispiel: + +```js +app.get('/example/a', (req, res) => { + res.send('Hello from A!'); +}); +``` + +Mehrere Callback-Funktionen können eine Weiterleitung verarbeiten (achten Sie darauf, dass Sie das Objekt `next` angeben). Beispiel: + +```js +app.get( + '/example/b', + (req, res, next) => { + console.log('the response will be sent by the next function ...'); + next(); + }, + (req, res) => { + res.send('Hello from B!'); + } +); +``` + +Ein Array von Callback-Funktionen kann eine Weiterleitung verarbeiten. Beispiel: + +```js +const cb0 = function (req, res, next) { + console.log('CB0'); + next(); +}; + +const cb1 = function (req, res, next) { + console.log('CB1'); + next(); +}; + +const cb2 = function (req, res) { + res.send('Hello from C!'); +}; + +app.get('/example/c', [cb0, cb1, cb2]); +``` + +Eine Kombination aus unabhängigen Funktionen und Funktionsarrays kann eine Weiterleitung verarbeiten. Beispiel: + +```js +const cb0 = function (req, res, next) { + console.log('CB0'); + next(); +}; + +const cb1 = function (req, res, next) { + console.log('CB1'); + next(); +}; + +app.get( + '/example/d', + [cb0, cb1], + (req, res, next) => { + console.log('the response will be sent by the next function ...'); + next(); + }, + (req, res) => { + res.send('Hello from D!'); + } +); +``` + +

    Antwortmethoden

    + +Über die Methoden für das Antwortobjekt (`res`) in der folgenden Tabelle kann eine Antwort an den Client gesendet und der Anforderung/Antwort-Zyklus beendet werden. Wenn keine dieser Methoden über einen Routenhandler aufgerufen wird, bleibt die Clientanforderung im Status "blockiert". + +| Methode | Beschreibung | +| --------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | +| [res.download()](/{{ page.lang }}/4x/api.html#res.download) | Gibt eine Eingabeaufforderung zum Herunterladen einer Datei aus. | +| [res.end()](/{{ page.lang }}/4x/api.html#res.end) | End the response process. | +| [res.json()](/{{ page.lang }}/4x/api.html#res.json) | Sendet eine JSON-Antwort. | +| [res.jsonp()](/{{ page.lang }}/4x/api.html#res.jsonp) | Sendet eine JSON-Antwort mit JSONP-Unterstützung. | +| [res.redirect()](/{{ page.lang }}/4x/api.html#res.redirect) | Leitet eine Anforderung um. | +| [res.render()](/{{ page.lang }}/4x/api.html#res.render) | Render a view template. | +| [res.send()](/{{ page.lang }}/4x/api.html#res.send) | Sendet eine Antwort mit unterschiedlichen Typen. | +| [res.sendFile](/{{ page.lang }}/4x/api.html#res.sendFile) | Sendet eine Datei als Oktett-Stream. | +| [res.sendStatus()](/{{ page.lang }}/4x/api.html#res.sendStatus) | Legt den Antwortstatuscode fest und sendet dessen Zeichenfolgedarstellung als Antworthauptteil. | + +

    app.route()

    + +Sie können mithilfe von `app.route()` verkettbare Routenhandler für einen Weiterleitungspfad erstellen. +Da der Pfad an einer einzelnen Position angegeben wird, ist das Erstellen modularer Weiterleitungen hilfreich, da Redundanzen und Schreibfehler reduziert werden. Weitere Informationen zu Weiterleitungen finden Sie in der Dokumentation zu [Router()](/{{ page.lang }}/4x/api.html#router). + +Dies ist ein Beispiel für verkettete Routenhandler, die mit der Funktion `app.route()` definiert werden. + +```js +app + .route('/book') + .get((req, res) => { + res.send('Get a random book'); + }) + .post((req, res) => { + res.send('Add a book'); + }) + .put((req, res) => { + res.send('Update the book'); + }); +``` + +

    express.Router

    + +Mit der Klasse `express.Router` lassen sich modular einbindbare Routenhandler erstellen. Eine `Router`-Instanz ist ein vollständiges Middleware- und Routingsystem. Aus diesem Grund wird diese Instanz oft auch als "Mini-App" bezeichnet. + +Im folgenden Beispiel wird ein Router als Modul erstellt, eine Middlewarefunktion in das Modul geladen, es werden Weiterleitungen definiert und das Modul letztendlich in einen Pfad in der Hauptanwendung eingebunden. + +Erstellen Sie eine Routerdatei namens `birds.js` mit dem folgenden Inhalt im Anwendungsverzeichnis: + +```js +const express = require('express'); +const router = express.Router(); + +// middleware that is specific to this router +const timeLog = (req, res, next) => { + console.log('Time: ', Date.now()); + next(); +}; +router.use(timeLog); + +// define the home page route +router.get('/', (req, res) => { + res.send('Birds home page'); +}); +// define the about route +router.get('/about', (req, res) => { + res.send('About birds'); +}); + +module.exports = router; +``` + +Laden Sie dann das Routermodul in die Anwendung: + +```js +const birds = require('./birds'); + +// ... + +app.use('/birds', birds); +``` + +Die Anwendung kann nun Anforderungen an die Pfade `/birds` und `/birds/about` bearbeiten und ruft die Middlewarefunktion `timeLog` auf, die speziell für diese Weiterleitung bestimmt ist. + +But if the parent route `/birds` has path parameters, it will not be accessible by default from the sub-routes. To make it accessible, you will need to pass the `mergeParams` option to the Router constructor [reference](/{{ page.lang }}/5x/api.html#app.use). + +```js +const router = express.Router({ mergeParams: true }); +``` diff --git a/astro/src/content/docs/de/4x/guide/using-middleware.md b/astro/src/content/docs/de/4x/guide/using-middleware.md new file mode 100644 index 0000000000..5a5ccae0ba --- /dev/null +++ b/astro/src/content/docs/de/4x/guide/using-middleware.md @@ -0,0 +1,293 @@ +--- +title: Express-Middleware verwenden +description: Learn how to use middleware in Express.js applications, including application-level and router-level middleware, error handling, and integrating third-party middleware. +--- + +# Middleware verwenden + +Express ist ein Weiterleitungs- und Middleware-Web-Framework, das selbst nur minimale Funktionalität aufweist: Eine Express-Anwendung besteht im Wesentlichen aus einer Reihe von Middlewarefunktionsaufrufen. + +_Middleware_ functions are functions that have access to the [request object](/{{ page.lang }}/5x/api.html#req) (`req`), the [response object](/{{ page.lang }}/5x/api.html#res) (`res`), and the next middleware function in the application's request-response cycle. Die nächste Middlewarefunktion wird im Allgemeinen durch die Variable `next` bezeichnet. + +Über Middlewarefunktionen lassen sich die folgenden Tasks ausführen: + +- Ausführen von Code +- Vornehmen von Änderungen an der Anforderung und an Antwortobjekten +- End the request-response cycle. +- Aufrufen der nächsten Middlewarefunktion im Stack + +Wenn über die aktuelle Middlewarefunktion der Anforderung/Antwort-Zyklus nicht beendet werden kann, muss `next()` aufgerufen werden, um die Steuerung an die nächste Middlewarefunktion zu übergeben. Andernfalls geht die Anforderung in den Status "Blockiert" über. + +Eine Express-Anwendung kann die folgenden Middlewaretypen verwenden: + +- [Middleware auf Anwendungsebene](#middleware.application) +- [Middleware auf Routerebene](#middleware.router) +- [Middleware für die Fehlerbehandlung](#middleware.error-handling) +- [Integrierte Middleware](#middleware.built-in) +- [Middleware anderer Anbieter](#middleware.third-party) + +Sie können Middleware auf Anwendungsebene und Routerebene mit einem optionalen Mountpfad laden. +Sie können auch eine Reihe von Middlewarefunktionen zusammen laden. Dadurch wird ein Sub-Stack des Middlewaresystems am Mountpunkt erstellt. + +

    Middleware auf Anwendungsebene

    + +Bind application-level middleware to an instance of the [app object](/{{ page.lang }}/5x/api.html#app) by using the `app.use()` and `app.METHOD()` functions, where `METHOD` is the HTTP method of the request that the middleware function handles (such as GET, PUT, or POST) in lowercase. + +Dieses Beispiel zeigt eine Middlewarefunktion ohne Mountpfad. Die Funktion wird immer dann ausgeführt, wenn die Anwendung eine Anforderung erhält. + +```js +const express = require('express'); +const app = express(); + +app.use((req, res, next) => { + console.log('Time:', Date.now()); + next(); +}); +``` + +Dieses Beispiel zeigt eine Middlewarefunktion mit dem Mountpfad `/user/:id`. Die Funktion wird für jede Art von HTTP-Anforderung auf dem Pfad `/user/:id` ausgeführt. + +```js +app.use('/user/:id', (req, res, next) => { + console.log('Request Type:', req.method); + next(); +}); +``` + +Dieses Beispiel zeigt eine Weiterleitung und deren Handlerfunktion (Middlewaresystem). Die Funktion verarbeitet GET-Anforderungen zum Pfad `/user/:id`. + +```js +app.get('/user/:id', (req, res, next) => { + res.send('USER'); +}); +``` + +Dies ist ein Beispiel zum Laden einer Reihe von Middlewarefunktionen an einem Mountpunkt mit einem Mountpfad. +Das Beispiel veranschaulicht einen Middleware-Stack, über den Anforderungsinformationen zu einer HTTP-Anforderung zum Pfad `/user/:id` ausgegeben werden. + +```js +app.use( + '/user/:id', + (req, res, next) => { + console.log('Request URL:', req.originalUrl); + next(); + }, + (req, res, next) => { + console.log('Request Type:', req.method); + next(); + } +); +``` + +Mit einem Routenhandler können Sie mehrere Weiterleitungen für einen Pfad definieren. Im folgenden Beispiel werden zwei Weiterleitungen für GET-Anforderungen zum Pfad `/user/:id` definiert. Die zweite Weiterleitung verursacht zwar keine Probleme, wird jedoch nie aufgerufen, da durch die erste Weiterleitung der Anforderung/Antwort-Zyklus beendet wird. + +Dieses Beispiel zeigt einen Middleware-Sub-Stack, über den GET-Anforderungen zum Pfad `/user/:id` verarbeitet werden. + +```js +app.get( + '/user/:id', + (req, res, next) => { + console.log('ID:', req.params.id); + next(); + }, + (req, res, next) => { + res.send('User Info'); + } +); + +// handler for the /user/:id path, which prints the user ID +app.get('/user/:id', (req, res, next) => { + res.send(req.params.id); +}); +``` + +Wenn Sie den Rest der Middlewarefunktionen eines Weiterleitungs-Middleware-Stack überspringen wollen, rufen Sie `next('route')` auf, um die Steuerung an die nächste Weiterleitung zu übergeben. + +{% capture next-function %} + +`next('route')` will work only in middleware functions that were loaded by using the `app.METHOD()` or `router.METHOD()` functions. + +{% endcapture %} + +{% include admonitions/note.html content=next-function %} + +Dieses Beispiel zeigt einen Middleware-Sub-Stack, über den GET-Anforderungen zum Pfad `/user/:id` verarbeitet werden. + +```js +app.get( + '/user/:id', + (req, res, next) => { + // if the user ID is 0, skip to the next route + if (req.params.id === '0') next('route'); + // otherwise pass the control to the next middleware function in this stack + else next(); + }, + (req, res, next) => { + // send a regular response + res.send('regular'); + } +); + +// handler for the /user/:id path, which sends a special response +app.get('/user/:id', (req, res, next) => { + res.send('special'); +}); +``` + +Middleware can also be declared in an array for reusability. + +Dies ist ein Beispiel zur Verwendung der Middlewarefunktion `express.static` mit einem ausführlich dargestellten Optionsobjekt: + +```js +function logOriginalUrl(req, res, next) { + console.log('Request URL:', req.originalUrl); + next(); +} + +function logMethod(req, res, next) { + console.log('Request Type:', req.method); + next(); +} + +const logStuff = [logOriginalUrl, logMethod]; +app.get('/user/:id', logStuff, (req, res, next) => { + res.send('User Info'); +}); +``` + +

    Middleware auf Routerebene

    + +Middleware auf Routerebene funktioniert in der gleichen Weise wie Middleware auf Anwendungsebene, mit dem einzigen Unterschied, dass sie an eine Instanz von `express.Router()` gebunden ist. + +```js +const router = express.Router(); +``` + +Laden Sie Middleware auf Routerebene über die Funktionen `router.use()` und `router.METHOD()`. + +Der folgende Beispielcode repliziert das Middlewaresystem, das oben für die Middleware auf Anwendungsebene gezeigt wird, durch Verwendung von Middleware auf Routerebene. + +```js +const express = require('express'); +const app = express(); +const router = express.Router(); + +// a middleware function with no mount path. This code is executed for every request to the router +router.use((req, res, next) => { + console.log('Time:', Date.now()); + next(); +}); + +// a middleware sub-stack shows request info for any type of HTTP request to the /user/:id path +router.use( + '/user/:id', + (req, res, next) => { + console.log('Request URL:', req.originalUrl); + next(); + }, + (req, res, next) => { + console.log('Request Type:', req.method); + next(); + } +); + +// a middleware sub-stack that handles GET requests to the /user/:id path +router.get( + '/user/:id', + (req, res, next) => { + // if the user ID is 0, skip to the next router + if (req.params.id === '0') next('route'); + // otherwise pass control to the next middleware function in this stack + else next(); + }, + (req, res, next) => { + // render a regular page + res.render('regular'); + } +); + +// handler for the /user/:id path, which renders a special page +router.get('/user/:id', (req, res, next) => { + console.log(req.params.id); + res.render('special'); +}); + +// mount the router on the app +app.use('/', router); +``` + +To skip the rest of the router's middleware functions, call `next('router')` +to pass control back out of the router instance. + +Dieses Beispiel zeigt einen Middleware-Sub-Stack, über den GET-Anforderungen zum Pfad `/user/:id` verarbeitet werden. + +```js +const express = require('express'); +const app = express(); +const router = express.Router(); + +// predicate the router with a check and bail out when needed +router.use((req, res, next) => { + if (!req.headers['x-auth']) return next('router'); + next(); +}); + +router.get('/user/:id', (req, res) => { + res.send('hello, user!'); +}); + +// use the router and 401 anything falling through +app.use('/admin', router, (req, res) => { + res.sendStatus(401); +}); +``` + +

    Middleware für die Fehlerbehandlung

    + +
    +Middleware für die Fehlerbehandlung benötigt immer *vier* Argumente. Sie müssen vier Argumente angeben, um die Erkennung als Middlewarefunktion für die Fehlerbehandlung zu ermöglichen. Selbst wenn das Objekt `next` nicht verwenden müssen, müssen Sie dies angeben, um die Signatur beizubehalten. Andernfalls wird das Objekt `next` als reguläre Middleware interpretiert, sodass keine Fehlerbehandlung möglich ist. +
    + +Middlewarefunktionen für die Fehlerbehandlung werden in derselben Weise definiert wie andere Middlewarefunktionen, außer dass Fehlerbehandlungsfunktionen speziell bei Signaturen vier anstatt drei Argumente aufweisen `(err, req, res, next)`: + +```js +app.use((err, req, res, next) => { + console.error(err.stack); + res.status(500).send('Something broke!'); +}); +``` + +Details zu Middleware für die Fehlerbehandlung siehe [Fehlerbehandlung](/{{ page.lang }}/guide/error-handling.html). + +

    Integrierte Middleware

    + +Seit Version 4.x bestehen bei Express keine Abhängigkeiten zu [Connect](https://github.com/senchalabs/connect) mehr. Mit Ausnahme von `express.static` befinden sich nun alle Middlewarefunktionen, die bisher in Express enthalten waren, in separaten Modulen. Sehen Sie sich hierzu auch die [Liste der Middlewarefunktionen](https://github.com/senchalabs/connect#middleware) an. + +Die einzige integrierte Middlewarefunktion in Express ist `express.static`. + +- [express.static](/en/5x/api.html#express.static) serves static assets such as HTML files, images, and so on. +- [express.json](/en/5x/api.html#express.json) parses incoming requests with JSON payloads. **NOTE: Available with Express 4.16.0+** +- [express.urlencoded](/en/5x/api.html#express.urlencoded) parses incoming requests with URL-encoded payloads. **NOTE: Available with Express 4.16.0+** + +

    Middleware anderer Anbieter

    + +Mit Middleware anderer Anbieter können Sie Express-Anwendungen um neue Funktionalität erweitern. + +Installieren Sie das Modul Node.js für die erforderliche Funktionalität. Laden Sie das Modul dann in Ihre Anwendung auf Anwendungsebene oder auf Routerebene. + +Das folgende Beispiel veranschaulicht das Installieren und Laden der Middlewarefunktion `cookie-parser` für das Cookie-Parsing. + +```bash +$ npm install cookie-parser +``` + +```js +const express = require('express'); +const app = express(); +const cookieParser = require('cookie-parser'); + +// load the cookie-parsing middleware +app.use(cookieParser()); +``` + +Eine nicht vollständige Liste zu den Middlewarefunktionen anderer Anbieter, die im Allgemeinen mit Express verwendet werden, finden Sie unter [Middleware anderer Anbieter](../resources/middleware.html). diff --git a/astro/src/content/docs/de/4x/guide/using-template-engines.md b/astro/src/content/docs/de/4x/guide/using-template-engines.md new file mode 100644 index 0000000000..d9423933d3 --- /dev/null +++ b/astro/src/content/docs/de/4x/guide/using-template-engines.md @@ -0,0 +1,58 @@ +--- +title: Template-Engines in Express verwenden +description: Discover how to integrate and use template engines like Pug, Handlebars, and EJS with Express.js to render dynamic HTML pages efficiently. +--- + +# Template-Engines in Express verwenden + +A _template engine_ enables you to use static template files in your application. At runtime, the template engine replaces +variables in a template file with actual values, and transforms the template into an HTML file sent to the client. +This approach makes it easier to design an HTML page. + +The [Express application generator](/{{ page.lang }}/starter/generator.html) uses [Pug](https://pugjs.org/api/getting-started.html) as its default, but it also supports [Handlebars](https://www.npmjs.com/package/handlebars), and [EJS](https://www.npmjs.com/package/ejs), among others. + +To render template files, set the following [application setting properties](/{{ page.lang }}/4x/api.html#app.set), in the default `app.js` created by the generator: + +- `views`, das Verzeichnis, in dem sich die Vorlagendateien befinden. Beispiel: `app.set('views', './views')` + This defaults to the `views` directory in the application root directory. +- `view engine`, die zu verwendende Template-Engine. Beispiel: `app.set('view engine', 'pug')` + +Installieren Sie dann das entsprechende npm-Paket für die Template-Engine: + +```bash +$ npm install pug --save +``` + +
    Express-konforme Template-Engines wie Pug exportieren eine Funktion namens `__express(filePath, options, callback)`, die über die Funktion `res.render()` aufgerufen wird, um den Vorlagencode ausgeben zu können. + +Einige Template-Engines folgen dieser Konvention nicht. Die Bibliothek [Consolidate.js](https://www.npmjs.org/package/consolidate) folgt dieser Konvention, indem alle gängigen Node.js-Template-Engines zugeordnet werden. Daher ist eine reibungslose Funktion in Express gewährleistet. + +
    + +Nach der Festlegung der View-Engine muss die Engine nicht angegeben oder das Template-Engine-Modul nicht in Ihre Anwendung geladen werden. Express lädt das Modul intern (wie unten für das obige Beispiel gezeigt). + +```js +app.set('view engine', 'pug'); +``` + +Erstellen Sie eine Pug-Vorlagendatei namens `index.pug` im Verzeichnis `views` mit dem folgenden Inhalt: + +```pug +html + head + title= title + body + h1= message +``` + +Dann erstellen Sie eine Weiterleitung, um die Datei `index.pug` auszugeben. Wenn die Eigenschaft `view engine` nicht festgelegt wurde, müssen Sie die Erweiterung der Datei `view` angeben. Andernfalls müssen Sie diese Erweiterung nicht angeben. + +```js +app.get('/', (req, res) => { + res.render('index', { title: 'Hey', message: 'Hello there!' }); +}); +``` + +Wenn Sie eine Anforderung zur Homepage ausführen, wird die Datei `index.pug` im HTML-Format ausgegeben. + +The view engine cache does not cache the contents of the template's output, only the underlying template itself. The view is still re-rendered with every request even when the cache is on. diff --git a/astro/src/content/docs/de/4x/guide/writing-middleware.md b/astro/src/content/docs/de/4x/guide/writing-middleware.md new file mode 100644 index 0000000000..bde6d0e8de --- /dev/null +++ b/astro/src/content/docs/de/4x/guide/writing-middleware.md @@ -0,0 +1,217 @@ +--- +title: Middleware für die Verwendung in Express-Anwendungen schreiben +description: Learn how to write custom middleware functions for Express.js applications, including examples and best practices for enhancing request and response handling. +--- + +# Middleware für die Verwendung in Express-Anwendungen schreiben + +

    Überblick

    + +_Middleware_ functions are functions that have access to the [request object](/{{ page.lang }}/5x/api.html#req) (`req`), the [response object](/{{ page.lang }}/5x/api.html#res) (`res`), and the `next` function in the application's request-response cycle. Die nächste Middlewarefunktion wird im Allgemeinen durch die Variable `next` bezeichnet. + +Über Middlewarefunktionen lassen sich die folgenden Tasks ausführen: + +- Ausführen von Code +- Vornehmen von Änderungen an der Anforderung und an Antwortobjekten +- End the request-response cycle. +- Aufrufen der nächsten Middleware im Stack + +Wenn über die aktuelle Middlewarefunktion der Anforderung/Antwort-Zyklus nicht beendet werden kann, muss `next()` aufgerufen werden, um die Steuerung an die nächste Middlewarefunktion zu übergeben. Andernfalls geht die Anforderung in den Status "Blockiert" über. + +Das folgende Beispiel zeigt die Elemente eines Middlewarefunktionsaufrufs: + +
    + + + + +
    Pfad (Weiterleitung), für den die Middlewarefunktion angewendet wird.
    + +
    Die Middlewarefunktion.
    + +
    Callback-Argument zur Middlewarefunktion, die nach der geltenden Konvention als "next" bezeichnet wird.
    + +
    HTTP response argument to the middleware function, called "res" by convention.
    + +
    HTTP request argument to the middleware function, called "req" by convention.
    + +
    +Elements of a middleware function call + +
    HTTP-Methode, für die die Middlewarefunktion angewendet wird.
    +
    + +Starting with Express 5, middleware functions that return a Promise will call `next(value)` when they reject or throw an error. `next` will be called with either the rejected value or the thrown Error. + +

    Beispiel

    + +Here is an example of a simple "Hello World" Express application. +The remainder of this article will define and add three middleware functions to the application: +one called `myLogger` that prints a simple log message, one called `requestTime` that +displays the timestamp of the HTTP request, and one called `validateCookies` that validates incoming cookies. + +```js +const express = require('express'); +const app = express(); + +app.get('/', (req, res) => { + res.send('Hello World!'); +}); + +app.listen(3000); +``` + +

    Dies ist ein Beispiel einer einfachen Express-Anwendung namens "Hello World", für die Sie zwei Middlewarefunktionen definieren:

    +Dies ist ein einfaches Beispiel einer Middlewarefunktion namens "myLogger". Diese Funktion gibt lediglich "LOGGED" aus, wenn eine Anforderung zur Anwendung über diese Funktion läuft. Die Middlewarefunktion ist der Variablen `myLogger` zugeordnet. + +```js +const myLogger = function (req, res, next) { + console.log('LOGGED'); + next(); +}; +``` + +
    +Beachten Sie den Aufruf oben zu `next()`. Durch den Aufruf dieser Funktion wird die nächste Middlewarefunktion in der Anwendung aufgerufen. +Die Funktion `next()` ist nicht Teil der Node.js- oder Express-API, sondern das dritte Argument, das an die Middlewarefunktion übergeben wird. Die Funktion `next()` kann jeden beliebigen Namen haben, per Konvention erhält sie jedoch immer den Namen "next". +Um Unklarheiten zu vermeiden, sollten Sie immer diese Konvention verwenden. +
    + +Zum Laden der Middlewarefunktion rufen Sie `app.use()` auf und geben die Middlewarefunktion an. +Beispiel: Durch den folgenden Code wird die Middlewarefunktion `myLogger` vor der Weiterleitung zum Stammverzeichnispfad (/) geladen. + +```js +const express = require('express'); +const app = express(); + +const myLogger = function (req, res, next) { + console.log('LOGGED'); + next(); +}; + +app.use(myLogger); + +app.get('/', (req, res) => { + res.send('Hello World!'); +}); + +app.listen(3000); +``` + +Sobald die Anwendung eine Anforderung erhält, gibt sie die Nachricht "LOGGED" an das Terminal aus. + +Die Reihenfolge beim Laden der Middleware ist wichtig: Middlewarefunktionen, die zuerst geladen werden, werden auch zuerst ausgeführt. + +Wenn `myLogger` nach der Weiterleitung zum Stammverzeichnispfad geladen wird, erreicht die Weiterleitung die Middlewarefunktion nicht. Die Anwendung gibt "LOGGED" nicht aus, weil der Routenhandler für den Stammverzeichnispfad den Anforderung/Antwort-Zyklus beendet. + +Die Middlewarefunktion `myLogger` gibt einfach eine Nachricht aus und übergibt dann die Anforderung zur nächsten Middlewarefunktion im Stack durch Aufruf der Funktion `next()`. + +

    Middleware function requestTime

    + +Im nächsten Beispiel wird die Eigenschaft `requestTime` zum Anforderungsobjekt hinzugefügt. Diese Middlewarefunktion erhält den Namen "requestTime". + +```js +const requestTime = function (req, res, next) { + req.requestTime = Date.now(); + next(); +}; +``` + +Die Anwendung verwendet nun die Middlewarefunktion `requestTime`. Außerdem verwendet die Callback-Funktion der Weiterleitung zum Stammverzeichnispfad die Eigenschaft, die die Middlewarefunktion zu `req` (dem Anforderungsobjekt) hinzufügt. + +```js +const express = require('express'); +const app = express(); + +const requestTime = function (req, res, next) { + req.requestTime = Date.now(); + next(); +}; + +app.use(requestTime); + +app.get('/', (req, res) => { + let responseText = 'Hello World!
    '; + responseText += `Requested at: ${req.requestTime}`; + res.send(responseText); +}); + +app.listen(3000); +``` + +Wenn Sie eine Anforderung zum Stammverzeichnis der Anwendung einleiten, zeigt die Anwendung nun die Zeitmarke Ihrer Anforderung im Browser an. + +

    Middleware function validateCookies

    + +Finally, we'll create a middleware function that validates incoming cookies and sends a 400 response if cookies are invalid. + +Here's an example function that validates cookies with an external async service. + +```js +async function cookieValidator(cookies) { + try { + await externallyValidateCookie(cookies.testCookie); + } catch { + throw new Error('Invalid cookies'); + } +} +``` + +Here, we use the [`cookie-parser`](/resources/middleware/cookie-parser.html) middleware to parse incoming cookies off the `req` object and pass them to our `cookieValidator` function. The `validateCookies` middleware returns a Promise that upon rejection will automatically trigger our error handler. + +```js +const express = require('express'); +const cookieParser = require('cookie-parser'); +const cookieValidator = require('./cookieValidator'); + +const app = express(); + +async function validateCookies(req, res, next) { + await cookieValidator(req.cookies); + next(); +} + +app.use(cookieParser()); + +app.use(validateCookies); + +// error handler +app.use((err, req, res, next) => { + res.status(400).send(err.message); +}); + +app.listen(3000); +``` + +
    +Note how `next()` is called after `await cookieValidator(req.cookies)`. This ensures that if `cookieValidator` resolves, the next middleware in the stack will get called. If you pass anything to the `next()` function (except the string `'route'` or `'router'`), Express regards the current request as being an error and will skip any remaining non-error handling routing and middleware functions. +
    + +Da Sie Zugriff auf das Anforderungsobjekt, das Antwortobjekt, die nächste Middlewarefunktion im Stack und die gesamte Node.js-API haben, sind die Möglichkeiten, die Sie mit Middlewarefunktionen haben, nahezu unendlich. + +Weitere Informationen zur Verwendung von Middleware in Express siehe [ Express-Middleware verwenden](/{{ page.lang }}/guide/using-middleware.html). + +

    Configurable middleware

    + +If you need your middleware to be configurable, export a function which accepts an options object or other parameters, which, then returns the middleware implementation based on the input parameters. + +File: `my-middleware.js` + +```js +module.exports = function (options) { + return function (req, res, next) { + // Implement the middleware function based on the options object + next(); + }; +}; +``` + +The middleware can now be used as shown below. + +```js +const mw = require('./my-middleware.js'); + +app.use(mw({ option1: '1', option2: '2' })); +``` + +Refer to [cookie-session](https://github.com/expressjs/cookie-session) and [compression](https://github.com/expressjs/compression) for examples of configurable middleware. diff --git a/astro/src/content/docs/de/4x/starter/basic-routing.md b/astro/src/content/docs/de/4x/starter/basic-routing.md new file mode 100644 index 0000000000..9742de59b7 --- /dev/null +++ b/astro/src/content/docs/de/4x/starter/basic-routing.md @@ -0,0 +1,63 @@ +--- +title: Basisrouting in Express +description: Learn the fundamentals of routing in Express.js applications, including how to define routes, handle HTTP methods, and create route handlers for your web server. +--- + +# Basisrouting + +Per _Routing_ wird bestimmt, wie eine Antwort auf eine Clientanforderung an einem bestimmten Endpunkt antwortet. Dies ist eine URI (oder ein Pfad) und eine bestimmte HTTP-Anforderungsmethode (GET, POST usw.). + +Jede Weiterleitung (Route) kann eine oder mehrere Handlerfunktionen haben, die ausgeführt werden, wenn die Weiterleitung abgeglichen wird. + +Weiterleitungsdefinitionen haben die folgende Struktur: + +```js +app.METHOD(PATH, HANDLER); +``` + +Where: + +- `app` ist eine Instanz von `express`. +- `METHOD` is an [HTTP request method](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Methods), in lowercase. +- `PATH` ist ein Pfad auf dem Server. +- `HANDLER` ist die Funktion, die ausgeführt wird, wenn die Weiterleitung abgeglichen wird. + +
    +In diesem Lernprogramm wird vorausgesetzt, dass eine Instanz von `express` namens `app` erstellt und der Server ausgeführt wird. Wenn Sie mit dem Erstellen und Starten von Anwendungen nicht vertraut sind, spielen Sie das [Beispiel "Hello World"](/{{ page.lang }}/starter/hello-world.html) durch. +
    + +Die folgenden Beispiele veranschaulichen das Definieren einfacher Weiterleitungen. + +Antworten Sie mit `Hello World!` auf der Homepage: + +```js +app.get('/', (req, res) => { + res.send('Hello World!'); +}); +``` + +Respond to a POST request on the root route (`/`), the application's home page: + +```js +app.post('/', (req, res) => { + res.send('Got a POST request'); +}); +``` + +Antworten Sie auf eine PUT-Anforderung zur Weiterleitung `/user`: + +```js +app.put('/user', (req, res) => { + res.send('Got a PUT request at /user'); +}); +``` + +Antworten Sie auf eine DELETE-Anforderung zur Weiterleitung `/user`: + +```js +app.delete('/user', (req, res) => { + res.send('Got a DELETE request at /user'); +}); +``` + +Details zum Thema Routing finden Sie in der entsprechenden [Routinganleitung](/{{ page.lang }}/guide/routing.html). diff --git a/astro/src/content/docs/de/4x/starter/examples.md b/astro/src/content/docs/de/4x/starter/examples.md new file mode 100644 index 0000000000..a25a6d9834 --- /dev/null +++ b/astro/src/content/docs/de/4x/starter/examples.md @@ -0,0 +1,16 @@ +--- +title: Express examples +description: Explore a collection of Express.js application examples covering various use cases, integrations, and advanced configurations to help you learn and build your projects. +--- + +{% capture examples %}{% include readmes/express-master/examples.md %}{% endcapture %} +{{ examples | replace: "](.", "](https://github.com/expressjs/express/tree/master/examples" }} + +## Additional examples + +These are some additional examples with more extensive integrations. + +{% include community-caveat.html %} + +- [prisma-fullstack](https://github.com/prisma/prisma-examples/tree/latest/pulse/fullstack-simple-chat) - Fullstack app with Express and Next.js using [Prisma](https://www.npmjs.com/package/prisma) as an ORM +- [prisma-rest-api-ts](https://github.com/prisma/prisma-examples/tree/latest/orm/express) - REST API with Express in TypeScript using [Prisma](https://www.npmjs.com/package/prisma) as an ORM diff --git a/astro/src/content/docs/de/4x/starter/faq.md b/astro/src/content/docs/de/4x/starter/faq.md new file mode 100644 index 0000000000..2f7dd8eff3 --- /dev/null +++ b/astro/src/content/docs/de/4x/starter/faq.md @@ -0,0 +1,75 @@ +--- +title: Häufig gestellte Fragen zu Express +description: Finden Sie Antworten auf häufig gestellte Fragen zu Express.js, darunter Themen wie Anwendungsstruktur, Models, Authentifizierung, Template-Engines, Fehlerbehandlung und mehr. +--- + +# Häufig gestellte Fragen + +## Wie muss ich meine Anwendung strukturieren? + +Auf diese Frage gibt es keine verbindliche Antwort. Die Antwort hängt vom Umfang Ihrer Anwendung und dem eingebundenen Team ab. Um so flexibel wie möglich zu sein, gibt es bei Express keine Voraussetzungen hinsichtlich der Struktur. + +Weiterleitungen und andere anwendungsspezifische Logik können in einer beliebigen Anzahl von Dateien und in jeder von Ihnen bevorzugten Verzeichnisstruktur vorkommen. Die folgenden Beispiele sollen als Entscheidungshilfe dienen: + +- [Weiterleitungslisten](https://github.com/expressjs/express/blob/4.13.1/examples/route-separation/index.js#L32-47) +- [Weiterleitungszuordnung](https://github.com/expressjs/express/blob/4.13.1/examples/route-map/index.js#L52-L66) +- [Controller im MVC-Stil](https://github.com/expressjs/express/tree/master/examples/mvc) + +Darüber hinaus gibt es Erweiterungen anderer Anbieter für Express, die zur Vereinfachung einiger dieser Muster beitragen: + +- [Weiterleitung mit "express-resource"](https://github.com/expressjs/express-resource) + +## Wie definiere ich Modelle? + +Express hat keine Vorstellungen von einer Datenbank. Dieses Konzept bleibt Node-Modulen anderer Anbieter überlassen, wodurch Schnittstellen zu allen Datenbank möglich sind. + +[LoopBack](http://loopback.io) zeigt ein Express-basiertes Framework, um das Modelle angeordnet sind. + +## Wie kann ich Benutzer authentifizieren? + +Die Authentifizierung ist ein weiterer meinungsstarker Bereich, in den Express nicht eingreift. Sie können ein Authentifizierungsschema nach Ihren Vorstellungen verwenden. +Ein einfaches Benutzername/Kennwort-Schema können Sie in [diesem Beispiel](https://github.com/expressjs/express/tree/master/examples/auth) sehen. + +## Welche Template-Engines unterstützt Express? + +Express unterstützt jede Template-Engine, die der `(path, locals, callback)`-Signatur entspricht. +Informationen zur Normalisierung von Template-Engine-Schnittstellen und -Caching siehe das Projekt [consolidate.js](https://github.com/visionmedia/consolidate.js). Nicht aufgelistete Template-Engines können trotzdem die Express-Signatur unterstützen. + +For more information, see [Using template engines with Express](/{{page.lang}}/guide/using-template-engines.html). + +## Wie handhabe ich 404-Antworten? + +In Express sind 404-Antworten nicht das Ergebnis eines Fehlers, sodass diese Antworten von der Fehlerbehandlungsroutine nicht erfasst werden. Dieses Verhalten ist damit zu erklären, dass eine 404-Antwort einfach angibt, dass keine weiteren Arbeiten auszuführen sind. In anderen Worten: Express hat alle Middlewarefunktionen und Weiterleitungen ausgeführt und festgestellt, dass keine Funktion eine Antwort zurückgegeben hat. Sie müssen also bei der Handhabung der 404-Antwort nur eine Middlewarefunktion am Ende des Stacks (unterhalb von allen anderen Funktionen) hinzufügen: + +```js +app.use((req, res, next) => { + res.status(404).send("Sorry can't find that!"); +}); +``` + +Add routes dynamically at runtime on an instance of `express.Router()` +so the routes are not superseded by a middleware function. + +## Wie richte ich eine Fehlerbehandlungsroutine ein? + +Middleware für die Fehlerbehandlung wird in derselben Weise definiert wie andere Middleware; außer dass sie vier anstatt drei Argumente aufweist. Dies gilt speziell bei der Signatur `(err, req, res, next)`: + +```js +app.use((err, req, res, next) => { + console.error(err.stack); + res.status(500).send('Something broke!'); +}); +``` + +Weitere Informationen siehe [Fehlerbehandlung](/{{ page.lang }}/guide/error-handling.html). + +## Wie gebe ich normales HTML-Format aus? + +Das ist nicht Ihre Aufgabe! Sie müssen kein HTML-Format mit der Funktion `res.render()` ausgeben. +Verwenden Sie die Funktion `res.sendFile()`, wenn Sie es mit einer bestimmten Datei zu tun haben. +Wenn Sie viele Assets aus einem Verzeichnis bedienen müssen, verwenden Sie die Middlewarefunktion `express.static()`. + +## Welche Version von Node.js benötigt Express? + +- [Express 4.x](/{{ page.lang }}/4x/api.html) requires Node.js 0.10 or higher. +- [Express 5.x](/{{ page.lang }}/5x/api.html) requires Node.js 18 or higher. diff --git a/astro/src/content/docs/de/4x/starter/generator.md b/astro/src/content/docs/de/4x/starter/generator.md new file mode 100644 index 0000000000..cf23c63154 --- /dev/null +++ b/astro/src/content/docs/de/4x/starter/generator.md @@ -0,0 +1,122 @@ +--- +title: Express-Anwendungsgenerator +description: Learn how to use the Express application generator tool to quickly create a skeleton for your Express.js applications, streamlining setup and configuration. +--- + +# Express-Anwendungsgenerator + +Mit dem Application Generator Tool `express` können Sie innerhalb kürzester Zeit ein Anwendungsgerüst erstellen. + +You can run the application generator with the `npx` command (available in Node.js 8.2.0). + +```bash +$ npx express-generator +``` + +For earlier Node versions, install the application generator as a global npm package and then launch it: + +```bash +$ npm install -g express-generator +$ express +``` + +Zeigen Sie die Befehlsoptionen mit der Option `-h` an: + +```bash +$ express -h + + Usage: express [options] [dir] + + Options: + + -h, --help output usage information + --version output the version number + -e, --ejs add ejs engine support + --hbs add handlebars engine support + --pug add pug engine support + -H, --hogan add hogan.js engine support + --no-view generate without view engine + -v, --view add view support (ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade) + -c, --css add stylesheet support (less|stylus|compass|sass) (defaults to plain css) + --git add .gitignore + -f, --force force on non-empty directory +``` + +Im folgenden Beispiel wird eine Express-Anwendung mit dem Namen _myapp_ im aktuellen Arbeitsverzeichnis erstellt: The app will be created in a folder named _myapp_ in the current working directory and the view engine will be set to Pug: + +```bash +$ express --view=pug myapp + + create : myapp + create : myapp/package.json + create : myapp/app.js + create : myapp/public + create : myapp/public/javascripts + create : myapp/public/images + create : myapp/routes + create : myapp/routes/index.js + create : myapp/routes/users.js + create : myapp/public/stylesheets + create : myapp/public/stylesheets/style.css + create : myapp/views + create : myapp/views/index.pug + create : myapp/views/layout.pug + create : myapp/views/error.pug + create : myapp/bin + create : myapp/bin/www +``` + +Installieren Sie dann Abhängigkeiten: + +```bash +$ cd myapp +$ npm install +``` + +Verwenden Sie unter Windows diesen Befehl: + +```bash +$ DEBUG=myapp:* npm start +``` + +Führen Sie unter MacOS oder Linux die Anwendung mit diesem Befehl aus: + +```bash +> set DEBUG=myapp:* & npm start +``` + +On Windows PowerShell, use this command: + +```bash +PS> $env:DEBUG='myapp:*'; npm start +``` + +Laden Sie dann `http://localhost:3000/` in Ihren Browser, um auf die Anwendung zuzugreifen. + +Die erstellte Anwendung hat die folgende Verzeichnisstruktur: + +```bash +. +├── app.js +├── bin +│ └── www +├── package.json +├── public +│ ├── images +│ ├── javascripts +│ └── stylesheets +│ └── style.css +├── routes +│ ├── index.js +│ └── users.js +└── views + ├── error.pug + ├── index.pug + └── layout.pug + +7 directories, 9 files +``` + +
    +Die vom Generator erstellte Anwendungsstruktur ist nur eine der vielen Möglichkeiten, Express-Anwendungen zu strukturieren. Sie können diese Struktur verwenden oder sie an Ihre Anforderungen anpassen. +
    diff --git a/astro/src/content/docs/de/4x/starter/hello-world.md b/astro/src/content/docs/de/4x/starter/hello-world.md new file mode 100644 index 0000000000..534ef7cd0a --- /dev/null +++ b/astro/src/content/docs/de/4x/starter/hello-world.md @@ -0,0 +1,42 @@ +--- +title: Beispiel "Hello World" in Express +description: Get started with Express.js by building a simple 'Hello World' application, demonstrating the basic setup and server creation for beginners. +--- + +# Beispiel "Hello World" + +
    +Dies ist wohl die einfachste Express-Anwendung, die Sie erstellen können. Es handelt sich um eine Anwendung mit nur einer Datei und — *nicht* das, was Sie mit dem [Express Generator](/{{ page.lang }}/starter/generator.html) erhalten würden. Mit dem Generator würde das Gerüst für eine vollständige Anwendung mit zahlreichen JavaScript-Dateien, Jade-Vorlagen und Unterverzeichnissen für verschiedene Zwecke erstellt werden. +
    + +```js +const express = require('express'); +const app = express(); +const port = 3000; + +app.get('/', (req, res) => { + res.send('Hello World!'); +}); + +app.listen(port, () => { + console.log(`Example app listening on port ${port}`); +}); +``` + +Die Anwendung startet einen Server und ist an Port 3000 empfangsbereit für Verbindungen. Die Anwendung antwortet mit "Hello World!" auf Anforderungen zur Stamm-URL (`/`) oder zu _route_. Bei jedem anderen Pfad lautet die Antwort **404 Not Found**. + +### Running Locally + +Erstellen Sie zunächst ein Verzeichnis namens `myapp`, wechseln Sie in das Verzeichnis und führen Sie `npm init` aus. Installieren Sie dann `express` als Abhängigkeit, wie im [Installationshandbuch](/{{ page.lang }}/starter/installing.html) beschrieben. + +Erstellen Sie im Verzeichnis `myapp` eine Datei namens `app.js` und fügen Sie den folgenden Code hinzu: + +
    `req` (Anforderung) und `res` (Antwort) sind genau dieselben Objekte, die Node bereitstellt. Sie können also `req.pipe()`, `req.on('data', callback)` und alle anderen Tasks, die Sie ausführen wollen, ohne Express ausführen.
    + +Führen Sie die Anwendung mit dem folgenden Befehl aus: + +```bash +$ node app.js +``` + +Laden Sie dann [http://localhost:3000/](http://localhost:3000/) in einen Browser, um die Ausgabe zu sehen. diff --git a/astro/src/content/docs/de/4x/starter/installing.md b/astro/src/content/docs/de/4x/starter/installing.md new file mode 100644 index 0000000000..8f8323f37d --- /dev/null +++ b/astro/src/content/docs/de/4x/starter/installing.md @@ -0,0 +1,48 @@ +--- +title: Express installieren +description: Erfahren Sie, wie Sie Express.js in Ihrer Node.js-Umgebung installieren, wie Sie Ihr Projektverzeichnis aufsetzen und Abhängigkeiten mit npm verwalten. +--- + +# Installation + +Angenommen, Sie haben [Node.js](https://nodejs.org/) bereits installiert. Erstellen Sie ein Verzeichnis für Ihre Anwendung und definieren Sie dieses Verzeichnis als Ihr Arbeitsverzeichnis. + +- [Express 4.x](/{{ page.lang }}/4x/api.html) requires Node.js 0.10 or higher. +- [Express 5.x](/{{ page.lang }}/5x/api.html) requires Node.js 18 or higher. + +```bash +$ mkdir myapp +$ cd myapp +``` + +Erstellen Sie mit dem Befehl `npm init` eine Datei namens `package.json` für Ihre Anwendung. +Weitere Informationen zur Funktionsweise von `package.json` finden Sie in den [Angaben zur Handhabung der npm-Datei package.json](https://docs.npmjs.com/files/package.json). + +```bash +$ npm init +``` + +Dieser Befehl fordert Sie zur Eingabe verschiedener Angaben wie Name und Version Ihrer Anwendung auf. +For now, you can simply hit RETURN to accept the defaults for most of them, with the following exception: + +``` +entry point: (index.js) +``` + +Geben Sie `app.js` oder einen Namen Ihrer Vorstellung als Namen für die Hauptdatei ein. Wenn dieser Name `index.js` lauten soll, drücken Sie die Eingabetaste, um den vorgeschlagenen Standarddateinamen zu akzeptieren. + +Installieren Sie jetzt Express im Verzeichnis `myapp` und speichern Sie es in der Abhängigkeitsliste. Beispiel: + +```bash +$ npm install express +``` + +Wenn Sie Express vorübergehend installieren und nicht zur Abhängigkeitsliste hinzufügen wollen, geben Sie die Option `--save` nicht an: + +```bash +$ npm install express --no-save +``` + +
    +Node-Module, die mit der Option `--save` installiert werden, werden zur `Abhängigkeitsliste` in der Datei `package.json` hinzugefügt. Danach werden bei der Ausführung von `npm install` im Verzeichnis `app` automatisch alle Module in der Abhängigkeitsliste installiert. +
    diff --git a/astro/src/content/docs/de/4x/starter/static-files.md b/astro/src/content/docs/de/4x/starter/static-files.md new file mode 100644 index 0000000000..30cd67fc22 --- /dev/null +++ b/astro/src/content/docs/de/4x/starter/static-files.md @@ -0,0 +1,74 @@ +--- +title: Statische Dateien in Express bereitstellen +description: Understand how to serve static files like images, CSS, and JavaScript in Express.js applications using the built-in 'static' middleware. +--- + +# Statische Dateien in Express bereitstellen + +Wenn Sie statische Dateien wie Bilder, CSS-Dateien und JavaScript-Dateien bereitstellen wollen, verwenden Sie die in Express integrierte Middlewarefunktion `express.static`. + +The function signature is: + +```js +express.static(root, [options]); +``` + +The `root` argument specifies the root directory from which to serve static assets. +For more information on the `options` argument, see [express.static](/{{page.lang}}/5x/api.html#express.static). + +Beispiel: Verwenden Sie den folgenden Code, um Bilder, CSS-Dateien und JavaScript-Dateien in einem Verzeichnis namens `public` bereitzustellen: + +```js +app.use(express.static('public')); +``` + +Jetzt können Sie die Dateien laden, die sich im Verzeichnis `public` befinden: + +```text +http://localhost:3000/images/kitten.jpg +http://localhost:3000/css/style.css +http://localhost:3000/js/app.js +http://localhost:3000/images/bg.png +http://localhost:3000/hello.html +``` + +
    Express sucht nach den Dateien, die sich auf das Verzeichnis mit den statischen Assets beziehen. Der Name dieses Verzeichnisses ist also nicht Teil der URL.
    + +Wenn Sie mehrere Verzeichnisse mit statischen Assets verwenden wollen, rufen Sie die Middlewarefunktion `express.static` mehrmals auf: + +```js +app.use(express.static('public')); +app.use(express.static('files')); +``` + +Express sucht in der Reihenfolge nach den Dateien, in der sie die Verzeichnisse mit den statischen Assets über die Middlewarefunktion `express.static` festgelegt haben. + +{% capture alert_content %} +For best results, [use a reverse proxy](/{{page.lang}}/advanced/best-practice-performance.html#use-a-reverse-proxy) cache to improve performance of serving static assets. +{% endcapture %} +{% include admonitions/note.html content=alert_content %} + +To create a virtual path prefix (where the path does not actually exist in the file system) for files that are served by the `express.static` function, [specify a mount path](/{{ page.lang }}/5x/api.html#app.use) for the static directory, as shown below: + +```js +app.use('/static', express.static('public')); +``` + +Jetzt können Sie die Dateien, die sich im Verzeichnis `public` befinden, aus dem Pfadpräfix `/static` laden. + +```text +http://localhost:3000/static/images/kitten.jpg +http://localhost:3000/static/css/style.css +http://localhost:3000/static/js/app.js +http://localhost:3000/static/images/bg.png +http://localhost:3000/static/hello.html +``` + +Der Pfad, den Sie für die Funktion `express.static` angeben, ist jedoch relativ zum Verzeichnis, aus dem Sie Ihren Prozess `node` starten. Wenn Sie die Express-Anwendung aus einem anderen Verzeichnis ausführen, ist es sicherer, den absoluten Pfad des Verzeichnisses zu verwenden, das Sie bereitstellen wollen: + +```js +const path = require('path'); +app.use('/static', express.static(path.join(__dirname, 'public'))); +``` + +For more details about the `serve-static` function and its options, see [serve-static](/resources/middleware/serve-static.html). diff --git a/astro/src/content/docs/de/5x/advanced/best-practice-performance.md b/astro/src/content/docs/de/5x/advanced/best-practice-performance.md new file mode 100644 index 0000000000..b1c5c672aa --- /dev/null +++ b/astro/src/content/docs/de/5x/advanced/best-practice-performance.md @@ -0,0 +1,307 @@ +--- +title: Leistungsspezifische Best Practices für Express-Anwendungen in Produktionsumgebungen +description: Discover performance and reliability best practices for Express apps in production, covering code optimizations and environment setups for optimal performance. +--- + +# Best Practices in Produktionsumgebungen: Leistung und Zuverlässigkeit + +In diesem Beitrag werden Best Practices in Bezug auf Leistung und Zuverlässigkeit für Express-Anwendungen behandelt, die in der Produktionsumgebung bereitgestellt werden. + +Dieses Thema gehört sicherlich zur "DevOps"-Welt und deckt traditionelle Entwicklungs- und Betriebsprozesse ab. Entsprechend sind die Informationen hier in zwei Teile unterteilt: + +- Things to do in your code (the dev part): + - Für statische Dateien Middleware verwenden + - Keine synchronen Funktionen verwenden + - [Do logging correctly](#do-logging-correctly) + - [Handle exceptions properly](#handle-exceptions-properly) +- Things to do in your environment / setup (the ops part): + - NODE_ENV auf "production" festlegen + - Automatischen Neustart Ihrer Anwendung sicherstellen + - Anwendung in einem Cluster ausführen + - Anforderungsergebnisse im Cache speichern + - Load Balancer verwenden + - Reverse Proxy verwenden + +## Things to do in your code {#in-code} + +Dies sind einige Beispiele für Maßnahmen, die Sie an Ihrem Code vornehmen können, um die Anwendungsleistung zu verbessern: + +- Für statische Dateien Middleware verwenden +- Keine synchronen Funktionen verwenden +- [Do logging correctly](#do-logging-correctly) +- [Handle exceptions properly](#handle-exceptions-properly) + +### GZIP-Komprimierung verwenden + +Mit der GZIP-Komprimierung lässt sich die Größe des Antworthauptteils deutlich verringern und somit die Geschwindigkeit der Webanwendung erhöhen. Verwenden Sie die Middleware [compression](https://www.npmjs.com/package/compression) für die GZIP-Komprimierung in Ihrer Express-Anwendung. Beispiel: + +```js +const compression = require('compression'); +const express = require('express'); +const app = express(); + +app.use(compression()); +``` + +Bei Websites mit hohem Datenverkehr in Produktionsumgebungen lässt sich die Komprimierung am besten installieren, indem sie auf Reverse Proxy-Ebene implementiert wird (siehe [Reverse Proxy verwenden](#proxy)). In diesem Fall wird die Middleware "compression" nicht benötigt. Details zur Aktivierung der GZIP-Komprimierung in Nginx siehe [Modul ngx_http_gzip_module](http://nginx.org/en/docs/http/ngx_http_gzip_module.html) in der Nginx-Dokumentation. + +### Keine synchronen Funktionen verwenden + +Synchrone Funktionen und Methoden belasten den Ausführungsprozess, bis sie zurückgegeben werden. Ein einzelner Aufruf für eine synchrone Funktion kann in wenigen Mikrosekunden oder Millisekunden zurückgegeben werden. Bei Websites mit hohem Datenverkehr hingegen summieren sich diese Aufrufe und verringern die Leistung der Anwendung. Sie sollten also deren Verwendung in Produktionsumgebungen vermeiden. + +Auch wenn Node und viele andere Module synchrone und asynchrone Versionen ihrer Funktionen bieten, sollten Sie in Produktionsumgebungen immer die asynchrone Version verwenden. Nur beim ersten Systemstart ist die Verwendung einer synchronen Funktion begründet. + +You can use the `--trace-sync-io` command-line flag to print a warning and a stack trace whenever your application uses a synchronous API. Auch wenn Sie diese natürlich nicht in der Produktionsumgebung verwenden werden, soll dadurch trotzdem sichergestellt werden, dass Ihr Code in der Produktionsumgebung eingesetzt werden kann. Weitere Informationen hierzu siehe [Wöchentliches Update für io.js 2.1.0](https://nodejs.org/en/blog/weekly-updates/weekly-update.2015-05-22/#2-1-0). + +### Do logging correctly + +Im Allgemeinen gibt es für die Protokollierung Ihrer Anwendung zwei Gründe: 1) Debugging und 2) Protokollierung von Anwendungsaktivitäten (im Wesentlichen alles andere, außer Debugging). Die Verwendung von`console.log()` oder `console.err()` zur Ausgabe von Protokollnachrichten an das Terminal ist in der Entwicklung gängige Praxis. But [these functions are synchronous](https://nodejs.org/api/console.html#console) when the destination is a terminal or a file, so they are not suitable for production, unless you pipe the output to another program. + +#### Für Debuggingzwecke + +Wenn Sie die Protokollierung für Debuggingzwecke nutzen, sollten Sie statt `console.log()` besser ein spezielles Debuggingmodul wie [debug](https://www.npmjs.com/package/debug) verwenden. Mit einem solchen Modul können Sie über die Umgebungsvariable DEBUG steuern, welche Debugnachrichten an `console.err()` gesendet werden (falls vorhanden). Um Ihre Anwendung rein asynchron zu halten, können Sie trotzdem `console.err()` per Pipe zu einem anderen Programm umleiten. Sie nehmen dann aber kein Debugging in der Produktionsumgebung vor, richtig? + +#### Für Anwendungsaktivitäten + +If you're logging app activity (for example, tracking traffic or API calls), instead of using `console.log()`, use a logging library like [Pino](https://www.npmjs.com/package/pino), which is the fastest and most efficient option available. + +### Ausnahmebedingungen ordnungsgemäß handhaben + +Node-Anwendungen stürzen ab, wenn eine nicht abgefangene Ausnahmebedingung vorkommt. Wenn diese Ausnahmebedingungen nicht behandelt und entsprechende Maßnahmen eingeleitet werden, stürzt Ihre Express-Anwendung ab und geht offline. Wenn Sie dem nachfolgenden Rat in [Sicherstellen, dass Ihre Anwendung automatisch neu gestartet wird](#restart) folgen, wird Ihre Anwendung nach einem Absturz wiederhergestellt. Glücklicherweise haben Express-Anwendungen nur eine kurze Initialisierungszeit. Nevertheless, you want to avoid crashing in the first place, and to do that, you need to handle exceptions properly. + +Mit folgenden Verfahren stellen Sie sicher, dass alle Ausnahmebedingungen gehandhabt werden: + +- ["try-catch" verwenden](#try-catch) +- ["Promises" verwenden](#promises) + +Um näher auf diese Themen eingehen zu können, müssen Sie sich ein grundlegendes Verständnis der Fehlerbehandlung in Node und Express aneignen: Verwendung von Error-first-Callbacks und Propagieren von Fehlern in Middleware. Node verwendet die Konvention "Error-first-Callback" für die Rückgabe von Fehlern von asynchronen Funktionen, bei denen der erste Parameter zur Callback-Funktion das Fehlerobjekt ist, gefolgt von Ergebnisdaten in den nachfolgenden Parametern. Um anzugeben, dass kein Fehler vorliegt, müssen Sie "null" als ersten Parameter übergeben. Die Callback-Funktion muss der Konvention "Error-first-Callback" folgen, um den Fehler sinnvoll bearbeiten zu können. In Express hat sich bewährt, die Funktion "next()" zu verwenden, um Fehler über die Middleware-Chain zu propagieren. + +Weitere Informationen zu den Grundlagen der Fehlerbehandlung siehe: + +- [Fehlerbehandlung in Node.js](https://www.tritondatacenter.com/node-js/production/design/errors) + +#### "try-catch" verwenden + +"try-catch" ist ein JavaScript-Sprachkonstrukt, mit dem Sie Ausnahmebedingungen in synchronem Code abfangen können. Verwenden Sie "try-catch" beispielsweise, um JSON-Parsing-Fehler wie unten gezeigt zu bearbeiten. + +Dies ist ein Beispiel zur Verwendung von "try-catch", um eine potenzielle "process-crashing"-Ausnahmebedingung zu handhaben. +Diese Middlewarefunktion akzeptiert einen Abfragefeldparameter mit dem Namen "params", der ein JSON-Objekt ist. + +```js +app.get('/search', (req, res) => { + // Simulating async operation + setImmediate(() => { + const jsonStr = req.query.params; + try { + const jsonObj = JSON.parse(jsonStr); + res.send('Success'); + } catch (e) { + res.status(400).send('Invalid JSON string'); + } + }); +}); +``` + +"try-catch" funktioniert jedoch nur in synchronem Code. Da die Node-Plattform primär asynchron ist (insbesondere in einer Produktionsumgebung), lassen sich mit "try-catch" nicht besonders viele Ausnahmebedingungen abfangen. + +#### "Promises" verwenden + +When an error is thrown in an `async` function or a rejected promise is awaited inside an `async` function, those errors will be passed to the error handler as if calling `next(err)` + +```js +app.get('/', async (req, res, next) => { + const data = await userData(); // If this promise fails, it will automatically call `next(err)` to handle the error. + + res.send(data); +}); + +app.use((err, req, res, next) => { + res.status(err.status ?? 500).send({ error: err.message }); +}); +``` + +Also, you can use asynchronous functions for your middleware, and the router will handle errors if the promise fails, for example: + +```js +app.use(async (req, res, next) => { + req.locals.user = await getUser(req); + + next(); // This will be called if the promise does not throw an error. +}); +``` + +Best practice is to handle errors as close to the site as possible. So while this is now handled in the router, it’s best to catch the error in the middleware and handle it without relying on separate error-handling middleware. + +#### What not to do + +Sie sollten _auf keinen_ Fall per Listener das Ereignis `uncaughtException` überwachen, das ausgegeben wird, wenn eine Ausnahmebedingung bis zurück zur Ereignisschleife bestehen bleibt. Durch das Hinzufügen eines Ereignislisteners für `uncaughtException` verändert sich das Standardverhalten des Prozesses, über das eine Ausnahmebedingung festgestellt wird. Das Ausführen einer Anwendung nach einer nicht abgefangenen Ausnahmebedingung ist aber eine durchaus riskante Vorgehensweise und wird nicht empfohlen, da der Prozessstatus störanfällig und unvorhersehbar wird. + +Außerdem wird die Verwendung von `uncaughtException` offiziell als [grobes Vorgehen](https://nodejs.org/api/process.html#process_event_uncaughtexception) angesehen, sodass es den [Vorschlag](https://github.com/nodejs/node-v0.x-archive/issues/2582) gibt, die Funktion aus dem Kern zu entfernen. Das Überwachen von `uncaughtException` per Listener ist also keine gute Idee. Daher empfehlen wir Dinge wie Mehrfachprozesse und Supervisoren: Ein Absturz und anschließender Neustart ist häufig die zuverlässigste Art der Fehlerbehebung. + +Zudem empfehlen wir, [domains](https://nodejs.org/api/domain.html) nicht zu verwenden. Mit diesem Modul, das zudem veraltet ist, lässt sich das Problem in der Regel nicht lösen. + +## Things to do in your environment / setup {#in-environment} + +Dies sind einige Beispiele für Maßnahmen, die Sie an Ihrer Systemumgebung vornehmen können, um die Anwendungsleistung zu verbessern: + +- NODE_ENV auf "production" festlegen +- Automatischen Neustart Ihrer Anwendung sicherstellen +- Anwendung in einem Cluster ausführen +- Anforderungsergebnisse im Cache speichern +- Load Balancer verwenden +- Reverse Proxy verwenden + +### NODE_ENV auf "production" festlegen + +In der Umgebungsvariablen NODE_ENV wird die Umgebung angegeben, in der eine Anwendung ausgeführt wird (in der Regel ist dies die Entwicklungs- oder Produktionsumgebung). One of the simplest things you can do to improve performance is to set NODE_ENV to `production`. + +Durch das Festlegen von NODE_ENV auf "production" führt Express Folgendes aus: + +- Speichern von Anzeigevorlagen im Cache. +- Speichern von CSS-Dateien, die aus CSS-Erweiterungen generiert wurden, im Cache. +- Generieren von weniger ausführlichen Fehlernachrichten. + +[Tests indicate](https://www.dynatrace.com/news/blog/the-drastic-effects-of-omitting-node-env-in-your-express-js-applications/) that just doing this can improve app performance by a factor of three! + +Wenn Sie umgebungsspezifischen Code schreiben müssen, können Sie den Wert von NODE_ENV mit `process.env.NODE_ENV` überprüfen. Beachten Sie, dass die Überprüfung des Werts seiner Umgebungsvariablen eine leistungsbezogene Penalisierung nach sich zieht. + +In einer Entwicklungsumgebung wird die Umgebungsvariable in der Regel in Ihrer interaktiven Shell festgelegt, indem Sie beispielsweise `export` oder Ihre Datei `.bash_profile` verwenden. But in general, you shouldn't do that on a production server; instead, use your OS's init system (systemd). Der nächste Abschnitt enthält weitere Details zur Verwendung des Init-Systems im Allgemeinen. Die Festlegung von NODE_ENV ist jedoch für das Leistungsverhalten so wichtig (und so einfach durchzuführen), dass hier besonders darauf eingegangen wird. + +Verwenden Sie bei systemd die Anweisung `Environment` in Ihrer Einheitendatei. Beispiel: + +```sh +# /etc/systemd/system/myservice.service +Environment=NODE_ENV=production +``` + +For more information, see [Using Environment Variables In systemd Units](https://www.flatcar.org/docs/latest/setup/systemd/environment-variables/). + +### Automatischen Neustart Ihrer Anwendung sicherstellen + +In der Produktionsumgebung sollte die Anwendung nie offline sein. Das bedeutet, dass Sie sicherstellen müssen, dass die Anwendung bei einem Absturz der Anwendung oder des Servers immer wieder neu gestartet wird. Auch wenn man hofft, das keines dieser Ereignisse jemals eintritt, muss man doch mit beiden Möglichkeiten rechnen und: + +- einen Prozessmanager verwenden, um die Anwendung (und Node) bei einem Absturz neu zu starten. +- das Init-System Ihres Betriebssystems verwenden, um den Prozessmanager bei einem Absturz des Betriebssystems neu zu starten. Außerdem kann das Init-System auch ohne einen Prozessmanager verwendet werden. + +Node-Anwendungen stürzen ab, wenn eine nicht abgefangene Ausnahmebedingung auftritt. Als Erstes müssen Sie in einem solchen Fall sicherstellen, dass Ihre Anwendung ausreichend getestet wurde und in der Lage ist, alle Ausnahmebedingungen zu handhaben (weitere Informationen siehe [Ausnahmebedingungen ordnungsgemäß handhaben](#exceptions)). Die sicherste Maßnahme ist jedoch, einen Mechanismus zu implementieren, über den bei einem Absturz der Anwendung ein automatischer Neustart der Anwendung ausgeführt wird. + +#### Prozessmanager verwenden + +In Entwicklungumgebungen wird die Anwendung einfach über die Befehlszeile mit `node server.js` oder einer vergleichbaren Datei gestartet. In der Produktionsumgebung hingegen ist durch diese Vorgehensweise die Katastrophe bereits vorprogrammiert. Wenn die Anwendung abstürzt, ist sie solange offline, bis Sie sie erneut starten. Um sicherzustellen, dass Ihre Anwendung nach einem Absturz neu gestartet wird, sollten Sie einen Prozessmanager verwenden. Ein Prozessmanager ist ein "Container" für Anwendungen, der die Bereitstellung erleichtert, eine hohe Verfügbarkeit sicherstellt und die Verwaltung der Anwendung zur Laufzeit ermöglicht. + +Neben einem Neustart der Anwendung nach einem Absturz bietet ein Prozessmanager noch weitere Möglichkeiten: + +- Einblicke in die Laufzeitleistung und die Ressourcennutzung +- Dynamische Änderung der Einstellungen zur Verbesserung des Leistungsverhaltens +- Control clustering (pm2). + +Historically, it was popular to use a Node.js process manager like [PM2](https://github.com/Unitech/pm2). See their documentation if you wish to do this. However, we recommend using your init system for process management. + +#### Init-System verwenden + +Als nächste Ebene der Zuverlässigkeit müssen Sie sicherstellen, dass Ihre Anwendung bei einem Serverneustart neu gestartet wird. Systeme können immer wieder aus verschiedenen Gründen abstürzen. Um sicherzustellen, dass Ihre Anwendung bei einem Serverabsturz neu gestartet wird, können Sie das in Ihr Betriebssystem integrierte Init-System verwenden. The main init system in use today is [systemd](https://wiki.debian.org/systemd). + +Es gibt zwei Möglichkeiten, Init-Systeme mit Ihrer Express-Anwendung zu verwenden: + +- Ausführung Ihrer Anwendung in einem Prozessmanager und Installation des Prozessmanagers als Service mit dem Init-System. Der Prozessmanager wird neu gestartet, wenn Ihre Anwendung abstürzt. Dies ist die empfohlene Vorgehensweise. +- Ausführung Ihrer Anwendung (und von Node) direkt mit dem Init-System. Diese Vorgehensweise ist zwar etwas einfacher, Sie profitieren jedoch nicht von den zusätzlichen Vorteilen des Einsatzes eines Prozessmanagers. + +##### systemd + +"systemd" ist ein Linux-System und Service-Manager. Die meisten wichtigen Linux-Distributionen haben "systemd" als Init-Standardsystem übernommen. + +Eine "systemd"-Servicekonfigurationsdatei wird als _Einheitendatei_ bezeichnet, die die Endung ".service" hat. Dies ist ein Beispiel für eine Einheitendatei zur direkten Verwaltung einer Node-Anwendung (ersetzen Sie den Text in Fettdruck durch Werte für Ihr System und Ihre Anwendung): Replace the values enclosed in `` for your system and app: + +```sh +[Unit] +Description= + +[Service] +Type=simple +ExecStart=/usr/local/bin/node +WorkingDirectory= + +User=nobody +Group=nogroup + +# Environment variables: +Environment=NODE_ENV=production + +# Allow many incoming connections +LimitNOFILE=infinity + +# Allow core dumps for debugging +LimitCORE=infinity + +StandardInput=null +StandardOutput=syslog +StandardError=syslog +Restart=always + +[Install] +WantedBy=multi-user.target +``` + +Weitere Informationen zu "systemd" siehe [systemd-Referenz (Man-Page)](http://www.freedesktop.org/software/systemd/man/systemd.unit.html). + +### Anwendung in einem Cluster ausführen + +In einem Multi-Core-System können Sie die Leistung einer Node-Anwendung mehrmals erhöhen, indem Sie einen Cluster von Prozessen starten. Ein Cluster führt mehrere Instanzen der Anwendung aus, idealerweise eine Instanz auf jedem CPU-Core. + +![Balancing between application instances using the cluster API](/images/clustering.png) + +Wichtig. Da die Anwendungsinstanzen als separate Prozesse ausgeführt werden, nutzen sie nicht dieselbe Hauptspeicherkapazität gemeinsam. Das heißt, Objekte befinden sich für jede Instanz der Anwendung auf lokaler Ebene. Daher kann der Status im Anwendungscode nicht beibehalten werden. Sie können jedoch einen speicherinternen Datenspeicher wie [Redis](http://redis.io/) verwenden, um sitzungsrelevante Daten und Statusinformationen zu speichern. Diese Einschränkung trifft im Wesentlichen auf alle Formen der horizontalen Skalierung zu, unabhängig davon, ob es sich um Clustering mit mehreren Prozessen oder mehreren physischen Servern handelt. + +Bei in Gruppen zusammengefassten Anwendungen (geclusterte Anwendungen) können Verarbeitungsprozesse einzeln ausfallen, ohne dass sich dies auf die restlichen Prozesse auswirkt. Neben den Leistungsvorteilen ist die Fehlerisolierung ein weiterer Grund, einen Cluster von Anwendungsprozessen auszuführen. Wenn ein Verarbeitungsprozess abstürzt, müssen Sie sicherstellen, dass das Ereignis protokolliert und ein neuer Prozess mithilfe von "cluster.fork()" gestartet wird. + +#### Clustermodule von Node verwenden + +Clustering is made possible with Node's [cluster module](https://nodejs.org/api/cluster.html). Dadurch wird ein Masterprozess eingeleitet, um Verarbeitungsprozesse zu starten und eingehende Verbindungen auf die Verarbeitungsprozesse zu verteilen. + +#### Using PM2 + +If you deploy your application with PM2, then you can take advantage of clustering _without_ modifying your application code. You should ensure your [application is stateless](https://pm2.keymetrics.io/docs/usage/specifics/#stateless-apps) first, meaning no local data is stored in the process (such as sessions, websocket connections and the like). + +When running an application with PM2, you can enable **cluster mode** to run it in a cluster with a number of instances of your choosing, such as the matching the number of available CPUs on the machine. You can manually change the number of processes in the cluster using the `pm2` command line tool without stopping the app. + +To enable cluster mode, start your application like so: + +```bash +# Start 4 worker processes +$ pm2 start npm --name my-app -i 4 -- start +# Auto-detect number of available CPUs and start that many worker processes +$ pm2 start npm --name my-app -i max -- start +``` + +This can also be configured within a PM2 process file (`ecosystem.config.js` or similar) by setting `exec_mode` to `cluster` and `instances` to the number of workers to start. + +Once running, the application can be scaled like so: + +```bash +# Add 3 more workers +$ pm2 scale my-app +3 +# Scale to a specific number of workers +$ pm2 scale my-app 2 +``` + +For more information on clustering with PM2, see [Cluster Mode](https://pm2.keymetrics.io/docs/usage/cluster-mode/) in the PM2 documentation. + +### Anforderungsergebnisse im Cache speichern + +Eine weitere Strategie zur Verbesserung des Leistungsverhaltens in Produktionsumgebungen ist das Speichern von Anforderungergebnissen im Cache. Ihre Anwendung muss also diese Operation nicht wiederholt ausführen, um dieselbe Anforderung wiederholt zu bedienen. + +Use a caching server like [Varnish](https://www.varnish-cache.org/) or [Nginx](https://blog.nginx.org/blog/nginx-caching-guide) (see also [Nginx Caching](https://serversforhackers.com/nginx-caching/)) to greatly improve the speed and performance of your app. + +### Load Balancer verwenden + +Unabhängig davon, wie gut eine Anwendung optimiert wurde, kann eine Einzelinstanz nur eine begrenzte Arbeitslast oder einen begrenzten Datenverkehr handhaben. Eine Möglichkeit, eine Anwendung zu skalieren, ist die Ausführung mehrerer Instanzen dieser Anwendung und die Verteilung des Datenverkehrs über eine Lastausgleichsfunktion (Load Balancer) vorzunehmen. Die Einrichtung eines solchen Load Balancer kann helfen, Leistung und Geschwindigkeit Ihrer Anwendung zu verbessern. + +Ein Load Balancer ist in der Regel ein Reverse Proxy, der den Datenverkehr zu und von mehreren Anwendungsinstanzen und Servern koordiniert. You can easily set up a load balancer for your app by using [Nginx](https://nginx.org/en/docs/http/load_balancing.html) or [HAProxy](https://www.digitalocean.com/community/tutorials/an-introduction-to-haproxy-and-load-balancing-concepts). + +Bei einer solchen Lastverteilung müssen Sie sicherstellen, dass Anforderungen, die einer bestimmten Sitzungs-ID zugeordnet sind, mit dem Prozess verbunden sind, von dem sie ursprünglich stammen. Dies wird auch als _Sitzungsaffinität_ oder _Affine Sitzungen_ bezeichnet und kann durch den obigen Vorschlag, einen Datenspeicher wie Redis für Sitzungsdaten zu verwenden (je nach Anwendung), umgesetzt werden. Eine Beschreibung hierzu siehe [Mehrere Knoten verwenden](https://socket.io/docs/v4/using-multiple-nodes/). + +### Reverse Proxy verwenden + +Ein Reverse Proxy befindet sich vor einer Webanwendung und führt Unterstützungsoperationen für die Anforderungen aus (außer das Weiterleiten von Anforderungen an die Anwendung). Fehlerseiten, Komprimierungen und Caching bearbeiten, Dateien bereitstellen und Lastverteilungen vornehmen. + +Durch die Übergabe von Tasks, die keine Kenntnis des Anwendungsstatus erfordern, an einen Reverse Proxy muss Express keine speziellen Anwendungstasks mehr ausführen. For this reason, it is recommended to run Express behind a reverse proxy like [Nginx](https://www.nginx.org/) or [HAProxy](https://www.haproxy.org/) in production. diff --git a/astro/src/content/docs/de/5x/advanced/best-practice-security.md b/astro/src/content/docs/de/5x/advanced/best-practice-security.md new file mode 100644 index 0000000000..374a1f98b2 --- /dev/null +++ b/astro/src/content/docs/de/5x/advanced/best-practice-security.md @@ -0,0 +1,282 @@ +--- +title: Sicherheitsspezifische Best Practices für Express-Anwendungen in Produktionsumgebungen +description: Discover crucial security best practices for Express apps in production, including using TLS, input validation, secure cookies, and preventing vulnerabilities. +--- + +# Best Practices in Produktionsumgebungen: Sicherheit + +## Überblick + +Der Begriff _"Produktion"_ bezieht sich auf die Phase im Softwarelebenszyklus, in der eine Anwendung oder API für Endbenutzer oder Verbraucher allgemein verfügbar ist. Im Gegensatz dazu wird in der Phase _"Entwicklung"_ noch aktiv Code geschrieben und getestet. Die Anwendung ist in dieser Phase noch nicht für externen Zugriff verfügbar. Die entsprechenden Systemumgebungen werden als _Produktionsumgebungen_ und _Entwicklungsumgebungen_ bezeichnet. + +Entwicklungs- und Produktionsumgebungen werden in der Regel unterschiedlich konfiguriert und weisen deutliche Unterschiede bei den Anforderungen auf. Was in der Entwicklung funktioniert, muss in der Produktion nicht unbedingt akzeptabel sein. Beispiel: In einer Entwicklungsumgebung ist eine ausführliche Protokollierung von Fehlern für Debuggingzwecke sinnvoll. Dieselbe Vorgehensweise kann in einer Produktionsumgebung jedoch zu einem Sicherheitsproblem führen. In einer Entwicklungsumgebung müssen Sie sich keine Gedanken zu Themen wie Skalierbarkeit, Zuverlässigkeit und Leistung machen, während dies in einer Produktionsumgebung kritische Faktoren sind. + +{% capture security-note %} + +If you believe you have discovered a security vulnerability in Express, please see +[Security Policies and Procedures](/en/resources/contributing.html#security-policies-and-procedures). + +{% endcapture %} + +{% include admonitions/note.html content=security-note %} + +In diesem Beitrag werden einige der Best Practices in Bezug auf das Thema Sicherheit für Express-Anwendungen behandelt, die in der Produktionsumgebung bereitgestellt werden. + +- [Production Best Practices: Security](#production-best-practices-security) + - [Overview](#overview) + - [Don't use deprecated or vulnerable versions of Express](#dont-use-deprecated-or-vulnerable-versions-of-express) + - Über [hsts](https://github.com/helmetjs/hsts) werden `Strict-Transport-Security`-Header festgelegt, über die sichere (HTTP over SSL/TLS) Verbindungen zum Server durchgesetzt werden. + - [Do not trust user input](#do-not-trust-user-input) + - [Prevent open redirects](#prevent-open-redirects) + - "Helmet" ist eine Ansammlung von neun kleineren Middlewarefunktionen, über die sicherheitsrelevante HTTP-Header festgelegt werden. + - [Reduce fingerprinting](#reduce-fingerprinting) + - Über [xssFilter](https://github.com/helmetjs/x-xss-protection) werden `X-XSS-Protection`-Header festgelegt, um XSS-Filter (Cross-site Scripting) in den meisten aktuellen Web-Browsern zu aktivieren. + - Über [noCache](https://github.com/helmetjs/nocache) werden `Cache-Control`- und Pragma-Header festgelegt, um clientseitiges Caching zu deaktivieren. + - Über [ieNoOpen](https://github.com/helmetjs/ienoopen) werden `X-Download-Options`-Header für IE8+ festgelegt. + - [Prevent brute-force attacks against authorization](#prevent-brute-force-attacks-against-authorization) + - [Ensure your dependencies are secure](#ensure-your-dependencies-are-secure) + - [Avoid other known vulnerabilities](#avoid-other-known-vulnerabilities) + - [Additional considerations](#additional-considerations) + +## Verwenden Sie keine veralteten oder anfälligen Versionen von Express + +Express 2.x und 3.x werden nicht mehr gepflegt. Sicherheits- und Leistungsprobleme in diesen Versionen werden nicht mehr behoben. Verwenden Sie diese Versionen nicht! Wenn Sie noch nicht auf Version 4 umgestellt haben, befolgen Sie die Anweisungen im [Migrationshandbuch](/{{ page.lang }}/guide/migrating-4.html). + +Stellen Sie außerdem sicher, dass Sie keine anfälligen Express-Versionen verwenden, die auf der [Seite mit den Sicherheitsupdates](/{{ page.lang }}/advanced/security-updates.html) aufgelistet sind. Falls doch, führen Sie ein Update auf eines der stabileren Releases durch, bevorzugt das aktuelle Release. + +## TLS verwenden + +Wenn über Ihre Anwendung vertrauliche Daten bearbeitet oder übertragen werden, sollten Sie [Transport Layer Security](https://en.wikipedia.org/wiki/Transport_Layer_Security) (TLS) verwenden, um die Verbindung und die Daten zu schützen. Diese Technologie verschlüsselt Daten, bevor sie vom Client zum Server gesendet werden. Dadurch lassen sich einige gängige (und einfache) Hackerattacken vermeiden. Auch wenn Ajax- und POST-Anforderungen nicht sofort offensichtlich und in Browsern "versteckt" zu sein scheinen, ist deren Netzverkehr anfällig für das [Ausspionieren von Paketen](https://en.wikipedia.org/wiki/Packet_analyzer) und [Man-in-the-Middle-Attacken](https://en.wikipedia.org/wiki/Man-in-the-middle_attack). + +Möglicherweise sind Sie mit SSL-Verschlüsselung (Secure Socket Layer) bereits vertraut. [TLS ist einfach der nächste Entwicklungsschritt bei SSL](). In anderen Worten: Wenn Sie bisher SSL verwendet haben, sollten Sie ein Upgrade auf TLS in Erwägung ziehen. Generell empfehlen wir für TLS den Nginx-Server. Eine gute Referenz zum Konfigurieren von TLS auf Nginx (und anderen Servern) ist [Empfohlene Serverkonfigurationen (Mozilla Wiki)](https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_Server_Configurations). + +Ein handliches Tool zum Abrufen eines kostenloses TLS-Zertifikats ist außerdem [Let's Encrypt](https://letsencrypt.org/about/), eine kostenlose, automatisierte und offene Zertifizierungsstelle der [Internet Security Research Group (ISRG)](https://letsencrypt.org/isrg/). + +## Do not trust user input + +For web applications, one of the most critical security requirements is proper user input validation and handling. This comes in many forms and we will not cover all of them here. +Ultimately, the responsibility for validating and correctly handling the types of user input your application accepts is yours. + +### Prevent open redirects + +An example of potentially dangerous user input is an _open redirect_, where an application accepts a URL as user input (often in the URL query, for example `?url=https://example.com`) and uses `res.redirect` to set the `location` header and +return a 3xx status. + +An application must validate that it supports redirecting to the incoming URL to avoid sending users to malicious links such as phishing websites, among other risks. + +Here is an example of checking URLs before using `res.redirect` or `res.location`: + +```js +app.use((req, res) => { + try { + if (new Url(req.query.url).host !== 'example.com') { + return res.status(400).end(`Unsupported redirect to host: ${req.query.url}`); + } + } catch (e) { + return res.status(400).end(`Invalid url: ${req.query.url}`); + } + res.redirect(req.query.url); +}); +``` + +## "Helmet" verwenden + +[Helmet](https://www.npmjs.com/package/helmet) kann beim Schutz Ihrer Anwendung gegen einige gängige Schwachstellen hilfreiche Dienste leisten, indem die HTTP-Header entsprechend konfiguriert werden. + +Helmet is a middleware function that sets security-related HTTP response headers. Helmet sets the following headers by default: + +- `Content-Security-Policy`: A powerful allow-list of what can happen on your page which mitigates many attacks +- `Cross-Origin-Opener-Policy`: Helps process-isolate your page +- `Cross-Origin-Resource-Policy`: Blocks others from loading your resources cross-origin +- `Origin-Agent-Cluster`: Changes process isolation to be origin-based +- `Referrer-Policy`: Controls the [`Referer`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referer) header +- `Strict-Transport-Security`: Tells browsers to prefer HTTPS +- `X-Content-Type-Options`: Avoids [MIME sniffing](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#mime_sniffing) +- `X-DNS-Prefetch-Control`: Controls DNS prefetching +- `X-Download-Options`: Forces downloads to be saved (Internet Explorer only) +- `X-Frame-Options`: Legacy header that mitigates [Clickjacking](https://en.wikipedia.org/wiki/Clickjacking) attacks +- `X-Permitted-Cross-Domain-Policies`: Controls cross-domain behavior for Adobe products, like Acrobat +- `X-Powered-By`: Info about the web server. Removed because it could be used in simple attacks +- `X-XSS-Protection`: Legacy header that tries to mitigate [XSS attacks](https://developer.mozilla.org/en-US/docs/Glossary/Cross-site_scripting), but makes things worse, so Helmet disables it + +Each header can be configured or disabled. To read more about it please go to [its documentation website][helmet]. + +Installieren Sie "Helmet" wie alle anderen Module: + +```bash +$ npm install helmet +``` + +So verwenden Sie "Helmet" in Ihrem Code: + +```js +// ... + +const helmet = require('helmet'); +app.use(helmet()); + +// ... +``` + +## Reduce fingerprinting + +It can help to provide an extra layer of security to reduce the ability of attackers to determine +the software that a server uses, known as "fingerprinting." Though not a security issue itself, +reducing the ability to fingerprint an application improves its overall security posture. +Server software can be fingerprinted by quirks in how it responds to specific requests, for example in +the HTTP response headers. + +Ein bewährtes Verfahren ist also, diesen Header mit der Methode `app.disable()` zu deaktivieren: + +```js +app.disable('x-powered-by'); +``` + +{% capture powered-advisory %} + +Disabling the `X-Powered-By header` does not prevent +a sophisticated attacker from determining that an app is running Express. It may +discourage a casual exploit, but there are other ways to determine an app is running +Express. + +{% endcapture %} + +{% include admonitions/note.html content=powered-advisory %} + +Express also sends its own formatted "404 Not Found" messages and formatter error +response messages. These can be changed by +[adding your own not found handler](/en/starter/faq.html#how-do-i-handle-404-responses) +and +[writing your own error handler](/en/guide/error-handling.html#writing-error-handlers): + +```js +// last app.use calls right before app.listen(): + +// custom 404 +app.use((req, res, next) => { + res.status(404).send("Sorry can't find that!"); +}); + +// custom error handler +app.use((err, req, res, next) => { + console.error(err.stack); + res.status(500).send('Something broke!'); +}); +``` + +## Cookies sicher verwenden + +Um sicherzustellen, dass Cookies Ihre Anwendung nicht für Angriffsmöglichkeiten öffnen, sollten Sie den standardmäßigen Namen des Sitzungscookies nicht verwenden und die Cookie-Sicherheitsoptionen entsprechend festlegen. + +Es gibt zwei wesentliche Middleware-Cookie-Sitzungsmodule: + +- [express-session](https://www.npmjs.com/package/express-session), das in Express 3.x integrierte `express.session`-Middleware ersetzt. +- [cookie-session](https://www.npmjs.com/package/cookie-session), das in Express 3.x integrierte `express.cookieSession`-Middleware ersetzt. + +Der Hauptunterschied zwischen diesen beiden Modulen liegt darin, wie die Cookie-Sitzungsdaten gespeichert werden. Die [express-session](https://www.npmjs.com/package/express-session)-Middleware speichert Sitzungsdaten auf dem Server. Sie speichert nur die Sitzungs-ID im Cookie und nicht die Sitzungsdaten. Standardmäßig wird dabei der speicherinterne Speicher verwendet. Eine Verwendung der Middleware in der Produktionsumgebung ist nicht vorgesehen. In der Produktionsumgebung müssen Sie einen skalierbaren "Session-Store" einrichten. Siehe hierzu die Liste der [kompatiblen Session-Stores](https://github.com/expressjs/session#compatible-session-stores). + +Im Gegensatz dazu implementiert die [cookie-session](https://www.npmjs.com/package/cookie-session)-Middleware cookiegestützten Speicher: Sie serialisiert die gesamte Sitzung zum Cookie und nicht nur einen Sitzungsschlüssel. Diese Middleware sollten Sie nur verwenden, wenn Sitzungsdaten relativ klein sind und einfach als primitive Werte (und nicht als Objekte) codiert sind. Auch wenn Browser mindestens 4096 Byte pro Cookie unterstützen sollten, müssen Sie sicherstellen, dass dieses Limit nicht überschritten wird. Überschreiten Sie auf keinen Fall die Größe von 4093 Byte pro Domäne. Achten Sie zudem darauf, dass die Cookiedaten für den Client sichtbar sind. Wenn also ein Grund vorliegt, die Daten sicher oder unkenntlich zu machen, ist "express-session" möglicherweise die bessere Wahl. + +### Verwenden Sie nicht den standardmäßigen Namen des Sitzungscookies + +Die Verwendung des standardmäßigen Namens des Sitzungscookies kann Ihre Anwendung anfällig für Attacken machen. Das mögliche Sicherheitsproblem ist vergleichbar mit `X-Powered-By`: ein potenzieller Angreifer kann diesen Header verwenden, um einen elektronischen Fingerabdruck des Servers zu erstellen und Attacken entsprechend zu platzieren. + +Über [noSniff](https://github.com/helmetjs/dont-sniff-mimetype) werden `X-Content-Type-Options`-Header festgelegt, um bei Browsern MIME-Sniffing von Antworten weg vom deklarierten Inhaltstyp (declared content-type) vorzubeugen. + +```js +const session = require('express-session'); +app.set('trust proxy', 1); // trust first proxy +app.use( + session({ + secret: 's3Cur3', + name: 'sessionId', + }) +); +``` + +### Cookie-Sicherheitsoptionen festlegen + +Legen Sie die folgenden Cookieoptionen fest, um die Sicherheit zu erhöhen: + +- `secure` - Stellt sicher, dass der Browser das Cookie nur über HTTPS sendet. +- `httpOnly` - Stellt sicher, dass das Cookie nur über HTTP(S) und nicht über das Client-JavaScript gesendet wird und dadurch Schutz gegen Cross-Site Scripting-Attacken besteht. +- `domain` - Gibt die Domäne des Cookies an, die für den Vergleich mit der Domäne des Servers verwendet wird, in der die URL angefordert wird. Stimmen diese beiden überein, müssen Sie das Pfadattribut überprüfen. +- `path` - Gibt den Pfad des Cookies an, der für den Vergleich mit dem Anforderungspfad verwendet wird. Wenn dieser Pfad und die Domäne übereinstimmen, können Sie das Cookie in der Anforderung senden. +- `expires` - Wird verwendet, um das Ablaufdatum für persistente Cookies festzulegen. + +Dies ist ein Beispiel zur Verwendung der [cookie-session](https://www.npmjs.com/package/cookie-session)-Middleware: + +```js +const session = require('cookie-session'); +const express = require('express'); +const app = express(); + +const expiryDate = new Date(Date.now() + 60 * 60 * 1000); // 1 hour +app.use( + session({ + name: 'session', + keys: ['key1', 'key2'], + cookie: { + secure: true, + httpOnly: true, + domain: 'example.com', + path: 'foo/bar', + expires: expiryDate, + }, + }) +); +``` + +## Prevent brute-force attacks against authorization + +Make sure login endpoints are protected to make private data more secure. + +A simple and powerful technique is to block authorization attempts using two metrics: + +1. The number of consecutive failed attempts by the same user name and IP address. +2. The number of failed attempts from an IP address over some long period of time. For example, block an IP address if it makes 100 failed attempts in one day. + +[rate-limiter-flexible](https://github.com/animir/node-rate-limiter-flexible) package provides tools to make this technique easy and fast. You can find [an example of brute-force protection in the documentation](https://github.com/animir/node-rate-limiter-flexible/wiki/Overall-example#login-endpoint-protection) + +## Ensure your dependencies are secure + +Using npm to manage your application's dependencies is powerful and convenient. But the packages that you use may contain critical security vulnerabilities that could also affect your application. The security of your app is only as strong as the "weakest link" in your dependencies. + +Since npm@6, npm automatically reviews every install request. Also, you can use `npm audit` to analyze your dependency tree. + +```bash +$ npm audit +``` + +If you want to stay more secure, consider [Snyk](https://snyk.io/). + +Snyk offers both a [command-line tool](https://www.npmjs.com/package/snyk) and a [Github integration](https://snyk.io/docs/github) that checks your application against [Snyk's open source vulnerability database](https://snyk.io/vuln/) for any known vulnerabilities in your dependencies. Install the CLI as follows: + +```bash +$ npm install -g snyk +$ cd your-app +``` + +Use this command to test your application for vulnerabilities: + +```bash +$ snyk test +``` + +### Vermeiden Sie andere Schwachstellen + +Achten Sie auf [Node Security Project](https://npmjs.com/advisories)-Empfehlungen, die Express oder andere Module, die Ihre Anwendung nutzt, beeinträchtigen können. Im Allgemeinen ist Node Security Project aber eine exzellente Ressource mit Wissen und Tools zur Sicherheit von Node. + +Letztendlich können Express-Anwendungen – wie viele andere Webanwendungen auch – anfällig für eine Vielzahl webbasierter Attacken sein. Machen Sie sich deshalb mit bekannten [webspezifischen Schwachstellen](https://www.owasp.org/www-project-top-ten/) vertraut und treffen Sie die geeigneten Vorkehrungen, um diese zu vermeiden. + +## Weitere Überlegungen + +Dies sind einige weitere Empfehlungen aus der hervorragenden [Node.js Security Checklist](https://blog.risingstack.com/node-js-security-checklist/). In diesem Blogbeitrag finden Sie alle Details zu diesen Empfehlungen: + +- Filtern und bereinigen Sie immer Benutzereingaben, um sich gegen XS-Angriffe (Cross-Site Scripting) und Befehlsinjektionsattacken zu schützen. +- Implementieren Sie Verteidungsmaßnahmen gegen SQL-Injection-Attacken, indem sie parametrisierte Abfragen oder vorbereitete Anweisungen einsetzen. +- Nutzen Sie das Open-Source-Tool [sqlmap](http://sqlmap.org/), um SQL-Injection-Schwachstellen in Ihrer Anwendung zu erkennen. +- Verwenden Sie die Tools [nmap](https://nmap.org/) und [sslyze](https://github.com/nabla-c0d3/sslyze), um die Konfiguration Ihrer SSL-Verschlüsselungen, -Schlüssel und Neuvereinbarungen sowie die Gültigkeit Ihres Zertifikats zu testen. +- Verwenden Sie [safe-regex](https://www.npmjs.com/package/safe-regex), um sicherzustellen, dass Ihre regulären Ausdrücke nicht für [Denial-of-Service-Attacken](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS) anfällig sind. + +[helmet]: diff --git a/astro/src/content/docs/de/5x/advanced/developing-template-engines.md b/astro/src/content/docs/de/5x/advanced/developing-template-engines.md new file mode 100644 index 0000000000..354927776d --- /dev/null +++ b/astro/src/content/docs/de/5x/advanced/developing-template-engines.md @@ -0,0 +1,45 @@ +--- +title: Template-Engines für Express entwickeln +description: Learn how to develop custom template engines for Express.js using app.engine(), with examples on creating and integrating your own template rendering logic. +--- + +# Template-Engines für Express entwickeln + +Verwenden Sie die Methode `app.engine(ext, callback)`, um Ihre eigene Template-Engine zu erstellen. `ext` bezieht sich auf die Dateierweiterung, `callback` ist die Template-Engine-Funktion, die die folgenden Elemente als Parameter akzeptiert: die Position der Datei, das Optionsobjekt und die Callback-Funktion. + +Der folgende Code ist ein Beispiel für die Implementierung einer sehr einfachen Template-Engine für die Ausgabe von `.ntl`-Dateien. + +```js +const fs = require('fs'); // this engine requires the fs module +app.engine('ntl', (filePath, options, callback) => { + // define the template engine + fs.readFile(filePath, (err, content) => { + if (err) return callback(err); + // this is an extremely simple template engine + const rendered = content + .toString() + .replace('#title#', `${options.title}`) + .replace('#message#', `

    ${options.message}

    `); + return callback(null, rendered); + }); +}); +app.set('views', './views'); // specify the views directory +app.set('view engine', 'ntl'); // register the template engine +``` + +Ihre Anwendung ist jetzt in der Lage, `.ntl`-Dateien auszugeben. Erstellen Sie im Verzeichnis `views` eine Datei namens `index.ntl` mit dem folgenden Inhalt. + +```pug +#title# +#message# +``` + +Erstellen Sie dann in Ihrer Anwendung die folgende Route. + +```js +app.get('/', (req, res) => { + res.render('index', { title: 'Hey', message: 'Hello there!' }); +}); +``` + +Wenn Sie eine Anforderung zur Homepage einleiten, wird `index.ntl` im HTML-Format ausgegeben. diff --git a/astro/src/content/docs/de/5x/advanced/healthcheck-graceful-shutdown.md b/astro/src/content/docs/de/5x/advanced/healthcheck-graceful-shutdown.md new file mode 100644 index 0000000000..545baf7174 --- /dev/null +++ b/astro/src/content/docs/de/5x/advanced/healthcheck-graceful-shutdown.md @@ -0,0 +1,30 @@ +--- +title: Health Checks and Graceful Shutdown +description: Learn how to implement health checks and graceful shutdown in Express apps to enhance reliability, manage deployments, and integrate with load balancers like Kubernetes. +--- + +# Health Checks and Graceful Shutdown + +## Graceful shutdown + +When you deploy a new version of your application, you must replace the previous version. The process manager you're using will first send a SIGTERM signal to the application to notify it that it will be killed. Once the application gets this signal, it should stop accepting new requests, finish all the ongoing requests, clean up the resources it used, including database connections and file locks then exit. + +### Beispiel + +```js +const server = app.listen(port); + +process.on('SIGTERM', () => { + debug('SIGTERM signal received: closing HTTP server'); + server.close(() => { + debug('HTTP server closed'); + }); +}); +``` + +## Health checks + +A load balancer uses health checks to determine if an application instance is healthy and can accept requests. For example, [Kubernetes has two health checks](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/): + +- `liveness`, that determines when to restart a container. +- `readiness`, that determines when a container is ready to start accepting traffic. When a pod is not ready, it is removed from the service load balancers. diff --git a/astro/src/content/docs/de/5x/advanced/security-updates.md b/astro/src/content/docs/de/5x/advanced/security-updates.md new file mode 100644 index 0000000000..c4c6733905 --- /dev/null +++ b/astro/src/content/docs/de/5x/advanced/security-updates.md @@ -0,0 +1,84 @@ +--- +title: Express-Sicherheitsupdates +description: Review the latest security updates and patches for Express.js, including detailed vulnerability lists for different versions to help maintain a secure application. +--- + +# Sicherheitsupdates + +
    +Schwachstellen bei Node.js wirken sich direkt auf Express aus. Daher sollten Sie [ein Auge auf Schwachstellen bei Node.js haben](https://nodejs.org +/en/blog/vulnerability/) und sicherstellen, dass Sie die aktuelle stabile Version von Node.js haben. +
    + +Die folgende Liste enthält die Express-Schwachstellen, die im angegebenen Versionsupdate behoben wurden. + +{% capture security-policy %} +If you believe you have discovered a security vulnerability in Express, please see +[Security Policies and Procedures](/{{page.lang}}/resources/contributing.html#security-policies-and-procedures). +{% endcapture %} + +{% include admonitions/note.html content=security-policy %} + +## 4.x + +- 4.21.2 + - The dependency `path-to-regexp` has been updated to address a [vulnerability](https://github.com/pillarjs/path-to-regexp/security/advisories/GHSA-rhx6-c78j-4q9w). +- 4.21.1 + - The dependency `cookie` has been updated to address a [vulnerability](https://github.com/jshttp/cookie/security/advisories/GHSA-pxg6-pf52-xh8x), This may affect your application if you use `res.cookie`. +- 4.20.0 + - Fixed XSS vulnerability in `res.redirect` ([advisory](https://github.com/expressjs/express/security/advisories/GHSA-qw6h-vgh9-j6wx), [CVE-2024-43796](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-43796)). + - The dependency `serve-static` has been updated to address a [vulnerability](https://github.com/advisories/GHSA-cm22-4g7w-348p). + - The dependency `send` has been updated to address a [vulnerability](https://github.com/advisories/GHSA-m6fv-jmcg-4jfg). + - The dependency `path-to-regexp` has been updated to address a [vulnerability](https://github.com/pillarjs/path-to-regexp/security/advisories/GHSA-9wv6-86v2-598j). + - The dependency `body-parser` has been updated to addres a [vulnerability](https://github.com/advisories/GHSA-qwcr-r2fm-qrc7), This may affect your application if you had url enconding activated. +- 4.19.0, 4.19.1 + - Fixed open redirect vulnerability in `res.location` and `res.redirect` ([advisory](https://github.com/expressjs/express/security/advisories/GHSA-rv95-896h-c2vc), [CVE-2024-29041](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-29041)). +- 4.17.3 + - The dependency `qs` has been updated to address a [vulnerability](https://github.com/advisories/GHSA-hrpp-h998-j3pp). This may affect your application if the following APIs are used: `req.query`, `req.body`, `req.param`. +- 4.16.0 + - The dependency `forwarded` has been updated to address a [vulnerability](https://npmjs.com/advisories/527). This may affect your application if the following APIs are used: `req.host`, `req.hostname`, `req.ip`, `req.ips`, `req.protocol`. + - The dependency `mime` has been updated to address a [vulnerability](https://npmjs.com/advisories/535), but this issue does not impact Express. + - The dependency `send` has been updated to provide a protection against a [Node.js 8.5.0 vulnerability](https://nodejs.org/en/blog/vulnerability/september-2017-path-validation/). This only impacts running Express on the specific Node.js version 8.5.0. +- 4.15.5 + - The dependency `debug` has been updated to address a [vulnerability](https://snyk.io/vuln/npm:debug:20170905), but this issue does not impact Express. + - The dependency `fresh` has been updated to address a [vulnerability](https://npmjs.com/advisories/526). This will affect your application if the following APIs are used: `express.static`, `req.fresh`, `res.json`, `res.jsonp`, `res.send`, `res.sendfile` `res.sendFile`, `res.sendStatus`. +- 4.15.3 + - The dependency `ms` has been updated to address a [vulnerability](https://snyk.io/vuln/npm:ms:20170412). This may affect your application if untrusted string input is passed to the `maxAge` option in the following APIs: `express.static`, `res.sendfile`, and `res.sendFile`. +- 4.15.2 + - The dependency `qs` has been updated to address a [vulnerability](https://snyk.io/vuln/npm:qs:20170213), but this issue does not impact Express. Updating to 4.15.2 is a good practice, but not required to address the vulnerability. +- 4.11.1 + - Offenlegungsgefahr beim Rootpfad in `express.static`, `res.sendfile` und `res.sendFile` behoben. +- 4.10.7 + - Offene Umadressierungsschwachstelle in `express.static` ([Empfehlung](https://npmjs.com/advisories/35), [CVE-2015-1164](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-1164)) behoben. +- 4.8.8 + - Schwachstellen durch Directory-Traversal-Technik in `express.static` ([Empfehlung](http://npmjs.com/advisories/32) , [CVE-2014-6394](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-6394)) behoben. +- 4.8.4 + - Node.js 0.10 kann in bestimmten Situationen Lecks bei `fd` aufweisen, die sich auf `express.static` und `res.sendfile` auswirken. Böswillige Anforderungen können zu Lecks bei `fd` führen und letztendlich `EMFILE`-Fehler nach sich ziehen und bewirken, dass Server nicht antworten. +- 4.8.0 + - Sparse-Arrays mit extrem hohen Indizes in der Abfragezeichenfolge können bewirken, dass für die Prozessausführung nicht genügend Arbeitsspeicher zur Verfügung steht und es zu einem Serverabsturz kommt. + - Extrem verschachtelte Abfragezeichenfolgenobjekte können bewirken, dass der Prozess blockiert und der Server dadurch vorübergehend nicht antwortet. + +## 3.x + +
    + **Express 3.x WIRD NICHT MEHR GEWARTET** + +Bekannte und unbekannte Probleme bei Sicherheit und Leistung in 3.x wurden seit dem letzten Update (1. August 2015) noch nicht behoben. Es wird dringend empfohlen, die aktuelle Version von Express zu verwenden. + +If you are unable to upgrade past 3.x, please consider [Commercial Support Options](/{{ page.lang }}/support#commercial-support-options). + +
    + +- 3.19.1 + - Offenlegungsgefahr beim Rootpfad in `express.static`, `res.sendfile` und `res.sendFile` behoben. +- 3.19.0 + - Offene Umadressierungsschwachstelle in `express.static` ([Empfehlung](https://npmjs.com/advisories/35), [CVE-2015-1164](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-1164)) behoben. +- 3.16.10 + - Schwachstellen durch Directory-Traversal-Technik in `express.static` behoben. +- 3.16.6 + - Node.js 0.10 kann in bestimmten Situationen Lecks bei `fd` aufweisen, die sich auf `express.static` und `res.sendfile` auswirken. Böswillige Anforderungen können zu Lecks bei `fd` führen und letztendlich `EMFILE`-Fehler nach sich ziehen und bewirken, dass Server nicht antworten. +- 3.16.0 + - Sparse-Arrays mit extrem hohen Indizes in der Abfragezeichenfolge können bewirken, dass für die Prozessausführung nicht genügend Arbeitsspeicher zur Verfügung steht und es zu einem Serverabsturz kommt. + - Extrem verschachtelte Abfragezeichenfolgenobjekte können bewirken, dass der Prozess blockiert und der Server dadurch vorübergehend nicht antwortet. +- 3.3.0 + - Die Antwort 404 bei einem nicht unterstützten Überschreibungsversuch war anfällig gegen Cross-Site Scripting-Attacken. diff --git a/astro/src/content/docs/de/5x/api.md b/astro/src/content/docs/de/5x/api.md new file mode 100644 index 0000000000..47f8327c8e --- /dev/null +++ b/astro/src/content/docs/de/5x/api.md @@ -0,0 +1,26 @@ +--- +version: 5x +title: Express 5.x - API-Referenz +description: Access the API reference for Express.js 5.x, detailing all modules, methods, and properties for building web applications with this latest version. +--- + +
    + +

    5.x API

    + +{% capture node-version %} + +Express 5.0 requires Node.js 18 or higher. + +{% endcapture %} + +{% include admonitions/note.html content=node-version %} + + +{% include api/en/5x/express.md %} +{% include api/en/5x/app.md %} +{% include api/en/5x/req.md %} +{% include api/en/5x/res.md %} +{% include api/en/5x/router.md %} + +
    diff --git a/astro/src/content/docs/de/5x/api/application/app-METHOD.md b/astro/src/content/docs/de/5x/api/application/app-METHOD.md new file mode 100644 index 0000000000..5251777667 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/application/app-METHOD.md @@ -0,0 +1,65 @@ +--- +title: app.METHOD +description: Routes an HTTP request, where METHOD is the HTTP method of the request, such as GET, +--- + +

    app.METHOD(path, callback [, callback ...])

    + +Routes an HTTP request, where METHOD is the HTTP method of the request, such as GET, +PUT, POST, and so on, in lowercase. Thus, the actual methods are `app.get()`, +`app.post()`, `app.put()`, and so on. See [Routing methods](#routing-methods) below for the complete list. + +{% include api/en/5x/routing-args.html %} + +#### Routing methods + +Express supports the following routing methods corresponding to the HTTP methods of the same names: + +
    +
      +
    • checkout
    • +
    • copy
    • +
    • delete
    • +
    • get
    • +
    • head
    • +
    • lock
    • +
    • merge
    • +
    • mkactivity
    • +
    +
      +
    • mkcol
    • +
    • move
    • +
    • m-search
    • +
    • notify
    • +
    • options
    • +
    • patch
    • +
    • post
    • +
    +
      +
    • purge
    • +
    • put
    • +
    • report
    • +
    • search
    • +
    • subscribe
    • +
    • trace
    • +
    • unlock
    • +
    • unsubscribe
    • +
    +
    + +The API documentation has explicit entries only for the most popular HTTP methods `app.get()`, +`app.post()`, `app.put()`, and `app.delete()`. +However, the other methods listed above work in exactly the same way. + +To route methods that translate to invalid JavaScript variable names, use the bracket notation. For example, `app['m-search']('/', function ...`. + +
    + The `app.get()` function is automatically called for the HTTP `HEAD` method in addition to the `GET` + method if `app.head()` was not called for the path before `app.get()`. +
    + +The method, `app.all()`, is not derived from any HTTP method and loads middleware at +the specified path for _all_ HTTP request methods. +For more information, see [app.all](#app.all). + +For more information on routing, see the [routing guide](/{{page.lang}}/guide/routing.html). diff --git a/astro/src/content/docs/de/5x/api/application/app-all.md b/astro/src/content/docs/de/5x/api/application/app-all.md new file mode 100644 index 0000000000..62daf475b3 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/application/app-all.md @@ -0,0 +1,49 @@ +--- +title: app.all +description: This method is like the standard [app.METHOD()](#app.METHOD) methods, +--- + +

    app.all(path, callback [, callback ...])

    + +This method is like the standard [app.METHOD()](#app.METHOD) methods, +except it matches all HTTP verbs. + +{% include api/en/5x/routing-args.html %} + +#### Examples + +The following callback is executed for requests to `/secret` whether using +GET, POST, PUT, DELETE, or any other HTTP request method: + +```js +app.all('/secret', (req, res, next) => { + console.log('Accessing the secret section ...'); + next(); // pass control to the next handler +}); +``` + +The `app.all()` method is useful for mapping "global" logic for specific path prefixes or arbitrary matches. For example, if you put the following at the top of all other +route definitions, it requires that all routes from that point on +require authentication, and automatically load a user. Keep in mind +that these callbacks do not have to act as end-points: `loadUser` +can perform a task, then call `next()` to continue matching subsequent +routes. + +```js +app.all('{*splat}', requireAuthentication, loadUser); +``` + +Or the equivalent: + +```js +app.all('{*splat}', requireAuthentication); +app.all('{*splat}', loadUser); +``` + +Another example is white-listed "global" functionality. +The example is similar to the ones above, but it only restricts paths that start with +"/api": + +```js +app.all('/api/{*splat}', requireAuthentication); +``` diff --git a/astro/src/content/docs/de/5x/api/application/app-delete-method.md b/astro/src/content/docs/de/5x/api/application/app-delete-method.md new file mode 100644 index 0000000000..bbc76ab702 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/application/app-delete-method.md @@ -0,0 +1,19 @@ +--- +title: app.delete +description: Routes HTTP DELETE requests to the specified path with the specified callback functions. +--- + +

    app.delete(path, callback [, callback ...])

    + +Routes HTTP DELETE requests to the specified path with the specified callback functions. +For more information, see the [routing guide](/{{page.lang}}/guide/routing.html). + +{% include api/en/5x/routing-args.html %} + +#### Example + +```js +app.delete('/', (req, res) => { + res.send('DELETE request to homepage'); +}); +``` diff --git a/astro/src/content/docs/de/5x/api/application/app-disable.md b/astro/src/content/docs/de/5x/api/application/app-disable.md new file mode 100644 index 0000000000..3c269bf4f6 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/application/app-disable.md @@ -0,0 +1,17 @@ +--- +title: app.disable +description: Sets the Boolean setting name to false, where name is one of the properties from the app settings table. +--- + +

    app.disable(name)

    + +Sets the Boolean setting `name` to `false`, where `name` is one of the properties from the [app settings table](#app.settings.table). +Calling `app.set('foo', false)` for a Boolean property is the same as calling `app.disable('foo')`. + +For example: + +```js +app.disable('trust proxy'); +app.get('trust proxy'); +// => false +``` diff --git a/astro/src/content/docs/de/5x/api/application/app-disabled.md b/astro/src/content/docs/de/5x/api/application/app-disabled.md new file mode 100644 index 0000000000..8183edb278 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/application/app-disabled.md @@ -0,0 +1,18 @@ +--- +title: app.disabled +description: Returns true if the Boolean setting name is disabled (false), where name is one of the properties from +--- + +

    app.disabled(name)

    + +Returns `true` if the Boolean setting `name` is disabled (`false`), where `name` is one of the properties from +the [app settings table](#app.settings.table). + +```js +app.disabled('trust proxy'); +// => true + +app.enable('trust proxy'); +app.disabled('trust proxy'); +// => false +``` diff --git a/astro/src/content/docs/de/5x/api/application/app-enable.md b/astro/src/content/docs/de/5x/api/application/app-enable.md new file mode 100644 index 0000000000..209d3364a8 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/application/app-enable.md @@ -0,0 +1,15 @@ +--- +title: app.enable +description: Sets the Boolean setting name to true, where name is one of the properties from the app settings table. +--- + +

    app.enable(name)

    + +Sets the Boolean setting `name` to `true`, where `name` is one of the properties from the [app settings table](#app.settings.table). +Calling `app.set('foo', true)` for a Boolean property is the same as calling `app.enable('foo')`. + +```js +app.enable('trust proxy'); +app.get('trust proxy'); +// => true +``` diff --git a/astro/src/content/docs/de/5x/api/application/app-enabled.md b/astro/src/content/docs/de/5x/api/application/app-enabled.md new file mode 100644 index 0000000000..d63c469d48 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/application/app-enabled.md @@ -0,0 +1,18 @@ +--- +title: app.enabled +description: Returns true if the setting name is enabled (true), where name is one of the properties from the app settings table +--- + +

    app.enabled(name)

    + +Returns `true` if the setting `name` is enabled (`true`), where `name` is one of the +properties from the [app settings table](#app.settings.table). + +```js +app.enabled('trust proxy'); +// => false + +app.enable('trust proxy'); +app.enabled('trust proxy'); +// => true +``` diff --git a/astro/src/content/docs/de/5x/api/application/app-engine.md b/astro/src/content/docs/de/5x/api/application/app-engine.md new file mode 100644 index 0000000000..7096d556f2 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/application/app-engine.md @@ -0,0 +1,41 @@ +--- +title: app.engine +description: Registers the given template engine callback as ext. +--- + +

    app.engine(ext, callback)

    + +Registers the given template engine `callback` as `ext`. + +By default, Express will `require()` the engine based on the file extension. +For example, if you try to render a "foo.pug" file, Express invokes the +following internally, and caches the `require()` on subsequent calls to increase +performance. + +```js +app.engine('pug', require('pug').__express); +``` + +Use this method for engines that do not provide `.__express` out of the box, +or if you wish to "map" a different extension to the template engine. + +For example, to map the EJS template engine to ".html" files: + +```js +app.engine('html', require('ejs').renderFile); +``` + +In this case, EJS provides a `.renderFile()` method with +the same signature that Express expects: `(path, options, callback)`, +though note that it aliases this method as `ejs.__express` internally +so if you're using ".ejs" extensions you don't need to do anything. + +Some template engines do not follow this convention. The +[consolidate.js](https://github.com/tj/consolidate.js) library maps Node template engines to follow this convention, +so they work seamlessly with Express. + +```js +const engines = require('consolidate'); +app.engine('haml', engines.haml); +app.engine('html', engines.hogan); +``` diff --git a/astro/src/content/docs/de/5x/api/application/app-get-method.md b/astro/src/content/docs/de/5x/api/application/app-get-method.md new file mode 100644 index 0000000000..8ad8b292d4 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/application/app-get-method.md @@ -0,0 +1,20 @@ +--- +title: app.get +description: Routes HTTP GET requests to the specified path with the specified callback functions. +--- + +

    app.get(path, callback [, callback ...])

    + +Routes HTTP GET requests to the specified path with the specified callback functions. + +{% include api/en/5x/routing-args.html %} + +For more information, see the [routing guide](/{{page.lang}}/guide/routing.html). + +#### Example + +```js +app.get('/', (req, res) => { + res.send('GET request to homepage'); +}); +``` diff --git a/astro/src/content/docs/de/5x/api/application/app-get.md b/astro/src/content/docs/de/5x/api/application/app-get.md new file mode 100644 index 0000000000..f385b1bfb9 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/application/app-get.md @@ -0,0 +1,18 @@ +--- +title: app.get +description: Returns the value of name app setting, where name is one of the strings in the app settings table +--- + +

    app.get(name)

    + +Returns the value of `name` app setting, where `name` is one of the strings in the +[app settings table](#app.settings.table). For example: + +```js +app.get('title'); +// => undefined + +app.set('title', 'My Site'); +app.get('title'); +// => "My Site" +``` diff --git a/astro/src/content/docs/de/5x/api/application/app-listen.md b/astro/src/content/docs/de/5x/api/application/app-listen.md new file mode 100644 index 0000000000..b7845a8c3c --- /dev/null +++ b/astro/src/content/docs/de/5x/api/application/app-listen.md @@ -0,0 +1,56 @@ +--- +title: app.listen +description: Starts a UNIX socket and listens for connections on the given path. +--- + +

    app.listen(path, [callback])

    + +Starts a UNIX socket and listens for connections on the given path. +This method is identical to Node's [http.Server.listen()](https://nodejs.org/api/http.html#http_server_listen). + +```js +const express = require('express'); +const app = express(); +app.listen('/tmp/sock'); +``` + +

    app.listen([port[, host[, backlog]]][, callback])

    + +Binds and listens for connections on the specified host and port. +This method is identical to Node's [http.Server.listen()](https://nodejs.org/api/http.html#http_server_listen). + +If port is omitted or is 0, the operating system will assign an arbitrary unused +port, which is useful for cases like automated tasks (tests, etc.). + +```js +const express = require('express'); +const app = express(); +app.listen(3000); +``` + +The `app` returned by `express()` is in fact a JavaScript +`Function`, designed to be passed to Node's HTTP servers as a callback +to handle requests. This makes it easy to provide both HTTP and HTTPS versions of +your app with the same code base, as the app does not inherit from these +(it is simply a callback): + +```js +const express = require('express'); +const https = require('https'); +const http = require('http'); +const app = express(); + +http.createServer(app).listen(80); +https.createServer(options, app).listen(443); +``` + +The `app.listen()` method returns an [http.Server](https://nodejs.org/api/http.html#http_class_http_server) object and (for HTTP) is a convenience method for the following: + +```js +app.listen = function () { + const server = http.createServer(this); + return server.listen.apply(server, arguments); +}; +``` + +{% include admonitions/note.html content="All the forms of Node's [http.Server.listen()](https://nodejs.org/api/http.html#http_server_listen) method are in fact actually supported." %} diff --git a/astro/src/content/docs/de/5x/api/application/app-locals.md b/astro/src/content/docs/de/5x/api/application/app-locals.md new file mode 100644 index 0000000000..f3718bc1a6 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/application/app-locals.md @@ -0,0 +1,39 @@ +--- +title: app.locals +description: The app.locals object has properties that are local variables within the application, +--- + +

    app.locals

    + +The `app.locals` object has properties that are local variables within the application, +and will be available in templates rendered with [res.render](#res.render). + +
    +The `locals` object is used by view engines to render a response. The object +keys may be particularly sensitive and should not contain user-controlled +input, as it may affect the operation of the view engine or provide a path to +cross-site scripting. Consult the documentation for the used view engine for +additional considerations. +
    + +```js +console.dir(app.locals.title); +// => 'My App' + +console.dir(app.locals.email); +// => 'me@myapp.com' +``` + +Once set, the value of `app.locals` properties persist throughout the life of the application, +in contrast with [res.locals](#res.locals) properties that +are valid only for the lifetime of the request. + +You can access local variables in templates rendered within the application. +This is useful for providing helper functions to templates, as well as application-level data. +Local variables are available in middleware via `req.app.locals` (see [req.app](#req.app)) + +```js +app.locals.title = 'My App'; +app.locals.strftime = require('strftime'); +app.locals.email = 'me@myapp.com'; +``` diff --git a/astro/src/content/docs/de/5x/api/application/app-mountpath.md b/astro/src/content/docs/de/5x/api/application/app-mountpath.md new file mode 100644 index 0000000000..1b0b530f69 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/application/app-mountpath.md @@ -0,0 +1,50 @@ +--- +title: app.mountpath +description: The app.mountpath property contains one or more path patterns on which a sub-app was mounted. +--- + +

    app.mountpath

    + +The `app.mountpath` property contains one or more path patterns on which a sub-app was mounted. + +
    + A sub-app is an instance of `express` that may be used for handling the request to a route. +
    + +```js +const express = require('express'); + +const app = express(); // the main app +const admin = express(); // the sub app + +admin.get('/', (req, res) => { + console.log(admin.mountpath); // /admin + res.send('Admin Homepage'); +}); + +app.use('/admin', admin); // mount the sub app +``` + +It is similar to the [baseUrl](#req.baseUrl) property of the `req` object, except `req.baseUrl` +returns the matched URL path, instead of the matched patterns. + +If a sub-app is mounted on multiple path patterns, `app.mountpath` returns the list of +patterns it is mounted on, as shown in the following example. + +```js +const admin = express(); + +admin.get('/', (req, res) => { + console.log(admin.mountpath); // [ '/adm{*splat}n', '/manager' ] + res.send('Admin Homepage'); +}); + +const secret = express(); +secret.get('/', (req, res) => { + console.log(secret.mountpath); // /secr{*splat}t + res.send('Admin Secret'); +}); + +admin.use('/secr{*splat}t', secret); // load the 'secret' router on '/secr{*splat}t', on the 'admin' sub app +app.use(['/adm{*splat}n', '/manager'], admin); // load the 'admin' router on '/adm{*splat}n' and '/manager', on the parent app +``` diff --git a/astro/src/content/docs/de/5x/api/application/app-onmount.md b/astro/src/content/docs/de/5x/api/application/app-onmount.md new file mode 100644 index 0000000000..0ca99b82e0 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/application/app-onmount.md @@ -0,0 +1,35 @@ +--- +title: app.on +description: The mount event is fired on a sub-app, when it is mounted on a parent app. The parent app is passed to the callback function. +--- + +

    app.on('mount', callback(parent))

    + +The `mount` event is fired on a sub-app, when it is mounted on a parent app. The parent app is passed to the callback function. + +
    +**NOTE** + +Sub-apps will: + +- Not inherit the value of settings that have a default value. You must set the value in the sub-app. +- Inherit the value of settings with no default value. + +For details, see [Application settings](/en/5x/api.html#app.settings.table). + +
    + +```js +const admin = express(); + +admin.on('mount', (parent) => { + console.log('Admin Mounted'); + console.log(parent); // refers to the parent app +}); + +admin.get('/', (req, res) => { + res.send('Admin Homepage'); +}); + +app.use('/admin', admin); +``` diff --git a/astro/src/content/docs/de/5x/api/application/app-param.md b/astro/src/content/docs/de/5x/api/application/app-param.md new file mode 100644 index 0000000000..b3ca5ccd89 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/application/app-param.md @@ -0,0 +1,83 @@ +--- +title: app.param +description: Add callback triggers to route parameters, where name is the name of the parameter or an array of parameter names, and callback is the callback function. +--- + +

    app.param(name, callback)

    + +Add callback triggers to [route parameters](/{{ page.lang }}/guide/routing.html#route-parameters), where `name` is the name of the parameter or an array of them, and `callback` is the callback function. The parameters of the callback function are the request object, the response object, the next middleware, the value of the parameter and the name of the parameter, in that order. + +If `name` is an array, the `callback` trigger is registered for each parameter declared in it, in the order in which they are declared. Furthermore, for each declared parameter except the last one, a call to `next` inside the callback will call the callback for the next declared parameter. For the last parameter, a call to `next` will call the next middleware in place for the route currently being processed, just like it would if `name` were just a string. + +For example, when `:user` is present in a route path, you may map user loading logic to automatically provide `req.user` to the route, or perform validations on the parameter input. + +```js +app.param('user', (req, res, next, id) => { + // try to get the user details from the User model and attach it to the request object + User.find(id, (err, user) => { + if (err) { + next(err); + } else if (user) { + req.user = user; + next(); + } else { + next(new Error('failed to load user')); + } + }); +}); +``` + +Param callback functions are local to the router on which they are defined. They are not inherited by mounted apps or routers, nor are they triggered for route parameters inherited from parent routers. Hence, param callbacks defined on `app` will be triggered only by route parameters defined on `app` routes. + +All param callbacks will be called before any handler of any route in which the param occurs, and they will each be called only once in a request-response cycle, even if the parameter is matched in multiple routes, as shown in the following examples. + +```js +app.param('id', (req, res, next, id) => { + console.log('CALLED ONLY ONCE'); + next(); +}); + +app.get('/user/:id', (req, res, next) => { + console.log('although this matches'); + next(); +}); + +app.get('/user/:id', (req, res) => { + console.log('and this matches too'); + res.end(); +}); +``` + +On `GET /user/42`, the following is printed: + +``` +CALLED ONLY ONCE +although this matches +and this matches too +``` + +```js +app.param(['id', 'page'], (req, res, next, value) => { + console.log('CALLED ONLY ONCE with', value); + next(); +}); + +app.get('/user/:id/:page', (req, res, next) => { + console.log('although this matches'); + next(); +}); + +app.get('/user/:id/:page', (req, res) => { + console.log('and this matches too'); + res.end(); +}); +``` + +On `GET /user/42/3`, the following is printed: + +``` +CALLED ONLY ONCE with 42 +CALLED ONLY ONCE with 3 +although this matches +and this matches too +``` diff --git a/astro/src/content/docs/de/5x/api/application/app-path.md b/astro/src/content/docs/de/5x/api/application/app-path.md new file mode 100644 index 0000000000..78c6885667 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/application/app-path.md @@ -0,0 +1,24 @@ +--- +title: app.path +description: Returns the canonical path of the app, a string. +--- + +

    app.path()

    + +Returns the canonical path of the app, a string. + +```js +const app = express(); +const blog = express(); +const blogAdmin = express(); + +app.use('/blog', blog); +blog.use('/admin', blogAdmin); + +console.log(app.path()); // '' +console.log(blog.path()); // '/blog' +console.log(blogAdmin.path()); // '/blog/admin' +``` + +The behavior of this method can become very complicated in complex cases of mounted apps: +it is usually better to use [req.baseUrl](#req.baseUrl) to get the canonical path of the app. diff --git a/astro/src/content/docs/de/5x/api/application/app-post-method.md b/astro/src/content/docs/de/5x/api/application/app-post-method.md new file mode 100644 index 0000000000..e961081239 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/application/app-post-method.md @@ -0,0 +1,19 @@ +--- +title: app.post +description: Routes HTTP POST requests to the specified path with the specified callback functions. +--- + +

    app.post(path, callback [, callback ...])

    + +Routes HTTP POST requests to the specified path with the specified callback functions. +For more information, see the [routing guide](/{{page.lang}}/guide/routing.html). + +{% include api/en/5x/routing-args.html %} + +#### Example + +```js +app.post('/', (req, res) => { + res.send('POST request to homepage'); +}); +``` diff --git a/astro/src/content/docs/de/5x/api/application/app-put-method.md b/astro/src/content/docs/de/5x/api/application/app-put-method.md new file mode 100644 index 0000000000..2eb53a77eb --- /dev/null +++ b/astro/src/content/docs/de/5x/api/application/app-put-method.md @@ -0,0 +1,18 @@ +--- +title: app.put +description: Routes HTTP PUT requests to the specified path with the specified callback functions. +--- + +

    app.put(path, callback [, callback ...])

    + +Routes HTTP PUT requests to the specified path with the specified callback functions. + +{% include api/en/5x/routing-args.html %} + +#### Example + +```js +app.put('/', (req, res) => { + res.send('PUT request to homepage'); +}); +``` diff --git a/astro/src/content/docs/de/5x/api/application/app-render.md b/astro/src/content/docs/de/5x/api/application/app-render.md new file mode 100644 index 0000000000..d5f65bf258 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/application/app-render.md @@ -0,0 +1,44 @@ +--- +title: app.render +description: Returns the rendered HTML of a view via the callback function. It accepts an optional parameter that is an object containing local variables for the vie +--- + +

    app.render(view, [locals], callback)

    + +Returns the rendered HTML of a view via the `callback` function. It accepts an optional parameter +that is an object containing local variables for the view. It is like [res.render()](#res.render), +except it cannot send the rendered view to the client on its own. + +
    +Think of `app.render()` as a utility function for generating rendered view strings. +Internally `res.render()` uses `app.render()` to render views. +
    + +
    +The `view` argument performs file system operations like reading a file from +disk and evaluating Node.js modules, and as so for security reasons should not +contain input from the end-user. +
    + +
    +The `locals` object is used by view engines to render a response. The object +keys may be particularly sensitive and should not contain user-controlled +input, as it may affect the operation of the view engine or provide a path to +cross-site scripting. Consult the documentation for the used view engine for +additional considerations. +
    + +
    +The local variable `cache` is reserved for enabling view cache. Set it to `true`, if you want to +cache view during development; view caching is enabled in production by default. +
    + +```js +app.render('email', (err, html) => { + // ... +}); + +app.render('email', { name: 'Tobi' }, (err, html) => { + // ... +}); +``` diff --git a/astro/src/content/docs/de/5x/api/application/app-route.md b/astro/src/content/docs/de/5x/api/application/app-route.md new file mode 100644 index 0000000000..a0f9816d5d --- /dev/null +++ b/astro/src/content/docs/de/5x/api/application/app-route.md @@ -0,0 +1,26 @@ +--- +title: app.route +description: Returns an instance of a single route, which you can then use to handle HTTP verbs with optional middleware. +--- + +

    app.route(path)

    + +Returns an instance of a single route, which you can then use to handle HTTP verbs with optional middleware. +Use `app.route()` to avoid duplicate route names (and thus typo errors). + +```js +const app = express(); + +app + .route('/events') + .all((req, res, next) => { + // runs for all HTTP verbs first + // think of it as route specific middleware! + }) + .get((req, res, next) => { + res.json({}); + }) + .post((req, res, next) => { + // maybe add a new event... + }); +``` diff --git a/astro/src/content/docs/de/5x/api/application/app-router.md b/astro/src/content/docs/de/5x/api/application/app-router.md new file mode 100644 index 0000000000..6bd664d291 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/application/app-router.md @@ -0,0 +1,24 @@ +--- +title: app.router +description: The application's in-built instance of router. This is created lazily, on first access. +--- + +

    app.router

    + +The application's in-built instance of router. This is created lazily, on first access. + +```js +const express = require('express'); +const app = express(); +const router = app.router; + +router.get('/', (req, res) => { + res.send('hello world'); +}); + +app.listen(3000); +``` + +You can add middleware and HTTP method routes to the `router` just like an application. + +For more information, see [Router](#router). diff --git a/astro/src/content/docs/de/5x/api/application/app-set.md b/astro/src/content/docs/de/5x/api/application/app-set.md new file mode 100644 index 0000000000..87302a6b81 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/application/app-set.md @@ -0,0 +1,25 @@ +--- +title: app.set +description: Assigns setting name to value +--- + +

    app.set(name, value)

    + +Assigns setting `name` to `value`. You may store any value that you want, +but certain names can be used to configure the behavior of the server. These +special names are listed in the [app settings table](#app.settings.table). + +Calling `app.set('foo', true)` for a Boolean property is the same as calling +`app.enable('foo')`. Similarly, calling `app.set('foo', false)` for a Boolean +property is the same as calling `app.disable('foo')`. + +Retrieve the value of a setting with [`app.get()`](#app.get). + +```js +app.set('title', 'My Site'); +app.get('title'); // "My Site" +``` + +

    Application Settings

    + +{% include api/en/5x/app-settings.md %} diff --git a/astro/src/content/docs/de/5x/api/application/app-settings.md b/astro/src/content/docs/de/5x/api/application/app-settings.md new file mode 100644 index 0000000000..5443d70d77 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/application/app-settings.md @@ -0,0 +1,335 @@ +--- +title: App.Settings +description: The following table lists application settings. +--- + +The following table lists application settings. + +Note that sub-apps will: + +- Not inherit the value of settings that have a default value. You must set the value in the sub-app. +- Inherit the value of settings with no default value; these are explicitly noted in the table below. + +Exceptions: Sub-apps will inherit the value of `trust proxy` even though it has a default value (for backward-compatibility); +Sub-apps will not inherit the value of `view cache` in production (when `NODE_ENV` is "production"). + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    PropertyTypeDescriptionDefault
    + `case sensitive routing` + Boolean

    Enable case sensitivity. + When enabled, "/Foo" and "/foo" are different routes. + When disabled, "/Foo" and "/foo" are treated the same.

    +

    NOTE: Sub-apps will inherit the value of this setting.

    +
    N/A (undefined) +
    + `env` + StringEnvironment mode. + Be sure to set to "production" in a production environment; + see Production best practices: performance and reliability. + + `process.env.NODE_ENV` (`NODE_ENV` environment variable) or "development" if `NODE_ENV` is not set. +
    + `etag` + Varied + Set the ETag response header. For possible values, see the [`etag` options table](#etag.options.table). + +[More about the HTTP ETag header](http://en.wikipedia.org/wiki/HTTP_ETag). + + + `weak` +
    + `jsonp callback name` + StringSpecifies the default JSONP callback name. + "callback" +
    + `json escape` + Boolean + Enable escaping JSON responses from the `res.json`, `res.jsonp`, and `res.send` APIs. This will escape the characters `<`, `>`, and `&` as Unicode escape sequences in JSON. The purpose of this is to assist with [mitigating certain types of persistent XSS attacks](https://blog.mozilla.org/security/2017/07/18/web-service-audits-firefox-accounts/) when clients sniff responses for HTML. +

    NOTE: Sub-apps will inherit the value of this setting.

    +
    N/A (undefined)
    + `json replacer` + VariedThe 'replacer' argument used by `JSON.stringify`. +

    NOTE: Sub-apps will inherit the value of this setting.

    +
    N/A (undefined) +
    + `json spaces` + VariedThe 'space' argument used by `JSON.stringify`. +This is typically set to the number of spaces to use to indent prettified JSON. +

    NOTE: Sub-apps will inherit the value of this setting.

    +
    N/A (undefined)
    + `query parser` + Varied +Disable query parsing by setting the value to `false`, or set the query parser to use either "simple" or "extended" or a custom query string parsing function. + +The simple query parser is based on Node's native query parser, [querystring](http://nodejs.org/api/querystring.html). + +The extended query parser is based on [qs](https://www.npmjs.org/package/qs). + +A custom query string parsing function will receive the complete query string, and must return an object of query keys and their values. + + "simple"
    + `strict routing` + Boolean

    Enable strict routing. + When enabled, the router treats "/foo" and "/foo/" as different. + Otherwise, the router treats "/foo" and "/foo/" as the same.

    +

    NOTE: Sub-apps will inherit the value of this setting.

    +
    N/A (undefined)
    + `subdomain offset` + NumberThe number of dot-separated parts of the host to remove to access subdomain.2
    + `trust proxy` + Varied + Indicates the app is behind a front-facing proxy, and to use the `X-Forwarded-*` headers to determine the connection and the IP address of the client. NOTE: `X-Forwarded-*` headers are easily spoofed and the detected IP addresses are unreliable. +

    + When enabled, Express attempts to determine the IP address of the client connected through the front-facing proxy, or series of proxies. The `req.ips` property, then contains an array of IP addresses the client is connected through. To enable it, use the values described in the trust proxy options table. +

    + The `trust proxy` setting is implemented using the proxy-addr package. For more information, see its documentation. +

    +NOTE: Sub-apps will inherit the value of this setting, even though it has a default value. +

    +
    + `false` (disabled) +
    + `views` + String or ArrayA directory or an array of directories for the application's views. If an array, the views are looked up in the order they occur in the array. + `process.cwd() + '/views'` +
    + `view cache` + Boolean

    Enables view template compilation caching.

    +

    NOTE: Sub-apps will not inherit the value of this setting in production (when `NODE_ENV` is "production").

    +
    + `true` in production, otherwise undefined. +
    + `view engine` + StringThe default engine extension to use when omitted. +

    NOTE: Sub-apps will inherit the value of this setting.

    +
    N/A (undefined)
    + `x-powered-by` + BooleanEnables the "X-Powered-By: Express" HTTP header. + `true` +
    +
    + +
    Options for `trust proxy` setting
    + +

    + Read [Express behind proxies](/{{page.lang}}/guide/behind-proxies.html) for more + information. +

    + +
    + + + + + + + + + + + + + + + + + + + + +
    TypeValue
    Boolean + If `true`, the client's IP address is understood as the left-most entry in the `X-Forwarded-*` header. + +If `false`, the app is understood as directly facing the Internet and the client's IP address is derived from `req.connection.remoteAddress`. This is the default setting. + +
    String
    String containing comma-separated values
    Array of strings
    + An IP address, subnet, or an array of IP addresses, and subnets to trust. Pre-configured subnet names are: + +- loopback - `127.0.0.1/8`, `::1/128` +- linklocal - `169.254.0.0/16`, `fe80::/10` +- uniquelocal - `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `fc00::/7` + +Set IP addresses in any of the following ways: + +Specify a single subnet: + +```js +app.set('trust proxy', 'loopback'); +``` + +Specify a subnet and an address: + +```js +app.set('trust proxy', 'loopback, 123.123.123.123'); +``` + +Specify multiple subnets as CSV: + +```js +app.set('trust proxy', 'loopback, linklocal, uniquelocal'); +``` + +Specify multiple subnets as an array: + +```js +app.set('trust proxy', ['loopback', 'linklocal', 'uniquelocal']); +``` + +When specified, the IP addresses or the subnets are excluded from the address determination process, and the untrusted IP address nearest to the application server is determined as the client's IP address. + +
    Number + Trust the nth hop from the front-facing proxy server as the client. +
    Function + Custom trust implementation. Use this only if you know what you are doing. + +```js +app.set('trust proxy', (ip) => { + if (ip === '127.0.0.1' || ip === '123.123.123.123') + return true; // trusted IPs + else return false; +}); +``` + +
    +
    + +
    Options for `etag` setting
    + +

    +**NOTE**: These settings apply only to dynamic files, not static files. +The [express.static](#express.static) middleware ignores these settings. +

    + +

    + The ETag functionality is implemented using the + [etag](https://www.npmjs.org/package/etag) package. + For more information, see its documentation. +

    + +
    + + + + + + + + + + + + + + + + +
    TypeValue
    Boolean + `true` enables weak ETag. This is the default setting.
    + `false` disables ETag altogether. +
    String + If "strong", enables strong ETag.
    + If "weak", enables weak ETag. +
    FunctionCustom ETag function implementation. Use this only if you know what you are doing. + +```js +app.set('etag', (body, encoding) => { + return generateHash(body, encoding); // consider the function is defined +}); +``` + +
    +
    diff --git a/astro/src/content/docs/de/5x/api/application/app-use.md b/astro/src/content/docs/de/5x/api/application/app-use.md new file mode 100644 index 0000000000..8a16a4e339 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/application/app-use.md @@ -0,0 +1,310 @@ +--- +title: app.use +description: Mounts the specified [middleware](/{{page.lang}}/guide/using-middleware.html) function or functions +--- + +

    app.use([path,] callback [, callback...])

    + +Mounts the specified [middleware](/{{page.lang}}/guide/using-middleware.html) function or functions +at the specified path: +the middleware function is executed when the base of the requested path matches `path`. + +{% include api/en/5x/routing-args.html %} + +#### Description + +A route will match any path that follows its path immediately with a "`/`". +For example: `app.use('/apple', ...)` will match "/apple", "/apple/images", +"/apple/images/news", and so on. + +Since `path` defaults to "/", middleware mounted without a path will be executed for every request to the app. +For example, this middleware function will be executed for _every_ request to the app: + +```js +app.use((req, res, next) => { + console.log('Time: %d', Date.now()); + next(); +}); +``` + +
    +**NOTE** + +Sub-apps will: + +- Not inherit the value of settings that have a default value. You must set the value in the sub-app. +- Inherit the value of settings with no default value. + +For details, see [Application settings](/en/5x/api.html#app.settings.table). + +
    + +Middleware functions are executed sequentially, therefore the order of middleware inclusion is important. + +```js +// this middleware will not allow the request to go beyond it +app.use((req, res, next) => { + res.send('Hello World'); +}); + +// requests will never reach this route +app.get('/', (req, res) => { + res.send('Welcome'); +}); +``` + +**Error-handling middleware** + +Error-handling middleware always takes _four_ arguments. You must provide four arguments to identify it as an error-handling middleware function. Even if you don't need to use the `next` object, you must specify it to maintain the signature. Otherwise, the `next` object will be interpreted as regular middleware and will fail to handle errors. For details about error-handling middleware, see: [Error handling](/{{ page.lang }}/guide/error-handling.html). + +Define error-handling middleware functions in the same way as other middleware functions, except with four arguments instead of three, specifically with the signature `(err, req, res, next)`): + +```js +app.use((err, req, res, next) => { + console.error(err.stack); + res.status(500).send('Something broke!'); +}); +``` + +#### Path examples + +The following table provides some simple examples of valid `path` values for +mounting middleware. + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeExample
    Path +Matches the exact path `/abcd` and any sub-paths starting with `/abcd/` (for example, `/abcd/foo`): + +```js +app.use('/abcd', (req, res, next) => { + next(); +}); +``` + +
    Path Pattern +This will match paths starting with `/abcd` and `/abd`: + +```js +app.use('/ab{c}d', (req, res, next) => { + next(); +}); +``` + +
    Regular Expression +This will match paths starting with `/abc` and `/xyz`: + +```js +app.use(/\/abc|\/xyz/, (req, res, next) => { + next(); +}); +``` + +
    Array +This will match paths starting with `/abcd`, `/xyza`, `/lmn`, and `/pqr`: + +```js +app.use(['/abcd', '/xyza', /\/lmn|\/pqr/], (req, res, next) => { + next(); +}); +``` + +
    +
    + +#### Middleware callback function examples + +The following table provides some simple examples of middleware functions that +can be used as the `callback` argument to `app.use()`, `app.METHOD()`, and `app.all()`. + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    UsageExample
    Single Middleware +You can define and mount a middleware function locally. + +```js +app.use((req, res, next) => { + next(); +}); +``` + +A router is valid middleware. + +```js +const router = express.Router(); +router.get('/', (req, res, next) => { + next(); +}); +app.use(router); +``` + +An Express app is valid middleware. + +```js +const subApp = express(); +subApp.get('/', (req, res, next) => { + next(); +}); +app.use(subApp); +``` + +
    Series of Middleware +You can specify more than one middleware function at the same mount path. + +```js +const r1 = express.Router(); +r1.get('/', (req, res, next) => { + next(); +}); + +const r2 = express.Router(); +r2.get('/', (req, res, next) => { + next(); +}); + +app.use(r1, r2); +``` + +
    Array +Use an array to group middleware logically. + +```js +const r1 = express.Router(); +r1.get('/', (req, res, next) => { + next(); +}); + +const r2 = express.Router(); +r2.get('/', (req, res, next) => { + next(); +}); + +app.use([r1, r2]); +``` + +
    Combination +You can combine all the above ways of mounting middleware. + +```js +function mw1(req, res, next) { + next(); +} +function mw2(req, res, next) { + next(); +} + +const r1 = express.Router(); +r1.get('/', (req, res, next) => { + next(); +}); + +const r2 = express.Router(); +r2.get('/', (req, res, next) => { + next(); +}); + +const subApp = express(); +subApp.get('/', (req, res, next) => { + next(); +}); + +app.use(mw1, [mw2, r1, r2], subApp); +``` + +
    +
    + +Following are some examples of using the [express.static](/{{page.lang}}/guide/using-middleware.html#middleware.built-in) +middleware in an Express app. + +Serve static content for the app from the "public" directory in the application directory: + +```js +// GET /style.css etc +app.use(express.static(path.join(__dirname, 'public'))); +``` + +Mount the middleware at "/static" to serve static content only when their request path is prefixed with "/static": + +```js +// GET /static/style.css etc. +app.use('/static', express.static(path.join(__dirname, 'public'))); +``` + +Disable logging for static content requests by loading the logger middleware after the static middleware: + +```js +app.use(express.static(path.join(__dirname, 'public'))); +app.use(logger()); +``` + +Serve static files from multiple directories, but give precedence to "./public" over the others: + +```js +app.use(express.static(path.join(__dirname, 'public'))); +app.use(express.static(path.join(__dirname, 'files'))); +app.use(express.static(path.join(__dirname, 'uploads'))); +``` diff --git a/astro/src/content/docs/de/5x/api/application/overview.md b/astro/src/content/docs/de/5x/api/application/overview.md new file mode 100644 index 0000000000..ee9b6ab334 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/application/overview.md @@ -0,0 +1,132 @@ +--- +title: Properties +description: section markdown="1"> +--- + +

    Application

    + +The `app` object conventionally denotes the Express application. +Create it by calling the top-level `express()` function exported by the Express module: + +```js +const express = require('express'); +const app = express(); + +app.get('/', (req, res) => { + res.send('hello world'); +}); + +app.listen(3000); +``` + +The `app` object has methods for + +- Routing HTTP requests; see for example, [app.METHOD](#app.METHOD) and [app.param](#app.param). +- Configuring middleware; see [app.route](#app.route). +- Rendering HTML views; see [app.render](#app.render). +- Registering a template engine; see [app.engine](#app.engine). + +It also has settings (properties) that affect how the application behaves; +for more information, see [Application settings](#app.settings.table). + +
    +The Express application object can be referred from the [request object](#req) and the [response object](#res) as `req.app`, and `res.app`, respectively. +
    + +

    Properties

    + +
    + {% include api/en/5x/app-locals.md %} +
    + +
    + {% include api/en/5x/app-mountpath.md %} +
    + +
    + {% include api/en/5x/app-router.md %} +
    + +

    Events

    + +
    + {% include api/en/5x/app-onmount.md %} +
    + +

    Methods

    + +
    + {% include api/en/5x/app-all.md %} +
    + +
    + {% include api/en/5x/app-delete-method.md %} +
    + +
    + {% include api/en/5x/app-disable.md %} +
    + +
    + {% include api/en/5x/app-disabled.md %} +
    + +
    + {% include api/en/5x/app-enable.md %} +
    + +
    + {% include api/en/5x/app-enabled.md %} +
    + +
    + {% include api/en/5x/app-engine.md %} +
    + +
    + {% include api/en/5x/app-get.md %} +
    + +
    + {% include api/en/5x/app-get-method.md %} +
    + +
    + {% include api/en/5x/app-listen.md %} +
    + +
    + {% include api/en/5x/app-METHOD.md %} +
    + +
    + {% include api/en/5x/app-param.md %} +
    + +
    + {% include api/en/5x/app-path.md %} +
    + +
    + {% include api/en/5x/app-post-method.md %} +
    + +
    + {% include api/en/5x/app-put-method.md %} +
    + +
    + {% include api/en/5x/app-render.md %} +
    + +
    + {% include api/en/5x/app-route.md %} +
    + +
    + {% include api/en/5x/app-set.md %} +
    + +
    + {% include api/en/5x/app-use.md %} +
    diff --git a/astro/src/content/docs/de/5x/api/express/express.json.md b/astro/src/content/docs/de/5x/api/express/express.json.md new file mode 100644 index 0000000000..a905bf45ed --- /dev/null +++ b/astro/src/content/docs/de/5x/api/express/express.json.md @@ -0,0 +1,43 @@ +--- +title: express.json +description: This is a built-in middleware function in Express. It parses incoming requests +--- + +

    express.json([options])

    + +This is a built-in middleware function in Express. It parses incoming requests +with JSON payloads and is based on +[body-parser](/resources/middleware/body-parser.html). + +Returns middleware that only parses JSON and only looks at requests where +the `Content-Type` header matches the `type` option. This parser accepts any +Unicode encoding of the body and supports automatic inflation of `gzip` and +`deflate` encodings. + +A new `body` object containing the parsed data is populated on the `request` +object after the middleware (i.e. `req.body`), or `undefined` if +there was no body to parse, the `Content-Type` was not matched, or an error +occurred. + +
    +As `req.body`'s shape is based on user-controlled input, all properties and +values in this object are untrusted and should be validated before trusting. +For example, `req.body.foo.toString()` may fail in multiple ways, for example +`foo` may not be there or may not be a string, and `toString` may not be a +function and instead a string or other user-input. +
    + +The following table describes the properties of the optional `options` object. + +
    + +| Property | Description | Type | Default | +| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | -------------------- | +| `inflate` | Enables or disables handling deflated (compressed) bodies; when disabled, deflated bodies are rejected. | Boolean | `true` | +| `limit` | Controls the maximum request body size. If this is a number, then the value specifies the number of bytes; if it is a string, the value is passed to the [bytes](https://www.npmjs.com/package/bytes) library for parsing. | Mixed | `"100kb"` | +| `reviver` | The `reviver` option is passed directly to `JSON.parse` as the second argument. You can find more information on this argument [in the MDN documentation about JSON.parse](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Example.3A_Using_the_reviver_parameter). | Function | `null` | +| `strict` | Enables or disables only accepting arrays and objects; when disabled will accept anything `JSON.parse` accepts. | Boolean | `true` | +| `type` | This is used to determine what media type the middleware will parse. This option can be a string, array of strings, or a function. If not a function, `type` option is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme) library and this can be an extension name (like `json`), a mime type (like `application/json`), or a mime type with a wildcard (like `*/*` or `*/json`). If a function, the `type` option is called as `fn(req)` and the request is parsed if it returns a truthy value. | Mixed | `"application/json"` | +| `verify` | This option, if supplied, is called as `verify(req, res, buf, encoding)`, where `buf` is a `Buffer` of the raw request body and `encoding` is the encoding of the request. The parsing can be aborted by throwing an error. | Function | `undefined` | + +
    diff --git a/astro/src/content/docs/de/5x/api/express/express.md b/astro/src/content/docs/de/5x/api/express/express.md new file mode 100644 index 0000000000..163c1c3f1f --- /dev/null +++ b/astro/src/content/docs/de/5x/api/express/express.md @@ -0,0 +1,39 @@ +--- +title: Methods +description: section markdown="1"> +--- + +

    express()

    + +Creates an Express application. The `express()` function is a top-level function exported by the `express` module. + +```js +const express = require('express'); +const app = express(); +``` + +

    Methods

    + +
    + {% include api/en/5x/express.json.md %} +
    + +
    + {% include api/en/5x/express.raw.md %} +
    + +
    + {% include api/en/5x/express.router.md %} +
    + +
    + {% include api/en/5x/express.static.md %} +
    + +
    + {% include api/en/5x/express.text.md %} +
    + +
    + {% include api/en/5x/express.urlencoded.md %} +
    diff --git a/astro/src/content/docs/de/5x/api/express/express.raw.md b/astro/src/content/docs/de/5x/api/express/express.raw.md new file mode 100644 index 0000000000..04011354a5 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/express/express.raw.md @@ -0,0 +1,41 @@ +--- +title: express.raw +description: This is a built-in middleware function in Express. It parses incoming request +--- + +

    express.raw([options])

    + +This is a built-in middleware function in Express. It parses incoming request +payloads into a `Buffer` and is based on +[body-parser](/resources/middleware/body-parser.html). + +Returns middleware that parses all bodies as a `Buffer` and only looks at requests +where the `Content-Type` header matches the `type` option. This parser accepts +any Unicode encoding of the body and supports automatic inflation of `gzip` and +`deflate` encodings. + +A new `body` `Buffer` containing the parsed data is populated on the `request` +object after the middleware (i.e. `req.body`), or `undefined` if +there was no body to parse, the `Content-Type` was not matched, or an error +occurred. + +
    +As `req.body`'s shape is based on user-controlled input, all properties and +values in this object are untrusted and should be validated before trusting. +For example, `req.body.toString()` may fail in multiple ways, for example +stacking multiple parsers `req.body` may be from a different parser. Testing +that `req.body` is a `Buffer` before calling buffer methods is recommended. +
    + +The following table describes the properties of the optional `options` object. + +
    + +| Property | Description | Type | Default | +| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ---------------------------- | +| `inflate` | Enables or disables handling deflated (compressed) bodies; when disabled, deflated bodies are rejected. | Boolean | `true` | +| `limit` | Controls the maximum request body size. If this is a number, then the value specifies the number of bytes; if it is a string, the value is passed to the [bytes](https://www.npmjs.com/package/bytes) library for parsing. | Mixed | `"100kb"` | +| `type` | This is used to determine what media type the middleware will parse. This option can be a string, array of strings, or a function. If not a function, `type` option is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme) library and this can be an extension name (like `bin`), a mime type (like `application/octet-stream`), or a mime type with a wildcard (like `*/*` or `application/*`). If a function, the `type` option is called as `fn(req)` and the request is parsed if it returns a truthy value. | Mixed | `"application/octet-stream"` | +| `verify` | This option, if supplied, is called as `verify(req, res, buf, encoding)`, where `buf` is a `Buffer` of the raw request body and `encoding` is the encoding of the request. The parsing can be aborted by throwing an error. | Function | `undefined` | + +
    diff --git a/astro/src/content/docs/de/5x/api/express/express.router.md b/astro/src/content/docs/de/5x/api/express/express.router.md new file mode 100644 index 0000000000..2474bc3fa0 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/express/express.router.md @@ -0,0 +1,29 @@ +--- +title: express.Router +description: Creates a new [router](#router) object. +--- + +

    express.Router([options])

    + +Creates a new [router](#router) object. + +```js +const router = express.Router([options]); +``` + +The optional `options` parameter specifies the behavior of the router. + +
    + +| Property | Description | Default | Availability | +| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | ------------ | +| `caseSensitive` | Enable case sensitivity. | Disabled by default, treating "/Foo" and "/foo" as the same. | | +| `mergeParams` | Preserve the `req.params` values from the parent router. If the parent and the child have conflicting param names, the child's value take precedence. | `false` | 4.5.0+ | +| `strict` | Enable strict routing. | Disabled by default, "/foo" and "/foo/" are treated the same by the router. |   | + +
    + +You can add middleware and HTTP method routes (such as `get`, `put`, `post`, and +so on) to `router` just like an application. + +For more information, see [Router](#router). diff --git a/astro/src/content/docs/de/5x/api/express/express.static.md b/astro/src/content/docs/de/5x/api/express/express.static.md new file mode 100644 index 0000000000..cb16475ae6 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/express/express.static.md @@ -0,0 +1,99 @@ +--- +title: express.static +description: This is a built-in middleware function in Express. +--- + +

    express.static(root, [options])

    + +This is a built-in middleware function in Express. +It serves static files and is based on [serve-static](/resources/middleware/serve-static.html). + +
    NOTE: For best results, [use a reverse proxy](/{{page.lang}}/advanced/best-practice-performance.html#use-a-reverse-proxy) cache to improve performance of serving static assets. +
    + +The `root` argument specifies the root directory from which to serve static assets. +The function determines the file to serve by combining `req.url` with the provided `root` directory. +When a file is not found, instead of sending a 404 response, it instead calls `next()` +to move on to the next middleware, allowing for stacking and fall-backs. + +The following table describes the properties of the `options` object. +See also the [example below](#example.of.express.static). + +
    + +| Property | Description | Type | Default | +| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------ | +| `dotfiles` | Determines how dotfiles (files or directories that begin with a dot ".") are treated.

    See [dotfiles](#dotfiles) below. | String | "ignore" | +| `etag` | Enable or disable etag generation

    NOTE: `express.static` always sends weak ETags. | Boolean | `true` | +| `extensions` | Sets file extension fallbacks: If a file is not found, search for files with the specified extensions and serve the first one found. Example: `['html', 'htm']`. | Mixed | `false` | +| `fallthrough` | Let client errors fall-through as unhandled requests, otherwise forward a client error.

    See [fallthrough](#fallthrough) below. | Boolean | `true` | +| `immutable` | Enable or disable the `immutable` directive in the `Cache-Control` response header. If enabled, the `maxAge` option should also be specified to enable caching. The `immutable` directive will prevent supported clients from making conditional requests during the life of the `maxAge` option to check if the file has changed. | Boolean | `false` | +| `index` | Sends the specified directory index file. Set to `false` to disable directory indexing. | Mixed | "index.html" | +| `lastModified` | Set the `Last-Modified` header to the last modified date of the file on the OS. | Boolean | `true` | +| `maxAge` | Set the max-age property of the Cache-Control header in milliseconds or a string in [ms format](https://www.npmjs.org/package/ms). | Number | 0 | +| `redirect` | Redirect to trailing "/" when the pathname is a directory. | Boolean | `true` | +| `setHeaders` | Function for setting HTTP headers to serve with the file.

    See [setHeaders](#setHeaders) below. | Function | | +| `acceptRanges` | Enable or disable accepting ranged requests. Disabling this will not send the Accept-Ranges header and will ignore the contents of the Range request header. | Boolean | true | +| `cacheControl` | Enable or disable setting the Cache-Control response header. Disabling this will ignore the immutable and maxAge options. | Boolean | true | + +
    + +For more information, see [Serving static files in Express](/starter/static-files.html). +and [Using middleware - Built-in middleware](/{{page.lang}}/guide/using-middleware.html#middleware.built-in). + +
    dotfiles
    + +Possible values for this option are: + +- "allow" - No special treatment for dotfiles. +- "deny" - Deny a request for a dotfile, respond with `403`, then call `next()`. +- "ignore" - Act as if the dotfile does not exist, respond with `404`, then call `next()`. + +
    fallthrough
    + +When this option is `true`, client errors such as a bad request or a request to a non-existent +file will cause this middleware to simply call `next()` to invoke the next middleware in the stack. +When false, these errors (even 404s), will invoke `next(err)`. + +Set this option to `true` so you can map multiple physical directories +to the same web address or for routes to fill in non-existent files. + +Use `false` if you have mounted this middleware at a path designed +to be strictly a single file system directory, which allows for short-circuiting 404s +for less overhead. This middleware will also reply to all methods. + +
    setHeaders
    + +For this option, specify a function to set custom response headers. Alterations to the headers must occur synchronously. + +The signature of the function is: + +```js +fn(res, path, stat); +``` + +Arguments: + +- `res`, the [response object](#res). +- `path`, the file path that is being sent. +- `stat`, the `stat` object of the file that is being sent. + +

    Example of express.static

    + +Here is an example of using the `express.static` middleware function with an elaborate options object: + +```js +const options = { + dotfiles: 'ignore', + etag: false, + extensions: ['htm', 'html'], + index: false, + maxAge: '1d', + redirect: false, + setHeaders(res, path, stat) { + res.set('x-timestamp', Date.now()); + }, +}; + +app.use(express.static('public', options)); +``` diff --git a/astro/src/content/docs/de/5x/api/express/express.text.md b/astro/src/content/docs/de/5x/api/express/express.text.md new file mode 100644 index 0000000000..10647ca41c --- /dev/null +++ b/astro/src/content/docs/de/5x/api/express/express.text.md @@ -0,0 +1,42 @@ +--- +title: express.text +description: This is a built-in middleware function in Express. It parses incoming request +--- + +

    express.text([options])

    + +This is a built-in middleware function in Express. It parses incoming request +payloads into a string and is based on +[body-parser](/resources/middleware/body-parser.html). + +Returns middleware that parses all bodies as a string and only looks at requests +where the `Content-Type` header matches the `type` option. This parser accepts +any Unicode encoding of the body and supports automatic inflation of `gzip` and +`deflate` encodings. + +A new `body` string containing the parsed data is populated on the `request` +object after the middleware (i.e. `req.body`), or `undefined` if +there was no body to parse, the `Content-Type` was not matched, or an error +occurred. + +
    +As `req.body`'s shape is based on user-controlled input, all properties and +values in this object are untrusted and should be validated before trusting. +For example, `req.body.trim()` may fail in multiple ways, for example +stacking multiple parsers `req.body` may be from a different parser. Testing +that `req.body` is a string before calling string methods is recommended. +
    + +The following table describes the properties of the optional `options` object. + +
    + +| Property | Description | Type | Default | +| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | -------------- | +| `defaultCharset` | Specify the default character set for the text content if the charset is not specified in the `Content-Type` header of the request. | String | `"utf-8"` | +| `inflate` | Enables or disables handling deflated (compressed) bodies; when disabled, deflated bodies are rejected. | Boolean | `true` | +| `limit` | Controls the maximum request body size. If this is a number, then the value specifies the number of bytes; if it is a string, the value is passed to the [bytes](https://www.npmjs.com/package/bytes) library for parsing. | Mixed | `"100kb"` | +| `type` | This is used to determine what media type the middleware will parse. This option can be a string, array of strings, or a function. If not a function, `type` option is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme) library and this can be an extension name (like `txt`), a mime type (like `text/plain`), or a mime type with a wildcard (like `*/*` or `text/*`). If a function, the `type` option is called as `fn(req)` and the request is parsed if it returns a truthy value. | Mixed | `"text/plain"` | +| `verify` | This option, if supplied, is called as `verify(req, res, buf, encoding)`, where `buf` is a `Buffer` of the raw request body and `encoding` is the encoding of the request. The parsing can be aborted by throwing an error. | Function | `undefined` | + +
    diff --git a/astro/src/content/docs/de/5x/api/express/express.urlencoded.md b/astro/src/content/docs/de/5x/api/express/express.urlencoded.md new file mode 100644 index 0000000000..6da362522b --- /dev/null +++ b/astro/src/content/docs/de/5x/api/express/express.urlencoded.md @@ -0,0 +1,45 @@ +--- +title: express.urlencoded +description: This is a built-in middleware function in Express. It parses incoming requests +--- + +

    express.urlencoded([options])

    + +This is a built-in middleware function in Express. It parses incoming requests +with urlencoded payloads and is based on [body-parser](/resources/middleware/body-parser.html). + +Returns middleware that only parses urlencoded bodies and only looks at +requests where the `Content-Type` header matches the `type` option. This +parser accepts only UTF-8 encoding of the body and supports automatic +inflation of `gzip` and `deflate` encodings. + +A new `body` object containing the parsed data is populated on the `request` +object after the middleware (i.e. `req.body`), or `undefined` if +there was no body to parse, the `Content-Type` was not matched, or an error +occurred. This object will contain key-value pairs, where the value can be +a string or array (when `extended` is `false`), or any type (when `extended` +is `true`). + +
    +As `req.body`'s shape is based on user-controlled input, all properties and +values in this object are untrusted and should be validated before trusting. +For example, `req.body.foo.toString()` may fail in multiple ways, for example +`foo` may not be there or may not be a string, and `toString` may not be a +function and instead a string or other user-input. +
    + +The following table describes the properties of the optional `options` object. + +
    + +| Property | Description | Type | Default | +| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------------------------------- | +| `extended` | This option allows to choose between parsing the URL-encoded data with the `querystring` library (when `false`) or the `qs` library (when `true`). The "extended" syntax allows for rich objects and arrays to be encoded into the URL-encoded format, allowing for a JSON-like experience with URL-encoded. For more information, please [see the qs library](https://www.npmjs.org/package/qs#readme). | Boolean | `false` | +| `inflate` | Enables or disables handling deflated (compressed) bodies; when disabled, deflated bodies are rejected. | Boolean | `true` | +| `limit` | Controls the maximum request body size. If this is a number, then the value specifies the number of bytes; if it is a string, the value is passed to the [bytes](https://www.npmjs.com/package/bytes) library for parsing. | Mixed | `"100kb"` | +| `parameterLimit` | This option controls the maximum number of parameters that are allowed in the URL-encoded data. If a request contains more parameters than this value, an error will be raised. | Number | `1000` | +| `type` | This is used to determine what media type the middleware will parse. This option can be a string, array of strings, or a function. If not a function, `type` option is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme) library and this can be an extension name (like `urlencoded`), a mime type (like `application/x-www-form-urlencoded`), or a mime type with a wildcard (like `*/x-www-form-urlencoded`). If a function, the `type` option is called as `fn(req)` and the request is parsed if it returns a truthy value. | Mixed | `"application/x-www-form-urlencoded"` | +| `verify` | This option, if supplied, is called as `verify(req, res, buf, encoding)`, where `buf` is a `Buffer` of the raw request body and `encoding` is the encoding of the request. The parsing can be aborted by throwing an error. | Function | `undefined` | +| `depth` | Configure the maximum depth of the `qs` library when `extended` is `true`. This allows you to limit the amount of keys that are parsed and can be useful to prevent certain types of abuse. Defaults to `32`. It is recommended to keep this value as low as possible. | Number | `32` | + +
    diff --git a/astro/src/content/docs/de/5x/api/request/overview.md b/astro/src/content/docs/de/5x/api/request/overview.md new file mode 100644 index 0000000000..203654e039 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/overview.md @@ -0,0 +1,160 @@ +--- +title: Properties +description: The req object represents the HTTP request and has properties for the request query string, parameters, body, HTTP headers, and so on +--- + +

    Request

    + +The `req` object represents the HTTP request and has properties for the +request query string, parameters, body, HTTP headers, and so on. In this documentation and by convention, +the object is always referred to as `req` (and the HTTP response is `res`) but its actual name is determined +by the parameters to the callback function in which you're working. + +For example: + +```js +app.get('/user/:id', (req, res) => { + res.send(`user ${req.params.id}`); +}); +``` + +But you could just as well have: + +```js +app.get('/user/:id', (request, response) => { + response.send(`user ${request.params.id}`); +}); +``` + +The `req` object is an enhanced version of Node's own request object +and supports all [built-in fields and methods](https://nodejs.org/api/http.html#http_class_http_incomingmessage). + +

    Properties

    + +
    +In Express 4, `req.files` is no longer available on the `req` object by default. To access uploaded files +on the `req.files` object, use multipart-handling middleware like [busboy](https://www.npmjs. +com/package/busboy), [multer](https://www.npmjs.com/package/multer), +[formidable](https://www.npmjs.com/package/formidable), +[multiparty](https://www.npmjs.com/package/multiparty), +[connect-multiparty](https://www.npmjs.com/package/connect-multiparty), +or [pez](https://www.npmjs.com/package/pez). +
    + +
    + {% include api/en/5x/req-app.md %} +
    + +
    + {% include api/en/5x/req-baseUrl.md %} +
    + +
    + {% include api/en/5x/req-body.md %} +
    + +
    + {% include api/en/5x/req-cookies.md %} +
    + +
    + {% include api/en/5x/req-fresh.md %} +
    + +
    + {% include api/en/5x/req-host.md %} +
    + +
    + {% include api/en/5x/req-hostname.md %} +
    + +
    + {% include api/en/5x/req-ip.md %} +
    + +
    + {% include api/en/5x/req-ips.md %} +
    + +
    + {% include api/en/5x/req-method.md %} +
    + +
    + {% include api/en/5x/req-originalUrl.md %} +
    + +
    + {% include api/en/5x/req-params.md %} +
    + +
    + {% include api/en/5x/req-path.md %} +
    + +
    + {% include api/en/5x/req-protocol.md %} +
    + +
    + {% include api/en/5x/req-query.md %} +
    + +
    + {% include api/en/5x/req-res.md %} +
    + +
    + {% include api/en/5x/req-route.md %} +
    + +
    + {% include api/en/5x/req-secure.md %} +
    + +
    + {% include api/en/5x/req-signedCookies.md %} +
    + +
    + {% include api/en/5x/req-stale.md %} +
    + +
    + {% include api/en/5x/req-subdomains.md %} +
    + +
    + {% include api/en/5x/req-xhr.md %} +
    + +

    Methods

    + +
    + {% include api/en/5x/req-accepts.md %} +
    + +
    + {% include api/en/5x/req-acceptsCharsets.md %} +
    + +
    + {% include api/en/5x/req-acceptsEncodings.md %} +
    + +
    + {% include api/en/5x/req-acceptsLanguages.md %} +
    + +
    + {% include api/en/5x/req-get.md %} +
    + +
    + {% include api/en/5x/req-is.md %} +
    + +
    + {% include api/en/5x/req-range.md %} +
    diff --git a/astro/src/content/docs/de/5x/api/request/req-accepts.md b/astro/src/content/docs/de/5x/api/request/req-accepts.md new file mode 100644 index 0000000000..763c6c6ab7 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/req-accepts.md @@ -0,0 +1,41 @@ +--- +title: req.accepts +description: Checks if the specified content types are acceptable, based on the request Accept HTTP header field. +--- + +

    req.accepts(types)

    + +Checks if the specified content types are acceptable, based on the request's `Accept` HTTP header field. +The method returns the best match, or if none of the specified content types is acceptable, returns +`false` (in which case, the application should respond with `406 "Not Acceptable"`). + +The `type` value may be a single MIME type string (such as "application/json"), +an extension name such as "json", a comma-delimited list, or an array. For a +list or array, the method returns the _best_ match (if any). + +```js +// Accept: text/html +req.accepts('html'); +// => "html" + +// Accept: text/*, application/json +req.accepts('html'); +// => "html" +req.accepts('text/html'); +// => "text/html" +req.accepts(['json', 'text']); +// => "json" +req.accepts('application/json'); +// => "application/json" + +// Accept: text/*, application/json +req.accepts('image/png'); +req.accepts('png'); +// => false + +// Accept: text/*;q=.5, application/json +req.accepts(['html', 'json']); +// => "json" +``` + +For more information, or if you have issues or concerns, see [accepts](https://github.com/expressjs/accepts). diff --git a/astro/src/content/docs/de/5x/api/request/req-acceptsCharsets.md b/astro/src/content/docs/de/5x/api/request/req-acceptsCharsets.md new file mode 100644 index 0000000000..69bed2797b --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/req-acceptsCharsets.md @@ -0,0 +1,12 @@ +--- +title: req.acceptsCharsets +description: Returns the first accepted charset of the specified character sets, +--- + +

    req.acceptsCharsets(charset [, ...])

    + +Returns the first accepted charset of the specified character sets, +based on the request's `Accept-Charset` HTTP header field. +If none of the specified charsets is accepted, returns `false`. + +For more information, or if you have issues or concerns, see [accepts](https://github.com/expressjs/accepts). diff --git a/astro/src/content/docs/de/5x/api/request/req-acceptsEncodings.md b/astro/src/content/docs/de/5x/api/request/req-acceptsEncodings.md new file mode 100644 index 0000000000..384e10bb6a --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/req-acceptsEncodings.md @@ -0,0 +1,12 @@ +--- +title: req.acceptsEncodings +description: Returns the first accepted encoding of the specified encodings, +--- + +

    req.acceptsEncodings(encoding [, ...])

    + +Returns the first accepted encoding of the specified encodings, +based on the request's `Accept-Encoding` HTTP header field. +If none of the specified encodings is accepted, returns `false`. + +For more information, or if you have issues or concerns, see [accepts](https://github.com/expressjs/accepts). diff --git a/astro/src/content/docs/de/5x/api/request/req-acceptsLanguages.md b/astro/src/content/docs/de/5x/api/request/req-acceptsLanguages.md new file mode 100644 index 0000000000..998805fa9e --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/req-acceptsLanguages.md @@ -0,0 +1,20 @@ +--- +title: req.acceptsLanguages +description: Returns the first accepted language of the specified languages, +--- + +

    req.acceptsLanguages([lang, ...])

    + +Returns the first accepted language of the specified languages, +based on the request's `Accept-Language` HTTP header field. +If none of the specified languages is accepted, returns `false`. + +If no `lang` argument is given, then `req.acceptsLanguages()` +returns all languages from the HTTP `Accept-Language` header +as an `Array`. + +For more information, or if you have issues or concerns, see [accepts](https://github.com/expressjs/accepts). + +Express (5.x) source: [request.js line 172](https://github.com/expressjs/express/blob/v5.1.0/lib/request.js#L172) + +Accepts (2.0) source: [index.js line 195](https://github.com/jshttp/accepts/blob/2.0.0/index.js#L195) diff --git a/astro/src/content/docs/de/5x/api/request/req-app.md b/astro/src/content/docs/de/5x/api/request/req-app.md new file mode 100644 index 0000000000..6594a0142a --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/req-app.md @@ -0,0 +1,25 @@ +--- +title: req.app +description: This property holds a reference to the instance of the Express application that is using the middleware. +--- + +

    req.app

    + +This property holds a reference to the instance of the Express application that is using the middleware. + +If you follow the pattern in which you create a module that just exports a middleware function +and `require()` it in your main file, then the middleware can access the Express instance via `req.app` + +For example: + +```js +// index.js +app.get('/viewdirectory', require('./mymiddleware.js')); +``` + +```js +// mymiddleware.js +module.exports = (req, res) => { + res.send(`The views directory is ${req.app.get('views')}`); +}; +``` diff --git a/astro/src/content/docs/de/5x/api/request/req-base-url.md b/astro/src/content/docs/de/5x/api/request/req-base-url.md new file mode 100644 index 0000000000..a49e6912ca --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/req-base-url.md @@ -0,0 +1,35 @@ +--- +title: req.baseUrl +description: The URL path on which a router instance was mounted. +--- + +

    req.baseUrl

    + +The URL path on which a router instance was mounted. + +The `req.baseUrl` property is similar to the [mountpath](#app.mountpath) property of the `app` object, +except `app.mountpath` returns the matched path pattern(s). + +For example: + +```js +const greet = express.Router(); + +greet.get('/jp', (req, res) => { + console.log(req.baseUrl); // /greet + res.send('Konichiwa!'); +}); + +app.use('/greet', greet); // load the router on '/greet' +``` + +Even if you use a path pattern or a set of path patterns to load the router, +the `baseUrl` property returns the matched string, not the pattern(s). In the +following example, the `greet` router is loaded on two path patterns. + +```js +app.use(['/gre:"param"t', '/hel{l}o'], greet); // load the router on '/gre:"param"t' and '/hel{l}o' +``` + +When a request is made to `/greet/jp`, `req.baseUrl` is "/greet". When a request is +made to `/hello/jp`, `req.baseUrl` is "/hello". diff --git a/astro/src/content/docs/de/5x/api/request/req-body.md b/astro/src/content/docs/de/5x/api/request/req-body.md new file mode 100644 index 0000000000..a921f3c624 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/req-body.md @@ -0,0 +1,30 @@ +--- +title: req.body +description: Contains key-value pairs of data submitted in the request body. +--- + +

    req.body

    + +Contains key-value pairs of data submitted in the request body. +By default, it is `undefined`, and is populated when you use body-parsing middleware such +as [`express.json()`](#express.json) or [`express.urlencoded()`](#express.urlencoded). + +
    +As `req.body`'s shape is based on user-controlled input, all properties and values in this object are untrusted and should be validated before trusting. For example, `req.body.foo.toString()` may fail in multiple ways, for example `foo` may not be there or may not be a string, and `toString` may not be a function and instead a string or other user-input. +
    + +The following example shows how to use body-parsing middleware to populate `req.body`. + +```js +const express = require('express'); + +const app = express(); + +app.use(express.json()); // for parsing application/json +app.use(express.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded + +app.post('/profile', (req, res, next) => { + console.log(req.body); + res.json(req.body); +}); +``` diff --git a/astro/src/content/docs/de/5x/api/request/req-cookies.md b/astro/src/content/docs/de/5x/api/request/req-cookies.md new file mode 100644 index 0000000000..806b6dc5ab --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/req-cookies.md @@ -0,0 +1,19 @@ +--- +title: req.cookies +description: When using cookie-parser middleware, this property is an object that contains cookies sent by the request +--- + +

    req.cookies

    + +When using [cookie-parser](https://www.npmjs.com/package/cookie-parser) middleware, this property is an object that +contains cookies sent by the request. If the request contains no cookies, it defaults to `{}`. + +```js +// Cookie: name=tj +console.dir(req.cookies.name); +// => "tj" +``` + +If the cookie has been signed, you have to use [req.signedCookies](#req.signedCookies). + +For more information, issues, or concerns, see [cookie-parser](https://github.com/expressjs/cookie-parser). diff --git a/astro/src/content/docs/de/5x/api/request/req-fresh.md b/astro/src/content/docs/de/5x/api/request/req-fresh.md new file mode 100644 index 0000000000..293c12e898 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/req-fresh.md @@ -0,0 +1,18 @@ +--- +title: req.fresh +description: When the response is still fresh in the client cache true is returned, otherwise false is returned to indicate that the client cache is now stale. +--- + +

    req.fresh

    + +When the response is still "fresh" in the client's cache `true` is returned, otherwise `false` is returned to indicate that the client cache is now stale and the full response should be sent. + +When a client sends the `Cache-Control: no-cache` request header to indicate an end-to-end reload request, this module will return `false` to make handling these requests transparent. + +Further details for how cache validation works can be found in the +[HTTP/1.1 Caching Specification](https://tools.ietf.org/html/rfc7234). + +```js +console.dir(req.fresh); +// => true +``` diff --git a/astro/src/content/docs/de/5x/api/request/req-get.md b/astro/src/content/docs/de/5x/api/request/req-get.md new file mode 100644 index 0000000000..ad116d8421 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/req-get.md @@ -0,0 +1,22 @@ +--- +title: req.get +description: Returns the specified HTTP request header field (case-insensitive match). +--- + +

    req.get(field)

    + +Returns the specified HTTP request header field (case-insensitive match). +The `Referrer` and `Referer` fields are interchangeable. + +```js +req.get('Content-Type'); +// => "text/plain" + +req.get('content-type'); +// => "text/plain" + +req.get('Something'); +// => undefined +``` + +Aliased as `req.header(field)`. diff --git a/astro/src/content/docs/de/5x/api/request/req-host.md b/astro/src/content/docs/de/5x/api/request/req-host.md new file mode 100644 index 0000000000..6b1191eb31 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/req-host.md @@ -0,0 +1,27 @@ +--- +title: req.host +description: Contains the host derived from the Host HTTP header. +--- + +

    req.host

    + +Contains the host derived from the `Host` HTTP header. + +When the [`trust proxy` setting](api.html#app.settings.table) +does not evaluate to `false`, this property will instead get the value +from the `X-Forwarded-Host` header field. This header can be set by +the client or by the proxy. + +If there is more than one `X-Forwarded-Host` header in the request, the +value of the first header is used. This includes a single header with +comma-separated values, in which the first value is used. + +```js +// Host: "example.com:3000" +console.dir(req.host); +// => 'example.com:3000' + +// Host: "[::1]:3000" +console.dir(req.host); +// => '[::1]:3000' +``` diff --git a/astro/src/content/docs/de/5x/api/request/req-hostname.md b/astro/src/content/docs/de/5x/api/request/req-hostname.md new file mode 100644 index 0000000000..94477d42ef --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/req-hostname.md @@ -0,0 +1,28 @@ +--- +title: req.hostname +description: Contains the hostname derived from the Host HTTP header. +--- + +

    req.hostname

    + +Contains the hostname derived from the `Host` HTTP header. + +When the [`trust proxy` setting](/5x/api.html#trust.proxy.options.table) +does not evaluate to `false`, this property will instead get the value +from the `X-Forwarded-Host` header field. This header can be set by +the client or by the proxy. + +If there is more than one `X-Forwarded-Host` header in the request, the +value of the first header is used. This includes a single header with +comma-separated values, in which the first value is used. + +
    +Prior to Express v4.17.0, the `X-Forwarded-Host` could not contain multiple +values or be present more than once. +
    + +```js +// Host: "example.com:3000" +console.dir(req.hostname); +// => 'example.com' +``` diff --git a/astro/src/content/docs/de/5x/api/request/req-ip.md b/astro/src/content/docs/de/5x/api/request/req-ip.md new file mode 100644 index 0000000000..dec38033cc --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/req-ip.md @@ -0,0 +1,17 @@ +--- +title: req.ip +description: Contains the remote IP address of the request. +--- + +

    req.ip

    + +Contains the remote IP address of the request. + +When the [`trust proxy` setting](/5x/api.html#trust.proxy.options.table) does not evaluate to `false`, +the value of this property is derived from the left-most entry in the +`X-Forwarded-For` header. This header can be set by the client or by the proxy. + +```js +console.dir(req.ip); +// => "127.0.0.1" +``` diff --git a/astro/src/content/docs/de/5x/api/request/req-ips.md b/astro/src/content/docs/de/5x/api/request/req-ips.md new file mode 100644 index 0000000000..424fcd28f0 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/req-ips.md @@ -0,0 +1,14 @@ +--- +title: req.ips +description: When the trust proxy setting does not evaluate to false, this property contains an array of IP addresses specified in the X-Forwarded-For request header +--- + +

    req.ips

    + +When the [`trust proxy` setting](/5x/api.html#trust.proxy.options.table) does not evaluate to `false`, +this property contains an array of IP addresses +specified in the `X-Forwarded-For` request header. Otherwise, it contains an +empty array. This header can be set by the client or by the proxy. + +For example, if `X-Forwarded-For` is `client, proxy1, proxy2`, `req.ips` would be +`["client", "proxy1", "proxy2"]`, where `proxy2` is the furthest downstream. diff --git a/astro/src/content/docs/de/5x/api/request/req-is.md b/astro/src/content/docs/de/5x/api/request/req-is.md new file mode 100644 index 0000000000..3c9b22623d --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/req-is.md @@ -0,0 +1,36 @@ +--- +title: req.is +description: Returns the matching content type if the incoming request's "Content-Type" HTTP header field +--- + +

    req.is(type)

    + +Returns the matching content type if the incoming request's "Content-Type" HTTP header field +matches the MIME type specified by the `type` parameter. If the request has no body, returns `null`. +Returns `false` otherwise. + +```js +// With Content-Type: text/html; charset=utf-8 +req.is('html'); // => 'html' +req.is('text/html'); // => 'text/html' +req.is('text/*'); // => 'text/*' + +// When Content-Type is application/json +req.is('json'); // => 'json' +req.is('application/json'); // => 'application/json' +req.is('application/*'); // => 'application/*' + +// Using arrays +// When Content-Type is application/json +req.is(['json', 'html']); // => 'json' + +// Using multiple arguments +// When Content-Type is application/json +req.is('json', 'html'); // => 'json' + +req.is('html'); // => false +req.is(['xml', 'yaml']); // => false +req.is('xml', 'yaml'); // => false +``` + +For more information, or if you have issues or concerns, see [type-is](https://github.com/expressjs/type-is). diff --git a/astro/src/content/docs/de/5x/api/request/req-method.md b/astro/src/content/docs/de/5x/api/request/req-method.md new file mode 100644 index 0000000000..92b683bcfd --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/req-method.md @@ -0,0 +1,9 @@ +--- +title: req.method +description: Contains a string corresponding to the HTTP method of the request +--- + +

    req.method

    + +Contains a string corresponding to the HTTP method of the request: +`GET`, `POST`, `PUT`, and so on. diff --git a/astro/src/content/docs/de/5x/api/request/req-originalUrl.md b/astro/src/content/docs/de/5x/api/request/req-originalUrl.md new file mode 100644 index 0000000000..c7d4b142ed --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/req-originalUrl.md @@ -0,0 +1,33 @@ +--- +title: req.originalUrl +description: req.url is not a native Express property, it is inherited from Node http module +--- + +

    req.originalUrl

    + +
    +`req.url` is not a native Express property, it is inherited from Node's [http module](https://nodejs.org/api/http.html#http_message_url). +
    + +This property is much like `req.url`; however, it retains the original request URL, +allowing you to rewrite `req.url` freely for internal routing purposes. For example, +the "mounting" feature of [app.use()](#app.use) will rewrite `req.url` to strip the mount point. + +```js +// GET /search?q=something +console.dir(req.originalUrl); +// => "/search?q=something" +``` + +`req.originalUrl` is available both in middleware and router objects, and is a +combination of `req.baseUrl` and `req.url`. Consider following example: + +```js +// GET 'http://www.example.com/admin/new?sort=desc' +app.use('/admin', (req, res, next) => { + console.dir(req.originalUrl); // '/admin/new?sort=desc' + console.dir(req.baseUrl); // '/admin' + console.dir(req.path); // '/new' + next(); +}); +``` diff --git a/astro/src/content/docs/de/5x/api/request/req-params.md b/astro/src/content/docs/de/5x/api/request/req-params.md new file mode 100644 index 0000000000..b87d9a66d3 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/req-params.md @@ -0,0 +1,44 @@ +--- +title: req.params +description: This property is an object containing properties mapped to the [named route "parameters"](/{{ page.lang }}/guide/routing.html#route-parameters). Fo... +--- + +

    req.params

    + +This property is an object containing properties mapped to the [named route "parameters"](/{{ page.lang }}/guide/routing.html#route-parameters). For example, if you have the route `/user/:name`, then the "name" property is available as `req.params.name`. This object defaults to `Object.create(null)` when using string paths, but remains a standard object with a normal prototype when the path is defined with a regular expression. + +```js +// GET /user/tj +console.dir(req.params.name); +// => "tj" +``` + +Properties corresponding to wildcard parameters are arrays containing separate path segments split on `/`: + +```js +app.get('/files/*file', (req, res) => { + console.dir(req.params.file); + // GET /files/note.txt + // => [ 'note.txt' ] + // GET /files/images/image.png + // => [ 'images', 'image.png' ] +}); +``` + +When you use a regular expression for the route definition, capture groups are provided as integer keys using `req.params[n]`, where `n` is the nth capture group. + +```js +app.use(/^\/file\/(.*)$/, (req, res) => { + // GET /file/javascripts/jquery.js + console.dir(req.params[0]); + // => "javascripts/jquery.js" +}); +``` + +Named capturing groups in regular expressions behave like named route parameters. For example the group from `/^\/file\/(?.*)$/` expression is available as `req.params.path`. + +If you need to make changes to a key in `req.params`, use the [app.param](/{{ page.lang }}/5x/api.html#app.param) handler. Changes are applicable only to [parameters](/{{ page.lang }}/guide/routing.html#route-parameters) already defined in the route path. + +Any changes made to the `req.params` object in a middleware or route handler will be reset. + +{% include admonitions/note.html content="Express automatically decodes the values in `req.params` (using `decodeURIComponent`)." %} diff --git a/astro/src/content/docs/de/5x/api/request/req-path.md b/astro/src/content/docs/de/5x/api/request/req-path.md new file mode 100644 index 0000000000..36341283a5 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/req-path.md @@ -0,0 +1,18 @@ +--- +title: req.path +description: Contains the path part of the request URL. +--- + +

    req.path

    + +Contains the path part of the request URL. + +```js +// example.com/users?sort=desc +console.dir(req.path); +// => "/users" +``` + +
    +When called from a middleware, the mount point is not included in `req.path`. See [app.use()](/5x/api.html#app.use) for more details. +
    diff --git a/astro/src/content/docs/de/5x/api/request/req-protocol.md b/astro/src/content/docs/de/5x/api/request/req-protocol.md new file mode 100644 index 0000000000..082e784b47 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/req-protocol.md @@ -0,0 +1,17 @@ +--- +title: req.protocol +description: Contains the request protocol string either http or (for TLS requests) https. +--- + +

    req.protocol

    + +Contains the request protocol string: either `http` or (for TLS requests) `https`. + +When the [`trust proxy` setting](#trust.proxy.options.table) does not evaluate to `false`, +this property will use the value of the `X-Forwarded-Proto` header field if present. +This header can be set by the client or by the proxy. + +```js +console.dir(req.protocol); +// => "http" +``` diff --git a/astro/src/content/docs/de/5x/api/request/req-query.md b/astro/src/content/docs/de/5x/api/request/req-query.md new file mode 100644 index 0000000000..98697eaa7e --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/req-query.md @@ -0,0 +1,26 @@ +--- +title: req.query +description: This property is an object containing a property for each query string parameter in the route. +--- + +

    req.query

    + +This property is an object containing a property for each query string parameter in the route. +When [query parser](#app.settings.table) is set to disabled, it is an empty object `{}`, otherwise it is the result of the configured query parser. + +
    +As `req.query`'s shape is based on user-controlled input, all properties and values in this object are untrusted and should be validated before trusting. For example, `req.query.foo.toString()` may fail in multiple ways, for example `foo` may not be there or may not be a string, and `toString` may not be a function and instead a string or other user-input. +
    + +The value of this property can be configured with the [query parser application setting](#app.settings.table) to work how your application needs it. A very popular query string parser is the [`qs` module](https://www.npmjs.org/package/qs), and this is used by default. The `qs` module is very configurable with many settings, and it may be desirable to use different settings than the default to populate `req.query`: + +```js +const qs = require('qs'); +app.set('query parser', (str) => + qs.parse(str, { + /* custom options */ + }) +); +``` + +Check out the [query parser application setting](#app.settings.table) documentation for other customization options. diff --git a/astro/src/content/docs/de/5x/api/request/req-range.md b/astro/src/content/docs/de/5x/api/request/req-range.md new file mode 100644 index 0000000000..6c103987a2 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/req-range.md @@ -0,0 +1,38 @@ +--- +title: req.range +description: Range header parser +--- + +

    req.range(size[, options])

    + +`Range` header parser. + +The `size` parameter is the maximum size of the resource. + +The `options` parameter is an object that can have the following properties. + +
    + +| Property | Type | Description | +| --------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `combine` | Boolean | Specify if overlapping & adjacent ranges should be combined, defaults to `false`. When `true`, ranges will be combined and returned as if they were specified that way in the header. | + +
    + +An array of ranges will be returned or negative numbers indicating an error parsing. + +- `-2` signals a malformed header string +- `-1` signals an unsatisfiable range + +```js +// parse header from request +const range = req.range(1000); + +// the type of the range +if (range.type === 'bytes') { + // the ranges + range.forEach((r) => { + // do something with r.start and r.end + }); +} +``` diff --git a/astro/src/content/docs/de/5x/api/request/req-res.md b/astro/src/content/docs/de/5x/api/request/req-res.md new file mode 100644 index 0000000000..94e5554756 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/req-res.md @@ -0,0 +1,9 @@ +--- +title: req.res +description: This property holds a reference to the +--- + +

    req.res

    + +This property holds a reference to the response object +that relates to this request object. diff --git a/astro/src/content/docs/de/5x/api/request/req-route.md b/astro/src/content/docs/de/5x/api/request/req-route.md new file mode 100644 index 0000000000..d2a3159b3b --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/req-route.md @@ -0,0 +1,36 @@ +--- +title: req.route +description: Contains the currently-matched route, a string +--- + +

    req.route

    + +Contains the currently-matched route, a string. For example: + +```js +app.get('/user/{:id}', (req, res) => { + console.dir(req.route, { depth: null }); + res.send('GET'); +}); +``` + +Example output from the previous snippet: + +``` +Route { + path: '/user/{:id}', + stack: [ + Layer { + handle: [Function (anonymous)], + keys: [], + name: '', + params: undefined, + path: undefined, + slash: false, + matchers: [ [Function: match] ], + method: 'get' + } + ], + methods: [Object: null prototype] { get: true } +} +``` diff --git a/astro/src/content/docs/de/5x/api/request/req-secure.md b/astro/src/content/docs/de/5x/api/request/req-secure.md new file mode 100644 index 0000000000..d3f86bdcd2 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/req-secure.md @@ -0,0 +1,14 @@ +--- +title: req.secure +description: A Boolean property that is true if a TLS connection is established. Equivalent to the following code. +--- + +

    req.secure

    + +A Boolean property that is true if a TLS connection is established. Equivalent to the following: + + + +```js +req.protocol === 'https'; +``` diff --git a/astro/src/content/docs/de/5x/api/request/req-signedCookies.md b/astro/src/content/docs/de/5x/api/request/req-signedCookies.md new file mode 100644 index 0000000000..b573fc082e --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/req-signedCookies.md @@ -0,0 +1,22 @@ +--- +title: req.signedCookies +description: When using cookie-parser middleware, this property contains signed cookies sent by the request +--- + +

    req.signedCookies

    + +When using [cookie-parser](https://www.npmjs.com/package/cookie-parser) middleware, this property +contains signed cookies sent by the request, unsigned and ready for use. Signed cookies reside +in a different object to show developer intent; otherwise, a malicious attack could be placed on +`req.cookie` values (which are easy to spoof). Note that signing a cookie does not make it "hidden" +or encrypted; but simply prevents tampering (because the secret used to sign is private). + +If no signed cookies are sent, the property defaults to `{}`. + +```js +// Cookie: user=tobi.CP7AWaXDfAKIRfH49dQzKJx7sKzzSoPq7/AcBBRVwlI3 +console.dir(req.signedCookies.user); +// => "tobi" +``` + +For more information, issues, or concerns, see [cookie-parser](https://github.com/expressjs/cookie-parser). diff --git a/astro/src/content/docs/de/5x/api/request/req-stale.md b/astro/src/content/docs/de/5x/api/request/req-stale.md new file mode 100644 index 0000000000..b39f5cb5ef --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/req-stale.md @@ -0,0 +1,14 @@ +--- +title: req.stale +description: Indicates whether the request is stale, and is the opposite of req.fresh. +--- + +

    req.stale

    + +Indicates whether the request is "stale," and is the opposite of `req.fresh`. +For more information, see [req.fresh](#req.fresh). + +```js +console.dir(req.stale); +// => true +``` diff --git a/astro/src/content/docs/de/5x/api/request/req-subdomains.md b/astro/src/content/docs/de/5x/api/request/req-subdomains.md new file mode 100644 index 0000000000..9395377b47 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/req-subdomains.md @@ -0,0 +1,18 @@ +--- +title: req.subdomains +description: An array of subdomains in the domain name of the request. +--- + +

    req.subdomains

    + +An array of subdomains in the domain name of the request. + +```js +// Host: "tobi.ferrets.example.com" +console.dir(req.subdomains); +// => ["ferrets", "tobi"] +``` + +The application property `subdomain offset`, which defaults to 2, is used for determining the +beginning of the subdomain segments. To change this behavior, change its value +using [app.set](/{{ page.lang }}/5x/api.html#app.set). diff --git a/astro/src/content/docs/de/5x/api/request/req-xhr.md b/astro/src/content/docs/de/5x/api/request/req-xhr.md new file mode 100644 index 0000000000..f247d20b05 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/request/req-xhr.md @@ -0,0 +1,14 @@ +--- +title: req.xhr +description: A Boolean property that is true if the request X-Requested-With header field is "XMLHttpRequest" +--- + +

    req.xhr

    + +A Boolean property that is `true` if the request's `X-Requested-With` header field is +"XMLHttpRequest", indicating that the request was issued by a client library such as jQuery. + +```js +console.dir(req.xhr); +// => true +``` diff --git a/astro/src/content/docs/de/5x/api/response/overview.md b/astro/src/content/docs/de/5x/api/response/overview.md new file mode 100644 index 0000000000..ac989a33d8 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/response/overview.md @@ -0,0 +1,135 @@ +--- +title: Properties +description: section markdown="1"> +--- + +

    Response

    + +The `res` object represents the HTTP response that an Express app sends when it gets an HTTP request. + +In this documentation and by convention, +the object is always referred to as `res` (and the HTTP request is `req`) but its actual name is determined +by the parameters to the callback function in which you're working. + +For example: + +```js +app.get('/user/:id', (req, res) => { + res.send(`user ${req.params.id}`); +}); +``` + +But you could just as well have: + +```js +app.get('/user/:id', (request, response) => { + response.send(`user ${request.params.id}`); +}); +``` + +The `res` object is an enhanced version of Node's own response object +and supports all [built-in fields and methods](https://nodejs.org/api/http.html#http_class_http_serverresponse). + +

    Properties

    + +
    + {% include api/en/5x/res-app.md %} +
    + +
    + {% include api/en/5x/res-headersSent.md %} +
    + +
    + {% include api/en/5x/res-locals.md %} +
    + +
    + {% include api/en/5x/res-req.md %} +
    + +

    Methods

    + +
    + {% include api/en/5x/res-append.md %} +
    + +
    + {% include api/en/5x/res-attachment.md %} +
    + +
    + {% include api/en/5x/res-cookie.md %} +
    + +
    + {% include api/en/5x/res-clearCookie.md %} +
    + +
    + {% include api/en/5x/res-download.md %} +
    + +
    + {% include api/en/5x/res-end.md %} +
    + +
    + {% include api/en/5x/res-format.md %} +
    + +
    + {% include api/en/5x/res-get.md %} +
    + +
    + {% include api/en/5x/res-json.md %} +
    + +
    + {% include api/en/5x/res-jsonp.md %} +
    + +
    + {% include api/en/5x/res-links.md %} +
    + +
    + {% include api/en/5x/res-location.md %} +
    + +
    + {% include api/en/5x/res-redirect.md %} +
    + +
    + {% include api/en/5x/res-render.md %} +
    + +
    + {% include api/en/5x/res-send.md %} +
    + +
    + {% include api/en/5x/res-sendFile.md %} +
    + +
    + {% include api/en/5x/res-sendStatus.md %} +
    + +
    + {% include api/en/5x/res-set.md %} +
    + +
    + {% include api/en/5x/res-status.md %} +
    + +
    + {% include api/en/5x/res-type.md %} +
    + +
    + {% include api/en/5x/res-vary.md %} +
    diff --git a/astro/src/content/docs/de/5x/api/response/res-app.md b/astro/src/content/docs/de/5x/api/response/res-app.md new file mode 100644 index 0000000000..b853d54dd3 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/response/res-app.md @@ -0,0 +1,10 @@ +--- +title: res.app +description: This property holds a reference to the instance of the Express application that is using the middleware. +--- + +

    res.app

    + +This property holds a reference to the instance of the Express application that is using the middleware. + +`res.app` is identical to the [req.app](#req.app) property in the request object. diff --git a/astro/src/content/docs/de/5x/api/response/res-append.md b/astro/src/content/docs/de/5x/api/response/res-append.md new file mode 100644 index 0000000000..abda903e81 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/response/res-append.md @@ -0,0 +1,21 @@ +--- +title: res.append +description: res.append appends the specified value to the HTTP response header field +--- + +

    res.append(field [, value])

    + +
    +`res.append()` is supported by Express v4.11.0+ +
    + +Appends the specified `value` to the HTTP response header `field`. If the header is not already set, +it creates the header with the specified value. The `value` parameter can be a string or an array. + +{% include admonitions/note.html content="calling `res.set()` after `res.append()` will reset the previously-set header value." %} + +```js +res.append('Link', ['', '']); +res.append('Set-Cookie', 'foo=bar; Path=/; HttpOnly'); +res.append('Warning', '199 Miscellaneous warning'); +``` diff --git a/astro/src/content/docs/de/5x/api/response/res-attachment.md b/astro/src/content/docs/de/5x/api/response/res-attachment.md new file mode 100644 index 0000000000..7d667eedd4 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/response/res-attachment.md @@ -0,0 +1,19 @@ +--- +title: res.attachment +description: Sets the HTTP response Content-Disposition header field to attachment +--- + +

    res.attachment([filename])

    + +Sets the HTTP response `Content-Disposition` header field to "attachment". If a `filename` is given, +then it sets the `Content-Type` based on the extension name via `res.type()`, +and sets the `Content-Disposition` "filename=" parameter. + +```js +res.attachment(); +// Content-Disposition: attachment + +res.attachment('path/to/logo.png'); +// Content-Disposition: attachment; filename="logo.png" +// Content-Type: image/png +``` diff --git a/astro/src/content/docs/de/5x/api/response/res-clearCookie.md b/astro/src/content/docs/de/5x/api/response/res-clearCookie.md new file mode 100644 index 0000000000..f2738bf189 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/response/res-clearCookie.md @@ -0,0 +1,24 @@ +--- +title: res.clearCookie +description: Clears the cookie with the specified name by sending a Set-Cookie header that sets its expiration date in the past. +--- + +

    res.clearCookie(name [, options])

    + +Clears the cookie with the specified `name` by sending a `Set-Cookie` header that sets its expiration date in the past. +This instructs the client that the cookie has expired and is no longer valid. For more information +about available `options`, see [res.cookie()](#res.cookie). + +
    +The `expires` and `max-age` options are being ignored completely. +
    + +
    +Web browsers and other compliant clients will only clear the cookie if the given +`options` is identical to those given to [res.cookie()](#res.cookie) +
    + +```js +res.cookie('name', 'tobi', { path: '/admin' }); +res.clearCookie('name', { path: '/admin' }); +``` diff --git a/astro/src/content/docs/de/5x/api/response/res-cookie.md b/astro/src/content/docs/de/5x/api/response/res-cookie.md new file mode 100644 index 0000000000..ab7e81de34 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/response/res-cookie.md @@ -0,0 +1,95 @@ +--- +title: res.cookie +description: Sets cookie name to value. The value parameter may be a string or object converted to JSON. +--- + +

    res.cookie(name, value [, options])

    + +Sets cookie `name` to `value`. The `value` parameter may be a string or object converted to JSON. + +The `options` parameter is an object that can have the following properties. + +
    + +| Property | Type | Description | +| ------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `domain` | String | Domain name for the cookie. Defaults to the domain name of the app. | +| `encode` | Function | A synchronous function used for cookie value encoding. Defaults to `encodeURIComponent`. | +| `expires` | Date | Expiry date of the cookie in GMT. If not specified or set to 0, creates a session cookie. | +| `httpOnly` | Boolean | Flags the cookie to be accessible only by the web server. | +| `maxAge` | Number | Convenient option for setting the expiry time relative to the current time in milliseconds. | +| `path` | String | Path for the cookie. Defaults to "/". | +| `partitioned` | Boolean | Indicates that the cookie should be stored using partitioned storage. See [Cookies Having Independent Partitioned State (CHIPS)](https://developer.mozilla.org/en-US/docs/Web/Privacy/Partitioned_cookies) for more details. | +| `priority` | String | Value of the "Priority" **Set-Cookie** attribute. | +| `secure` | Boolean | Marks the cookie to be used with HTTPS only. | +| `signed` | Boolean | Indicates if the cookie should be signed. | +| `sameSite` | Boolean or String | Value of the "SameSite" **Set-Cookie** attribute. More information at [https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00#section-4.1.1](https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00#section-4.1.1). | + +
    + +
    +All `res.cookie()` does is set the HTTP `Set-Cookie` header with the options provided. +Any option not specified defaults to the value stated in [RFC 6265](http://tools.ietf.org/html/rfc6265). +
    + +For example: + +```js +res.cookie('name', 'tobi', { domain: '.example.com', path: '/admin', secure: true }); +res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true }); +``` + +You can set multiple cookies in a single response by calling `res.cookie` multiple times, for example: + +```js +res + .status(201) + .cookie('access_token', `Bearer ${token}`, { + expires: new Date(Date.now() + 8 * 3600000), // cookie will be removed after 8 hours + }) + .cookie('test', 'test') + .redirect(301, '/admin'); +``` + +The `encode` option allows you to choose the function used for cookie value encoding. +Does not support asynchronous functions. + +Example use case: You need to set a domain-wide cookie for another site in your organization. +This other site (not under your administrative control) does not use URI-encoded cookie values. + +```js +// Default encoding +res.cookie('some_cross_domain_cookie', 'http://mysubdomain.example.com', { domain: 'example.com' }); +// Result: 'some_cross_domain_cookie=http%3A%2F%2Fmysubdomain.example.com; Domain=example.com; Path=/' + +// Custom encoding +res.cookie('some_cross_domain_cookie', 'http://mysubdomain.example.com', { + domain: 'example.com', + encode: String, +}); +// Result: 'some_cross_domain_cookie=http://mysubdomain.example.com; Domain=example.com; Path=/;' +``` + +The `maxAge` option is a convenience option for setting "expires" relative to the current time in milliseconds. +The following is equivalent to the second example above. + +```js +res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true }); +``` + +You can pass an object as the `value` parameter; it is then serialized as JSON and parsed by `bodyParser()` middleware. + +```js +res.cookie('cart', { items: [1, 2, 3] }); +res.cookie('cart', { items: [1, 2, 3] }, { maxAge: 900000 }); +``` + +When using [cookie-parser](https://www.npmjs.com/package/cookie-parser) middleware, this method also +supports signed cookies. Simply include the `signed` option set to `true`. +Then, `res.cookie()` will use the secret passed to `cookieParser(secret)` to sign the value. + +```js +res.cookie('name', 'tobi', { signed: true }); +``` + +Later, you may access this value through the [req.signedCookies](#req.signedCookies) object. diff --git a/astro/src/content/docs/de/5x/api/response/res-download.md b/astro/src/content/docs/de/5x/api/response/res-download.md new file mode 100644 index 0000000000..42eb6db49f --- /dev/null +++ b/astro/src/content/docs/de/5x/api/response/res-download.md @@ -0,0 +1,66 @@ +--- +title: res.download +description: res.download provides access to data on the running file system +--- + +

    res.download(path [, filename] [, options] [, fn])

    + +
    +The optional `options` argument is supported by Express v4.16.0 onwards. +
    + +Transfers the file at `path` as an "attachment". Typically, browsers will prompt the user for download. +By default, the `Content-Disposition` header "filename=" parameter is derived from the `path` argument, but can be overridden with the `filename` parameter. +If `path` is relative, then it will be based on the current working directory of the process or +the `root` option, if provided. + +
    +This API provides access to data on the running file system. Ensure that either (a) the way in +which the `path` argument was constructed is secure if it contains user input or (b) set the `root` +option to the absolute path of a directory to contain access within. + +When the `root` option is provided, Express will validate that the relative path provided as +`path` will resolve within the given `root` option. + +
    + +The following table provides details on the `options` parameter. + +
    +The optional `options` argument is supported by Express v4.16.0 onwards. +
    + +
    + +| Property | Description | Default | Availability | +| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------ | +| `maxAge` | Sets the max-age property of the `Cache-Control` header in milliseconds or a string in [ms format](https://www.npmjs.org/package/ms) | 0 | 4.16+ | +| `root` | Root directory for relative filenames. | | 4.18+ | +| `lastModified` | Sets the `Last-Modified` header to the last modified date of the file on the OS. Set `false` to disable it. | Enabled | 4.16+ | +| `headers` | Object containing HTTP headers to serve with the file. The header `Content-Disposition` will be overridden by the `filename` argument. | | 4.16+ | +| `dotfiles` | Option for serving dotfiles. Possible values are "allow", "deny", "ignore". | "ignore" | 4.16+ | +| `acceptRanges` | Enable or disable accepting ranged requests. | `true` | 4.16+ | +| `cacheControl` | Enable or disable setting `Cache-Control` response header. | `true` | 4.16+ | +| `immutable` | Enable or disable the `immutable` directive in the `Cache-Control` response header. If enabled, the `maxAge` option should also be specified to enable caching. The `immutable` directive will prevent supported clients from making conditional requests during the life of the `maxAge` option to check if the file has changed. | `false` | 4.16+ | + +
    + +The method invokes the callback function `fn(err)` when the transfer is complete +or when an error occurs. If the callback function is specified and an error occurs, +the callback function must explicitly handle the response process either by +ending the request-response cycle, or by passing control to the next route. + +```js +res.download('/report-12345.pdf'); + +res.download('/report-12345.pdf', 'report.pdf'); + +res.download('/report-12345.pdf', 'report.pdf', (err) => { + if (err) { + // Handle error, but keep in mind the response may be partially-sent + // so check res.headersSent + } else { + // decrement a download credit, etc. + } +}); +``` diff --git a/astro/src/content/docs/de/5x/api/response/res-end.md b/astro/src/content/docs/de/5x/api/response/res-end.md new file mode 100644 index 0000000000..1d59764120 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/response/res-end.md @@ -0,0 +1,15 @@ +--- +title: res.end +description: Ends the response process. This method actually comes from Node core, specifically the response.end method of http.ServerResponse. +--- + +

    res.end([data[, encoding]][, callback])

    + +Ends the response process. This method actually comes from Node core, specifically the [response.end() method of http.ServerResponse](https://nodejs.org/api/http.html#responseenddata-encoding-callback). + +Use to quickly end the response without any data. If you need to respond with data, instead use methods such as [res.send()](#res.send) and [res.json()](#res.json). + +```js +res.end(); +res.status(404).end(); +``` diff --git a/astro/src/content/docs/de/5x/api/response/res-format.md b/astro/src/content/docs/de/5x/api/response/res-format.md new file mode 100644 index 0000000000..92e7c40e45 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/response/res-format.md @@ -0,0 +1,57 @@ +--- +title: res.format +description: Performs content-negotiation on the Accept HTTP header on the request object, when present. +--- + +

    res.format(object)

    + +Performs content-negotiation on the `Accept` HTTP header on the request object, when present. +It uses [req.accepts()](#req.accepts) to select a handler for the request, based on the acceptable +types ordered by their quality values. If the header is not specified, the first callback is invoked. +When no match is found, the server responds with 406 "Not Acceptable", or invokes the `default` callback. + +The `Content-Type` response header is set when a callback is selected. However, you may alter +this within the callback using methods such as `res.set()` or `res.type()`. + +The following example would respond with `{ "message": "hey" }` when the `Accept` header field is set +to "application/json" or "\*/json" (however, if it is "\*/\*", then the response will be "hey"). + +```js +res.format({ + 'text/plain'() { + res.send('hey'); + }, + + 'text/html'() { + res.send('

    hey

    '); + }, + + 'application/json'() { + res.send({ message: 'hey' }); + }, + + default() { + // log the request and respond with 406 + res.status(406).send('Not Acceptable'); + }, +}); +``` + +In addition to canonicalized MIME types, you may also use extension names mapped +to these types for a slightly less verbose implementation: + +```js +res.format({ + text() { + res.send('hey'); + }, + + html() { + res.send('

    hey

    '); + }, + + json() { + res.send({ message: 'hey' }); + }, +}); +``` diff --git a/astro/src/content/docs/de/5x/api/response/res-get.md b/astro/src/content/docs/de/5x/api/response/res-get.md new file mode 100644 index 0000000000..300dd9d1a9 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/response/res-get.md @@ -0,0 +1,14 @@ +--- +title: res.get +description: Returns the HTTP response header specified by field. +--- + +

    res.get(field)

    + +Returns the HTTP response header specified by `field`. +The match is case-insensitive. + +```js +res.get('Content-Type'); +// => "text/plain" +``` diff --git a/astro/src/content/docs/de/5x/api/response/res-headersSent.md b/astro/src/content/docs/de/5x/api/response/res-headersSent.md new file mode 100644 index 0000000000..ed9b41069e --- /dev/null +++ b/astro/src/content/docs/de/5x/api/response/res-headersSent.md @@ -0,0 +1,16 @@ +--- +title: res.headersSent +description: Boolean property that indicates if the app sent HTTP headers for the response. +--- + +

    res.headersSent

    + +Boolean property that indicates if the app sent HTTP headers for the response. + +```js +app.get('/', (req, res) => { + console.log(res.headersSent); // false + res.send('OK'); + console.log(res.headersSent); // true +}); +``` diff --git a/astro/src/content/docs/de/5x/api/response/res-json.md b/astro/src/content/docs/de/5x/api/response/res-json.md new file mode 100644 index 0000000000..40d6c0c083 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/response/res-json.md @@ -0,0 +1,18 @@ +--- +title: res.json +description: Sends a JSON response. This method sends a response (with the correct content-type) that is the parameter converted to a +--- + +

    res.json([body])

    + +Sends a JSON response. This method sends a response (with the correct content-type) that is the parameter converted to a +JSON string using [JSON.stringify()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify). + +The parameter can be any JSON type, including object, array, string, Boolean, number, or null, +and you can also use it to convert other values to JSON. + +```js +res.json(null); +res.json({ user: 'tobi' }); +res.status(500).json({ error: 'message' }); +``` diff --git a/astro/src/content/docs/de/5x/api/response/res-jsonp.md b/astro/src/content/docs/de/5x/api/response/res-jsonp.md new file mode 100644 index 0000000000..7dad964a15 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/response/res-jsonp.md @@ -0,0 +1,37 @@ +--- +title: res.jsonp +description: Sends a JSON response with JSONP support. This method is identical to res.json, +--- + +

    res.jsonp([body])

    + +Sends a JSON response with JSONP support. This method is identical to `res.json()`, +except that it opts-in to JSONP callback support. + +```js +res.jsonp(null); +// => callback(null) + +res.jsonp({ user: 'tobi' }); +// => callback({ "user": "tobi" }) + +res.status(500).jsonp({ error: 'message' }); +// => callback({ "error": "message" }) +``` + +By default, the JSONP callback name is simply `callback`. Override this with the +jsonp callback name setting. + +The following are some examples of JSONP responses using the same code: + +```js +// ?callback=foo +res.jsonp({ user: 'tobi' }); +// => foo({ "user": "tobi" }) + +app.set('jsonp callback name', 'cb'); + +// ?cb=foo +res.status(500).jsonp({ error: 'message' }); +// => foo({ "error": "message" }) +``` diff --git a/astro/src/content/docs/de/5x/api/response/res-links.md b/astro/src/content/docs/de/5x/api/response/res-links.md new file mode 100644 index 0000000000..db6aaba927 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/response/res-links.md @@ -0,0 +1,25 @@ +--- +title: res.links +description: Joins the links provided as properties of the parameter to populate the response Link HTTP header field +--- + + + +Joins the `links` provided as properties of the parameter to populate the response's +`Link` HTTP header field. + +For example, the following call: + +```js +res.links({ + next: 'http://api.example.com/users?page=2', + last: 'http://api.example.com/users?page=5', +}); +``` + +Yields the following results: + +``` +Link: ; rel="next", + ; rel="last" +``` diff --git a/astro/src/content/docs/de/5x/api/response/res-locals.md b/astro/src/content/docs/de/5x/api/response/res-locals.md new file mode 100644 index 0000000000..d2cf8c9b85 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/response/res-locals.md @@ -0,0 +1,33 @@ +--- +title: res.locals +description: Use this property to set variables accessible in templates rendered with [res.render](#res.render). +--- + +

    res.locals

    + +Use this property to set variables accessible in templates rendered with [res.render](#res.render). +The variables set on `res.locals` are available within a single request-response cycle, and will not +be shared between requests. + +
    +The `locals` object is used by view engines to render a response. The object +keys may be particularly sensitive and should not contain user-controlled +input, as it may affect the operation of the view engine or provide a path to +cross-site scripting. Consult the documentation for the used view engine for +additional considerations. +
    + +In order to keep local variables for use in template rendering between requests, use +[app.locals](#app.locals) instead. + +This property is useful for exposing request-level information such as the request path name, +authenticated user, user settings, and so on to templates rendered within the application. + +```js +app.use((req, res, next) => { + // Make `user` and `authenticated` available in templates + res.locals.user = req.user; + res.locals.authenticated = !req.user.anonymous; + next(); +}); +``` diff --git a/astro/src/content/docs/de/5x/api/response/res-location.md b/astro/src/content/docs/de/5x/api/response/res-location.md new file mode 100644 index 0000000000..37104a0eb3 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/response/res-location.md @@ -0,0 +1,22 @@ +--- +title: res.location +description: Sets the response Location HTTP header to the specified path parameter. +--- + +

    res.location(path)

    + +Sets the response `Location` HTTP header to the specified `path` parameter. + +```js +res.location('/foo/bar'); +res.location('http://example.com'); +``` + +
    +After encoding the URL, if not encoded already, Express passes the specified URL to the browser in the `Location` header, +without any validation. + +Browsers take the responsibility of deriving the intended URL from the current URL +or the referring URL, and the URL specified in the `Location` header; and redirect the user accordingly. + +
    diff --git a/astro/src/content/docs/de/5x/api/response/res-redirect.md b/astro/src/content/docs/de/5x/api/response/res-redirect.md new file mode 100644 index 0000000000..86932014ca --- /dev/null +++ b/astro/src/content/docs/de/5x/api/response/res-redirect.md @@ -0,0 +1,56 @@ +--- +title: res.redirect +description: Redirects to the URL derived from the specified path, with specified status, a positive integer +--- + +

    res.redirect([status,] path)

    + +Redirects to the URL derived from the specified `path`, with specified `status`, a positive integer +that corresponds to an [HTTP status code](https://www.rfc-editor.org/rfc/rfc9110.html#name-status-codes). +If not specified, `status` defaults to `302 "Found"`. + +```js +res.redirect('/foo/bar'); +res.redirect('http://example.com'); +res.redirect(301, 'http://example.com'); +res.redirect('../login'); +``` + +Redirects can be a fully-qualified URL for redirecting to a different site: + +```js +res.redirect('http://google.com'); +``` + +Redirects can be relative to the root of the host name. For example, if the +application is on `http://example.com/admin/post/new`, the following +would redirect to the URL `http://example.com/admin`: + +```js +res.redirect('/admin'); +``` + +Redirects can be relative to the current URL. For example, +from `http://example.com/blog/admin/` (notice the trailing slash), the following +would redirect to the URL `http://example.com/blog/admin/post/new`. + +```js +res.redirect('post/new'); +``` + +Redirecting to `post/new` from `http://example.com/blog/admin` (no trailing slash), +will redirect to `http://example.com/blog/post/new`. + +If you found the above behavior confusing, think of path segments as directories +(with trailing slashes) and files, it will start to make sense. + +Path-relative redirects are also possible. If you were on +`http://example.com/admin/post/new`, the following would redirect to +`http://example.com/admin/post`: + +```js +res.redirect('..'); +``` + +See also [Security best practices: Prevent open redirect +vulnerabilities](http://expressjs.com/en/advanced/best-practice-security.html#prevent-open-redirects). diff --git a/astro/src/content/docs/de/5x/api/response/res-render.md b/astro/src/content/docs/de/5x/api/response/res-render.md new file mode 100644 index 0000000000..c9a4cad9f9 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/response/res-render.md @@ -0,0 +1,42 @@ +--- +title: res.render +description: Renders a view and sends the rendered HTML string to the client. +--- + +

    res.render(view [, locals] [, callback])

    + +Renders a `view` and sends the rendered HTML string to the client. +Optional parameters: + +- `locals`, an object whose properties define local variables for the view. +- `callback`, a callback function. If provided, the method returns both the possible error and rendered string, but does not perform an automated response. When an error occurs, the method invokes `next(err)` internally. + +The `view` argument is a string that is the file path of the view file to render. This can be an absolute path, or a path relative to the `views` setting. If the path does not contain a file extension, then the `view engine` setting determines the file extension. If the path does contain a file extension, then Express will load the module for the specified template engine (via `require()`) and render it using the loaded module's `__express` function. + +For more information, see [Using template engines with Express](/{{page.lang}}/guide/using-template-engines.html). + +{% include admonitions/warning.html content="The `view` argument performs file system operations like reading a file from disk and evaluating Node.js modules, and as so for security reasons should not contain input from the end-user." %} + +{% include admonitions/warning.html content="The `locals` object is used by view engines to render a response. The object +keys may be particularly sensitive and should not contain user-controlled +input, as it may affect the operation of the view engine or provide a path to +cross-site scripting. Consult the documentation for the used view engine for +additional considerations." %} + +{% include admonitions/caution.html content="The local variable `cache` enables view caching. Set it to `true`, +to cache the view during development; view caching is enabled in production by default." %} + +```js +// send the rendered view to the client +res.render('index'); + +// if a callback is specified, the rendered HTML string has to be sent explicitly +res.render('index', (err, html) => { + res.send(html); +}); + +// pass a local variable to the view +res.render('user', { name: 'Tobi' }, (err, html) => { + // ... +}); +``` diff --git a/astro/src/content/docs/de/5x/api/response/res-req.md b/astro/src/content/docs/de/5x/api/response/res-req.md new file mode 100644 index 0000000000..f20548a045 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/response/res-req.md @@ -0,0 +1,9 @@ +--- +title: res.req +description: This property holds a reference to the +--- + +

    res.req

    + +This property holds a reference to the request object +that relates to this response object. diff --git a/astro/src/content/docs/de/5x/api/response/res-send.md b/astro/src/content/docs/de/5x/api/response/res-send.md new file mode 100644 index 0000000000..dd1797ff42 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/response/res-send.md @@ -0,0 +1,44 @@ +--- +title: res.send +description: Sends the HTTP response. +--- + +

    res.send([body])

    + +Sends the HTTP response. + +The `body` parameter can be a `Buffer` object, a `String`, an object, `Boolean`, or an `Array`. +For example: + +```js +res.send(Buffer.from('whoop')); +res.send({ some: 'json' }); +res.send('

    some html

    '); +res.status(404).send('Sorry, we cannot find that!'); +res.status(500).send({ error: 'something blew up' }); +``` + +This method performs many useful tasks for simple non-streaming responses: +For example, it automatically assigns the `Content-Length` HTTP response header field +and provides automatic HEAD and HTTP cache freshness support. + +When the parameter is a `Buffer` object, the method sets the `Content-Type` +response header field to "application/octet-stream", unless previously defined as shown below: + +```js +res.set('Content-Type', 'text/html'); +res.send(Buffer.from('

    some html

    ')); +``` + +When the parameter is a `String`, the method sets the `Content-Type` to "text/html": + +```js +res.send('

    some html

    '); +``` + +When the parameter is an `Array` or `Object`, Express responds with the JSON representation: + +```js +res.send({ user: 'tobi' }); +res.send([1, 2, 3]); +``` diff --git a/astro/src/content/docs/de/5x/api/response/res-sendFile.md b/astro/src/content/docs/de/5x/api/response/res-sendFile.md new file mode 100644 index 0000000000..750532497f --- /dev/null +++ b/astro/src/content/docs/de/5x/api/response/res-sendFile.md @@ -0,0 +1,91 @@ +--- +title: res.sendFile +description: res.sendFile transfers the file at the given path. Sets the Content-Type response HTTP header field based on the filename extension +--- + +

    res.sendFile(path [, options] [, fn])

    + +
    +`res.sendFile()` is supported by Express v4.8.0 onwards. +
    + +Transfers the file at the given `path`. Sets the `Content-Type` response HTTP header field +based on the filename's extension. Unless the `root` option is set in +the options object, `path` must be an absolute path to the file. + +
    +This API provides access to data on the running file system. Ensure that either (a) the way in +which the `path` argument was constructed into an absolute path is secure if it contains user +input or (b) set the `root` option to the absolute path of a directory to contain access within. + +When the `root` option is provided, the `path` argument is allowed to be a relative path, +including containing `..`. Express will validate that the relative path provided as `path` will +resolve within the given `root` option. + +
    + +The following table provides details on the `options` parameter. + +
    + +| Property | Description | Default | Availability | +| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------ | +| `maxAge` | Sets the max-age property of the `Cache-Control` header in milliseconds or a string in [ms format](https://www.npmjs.org/package/ms) | 0 | | +| `root` | Root directory for relative filenames. | | | +| `lastModified` | Sets the `Last-Modified` header to the last modified date of the file on the OS. Set `false` to disable it. | Enabled | 4.9.0+ | +| `headers` | Object containing HTTP headers to serve with the file. | | | +| `dotfiles` | Option for serving dotfiles. Possible values are "allow", "deny", "ignore". | "ignore" |   | +| `acceptRanges` | Enable or disable accepting ranged requests. | `true` | 4.14+ | +| `cacheControl` | Enable or disable setting `Cache-Control` response header. | `true` | 4.14+ | +| `immutable` | Enable or disable the `immutable` directive in the `Cache-Control` response header. If enabled, the `maxAge` option should also be specified to enable caching. The `immutable` directive will prevent supported clients from making conditional requests during the life of the `maxAge` option to check if the file has changed. | `false` | 4.16+ | + +
    + +The method invokes the callback function `fn(err)` when the transfer is complete +or when an error occurs. If the callback function is specified and an error occurs, +the callback function must explicitly handle the response process either by +ending the request-response cycle, or by passing control to the next route. + +Here is an example of using `res.sendFile` with all its arguments. + +```js +app.get('/file/:name', (req, res, next) => { + const options = { + root: path.join(__dirname, 'public'), + dotfiles: 'deny', + headers: { + 'x-timestamp': Date.now(), + 'x-sent': true, + }, + }; + + const fileName = req.params.name; + res.sendFile(fileName, options, (err) => { + if (err) { + next(err); + } else { + console.log('Sent:', fileName); + } + }); +}); +``` + +The following example illustrates using +`res.sendFile` to provide fine-grained support for serving files: + +```js +app.get('/user/:uid/photos/:file', (req, res) => { + const uid = req.params.uid; + const file = req.params.file; + + req.user.mayViewFilesFrom(uid, (yes) => { + if (yes) { + res.sendFile(`/uploads/${uid}/${file}`); + } else { + res.status(403).send("Sorry! You can't see that."); + } + }); +}); +``` + +For more information, or if you have issues or concerns, see [send](https://github.com/pillarjs/send). diff --git a/astro/src/content/docs/de/5x/api/response/res-sendStatus.md b/astro/src/content/docs/de/5x/api/response/res-sendStatus.md new file mode 100644 index 0000000000..ae77bd6f46 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/response/res-sendStatus.md @@ -0,0 +1,20 @@ +--- +title: res.sendStatus +description: Sets the response HTTP status code to statusCode and sends the registered status message as the text response body. If an unknown status code is specified, the response body will be just the code number. +--- + +

    res.sendStatus(statusCode)

    + +Sets the response HTTP status code to `statusCode` and sends the registered status message as the text response body. If an unknown status code is specified, the response body will just be the code number. + +```js +res.sendStatus(404); +``` + +
    +Some versions of Node.js will throw when `res.statusCode` is set to an +invalid HTTP status code (outside of the range `100` to `599`). Consult +the HTTP server documentation for the Node.js version being used. +
    + +[More about HTTP Status Codes](http://en.wikipedia.org/wiki/List_of_HTTP_status_codes) diff --git a/astro/src/content/docs/de/5x/api/response/res-set.md b/astro/src/content/docs/de/5x/api/response/res-set.md new file mode 100644 index 0000000000..6d2b01e63e --- /dev/null +++ b/astro/src/content/docs/de/5x/api/response/res-set.md @@ -0,0 +1,21 @@ +--- +title: res.set +description: Sets the response HTTP header field to value. +--- + +

    res.set(field [, value])

    + +Sets the response's HTTP header `field` to `value`. +To set multiple fields at once, pass an object as the parameter. + +```js +res.set('Content-Type', 'text/plain'); + +res.set({ + 'Content-Type': 'text/plain', + 'Content-Length': '123', + ETag: '12345', +}); +``` + +Aliased as `res.header(field [, value])`. diff --git a/astro/src/content/docs/de/5x/api/response/res-status.md b/astro/src/content/docs/de/5x/api/response/res-status.md new file mode 100644 index 0000000000..4969cd4ff9 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/response/res-status.md @@ -0,0 +1,15 @@ +--- +title: res.status +description: Sets the HTTP status for the response. +--- + +

    res.status(code)

    + +Sets the HTTP status for the response. +It is a chainable alias of Node's [response.statusCode](http://nodejs.org/api/http.html#http_response_statuscode). + +```js +res.status(403).end(); +res.status(400).send('Bad Request'); +res.status(404).sendFile('/absolute/path/to/404.png'); +``` diff --git a/astro/src/content/docs/de/5x/api/response/res-type.md b/astro/src/content/docs/de/5x/api/response/res-type.md new file mode 100644 index 0000000000..b566a8d143 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/response/res-type.md @@ -0,0 +1,18 @@ +--- +title: res.type +description: Sets the Content-Type HTTP header to the MIME type as determined by the specified type. If type contains the slash character, then it sets the Content-Type to the exact value. +--- + +

    res.type(type)

    + +Sets the `Content-Type` HTTP header to the MIME type as determined by the specified `type`. If `type` contains the "/" character, then it sets the `Content-Type` to the exact value of `type`, otherwise it is assumed to be a file extension and the MIME type is looked up using the `contentType()` method of the `mime-types` package. + +```js +res.type('.html'); // => 'text/html' +res.type('html'); // => 'text/html' +res.type('json'); // => 'application/json' +res.type('application/json'); // => 'application/json' +res.type('png'); // => image/png: +``` + +Aliased as `res.contentType(type)`. diff --git a/astro/src/content/docs/de/5x/api/response/res-vary.md b/astro/src/content/docs/de/5x/api/response/res-vary.md new file mode 100644 index 0000000000..164bed9285 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/response/res-vary.md @@ -0,0 +1,12 @@ +--- +title: res.vary +description: Adds the field to the Vary response header, if it is not there already. +--- + +

    res.vary(field)

    + +Adds the field to the `Vary` response header, if it is not there already. + +```js +res.vary('User-Agent').render('docs'); +``` diff --git a/astro/src/content/docs/de/5x/api/router/overview.md b/astro/src/content/docs/de/5x/api/router/overview.md new file mode 100644 index 0000000000..e961fa8eb6 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/router/overview.md @@ -0,0 +1,66 @@ +--- +title: Methods +description: section markdown="1"> +--- + +

    Router

    + +
    +A `router` object is an instance of middleware and routes. You can think of it +as a "mini-application," capable only of performing middleware and routing +functions. Every Express application has a built-in app router. + +A router behaves like middleware itself, so you can use it as an argument to +[app.use()](#app.use) or as the argument to another router's [use()](#router.use) method. + +The top-level `express` object has a [Router()](#express.router) method that creates a new `router` object. + +Once you've created a router object, you can add middleware and HTTP method routes (such as `get`, `put`, `post`, +and so on) to it just like an application. For example: + +```js +// invoked for any requests passed to this router +router.use((req, res, next) => { + // .. some logic here .. like any other middleware + next(); +}); + +// will handle any request that ends in /events +// depends on where the router is "use()'d" +router.get('/events', (req, res, next) => { + // .. +}); +``` + +You can then use a router for a particular root URL in this way separating your routes into files or even mini-apps. + +```js +// only requests to /calendar/* will be sent to our "router" +app.use('/calendar', router); +``` + +Keep in mind that any middleware applied to a router will run for all requests on that router's path, even those that aren't part of the router. + +
    + +

    Methods

    + +
    + {% include api/en/5x/router-all.md %} +
    + +
    + {% include api/en/5x/router-METHOD.md %} +
    + +
    + {% include api/en/5x/router-param.md %} +
    + +
    + {% include api/en/5x/router-route.md %} +
    + +
    + {% include api/en/5x/router-use.md %} +
    diff --git a/astro/src/content/docs/de/5x/api/router/router-METHOD.md b/astro/src/content/docs/de/5x/api/router/router-METHOD.md new file mode 100644 index 0000000000..a4eb343c90 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/router/router-METHOD.md @@ -0,0 +1,71 @@ +--- +title: router.METHOD +description: The router.METHOD methods provide the routing functionality in Express, where METHOD is one of the HTTP methods, such as GET, PUT, POST, and so on, in lowercase +--- + +

    router.METHOD(path, [callback, ...] callback)

    + +The `router.METHOD()` methods provide the routing functionality in Express, +where METHOD is one of the HTTP methods, such as GET, PUT, POST, and so on, +in lowercase. Thus, the actual methods are `router.get()`, `router.post()`, +`router.put()`, and so on. + +
    + The `router.get()` function is automatically called for the HTTP `HEAD` method in + addition to the `GET` method if `router.head()` was not called for the + path before `router.get()`. +
    + +You can provide multiple callbacks, and all are treated equally, and behave just +like middleware, except that these callbacks may invoke `next('route')` +to bypass the remaining route callback(s). You can use this mechanism to perform +pre-conditions on a route then pass control to subsequent routes when there is no +reason to proceed with the route matched. + +The following snippet illustrates the most simple route definition possible. +Express translates the path strings to regular expressions, used internally +to match incoming requests. Query strings are _not_ considered when performing +these matches, for example "GET /" would match the following route, as would +"GET /?name=tobi". + +```js +router.get('/', (req, res) => { + res.send('hello world'); +}); +``` + +You can also use regular expressions—useful if you have very specific +constraints, for example the following would match "GET /commits/71dbb9c" as well +as "GET /commits/71dbb9c..4c084f9". + +```js +router.get(/^\/commits\/(\w+)(?:\.\.(\w+))?$/, (req, res) => { + const from = req.params[0]; + const to = req.params[1] || 'HEAD'; + res.send(`commit range ${from}..${to}`); +}); +``` + +You can use `next` primitive to implement a flow control between different +middleware functions, based on a specific program state. Invoking `next` with +the string `'router'` will cause all the remaining route callbacks on that router +to be bypassed. + +The following example illustrates `next('router')` usage. + +```js +function fn(req, res, next) { + console.log('I come here'); + next('router'); +} +router.get('/foo', fn, (req, res, next) => { + console.log('I dont come here'); +}); +router.get('/foo', (req, res, next) => { + console.log('I dont come here'); +}); +app.get('/foo', (req, res) => { + console.log(' I come here too'); + res.end('good'); +}); +``` diff --git a/astro/src/content/docs/de/5x/api/router/router-Router.md b/astro/src/content/docs/de/5x/api/router/router-Router.md new file mode 100644 index 0000000000..de2867f15c --- /dev/null +++ b/astro/src/content/docs/de/5x/api/router/router-Router.md @@ -0,0 +1,5 @@ +--- +title: Router +--- + +

    Router([options])

    diff --git a/astro/src/content/docs/de/5x/api/router/router-all.md b/astro/src/content/docs/de/5x/api/router/router-all.md new file mode 100644 index 0000000000..6a0461bc82 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/router/router-all.md @@ -0,0 +1,36 @@ +--- +title: router.all +description: This method is just like the router.METHOD methods, except that it matches all HTTP methods (verbs). +--- + +

    router.all(path, [callback, ...] callback)

    + +This method is just like the `router.METHOD()` methods, except that it matches all HTTP methods (verbs). + +This method is extremely useful for +mapping "global" logic for specific path prefixes or arbitrary matches. +For example, if you placed the following route at the top of all other +route definitions, it would require that all routes from that point on +would require authentication, and automatically load a user. Keep in mind +that these callbacks do not have to act as end points; `loadUser` +can perform a task, then call `next()` to continue matching subsequent +routes. + +```js +router.all('{*splat}', requireAuthentication, loadUser); +``` + +Or the equivalent: + +```js +router.all('{*splat}', requireAuthentication); +router.all('{*splat}', loadUser); +``` + +Another example of this is white-listed "global" functionality. Here, +the example is much like before, but it only restricts paths prefixed with +"/api": + +```js +router.all('/api/{*splat}', requireAuthentication); +``` diff --git a/astro/src/content/docs/de/5x/api/router/router-param.md b/astro/src/content/docs/de/5x/api/router/router-param.md new file mode 100644 index 0000000000..184e0792e4 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/router/router-param.md @@ -0,0 +1,67 @@ +--- +title: router.param +description: Adds callback triggers to route parameters, where name is the name of the parameter and callback is the callback function. Although name is technically optional, it is required. +--- + +

    router.param(name, callback)

    + +Adds callback triggers to route parameters, where `name` is the name of the parameter and `callback` is the callback function. Although `name` is technically optional, using this method without it is deprecated starting with Express v4.11.0 (see below). + +The parameters of the callback function are: + +- `req`, the request object. +- `res`, the response object. +- `next`, indicating the next middleware function. +- The value of the `name` parameter. +- The name of the parameter. + +
    +Unlike `app.param()`, `router.param()` does not accept an array of route parameters. +
    + +For example, when `:user` is present in a route path, you may map user loading logic to automatically provide `req.user` to the route, or perform validations on the parameter input. + +```js +router.param('user', (req, res, next, id) => { + // try to get the user details from the User model and attach it to the request object + User.find(id, (err, user) => { + if (err) { + next(err); + } else if (user) { + req.user = user; + next(); + } else { + next(new Error('failed to load user')); + } + }); +}); +``` + +Param callback functions are local to the router on which they are defined. They are not inherited by mounted apps or routers, nor are they triggered for route parameters inherited from parent routers. Hence, param callbacks defined on `router` will be triggered only by route parameters defined on `router` routes. + +A param callback will be called only once in a request-response cycle, even if the parameter is matched in multiple routes, as shown in the following examples. + +```js +router.param('id', (req, res, next, id) => { + console.log('CALLED ONLY ONCE'); + next(); +}); + +router.get('/user/:id', (req, res, next) => { + console.log('although this matches'); + next(); +}); + +router.get('/user/:id', (req, res) => { + console.log('and this matches too'); + res.end(); +}); +``` + +On `GET /user/42`, the following is printed: + +``` +CALLED ONLY ONCE +although this matches +and this matches too +``` diff --git a/astro/src/content/docs/de/5x/api/router/router-route.md b/astro/src/content/docs/de/5x/api/router/router-route.md new file mode 100644 index 0000000000..f3d9d42075 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/router/router-route.md @@ -0,0 +1,54 @@ +--- +title: router.route +description: Returns an instance of a single route which you can then use to handle HTTP verbs +--- + +

    router.route(path)

    + +Returns an instance of a single route which you can then use to handle HTTP verbs +with optional middleware. Use `router.route()` to avoid duplicate route naming and +thus typing errors. + +Building on the `router.param()` example above, the following code shows how to use +`router.route()` to specify various HTTP method handlers. + +```js +const router = express.Router(); + +router.param('user_id', (req, res, next, id) => { + // sample user, would actually fetch from DB, etc... + req.user = { + id, + name: 'TJ', + }; + next(); +}); + +router + .route('/users/:user_id') + .all((req, res, next) => { + // runs for all HTTP verbs first + // think of it as route specific middleware! + next(); + }) + .get((req, res, next) => { + res.json(req.user); + }) + .put((req, res, next) => { + // just an example of maybe updating the user + req.user.name = req.params.name; + // save user ... etc + res.json(req.user); + }) + .post((req, res, next) => { + next(new Error('not implemented')); + }) + .delete((req, res, next) => { + next(new Error('not implemented')); + }); +``` + +This approach re-uses the single `/users/:user_id` path and adds handlers for +various HTTP methods. + +{% include admonitions/note.html content="When you use `router.route()`, middleware ordering is based on when the _route_ is created, not when method handlers are added to the route. For this purpose, you can consider method handlers to belong to the route to which they were added." %} diff --git a/astro/src/content/docs/de/5x/api/router/router-use.md b/astro/src/content/docs/de/5x/api/router/router-use.md new file mode 100644 index 0000000000..6e31cf7f22 --- /dev/null +++ b/astro/src/content/docs/de/5x/api/router/router-use.md @@ -0,0 +1,111 @@ +--- +title: router.use +description: Uses the specified middleware function or functions, with optional mount path that defaults to slash. +--- + +

    router.use([path], [function, ...] function)

    + +Uses the specified middleware function or functions, with optional mount path `path`, that defaults to "/". + +This method is similar to [app.use()](#app.use). A simple example and use case is described below. +See [app.use()](#app.use) for more information. + +Middleware is like a plumbing pipe: requests start at the first middleware function defined +and work their way "down" the middleware stack processing for each path they match. + +```js +const express = require('express'); +const app = express(); +const router = express.Router(); + +// simple logger for this router's requests +// all requests to this router will first hit this middleware +router.use((req, res, next) => { + console.log('%s %s %s', req.method, req.url, req.path); + next(); +}); + +// this will only be invoked if the path starts with /bar from the mount point +router.use('/bar', (req, res, next) => { + // ... maybe some additional /bar logging ... + next(); +}); + +// always invoked +router.use((req, res, next) => { + res.send('Hello World'); +}); + +app.use('/foo', router); + +app.listen(3000); +``` + +The "mount" path is stripped and is _not_ visible to the middleware function. +The main effect of this feature is that a mounted middleware function may operate without +code changes regardless of its "prefix" pathname. + +The order in which you define middleware with `router.use()` is very important. +They are invoked sequentially, thus the order defines middleware precedence. For example, +usually a logger is the very first middleware you would use, so that every request gets logged. + +```js +const logger = require('morgan'); + +router.use(logger()); +router.use(express.static(path.join(__dirname, 'public'))); +router.use((req, res) => { + res.send('Hello'); +}); +``` + +Now suppose you wanted to ignore logging requests for static files, but to continue +logging routes and middleware defined after `logger()`. You would simply move the call to `express.static()` to the top, +before adding the logger middleware: + +```js +router.use(express.static(path.join(__dirname, 'public'))); +router.use(logger()); +router.use((req, res) => { + res.send('Hello'); +}); +``` + +Another example is serving files from multiple directories, +giving precedence to "./public" over the others: + +```js +app.use(express.static(path.join(__dirname, 'public'))); +app.use(express.static(path.join(__dirname, 'files'))); +app.use(express.static(path.join(__dirname, 'uploads'))); +``` + +The `router.use()` method also supports named parameters so that your mount points +for other routers can benefit from preloading using named parameters. + +**NOTE**: Although these middleware functions are added via a particular router, _when_ +they run is defined by the path they are attached to (not the router). Therefore, +middleware added via one router may run for other routers if its routes +match. For example, this code shows two different routers mounted on the same path: + +```js +const authRouter = express.Router(); +const openRouter = express.Router(); + +authRouter.use(require('./authenticate').basic(usersdb)); + +authRouter.get('/:user_id/edit', (req, res, next) => { + // ... Edit user UI ... +}); +openRouter.get('/', (req, res, next) => { + // ... List users ... +}); +openRouter.get('/:user_id', (req, res, next) => { + // ... View user ... +}); + +app.use('/users', authRouter); +app.use('/users', openRouter); +``` + +Even though the authentication middleware was added via the `authRouter` it will run on the routes defined by the `openRouter` as well since both routers were mounted on `/users`. To avoid this behavior, use different paths for each router. diff --git a/astro/src/content/docs/de/5x/guide/behind-proxies.md b/astro/src/content/docs/de/5x/guide/behind-proxies.md new file mode 100644 index 0000000000..b56026a0d2 --- /dev/null +++ b/astro/src/content/docs/de/5x/guide/behind-proxies.md @@ -0,0 +1,90 @@ +--- +title: Express hinter Proxys +description: Learn how to configure Express.js applications to work correctly behind reverse proxies, including using the trust proxy setting to handle client IP addresses. +--- + +# Express hinter Proxys + +When running an Express app behind a reverse proxy, some of the Express APIs may return different values than expected. In order to adjust for this, the `trust proxy` application setting may be used to expose information provided by the reverse proxy in the Express APIs. The most common issue is express APIs that expose the client's IP address may instead show an internal IP address of the reverse proxy. + +
    +When configuring the `trust proxy` setting, it is important to understand the exact setup of the reverse proxy. Since this setting will trust values provided in the request, it is important that the combination of the setting in Express matches how the reverse proxy operates. +
    + +Bei der Ausführung einer Express-Anwendung hinter einem Proxy legen Sie die Anwendungsvariable `trust proxy` (mithilfe von [app.set()](/{{ page.lang }}/4x/api.html#app.set)) auf einen der in der folgenden Tabelle enthaltenen Werte fest: + + + + + + + + + + + + + + + + + + + + + +
    TypWert
    BooleschWenn `true` angegeben wird, wird die IP-Adresse des Clients als der äußerst rechte Eintrag im Header `X-Forwarded-*` interpretiert. + +Wenn `false` angegeben wird, wird die Anwendung als direkte Verbindung zum Internet gesehen. Die IP-Adresse des Clients wird dann von `req.connection.remoteAddress` abgeleitet. Dies ist die Standardeinstellung. + +
    +When setting to `true`, it is important to ensure that the last reverse proxy trusted is removing/overwriting all of the following HTTP headers: `X-Forwarded-For`, `X-Forwarded-Host`, and `X-Forwarded-Proto`, otherwise it may be possible for the client to provide any value. +
    +
    IP addresses +An IP address, subnet, or an array of IP addresses and subnets to trust as being a reverse proxy. The following list shows the pre-configured subnet names: + +- loopback - `127.0.0.1/8`, `::1/128` +- linklocal - `169.254.0.0/16`, `fe80::/10` +- uniquelocal - `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `fc00::/7` + +Sie können IP-Adressen wie folgt festlegen: + +```js +app.set('trust proxy', 'loopback'); // specify a single subnet +app.set('trust proxy', 'loopback, 123.123.123.123'); // specify a subnet and an address +app.set('trust proxy', 'loopback, linklocal, uniquelocal'); // specify multiple subnets as CSV +app.set('trust proxy', ['loopback', 'linklocal', 'uniquelocal']); // specify multiple subnets as an array +``` + +Sobald die Werte angegeben wurden, werden die betreffenden IP-Adressen und Teilnetze aus dem Adressfeststellungsprozess ausgeschlossen. Die nicht vertrauenswürdige IP-Adresse, die am nächsten zum Anwendungsserver liegt, wird als IP-Adresse des Clients festgelegt. This works by checking if `req.socket.remoteAddress` is trusted. If so, then each address in `X-Forwarded-For` is checked from right to left until the first non-trusted address. + +
    Zahl +Use the address that is at most `n` number of hops away from the Express application. `req.socket.remoteAddress` is the first hop, and the rest are looked for in the `X-Forwarded-For` header from right to left. A value of `0` means that the first untrusted address would be `req.socket.remoteAddress`, i.e. there is no reverse proxy. + +
    +When using this setting, it is important to ensure there are not multiple, different-length paths to the Express application such that the client can be less than the configured number of hops away, otherwise it may be possible for the client to provide any value. +
    +
    Function +Custom trust implementation. + +```js +app.set('trust proxy', (ip) => { + if (ip === '127.0.0.1' || ip === '123.123.123.123') + return true; // trusted IPs + else return false; +}); +``` + +
    + +Enabling `trust proxy` will have the following impact: + +
      +
    • Der Wert für [req.hostname](/{{ page.lang }}/api.html#req.hostname) wird vom Wert abgeleitet, der im Header `X-Forwarded-Host` festgelegt wurde. Dieser Wert kann vom Client oder Proxy festgelegt werden.
    • +
    • `X-Forwarded-Proto` kann vom Reverse Proxy festgelegt werden, um der Anwendung mitzuteilen, ob es sich um `https` oder `http` oder sogar um einen ungültigen Namen handelt. Dieser Wert wird durch [req.protocol](/{{ page.lang }}/api.html#req.protocol) abgebildet. +
    • +
    • Als Werte für [req.ip](/{{ page.lang }}/api.html#req.ip) und [req.ips](/{{ page.lang }}/api.html#req.ips) wird die Liste der Adressen aus `X-Forwarded-For` herangezogen. +
    • +
    + +Die Einstellung für `trust proxy` wird mithilfe des [proxy-addr](https://www.npmjs.com/package/proxy-addr)-Pakets implementiert. Weitere Informationen finden Sie in der zugehörigen Dokumentation. diff --git a/astro/src/content/docs/de/5x/guide/database-integration.md b/astro/src/content/docs/de/5x/guide/database-integration.md new file mode 100644 index 0000000000..fcd6291fc1 --- /dev/null +++ b/astro/src/content/docs/de/5x/guide/database-integration.md @@ -0,0 +1,509 @@ +--- +title: Datenbankintegration in Express +description: Discover how to integrate various databases with Express.js applications, including setup examples for MongoDB, MySQL, PostgreSQL, and more. +--- + +# Datenbankintegration + +Die Herstellung einer Verbindung zwischen Datenbanken und Express-Anwendungen erfolgt einfach durch Laden eines geeigneten Node.js-Treibers für die Datenbank in Ihre Anwendung. In diesem Dokument wird in Kurzform beschrieben, wie einige der gängigsten Node.js-Module für Datenbanksysteme Ihrer Express-Anwendung hinzugefügt und verwendet werden: + +- [Cassandra](#cassandra) +- [Couchbase](#couchbase) +- [CouchDB](#couchdb) +- [LevelDB](#leveldb) +- [MySQL](#mysql) +- [MongoDB](#mongo) +- [Neo4j](#neo4j) +- [Oracle](#oracle) +- [PostgreSQL](#postgres) +- [Redis](#redis) +- +- [SQLite](#sqlite) +- [ElasticSearch](#elasticsearch) + +
    +Diese Datenbanktreiber sind neben zahlreichen anderen Treibern verfügbar. Weitere Optionen finden Sie auf der [npm](https://www.npmjs.com/)-Site. +
    + +## Cassandra + +**Modul**: [cassandra-driver](https://github.com/datastax/nodejs-driver) +**Installation** + +### Installation + +```bash +$ npm install cassandra-driver +``` + +### Beispiel + +```js +const cassandra = require('cassandra-driver'); +const client = new cassandra.Client({ contactPoints: ['localhost'] }); + +client.execute('select key from system.local', (err, result) => { + if (err) throw err; + console.log(result.rows[0]); +}); +``` + +## Couchbase + +**Module**: [couchnode](https://github.com/couchbase/couchnode) + +### Installation + +```bash +$ npm install couchbase +``` + +### Beispiel + +```js +const couchbase = require('couchbase'); +const bucket = new couchbase.Cluster('http://localhost:8091').openBucket('bucketName'); + +// add a document to a bucket +bucket.insert('document-key', { name: 'Matt', shoeSize: 13 }, (err, result) => { + if (err) { + console.log(err); + } else { + console.log(result); + } +}); + +// get all documents with shoe size 13 +const n1ql = 'SELECT d.* FROM `bucketName` d WHERE shoeSize = $1'; +const query = N1qlQuery.fromString(n1ql); +bucket.query(query, [13], (err, result) => { + if (err) { + console.log(err); + } else { + console.log(result); + } +}); +``` + +## CouchDB + +**Modul**: [nano](https://github.com/dscape/nano) +**Installation** + +### Installation + +```bash +$ npm install nano +``` + +### Beispiel + +```js +const nano = require('nano')('http://localhost:5984'); +nano.db.create('books'); +const books = nano.db.use('books'); + +// Insert a book document in the books database +books.insert({ name: 'The Art of war' }, null, (err, body) => { + if (err) { + console.log(err); + } else { + console.log(body); + } +}); + +// Get a list of all books +books.list((err, body) => { + if (err) { + console.log(err); + } else { + console.log(body.rows); + } +}); +``` + +## LevelDB + +**Modul**: [levelup](https://github.com/rvagg/node-levelup) +**Installation** + +### Installation + +```bash +$ npm install level levelup leveldown +``` + +### Beispiel + +```js +const levelup = require('levelup'); +const db = levelup('./mydb'); + +db.put('name', 'LevelUP', (err) => { + if (err) return console.log('Ooops!', err); + + db.get('name', (err, value) => { + if (err) return console.log('Ooops!', err); + + console.log(`name=${value}`); + }); +}); +``` + +## MySQL + +**Modul**: [mysql](https://github.com/felixge/node-mysql/) +**Installation** + +### Installation + +```bash +$ npm install mysql +``` + +### Beispiel + +```js +const mysql = require('mysql'); +const connection = mysql.createConnection({ + host: 'localhost', + user: 'dbuser', + password: 's3kreee7', + database: 'my_db', +}); + +connection.connect(); + +connection.query('SELECT 1 + 1 AS solution', (err, rows, fields) => { + if (err) throw err; + + console.log('The solution is: ', rows[0].solution); +}); + +connection.end(); +``` + +## MongoDB + +**Modul**: [mongodb](https://github.com/mongodb/node-mongodb-native) +**Installation** + +### Installation + +```bash +$ npm install mongodb +``` + +### Example (v2.\*) + +```js +const MongoClient = require('mongodb').MongoClient; + +MongoClient.connect('mongodb://localhost:27017/animals', (err, db) => { + if (err) throw err; + + db.collection('mammals') + .find() + .toArray((err, result) => { + if (err) throw err; + + console.log(result); + }); +}); +``` + +### Example (v3.\*) + +```js +const MongoClient = require('mongodb').MongoClient; + +MongoClient.connect('mongodb://localhost:27017/animals', (err, client) => { + if (err) throw err; + + const db = client.db('animals'); + + db.collection('mammals') + .find() + .toArray((err, result) => { + if (err) throw err; + + console.log(result); + }); +}); +``` + +Wenn Sie nach einem Objektmodelltreiber für MongoDB suchen, schauen Sie unter [Mongoose](https://github.com/LearnBoost/mongoose) nach. + +## Neo4j + +**Module**: [neo4j-driver](https://github.com/neo4j/neo4j-javascript-driver) + +### Installation + +```bash +$ npm install neo4j-driver +``` + +### Beispiel + +```js +const neo4j = require('neo4j-driver'); +const driver = neo4j.driver('neo4j://localhost:7687', neo4j.auth.basic('neo4j', 'letmein')); + +const session = driver.session(); + +session.readTransaction((tx) => { + return tx + .run('MATCH (n) RETURN count(n) AS count') + .then((res) => { + console.log(res.records[0].get('count')); + }) + .catch((error) => { + console.log(error); + }); +}); +``` + +## Oracle + +**Modul**: [oracledb](https://github.com/oracle/node-oracledb) + +### Installation + +Anmerkung: [Siehe Installations-Voraussetzungen](https://github.com/oracle/node-oracledb#-installation). + +```bash +$ npm install oracledb +``` + +### Beispiel + +```js +const oracledb = require('oracledb'); +const config = { + user: '', + password: '', + connectString: 'localhost:1521/orcl', +}; + +async function getEmployee(empId) { + let conn; + + try { + conn = await oracledb.getConnection(config); + + const result = await conn.execute('select * from employees where employee_id = :id', [empId]); + + console.log(result.rows[0]); + } catch (err) { + console.log('Ouch!', err); + } finally { + if (conn) { + // conn assignment worked, need to close + await conn.close(); + } + } +} + +getEmployee(101); +``` + +## PostgreSQL + +**Modul**: [pg-promise](https://github.com/vitaly-t/pg-promise) +**Installation** + +### Installation + +```bash +$ npm install pg-promise +``` + +### Beispiel + +```js +const pgp = require('pg-promise')(/* options */); +const db = pgp('postgres://username:password@host:port/database'); + +db.one('SELECT $1 AS value', 123) + .then((data) => { + console.log('DATA:', data.value); + }) + .catch((error) => { + console.log('ERROR:', error); + }); +``` + +## Redis + +**Modul**: [redis](https://github.com/mranney/node_redis) +**Installation** + +### Installation + +```bash +$ npm install redis +``` + +### Beispiel + +```js +const redis = require('redis'); +const client = redis.createClient(); + +client.on('error', (err) => { + console.log(`Error ${err}`); +}); + +client.set('string key', 'string val', redis.print); +client.hset('hash key', 'hashtest 1', 'some value', redis.print); +client.hset(['hash key', 'hashtest 2', 'some other value'], redis.print); + +client.hkeys('hash key', (err, replies) => { + console.log(`${replies.length} replies:`); + + replies.forEach((reply, i) => { + console.log(` ${i}: ${reply}`); + }); + + client.quit(); +}); +``` + +## SQL Server + +**Module**: [tedious](https://github.com/tediousjs/tedious) + +### Installation + +```bash +$ npm install tedious +``` + +### Beispiel + +```js +const Connection = require('tedious').Connection; +const Request = require('tedious').Request; + +const config = { + server: 'localhost', + authentication: { + type: 'default', + options: { + userName: 'your_username', // update me + password: 'your_password', // update me + }, + }, +}; + +const connection = new Connection(config); + +connection.on('connect', (err) => { + if (err) { + console.log(err); + } else { + executeStatement(); + } +}); + +function executeStatement() { + request = new Request("select 123, 'hello world'", (err, rowCount) => { + if (err) { + console.log(err); + } else { + console.log(`${rowCount} rows`); + } + connection.close(); + }); + + request.on('row', (columns) => { + columns.forEach((column) => { + if (column.value === null) { + console.log('NULL'); + } else { + console.log(column.value); + } + }); + }); + + connection.execSql(request); +} +``` + +## SQLite + +**Modul**: [sqlite3](https://github.com/mapbox/node-sqlite3) +**Installation** + +### Installation + +```bash +$ npm install sqlite3 +``` + +### Beispiel + +```js +const sqlite3 = require('sqlite3').verbose(); +const db = new sqlite3.Database(':memory:'); + +db.serialize(() => { + db.run('CREATE TABLE lorem (info TEXT)'); + const stmt = db.prepare('INSERT INTO lorem VALUES (?)'); + + for (let i = 0; i < 10; i++) { + stmt.run(`Ipsum ${i}`); + } + + stmt.finalize(); + + db.each('SELECT rowid AS id, info FROM lorem', (err, row) => { + console.log(`${row.id}: ${row.info}`); + }); +}); + +db.close(); +``` + +## ElasticSearch + +**Modul**: [elasticsearch](https://github.com/elastic/elasticsearch-js) +**Installation** + +### Installation + +```bash +$ npm install elasticsearch +``` + +### Beispiel + +```js +const elasticsearch = require('elasticsearch'); +const client = elasticsearch.Client({ + host: 'localhost:9200', +}); + +client + .search({ + index: 'books', + type: 'book', + body: { + query: { + multi_match: { + query: 'express js', + fields: ['title', 'description'], + }, + }, + }, + }) + .then( + (response) => { + const hits = response.hits.hits; + }, + (error) => { + console.trace(error.message); + } + ); +``` diff --git a/astro/src/content/docs/de/5x/guide/debugging.md b/astro/src/content/docs/de/5x/guide/debugging.md new file mode 100644 index 0000000000..573b701338 --- /dev/null +++ b/astro/src/content/docs/de/5x/guide/debugging.md @@ -0,0 +1,126 @@ +--- +title: Debugging bei Express +description: Learn how to enable and use debugging logs in Express.js applications by setting the DEBUG environment variable for enhanced troubleshooting. +--- + +# Debugging bei Express + +Wenn Sie alle in Express verwendeten internen Protokolle anzeigen wollen, legen Sie beim Starten Ihrer Anwendung die Umgebungsvariable `DEBUG` auf `express:*` fest. + +```bash +$ DEBUG=express:* node index.js +``` + +Verwenden Sie unter Windows den entsprechenden Befehl. + +```bash +> $env:DEBUG = "express:*"; node index.js +``` + +Die Ausführung dieses Befehls für die durch [express generator](/{{ page.lang }}/starter/generator.html) generierte Standardanwendung resultiert in folgender Ausgabe: + +```bash +$ DEBUG=express:* node ./bin/www + express:router:route new / +0ms + express:router:layer new / +1ms + express:router:route get / +1ms + express:router:layer new / +0ms + express:router:route new / +1ms + express:router:layer new / +0ms + express:router:route get / +0ms + express:router:layer new / +0ms + express:application compile etag weak +1ms + express:application compile query parser extended +0ms + express:application compile trust proxy false +0ms + express:application booting in development mode +1ms + express:router use / query +0ms + express:router:layer new / +0ms + express:router use / expressInit +0ms + express:router:layer new / +0ms + express:router use / favicon +1ms + express:router:layer new / +0ms + express:router use / logger +0ms + express:router:layer new / +0ms + express:router use / jsonParser +0ms + express:router:layer new / +1ms + express:router use / urlencodedParser +0ms + express:router:layer new / +0ms + express:router use / cookieParser +0ms + express:router:layer new / +0ms + express:router use / stylus +90ms + express:router:layer new / +0ms + express:router use / serveStatic +0ms + express:router:layer new / +0ms + express:router use / router +0ms + express:router:layer new / +1ms + express:router use /users router +0ms + express:router:layer new /users +0ms + express:router use / &lt;anonymous&gt; +0ms + express:router:layer new / +0ms + express:router use / &lt;anonymous&gt; +0ms + express:router:layer new / +0ms + express:router use / &lt;anonymous&gt; +0ms + express:router:layer new / +0ms +``` + +Bei einer Anforderung an die Anwendung sind die Protokolle im Express-Code angegeben: + +```bash + express:router dispatching GET / +4h + express:router query : / +2ms + express:router expressInit : / +0ms + express:router favicon : / +0ms + express:router logger : / +1ms + express:router jsonParser : / +0ms + express:router urlencodedParser : / +1ms + express:router cookieParser : / +0ms + express:router stylus : / +0ms + express:router serveStatic : / +2ms + express:router router : / +2ms + express:router dispatching GET / +1ms + express:view lookup "index.pug" +338ms + express:view stat "/projects/example/views/index.pug" +0ms + express:view render "/projects/example/views/index.pug" +1ms +``` + +Wenn Sie nur die Protokolle von der Routerimplementierung sehen wollen, legen Sie den Wert für `DEBUG` auf `express:router` fest. Gleichermaßen gilt: Wenn Sie nur die Protokolle von der Anwendungsimplementierung sehen wollen, legen Sie den Wert für `DEBUG` auf `express:application` fest, usw. + +## Von `express` generierte Anwendungen + +An application generated by the `express` command uses the `debug` module and its debug namespace is scoped to the name of the application. + +Beispiel: Wenn Sie die Anwendung mit `$ express sample-app` generiert haben, können Sie die Debuganweisungen mit dem folgenden Befehl aktivieren: + +```bash +$ DEBUG=sample-app:* node ./bin/www +``` + +Sie können mehrere Debug-Namespaces in einer durch Kommas getrennten Namensliste angeben: + +```bash +$ DEBUG=http,mail,express:* node index.js +``` + +## Advanced options + +When running through Node.js, you can set a few environment variables that will change the behavior of the debug logging: + +| Name | Purpose | +| ------------------- | ------------------------------------------------- | +| `DEBUG` | Enables/disables specific debugging namespaces. | +| `DEBUG_COLORS` | Whether or not to use colors in the debug output. | +| `DEBUG_DEPTH` | Object inspection depth. | +| `DEBUG_FD` | File descriptor to write debug output to. | +| `DEBUG_SHOW_HIDDEN` | Shows hidden properties on inspected objects. | + +{% capture debug-text %} + +The environment variables beginning with `DEBUG_` end up being +converted into an Options object that gets used with `%o`/`%O` formatters. +See the Node.js documentation for +[`util.inspect()`](https://nodejs.org/api/util.html#util_util_inspect_object_options) +for the complete list. + +{% endcapture %} + +{% include admonitions/note.html content=debug-text %} diff --git a/astro/src/content/docs/de/5x/guide/error-handling.md b/astro/src/content/docs/de/5x/guide/error-handling.md new file mode 100644 index 0000000000..9b7c30e8d3 --- /dev/null +++ b/astro/src/content/docs/de/5x/guide/error-handling.md @@ -0,0 +1,289 @@ +--- +title: Fehlerbehandlung in Express +description: Understand how Express.js handles errors in synchronous and asynchronous code, and learn to implement custom error handling middleware for your applications. +--- + +# Fehlerbehandlung + +_Error Handling_ refers to how Express catches and processes errors that +occur both synchronously and asynchronously. Express comes with a default error +handler so you don't need to write your own to get started. + +## Catching Errors + +It's important to ensure that Express catches all errors that occur while +running route handlers and middleware. + +Errors that occur in synchronous code inside route handlers and middleware +require no extra work. If synchronous code throws an error, then Express will +catch and process it. Beispiel: + +```js +app.get('/', (req, res) => { + throw new Error('BROKEN'); // Express will catch this on its own. +}); +``` + +Middlewarefunktionen für die Fehlerbehandlung werden in derselben Weise definiert wie andere Middlewarefunktionen, nur, dass Fehlerbehandlungsfunktionen vier anstatt drei Argumente aufweisen: +`(err, req, res, next)`. Beispiel: + +```js +app.get('/', (req, res, next) => { + fs.readFile('/file-does-not-exist', (err, data) => { + if (err) { + next(err); // Pass errors to Express. + } else { + res.send(data); + } + }); +}); +``` + +Middleware für die Fehlerbehandlung wird ganz zuletzt nach allen anderen `app.use()`- und Weiterleitungsaufrufen definiert. +Beispiel: + +```js +app.get('/user/:id', async (req, res, next) => { + const user = await getUserById(req.params.id); + res.send(user); +}); +``` + +If `getUserById` throws an error or rejects, `next` will be called with either +the thrown error or the rejected value. If no rejected value is provided, `next` +will be called with a default Error object provided by the Express router. + +Wenn Sie Übergaben an die Funktion `next()` vornehmen (außer die Zeichenfolge `'route'`), sieht Express die aktuelle Anforderung als Fehler an und überspringt alle verbleibenden fehlerfreien Behandlungsroutinen und Middlewarefunktionen. + +If the callback in a sequence provides no data, only errors, you can simplify +this code as follows: + +```js +app.get('/', [ + function (req, res, next) { + fs.writeFile('/inaccessible-path', 'data', next); + }, + function (req, res) { + res.send('OK'); + }, +]); +``` + +In the above example, `next` is provided as the callback for `fs.writeFile`, +which is called with or without errors. If there is no error, the second +handler is executed, otherwise Express catches and processes the error. + +Bei einem Routenhandler mit mehreren Callback-Funktionen können Sie den Parameter `route` verwenden, um den nächsten Routenhandler zu überspringen. Beispiel: + +```js +app.get('/', (req, res, next) => { + setTimeout(() => { + try { + throw new Error('BROKEN'); + } catch (err) { + next(err); + } + }, 100); +}); +``` + +The above example uses a `try...catch` block to catch errors in the +asynchronous code and pass them to Express. If the `try...catch` +block were omitted, Express would not catch the error since it is not part of the synchronous +handler code. + +Use promises to avoid the overhead of the `try...catch` block or when using functions +that return promises. Beispiel: + +```js +app.get('/', (req, res, next) => { + Promise.resolve() + .then(() => { + throw new Error('BROKEN'); + }) + .catch(next); // Errors will be passed to Express. +}); +``` + +Since promises automatically catch both synchronous errors and rejected promises, +you can simply provide `next` as the final catch handler and Express will catch errors, +because the catch handler is given the error as the first argument. + +You could also use a chain of handlers to rely on synchronous error +catching, by reducing the asynchronous code to something trivial. Beispiel: + +```js +app.get('/', [ + function (req, res, next) { + fs.readFile('/maybe-valid-file', 'utf-8', (err, data) => { + res.locals.data = data; + next(err); + }); + }, + function (req, res) { + res.locals.data = res.locals.data.split(',')[1]; + res.send(res.locals.data); + }, +]); +``` + +The above example has a couple of trivial statements from the `readFile` +call. If `readFile` causes an error, then it passes the error to Express, otherwise you +quickly return to the world of synchronous error handling in the next handler +in the chain. Then, the example above tries to process the data. If this fails, then the +synchronous error handler will catch it. If you had done this processing inside +the `readFile` callback, then the application might exit and the Express error +handlers would not run. + +Whichever method you use, if you want Express error handlers to be called in and the +application to survive, you must ensure that Express receives the error. + +## Die Standardfehlerbehandlungsroutine (Default Error Handler) + +Express ist bereits mit einer integrierten Fehlerbehandlungsroutine ausgestattet, mit der alle in der Anwendung festgestellten Fehler gehandhabt werden können. Diese Middleware für die Fehlerbehandlung wird am Ende des Middleware-Funktionsstack hinzugefügt. + +Wenn Sie einen Fehler an `next()` übergeben und diesen nicht mit einem Error-Handler bearbeiten, wird dieser über den integrierten Error-Handler bearbeitet. Der Fehler wird mit dem Stack-Trace zum Client geschrieben. Der Stack-Trace ist in der Produktionsumgebung nicht verfügbar. + +
    +Legen Sie die Umgebungsvariable `NODE_ENV` auf `production` fest, um die Anwendung im Produktionsmodus auszuführen. +
    + +When an error is written, the following information is added to the +response: + +- The `res.statusCode` is set from `err.status` (or `err.statusCode`). If + this value is outside the 4xx or 5xx range, it will be set to 500. +- The `res.statusMessage` is set according to the status code. +- The body will be the HTML of the status code message when in production + environment, otherwise will be `err.stack`. +- Any headers specified in an `err.headers` object. + +Wenn `next()` mit einem Fehler aufgerufen wird, nachdem Sie mit dem Schreiben der Antwort begonnen haben (z. B., wenn Sie beim Streamen der Antwort zum Client einen Fehler feststellen), schließt die Standardfehlerbehandlungsroutine in Express die Verbindung, und die Anforderung schlägt fehl. + +Wenn Sie also einen angepassten Error-Handler hinzufügen, empfiehlt es sich, eine Delegierung zur Standardfehlerbehandlungsroutine in Express vorzunehmen, wenn die Header bereits an den Client gesendet wurden: + +```js +function errorHandler(err, req, res, next) { + if (res.headersSent) { + return next(err); + } + res.status(500); + res.render('error', { error: err }); +} +``` + +Note that the default error handler can get triggered if you call `next()` with an error +in your code more than once, even if custom error handling middleware is in place. + +Other error handling middleware can be found at [Express middleware](/{{ page.lang }}/resources/middleware.html). + +## Writing error handlers + +Define error-handling middleware functions in the same way as other middleware functions, +except error-handling functions have four arguments instead of three: +`(err, req, res, next)`. Beispiel: + +```js +app.use((err, req, res, next) => { + console.error(err.stack); + res.status(500).send('Something broke!'); +}); +``` + +You define error-handling middleware last, after other `app.use()` and routes calls; for example: + +```js +const bodyParser = require('body-parser'); +const methodOverride = require('method-override'); + +app.use( + bodyParser.urlencoded({ + extended: true, + }) +); +app.use(bodyParser.json()); +app.use(methodOverride()); +app.use((err, req, res, next) => { + // logic +}); +``` + +Antworten von der Middlewarefunktion können das von Ihnen gewünschte Format aufweisen wie beispielsweise eine Fehlerseite im HTML-Format, eine einfache Nachricht oder eine JSON-Zeichenfolge. + +Für organisatorische Zwecke (und Frameworks der höheren Ebene) können Sie mehrere Middlewarefunktionen für die Fehlerbehandlung definieren, wie Sie dies bei regulären Middlewarefunktionen auch tun würden. Wenn Sie beispielsweise eine Fehlerbehandlungsroutine (Error-Handler) für Anforderungen über `XHR` und andere Anforderungen definieren wollen, können Sie die folgenden Befehle verwenden: + +```js +const bodyParser = require('body-parser'); +const methodOverride = require('method-override'); + +app.use( + bodyParser.urlencoded({ + extended: true, + }) +); +app.use(bodyParser.json()); +app.use(methodOverride()); +app.use(logErrors); +app.use(clientErrorHandler); +app.use(errorHandler); +``` + +In diesem Beispiel kann die generische `logErrors`-Funktion Anforderungs- und Fehlerinformationen in `stderr` schreiben: + +```js +function logErrors(err, req, res, next) { + console.error(err.stack); + next(err); +} +``` + +In diesem Beispiel wird `clientErrorHandler` wie folgt definiert. In diesem Fall wird der Fehler explizit an den nächsten Error-Handler übergeben: + +Notice that when _not_ calling "next" in an error-handling function, you are responsible for writing (and ending) the response. Otherwise, those requests will "hang" and will not be eligible for garbage collection. + +```js +function clientErrorHandler(err, req, res, next) { + if (req.xhr) { + res.status(500).send({ error: 'Something failed!' }); + } else { + next(err); + } +} +``` + +Die `errorHandler`-Funktion "catch-all" kann wie folgt implementiert werden: + +```js +function errorHandler(err, req, res, next) { + res.status(500); + res.render('error', { error: err }); +} +``` + +If you have a route handler with multiple callback functions, you can use the `route` parameter to skip to the next route handler. Beispiel: + +```js +app.get( + '/a_route_behind_paywall', + (req, res, next) => { + if (!req.user.hasPaid) { + // continue handling this request + next('route'); + } else { + next(); + } + }, + (req, res, next) => { + PaidContent.find((err, doc) => { + if (err) return next(err); + res.json(doc); + }); + } +); +``` + +In diesem Beispiel wird der Handler `getPaidContent` übersprungen. Alle verbleibenden Handler in `app` für `/a_route_behind_paywall` werden jedoch weiter ausgeführt. + +
    +Aufrufe zu `next()` und `next(err)` geben an, dass der aktuelle Handler abgeschlossen ist und welchen Status er aufweist. Durch `next(err)` werden alle verbleibenden Handler in der Kette übersprungen. Ausgenommen hiervor sind die Handler, die konfiguriert sind, um Fehler wie oben beschrieben zu behandeln. +
    diff --git a/astro/src/content/docs/de/5x/guide/migrating-4.md b/astro/src/content/docs/de/5x/guide/migrating-4.md new file mode 100644 index 0000000000..7846241979 --- /dev/null +++ b/astro/src/content/docs/de/5x/guide/migrating-4.md @@ -0,0 +1,554 @@ +--- +title: Migration auf Express 4 +description: A guide to migrating your Express.js applications from version 3 to 4, covering changes in middleware, routing, and how to update your codebase effectively. +--- + +# Wechsel zu Express 4 + +

    Überblick

    + +Express 4 bietet grundlegende Veränderungen im Vergleich zu Express 3. Das bedeutet, dass eine Express 3-Anwendung nicht funktioniert, wenn Sie die Express-Version in ihren Abhängigkeiten aktualisieren. + +In diesem Beitrag werden folgende Themen behandelt: + + + +

    Änderungen in Express 4

    + +In Express 4 wurden einige signifikante Änderungen vorgenommen: + + + +Siehe hierzu auch: + +- [Neue Features/Funktionen in 4.x.](https://github.com/expressjs/express/wiki/New-features-in-4.x) +- [Migration von 3.x auf 4.x.](https://github.com/expressjs/express/wiki/Migrating-from-3.x-to-4.x) + +

    +Änderungen am Express-Core- und Middlewaresystem

    + +In Express 4 bestehen keine Abhängigkeiten mehr zu Connect. Alle integrierten Middlewarefunktionen werden aus dem Core entfernt. Ausgenommen hiervon ist die Funktion `express.static`. Das bedeutet, dass Express nun ein unabhängiges Routing- und Middleware-Web-Framework ist und Express-Versionierung und -Releases von Middleware-Updates nicht betroffen sind. + +Ohne integrierte Middleware müssen Sie explizit alle Middlewarefunktionen hinzufügen, die für die Ausführung Ihrer Anwendung erforderlich sind. Befolgen Sie einfach diese Schritte: + +1. Installieren des Moduls: `npm install --save ` +2. Anfordern des Moduls in Ihrer Anwendung: `require('modulname')` +3. Verwendung des Moduls gemäß Dokumentation: `app.use( ... )` + +In der folgenden Tabelle sind Express 3-Middlewarefunktionen und deren Entsprechungen in Express 4 aufgelistet. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Express 3Express 4
    express.bodyParserbody-parser + +multer
    express.compresscompression
    express.cookieSessioncookie-session
    express.cookieParsercookie-parser
    express.loggermorgan
    express.sessionexpress-session
    express.faviconserve-favicon
    express.responseTimeresponse-time
    express.errorHandlererrorhandler
    express.methodOverridemethod-override
    express.timeoutconnect-timeout
    express.vhostvhost
    express.csrfcsurf
    express.directoryserve-index
    express.staticserve-static
    + +Hier finden Sie die [komplette Liste](https://github.com/senchalabs/connect#middleware) der Express 4-Middleware. + +In den meisten Fällen können Sie einfach nur die Middleware der alten Version 3 durch deren Entsprechung in Express 4 ersetzen. Details hierzu finden Sie in der modulspezifischen Dokumentation in GitHub. + +

    app.use akzeptiert Parameter.

    + +In Version 4 können Sie über einen Variablenparameter den Pfad definieren, in den Middlewarefunktionen geladen werden. Dann können Sie den Wert des Parameters aus dem Routenhandler laden. +Beispiel: + +```js +app.use('/book/:id', (req, res, next) => { + console.log('ID:', req.params.id); + next(); +}); +``` + +

    +Das Routingsystem +

    + +Anwendungen laden nun implizit Routing-Middleware. Sie müssen sich also keine Gedanken mehr über die Reihenfolge machen, in der die Middleware in Bezug auf die `router`-Middleware geladen wird. + +Das Routingsystem verfügt jedoch über zwei neue Funktionen, die beim Organisieren Ihrer Weiterleitungen helfen: + +{: .doclist } + +- Die neue Methode `app.route()` zum Erstellen verkettbarer Routenhandler für einen Weiterleitungspfad +- Die neue Klasse `express.Router` zum Erstellen modular einbindbarer Routenhandler + +

    Die Methode app.route()

    + +Die neue Methode `app.route()` hilft beim Erstellen verkettbarer Routenhandler für einen Weiterleitungspfad. Da der Pfad an einer einzelnen Position angegeben wird, ist das Erstellen modularer Weiterleitungen hilfreich, da Redundanzen und Schreibfehler reduziert werden. Weitere Informationen zu Weiterleitungen finden Sie in der Dokumentation zu [`Router()`](/{{ page.lang }}/4x/api.html#router). + +Dies ist ein Beispiel für verkettete Routenhandler, die mit der Funktion `app.route()` definiert werden. + +```js +app + .route('/book') + .get((req, res) => { + res.send('Get a random book'); + }) + .post((req, res) => { + res.send('Add a book'); + }) + .put((req, res) => { + res.send('Update the book'); + }); +``` + +

    Die Klasse express.Router

    + +Eine weitere Funktion, die beim Organisieren von Weiterleitungen hilft, ist die neue Klasse `express.Router`. Über diese Klasse können Sie modular einbindbare Routenhandler erstellen. Eine `Router`-Instanz ist ein vollständiges Middleware- und Routingsystem. Aus diesem Grund wird diese Instanz oft auch als "Mini-App" bezeichnet. + +Im folgenden Beispiel wird ein Router als Modul erstellt, Middleware in das Modul geladen, es werden Weiterleitungen definiert und das Modul letztendlich in einen Pfad in der Hauptanwendung eingebunden. + +Beispiel: Erstellen Sie eine Routerdatei namens `birds.js` mit dem folgenden Inhalt im Anwendungsverzeichnis: + +```js +var express = require('express'); +var router = express.Router(); + +// middleware specific to this router +router.use((req, res, next) => { + console.log('Time: ', Date.now()); + next(); +}); +// define the home page route +router.get('/', (req, res) => { + res.send('Birds home page'); +}); +// define the about route +router.get('/about', (req, res) => { + res.send('About birds'); +}); + +module.exports = router; +``` + +Laden Sie dann das Routermodul in die Anwendung: + +```js +var birds = require('./birds'); + +// ... + +app.use('/birds', birds); +``` + +Die Anwendung kann nun Anforderungen an die Pfade `/birds` und `/birds/about` bearbeiten und ruft die Middleware `timeLog` auf, die speziell für diese Weiterleitung bestimmt ist. + +

    +Weitere Änderungen

    + +In der folgenden Tabelle sind andere kleinere, aber trotzdem wichtige Änderungen in Express 4 aufgeführt: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ObjektBeschreibung
    Node.js +Express 4 erfordert Node.js 0.10.x oder höher und unterstützt nicht mehr Node.js 0.8.x. +
    +`http.createServer()` + +Das Modul `http` wird nicht mehr benötigt, es sei denn, Sie müssen direkt mit dem Modul arbeiten (socket.io/SPDY/HTTPS). Die Anwendung kann mithilfe der Funktion `app.listen()` gestartet werden. +
    +`app.configure()` + +Die Funktion `app.configure()` wurde entfernt. Verwenden Sie die Funktion `process.env.NODE_ENV` oder `app.get('env')`, um die Umgebung zu erkennen und die Anwendung entsprechend zu konfigurieren. +
    +`json spaces` + +Die Anwendungseigenschaft `json spaces` ist in Express 4 standardmäßig inaktiviert. +
    +`req.accepted()` + +Verwenden Sie `req.accepts()`, `req.acceptsEncodings()`, `req.acceptsCharsets()` und `req.acceptsLanguages()`. +
    +`res.location()` + +Löst keine relativen URLs mehr auf. +
    +`req.params` + +War bisher ein Array, ist nun ein Objekt. +
    +`res.locals` + +War bisher eine Funktion, ist nun ein Objekt. +
    +`res.headerSent` + +Geändert in `res.headersSent`. +
    +`app.route` + +Nun verfügbar als `app.mountpath`. +
    +`res.on('header')` + +Entfernt. +
    +`res.charset` + +Entfernt. +
    +`res.setHeader('Set-Cookie', val)` + +Die Funktionalität ist nun auf die Einstellung des Basis-Cookiewerts begrenzt. Verwenden Sie `res.cookie()`, um weitere Funktionalität zu erhalten. +
    + +

    Beispiel für eine Anwendungsmigration

    + +Dies ist ein Beispiel für die Migration einer Express 3-Anwendung auf Express 4. +Die dabei interessanten Dateien sind `app.js` und `package.json`. + +

    +Anwendung der Version 3 +

    + +

    app.js

    + +Es wird eine Express v.3-Anwendung mit der folgenden Datei `app.js` angenommen: + +```js +var express = require('express'); +var routes = require('./routes'); +var user = require('./routes/user'); +var http = require('http'); +var path = require('path'); + +var app = express(); + +// all environments +app.set('port', process.env.PORT || 3000); +app.set('views', path.join(__dirname, 'views')); +app.set('view engine', 'pug'); +app.use(express.favicon()); +app.use(express.logger('dev')); +app.use(express.methodOverride()); +app.use(express.session({ secret: 'your secret here' })); +app.use(express.bodyParser()); +app.use(app.router); +app.use(express.static(path.join(__dirname, 'public'))); + +// development only +if (app.get('env') === 'development') { + app.use(express.errorHandler()); +} + +app.get('/', routes.index); +app.get('/users', user.list); + +http.createServer(app).listen(app.get('port'), () => { + console.log('Express server listening on port ' + app.get('port')); +}); +``` + +

    package.json

    + +Die zugehörige `package.json`-Datei der Version 3 sieht in etwa wie folgt aus: + +```json +{ + "name": "application-name", + "version": "0.0.1", + "private": true, + "scripts": { + "start": "node app.js" + }, + "dependencies": { + "express": "3.12.0", + "pug": "*" + } +} +``` + +

    +Prozess +

    + +Beginnen Sie den Migrationsprozess mit der Installation der erforderlichen Middleware für die Express 4-Anwendung und der Aktualisierung von Express und Pug auf die aktuellen Versionen. Verwenden Sie hierzu den folgenden Befehl: + +```bash +$ npm install serve-favicon morgan method-override express-session body-parser multer errorhandler express@latest pug@latest --save +``` + +Nehmen Sie an `app.js` die folgenden Änderungen vor: + +1. Die integrierten Express-Middlewarefunktionen `express.favicon`, + `express.logger`, `express.methodOverride`, + `express.session`, `express.bodyParser` und + `express.errorHandler` sind im Objekt `express` nicht mehr verfügbar. Sie müssen deren Alternativen manuell installieren und in die Anwendung laden. + +2. Sie müssen die Funktion `app.router` nicht mehr laden. + Sie ist kein gültiges Express 4-Anwendungsobjekt. Entfernen Sie also den Code `app.use(app.router);`. + +3. Stellen Sie sicher, dass die Middlewarefunktionen in der richtigen Reihenfolge geladen werden – laden Sie `errorHandler` nach dem Laden der Anwendungsweiterleitungen. + +

    Anwendung der Version 4

    + +

    package.json

    + +Durch Ausführung des Befehls `npm` wird `package.json` wie folgt aktualisiert: + +```json +{ + "name": "application-name", + "version": "0.0.1", + "private": true, + "scripts": { + "start": "node app.js" + }, + "dependencies": { + "body-parser": "^1.5.2", + "errorhandler": "^1.1.1", + "express": "^4.8.0", + "express-session": "^1.7.2", + "pug": "^2.0.0", + "method-override": "^2.1.2", + "morgan": "^1.2.2", + "multer": "^0.1.3", + "serve-favicon": "^2.0.1" + } +} +``` + +

    app.js

    + +Entfernen Sie dann ungültigen Code, laden Sie die erforderliche Middleware und nehmen Sie andere Änderungen nach Bedarf vor. Die Datei `app.js` sieht dann wie folgt aus: + +```js +var http = require('http'); +var express = require('express'); +var routes = require('./routes'); +var user = require('./routes/user'); +var path = require('path'); + +var favicon = require('serve-favicon'); +var logger = require('morgan'); +var methodOverride = require('method-override'); +var session = require('express-session'); +var bodyParser = require('body-parser'); +var multer = require('multer'); +var errorHandler = require('errorhandler'); + +var app = express(); + +// all environments +app.set('port', process.env.PORT || 3000); +app.set('views', path.join(__dirname, 'views')); +app.set('view engine', 'pug'); +app.use(favicon(path.join(__dirname, '/public/favicon.ico'))); +app.use(logger('dev')); +app.use(methodOverride()); +app.use( + session({ + resave: true, + saveUninitialized: true, + secret: 'uwotm8', + }) +); +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: true })); +app.use(multer()); +app.use(express.static(path.join(__dirname, 'public'))); + +app.get('/', routes.index); +app.get('/users', user.list); + +// error handling middleware should be loaded after the loading the routes +if (app.get('env') === 'development') { + app.use(errorHandler()); +} + +var server = http.createServer(app); +server.listen(app.get('port'), () => { + console.log('Express server listening on port ' + app.get('port')); +}); +``` + +
    Wenn Sie nicht direkt mit dem Modul `http` arbeiten müssen (socket.io/SPDY/HTTPS), ist das Laden des Moduls nicht erforderlich. Die Anwendung kann dann einfach wie folgt gestartet werden: + +```js +app.listen(app.get('port'), () => { + console.log('Express server listening on port ' + app.get('port')); +}); +``` + +
    + +

    Anwendung ausführen

    + +Der Migrationsprozess ist abgeschlossen und die Anwendung ist nun eine Express 4-Anwendung. Zum Bestätigen starten Sie die Anwendung mit dem folgenden Befehl: + +```bash +$ node . +``` + +Laden Sie [http://localhost:3000](http://localhost:3000) und sehen Sie, wie die Homepage von Express 4 wiedergegeben wird. + +

    Upgrade auf den Express 4 App Generator

    + +Das Befehlszeilentool zum Generieren einer Express-Anwendung ist nach wie vor `express`. Für ein Upgrade auf die neue Version müssen Sie jedoch den Express 3 App Generator deinstallieren und dann den neuen Generator `express-generator` installieren. + +

    Installation

    + +Wenn der Express 3 App Generator bereits auf Ihrem System installiert ist, müssen Sie diesen deinstallieren: + +```bash +$ npm uninstall -g express +``` + +Abhängig davon, wie Ihre Datei- und Verzeichnissberechtigungen konfiguriert sind, müssen Sie diesen Befehl möglicherweise mit `sudo` ausführen. + +Installieren Sie nun den neuen Generator: + +```bash +$ npm install -g express-generator +``` + +Abhängig davon, wie Ihre Datei- und Verzeichnissberechtigungen konfiguriert sind, müssen Sie diesen Befehl möglicherweise mit `sudo` ausführen. + +Nun wird der Befehl `express` auf Ihrem System auf den Express 4 App Generator aktualisiert. + +

    Änderungen am App Generator

    + +Befehlsoptionen und -nutzung bleiben größtenteils unverändert. Es gelten jedoch folgende Ausnahmen: + +{: .doclist } + +- Option `--sessions` wurde entfernt. +- Option `--jshtml` wurde entfernt. +- Option `--hogan` wurde hinzugefügt, um [Hogan.js](http://twitter.github.io/hogan.js/) zu unterstützen. + +

    Beispiel

    + +Führen Sie den folgenden Befehl aus, um eine Express 4-Anwendung zu erstellen: + +```bash +$ express app4 +``` + +Wenn Sie sich den Inhalt der Datei `app4/app.js` ansehen, werden Sie feststellen, dass alle Middlewarefunktionen (außer `express.static`), die für die Anwendung erforderlich sind, als unabhängige Module geladen werden und die Middleware `router` nicht mehr explizit in die Anwendung geladen wird. + +Sie werden auch feststellen, dass die Datei `app.js` nun ein Node.js-Modul ist – im Gegensatz zur eigenständigen Anwendung, die vom bisherigen Generator generiert wurde. + +Starten Sie nach der Installation der Abhängigkeiten die Anwendung mit dem folgenden Befehl: + +```bash +$ npm start +``` + +Wenn Sie sich das npm-Startscript in der Datei `package.json` näher ansehen, werden Sie feststellen, dass der eigentliche Befehl, der die Anwendung startet, `node ./bin/www` heißt. Dieser Befehl lautete in Express 3 `node app.js`. + +Da die Datei `app.js`, die vom Express 4 Generator erstellt wurde, nun ein Node.js-Modul ist, kann dieses nicht mehr wie bisher unabhängig als Anwendung gestartet werden (es sei denn, Sie ändern den Code). Das Modul muss in eine Node.js-Datei geladen und über die Node.js-Datei gestartet werden. Die Node.js-Datei ist in diesem Fall `./bin/www`. + +Weder das Verzeichnis `bin` noch die erweiterungslose Datei `www` ist für das Erstellen einer Express-Anwendung oder das Starten der Anwendung zwingend erforderlich. Dies sind lediglich Vorschläge des Generators. Sie können diese also je nach Ihren Anforderungen ändern. + +Um das Verzeichnis `www` zu löschen und alles im "Express 3-Stil" zu belassen, löschen Sie die Zeile mit dem Eintrag `module.exports = app;` am Ende der Datei `app.js`. Fügen Sie dann stattdessen den folgenden Code an derselben Position ein: + +```js +app.set('port', process.env.PORT || 3000); + +var server = app.listen(app.get('port'), () => { + debug('Express server listening on port ' + server.address().port); +}); +``` + +Stellen Sie sicher, dass Sie das Modul `debug` am Anfang der Datei `app.js` laden. Verwenden Sie dazu den folgenden Code: + +```js +var debug = require('debug')('app4'); +``` + +Ändern Sie als Nächstes `"start": "node ./bin/www"` in der Datei `package.json` in `"start": "node app.js"`. + +Sie haben nun die Funktionalität von `./bin/www` wieder in `app.js` verschoben. Diese Änderung wird nicht empfohlen. Die Übung hat Ihnen jedoch geholfen, zu verstehen, wie die Datei `./bin/www` funktioniert und warum die Datei `app.js` nicht mehr automatisch gestartet wird. diff --git a/astro/src/content/docs/de/5x/guide/migrating-5.md b/astro/src/content/docs/de/5x/guide/migrating-5.md new file mode 100644 index 0000000000..fd4ff016c8 --- /dev/null +++ b/astro/src/content/docs/de/5x/guide/migrating-5.md @@ -0,0 +1,587 @@ +--- +title: Migration auf Express 5 +description: A comprehensive guide to migrating your Express.js applications from version 4 to 5, detailing breaking changes, deprecated methods, and new improvements. +--- + +# Wechsel zu Express 5 + +

    Überblick

    + +Express 5.0 befindet sich noch in der Beta-Release-Phase. Hier finden Sie jedoch bereits eine Vorschau zu den Änderungen in diesem Release und zur Migration Ihrer Express 4-Anwendung auf Express 5. + +To install this version, you need to have a Node.js version 18 or higher. Then, execute the following command in your application directory: + +```sh +npm install "express@5" +``` + +Sie können Ihre automatisierten Tests ausführen, um zu sehen, was fehlschlägt, und Probleme gemäß den folgenden Updates beheben. Nachdem Sie alle Testfehler behoben haben, führen Sie Ihre Anwendung aus, um zu sehen, welche Fehler noch auftreten. Sie werden sofort feststellen, ob die Anwendung Methoden oder Eigenschaften verwendet, die nicht unterstützt werden. + +## Express 5 Codemods + +To help you migrate your express server, we have created a set of codemods that will help you automatically update your code to the latest version of Express. + +Run the following command for run all the codemods available: + +```sh +npx @expressjs/codemod upgrade +``` + +If you want to run a specific codemod, you can run the following command: + +```sh +npx @expressjs/codemod name-of-the-codemod +``` + +You can find the list of available codemods [here](https://github.com/expressjs/codemod?tab=readme-ov-file#available-codemods). + +

    Änderungen in Express 5

    + +**Entfernte Methoden und Eigenschaften** + + + +**Verbesserungen** + + + +**Geändert** + + + +## Entfernte Methoden und Eigenschaften + +Wenn Sie eine dieser Methoden oder Eigenschaften in Ihrer Anwendung verwenden, stürzt die Anwendung ab. Sie müssen also Ihre Anwendung ändern, wenn Sie auf Version 5 umgestellt haben. + +

    app.del()

    + +Express 5 unterstützt die Funktion `app.del()` nicht mehr. Wenn Sie diese Funktion verwenden, wird ein Fehler ausgelöst. Für die Registrierung von HTTP DELETE-Weiterleitungen verwenden Sie stattdessen die Funktion `app.delete()`. + +Anfänglich wurde `del` statt `delete` verwendet, weil `delete` in JavaScript ein reserviertes Schlüsselwort ist. Ab ECMAScript 6 jedoch können `delete` und andere reservierte Schlüsselwörter legal als Eigenschaftsnamen verwendet werden. + +{% capture codemod-deprecated-signatures %} +You can replace the deprecated signatures with the following command: + +```plaintext +npx @expressjs/codemod v4-deprecated-signatures +``` + +{% endcapture %} + +{% include admonitions/note.html content=codemod-deprecated-signatures %} + +```js +// v4 +app.del('/user/:id', (req, res) => { + res.send(`DELETE /user/${req.params.id}`); +}); + +// v5 +app.delete('/user/:id', (req, res) => { + res.send(`DELETE /user/${req.params.id}`); +}); +``` + +

    app.param(fn)

    + +Die Signatur `app.param(fn)` wurde für die Änderung der Verhaltensweise der Funktion `app.param(name, fn)` verwendet. Seit v4.11.0 wurde sie nicht mehr verwendet. In Express 5 wird sie überhaupt nicht mehr unterstützt. + +

    Pluralisierte Methodennamen

    + +Die folgenden Methodennamen wurden pluralisiert. In Express 4 wurde bei Verwendung der alten Methoden eine Warnung zur Einstellung der Unterstützung ausgegeben. Express 5 unterstützt diese Methoden nicht mehr. + +`req.acceptsLanguage()` wird durch `req.acceptsLanguages()` ersetzt. + +`req.acceptsCharset()` wird durch `req.acceptsCharsets()` ersetzt. + +`req.acceptsEncoding()` wird durch `req.acceptsEncodings()` ersetzt. + +{% capture codemod-pluralized-methods %} +You can replace the deprecated signatures with the following command: + +```plaintext +npx @expressjs/codemod pluralized-methods +``` + +{% endcapture %} + +{% include admonitions/note.html content=codemod-pluralized-methods %} + +```js +// v4 +app.all('/', (req, res) => { + req.acceptsCharset('utf-8'); + req.acceptsEncoding('br'); + req.acceptsLanguage('en'); + + // ... +}); + +// v5 +app.all('/', (req, res) => { + req.acceptsCharsets('utf-8'); + req.acceptsEncodings('br'); + req.acceptsLanguages('en'); + + // ... +}); +``` + +

    Führender Doppelpunkt (:) im Namen für app.param(name, fn)

    + +Ein führendes Doppelpunktzeichen (:) im Namen für die Funktion `app.param(name, fn)` ist ein Überbleibsel aus Express 3. Aus Gründen der Abwärtskompatibilität wurde dieser Name in Express 4 mit einem Hinweis zu veralteten Versionen weiter unterstützt. In Express 5 wird dieser Name stillschwiegend ignoriert und der Namensparameter ohne einen vorangestellten Doppelpunkt verwendet. + +Dies dürfte keine Auswirkungen auf Ihren Code haben, wenn Sie die Express 4-Dokumentation zu [app.param](/{{ page.lang }}/4x/api.html#app.param) befolgen, da dort der führende Doppelpunkt nicht erwähnt wird. + +

    req.param(name)

    + +Dieses potenziell verwirrende und durchaus riskante Verfahren des Abrufens von Formulardaten wurde entfernt. Sie müssen nun ganz speziell nach dem übergebenen Parameternamen im Objekt `req.params`, `req.body` oder `req.query` suchen. + +{% capture codemod-req-param %} +You can replace the deprecated signatures with the following command: + +```plaintext +npx @expressjs/codemod req-param +``` + +{% endcapture %} + +{% include admonitions/note.html content=codemod-req-param %} + +```js +// v4 +app.post('/user', (req, res) => { + const id = req.param('id'); + const body = req.param('body'); + const query = req.param('query'); + + // ... +}); + +// v5 +app.post('/user', (req, res) => { + const id = req.params.id; + const body = req.body; + const query = req.query; + + // ... +}); +``` + +

    res.json(obj, status)

    + +Express 5 unterstützt die Signatur `res.json(obj, status)` nicht mehr. Stattdessen müssen Sie den Status festlegen und diesen dann mit `res.json()`-Methoden wie dieser verketten: `res.status(status).json(obj)`. + +{% include admonitions/note.html content=codemod-deprecated-signatures %} + +```js +// v4 +app.post('/user', (req, res) => { + res.json({ name: 'Ruben' }, 201); +}); + +// v5 +app.post('/user', (req, res) => { + res.status(201).json({ name: 'Ruben' }); +}); +``` + +

    res.jsonp(obj, status)

    + +Express 5 unterstützt die Signatur `res.jsonp(obj, status)` nicht mehr. Stattdessen müssen Sie den Status festlegen und diesen dann mit `res.jsonp()`-Methoden wie dieser verketten: `res.status(status).jsonp(obj)`. + +{% include admonitions/note.html content=codemod-deprecated-signatures %} + +```js +// v4 +app.post('/user', (req, res) => { + res.jsonp({ name: 'Ruben' }, 201); +}); + +// v5 +app.post('/user', (req, res) => { + res.status(201).jsonp({ name: 'Ruben' }); +}); +``` + +

    res.redirect(url, status)

    + +Express 5 unterstützt die Signatur `res.send(obj, status)` nicht mehr. Stattdessen müssen Sie den Status festlegen und diesen dann mit `res.send()`-Methoden wie dieser verketten: `res.status(status).send(obj)`. + +{% include admonitions/note.html content=codemod-deprecated-signatures %} + +```js +// v4 +app.get('/user', (req, res) => { + res.redirect('/users', 301); +}); + +// v5 +app.get('/user', (req, res) => { + res.redirect(301, '/users'); +}); +``` + +

    res.redirect('back') and res.location('back')

    + +Express 5 no longer supports the magic string `back` in the `res.redirect()` and `res.location()` methods. Instead, use the `req.get('Referrer') || '/'` value to redirect back to the previous page. In Express 4, the `res.redirect('back')` and `res.location('back')` methods were deprecated. + +{% capture codemod-magic-redirect %} +You can replace the deprecated signatures with the following command: + +```plaintext +npx @expressjs/codemod magic-redirect +``` + +{% endcapture %} + +{% include admonitions/note.html content=codemod-magic-redirect %} + +```js +// v4 +app.get('/user', (req, res) => { + res.redirect('back'); +}); + +// v5 +app.get('/user', (req, res) => { + res.redirect(req.get('Referrer') || '/'); +}); +``` + +

    res.send(body, status)

    + +Express 5 no longer supports the signature `res.send(obj, status)`. Instead, set the status and then chain it to the `res.send()` method like this: `res.status(status).send(obj)`. + +{% include admonitions/note.html content=codemod-deprecated-signatures %} + +```js +// v4 +app.get('/user', (req, res) => { + res.send({ name: 'Ruben' }, 200); +}); + +// v5 +app.get('/user', (req, res) => { + res.status(200).send({ name: 'Ruben' }); +}); +``` + +

    res.send(status)

    + +Express 5 unterstützt die Signatur res.send(status), nicht mehr, wobei _`status`_ für eine Zahl steht. Verwenden Sie stattdessen die Funktion `res.sendStatus(statusCode)`, mit der der Statuscode für den HTTP-Antwort-Header festgelegt und die Textversion des Codes gesendet wird: "Not Found" (Nicht gefunden), "Internal Server Error" (Interner Serverfehler) usw. +Wenn Sie eine Zahl senden und hierfür die Funktion `res.send()` verwenden müssen, müssen Sie die Zahl in Anführungszeichen setzen, um diese in eine Zeichenfolge zu konvertieren. Dadurch interpretiert Express diese Zahl nicht als Versuch, die nicht mehr unterstützte alte Signatur zu verwenden. + +{% include admonitions/note.html content=codemod-deprecated-signatures %} + +```js +// v4 +app.get('/user', (req, res) => { + res.send(200); +}); + +// v5 +app.get('/user', (req, res) => { + res.sendStatus(200); +}); +``` + +

    res.sendfile()

    + +Die Funktion `res.sendfile()` wurde durch eine Version in Camel-Schreibweise von `res.sendFile()` in Express 5 ersetzt. + +**Note:** In Express 5, `res.sendFile()` uses the `mime-types` package for MIME type detection, which returns different Content-Type values than Express 4 for several common file types: + +- JavaScript files (.js): now "text/javascript" instead of "application/javascript" +- JSON files (.json): now "application/json" instead of "text/json" +- CSS files (.css): now "text/css" instead of "text/plain" +- XML files (.xml): now "application/xml" instead of "text/xml" +- Font files (.woff): now "font/woff" instead of "application/font-woff" +- SVG files (.svg): now "image/svg+xml" instead of "application/svg+xml" + +{% include admonitions/note.html content=codemod-deprecated-signatures %} + +```js +// v4 +app.get('/user', (req, res) => { + res.sendfile('/path/to/file'); +}); + +// v5 +app.get('/user', (req, res) => { + res.sendFile('/path/to/file'); +}); +``` + +

    router.param(fn)

    + +The `router.param(fn)` signature was used for modifying the behavior of the `router.param(name, fn)` function. Seit v4.11.0 wurde sie nicht mehr verwendet. In Express 5 wird sie überhaupt nicht mehr unterstützt. + +

    express.static.mime

    + +In Express 5, `mime` is no longer an exported property of the `static` field. +Use the [`mime-types` package](https://github.com/jshttp/mime-types) to work with MIME type values. + +**Important:** This change affects not only direct usage of `express.static.mime` but also other Express methods that rely on MIME type detection, such as `res.sendFile()`. The following MIME types have changed from Express 4: + +- JavaScript files (.js): now served as "text/javascript" instead of "application/javascript" +- JSON files (.json): now served as "application/json" instead of "text/json" +- CSS files (.css): now served as "text/css" instead of "text/plain" +- HTML files (.html): now served as "text/html; charset=utf-8" instead of just "text/html" +- XML files (.xml): now served as "application/xml" instead of "text/xml" +- Font files (.woff): now served as "font/woff" instead of "application/font-woff" + +```js +// v4 +express.static.mime.lookup('json'); + +// v5 +const mime = require('mime-types'); +mime.lookup('json'); +``` + +

    express:router debug logs

    + +In Express 5, router handling logic is performed by a dependency. Therefore, the +debug logs for the router are no longer available under the `express:` namespace. +In v4, the logs were available under the namespaces `express:router`, `express:router:layer`, +and `express:router:route`. All of these were included under the namespace `express:*`. +In v5.1+, the logs are available under the namespaces `router`, `router:layer`, and `router:route`. +The logs from `router:layer` and `router:route` are included in the namespace `router:*`. +To achieve the same detail of debug logging when using `express:*` in v4, use a conjunction of +`express:*`, `router`, and `router:*`. + +```sh +# v4 +DEBUG=express:* node index.js + +# v5 +DEBUG=express:*,router,router:* node index.js +``` + +## Geändert + +

    Path route matching syntax

    + +Path route matching syntax is when a string is supplied as the first parameter to the `app.all()`, `app.use()`, `app.METHOD()`, `router.all()`, `router.METHOD()`, and `router.use()` APIs. The following changes have been made to how the path string is matched to an incoming request: + +- The wildcard `*` must have a name, matching the behavior of parameters `:`, use `/*splat` instead of `/*` + +```js +// v4 +app.get('/*', async (req, res) => { + res.send('ok'); +}); + +// v5 +app.get('/*splat', async (req, res) => { + res.send('ok'); +}); +``` + +{% capture note_wildcard %} +`*splat` matches any path without the root path. If you need to match the root path as well `/`, you can use `/{*splat}`, wrapping the wildcard in braces. + +```js +// v5 +app.get('/{*splat}', async (req, res) => { + res.send('ok'); +}); +``` + +{% endcapture %} +{% include admonitions/note.html content=note_wildcard %} + +- The optional character `?` is no longer supported, use braces instead. + +```js +// v4 +app.get('/:file.:ext?', async (req, res) => { + res.send('ok'); +}); + +// v5 +app.get('/:file{.:ext}', async (req, res) => { + res.send('ok'); +}); +``` + +- Regexp characters are not supported. Beispiel: + +```js +app.get('/[discussion|page]/:slug', async (req, res) => { + res.status(200).send('ok'); +}); +``` + +should be changed to: + +```js +app.get(['/discussion/:slug', '/page/:slug'], async (req, res) => { + res.status(200).send('ok'); +}); +``` + +- Some characters have been reserved to avoid confusion during upgrade (`()[]?+!`), use `\` to escape them. +- Parameter names now support valid JavaScript identifiers, or quoted like `:"this"`. + +

    Rejected promises handled from middleware and handlers

    + +Request middleware and handlers that return rejected promises are now handled by forwarding the rejected value as an `Error` to the error handling middleware. This means that using `async` functions as middleware and handlers are easier than ever. When an error is thrown in an `async` function or a rejected promise is `await`ed inside an async function, those errors will be passed to the error handler as if calling `next(err)`. + +Details of how Express handles errors is covered in the [error handling documentation](/en/guide/error-handling.html). + +

    express.urlencoded

    + +The `express.urlencoded` method makes the `extended` option `false` by default. + +

    express.static dotfiles

    + +In Express 5, the `express.static` middleware's `dotfiles` option now defaults to `"ignore"`. This is a change from Express 4, where dotfiles were served by default. As a result, files inside a directory that starts with a dot (`.`), such as `.well-known`, will no longer be accessible and will return a **404 Not Found** error. This can break functionality that depends on serving dot-directories, such as Android App Links, and Apple Universal Links. + +Example of breaking code: + +```js +// v4 +app.use(express.static('public')); +``` + +After migrating to Express 5, a request to `/.well-known/assetlinks.json` will result in a **404 Not Found**. + +To fix this, serve specific dot-directories explicitly using the `dotfiles: "allow"` option: + +```js +// v5 +app.use('/.well-known', express.static('public/.well-known', { dotfiles: 'allow' })); +app.use(express.static('public')); +``` + +This approach allows you to safely serve only the intended dot-directories while keeping the default secure behavior for other dotfiles, which remain inaccessible. + +

    app.listen

    + +In Express 5, the `app.listen` method will invoke the user-provided callback function (if provided) when the server receives an error event. In Express 4, such errors would be thrown. This change shifts error-handling responsibility to the callback function in Express 5. If there is an error, it will be passed to the callback as an argument. +Beispiel: + +```js +const server = app.listen(8080, '0.0.0.0', (error) => { + if (error) { + throw error; // e.g. EADDRINUSE + } + console.log(`Listening on ${JSON.stringify(server.address())}`); +}); +``` + +

    app.router

    + +Das Objekt `app.router`, das in Express 4 entfernt wurde, ist in Express 5 wieder verfügbar. In der neuen Version fungiert dieses Objekt nur als Referenz zum Express-Basisrouter – im Gegensatz zu Express 3, wo die Anwendung dieses Objekt explizit laden musste. + +

    req.body

    + +The `req.body` property returns `undefined` when the body has not been parsed. In Express 4, it returns `{}` by default. + +

    req.host

    + +In Express 4 übergab die Funktion `req.host` nicht ordnungsgemäß eine eventuell vorhandene Portnummer. In Express 5 wird die Portnummer beibehalten. + +

    req.params

    + +The `req.params` object now has a **null prototype** when using string paths. However, if the path is defined with a regular expression, `req.params` remains a standard object with a normal prototype. Additionally, there are two important behavioral changes: + +**Wildcard parameters are now arrays:** + +Wildcards (e.g., `/*splat`) capture path segments as an array instead of a single string. + +```js +app.get('/*splat', (req, res) => { + // GET /foo/bar + console.dir(req.params); + // => [Object: null prototype] { splat: [ 'foo', 'bar' ] } +}); +``` + +**Unmatched parameters are omitted:** + +In Express 4, unmatched wildcards were empty strings (`''`) and optional `:` parameters (using `?`) had a key with value `undefined`. In Express 5, unmatched parameters are completely omitted from `req.params`. + +```js +// v4: unmatched wildcard is empty string +app.get('/*', (req, res) => { + // GET / + console.dir(req.params); + // => { '0': '' } +}); + +// v4: unmatched optional param is undefined +app.get('/:file.:ext?', (req, res) => { + // GET /image + console.dir(req.params); + // => { file: 'image', ext: undefined } +}); + +// v5: unmatched optional param is omitted +app.get('/:file{.:ext}', (req, res) => { + // GET /image + console.dir(req.params); + // => [Object: null prototype] { file: 'image' } +}); +``` + +

    req.query

    + +The `req.query` property is no longer a writable property and is instead a getter. The default query parser has been changed from "extended" to "simple". + +

    res.clearCookie

    + +The `res.clearCookie` method ignores the `maxAge` and `expires` options provided by the user. + +

    res.status

    + +The `res.status` method only accepts integers in the range of `100` to `999`, following the behavior defined by Node.js, and it returns an error when the status code is not an integer. + +

    res.vary

    + +The `res.vary` throws an error when the `field` argument is missing. In Express 4, if the argument was omitted, it gave a warning in the console + +## Verbesserungen + +

    res.render()

    + +Diese Methode erzwingt nun asynchrones Verhalten für alle View-Engines, sodass durch View-Engines mit synchroner Implementierung verursachte Fehler vermieden werden, durch die die empfohlene Schnittstelle nicht verwendet werden konnte. + +

    Brotli encoding support

    + +Express 5 supports Brotli encoding for requests received from clients that support it. diff --git a/astro/src/content/docs/de/5x/guide/overriding-express-api.md b/astro/src/content/docs/de/5x/guide/overriding-express-api.md new file mode 100644 index 0000000000..db65ce792f --- /dev/null +++ b/astro/src/content/docs/de/5x/guide/overriding-express-api.md @@ -0,0 +1,70 @@ +--- +title: Overriding the Express API +description: Discover how to customize and extend the Express.js API by overriding methods and properties on the request and response objects using prototypes. +--- + +# Overriding the Express API + +The Express API consists of various methods and properties on the request and response objects. These are inherited by prototype. There are two extension points for the Express API: + +1. The global prototypes at `express.request` and `express.response`. +2. App-specific prototypes at `app.request` and `app.response`. + +Altering the global prototypes will affect all loaded Express apps in the same process. If desired, alterations can be made app-specific by only altering the app-specific prototypes after creating a new app. + +## Methods + +You can override the signature and behavior of existing methods with your own, by assigning a custom function. + +Following is an example of overriding the behavior of [res.sendStatus](/4x/api.html#res.sendStatus). + +```js +app.response.sendStatus = function (statusCode, type, message) { + // code is intentionally kept simple for demonstration purpose + return this.contentType(type).status(statusCode).send(message); +}; +``` + +The above implementation completely changes the original signature of `res.sendStatus`. It now accepts a status code, encoding type, and the message to be sent to the client. + +The overridden method may now be used this way: + +```js +res.sendStatus(404, 'application/json', '{"error":"resource not found"}'); +``` + +## Properties + +Properties in the Express API are either: + +1. Assigned properties (ex: `req.baseUrl`, `req.originalUrl`) +2. Defined as getters (ex: `req.secure`, `req.ip`) + +Since properties under category 1 are dynamically assigned on the `request` and `response` objects in the context of the current request-response cycle, their behavior cannot be overridden. + +Properties under category 2 can be overwritten using the Express API extensions API. + +The following code rewrites how the value of `req.ip` is to be derived. Now, it simply returns the value of the `Client-IP` request header. + +```js +Object.defineProperty(app.request, 'ip', { + configurable: true, + enumerable: true, + get() { + return this.get('Client-IP'); + }, +}); +``` + +## Prototype + +In order to provide the Express API, the request/response objects passed to Express (via `app(req, res)`, for example) need to inherit from the same prototype chain. By default, this is `http.IncomingRequest.prototype` for the request and `http.ServerResponse.prototype` for the response. + +Unless necessary, it is recommended that this be done only at the application level, rather than globally. Also, take care that the prototype that is being used matches the functionality as closely as possible to the default prototypes. + +```js +// Use FakeRequest and FakeResponse in place of http.IncomingRequest and http.ServerResponse +// for the given app reference +Object.setPrototypeOf(Object.getPrototypeOf(app.request), FakeRequest.prototype); +Object.setPrototypeOf(Object.getPrototypeOf(app.response), FakeResponse.prototype); +``` diff --git a/astro/src/content/docs/de/5x/guide/routing.md b/astro/src/content/docs/de/5x/guide/routing.md new file mode 100644 index 0000000000..f365b137f3 --- /dev/null +++ b/astro/src/content/docs/de/5x/guide/routing.md @@ -0,0 +1,417 @@ +--- +title: Weiterleitung in Express +description: Learn how to define and use routes in Express.js applications, including route methods, route paths, parameters, and using Router for modular routing. +--- + +# Weiterleitung (Routing) + +Der Begriff _Weiterleitung_ (Routing) bezieht sich auf die Definition von Anwendungsendpunkten (URIs) und deren Antworten auf Clientanforderungen. +Eine Einführung in dieses Routing siehe [Basisrouting](/{{ page.lang }}/starter/basic-routing.html). + +You define routing using methods of the Express `app` object that correspond to HTTP methods; +for example, `app.get()` to handle GET requests and `app.post` to handle POST requests. For a full list, +see [app.METHOD](/{{ page.lang }}/5x/api.html#app.METHOD). You can also use [app.all()](/{{ page.lang }}/5x/api.html#app.all) to handle all HTTP methods and [app.use()](/{{ page.lang }}/5x/api.html#app.use) to +specify middleware as the callback function (See [Using middleware](/{{ page.lang }}/guide/using-middleware.html) for details). + +These routing methods specify a callback function (sometimes called "handler functions") called when the application receives a request to the specified route (endpoint) and HTTP method. In other words, the application "listens" for requests that match the specified route(s) and method(s), and when it detects a match, it calls the specified callback function. + +In fact, the routing methods can have more than one callback function as arguments. +With multiple callback functions, it is important to provide `next` as an argument to the callback function and then call `next()` within the body of the function to hand off control +to the next callback. + +Der folgende Code ist ein Beispiel für ein sehr einfaches Basisrouting. + +```js +const express = require('express'); +const app = express(); + +// respond with "hello world" when a GET request is made to the homepage +app.get('/', (req, res) => { + res.send('hello world'); +}); +``` + +

    Weiterleitungsmethoden

    + +Eine Weiterleitungsmethode wird von einer HTTP-Methode abgeleitet und an eine Instanz der Klasse `express` angehängt. + +Der folgende Code ist ein Beispiel für Weiterleitungen, die für die Methoden GET und POST zum Stamm (Root) der Anwendung definiert werden. + +```js +// GET method route +app.get('/', (req, res) => { + res.send('GET request to the homepage'); +}); + +// POST method route +app.post('/', (req, res) => { + res.send('POST request to the homepage'); +}); +``` + +Express supports methods that correspond to all HTTP request methods: `get`, `post`, and so on. +For a full list, see [app.METHOD](/{{ page.lang }}/5x/api.html#app.METHOD). + +Es gibt eine spezielle Weiterleitungsmethode, `app.all()`, die nicht von einer HTTP-Methode abgeleitet wird. Diese Methode wird zum Laden von Middlewarefunktionen bei einem Pfad für alle Anforderungsmethoden verwendet. Im folgenden Beispiel wird der Handler für Anforderungen zur Weiterleitung "/secret" ausgeführt, um herauszufinden, ob Sie GET-, POST-, PUT-, DELETE- oder andere HTTP-Anforderungsmethoden verwenden, die im [HTTP-Modul](https://nodejs.org/api/http.html#http_http_methods) unterstützt werden. + +```js +app.all('/secret', (req, res, next) => { + console.log('Accessing the secret section ...'); + next(); // pass control to the next handler +}); +``` + +

    Weiterleitungspfade

    + +Über Weiterleitungspfade werden in Kombination mit einer Anforderungsmethode die Endpunkte definiert, bei denen Anforderungen erfolgen können. Weiterleitungspfade können Zeichenfolgen, Zeichenfolgemuster oder reguläre Ausdrücke sein. + +{% capture caution-character %} In express 5, the characters `?`, `+`, `*`, `[]`, and `()` are handled differently than in version 4, please review the [migration guide](/{{ page.lang }}/guide/migrating-5.html#path-syntax) for more information.{% endcapture %} + +{% include admonitions/caution.html content=caution-character %} + +{% capture note-dollar-character %}In express 4, regular expression characters such as `$` need to be escaped with a `\`. +{% endcapture %} + +{% include admonitions/caution.html content=note-dollar-character %} + +{% capture note-path-to-regexp %} + +Express uses [path-to-regexp](https://www.npmjs.com/package/path-to-regexp) for matching the route paths; see the path-to-regexp documentation for all the possibilities in defining route paths. [Express Route Tester](http://forbeslindesay.github.io/express-route-tester/) ist ein handliches Tool zum Testen von Express-Basisweiterleitungen, auch wenn dieses Tool keine Musterabgleiche unterstützt. + +{% endcapture %} + +{% include admonitions/note.html content=note-path-to-regexp %} + +{% capture query-string-note %} + +Query strings are not part of the route path. + +{% endcapture %} + +{% include admonitions/warning.html content=query-string-note %} + +### Route paths based on strings + +Dieser Weiterleitungspfad gleicht Weiterleitungsanforderungen zum Stammverzeichnis (`/`) ab. + +```js +app.get('/', (req, res) => { + res.send('root'); +}); +``` + +Dieser Weiterleitungspfad gleicht Anforderungen mit `/about` ab. + +```js +app.get('/about', (req, res) => { + res.send('about'); +}); +``` + +Dieser Weiterleitungspfad gleicht Anforderungen mit `/random.text` ab. + +```js +app.get('/random.text', (req, res) => { + res.send('random.text'); +}); +``` + +### Route paths based on string patterns + +{% capture caution-string-patterns %} The string patterns in Express 5 no longer work. Please refer to the [migration guide](/{{ page.lang }}/guide/migrating-5.html#path-syntax) for more information.{% endcapture %} + +{% include admonitions/caution.html content=caution-string-patterns %} + +Dieser Weiterleitungspfad gleicht `acd` und `abcd` ab. + +```js +app.get('/ab?cd', (req, res) => { + res.send('ab?cd'); +}); +``` + +Dies sind einige Beispiele für Weiterleitungspfade auf Basis von Zeichenfolgemustern. + +```js +app.get('/ab+cd', (req, res) => { + res.send('ab+cd'); +}); +``` + +Dies sind einige Beispiele für Weiterleitungspfade auf Basis von Zeichenfolgen. + +```js +app.get('/ab*cd', (req, res) => { + res.send('ab*cd'); +}); +``` + +Dieser Weiterleitungspfad gleicht `/abe` und `/abcde` ab. + +```js +app.get('/ab(cd)?e', (req, res) => { + res.send('ab(cd)?e'); +}); +``` + +### Route paths based on regular expressions + +Dieser Weiterleitungspfad gleicht alle Weiterleitungsnamen ab, die den Buchstaben "a" enthalten. + +```js +app.get(/a/, (req, res) => { + res.send('/a/'); +}); +``` + +Dieser Weiterleitungspfad gleicht `butterfly` und `dragonfly`, jedoch nicht `butterflyman`, `dragonfly man` usw. + +```js +app.get(/.*fly$/, (req, res) => { + res.send('/.*fly$/'); +}); +``` + +

    Route parameters

    + +Route parameters are named URL segments that are used to capture the values specified at their position in the URL. The captured values are populated in the `req.params` object, with the name of the route parameter specified in the path as their respective keys. + +``` +Route path: /users/:userId/books/:bookId +Request URL: http://localhost:3000/users/34/books/8989 +req.params: { "userId": "34", "bookId": "8989" } +``` + +To define routes with route parameters, simply specify the route parameters in the path of the route as shown below. + +```js +app.get('/users/:userId/books/:bookId', (req, res) => { + res.send(req.params); +}); +``` + +
    +The name of route parameters must be made up of "word characters" ([A-Za-z0-9_]). +
    + +Since the hyphen (`-`) and the dot (`.`) are interpreted literally, they can be used along with route parameters for useful purposes. + +``` +Route path: /flights/:from-:to +Request URL: http://localhost:3000/flights/LAX-SFO +req.params: { "from": "LAX", "to": "SFO" } +``` + +``` +Route path: /plantae/:genus.:species +Request URL: http://localhost:3000/plantae/Prunus.persica +req.params: { "genus": "Prunus", "species": "persica" } +``` + +{% capture warning-regexp %} +In express 5, Regexp characters are not supported in route paths, for more information please refer to the [migration guide](/{{ page.lang }}/guide/migrating-5.html#path-syntax).{% endcapture %} + +{% include admonitions/caution.html content=warning-regexp %} + +To have more control over the exact string that can be matched by a route parameter, you can append a regular expression in parentheses (`()`): + +``` +Route path: /user/:userId(\d+) +Request URL: http://localhost:3000/user/42 +req.params: {"userId": "42"} +``` + +{% capture escape-advisory %} + +Because the regular expression is usually part of a literal string, be sure to escape any `\` characters with an additional backslash, for example `\\d+`. + +{% endcapture %} + +{% include admonitions/warning.html content=escape-advisory %} + +{% capture warning-version %} + +In Express 4.x, the `*` character in regular expressions is not interpreted in the usual way. As a workaround, use `{0,}` instead of `*`. This will likely be fixed in Express 5. + +{% endcapture %} + +{% include admonitions/warning.html content=warning-version %} + +

    Routenhandler (Weiterleitungsroutinen)

    + +Sie können mehrere Callback-Funktionen angeben, die sich wie [Middleware](/{{ page.lang }}/guide/using-middleware.html) verhalten, um eine Anforderung zu verarbeiten. Die einzige Ausnahme hierbei ist, dass diese Callbacks möglicherweise `next('route')` aufrufen, um die verbleibenden Weiterleitungs-Callbacks zu umgehen. Mit diesem Verfahren können Sie Vorabbedingungen für eine Weiterleitung festlegen und dann die Steuerung an nachfolgende Weiterleitungen übergeben, wenn kein Grund vorliegt, mit der aktuellen Weiterleitung fortzufahren. + +```js +app.get('/user/:id', (req, res, next) => { + if (req.params.id === '0') { + return next('route'); + } + res.send(`User ${req.params.id}`); +}); + +app.get('/user/:id', (req, res) => { + res.send('Special handler for user ID 0'); +}); +``` + +In this example: + +- `GET /user/5` → handled by first route → sends "User 5" +- `GET /user/0` → first route calls `next('route')`, skipping to the next matching `/user/:id` route + +Routenhandler können eine Funktion und/oder ein Funktionsarray sein, wie in den folgenden Beispielen zu sehen ist. + +Eine einzelne Callback-Funktion kann eine Weiterleitung verarbeiten. Beispiel: + +```js +app.get('/example/a', (req, res) => { + res.send('Hello from A!'); +}); +``` + +Mehrere Callback-Funktionen können eine Weiterleitung verarbeiten (achten Sie darauf, dass Sie das Objekt `next` angeben). Beispiel: + +```js +app.get( + '/example/b', + (req, res, next) => { + console.log('the response will be sent by the next function ...'); + next(); + }, + (req, res) => { + res.send('Hello from B!'); + } +); +``` + +Ein Array von Callback-Funktionen kann eine Weiterleitung verarbeiten. Beispiel: + +```js +const cb0 = function (req, res, next) { + console.log('CB0'); + next(); +}; + +const cb1 = function (req, res, next) { + console.log('CB1'); + next(); +}; + +const cb2 = function (req, res) { + res.send('Hello from C!'); +}; + +app.get('/example/c', [cb0, cb1, cb2]); +``` + +Eine Kombination aus unabhängigen Funktionen und Funktionsarrays kann eine Weiterleitung verarbeiten. Beispiel: + +```js +const cb0 = function (req, res, next) { + console.log('CB0'); + next(); +}; + +const cb1 = function (req, res, next) { + console.log('CB1'); + next(); +}; + +app.get( + '/example/d', + [cb0, cb1], + (req, res, next) => { + console.log('the response will be sent by the next function ...'); + next(); + }, + (req, res) => { + res.send('Hello from D!'); + } +); +``` + +

    Antwortmethoden

    + +Über die Methoden für das Antwortobjekt (`res`) in der folgenden Tabelle kann eine Antwort an den Client gesendet und der Anforderung/Antwort-Zyklus beendet werden. Wenn keine dieser Methoden über einen Routenhandler aufgerufen wird, bleibt die Clientanforderung im Status "blockiert". + +| Methode | Beschreibung | +| --------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | +| [res.download()](/{{ page.lang }}/4x/api.html#res.download) | Gibt eine Eingabeaufforderung zum Herunterladen einer Datei aus. | +| [res.end()](/{{ page.lang }}/4x/api.html#res.end) | End the response process. | +| [res.json()](/{{ page.lang }}/4x/api.html#res.json) | Sendet eine JSON-Antwort. | +| [res.jsonp()](/{{ page.lang }}/4x/api.html#res.jsonp) | Sendet eine JSON-Antwort mit JSONP-Unterstützung. | +| [res.redirect()](/{{ page.lang }}/4x/api.html#res.redirect) | Leitet eine Anforderung um. | +| [res.render()](/{{ page.lang }}/4x/api.html#res.render) | Render a view template. | +| [res.send()](/{{ page.lang }}/4x/api.html#res.send) | Sendet eine Antwort mit unterschiedlichen Typen. | +| [res.sendFile](/{{ page.lang }}/4x/api.html#res.sendFile) | Sendet eine Datei als Oktett-Stream. | +| [res.sendStatus()](/{{ page.lang }}/4x/api.html#res.sendStatus) | Legt den Antwortstatuscode fest und sendet dessen Zeichenfolgedarstellung als Antworthauptteil. | + +

    app.route()

    + +Sie können mithilfe von `app.route()` verkettbare Routenhandler für einen Weiterleitungspfad erstellen. +Da der Pfad an einer einzelnen Position angegeben wird, ist das Erstellen modularer Weiterleitungen hilfreich, da Redundanzen und Schreibfehler reduziert werden. Weitere Informationen zu Weiterleitungen finden Sie in der Dokumentation zu [Router()](/{{ page.lang }}/4x/api.html#router). + +Dies ist ein Beispiel für verkettete Routenhandler, die mit der Funktion `app.route()` definiert werden. + +```js +app + .route('/book') + .get((req, res) => { + res.send('Get a random book'); + }) + .post((req, res) => { + res.send('Add a book'); + }) + .put((req, res) => { + res.send('Update the book'); + }); +``` + +

    express.Router

    + +Mit der Klasse `express.Router` lassen sich modular einbindbare Routenhandler erstellen. Eine `Router`-Instanz ist ein vollständiges Middleware- und Routingsystem. Aus diesem Grund wird diese Instanz oft auch als "Mini-App" bezeichnet. + +Im folgenden Beispiel wird ein Router als Modul erstellt, eine Middlewarefunktion in das Modul geladen, es werden Weiterleitungen definiert und das Modul letztendlich in einen Pfad in der Hauptanwendung eingebunden. + +Erstellen Sie eine Routerdatei namens `birds.js` mit dem folgenden Inhalt im Anwendungsverzeichnis: + +```js +const express = require('express'); +const router = express.Router(); + +// middleware that is specific to this router +const timeLog = (req, res, next) => { + console.log('Time: ', Date.now()); + next(); +}; +router.use(timeLog); + +// define the home page route +router.get('/', (req, res) => { + res.send('Birds home page'); +}); +// define the about route +router.get('/about', (req, res) => { + res.send('About birds'); +}); + +module.exports = router; +``` + +Laden Sie dann das Routermodul in die Anwendung: + +```js +const birds = require('./birds'); + +// ... + +app.use('/birds', birds); +``` + +Die Anwendung kann nun Anforderungen an die Pfade `/birds` und `/birds/about` bearbeiten und ruft die Middlewarefunktion `timeLog` auf, die speziell für diese Weiterleitung bestimmt ist. + +But if the parent route `/birds` has path parameters, it will not be accessible by default from the sub-routes. To make it accessible, you will need to pass the `mergeParams` option to the Router constructor [reference](/{{ page.lang }}/5x/api.html#app.use). + +```js +const router = express.Router({ mergeParams: true }); +``` diff --git a/astro/src/content/docs/de/5x/guide/using-middleware.md b/astro/src/content/docs/de/5x/guide/using-middleware.md new file mode 100644 index 0000000000..5a5ccae0ba --- /dev/null +++ b/astro/src/content/docs/de/5x/guide/using-middleware.md @@ -0,0 +1,293 @@ +--- +title: Express-Middleware verwenden +description: Learn how to use middleware in Express.js applications, including application-level and router-level middleware, error handling, and integrating third-party middleware. +--- + +# Middleware verwenden + +Express ist ein Weiterleitungs- und Middleware-Web-Framework, das selbst nur minimale Funktionalität aufweist: Eine Express-Anwendung besteht im Wesentlichen aus einer Reihe von Middlewarefunktionsaufrufen. + +_Middleware_ functions are functions that have access to the [request object](/{{ page.lang }}/5x/api.html#req) (`req`), the [response object](/{{ page.lang }}/5x/api.html#res) (`res`), and the next middleware function in the application's request-response cycle. Die nächste Middlewarefunktion wird im Allgemeinen durch die Variable `next` bezeichnet. + +Über Middlewarefunktionen lassen sich die folgenden Tasks ausführen: + +- Ausführen von Code +- Vornehmen von Änderungen an der Anforderung und an Antwortobjekten +- End the request-response cycle. +- Aufrufen der nächsten Middlewarefunktion im Stack + +Wenn über die aktuelle Middlewarefunktion der Anforderung/Antwort-Zyklus nicht beendet werden kann, muss `next()` aufgerufen werden, um die Steuerung an die nächste Middlewarefunktion zu übergeben. Andernfalls geht die Anforderung in den Status "Blockiert" über. + +Eine Express-Anwendung kann die folgenden Middlewaretypen verwenden: + +- [Middleware auf Anwendungsebene](#middleware.application) +- [Middleware auf Routerebene](#middleware.router) +- [Middleware für die Fehlerbehandlung](#middleware.error-handling) +- [Integrierte Middleware](#middleware.built-in) +- [Middleware anderer Anbieter](#middleware.third-party) + +Sie können Middleware auf Anwendungsebene und Routerebene mit einem optionalen Mountpfad laden. +Sie können auch eine Reihe von Middlewarefunktionen zusammen laden. Dadurch wird ein Sub-Stack des Middlewaresystems am Mountpunkt erstellt. + +

    Middleware auf Anwendungsebene

    + +Bind application-level middleware to an instance of the [app object](/{{ page.lang }}/5x/api.html#app) by using the `app.use()` and `app.METHOD()` functions, where `METHOD` is the HTTP method of the request that the middleware function handles (such as GET, PUT, or POST) in lowercase. + +Dieses Beispiel zeigt eine Middlewarefunktion ohne Mountpfad. Die Funktion wird immer dann ausgeführt, wenn die Anwendung eine Anforderung erhält. + +```js +const express = require('express'); +const app = express(); + +app.use((req, res, next) => { + console.log('Time:', Date.now()); + next(); +}); +``` + +Dieses Beispiel zeigt eine Middlewarefunktion mit dem Mountpfad `/user/:id`. Die Funktion wird für jede Art von HTTP-Anforderung auf dem Pfad `/user/:id` ausgeführt. + +```js +app.use('/user/:id', (req, res, next) => { + console.log('Request Type:', req.method); + next(); +}); +``` + +Dieses Beispiel zeigt eine Weiterleitung und deren Handlerfunktion (Middlewaresystem). Die Funktion verarbeitet GET-Anforderungen zum Pfad `/user/:id`. + +```js +app.get('/user/:id', (req, res, next) => { + res.send('USER'); +}); +``` + +Dies ist ein Beispiel zum Laden einer Reihe von Middlewarefunktionen an einem Mountpunkt mit einem Mountpfad. +Das Beispiel veranschaulicht einen Middleware-Stack, über den Anforderungsinformationen zu einer HTTP-Anforderung zum Pfad `/user/:id` ausgegeben werden. + +```js +app.use( + '/user/:id', + (req, res, next) => { + console.log('Request URL:', req.originalUrl); + next(); + }, + (req, res, next) => { + console.log('Request Type:', req.method); + next(); + } +); +``` + +Mit einem Routenhandler können Sie mehrere Weiterleitungen für einen Pfad definieren. Im folgenden Beispiel werden zwei Weiterleitungen für GET-Anforderungen zum Pfad `/user/:id` definiert. Die zweite Weiterleitung verursacht zwar keine Probleme, wird jedoch nie aufgerufen, da durch die erste Weiterleitung der Anforderung/Antwort-Zyklus beendet wird. + +Dieses Beispiel zeigt einen Middleware-Sub-Stack, über den GET-Anforderungen zum Pfad `/user/:id` verarbeitet werden. + +```js +app.get( + '/user/:id', + (req, res, next) => { + console.log('ID:', req.params.id); + next(); + }, + (req, res, next) => { + res.send('User Info'); + } +); + +// handler for the /user/:id path, which prints the user ID +app.get('/user/:id', (req, res, next) => { + res.send(req.params.id); +}); +``` + +Wenn Sie den Rest der Middlewarefunktionen eines Weiterleitungs-Middleware-Stack überspringen wollen, rufen Sie `next('route')` auf, um die Steuerung an die nächste Weiterleitung zu übergeben. + +{% capture next-function %} + +`next('route')` will work only in middleware functions that were loaded by using the `app.METHOD()` or `router.METHOD()` functions. + +{% endcapture %} + +{% include admonitions/note.html content=next-function %} + +Dieses Beispiel zeigt einen Middleware-Sub-Stack, über den GET-Anforderungen zum Pfad `/user/:id` verarbeitet werden. + +```js +app.get( + '/user/:id', + (req, res, next) => { + // if the user ID is 0, skip to the next route + if (req.params.id === '0') next('route'); + // otherwise pass the control to the next middleware function in this stack + else next(); + }, + (req, res, next) => { + // send a regular response + res.send('regular'); + } +); + +// handler for the /user/:id path, which sends a special response +app.get('/user/:id', (req, res, next) => { + res.send('special'); +}); +``` + +Middleware can also be declared in an array for reusability. + +Dies ist ein Beispiel zur Verwendung der Middlewarefunktion `express.static` mit einem ausführlich dargestellten Optionsobjekt: + +```js +function logOriginalUrl(req, res, next) { + console.log('Request URL:', req.originalUrl); + next(); +} + +function logMethod(req, res, next) { + console.log('Request Type:', req.method); + next(); +} + +const logStuff = [logOriginalUrl, logMethod]; +app.get('/user/:id', logStuff, (req, res, next) => { + res.send('User Info'); +}); +``` + +

    Middleware auf Routerebene

    + +Middleware auf Routerebene funktioniert in der gleichen Weise wie Middleware auf Anwendungsebene, mit dem einzigen Unterschied, dass sie an eine Instanz von `express.Router()` gebunden ist. + +```js +const router = express.Router(); +``` + +Laden Sie Middleware auf Routerebene über die Funktionen `router.use()` und `router.METHOD()`. + +Der folgende Beispielcode repliziert das Middlewaresystem, das oben für die Middleware auf Anwendungsebene gezeigt wird, durch Verwendung von Middleware auf Routerebene. + +```js +const express = require('express'); +const app = express(); +const router = express.Router(); + +// a middleware function with no mount path. This code is executed for every request to the router +router.use((req, res, next) => { + console.log('Time:', Date.now()); + next(); +}); + +// a middleware sub-stack shows request info for any type of HTTP request to the /user/:id path +router.use( + '/user/:id', + (req, res, next) => { + console.log('Request URL:', req.originalUrl); + next(); + }, + (req, res, next) => { + console.log('Request Type:', req.method); + next(); + } +); + +// a middleware sub-stack that handles GET requests to the /user/:id path +router.get( + '/user/:id', + (req, res, next) => { + // if the user ID is 0, skip to the next router + if (req.params.id === '0') next('route'); + // otherwise pass control to the next middleware function in this stack + else next(); + }, + (req, res, next) => { + // render a regular page + res.render('regular'); + } +); + +// handler for the /user/:id path, which renders a special page +router.get('/user/:id', (req, res, next) => { + console.log(req.params.id); + res.render('special'); +}); + +// mount the router on the app +app.use('/', router); +``` + +To skip the rest of the router's middleware functions, call `next('router')` +to pass control back out of the router instance. + +Dieses Beispiel zeigt einen Middleware-Sub-Stack, über den GET-Anforderungen zum Pfad `/user/:id` verarbeitet werden. + +```js +const express = require('express'); +const app = express(); +const router = express.Router(); + +// predicate the router with a check and bail out when needed +router.use((req, res, next) => { + if (!req.headers['x-auth']) return next('router'); + next(); +}); + +router.get('/user/:id', (req, res) => { + res.send('hello, user!'); +}); + +// use the router and 401 anything falling through +app.use('/admin', router, (req, res) => { + res.sendStatus(401); +}); +``` + +

    Middleware für die Fehlerbehandlung

    + +
    +Middleware für die Fehlerbehandlung benötigt immer *vier* Argumente. Sie müssen vier Argumente angeben, um die Erkennung als Middlewarefunktion für die Fehlerbehandlung zu ermöglichen. Selbst wenn das Objekt `next` nicht verwenden müssen, müssen Sie dies angeben, um die Signatur beizubehalten. Andernfalls wird das Objekt `next` als reguläre Middleware interpretiert, sodass keine Fehlerbehandlung möglich ist. +
    + +Middlewarefunktionen für die Fehlerbehandlung werden in derselben Weise definiert wie andere Middlewarefunktionen, außer dass Fehlerbehandlungsfunktionen speziell bei Signaturen vier anstatt drei Argumente aufweisen `(err, req, res, next)`: + +```js +app.use((err, req, res, next) => { + console.error(err.stack); + res.status(500).send('Something broke!'); +}); +``` + +Details zu Middleware für die Fehlerbehandlung siehe [Fehlerbehandlung](/{{ page.lang }}/guide/error-handling.html). + +

    Integrierte Middleware

    + +Seit Version 4.x bestehen bei Express keine Abhängigkeiten zu [Connect](https://github.com/senchalabs/connect) mehr. Mit Ausnahme von `express.static` befinden sich nun alle Middlewarefunktionen, die bisher in Express enthalten waren, in separaten Modulen. Sehen Sie sich hierzu auch die [Liste der Middlewarefunktionen](https://github.com/senchalabs/connect#middleware) an. + +Die einzige integrierte Middlewarefunktion in Express ist `express.static`. + +- [express.static](/en/5x/api.html#express.static) serves static assets such as HTML files, images, and so on. +- [express.json](/en/5x/api.html#express.json) parses incoming requests with JSON payloads. **NOTE: Available with Express 4.16.0+** +- [express.urlencoded](/en/5x/api.html#express.urlencoded) parses incoming requests with URL-encoded payloads. **NOTE: Available with Express 4.16.0+** + +

    Middleware anderer Anbieter

    + +Mit Middleware anderer Anbieter können Sie Express-Anwendungen um neue Funktionalität erweitern. + +Installieren Sie das Modul Node.js für die erforderliche Funktionalität. Laden Sie das Modul dann in Ihre Anwendung auf Anwendungsebene oder auf Routerebene. + +Das folgende Beispiel veranschaulicht das Installieren und Laden der Middlewarefunktion `cookie-parser` für das Cookie-Parsing. + +```bash +$ npm install cookie-parser +``` + +```js +const express = require('express'); +const app = express(); +const cookieParser = require('cookie-parser'); + +// load the cookie-parsing middleware +app.use(cookieParser()); +``` + +Eine nicht vollständige Liste zu den Middlewarefunktionen anderer Anbieter, die im Allgemeinen mit Express verwendet werden, finden Sie unter [Middleware anderer Anbieter](../resources/middleware.html). diff --git a/astro/src/content/docs/de/5x/guide/using-template-engines.md b/astro/src/content/docs/de/5x/guide/using-template-engines.md new file mode 100644 index 0000000000..d9423933d3 --- /dev/null +++ b/astro/src/content/docs/de/5x/guide/using-template-engines.md @@ -0,0 +1,58 @@ +--- +title: Template-Engines in Express verwenden +description: Discover how to integrate and use template engines like Pug, Handlebars, and EJS with Express.js to render dynamic HTML pages efficiently. +--- + +# Template-Engines in Express verwenden + +A _template engine_ enables you to use static template files in your application. At runtime, the template engine replaces +variables in a template file with actual values, and transforms the template into an HTML file sent to the client. +This approach makes it easier to design an HTML page. + +The [Express application generator](/{{ page.lang }}/starter/generator.html) uses [Pug](https://pugjs.org/api/getting-started.html) as its default, but it also supports [Handlebars](https://www.npmjs.com/package/handlebars), and [EJS](https://www.npmjs.com/package/ejs), among others. + +To render template files, set the following [application setting properties](/{{ page.lang }}/4x/api.html#app.set), in the default `app.js` created by the generator: + +- `views`, das Verzeichnis, in dem sich die Vorlagendateien befinden. Beispiel: `app.set('views', './views')` + This defaults to the `views` directory in the application root directory. +- `view engine`, die zu verwendende Template-Engine. Beispiel: `app.set('view engine', 'pug')` + +Installieren Sie dann das entsprechende npm-Paket für die Template-Engine: + +```bash +$ npm install pug --save +``` + +
    Express-konforme Template-Engines wie Pug exportieren eine Funktion namens `__express(filePath, options, callback)`, die über die Funktion `res.render()` aufgerufen wird, um den Vorlagencode ausgeben zu können. + +Einige Template-Engines folgen dieser Konvention nicht. Die Bibliothek [Consolidate.js](https://www.npmjs.org/package/consolidate) folgt dieser Konvention, indem alle gängigen Node.js-Template-Engines zugeordnet werden. Daher ist eine reibungslose Funktion in Express gewährleistet. + +
    + +Nach der Festlegung der View-Engine muss die Engine nicht angegeben oder das Template-Engine-Modul nicht in Ihre Anwendung geladen werden. Express lädt das Modul intern (wie unten für das obige Beispiel gezeigt). + +```js +app.set('view engine', 'pug'); +``` + +Erstellen Sie eine Pug-Vorlagendatei namens `index.pug` im Verzeichnis `views` mit dem folgenden Inhalt: + +```pug +html + head + title= title + body + h1= message +``` + +Dann erstellen Sie eine Weiterleitung, um die Datei `index.pug` auszugeben. Wenn die Eigenschaft `view engine` nicht festgelegt wurde, müssen Sie die Erweiterung der Datei `view` angeben. Andernfalls müssen Sie diese Erweiterung nicht angeben. + +```js +app.get('/', (req, res) => { + res.render('index', { title: 'Hey', message: 'Hello there!' }); +}); +``` + +Wenn Sie eine Anforderung zur Homepage ausführen, wird die Datei `index.pug` im HTML-Format ausgegeben. + +The view engine cache does not cache the contents of the template's output, only the underlying template itself. The view is still re-rendered with every request even when the cache is on. diff --git a/astro/src/content/docs/de/5x/guide/writing-middleware.md b/astro/src/content/docs/de/5x/guide/writing-middleware.md new file mode 100644 index 0000000000..bde6d0e8de --- /dev/null +++ b/astro/src/content/docs/de/5x/guide/writing-middleware.md @@ -0,0 +1,217 @@ +--- +title: Middleware für die Verwendung in Express-Anwendungen schreiben +description: Learn how to write custom middleware functions for Express.js applications, including examples and best practices for enhancing request and response handling. +--- + +# Middleware für die Verwendung in Express-Anwendungen schreiben + +

    Überblick

    + +_Middleware_ functions are functions that have access to the [request object](/{{ page.lang }}/5x/api.html#req) (`req`), the [response object](/{{ page.lang }}/5x/api.html#res) (`res`), and the `next` function in the application's request-response cycle. Die nächste Middlewarefunktion wird im Allgemeinen durch die Variable `next` bezeichnet. + +Über Middlewarefunktionen lassen sich die folgenden Tasks ausführen: + +- Ausführen von Code +- Vornehmen von Änderungen an der Anforderung und an Antwortobjekten +- End the request-response cycle. +- Aufrufen der nächsten Middleware im Stack + +Wenn über die aktuelle Middlewarefunktion der Anforderung/Antwort-Zyklus nicht beendet werden kann, muss `next()` aufgerufen werden, um die Steuerung an die nächste Middlewarefunktion zu übergeben. Andernfalls geht die Anforderung in den Status "Blockiert" über. + +Das folgende Beispiel zeigt die Elemente eines Middlewarefunktionsaufrufs: + +
    + + + + +
    Pfad (Weiterleitung), für den die Middlewarefunktion angewendet wird.
    + +
    Die Middlewarefunktion.
    + +
    Callback-Argument zur Middlewarefunktion, die nach der geltenden Konvention als "next" bezeichnet wird.
    + +
    HTTP response argument to the middleware function, called "res" by convention.
    + +
    HTTP request argument to the middleware function, called "req" by convention.
    + +
    +Elements of a middleware function call + +
    HTTP-Methode, für die die Middlewarefunktion angewendet wird.
    +
    + +Starting with Express 5, middleware functions that return a Promise will call `next(value)` when they reject or throw an error. `next` will be called with either the rejected value or the thrown Error. + +

    Beispiel

    + +Here is an example of a simple "Hello World" Express application. +The remainder of this article will define and add three middleware functions to the application: +one called `myLogger` that prints a simple log message, one called `requestTime` that +displays the timestamp of the HTTP request, and one called `validateCookies` that validates incoming cookies. + +```js +const express = require('express'); +const app = express(); + +app.get('/', (req, res) => { + res.send('Hello World!'); +}); + +app.listen(3000); +``` + +

    Dies ist ein Beispiel einer einfachen Express-Anwendung namens "Hello World", für die Sie zwei Middlewarefunktionen definieren:

    +Dies ist ein einfaches Beispiel einer Middlewarefunktion namens "myLogger". Diese Funktion gibt lediglich "LOGGED" aus, wenn eine Anforderung zur Anwendung über diese Funktion läuft. Die Middlewarefunktion ist der Variablen `myLogger` zugeordnet. + +```js +const myLogger = function (req, res, next) { + console.log('LOGGED'); + next(); +}; +``` + +
    +Beachten Sie den Aufruf oben zu `next()`. Durch den Aufruf dieser Funktion wird die nächste Middlewarefunktion in der Anwendung aufgerufen. +Die Funktion `next()` ist nicht Teil der Node.js- oder Express-API, sondern das dritte Argument, das an die Middlewarefunktion übergeben wird. Die Funktion `next()` kann jeden beliebigen Namen haben, per Konvention erhält sie jedoch immer den Namen "next". +Um Unklarheiten zu vermeiden, sollten Sie immer diese Konvention verwenden. +
    + +Zum Laden der Middlewarefunktion rufen Sie `app.use()` auf und geben die Middlewarefunktion an. +Beispiel: Durch den folgenden Code wird die Middlewarefunktion `myLogger` vor der Weiterleitung zum Stammverzeichnispfad (/) geladen. + +```js +const express = require('express'); +const app = express(); + +const myLogger = function (req, res, next) { + console.log('LOGGED'); + next(); +}; + +app.use(myLogger); + +app.get('/', (req, res) => { + res.send('Hello World!'); +}); + +app.listen(3000); +``` + +Sobald die Anwendung eine Anforderung erhält, gibt sie die Nachricht "LOGGED" an das Terminal aus. + +Die Reihenfolge beim Laden der Middleware ist wichtig: Middlewarefunktionen, die zuerst geladen werden, werden auch zuerst ausgeführt. + +Wenn `myLogger` nach der Weiterleitung zum Stammverzeichnispfad geladen wird, erreicht die Weiterleitung die Middlewarefunktion nicht. Die Anwendung gibt "LOGGED" nicht aus, weil der Routenhandler für den Stammverzeichnispfad den Anforderung/Antwort-Zyklus beendet. + +Die Middlewarefunktion `myLogger` gibt einfach eine Nachricht aus und übergibt dann die Anforderung zur nächsten Middlewarefunktion im Stack durch Aufruf der Funktion `next()`. + +

    Middleware function requestTime

    + +Im nächsten Beispiel wird die Eigenschaft `requestTime` zum Anforderungsobjekt hinzugefügt. Diese Middlewarefunktion erhält den Namen "requestTime". + +```js +const requestTime = function (req, res, next) { + req.requestTime = Date.now(); + next(); +}; +``` + +Die Anwendung verwendet nun die Middlewarefunktion `requestTime`. Außerdem verwendet die Callback-Funktion der Weiterleitung zum Stammverzeichnispfad die Eigenschaft, die die Middlewarefunktion zu `req` (dem Anforderungsobjekt) hinzufügt. + +```js +const express = require('express'); +const app = express(); + +const requestTime = function (req, res, next) { + req.requestTime = Date.now(); + next(); +}; + +app.use(requestTime); + +app.get('/', (req, res) => { + let responseText = 'Hello World!
    '; + responseText += `Requested at: ${req.requestTime}`; + res.send(responseText); +}); + +app.listen(3000); +``` + +Wenn Sie eine Anforderung zum Stammverzeichnis der Anwendung einleiten, zeigt die Anwendung nun die Zeitmarke Ihrer Anforderung im Browser an. + +

    Middleware function validateCookies

    + +Finally, we'll create a middleware function that validates incoming cookies and sends a 400 response if cookies are invalid. + +Here's an example function that validates cookies with an external async service. + +```js +async function cookieValidator(cookies) { + try { + await externallyValidateCookie(cookies.testCookie); + } catch { + throw new Error('Invalid cookies'); + } +} +``` + +Here, we use the [`cookie-parser`](/resources/middleware/cookie-parser.html) middleware to parse incoming cookies off the `req` object and pass them to our `cookieValidator` function. The `validateCookies` middleware returns a Promise that upon rejection will automatically trigger our error handler. + +```js +const express = require('express'); +const cookieParser = require('cookie-parser'); +const cookieValidator = require('./cookieValidator'); + +const app = express(); + +async function validateCookies(req, res, next) { + await cookieValidator(req.cookies); + next(); +} + +app.use(cookieParser()); + +app.use(validateCookies); + +// error handler +app.use((err, req, res, next) => { + res.status(400).send(err.message); +}); + +app.listen(3000); +``` + +
    +Note how `next()` is called after `await cookieValidator(req.cookies)`. This ensures that if `cookieValidator` resolves, the next middleware in the stack will get called. If you pass anything to the `next()` function (except the string `'route'` or `'router'`), Express regards the current request as being an error and will skip any remaining non-error handling routing and middleware functions. +
    + +Da Sie Zugriff auf das Anforderungsobjekt, das Antwortobjekt, die nächste Middlewarefunktion im Stack und die gesamte Node.js-API haben, sind die Möglichkeiten, die Sie mit Middlewarefunktionen haben, nahezu unendlich. + +Weitere Informationen zur Verwendung von Middleware in Express siehe [ Express-Middleware verwenden](/{{ page.lang }}/guide/using-middleware.html). + +

    Configurable middleware

    + +If you need your middleware to be configurable, export a function which accepts an options object or other parameters, which, then returns the middleware implementation based on the input parameters. + +File: `my-middleware.js` + +```js +module.exports = function (options) { + return function (req, res, next) { + // Implement the middleware function based on the options object + next(); + }; +}; +``` + +The middleware can now be used as shown below. + +```js +const mw = require('./my-middleware.js'); + +app.use(mw({ option1: '1', option2: '2' })); +``` + +Refer to [cookie-session](https://github.com/expressjs/cookie-session) and [compression](https://github.com/expressjs/compression) for examples of configurable middleware. diff --git a/astro/src/content/docs/de/5x/starter/basic-routing.md b/astro/src/content/docs/de/5x/starter/basic-routing.md new file mode 100644 index 0000000000..9742de59b7 --- /dev/null +++ b/astro/src/content/docs/de/5x/starter/basic-routing.md @@ -0,0 +1,63 @@ +--- +title: Basisrouting in Express +description: Learn the fundamentals of routing in Express.js applications, including how to define routes, handle HTTP methods, and create route handlers for your web server. +--- + +# Basisrouting + +Per _Routing_ wird bestimmt, wie eine Antwort auf eine Clientanforderung an einem bestimmten Endpunkt antwortet. Dies ist eine URI (oder ein Pfad) und eine bestimmte HTTP-Anforderungsmethode (GET, POST usw.). + +Jede Weiterleitung (Route) kann eine oder mehrere Handlerfunktionen haben, die ausgeführt werden, wenn die Weiterleitung abgeglichen wird. + +Weiterleitungsdefinitionen haben die folgende Struktur: + +```js +app.METHOD(PATH, HANDLER); +``` + +Where: + +- `app` ist eine Instanz von `express`. +- `METHOD` is an [HTTP request method](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Methods), in lowercase. +- `PATH` ist ein Pfad auf dem Server. +- `HANDLER` ist die Funktion, die ausgeführt wird, wenn die Weiterleitung abgeglichen wird. + +
    +In diesem Lernprogramm wird vorausgesetzt, dass eine Instanz von `express` namens `app` erstellt und der Server ausgeführt wird. Wenn Sie mit dem Erstellen und Starten von Anwendungen nicht vertraut sind, spielen Sie das [Beispiel "Hello World"](/{{ page.lang }}/starter/hello-world.html) durch. +
    + +Die folgenden Beispiele veranschaulichen das Definieren einfacher Weiterleitungen. + +Antworten Sie mit `Hello World!` auf der Homepage: + +```js +app.get('/', (req, res) => { + res.send('Hello World!'); +}); +``` + +Respond to a POST request on the root route (`/`), the application's home page: + +```js +app.post('/', (req, res) => { + res.send('Got a POST request'); +}); +``` + +Antworten Sie auf eine PUT-Anforderung zur Weiterleitung `/user`: + +```js +app.put('/user', (req, res) => { + res.send('Got a PUT request at /user'); +}); +``` + +Antworten Sie auf eine DELETE-Anforderung zur Weiterleitung `/user`: + +```js +app.delete('/user', (req, res) => { + res.send('Got a DELETE request at /user'); +}); +``` + +Details zum Thema Routing finden Sie in der entsprechenden [Routinganleitung](/{{ page.lang }}/guide/routing.html). diff --git a/astro/src/content/docs/de/5x/starter/examples.md b/astro/src/content/docs/de/5x/starter/examples.md new file mode 100644 index 0000000000..a25a6d9834 --- /dev/null +++ b/astro/src/content/docs/de/5x/starter/examples.md @@ -0,0 +1,16 @@ +--- +title: Express examples +description: Explore a collection of Express.js application examples covering various use cases, integrations, and advanced configurations to help you learn and build your projects. +--- + +{% capture examples %}{% include readmes/express-master/examples.md %}{% endcapture %} +{{ examples | replace: "](.", "](https://github.com/expressjs/express/tree/master/examples" }} + +## Additional examples + +These are some additional examples with more extensive integrations. + +{% include community-caveat.html %} + +- [prisma-fullstack](https://github.com/prisma/prisma-examples/tree/latest/pulse/fullstack-simple-chat) - Fullstack app with Express and Next.js using [Prisma](https://www.npmjs.com/package/prisma) as an ORM +- [prisma-rest-api-ts](https://github.com/prisma/prisma-examples/tree/latest/orm/express) - REST API with Express in TypeScript using [Prisma](https://www.npmjs.com/package/prisma) as an ORM diff --git a/astro/src/content/docs/de/5x/starter/faq.md b/astro/src/content/docs/de/5x/starter/faq.md new file mode 100644 index 0000000000..2f7dd8eff3 --- /dev/null +++ b/astro/src/content/docs/de/5x/starter/faq.md @@ -0,0 +1,75 @@ +--- +title: Häufig gestellte Fragen zu Express +description: Finden Sie Antworten auf häufig gestellte Fragen zu Express.js, darunter Themen wie Anwendungsstruktur, Models, Authentifizierung, Template-Engines, Fehlerbehandlung und mehr. +--- + +# Häufig gestellte Fragen + +## Wie muss ich meine Anwendung strukturieren? + +Auf diese Frage gibt es keine verbindliche Antwort. Die Antwort hängt vom Umfang Ihrer Anwendung und dem eingebundenen Team ab. Um so flexibel wie möglich zu sein, gibt es bei Express keine Voraussetzungen hinsichtlich der Struktur. + +Weiterleitungen und andere anwendungsspezifische Logik können in einer beliebigen Anzahl von Dateien und in jeder von Ihnen bevorzugten Verzeichnisstruktur vorkommen. Die folgenden Beispiele sollen als Entscheidungshilfe dienen: + +- [Weiterleitungslisten](https://github.com/expressjs/express/blob/4.13.1/examples/route-separation/index.js#L32-47) +- [Weiterleitungszuordnung](https://github.com/expressjs/express/blob/4.13.1/examples/route-map/index.js#L52-L66) +- [Controller im MVC-Stil](https://github.com/expressjs/express/tree/master/examples/mvc) + +Darüber hinaus gibt es Erweiterungen anderer Anbieter für Express, die zur Vereinfachung einiger dieser Muster beitragen: + +- [Weiterleitung mit "express-resource"](https://github.com/expressjs/express-resource) + +## Wie definiere ich Modelle? + +Express hat keine Vorstellungen von einer Datenbank. Dieses Konzept bleibt Node-Modulen anderer Anbieter überlassen, wodurch Schnittstellen zu allen Datenbank möglich sind. + +[LoopBack](http://loopback.io) zeigt ein Express-basiertes Framework, um das Modelle angeordnet sind. + +## Wie kann ich Benutzer authentifizieren? + +Die Authentifizierung ist ein weiterer meinungsstarker Bereich, in den Express nicht eingreift. Sie können ein Authentifizierungsschema nach Ihren Vorstellungen verwenden. +Ein einfaches Benutzername/Kennwort-Schema können Sie in [diesem Beispiel](https://github.com/expressjs/express/tree/master/examples/auth) sehen. + +## Welche Template-Engines unterstützt Express? + +Express unterstützt jede Template-Engine, die der `(path, locals, callback)`-Signatur entspricht. +Informationen zur Normalisierung von Template-Engine-Schnittstellen und -Caching siehe das Projekt [consolidate.js](https://github.com/visionmedia/consolidate.js). Nicht aufgelistete Template-Engines können trotzdem die Express-Signatur unterstützen. + +For more information, see [Using template engines with Express](/{{page.lang}}/guide/using-template-engines.html). + +## Wie handhabe ich 404-Antworten? + +In Express sind 404-Antworten nicht das Ergebnis eines Fehlers, sodass diese Antworten von der Fehlerbehandlungsroutine nicht erfasst werden. Dieses Verhalten ist damit zu erklären, dass eine 404-Antwort einfach angibt, dass keine weiteren Arbeiten auszuführen sind. In anderen Worten: Express hat alle Middlewarefunktionen und Weiterleitungen ausgeführt und festgestellt, dass keine Funktion eine Antwort zurückgegeben hat. Sie müssen also bei der Handhabung der 404-Antwort nur eine Middlewarefunktion am Ende des Stacks (unterhalb von allen anderen Funktionen) hinzufügen: + +```js +app.use((req, res, next) => { + res.status(404).send("Sorry can't find that!"); +}); +``` + +Add routes dynamically at runtime on an instance of `express.Router()` +so the routes are not superseded by a middleware function. + +## Wie richte ich eine Fehlerbehandlungsroutine ein? + +Middleware für die Fehlerbehandlung wird in derselben Weise definiert wie andere Middleware; außer dass sie vier anstatt drei Argumente aufweist. Dies gilt speziell bei der Signatur `(err, req, res, next)`: + +```js +app.use((err, req, res, next) => { + console.error(err.stack); + res.status(500).send('Something broke!'); +}); +``` + +Weitere Informationen siehe [Fehlerbehandlung](/{{ page.lang }}/guide/error-handling.html). + +## Wie gebe ich normales HTML-Format aus? + +Das ist nicht Ihre Aufgabe! Sie müssen kein HTML-Format mit der Funktion `res.render()` ausgeben. +Verwenden Sie die Funktion `res.sendFile()`, wenn Sie es mit einer bestimmten Datei zu tun haben. +Wenn Sie viele Assets aus einem Verzeichnis bedienen müssen, verwenden Sie die Middlewarefunktion `express.static()`. + +## Welche Version von Node.js benötigt Express? + +- [Express 4.x](/{{ page.lang }}/4x/api.html) requires Node.js 0.10 or higher. +- [Express 5.x](/{{ page.lang }}/5x/api.html) requires Node.js 18 or higher. diff --git a/astro/src/content/docs/de/5x/starter/generator.md b/astro/src/content/docs/de/5x/starter/generator.md new file mode 100644 index 0000000000..cf23c63154 --- /dev/null +++ b/astro/src/content/docs/de/5x/starter/generator.md @@ -0,0 +1,122 @@ +--- +title: Express-Anwendungsgenerator +description: Learn how to use the Express application generator tool to quickly create a skeleton for your Express.js applications, streamlining setup and configuration. +--- + +# Express-Anwendungsgenerator + +Mit dem Application Generator Tool `express` können Sie innerhalb kürzester Zeit ein Anwendungsgerüst erstellen. + +You can run the application generator with the `npx` command (available in Node.js 8.2.0). + +```bash +$ npx express-generator +``` + +For earlier Node versions, install the application generator as a global npm package and then launch it: + +```bash +$ npm install -g express-generator +$ express +``` + +Zeigen Sie die Befehlsoptionen mit der Option `-h` an: + +```bash +$ express -h + + Usage: express [options] [dir] + + Options: + + -h, --help output usage information + --version output the version number + -e, --ejs add ejs engine support + --hbs add handlebars engine support + --pug add pug engine support + -H, --hogan add hogan.js engine support + --no-view generate without view engine + -v, --view add view support (ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade) + -c, --css add stylesheet support (less|stylus|compass|sass) (defaults to plain css) + --git add .gitignore + -f, --force force on non-empty directory +``` + +Im folgenden Beispiel wird eine Express-Anwendung mit dem Namen _myapp_ im aktuellen Arbeitsverzeichnis erstellt: The app will be created in a folder named _myapp_ in the current working directory and the view engine will be set to Pug: + +```bash +$ express --view=pug myapp + + create : myapp + create : myapp/package.json + create : myapp/app.js + create : myapp/public + create : myapp/public/javascripts + create : myapp/public/images + create : myapp/routes + create : myapp/routes/index.js + create : myapp/routes/users.js + create : myapp/public/stylesheets + create : myapp/public/stylesheets/style.css + create : myapp/views + create : myapp/views/index.pug + create : myapp/views/layout.pug + create : myapp/views/error.pug + create : myapp/bin + create : myapp/bin/www +``` + +Installieren Sie dann Abhängigkeiten: + +```bash +$ cd myapp +$ npm install +``` + +Verwenden Sie unter Windows diesen Befehl: + +```bash +$ DEBUG=myapp:* npm start +``` + +Führen Sie unter MacOS oder Linux die Anwendung mit diesem Befehl aus: + +```bash +> set DEBUG=myapp:* & npm start +``` + +On Windows PowerShell, use this command: + +```bash +PS> $env:DEBUG='myapp:*'; npm start +``` + +Laden Sie dann `http://localhost:3000/` in Ihren Browser, um auf die Anwendung zuzugreifen. + +Die erstellte Anwendung hat die folgende Verzeichnisstruktur: + +```bash +. +├── app.js +├── bin +│ └── www +├── package.json +├── public +│ ├── images +│ ├── javascripts +│ └── stylesheets +│ └── style.css +├── routes +│ ├── index.js +│ └── users.js +└── views + ├── error.pug + ├── index.pug + └── layout.pug + +7 directories, 9 files +``` + +
    +Die vom Generator erstellte Anwendungsstruktur ist nur eine der vielen Möglichkeiten, Express-Anwendungen zu strukturieren. Sie können diese Struktur verwenden oder sie an Ihre Anforderungen anpassen. +
    diff --git a/astro/src/content/docs/de/5x/starter/hello-world.md b/astro/src/content/docs/de/5x/starter/hello-world.md new file mode 100644 index 0000000000..534ef7cd0a --- /dev/null +++ b/astro/src/content/docs/de/5x/starter/hello-world.md @@ -0,0 +1,42 @@ +--- +title: Beispiel "Hello World" in Express +description: Get started with Express.js by building a simple 'Hello World' application, demonstrating the basic setup and server creation for beginners. +--- + +# Beispiel "Hello World" + +
    +Dies ist wohl die einfachste Express-Anwendung, die Sie erstellen können. Es handelt sich um eine Anwendung mit nur einer Datei und — *nicht* das, was Sie mit dem [Express Generator](/{{ page.lang }}/starter/generator.html) erhalten würden. Mit dem Generator würde das Gerüst für eine vollständige Anwendung mit zahlreichen JavaScript-Dateien, Jade-Vorlagen und Unterverzeichnissen für verschiedene Zwecke erstellt werden. +
    + +```js +const express = require('express'); +const app = express(); +const port = 3000; + +app.get('/', (req, res) => { + res.send('Hello World!'); +}); + +app.listen(port, () => { + console.log(`Example app listening on port ${port}`); +}); +``` + +Die Anwendung startet einen Server und ist an Port 3000 empfangsbereit für Verbindungen. Die Anwendung antwortet mit "Hello World!" auf Anforderungen zur Stamm-URL (`/`) oder zu _route_. Bei jedem anderen Pfad lautet die Antwort **404 Not Found**. + +### Running Locally + +Erstellen Sie zunächst ein Verzeichnis namens `myapp`, wechseln Sie in das Verzeichnis und führen Sie `npm init` aus. Installieren Sie dann `express` als Abhängigkeit, wie im [Installationshandbuch](/{{ page.lang }}/starter/installing.html) beschrieben. + +Erstellen Sie im Verzeichnis `myapp` eine Datei namens `app.js` und fügen Sie den folgenden Code hinzu: + +
    `req` (Anforderung) und `res` (Antwort) sind genau dieselben Objekte, die Node bereitstellt. Sie können also `req.pipe()`, `req.on('data', callback)` und alle anderen Tasks, die Sie ausführen wollen, ohne Express ausführen.
    + +Führen Sie die Anwendung mit dem folgenden Befehl aus: + +```bash +$ node app.js +``` + +Laden Sie dann [http://localhost:3000/](http://localhost:3000/) in einen Browser, um die Ausgabe zu sehen. diff --git a/astro/src/content/docs/de/5x/starter/installing.md b/astro/src/content/docs/de/5x/starter/installing.md new file mode 100644 index 0000000000..8f8323f37d --- /dev/null +++ b/astro/src/content/docs/de/5x/starter/installing.md @@ -0,0 +1,48 @@ +--- +title: Express installieren +description: Erfahren Sie, wie Sie Express.js in Ihrer Node.js-Umgebung installieren, wie Sie Ihr Projektverzeichnis aufsetzen und Abhängigkeiten mit npm verwalten. +--- + +# Installation + +Angenommen, Sie haben [Node.js](https://nodejs.org/) bereits installiert. Erstellen Sie ein Verzeichnis für Ihre Anwendung und definieren Sie dieses Verzeichnis als Ihr Arbeitsverzeichnis. + +- [Express 4.x](/{{ page.lang }}/4x/api.html) requires Node.js 0.10 or higher. +- [Express 5.x](/{{ page.lang }}/5x/api.html) requires Node.js 18 or higher. + +```bash +$ mkdir myapp +$ cd myapp +``` + +Erstellen Sie mit dem Befehl `npm init` eine Datei namens `package.json` für Ihre Anwendung. +Weitere Informationen zur Funktionsweise von `package.json` finden Sie in den [Angaben zur Handhabung der npm-Datei package.json](https://docs.npmjs.com/files/package.json). + +```bash +$ npm init +``` + +Dieser Befehl fordert Sie zur Eingabe verschiedener Angaben wie Name und Version Ihrer Anwendung auf. +For now, you can simply hit RETURN to accept the defaults for most of them, with the following exception: + +``` +entry point: (index.js) +``` + +Geben Sie `app.js` oder einen Namen Ihrer Vorstellung als Namen für die Hauptdatei ein. Wenn dieser Name `index.js` lauten soll, drücken Sie die Eingabetaste, um den vorgeschlagenen Standarddateinamen zu akzeptieren. + +Installieren Sie jetzt Express im Verzeichnis `myapp` und speichern Sie es in der Abhängigkeitsliste. Beispiel: + +```bash +$ npm install express +``` + +Wenn Sie Express vorübergehend installieren und nicht zur Abhängigkeitsliste hinzufügen wollen, geben Sie die Option `--save` nicht an: + +```bash +$ npm install express --no-save +``` + +
    +Node-Module, die mit der Option `--save` installiert werden, werden zur `Abhängigkeitsliste` in der Datei `package.json` hinzugefügt. Danach werden bei der Ausführung von `npm install` im Verzeichnis `app` automatisch alle Module in der Abhängigkeitsliste installiert. +
    diff --git a/astro/src/content/docs/de/5x/starter/static-files.md b/astro/src/content/docs/de/5x/starter/static-files.md new file mode 100644 index 0000000000..30cd67fc22 --- /dev/null +++ b/astro/src/content/docs/de/5x/starter/static-files.md @@ -0,0 +1,74 @@ +--- +title: Statische Dateien in Express bereitstellen +description: Understand how to serve static files like images, CSS, and JavaScript in Express.js applications using the built-in 'static' middleware. +--- + +# Statische Dateien in Express bereitstellen + +Wenn Sie statische Dateien wie Bilder, CSS-Dateien und JavaScript-Dateien bereitstellen wollen, verwenden Sie die in Express integrierte Middlewarefunktion `express.static`. + +The function signature is: + +```js +express.static(root, [options]); +``` + +The `root` argument specifies the root directory from which to serve static assets. +For more information on the `options` argument, see [express.static](/{{page.lang}}/5x/api.html#express.static). + +Beispiel: Verwenden Sie den folgenden Code, um Bilder, CSS-Dateien und JavaScript-Dateien in einem Verzeichnis namens `public` bereitzustellen: + +```js +app.use(express.static('public')); +``` + +Jetzt können Sie die Dateien laden, die sich im Verzeichnis `public` befinden: + +```text +http://localhost:3000/images/kitten.jpg +http://localhost:3000/css/style.css +http://localhost:3000/js/app.js +http://localhost:3000/images/bg.png +http://localhost:3000/hello.html +``` + +
    Express sucht nach den Dateien, die sich auf das Verzeichnis mit den statischen Assets beziehen. Der Name dieses Verzeichnisses ist also nicht Teil der URL.
    + +Wenn Sie mehrere Verzeichnisse mit statischen Assets verwenden wollen, rufen Sie die Middlewarefunktion `express.static` mehrmals auf: + +```js +app.use(express.static('public')); +app.use(express.static('files')); +``` + +Express sucht in der Reihenfolge nach den Dateien, in der sie die Verzeichnisse mit den statischen Assets über die Middlewarefunktion `express.static` festgelegt haben. + +{% capture alert_content %} +For best results, [use a reverse proxy](/{{page.lang}}/advanced/best-practice-performance.html#use-a-reverse-proxy) cache to improve performance of serving static assets. +{% endcapture %} +{% include admonitions/note.html content=alert_content %} + +To create a virtual path prefix (where the path does not actually exist in the file system) for files that are served by the `express.static` function, [specify a mount path](/{{ page.lang }}/5x/api.html#app.use) for the static directory, as shown below: + +```js +app.use('/static', express.static('public')); +``` + +Jetzt können Sie die Dateien, die sich im Verzeichnis `public` befinden, aus dem Pfadpräfix `/static` laden. + +```text +http://localhost:3000/static/images/kitten.jpg +http://localhost:3000/static/css/style.css +http://localhost:3000/static/js/app.js +http://localhost:3000/static/images/bg.png +http://localhost:3000/static/hello.html +``` + +Der Pfad, den Sie für die Funktion `express.static` angeben, ist jedoch relativ zum Verzeichnis, aus dem Sie Ihren Prozess `node` starten. Wenn Sie die Express-Anwendung aus einem anderen Verzeichnis ausführen, ist es sicherer, den absoluten Pfad des Verzeichnisses zu verwenden, das Sie bereitstellen wollen: + +```js +const path = require('path'); +app.use('/static', express.static(path.join(__dirname, 'public'))); +``` + +For more details about the `serve-static` function and its options, see [serve-static](/resources/middleware/serve-static.html). diff --git a/astro/src/content/docs/es/3x/api.md b/astro/src/content/docs/es/3x/api.md new file mode 100644 index 0000000000..ef30a012d1 --- /dev/null +++ b/astro/src/content/docs/es/3x/api.md @@ -0,0 +1,23 @@ +--- +version: 3x +title: Express 3.x - Referencia de API +description: Access the API reference for Express.js version 3.x, noting that this version is end-of-life and no longer maintained - includes details on modules and methods. +--- + +
    + +
    + **Express 3.x YA NO SE MANTIENE** + +Los problemas de rendimiento y seguridad conocidos y desconocidos en 3.x no se han solucionado desde la última actualización (1 de agosto de 2015). Se recomienda especialmente utilizar la última versión de Express. + +If you are unable to upgrade past 3.x, please consider [Commercial Support Options](/{{ page.lang }}/support#commercial-support-options). + +
    + +

    API de 3.x

    + + +{% include api/en/3x/app.md %} + +
    diff --git a/astro/src/content/docs/es/4x/api.md b/astro/src/content/docs/es/4x/api.md new file mode 100644 index 0000000000..32f222a249 --- /dev/null +++ b/astro/src/content/docs/es/4x/api.md @@ -0,0 +1,26 @@ +--- +version: 4x +title: Express 4.x - Referencia de API +description: Access the API reference for Express.js 4.x, detailing all modules, methods, and properties for building web applications with this version. +--- + +
    + +

    API de 4.x

    + +{% capture node-version %} + +Express 4.0 requires Node.js 0.10 or higher. + +{% endcapture %} + +{% include admonitions/note.html content=node-version %} + + +{% include api/en/4x/express.md %} +{% include api/en/4x/app.md %} +{% include api/en/4x/req.md %} +{% include api/en/4x/res.md %} +{% include api/en/4x/router.md %} + +
    diff --git a/astro/src/content/docs/es/5x/api.md b/astro/src/content/docs/es/5x/api.md new file mode 100644 index 0000000000..8f4978f308 --- /dev/null +++ b/astro/src/content/docs/es/5x/api.md @@ -0,0 +1,26 @@ +--- +version: 5x +title: Express 5.x - Referencia de API +description: Access the API reference for Express.js 5.x, detailing all modules, methods, and properties for building web applications with this latest version. +--- + +
    + +

    5.x API

    + +{% capture node-version %} + +Express 5.0 requires Node.js 18 or higher. + +{% endcapture %} + +{% include admonitions/note.html content=node-version %} + + +{% include api/en/5x/express.md %} +{% include api/en/5x/app.md %} +{% include api/en/5x/req.md %} +{% include api/en/5x/res.md %} +{% include api/en/5x/router.md %} + +
    diff --git a/astro/src/content/docs/fr/3x/api.md b/astro/src/content/docs/fr/3x/api.md new file mode 100644 index 0000000000..f8d45340cc --- /dev/null +++ b/astro/src/content/docs/fr/3x/api.md @@ -0,0 +1,23 @@ +--- +version: 3x +title: Express 3.x - Référence de l'API +description: Access the API reference for Express.js version 3.x, noting that this version is end-of-life and no longer maintained - includes details on modules and methods. +--- + +
    + +
    + **Express 3.x N'EST PLUS PRIS EN CHARGE** + +Les problèmes de performances et de sécurité connus et inconnus n'ont pas été traités depuis la dernière mise à jour (1er août 2015). Il est fortement recommandé d'utiliser la dernière version d'Express. + +If you are unable to upgrade past 3.x, please consider [Commercial Support Options](/{{ page.lang }}/support#commercial-support-options). + +
    + +

    API 3.x

    + + +{% include api/en/3x/app.md %} + +
    diff --git a/astro/src/content/docs/fr/4x/api.md b/astro/src/content/docs/fr/4x/api.md new file mode 100644 index 0000000000..7e1c0c7d04 --- /dev/null +++ b/astro/src/content/docs/fr/4x/api.md @@ -0,0 +1,26 @@ +--- +version: 4x +title: Express 4.x - Référence de l'API +description: Access the API reference for Express.js 4.x, detailing all modules, methods, and properties for building web applications with this version. +--- + +
    + +

    API 4.x

    + +{% capture node-version %} + +Express 4.0 requires Node.js 0.10 or higher. + +{% endcapture %} + +{% include admonitions/note.html content=node-version %} + + +{% include api/en/4x/express.md %} +{% include api/en/4x/app.md %} +{% include api/en/4x/req.md %} +{% include api/en/4x/res.md %} +{% include api/en/4x/router.md %} + +
    diff --git a/astro/src/content/docs/fr/5x/api.md b/astro/src/content/docs/fr/5x/api.md new file mode 100644 index 0000000000..3ff3f0e991 --- /dev/null +++ b/astro/src/content/docs/fr/5x/api.md @@ -0,0 +1,26 @@ +--- +version: 5x +title: Express 5.x - Référence de l'API +description: Access the API reference for Express.js 5.x, detailing all modules, methods, and properties for building web applications with this latest version. +--- + +
    + +

    5.x API

    + +{% capture node-version %} + +Express 5.0 requires Node.js 18 or higher. + +{% endcapture %} + +{% include admonitions/note.html content=node-version %} + + +{% include api/en/5x/express.md %} +{% include api/en/5x/app.md %} +{% include api/en/5x/req.md %} +{% include api/en/5x/res.md %} +{% include api/en/5x/router.md %} + +
    diff --git a/astro/src/content/docs/it/3x/api.md b/astro/src/content/docs/it/3x/api.md new file mode 100644 index 0000000000..36a2ddc0e3 --- /dev/null +++ b/astro/src/content/docs/it/3x/api.md @@ -0,0 +1,23 @@ +--- +version: 3x +title: Express 3.x - Riferimento API +description: Access the API reference for Express.js version 3.x, noting that this version is end-of-life and no longer maintained - includes details on modules and methods. +--- + +
    + +
    + **Express 3.x NON È PIU' SUPPORTATO** + +I problemi noti e non noti relativi alla sicurezza presenti in 3.x non sono stati indirizzati dall'ultimo aggiornamento (1 agosto 2015). Si consiglia di utilizzare l'ultima versione di Express. + +If you are unable to upgrade past 3.x, please consider [Commercial Support Options](/{{ page.lang }}/support#commercial-support-options). + +
    + +

    API 3.x

    + + +{% include api/en/3x/app.md %} + +
    diff --git a/astro/src/content/docs/it/4x/api.md b/astro/src/content/docs/it/4x/api.md new file mode 100644 index 0000000000..684819a994 --- /dev/null +++ b/astro/src/content/docs/it/4x/api.md @@ -0,0 +1,26 @@ +--- +version: 4x +title: Express 4.x - Riferimento API +description: Access the API reference for Express.js 4.x, detailing all modules, methods, and properties for building web applications with this version. +--- + +
    + +

    API 4.x

    + +{% capture node-version %} + +Express 4.0 requires Node.js 0.10 or higher. + +{% endcapture %} + +{% include admonitions/note.html content=node-version %} + + +{% include api/en/4x/express.md %} +{% include api/en/4x/app.md %} +{% include api/en/4x/req.md %} +{% include api/en/4x/res.md %} +{% include api/en/4x/router.md %} + +
    diff --git a/astro/src/content/docs/it/5x/api.md b/astro/src/content/docs/it/5x/api.md new file mode 100644 index 0000000000..76f0822f91 --- /dev/null +++ b/astro/src/content/docs/it/5x/api.md @@ -0,0 +1,26 @@ +--- +version: 5x +title: Express 5.x - Riferimento API +description: Access the API reference for Express.js 5.x, detailing all modules, methods, and properties for building web applications with this latest version. +--- + +
    + +

    5.x API

    + +{% capture node-version %} + +Express 5.0 requires Node.js 18 or higher. + +{% endcapture %} + +{% include admonitions/note.html content=node-version %} + + +{% include api/en/5x/express.md %} +{% include api/en/5x/app.md %} +{% include api/en/5x/req.md %} +{% include api/en/5x/res.md %} +{% include api/en/5x/router.md %} + +
    diff --git a/astro/src/content/docs/ja/3x/api.md b/astro/src/content/docs/ja/3x/api.md new file mode 100644 index 0000000000..28b0f210f3 --- /dev/null +++ b/astro/src/content/docs/ja/3x/api.md @@ -0,0 +1,23 @@ +--- +version: 3x +title: Express 3.x - API リファレンス +description: Access the API reference for Express.js version 3.x, noting that this version is end-of-life and no longer maintained - includes details on modules and methods. +--- + +
    + +
    + **Express 3.x は保守されなくなりました** + +3.xの既知および未知のセキュリティ問題は、最終更新(2015年8月1日)以降は対処されていません。3.x系を使用することは安全であると見なされるべきではありません。 It is highly recommended to use the latest version of Express. + +If you are unable to upgrade past 3.x, please consider [Commercial Support Options](/{{ page.lang }}/support#commercial-support-options). + +
    + +

    3.x API

    + + +{% include api/en/3x/app.md %} + +
    diff --git a/astro/src/content/docs/ja/4x/api.md b/astro/src/content/docs/ja/4x/api.md new file mode 100644 index 0000000000..0a4c7888a1 --- /dev/null +++ b/astro/src/content/docs/ja/4x/api.md @@ -0,0 +1,26 @@ +--- +version: 4x +title: Express 4.x - API リファレンス +description: Access the API reference for Express.js 4.x, detailing all modules, methods, and properties for building web applications with this version. +--- + +
    + +

    4.x API

    + +{% capture node-version %} + +Express 4.0 requires Node.js 0.10 or higher. + +{% endcapture %} + +{% include admonitions/note.html content=node-version %} + + +{% include api/en/4x/express.md %} +{% include api/en/4x/app.md %} +{% include api/en/4x/req.md %} +{% include api/en/4x/res.md %} +{% include api/en/4x/router.md %} + +
    diff --git a/astro/src/content/docs/ja/5x/api.md b/astro/src/content/docs/ja/5x/api.md new file mode 100644 index 0000000000..978914721c --- /dev/null +++ b/astro/src/content/docs/ja/5x/api.md @@ -0,0 +1,26 @@ +--- +version: 5x +title: Express 5.x - API リファレンス +description: Access the API reference for Express.js 5.x, detailing all modules, methods, and properties for building web applications with this latest version. +--- + +
    + +

    5.x API

    + +{% capture node-version %} + +Express 5.0 requires Node.js 18 or higher. + +{% endcapture %} + +{% include admonitions/note.html content=node-version %} + + +{% include api/en/5x/express.md %} +{% include api/en/5x/app.md %} +{% include api/en/5x/req.md %} +{% include api/en/5x/res.md %} +{% include api/en/5x/router.md %} + +
    diff --git a/astro/src/content/docs/ko/3x/api.md b/astro/src/content/docs/ko/3x/api.md new file mode 100644 index 0000000000..271f82aca3 --- /dev/null +++ b/astro/src/content/docs/ko/3x/api.md @@ -0,0 +1,26 @@ +--- +version: 3x +title: Express 3.x - API 참조 +description: Express.js 3.x 버전의 API 참조에 접근할 수 있습니다. 이 버전은 지원이 종료되었으며 더 이상 유지보수되지 않습니다. 모듈과 메소드에 대한 상세한 정보가 포함되어 있습니다. +--- + +
    + +
    + **Express 3.x은 더 이상 유지보수되지 않습니다.** + +3.x의 알려진 또는 알려지지 않은 보안 및 성능 문제는 마지막 업데이트(2015년 8월 1일) 이후로 처리되지 않고 있습니다. 최신 버전의 Express를 사용할 것을 강력히 권장합니다. + +버전 3.x 이상으로 업그레이드할 수 없는 경우, [상업적 지원 옵션](/{{ page.lang }}/support#commercial-support-options)을 고려해주시기 바랍니다. + +
    + +

    3.x API

    + +{% include api/en/3x/express.md %} +{% include api/en/3x/app.md %} +{% include api/en/3x/req.md %} +{% include api/en/3x/res.md %} +{% include api/en/3x/middleware.md %} + +
    diff --git a/astro/src/content/docs/ko/4x/api.md b/astro/src/content/docs/ko/4x/api.md new file mode 100644 index 0000000000..d6bb85d431 --- /dev/null +++ b/astro/src/content/docs/ko/4x/api.md @@ -0,0 +1,26 @@ +--- +version: 4x +title: Express 4.x - API 참조 +description: Express.js 4.x의 API 레퍼런스를 확인하여, 이 버전으로 웹 애플리케이션을 구축할 때 사용할 수 있는 모든 모듈, 메서드, 속성에 대해 자세히 알아봅니다. +--- + +
    + +

    4.x API

    + +{% capture node-version %} + +Express 4.0에는 Node.js 0.10 이상이 필요합니다. + +{% endcapture %} + +{% include admonitions/note.html content=node-version %} + + +{% include api/en/4x/express.md %} +{% include api/en/4x/app.md %} +{% include api/en/4x/req.md %} +{% include api/en/4x/res.md %} +{% include api/en/4x/router.md %} + +
    diff --git a/astro/src/content/docs/ko/5x/api.md b/astro/src/content/docs/ko/5x/api.md new file mode 100644 index 0000000000..41a0efb560 --- /dev/null +++ b/astro/src/content/docs/ko/5x/api.md @@ -0,0 +1,26 @@ +--- +version: 5x +title: Express 5.x - API 참조 +description: Express.js 5.x의 API 레퍼런스를 확인하여, 이 버전으로 웹 애플리케이션을 구축할 때 사용할 수 있는 모든 모듈, 메서드, 속성에 대해 자세히 알아봅니다. +--- + +
    + +

    5.x API

    + +{% capture node-version %} + +Express 5.0에는 Node.js 18 이상이 필요합니다. + +{% endcapture %} + +{% include admonitions/note.html content=node-version %} + + +{% include api/en/5x/express.md %} +{% include api/en/5x/app.md %} +{% include api/en/5x/req.md %} +{% include api/en/5x/res.md %} +{% include api/en/5x/router.md %} + +
    diff --git a/astro/src/content/docs/pt-br/3x/api.md b/astro/src/content/docs/pt-br/3x/api.md new file mode 100644 index 0000000000..a3337ccaaf --- /dev/null +++ b/astro/src/content/docs/pt-br/3x/api.md @@ -0,0 +1,23 @@ +--- +version: 3x +title: Express 3.x - Referência de API +description: Acesso à referência da API do Express.js versão 3.x, observando que esta versão é final de vida e não mais mantida - inclui detalhes sobre módulos e métodos. +--- + +
    + +
    + **Express 3.x support is ending soon** + +This series will continue to receive only security updates and bug fixes until July 2015. It is highly recommended to upgrade to Express 4.x. + +Se você não puder atualizar as últimas 3.x, por favor considere as [Opções de Suporte Comercial](/{{ page.lang }}/support#comercial-support-options). + +
    + +

    3.x API

    + + +{% include api/en/3x/app.md %} + +
    diff --git a/astro/src/content/docs/pt-br/4x/api.md b/astro/src/content/docs/pt-br/4x/api.md new file mode 100644 index 0000000000..6b40fd947f --- /dev/null +++ b/astro/src/content/docs/pt-br/4x/api.md @@ -0,0 +1,26 @@ +--- +version: 4x +title: Express 4.x - Referência de API +description: Acesse a referência da API para Express.js 4.x, detalhando todos os módulos, métodos e propriedades para construir aplicações web com esta versão. +--- + +
    + +

    API 4.x

    + +{% capture node-version %} + +Express 4.0 requer Node.js 0.10 ou superior. + +{% endcapture %} + +{% include admonitions/note.html content=node-version %} + + +{% include api/en/4x/express.md %} +{% include api/en/4x/app.md %} +{% include api/en/4x/req.md %} +{% include api/en/4x/res.md %} +{% include api/en/4x/router.md %} + +
    diff --git a/astro/src/content/docs/pt-br/5x/api.md b/astro/src/content/docs/pt-br/5x/api.md new file mode 100644 index 0000000000..28692618b7 --- /dev/null +++ b/astro/src/content/docs/pt-br/5x/api.md @@ -0,0 +1,26 @@ +--- +version: 5x +title: Express 5.x - Referência da API +description: Acesse a referência da API para Express.js 5.x, detalhando todos os módulos, métodos e propriedades para construir aplicações web com esta versão mais recente. +--- + +
    + +

    5.x API

    + +{% capture node-version %} + +Express 5.0 requer Node.js 18 ou superior. + +{% endcapture %} + +{% include admonitions/note.html content=node-version %} + + +{% include api/en/5x/express.md %} +{% include api/en/5x/app.md %} +{% include api/en/5x/req.md %} +{% include api/en/5x/res.md %} +{% include api/en/5x/router.md %} + +
    diff --git a/astro/src/content/docs/zh-cn/3x/api.md b/astro/src/content/docs/zh-cn/3x/api.md new file mode 100644 index 0000000000..734834df57 --- /dev/null +++ b/astro/src/content/docs/zh-cn/3x/api.md @@ -0,0 +1,23 @@ +--- +version: 3x +title: Express 3.x - API 参考 +description: Access the API reference for Express.js version 3.x, noting that this version is end-of-life and no longer maintained - includes details on modules and methods. +--- + +
    + +
    + **Express 3.x 不再受到维护** + +Known and unknown security and performance issues in 3.x have not been addressed since the last update (1 August, 2015). It is highly recommended to use the latest version of Express. + +If you are unable to upgrade past 3.x, please consider [Commercial Support Options](/{{ page.lang }}/support#commercial-support-options). + +
    + +

    3.x API

    + + +{% include api/en/3x/app.md %} + +
    diff --git a/astro/src/content/docs/zh-cn/4x/api.md b/astro/src/content/docs/zh-cn/4x/api.md new file mode 100644 index 0000000000..a504c0acc3 --- /dev/null +++ b/astro/src/content/docs/zh-cn/4x/api.md @@ -0,0 +1,26 @@ +--- +version: 4x +title: Express 4.x - API 参考 +description: Access the API reference for Express.js 4.x, detailing all modules, methods, and properties for building web applications with this version. +--- + +
    + +

    4.x API

    + +{% capture node-version %} + +Express 4.0 requires Node.js 0.10 or higher. + +{% endcapture %} + +{% include admonitions/note.html content=node-version %} + + +{% include api/en/4x/express.md %} +{% include api/en/4x/app.md %} +{% include api/en/4x/req.md %} +{% include api/en/4x/res.md %} +{% include api/en/4x/router.md %} + +
    diff --git a/astro/src/content/docs/zh-cn/5x/api.md b/astro/src/content/docs/zh-cn/5x/api.md new file mode 100644 index 0000000000..13d67f0666 --- /dev/null +++ b/astro/src/content/docs/zh-cn/5x/api.md @@ -0,0 +1,26 @@ +--- +version: 5x +title: Express 5.x - API 参考 +description: Access the API reference for Express.js 5.x, detailing all modules, methods, and properties for building web applications with this latest version. +--- + +
    + +

    5.x API

    + +{% capture node-version %} + +Express 5.0 requires Node.js 18 or higher. + +{% endcapture %} + +{% include admonitions/note.html content=node-version %} + + +{% include api/en/5x/express.md %} +{% include api/en/5x/app.md %} +{% include api/en/5x/req.md %} +{% include api/en/5x/res.md %} +{% include api/en/5x/router.md %} + +
    diff --git a/astro/src/content/docs/zh-tw/3x/api.md b/astro/src/content/docs/zh-tw/3x/api.md new file mode 100644 index 0000000000..b6a66321a2 --- /dev/null +++ b/astro/src/content/docs/zh-tw/3x/api.md @@ -0,0 +1,23 @@ +--- +version: 3x +title: Express 3.x - API 參照 +description: Access the API reference for Express.js version 3.x, noting that this version is end-of-life and no longer maintained - includes details on modules and methods. +--- + +
    + +
    + **Express 3.x 已不再維護** + +Known and unknown security and performance issues in 3.x have not been addressed since the last update (1 August, 2015). It is highly recommended to use the latest version of Express. + +If you are unable to upgrade past 3.x, please consider [Commercial Support Options](/{{ page.lang }}/support#commercial-support-options). + +
    + +

    3.x API

    + + +{% include api/en/3x/app.md %} + +
    diff --git a/astro/src/content/docs/zh-tw/4x/api.md b/astro/src/content/docs/zh-tw/4x/api.md new file mode 100644 index 0000000000..0846c8f06d --- /dev/null +++ b/astro/src/content/docs/zh-tw/4x/api.md @@ -0,0 +1,26 @@ +--- +version: 4x +title: Express 4.x - API 參照 +description: Access the API reference for Express.js 4.x, detailing all modules, methods, and properties for building web applications with this version. +--- + +
    + +

    4.x API

    + +{% capture node-version %} + +Express 4.0 requires Node.js 0.10 or higher. + +{% endcapture %} + +{% include admonitions/note.html content=node-version %} + + +{% include api/en/4x/express.md %} +{% include api/en/4x/app.md %} +{% include api/en/4x/req.md %} +{% include api/en/4x/res.md %} +{% include api/en/4x/router.md %} + +
    diff --git a/astro/src/content/docs/zh-tw/5x/api.md b/astro/src/content/docs/zh-tw/5x/api.md new file mode 100644 index 0000000000..857895824e --- /dev/null +++ b/astro/src/content/docs/zh-tw/5x/api.md @@ -0,0 +1,26 @@ +--- +version: 5x +title: Express 5.x - API 參照 +description: Access the API reference for Express.js 5.x, detailing all modules, methods, and properties for building web applications with this latest version. +--- + +
    + +

    5.x API

    + +{% capture node-version %} + +Express 5.0 requires Node.js 18 or higher. + +{% endcapture %} + +{% include admonitions/note.html content=node-version %} + + +{% include api/en/5x/express.md %} +{% include api/en/5x/app.md %} +{% include api/en/5x/req.md %} +{% include api/en/5x/res.md %} +{% include api/en/5x/router.md %} + +
    diff --git a/astro/src/i18n/locales.ts b/astro/src/i18n/locales.ts new file mode 100644 index 0000000000..79ed73d631 --- /dev/null +++ b/astro/src/i18n/locales.ts @@ -0,0 +1,45 @@ +import en from './ui/en.json'; +import fr from './ui/fr.json'; +import de from './ui/de.json'; +import es from './ui/es.json'; +import it from './ui/it.json'; +import ja from './ui/ja.json'; +import ko from './ui/ko.json'; +import ptBr from './ui/pt-br.json'; +import zhCn from './ui/zh-cn.json'; +import zhTw from './ui/zh-tw.json'; + +export const languages = { + en: { label: 'English', direction: 'ltr' }, + de: { label: 'Deutsch', direction: 'ltr' }, + es: { label: 'Español', direction: 'ltr' }, + fr: { label: 'Français', direction: 'ltr' }, + it: { label: 'Italiano', direction: 'ltr' }, + ja: { label: '日本語', direction: 'ltr' }, + ko: { label: '한국어', direction: 'ltr' }, + 'pt-br': { label: 'Português', direction: 'ltr' }, + 'zh-cn': { label: '简体中文', direction: 'ltr' }, + 'zh-tw': { label: '繁體中文', direction: 'ltr' }, +} as const; + +export type LanguageCode = keyof typeof languages; + +export const languagesArray = Object.entries(languages).map(([code, obj]) => ({ + code, + label: obj.label, +})); + +export const defaultLang = 'en'; + +export const ui = { + en, + fr, + de, + es, + it, + ja, + ko, + 'pt-br': ptBr, + 'zh-cn': zhCn, + 'zh-tw': zhTw, +} as const; diff --git a/astro/src/i18n/ui.ts b/astro/src/i18n/ui.ts deleted file mode 100644 index 0bb540de77..0000000000 --- a/astro/src/i18n/ui.ts +++ /dev/null @@ -1,15 +0,0 @@ -export const languages = { - en: 'English', - fr: 'Français', -}; - -export const defaultLang = 'en'; - -export const ui = { - en: { - 'home.welcome': 'Welcome', - }, - fr: { - 'home.welcome': 'Bienvenue', - }, -} as const; diff --git a/astro/src/i18n/ui/de.json b/astro/src/i18n/ui/de.json new file mode 100644 index 0000000000..91eceeb47f --- /dev/null +++ b/astro/src/i18n/ui/de.json @@ -0,0 +1,75 @@ +{ + "home.welcome": "Willkommen", + "home.workInProgress": "Dies ist eine Work-in-Progress-Homepage.", + "home.reviewDesignSystemPrefix": "Sehen Sie sich die", + "home.reviewDesignSystemLink": "Designsystem-Grundlagen", + "home.reviewDesignSystemSuffix": "Demoseite an, um alle Tokens, Primitiven und Muster zu erkunden.", + "search.placeholder": "Tippen Sie, um zu suchen...", + "search.ariaLabel": "Suchen oder eine Frage stellen", + "theme.toggle": "Theme umschalten", + "theme.switchToLight": "Zum hellen Modus wechseln", + "theme.switchToDark": "Zum dunklen Modus wechseln", + "version.selectLabel": "API-Version auswählen", + "nav.mainMenu": "Hauptmenü", + "nav.toggleMenu": "Menü umschalten", + "nav.home": "Express-Startseite", + "nav.breadcrumb": "Breadcrumb", + "nav.mainNavigation": "Hauptnavigation", + "nav.selectVersion": "Dokumentationsversion auswählen", + "menu.docs": "Docs", + "menu.docsAria": "Dokumentation", + "menu.api": "API", + "menu.apiAria": "API-Referenz", + "menu.resources": "Ressourcen", + "menu.resourcesAria": "Ressourcen", + "menu.blog": "Blog", + "menu.blogAria": "Blog", + "menu.support": "Support", + "menu.supportAria": "Support", + "menu.gettingStarted": "Erste Schritte", + "menu.installing": "Installation", + "menu.installingAria": "Express installieren", + "menu.helloWorld": "Hello World", + "menu.helloWorldAria": "Hello-World-Beispiel", + "menu.expressGenerator": "Express-Generator", + "menu.expressGeneratorAria": "Express-Generator", + "menu.guide": "Leitfaden", + "menu.routing": "Routing", + "menu.routingAria": "Routing-Leitfaden", + "menu.writingMiddleware": "Middleware schreiben", + "menu.writingMiddlewareAria": "Middleware-Schreiben-Leitfaden", + "menu.usingMiddleware": "Middleware verwenden", + "menu.usingMiddlewareAria": "Middleware-Verwendungs-Leitfaden", + "menu.advancedTopics": "Fortgeschrittene Themen", + "menu.buildingTemplateEngines": "Template-Engines erstellen", + "menu.buildingTemplateEnginesAria": "Template-Engines-Erstellen-Leitfaden", + "menu.overview": "Übersicht", + "menu.overviewAria": "Übersicht", + "menu.application": "Anwendung", + "menu.applicationOverviewAria": "Anwendungsübersicht", + "menu.properties": "Eigenschaften", + "menu.applicationPropertiesAria": "Anwendungseigenschaften", + "menu.methods": "Methoden", + "menu.applicationMethodsAria": "Anwendungsmethoden", + "menu.request": "Request", + "menu.requestOverviewAria": "Request-Übersicht", + "menu.requestPropertiesAria": "Request-Eigenschaften", + "menu.response": "Response", + "menu.responseOverviewAria": "Response-Übersicht", + "menu.responsePropertiesAria": "Response-Eigenschaften", + "menu.router": "Router", + "menu.routerOverviewAria": "Router-Übersicht", + "menu.routerMethodsAria": "Router-Methoden", + "menu.community": "Community", + "menu.communityAria": "Community-Ressourcen", + "menu.glossary": "Glossar", + "menu.glossaryAria": "Glossar der Begriffe", + "menu.middleware": "Middleware", + "menu.middlewareAria": "Middleware-Ressourcen", + "menu.middlewareOverviewAria": "Middleware-Übersicht", + "404.title": "404 - Seite nicht gefunden", + "404.description": "Die gesuchte Seite konnte nicht gefunden werden.", + "404.heading": "Seite nicht gefunden", + "404.message": "Die gesuchte Seite existiert nicht oder wurde verschoben.", + "404.goHome": "Zur Startseite" +} diff --git a/astro/src/i18n/ui/en.json b/astro/src/i18n/ui/en.json new file mode 100644 index 0000000000..79799945d4 --- /dev/null +++ b/astro/src/i18n/ui/en.json @@ -0,0 +1,75 @@ +{ + "home.welcome": "Welcome", + "home.workInProgress": "This is a work-in-progress homepage.", + "home.reviewDesignSystemPrefix": "Review the", + "home.reviewDesignSystemLink": "Design System Foundations", + "home.reviewDesignSystemSuffix": "demo page to explore all tokens, primitives, and patterns.", + "search.placeholder": "Start typing...", + "search.ariaLabel": "Search or ask a question", + "theme.toggle": "Toggle theme", + "theme.switchToLight": "Switch to light mode", + "theme.switchToDark": "Switch to dark mode", + "version.selectLabel": "Select API version", + "nav.mainMenu": "Main menu", + "nav.toggleMenu": "Toggle menu", + "nav.home": "Express home", + "nav.breadcrumb": "Breadcrumb", + "nav.mainNavigation": "Main navigation", + "nav.selectVersion": "Select documentation version", + "menu.docs": "Docs", + "menu.docsAria": "Documentation", + "menu.api": "API", + "menu.apiAria": "API Reference", + "menu.resources": "Resources", + "menu.resourcesAria": "Resources", + "menu.blog": "Blog", + "menu.blogAria": "Blog", + "menu.support": "Support", + "menu.supportAria": "Support", + "menu.gettingStarted": "Getting started", + "menu.installing": "Installing", + "menu.installingAria": "Installing Express", + "menu.helloWorld": "Hello world", + "menu.helloWorldAria": "Hello world example", + "menu.expressGenerator": "Express generator", + "menu.expressGeneratorAria": "Express generator", + "menu.guide": "Guide", + "menu.routing": "Routing", + "menu.routingAria": "Routing guide", + "menu.writingMiddleware": "Writing middleware", + "menu.writingMiddlewareAria": "Writing middleware guide", + "menu.usingMiddleware": "Using middleware", + "menu.usingMiddlewareAria": "Using middleware guide", + "menu.advancedTopics": "Advanced topics", + "menu.buildingTemplateEngines": "Building template engines", + "menu.buildingTemplateEnginesAria": "Building template engines guide", + "menu.overview": "Overview", + "menu.overviewAria": "Overview", + "menu.application": "Application", + "menu.applicationOverviewAria": "Application overview", + "menu.properties": "Properties", + "menu.applicationPropertiesAria": "Application properties", + "menu.methods": "Methods", + "menu.applicationMethodsAria": "Application methods", + "menu.request": "Request", + "menu.requestOverviewAria": "Request overview", + "menu.requestPropertiesAria": "Request properties", + "menu.response": "Response", + "menu.responseOverviewAria": "Response overview", + "menu.responsePropertiesAria": "Response properties", + "menu.router": "Router", + "menu.routerOverviewAria": "Router overview", + "menu.routerMethodsAria": "Router methods", + "menu.community": "Community", + "menu.communityAria": "Community resources", + "menu.glossary": "Glossary", + "menu.glossaryAria": "Glossary of terms", + "menu.middleware": "Middleware", + "menu.middlewareAria": "Middleware resources", + "menu.middlewareOverviewAria": "Middleware overview", + "404.title": "404 - Page Not Found", + "404.description": "The page you are looking for could not be found.", + "404.heading": "Page Not Found", + "404.message": "The page you are looking for does not exist or has been moved.", + "404.goHome": "Go to Home" +} diff --git a/astro/src/i18n/ui/es.json b/astro/src/i18n/ui/es.json new file mode 100644 index 0000000000..c55c5644b3 --- /dev/null +++ b/astro/src/i18n/ui/es.json @@ -0,0 +1,75 @@ +{ + "home.welcome": "Bienvenido", + "home.workInProgress": "Esta es una página de inicio en desarrollo.", + "home.reviewDesignSystemPrefix": "Revisa la página de demostración de", + "home.reviewDesignSystemLink": "Fundamentos del Sistema de Diseño", + "home.reviewDesignSystemSuffix": "para explorar todos los tokens, primitivas y patrones.", + "search.placeholder": "Empieza a escribir...", + "search.ariaLabel": "Buscar o hacer una pregunta", + "theme.toggle": "Cambiar tema", + "theme.switchToLight": "Cambiar a modo claro", + "theme.switchToDark": "Cambiar a modo oscuro", + "version.selectLabel": "Seleccionar versión de API", + "nav.mainMenu": "Menú principal", + "nav.toggleMenu": "Alternar menú", + "nav.home": "Inicio de Express", + "nav.breadcrumb": "Breadcrumb", + "nav.mainNavigation": "Navegación principal", + "nav.selectVersion": "Seleccionar versión de documentación", + "menu.docs": "Docs", + "menu.docsAria": "Documentación", + "menu.api": "API", + "menu.apiAria": "Referencia API", + "menu.resources": "Recursos", + "menu.resourcesAria": "Recursos", + "menu.blog": "Blog", + "menu.blogAria": "Blog", + "menu.support": "Soporte", + "menu.supportAria": "Soporte", + "menu.gettingStarted": "Primeros pasos", + "menu.installing": "Instalación", + "menu.installingAria": "Instalar Express", + "menu.helloWorld": "Hello World", + "menu.helloWorldAria": "Ejemplo Hello World", + "menu.expressGenerator": "Generador Express", + "menu.expressGeneratorAria": "Generador Express", + "menu.guide": "Guía", + "menu.routing": "Enrutamiento", + "menu.routingAria": "Guía de enrutamiento", + "menu.writingMiddleware": "Escribir middleware", + "menu.writingMiddlewareAria": "Guía para escribir middleware", + "menu.usingMiddleware": "Usar middleware", + "menu.usingMiddlewareAria": "Guía de uso de middleware", + "menu.advancedTopics": "Temas avanzados", + "menu.buildingTemplateEngines": "Crear motores de plantillas", + "menu.buildingTemplateEnginesAria": "Guía para crear motores de plantillas", + "menu.overview": "Descripción general", + "menu.overviewAria": "Descripción general", + "menu.application": "Aplicación", + "menu.applicationOverviewAria": "Descripción general de la aplicación", + "menu.properties": "Propiedades", + "menu.applicationPropertiesAria": "Propiedades de la aplicación", + "menu.methods": "Métodos", + "menu.applicationMethodsAria": "Métodos de la aplicación", + "menu.request": "Request", + "menu.requestOverviewAria": "Descripción general de Request", + "menu.requestPropertiesAria": "Propiedades de Request", + "menu.response": "Response", + "menu.responseOverviewAria": "Descripción general de Response", + "menu.responsePropertiesAria": "Propiedades de Response", + "menu.router": "Router", + "menu.routerOverviewAria": "Descripción general del Router", + "menu.routerMethodsAria": "Métodos del Router", + "menu.community": "Comunidad", + "menu.communityAria": "Recursos de la comunidad", + "menu.glossary": "Glosario", + "menu.glossaryAria": "Glosario de términos", + "menu.middleware": "Middleware", + "menu.middlewareAria": "Recursos de middleware", + "menu.middlewareOverviewAria": "Descripción general de middleware", + "404.title": "404 - Página no encontrada", + "404.description": "La página que buscas no se pudo encontrar.", + "404.heading": "Página no encontrada", + "404.message": "La página que buscas no existe o ha sido movida.", + "404.goHome": "Ir a inicio" +} diff --git a/astro/src/i18n/ui/fr.json b/astro/src/i18n/ui/fr.json new file mode 100644 index 0000000000..f0cbb56e57 --- /dev/null +++ b/astro/src/i18n/ui/fr.json @@ -0,0 +1,75 @@ +{ + "home.welcome": "Bienvenue", + "home.workInProgress": "Ceci est une page d'accueil en cours de développement.", + "home.reviewDesignSystemPrefix": "Consultez la page de démonstration des", + "home.reviewDesignSystemLink": "fondamentaux du système de design", + "home.reviewDesignSystemSuffix": "pour explorer tous les tokens, primitives et motifs.", + "search.placeholder": "Commencez à taper...", + "search.ariaLabel": "Rechercher ou poser une question", + "theme.toggle": "Changer de thème", + "theme.switchToLight": "Passer en mode clair", + "theme.switchToDark": "Passer en mode sombre", + "version.selectLabel": "Sélectionner la version de l'API", + "nav.mainMenu": "Menu principal", + "nav.toggleMenu": "Basculer le menu", + "nav.home": "Accueil Express", + "nav.breadcrumb": "Fil d'Ariane", + "nav.mainNavigation": "Navigation principale", + "nav.selectVersion": "Sélectionner la version de la documentation", + "menu.docs": "Docs", + "menu.docsAria": "Documentation", + "menu.api": "API", + "menu.apiAria": "Référence API", + "menu.resources": "Ressources", + "menu.resourcesAria": "Ressources", + "menu.blog": "Blog", + "menu.blogAria": "Blog", + "menu.support": "Support", + "menu.supportAria": "Support", + "menu.gettingStarted": "Démarrage", + "menu.installing": "Installation", + "menu.installingAria": "Installer Express", + "menu.helloWorld": "Hello World", + "menu.helloWorldAria": "Exemple Hello World", + "menu.expressGenerator": "Générateur Express", + "menu.expressGeneratorAria": "Générateur Express", + "menu.guide": "Guide", + "menu.routing": "Routage", + "menu.routingAria": "Guide de routage", + "menu.writingMiddleware": "Écrire un middleware", + "menu.writingMiddlewareAria": "Guide d'écriture de middleware", + "menu.usingMiddleware": "Utiliser un middleware", + "menu.usingMiddlewareAria": "Guide d'utilisation de middleware", + "menu.advancedTopics": "Sujets avancés", + "menu.buildingTemplateEngines": "Créer des moteurs de templates", + "menu.buildingTemplateEnginesAria": "Guide de création de moteurs de templates", + "menu.overview": "Aperçu", + "menu.overviewAria": "Aperçu", + "menu.application": "Application", + "menu.applicationOverviewAria": "Aperçu de l'application", + "menu.properties": "Propriétés", + "menu.applicationPropertiesAria": "Propriétés de l'application", + "menu.methods": "Méthodes", + "menu.applicationMethodsAria": "Méthodes de l'application", + "menu.request": "Request", + "menu.requestOverviewAria": "Aperçu de Request", + "menu.requestPropertiesAria": "Propriétés de Request", + "menu.response": "Response", + "menu.responseOverviewAria": "Aperçu de Response", + "menu.responsePropertiesAria": "Propriétés de Response", + "menu.router": "Router", + "menu.routerOverviewAria": "Aperçu du Router", + "menu.routerMethodsAria": "Méthodes du Router", + "menu.community": "Communauté", + "menu.communityAria": "Ressources de la communauté", + "menu.glossary": "Glossaire", + "menu.glossaryAria": "Glossaire des termes", + "menu.middleware": "Middleware", + "menu.middlewareAria": "Ressources middleware", + "menu.middlewareOverviewAria": "Aperçu du middleware", + "404.title": "404 - Page non trouvée", + "404.description": "La page que vous recherchez est introuvable.", + "404.heading": "Page non trouvée", + "404.message": "La page que vous recherchez n'existe pas ou a été déplacée.", + "404.goHome": "Aller à l'accueil" +} diff --git a/astro/src/i18n/ui/it.json b/astro/src/i18n/ui/it.json new file mode 100644 index 0000000000..765fe1e107 --- /dev/null +++ b/astro/src/i18n/ui/it.json @@ -0,0 +1,75 @@ +{ + "home.welcome": "Benvenuto", + "home.workInProgress": "Questa è una homepage in fase di sviluppo.", + "home.reviewDesignSystemPrefix": "Rivedi la pagina di dimostrazione dei", + "home.reviewDesignSystemLink": "fondamenti del sistema di design", + "home.reviewDesignSystemSuffix": "per esplorare tutti i token, le primitive e i pattern.", + "search.placeholder": "Inizia a digitare...", + "search.ariaLabel": "Cerca o fai una domanda", + "theme.toggle": "Cambia tema", + "theme.switchToLight": "Passa alla modalità chiara", + "theme.switchToDark": "Passa alla modalità scura", + "version.selectLabel": "Seleziona versione API", + "nav.mainMenu": "Menu principale", + "nav.toggleMenu": "Attiva/disattiva menu", + "nav.home": "Home di Express", + "nav.breadcrumb": "Breadcrumb", + "nav.mainNavigation": "Navigazione principale", + "nav.selectVersion": "Seleziona versione documentazione", + "menu.docs": "Docs", + "menu.docsAria": "Documentazione", + "menu.api": "API", + "menu.apiAria": "Riferimento API", + "menu.resources": "Risorse", + "menu.resourcesAria": "Risorse", + "menu.blog": "Blog", + "menu.blogAria": "Blog", + "menu.support": "Supporto", + "menu.supportAria": "Supporto", + "menu.gettingStarted": "Per iniziare", + "menu.installing": "Installazione", + "menu.installingAria": "Installare Express", + "menu.helloWorld": "Hello World", + "menu.helloWorldAria": "Esempio Hello World", + "menu.expressGenerator": "Generatore Express", + "menu.expressGeneratorAria": "Generatore Express", + "menu.guide": "Guida", + "menu.routing": "Routing", + "menu.routingAria": "Guida al routing", + "menu.writingMiddleware": "Scrivere middleware", + "menu.writingMiddlewareAria": "Guida alla scrittura middleware", + "menu.usingMiddleware": "Usare middleware", + "menu.usingMiddlewareAria": "Guida all'uso middleware", + "menu.advancedTopics": "Argomenti avanzati", + "menu.buildingTemplateEngines": "Creare motori di template", + "menu.buildingTemplateEnginesAria": "Guida alla creazione di motori di template", + "menu.overview": "Panoramica", + "menu.overviewAria": "Panoramica", + "menu.application": "Applicazione", + "menu.applicationOverviewAria": "Panoramica dell'applicazione", + "menu.properties": "Proprietà", + "menu.applicationPropertiesAria": "Proprietà dell'applicazione", + "menu.methods": "Metodi", + "menu.applicationMethodsAria": "Metodi dell'applicazione", + "menu.request": "Request", + "menu.requestOverviewAria": "Panoramica Request", + "menu.requestPropertiesAria": "Proprietà Request", + "menu.response": "Response", + "menu.responseOverviewAria": "Panoramica Response", + "menu.responsePropertiesAria": "Proprietà Response", + "menu.router": "Router", + "menu.routerOverviewAria": "Panoramica Router", + "menu.routerMethodsAria": "Metodi Router", + "menu.community": "Comunità", + "menu.communityAria": "Risorse della comunità", + "menu.glossary": "Glossario", + "menu.glossaryAria": "Glossario dei termini", + "menu.middleware": "Middleware", + "menu.middlewareAria": "Risorse middleware", + "menu.middlewareOverviewAria": "Panoramica middleware", + "404.title": "404 - Pagina non trovata", + "404.description": "La pagina che stai cercando non è stata trovata.", + "404.heading": "Pagina non trovata", + "404.message": "La pagina che stai cercando non esiste o è stata spostata.", + "404.goHome": "Vai alla home" +} diff --git a/astro/src/i18n/ui/ja.json b/astro/src/i18n/ui/ja.json new file mode 100644 index 0000000000..dcd5771120 --- /dev/null +++ b/astro/src/i18n/ui/ja.json @@ -0,0 +1,75 @@ +{ + "home.welcome": "ようこそ", + "home.workInProgress": "これは開発中のホームページです。", + "home.reviewDesignSystemPrefix": "", + "home.reviewDesignSystemLink": "デザインシステム基礎", + "home.reviewDesignSystemSuffix": "のデモページを確認して、すべてのトークン、プリミティブ、パターンを探索してください。", + "search.placeholder": "入力を開始...", + "search.ariaLabel": "検索または質問する", + "theme.toggle": "テーマを切り替え", + "theme.switchToLight": "ライトモードに切り替え", + "theme.switchToDark": "ダークモードに切り替え", + "version.selectLabel": "APIバージョンを選択", + "nav.mainMenu": "メインメニュー", + "nav.toggleMenu": "メニューを切り替え", + "nav.home": "Expressホーム", + "nav.breadcrumb": "パンくずリスト", + "nav.mainNavigation": "メインナビゲーション", + "nav.selectVersion": "ドキュメントバージョンを選択", + "menu.docs": "ドキュメント", + "menu.docsAria": "ドキュメント", + "menu.api": "API", + "menu.apiAria": "APIリファレンス", + "menu.resources": "リソース", + "menu.resourcesAria": "リソース", + "menu.blog": "ブログ", + "menu.blogAria": "ブログ", + "menu.support": "サポート", + "menu.supportAria": "サポート", + "menu.gettingStarted": "はじめに", + "menu.installing": "インストール", + "menu.installingAria": "Expressをインストール", + "menu.helloWorld": "Hello World", + "menu.helloWorldAria": "Hello Worldの例", + "menu.expressGenerator": "Expressジェネレーター", + "menu.expressGeneratorAria": "Expressジェネレーター", + "menu.guide": "ガイド", + "menu.routing": "ルーティング", + "menu.routingAria": "ルーティングガイド", + "menu.writingMiddleware": "ミドルウェアの作成", + "menu.writingMiddlewareAria": "ミドルウェア作成ガイド", + "menu.usingMiddleware": "ミドルウェアの使用", + "menu.usingMiddlewareAria": "ミドルウェア使用ガイド", + "menu.advancedTopics": "高度なトピック", + "menu.buildingTemplateEngines": "テンプレートエンジンの構築", + "menu.buildingTemplateEnginesAria": "テンプレートエンジン構築ガイド", + "menu.overview": "概要", + "menu.overviewAria": "概要", + "menu.application": "アプリケーション", + "menu.applicationOverviewAria": "アプリケーション概要", + "menu.properties": "プロパティ", + "menu.applicationPropertiesAria": "アプリケーションプロパティ", + "menu.methods": "メソッド", + "menu.applicationMethodsAria": "アプリケーションメソッド", + "menu.request": "Request", + "menu.requestOverviewAria": "Request概要", + "menu.requestPropertiesAria": "Requestプロパティ", + "menu.response": "Response", + "menu.responseOverviewAria": "Response概要", + "menu.responsePropertiesAria": "Responseプロパティ", + "menu.router": "Router", + "menu.routerOverviewAria": "Router概要", + "menu.routerMethodsAria": "Routerメソッド", + "menu.community": "コミュニティ", + "menu.communityAria": "コミュニティリソース", + "menu.glossary": "用語集", + "menu.glossaryAria": "用語集", + "menu.middleware": "ミドルウェア", + "menu.middlewareAria": "ミドルウェアリソース", + "menu.middlewareOverviewAria": "ミドルウェア概要", + "404.title": "404 - ページが見つかりません", + "404.description": "お探しのページが見つかりませんでした。", + "404.heading": "ページが見つかりません", + "404.message": "お探しのページは存在しないか、移動されました。", + "404.goHome": "ホームに戻る" +} diff --git a/astro/src/i18n/ui/ko.json b/astro/src/i18n/ui/ko.json new file mode 100644 index 0000000000..7006ef4e4a --- /dev/null +++ b/astro/src/i18n/ui/ko.json @@ -0,0 +1,75 @@ +{ + "home.welcome": "환영합니다", + "home.workInProgress": "이것은 작업 중인 홈페이지입니다.", + "home.reviewDesignSystemPrefix": "", + "home.reviewDesignSystemLink": "디자인 시스템 기초", + "home.reviewDesignSystemSuffix": "데모 페이지를 검토하여 모든 토큰, 프리미티브 및 패턴을 탐색하세요.", + "search.placeholder": "입력을 시작하세요...", + "search.ariaLabel": "검색 또는 질문하기", + "theme.toggle": "테마 전환", + "theme.switchToLight": "라이트 모드로 전환", + "theme.switchToDark": "다크 모드로 전환", + "version.selectLabel": "API 버전 선택", + "nav.mainMenu": "메인 메뉴", + "nav.toggleMenu": "메뉴 전환", + "nav.home": "Express 홈", + "nav.breadcrumb": "탐색 경로", + "nav.mainNavigation": "메인 내비게이션", + "nav.selectVersion": "문서 버전 선택", + "menu.docs": "문서", + "menu.docsAria": "문서", + "menu.api": "API", + "menu.apiAria": "API 참조", + "menu.resources": "리소스", + "menu.resourcesAria": "리소스", + "menu.blog": "블로그", + "menu.blogAria": "블로그", + "menu.support": "지원", + "menu.supportAria": "지원", + "menu.gettingStarted": "시작하기", + "menu.installing": "설치", + "menu.installingAria": "Express 설치", + "menu.helloWorld": "Hello World", + "menu.helloWorldAria": "Hello World 예제", + "menu.expressGenerator": "Express 생성기", + "menu.expressGeneratorAria": "Express 생성기", + "menu.guide": "가이드", + "menu.routing": "라우팅", + "menu.routingAria": "라우팅 가이드", + "menu.writingMiddleware": "미들웨어 작성", + "menu.writingMiddlewareAria": "미들웨어 작성 가이드", + "menu.usingMiddleware": "미들웨어 사용", + "menu.usingMiddlewareAria": "미들웨어 사용 가이드", + "menu.advancedTopics": "고급 주제", + "menu.buildingTemplateEngines": "템플릿 엔진 구축", + "menu.buildingTemplateEnginesAria": "템플릿 엔진 구축 가이드", + "menu.overview": "개요", + "menu.overviewAria": "개요", + "menu.application": "애플리케이션", + "menu.applicationOverviewAria": "애플리케이션 개요", + "menu.properties": "속성", + "menu.applicationPropertiesAria": "애플리케이션 속성", + "menu.methods": "메서드", + "menu.applicationMethodsAria": "애플리케이션 메서드", + "menu.request": "Request", + "menu.requestOverviewAria": "Request 개요", + "menu.requestPropertiesAria": "Request 속성", + "menu.response": "Response", + "menu.responseOverviewAria": "Response 개요", + "menu.responsePropertiesAria": "Response 속성", + "menu.router": "Router", + "menu.routerOverviewAria": "Router 개요", + "menu.routerMethodsAria": "Router 메서드", + "menu.community": "커뮤니티", + "menu.communityAria": "커뮤니티 리소스", + "menu.glossary": "용어집", + "menu.glossaryAria": "용어집", + "menu.middleware": "미들웨어", + "menu.middlewareAria": "미들웨어 리소스", + "menu.middlewareOverviewAria": "미들웨어 개요", + "404.title": "404 - 페이지를 찾을 수 없습니다", + "404.description": "찾으시는 페이지를 찾을 수 없습니다.", + "404.heading": "페이지를 찾을 수 없습니다", + "404.message": "찾으시는 페이지가 존재하지 않거나 이동되었습니다.", + "404.goHome": "홈으로 이동" +} diff --git a/astro/src/i18n/ui/pt-br.json b/astro/src/i18n/ui/pt-br.json new file mode 100644 index 0000000000..68a043d648 --- /dev/null +++ b/astro/src/i18n/ui/pt-br.json @@ -0,0 +1,75 @@ +{ + "home.welcome": "Bem-vindo", + "home.workInProgress": "Esta é uma página inicial em desenvolvimento.", + "home.reviewDesignSystemPrefix": "Revise a página de demonstração dos", + "home.reviewDesignSystemLink": "Fundamentos do Sistema de Design", + "home.reviewDesignSystemSuffix": "para explorar todos os tokens, primitivas e padrões.", + "search.placeholder": "Comece a digitar...", + "search.ariaLabel": "Pesquisar ou fazer uma pergunta", + "theme.toggle": "Alternar tema", + "theme.switchToLight": "Mudar para modo claro", + "theme.switchToDark": "Mudar para modo escuro", + "version.selectLabel": "Selecionar versão da API", + "nav.mainMenu": "Menu principal", + "nav.toggleMenu": "Alternar menu", + "nav.home": "Início do Express", + "nav.breadcrumb": "Navegação estrutural", + "nav.mainNavigation": "Navegação principal", + "nav.selectVersion": "Selecionar versão da documentação", + "menu.docs": "Docs", + "menu.docsAria": "Documentação", + "menu.api": "API", + "menu.apiAria": "Referência da API", + "menu.resources": "Recursos", + "menu.resourcesAria": "Recursos", + "menu.blog": "Blog", + "menu.blogAria": "Blog", + "menu.support": "Suporte", + "menu.supportAria": "Suporte", + "menu.gettingStarted": "Primeiros passos", + "menu.installing": "Instalação", + "menu.installingAria": "Instalar Express", + "menu.helloWorld": "Hello World", + "menu.helloWorldAria": "Exemplo Hello World", + "menu.expressGenerator": "Gerador Express", + "menu.expressGeneratorAria": "Gerador Express", + "menu.guide": "Guia", + "menu.routing": "Roteamento", + "menu.routingAria": "Guia de roteamento", + "menu.writingMiddleware": "Escrever middleware", + "menu.writingMiddlewareAria": "Guia para escrever middleware", + "menu.usingMiddleware": "Usar middleware", + "menu.usingMiddlewareAria": "Guia de uso de middleware", + "menu.advancedTopics": "Tópicos avançados", + "menu.buildingTemplateEngines": "Construir motores de template", + "menu.buildingTemplateEnginesAria": "Guia para construir motores de template", + "menu.overview": "Visão geral", + "menu.overviewAria": "Visão geral", + "menu.application": "Aplicação", + "menu.applicationOverviewAria": "Visão geral da aplicação", + "menu.properties": "Propriedades", + "menu.applicationPropertiesAria": "Propriedades da aplicação", + "menu.methods": "Métodos", + "menu.applicationMethodsAria": "Métodos da aplicação", + "menu.request": "Request", + "menu.requestOverviewAria": "Visão geral do Request", + "menu.requestPropertiesAria": "Propriedades do Request", + "menu.response": "Response", + "menu.responseOverviewAria": "Visão geral do Response", + "menu.responsePropertiesAria": "Propriedades do Response", + "menu.router": "Router", + "menu.routerOverviewAria": "Visão geral do Router", + "menu.routerMethodsAria": "Métodos do Router", + "menu.community": "Comunidade", + "menu.communityAria": "Recursos da comunidade", + "menu.glossary": "Glossário", + "menu.glossaryAria": "Glossário de termos", + "menu.middleware": "Middleware", + "menu.middlewareAria": "Recursos de middleware", + "menu.middlewareOverviewAria": "Visão geral do middleware", + "404.title": "404 - Página não encontrada", + "404.description": "A página que você está procurando não foi encontrada.", + "404.heading": "Página não encontrada", + "404.message": "A página que você está procurando não existe ou foi movida.", + "404.goHome": "Ir para a página inicial" +} diff --git a/astro/src/i18n/ui/zh-cn.json b/astro/src/i18n/ui/zh-cn.json new file mode 100644 index 0000000000..0559aa7ab2 --- /dev/null +++ b/astro/src/i18n/ui/zh-cn.json @@ -0,0 +1,75 @@ +{ + "home.welcome": "欢迎", + "home.workInProgress": "这是一个正在开发中的主页。", + "home.reviewDesignSystemPrefix": "查看", + "home.reviewDesignSystemLink": "设计系统基础", + "home.reviewDesignSystemSuffix": "演示页面,探索所有令牌、原语和模式。", + "search.placeholder": "开始输入...", + "search.ariaLabel": "搜索或提问", + "theme.toggle": "切换主题", + "theme.switchToLight": "切换到浅色模式", + "theme.switchToDark": "切换到深色模式", + "version.selectLabel": "选择API版本", + "nav.mainMenu": "主菜单", + "nav.toggleMenu": "切换菜单", + "nav.home": "Express主页", + "nav.breadcrumb": "面包屑导航", + "nav.mainNavigation": "主导航", + "nav.selectVersion": "选择文档版本", + "menu.docs": "文档", + "menu.docsAria": "文档", + "menu.api": "API", + "menu.apiAria": "API参考", + "menu.resources": "资源", + "menu.resourcesAria": "资源", + "menu.blog": "博客", + "menu.blogAria": "博客", + "menu.support": "支持", + "menu.supportAria": "支持", + "menu.gettingStarted": "入门", + "menu.installing": "安装", + "menu.installingAria": "安装Express", + "menu.helloWorld": "Hello World", + "menu.helloWorldAria": "Hello World示例", + "menu.expressGenerator": "Express生成器", + "menu.expressGeneratorAria": "Express生成器", + "menu.guide": "指南", + "menu.routing": "路由", + "menu.routingAria": "路由指南", + "menu.writingMiddleware": "编写中间件", + "menu.writingMiddlewareAria": "编写中间件指南", + "menu.usingMiddleware": "使用中间件", + "menu.usingMiddlewareAria": "使用中间件指南", + "menu.advancedTopics": "高级主题", + "menu.buildingTemplateEngines": "构建模板引擎", + "menu.buildingTemplateEnginesAria": "构建模板引擎指南", + "menu.overview": "概述", + "menu.overviewAria": "概述", + "menu.application": "应用程序", + "menu.applicationOverviewAria": "应用程序概述", + "menu.properties": "属性", + "menu.applicationPropertiesAria": "应用程序属性", + "menu.methods": "方法", + "menu.applicationMethodsAria": "应用程序方法", + "menu.request": "Request", + "menu.requestOverviewAria": "Request概述", + "menu.requestPropertiesAria": "Request属性", + "menu.response": "Response", + "menu.responseOverviewAria": "Response概述", + "menu.responsePropertiesAria": "Response属性", + "menu.router": "Router", + "menu.routerOverviewAria": "Router概述", + "menu.routerMethodsAria": "Router方法", + "menu.community": "社区", + "menu.communityAria": "社区资源", + "menu.glossary": "术语表", + "menu.glossaryAria": "术语表", + "menu.middleware": "中间件", + "menu.middlewareAria": "中间件资源", + "menu.middlewareOverviewAria": "中间件概述", + "404.title": "404 - 页面未找到", + "404.description": "您正在查找的页面无法找到。", + "404.heading": "页面未找到", + "404.message": "您正在查找的页面不存在或已被移动。", + "404.goHome": "返回主页" +} diff --git a/astro/src/i18n/ui/zh-tw.json b/astro/src/i18n/ui/zh-tw.json new file mode 100644 index 0000000000..8f5067b2e7 --- /dev/null +++ b/astro/src/i18n/ui/zh-tw.json @@ -0,0 +1,75 @@ +{ + "home.welcome": "歡迎", + "home.workInProgress": "這是一個正在開發中的首頁。", + "home.reviewDesignSystemPrefix": "查看", + "home.reviewDesignSystemLink": "設計系統基礎", + "home.reviewDesignSystemSuffix": "演示頁面,探索所有令牌、原語和模式。", + "search.placeholder": "開始輸入...", + "search.ariaLabel": "搜尋或提問", + "theme.toggle": "切換主題", + "theme.switchToLight": "切換到淺色模式", + "theme.switchToDark": "切換到深色模式", + "version.selectLabel": "選擇API版本", + "nav.mainMenu": "主選單", + "nav.toggleMenu": "切換選單", + "nav.home": "Express首頁", + "nav.breadcrumb": "麵包屑導航", + "nav.mainNavigation": "主導航", + "nav.selectVersion": "選擇文件版本", + "menu.docs": "文件", + "menu.docsAria": "文件", + "menu.api": "API", + "menu.apiAria": "API參考", + "menu.resources": "資源", + "menu.resourcesAria": "資源", + "menu.blog": "部落格", + "menu.blogAria": "部落格", + "menu.support": "支援", + "menu.supportAria": "支援", + "menu.gettingStarted": "入門", + "menu.installing": "安裝", + "menu.installingAria": "安裝Express", + "menu.helloWorld": "Hello World", + "menu.helloWorldAria": "Hello World範例", + "menu.expressGenerator": "Express產生器", + "menu.expressGeneratorAria": "Express產生器", + "menu.guide": "指南", + "menu.routing": "路由", + "menu.routingAria": "路由指南", + "menu.writingMiddleware": "編寫中介軟體", + "menu.writingMiddlewareAria": "編寫中介軟體指南", + "menu.usingMiddleware": "使用中介軟體", + "menu.usingMiddlewareAria": "使用中介軟體指南", + "menu.advancedTopics": "進階主題", + "menu.buildingTemplateEngines": "建立範本引擎", + "menu.buildingTemplateEnginesAria": "建立範本引擎指南", + "menu.overview": "概述", + "menu.overviewAria": "概述", + "menu.application": "應用程式", + "menu.applicationOverviewAria": "應用程式概述", + "menu.properties": "屬性", + "menu.applicationPropertiesAria": "應用程式屬性", + "menu.methods": "方法", + "menu.applicationMethodsAria": "應用程式方法", + "menu.request": "Request", + "menu.requestOverviewAria": "Request概述", + "menu.requestPropertiesAria": "Request屬性", + "menu.response": "Response", + "menu.responseOverviewAria": "Response概述", + "menu.responsePropertiesAria": "Response屬性", + "menu.router": "Router", + "menu.routerOverviewAria": "Router概述", + "menu.routerMethodsAria": "Router方法", + "menu.community": "社群", + "menu.communityAria": "社群資源", + "menu.glossary": "詞彙表", + "menu.glossaryAria": "詞彙表", + "menu.middleware": "中介軟體", + "menu.middlewareAria": "中介軟體資源", + "menu.middlewareOverviewAria": "中介軟體概述", + "404.title": "404 - 頁面未找到", + "404.description": "您正在尋找的頁面無法找到。", + "404.heading": "頁面未找到", + "404.message": "您正在尋找的頁面不存在或已被移動。", + "404.goHome": "返回首頁" +} diff --git a/astro/src/i18n/utils.ts b/astro/src/i18n/utils.ts index 72ade3c5ba..21d3b1b620 100644 --- a/astro/src/i18n/utils.ts +++ b/astro/src/i18n/utils.ts @@ -1,4 +1,4 @@ -import { ui, defaultLang } from './ui'; +import { ui, defaultLang, languages } from './locales'; export function getLangFromUrl(url: URL) { const [, lang] = url.pathname.split('/'); @@ -7,7 +7,39 @@ export function getLangFromUrl(url: URL) { } export function useTranslations(lang: keyof typeof ui) { - return function t(key: keyof (typeof ui)[typeof defaultLang]) { - return ui[lang][key] || ui[defaultLang][key]; + return function t(key: keyof (typeof ui)[typeof defaultLang] | string): string { + return ( + ui[lang][key as keyof (typeof ui)[typeof defaultLang]] || + ui[defaultLang][key as keyof (typeof ui)[typeof defaultLang]] || + key + ); }; } + +/** + * Get all supported language codes + */ +export function getLanguageCodes(): string[] { + return Object.keys(languages); +} + +/** + * Create a regex pattern to match language prefixes in URLs + */ +export function createLanguagePathRegex(): RegExp { + const codes = getLanguageCodes().join('|'); + return new RegExp(`^/(${codes})/`); +} + +/** + * Replace the language code in a path with a new one + */ +export function replaceLanguageInPath(path: string, newLang: string): string { + const langRegex = createLanguagePathRegex(); + + if (langRegex.test(path)) { + return path.replace(langRegex, `/${newLang}/`); + } else { + return `/${newLang}${path}`; + } +} diff --git a/astro/src/layouts/Layout.astro b/astro/src/layouts/Layout.astro index 5f6c5c2511..47d299449b 100644 --- a/astro/src/layouts/Layout.astro +++ b/astro/src/layouts/Layout.astro @@ -3,6 +3,8 @@ import '@styles/main.css'; import { Flex, FlexItem } from '@components/primitives'; import { Footer, Sidebar } from '@/components/patterns'; import { Header } from '@/components/patterns'; +import { getLangFromUrl, replaceLanguageInPath } from '@/i18n/utils'; +import { languages } from '@/i18n/locales'; interface Props { title?: string; @@ -13,12 +15,13 @@ const { title = 'Express - Node.js web application framework', description = 'Fast, unopinionated, minimalist web framework for Node.js', } = Astro.props; + +const lang = getLangFromUrl(Astro.url); --- - + - + `} + /> + + +

    Grid & Layout

    diff --git a/astro/src/pages/[lang]/index.astro b/astro/src/pages/[lang]/index.astro index 010d9dd988..5c36cf363c 100644 --- a/astro/src/pages/[lang]/index.astro +++ b/astro/src/pages/[lang]/index.astro @@ -2,7 +2,7 @@ import { Body, Container, H1 } from '@components/primitives'; import Layout from '@layouts/Layout.astro'; import { getLangFromUrl, useTranslations } from '@i18n/utils'; -import { languages } from '@i18n/ui'; +import { languages } from '@i18n/locales'; export function getStaticPaths() { return Object.keys(languages).map((lang) => ({ @@ -17,11 +17,12 @@ const t = useTranslations(lang);

    {t('home.welcome')}

    - This is a work-in-progress homepage. + {t('home.workInProgress')}
    diff --git a/astro/src/pages/[lang]/support/index.astro b/astro/src/pages/[lang]/support/index.astro index 30b6055d12..b9d7446b41 100644 --- a/astro/src/pages/[lang]/support/index.astro +++ b/astro/src/pages/[lang]/support/index.astro @@ -5,7 +5,7 @@ * TODO: This is a temporary index page for support page. This will be replaced with a proper support layout in the future. */ import Layout from '@layouts/Layout.astro'; -import { languages } from '@i18n/ui'; +import { languages } from '@i18n/locales'; import { Container } from '@/components/primitives'; export function getStaticPaths() { From ec12bf5331f6bedcb8b8ad75b46988bc22eaa80e Mon Sep 17 00:00:00 2001 From: Francesca Giannino Date: Wed, 4 Mar 2026 10:52:45 +0100 Subject: [PATCH 08/17] feat(redesign): Homepage Hero component (#2203) --- astro/astro.config.mjs | 20 +- astro/package-lock.json | 203 ++++++++++- astro/package.json | 1 + astro/public/hero-poster-light.jpg | Bin 0 -> 92247 bytes astro/public/hero-poster.jpg | Bin 0 -> 96214 bytes astro/public/logo-express-black.svg | 20 ++ astro/public/logo-express-white.svg | 20 ++ astro/public/videos/hero-background-light.mp4 | Bin 0 -> 587584 bytes astro/public/videos/hero-background.mp4 | Bin 0 -> 666659 bytes astro/src/components/patterns/Hero/Hero.astro | 271 ++++++++++++++ astro/src/components/patterns/Hero/Hero.css | 332 ++++++++++++++++++ astro/src/components/patterns/Hero/index.ts | 7 + astro/src/components/patterns/index.ts | 1 + .../primitives/Container/Container.css | 4 +- .../components/primitives/Typography/H1.astro | 1 + astro/src/content.config.ts | 10 + astro/src/i18n/ui/de.json | 6 +- astro/src/i18n/ui/en.json | 6 +- astro/src/i18n/ui/es.json | 6 +- astro/src/i18n/ui/fr.json | 6 +- astro/src/i18n/ui/it.json | 6 +- astro/src/i18n/ui/ja.json | 6 +- astro/src/i18n/ui/ko.json | 6 +- astro/src/i18n/ui/pt-br.json | 6 +- astro/src/i18n/ui/zh-cn.json | 6 +- astro/src/i18n/ui/zh-tw.json | 6 +- astro/src/icons/logo-express-black.svg | 20 ++ astro/src/icons/logo-express-white.svg | 20 ++ astro/src/pages/[lang]/index.astro | 23 +- astro/src/styles/base/_expressive-code.css | 24 ++ astro/src/styles/main.css | 3 + 31 files changed, 1005 insertions(+), 35 deletions(-) create mode 100644 astro/public/hero-poster-light.jpg create mode 100644 astro/public/hero-poster.jpg create mode 100644 astro/public/logo-express-black.svg create mode 100644 astro/public/logo-express-white.svg create mode 100644 astro/public/videos/hero-background-light.mp4 create mode 100644 astro/public/videos/hero-background.mp4 create mode 100644 astro/src/components/patterns/Hero/Hero.astro create mode 100644 astro/src/components/patterns/Hero/Hero.css create mode 100644 astro/src/components/patterns/Hero/index.ts create mode 100644 astro/src/icons/logo-express-black.svg create mode 100644 astro/src/icons/logo-express-white.svg create mode 100644 astro/src/styles/base/_expressive-code.css diff --git a/astro/astro.config.mjs b/astro/astro.config.mjs index 3441315e48..6bf48350f7 100644 --- a/astro/astro.config.mjs +++ b/astro/astro.config.mjs @@ -2,14 +2,22 @@ import { defineConfig } from 'astro/config'; import mdx from '@astrojs/mdx'; import icon from 'astro-icon'; +import expressiveCode from 'astro-expressive-code'; // https://astro.build/config export default defineConfig({ site: 'https://expressjs.com', - integrations: [mdx(), icon()], - markdown: { - shikiConfig: { - theme: 'github-dark', - }, - }, + integrations: [ + expressiveCode({ + themes: ['github-dark'], + styleOverrides: { + uiFontSize: 'var(--font-size-sm)', + codeFontSize: 'var(--font-size-sm)', + borderRadius: 'var(--radius-base)', + borderWidth: 'var(--border-width-1)', + }, + }), + mdx(), + icon(), + ], }); diff --git a/astro/package-lock.json b/astro/package-lock.json index aa3d7adfca..1813b831f9 100644 --- a/astro/package-lock.json +++ b/astro/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@astrojs/mdx": "^4.3.13", "astro": "^5.18.0", + "astro-expressive-code": "^0.41.7", "astro-icon": "^1.1.5" }, "devDependencies": { @@ -321,6 +322,14 @@ "postcss": "^8.4" } }, + "node_modules/@ctrl/tinycolor": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-4.2.0.tgz", + "integrity": "sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==", + "engines": { + "node": ">=14" + } + }, "node_modules/@emnapi/runtime": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", @@ -891,6 +900,83 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@expressive-code/core": { + "version": "0.41.7", + "resolved": "https://registry.npmjs.org/@expressive-code/core/-/core-0.41.7.tgz", + "integrity": "sha512-ck92uZYZ9Wba2zxkiZLsZGi9N54pMSAVdrI9uW3Oo9AtLglD5RmrdTwbYPCT2S/jC36JGB2i+pnQtBm/Ib2+dg==", + "dependencies": { + "@ctrl/tinycolor": "^4.0.4", + "hast-util-select": "^6.0.2", + "hast-util-to-html": "^9.0.1", + "hast-util-to-text": "^4.0.1", + "hastscript": "^9.0.0", + "postcss": "^8.4.38", + "postcss-nested": "^6.0.1", + "unist-util-visit": "^5.0.0", + "unist-util-visit-parents": "^6.0.1" + } + }, + "node_modules/@expressive-code/core/node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/@expressive-code/core/node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@expressive-code/plugin-frames": { + "version": "0.41.7", + "resolved": "https://registry.npmjs.org/@expressive-code/plugin-frames/-/plugin-frames-0.41.7.tgz", + "integrity": "sha512-diKtxjQw/979cTglRFaMCY/sR6hWF0kSMg8jsKLXaZBSfGS0I/Hoe7Qds3vVEgeoW+GHHQzMcwvgx/MOIXhrTA==", + "dependencies": { + "@expressive-code/core": "^0.41.7" + } + }, + "node_modules/@expressive-code/plugin-shiki": { + "version": "0.41.7", + "resolved": "https://registry.npmjs.org/@expressive-code/plugin-shiki/-/plugin-shiki-0.41.7.tgz", + "integrity": "sha512-DL605bLrUOgqTdZ0Ot5MlTaWzppRkzzqzeGEu7ODnHF39IkEBbFdsC7pbl3LbUQ1DFtnfx6rD54k/cdofbW6KQ==", + "dependencies": { + "@expressive-code/core": "^0.41.7", + "shiki": "^3.2.2" + } + }, + "node_modules/@expressive-code/plugin-text-markers": { + "version": "0.41.7", + "resolved": "https://registry.npmjs.org/@expressive-code/plugin-text-markers/-/plugin-text-markers-0.41.7.tgz", + "integrity": "sha512-Ewpwuc5t6eFdZmWlFyeuy3e1PTQC0jFvw2Q+2bpcWXbOZhPLsT7+h8lsSIJxb5mS7wZko7cKyQ2RLYDyK6Fpmw==", + "dependencies": { + "@expressive-code/core": "^0.41.7" + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -2833,6 +2919,17 @@ "url": "https://github.com/sponsors/ota-meshi" } }, + "node_modules/astro-expressive-code": { + "version": "0.41.7", + "resolved": "https://registry.npmjs.org/astro-expressive-code/-/astro-expressive-code-0.41.7.tgz", + "integrity": "sha512-hUpogGc6DdAd+I7pPXsctyYPRBJDK7Q7d06s4cyP0Vz3OcbziP3FNzN0jZci1BpCvLn9675DvS7B9ctKKX64JQ==", + "dependencies": { + "rehype-expressive-code": "^0.41.7" + }, + "peerDependencies": { + "astro": "^4.0.0-beta || ^5.0.0-beta || ^3.3.0 || ^6.0.0-beta" + } + }, "node_modules/astro-icon": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/astro-icon/-/astro-icon-1.1.5.tgz", @@ -3388,6 +3485,15 @@ "integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==", "license": "MIT" }, + "node_modules/bcp-47-match": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/bcp-47-match/-/bcp-47-match-2.0.3.tgz", + "integrity": "sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -3869,6 +3975,21 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/css-selector-parser": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-3.3.0.tgz", + "integrity": "sha512-Y2asgMGFqJKF4fq4xHDSlFYIkeVfRsm69lQC1q9kbEsH5XtnINTMrweLkjYMeaUgiXBy/uvKeO/a1JHTNnmB2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, "node_modules/css-tree": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz", @@ -4144,6 +4265,18 @@ "node": ">=0.3.1" } }, + "node_modules/direction": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/direction/-/direction-2.0.1.tgz", + "integrity": "sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==", + "bin": { + "direction": "cli.js" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", @@ -4939,6 +5072,17 @@ "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", "license": "MIT" }, + "node_modules/expressive-code": { + "version": "0.41.7", + "resolved": "https://registry.npmjs.org/expressive-code/-/expressive-code-0.41.7.tgz", + "integrity": "sha512-2wZjC8OQ3TaVEMcBtYY4Va3lo6J+Ai9jf3d4dbhURMJcU4Pbqe6EcHe424MIZI0VHUA1bR6xdpoHYi3yxokWqA==", + "dependencies": { + "@expressive-code/core": "^0.41.7", + "@expressive-code/plugin-frames": "^0.41.7", + "@expressive-code/plugin-shiki": "^0.41.7", + "@expressive-code/plugin-text-markers": "^0.41.7" + } + }, "node_modules/exsolve": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", @@ -5528,6 +5672,18 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hast-util-has-property": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-has-property/-/hast-util-has-property-3.0.0.tgz", + "integrity": "sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/hast-util-is-element": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", @@ -5579,6 +5735,32 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hast-util-select": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/hast-util-select/-/hast-util-select-6.0.4.tgz", + "integrity": "sha512-RqGS1ZgI0MwxLaKLDxjprynNzINEkRHY2i8ln4DDjgv9ZhcYVIHN9rlpiYsqtFwrgpYU361SyWDQcGNIBVu3lw==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "bcp-47-match": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "css-selector-parser": "^3.0.0", + "devlop": "^1.0.0", + "direction": "^2.0.0", + "hast-util-has-property": "^3.0.0", + "hast-util-to-string": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "nth-check": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/hast-util-to-estree": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.3.tgz", @@ -5676,6 +5858,18 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hast-util-to-string": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-3.0.1.tgz", + "integrity": "sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/hast-util-to-text": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz", @@ -8756,6 +8950,14 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/rehype-expressive-code": { + "version": "0.41.7", + "resolved": "https://registry.npmjs.org/rehype-expressive-code/-/rehype-expressive-code-0.41.7.tgz", + "integrity": "sha512-25f8ZMSF1d9CMscX7Cft0TSQIqdwjce2gDOvQ+d/w0FovsMwrSt3ODP4P3Z7wO1jsIJ4eYyaDRnIR/27bd/EMQ==", + "dependencies": { + "expressive-code": "^0.41.7" + } + }, "node_modules/rehype-parse": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-9.0.1.tgz", @@ -10315,7 +10517,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, "license": "MIT" }, "node_modules/vfile": { diff --git a/astro/package.json b/astro/package.json index fec4a06e30..1841b05bd7 100644 --- a/astro/package.json +++ b/astro/package.json @@ -17,6 +17,7 @@ "dependencies": { "@astrojs/mdx": "^4.3.13", "astro": "^5.18.0", + "astro-expressive-code": "^0.41.7", "astro-icon": "^1.1.5" }, "devEngines": { diff --git a/astro/public/hero-poster-light.jpg b/astro/public/hero-poster-light.jpg new file mode 100644 index 0000000000000000000000000000000000000000..135b4be9648ce55e8526ef5e29c7c77991f8db86 GIT binary patch literal 92247 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 mUtO*6lBHDSB=+otcMDP~@<+gJSzF4?8q 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 + + + + + + + + + + + + + + + + + + + diff --git a/astro/public/logo-express-white.svg b/astro/public/logo-express-white.svg new file mode 100644 index 0000000000..6b14ccf672 --- /dev/null +++ b/astro/public/logo-express-white.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/astro/public/videos/hero-background-light.mp4 b/astro/public/videos/hero-background-light.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..e20340f1ea1e0f358d95eddaebd0844ae370580e GIT binary patch literal 587584 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±%uPTBcy&V0XbQ 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 z

    LwaY;wXkkViYAL2qQ6rs|fg+@lF%mKL7%Awe6L6xx*BZ3kY_oV7ML3i}|7S zJ=5!jJRmZ#ivXcQ_QN~@PwP(8L88>L_l`5w1O{SXd+Zkr@EbEWo+9XL>O&RXJR*PSw)*v$|bUm)8s(_fX~AC<4GCQa5g%aExRR zOMe=rSfI@C4VVn4KGs&6!o=id>E*7JXB2`n0kJ78c*w7Oh;S7UH2&!?Pc%6iR0<4v z_ba7K|2O*J*z6Nyla9}e*uM}+bGNI^{CkALB^Oq2`Z5X#G3ti09bwwZ7xd~~U%8W+ zx3sbA$WJ}px$w!P`mm{Oloi`1sImNODlwr-F(Cy`pgH64SV4r#qfZc8scq?#NFpB1 zNP|h+WKoNy%4;B(hWJl{UwA?teTTnpQzpqY85kN?FqCLfiCdpvNK0ZYyo3`{LX$b- zj8{r_{@(AbW&edV=x{H)yg6@}pd-M086=%L3@$?shR%$D%_&=hj?e-3c1tv=mkrfJ z!$LWNoQC^wR91})W7oh!PrgS#Iu==U;>P9##Y$DP?8knk?uR7hMNTByM|)$4!dxeY z4ca-;L;4m{mK%H93lg^S9bKQfhyl$jY)pMCkSiA-+`G5YD`MG9Cle0$E!`@TR_> z%^-;4T$H6*$`U}oZnx~ahL=EAdY}rq zFRh6dW0a)r(TpsV*!Y-y-M|}FJVkX0jW);9zT!2kO0X9FT9K=GP$zZhI`cg6JG4BR zmC8LUPZwKSi?2Clg9}6%Bk5&1yQ{u3^e@d!4IfKa&)V8{8Z+0-E`x>=Qh&EM5yISa z;LxHS1g-X_n`|;2Y%i12tOY$D@kEV8HA5ir&&K6txbiHx1f?4(Bjkd|cf|tEbbsv{ zQkSe?mPyaS2|~urr=FgC0r|la%7zUaB_F_BR7IIchGV$QynyctECZBs6nV*p*Wd3s z09Kv9NCJPAQRoW%l@`QVJDN;IE?J8p(lYInSgb zFwja2Sno!c3O}l|V-}NdyDt1|~#iUpzo(X2h&9D-Owd ziH7JawvEC5e{GNWk}z`{&qY=ziWMvNf@9^fKIP^RY<*owp@-Z~EFH7uvAXje)_4Cp z&D|1Tcq1_=ICa&`Iai`Sh|D+%Z-3M1cf^=9QOZamHSTa+x+NFWuRaTV&F@^R#8lQ* zO$KJt9QAh-KWfBUr)RaCT>J&Um2r5|-c^@%)};7|lx^Q*i(amDg|dW+At-c_d^%vi zK9MX+8wr_j>KPj7=Y--sq18vRk0%O}n|Do3#1V?;7 z6s?>-ndsVUcncl4h)c5`r-?xTQdTE-!hL8?onT_)?=p=AvJ3o>Ps7nak=JYt&`42) z@d@$cObKb99uh2H`2nLYHlj{7EKtvJkrE=^?*%3AJdRvyE%F;0a|;*UEbgQ;cbf8? zlP|qPo_gEp@^I}=!%^5lOqReG`_6FnvqQD<)Ya)#=4n1wTM!VEeJeO6oGTH(pjvs3 z=K+pYGJs@}bWT9S&gWhr0z8hr2Gr7i4?*4@eQ1yv!+?fr%DE(-qnGddK3@s!-D95p&Xp%ap`!SEaQo|JfgR*a|rkAZpc90S%zd2H8^--ptD| z=^y2_wYM0vvRA(le;gd%cY9<#T#i}p_rd5#xjA>yux8$>i#GTGO5^8P;e5&OHeq{0 zE&q0ZHjvw(ytCf4ia#^j+>A%%4fIqb9wU`}Rf!ZS0+&dD^n%P$-v3xXl-J`)zedqV zHd<#@nB z(=_rQ0u~Kft4yPJFqf~-*`4l{01Q^&s5t0upFSVTMam~rd3M)E{RjmAn;@m+>52Tl z0?nTB2_AFrf8<(;@9?)pus{zF)QwDfg_gP?HjakaO7y~#B9!S$huxP1c76q~RE>r< zBDqxB(IfjRzbiYE5qjDD|Ixl38oDjmO6-OtHeuCg?H7qxLwuEmJ43v^;xdw*8 zBH|&D8f7@_iBAQDDYTHXqx-4_q2d@D`zQJer4JZC-*CQnvj%}TdA&|&tZwWbjt9{gwsTn-Jx5+jLgUDOV_z8DIfIH8|3M5^ zpFMn)b0S)`pMT!u{p%8=gUyAf$MbT(ncHVopFJOG9xh9vrwNr2GFlo?^zS5ZDUZp~ zfB;`mRm^y;#WjpdZN*=QTA2pbTDC-o`!Zt+9(=Z;N%dtq8j*kW{(ns_*;IbkMRH_gozhM z+0gm@bxc2sEa-!{r^s)-X*}TGD#aycEiPGp(oD*UHj4IClZFGmAie2b{i-hvvr$YR zf8UZPr(++~msn#&i>0zcGyHKd(OmpYZ3fy)yNPoEKyW{5B#DX zlYj(&STnuTDD3ujEa=RO_qC=9pQ0A6x*N`d9$k5` z$J0e5ZzP_adK~cDaLJg2I^+ljff&--QZGO@hL&JG)}e<4mM`~a5a5n*pQr`prV%cg z1Bv>IfG^gLaZ(TIDP#w0&>otg1Cm59qvz`oNLM-L$H?bgCLmFvex|E-C|7m(hr(Cb z-uk+u5IUAPeqHEhus`PREj#T(x_<;^DZ6btD zlX`>aT6rilyM84dZ7oye`%A5SLPXbN9XFO#TR0>LxycubjzA=nSo#~t3{ zedv7M1ZMRi0Ey)&1l67BY|eZ8dP*sydKP&zX2|5Hm>$?km6-~z$1>VK!Cca7U+&d3 zD#JCtwqpq3XM#1;<=vLBHE8%2O+p+xI5rd|QSB6dV#vNMLBHR0Ak+WRg~so0r|7ReFbEiFp$fp96J50eEv&p9k+3m82@5>Kr3ygwMKS19gisz zYy}NSFROrrU)N5TjqIms4W4W#U#6d7H1 zM5RwkTo6kE`}E;Y;9B6hvgJ}3QK`MSh%M2c*zchtt>5l9-sU;Ls8NAngth$%dC+t1 z_!ya0RUvyXbX|Sai4HUD3o*dF#9F640PQSv@f7txr-^o;je51LPc4Po>gZ1X+_FWy z5mO!^dhP=Fcpi-nLuQM2;KTDAg%c8tIp_GTUa?Cf74tn+6Ajze#&Ch|{jEwSOHsF6 zUv(8`2X;Mzu=OKPqp!;kq>BH7t!oB+a}0>1lL>NOkH#9ixC`c-B}z$A!ytL>vMT76 zrMTsxm!yysO8e!ZZhSs_>uR8?fu>D#N8D>86&Tio!Q{Z}*E%ru%^UeHi84_keeP(z ztgnXcI{Mk_diHNs$}#f)5y*pJbgAE5CQ$LJTWp@2F6|eC4yOqq@_DR`4EteW-g%cM za8rzoSv`%JV~>u1%S8Kd9%=gci|40f6VrL@xGAKQ?o#lNVeKKM!koIc6nrK3AznM4 z|4f->fa>~*%3e2PjMblJfWHV8?O%_>AG#4MqDH?cbu62#RX^v@1F@)7eGes`aAK7+ zXre+>+nl;WQBUJzt@u2C4FRL4#@eH`qcXIE%3TuZ@H=q{S~BwD*mQ?sx=G~X!Eu=^ z&8jh*u%!665*@@0+1X>y;||^*&;s&-pvkV>)~3Sq;@l9&{c_kG)ALo}NxKCT-q?Uf zS!{0{T*Jyy6wD#s1Gyo*UW0CsD8D@vG$!ise}f15?WM@D(P*KpIs|iFJU^8dB6?@+ zaQ9WowkggadCn5F2utFW8I;Bd%V==Ab%6r-BvL?LOOy1VMfH0z>aq)3*95SMDoLSZ z@k_qMbb+JOB*qfG#nXK0ynKP!2xspRl_m(h1>_Kg5T?53G&Oc1uc$?`4~F7)Wtfal z%wAhms)U`Jf9LUo$(-Vgap!=ggPpTZ3jcih5BTKI{*XS5#q7u+G@M-R<@oo4ZWE6w7mW>XX>pPrD&8!4AU60kL2WmVagL2)kP8o z^7dG$q>JW?)^r)=Zziiixoe7d_EmkSCBIviqxtSD7j&3K2|#;41&mX^6X7iNZ^N_N zfkD8hq5sAHK+;7+Xm&=nbRyjEQb7q5Q(;)8paf7mX25VE+eWTUfSZw7(9X=H0RW5~26(OM8|Z!%D_?;t%gEEsdN0x`SLn0<8f@n-DfkENA&BY5T}oS}w+x zq!~U(uJ2w$n5#$8RpFVIH%l}Arn~Cq$g@`gP<%>G9x+wZ8tKpZzBpE)`Ys8hx8E3L zVp+P3iMdCQtyyDI9tPwX<*H%!qK}>gUeqc^7HwsVyU?&vxy#j-o1vN08f znsgP%h>6z{*o)mAnziYh@TnfC-EW<{vy8$&fAH|z-8WOK0tykM$q~W@v$)qRP-6Wb0+gN%`ZJ) zl?f9^*nb%n00q8Yeg012w7-Ob765Uy{3F}V^ht77U6?LPPrX&~ryako`6HheOk+c; z6~1wR;Q)?@aD*)^|84Bn{Hybi<6!;(o9(+f4s3w%OWcK+|EM!$L-Api&((Kenjyq&(FK$2YEc{jIJg0g*Mrbr@;zLn)%E z5xoc`qHn#_$hHksWaw!?c5eNiHu=j0l(%NiK9^yuDs-L zT6Tww6(W78CuwdkQePO1S>m)QjicpVgkIUMDj&vGCsm!MDhOK>WMC$!8lT9Pn;myt zFS2%!*uS(onj9CWvVyEF>=k?M6TMpN2uxj$ca1-jTH6;@vVlB7N8OQW@nj^nO>G9v(PN=hYQTbOsCV zx^OuWIK9ohi23e3iiR-WDWnHJrCV)BR z;hx6N)>AimwzG-KEsAahy^X_j66;adf81+;xZ;KqrR zY%x(MI%-f_Ndgu6lx`?-Z@6TP6Q1BqgftI!nMYX1C+_{peY*6V%e>*lwi+( ztrs8Ev&)MdgJKQDdCYanKXYR;R;m{9k7A+zn7|qlg|RwxT$J3lPwHQ+O%TthMPgsU zbM1hDz0QUpxwltp0u*a=4XQ*d<)8G2AJ~r8eyqw)GXA^DQMRzkir!x%QUAYz3jedG zw|CDnQ%6J(S0myiv5JKxxc&B0XS#=Qqb=5cQo{^jjC15LV=@(_rWK@zYCNuR!2Vp1 zMqpWQb869_xa0QP4!z5l5d66Vus4N1hE^erNu=2kcj$oq*)ml^#BOosCpcf;lAXhs zrOee>KGfU=&@=kyxA}T13QaQvRk-_C6V;(QoHLrg4D~~4_x@d=qu@-1JJ+FfVjOw_ zrHzf;jng62Z|L~1n(!!N+npu9+Meu&aO{0;>maK|ud2gM37T7|4};@US%SClwUfdv zWq>uIhQd}95PXtnj64|7kJL(Mz_<)QiF?u@52Yg1${~12C@mqCeBzt?K1GqE#nt(x z{z5*9)aN^&tE~k)0KwaN$Vq(Z!r&&hOPfX<;e_!>6;O)@XqmyI@q_K(vSK3gC{#eS z`@QIY*Q{%Sg{c)SbR&W}o$i1ephrkGjuFk2_M#2OuLC}arh~Nx7rdywlj(CZ?Kayz z=9vy_PN)Jtu~8EfCjQ~IEv_XV#pw)Ik;pXGU{+95WT%~+MqGG+nNG0^3n8pt)ySM_*+BHn6ejk0%eV$HN6(4&^aNz`)p zcRjlKf|XxwY7>L$!D3n5780RkHWob>xx55k`q=T>zGY!Z;@mqYhG<(Jk(fu%42lRJ zv_m$%Jp=?F?izi+6X*RG523@o3P@XGIYgRJ5wM_V52yP)TmFZdcdxtxTb1MV7O?g7 z8{t0c!z~ky3YXVn$bLRnmJeWzRf*u=rOqEm-ertJ?`&1TxL#$N3nT*~>33O@Z=48u zicgB+r?sirO?x=#GlBu5e%RhmWWVy>qO-Ya2_)hQ)YYXe;H=8hnG2DH)R> zCK;IsK}^QYX11eZcoR*+IQ?M=t@Gu!5uQD+|I}yGU?VA|Np}}<2!E;c3ImMMXR(=; z998Pi2N{?8GHp%hdx5;=z8e-?{!0)P7IrEvli1FyQXlPu+U#@1<&DZa#AB#-bJ#>ws^W%8|BmaVkZMH ztUSsG==xNY^9qQiq^g2G_lmgWN4F%i?3Ew|jXV1Dr+I@L&)JR3CK)C>G)i4owjV5; zsZo$dWv`og?!_E$peIOvR#YFyz6FM2GCdmkM2BsVMcPVgLi{o#Y%lhEkS1856n-2? zd5tljkz{VlzdWpSss)|jY|97Z%@q)gO1;Tx-Df(?z8==&Y(=dy7SAw4#MqjDxjB?GPlk*rsMW&! zysvy2FP)FT;80SG-rE`67gvc&lhbiSdO)!XSH`wJqhvKByUr_&9GONZ`P!o&WDe3L zp7oufhQ*XK&3>)MjY&BtS2XinaZ7$w3V_8D}JyT@oE_kUL7VIHi{eE&?V+}TCZ`L=9U z{)GGBOCrzQ0`8G0 zvQ*T`1GH*ip_@?f_O9nM8I{NCVriv}yB1%(4$l$FrPnkymH^+NiN&$d6_A8!CACw= zA_l0WxWS=m6F_`yjupLV zDN@XfGtEBJpjbWbf z2R$DC6)CIH%o+N6=T zBW3neJBOr1YKaD_L-7L{d`6})+~hmb7Q!yak0={MyW~DY!d*Li8n?N-h+QW7cJaSm zQ2xU~S2ZlpQA^m;bcM?nh1W`)bHFdb{-da8I>G1pKJJcU62tZcgAM>tb_19#%FK2T zS^#Ee1E_V!J^7WaLaJ^!TmbZC1pE-BIgs}{UmbRKXM8H7<0??6ATGAY>cR1=9`vI; z)DspGdh=wqx=OBJC^_YB_HjnMJ(tkXzG4%!?{Lxj?assMs=tYdO#b>7u29iYc)ts? zB^5&|aast#Z9IrHMI4iAAvC#%mp>l=7MFxlRI{{sl{v~pM$zCIRcCDc^(%zSc|nI= zYFLuV5b+7S5p9R2B^nc<Z2M3MTUi81Homc0H6VsfLc~gI50X1gXein+!%q#Rl1$@9){9IUA`MU}L23s4@YZq{q`ksqs}p%1UzaJ= z;1iGdu&C|~D1w!n{6`}qEhO-l_Xex!xcUT3Fj&n9`{1@ma)Xoe4{033+inuv^82YzX(np%;gub zgWdZKzMamVq2A`<4bI{5&Io))4?D6ei~8v9IuaM3ifjTW;sQ+?jfYT?cme`IE@U0s zfQokg8~S6s(%DOGcJ_g}ytWyR<8w_=I*O0&hS1Yf(ShPtq^Gk;ySH8ajSf ztfQr&*?d=>2Hh$XY2q1gy3oN}bPvqW&dLSN+hNyOmwd%hpY`xS*f?3=Shhk1*L4ugt-q_9U&WdKA8SK(^$>6+>nYAzMH?IB5(}SDx4N2*BG*_cY&2{eu%OWehk4 zT*CNt%j6Ku*Q{2e9mLmj`@a|cNStk&AV>P3SZS0u_t7_^DK%X;4j03xz^gic z$e!^Ac*9nRp(y!Bw#~e{kfhQ%;xV9J=3Zq|_O9FE$dGUCZuG;Z+`*F0ooqrNB(KMo z^y5Q|gg zPkUQCs)#`rj>MBzWF;^SSGdl8SqvyIhC|*F zQ0}nJD}tUN+ZN)E}}ZvBHj9`J=w_HQoDK2R0Jvx{OXdL4^^ILHV=T1 zTcR4?$gN*teJwhzJ0R_Qs4gFN5L{U2Hl`6}h)Mp4{?*6KnNhwpQc*rokW$Roi5Fg+ z2;_>QU}XyDxCM^sT1FvqTUo-bn;ZtPHJ!LlaMp9QtAt8`5^gI&vR9B75ADhg=IXa_ zW~nc+t39tuY5QIabo&Wj9tbZnmEDW|W23>uh(#m~xo6?FBY1ED%##nH!7$$nj5E{r zD0HE38A;4O5_a-JbmSl@&N>kWDP z7WSqzPM-{)x;=gXIo-*Q8LtYH4MAxG4OAh-g*TOX_2}xU2iAJ(zyF|tDu>PkPSv61 zKdjN-jz{1^_~wkGZTb9GR;;>t8p;bf4Eaxz7YpMmkZ3G1&=S}$SLRqWWHL&sv&0E4 zJyOBK?Z>$%p#+3`6lk<4GP1dl4RADR#v;;>q0_(LU;AHJK}6naou3Z#xi4$VwB@EM zpLdw!82(=xp{hPi=J6~`ZkN8dwfbaz^jhkmv*nyDQItePH0fo(CU$d4ThGKXkR2RZ zy`y0sfvEHP-*7sddvm6>!QJSGjKQNwVDR3^tZGr-cgE~Z$J++TsT-pOE)r$#yEmn;H8ZZn%Zdt<1}G4t5V>R>$kNpn3ZjDI;K?|+$s|IHyd zKLTPfc~-uw;I6a|FmnokBB#80@4rj<0JJ{b3IwTEQg@+U zyQDdv597Bjmn{-Ta0TU~ejkjM%rN|0+yu6%^wXor-ienMLr zaDH#KrcX_4io?->+=EYdG52kJ>pRH9j(gwKmq+JP2E|Z%~A;X-+1M>7FDOq$O^}~bs!|%dM26Svf$4vRVoqp0Gil?hO>D;8L2%`FK zGF#zWNE6*t=}eg5hpP>*<>aB%C3g#&4b||2*h-rn3|uAItA%&5p}Y1dPj=I>RAxUl zLvoBl$t4(gU~t_7?kb2!5vm4b7pw;O0SYw2^noUDPovzu2)iT;+0{Zkiua1~T}stN z4!vMp)}w^*o&F?9^YHbQ&f3eXbsuqzCE+6!lVhm!2nqCzL>F7~UX^5jC1 zlB@pf(i$8zS*bN?>hJPJ7%+eHs%sQ5f%c$q-;|kvnQt&G1d+-y<9$rGba*UyvIwsD z;ga2hPIUKdHG%c)5ZqV)2&3%d=Vlgr45=1aDHHEk$|oDgwfK`nW=+CSk&lF$lT-IR z&`O%JAJXsSP3H}NK+*loShVeP+K?6Xer&|k z*~{`c40-~^Y-|RMX|GvV)-y8=%&CjutJJigY!@Adkx&`I)u-^R^q=~#;)<%8^aIV< zGg1^{OPkDK!quWgNSgd4?5e~KZ6NX)vmmM<8(k%I0AdtNik7=U<^lJ>0;@8`C$;TCqW|Gn4BQ{*g>e#>oFJp+b{9YdX6QME%CU3{w) zFO%G6SBDMcCF`^XchmUG;12{wl}h2ngX4UP`X?onEA6&k>Y0>2f{d`HqCpuxsrBjK z2B#@P(pGqX+lgi>(;cP>MB)ojrgc*|6p4&*T?2O8W;6u@@0S4nl6yFbcxLyO?4ep_3ASjW^xh`q zrPzv1JqDUAm*caNXvrRO8YtU{N}R7#Dx}jcGG5}g59^isPjCzslzE-fB<@poVFRx%1=)vfx7ZyhglZ{pUqk zYi2X~-u1v5_gDCb^4#7ZCZ|`}XQLd}#OzX5?o>PG*@KsIF30aX;$=7Co^?OI2L%-h!)I*jTg@^{tTh#S?^qZ0Z|* zZ-$i_7x+B;zOJ4kL<{JV00S=WJ;x$Y#A6@?y*~>IPOK z#k$2tj8FDDzCXzk(s8$ZV}~X*VQm)^jhj7?GO6Ae6nQ5n)9|r7Lh?k*{kAcQ)07(! zs}$hLUG7W@(HPwfa7K{GgKxo4DlvlUmf+g?hY(|vTvAEpbB(@iRKfu*WCm_mFwqn8 z66uC`(B>zC*{8z8ay4vwB9IOZF;_!9RMW zc`rS#!p^${G8!SRF37M8J-__y(Nxzpx8OWz~M zvtJY}holyA{irPzJxVHMl>{1Ml7Vj-JDIE1=~3u8RD=ASksCRL>2apFl2aFWxHDaj zPrrmUH~SuJgZTU)o6JJ1nPy@>g@2D`NQLdpi~ZJ9-GuX}>TQC&Xo?#A@DcL_1j3fAaA7+_Vrl7jTBN9EO(bj?ezqI`>!&F1(byzvu6|H5Tp+5{N&th0N!u0 z2qnl8sp7i*s=&*>G&D8s*S~wuRKT4l9KS>fkGHy_n5j3bOd9I~N5uwwndmdIgqIy= z2_Acy!rhr0BUrU>?=w)DwXyF6w8CmrQ(lN{{;2~?oaluV_-H1iD!$M$2SQOgPm&>T<`uY$rnBZg>@^#bR9;XFcF zUorUstMxwOla5imt8#Feqg>$8)(_(7Zh2mv;{Gl9KdBf_m4RD%>~s(xpFoWG2?g+v zTv-FX%M|j?PKg9Y?3S=~=rcFT*gJis{ppn6r1QoTFD(|$jz#TJPXCHnRu*gxzsE6| z<8&Ez#BB~Scp@Ii1F)K+56LfsfEoFdPs|;DHoH9Dy7=&GS|mVA3R=prO0!T8J4?0{ zZ?B$aI>i$r9%>Es$X2frX583JP|j0ottn+U3pDCd;Hlt2s$1x|*r7X{)IwLJmg=6j%OJ?etTx+`vVZww z^MP>WFBg2}!}?cHh)@x=SKnmjj{4yHUmh210OKP z>a<$qjq><;a?Zm(>#x$wPn|O!KB?uS{Tsk9HKIXC`p$NLlKo(&|7s-q%Bj=0A=Z-f zd4{iNr{umTUO_*2?`@*hn;9B9T#zx`ZCZdM06^VcV#6+RrmR!4&~o?X9d^+3ztVIB zq(<^#zczM);+6Y)>zj2zAW!3c`VX`xDmKHRnMKz-gp{q)YU6t<@k-spP@g3{0n3$k z8=(O*KA(F^wAQj4xhDI#BT>i_5L@H2`=6W1;JgT9BNTRy|G8V%`+u|4#-LXu$HoG%2N)v^nF)2QVd7h4t7IB0qR^HexPz=1oxp`*Q(sP~I(P@%~NX(oTP z@O0%eC2rqx_gd8mKILHVwx5+loar=lUq>@=V?vII9vCeO0?J#p&-nEFXfr?P6#k^n zAEyx4OfTBphl&78n3svle=gPC7-faV?((O5Uf)_HBXBSaiK!aL%D45lM2I^J9+XB% zM2CrRYO+_Ho*z*Fvh3Gm-MkLo^wlcsM7O8kNm}YUNTA>P>V0pWDjEvgxAyX10v(FLXMOBu>2>*X#4C@RvU37;`^>WwX3wc{U)w7*Na*Jzq*r8;uHwc@g9Q%rPv%JJWuR7TnqzQXtNcW(YhTKdx5S18aV@a0+s z|2pDn6nN19y_l?EphHbKHhVansiChmco7xlRhJ>=O-!5Imp}aT22D{?P0?8`c?(tj zyC0Nz1+DK->h}H7fty(JvB80LPeu*B`|a31sMEcos}{MUYsGA~`!p(Ji~*#XnsARY zYHrzOEoXU&vx*q&ZQDsCNCc4XZI~~Som!Buy@Yml&LLQma>@eS2)4l|yo&y%$o6E~ zkN6fj19tHny8gn`@hU)nHPz422wG9CwLvMhXvaI+tr|@=GJ=(;fkaeit{FLAf;rTv zQX1oJACDQ~P%EDm!w9wiD8@|bP4y0r4i=fdcMHl^dQswivozZSHb-}PV-s0%C&Q-E z!GpvGG3Z{cyoBhCbz!VLGso$B#uU$`L4jS<8P1dD1o)O5DSRU$@ZbcttK~_;Jozo_Y zCQP;ColWAn= zVn&E8xl^NbDnEiLHiEYV@+Uh{OedDl#ifyz(~UWXeds>^g2>rwCdb%%Jf0+)n&_y} z!WV_KwvNLE1BC zAXFTT{LrJ5?X7Qr%Ptn$&C{`yGMY%h62zvP?jF0bU8r7`?+`jZlG*4faTR7Utty^jk$7 z^){aL5;Tip=b7hj?PKYb0A*SZi+b;8V8ER%)nH)@w*~2v$k$^&`Rm-%{>N!nmQp!6 zwO>Ps?i$u}AaDND%e>!5%;CnGYIR&p+<%a-cw>vy{)K7mtYky3%n>ESo2bLa)A_b^ zT-8xO<;`9L+=8IxiNI2arV?gI`7A+aTXo`lBNe7CQtZSnEO`K3c;$5#_!9%zU=y5i zQL(*R!A+FVS+oXITuG<0jvQoq`mBCPCScH8 zRIb-~B)9#yYW%ts%a*IK!P=S=N~8(x8W(cYdrw|-mk%~WE08b2yKwWOiF#l3spB#S&u?0Z%xc>c3(G~;;iB8%?dhWUE^ajE_!#9~<6-Oo z{_Rv7wcg?j>m@D!#*K)xCP@^Nz+=Uk6T|Bk<`F@PK~D-!^l*NV^ENhu`4)pm(sFQE$Cr!{J%cmD>Qz$=}?#=g9Tp3&r-AnqXCiHTY+C<5I9P8pta)dr-79xrP}o zqj%y?lf#>#3F^f=mE6}9~;H0@v$BRrUya#e+#Wjwv9K0S%W!xwN0?(Rk z;7E5LNL%{ojcs%-e@sY2FfD0@55IatBE~K3#R*KuI35%}X}EOJ=|#bwnq178nPXeg z>#cp472ll99UGCofebaJ!pA8e+C%#@B(>f4wu>rhGQgZG#zLE8+-fZOrBV<)h-ij?SXXx$tH3KH;-v)hl^@$ zi2|(1=VR#dvi|tW0(j4ni;P9n?(O_LITdc~Kl&i6vR-k4?~n%U{)^!T`FT7J*dmbY zjS0!8@9+KSS9V%e<&jbsmgk2|CSCimY=aBR(Gw4~`rmle$-r^eO7jvte~^Uu9hb)A z+TfPrU_x2jx;XPtNEHo-L?L$$lk@KOIi z4iH?5=LM6hl(eZc(>D;rak9?5-$<|DJ|H6v#$kyd@ZRc%kc#}`*I5HiknHaZPu%OA z_&JE-V}`i&|Dwj)f8rD;u7`gPKitB+_QxvA3|K#|Y!2uNEQEs)!%`-QemGghkN0HAB%Gca#xVg#G{k8JKiqeoxrru9RxH#|-hVmIbHL$PoIV`2Q*O zQlk;30|Z%#L0jH?P(${Toc&`#6lazyg>HHecAknq-PIK+TJuBXsv7BG(7wPurQ;x9 zh&U+f6k2OjsrPTT>HnlFwA?ui8<+_s6J7z^mpGNQ;1K)vNd|j_dYfu)v@I(djCCG; zPOh%jkhh@vAHbydzZUTSG0J{qC+>8x=bpN=jvoGAO3;OvF+q~I^BNArdkZ2AQ5;_s z{EZ%*XnhZKJPz*Yamm3n;vd!I#`dg~SeeKS3-b&KfTR1HBfv7M)Y+b2cu|UgmLGiavwrOu^!&C-480 zp6dTE-vS*Z1zI`w%P){9BBHkHK6XK;glK@xSdQo1X*lL*6LF5Xi#eFM4e$_sJ&$Ig zErA!$`-QV9_Z06cZf&NKTho`w7RtEPTjV4_ReY0XxL4cvg`rW?yo)jeDXUXZTGlIs zI{j9fUbUNV045D`>qqgU%c*Uo4A%1gJjeELZ%bwQmhR*GDQ_%i59g0ZRg<+SlvJlm zuTIyD7i}Q&)2wAJtzf8J7n(_S`Cwr~1c8tncIaR?dW@cXN6pAH7Cyt!@lC&r0@l_J zK{#c3xVz|OI9atG_}6b(=05i|Yw9M`*I@4~T5noBb2wf@`$VVW?bK#HMK_k=jd zKt5Q{J^wf`$6YA<6iP1(aA(gm-#tFY{g`gx5w12wec!sBgA5xsz6DV-BzPn`GhsOV z{8%q$%bc6goa%E1*$$&%p$T*%3C77wBfq!&y<(sb8%BOn4Sv8RH3nlXnoCMtNFS_sQ=y)`#N3PT`S3ATl^F zWd?*Xc32xAgEeD`7dh73a0sLtdN14^t>HfdzfST@_4irNi-yTWs?MNwcyLf~dVhfj z88lr?c~Oe%w^g@B@V6yUkE=L8K;_QOOe?x@{wV&$@&|0Rn5TV_i}eg0i;48vv(uXQ zr5W^Rz)g;cErO-!8w9BevrM#<|NYk{XZZVLGQtuaOylu|BE}j&Bu&-#6(+^)jQ&%b zmgjMtI7!E;(@n^X`OqYZE@r-2xZz7XbE0T@seO{or2@HZ?Dcy|vZzCf#(5Qq$!MoB zP>z$dhsiH@)3Y*kKDcn+j!QNn+!etu^r29=w^Gd2c-jFv%*g3itq!!-lnv#pG^OYr z9mUdFu2#vWnz{ z%1@u+hh`;xPhPZ6(le++b|)U1KPx5pTebr!S9lTtBQk86VPXRBknPZOv342?maORm zpO#B~KGrBF5LY-TOXe9WoXFCqcqx9Jak*kRG78_62ihW0AOoWL3entzJFrN04SLw| z5M_KD>Wy|MQ)!!SX}6@j4Ig|n%!^4ed}ho%Bhvi$h{J%P6_w5tYE8z5@+enKU)6krLRYtU_9&tB-JA@rCaz}nBmJ= zRZ+eyY@gPoyIU3m>OF_GM!5(abR33yY~=KPC*^n4$c|Uu+h?Nr(XnT2V`8EUT<;ak ztV=E=hYE`6kGOY$S5X(ha>rEHz;g5A7+S@yGvqKnfH`^Da+-B#KlW3!-z$ToqDU2C z?wD4G063B|=dT7OX)U*>pm!~ilW&9!2h2;W_j>t78mpEyyPC{*1>gZzxq4X~ zQMSa>*i*^-bN;EhZs3w*r;p5j!R@T^gzq1`#^n<#tl$}yWtF5DYI<`5iU4}uNu{yK z2Q9GZR&Kc+^BtTo#BjBWDbA4QhEqei*_W1-J&q_H)Ke({#qsy|e02R3#Ux!Iku0|+ z`TRSgw^~$4@Ueb``r(y3S=J>&Pml$4V4v)7YT3kOX|*>AUggJs-6CsaAUP#<%J4f^ ziZAWX)3hL5yA&NSrs$Zrcgq4%DiL^J{7WMz>g~c|Mr87}HJe!)*1y)Np=d5RnB_O; zYD?DjdzCSwerQLIn247j@9c}eZF^yojTpYDo)n7p`6=pF_6&%`bkEEqVQe~xTD=6kR8eaDdV-mizN=uo zj@!&muQoAGt6_TbPM2*QlKX;cnnfQ=iS@6z`KQ|!Dg0R_{_PouI zzniwJalXS}V(3A9ZL?3;&AA19P=5Z!WpU*W3FEen^Z@_`{qpb2f*+tG&A}J{2V|cj zBa*4&>iop)lP*PBJd5!Cocoo6xqU+cFIz5i)+vhbDgXXknb`t3qR4;xbVWoTArLmu zIC&P&BU8c99vjG8$c})~(*W{vRE4?mdr$ZvG1*2MA?>D(eRR-j6KkTOlK)Hj+HwQx zi-n-Q?~@(l!_>2f;aBlFi>)-m0pN!_W_NA!u#@(H|M?`El)U9AMv$k>$kdrD(-|!; zW{~Y$M_-zkj~GqaD?$g_)OM+A;e%}R?-U9|`~PzqPAZeQWHx6HAX`dpKK4G@cz$MU zDm$vg#wH7C29Sq_7HZGjWdR2X_?EjL1mAZvq4_sekQyW3N_dN5N9kM&vGCQzAE!Gu zNwklCm7BZcA}DbMAQYjg%)6;<$Q9hP?9=m8pt(amm-fewDq1kcwmT1 zaMSb*6Cu-juddbAzLq5PvdDWTD)?of!;J-p-><(Si$Of(j^HBrz;Jb@6r1YlCP&W$LqRx$H{6i~wi;RA9hb}52|$ENLeT1%7^kFLT~ z8acFAdoE0c7NTk-!G?bk)RTbmGByCGaclH1Ap`#Mp99JWT+9Kth`i;sq4;?Hxe}*6 z1QPzx2oCU)HMqwJUd45dsGI_DQcr0GiND5zz4s?0Zi-2maP$~C9-!k3zcoG6p^xyq zr_JE7J`wcvoL z^)I(<{-^G7;(A2a{jyyv#r$vW*_Qz0PGGbE?#i?X;>_RQJcZh*C>t--b}1Wt1Va{# zMq~(d2-Rn`CyH<%_&Z33O;DVqlN(%~+f!|3tkYyWZzff~TP0_uVmMuJ%P0z?tkO$|0e_TFP1@Vx7j=##1%GXn8QAvjiZw_4BZ`pRq7Oksq;8(+Cw^ZHnU=u zlI16t(kHk#?5~k{tq`XJCy-3(#o$w+`7Jzk8Lm`yI+sTlBjv`cknqRg#wgXq4%!QgdH}e<{%-x}SYpm$NAzs#e zW0(ORPg<<J7ZdJm~(U037L`25J6+7xS%<%@@>k8{tbK{| z5Wh8wi#T@r;?k?D+u)}|+0sr&mPXRCs8c1h^*2@EQho4F&k7#po9U4Ob1~~3=9gqp z5n(Tk{%>DL^wRbwi?s=u;k~&$dFc=^s}>b~IHI4#*L^|`5$i|FXFOP~4@H&+LH^7z zX1!jCjHDz9G$3~RlztU6jGu@8WL}jyq0pA^?16nvf~?pspn{Y{w9}PIrYyX1NKR@+ z2~x!Qb0ei1U#OjGnzW&wd*aB3Ck@y1kc{|Sh4^YCT=#Q5mx63^poBXJ>#qQ6kfUk> z;Kxg~`+1-d8&hk?9U0EK`sq0x?S@$OdQjUR9x%v6t}v=vr`BltaaqG!T8yN_hPwn0 zgPGxhd{X|O%8v*8c1hF|iO}jt%h3>kj6|UQm}9UvjCGGba}Nz-!djdo7VK<6E2Kd& zjvZr@3Ptv))pn`A9ZK2}z-?m_T37HQuWdf~&E#-7>fLj|?vvj9klwrg(3K%kPPwFw zoQL6{Evy8U7h=ohWXnG;ed^FqFci&*KM=SLXa>d6?pA!rU}s|ui_)yVc*jjfa@-6d z``O(|jeAf^BEkINhPm9TqCbhVwj|`mIa*v08{V~Ph1Yi6Nx|(WKPRP;&6>m{Zjkh( za&tm4X_)qL`%+tpa)b{qKgq4XkWj|cxV7RQ#9)xwlm~VU?iBs|a8qOWJngAXHiMx+ zY(=V6rvOF-+g`^{T%j=^jSWq)$y;{(=lGptNsj^`<_Y_Mij_JJ&+@~A zwL~>P9m#pMX34q0jN23EnDpWVB%0C){BwsrKp?o_@G{wAyd)wnn-MBVH@7gSIToWh z>tcIrc6J&{#NPq(t^~A_Tl77CkJhOVo%=zh4sCbk=HI-PMxnQ=*|6}3h$exTswIJJfJn?hSmxcf2+qNRZiB) z`>X>6ncUeA;d0g-EIoTR(*BV^-tLrQx|ku202vQvp%sLv9c!d5uD!RE94a;ziaTxR zn}1f!5-1O&EMkr3!<$tS0Tc*MvT|2X3XW=9fEq3sm zm!;f)5m}Hzs5|?fTj%UZ-m(%<0)N|DB`^NHGk*AO=REh!5(2;5qaVlH4XU+{;D=zu zHCK*w23?OR>WxCaT_$|W-JgaObd6%;oXy)jUi=nYQKfiP@@#(h?3FPjo3O{`Nkxeu&=iz=(w2 zyFG7G&4u*+t?Q;zMq@tI@mk>Oo2gu`odpSq(DI0E*YS$;@ih7)b?U*;!EYmVc)o`CiuhuCIBjNsPXceBx?giHCF7Et=IEz(Z3XRPwX+d~pAM@%olX=NE+$;v0ao4sS z#Y#%oc7P4JCsypdCjm+x+|TpO+(kOI6OgGI&Q)m*-$Ugst5AY$5LwXn{(V_ySE=hK zqt|BL3~qe$VZXu9D%WTA31S&q+THgt*v;PLI;Gb;InDj$i~?3C;Zn?bDEIXG%##=z z(R-4OHNbe9Va?`Z)C+D3`jjm}KgjqoSs6)`a!LUQu+Q}2AE4I&1PW3hJ2SFfp2ekf zq?Ky>c#?}KS4uD|G%HM47^0pE_|N zeNyLQY6`}O^GT23YV24%KsY-ANF%V)6{D#VAU+DzNF`JjdlhRXwBu9wyAFBgu93!Y zL337V+|Wsb`)-_@zE~)w>)k6*`Axp2^t=fZm8f)p72%2&I9yxuGn4Ph$#xVkE`@!S zs2^h}b$uk?{PE5Oe#`m!W=Appbaa{Ke9Y4x9EK) z?qI1#kXRjk#D)ulzDszoZf7&?R`XXCHAL%0>GNGUqV=&rc=8#g3WNL3l3c)Umr*~& z!MxsGH<;-hx)7q^NsIvwFr| zsrnqKlI2;7UM!*5kT?@BNS)vF;U-5%y3dfXB!H-jWLgjUB8bEo9R3Rwv-nJ^AivS1 zpBJYSEnz3-9lU-GL7cv>FA?ukM{!3zO6FEd$Kri&T1(uUwPsBBDyy*vzc4~i=Dy?p zC%OLGdv8!DohdCeT;DJx&PiJDJ||v_3(v3{T)t{dA=@zIujM!CVS4)+ZVOtP16{hS z;?7GW1c@=pRBw5`ib#X_43=Lm8Pv^>IyJ$)sXLrXa#wI{< zD(c#7z0Cey{umB4G;64gU?v5dpZ*@NaY>^Bz>|B$voc?Hz*NO9YJ>aT{de8U? z58`y-^6&JW6C~3*%Os!SA$w`emObp5{d2ikAKhZPXJ|bJr0Bohy+9fN$)|v(FJ@8v zrnjloamMvD@03K-mHicr0+bbA+}@VmXQ^m--aeuqTCYV-n~r)vPlr$--h{+(iYwM_ zVYr=Od_{kGqF46g=&T_WX^aD8d4e9FLOnLKXErlQ5q(^1_}e1ET9$EC&ha(r1j>dj zb_>#lr7_o?IU2LGlt}_U$Izsu1Kn(LyU@U}KXy(Ug{|vP7`D~bxOuZMrqC!fR!8!J zBAEIU_CffYr6Z7CIRzawgo5Fn@LJkp%~3BD^#bdN1jk^DHn2x4CHZn{gkECS*F%Lh zaNgAiGN@3u7@)d_KdNd1ZTtF8`>ZlIYP&2A!~L{Z<4qqTJM~ z_n~{zyKF18=CJc9nh?YnQzTFPOgy-TM&_NvC-P<32Fqwiy_(VByq&Zce2HQ2V^yBb z%8MKY4PKY1o+d8usDFaDRz~FOz7w>voSHBCx8=o~CDtkP885b_f!5<53s}{S)F|Q9pB!?YR<0=RY zzsp~SOdWP+tw*c^ng=NYU{~oVC!`u;N^v|3-_yjNuSo+f!wFYQdj$$Tj(vTYcEYwn zdLnyzH&oF0((5N6nxOSrFki>KN$ffcqw5xc6V=4?Cu&y?HE**xru(4eq~#23K?j3f z^8l00Q;Dt1bz8>SZGUU~?WE_(p2p3bR)Lynq{`)(LxeoP4eun`JZ!+*hM45C@Y4+7 z9;cEa%9ssrtCX0lb)Wcw;9E;$qw{~Ci2$zt%aw6G@(;Yj?{e-s@bXJfnqS*w6Q)X&bsQ9{z;)?R%0eB4E#)tJ;`X!E(F+JoXW%`J>?dwAv1U zYUoyJ>WNNlqhL06UzD0L?p=hgVynbA}o%ey2ONq3h;dF=DNKqs2e7kEMMtE;RsTu8>Fbo z`V65%QY&nG`U-YO{`2SLEaBDTYGg2C0UeNglUHc78PO>Toxtsx_j9$&CQ1D8w z{FvKu78p6KeS0swQcRy!EI@Ju2ZZvj9d?RxY-Dw2z#fvgCbsPEExrR3 zU=_K&dn}WP3eWz^I$wf2wj~(fK+}GcCK9+!J}ZrI>`J^-gH%7{rr4j zQFu59)2J@alW{z#?yR%XLj>L{T1P8f=mrSSD?!X~U`7Kl!lNWdu*{koP)n!40BD;k z?@btuz+N{Sp^qr=l=l5nSQSG{aq){C`M{KR$MX5li192)%Nrrlmi(ZAaV04ch}h=B zRr=GXROFlLY@2|f=5^|r*JmgT#~%9Mh~4bv>-^Ze?F!GD6tkLpEw&68-d+eOn1AIH zm@=<4Za&J;yxcAJsCoB_e_Ioa;J6%T>3PBU2jyEJd-x)nO+$Y9IrM=B4}L+_0U#uh z&sE?hscfaDQ%s&Jl){nYH*xjwB&^m)$<$bE*HS|R)_GJsG|5dU3on{x-F|+6G|8t#AP+l++j@JQMqUk9h(O&bB4m+|^Q?p4mhvlo=X z0Ns}xr&QTAy~oBo{l3>OZddZziCf8jjXPpw`(kLBQQ7N5n7PC!UVBOFL6rRGa{gX(yHajjsFGtxcRxwg6p<4Eh7_Rvrd)?lu27ol|iB zR!q_ycPm{zoOB3cghVYyp$gp--*6?|u)s%r(VMO}e~c2KmHf}jUm92*_ai?S^lbhI z^|aC0;P$`p)#7v_2_BcARQ{nhSeu+g_kDd!XCfBorM~DpQy+EDqD(JpBNNHRJr3^W zMx{*op00eRj(Wtik>mi!cpbpo$V%+pu#WR}ekmuwnVm~B>sOrR~0^udnj z2Aye#_@_u{EJ~v}iCZ~*(kh6Z)25I#pkDvFKM?uq8|&W`^}p|DkbAOj50pP|a3QZ6 z&YMf5ROzUSaon61S$k%5?85Q^0Q|Vh(0PQ(p2mYaEhQjC+KJrl!&&^jH$yweOM&(~ zm`X>W@);k4W^B4tKm7FzV zgmNw|47pdhdYeAq*fQw*41$6$QCXA09)&1XwxMy;f%!lf-{i$!UPp9sF!au|wux-) z4kZx+#RdxrFLGJRGxk*KYz63_4*HG3tyWSH5k_NmR}MC-VN z0Fjgt?bi}#rDkUVm!B3AFJ{K1yRCatga0=9*5n;Iuqio?TXwr=lJ9UEca-z8Q{Pzi zP5vrafk!DGQ%Xi8=D%LNkiWg~poT_j-bI z^bt+w=@2K-?d?wn1f-GroH{lOTh9-@3r8+3gu%`27mu5y4DOAN9x~Aux)TMHV%J5z z9}4W86^sbo=-mE<0X%;6Qxo0W&S@@1LUFPCb1l?!xYW#+NU}gA-Eee~9GB_@`IIk* zSQwQna_fP2vq$^+ZzFjj-jvV(W9yx|1A(?}-PpEmr()Z-E4FRhww;P?+qP}nIobC< zthG-&KVh~uU;60y?y2%4b=}w}kUiS^uM#D_hA!MLwDqi8$nRa&dA+?U(`Tn|usw#| z)$Q@iB_C*mIxW2V8$G%-P=fhiUkDH&<_qBx7{`!^I z!-pEr#_xBGZI|bsdYg{$wg8Q5Vd?)PT!$Z|iUjK(KzIBaTRIc(`HP}GN#HR`H8RTK zD+i&G*hoRRJ$mgYM;!OhMKG^ifL6M7t0OGxvfma6DU_U!ae^dQX;p z^S^2#h(dh&c4fbUX&F4yq@s`qdLDsb?!iO-0unBTG0<+KMtXnHwGE4RVl{LdN1dBG zAmQFg>2DcU>>^cjtZG`-uPhN|1}P5O00}#lhgNn^!BH0+c|>)pAU&ZB)1DJ_^Hi<; z0#=sI=Gr63B<7f;dn&?e6;<&eWEo>M4q7eFsYhqfUb`Y@srIGpDozQ1&pHff}bf`Mk*>Q5GEC> zBq2#26cIe_0+aa+dS|&kz1JWH-;ye3ST4I0J+KWBGiX_Sh$?&r1KGU_=5GkUckia<$qA^ zdtpP9_OQ9A0!*TsR|zEyb+fK;GC(`8r1l*Ty97}JPav3JlKDV*vXjeb1@XO36@Q$1 z5eCTXbN$!VX#zn8{STspOBOUGSk;)5x*Ujkt2-R}>IHipU#|dxF;PM2+3F7sb^wNQ zixy~n&&}QfxxAfKqW}W7**W@e`wLQ9Bup!x`aRBk2CL?#^?r4*4L~2Ffd6)0uQ5)$cqSD-j0U6YlrHzopSBjAtdkFYnH=1mWI#qqMd=J$xfSV!l;f6Gq zf1FV@NY2+61h|7 zc-fr|)>s%!yMB>zyjLNZNYsl+6fDu}`=4AYUGy-gJ@0T}1fVlTDdi5R^3WiAc|~Wp z>;C+gy?+Y%U|33QF8B9LfWjHj8Qjk-ymuV;;H&iua7mxD_Tl<6fzW1f*p%Q8nKB|D zaeY5?Bp71;$&UkGh62T1c#jZ3STS~~rEL+BYM6)bM$w%5kHPf880ro9lW)SBjZg`0 zB<^o>sn*3SZRopuz8!cr%ETjJofiK0AIQn!KP3T*c0#}^unf3;SetvuG6|v9e~odz>DMhvxU`KPlssDF%Z~Ypm+VcAk^W+;Mf7 z@(tsbgr*3btfiawb|Ul@!u?n#R!?O&hcmDL(JVUX`xSg&|BX(1e?tvISl~2OPNTE; zzFB{V@H^NJR*FG*1q$}wcFSf5B=qU)Zg7<^4SF^lPRF4Fz!37$1(y&!tXf%d>aD8t z19fsaA2QO51PeRj%mrrVtn2WMNhHXL)Gi@@WAe{GKO0_hIYE7wv$o|AowpfbvP!lI ze1cwHuddi6JcATwP;!X~L%T`t;2bz2YLCO^e5D>?At?Rz$o)m>Xy)t`gMD!0hqti@ z)Qn_xJ{Jn7AMYC0hWuihG39(E&}Hc4{OS2w5hsNde-P&??po3aE`}qRUQ&S$H5fwA zJD7VzRPPO#IBy#$Yxiji$$ZX!2YP<@d~$GY1bzQMQxWtR!|Kk#f~o)>H7u6QPCwDY zICT6eh$3)efR*nBgME}Cw z7jOP@Sj0YXso8+&ci;dynCH$B;|Q8omEAQ0P|J3(N0ND0f-ak?L92gcYic%`zC$q1 zCQ(DZmI}n1^ye=NdxFW#o|>D8|1%uY!vbkdZ8mQL8m~u#)@={WJDV0HNx`R4H;<+g z3k<-K`{|{+9A(w-*INDj58vrOb1PWk0b)ZxD#PsVC+lV88*>+ZK-aFO&qWI^dzI$8 zZSyH2(3e3X-B(7rF%^qrG%yS;!j6tUsk#HZWa`4<0?3kyJ=Ty!vfA!T#q`2U$cHZ` z#ibY==Smbo1T-apAt|o>8279b`9NLOK^{Q`QNX-L2?|D9p?UQmIl1X9phR6CQN{*oDP(Q5L%24PuZ{Vm7#%x?z5O)2W7X zYR>l?Lnyblh>cUsqAKsibHpqUtjW*jBQS=Z3nguCsnSP3gWoXHS#f*tpXu!Qrykno zr!pYxzzi{obEYew6fSq(=2tGJ;T&80%*vI4cP3C8pYcgQsH9JHK=TCv3fyL9t{Xu# zg5^3ps1LoDobKhDKE_E|@@hr|A!-9^7jxr=U#M^u(`DN?s~wra;ACe9hEjTx+m zac2=E4QGttFa*9yi|Yfv=uo0``tk1pw>dV5|Crhyk5y$RBp>n8K4PF5 zcjmC;xKZ*DXFs#Cmedy987>{Uv@mav|BLY}z9K_gvO;2W@wIh zUL{juk|xpd^cc^Ro>>M43F|hEm6RbQSg;~{y4tqDAaP`;bR}F&jFqT{9Cf%A-ZGdH zKH-^i(&R=uluf~Ru{AL8Co71?*uA1 zoV;Bhs&Z=8p3l+MJQb9A4a)e9PMkqP()o1=58GiBnyu46VNWPX`sslF&;2~!-ay(v zsjdo?wSPPqCo3fEq6+O9MR%f6jAv^!9XfZhUo^=UJSSEem zA6qV{p%VqnSdEnk>t%!6S`p25m%BeaA2`!;VOBnld7Y{r5k^%wa! znif?H6}my5VrzBL^9;Vkf^lFd`O;ZK+`oyX&c5sMFLFNLdgmjV$yLfEF0LG@UxW9It5ub*syimgI_|)BQ8}bB++9 z?5?7WeX4UGA4-gGg7XRzr575m!uns_0zH4BcS##csTQ3?vczU7l3CiQQf@^F@wR)P z3=D+l^4Xv2=hZ|kb>hwQ)=+wB@8yOD;Pa!5ftyTK=h*FxJUeq$GRg61=z#GF8jzl1 z(`d8HlkcT8NRnW#`(tFf>A8_r0q#c`#>K7tlR+LS+QIAUx?Luylj+JI{m#<*x+q8; z;=J*B;MG`8+w*yM9U2FvD2z&7ne$M9+ubb}wFGflUW%aZfw9hO8>F#P(;c5&PxfZZ zAIMbl?LMg9{sUS{L3q0gHM!(SS?YXzNMj9YGx0aiTC}LSdUrPZIR>vwm%LS7^D~+KB zI#&^JyC){)gc2B=atXRo2_%+V?t!{meh|Yj$DN?+%_u`B2Ejc<>lY`yydeU!@g9Z| znV#Hb4SlH2Vn9O>`*q^ZV^F~CK&it^eXP11^iP!g%N8C5hCLz)vp3<50!Hw~_hbQD zl-jhTuq3-;WEQK!*BDDUqk?A}j4Q?oK&C=27IPy1W}Jv?>RhL1uj)KwWrUWpJ%tl0 znr1AT8=scs=<7D6sy89T5X_PGJ$hkjYjP!m6_tX(fT2jdQU<)7NwoI z3Yyo9I#~59tLKDDg-@@IW|BrSw6QfkxXLVSLGeUwy1T;njqj@;VJzoHQ4~Uc!TUBH zLs13y;jMS4cy|W0DY;WnifSUZdYV%Lre(@hm^=w5k24E_UbgEE@3vjTgtkQ457aRk z<#>D0R4^quG2?sOD%G$wp&G2b^312{1wj%pdk;L)D=>~BaPBNu3B^EiECR_3347}5Tn1Ykq&X|4|Tkdjc0 zTC2=K@8o-H6a2#@z}n#&TCN$W;%D(9zSUU%)+Dto{jG6ifdc8qacS$uO*>VjzCwi< zE�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�Z9IJzlA2B287hzd}o0O+}^>}!tbC{ zNd8PM47<7mZhK%@KaUY@@madsA}0DBL&BM~zF64AzwTdEdmgI;8|YK20NXGi29xZf zJBioLGCVJ**5rmI`0IQh*g0e1ZmS7z>2C&UWApJE5P^XPEd&uZsmj>%t3fp!o z26{6GN#y)ge^nK7~&a?=f`+-f%OkN=&WmqC4Y)mvHhWFG&?C#DI~ zVBIXRU{TSLMLUXWGxT0&dD`ebz732jL3lF1#IoJTxOc#L<$Ltg87q!mR>43;1$_d5 zAR%P!A!)BPzh~{US&_{`Pl4?F+BMFc%T^x1gZ)rzvCN84DRrivfWlLeACvlU1Do!K z8vQ&8g{Ee$CH(PgY)-FnKMWUm!#@r+M7|T;=mf;Mn?%(>+SQxsF;m!J}|fo`8J`b{^3HhgD{ zx?!C08je|01zh8Nj%eW(UO8_x2HTN4^2grm1*KFs>|`;BJ@3k5nyop4{-RnxqxHjf z0i0AwV2<@G*x9rl?Di3qFCbHV@9DA+tHhH*GNd@HxZ&{cxKny73qt7GMkKG3#cYp| z^PoFTMZUx-ggoWRKMi-p;0J@}0FGZ{E2{C;?;yqF-ov7#LKb~a3geCNDalP6KQ?fh zp%R7AZsd%trBw-;26G7pVr;*TBTVZJJHiK%4$U@D$nkr8JQEos6n~YqGqbSo>Nkie zwW_y7z<1%u}ns1MzLlIAaskt!U*ac3|r!-cc!F|WxR!YZf zj$~1j=0%xjap!mpV!;-!VC~4^eu0%P*U;B%>S8Y^>fm{Id7}YRVjhx%MvUKGZ(EV} z3N_si6XX;j)z-l-O|m>-(2>2%?sg5)*dqqitP8OV%bA?h9xSz6Atff0ROv0H@XdVD zSI5F}!sOr=9QV>dr4V2-(mDzfc`PO330v^3#hA4~Yv_gvv$5zWPkv|MZN5EF%vHXM zY-k^M5+F7IjBHm(r2@iGuG`hNP}!PdrE$y%#91CZb-h?%3|! zKNznOH67i{nO2_IV;vir%i%#s8`HC>paS)m995OQ&q`qy6d+D|T1kU`sw+9V?R$dH zW_6hzB9)$HYnUjs(UAvCCxi*IVJY0X3w7FiL%p%EmwBwO0v+sS1tWg{rn~7TGQupH zTKSZV>Op;3v0CdxR8}fb&ID~$kk583q3`y1;{>D1eb)n`M z%I`YP1pP4xH$-;fB)S2Ns)0xL>yG%ZcA;L*DC{7~QO zz~UUHp`Ohik+gl-%IO((pdZo8)$r87j)JI2Ry^6L$9{c*fN6`)rOpMUSBQBe+iS3j zU7`JRSfy?`#WIV6Gg`t#)&ObWVxm{{G5gb}gVL6p%nvOiSYE|4zW=*H2Yovtl4gwI zX=p|TaUH59(U-oFB4O(Uj4|#at{!=1I0#o!#9}M9O3n57n-MDnYz0IH3*%NRO#38B zI%UHmv%g>(z@YPh5Mf(5(Hh$db-z|>G-Mql3)xY>-z;y&16IGa7?Dt<4jd8^#W&t@ z!!#tE09w?w8e*Z?=HqeH7{C;I9Q*4~+cj%KbtympO))hiP$pv4ZS7Dm^dX~gA~7q_ zW!hV~(pimSrr}ubyK-N9wZfKlK!&6J+`aXV|t?}W~K;VXFH)^ z7z(TdVDVLXs-X5}>l5{8A24`fi#?aMl38~#={swdA#(Zz=#5`C2Uo!NV(uP1o*roT zz@UW8JOYKPZaZlsp`Ge2qjRHm9|55YHm6juntJj8Vk)FzfHUrPoql~W7$`UqDl0)v z0$T53|C!G}NG^GO7=sA_L~KqcdtwvYUZUEV?+OMpyEc_^74P>}A> ztc~|FoFlARdwU?)s}>?dNMwjMugpe(ofYyVFocVoQ~_JVXq{vO%h6|@-uR->1Cjhk zT2WCa9Y0on^rcjJ%R=~rrChZ$xn$*6D5x740A}=iw~gV?b^339QiIQpQoa5-l%Js= zo`(x8uCQ%i{$&6{BT>zYH@PzFWNBw`EP(cuS%>+hC#(Y1^;;t zq$WkcD)1VeU^!#9K-P1J8te9#t_WvTfl!$`hc=qPMg1dpR!HXBIc22JcKXO;wzWYR zjxNtV#)+p9!bCFEhI)(^(|yBTmeu}lH+*8KzLf5d#YxV9@}_EOqu#lX;(HwIWPwp` z7$8B=(A9E;JD0D9Lml75PF(VarENLi7hQ-b5Co$geP%RZ2~MyWE=E&)Zp~Xj_;YV6 zcZ%Qz+*QNL^fg1lxegU0IKakB4BthE_d`(YIdjop_#t#c+{~hF6H#UTVx&qy2k z#8y#;d4CLwq19;kVA5v1BMh{le|Rjko_OfHKuHj>(o1RRw1=#MK8Bc*34+E&ijBR} ztY-V7AebbS3&mHP)KtYh{h~335 zMxUnpPmLtnYq5gnLG{KN=Z1I>ef0XmqIB+)G2o;#bwUD=`9o}KIi|f4AhlLWG@-UU z!rQT1RtHew4vP@;mJo>`*di`X4c+wuZ zbpwdSo(aMFZd(pQVPNB5(C zrpkwbwB7>^O><^Mtc+qv>z^cT5H+msO+NFXbwl~B+v3>EXrVcn`@PM1`*Ae)^Y4yT z;-6BnTCLB-&FH$}0n~^l)9jZ{w(f~lKa+S^<@@3}h1{8p_vf0ibh&QWkWCrs3@MnS z)9*`O3NSbEzX*vSems#FP34x2vK$1!Z!uhrYO+N1PFtao$#whuc=qK^D= zdV0T(7ie6m9lEgc@;KxOs-bOF>gw&tWwraXV23q%X5r*P#gnvDrtWdtae)f|1=9FP zsy#}cfwhYlBCKD2%QK3966-52vBeWej)s-VU*s!z@9~G1=MaK4AoZQBzkKgh&_vV1 ztBeyjzUCyZR~$={5I&rON^CBTaLV+Z76;I)uY)7O(Sr07bjJ;4$VACH@6PG6J82)v ziKs;Se9oks#rUJlM?x^}bKcO-|Ncyz05YO+wF+&!zIRMsVwrTIBGm@k(I-Ro2 zIj(Kz8nXPr*Tx|NkZ_ql_+MBr0|jyb=fHgx5?+#prA@pm5l@C1j`H zyH}1Wq}@aBp06e_U43zPPp?c1Y@^z}m{Uf+$Wshx!Gb)JQbog95bROKDF2KI?%1EC zHs39z)*NJDBx|n|_KMC#qw~Qj$0-ftqzt?`&0Kj%b!fslC@F_(x90h`{Q#;nd0Fp+*6Fnq36>f0-g2sKOqM{^0V|p5c5RTjHPg(=>XFjOQ z(zpRjzNK?wG(u&+r0}vo-7bm3wr2CVIJqDU^`_jK+Wc1*e070000H zr3b-_6N5o9kc`m zeS@;i^F-P}Uw_5|U%Q1kqVJ0Oz5Z)f#zCOek5e!}ibaF!(b9!oah$z5^tDkSP)B&_ z%sut*-qIZ+k8zd8E*G5bk*$Je zw)7HngRpnB3emVkOB6461Q2)&+{OZydjpUEk&jQlfeh&Q-A2AkXjpaHV6*Gh)J=yw z_aPK{hJm?G^3eX@Gx>?W$cv`v&g?M0!3g{bvviJsC)kh<_H#TQ5q_7j_w1@42)ZD& zwR{Yde<9ZjqYMCq4QuzSP$rS1PxFpI8Q`m;NozoO|hI;w?wdiao zeqm)?LcxYI_n$F0q`DIRYhsrhyd@k6Z3tB{&hfRzt_z!>Hy*Pjep1=eIKj(3@<8jZ zYFhep`=aJAo9ls$fGN6q`dgQ~HRTC&&L$h!z$fe#XTUR<8X`BIUj+Ja zAD*o}j4p3ah##4C=%n+E`{;byEZ0$0GWUh-f&1_MXDxA1?8J>OMi?egN%u!?YAjfT zl+{>SwG_Ixw4#s=^&|E{Hh#SJcUmfFnK&RobcXhC@Ik<(!hLuj_cR`?MMO(2SE91` z=Pl|QR7&M%>cXUh^il5%|G1N$^|@?Yj(;z?2?ENL8?k`4RJQ>J?m(#Y6Ru7GB48W% z@uH{s@`9x)v!k)5ZGzxRXB#k*TtCMDi_RPzwH_ z)k6WEdk4y5KUFz?=3u;0tOJ5wB;K;h3?Iz6P&5T$?M5;>?y??aeli zU7qdT2(7(&ln3Cq^0`OzmD%?oair?^)f@IsPK?TMRkUUXo({k+=x@VOx>mr zKtfSHWmCaPOBL@O+8HfOpW)kYVb5a85NxxJJ0ZM$7(~0N)lxn(X&DFnVnsZuW=ikM ztE@HjmQybzH>P!DT?U5jgf5K^X5c+?SfIx$0+Nekt;nRCM4)Wzcm_Fx86D~G^%HSM zNNoTiW7()J)E=kBi* zV#~r6eiiY=#s_O`q#q`cSQ}t9Q$Dp<iNDaGM4r|_}`RicV|MQF%>hD4MV z)^=;b;v`v63C?^BOopC};vw+M-sCgA~ z$k!#`HeEQMkH{e(H8rtiHh%AFrR8pC(Z}JEK(dP+P$Gb_) zkAv|AL>)7C8+*0LqQYrR#2_q!2_!ILy93*wg@F_QV{5RZ%3o$FoBiFG0tNu)uKw3N zB-~L5Wd+z|X6megJ%J$RLw?jBG%=KiH87n@;}+M*OPHYF__iyca>I$YtSfkueit`h z89amY|8t!+2mbsae7Fd@Q+2lb)hxE{x^u_?x>02GE=rDB>?Ra`roMcNz}c#r(=!o3 zU3XY!Kw=8mW?Qves2RRhair1w9xAn#WHo;Wd{wFNBf3YTxz|Y;!@mWO>YJL-NR8lf z;=!#BW2cI&UG#+w-dUeow4eg)95D(bvbtMmI7t=OHTS@|RqiPKS5FTM`d?YFaW2M6 zzh?H7&_7sj6VTW zOX^aQ`jbMnk-rH1A<_+Mu0E^M;HaY=6PNC_bw+}WjaqPaDX|t$;fx#(gquQ_8LEM% zdQgP*?fP?& z@x0Y%9Ch3zdjSCG2aUr50APN;pKrfGSvb>XQxT?4vl;PvP+HrWSi7eGcZ~i{Qk0}D zfFBREz_m4*F*m*c`3@rn@FxranGS$j4MdW~ zpvzCEEJ&zewTwCLaDdoWazlha5o+|R&01xm>hf}Y6S(7%FXrI{Ug?&$nHi8RS^z*L z2xj+3jRk^B{cg2`+NaOorKC;;gCp?-y$PAE z>D^u~6FVyl;`(5Mx6{I*iY8N*%!@eKa)&~cl8Cls92-hAn-K`Nea>D_Pf672ZI7QQ zuBggLTl_r5Qw3PQ{k=PrnQf?8*Q%?OEx^jWZ>pZrkiaNv3HZnhIb@B-6Fpmk#Dg~P zH_hrmz_o_DNe?O*?HE)j)dxVNGV&QIjBh<^OiVoI^}_gdnu3MoI7AQte6| z_$<$)8+2X_Gy7XD1dt42NU2`td3AZM%z1}Mv)mU0Qu&T%L|E2DI@`CR~jzs&+mjq+4cu7R)dCi%VA&J@sb7X&Y8G6(CuOE^rGUM#P4 zVX7&fXZ_^x6)-|7$a)v8@8Z2J|HhJ{9Pg=31VyPmm2!LpTsIFV?!f{N7)*Wo3Fz{; z$*iueN)u&jb^A1El?{o-?pU;VyDF5{XmrIy^@KeHb+b&A*4~f7n+|TEyJJm&Lmx07{0iaF*Ym#|1;= zUv*-ihE-4PK^C1yrF&Pn7%oyfs9@wsR4l^@L~K=E10KK;x;(cj_oapAj(>& zYk4Qi>#w%e9>W7&r`7|BC67t>{-kQtKla)UXDmf6@JvJ@E+LI8o9(nk@N*+z6J-0N zZ{qX8RGbx(0Qvd00&@hO^RjqwYHwYwaj!vxFB%>QbN;1wm}ZeNu(;&7(6t{8QZ&&P z1*wT!D&{9M6_a07<%!IG2`iGA)7gC7{B*G^Jr*t&w)I-uvz-OtkhWIZMQh@Hhcib> z>^(CV)^c~0$Uv?ci`k|~V329~24fuVaD63)CClj#HvOSylO%Dhg~JE`H0A0UikYW3z`iqK?YgbPG;oS+xLk#TZRQ_2m}RkB)@ zz^}23;Kh~e*#U69sbBH<3W+Jf} zObF)7A*|N}Uu){vJ7|-ZclrFId+uRDqp?|Qq zri2>LQv%nsOQu>~6F2lo$EL01aRNAgDrbfnzT@TSWOP;&ocd^g*Yq6lu=ivuYN(gJ z_A)F_eOT*jYPa+#^qF8@WNw;azcOQtWxj4TX0P1by0ef#={}e1`O;$Q81_x>pw-q%G^OxrU)F4yC|Ld#PDk7>)dsPaqyT zb?A$)K&=NI0HBIq2!$$ov!^LesytA$zk{>Ff8>kH^G`xO!3Zq9wJjdlxh>k+TjFe? zd00xU@lN;VWJ~h;%(~Xp%k~zgOd=`gK@XxJxcaar(hbV(KoYNMALJ2|*RV>6E+qY8 za#`=y(48jRpH%M?F$_Bxm)gEZ{c-v+ro`<9JLH*9tZ*{pn%R>B`ns)JpZBVFJx5J7 z`o5|xi>+S=gpwdKCIbc3ww$Ci{R1C{p>MyFDfwhmIjn3)Nw4!LVSC)=20WxohL2>t z&D4KPnrkq)3D_X{{1DcMn-$BaHR zd%&gmq($OaYj5B68F#0;IQ;GD4UVuQZb5;p!K>H>J2P3~VitC&mtmtNAKTHeJ@&Cg zjo=b`z04w-H^hC9?>fNrB{0O-3MLak0ixCmKILst&SFS?KF|hT??L9#N>_wLE9PhZ9)*m`b7q( zve@L-ISO;qiyS68tpZoAC@$|3v)a#zKq-eXSOlsYEh7SCL6)@Rk5l`#zqjLOP5h!n z1bl~4zrk!~F*R2ICm&Ee(#8rs2I+92kApL&Mt>~dJ8a~V{d&4MZaEkg;G<~YB2~pf z5&!^1(+)-S06}}I>S-CHaU*#)souRD<%-gMz{-ZBuYLtGlKY{Lkg@%=5;Ae{IELt! zdjm2SiFZccA47!wYyr}>1=o^$&1wYm_B+6v%4NQMt1dA5&`k;G6@|qChd}EH)rzZa zdCv?QC9?<-*pQhkvA-KQsUU*xfn_V5^pVd3IdkZQRLVrlfO-nZ{s*RTfsU0xAkU4P zw{+Z%(McYf;!p++APQ7+++KsPVh6GT$)K-*Fum-)QZ`@Dd~!eX{W{VifIa^Qlt630 z<~$w3qLplrOP4}ZSX7(&;n30>SFnxvw7454p&z>y#wQJ|&YHR~#xoC#v)8Wr#`=4v zzyFo6;6GA;!b=xFsKRYIyyQ0U!UwoAedL#6>ewjh6&C%(3Hzi!Jxt%%f$O#VHxR89 zECQxt(E?!OXeLkO%cs&LimGs)8-R-b+}n9| z$WU;MKQ&sa%l!0{RwzxjTDE}x(e7^0%wP?80cW;op&RCuw<6)NOf4i2?bosl=pG#a zWPca~OiqFx8a5e40fSSRdvZu20)@ak=cAc*CIqJ}zQ!=Jpp8dLfbQ=%JKNkQo8}~y z-+Jf;`>Xbs2wg3Fmw5yF4QS~%e8rIkF9pv{JR?}r_Om0k$8nF0%tx;Vtgo^R)8h4f zvSFVjGep-FS?;9(C7_Y00VFI|1Od_urqtLyuz2$L6&T37l1|qKr#{qtrh{Gy_N?u5 zrYa0r%AQD%3tH!#)y3IhKpF)62BYU!|E*eZoIX#!fB;)0tGBqALrMgqm3xe0D`(5X z#J<8ko5K&!Pn=X`M!-?gpbQUFnvXmo73N6v4cVD`2m~Egq=(2z_c5u#n{lts!^(B3 zR@axKAM)mDCrWZGN-WDpHAok+n zTmfmxDv$N7GajXmreoG_@UZCf5y=Y83Ofnx_DSH&l=jF7K>7}RYDZgQIZlgn2~LYi zIiAinp-o?3DMJ*#Izr~sC?PoN_&78l64#QQOk&K?P)}iq2)$lMdeK=SFw-k*?Y!Az z=cHOOEF;kC#aA$4uJ~))nj^a&GhWEMsTPU!xEGdPufUKz1=7caE8j#$%~}T50VEB@ zM^&b7EY zUYvyT&|V7|t{PeE8UGkbvK6G|P*o)ERPIC~VE!bYK`#?~7<(|wasA7((9MUJvx;3_ zMrBx{PRKysb$=qyrTEtP9))mm(f>2!Mq^CJvdtLDu}LJx^^tXJ>+Bd zQ(I|Wl4hM0&6n7>$sDP1C!!$4P>h#)+)fa$Fi9tDC_4k*H-Nsg^=N`gey_rTGxrDUDb{Bb}m02GHYnb%D=epKK9dV5j1dnwN=Rb4wgPzT6`RE>U zi=bG*H+569ACB99qx_?P-R43RYdri?Erx_Mw0A@}L*}~nn`(x^g+Bu5(p1l1GX+M4 zt}R@V^A{+H=L7qxtbOOMChy^wtPc1~Sv05$hHro_I(&A%g zw`}F%OD(?jw*|~}`@d}FmFdeUZWyUa0h2@;8ZHmvR%ty&He9Ma@5wan7U zZfx40j-)cHR3W=>-JlI10CkQg>T)TkR2-=7w8Y;bmI~sa9&!5w9??Yqni#2=?oLUQ zJ@C2*5XLjQ65IiuKj&7==Z$PQWC!zZGoI^Fc7bQO+bAB;Tm!1+FqRvhG+S}{JL-w~ zfSpUt%rDaJ64zKo=aL6nZYP*ulF0Q&ie96OxYX=2>0TA>jluH|-GlE1_7a`fszu+o zsnVI?W!S0$R}^+J(lWs=mML>yoaR>0c?}{h!~)vWkKbAXp4f#0xuW~7%Fxug@fqlE0IILX#qDR0I*#A(rEjS@rtjeLMiGWeDd2|%%)D~ZM^XUW zio=!6;%oJ+tp$U90zaO#xJfgaG}=ib3I^ozQ6|=mzfhDjB24FntujXPE{0Ja06&yi+S@c@rUF0)cyW>U3mDvsF`S5CiJbjH+oeiM|1^IoqHY@Eq(3L z$}kDOm;Y-VKS+qhKQh6D(Ir-OND}UXl*e5Ik*oMN`p3=vk(U8OZ()U1YnDl*l;NH) z>((j^`kU|{+1my-uB0gtw`bMNUL<2J1C*0p#Ff9Uv~nH?Kn-N?1Z*|cY~aE`^=I0; z$R)w^%IZ2h;B>x~moMb^Ttj(LwM z#8#IXnF}uY-A*fneQJ4j{r_gobRgffyhGNbC$9vMP~z$wmTtkC?YdMOqedpqqTLG6 z$o+Uh)3%uZsb3S9OXRQU0hc?W0nP-zUT;KT3P0YP&vY)Y0o9+ZB)wO3*-))xjTJrD zwhe_h}X^n`6nlzb93R}$?QahaYW-_}S z^{yu`ig)*4#W1C(*O4&^Xe(E4upr4;LPS)_x*Ml@-~{ZN7}l;lXQ2?8M&Y9YB2-BJ z4K7aW>Ts##iNHt;$jsw{{ID4GHMW>KVBIy= zORt0&4o@2xAUyqN-aO)8n=H`okDh zONIk5^u7_zjl#rR0sSjRw~{2mh#V~~I5eUFVVInU$rxd}EygHz-@BF3f`S!&B0MIx zzsX=xONE}96A|B{pgk2%%_OXl(*}4Zwk}}`Pq@7Krq1p_Ihd}b&-hMSIR5%>LL?6} zkC2Gq$rk;Z9nMWxd+ARWIH~kOeIVsPcY4?XL20wAygKg7)UUliFFyGc`cCkfL&*LV z?v_#FeX>;O-Np5Nkc28#dS3OH^_9gRnvinjCG-wZGC3xFdT&nlXt*=iXBcBfb6PX) znDfT1g+Ac9qV_^agbwn}p(9rP1MbvMYow39(+F4@pBwDdIr*j-uN!wA*4{jAHosj; zdBNOo7%tEPq*y$%ZL+9^Q;E{Vm5!jd4g+_i+}_gq5KrNYOJ#ERezpU)U?i^p zioccV-)u-RzQE?D9tlMuxWm|I(^b1ZD^`1f^LzTu9eD`&-%edD0cn-9GI7N8?y zAb}u}cmP_~Qetq4i(ku)BfYxKsb)B$`17S9?8vq5cSw;*itV=62pNgW zyvo_ysf%lCsKtQIp3`K3I|ntY^0g((cf?-)gqzrYa22c*Y0f}6XZTMOXNJwipmb*h zs+!a}vN8?GN~qdpKUSeag3UT9?Mo1R$;8KuPqy4QJY^Ija}dN0e62xS z=%E6B7o_0VYo2exK1CP=j9)F`!+RgNJ-1fi>r!E&JdH?8-(_m;xGGbGyk-msjRNg& zAcXKy?G8Wsjr6vghe2NcEliTGf-wG{*CS7X;-s8;rDT?tuy{ zt@w^+opst`{Qbc`Dr`Y;RVjr1OH$8DLGObOS*+k%-g^HkKQqUSe-_~uE1o2X9QBnN zhW?)E=Yda>Zv#?H8K|=(Y{T}?oe@;@5Onj{d{8pjf@M*K$k^uYi1T1A4}q!dPY^`& zx_J!4OHL%6qFJoAK&H{Bn#5`t2}k^!aP#f)yohv_(>u8EGifViBJ$ZARmBS$o@3=M zz~5?-RpO5y6kMSy|5?70t5~Cf!u!hs7A*8#O0n5Iq(yxLT+`?Tu(fL^g`qAB!p zw($=wS*ZX&*dknMmL^^MriWRb7iYkPJ$&db7S$TYV8nR?t`isZMuc&da}7z_jYzB$ zo7xW%KlW~ZTF79hVA@LUR*J*uTL(^zm>mz5TVuMW-f8FR`kKQ$L#9r>ng{v{vnO35 zbu)}jziX8)`wYS_iP**Gda%Uq((~8OJz>R^dc@wfHpQk6)_z@XR$rI=7prp%CIa8M zTqq?~%ki%K>|9)99jS~phJFjOtq;-QUmRj@e+LiYO_9woN21w?Yi3f-B^p3vngQ`h zAWFs%!_v?VMLd>J2R(*{|W4Vhjd!aG$u{YEh{UN!E-}Z+LDgd9UMyK@{#N^HBP(VWn-^Nj ziHEZ+gkH42AwI2Z61NP<2<}*ISXah(N5AjK;wEB6_>s98w?v6HJYUjnm=@*`!22pz zmM%&16_rnO#5w~7L@R-=cr@ys6MzY6YIg)tAAw7YJDcNWAzZ-Wvm(VR)!;PH7r@&V z10ReQ^%Y*sY0bThx<62;DZB@aZ=0)}adj;?!6A~IOFr@wm85(lf7j1nwlDyh>B)3Znc*RM6@ySXe7c)k6Bp71? zFcvuMSVt%s_A=Hi)k!Z&L!v!pAYD*HQpw;JQIZ=kn_W(m?OT38&V$_3(w^RBu8iQ5yXcB9gd@LV$K{AuYBvJ%9iBogk1ajU2g2&IWTm#n*duaOl$GC~R!yhs;1!D%?!n zl6xkr?}ou8TjeD88=kiOH&lEqZ4?glPeJ$o!eYunt~#?TX797l#nGke5ptDwx~l)8 zZhw8|Ex^vbyI%U=-tFw^#d--=OwrNuu``CM0ory{hpcrdIi z>DCCoo{w3lR3i@oUL38E2l79GS;j7d`p2J`>&}!8!;z_7heOvDMuTEo$7ZlvXUj*= zooXXe_y z8|Gb7T5bEiZB~eCcp-Q7w;zf85e?ukadE&=<_XX}$S6NMR(ZsfjIs^z& ziLD?#-UsRB7M0QplLM!XXtHtqv^dq!U3h?8%&%<& z$5+&nzbQZ`y_bDvjW?>gC0zIFq#s@#O3!*920P^&jWuAntd_ZBh8>;y}t)&zSOX zTzy)J+;WEP)?|@Zp}finQrEur>+skR8_phzrcu|^5 zg`QIrGr!a9468JuNR%;Ul=b3Jj@L|rVdf(J%ZgXet;I#VqqI{(2ttU0AZyIwK}sv%-0Sc;l7}({TM_yl<7wHuJ5 zk7ZZGi7gx9H(8Gnnrs3?Ps$jYuTTKhCrrBJKoGbuW1Kp6Xil(cCF0`Dh!%{cCmJ#ioq-gr*}LfjQBVKe9dNiT)FH%1@=Emiec4>F}*`< zHdCJ5I~H*Lf&M;LTZX_=;wP`_gOE)Yf;BHq%#9#)@?NYb&3^m1LMG>)19+1J`p_Iu z<4knLv#{!KPx^ci>?0`9YCYEangzJS_T{9G%1ReIS957zF0jPmVnI~~ z2lC$PD?k7M0{~w3&MrE20r2)JmjAs^gpxY)vgDrKvvBUsPs4B0I=zS>-`+wttY@VO z&<5#h{JeWXvIV;Qdi!4Eu#WfcCUeknW|4sC@)RXcB|Dgn=-U6xoGWDeG-x%)67!mkIH9r9<(@gi%U!S z;O+mL@#OUHG2SNwouWh{+5RA16;8r^PNXy#kMNNVVw5!w%TxlapT9-#o?nK6#pdQd zn<^e5f_I_VzUwKY+xt{(D$*UPy?ph!1QRmNbOJrWan*z?=MbyG+WDE!)rbH90{{W0 zJ0xD(<%11JLe@VMvKw|qZ*b0h;^yYaN2}EcV7`4NuF%Nq4-u8ok6R)>f@z_;n1l(N z$pqK`j|3fCdUK5WAx{n@$?$5=GJ6SNIShKIBx(s_IGA;g_U`yW3Y<7A2$mhbHw^L5 z&4UMaPbfukF_;wSr)WfHR#-W2l+}n0g9FT|K~=W&STKj-}V- zN8_{|H!gPI)$p}!6m4}K#sfmVQtQX!M6AZ+N9@0_cVHe$5=1Qm`C5lhZH)cLo{haL zN)xab2N+L)00093P3KV?=c1b4Kj|vKW=BlqN<2fl)__l|yO{zk zTiN@TsHy3l4tMbjiUUUtXN9_XX}Gx<6(bhmG3?#|b^J$>)5Jp#P4*r<@m`_J}R@y9_{yZLv;I<5##eSPSrzYZA$qjUCm$s(lYkv8ki&Q^b$mThGYv(hc7&l~&d$J^ zeSlTS3P_Eh{I347v@&_p?7jVXQ_Hck;%fCAg8<@j2gMJ>BzhfB@={e^*{C zb#dKd5jW*EFIT9!hv1}XFV~{6^STnS000934%=_`d+H4o#&x6MhEVF(9TcEF8JeJh zpQv*F`w}E}lz7Vt-#;&;FO!1Xp4+erEfAbB@>)G~Ktgr?xXR$|f4Y|>5Jc*Dd{QjZ zcu+z75!*Wmd$m%3F1Dd3Vmx@!m`qAr>lrV0_v;*!2AzYv|wX;WzN#L>~9Pb-B>&C#vQW&d*G%>GI zlhL27Nx6`Kg`e)AUmmhRDB(d;X7V}?;l2B7A?G{qcHm^m+ii#9=iKrfYbD0LawOFy|U(P}s_00093*^^Wi1~Z*q8lXqMDNZX%E1Gw`%LiPg z&mvG+oC<^bhN)>X+&_D^Ey?Attf!}>1D%xr8Y?H(QqY!ZFBoJI*cx2UOKQdzg>6F~ z*V+@zSQ*Ksy^rZEqV`kT0!rXa>&E^$-D(b~_1*Y{hk9HS53VmI>us~$lFaIys-7^R z0{xQCW!lVQOm z11;adf1|h5vA9U6ZV#n3BC$H1FXJ$vJ}eX<8Lr+?v3MG-v3u4K{U-(ZrXaSq2okeB zkDFV_U(5@nQ|aH3ooEqHawsxQd{i0TDr3D*HhS)NT>yAI+vTq9ig@X>Wt+l0>o=2b zH4tqMoXe`dyL=U1_?;h+x9fpq5BQZ+BvPSBE(4V*c5t{#ylQuZ{(GTlSkgRMY-!B!m6{5tE zA-NZ;E^%f;KmY&;j&%u$&C84-?JqBgK-PiWfMQgD<`8LGUllh?%qb&l-51r3_6PTnQI(5cQ5&k3uA6ZNrdCdJzBgtdH)0o271lmHHGMQ8 z=sO<{e24)tLhK&DLEdjKs|KZN<$*&$@^{p;$-bO);WFVpmr^>9GT048gFs5Y;pkWPV90-ccIWf13cWZU<2|KbpBi-&4d&L9=F zhgel2f*<-NFocNTA-JrmM!-jjG%05r`_RPE_WW9ZSA$5NXYJZeO09hXwTNEht#$;; zSGC9K<{zvsi}tjIV;bwN4!ND0xP~uSt-hZ#3LpYCNe9dy$vT*2JH?@PUX{L+qT)QL zr#|yg&Zj3dK1a4Pnm0Q-VSZmvTiFe#?$~f4;Nv=R3$6tAM?lCtVBQ+N#fG@?)U-^Z zP3hg+?TqWAP2NS5o>=eZAk&DXWW#r=fsE-rbn5cJx%JSy;+*2xkM{=v00RI5=QOXs zlyTL{q3Zp}1dh9aUEg^4J*Hq-OXNj%fsZ>qyUAplD`A>tDl_MfsnGLo$XhfZn61OA zAb96=N^kW_^oTfUg!oG3XqG z5%a>OmKKRV%^*x00*YW;T|C*P+skUB*{LAeS1K)N!J5OX!#UC%9#vCLK?2L4Mr!gL z=LhUV|2WNZlMzCVdq%@IfCa!)q|ffNNt42%ux}hi4XEh3(o#v2Z{Kf2gI+_GFZ%=N z+o`MF?9;~S8++4>425XpyJGgIw-nz-9Nh{hm;e9+00oUY#4kc}4rzKOf|(`Y@5O5QOxI-~a#wi_a_O0-uov zB?`yE&bYXGGi(ucH0Fz6*h)+8M9X!wz}7k+TS;fuHl1QQ`W$nP%X%xBZl+z#>uYJN z!!nQtyu*0rLVbEBTag~WRKX9N>&`5Wp4>D7KwmenfvIFeKzS-B8ITI#5=@`z zwxgK#Wjiz!0iN;K{8e7ZcfSdxU@+ZN`ZTj6fBCc}EKT`O*H1nTUSXHSXV%c*ZqR=( z{P+L>0{{Th$37e!)d0*2+cjxJnf%@k6H zrqQ@*&4qTzQ3*K8CWm^qe^p&tfweK&8tw|g39{G@&CfvCd-99t2A@RbIVwq7G>~Fw z6NHusUJj-QBk+jY8{S_|fQjQ2c-0Fs^^@U}@$bHbqd))v0|O3g<1MEU0#xP4B|Qc^ za;%S_L0K)!rlreV-o_MEkLa@TXt>n)R+7laRHTDCXJ=c3Qr&%2YhRb99D2?l%U^Z8 zZ!KKh1tKRh+tz5}qb|Knl60$iU%Jo1x=s;NgC-#urKv>o*SsV9JuP zl0YP0`pYwG7C-7dWjIu4hn%z%AMxfkih7MAI`xuT!`3-G;q0(vN`^aBhllc@$aB0EO>$WU%gECHWZW1p=$0)kxb8*5Bxjqc@=x75d4q z3seW|+JP#=DJ-gxZO7(0ETYU^i}PY>Gk|&reNVFd>r^v&8ykXa;d^~p$%^Im{Mw@( z3Afq+gTl>MSzjYyq6Lz-sAM9N*ys^Cac1Ec%I7%(Y}3(icqJGY@n|Ruk z93`E}81&j=1Lh(8>4!S1y@fldU$!x#IK&Y@casc9Zf(w&f*3(SV$Xa#&QvKn+^OJZ z><2njr^dP}l(RtQNi=_KO7y1*J48r{>QrWP4_(p*Yh{n%WjoM#KU9K4lZC3{n`&{B zntAPEABA=vdG_>g2OXH7e2>QNsFmoi(}l|BCJEnVp;@93I|XWeYN#AzRcfT7)f{La z#&PJWD38FXL{Q2-l73=oZ$P>Gt2d72tx2G=%|A`G3zXzh@@oap#&O&_Me+HtC^@`$ z-PrFEqk&Rc{CM7Iz!ye$6y4T7^&g4+S*n{(d;*SkU@kaVWRX z;~rdV4)3x^$#8Y649F;zSpfEH7Kt#;I1$qrWg*nB?z90eku893{h=IdkY^d$A#moDM(QFz-zjY2SLk8Oq4?kzc{_F!4Ij zTOY^kljG)_Sn)GA6z&HqC{ZJn$_|dumzaO@qq8u)zsgid$|Ab8&r~m1(9>@>1uHq- zNz56}NXnUvbW`SybTS-5IK_$T(0l;K32aIVX3X!DXq}LkSkv6EVyVH&oHA0(sI&th zO|o{A3S)b8xQ;9haRg(w)S^`Syg7JwyU^#URBHzQq;D!8%x?Ko7vsMPCNQ4)nrT9O zfgp3jXjOT<`<(TE6w{TTm*Sc0mGn8IwkC9hSSc1pR2h-drEE?8hR?}KR6g6Q7-OmgEz*IQ+4SLOlO2$q)W=xB5h;l8X<~lr zJ*TX!xQFyHLRdH&5^;CwwnTa9xdh0!H-IgE@siexR6yFJ#CiC4T#8m5e&82C&JeGP z+kHgGuu8R4KaC$jpWOK)$q!6Gr|EDc!NBL)24QvN+r!UbEa9}m{!{v= z1s{KmVQ)edT%WTaG9*#W9vDPnr}`oVMLBNEUx>(a2sUP(UVvf(TI`gqu?htK?szi7 z;@blSo2(z%6AG5p_{QtUZqA;gS6K?L<}9kW;x3xp6vqWl|3O$ey;=z=7Fk8j=1L3n zJ>WVjH*}fF@t9Z%3@eR=bdJDD$OQ2Xi@v-n5pm5F&W`#+3JE;PTGJ!kZ@n6S?YR_ycD(be;;$t=qvkoCn z$6$IX@+$08NkA<+M;`vhYk2_Xw{yU`=D`@wb}>Hy4TmO{3Q1RPSv{PR0pR~L_t=Vw zC2SXu1N%mC4Ot+6S>(7pu_^Zzc>eD(glNNsC^kmAQ6Z%qC)5N=I9)}QMlOI$nd?0v zLsO|TALG6p5n(D_dv5^zv~}e_mY!ZmN$)6akUp+@`~cZ!B-h8Urxwo{O{iQfm&McV zJv@?nzSrhj?XgGL!8XP>kd6a!qD**4lVaNWlVfWpf*vXqq`xY#S8y``L_q6w2nxC8gR|GmsnY@&@&I`8UUVGIiXEQ<678|BWV7p7c z*fSR1019+D+3u`j8JXadt25i$m1|@JFP6cevx?grz5ZHg76eeM9L!xKOhL*RxWnIX z^_y1ht*16SJ~^pk!nd6iwT}A`=HU=v9y&qbw>`DloB-o7&8N(Xqvg7yGF@Y>!~h>x z8GN1a>V3f=Ty+S%3BJ(NfL`i`SlV)%J`I&>XjFLv|8qHt`(2>?wU5$ZIeB3MUi=rg zt3A`dLuRJ;o(YYtpnE^4lg6s;nFl{x@#pDfbtAWudA1Z}26=aNPH{<@wmN9->bLWY zfMo^O(T?ZRjo@r7sZGzOvR2Id(#FKad*Rlp8;3fbqHx8e6+tqhJ3bK}5n3yp+gy#< z#8FzyG!+qqj&$%@NeQICG!(f*Q(9lRa>iZLU@xnQf9epTAu}#xkmoisuXa3+Yvf)t ztavXFZ%F;?6!)7`NqFqHTG7UFD&9J^%L^2lY^XY82F(OLqxn$C=JD7aFF-vTon!p% zEK0@tqH--7k)yS85~yo8iC_s-3D>H2P(&gk%=;ivDx>p&2pWer&-QbZxiEj>G&G%} zzDec;9lhvrG(7n9Qn|?8V(~sM*ndw7MS_wufB*mjT0x#dc!hre00RI30|5n*u9!aKgnW~_IM3l6 zy938E(1`7aU0-Lx3C3;AXu3sE4PI^HK(A=x)MgP}CUl?3k-d$NdX@U!m<@JV-bum{ zUM7rNH_u-RJ9VpX&5)uviaz`}gPJ|6f@VX#$%o`g@|}izF)BQN20ADz*X7-%|M25xZ@|^VE-F_T1gAyKvLXeYs)BoXrt(~% za79@u2RaiUN?I6jY(ToWM#c6KhPd`5t|WKeJu$`q0#oBYqR&6v0N*vUZ4l(}`haBR zUY1I3_GA^1M8D`;3LP!~ek}O0#7$(olO-l$O!i92@@=mZvMHWk;u8~`_)IhRJxpbN z=27uStmkdJ&4a1lnSPok4e?+{2!zfMz>$B{MF}3`VY>qbRZ+|KpR$SdbUYD{mbo?Q#6D?z1x1-Hi zo!{Emb~A+kOPZf!)TvIFr|Ze;zchN)>T77!b{L-Vy{dvO_w3+1#R!CVrE7uEueRR# zJ+Kt&Y9#SM0CzzE008s>o?&!Ce*gdj00094Sw;*5QlkCAl-^ABl3(}Wf3K17FNK7U zgb!%9d}pTwQiMQ7qvpGW0XdT-E>7bb6k~{HV+MW7tIq)XfFb**5U8XJ%nrV-w(-cy+0`9WNbJgdG$0z~ zN+boUCkYzD2W;m`Z5UpN4J_61LjlO=K!4-cGkF7<{0uii6FmW(s5&4C2mu6BIh|RNl zV7-V4qBLZWS^Nhe1ZBsOP0^|${%W3W(q7}}S9X}%Keu7Cc*(}EhTPr!w35M9F%Bg@ z)TwDv1nck^Wyrd>)^(~_b>0zQA%^i1$5ccGVK9wftt_zdaw%p>Vx&c43q|b?fH@qN z^e+SeZ|?#Fwv{eAo5Ii}SZC;ZXM?BJqS-FfO-q1a+4o#N{wXh9o<#K-(F+B&yRBq=Up+rFzr?HITGN0A#@Z(` zp0##t?loYvbolVNQbV$Y0?5OGiwTjBrd@#?M|<+o)|Smf>KcQ4=&|6JgsG#N_Iu8+ zGO5GozC;&4Gt0s2-Uw#Z);<|5#lh1^U8vzIXN;5gO z5tsavO}_sV4z!iS3oT*^8zr7c|4D^n{Jd2iRK?bCQ3!X`qlrK&Eey5ojMuB1cl&a< zHf!)aRijS>s$Ebt+Zq$~$JJEc(AK?^u61z&-9yX?PbbB71{dm7;# z3Ti&IU?{c|;M`t&m6E9!7S&&&%I-IpV79iWIKFrk^v8ofmA*m|k5UR>j~Ksu?Q0x5 z0@_t;B(aH_u^11^?u@lZFNq8{(qCnI-wh;S5&}wzGjA8p`s?hF2|P$43Av_7JNf0+ z>avxrvcF|uA(y~M(^@(&X)alKZA2qVP1rooSH)bacOTcEhX%>|XnMaQr*Lk1UW=0s zMtm11I1ufBQ%@R+0&(-FaBADGAwIMl{nl^`1pOKMX8i zh=oSy@9XcQZwLAje3j%RnOFnwyXBD9n%6PSv9fL-Slb)v$p|m~sV1!Hopd12Ix^0D z6x>#paytek2nTJ&#clLFbQU~CIgdc`)48}UaMmJ^SGgxcwP9)E1hwCxQhD$OYjBi( zF`MAfk%<=f$aXqe!h|Ty6LroPge!Q;5t(t4O&msz}o9R((*;5SnK;1uR z1gcf%I=+Bg!R_rdwvkwMs#8L6 zr;ir5B0*Z@x^k3y<0&IMPLVc%-lqxN8T=ORV~1sfS-xk|aCnulV(ld)p0mXNXEoNX zoa#{5SBbO9iufZhv=1R-F5Dsr@+cW^t@K;|Gp=u{8&03}-7hk?er4`Qzy)-689VMg z!=<6}%|($A5Ne>wnekkq*Lclg48#}385!m6xQ;|wF3*&SCZ>932n|B|(a9B*VTr`B zk7S!h3)^N?skLc}(X)i}2JLp$JjsZ7suOBa>O>N#Z5>rHc-V;TU!B>YD`A5mu*K~; zS-zDjajkbaaN0Lt+YLg-)|DGVl?HuZj8|q(TO1p3+WBPWUpAofAwz&Ursxkq0S{NK z636?pfahAf{!x9L&UcTcT8^mZ=kPtQ95lBSVzcfyVsU-G$zKKPdsoAzlCKRn21>|w z8KZg-_li1O`STM82&w)2EZG0mf1Ntrq4XV1K!_Nq5ER*z_B`&a>2L6txz2PiM z1*BSLw-{pL&`nGp`ki<;Bp@ft@+nkr`*{wWS2sJmTLWphBI@vuQwt%X`|cKJp>G}j ze5XKGzKNzptxY0AW}Wx5DHA1h8-?6!V*f7i{KzY~F6=5!$$M0@$HewPU4GG=O=vTJ$7tOPA zZ&`M%Iht^wCEFSLYvwLPdCmtImA{5yo}At5FYfG<~n`A`=;0QIYG@`t;pos`}&-f z2i|0t8MCQtRGfY#M;`!F7KP{Pz6E*xh5Z{-!*7uU? zGz0~!vW$G;O4fEyU#r1llYKM@gZb-x2Q^|n1>_20u6L(Q*CMvE%vV6ub ziwFb*jx3)5+6SjQ?yJ?)$~+>nUjv=2Cb(u2Vj`a$eXJg z>u91&e^kcvftxEKnJywTU=~U&?fO9F)XwcYtzFFIV(7SBkjZS^qh&=;48@*#%N&kC zD=uQU2&0?N(0)h9aS9p4Dfv+k^U30oaAEIzhA@Iu)#67e=yU{?N4}vo)!YssI1ND z1)-}RmT}SQ=f;PWaS6_uWEM$j^AKD_GTW;IYREatjY!1i=eL#1~zq!Oq~OB zD8Lq^W81m0ZQHhO+q$uB+qP}nHg0S?o84Eh_WgxZHB)oCd%iAW23edT5)*JjeyGsc z0DSBJ0C8nT?S_&9KKOM5ulp%uOt{29rKRqOTuL&=_&POoLT>I`tdjLbbK`-r;t-F= zhfp|71-zSFHr9SVD;m$%6Pb3-1E8R{(*9y!RR9w-Etm%?#Obd*tf?zEz0x z2vtDrN3mgYKxtvU0;2kC4}(Ws-sGnP4i`2Oredy2FX7D5t1uXhGlxSj zt>1`kn;&L2r|<&aR~Ds!y72qY@HvTX5ch<{(@ybEiOsPT@>r%^0 z*x%+#y@tjdK9VCvJccf5W$2QFm)@vfzH5w8xB)dyV^JU%fs1BIT)5Nx%N`7*)=TJ* zyFl<|lmpL|ut339fj=MV`6UxyGi~F`;rfbFi6Yg^RnIFgcn$5vTR+ku?OmVZ+yr(F zBiNlywS1}!Lr5o977q4t?W8|OEuf2C(3tA1Fr(FyX)$w8jipM$jQ?pmuLla7mj)3= z_Gf8X+@!=24uPc3*?WZ<8Xm!J-S)|CSU0hg9v-qvC-N&mrWB?oF$vyR8~7JNW_1}U z4?ZUkoXOiUn5zmbO+4J*RwLn6jk7W_a;&jllhC$r3M+Ax`IjN^)2y`&l;zkO%+i+u zZBn~Y)j<6d*RM%rc!+dNIi5oh=wslYeRgx8&+~SeXhaf>38h&6>b>(kL5{^5{#I0{&;aKZ*R&nAn z99$->Fj2X9A&mOxXM0P)jLcFOOBu&Bcy~}v5Bc94RVN4f27^lPI4{`y`Vs39Gpfb# zapdgyE%({z(tIAtupTg^&~t0}zCJWWqhnN*$nS>91(;L(UjQyJ0CSJ02Q8?3NyMYC zdm0i%{FccY7CPd~NyWQQ9Yl1&E>Rjztg!M>cZ75pN|d{Nl5vDyUAji7Agc;H4Uh2!BPI|<(A@$4=*FH9^t!93TMvlT=eqrsaPeAFxZ zN%aN3kq%mVgIT8UO`;P>RP;>D7q)KgU9r_GawZ8l;va^DWF2L=#W-8V)GoYU331~0 zo90{&aGU|mLAQLQ1g-cU=KW9(&8zch23KAzb?vWm_ZgF zA)*NBr7(%|PQ|}nJk(Q<>An-ndHf?QB7}m~0Pw#SJ|H(>PU(O7e!t`UUCyQ!NZ+_<%LJbh{t)OzVU#4K=uifz!SJp%LuMJ!w>`@44S^d zT1T}`wGFG&`|04s_A3NB*TqZs^#i?f@}GY6!=FL>Oi{A&a`25k+l8bSfLU?yGSWAU zE2<%ZVOG;S|D*Kn(jnw>VotcoD)!Z@vVa5h_Mj%9@Tbc=KVs~!N^6JFg5HMFkwu1IYRmt#Woje)7^vX z-HAOzG)U}?J$^)Io73iYF&*}k_8?CQg$36E+Sxu1&fv}JP?sD+f{`Ep8`5JG4ReE~ z06>9=UL~>k(F3pntr5RR1w&|O%SN93=*N!tfW-t(9H{jOBDZh2B?o}?B ziss;&gw%UU!P!Ax-DnptQ-az|`_Ht;T^U8=npsz#3$pMQl!C@pNd}b^NDt-YW|Vh2bYNOUJeA zGsMt{xI(dSyaALyz9sa{Lf(29@&vc`HgU#Uk}4wZkivhYx-{f;0|^l_6&1|dyvURh zd0epuyJ?)U2LwQ|LEayJDA*BPuEvlhPJePCzbZ)uTDc*CZMp6>P349rkZ9K9Y!NTP= z#0Llm(v>rPzZu^glFblEWxo$ia4Ct;Nre+a_Xwq3Wn9^cw|hvs zLMbUjZqhdTA60nowX2nGrgkJF&6u-}W)gs9FAu&A3(Mw$o!XtWDesIb=3{`~c# zjFt*`)(5mt!L?%DBBzM!vyl2SQT{MWSotI0ui!KPG}4~|^SlmF;X)+M1z@*>A+*a$1#Xo0)o0(Y4sgwN>`3gpv1bmSk#9CHG1clj_}SE09KrTCixN{DYEBu$@nYux*LjIx>K zV?FmZVI|=2=%<7^=?yj|PLy6El{RD=4}7_B}z zmzt7d)p|Ilx~I>Hm9;0PY|3vE5XYE48_ea3oCJ9ULe@+&(o&J$WXTvXl&7rCrgGDj zKTS~oX$?iDs-dpU_cRlZAvf1VfX_txa~`ENv@P6Fp7{t`a(o};jP=xF2_A#rdsHzP zO2C1b?woo|2b(z1F7bkUQM;;OH@olB=$CCjh~buitm8ur3wXF|=$S-<^i9?CnQexZ zhM@h8zosv;h!{1rbBI)1as%9 zoWdWcHz7RW+U%g$6TR>>Yxq>!su(NwH(%IZj$;4VM&TpG;vez~Ra;y=P2NYs)4(-r z!6L*=QU%QU98QLeT3i`ihyEN^Q*mXO8R}eqs2A5C{9RIJmn!w~a(i$@2wUnu4U>vk zO>lo8r{iGz$Inv^weOCr$hNFWMIdaJCC{Nna|h6;KsHBh?*FxQYNXR?w0501OORhD`U{EqUqYPG{~OhIs4Sn_xDa1%3}wrn;Q zFscTqw-1KnE*d6y))iiq2+5!<4tYB*d1u=O(FCR4u6zwqfhYY73b@6zs*yDj9)ed5 zd;;Xg+f1A2N)*3ogKeeoIQY(00GDStv|tRE5!-IA^%mv7b!m4I`m6wB=SU4p{#ZyV ztH7h}D41^2Ck1Ao320>&FtVEzpRaHKc_-qLTZ!T>-#rrihWRG*CJh%!6dln`Kk}6e zS~y#kT_gGRumx78^_Wm+iDlM)i=rY95eV37@q&;#UIPFCXlj9s8Eyh8;|YC)-v7n{ zK@NF-FWB+Xdz7l?K7f5A`*4P-KVR%lX)s^Wx$rh!0}rN=C*f!}a2~qB>>&CxSHGZ( z4`~|M&QHQWu*2v1)Ot4o%eety)ZMv!g3~=^#t_nB>48?fy6f~(%tTAVB%h$u5;}` z^4sty1I6^iGKOU+O5tCS$T)ASXxj*mlKas67StZEnt`6XhR)apL zSH@U^^zL64XW!Ed5CYG_%T!A}yDKX@bh5ZlZZdMLM5t?tZhxy^3FcK|+1=7dko!DX z8F;z{6pyb9GYP5T=d)Ip;7WyeABDlzsiAVP`p;@nDUrsqL0g|hh=M2xsS_L)Z8+S`5E-E8$OOD)&L4ZdYiprF1*J06K-u+V}@=Khg7Hdy|Afq{vg1=J+gfV`@o>+4aTTs4#H+ zz50ituJ+UM#qnRIke-rsmCMxmyRTJrAmzcw1F-AyqFtlvd?@#JB?`n zwhANzn)Tma1++^W>XDsEv)|yqnm!gu+#S3p#7cDa>t-G1vrEWcsSG$%?V4s<_3V_! z;Ob9zOa+Kr?{kMn@NyM0mC&Rsv*&X4KD2SB8+BVfKwXef_baw1V>)4vig7F8v!l?J zl~4$%I$|0lYF_E~*Sn>A^r}NyHVzWu!SjFl^!koV!~~Y_)^|9`rZlak9P=IxS86oB zdT{!x8hjrIpzC1!`+E`URKGYSVk*kIQ)kTl2+BTMLoyS7F@i9 z&}eB_F&as2=xI}N*`uJMp-6|S#Gb6O1dUVnj6l3sVt%fR#BhA^>4=48AXjAWU--F+ zPmLxnd?sfy?M(G62Af({{9e+9Sr2LnT|hdzv~@MUXN2o4K60+9s8_|{RJbxc4d91| z5SOfcM`*s>D(;&ZNh)uk$4n)gX#)Vm2Vk)AUc&)nS_e6~?vuXlQ?U_0 zc^SlI;H+jDur| zF`kEAFUy+v(T%mt(!{YwJG~w8oAO0kQHC2#*8T1bW;JE$llRIQuVJfdW}GT94VQuF zA9TyLO^W)5U+nY{pYDg--$~9lg%pze#B0YhD9CIRrE5z!6SJ&Jp|wH$)FQD+fA4+H zlVR6k>Ec|nJ{a%Vo{EGq%)zsZsO)pg()(RpZKN;cbZx!rfM!HNQqc+$aTO3Fg>UvB zhP)~x6d~NrA~H!L2tjBVG*k6Z83-d!!Q~-GcQ67zD1SmKvlub6Mw*5Y(3M9OP z!r@fmxe5}zWXN5g{OjY>CI)8==%2Q|Q|ZR&I8Oc(v&fK8qKTlTBfSC#@t}~T>)a+p zETH%A7_Z{xag?C`EAf{3w)Kw04+#l;iYWF~S62?wl9f@h-77ssmhxy!h|^s_PGOm8 zhADX)^A2d!&9s;nm$=n#@==!!^ZOX<`+t??V1Lf4MzrGTmEtFiHqCK>My8Yo zclLmcn>JhK&5LqX4Hfp~$Z|1*#YR_)SV$+uzlQkLN7Gt_91cpPK51*eDa%g-ail)A zXYA0g=Iw`ws>?F&%&#_Xr#l8i`0ygBRA5@{%k>1N+*OgyI_bEp6L?DKo_Yf+0vW(K0)m!86`w zW^GCq-%FmqNpyo+eie93-98ug4IZMX8$FaSiTW8G1A%?H!nvst>HD&K9IBWOM_3uV zaBl7@ptVuk8Wb9NkcgR5n=N#GF7&v9DCdRz&mtIT$ob5C$n3LXLscSwq9JWqB;sd0 z(CWv*SIbVDFy(bco!N&oCNdPyI^41WX=?Gu}m&!rHbOPHzli#{pBW*fvl!- z?4HIhgQnQc4{tX-0=qY;yNexZBs&ES*Al9JN9EvpDJ>MXON z>y?fJJjQA3yI)m;SxfjWe3!GG2TTpHNgX`=wl6hCX9UKi6tbvDnle~3(`NT6ts&_A z6DBHe6zyW3H)@pWvLTOBM#-2QFtHngb(cV?XTC5d_A z_&e?J4o%$)G`5^6jbhCaPD!5EZ>31HY|bLX@@#bE7GX;|FO}`+z|h}bhrDCGLGvh! zTeF8L!omZC!15Q36@*CvS7gEU{&w}E319euq zp+RDUZLxDftu{+zkSko{)rn6(vg>kxWue)pPKf*sol*kcF^9kUwww;w_ly%Vi-KKW zAGb!D69>f-U^P1MWuf}DB<(UsraOeU`LiAWMzf(@hJC~YzlN*)AfMd`7GLcZ5O(h* zZ46jjmX|!o?^9^SU~HH5lnXMnWa&GHSa1&U;cSGWv}&ULyn67-uPr7$Nvw^urD*@X z(uJkz@NeDbm5bC)Sp&-Hf1=KT7nym`n{O@#O+(l=3{9=wcP(O{mf+77b*!lbme7X~ z@@eCVTWuwHxe-p=^Ass9`Ok=>J8U_aGCJtBjD`teHBrS+K`+Y_zwAs^D*STa&>F^V zC4d*h7TqrvTRAnn#GhvSh;mfs4QQ%()CUgTB8aZ9+9UOwpEUXpzl|z$ z83{17{Ni+gseT+is8pfIi@v`CKT?qzyoUtd>8J|%h~u7&r$RQ;VZlF5vf?J!Q0+rB zrHu}j!7`m0)!D1Zx}1bwgWgnHVxn>8|MpUAGDK0_feK~J6jw6neu^OmAk>73&P>4* zHH4Afb~%|Ok~1AKrv72S)@vKKe9JR!FfIc5Tj2u%^oOVOP>o2XJa6}+iJ!Hk+xdYVomp_ur?~nr#9n2 zhSd!FoPdj{w(2D!F8?C;5nnAR*f8Zpk26_QahLyiF|fSKn2bgG=}Q4UsF0J0?qk=n z&R5>pU31HY?hp(Pk$?O}+9P5nYmI08Vu3S#+2Zqgrh zc2%QRhNh_9lzztK=Y3r|TX@H;HP;}mDRJTg74_nZ$BnN0v2N^d6debSeEV>v>$HCm zZgpT&t(qMQ?nUv}(5Y2J&m*O8Wvn|cJAspXS%U3F@DPYiv@0B*oVVobhCHeu!B8a%{$VNg}5Y$05-+_X5{)$(#^+TT_FiT2OH1ycm zzOXwvT1*G{Q+Yf0@v_}(KUnp%$U0INuV2KmC9S<;j0P-!}p$h%0Mto*kInd0G}t^aZk42@(Z)Y`N=pvG}KusA-Ry0t2o3yDUJ`BZl{c z(rK~60?-A%xF+_r_nU$^+~raNfP#^ro_7RKmB`X4tEqI*@<^K-xq$n4`$SLS+(ee zdoDd5_Oh#cN)n_P#^XOSg5~Mc(VEREbh*;X@%E=y@0TdsUY=Hn@{tW*lgwZIcG&=_ zW4tB@uhq#UlCiWEr8REO`CtzdLJfEiA;{QWXmG&P3>WtKJMZ~6{V91-k6SIq_%d?! zgZ{7Jq9l-s^lQ{9Fs6Y}{d}|Y|GzW@vSKqOoo2v?VM0Dc#*a$Pijnj*0*o}{UkAsG z@4Qh1kbEK+-l}lSrbw)|4H4t7^|MeQ2405&*sfF7 z&|R_WLbEOXq#KnrVY)R$HTuc7W%=46b5v!g%-y=bDUuLv+KJ>bs^$@WD^%H{TKw93 z(l3!EQjX;Vny3_mXT~us zb8w2^B%Jk$t|G7(p*enDZ>BDRnq#5`VPQ3K+mA&i`|Szrt(jr0|K{ zlH#9Fl{c(vq9g7WSVmUBDT{yzR*hR(RxP%!Z;E)Z1Hkq|J8*iYqzUREm#GKIn!D;4 zM6jFI5}Poai5xp4O)#F;Kfk;u#z&jJh{$ewJgv%}7b5U|n(ozBbO`iuT5|GN#9zef zjvF%sBIvbup1YggxR`haYQKpCOKS#?0adi|IIzVY_JFOc3iI$b8rYGifRHHxqWSNoUPaRNF1!sB|te;_5(K`WozXL9YR zD!^{B7bK^Om%J#ObE*~ek(9wZTz*R@fRet0U(9teLp7Q1Xfh2klmD7$Ub#NqXwkWX z$(JRESO>6AuSfgF-LF7z zMbJ%#k_K>u(TD{ZTbZDY)3zPnZHuz6_U6-Q`0*<~ztXy{_qJ%bZD?FBQWO`#2E0)_ zT7!W!$9dbI*2wLx04zEak~4N|wf$c0N6bwsuH|&8s6d>Z0_;Wznk_53dc=B;B-wKnZh2rtKJP zlmmgvO!zDu^EJhfUBT}F&Yf_4&h6Uilc~?C@@8Sf!rx)bg~AP?%1>||kalz_c2(E+ zUMNIXJ{$# zaz-1gWzyhl&8Q0QcL=qHDqBD4=++HacqnHE7}UoyOLZz8&lhCpP49nEwc{45~r4YL%YzzoJ!W@ORqA zU4H+{1h4D*8>o~kt^4L|MOp#bZQ;0M5&_LCv4F|vYH^h+5@f*;zc7gjtKlv&q7sH^4gCo8)sMsngD7aDE8A(rZZDBw23xr|jLGNSNXIUGM9M`W%n72phjFXUB(RA!WE zes{qbkVdECGB%7@7xJ#V(sD{~Bkm@^Ehu)uR3v>P&VbLjeY5+&Y=v!i$Fl$%MLY!} zT;FR($TX_wL``!;R*b z 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 z%0D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 lXs< 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 z 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 MpflDFLg4iO0W^tmO#lD@ literal 0 HcmV?d00001 diff --git a/astro/public/videos/hero-background.mp4 b/astro/public/videos/hero-background.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..fcf4b00df01992b402c713e9d49b6e0a05d67db7 GIT binary patch literal 666659 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 z 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

    Oydhfw`f0-BIgJ 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%0DJAdNV0`ZG@^f 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�wUrxx8j=K8 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

    xLO+*7!Y}VkFRV%&ITFn!WKnr$arAQQtOi&lfu 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

    *NLf>F_m1REc0Q?r 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�t-vc9!;Uv{+&nXC(41`xlq~6RS2lPn)9!dM1`Nr?||87w`$_prb1Z;}oVGmoqIc7MG%; zge|;N7bX8(E)briU%dox%vW#L(!fzEMa#$IU3k9LbHA$o_)ld(wqlPR?25~;M? zM9*>vgaFZ1qrP z3+TIo74(n_feDTZ(A_`9hTT~Dx~nj$Ek*wDYI}5b9K$SmWekP}X<};-_~n%n$GfeE%R>~+U*S1W&<*xlpk&sQA$azs5a8_MW zP!Hrvkg_UomuOCQ%BKPR>&=;u_jS(~-37ihx2k{by|tU#NG7wUg_vjC@Pu7AlD-V|`%UGR5_ydG9@Qo@x_nZY}Veb?Z$g;Z`aN^ z-%u7^MIXx{2MPS>5i?M~KhQ)PL8w9g>^)ho2Kbp%ttd(J#X|}hzD~(PqUzCJFPj4+ zabfS@rk1J|D#2h(!{E$7uIqNT2S^Q|qOIrn(|CHC#JwOiFOEadEH!e?a9enDD1aF) z>}A_SAd<*ks5+~o5TOzq@`vJJ8shBDdr zn-XTI!W+M?tA+fcB^^hxGd{W^*B>A7YT5(Y!~Ha8rUpVwtAhcf|D+h`NI;A$lCmT6 zFbl$A7V)?8t;W_;VHOFSGALvw+(w9-)x&utvNxyTCcWSM6AXo_MDhX>s>Cwl&BOzqbzoZ=wo_=`9etAd?1}W!z@}5W>?Inb|MUU0;hKfKBWKwj<4Vd z+3|Lys#KBA7UT8B?ZVv>ki%T_efR@L;u26hv zBW902E-BN0UH){He)?=)2I})TxccK`IENC(fwklT^QLINAQK8I)VmtK+SnO3I)|Y0 zhT^VCDl(-JZMUni#zxzeBUIW>N#1uPV`xiY6lE;L_8M7OkjBAX`htaPr7^cLZb6a?>MC zesW9aaqT(x%r?OEa%7&v<%EJ2Nz>$(92}C_89!e9Q+$&>Clz#@@vj4oz|1=iuh-Jm z+B<+{(tV`g1~ZBi!Wk;^y*GD6iDexHt+LkhZ@lvdF2hY0#BzE<%*e_!cedcpCs@B1 zM5BNv@3nb4*j)c_jXejRo`O#EEEIw3w1#mXPuc7)D5FaP3 z8+0Jpa3F`|y1A5VCcb6vHIaW9I}y__CF_=Pjnw3PiViE7vm+N!9<@nAy`tlU<6B~~ z&hsInvLG3+oC)?^9&Ndm&OChY&tdxfsfd9G#3PQ=aqHKUMs(u^IS$t*t?w-YtXJ%6 zt<-R94(NN@m27L!^RFj;_kl~zBnzcqC-x6c6ZX-V^u3o2kWVBzh%_eF?}9Ue+mVZZ zBv_#FgvWA=@nX7LBQYOg_w%a_m}+F70cb%UnLdg(2Ui9$Fyaw znW)bQ#2yWGlx}G64fX{8Z%gY!a)%oWA$D%BA7K26r?F{t5gH|xamIu_k|88_osy*w z{FM`%i9AzOgBboDPw$T^tB$$fVMP95Y&GhYB9L<1_IawHXnCb#-h8mBcut^Z?Ms~5 z+E{mS3JUWexb)w~%hlo;KW?&0ZNg`@2RivTZ jjLXzfiPsfBVIb+!M!;DKA-kUB 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