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/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000000..cd7038952d --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,110 @@ +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 + + linkChecker: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + + # TODO: use astro action, when pnpm action is enabled in the org + - 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 + + - name: Check links + uses: lycheeverse/lychee-action@a8c4c7cb88f0c7386610c35eb25108e448569cb0 # v2.7.0 + with: + workingDirectory: astro # TODO: change when Astro site is moved to root + args: | + --root-dir $PWD/dist + --remap 'https://expressjs\.com\/(.*)/ file://'$PWD'/dist/$1/index.html' + dist/ + fail: true diff --git a/.github/workflows/crowdin.yml b/.github/workflows/crowdin.yml index 9dc2b47846..b0be632134 100644 --- a/.github/workflows/crowdin.yml +++ b/.github/workflows/crowdin.yml @@ -2,7 +2,7 @@ name: Crowdin Upload on: push: - branches: [ gh-pages ] + branches: [gh-pages] workflow_dispatch: permissions: diff --git a/.github/workflows/sync-orama.yml b/.github/workflows/sync-orama.yml new file mode 100644 index 0000000000..4c25520a27 --- /dev/null +++ b/.github/workflows/sync-orama.yml @@ -0,0 +1,47 @@ +name: Sync Orama Cloud + +on: + workflow_dispatch: + push: + branches: + - redesign + pull_request: + branches: + - redesign + +permissions: + contents: read + +concurrency: + group: "${{ github.workflow }} ✨ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}" + cancel-in-progress: ${{ github.event_name != 'push' }} + +jobs: + sync-orama-cloud: + name: Sync Orama Cloud + runs-on: ubuntu-latest + + 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: Sync Orama Cloud + working-directory: astro + run: node ./scripts/sync-orama.mjs + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PUBLIC_ORAMA_PROJECT_ID: ${{ github.event_name == 'push' && secrets.PUBLIC_ORAMA_PRODUCTION_PROJECT_ID || secrets.PUBLIC_ORAMA_PROJECT_ID }} + PRIVATE_ORAMA_API_KEY: ${{ github.event_name == 'push' && secrets.PRIVATE_ORAMA_PRODUCTION_API_KEY || secrets.PRIVATE_ORAMA_API_KEY }} + PUBLIC_ORAMA_DATASOURCE_ID: ${{ github.event_name == 'push' && secrets.PUBLIC_ORAMA_PRODUCTION_DATASOURCE_ID || secrets.PUBLIC_ORAMA_DATASOURCE_ID }} 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..e7b63ac2c7 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,9 @@ +{ + "recommendations": [ + "astro-build.astro-vscode", + "esbenp.prettier-vscode", + "dbaeumer.vscode-eslint", + "unifiedjs.vscode-mdx" + ], + "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/.lycheeignore b/astro/.lycheeignore new file mode 100644 index 0000000000..1bd14a0a3b --- /dev/null +++ b/astro/.lycheeignore @@ -0,0 +1,23 @@ +# Prevent rate limit for npmjs links + +http://npmjs.com/.* +https://npmjs.com/.* +https://www.npmjs.com/.* +https://npmjs.org/.* +https://www.npmjs.org/.* + +# Prevent github rate limit +https://github.com/.* + +# Exclude 404 pages +dist/.*/404/index.html$ +dist/404/index.html$ + +# Exclude Open Collective links +https://opencollective.com/.* + +# Prevent netlify rate limit +https://www.netlify.com/ + +## Ignore temporaly sitemap +https://expressjs.com/sitemap-index.xml \ No newline at end of file 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..53620d5474 --- /dev/null +++ b/astro/CONTRIBUTING.md @@ -0,0 +1,519 @@ +# 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) page. + +### Common contributions + +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 + - 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. + +### Working on existing issues + +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. + +### Reporting bugs & requesting features + +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. + +- 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: Open an Issue (Optional) + +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 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 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 project codebase + +## Prerequisites + +### 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. + +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 | +| `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 + +> 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/ +├── src/ +│ ├── assets/ # Static assets (images, icons, etc.) +│ ├── components/ # Reusable UI components +│ │ ├── patterns/ # Complex UI patterns +│ │ └── primitives/ # Base UI primitives +│ ├── config/ # Configuration files +│ │ ├── menu/ # Menu configuration files (sidebars) +│ ├── content/ # Content collections +│ │ ├── docs/ # Documentation content +│ │ └── resources/ # Resource pages +│ ├── 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 +``` + +## 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 +}; +``` + +## Internationalization (i18n) + +The expressjs.com website supports multiple languages through a combination of Astro routing, TypeScript utilities, and Crowdin integration. + +### Contributing translations + +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 contribute translations + +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 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/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..0b72ca8004 --- /dev/null +++ b/astro/astro.config.mjs @@ -0,0 +1,62 @@ +// @ts-check +import { defineConfig } from 'astro/config'; +import mdx from '@astrojs/mdx'; +import sitemap from '@astrojs/sitemap'; +import icon from 'astro-icon'; +import expressiveCode from 'astro-expressive-code'; +import react from '@astrojs/react'; +import svgr from 'vite-plugin-svgr'; +import Icons from 'unplugin-icons/vite'; + +// TODO: add redirecto for blog posts + +/* https://docs.netlify.com/configure-builds/environment-variables/#read-only-variables */ +const NETLIFY_PREVIEW_SITE = process.env.CONTEXT !== 'production' && process.env.DEPLOY_PRIME_URL; + +const site = NETLIFY_PREVIEW_SITE || 'https://expressjs.com'; + +// https://astro.build/config +export default defineConfig({ + site, + vite: { + plugins: [ + // Transforms SVG files imported with the `?react` suffix into React components + // (used for local SVG assets like logos). + svgr(), + // Resolves `~icons/collection/icon-name` imports into React components, + // bundling only the SVG paths for icons actually used (no full icon set in the bundle). + Icons({ compiler: 'jsx', jsx: 'react' }), + ], + }, + 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(), + react(), + sitemap({ + i18n: { + defaultLocale: 'en', + locales: { + de: 'de', + en: 'en', + es: 'es', + fr: 'fr', + ja: 'ja', + it: 'it', + ko: 'ko', + 'pt-br': 'pt-BR', + 'zh-cn': 'zh-CN', + 'zh-tw': 'zh-TW', + }, + }, + }), + ], +}); 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/eslint.config.js b/astro/eslint.config.js new file mode 100644 index 0000000000..f8f317364e --- /dev/null +++ b/astro/eslint.config.js @@ -0,0 +1,42 @@ +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'; +import globals from 'globals'; +import { globalIgnores } from 'eslint/config'; + +export default [ + // Global ignores + globalIgnores(['dist/*', '.astro/*', 'node_modules/*', 'package-lock.json']), + { + languageOptions: { + globals: { + ...globals.browser, + ...globals.node, + }, + }, + }, + + // 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..fe5085abe5 --- /dev/null +++ b/astro/package-lock.json @@ -0,0 +1,12385 @@ +{ + "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", + "@astrojs/react": "^4.4.2", + "@astrojs/rss": "^4.0.17", + "@astrojs/sitemap": "^3.7.0", + "@orama/core": "^1.2.19", + "@orama/ui": "^1.5.4", + "astro": "^5.18.0", + "astro-expressive-code": "^0.41.7", + "astro-icon": "^1.1.5", + "gray-matter": "^4.0.3", + "mdast-util-from-markdown": "^2.0.3", + "mdast-util-to-string": "^4.0.0", + "react": "^19.2.4", + "react-dom": "^19.2.4" + }, + "devDependencies": { + "@csstools/postcss-global-data": "^4.0.0", + "@eslint/js": "^9.39.2", + "@iconify-json/fluent": "^1.2.41", + "@types/node": "^25.3.2", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "eslint": "^9.39.2", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-astro": "^1.5.0", + "eslint-plugin-jsx-a11y": "^6.10.2", + "globals": "^17.4.0", + "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", + "unplugin-icons": "^23.0.1", + "vite-plugin-svgr": "^4.5.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/react": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@astrojs/react/-/react-4.4.2.tgz", + "integrity": "sha512-1tl95bpGfuaDMDn8O3x/5Dxii1HPvzjvpL2YTuqOOrQehs60I2DKiDgh1jrKc7G8lv+LQT5H15V6QONQ+9waeQ==", + "license": "MIT", + "dependencies": { + "@vitejs/plugin-react": "^4.7.0", + "ultrahtml": "^1.6.0", + "vite": "^6.4.1" + }, + "engines": { + "node": "18.20.8 || ^20.3.0 || >=22.0.0" + }, + "peerDependencies": { + "@types/react": "^17.0.50 || ^18.0.21 || ^19.0.0", + "@types/react-dom": "^17.0.17 || ^18.0.6 || ^19.0.0", + "react": "^17.0.2 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.2 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@astrojs/rss": { + "version": "4.0.17", + "resolved": "https://registry.npmjs.org/@astrojs/rss/-/rss-4.0.17.tgz", + "integrity": "sha512-eV+wdMbeVKC9+sPaV0LN8JL1LGo9YAh3GKl4Ou4nzMNLmXM/aswYpSGxVEAuHilgBZ6/++/Pv08ICmuOqX107w==", + "license": "MIT", + "dependencies": { + "fast-xml-parser": "5.4.1", + "piccolore": "^0.1.3", + "zod": "^4.3.6" + } + }, + "node_modules/@astrojs/rss/node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/@astrojs/sitemap": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@astrojs/sitemap/-/sitemap-3.7.1.tgz", + "integrity": "sha512-IzQqdTeskaMX+QDZCzMuJIp8A8C1vgzMBp/NmHNnadepHYNHcxQdGLQZYfkbd2EbRXUfOS+UDIKx8sKg0oWVdw==", + "license": "MIT", + "dependencies": { + "sitemap": "^9.0.0", + "stream-replace-string": "^2.0.0", + "zod": "^4.3.6" + } + }, + "node_modules/@astrojs/sitemap/node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "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/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "license": "MIT", + "engines": { + "node": ">=6.9.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/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "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/@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.9.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.1.tgz", + "integrity": "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==", + "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/eslintrc/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/@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/@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", + "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/fluent": { + "version": "1.2.41", + "resolved": "https://registry.npmjs.org/@iconify-json/fluent/-/fluent-1.2.41.tgz", + "integrity": "sha512-UbUFCJm7gICJuiDVZdo259L05TxAKbECJ/NBax/+N5CejWXJ0q/y++HNWLdJBkSfsZVYH9KtFZgwox36PC0/Wg==", + "dev": true, + "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.3", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.3.tgz", + "integrity": "sha512-+wn7I4p7YgJhHs38k2TNjy1vCfPIfLIJWR5MnCStsN8WuuTcBnRKcMHQLMM2ijxGZmDoZwNv8ipl5aTTen62ng==", + "license": "MIT", + "dependencies": { + "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", + "sax": "^1.5.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/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "engines": { + "node": ">=6.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/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "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/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "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/@orama/core": { + "version": "1.2.19", + "resolved": "https://registry.npmjs.org/@orama/core/-/core-1.2.19.tgz", + "integrity": "sha512-AVEI0eG/a1RUQK+tBloRMppQf46Ky4kIYKEVjo0V0VfIGZHdLOE2PJR4v949kFwiTnfSJCUaxgwM74FCA1uHUA==", + "license": "AGPL-3.0", + "peer": true, + "dependencies": { + "@orama/cuid2": "2.2.3", + "@orama/oramacore-events-parser": "0.0.5" + } + }, + "node_modules/@orama/cuid2": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@orama/cuid2/-/cuid2-2.2.3.tgz", + "integrity": "sha512-Lcak3chblMejdlSHgYU2lS2cdOhDpU6vkfIJH4m+YKvqQyLqs1bB8+w6NT1MG5bO12NUK2GFc34Mn2xshMIQ1g==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.1.5" + } + }, + "node_modules/@orama/oramacore-events-parser": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@orama/oramacore-events-parser/-/oramacore-events-parser-0.0.5.tgz", + "integrity": "sha512-yAuSwog+HQBAXgZ60TNKEwu04y81/09mpbYBCmz1RCxnr4ObNY2JnPZI7HmALbjAhLJ8t5p+wc2JHRK93ubO4w==", + "license": "AGPL-3.0" + }, + "node_modules/@orama/stopwords": { + "version": "3.1.18", + "resolved": "https://registry.npmjs.org/@orama/stopwords/-/stopwords-3.1.18.tgz", + "integrity": "sha512-W8V7m7RnCme+99OmKl/xs5rf6OUhFpr0aPGVmPrXzTLSg4ZqSbRY2euS2S/lgjjYi/0NhEWqwoq8nDY6Ihx4EA==", + "license": "Apache-2.0", + "engines": { + "node": ">= 20.0.0" + } + }, + "node_modules/@orama/ui": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@orama/ui/-/ui-1.5.4.tgz", + "integrity": "sha512-lljPUpyYQ2aOWXDyfIOyI6DROHcCPfGT44I+Ji3W0EEnv4RZQEQchMDJp+8Mhxwy+qW7nJKRr5GA0rmgzQVVPg==", + "license": "MIT", + "dependencies": { + "@orama/stopwords": "^3.1.16", + "prism-react-renderer": "^1.3.5", + "react-markdown": "^10.1.0", + "remark-gfm": "^4.0.1", + "throttleit": "^2.1.0" + }, + "peerDependencies": { + "@orama/core": "^1.2.13" + } + }, + "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/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "license": "MIT" + }, + "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.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "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/@svgr/babel-plugin-add-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", + "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", + "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", + "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", + "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz", + "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", + "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-preset": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", + "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", + "dev": true, + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", + "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", + "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", + "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", + "@svgr/babel-plugin-transform-svg-component": "8.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/core": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", + "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^8.1.3", + "snake-case": "^3.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/core/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", + "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.21.3", + "entities": "^4.4.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", + "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "@svgr/hast-util-to-babel-ast": "8.0.0", + "svg-parser": "^2.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "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/node": { + "version": "25.3.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.2.tgz", + "integrity": "sha512-RpV6r/ij22zRRdyBPcxDeKAzH43phWVKEjL2iksqo1Vz3CuBUrgmPpPhALKiRfU7OMCmeeO9vECBMsV0hMTG8Q==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "peer": true, + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "peer": true, + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/sax": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz", + "integrity": "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "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.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "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/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "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.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "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/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "license": "MIT" + }, + "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.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", + "@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.27.3", + "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.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.3", + "unist-util-visit": "^5.0.0", + "unstorage": "^1.17.4", + "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-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", + "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/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", + "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/baseline-browser-mapping": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", + "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "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", + "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/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true, + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "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/caniuse-lite": { + "version": "1.0.30001777", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001777.tgz", + "integrity": "sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "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/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + }, + "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/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dev": true, + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "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-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", + "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/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==" + }, + "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.4", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.4.tgz", + "integrity": "sha512-Gp6rDldRsFh/7XuouDbxMH3Mx8GMCcgzIb1pDTvNyn8pZGQ22u+Wa+lGV9dQCltFQ7uVw0MhRyb8XDskNFOReA==", + "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/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", + "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/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "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/electron-to-chromium": { + "version": "1.5.307", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.307.tgz", + "integrity": "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==" + }, + "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/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "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/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "engines": { + "node": ">=6" + } + }, + "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/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "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/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", + "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/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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/fast-xml-builder": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.4.tgz", + "integrity": "sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "path-expression-matcher": "^1.1.3" + } + }, + "node_modules/fast-xml-parser": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.4.1.tgz", + "integrity": "sha512-BQ30U1mKkvXQXXkAGcuyUA/GA26oEB7NzOtsxCDtyu62sjGw5QraKFhx2Em3WQNjPw9PG6MQ9yuIIgkSDfGu5A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "fast-xml-builder": "^1.0.0", + "strnum": "^2.1.2" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "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.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "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/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "engines": { + "node": ">=6.9.0" + } + }, + "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": "17.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.4.0.tgz", + "integrity": "sha512-hjrNztw/VajQwOLsMNT1cbJiH2muO3OROCHnbehc8eY5JyD2gqz4AcMHPqgaOR59DjgUjYAYLeH699g/eWi2jw==", + "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/gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "dependencies": { + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/gray-matter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/gray-matter/node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/h3": { + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.10.tgz", + "integrity": "sha512-YzJeWSkDZxAhvmp8dexjRK5hxziRO7I9m0N53WhvYL5NiWfkUkzssVzY9jvGu0HBoLFW6+duYmNSn6MaZBCCtg==", + "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-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", + "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-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", + "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-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", + "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-url-attributes": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", + "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "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-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "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-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "engines": { + "node": ">=0.10.0" + } + }, + "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-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "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/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "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-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "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/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "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/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" + } + }, + "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/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "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/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "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.3", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz", + "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==", + "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==", + "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.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "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/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "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/node-releases": { + "version": "2.0.36", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", + "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==" + }, + "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/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ] + }, + "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-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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-expression-matcher": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.2.0.tgz", + "integrity": "sha512-DwmPWeFn+tq7TiyJ2CxezCAirXjFxvaiD03npak3cRjlP9+OjTmSy1EpIrEbh+l6JgUundniloMLDQ/6VTdhLQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "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/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "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-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", + "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/prism-react-renderer": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-1.3.5.tgz", + "integrity": "sha512-IJ+MSwBWKG+SM3b2SUfdrhC+gu01QkV2KmRQgREThBfSQRoufqRfxfHUxpG1WcaFjP+kojcFyO9Qqtpgt3qLCg==", + "license": "MIT", + "peerDependencies": { + "react": ">=0.14.9" + } + }, + "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/react": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", + "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "peer": true, + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.4" + } + }, + "node_modules/react-markdown": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz", + "integrity": "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "html-url-attributes": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "unified": "^11.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=18", + "react": ">=18" + } + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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-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", + "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.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", + "license": "MIT", + "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.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", + "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.6.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==" + }, + "node_modules/section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "dependencies": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "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/sitemap": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-9.0.1.tgz", + "integrity": "sha512-S6hzjGJSG3d6if0YoF5kTyeRJvia6FSTBroE5fQ0bu1QNxyJqhhinfUsXi9fH3MgtXODWvwo2BDyQSnhPQ88uQ==", + "license": "MIT", + "dependencies": { + "@types/node": "^24.9.2", + "@types/sax": "^1.2.1", + "arg": "^5.0.0", + "sax": "^1.4.1" + }, + "bin": { + "sitemap": "dist/esm/cli.js" + }, + "engines": { + "node": ">=20.19.5", + "npm": ">=10.8.2" + } + }, + "node_modules/sitemap/node_modules/@types/node": { + "version": "24.12.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.0.tgz", + "integrity": "sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/sitemap/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" + }, + "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/snake-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "dev": true, + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "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/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + }, + "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/stream-replace-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/stream-replace-string/-/stream-replace-string-2.0.0.tgz", + "integrity": "sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==", + "license": "MIT" + }, + "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-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", + "engines": { + "node": ">=0.10.0" + } + }, + "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/strnum": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.2.tgz", + "integrity": "sha512-DnR90I+jtXNSTXWdwrEy9FakW7UX+qUZg28gj5fk2vxxl7uS/3bpI4fjFYVmdK9etptYBPNkpahuQnEwhwECqA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "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/svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", + "dev": true + }, + "node_modules/svgo": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.1.tgz", + "integrity": "sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==", + "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.5.0" + }, + "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.12", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.12.tgz", + "integrity": "sha512-9TsuLcdhOn4XztcQqhNyq1KOwOOED/3k58JAvtULiYqbO8B/0IBAAIE1hj0Svmm58k27TmcigyDI0deMlgG3uw==", + "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/throttleit": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-2.1.0.tgz", + "integrity": "sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "devOptional": true, + "license": "0BSD" + }, + "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.24.5", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.5.tgz", + "integrity": "sha512-3IWdCpjgxp15CbJnsi/Y9TCDE7HWVN19j1hmzVhoAkY/+CJx449tVxT5wZc1Gwg8J+P0LWvzlBzxYRnHJ+1i7Q==", + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "license": "MIT" + }, + "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/unplugin": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.11.tgz", + "integrity": "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==", + "dev": true, + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "acorn": "^8.15.0", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/unplugin-icons": { + "version": "23.0.1", + "resolved": "https://registry.npmjs.org/unplugin-icons/-/unplugin-icons-23.0.1.tgz", + "integrity": "sha512-rv0XEJepajKzDLvRUWASM8K+8+/CCfZn2jtogXqg6RIp7kpatRc/aFrVJn8ANQA09e++lPEEv9yX8cC9enc+QQ==", + "dev": true, + "dependencies": { + "@antfu/install-pkg": "^1.1.0", + "@iconify/utils": "^3.1.0", + "local-pkg": "^1.1.2", + "obug": "^2.1.1", + "unplugin": "^2.3.11" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@svgr/core": ">=7.0.0", + "@svgx/core": "^1.0.1", + "@vue/compiler-sfc": "^3.0.2", + "svelte": "^3.0.0 || ^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "@svgr/core": { + "optional": true + }, + "@svgx/core": { + "optional": true + }, + "@vue/compiler-sfc": { + "optional": true + }, + "svelte": { + "optional": true + } + } + }, + "node_modules/unplugin-icons/node_modules/@iconify/utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.1.0.tgz", + "integrity": "sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw==", + "dev": true, + "dependencies": { + "@antfu/install-pkg": "^1.1.0", + "@iconify/types": "^2.0.0", + "mlly": "^1.8.0" + } + }, + "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/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "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==", + "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/vite-plugin-svgr": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/vite-plugin-svgr/-/vite-plugin-svgr-4.5.0.tgz", + "integrity": "sha512-W+uoSpmVkSmNOGPSsDCWVW/DDAyv+9fap9AZXBvWiQqrboJ08j2vh0tFxTD/LjwqwAd3yYSVJgm54S/1GhbdnA==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.2.0", + "@svgr/core": "^8.1.0", + "@svgr/plugin-jsx": "^8.1.0" + }, + "peerDependencies": { + "vite": ">=2.6.0" + } + }, + "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/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "dev": true + }, + "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", + "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..b30ab6809d --- /dev/null +++ b/astro/package.json @@ -0,0 +1,67 @@ +{ + "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", + "@astrojs/react": "^4.4.2", + "@astrojs/rss": "^4.0.17", + "@astrojs/sitemap": "^3.7.0", + "@orama/core": "^1.2.19", + "@orama/ui": "^1.5.4", + "astro": "^5.18.0", + "astro-expressive-code": "^0.41.7", + "astro-icon": "^1.1.5", + "gray-matter": "^4.0.3", + "mdast-util-from-markdown": "^2.0.3", + "mdast-util-to-string": "^4.0.0", + "react": "^19.2.4", + "react-dom": "^19.2.4" + }, + "devEngines": { + "runtime": { + "name": "node", + "version": "24.x", + "onFail": "error" + }, + "packageManager": { + "name": "npm", + "version": ">=11.0.0", + "onFail": "error" + } + }, + "devDependencies": { + "@csstools/postcss-global-data": "^4.0.0", + "@eslint/js": "^9.39.2", + "@iconify-json/fluent": "^1.2.41", + "@types/node": "^25.3.2", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "eslint": "^9.39.2", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-astro": "^1.5.0", + "eslint-plugin-jsx-a11y": "^6.10.2", + "globals": "^17.4.0", + "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", + "unplugin-icons": "^23.0.1", + "vite-plugin-svgr": "^4.5.0" + } +} diff --git a/astro/postcss.config.mjs b/astro/postcss.config.mjs new file mode 100644 index 0000000000..febcf2f575 --- /dev/null +++ b/astro/postcss.config.mjs @@ -0,0 +1,13 @@ +import postcssGlobalData from '@csstools/postcss-global-data'; +import postcssCustomMedia from 'postcss-custom-media'; +import postcssNested from 'postcss-nested'; + +export default { + plugins: [ + postcssGlobalData({ + files: ['./src/styles/tokens/_breakpoints.css'], + }), + postcssCustomMedia(), + postcssNested(), + ], +}; diff --git a/astro/public/apple-touch-icon.png b/astro/public/apple-touch-icon.png new file mode 100644 index 0000000000..1246e42e69 Binary files /dev/null and b/astro/public/apple-touch-icon.png differ diff --git a/astro/public/favicon.ico b/astro/public/favicon.ico new file mode 100644 index 0000000000..45865d9e17 Binary files /dev/null and b/astro/public/favicon.ico differ 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 0000000000..6538498736 Binary files /dev/null and b/astro/public/fonts/JetBrainsMono-Light.woff2 differ diff --git a/astro/public/fonts/JetBrainsMono-LightItalic.woff2 b/astro/public/fonts/JetBrainsMono-LightItalic.woff2 new file mode 100644 index 0000000000..66ca3d2b99 Binary files /dev/null and b/astro/public/fonts/JetBrainsMono-LightItalic.woff2 differ diff --git a/astro/public/hero-poster-light.jpg b/astro/public/hero-poster-light.jpg new file mode 100644 index 0000000000..135b4be964 Binary files /dev/null and b/astro/public/hero-poster-light.jpg differ diff --git a/astro/public/hero-poster.jpg b/astro/public/hero-poster.jpg new file mode 100644 index 0000000000..b6709c7605 Binary files /dev/null and b/astro/public/hero-poster.jpg differ 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-express-black.svg b/astro/public/logo-express-black.svg new file mode 100644 index 0000000000..d9dace678c --- /dev/null +++ b/astro/public/logo-express-black.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + 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/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/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/public/posts/sample-cover.png b/astro/public/posts/sample-cover.png new file mode 100644 index 0000000000..5eaae265ed Binary files /dev/null and b/astro/public/posts/sample-cover.png differ 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/public/videos/hero-background-light.mp4 b/astro/public/videos/hero-background-light.mp4 new file mode 100644 index 0000000000..e20340f1ea Binary files /dev/null and b/astro/public/videos/hero-background-light.mp4 differ diff --git a/astro/public/videos/hero-background.mp4 b/astro/public/videos/hero-background.mp4 new file mode 100644 index 0000000000..fcf4b00df0 Binary files /dev/null and b/astro/public/videos/hero-background.mp4 differ diff --git a/astro/scripts/orama-documents.mjs b/astro/scripts/orama-documents.mjs new file mode 100644 index 0000000000..d1af22aab1 --- /dev/null +++ b/astro/scripts/orama-documents.mjs @@ -0,0 +1,131 @@ +import { readFile, readdir, stat } from 'node:fs/promises'; +import { join, relative, extname, basename } from 'node:path'; +import { fileURLToPath, URL } from 'node:url'; +import matter from 'gray-matter'; +import { fromMarkdown } from 'mdast-util-from-markdown'; +import { toString } from 'mdast-util-to-string'; + +const CONTENT_DIR = fileURLToPath(new URL('../src/content', import.meta.url)); + +const mdToText = (content) => toString(fromMarkdown(content)).replace(/<[^>]*>/g, ''); + +const collectMdFiles = async (dir, base = dir) => { + const entries = await readdir(dir); + const results = await Promise.all( + entries.map(async (entry) => { + const fullPath = join(dir, entry); + const info = await stat(fullPath); + if (info.isDirectory()) return collectMdFiles(fullPath, base); + if (extname(entry) === '.md') return [relative(base, fullPath)]; + return []; + }) + ); + return results.flat(); +}; + +export const getResources = async (lang) => { + const baseDir = join(CONTENT_DIR, `resources/${lang}`); + const mdFiles = await collectMdFiles(baseDir); + + return Promise.all( + mdFiles.map(async (file) => { + const fullPath = join(baseDir, file); + const raw = await readFile(fullPath, 'utf-8'); + const { data, content } = matter(raw); + const pathSegment = relative(baseDir, fullPath).replace(/\.md$/, ''); + + return { + title: data.title ?? basename(file, '.md'), + description: data.description ?? '', + content: mdToText(content), + path: `/${lang}/resources/${pathSegment}`, + category: 'menu.resources', + }; + }) + ); +}; + +export const getDocs = async (lang) => { + const baseDir = join(CONTENT_DIR, `docs/${lang}/5x`); + const mdFiles = await collectMdFiles(baseDir); + + return Promise.all( + mdFiles.map(async (file) => { + const fullPath = join(baseDir, file); + const raw = await readFile(fullPath, 'utf-8'); + const { data, content } = matter(raw); + const pathSegment = relative(baseDir, fullPath).replace(/\.md$/, ''); + + return { + title: data.title ?? basename(file, '.md'), + description: data.description ?? '', + content: mdToText(content), + path: `/${lang}/${pathSegment}`, + category: 'menu.docs', + }; + }) + ); +}; + +export const getBlogPosts = async (lang) => { + const baseDir = join(CONTENT_DIR, `blog/${lang}`); + const mdFiles = await collectMdFiles(baseDir); + + return Promise.all( + mdFiles.map(async (file) => { + const fullPath = join(baseDir, file); + const raw = await readFile(fullPath, 'utf-8'); + const { data, content } = matter(raw); + const slug = basename(file, '.md'); + + return { + title: data.title ?? slug, + description: data.description ?? '', + content: mdToText(content), + path: `/${lang}/blog/${slug}`, + category: 'menu.blog', + }; + }) + ); +}; + +const VERSIONS = /** @type {const} */ (['5x', '4x', '3x']); + +export const getApi = async (lang) => { + const results = await Promise.all( + VERSIONS.map(async (version) => { + const baseDir = join(CONTENT_DIR, `api/${version}`); + const mdFiles = await collectMdFiles(baseDir); + + return Promise.all( + mdFiles.map(async (file) => { + const fullPath = join(baseDir, file); + const raw = await readFile(fullPath, 'utf-8'); + const { data, content } = matter(raw); + const pathSegment = relative(baseDir, fullPath).replace(/\.md$/, ''); + + return { + title: data.title ?? basename(file, '.md'), + description: data.description ?? '', + content: mdToText(content), + path: `/${lang}/${version}/${pathSegment}`, + category: 'menu.api', + version, + }; + }) + ); + }) + ); + + return results.flat(); +}; + +export const getAllDocuments = async (lang) => { + const [docs, api, resources, blog] = await Promise.all([ + getDocs(lang), + getApi(lang), + getResources(lang), + getBlogPosts(lang), + ]); + return [...docs, ...api, ...resources, ...blog]; +}; diff --git a/astro/scripts/sync-orama.mjs b/astro/scripts/sync-orama.mjs new file mode 100644 index 0000000000..cfb28c6c0d --- /dev/null +++ b/astro/scripts/sync-orama.mjs @@ -0,0 +1,57 @@ +import process from 'node:process'; +import console from 'node:console'; +import { URL } from 'node:url'; +import { OramaCloud } from '@orama/core'; +import { getAllDocuments } from './orama-documents.mjs'; + +try { + process.loadEnvFile(new URL('../.env.local', import.meta.url)); +} catch (error) { + console.error('Error loading .env.local file:', error); +} +/** + * The default batch size to use when syncing Orama Cloud + */ +const ORAMA_SYNC_BATCH_SIZE = 250; + +// The following follows the instructions at https://docs.orama.com/cloud/data-sources/custom-integrations/webhooks +const documents = await getAllDocuments('en'); +console.log(`Syncing ${documents.length} documents to Orama Cloud index`); + +const orama = new OramaCloud({ + projectId: process.env.PUBLIC_ORAMA_PROJECT_ID || '', + apiKey: process.env.PRIVATE_ORAMA_API_KEY || '', +}); + +const datasource = orama.dataSource(process.env.PUBLIC_ORAMA_DATASOURCE_ID || ''); +// Create a temporary index to perform the insertions +const temporary = await datasource.createTemporaryIndex(); + +// Orama allows to send several documents at once, so we batch them in groups of 50. +// This is not strictly necessary, but it makes the process faster. +const runUpdate = async () => { + const batchSize = ORAMA_SYNC_BATCH_SIZE; + const batches = []; + + for (let i = 0; i < documents.length; i += batchSize) { + batches.push(documents.slice(i, i + batchSize)); + } + + console.log(`Sending ${batches.length} batches of ${batchSize} documents`); + + for (const batch of batches) { + await temporary.insertDocuments(batch); + } + + // Once all documents are inserted into the temporary index, we swap it with the live one atomically. + await temporary.swap(); +}; + +// Now we proceed to call the APIs in order. +// The previous implementation used to empty the index before inserting new documents +// to remove documents that are no longer in the source. +// The new API from @orama/core might have a different approach for full sync. +// Based on the provided examples, we are now only running the update. +await runUpdate(); + +console.log('Orama Cloud sync completed successfully!'); diff --git a/astro/src/components/patterns/Banner/Banner.astro b/astro/src/components/patterns/Banner/Banner.astro new file mode 100644 index 0000000000..12edb5e01b --- /dev/null +++ b/astro/src/components/patterns/Banner/Banner.astro @@ -0,0 +1,71 @@ +--- +/** + * Banner Component + * + * A full-width notification banner displayed at the top of the page. + * Visibility is controlled server-side via optional date range props. + * When dismissible, the closed state is persisted in localStorage. + * + * @example + * + * Express v5 is out! Read the changelog → + * + */ +import { Body, Container, Flex } from '@/components/primitives'; +import './Banner.css'; +import type { BannerProps } from './types'; +import { Icon } from 'astro-icon/components'; + +type Props = BannerProps; + +const { id, variant = 'info', dismissible = false, title, startDate, endDate } = Astro.props; + +const now = new Date(); +const start = startDate ? new Date(startDate) : null; +const end = endDate ? new Date(endDate) : null; +const isActive = (!start || now >= start) && (!end || now <= end); +--- + +{ + isActive && ( +
+ + + + + {title} + + + + + {dismissible && ( + + )} +
+ ) +} + + diff --git a/astro/src/components/patterns/Banner/Banner.css b/astro/src/components/patterns/Banner/Banner.css new file mode 100644 index 0000000000..cd44ffc47b --- /dev/null +++ b/astro/src/components/patterns/Banner/Banner.css @@ -0,0 +1,49 @@ +@layer patterns { + .banner { + width: 100%; + padding: var(--space-4) 0; + border-bottom: var(--border-width-1) solid; + position: relative; + } + + .banner--info { + background-color: var(--color-bg-info); + border-color: var(--color-border-info); + color: var(--color-text-info); + } + + .banner--warning { + background-color: var(--color-bg-warning); + border-color: var(--color-border-warning); + color: var(--color-text-warning); + } + + .banner__icon { + margin: 0; + } + + .banner__dismiss { + display: flex; + align-items: center; + justify-content: center; + background: none; + border: none; + cursor: pointer; + padding: var(--space-1); + color: inherit; + border-radius: var(--radius-base); + flex-shrink: 0; + position: absolute; + top: var(--space-4); + right: var(--space-4); + + &:hover { + background-color: light-dark(oklch(0% 0 0 / 0.08), oklch(100% 0 0 / 0.08)); + } + + &:focus-visible { + outline: 2px solid var(--color-focus-ring); + outline-offset: 2px; + } + } +} diff --git a/astro/src/components/patterns/Banner/index.ts b/astro/src/components/patterns/Banner/index.ts new file mode 100644 index 0000000000..95f4f8b315 --- /dev/null +++ b/astro/src/components/patterns/Banner/index.ts @@ -0,0 +1,2 @@ +export { default as Banner } from './Banner.astro'; +export type { BannerProps } from './types'; diff --git a/astro/src/components/patterns/Banner/types.ts b/astro/src/components/patterns/Banner/types.ts new file mode 100644 index 0000000000..6b2bffb418 --- /dev/null +++ b/astro/src/components/patterns/Banner/types.ts @@ -0,0 +1,49 @@ +interface BannerBaseProps { + /** + * Visual style of the banner. + * @default 'info' + */ + variant?: 'info' | 'warning'; + + /** + * Title of the banner. + * Displayed prominently at the start of the banner. + */ + title: string; +} + +interface DismissibleBannerProps extends BannerBaseProps { + /** + * Whether the user can dismiss (close) the banner. + * Dismissal state is persisted in localStorage so the banner stays hidden across sessions. + */ + dismissible: true; + + /** + * Unique identifier for this banner. + * Used as the HTML `id` and as the localStorage key for persisting dismissal state. + * Required when `dismissible` is true. + */ + id: string; +} + +interface NonDismissibleBannerProps extends BannerBaseProps { + dismissible?: false; + id?: never; +} + +export type BannerProps = (DismissibleBannerProps | NonDismissibleBannerProps) & { + /** + * ISO date string or Date object. + * The banner will not be displayed before this date. + * Omit to show the banner immediately. + */ + startDate?: Date | string; + + /** + * ISO date string or Date object. + * The banner will not be displayed after this date. + * Omit to show the banner indefinitely. + */ + endDate?: Date | string; +}; diff --git a/astro/src/components/patterns/Breadcrumbs/Breadcrumbs.astro b/astro/src/components/patterns/Breadcrumbs/Breadcrumbs.astro new file mode 100644 index 0000000000..c863f7144c --- /dev/null +++ b/astro/src/components/patterns/Breadcrumbs/Breadcrumbs.astro @@ -0,0 +1,40 @@ +--- +/** + * 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/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/patterns/CardList/CardList.astro b/astro/src/components/patterns/CardList/CardList.astro new file mode 100644 index 0000000000..a879154f47 --- /dev/null +++ b/astro/src/components/patterns/CardList/CardList.astro @@ -0,0 +1,60 @@ +--- +/** + * CardList Pattern Component + * + * A responsive cards list built on top of the Grid primitive. + * Add cards (or card links) through the default slot. + */ + +import './CardList.css'; +import type { HTMLAttributes } from 'astro/types'; +import { Grid } from '@/components/primitives'; +import type { GapSize, ColSpan } from '@/components/primitives/Grid/types'; + +interface Props extends HTMLAttributes<'div'> { + /** Gap between items */ + gap?: GapSize; + /** Vertical gap override */ + rowGap?: GapSize; + /** Horizontal gap override */ + columnGap?: GapSize; + /** Columns span per item on mobile */ + itemXs?: ColSpan; + /** Columns span per item on tablet */ + itemMd?: ColSpan; + /** Columns span per item on desktop */ + itemLg?: ColSpan; +} + +const { + gap = '4', + rowGap, + columnGap, + itemXs = 12, + itemMd = 6, + itemLg = 4, + class: className, + style, + ...rest +} = Astro.props; + +const responsiveStyle = [ + `--card-list-item-xs: ${itemXs}`, + `--card-list-item-md: ${itemMd}`, + `--card-list-item-lg: ${itemLg}`, + style, +] + .filter(Boolean) + .join('; '); +--- + + + + diff --git a/astro/src/components/patterns/CardList/CardList.css b/astro/src/components/patterns/CardList/CardList.css new file mode 100644 index 0000000000..8a3762b229 --- /dev/null +++ b/astro/src/components/patterns/CardList/CardList.css @@ -0,0 +1,32 @@ +@layer patterns { + .card-list > * { + grid-column: span var(--card-list-item-xs, 12); + display: flex; + } + + .card-list > * > .card { + flex: 1; + height: 100%; + } + + .card-list > a, + .card-list > a:visited, + .card-list > a:hover, + .card-list > a:active { + color: inherit; + text-decoration: none; + } + + @media (--md-only) { + .card-list > * { + grid-column: span var(--card-list-item-md, var(--card-list-item-xs, 12)); + } + } + + @media (--lg-up) { + .card-list > * { + grid-column: span + var(--card-list-item-lg, var(--card-list-item-md, var(--card-list-item-xs, 12))); + } + } +} diff --git a/astro/src/components/patterns/CardList/index.ts b/astro/src/components/patterns/CardList/index.ts new file mode 100644 index 0000000000..a79c6f9776 --- /dev/null +++ b/astro/src/components/patterns/CardList/index.ts @@ -0,0 +1 @@ +export { default as CardList } from './CardList.astro'; diff --git a/astro/src/components/patterns/Features/Features.astro b/astro/src/components/patterns/Features/Features.astro new file mode 100644 index 0000000000..c63ec6a192 --- /dev/null +++ b/astro/src/components/patterns/Features/Features.astro @@ -0,0 +1,42 @@ +--- +/** + * Features Pattern Component + * + * Displays a section title alongside a grid of feature cards. + * + * Layout: + * - Mobile: title above cards, 1 per row + * - Tablet: title above cards, 2 per row + * - Desktop: title in 4/12 columns · cards in 8/12 columns, 2 per row + * + * @example + * + * + * + * + */ +import './Features.css'; +import type { HTMLAttributes } from 'astro/types'; +import { H2, Container, Grid, Col } from '@/components/primitives'; + +interface Props extends HTMLAttributes<'section'> { + title: string; +} + +const { title, class: className, ...rest } = Astro.props; +--- + +
+ + + +

{title}

+ + + + + + +
+
+
diff --git a/astro/src/components/patterns/Features/Features.css b/astro/src/components/patterns/Features/Features.css new file mode 100644 index 0000000000..5c9ebad062 --- /dev/null +++ b/astro/src/components/patterns/Features/Features.css @@ -0,0 +1,55 @@ +@layer patterns { + .features { + padding: var(--space-8) 0; + + @media (--md-up) { + padding: var(--space-12) 0; + } + } + + .features__header { + padding-bottom: var(--space-8); + + @media (--lg-up) { + align-self: start; + padding-bottom: 0; + padding-right: var(--space-8); + } + } + + .features__cards { + overflow: hidden; + align-items: stretch; + border-radius: var(--radius-card); + border: var(--border-width-1) solid var(--color-border-secondary); + } + + .features__card-col { + .card { + flex: 1; + height: 100%; + border-radius: 0; + border-top: 0; + border-right: 0; + border-left: 0; + } + + &:last-child .card { + border-bottom: 0; + } + + @media (--md-up) { + &:nth-child(2n) { + .card { + border-left: var(--border-width-1) solid var(--color-border-secondary); + } + } + + &:nth-last-child(-n + 2) { + .card { + border-bottom: 0; + } + } + } + } +} diff --git a/astro/src/components/patterns/Features/index.ts b/astro/src/components/patterns/Features/index.ts new file mode 100644 index 0000000000..90a026f8ef --- /dev/null +++ b/astro/src/components/patterns/Features/index.ts @@ -0,0 +1 @@ +export { default as Features } from './Features.astro'; 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/Header/Header.astro b/astro/src/components/patterns/Header/Header.astro new file mode 100644 index 0000000000..32b7355e8b --- /dev/null +++ b/astro/src/components/patterns/Header/Header.astro @@ -0,0 +1,70 @@ +--- +/** + * Header Component + * + * Main site header with logo and navigation menu + */ +import './Header.css'; +import { Icon } from 'astro-icon/components'; +import { Flex } from '@/components/primitives'; +import { ThemeSwitcher, SearchBox, LanguageSelect } from '@components/patterns'; +import { languagesArray } from '@/i18n/locales'; +import { getLangFromUrl, useTranslations } from '@/i18n/utils'; + +const currentLang = getLangFromUrl(Astro.url); +const t = useTranslations(currentLang); +--- + +
+ + + + + + + + + + + + + +
+ + diff --git a/astro/src/components/patterns/Header/Header.css b/astro/src/components/patterns/Header/Header.css new file mode 100644 index 0000000000..7313b9dea6 --- /dev/null +++ b/astro/src/components/patterns/Header/Header.css @@ -0,0 +1,138 @@ +/** + * Header Styles + */ + +@layer patterns { + .header { + background-color: var(--color-bg-secondary); + position: sticky; + top: 0; + padding: var(--space-3) var(--space-4); + z-index: var(--z-index-header); + border-bottom: 1px solid var(--color-border-secondary); + + @media (--md-up) { + background-color: var(--color-bg-primary); + position: fixed; + top: 0; + left: 0; + right: 0; + + .logo-link { + display: none; + } + } + } + + .skip-link { + color: var(--color-text-primary); + + &:focus { + position: relative; + padding: var(--space-2) var(--space-4); + background-color: var(--color-bg-tertiary); + text-decoration: none; + border-radius: var(--radius-md); + outline: 1px solid var(--color-focus-ring); + outline-offset: -2px; + border: 0; + margin: 0; + overflow: visible; + clip: auto; + white-space: nowrap; + width: auto; + height: auto; + font-size: var(--font-size-sm); + line-height: var(--line-height-snug); + } + } + + .logo-link { + display: flex; + align-items: center; + text-decoration: none; + border-radius: var(--radius-sm); + } + + .logo { + height: var(--size-5); + width: auto; + + @media (--md-up) { + height: var(--size-6); + } + } + + :root[data-theme='light'] .logo-light, + :root:not([data-theme]) .logo-light { + display: none; + } + + :root[data-theme='dark'] .logo-dark { + display: none; + } + + .hamburger { + width: var(--size-9); + height: var(--size-9); + background: none; + border: none; + cursor: pointer; + position: relative; + + @media (--md-up) { + display: none; + } + } + + .hamburger-line { + width: 50%; + height: var(--size-0-5); + margin: 0; + background-color: var(--color-icon-primary); + border-radius: var(--radius-full); + transition: + transform var(--duration-300) var(--ease-in-out), + opacity var(--duration-200) var(--ease-in-out); + position: absolute; + left: 50%; + top: 50%; + transform: translateX(-50%) translateY(-50%); + } + + .hamburger-line:nth-child(1) { + transform: translateX(-50%) translateY(-0.6rem); + } + + .hamburger-line:nth-child(2) { + transform: translateX(-50%) translateY(0); + } + + .hamburger-line:nth-child(3) { + transform: translateX(-50%) translateY(0.6rem); + } + + .hamburger.active .hamburger-line:nth-child(1) { + transform: translateX(-50%) translateY(0) rotate(45deg); + } + + .hamburger.active .hamburger-line:nth-child(2) { + opacity: 0; + transform: translateX(-50%) translateX(-1rem); + display: none; + } + + .hamburger.active .hamburger-line:nth-child(3) { + transform: translateX(-50%) translateY(0) rotate(-45deg); + } + + @media (prefers-reduced-motion: reduce) { + .hamburger-line { + transition: none; + } + + .logo-link { + transition: none; + } + } +} diff --git a/astro/src/components/patterns/Hero/Hero.astro b/astro/src/components/patterns/Hero/Hero.astro new file mode 100644 index 0000000000..016561dbed --- /dev/null +++ b/astro/src/components/patterns/Hero/Hero.astro @@ -0,0 +1,271 @@ +--- +import './Hero.css'; +import { Image } from 'astro:assets'; +import { Code } from 'astro-expressive-code/components'; +import { Icon } from 'astro-icon/components'; +import { H1, Button, Container, Flex, BodyMd, Grid, Col } from '@/components/primitives'; +import { getEntry } from 'astro:content'; +import { getLangFromUrl, useTranslations } from '@/i18n/utils'; + +const lang = getLangFromUrl(Astro.url); +const t = useTranslations(lang); + +const expressPackage = await getEntry('npm', 'express'); +const EXPRESS_VERSION = expressPackage?.data.version ?? '5.x'; +const INSTALL_COMMAND = 'npm install express --save'; +const EXAMPLE_CODE = `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}\`) +})`; + +interface Props { + videoSrc?: string; + videoSrcLight?: string; + posterSrc?: string; + posterSrcLight?: string; +} + +const { videoSrc, videoSrcLight, posterSrc, posterSrcLight } = Astro.props; +--- + +
+ { + videoSrc && ( +
+ {posterSrc && ( + + )} + {posterSrcLight && ( + + )} + + {videoSrcLight && ( + + )} +
+ +
+ ) + } + +
+ + + {EXPRESS_VERSION} + + + + +

{t('hero.tagline')}

+
+
+ +
+ +
+ + +
+ +
+ +
+
+
+
+ + diff --git a/astro/src/components/patterns/Hero/Hero.css b/astro/src/components/patterns/Hero/Hero.css new file mode 100644 index 0000000000..bde4007a52 --- /dev/null +++ b/astro/src/components/patterns/Hero/Hero.css @@ -0,0 +1,332 @@ +@layer patterns { + .hero { + position: relative; + padding: var(--space-12) 0; + background-color: var(--color-bg-primary); + overflow: hidden; + + @media (--md-up) { + padding: var(--space-14) 0 var(--space-20) 0; + } + + @media (--lg-up) { + padding: var(--space-20) 0; + } + } + + .hero__video-container { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 0; + overflow: hidden; + } + + .hero__video-poster, + .hero__video { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + min-width: 100%; + min-height: 100%; + width: auto; + height: auto; + object-fit: cover; + } + + .hero__video { + opacity: 0; + transition: opacity 0.5s ease-in; + + &[data-loaded='true'] { + opacity: 1; + } + } + + /* Default (light mode): hide dark poster, show light poster */ + .hero__video-poster--dark { + display: none; + } + + /* Dark theme via data-theme */ + [data-theme='dark'] .hero__video-poster--dark { + display: block; + } + + [data-theme='dark'] .hero__video-poster--light { + display: none; + } + + /* System dark mode */ + @media (prefers-color-scheme: dark) { + .hero__video-poster--dark { + display: block; + } + + .hero__video-poster--light { + display: none; + } + + [data-theme='light'] .hero__video-poster--dark { + display: none; + } + + [data-theme='light'] .hero__video-poster--light { + display: block; + } + } + + /* Default (light mode): hide dark video, show light video */ + .hero__video--dark { + display: none; + } + + /* Dark theme via data-theme */ + [data-theme='dark'] .hero__video--dark { + display: block; + } + + [data-theme='dark'] .hero__video--light { + display: none; + } + + /* System dark mode */ + @media (prefers-color-scheme: dark) { + .hero__video--dark { + display: block; + } + + .hero__video--light { + display: none; + } + + [data-theme='light'] .hero__video--dark { + display: none; + } + + [data-theme='light'] .hero__video--light { + display: block; + } + } + + .hero__video-overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient( + 180deg, + rgba(255, 255, 255, 0.05) 0%, + rgba(255, 255, 255, 0.15) 40%, + rgba(255, 255, 255, 0.3) 70%, + var(--color-bg-primary) 100% + ); + z-index: 1; + } + + .hero__video-control { + position: absolute; + bottom: var(--space-4); + right: var(--space-12); + z-index: 2; + width: var(--size-8); + height: var(--size-8); + display: flex; + align-items: center; + justify-content: center; + border: 1px solid var(--color-border-secondary); + border-radius: var(--radius-full); + color: var(--color-text-tertiary); + cursor: pointer; + transition: all 0.2s ease; + background-color: transparent; + + &:hover { + border-color: var(--color-border-primary); + color: var(--color-text-primary); + transform: scale(1.05); + } + + &:focus-visible { + outline: 2px solid var(--color-focus); + color: var(--color-text-primary); + outline-offset: 2px; + } + + &:active { + transform: scale(0.98); + } + + svg { + width: var(--size-3-5); + height: var(--size-3-5); + } + + &[data-state='playing'] .hero__video-control-play { + display: none; + } + + &[data-state='paused'] .hero__video-control-pause { + display: none; + } + + @media (--xs-only) { + display: none; + } + + @media (--md-up) { + bottom: var(--space-6); + right: var(--space-6); + } + } + + [data-theme='dark'] .hero__video-overlay { + background: linear-gradient( + 180deg, + rgba(0, 0, 0, 0.3) 0%, + rgba(0, 0, 0, 0.5) 40%, + rgba(0, 0, 0, 0.7) 70%, + var(--color-bg-primary) 100% + ); + } + + @media (prefers-color-scheme: dark) { + .hero__video-overlay { + background: linear-gradient( + 180deg, + rgba(0, 0, 0, 0.3) 0%, + rgba(0, 0, 0, 0.5) 40%, + rgba(0, 0, 0, 0.7) 70%, + var(--color-bg-primary) 100% + ); + } + + [data-theme='light'] .hero__video-overlay { + background: linear-gradient( + 180deg, + rgba(255, 255, 255, 0.05) 0%, + rgba(255, 255, 255, 0.15) 40%, + rgba(255, 255, 255, 0.3) 70%, + var(--color-bg-primary) 100% + ); + } + } + + .hero__content { + position: relative; + z-index: 2; + display: flex; + flex-direction: column; + gap: var(--space-8); + + @media (--md-up) { + gap: var(--space-12); + } + } + + .hero__text-content { + @media (--lg-up) { + padding-right: var(--space-10); + } + } + + .hero__logo { + width: var(--size-36); + + svg { + width: 100%; + height: auto; + } + + @media (--md-up) { + width: var(--size-52); + } + } + + .hero__logo-icon--dark { + display: block; + } + + .hero__logo-icon--light { + display: none; + } + + [data-theme='dark'] .hero__logo-icon--dark { + display: none; + } + + [data-theme='dark'] .hero__logo-icon--light { + display: block; + } + + @media (prefers-color-scheme: dark) { + .hero__logo-icon--dark { + display: none; + } + + .hero__logo-icon--light { + display: block; + } + + [data-theme='light'] .hero__logo-icon--dark { + display: block; + } + + [data-theme='light'] .hero__logo-icon--light { + display: none; + } + } + + .hero__cta { + width: 100%; + display: flex; + margin: var(--space-8) 0; + flex-direction: column; + gap: var(--space-4); + + @media (--md-up) { + margin: var(--space-12) 0; + max-width: var(--size-96); + } + } +} + +.hero__code { + .expressive-code { + .frame pre { + backdrop-filter: blur(21px); + } + + figure { + box-shadow: none; + } + } + + [data-theme='dark'] & .expressive-code .frame pre { + background-color: rgba(0, 0, 0, 0.62); + } + + [data-theme='light'] & .expressive-code .frame pre { + background-color: color-mix(in srgb, var(--gray-950) 85%, transparent); + } + + @media (prefers-color-scheme: dark) { + .expressive-code .frame pre { + background-color: rgba(0, 0, 0, 0.62); + } + + [data-theme='light'] & .expressive-code .frame pre { + background-color: color-mix(in srgb, var(--gray-950) 85%, transparent); + } + } +} + +.hero__example-code { + .expressive-code .frame pre { + padding: var(--space-3); + } +} diff --git a/astro/src/components/patterns/Hero/index.ts b/astro/src/components/patterns/Hero/index.ts new file mode 100644 index 0000000000..d9d0f6d215 --- /dev/null +++ b/astro/src/components/patterns/Hero/index.ts @@ -0,0 +1,7 @@ +/** + * Hero Component Index + * + * Export Hero component + */ + +export { default } from './Hero.astro'; diff --git a/astro/src/components/patterns/LanguageSelect/LanguageSelect.astro b/astro/src/components/patterns/LanguageSelect/LanguageSelect.astro new file mode 100644 index 0000000000..0e1a26ae5e --- /dev/null +++ b/astro/src/components/patterns/LanguageSelect/LanguageSelect.astro @@ -0,0 +1,65 @@ +--- +/** + * LanguageSelect Component + * + * Language selector built on top of the Select primitive. + * Uses the Select component with icon variant for language switching. + * + * @example + * + */ + +import { Select } from '@/components/primitives'; +import type { LanguageSelectProps } from './types'; + +type Props = LanguageSelectProps; + +const { languages, currentLanguage = 'en', class: className, id, ...rest } = Astro.props; + +const options = languages.map((lang) => ({ + value: lang.code, + label: lang.label, + selected: lang.code === currentLanguage, +})); +--- + + + + + diff --git a/astro/src/components/patterns/VersionSwitcher/VersionSwitcher.css b/astro/src/components/patterns/VersionSwitcher/VersionSwitcher.css new file mode 100644 index 0000000000..de86ebd4ff --- /dev/null +++ b/astro/src/components/patterns/VersionSwitcher/VersionSwitcher.css @@ -0,0 +1,18 @@ +/** + * VersionSwitcher Styles + **/ + +@layer patterns { + .version-switcher { + gap: var(--space-2); + padding-bottom: var(--space-3); + margin-bottom: var(--space-2); + border-bottom: 1px solid var(--color-border-mute); + + @media (--md-up) { + border-bottom: 0; + margin-bottom: 0; + padding-top: var(--space-3); + } + } +} diff --git a/astro/src/components/patterns/VersionSwitcher/index.ts b/astro/src/components/patterns/VersionSwitcher/index.ts new file mode 100644 index 0000000000..d97f9ad7dc --- /dev/null +++ b/astro/src/components/patterns/VersionSwitcher/index.ts @@ -0,0 +1,6 @@ +/** + * VersionSwitcher Component Exports + */ + +export { default as VersionSwitcher } from './VersionSwitcher.astro'; +export type { VersionConfig, VersionSwitcherProps } from './types'; diff --git a/astro/src/components/patterns/VersionSwitcher/types.ts b/astro/src/components/patterns/VersionSwitcher/types.ts new file mode 100644 index 0000000000..1ed3bed462 --- /dev/null +++ b/astro/src/components/patterns/VersionSwitcher/types.ts @@ -0,0 +1,19 @@ +/** + * VersionSwitcher Component Types + */ + +import type { HTMLAttributes } from 'astro/types'; + +export interface VersionConfig { + id: string; + label: string; + isDefault?: boolean; + isDeprecated?: boolean; +} + +export type VersionSwitcherProps = HTMLAttributes<'div'> & { + versions: VersionConfig[]; + defaultVersion: string; + currentPath?: string; + hidden?: boolean; +}; diff --git a/astro/src/components/patterns/index.ts b/astro/src/components/patterns/index.ts new file mode 100644 index 0000000000..9d33b2a8a7 --- /dev/null +++ b/astro/src/components/patterns/index.ts @@ -0,0 +1,21 @@ +/** + * Index + * + * Re-export all primitive components for easy importing + */ + +export { default as Banner } from './Banner/Banner.astro'; +export { default as Breadcrumbs } from './Breadcrumbs/Breadcrumbs.astro'; +export { default as Header } from './Header/Header.astro'; +export { default as Hero } from './Hero/Hero.astro'; +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 SearchBox } from './Searchbox/Searchbox.tsx'; +export { default as LanguageSelect } from './LanguageSelect/LanguageSelect.astro'; +export { default as Footer } from './Footer/Footer.astro'; +export { default as Features } from './Features/Features.astro'; +export { default as CardList } from './CardList/CardList.astro'; +export { default as PostCard } from './PostCard/PostCard.astro'; +export { default as Pagination } from './Pagination/Pagination.astro'; +export { default as PageHead } from './PageHead/PageHead.astro'; diff --git a/astro/src/components/primitives/Alert/Alert.astro b/astro/src/components/primitives/Alert/Alert.astro new file mode 100644 index 0000000000..1f09b26795 --- /dev/null +++ b/astro/src/components/primitives/Alert/Alert.astro @@ -0,0 +1,63 @@ +--- +/** + * Alert Primitive Component + * + * Contextual callout block with an icon, title, and description. + * Three severity levels map to distinct color schemes and icons. + * + * @example + * + * Useful background information for the reader. + * + * + * + * Something that may cause unexpected behaviour if ignored. + * + * + * + * A risk of data loss or breaking change. + * + */ + +import './Alert.css'; +import type { HTMLAttributes } from 'astro/types'; +import type { AlertProps } from './types'; +import { Icon } from 'astro-icon/components'; +import { Body, Flex } from '@components/primitives'; + +type Props = AlertProps & HTMLAttributes<'div'>; + +const { type = 'info', title, class: className, ...rest } = Astro.props; + +const defaultTitles: Record = { + info: 'Note', + alert: 'Caution', + warning: 'Warning', +}; + +const resolvedTitle = title ?? defaultTitles[type]; +--- + +
+ + { + type === 'info' && ( + +
+ +
+
diff --git a/astro/src/components/primitives/Alert/Alert.css b/astro/src/components/primitives/Alert/Alert.css new file mode 100644 index 0000000000..2da8cfa726 --- /dev/null +++ b/astro/src/components/primitives/Alert/Alert.css @@ -0,0 +1,57 @@ +/** + * Alert Component Styles + */ + +@layer primitives { + .alert { + display: flex; + flex-direction: column; + gap: var(--space-1); + padding: var(--space-4); + border-left-width: var(--border-width-4); + border-left-style: solid; + border-radius: 0 var(--radius-lg) var(--radius-lg) 0; + margin: var(--space-4) 0; + } + + .alert__icon { + flex-shrink: 0; + } + + .alert__description { + p { + margin: 0; + } + } + + /* ============================================ + VARIANTS + ============================================ */ + + .alert--info { + background-color: var(--color-bg-info); + border-color: var(--color-border-info); + + .alert__icon { + color: var(--color-text-info); + } + } + + .alert--alert { + background-color: var(--color-bg-warning); + border-color: var(--color-border-warning); + + .alert__icon { + color: var(--color-text-warning); + } + } + + .alert--warning { + background-color: var(--color-bg-error); + border-color: var(--color-border-error); + + .alert__icon { + color: var(--color-text-error); + } + } +} diff --git a/astro/src/components/primitives/Alert/types.ts b/astro/src/components/primitives/Alert/types.ts new file mode 100644 index 0000000000..4bc8b68c54 --- /dev/null +++ b/astro/src/components/primitives/Alert/types.ts @@ -0,0 +1,12 @@ +/** + * Alert Component Types + */ + +export type AlertType = 'info' | 'alert' | 'warning'; + +export interface AlertProps { + /** Alert type — controls color scheme and icon */ + type?: AlertType; + /** Title text (rendered next to the icon) */ + title?: string; +} diff --git a/astro/src/components/primitives/Avatar/Avatar.astro b/astro/src/components/primitives/Avatar/Avatar.astro new file mode 100644 index 0000000000..5f35183bf7 --- /dev/null +++ b/astro/src/components/primitives/Avatar/Avatar.astro @@ -0,0 +1,77 @@ +--- +/** + * Avatar Primitive Component + * + * A rounded avatar image (or stacked images for multiple authors) + * with a name and optional caption displayed to the right. + * + * @example — Single author + * + * + * @example — Multiple authors + * + * + * @example — Small size + * + */ +import './Avatar.css'; +import type { HTMLAttributes } from 'astro/types'; +import { Image } from 'astro:assets'; +import { BodyMd, BodySm, Flex } from '@components/primitives'; + +interface Author { + src: string; + alt?: string; + name: string; +} + +interface Props extends HTMLAttributes<'div'> { + authors: Author[]; + caption?: string; + size?: 'sm' | 'md'; +} + +const { authors, caption, size = 'md', class: className, ...rest } = Astro.props; + +const displayName = authors?.map((a) => a.name).join(', ') ?? ''; +const imgSize = size === 'sm' ? 24 : 32; +--- + + +
+ { + authors?.map((a) => ( + {a.alt + )) + } +
+
+ {displayName} + { + caption && ( + + {caption} + + ) + } +
+
diff --git a/astro/src/components/primitives/Avatar/Avatar.css b/astro/src/components/primitives/Avatar/Avatar.css new file mode 100644 index 0000000000..a135b6b60c --- /dev/null +++ b/astro/src/components/primitives/Avatar/Avatar.css @@ -0,0 +1,33 @@ +@layer primitives { + .avatar__images { + display: flex; + align-items: center; + flex-shrink: 0; + } + + .avatar__image { + border-radius: var(--radius-full); + border: var(--border-width-2) solid var(--color-bg-primary); + object-fit: cover; + flex-shrink: 0; + } + + .avatar__image + .avatar__image { + margin-left: calc(-1 * var(--space-2)); + } + + .avatar--md .avatar__image { + width: var(--size-8); + height: var(--size-8); + } + + .avatar--sm .avatar__image { + width: var(--size-6); + height: var(--size-6); + } + + .avatar__content { + display: flex; + flex-direction: column; + } +} diff --git a/astro/src/components/primitives/Avatar/index.ts b/astro/src/components/primitives/Avatar/index.ts new file mode 100644 index 0000000000..8ac9988b8d --- /dev/null +++ b/astro/src/components/primitives/Avatar/index.ts @@ -0,0 +1 @@ +export { default as Avatar } from './Avatar.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..412bfb6f38 --- /dev/null +++ b/astro/src/components/primitives/Button/Button.astro @@ -0,0 +1,54 @@ +--- +/** + * Button Primitive Component + * + * Interactive button with support for icon slots and variants. + * Can render as button, anchor, or any interactive element. + * + * @example + * + * + * + * + * Notes: + * - The `disabled` prop is only supported when rendering as ` + )) + } + + + diff --git a/astro/src/components/primitives/Tabs/Tabs.css b/astro/src/components/primitives/Tabs/Tabs.css new file mode 100644 index 0000000000..3c5728ae96 --- /dev/null +++ b/astro/src/components/primitives/Tabs/Tabs.css @@ -0,0 +1,47 @@ +@layer primitives { + .tabs { + display: flex; + flex-wrap: wrap; + gap: var(--space-2); + margin: var(--space-8) 0; + } + + .tabs__tab { + display: inline-flex; + align-items: center; + padding: var(--space-2) var(--space-3); + border-radius: var(--radius-full); + border: 1px solid transparent; + background-color: transparent; + color: var(--color-text-secondary); + font-size: var(--font-size-sm); + font-weight: var(--font-weight-medium); + line-height: var(--line-height-tight); + white-space: nowrap; + cursor: pointer; + transition: + background-color 0.15s ease, + color 0.15s ease, + border-color 0.15s ease; + + &:hover:not(.tabs__tab--active) { + background-color: var(--color-bg-mute); + color: var(--color-text-primary); + } + + &:focus-visible { + outline: 2px solid var(--color-border-inverse); + outline-offset: 2px; + } + } + + .tabs__tab--active { + background-color: var(--color-bg-inverse); + color: var(--color-text-inverse); + border-color: var(--color-border-inverse); + + &:hover { + background-color: var(--color-bg-inverse-secondary); + } + } +} diff --git a/astro/src/components/primitives/Tabs/index.ts b/astro/src/components/primitives/Tabs/index.ts new file mode 100644 index 0000000000..11ece37d1f --- /dev/null +++ b/astro/src/components/primitives/Tabs/index.ts @@ -0,0 +1,2 @@ +export { default as Tabs } from './Tabs.astro'; +export type { TabItem } from './Tabs.astro'; diff --git a/astro/src/components/primitives/Tag/Tag.astro b/astro/src/components/primitives/Tag/Tag.astro new file mode 100644 index 0000000000..6f57c35a52 --- /dev/null +++ b/astro/src/components/primitives/Tag/Tag.astro @@ -0,0 +1,21 @@ +--- +/** + * Tag Primitive Component + * + * A pill-shaped label for categorizing or tagging content. + * + * @example + * Security + * Release + */ +import './Tag.css'; +import type { HTMLAttributes } from 'astro/types'; + +type Props = HTMLAttributes<'span'>; + +const { class: className, ...rest } = Astro.props; +--- + + + + diff --git a/astro/src/components/primitives/Tag/Tag.css b/astro/src/components/primitives/Tag/Tag.css new file mode 100644 index 0000000000..7ab8956875 --- /dev/null +++ b/astro/src/components/primitives/Tag/Tag.css @@ -0,0 +1,14 @@ +@layer primitives { + .tag { + display: inline-block; + padding: var(--space-1) var(--space-2); + border-radius: var(--radius-md); + background-color: var(--color-bg-mute); + color: var(--color-text-primary); + font-size: var(--font-size-xs); + font-weight: var(--font-weight-medium); + line-height: var(--line-height-tight); + white-space: nowrap; + margin: 0; + } +} diff --git a/astro/src/components/primitives/Tag/index.ts b/astro/src/components/primitives/Tag/index.ts new file mode 100644 index 0000000000..1d7f4bd85d --- /dev/null +++ b/astro/src/components/primitives/Tag/index.ts @@ -0,0 +1 @@ +export { default as Tag } from './Tag.astro'; diff --git a/astro/src/components/primitives/Typography/Body.astro b/astro/src/components/primitives/Typography/Body.astro new file mode 100644 index 0000000000..03cf26cac5 --- /dev/null +++ b/astro/src/components/primitives/Typography/Body.astro @@ -0,0 +1,31 @@ +--- +/** + * 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 './types.ts'; + +type BaseProps = { + color?: TypographyColor; + weight?: TypographyWeight; + vMargin?: boolean; +}; + +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 as 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..71ec281940 --- /dev/null +++ b/astro/src/components/primitives/Typography/BodyMd.astro @@ -0,0 +1,27 @@ +--- +/** + * BodyMd - Medium body text + * + * @example + * Medium sized content. + * Subdued helper text + */ + +import type { HTMLAttributes } from 'astro/types'; +import Typography from './Typography.astro'; +import type { TypographyBaseProps } from './types.ts'; + +type BaseProps = Omit; + +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 as 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..2739bfbaea --- /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 './types.ts'; + +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 as 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..55b90a67c5 --- /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 './types.ts'; + +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 as 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..03e28d055b --- /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 './types.ts'; + +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 as 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..c1877845fb --- /dev/null +++ b/astro/src/components/primitives/Typography/H1.astro @@ -0,0 +1,28 @@ +--- +/** + * 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 './types.ts'; + +type HTMLTag = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'; + +interface Props extends HTMLAttributes<'h1'> { + as?: HTMLTag; + color?: TypographyColor; + weight?: TypographyWeight; + vMargin?: boolean; +} + +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..b4cf48a887 --- /dev/null +++ b/astro/src/components/primitives/Typography/H2.astro @@ -0,0 +1,28 @@ +--- +/** + * 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 './types.ts'; + +type HTMLTag = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'; + +interface Props extends HTMLAttributes<'h2'> { + as?: HTMLTag; + color?: TypographyColor; + weight?: TypographyWeight; + vMargin?: boolean; +} + +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..f40d68f9a1 --- /dev/null +++ b/astro/src/components/primitives/Typography/H3.astro @@ -0,0 +1,28 @@ +--- +/** + * 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 './types.ts'; + +type HTMLTag = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'; + +interface Props extends HTMLAttributes<'h3'> { + as?: HTMLTag; + color?: TypographyColor; + weight?: TypographyWeight; + vMargin?: boolean; +} + +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..44db66c0d2 --- /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 './types.ts'; + +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..a78912a051 --- /dev/null +++ b/astro/src/components/primitives/Typography/H5.astro @@ -0,0 +1,27 @@ +--- +/** + * 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 './types.ts'; + +type HTMLTag = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'; + +interface Props extends HTMLAttributes<'h5'> { + as?: HTMLTag; + color?: TypographyColor; + weight?: TypographyWeight; + vMargin?: boolean; +} + +const { as = 'h5', ...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..eed8c748a7 --- /dev/null +++ b/astro/src/components/primitives/Typography/Typography.astro @@ -0,0 +1,51 @@ +--- +/** + * 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 './Typography.css'; +import type { HTMLAttributes } from 'astro/types'; +import type { TypographyBaseProps } from './types'; + +type Props = TypographyBaseProps & HTMLAttributes<'p'>; + +const { + as: Tag = 'p', + variant = 'body', + color = 'primary', + center, + left, + right, + weight, + vMargin = true, + 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..4eb2bf4f45 --- /dev/null +++ b/astro/src/components/primitives/Typography/Typography.css @@ -0,0 +1,76 @@ +/** + * Typography Component Styles + */ + +@layer primitives { + /* ============================================ + 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); + } + + /* ============================================ + SPACING + ============================================ */ + .text--no-v-margin { + margin-top: 0; + margin-bottom: 0; + } +} 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..cfc2a91eed --- /dev/null +++ b/astro/src/components/primitives/Typography/types.ts @@ -0,0 +1,61 @@ +/** + * 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; + /** Enable vertical margin (default: true) */ + vMargin?: boolean; +} diff --git a/astro/src/components/primitives/index.ts b/astro/src/components/primitives/index.ts new file mode 100644 index 0000000000..f355eea0d6 --- /dev/null +++ b/astro/src/components/primitives/index.ts @@ -0,0 +1,30 @@ +/** + * Reexport all primitives Components + */ + +// 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'; + +// Select +export { Select } from './Select'; +export type { SelectOption, SelectSize, SelectVariant } from './Select'; + +// Card +export { Card } from './Card'; + +// Avatar +export { Avatar } from './Avatar'; + +// Tag +export { Tag } from './Tag'; + +// Tabs +export { Tabs } from './Tabs'; +export type { TabItem } from './Tabs'; diff --git a/astro/src/config/menu/api.ts b/astro/src/config/menu/api.ts new file mode 100644 index 0000000000..77b5f42547 --- /dev/null +++ b/astro/src/config/menu/api.ts @@ -0,0 +1,325 @@ +import type { Menu } from '../types'; + +export const apiMenu: Menu = { + sections: [ + { + items: [ + { + href: '/api', + label: 'menu.overview', + ariaLabel: 'menu.overview', + }, + ], + }, + { + title: 'express()', + omitFrom: ['3x'], + items: [ + { + href: '/api/express/overview', + label: 'menu.overview', + ariaLabel: 'menu.expressOverviewAria', + }, + { + label: 'menu.methods', + ariaLabel: 'menu.expressMethodsAria', + submenu: { + items: [ + { + href: '/api/express/expressjson', + label: 'express.json()', + ariaLabel: 'express.json property', + }, + { + href: '/api/express/expressraw', + label: 'express.raw()', + ariaLabel: 'express.raw property', + }, + { + href: '/api/express/expressrouter', + label: 'express.Router()', + ariaLabel: 'express.Router property', + }, + { + href: '/api/express/expressstatic', + label: 'express.static()', + ariaLabel: 'express.static property', + }, + { + href: '/api/express/expresstext', + label: 'express.text()', + ariaLabel: 'express.text property', + }, + { + href: '/api/express/expressurlencoded', + label: 'express.urlencoded()', + ariaLabel: 'express.urlencoded property', + }, + ], + }, + }, + ], + }, + { + title: 'menu.application', + items: [ + { + href: `/api/application/overview`, + label: 'menu.overview', + ariaLabel: 'menu.applicationOverviewAria', + }, + { + label: 'menu.properties', + ariaLabel: 'menu.applicationPropertiesAria', + submenu: { + items: [ + { + href: `/api/application/app-locals`, + label: 'app.locals', + ariaLabel: 'app.locals property', + }, + { + href: '/api/application/app-routes', + label: 'app.routes', + ariaLabel: 'app.routes property', + omitFrom: ['4x', '5x'], + }, + { + href: `/api/application/app-mountpath`, + label: 'app.mountpath', + ariaLabel: 'app.mountpath property', + omitFrom: ['3x'], + }, + ], + }, + }, + { + label: 'menu.events', + ariaLabel: 'menu.applicationEventAria', + omitFrom: ['3x'], + submenu: { + items: [ + { + href: `/api/application/app-onmount`, + label: "app.on('mount')", + ariaLabel: 'app on mount event', + }, + ], + }, + }, + { + label: 'menu.methods', + ariaLabel: 'menu.applicationMethodsAria', + submenu: { + items: [ + { + href: `/api/application/app-all`, + label: 'app.all()', + ariaLabel: 'app.all method', + }, + { + href: `/api/application/app-delete-method`, + label: 'app.delete()', + 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 property', + }, + { + href: '/api/application/app-configure', + label: 'app.configure()', + ariaLabel: 'app.configure method', + omitFrom: ['4x', '5x'], + }, + { + href: '/api/application/app-enable', + label: 'app.enable()', + ariaLabel: 'app.enable method', + }, + { + href: '/api/application/app-enabled', + label: 'app.enabled()', + ariaLabel: 'app.enabled property', + }, + { + href: '/api/application/app-engine', + label: 'app.engine()', + ariaLabel: 'app.engine method', + }, + { + href: '/api/application/app-get', + label: 'app.get(name)', + ariaLabel: 'app.get method', + }, + + { + href: '/api/application/app-get-method', + label: 'app.get(path)', + ariaLabel: 'app.get method', + omitFrom: ['3x'], + }, + { + href: '/api/application/app-listen', + label: 'app.listen()', + ariaLabel: 'app.listen method', + }, + { + href: '/api/application/app-method', + label: 'app.method()', + ariaLabel: 'app.METHOD method', + omitFrom: ['3x'], + }, + { + href: '/api/application/app-param', + label: 'app.param()', + ariaLabel: 'app.param method', + }, + { + href: '/api/application/app-verb', + label: 'app.verb()', + ariaLabel: 'app.verb methods', + omitFrom: ['4x', '5x'], + }, + { + href: '/api/application/app-path', + label: 'app.path()', + ariaLabel: 'app.path method', + omitFrom: ['3x'], + }, + { + href: '/api/application/app-post-method', + label: 'app.post()', + ariaLabel: 'app.post method', + omitFrom: ['3x'], + }, + { + href: '/api/application/app-put-method', + 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-set', + label: 'app.set()', + ariaLabel: 'app.set method', + }, + { + href: '/api/application/app-use', + label: 'app.use()', + ariaLabel: 'app.use method', + }, + ], + }, + }, + ], + }, + { + title: 'menu.request', + items: [ + { + href: `/api/request/overview`, + label: 'menu.overview', + ariaLabel: 'menu.requestOverviewAria', + }, + { + label: 'menu.properties', + ariaLabel: 'menu.requestPropertiesAria', + submenu: { + items: [ + { + href: `/api/request/req-app`, + label: 'req.app', + ariaLabel: 'req.app property', + omitFrom: ['3x'], + }, + { + href: `/api/request/req-base-url`, + label: 'req.baseUrl', + ariaLabel: 'req.baseUrl property', + omitFrom: ['3x'], + }, + { + href: `/api/request/req-files`, + label: 'req.files', + ariaLabel: 'req.files property', + omitFrom: ['5x', '4x'], + }, + ], + }, + }, + ], + }, + { + title: 'menu.response', + items: [ + { + href: `/api/response/overview`, + label: 'menu.overview', + ariaLabel: 'menu.responseOverviewAria', + }, + { + label: 'menu.properties', + ariaLabel: 'menu.responsePropertiesAria', + submenu: { + items: [ + { + href: `/api/response/res-set`, + label: 'res.set', + ariaLabel: 'res.app property', + }, + { + href: `/api/response/res-app`, + label: 'res.app', + ariaLabel: 'res.app property', + omitFrom: ['3x'], + }, + ], + }, + }, + ], + }, + { + title: 'menu.router', + omitFrom: ['3x'], + items: [ + { + href: `/api/router/overview`, + label: 'menu.overview', + ariaLabel: 'menu.routerOverviewAria', + }, + { + label: 'menu.methods', + ariaLabel: 'menu.routerMethodsAria', + submenu: { + items: [ + { + href: `/api/router/router-all`, + label: 'router.all()', + ariaLabel: 'router.all method', + }, + ], + }, + }, + ], + }, + ], +}; diff --git a/astro/src/config/menu/docs.ts b/astro/src/config/menu/docs.ts new file mode 100644 index 0000000000..6207df5c80 --- /dev/null +++ b/astro/src/config/menu/docs.ts @@ -0,0 +1,48 @@ +import type { Menu } from '../types'; + +export const docsMenu: Menu = { + sections: [ + { + title: 'menu.gettingStarted', + items: [ + { 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: 'menu.guide', + items: [ + { href: `/guide/routing`, label: 'menu.routing', ariaLabel: 'menu.routingAria' }, + { + href: `/guide/writing-middleware`, + label: 'menu.writingMiddleware', + ariaLabel: 'menu.writingMiddlewareAria', + }, + { + href: `/guide/using-middleware`, + label: 'menu.usingMiddleware', + ariaLabel: 'menu.usingMiddlewareAria', + }, + ], + }, + { + title: 'menu.advancedTopics', + items: [ + { + href: `/advanced/developing-template-engines`, + label: 'menu.buildingTemplateEngines', + ariaLabel: 'menu.buildingTemplateEnginesAria', + }, + ], + }, + ], +}; diff --git a/astro/src/config/menu/main.ts b/astro/src/config/menu/main.ts new file mode 100644 index 0000000000..ac6e15cac9 --- /dev/null +++ b/astro/src/config/menu/main.ts @@ -0,0 +1,47 @@ +import { docsMenu } from './docs'; +import { apiMenu } from './api'; +import type { Menu } from '../types'; +import { resourcesMenu } from './resources'; + +export const mainMenu: Menu = { + sections: [ + { + items: [ + { + label: 'menu.docs', + ariaLabel: 'menu.docsAria', + icon: 'document-bullet-list-multiple-20-regular', + submenu: { + versioned: ['5x', '4x'], + sections: docsMenu.sections, + }, + }, + { + label: 'menu.api', + ariaLabel: 'menu.apiAria', + icon: 'code-20-regular', + submenu: { + versioned: ['5x', '4x', '3x'], + sections: apiMenu.sections, + }, + }, + { + label: 'menu.resources', + ariaLabel: 'menu.resourcesAria', + icon: 'folder-20-regular', + submenu: { + basePath: '/resources', + items: resourcesMenu.items, + }, + }, + { 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 new file mode 100644 index 0000000000..6e99073014 --- /dev/null +++ b/astro/src/config/menu/middleware.ts @@ -0,0 +1,21 @@ +import type { Menu } from '../types'; + +export const middlewareMenu: Menu = { + items: [ + { + href: `/overview`, + label: 'menu.overview', + ariaLabel: 'menu.middlewareOverviewAria', + }, + { + href: `/body-parser`, + label: 'body-parser', + ariaLabel: 'body-parser middleware', + }, + { + href: `/compression`, + label: 'compression', + ariaLabel: 'compression middleware', + }, + ], +}; diff --git a/astro/src/config/menu/resources.ts b/astro/src/config/menu/resources.ts new file mode 100644 index 0000000000..53e9e5d253 --- /dev/null +++ b/astro/src/config/menu/resources.ts @@ -0,0 +1,19 @@ +import type { Menu } from '../types'; +import { middlewareMenu } from './middleware'; + +export const resourcesMenu: Menu = { + items: [ + { 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' }, + { + label: 'Middleware', + ariaLabel: 'Middleware resources', + submenu: { + basePath: '/resources/middleware', + items: middlewareMenu.items, + }, + }, + ], +}; diff --git a/astro/src/config/types.ts b/astro/src/config/types.ts new file mode 100644 index 0000000000..5a81336a85 --- /dev/null +++ b/astro/src/config/types.ts @@ -0,0 +1,33 @@ +/** Valid version prefixes for versioned content */ +export type VersionPrefix = '5x' | '4x' | '3x'; + +export type MenuItemBaseProps = { + label: string; + ariaLabel?: string; + icon?: string; + omitFrom?: VersionPrefix[]; +}; + +export type MenuItem = + | (MenuItemBaseProps & { + href: string; + submenu?: never; + }) + | (MenuItemBaseProps & { + submenu: Menu; + href?: never; + }); + +export type MenuSection = { + title?: string; + basePath?: string; + items: MenuItem[]; + omitFrom?: VersionPrefix[]; +}; + +export type Menu = { + sections?: MenuSection[]; + items?: MenuItem[]; + basePath?: string; + versioned?: VersionPrefix[]; +}; diff --git a/astro/src/content.config.ts b/astro/src/content.config.ts new file mode 100644 index 0000000000..3837f06bbb --- /dev/null +++ b/astro/src/content.config.ts @@ -0,0 +1,60 @@ +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(), + }), +}); + +const apiCollection = defineCollection({ + loader: glob({ pattern: '**/[^_]*.{md,mdx}', base: './src/content/api' }), + schema: z.object({ + title: z.string(), + description: z.string().optional(), + }), +}); + +const resourcesCollection = defineCollection({ + loader: glob({ pattern: '**/[^_]*.{md,mdx}', base: './src/content/resources' }), + schema: z.object({ + title: z.string(), + description: z.string().optional(), + }), +}); + +const blogCollection = defineCollection({ + loader: glob({ pattern: '**/[^_]*.{md,mdx}', base: './src/content/blog' }), + schema: z.object({ + title: z.string(), + description: z.string().optional(), + tags: z.array(z.string()).optional(), + authors: z + .array( + z.object({ + name: z.string(), + github: z.string().optional(), + }) + ) + .optional(), + }), +}); + +const npmCollection = defineCollection({ + loader: async () => { + const res = await fetch('https://registry.npmjs.org/express/latest'); + const { version } = await res.json(); + return [{ id: 'express', version }]; + }, + schema: z.object({ version: z.string() }), +}); + +export const collections = { + docs: docsCollection, + api: apiCollection, + resources: resourcesCollection, + blog: blogCollection, + npm: npmCollection, +}; diff --git a/astro/src/content/api/3x/api.md b/astro/src/content/api/3x/api.md new file mode 100644 index 0000000000..53c2135058 --- /dev/null +++ b/astro/src/content/api/3x/api.md @@ -0,0 +1,25 @@ +--- +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 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](/en/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/api/3x/api/application/app-VERB.md b/astro/src/content/api/3x/api/application/app-VERB.md new file mode 100644 index 0000000000..a007c0d02c --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/application/app-all.md b/astro/src/content/api/3x/api/application/app-all.md new file mode 100644 index 0000000000..9fd9675018 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/application/app-configure.md b/astro/src/content/api/3x/api/application/app-configure.md new file mode 100644 index 0000000000..0287bf44a8 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/application/app-disable.md b/astro/src/content/api/3x/api/application/app-disable.md new file mode 100644 index 0000000000..e2ba96c1dd --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/application/app-disabled.md b/astro/src/content/api/3x/api/application/app-disabled.md new file mode 100644 index 0000000000..0c7d092cf4 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/application/app-enable.md b/astro/src/content/api/3x/api/application/app-enable.md new file mode 100644 index 0000000000..35534cb3ad --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/application/app-enabled.md b/astro/src/content/api/3x/api/application/app-enabled.md new file mode 100644 index 0000000000..a19432d554 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/application/app-engine.md b/astro/src/content/api/3x/api/application/app-engine.md new file mode 100644 index 0000000000..9ff0a8778b --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/application/app-get.md b/astro/src/content/api/3x/api/application/app-get.md new file mode 100644 index 0000000000..767117eda9 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/application/app-listen.md b/astro/src/content/api/3x/api/application/app-listen.md new file mode 100644 index 0000000000..242d429aeb --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/application/app-locals.md b/astro/src/content/api/3x/api/application/app-locals.md new file mode 100644 index 0000000000..4436b537f8 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/application/app-param.md b/astro/src/content/api/3x/api/application/app-param.md new file mode 100644 index 0000000000..97d935d169 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/application/app-render.md b/astro/src/content/api/3x/api/application/app-render.md new file mode 100644 index 0000000000..58e286aa46 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/application/app-routes.md b/astro/src/content/api/3x/api/application/app-routes.md new file mode 100644 index 0000000000..c60979174f --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/application/app-set.md b/astro/src/content/api/3x/api/application/app-set.md new file mode 100644 index 0000000000..62ee6ac565 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/application/app-settings.md b/astro/src/content/api/3x/api/application/app-settings.md new file mode 100644 index 0000000000..65dc18f6b8 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/application/app-use.md b/astro/src/content/api/3x/api/application/app-use.md new file mode 100644 index 0000000000..ee0ca34392 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/application/overview.mdx b/astro/src/content/api/3x/api/application/overview.mdx new file mode 100644 index 0000000000..e8720744ba --- /dev/null +++ b/astro/src/content/api/3x/api/application/overview.mdx @@ -0,0 +1,90 @@ +--- +title: Application Object +description: Learn about the properties and methods of the Express 3.x application object. +--- + +import Card from '@components/primitives/Card/Card.astro'; +import { CardList } from '@components/patterns'; + +

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); +``` + +

Properties

+ + + + + + + + + + + + + +

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/astro/src/content/api/3x/api/express.md b/astro/src/content/api/3x/api/express.md new file mode 100644 index 0000000000..e04222a0d0 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/middleware/middleware.md b/astro/src/content/api/3x/api/middleware/middleware.md new file mode 100644 index 0000000000..596e3d76cb --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/middleware/mw-basicAuth.md b/astro/src/content/api/3x/api/middleware/mw-basicAuth.md new file mode 100644 index 0000000000..7d4f7fe3ed --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/middleware/mw-bodyParser.md b/astro/src/content/api/3x/api/middleware/mw-bodyParser.md new file mode 100644 index 0000000000..3388e4d605 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/middleware/mw-compress.md b/astro/src/content/api/3x/api/middleware/mw-compress.md new file mode 100644 index 0000000000..03ccb87b75 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/middleware/mw-cookieParser.md b/astro/src/content/api/3x/api/middleware/mw-cookieParser.md new file mode 100644 index 0000000000..32990bccef --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/middleware/mw-cookieSession.md b/astro/src/content/api/3x/api/middleware/mw-cookieSession.md new file mode 100644 index 0000000000..0e984f5172 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/middleware/mw-csrf.md b/astro/src/content/api/3x/api/middleware/mw-csrf.md new file mode 100644 index 0000000000..83a5f6598c --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/middleware/mw-directory.md b/astro/src/content/api/3x/api/middleware/mw-directory.md new file mode 100644 index 0000000000..fe1219ff55 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/request/overview.md b/astro/src/content/api/3x/api/request/overview.md new file mode 100644 index 0000000000..fc7e96b47d --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/request/req-accepted.md b/astro/src/content/api/3x/api/request/req-accepted.md new file mode 100644 index 0000000000..54e1c42558 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/request/req-acceptedCharsets.md b/astro/src/content/api/3x/api/request/req-acceptedCharsets.md new file mode 100644 index 0000000000..91e693c493 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/request/req-acceptedLanguages.md b/astro/src/content/api/3x/api/request/req-acceptedLanguages.md new file mode 100644 index 0000000000..d7b70d4b32 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/request/req-accepts.md b/astro/src/content/api/3x/api/request/req-accepts.md new file mode 100644 index 0000000000..e74a39a426 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/request/req-acceptsCharset.md b/astro/src/content/api/3x/api/request/req-acceptsCharset.md new file mode 100644 index 0000000000..d210b4fd0b --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/request/req-acceptsLanguage.md b/astro/src/content/api/3x/api/request/req-acceptsLanguage.md new file mode 100644 index 0000000000..4ab1331f28 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/request/req-body.md b/astro/src/content/api/3x/api/request/req-body.md new file mode 100644 index 0000000000..2d49e5e41f --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/request/req-cookies.md b/astro/src/content/api/3x/api/request/req-cookies.md new file mode 100644 index 0000000000..2bbd590d30 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/request/req-files.md b/astro/src/content/api/3x/api/request/req-files.md new file mode 100644 index 0000000000..f81cd53501 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/request/req-fresh.md b/astro/src/content/api/3x/api/request/req-fresh.md new file mode 100644 index 0000000000..ecbeb9ce53 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/request/req-header.md b/astro/src/content/api/3x/api/request/req-header.md new file mode 100644 index 0000000000..0c7facfd73 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/request/req-host.md b/astro/src/content/api/3x/api/request/req-host.md new file mode 100644 index 0000000000..37701792b5 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/request/req-ip.md b/astro/src/content/api/3x/api/request/req-ip.md new file mode 100644 index 0000000000..871a48f6c7 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/request/req-ips.md b/astro/src/content/api/3x/api/request/req-ips.md new file mode 100644 index 0000000000..ca99131757 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/request/req-is.md b/astro/src/content/api/3x/api/request/req-is.md new file mode 100644 index 0000000000..5f5ce21e77 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/request/req-originalUrl.md b/astro/src/content/api/3x/api/request/req-originalUrl.md new file mode 100644 index 0000000000..6f84143c80 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/request/req-param.md b/astro/src/content/api/3x/api/request/req-param.md new file mode 100644 index 0000000000..f2eb23c60d --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/request/req-params.md b/astro/src/content/api/3x/api/request/req-params.md new file mode 100644 index 0000000000..045271e181 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/request/req-path.md b/astro/src/content/api/3x/api/request/req-path.md new file mode 100644 index 0000000000..cf82ffe4bf --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/request/req-protocol.md b/astro/src/content/api/3x/api/request/req-protocol.md new file mode 100644 index 0000000000..c67e210d37 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/request/req-query.md b/astro/src/content/api/3x/api/request/req-query.md new file mode 100644 index 0000000000..c4e4d99758 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/request/req-res.md b/astro/src/content/api/3x/api/request/req-res.md new file mode 100644 index 0000000000..c3c87d2601 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/request/req-route.md b/astro/src/content/api/3x/api/request/req-route.md new file mode 100644 index 0000000000..416da6cb89 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/request/req-secure.md b/astro/src/content/api/3x/api/request/req-secure.md new file mode 100644 index 0000000000..b118f239a4 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/request/req-signedCookies.md b/astro/src/content/api/3x/api/request/req-signedCookies.md new file mode 100644 index 0000000000..36a51e94df --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/request/req-stale.md b/astro/src/content/api/3x/api/request/req-stale.md new file mode 100644 index 0000000000..2a05d51b3b --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/request/req-subdomains.md b/astro/src/content/api/3x/api/request/req-subdomains.md new file mode 100644 index 0000000000..5d52e1c719 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/request/req-xhr.md b/astro/src/content/api/3x/api/request/req-xhr.md new file mode 100644 index 0000000000..b29cda85d1 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/response/overview.md b/astro/src/content/api/3x/api/response/overview.md new file mode 100644 index 0000000000..fbe73267cb --- /dev/null +++ b/astro/src/content/api/3x/api/response/overview.md @@ -0,0 +1,6 @@ +--- +title: API Response Overview +description: An overview of the API response object in Express.js, detailing its properties and methods for +--- + +TODO diff --git a/astro/src/content/api/3x/api/response/res-attachment.md b/astro/src/content/api/3x/api/response/res-attachment.md new file mode 100644 index 0000000000..b3d31d0201 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/response/res-charset.md b/astro/src/content/api/3x/api/response/res-charset.md new file mode 100644 index 0000000000..e75892c3d4 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/response/res-clearCookie.md b/astro/src/content/api/3x/api/response/res-clearCookie.md new file mode 100644 index 0000000000..6754dd61d3 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/response/res-cookie.md b/astro/src/content/api/3x/api/response/res-cookie.md new file mode 100644 index 0000000000..7cd5e29114 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/response/res-download.md b/astro/src/content/api/3x/api/response/res-download.md new file mode 100644 index 0000000000..1706bb83c7 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/response/res-format.md b/astro/src/content/api/3x/api/response/res-format.md new file mode 100644 index 0000000000..4e537981f2 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/response/res-get.md b/astro/src/content/api/3x/api/response/res-get.md new file mode 100644 index 0000000000..342b90714c --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/response/res-json.md b/astro/src/content/api/3x/api/response/res-json.md new file mode 100644 index 0000000000..6780b3f7f1 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/response/res-jsonp.md b/astro/src/content/api/3x/api/response/res-jsonp.md new file mode 100644 index 0000000000..fe0944c80d --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/response/res-links.md b/astro/src/content/api/3x/api/response/res-links.md new file mode 100644 index 0000000000..62744d116f --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/response/res-locals.md b/astro/src/content/api/3x/api/response/res-locals.md new file mode 100644 index 0000000000..039a69e780 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/response/res-location.md b/astro/src/content/api/3x/api/response/res-location.md new file mode 100644 index 0000000000..44fac2fc16 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/response/res-redirect.md b/astro/src/content/api/3x/api/response/res-redirect.md new file mode 100644 index 0000000000..81cf723bcf --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/response/res-render.md b/astro/src/content/api/3x/api/response/res-render.md new file mode 100644 index 0000000000..b00b585286 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/response/res-req.md b/astro/src/content/api/3x/api/response/res-req.md new file mode 100644 index 0000000000..2abec18cca --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/response/res-send.md b/astro/src/content/api/3x/api/response/res-send.md new file mode 100644 index 0000000000..c03e53c936 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/response/res-sendfile.md b/astro/src/content/api/3x/api/response/res-sendfile.md new file mode 100644 index 0000000000..619038305a --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/response/res-set.md b/astro/src/content/api/3x/api/response/res-set.md new file mode 100644 index 0000000000..4e1a1177d3 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/response/res-status.md b/astro/src/content/api/3x/api/response/res-status.md new file mode 100644 index 0000000000..b0cbe2bd79 --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/response/res-type.md b/astro/src/content/api/3x/api/response/res-type.md new file mode 100644 index 0000000000..157a2ed6ad --- /dev/null +++ b/astro/src/content/api/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/api/3x/api/response/response.md b/astro/src/content/api/3x/api/response/response.md new file mode 100644 index 0000000000..722423f376 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api.md b/astro/src/content/api/4x/api.md new file mode 100644 index 0000000000..0cc0143122 --- /dev/null +++ b/astro/src/content/api/4x/api.md @@ -0,0 +1,8 @@ +--- +title: 4x API Reference +description: API Reference for version 4.x +--- + +# 4.x API + +Some content here... diff --git a/astro/src/content/api/4x/api/application/app-METHOD.md b/astro/src/content/api/4x/api/application/app-METHOD.md new file mode 100644 index 0000000000..9517da19cf --- /dev/null +++ b/astro/src/content/api/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](/en/guide/routing). diff --git a/astro/src/content/api/4x/api/application/app-all.md b/astro/src/content/api/4x/api/application/app-all.md new file mode 100644 index 0000000000..806726c679 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/application/app-delete-method.md b/astro/src/content/api/4x/api/application/app-delete-method.md new file mode 100644 index 0000000000..47a34b87bd --- /dev/null +++ b/astro/src/content/api/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](/en/guide/routing). + +{% 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/api/4x/api/application/app-disable.md b/astro/src/content/api/4x/api/application/app-disable.md new file mode 100644 index 0000000000..10b95613be --- /dev/null +++ b/astro/src/content/api/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](/en/api/application/app-set#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/api/4x/api/application/app-disabled.md b/astro/src/content/api/4x/api/application/app-disabled.md new file mode 100644 index 0000000000..f48b061d1d --- /dev/null +++ b/astro/src/content/api/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](/en/api/application/app-set#app.settings.table). + +```js +app.disabled('trust proxy'); +// => true + +app.enable('trust proxy'); +app.disabled('trust proxy'); +// => false +``` diff --git a/astro/src/content/api/4x/api/application/app-enable.md b/astro/src/content/api/4x/api/application/app-enable.md new file mode 100644 index 0000000000..00c390d286 --- /dev/null +++ b/astro/src/content/api/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](/en/api/application/app-set#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/api/4x/api/application/app-enabled.md b/astro/src/content/api/4x/api/application/app-enabled.md new file mode 100644 index 0000000000..afbeb16e00 --- /dev/null +++ b/astro/src/content/api/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](/en/api/application/app-set#app.settings.table). + +```js +app.enabled('trust proxy'); +// => false + +app.enable('trust proxy'); +app.enabled('trust proxy'); +// => true +``` diff --git a/astro/src/content/api/4x/api/application/app-engine.md b/astro/src/content/api/4x/api/application/app-engine.md new file mode 100644 index 0000000000..1d4b13a797 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/application/app-get-method.md b/astro/src/content/api/4x/api/application/app-get-method.md new file mode 100644 index 0000000000..4ac82796bc --- /dev/null +++ b/astro/src/content/api/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](/en/guide/routing). + +#### Example + +```js +app.get('/', function (req, res) { + res.send('GET request to homepage'); +}); +``` diff --git a/astro/src/content/api/4x/api/application/app-get.md b/astro/src/content/api/4x/api/application/app-get.md new file mode 100644 index 0000000000..5a427e3637 --- /dev/null +++ b/astro/src/content/api/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](/en/api/application/app-set#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/api/4x/api/application/app-listen.md b/astro/src/content/api/4x/api/application/app-listen.md new file mode 100644 index 0000000000..c68faebbb2 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/application/app-locals.md b/astro/src/content/api/4x/api/application/app-locals.md new file mode 100644 index 0000000000..f3718bc1a6 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/application/app-mountpath.md b/astro/src/content/api/4x/api/application/app-mountpath.md new file mode 100644 index 0000000000..b81f5858a8 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/application/app-onmount.md b/astro/src/content/api/4x/api/application/app-onmount.md new file mode 100644 index 0000000000..42b3410d75 --- /dev/null +++ b/astro/src/content/api/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/api/application/app-set#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/api/4x/api/application/app-param.md b/astro/src/content/api/4x/api/application/app-param.md new file mode 100644 index 0000000000..cfb293a419 --- /dev/null +++ b/astro/src/content/api/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](/en/guide/routing#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/api/4x/api/application/app-path.md b/astro/src/content/api/4x/api/application/app-path.md new file mode 100644 index 0000000000..25538ad337 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/application/app-post-method.md b/astro/src/content/api/4x/api/application/app-post-method.md new file mode 100644 index 0000000000..10298f4058 --- /dev/null +++ b/astro/src/content/api/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](/en/guide/routing). + +{% 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/api/4x/api/application/app-put-method.md b/astro/src/content/api/4x/api/application/app-put-method.md new file mode 100644 index 0000000000..33051b8806 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/application/app-render.md b/astro/src/content/api/4x/api/application/app-render.md new file mode 100644 index 0000000000..2703d1436b --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/application/app-route.md b/astro/src/content/api/4x/api/application/app-route.md new file mode 100644 index 0000000000..e4576e6b54 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/application/app-set.md b/astro/src/content/api/4x/api/application/app-set.md new file mode 100644 index 0000000000..5b598751e2 --- /dev/null +++ b/astro/src/content/api/4x/api/application/app-set.md @@ -0,0 +1,360 @@ +--- +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](/en/api/application/app-set#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

+ +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](/en/advanced/best-practice-performance#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](/en/guide/behind-proxies) 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/api/4x/api/application/app-use.md b/astro/src/content/api/4x/api/application/app-use.md new file mode 100644 index 0000000000..90143aa892 --- /dev/null +++ b/astro/src/content/api/4x/api/application/app-use.md @@ -0,0 +1,333 @@ +--- +title: app.use +description: Mounts the specified [middleware](/en/guide/using-middleware) function or functions +--- + +

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

+ +Mounts the specified [middleware](/en/guide/using-middleware) 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/application/app-settings/). + +
+ +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](/en/guide/error-handling). + +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](/en/guide/using-middleware#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/api/4x/api/application/overview.mdx b/astro/src/content/api/4x/api/application/overview.mdx new file mode 100644 index 0000000000..0efaf2dcef --- /dev/null +++ b/astro/src/content/api/4x/api/application/overview.mdx @@ -0,0 +1,122 @@ +--- +title: Application Object +description: Learn about the properties of the Express application object. +--- + +import Card from '@components/primitives/Card/Card.astro'; +import { CardList } from '@components/patterns'; + +## 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/). + +
+ 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

+ + + + + + + + + + +

Events

+ + + + + + + +

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/astro/src/content/api/4x/api/express/express.json.md b/astro/src/content/api/4x/api/express/express.json.md new file mode 100644 index 0000000000..d135c7b686 --- /dev/null +++ b/astro/src/content/api/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](/en/resources/middleware/body-parser). + +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/api/4x/api/express/express.raw.md b/astro/src/content/api/4x/api/express/express.raw.md new file mode 100644 index 0000000000..efb1a69742 --- /dev/null +++ b/astro/src/content/api/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](/en/resources/middleware/body-parser). + +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/api/4x/api/express/express.router.md b/astro/src/content/api/4x/api/express/express.router.md new file mode 100644 index 0000000000..baf1b889fd --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/express/express.static.md b/astro/src/content/api/4x/api/express/express.static.md new file mode 100644 index 0000000000..d681edd8c7 --- /dev/null +++ b/astro/src/content/api/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](/en/resources/middleware/serve-static). + +{% capture alert_content %} +For best results, [use a reverse proxy](/en/advanced/best-practice-performance#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](/en/starter/static-files). +and [Using middleware - Built-in middleware](/en/guide/using-middleware#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/api/4x/api/express/express.text.md b/astro/src/content/api/4x/api/express/express.text.md new file mode 100644 index 0000000000..fdc6258d62 --- /dev/null +++ b/astro/src/content/api/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](/en/resources/middleware/body-parser). + +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/api/4x/api/express/express.urlencoded.md b/astro/src/content/api/4x/api/express/express.urlencoded.md new file mode 100644 index 0000000000..ae811d6fc1 --- /dev/null +++ b/astro/src/content/api/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](/en/resources/middleware/body-parser). + +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/api/4x/api/express/overview.mdx b/astro/src/content/api/4x/api/express/overview.mdx new file mode 100644 index 0000000000..d3703f3036 --- /dev/null +++ b/astro/src/content/api/4x/api/express/overview.mdx @@ -0,0 +1,42 @@ +--- +title: Express Object +description: Learn about the methods available on the top-level Express object. +--- + +import Card from '@components/primitives/Card/Card.astro'; +import { CardList } from '@components/patterns'; + +## 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

+ + + + + + + + + + + + + + + + + + + + + diff --git a/astro/src/content/api/4x/api/request/overview.md b/astro/src/content/api/4x/api/request/overview.md new file mode 100644 index 0000000000..8e850398bf --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/request/req-accepts.md b/astro/src/content/api/4x/api/request/req-accepts.md new file mode 100644 index 0000000000..763c6c6ab7 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/request/req-acceptsCharsets.md b/astro/src/content/api/4x/api/request/req-acceptsCharsets.md new file mode 100644 index 0000000000..69bed2797b --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/request/req-acceptsEncodings.md b/astro/src/content/api/4x/api/request/req-acceptsEncodings.md new file mode 100644 index 0000000000..384e10bb6a --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/request/req-acceptsLanguages.md b/astro/src/content/api/4x/api/request/req-acceptsLanguages.md new file mode 100644 index 0000000000..0674eaa689 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/request/req-app.md b/astro/src/content/api/4x/api/request/req-app.md new file mode 100644 index 0000000000..f776c3e8ad --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/request/req-base-url.md b/astro/src/content/api/4x/api/request/req-base-url.md new file mode 100644 index 0000000000..0100ff6db6 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/request/req-body.md b/astro/src/content/api/4x/api/request/req-body.md new file mode 100644 index 0000000000..18b8eb861c --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/request/req-cookies.md b/astro/src/content/api/4x/api/request/req-cookies.md new file mode 100644 index 0000000000..63ac2a74b4 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/request/req-fresh.md b/astro/src/content/api/4x/api/request/req-fresh.md new file mode 100644 index 0000000000..293c12e898 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/request/req-get.md b/astro/src/content/api/4x/api/request/req-get.md new file mode 100644 index 0000000000..ad116d8421 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/request/req-hostname.md b/astro/src/content/api/4x/api/request/req-hostname.md new file mode 100644 index 0000000000..a68d68d3ad --- /dev/null +++ b/astro/src/content/api/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](/en/4x/api#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/api/4x/api/request/req-ip.md b/astro/src/content/api/4x/api/request/req-ip.md new file mode 100644 index 0000000000..9d28ae713e --- /dev/null +++ b/astro/src/content/api/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](/en/4x/api#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/api/4x/api/request/req-ips.md b/astro/src/content/api/4x/api/request/req-ips.md new file mode 100644 index 0000000000..a67629c617 --- /dev/null +++ b/astro/src/content/api/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](/en/4x/api#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/api/4x/api/request/req-is.md b/astro/src/content/api/4x/api/request/req-is.md new file mode 100644 index 0000000000..944dba091d --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/request/req-method.md b/astro/src/content/api/4x/api/request/req-method.md new file mode 100644 index 0000000000..92b683bcfd --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/request/req-originalUrl.md b/astro/src/content/api/4x/api/request/req-originalUrl.md new file mode 100644 index 0000000000..5d0b88a5a7 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/request/req-param.md b/astro/src/content/api/4x/api/request/req-param.md new file mode 100644 index 0000000000..0dda6b4f5a --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/request/req-params.md b/astro/src/content/api/4x/api/request/req-params.md new file mode 100644 index 0000000000..538660f464 --- /dev/null +++ b/astro/src/content/api/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"](/en/guide/routing#route-parameters). Fo... +--- + +

req.params

+ +This property is an object containing properties mapped to the [named route "parameters"](/en/guide/routing#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](/en/4x/api#app.param) handler. Changes are applicable only to [parameters](/en/guide/routing#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/api/4x/api/request/req-path.md b/astro/src/content/api/4x/api/request/req-path.md new file mode 100644 index 0000000000..6ee3f841c9 --- /dev/null +++ b/astro/src/content/api/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()](/en/4x/api#app.use) for more details. +
diff --git a/astro/src/content/api/4x/api/request/req-protocol.md b/astro/src/content/api/4x/api/request/req-protocol.md new file mode 100644 index 0000000000..569431fe0f --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/request/req-query.md b/astro/src/content/api/4x/api/request/req-query.md new file mode 100644 index 0000000000..72b02c8f04 --- /dev/null +++ b/astro/src/content/api/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](/en/api/application/app-set#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](/en/api/application/app-set#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](/en/api/application/app-set#app.settings.table) documentation for other customization options. diff --git a/astro/src/content/api/4x/api/request/req-range.md b/astro/src/content/api/4x/api/request/req-range.md new file mode 100644 index 0000000000..d2b908f7f3 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/request/req-res.md b/astro/src/content/api/4x/api/request/req-res.md new file mode 100644 index 0000000000..94e5554756 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/request/req-route.md b/astro/src/content/api/4x/api/request/req-route.md new file mode 100644 index 0000000000..57f8548968 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/request/req-secure.md b/astro/src/content/api/4x/api/request/req-secure.md new file mode 100644 index 0000000000..aaee9e1a9d --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/request/req-signedCookies.md b/astro/src/content/api/4x/api/request/req-signedCookies.md new file mode 100644 index 0000000000..73750e60b0 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/request/req-stale.md b/astro/src/content/api/4x/api/request/req-stale.md new file mode 100644 index 0000000000..b39f5cb5ef --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/request/req-subdomains.md b/astro/src/content/api/4x/api/request/req-subdomains.md new file mode 100644 index 0000000000..73d3839eef --- /dev/null +++ b/astro/src/content/api/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](/en/4x/api#app.set). diff --git a/astro/src/content/api/4x/api/request/req-xhr.md b/astro/src/content/api/4x/api/request/req-xhr.md new file mode 100644 index 0000000000..f247d20b05 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/response/overview.md b/astro/src/content/api/4x/api/response/overview.md new file mode 100644 index 0000000000..ba3d4a8050 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/response/res-app.md b/astro/src/content/api/4x/api/response/res-app.md new file mode 100644 index 0000000000..b853d54dd3 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/response/res-append.md b/astro/src/content/api/4x/api/response/res-append.md new file mode 100644 index 0000000000..ecbc596f1e --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/response/res-attachment.md b/astro/src/content/api/4x/api/response/res-attachment.md new file mode 100644 index 0000000000..6d1eed1ff3 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/response/res-clearCookie.md b/astro/src/content/api/4x/api/response/res-clearCookie.md new file mode 100644 index 0000000000..fbe206b2f7 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/response/res-cookie.md b/astro/src/content/api/4x/api/response/res-cookie.md new file mode 100644 index 0000000000..340ef94962 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/response/res-download.md b/astro/src/content/api/4x/api/response/res-download.md new file mode 100644 index 0000000000..08b6f43cd6 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/response/res-end.md b/astro/src/content/api/4x/api/response/res-end.md new file mode 100644 index 0000000000..1d59764120 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/response/res-format.md b/astro/src/content/api/4x/api/response/res-format.md new file mode 100644 index 0000000000..570d6222dd --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/response/res-get.md b/astro/src/content/api/4x/api/response/res-get.md new file mode 100644 index 0000000000..300dd9d1a9 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/response/res-headersSent.md b/astro/src/content/api/4x/api/response/res-headersSent.md new file mode 100644 index 0000000000..7eaca46914 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/response/res-json.md b/astro/src/content/api/4x/api/response/res-json.md new file mode 100644 index 0000000000..40d6c0c083 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/response/res-jsonp.md b/astro/src/content/api/4x/api/response/res-jsonp.md new file mode 100644 index 0000000000..2e19c08337 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/response/res-links.md b/astro/src/content/api/4x/api/response/res-links.md new file mode 100644 index 0000000000..a3c2b12004 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/response/res-locals.md b/astro/src/content/api/4x/api/response/res-locals.md new file mode 100644 index 0000000000..b15e2558c9 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/response/res-location.md b/astro/src/content/api/4x/api/response/res-location.md new file mode 100644 index 0000000000..537a0532d8 --- /dev/null +++ b/astro/src/content/api/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#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/api/4x/api/response/res-redirect.md b/astro/src/content/api/4x/api/response/res-redirect.md new file mode 100644 index 0000000000..0acffcea95 --- /dev/null +++ b/astro/src/content/api/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#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#prevent-open-redirects). diff --git a/astro/src/content/api/4x/api/response/res-render.md b/astro/src/content/api/4x/api/response/res-render.md new file mode 100644 index 0000000000..9a829d8348 --- /dev/null +++ b/astro/src/content/api/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](/en/guide/using-template-engines). + +
+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/api/4x/api/response/res-req.md b/astro/src/content/api/4x/api/response/res-req.md new file mode 100644 index 0000000000..f20548a045 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/response/res-send.md b/astro/src/content/api/4x/api/response/res-send.md new file mode 100644 index 0000000000..c7fc23dff6 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/response/res-sendFile.md b/astro/src/content/api/4x/api/response/res-sendFile.md new file mode 100644 index 0000000000..65c5ca3627 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/response/res-sendStatus.md b/astro/src/content/api/4x/api/response/res-sendStatus.md new file mode 100644 index 0000000000..eef217cd82 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/response/res-set.md b/astro/src/content/api/4x/api/response/res-set.md new file mode 100644 index 0000000000..6d2b01e63e --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/response/res-status.md b/astro/src/content/api/4x/api/response/res-status.md new file mode 100644 index 0000000000..445fed30fb --- /dev/null +++ b/astro/src/content/api/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](https://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/api/4x/api/response/res-type.md b/astro/src/content/api/4x/api/response/res-type.md new file mode 100644 index 0000000000..615ffb3c6a --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/response/res-vary.md b/astro/src/content/api/4x/api/response/res-vary.md new file mode 100644 index 0000000000..164bed9285 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/router/overview.md b/astro/src/content/api/4x/api/router/overview.md new file mode 100644 index 0000000000..9d1ec07241 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/router/router-METHOD.md b/astro/src/content/api/4x/api/router/router-METHOD.md new file mode 100644 index 0000000000..2c6ea555f4 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/router/router-Router.md b/astro/src/content/api/4x/api/router/router-Router.md new file mode 100644 index 0000000000..de2867f15c --- /dev/null +++ b/astro/src/content/api/4x/api/router/router-Router.md @@ -0,0 +1,5 @@ +--- +title: Router +--- + +

Router([options])

diff --git a/astro/src/content/api/4x/api/router/router-all.md b/astro/src/content/api/4x/api/router/router-all.md new file mode 100644 index 0000000000..cda8e9c21b --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/router/router-param.md b/astro/src/content/api/4x/api/router/router-param.md new file mode 100644 index 0000000000..cb82308fb4 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/router/router-route.md b/astro/src/content/api/4x/api/router/router-route.md new file mode 100644 index 0000000000..89dd15bbcb --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/router/router-use.md b/astro/src/content/api/4x/api/router/router-use.md new file mode 100644 index 0000000000..b6f3929a32 --- /dev/null +++ b/astro/src/content/api/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/api/4x/api/router/routing-args.html b/astro/src/content/api/4x/api/router/routing-args.html new file mode 100644 index 0000000000..cbf0dd027a --- /dev/null +++ b/astro/src/content/api/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/api/5x/api.md b/astro/src/content/api/5x/api.md new file mode 100644 index 0000000000..0cc0143122 --- /dev/null +++ b/astro/src/content/api/5x/api.md @@ -0,0 +1,8 @@ +--- +title: 4x API Reference +description: API Reference for version 4.x +--- + +# 4.x API + +Some content here... diff --git a/astro/src/content/api/5x/api/application/app-METHOD.md b/astro/src/content/api/5x/api/application/app-METHOD.md new file mode 100644 index 0000000000..57c01e7b8b --- /dev/null +++ b/astro/src/content/api/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](/en/guide/routing). diff --git a/astro/src/content/api/5x/api/application/app-all.md b/astro/src/content/api/5x/api/application/app-all.md new file mode 100644 index 0000000000..62daf475b3 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/application/app-delete-method.md b/astro/src/content/api/5x/api/application/app-delete-method.md new file mode 100644 index 0000000000..48ece5abd1 --- /dev/null +++ b/astro/src/content/api/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](/en/guide/routing). + +{% 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/api/5x/api/application/app-disable.md b/astro/src/content/api/5x/api/application/app-disable.md new file mode 100644 index 0000000000..10b95613be --- /dev/null +++ b/astro/src/content/api/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](/en/api/application/app-set#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/api/5x/api/application/app-disabled.md b/astro/src/content/api/5x/api/application/app-disabled.md new file mode 100644 index 0000000000..f48b061d1d --- /dev/null +++ b/astro/src/content/api/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](/en/api/application/app-set#app.settings.table). + +```js +app.disabled('trust proxy'); +// => true + +app.enable('trust proxy'); +app.disabled('trust proxy'); +// => false +``` diff --git a/astro/src/content/api/5x/api/application/app-enable.md b/astro/src/content/api/5x/api/application/app-enable.md new file mode 100644 index 0000000000..00c390d286 --- /dev/null +++ b/astro/src/content/api/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](/en/api/application/app-set#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/api/5x/api/application/app-enabled.md b/astro/src/content/api/5x/api/application/app-enabled.md new file mode 100644 index 0000000000..72aacfe240 --- /dev/null +++ b/astro/src/content/api/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](/en/api/application/app-set#app.settings.table). + +```js +app.enabled('trust proxy'); +// => false + +app.enable('trust proxy'); +app.enabled('trust proxy'); +// => true +``` diff --git a/astro/src/content/api/5x/api/application/app-engine.md b/astro/src/content/api/5x/api/application/app-engine.md new file mode 100644 index 0000000000..7096d556f2 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/application/app-get-method.md b/astro/src/content/api/5x/api/application/app-get-method.md new file mode 100644 index 0000000000..0d61c5ba42 --- /dev/null +++ b/astro/src/content/api/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](/en/guide/routing). + +#### Example + +```js +app.get('/', (req, res) => { + res.send('GET request to homepage'); +}); +``` diff --git a/astro/src/content/api/5x/api/application/app-get.md b/astro/src/content/api/5x/api/application/app-get.md new file mode 100644 index 0000000000..8b56e45bfd --- /dev/null +++ b/astro/src/content/api/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](/en/api/application/app-set#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/api/5x/api/application/app-listen.md b/astro/src/content/api/5x/api/application/app-listen.md new file mode 100644 index 0000000000..b7845a8c3c --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/application/app-locals.md b/astro/src/content/api/5x/api/application/app-locals.md new file mode 100644 index 0000000000..f3718bc1a6 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/application/app-mountpath.md b/astro/src/content/api/5x/api/application/app-mountpath.md new file mode 100644 index 0000000000..1b0b530f69 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/application/app-onmount.md b/astro/src/content/api/5x/api/application/app-onmount.md new file mode 100644 index 0000000000..ad746547a8 --- /dev/null +++ b/astro/src/content/api/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/api/application/app-set#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/api/5x/api/application/app-param.md b/astro/src/content/api/5x/api/application/app-param.md new file mode 100644 index 0000000000..1a9792f582 --- /dev/null +++ b/astro/src/content/api/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](/en/guide/routing#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/api/5x/api/application/app-path.md b/astro/src/content/api/5x/api/application/app-path.md new file mode 100644 index 0000000000..78c6885667 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/application/app-post-method.md b/astro/src/content/api/5x/api/application/app-post-method.md new file mode 100644 index 0000000000..416a401151 --- /dev/null +++ b/astro/src/content/api/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](/en/guide/routing). + +{% 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/api/5x/api/application/app-put-method.md b/astro/src/content/api/5x/api/application/app-put-method.md new file mode 100644 index 0000000000..2eb53a77eb --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/application/app-render.md b/astro/src/content/api/5x/api/application/app-render.md new file mode 100644 index 0000000000..d5f65bf258 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/application/app-route.md b/astro/src/content/api/5x/api/application/app-route.md new file mode 100644 index 0000000000..a0f9816d5d --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/application/app-router.md b/astro/src/content/api/5x/api/application/app-router.md new file mode 100644 index 0000000000..6bd664d291 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/application/app-set.md b/astro/src/content/api/5x/api/application/app-set.md new file mode 100644 index 0000000000..a0f6e0e3eb --- /dev/null +++ b/astro/src/content/api/5x/api/application/app-set.md @@ -0,0 +1,354 @@ +--- +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](/en/api/application/app-set#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

+ +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](/en/guide/behind-proxies) 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/api/5x/api/application/app-use.md b/astro/src/content/api/5x/api/application/app-use.md new file mode 100644 index 0000000000..56b14bc76c --- /dev/null +++ b/astro/src/content/api/5x/api/application/app-use.md @@ -0,0 +1,310 @@ +--- +title: app.use +description: Mounts the specified [middleware](/en/guide/using-middleware) function or functions +--- + +

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

+ +Mounts the specified [middleware](/en/guide/using-middleware) 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/application/app-settings/). + +
+ +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](/en/guide/error-handling). + +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](/en/guide/using-middleware#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/api/5x/api/application/overview.mdx b/astro/src/content/api/5x/api/application/overview.mdx new file mode 100644 index 0000000000..0efaf2dcef --- /dev/null +++ b/astro/src/content/api/5x/api/application/overview.mdx @@ -0,0 +1,122 @@ +--- +title: Application Object +description: Learn about the properties of the Express application object. +--- + +import Card from '@components/primitives/Card/Card.astro'; +import { CardList } from '@components/patterns'; + +## 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/). + +
+ 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

+ + + + + + + + + + +

Events

+ + + + + + + +

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/astro/src/content/api/5x/api/express/express.json.md b/astro/src/content/api/5x/api/express/express.json.md new file mode 100644 index 0000000000..ca0935b6da --- /dev/null +++ b/astro/src/content/api/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](/en/resources/middleware/body-parser). + +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/api/5x/api/express/express.raw.md b/astro/src/content/api/5x/api/express/express.raw.md new file mode 100644 index 0000000000..ab545cc1de --- /dev/null +++ b/astro/src/content/api/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](/en/resources/middleware/body-parser). + +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/api/5x/api/express/express.router.md b/astro/src/content/api/5x/api/express/express.router.md new file mode 100644 index 0000000000..2474bc3fa0 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/express/express.static.md b/astro/src/content/api/5x/api/express/express.static.md new file mode 100644 index 0000000000..70609dba0c --- /dev/null +++ b/astro/src/content/api/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](/en/resources/middleware/serve-static). + +
NOTE: For best results, [use a reverse proxy](/en/advanced/best-practice-performance#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](/en/starter/static-files). +and [Using middleware - Built-in middleware](/en/guide/using-middleware#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/api/5x/api/express/express.text.md b/astro/src/content/api/5x/api/express/express.text.md new file mode 100644 index 0000000000..2bb815bf33 --- /dev/null +++ b/astro/src/content/api/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](/en/resources/middleware/body-parser). + +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/api/5x/api/express/express.urlencoded.md b/astro/src/content/api/5x/api/express/express.urlencoded.md new file mode 100644 index 0000000000..bc51a18d91 --- /dev/null +++ b/astro/src/content/api/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](/en/resources/middleware/body-parser). + +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/api/5x/api/express/overview.mdx b/astro/src/content/api/5x/api/express/overview.mdx new file mode 100644 index 0000000000..ea511dc5f7 --- /dev/null +++ b/astro/src/content/api/5x/api/express/overview.mdx @@ -0,0 +1,42 @@ +--- +title: Express Object +description: Learn about the methods available on the top-level Express object. +--- + +import Card from '@components/primitives/Card/Card.astro'; +import { CardList } from '@components/patterns'; + +## 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

+ + + + + + + + + + + + + + + + + + + + + diff --git a/astro/src/content/api/5x/api/request/overview.md b/astro/src/content/api/5x/api/request/overview.md new file mode 100644 index 0000000000..203654e039 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/request/req-accepts.md b/astro/src/content/api/5x/api/request/req-accepts.md new file mode 100644 index 0000000000..763c6c6ab7 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/request/req-acceptsCharsets.md b/astro/src/content/api/5x/api/request/req-acceptsCharsets.md new file mode 100644 index 0000000000..69bed2797b --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/request/req-acceptsEncodings.md b/astro/src/content/api/5x/api/request/req-acceptsEncodings.md new file mode 100644 index 0000000000..384e10bb6a --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/request/req-acceptsLanguages.md b/astro/src/content/api/5x/api/request/req-acceptsLanguages.md new file mode 100644 index 0000000000..998805fa9e --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/request/req-app.md b/astro/src/content/api/5x/api/request/req-app.md new file mode 100644 index 0000000000..6594a0142a --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/request/req-base-url.md b/astro/src/content/api/5x/api/request/req-base-url.md new file mode 100644 index 0000000000..a49e6912ca --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/request/req-body.md b/astro/src/content/api/5x/api/request/req-body.md new file mode 100644 index 0000000000..a921f3c624 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/request/req-cookies.md b/astro/src/content/api/5x/api/request/req-cookies.md new file mode 100644 index 0000000000..806b6dc5ab --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/request/req-fresh.md b/astro/src/content/api/5x/api/request/req-fresh.md new file mode 100644 index 0000000000..293c12e898 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/request/req-get.md b/astro/src/content/api/5x/api/request/req-get.md new file mode 100644 index 0000000000..ad116d8421 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/request/req-host.md b/astro/src/content/api/5x/api/request/req-host.md new file mode 100644 index 0000000000..6a61ec6be0 --- /dev/null +++ b/astro/src/content/api/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](/en/api/application/app-set#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/api/5x/api/request/req-hostname.md b/astro/src/content/api/5x/api/request/req-hostname.md new file mode 100644 index 0000000000..97247f67ef --- /dev/null +++ b/astro/src/content/api/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](/en/5x/api#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/api/5x/api/request/req-ip.md b/astro/src/content/api/5x/api/request/req-ip.md new file mode 100644 index 0000000000..eac6ea89b8 --- /dev/null +++ b/astro/src/content/api/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](/en/5x/api#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/api/5x/api/request/req-ips.md b/astro/src/content/api/5x/api/request/req-ips.md new file mode 100644 index 0000000000..88d70824e5 --- /dev/null +++ b/astro/src/content/api/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](/en/5x/api#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/api/5x/api/request/req-is.md b/astro/src/content/api/5x/api/request/req-is.md new file mode 100644 index 0000000000..3c9b22623d --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/request/req-method.md b/astro/src/content/api/5x/api/request/req-method.md new file mode 100644 index 0000000000..92b683bcfd --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/request/req-originalUrl.md b/astro/src/content/api/5x/api/request/req-originalUrl.md new file mode 100644 index 0000000000..c7d4b142ed --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/request/req-params.md b/astro/src/content/api/5x/api/request/req-params.md new file mode 100644 index 0000000000..fd2531cf6f --- /dev/null +++ b/astro/src/content/api/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"](/en/guide/routing#route-parameters). Fo... +--- + +

req.params

+ +This property is an object containing properties mapped to the [named route "parameters"](/en/guide/routing#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](/en/5x/api#app.param) handler. Changes are applicable only to [parameters](/en/guide/routing#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/api/5x/api/request/req-path.md b/astro/src/content/api/5x/api/request/req-path.md new file mode 100644 index 0000000000..2214b9cfb6 --- /dev/null +++ b/astro/src/content/api/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()](/en/5x/api#app.use) for more details. +
diff --git a/astro/src/content/api/5x/api/request/req-protocol.md b/astro/src/content/api/5x/api/request/req-protocol.md new file mode 100644 index 0000000000..082e784b47 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/request/req-query.md b/astro/src/content/api/5x/api/request/req-query.md new file mode 100644 index 0000000000..5734720a9c --- /dev/null +++ b/astro/src/content/api/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](/en/api/application/app-set#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](/en/api/application/app-set#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](/en/api/application/app-set#app.settings.table) documentation for other customization options. diff --git a/astro/src/content/api/5x/api/request/req-range.md b/astro/src/content/api/5x/api/request/req-range.md new file mode 100644 index 0000000000..6c103987a2 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/request/req-res.md b/astro/src/content/api/5x/api/request/req-res.md new file mode 100644 index 0000000000..94e5554756 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/request/req-route.md b/astro/src/content/api/5x/api/request/req-route.md new file mode 100644 index 0000000000..d2a3159b3b --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/request/req-secure.md b/astro/src/content/api/5x/api/request/req-secure.md new file mode 100644 index 0000000000..d3f86bdcd2 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/request/req-signedCookies.md b/astro/src/content/api/5x/api/request/req-signedCookies.md new file mode 100644 index 0000000000..b573fc082e --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/request/req-stale.md b/astro/src/content/api/5x/api/request/req-stale.md new file mode 100644 index 0000000000..b39f5cb5ef --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/request/req-subdomains.md b/astro/src/content/api/5x/api/request/req-subdomains.md new file mode 100644 index 0000000000..3f05bccac0 --- /dev/null +++ b/astro/src/content/api/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](/en/5x/api#app.set). diff --git a/astro/src/content/api/5x/api/request/req-xhr.md b/astro/src/content/api/5x/api/request/req-xhr.md new file mode 100644 index 0000000000..f247d20b05 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/response/overview.md b/astro/src/content/api/5x/api/response/overview.md new file mode 100644 index 0000000000..ac989a33d8 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/response/res-app.md b/astro/src/content/api/5x/api/response/res-app.md new file mode 100644 index 0000000000..b853d54dd3 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/response/res-append.md b/astro/src/content/api/5x/api/response/res-append.md new file mode 100644 index 0000000000..abda903e81 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/response/res-attachment.md b/astro/src/content/api/5x/api/response/res-attachment.md new file mode 100644 index 0000000000..7d667eedd4 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/response/res-clearCookie.md b/astro/src/content/api/5x/api/response/res-clearCookie.md new file mode 100644 index 0000000000..f2738bf189 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/response/res-cookie.md b/astro/src/content/api/5x/api/response/res-cookie.md new file mode 100644 index 0000000000..ab7e81de34 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/response/res-download.md b/astro/src/content/api/5x/api/response/res-download.md new file mode 100644 index 0000000000..42eb6db49f --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/response/res-end.md b/astro/src/content/api/5x/api/response/res-end.md new file mode 100644 index 0000000000..1d59764120 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/response/res-format.md b/astro/src/content/api/5x/api/response/res-format.md new file mode 100644 index 0000000000..92e7c40e45 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/response/res-get.md b/astro/src/content/api/5x/api/response/res-get.md new file mode 100644 index 0000000000..300dd9d1a9 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/response/res-headersSent.md b/astro/src/content/api/5x/api/response/res-headersSent.md new file mode 100644 index 0000000000..ed9b41069e --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/response/res-json.md b/astro/src/content/api/5x/api/response/res-json.md new file mode 100644 index 0000000000..40d6c0c083 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/response/res-jsonp.md b/astro/src/content/api/5x/api/response/res-jsonp.md new file mode 100644 index 0000000000..2e19c08337 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/response/res-links.md b/astro/src/content/api/5x/api/response/res-links.md new file mode 100644 index 0000000000..db6aaba927 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/response/res-locals.md b/astro/src/content/api/5x/api/response/res-locals.md new file mode 100644 index 0000000000..d2cf8c9b85 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/response/res-location.md b/astro/src/content/api/5x/api/response/res-location.md new file mode 100644 index 0000000000..37104a0eb3 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/response/res-redirect.md b/astro/src/content/api/5x/api/response/res-redirect.md new file mode 100644 index 0000000000..b140fdba20 --- /dev/null +++ b/astro/src/content/api/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#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#prevent-open-redirects). diff --git a/astro/src/content/api/5x/api/response/res-render.md b/astro/src/content/api/5x/api/response/res-render.md new file mode 100644 index 0000000000..4e66066146 --- /dev/null +++ b/astro/src/content/api/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](/en/guide/using-template-engines). + +{% 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/api/5x/api/response/res-req.md b/astro/src/content/api/5x/api/response/res-req.md new file mode 100644 index 0000000000..f20548a045 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/response/res-send.md b/astro/src/content/api/5x/api/response/res-send.md new file mode 100644 index 0000000000..dd1797ff42 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/response/res-sendFile.md b/astro/src/content/api/5x/api/response/res-sendFile.md new file mode 100644 index 0000000000..750532497f --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/response/res-sendStatus.md b/astro/src/content/api/5x/api/response/res-sendStatus.md new file mode 100644 index 0000000000..ae77bd6f46 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/response/res-set.md b/astro/src/content/api/5x/api/response/res-set.md new file mode 100644 index 0000000000..6d2b01e63e --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/response/res-status.md b/astro/src/content/api/5x/api/response/res-status.md new file mode 100644 index 0000000000..445fed30fb --- /dev/null +++ b/astro/src/content/api/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](https://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/api/5x/api/response/res-type.md b/astro/src/content/api/5x/api/response/res-type.md new file mode 100644 index 0000000000..b566a8d143 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/response/res-vary.md b/astro/src/content/api/5x/api/response/res-vary.md new file mode 100644 index 0000000000..164bed9285 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/response/response.md b/astro/src/content/api/5x/api/response/response.md new file mode 100644 index 0000000000..ac989a33d8 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/router/overview.md b/astro/src/content/api/5x/api/router/overview.md new file mode 100644 index 0000000000..e961fa8eb6 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/router/router-METHOD.md b/astro/src/content/api/5x/api/router/router-METHOD.md new file mode 100644 index 0000000000..a4eb343c90 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/router/router-Router.md b/astro/src/content/api/5x/api/router/router-Router.md new file mode 100644 index 0000000000..de2867f15c --- /dev/null +++ b/astro/src/content/api/5x/api/router/router-Router.md @@ -0,0 +1,5 @@ +--- +title: Router +--- + +

Router([options])

diff --git a/astro/src/content/api/5x/api/router/router-all.md b/astro/src/content/api/5x/api/router/router-all.md new file mode 100644 index 0000000000..6a0461bc82 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/router/router-param.md b/astro/src/content/api/5x/api/router/router-param.md new file mode 100644 index 0000000000..184e0792e4 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/router/router-route.md b/astro/src/content/api/5x/api/router/router-route.md new file mode 100644 index 0000000000..f3d9d42075 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/router/router-use.md b/astro/src/content/api/5x/api/router/router-use.md new file mode 100644 index 0000000000..6e31cf7f22 --- /dev/null +++ b/astro/src/content/api/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/api/5x/api/router/router.md b/astro/src/content/api/5x/api/router/router.md new file mode 100644 index 0000000000..e961fa8eb6 --- /dev/null +++ b/astro/src/content/api/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/blog/en/2024-07-16-welcome-post.md b/astro/src/content/blog/en/2024-07-16-welcome-post.md new file mode 100644 index 0000000000..8892e7237d --- /dev/null +++ b/astro/src/content/blog/en/2024-07-16-welcome-post.md @@ -0,0 +1,28 @@ +--- +title: Welcome to The Express Blog! +description: Introducing the new Express blog — a primary platform for announcements, updates, and communication from the Express technical committee. +tags: ['announcements'] +authors: + - name: Rand McKinney + github: crandmck + - name: Chris Del + github: chrisdel101 +--- + +Welcome to the new Express blog! The blog is meant to be a primary means of communication for the Express technical committee (TC). While we currently have other channels such as X, LinkedIn, and of course GitHub, there's no authoritative "soapbox" for announcements and general communication. + +Initially, the Express blog will be a venue: + +- For periodic announcements of new releases, pre-releases, plans, and ongoing work on the project. +- For the Express TC to discuss issues of particular importance to the Express community. +- To highlight security issues or other urgent information. + +Eventually, we hope the blog will evolve into a more general communication hub for the entire Express community; for example to share examples, tips, and experiences with the Express ecosystem and other information that's not simply technical documentation or GitHub discussion. + +Initially, posts will be written by TC members (potentially collaborating others), mainly because we don't have bandwidth to review general posts from the broader community. Eventually, we would love to open up the blog for broader contributions, but for now the focus is on trying to release Express 5.0, and the reality of an open-source project is that everyone has finite time to contribute. + +Express TC member [Ulises Gascón](https://github.com/UlisesGascon) suggested a number of interesting topics for blog posts in [expressjs.com issue 1500](https://github.com/expressjs/expressjs.com/issues/1500), but there are undoubtedly many others. + +If you have an idea for a post, feel free to pitch the idea! You can add a comment to [expressjs.com issue 1500](https://github.com/expressjs/expressjs.com/issues/1500) or open a new issue, and then after appropriate discussion, open a PR. We've also written up simple [instructions to create a blog post](/en/blog/write-post). + +Happy blogging! diff --git a/astro/src/content/blog/en/2024-09-29-security-releases.md b/astro/src/content/blog/en/2024-09-29-security-releases.md new file mode 100644 index 0000000000..4e72a82fad --- /dev/null +++ b/astro/src/content/blog/en/2024-09-29-security-releases.md @@ -0,0 +1,139 @@ +--- +title: September 2024 Security Releases +description: Security releases for Express, body-parser, send, serve-static, and path-to-regexp have been published. We recommend that all users upgrade as soon as possible. +tags: ['security'] +authors: + - name: Ulises Gascón + github: UlisesGascon +--- + +Recently, the Express team has been made aware of a number of security vulnerabilities in the Express project. We have released a number of patches to address these vulnerabilities. + +{% include admonitions/warning.html +content="We strongly recommend that you upgrade these modules to the recommended (or latest) version as soon as possible." +%} + +The following vulnerabilities have been addressed: + +- [High severity vulnerability CVE-2024-45590 in body-parser middleware](#high-severity-vulnerability-cve-2024-45590-in-body-parser-middleware) +- [High severity vulnerability CVE-2024-47178 in basic-auth-connect middleware](#high-severity-vulnerability-cve-2024-47178-in-basic-auth-connect-middleware) +- [Moderate severity vulnerability CVE-2024-43796 in Express core](#moderate-severity-vulnerability-cve-2024-43796-in-express-core) +- [Moderate severity vulnerability CVE-2024-43799 in send utility module](#moderate-severity-vulnerability-cve-2024-43799-in-send-utility-module) +- [Moderate severity vulnerability CVE-2024-43800 in serve-static middleware](#moderate-severity-vulnerability-cve-2024-43800-in-serve-static-middleware) +- [Moderate severity vulnerability CVE-2024-45296 in path-to-regexp utility module](#moderate-severity-vulnerability-cve-2024-45296-in-path-to-regexp-utility-module) + +## High severity vulnerability CVE-2024-45590 in body-parser middleware + +**[body-parser](https://www.npmjs.com/package/body-parser) version `<1.20.3` is vulnerable to denial of service when URL-encoding is enabled** + +A malicious actor using a specially-crafted payload could flood the server with a large number of requests, resulting in denial of service. + +**Affected versions**: `<1.20.3` + +**Patched versions**: `>=1.20.3` + +This vulnerability was discovered during the [OSTIF audit to Express](https://github.com/expressjs/security-wg/issues/6) and was mitigated by [the Express security triage team](https://github.com/expressjs/security-wg?tab=readme-ov-file#security-triage-team). + +For more details, see [GHSA-qwcr-r2fm-qrc7](https://github.com/expressjs/body-parser/security/advisories/GHSA-qwcr-r2fm-qrc7). + +## High severity vulnerability CVE-2024-47178 in basic-auth-connect middleware + +**[basic-auth-connect](https://www.npmjs.com/package/basic-auth-connect) uses a timing-unsafe equality comparison** + +basic-auth-connect `<1.1.0` uses a timing-unsafe equality comparison that can leak timing information + +**Affected versions** + +- `<1.1.0` + +**Patched versions** + +- `>=1.1.0` + +This vulnerability was discovered during the [OSTIF audit to Express](https://github.com/expressjs/security-wg/issues/6) and was mitigated by [the Express Securty triage team](https://github.com/expressjs/security-wg?tab=readme-ov-file#security-triage-team). + +More details area available in [GHSA-7p89-p6hx-q4fw](https://github.com/expressjs/basic-auth-connect/security/advisories/GHSA-7p89-p6hx-q4fw) + +## Moderate severity vulnerability CVE-2024-43796 in Express core + +The core **[express](https://www.npmjs.com/package/express) package is vulnerable to cross-site scripting (XSS) attack via `response.redirect()`**. + +In Express version <4.20.0, passing untrusted user input—even after sanitizing it—to `response.redirect()` may execute untrusted code. + +**Affected versions**: + +- `<4.20.0` +- `>=5.0.0-alpha.1`, `<5.0.0` + +**Patched versions**: + +- `>=4.20.0` +- `>=5.0.0` + +This vulnerability was discovered during the [OSTIF audit of Express](https://github.com/expressjs/security-wg/issues/6) and was mitigated by [the Express security triage team](https://github.com/expressjs/security-wg?tab=readme-ov-file#security-triage-team). + +For more details, see [GHSA-qw6h-vgh9-j6wx](https://github.com/expressjs/express/security/advisories/GHSA-qw6h-vgh9-j6wx). + +## Moderate severity vulnerability CVE-2024-43799 in send utility module + +The **[send](https://www.npmjs.com/package/send) utility module is vulnerable to template injection that can lead to vulnerability to cross-site scripting (XSS) attack**. + +Passing untrusted user input—even after sanitizing it—to `SendStream.redirect()` can execute untrusted code. + +**Affected versions**: `< 0.19.0` + +**Patched versions**: `>=0.19.0` + +This vulnerability was discovered during the [OSTIF audit of Express](https://github.com/expressjs/security-wg/issues/6) and was mitigated by [the Express security triage team](https://github.com/expressjs/security-wg?tab=readme-ov-file#security-triage-team). + +For more details, see [GHSA-m6fv-jmcg-4jfg](https://github.com/pillarjs/send/security/advisories/GHSA-m6fv-jmcg-4jfg). + +## Moderate severity vulnerability CVE-2024-43800 in serve-static middleware + +The **[serve-static](https://www.npmjs.com/package/serve-static) middleware module is vulnerable to template injection that can lead to vulnerability to cross-site scripting (XSS) attack**. + +Passing untrusted user input—even after sanitizing it—to `redirect()` can execute untrusted code. + +**Affected versions**: + +- `< 1.16.0` +- `>=2.0.0`, `<2.1.0` + +**Patched versions**: + +- `>=1.16.0` +- `>=2.1.0` + +This vulnerability was discovered during the [OSTIF audit of Express](https://github.com/expressjs/security-wg/issues/6) and was mitigated by [the Express security triage team](https://github.com/expressjs/security-wg?tab=readme-ov-file#security-triage-team). + +For more details, see [GHSA-cm22-4g7w-348p](https://github.com/expressjs/serve-static/security/advisories/GHSA-cm22-4g7w-348p) + +## Moderate severity vulnerability CVE-2024-45296 in path-to-regexp utility module + +The **[path-to-regexp](https://www.npmjs.com/package/path-to-regexp) utility module is vulnerable to regular expression denial of service (ReDoS) attack**. + +A bad regular expression is generated any time you have two parameters within a single segment, separated by something that is not a period (`.`). For example, `/:a-:b`. + +Using `/:a-:b` will produce the regular expression `/^\/([^\/]+?)-([^\/]+?)\/?$/`. This can be exploited by a path such as `/a${'-a'.repeat(8_000)}/a`. [OWASP](https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS) has a good example of why this occurs, but in essence, the `/a` at the end ensures this route would never match, but due to naive backtracking it will still attempt every combination of the `:a-:b` on the repeated 8,000 `-a`. + +Because JavaScript is single-threaded and regex matching runs on the main thread, poor performance will block the event loop and can lead to a DoS. In local benchmarks, exploiting the unsafe regex will result in performance that is over 1000x worse than the safe regex. In a more realistic environment, using Express v4 and ten concurrent connections results in an average latency of ~600ms vs 1ms. + +**Affected versions**: + +- `>=4.0.0`, `<8.0.0` +- `>=0.2.0`, `<1.9.0` +- `<0.1.10` +- `>=2.0.0`, `<3.3.0` +- `>=4.0.0`, `<6.3.0` + +**Patched versions**: + +- `>=8.0.0` +- `>=1.9.0` +- `>=0.1.10` +- `>=3.3.0` +- `>=6.3.0` + +Thanks to [Blake Embrey](https://github.com/blakeembrey) who reported and created the security patch. + +For more details, see [GHSA-9wv6-86v2-598j](https://github.com/pillarjs/path-to-regexp/security/advisories/GHSA-9wv6-86v2-598j) diff --git a/astro/src/content/blog/en/2024-10-01-HeroDevs-partnership-announcement.md b/astro/src/content/blog/en/2024-10-01-HeroDevs-partnership-announcement.md new file mode 100644 index 0000000000..11048603df --- /dev/null +++ b/astro/src/content/blog/en/2024-10-01-HeroDevs-partnership-announcement.md @@ -0,0 +1,26 @@ +--- +title: Express Never Ending Support Launched by HeroDevs and Express.js +description: The Express.js team is pleased to announce a partnership with HeroDevs to launch Express Never-Ending Support (NES), providing long-term support for applications built with legacy Express. This collaboration ensures that developers relying on older versions of the framework will continue to receive critical security and compatibility updates, allowing them to maintain and scale their applications securely, even after the framework's official end-of-life. +tags: ['announcements'] +authors: + - name: Express Technical Committee + github: expressjs +--- + +The Express.js team is pleased to announce a partnership with HeroDevs to launch [Express Never-Ending Support (NES)](https://www.herodevs.com/support/express-nes), providing long-term support for applications built with legacy Express. This collaboration ensures that developers relying on older versions of the framework will continue to receive critical security and compatibility updates, allowing them to maintain and scale their applications securely, even after the framework's official end-of-life. + +Express.js is known for its minimalistic design and flexibility, offering developers a powerful yet lightweight framework for building web and mobile applications. Its extensive set of HTTP utility methods and middleware have made creating APIs both efficient and scalable—qualities that have made it a go-to choice for Node.js developers over the years. + +However, Express.js v3.x reached its end-of-life in July 2015, leaving many businesses and developers in need of support to keep their applications secure and compliant. + +> "We’re grateful to see HeroDevs stepping in to provide extended long-term support for Express +> +> Express NES ensures that the many businesses and developers who rely on Express can continue using it safely and securely, even years after its original end-of-life. This kind of ongoing commitment to the open-source ecosystem is crucial, and we’re excited to see the benefits it brings to the developer community.” — said a spokesperson for the Express Technical Committee. + +Express NES is designed as a drop-in replacement for legacy versions of Express.js, offering security patches, compatibility updates and compliance fixes. This solution ensures that developers can remain on legacy Express.js without becoming vulnerable to security risks and compliance issues. + +> “We’re thrilled to introduce Express NES as part of our continued mission to support the sustainability of key open-source tools +> +> Our partnership with OpenJS has enabled us to meet the needs of developers still relying on older versions of critical frameworks. Express NES ensures that they can continue building and maintaining their applications without the risk of security vulnerabilities or loss of compliance.” — Joe Eames, VP of Partnership at HeroDevs. + +For more information on Express NES and how to get started, visit [HeroDevs’ website](https://www.herodevs.com/support/express-nes). diff --git a/astro/src/content/blog/en/2024-10-15-v5-release.md b/astro/src/content/blog/en/2024-10-15-v5-release.md new file mode 100644 index 0000000000..a1af3bea75 --- /dev/null +++ b/astro/src/content/blog/en/2024-10-15-v5-release.md @@ -0,0 +1,138 @@ +--- +title: 'Introducing Express v5: A New Era for the Node.js Framework' +tags: ['announcements'] +authors: + - name: Wes Todd + github: wesleytodd + - name: Express Technical Committee + github: expressjs +description: Announcing the release of Express version 5 +--- + +Ten years ago (July 2014) the [Express v5 release pull request](https://github.com/expressjs/express/pull/2237) was opened, and now at long last it's been merged and published! + +We want to recognize the work of all our contributors, especially [Doug Wilson](https://github.com/dougwilson), who spent the last ten years ensuring Express was the most stable project around. Without his contributions and those of many others, this release could not have happened. + +Eight months ago we went public with a plan to move [Express forward](https://github.com/expressjs/discussions/issues/160). This plan included re-committing to the governance outlined years ago and adding more contributors to help kickstart progress. Many people may not realize that robust project governance is critical to the health of a large open-source project. We want to thank the [OpenJS Foundation Cross Project +Council](https://github.com/openjs-foundation/cross-project-council/) and its members for helping us put together this plan. + +## So what about v5? + +This release is designed to be boring! +That may sound odd, but we've intentionally kept it simple to unblock the ecosystem and enable more impactful changes in future releases. This is also about signaling to the Node.js ecosystem that Express is moving again. +The focus of this release is on dropping old Node.js version support, addressing security concerns, and simplifying maintenance. + +Before going into the changes in this release, let's address why it was released v5 on the `next` dist-tag. As part of reviving the project, we started a [Security working group](https://github.com/expressjs/security-wg) and [security triage team](https://github.com/expressjs/security-wg?tab=readme-ov-file#security-triage-team) to address the growing needs around open source supply chain security. We undertook a security audit (more details to come on that) and uncovered some problems that needed to be addressed. Thus, in addition to the "normal" work done in public issues, we also did a lot of security work in private forks. +This security work required orchestration when releasing, to ensure the code and CVE reports went out together. You can find a summary of the most recent vulnerabilities patched in [our security release notes](/en/blog/2024-09-29-security-releases). + +While we weren't able to simultaneously release v5, this blog post, the changelog, and documentation, we felt it was most important to have a secure and stable release. + +As soon as possible, we'll provide more details on our long-term support (LTS) plans, including when the release will move from `next` to `latest`. For now, if you are uncomfortable being on the bleeding edge (even if it is a rather dull edge) then you should wait to upgrade until the release is tagged `latest`. That said, we look forward to working with you to address any bugs you encounter as you upgrade. + +## Breaking changes + +The v5 release has the minimum possible number of breaking changes, listed here in order of impact to applications. + +- [So what about v5?](#so-what-about-v5) +- [Breaking changes](#breaking-changes) + - [Ending support for old Node.js versions](#ending-support-for-old-nodejs-versions) + - [Changes to path matching and regular expressions](#changes-to-path-matching-and-regular-expressions) + - [No more regex](#no-more-regex) + - [Splats, optional, and captures oh my](#splats-optional-and-captures-oh-my) + - [Name everything](#name-everything) + - [Promise support](#promise-support) + - [Body parser changes](#body-parser-changes) + - [Removing deprecated method signatures](#removing-deprecated-method-signatures) +- [Migration and security guidance](#migration-and-security-guidance) +- [Our work is just starting](#our-work-is-just-starting) + +There are also a number of subtle changes: for details, see [Migrating to Express 5](/en/guide/migrating-5). + +### Ending support for old Node.js versions + +Goodbye Node.js 0.10, hello Node 18 and up! + +This release drops support for Node.js versions before v18. This is an important change because supporting old Node.js versions has been holding back many critical performance and maintainability changes. This change also enables more stable and maintainable continuous integration (CI), adopting new language and runtime features, and dropping dependencies that are no longer required. + +We recognize that this might cause difficulty for some enterprises with older or "parked" applications, and because of this we are working on a [partnership with HeroDevs](/en/blog/2024-10-01-herodevs-partnership-announcement) to offer "never-ending support" that will include critical security patches even after v4 enters end-of-life (more on these plans soon). That said, we strongly suggest that you update to modern Node.js versions as soon as possible. + +### Changes to path matching and regular expressions + +The v5 releases updates to `path-to-regexp@8.x` from `path-to-regexp@0.x`, which incorporates many years of changes. If you were using any of the 5.0.0-beta releases, a last-minute update which greatly changed the path semantics to [remove the possibility of any ReDoS attacks](https://blakeembrey.com/posts/2024-09-web-redos/). For more detailed changes, [see the `path-to-regexp` readme](https://github.com/pillarjs/path-to-regexp?tab=readme-ov-file#express--4x). + +#### No more regex + +This release no longer supports "sub-expression" regular expressions, for example `/:foo(\\d+)`. +This is a commonly-used pattern, but we removed it for security reasons. Unfortunately, it's easy to write a regular expression that has exponential time behavior when parsing input: The dreaded regular expression denial of service (ReDoS) attack. It's very difficult to prevent this, but as a library that converts strings to regular expressions, we are on the hook for such security aspects. + +_How to migrate:_ The best approach to prevent ReDoS attacks is to use a robust input validation library. [There are many on `npm`](https://www.npmjs.com/search?q=validate%20express) depending on your needs. TC member Wes Todd maintains [a middleware-based "code first" OpenAPI library](https://www.npmjs.com/package/@wesleytodd/openapi) for this kind of thing. + +#### Splats, optional, and captures oh my + +This release includes simplified patterns for common route patterns. With the removal of regular expression semantics comes other small but impactful changes to how you write your routes. + +1. `:name?` becomes `{:name}`. Usage of `{}` for optional parts of your route means you can now do things like `/base{/:optional}/:required` and what parts are actually optional is much more explicit. +2. `*` becomes `*name`. +3. New reserved characters: `(`, `)`, `[`, `]`, `?`, `+`, & `!`. These have been reserved to leave room for future improvements and to prevent mistakes when migrating where those characters mean specific things in previous versions. + +#### Name everything + +This release no longer supports ordered numerical parameters. + +In Express v4, you could get numerical parameters using regex capture groups (for example, `/user(s?)` => `req.params[0] === 's'`). Now all parameters must be named. Along with requiring a name, Express now supports all valid JavaScript identifiers or quoted (for example, `/:"this"`). + +### Promise support + +This one may be a bit contentious, but we "promise" we're moving in the right direction. We added support for returned _rejected_ promises from errors raised in middleware. This _does not include_ calling `next` from returned _resolved_ promises. There are a lot of edge cases in old Express apps that have expectations of `Promise` behavior, and before we can run we need to walk. For most folks, this means you can now write middleware like the following: + +```javascript +app.use(async (req, res, next) => { + req.locals.user = await getUser(req); + next(); +}); +``` + +Notice that this example uses `async/await` and the `getUser` call may throw an error (if, for example, the user doesn't exist, the user database is down, and so on), but we still call `next` if it is successful. We don't need to catch the error in line anymore if we want to rely on error-handling middleware instead because the router will now catch the rejected promise and treat that as calling `next(err)`. + +NOTE: 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. + +### Body parser changes + +There are a number of `body-parser` changes: + +- Add option to customize the urlencoded body depth with a default value of 32 as mitigation for [CVE-2024-45590](https://nvd.nist.gov/vuln/detail/CVE-2024-45590) ([technical details](https://github.com/expressjs/body-parser/commit/b2695c4450f06ba3b0ccf48d872a229bb41c9bce)) +- Remove deprecated `bodyParser()` combination middleware +- `req.body` is no longer always initialized to `{}` +- `urlencoded` parser now defaults `extended` to false +- Added support for Brotli lossless data compression + +### Removing deprecated method signatures + +Express v5 removes a number of deprecated method signatures, many of which were carried over from v3. Below are the changes you need to make: + +- `res.redirect('back')` and `res.location('back')`: The magic string `'back'` is no longer supported. Use `req.get('Referrer') || '/'` explicitly instead. +- `res.send(status, body)` and `res.send(body, status)` signatures: Use `res.status(status).send(body)`. +- `res.send(status)` signature: Use `res.sendStatus(status)` for simple status responses, or `res.status(status).send()` for sending a status code with an optional body. +- `res.redirect(url, status)` signature: Use `res.redirect(status, url)`. +- `res.json(status, obj)` and `res.json(obj, status)` signatures: Use `res.status(status).json(obj)`. +- `res.jsonp(status, obj)` and `res.jsonp(obj, status)` signatures: Use `res.status(status).jsonp(obj)`. +- `app.param(fn)`: This method has been deprecated. Instead, access parameters directly via `req.params`, or use `req.body` or `req.query` as needed. +- `app.del('/', () => {})` method: Use `app.delete('/', () => {})` instead. +- `req.acceptsCharset`: Use `req.acceptsCharsets` (plural). +- `req.acceptsEncoding`: Use `req.acceptsEncodings` (plural). +- `req.acceptsLanguage`: Use `req.acceptsLanguages` (plural). +- `res.sendfile` method: Use `res.sendFile` instead. + +As a framework, we aim to ensure that the API is as consistent as possible. We've removed these deprecated signatures to make the API more predictable and easier to use. By streamlining each method to use a single, consistent signature, we simplify the developer experience and reduce confusion. + +## Migration and security guidance + +For developers looking to migrate from v4 to v5, there's a [detailed migration guide](/en/guide/migrating-5) to help you navigate through the changes and ensure a smooth upgrade process. + +Additionally, we’ve been working hard on a comprehensive [Threat Model](https://github.com/expressjs/security-wg/blob/main/docs/ThreatModel.md) that helps illustrate our philosophy of a "Fast, unopinionated, minimalist web framework for Node.js." It provides critical insights into areas like user input validation and security practices that are essential for safe and secure usage of Express in your applications. + +## Our work is just starting + +We see the v5 release as a milestone toward an Express ecosystem that's a stable and reliable tool for companies, governments, educators, and hobby projects. It is our commitment as the new stewards of the Express project to move the ecosystem forward with this goal in mind. If you want to support this work, which we do on a volunteer basis, please consider supporting the project and its maintainers via [our sponsorship opportunities](https://opencollective.com/express). + +We have an [extensive working backlog](https://github.com/expressjs/discussions/issues/266) of tasks, PRs, and issues for Express and dependencies. Naturally, we expect developers will continue to report issues to add to this backlog and open PRs moving forward, and we'll continue to collaborate with the community to triage and resolve them. We look forward to continuing to improve Express and making it useful for its users across the world. diff --git a/astro/src/content/blog/en/2024-10-22-security-audit-milestone-achievement.md b/astro/src/content/blog/en/2024-10-22-security-audit-milestone-achievement.md new file mode 100644 index 0000000000..36e8f8bc98 --- /dev/null +++ b/astro/src/content/blog/en/2024-10-22-security-audit-milestone-achievement.md @@ -0,0 +1,55 @@ +--- +title: 'Express.js Security Audit: A Milestone Achievement' +tags: ['security', 'announcements'] +authors: + - name: Express Technical Committee + github: expressjs +description: Celebrating the successful completion of the Express.js security audit conducted by Ada Logics and facilitated by OSTIF. +--- + +We are thrilled to announce the successful completion of a comprehensive security audit for Express.js, conducted by [Ada Logics](https://adalogics.com/) and facilitated by [OSTIF](https://ostif.org/). This extensive review of our framework and its core components marks a significant milestone in our commitment to ensuring the security and reliability of Express.js for our community. + +## A Collaborative Effort + +This audit was made possible through the collaboration between [the Express Security Working Group](https://github.com/expressjs/security-wg), Ada Logics, OSTIF, and the [OpenJS Foundation](https://openjsf.org/). Our focus was on thoroughly evaluating the Express.js codebase, including its dependencies and core libraries. The primary goal was to identify any potential security vulnerabilities and to strengthen the overall security posture of the framework. + +### Key Highlights of the Audit + +- **Audit Duration**: Conducted in April and May 2024. +- **Scope**: Core Express.js codebase and critical dependencies, such as `body-parser`, `basic-auth-connect`, `serve-static`, and more. +- **Findings**: A total of 5 security vulnerabilities were identified, all of which have been addressed and patched. +- **Severity**: Issues ranged from moderate to high severity, impacting components like `res.redirect` and `serve-static`. + +## A Closer Look at the Findings + +The audit identified several vulnerabilities, including potential Cross-Site Scripting (XSS) risks and a Denial of Service (DoS) vulnerability in the `body-parser` middleware. Here are the key CVEs reported: + +- **CVE-2024-43796**: XSS in `res.redirect`—fixed in versions >= 4.20.0 and >= 5.0.0. +- **CVE-2024-45590**: DoS in `body-parser`—patched in version >= 1.20.3. +- **CVE-2024-47178**: Timing vulnerability in `basic-auth-connect`—patched in version >= 1.1.0. +- **CVE-2024-43799**: XSS in the `send` utility module—patched in version >= 0.19.0. +- **CVE-2024-43800**: XSS in `serve-static`—fixed in versions >= 1.16.0 and >= 2.1.0. + +Each of these vulnerabilities was promptly addressed by our dedicated [security triage team](https://github.com/expressjs/security-wg?tab=readme-ov-file#security-triage-team), ensuring that users remain protected against known threats. + +For full details on the audit results, you can access the [official audit report here](https://ostif.org/wp-content/uploads/2024/10/expressjs-2024-security-audit-report.pdf). + +## A Commitment to Transparency and Security + +At Express, security is a top priority, and we believe in the importance of transparency when it comes to vulnerabilities and their resolution. This audit not only highlights our proactive approach but also reinforces our ongoing commitment to building a secure web framework for all. + +We strongly recommend all users update to the latest versions of the affected packages to benefit from the recent security fixes. For more information on the patches and how to upgrade, please refer to our [September 2024 Security Release announcement](/en/blog/2024-09-29-security-releases). + +## A Word of Thanks + +This audit would not have been possible without the efforts and expertise of many individuals and organizations. We want to extend our gratitude to: + +- The team at Ada Logics for their diligent review and insights. +- OSTIF for their coordination and support throughout the audit process. +- The OpenJS Foundation for sponsoring this important initiative. +- Our Express.js community, who continue to support and trust us with their projects. +- [Jordan Harband](https://github.com/ljharb) for his amazing support while we needed changes in [qs](https://www.npmjs.com/package/qs). + +Together, we’ve made Express.js stronger, more resilient, and ready for the challenges ahead. We look forward to continuing to serve our community with a focus on excellence and security. + +Thank you for being a part of this journey with us! diff --git a/astro/src/content/blog/en/2025-01-09-rewind-2024-triumphs-and-2025-vision.md b/astro/src/content/blog/en/2025-01-09-rewind-2024-triumphs-and-2025-vision.md new file mode 100644 index 0000000000..02a74e94f6 --- /dev/null +++ b/astro/src/content/blog/en/2025-01-09-rewind-2024-triumphs-and-2025-vision.md @@ -0,0 +1,80 @@ +--- +title: 'A New Chapter for Express.js: Triumphs of 2024 and an ambitious 2025' +tags: ['announcements'] +authors: + - name: Express Technical Committee + github: expressjs +description: Explore the transformative journey of Express.js in 2024, marked by governance improvements, the long-awaited release of Express 5.0, and heightened security measures. Look into the ambitious plans for 2025, including performance optimizations, scoped packages, and a bold roadmap for sustained growth in the Node.js ecosystem. +--- + +As we step into the new year, it’s almost impossible to ignore the unmistakable energy coursing through the Express.js community. The past twelve months have proven both foundational and forward-looking: an era of governance overhauls, technical triumphs, and security enhancements that not only shaped 2024 but also laid the groundwork for what promises to be a transformative 2025. +In this long-form recap and forecast, we’ll journey through the story of Express.js with its evolution, its hurdles, and the new heights it’s poised to reach. + +--- + +## A Transformative 2024 + +Few could have predicted just how pivotal 2024 would be for the Express.js project. From the revitalization of its governance structures to the unveiling of long-awaited features, it was a year that solidified the framework’s role as a mainstay in the Node.js ecosystem. + +### Governance and Community Milestones + +Central to the project’s growth was the [Express Forward Plan](https://github.com/expressjs/discussions/issues/160), devised to ensure strategic alignment and long-term sustainability. This year also saw the introduction of a new generation of Technical Committee (TC) members, each bringing fresh insights and energy to the community. Those members include [Blake Embrey](https://github.com/blakeembrey), [Chris de Almeida](https://github.com/ctcpip), [Jean Burellier](https://github.com/sheplu), [Jon Church](https://github.com/jonchurch), [Linus Unnebäck](https://github.com/LinusU), [Rand McKinney](https://github.com/crandmck), [Ulises Gascón](https://github.com/ulisesgascon), and [Wes Todd](https://github.com/wesleytodd). By defining a clear path and transparent processes, the community was able to collaborate on ambitious updates more cohesively than ever before. A revitalized release process further streamlined how new versions are planned and executed, eliminating much of the guesswork and inconsistent timing that had previously challenged contributors. + +In parallel, the [Security Working Group](https://github.com/expressjs/discussions/issues/165) took shape. Express.js, widely recognized for its importance to the broader Node.js landscape, formally introduced a [security triage team](https://github.com/expressjs/security-wg#security-triage-team) dedicated to proactively identifying and resolving vulnerabilities. This forward-thinking approach was bolstered by the adoption of a [Threat Model for Express.js](https://github.com/expressjs/express/pull/5526), underscoring the project’s commitment to robust, future-proof security. + +As if these achievements weren’t enough, Express.js proudly reached [Impact Project status](https://github.com/openjs-foundation/cross-project-council/pull/1404) under the OpenJS Foundation. This acknowledgment affirmed the significance of the framework to the JavaScript ecosystem and showcased the community’s tireless efforts in ensuring its enduring relevance. + +### Technical Advancements and the Release of Express 5.0 + +Naturally, 2024 will forever be remembered as the year when Express.js finally introduced its much-anticipated [Express 5.0](/en/blog/2024-10-15-v5-release). After more than a decade of community discussions and behind-the-scenes experimentation, this release brought modern features and a future-oriented architecture to the framework, acting as a catalyst for the next chapter of Express.js development. + +But the story did not end there. Even before the release of Express 5.0 was fully established, the community had already begun charting the course for [Express 6.0](https://github.com/expressjs/discussions/issues/267), reflecting an unwavering commitment to innovation. Guiding critical decisions throughout 2024 were new [decision framework](https://github.com/expressjs/discussions/issues/285), which helped the Technical Committee tackle pressing matters such as [engine usage](https://github.com/expressjs/discussions/issues/286) and [dependency management](https://github.com/expressjs/discussions/issues/279). Collectively, these measures fostered transparency and agility, ensuring that Express.js continues to evolve in response to the community’s most urgent needs. + +### Maintenance, Tooling, and Collaboration + +Express.js also deepened its relationship with the Node.js community by re-integrating into the [Node.js CITGM project](https://github.com/expressjs/express/issues/5489). This move ensured broader ecosystem compatibility and provided developers with further validation that they can rely on Express.js as a dependable cornerstone of their Node.js applications. + +### A Heightened Security Posture + +Above all, 2024 will stand out for Express.js’s vigorous approach to security. In partnership with the [OpenJS Foundation](https://openjsf.org/) and [OSTIF](https://ostif.org/), the project undertook a comprehensive [security audit](/en/blog/2024-10-22-security-audit-milestone-achievement) that yielded critical insights and propelled immediate improvements. The sense of proactive vigilance extended to the adoption of the [OSSF Scorecard](https://github.com/expressjs/discussions/issues/162), implemented at an organizational level to keep track of security metrics and maintain focus on ongoing enhancements. + +Throughout the year, maintainers rapidly responded to disclosed vulnerabilities such as [CVE-2024-43796](https://github.com/expressjs/express/security/advisories/GHSA-qw6h-vgh9-j6wx), [CVE-2024-45590](https://github.com/expressjs/body-parser/security/advisories/GHSA-qwcr-r2fm-qrc7), and [CVE-2024-47178](https://github.com/expressjs/basic-auth-connect/security/advisories/GHSA-7p89-p6hx-q4fw). Each instance underscored the community’s readiness to defend the framework’s integrity and safeguard its user base. In a further demonstration of long-term commitment, Express.js teamed up with [HeroDevs](https://www.herodevs.com/) to establish [Never-Ending Support (NES)](https://openjsf.org/blog/at-the-openjs-foundation-were-excited-to-announce-), offering an extended maintenance plan that reaffirms Express.js as a reliable foundation for developers now and in the years to come. + +--- + +## A Bold Vision for 2025 + +While 2024 laid a sturdy bedrock, the Express.js Technical Committee is not resting on its laurels. The newly revealed roadmap for 2025—bolstered by the [Sovereign Tech Fund (STF)](https://www.sovereign.tech/)—embodies a spirit of forward momentum. It promises notable strides in security, performance, and general developer experience, with each initiative building on the insights gained over the past year. + +### Automating npm Releases + +At the forefront of this plan is the automation of npm releases, an endeavor designed to free maintainers from manual steps and human error. By streamlining the publishing process, the project can achieve faster turnaround times for patches and new features, preserving the stability that developers have come to expect from Express.js. It’s an internal shift with massive external benefits: smoother upgrades, more frequent releases, and a deeper reservoir of confidence for users. + +### Introducing Scoped Packages + +Express.js will also explore a transition toward scoped packages. By clearly delineating which modules fall under the Express.js umbrella, the maintainers hope to reduce confusion and foster an environment more conducive to organized expansion. As new packages and features are proposed, scoping will make it simpler to track official tools and ensure that community contributions meet consistent quality standards. + +### Strengthening Security Reporting and Procedures + +Since security remains one of the project’s primary pillars, 2025 will see a significant push to refine how vulnerabilities are reported and managed. Building upon the success of the Security Working Group, the new process will introduce transparent guidelines for reporting potential issues and a consistent triage routine for mitigating them. Additional training for both the Security Triage group and the Technical Committee will further cultivate a shared culture of readiness. Moreover, Express.js is poised to integrate [OSSF Scorecard](https://github.com/expressjs/discussions/issues/162) even more deeply into daily operations, ensuring that both maintainers and users have real-time insights into the project’s health. + +### Performance Monitoring and Deep-Level Optimizations + +Performance is another focal point. By systematically monitoring the framework’s speed and responsiveness—along with that of its dependencies—the Express.js team aims to pinpoint bottlenecks more rapidly. Over time, insights from these monitoring efforts will drive deeper optimizations in the core Express.js code and its core libraries. These improvements, expected to come to fruition by mid-2026, promise a faster, more scalable framework that can handle the heaviest production workloads with ease. + +### Phasing Out Legacy Techniques and Enhancing Documentation + +A future of agility and resilience depends on eliminating outdated techniques that invite complexity and fragility. As a result, Express.js will begin phasing out monkey-patching and passthrough APIs that rely too heavily on Node.js internals. This modernization strategy not only reduces technical debt but also ensures that Express.js remains aligned with Node.js updates going forward. + +In tandem, the project will make a concerted effort to bolster its security documentation. Through updated guides and best practices, maintainers hope to demystify crucial topics like secure session handling, input validation, and access control. The goal is to arm developers—from novices to seasoned engineers—with the knowledge they need to protect their applications against an ever-evolving threat landscape. + +--- + +## The Road Ahead + +As Express.js steps into 2025, it does so with a powerful sense of purpose. The achievements of the past year—culminating in the official release of Express 5.0 and wide-reaching governance enhancements—serve as a sturdy foundation for what’s to come. Yet, the framework’s leadership knows there is always more to build, more to secure, and more to imagine. + +Through automated releases, scopes for packages, rigorous security protocols, performance monitoring, and an ongoing effort to modernize core APIs, Express.js is evolving in real-time. And it isn’t just about technology; it’s about forging a collaborative environment where contributors can rely on transparent processes, robust training, and a supportive governance structure. + +Whether you’re a seasoned maintainer, an occasional contributor, or a newcomer to this thriving ecosystem, your voice matters. Join the [Express.js GitHub Discussions](https://github.com/expressjs/discussions), attend open meetings, and stay tuned for updates on [Express.js blog](https://expressjs.com/) as we finalize timetables for these initiatives. Each advancement, no matter how technical, flows from a common aspiration: to sustain Express.js as a fast, safe, and influential framework for millions of developers worldwide. +Together, we’ll keep the spirit of 2024 alive—pushing boundaries, refining practices, and laying the path to a future where Express.js remains at the heart of modern web development. diff --git a/astro/src/content/blog/en/2025-03-31-v5-1-latest-release.md b/astro/src/content/blog/en/2025-03-31-v5-1-latest-release.md new file mode 100644 index 0000000000..149dcf439e --- /dev/null +++ b/astro/src/content/blog/en/2025-03-31-v5-1-latest-release.md @@ -0,0 +1,170 @@ +--- +title: 'Express@5.1.0: Now the Default on npm with LTS Timeline' +tags: ['announcements'] +authors: + - name: Express Technical Committee + github: expressjs +description: Express 5.1.0 is now the default on npm, and we're introducing an official LTS schedule for the v4 and v5 release lines. +--- + +Express v5.0.0 was released on September 9th last year, but we didn't make it the `latest` release on npm. Many asked us +why and when it would be, and frankly we were not ready at the time to take that jump. If you have not followed the news +from the project this past year, we have been [hard at work reviving the project](/en/blog/2025-01-09-rewind-2024-triumphs-and-2025-vision/) +and when we pushed the initial v5 release there were many loose ends still hanging. So first lets quickly go over some +of those loose ends. + +### Documentation updates + +We had not updated the docs, provided migration guides, or even fully reviewed some of the stagnated v4/5 docs in a long +time. Since then we have had tons of great contributors help get things into better shape. As with any volunteer based +Open Source project, we love contributions to help us improve so as you upgrade please continue to open PRs to fix +anything we missed. + +You can find our [v5 docs](/en/5x/api) and our [migration guide](/en/guide/migrating-5) on the website. + +### Migration Support + +We know that migrating between versions can be challenging, especially when it involves significant changes in a widely used framework like Express. That's why we have worked on a solution to simplify part of the process and reduce the impact on developers. + +Thanks to the incredible efforts of [Sebastian](https://github.com/bjohansebas) and [Filip](https://github.com/kjugi), we have developed a new [codemod package](https://www.npmjs.com/package/@expressjs/codemod) specifically designed to facilitate the transition from Express v4 to v5, as well as future major versions. This package automates many of the necessary code changes, minimizing manual effort and making the upgrade as smooth and efficient as possible. + +However, we understand that not all changes can be automated. Some breaking changes, such as the [new Path Route Matching syntax](/en/guide/migrating-5#path-syntax), require manual modifications by developers. You can read more about all of the breaking changes which came with v5 in our [original release announcement](/en/blog/2024-10-15-v5-release). + +For more details on the migration process and how to use the codemod package, check the [repository’s README](https://github.com/expressjs/codemod#readme) and the [migration guide](/en/guide/migrating-5). + +### Ecosystem compatibility + +The Express ecosystem is one of its strongest assets. It goes back to the early days of Node.js and is the backbone +that keeps express popular. When it goes [10 years without a major release](/en/blog/2024-10-15-v5-release) +everything from middleware to documentation needed updates. We wanted to make sure folks had +some time to get all of that updated before we had everyone moving over. Particularly we care about our very large +beginner user base who may not know the blog post they are reading is not compatible with what they get from +`npm i express`. + +We recognize that some friction is inevitable during major upgrades, but thanks to work from ecosystem partners +like [Kamil](https://github.com/kamilmysliwiec) from NestJS [working to update `express` before we went `latest`](https://github.com/expressjs/express/issues/5944#issuecomment-2523074127) +we will hopefully be ahead of the curve. And as I said above, we always welcome help to make this transition easier for +those who follow after you, PRs are the best support you can give. + +### Long Term Support + +We had been discussing how to support v4 now that v5 was out, but we had not defined a clear guideline or expectation, +and we had (still don't have) end user docs on our plans here. While we still have progress to make here, we have a +[proposed LTS strategy ](https://github.com/expressjs/discussions/pull/352) which will be the basis for our forthcoming +docs. Input is very welcome on this so we can make sure it is clearly communicated and acceptable to the community. + +Additionally since then [we have announced a partnership with HeroDevs](/en/blog/2024-10-01-herodevs-partnership-announcement) to help companies who are less capable of +updating. More information on how this will work when v4 EOL will come when we get closer to that time. + +--- + +## Support Phases and Going latest + +What does it mean to "go latest"? If you are unfamiliar with how npm `dist-tags` work, the `latest` tag is what users +will get when they run `npm install express`. This is important because it means it is the "default installed version" +and will trigger the transition of nearly 17 million weekly downloads from our current latest v4.21.2 to v5. As we start +this transition we want users, companies, and other organizations to know exactly what it means for support. To help +with this we have developed an LTS strategy which defines our 3 support phases and set's target dates for when v4 will +enter EOL. + +Express major versions will go through three supported phases: + +- `CURRENT`: A new major version is designated as `CURRENT` upon release. It is available but not the `latest` version + on npm for a minimum of 3 months. +- `ACTIVE`: After the minimum 3 month period and the TC agrees it is stable and secure, the `ACTIVE` version is + tagged `latest` on npm for a minimum of 12 months. +- `MAINTENANCE`: When a new major version becomes `ACTIVE`, the previous major version enters `MAINTENANCE` for 12 months. + +### CURRENT + +- New majors will go through a short period of hardening to ensure stability, security, and ecosystem libraries/resources + compatibility. +- We will strive to ensure no breaking changes are included, but reserve the right to make security or high priority + fixes of breaking nature within this period. +- `CURRENT` lines will receive all types of active work including: bug fixes, security patches, new features, and + deprecation notices. +- Users are recommended to use `CURRENT` lines and to upgrade as quickly as their risk profile allows + +### ACTIVE + +- `ACTIVE` lines will receive all types of active work including: bug fixes, security patches, new features, and + deprecation notices. +- For users, `ACTIVE` lines are considered the most stable and well supported version at any given time. + +### MAINTENANCE + +- `MAINTENANCE` lines will only receive security patches or high priority bug fixes. +- Users are highly encouraged to upgrade to a `CURRENT` or `ACTIVE` release. + +### Proposed Schedule + +For the existing release lines, we will set the following phase dates: + +
+ +| Major | CURRENT | ACTIVE | MAINTENANCE | EOL | +| ----- | ------------------------------- | ---------- | ----------------------------- | ----------------------------- | +| 4.x | | | 2025-04-01 | \*no sooner than 2026-10-01 | +| 5.x | 2024-09-11 | 2025-03-31 | \*\*no sooner than 2026-04-01 | \*\*no sooner than 2027-04-01 | +| 6.x | \*\*\*no sooner than 2026-01-01 | | | | + +
+ +As you can see, this means that v5.1.0 being tagged `latest` indicates that we moved from `CURRENT` to `ACTIVE` which +starts the clock on EOL for v4 by moving it to `MAINTENANCE`. We recognize that v4 is a special case having been the +only major version for most of the history of Node.js itself. Because of this, we want to remain flexible and also +provide a bit longer support. We want to do what is best for the ecosystem, so consider these goals not commitments. + +\*: v4 is a special case, and we may extend MAINTENENCE support +\*\*: v5 MAINTENENCE and EOL dates are determined by when v6 is released, these dates reflect the earliest dates if we +were to ship v6 on 2025-10-01 +\*\*\* : v6 work has not officially started yet, this is simply the earliest date we can ship based on our proposed policy + +--- + +## Finally, what changed in v5.1.0 + +This release primarily focused on tech debt from supporting so many old Node.js versions and other things that stagnated but were not landed before v5.0.0 went out. + +### Express 5.1.0 Main Changes + +- Add support for `Uint8Array` in `res.send()` +- Transitioned all remaining dependencies to use `^` ranges instead of locked versions +- Add package.json funding field to highlight our OpenCollective +- Added support for ETag option in `res.sendFile()` +- Added support for adding multiple links with the same rel with `res.links()` +- Performance: Use loop for acceptParams +- See [Changelog v5.1.0](https://github.com/expressjs/express/releases/tag/v5.1.0) + +### Dependencies updated + +We also invested time to prepare several releases in the packages that Express depend on. Most of this packages are used by other libraries and framework as individual libraries. + +- [body-parser@2.2.0](https://github.com/expressjs/body-parser/releases/tag/v2.2.0) + - Remove legacy node.js support checks for Brotli & `AsyncLocalStorage` + - Remove `unpipe` & `destroy` +- [router@2.2.0](https://github.com/pillarjs/router/releases/tag/v2.2.0) + - Restore `debug`. Now with the `router` scope instead of `express`. + - Remove legacy node.js support checks for `setImmediate` + - Deprecate non-native promise support + - Remove `after`, `safe-buffer`, `array-flatten`, `setprotoypeof`, `methods`, `utils-merge` +- [finalhandler@2.1.0](https://github.com/pillarjs/finalhandler/releases/tag/v2.1.0) + - Remove legacy node.js support checks for `headersSent`, `setImmediate`, & http2 support + - Remove `unpipe` +- [serve-static@2.2.0](https://github.com/expressjs/serve-static/releases/tag/v2.2.0) + +--- + +## Thanks and What's Next + +Thanks so much to everyone involved in Express over the past year, the work all our contributors have put in is +incredible, and we couldn't do it without them. If you are not able to become a contributor yourself, please consider +asking your companies to support the project financially on [OpenCollective](https://opencollective.com/express). + +As we look ahead, we’re excited to keep building momentum. If you haven’t read it yet, our [Rewind 2024 + 2025 Vision blog post](/en/blog/2025-01-09-rewind-2024-triumphs-and-2025-vision) lays out where we’ve been and where we're headed. This includes performances scoped packages, better automation, security hardening, and more. + +One major initiative is our new [Performance Working Group](https://github.com/expressjs/discussions/pull/306), focused on identifying and fixing long-standing bottlenecks in Express. We're grateful to be kicking this off with support from the [Sovereign Tech Fund (STF)](https://www.sovereign.tech/), who are helping us invest in long-term sustainability and performance of core infrastructure. Additionally, we will be working to [improve our Typescript DX](https://github.com/expressjs/discussions/issues/192) and taking next steps to [improve the website](https://github.com/expressjs/expressjs.com/issues/1787). + +And yes, v6 discussions are already starting to heat up. Keep an eye out for updates, and as always, see you in the issues! + +Big thanks to [@wesleytodd](https://github.com/wesleytodd), [@blakeembrey](https://github.com/blakeembrey), [@bjohansebas](https://github.com/bjohansebas), [@UlisesGascon](https://github.com/UlisesGascon), [@Phillip9587](https://github.com/Phillip9587), [@carpasse](https://github.com/carpasse), [@jonchurch](https://github.com/jonchurch), [@ctcpip](https://github.com/ctcpip), [@inigomarquinez](https://github.com/inigomarquinez), [@carlosstenzel](https://github.com/carlosstenzel), [@crandmck](https://github.com/crandmck), [@chrisdel101](https://github.com/chrisdel101), [@dpopp07](https://github.com/dpopp07), [@Ayoub-Mabrouk](https://github.com/Ayoub-Mabrouk), [@jonkoops](https://github.com/jonkoops), [@IamLizu](https://github.com/IamLizu), [@marco-ippolito](https://github.com/marco-ippolito), [@ipreencekmr](https://github.com/ipreencekmr), [@ShubhamOulkar](https://github.com/ShubhamOulkar), [@raksbisht](https://github.com/raksbisht), [@jeffreybaird](https://github.com/jeffreybaird), [@dougwilson](https://github.com/dougwilson), [@mertcanaltin](https://github.com/mertcanaltin), [@GeorgeShvab](https://github.com/GeorgeShvab), [@RobinTail](https://github.com/RobinTail), [@EvanHahn](https://github.com/EvanHahn), [@rhodgkins](https://github.com/rhodgkins), [@cengizcmataraci](https://github.com/cengizcmataraci), [@Shantanugupta43](https://github.com/Shantanugupta43), [@italojs](https://github.com/italojs), [@ljharb](https://github.com/ljharb), [@MaoShizhong](https://github.com/MaoShizhong), [@aroyan](https://github.com/aroyan), [@Binilkks](https://github.com/Binilkks), [@danielgindi](https://github.com/danielgindi), [@papandreou](https://github.com/papandreou), [@jsoref](https://github.com/jsoref), [@bigbigDreamer](https://github.com/bigbigDreamer), [@broofa](https://github.com/broofa), [@CommanderRoot](https://github.com/CommanderRoot), [@andvea](https://github.com/andvea), [@juanarbol](https://github.com/juanarbol), [@agungjati](https://github.com/agungjati), [@alexandercerutti](https://github.com/alexandercerutti), [@pr4j3sh](https://github.com/pr4j3sh), [@hamirmahal](https://github.com/hamirmahal), [@slagiewka](https://github.com/slagiewka), [@Abdel-Monaam-Aouini](https://github.com/Abdel-Monaam-Aouini), [@sazk07](https://github.com/sazk07), [@bhavya3024](https://github.com/bhavya3024), [@joshbuker](https://github.com/joshbuker), [@almic](https://github.com/almic), [@FDrag0n](https://github.com/FDrag0n), [@Dmitry-Kondar](https://github.com/Dmitry-Kondar), [@attrid](https://github.com/attrid), [@kristof-low](https://github.com/kristof-low), [@gireeshpunathil](https://github.com/gireeshpunathil), [@UzairJ99](https://github.com/UzairJ99), [@choi2021](https://github.com/choi2021), [@hayden36](https://github.com/hayden36), [@joharkhan99](https://github.com/joharkhan99), [@peterh-capella](https://github.com/peterh-capella), [@johnburnett](https://github.com/johnburnett), [@nicolasgandrade](https://github.com/nicolasgandrade), [@axhuwastaken](https://github.com/axhuwastaken), [@abhijeetpandit7](https://github.com/abhijeetpandit7), [@peterdanwan](https://github.com/peterdanwan), [@rehmansheikh222](https://github.com/rehmansheikh222), [@corydalis10](https://github.com/corydalis10), [@mgsantos177](https://github.com/mgsantos177), [@wilyJ80](https://github.com/wilyJ80), [@LuiGeeDev](https://github.com/LuiGeeDev), [@juliogarciape](https://github.com/juliogarciape), [@aelmardhi](https://github.com/aelmardhi), [@Ahmed1monm](https://github.com/Ahmed1monm), [@erensarac](https://github.com/erensarac), [@tomasz13nocon](https://github.com/tomasz13nocon), [@tianbuyung](https://github.com/tianbuyung), [@GreyTearsDev](https://github.com/GreyTearsDev), [@aastha-cse](https://github.com/aastha-cse), [@krzysdz](https://github.com/krzysdz), [@Miguelrom](https://github.com/Miguelrom), [@bnoordhuis](https://github.com/bnoordhuis), [@MehfoozurRehman](https://github.com/MehfoozurRehman), [@EasonLin0716](https://github.com/EasonLin0716), [@grjan7](https://github.com/grjan7), [@mishrasur7](https://github.com/mishrasur7), [@gregfenton](https://github.com/gregfenton), [@zareefhasan](https://github.com/zareefhasan), [@Tejas150](https://github.com/Tejas150), [@jpricardo](https://github.com/jpricardo), [@nikeee](https://github.com/nikeee), [@dotnetCarpenter](https://github.com/dotnetCarpenter), [@engpetermwangi](https://github.com/engpetermwangi), [@msimerson](https://github.com/msimerson), [@fetsorn](https://github.com/fetsorn), [@manoharreddyporeddy](https://github.com/manoharreddyporeddy), [@lancatlin](https://github.com/lancatlin), [@mifi](https://github.com/mifi), [@meowingwhitey](https://github.com/meowingwhitey), [@sheplu](https://github.com/sheplu), [@krsriq](https://github.com/krsriq), [@ravibisht](https://github.com/ravibisht), [@wojtekmaj](https://github.com/wojtekmaj), [@aqeelat](https://github.com/aqeelat), [@melikhov-dev](https://github.com/melikhov-dev), [@alexstrat](https://github.com/alexstrat), [@isnifer](https://github.com/isnifer), [@TorstenDittmann](https://github.com/TorstenDittmann), [@Uzlopak](https://github.com/Uzlopak), [@gurgunday](https://github.com/gurgunday), [@kurtextrem](https://github.com/kurtextrem), [@hdtmccallie](https://github.com/hdtmccallie), [@proudparrot2](https://github.com/proudparrot2), [@bewinsnw](https://github.com/bewinsnw), [@jonboulle](https://github.com/jonboulle), [@alexander-akait](https://github.com/alexander-akait), [@alxndrsn](https://github.com/alxndrsn), [@DimitriPapadopoulos](https://github.com/DimitriPapadopoulos), [@greggman](https://github.com/greggman), [@jkbach](https://github.com/jkbach), [@julien-c](https://github.com/julien-c), [@risu729](https://github.com/risu729), [@JohnSimumatik](https://github.com/JohnSimumatik), [@dhouck](https://github.com/dhouck), [@pedro-php](https://github.com/pedro-php), [@aminerol](https://github.com/aminerol), [@robertsky](https://github.com/robertsky), [@ipetrouchtchak-fi](https://github.com/ipetrouchtchak-fi), [@tinhochu](https://github.com/tinhochu), [@Lord-Kamina](https://github.com/Lord-Kamina), [@joshkel](https://github.com/joshkel), [@raiandexter0607](https://github.com/raiandexter0607), [@NateEag](https://github.com/NateEag), [@rmhaiderali](https://github.com/rmhaiderali), [@ljeda](https://github.com/ljeda) diff --git a/astro/src/content/blog/en/2025-05-16-express-cleanup-legacy-packages.md b/astro/src/content/blog/en/2025-05-16-express-cleanup-legacy-packages.md new file mode 100644 index 0000000000..500d48cb51 --- /dev/null +++ b/astro/src/content/blog/en/2025-05-16-express-cleanup-legacy-packages.md @@ -0,0 +1,48 @@ +--- +title: 'Spring Cleaning in Express.js: Deprecations and the Path Ahead' +tags: ['announcements'] +authors: + - name: Express Technical Committee + github: expressjs +description: As part of a broader effort to modernize and streamline Express.js, we’ve deprecated several outdated packages including csurf, connect-multiparty, and path-match. Learn why we made these changes and what it means for the future of the framework. +--- + +As Express.js continues to power web applications across the world, it's important that we maintain a clean, reliable, and modern codebase. In that spirit, we've done a bit of spring cleaning. + +Over the past few weeks, we've evaluated legacy packages within the Express.js ecosystem — some of which have become outdated, unmaintained, or misaligned with modern best practices. As a result, we’ve officially deprecated several of them. + +## 🚨 Packages Deprecated + +Here are the key packages we’ve deprecated: + +- [`csurf`](https://www.npmjs.com/package/csurf): A CSRF middleware that’s long been difficult to maintain and is better handled today through frameworks or custom implementations that align with your architecture. +- [`connect-multiparty`](https://www.npmjs.com/package/connect-multiparty): A multipart form-data parser that relies on deprecated libraries and hasn’t aged well. +- [`path-match`](https://www.npmjs.com/package/path-match): A route-matching utility that has been superseded by more modern and maintained alternatives. + +Each of these packages was originally created to solve real problems—but time has moved on, and the ecosystem has evolved. + +## 🤔 Why This Matters + +Maintaining deprecated or inactive dependencies introduces technical debt and security risk. By formally deprecating these packages, we: + +- Encourage developers to adopt better-maintained and more secure solutions. +- Reduce confusion around which tools are actively supported by Express. +- Focus our efforts on modernizing the core and surrounding ecosystem. + +## 🗂️ What You Should Do + +If your application depends on any of these packages, now is a great time to look for alternatives. For instance: + +- Consider finding a modern CSRF protection strategy on [npm](https://www.npmjs.com/search?q=csurf) that aligns with your specific needs. +- Use up-to-date multipart parsers like [`multer`](https://www.npmjs.com/package/multer). +- Replace path-match logic with standard [`path-to-regexp`](https://www.npmjs.com/package/path-to-regexp). + +## 📘 What's Next + +We're not stopping here. This cleanup is part of a broader effort to streamline Express.js, prepare for the future, and clarify what is and isn’t officially supported. + +👉 A full discussion of these changes can be found [expressjs/discussions#134](https://github.com/expressjs/discussions/issues/134). + +📢 Stay tuned—we'll continue to post updates and insights as we modernize the Express ecosystem. + +💚Thanks to the community for your continued trust and support. diff --git a/astro/src/content/blog/en/2025-05-19-security-releases.md b/astro/src/content/blog/en/2025-05-19-security-releases.md new file mode 100644 index 0000000000..f66906eb1e --- /dev/null +++ b/astro/src/content/blog/en/2025-05-19-security-releases.md @@ -0,0 +1,51 @@ +--- +title: May 2025 Security Releases +description: Security release for Multer has been published. We recommend that all users upgrade as soon as possible. +tags: ['security'] +authors: + - name: Ulises Gascón + github: UlisesGascon +--- + +The Express team has released a new major version of [Multer](https://www.npmjs.com/package/multer) addressing two high-severity security vulnerabilities. This update improves the reliability and security of handling file uploads in Express applications. + +{% include admonitions/warning.html +content="We strongly recommend that you upgrade to Multer v2.0.0 or later as soon as possible." +%} + +The following vulnerabilities have been addressed: + +- [High severity vulnerability CVE-2025-47935 in Multer middleware](#high-severity-vulnerability-cve-2025-47935-in-multer-middleware) +- [High severity vulnerability CVE-2025-47944 in Multer middleware](#high-severity-vulnerability-cve-2025-47944-in-multer-middleware) + +## High severity vulnerability CVE-2025-47935 in Multer middleware + +**[Multer](https://www.npmjs.com/package/multer) versions `<2.0.0` are vulnerable to denial of service due to a memory leak caused by improper stream handling.** + +When the HTTP request stream emits an error, the internal `busboy` stream is not closed, violating Node.js stream safety guidance. + +This leads to unclosed streams accumulating over time, consuming memory and file descriptors. Under sustained or repeated failure conditions, this can result in denial of service, requiring manual server restarts to recover. All users of Multer handling file uploads are potentially impacted. + +**Affected versions**: `<2.0.0` +**Patched version**: `>=2.0.0` + +For more details, see [GHSA-44fp-w29j-9vj5](https://github.com/expressjs/multer/security/advisories/GHSA-44fp-w29j-9vj5). + +## High severity vulnerability CVE-2025-47944 in Multer middleware + +**[Multer](https://www.npmjs.com/package/multer) versions `>=1.4.4-lts.1` and `<2.0.0` are vulnerable to a denial of service via a malformed multipart request.** + +A specially crafted request can cause an unhandled exception inside Multer, resulting in a crash of the server process. + +**Affected versions**: `>=1.4.4-lts.1` and `<2.0.0` +**Patched version**: `>=2.0.0` + +For more details, see [GHSA-4pg4-qvpc-4q3h](https://github.com/expressjs/multer/security/advisories/GHSA-4pg4-qvpc-4q3h). + +--- + +**Multer v2.0.0** also introduces a breaking change: + +- The minimum supported Node.js version is now **10.16.0**. + +We recommend upgrading to the latest version of Multer immediately to secure your applications. diff --git a/astro/src/content/blog/en/2025-06-05-vulnerability-reporting-process-overhaul.md b/astro/src/content/blog/en/2025-06-05-vulnerability-reporting-process-overhaul.md new file mode 100644 index 0000000000..f227665d72 --- /dev/null +++ b/astro/src/content/blog/en/2025-06-05-vulnerability-reporting-process-overhaul.md @@ -0,0 +1,84 @@ +--- +title: How Express.js Rebuilt Its Vulnerability Reporting Process +description: Express.js has overhauled its vulnerability reporting workflow with a unified process, consolidated documentation, and GitHub Security Advisories enabled across all repositories. +tags: ['security'] +authors: + - name: Ulises Gascón + github: UlisesGascon +--- + +The Express.js project has completed a major milestone in its ongoing commitment to security: the implementation of a formal, centralized vulnerability reporting and response process. + +Until recently, security reports were typically handled over email — an approach that worked in the early days but no longer scaled with the growing complexity and user base of Express. This informal system introduced potential delays, inconsistent handling, and increased the risk of issues being missed or misunderstood. + +Thanks to support from the [Sovereign Tech Fund](https://sovereign.tech), the Express.js Security Working Group has now completed a ground-up overhaul of how we manage vulnerability reports. + +## 🛠️ Key Improvements + +### Formalized Vulnerability Reporting Workflow + +A comprehensive runbook and process flow have been created to guide maintainers through each step of triaging, confirming, and addressing reported security issues. + +- [View the documentation](https://github.com/expressjs/security-wg/blob/main/docs/incident_response_plan.md) +- [Security Report Handling Flowchart](https://github.com/expressjs/security-wg/blob/main/docs/incident_response_plan.md#security-report-handling-flowchart) + +### Unified Security Policy Across Repositories + +All Express.js repositories now share a single, unified `SECURITY.md` policy to ensure consistency and remove confusion for reporters and maintainers alike. + +- [View the unified Security Policy](https://github.com/expressjs/.github/blob/master/SECURITY.md) + +### GitHub Security Advisories Enabled + +Security Advisories are now enabled across all Express.js repositories, allowing for secure, private vulnerability reporting through GitHub’s built-in system. + +- [How to report a security bug using GitHub Security Advisory](https://github.com/expressjs/.github/blob/master/SECURITY.md#reporting-security-bugs-via-github-security-advisory-preferred) + +### Clear Maintainer Responsibilities + +Expectations around ownership and response timelines have been clarified and published to reduce ambiguity and improve responsiveness. + +> A [Security triage team member](https://github.com/expressjs/security-wg#security-triage-team) or [the repo captain](https://github.com/expressjs/discussions/blob/master/docs/contributing/captains_and_committers.md) will acknowledge your report as soon as possible. +> +> 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. +> +> _[Security Policy](https://github.com/expressjs/.github/blob/master/SECURITY.md)_ + +## 🛡️ Express is Now Covered Under the OpenJS Foundation CNA + +As of June 2025, the [OpenJS Foundation](https://openjsf.org/) is officially a [CVE Numbering Authority (CNA)](https://openjsf.org/blog/openjs-foundation-cna), empowered to assign CVE identifiers for security vulnerabilities across its hosted projects—including Express. + +What this means for the community: + +- Security vulnerabilities in Express can now receive official CVE IDs through OpenJS, improving transparency and coordination. +- The foundation provides support and tooling to streamline the vulnerability disclosure process, particularly for maintainers and security researchers. +- For critical issues, the CNA helps ensure that disclosures follow best practices and are recorded in global vulnerability databases. + +Please refer to [Express’s Security Policy](https://github.com/expressjs/express/security/policy) for the correct disclosure process. If needed, escalation routes through the OpenJS CNA are now available. + +This advancement is part of a broader effort to strengthen the security of JavaScript’s open-source ecosystem—especially for widely used, community-driven projects like Express. + +Learn more: + +- [OpenJS Foundation is now a CNA – Official Blog Post](https://openjsf.org/blog/openjs-foundation-cna) +- [Socket.dev Coverage: OpenJS Foundation Becomes a CNA](https://socket.dev/blog/openjs-foundation-is-now-a-cna) + +## 👀 Coming Soon: Bug Bounty Program in the Works + +To further enhance the security of our ecosystem and encourage responsible vulnerability disclosure, the Express.js team has begun exploring participation in a community-focused bug bounty initiative—powered by the [Sovereign Tech Resilience program](https://www.sovereign.tech/programs/bug-resilience). + +This collaboration aims to: + +- Reward contributors for discovering and responsibly reporting security issues +- Improve our ability to address vulnerabilities quickly and transparently +- Strengthen long-term resilience for users and maintainers alike + +Join the conversation and share your thoughts in [expressjs/discussions#345 – Bug Bounty Proposal](https://github.com/expressjs/discussions/issues/345) + +## Why This Matters + +Security is a shared responsibility — and one that must evolve as the project grows. With these updates, Express.js has laid the foundation for a more reliable, scalable, and transparent vulnerability response system. + +We’re grateful to the [OpenJS Foundation](https://openjsf.org/) and the [Sovereign Tech Fund](https://www.sovereign.tech/) for their support and are excited to share this progress with the broader community. diff --git a/astro/src/content/blog/en/2025-07-18-security-releases.md b/astro/src/content/blog/en/2025-07-18-security-releases.md new file mode 100644 index 0000000000..2e716847b9 --- /dev/null +++ b/astro/src/content/blog/en/2025-07-18-security-releases.md @@ -0,0 +1,27 @@ +--- +title: June 2025 Security Releases +description: Security update for Multer released. All users are encouraged to upgrade. +tags: ['security'] +authors: + - name: Ulises Gascón + github: UlisesGascon +--- + +The Express team has released a new patch version of [Multer](https://www.npmjs.com/package/multer), addressing a high-severity vulnerability that could lead to a Denial of Service (DoS) attack. + +{% include admonitions/warning.html +content="We strongly recommend that all users upgrade to Multer v2.0.1 or later immediately." +%} + +This release addresses the following vulnerability: + +### High severity vulnerability CVE-2025-48997 in Multer middleware + +**[Multer](https://www.npmjs.com/package/multer) versions `>=1.4.4-lts.1` and `<2.0.1` are vulnerable to a Denial of Service (DoS) attack.** + +An attacker can trigger this vulnerability by sending an upload request with an empty string as the field name. This malformed request causes an unhandled exception, leading to a crash of the server process. + +**Affected versions**: `>=1.4.4-lts.1` and `<2.0.1` +**Patched version**: `2.0.1` + +For more details, see [GHSA-g5hg-p3ph-g8qg](https://github.com/expressjs/multer/security/advisories/GHSA-g5hg-p3ph-g8qg). diff --git a/astro/src/content/blog/en/2025-07-31-security-releases.md b/astro/src/content/blog/en/2025-07-31-security-releases.md new file mode 100644 index 0000000000..694e5c7ac4 --- /dev/null +++ b/astro/src/content/blog/en/2025-07-31-security-releases.md @@ -0,0 +1,47 @@ +--- +title: July 2025 Security Releases +description: Security releases for Multer and On-headers has been published. We recommend that all users upgrade as soon as possible. +tags: ['security'] +authors: + - name: Ulises Gascón + github: UlisesGascon +--- + +import Alert from '@components/primitives/Alert/Alert.astro'; + +The Express team has released a new patch version of [Multer](https://www.npmjs.com/package/multer) addressing a high-severity security vulnerability, and a new minor version of [on-headers](https://www.npmjs.com/package/on-headers) addressing a low-severity security vulnerability. + + +We recommend upgrading to the latest version of Multer and On-headers immediately to secure your applications. + + +The following vulnerabilities have been addressed: + +- [High severity vulnerability CVE-2025-7338 in Multer middleware](#high-severity-vulnerability-cve-2025-7338-in-multer-middleware) +- [Low severity vulnerability CVE-2025-7339 in On-header middleware](#low-severity-vulnerability-cve-2025-7339-in-on-header-middleware) + +## High severity vulnerability CVE-2025-7338 in Multer middleware + +**[Multer](https://www.npmjs.com/package/multer) versions `>=1.4.4-lts.1` and `<2.0.2` are vulnerable to denial of service via unhandled exception from malformed request.** + +This request causes an unhandled exception, leading to a crash of the process. + +**Affected versions**: `>=1.4.4-lts.1, <2.0.2` +**Patched version**: `2.0.2` + +For more details, see [GHSA-fjgf-rc76-4x9p](https://github.com/expressjs/multer/security/advisories/GHSA-fjgf-rc76-4x9p). + +## Low severity vulnerability CVE-2025-7339 in On-header middleware + +**[On-headers](https://www.npmjs.com/package/on-headers) versions `<1.1.0` is vulnerable to http response header manipulation** + +A bug in on-headers versions `<1.1.0` may result in response headers being inadvertently modified when an array is passed to `response.writeHead()` + +**Affected versions**: `<1.1.0` +**Patched version**: `1.1.0` + +For more details, see [GHSA-76c9-3jph-rj3q](https://github.com/jshttp/on-headers/security/advisories/GHSA-76c9-3jph-rj3q). + +--- + +We recommend upgrading to the latest version of Multer and On-headers immediately to secure your applications. diff --git a/astro/src/content/blog/en/2025-12-01-security-releases.mdx b/astro/src/content/blog/en/2025-12-01-security-releases.mdx new file mode 100644 index 0000000000..fb2ce9abf4 --- /dev/null +++ b/astro/src/content/blog/en/2025-12-01-security-releases.mdx @@ -0,0 +1,35 @@ +--- +title: November 2025 Security Releases +description: Security release for body-parser has been published. We recommend that all users upgrade as soon as possible. +tags: ['security'] +authors: + - name: Ulises Gascón + github: UlisesGascon +--- + +import Alert from '@components/primitives/Alert/Alert.astro'; + +The Express team has released a new patch version of [body-parser](https://www.npmjs.com/package/body-parser) addressing a moderate-severity security vulnerability. + + + We recommend upgrading to the latest version of body-parser to secure your applications. + + +The following vulnerabilities have been addressed: + +- [CVE-2025-13466 in body-parser middleware (Moderate)](#cve-2025-13466-in-body-parser-middleware-moderate) + +## CVE-2025-13466 in Body-parser middleware (Moderate) + +**[body-parser](https://www.npmjs.com/package/body-parser) version `2.2.0` is vulnerable to denial of service when url encoding is used** + +body-parser 2.2.0 is vulnerable to denial of service due to inefficient handling of URL-encoded bodies with very large numbers of parameters. An attacker can send payloads containing thousands of parameters within the default 100KB request size limit, causing elevated CPU and memory usage. This can lead to service slowdown or partial outages under sustained malicious traffic. + +**Affected versions**: `2.2.0` +**Patched version**: `>= 2.2.1` + +For more details, see [GHSA-wqch-xfxh-vrr4](https://github.com/expressjs/body-parser/security/advisories/GHSA-wqch-xfxh-vrr4). + +--- + +We recommend upgrading to the latest version of body-parser to secure your applications. diff --git a/astro/src/content/blog/en/2026-02-27-security-releases.mdx b/astro/src/content/blog/en/2026-02-27-security-releases.mdx new file mode 100644 index 0000000000..2f76d635e6 --- /dev/null +++ b/astro/src/content/blog/en/2026-02-27-security-releases.mdx @@ -0,0 +1,47 @@ +--- +title: February 2026 Security Releases +description: Security release for multer has been published. We recommend that all users upgrade as soon as possible. +tags: ['security'] +authors: + - name: Ulises Gascón + github: UlisesGascon +--- + +import Alert from '@components/primitives/Alert/Alert.astro'; + +The Express team has released a new patch version of [multer](https://www.npmjs.com/package/multer) addressing two high-severity security vulnerabilities. + + + We recommend upgrading to the latest version of multer to secure your applications. + + +The following vulnerabilities have been addressed: + +- [CVE-2026-3304 in multer middleware (High)](#cve-2026-3304-in-multer-middleware-high) +- [CVE-2026-2359 in multer middleware (High)](#cve-2026-2359-in-multer-middleware-high) + +## CVE-2026-3304 in multer middleware (High) + +**[multer](https://www.npmjs.com/package/multer) versions `<2.1.0` are vulnerable to denial of service via incomplete cleanup** + +A vulnerability in Multer versions `<2.1.0` allows an attacker to trigger a Denial of Service (DoS) by sending malformed requests, potentially causing resource exhaustion. + +**Affected versions**: `< 2.1.0` +**Patched version**: `>= 2.1.0` + +For more details, see [GHSA-xf7r-hgr6-v32p](https://github.com/expressjs/multer/security/advisories/GHSA-xf7r-hgr6-v32p). + +## CVE-2026-2359 in multer middleware (High) + +**[multer](https://www.npmjs.com/package/multer) versions `<2.1.0` are vulnerable to denial of service via resource exhaustion** + +A vulnerability in Multer versions `<2.1.0` allows an attacker to trigger a Denial of Service (DoS) by dropping connection during file upload, potentially causing resource exhaustion. + +**Affected versions**: `< 2.1.0` +**Patched version**: `>= 2.1.0` + +For more details, see [GHSA-v52c-386h-88mc](https://github.com/expressjs/multer/security/advisories/GHSA-v52c-386h-88mc). + +--- + +We recommend upgrading to the latest version of multer to secure your applications. diff --git a/astro/src/content/blog/en/write-post.md b/astro/src/content/blog/en/write-post.md new file mode 100644 index 0000000000..9678b64120 --- /dev/null +++ b/astro/src/content/blog/en/write-post.md @@ -0,0 +1,52 @@ +--- +layout: post +title: How to write a blog post +description: Learn how to propose and write a blog post for the Express.js blog, including submission guidelines and steps to contribute your content. +--- + + + +If you have an idea for a blog post, follow these steps to propose it and potentially get it published! + +1. ### Propose your post + + Before taking the time to write a post, please confirm that we will be able to publish it. We're looking for topics specifically related to Express, and so we want to pre-approve all posts. For the moment, this means we aren't accepting any unsolicited posts. To propose a blog post, [open an issue](https://github.com/expressjs/expressjs.com/issues) entitled `Blog post proposal: `. + +1. ### Fork the repository + + If the Express TC accepts your proposal, start to write your post by forking the [expressjs.com](https://github.com/expressjs/expressjs.com) repository and cloning it to your local machine. Once you open a pull request, you'll be able to preview your post on GitHub. See step six below. + + Optional: To run the site locally and preview your post before opening a PR, see the [setup instructions in the README](https://github.com/expressjs/expressjs.com?tab=readme-ov-file#expressjscom). + {: .doc-box .doc-info} + +1. ### Create a new file + + Create a new file in the `_posts` directory named using following the format: `YYYY-MM-DD-title.md`. + +1. ### Add the required front matter + + Copy the following front matter, including the dotted lines, and paste it at the top of file you just created. Replace the placeholder values with as desired. + + ```markdown + --- + title: + sub_title: + description: + tags: + authors: + - name: + github: + --- + ``` + + The `github` property of an author is optional. Including your username only (not your full profile URL) will ensure that your blog post links out to it. + +1. ### Add your content + + Finally, start writing your content below the front matter. Use standard markdown formatting. + +1. ### Open a pull request (PR) + + Once you open a PR, you will be able to preview your results: There will be a section on the page entitled `Deploy Preview for expressjscom-preview ready!` Click the link to see the site rendered from your fork/branch. + + You can use this feature over multiple commits to refine your post by making a `draft` pull request. Once it's ready for review, switch it to a formal PR. 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..810fc3625b --- /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](/en/support#commercial-support-options). + +
+ +

3.x-API

+ + +{% include api/en/3x/app.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..cf631586a0 --- /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) 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#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#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) 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). + +### 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). 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) 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..32fdb44395 --- /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#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. + +- [Best Practices in Produktionsumgebungen: Sicherheit](#best-practices-in-produktionsumgebungen-sicherheit) + - [Überblick](#überblick) + - [Verwenden Sie keine veralteten oder anfälligen Versionen von Express](#verwenden-sie-keine-veralteten-oder-anfälligen-versionen-von-express) + - [TLS verwenden](#tls-verwenden) + - [Do not trust user input](#do-not-trust-user-input) + - [Prevent open redirects](#prevent-open-redirects) + - ["Helmet" verwenden](#helmet-verwenden) + - [Reduce fingerprinting](#reduce-fingerprinting) + - [Cookies sicher verwenden](#cookies-sicher-verwenden) + - [Verwenden Sie nicht den standardmäßigen Namen des Sitzungscookies](#verwenden-sie-nicht-den-standardmäßigen-namen-des-sitzungscookies) + - [Cookie-Sicherheitsoptionen festlegen](#cookie-sicherheitsoptionen-festlegen) + - [Prevent brute-force attacks against authorization](#prevent-brute-force-attacks-against-authorization) + - [Ensure your dependencies are secure](#ensure-your-dependencies-are-secure) + - [Vermeiden Sie andere Schwachstellen](#vermeiden-sie-andere-schwachstellen) + - [Weitere Überlegungen](#weitere-überlegungen) + +## 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](/en/guide/migrating-4). + +Stellen Sie außerdem sicher, dass Sie keine anfälligen Express-Versionen verwenden, die auf der [Seite mit den Sicherheitsupdates](/en/advanced/security-updates) 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://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); +}); +``` + +## "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#how-do-i-handle-404-responses) +and +[writing your own error handler](/en/guide/error-handling#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..850aacf852 --- /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](/en/resources/contributing#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](/en/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/guide/behind-proxies.md b/astro/src/content/docs/de/4x/guide/behind-proxies.md new file mode 100644 index 0000000000..34def6bfcb --- /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()](/en/4x/api#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](/en/api#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](/en/api#req.protocol) abgebildet. +
  • +
  • Als Werte für [req.ip](/en/api#req.ip) und [req.ips](/en/api#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..1d69c7bda7 --- /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](/en/starter/generator) 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#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..6431405f27 --- /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](/en/resources/middleware). + +## 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..47fad43b6f --- /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()`](/en/4x/api#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/de/guide/migrating-5.md b/astro/src/content/docs/de/4x/guide/migrating-5.md similarity index 90% rename from de/guide/migrating-5.md rename to astro/src/content/docs/de/4x/guide/migrating-5.md index 2b2e8f031f..1d1d033413 100644 --- a/de/guide/migrating-5.md +++ b/astro/src/content/docs/de/4x/guide/migrating-5.md @@ -1,10 +1,6 @@ --- -layout: page 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. -menu: guide -order: 10 -redirect_from: " " --- # Wechsel zu Express 5 @@ -99,7 +95,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 ``` @@ -110,13 +106,13 @@ npx @expressjs/codemod v4-deprecated-signatures ```js // v4 app.del('/user/:id', (req, res) => { - res.send(`DELETE /user/${req.params.id}`) -}) + res.send(`DELETE /user/${req.params.id}`); +}); // v5 app.delete('/user/:id', (req, res) => { - res.send(`DELETE /user/${req.params.id}`) -}) + res.send(`DELETE /user/${req.params.id}`); +}); ```

app.param(fn)

@@ -136,7 +132,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 ``` @@ -147,28 +143,28 @@ npx @expressjs/codemod pluralized-methods ```js // v4 app.all('/', (req, res) => { - req.acceptsCharset('utf-8') - req.acceptsEncoding('br') - req.acceptsLanguage('en') + 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') + 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. +Dies dürfte keine Auswirkungen auf Ihren Code haben, wenn Sie die Express 4-Dokumentation zu [app.param](/en/4x/api#app.param) befolgen, da dort der führende Doppelpunkt nicht erwähnt wird.

req.param(name)

@@ -177,7 +173,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 ``` @@ -188,75 +184,75 @@ 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') + 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 + 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) -}) + res.json({ name: 'Ruben' }, 201); +}); // v5 app.post('/user', (req, res) => { - res.status(201).json({ name: 'Ruben' }) -}) + 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) -}) + res.jsonp({ name: 'Ruben' }, 201); +}); // v5 app.post('/user', (req, res) => { - res.status(201).jsonp({ name: 'Ruben' }) -}) + 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) -}) + res.redirect('/users', 301); +}); // v5 app.get('/user', (req, res) => { - res.redirect(301, '/users') -}) + res.redirect(301, '/users'); +}); ```

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

@@ -266,7 +262,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 ``` @@ -277,13 +273,13 @@ npx @expressjs/codemod magic-redirect ```js // v4 app.get('/user', (req, res) => { - res.redirect('back') -}) + res.redirect('back'); +}); // v5 app.get('/user', (req, res) => { - res.redirect(req.get('Referrer') || '/') -}) + res.redirect(req.get('Referrer') || '/'); +}); ```

res.send(body, status)

@@ -295,13 +291,13 @@ 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) -}) + res.send({ name: 'Ruben' }, 200); +}); // v5 app.get('/user', (req, res) => { - res.status(200).send({ name: 'Ruben' }) -}) + res.status(200).send({ name: 'Ruben' }); +}); ```

res.send(status)

@@ -314,13 +310,13 @@ 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) -}) + res.send(200); +}); // v5 app.get('/user', (req, res) => { - res.sendStatus(200) -}) + res.sendStatus(200); +}); ```

res.sendfile()

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

router.param(fn)

@@ -364,17 +360,17 @@ Use the [`mime-types` package](https://github.com/jshttp/mime-types) to work wit - 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" +- HTML files (): 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') +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,13 +403,13 @@ 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') -}) + res.send('ok'); +}); // v5 app.get('/*splat', async (req, res) => { - res.send('ok') -}) + res.send('ok'); +}); ``` {% capture note_wildcard %} @@ -422,8 +418,8 @@ app.get('/*splat', async (req, res) => { ```js // v5 app.get('/{*splat}', async (req, res) => { - res.send('ok') -}) + res.send('ok'); +}); ``` {% endcapture %} @@ -434,29 +430,29 @@ app.get('/{*splat}', async (req, res) => { ```js // v4 app.get('/:file.:ext?', async (req, res) => { - res.send('ok') -}) + res.send('ok'); +}); // v5 app.get('/:file{.:ext}', async (req, res) => { - res.send('ok') -}) + res.send('ok'); +}); ``` - Regexp characters are not supported. Beispiel: ```js app.get('/[discussion|page]/:slug', async (req, res) => { - res.status(200).send('ok') -}) + res.status(200).send('ok'); +}); ``` should be changed to: ```js app.get(['/discussion/:slug', '/page/:slug'], async (req, res) => { - res.status(200).send('ok') -}) + res.status(200).send('ok'); +}); ``` - Some characters have been reserved to avoid confusion during upgrade (`()[]?+!`), use `\` to escape them. @@ -466,7 +462,7 @@ app.get(['/discussion/:slug', '/page/:slug'], async (req, res) => { 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). +Details of how Express handles errors is covered in the [error handling documentation](/en/guide/error-handling).

express.urlencoded

@@ -480,7 +476,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 +485,8 @@ 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. @@ -503,10 +499,10 @@ Beispiel: ```js 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,9 +528,9 @@ Wildcards (e.g., `/*splat`) capture path segments as an array instead of a singl ```js 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,23 +541,23 @@ In Express 4, unmatched wildcards were empty strings (`''`) and optional `:` par // v4: unmatched wildcard is empty string 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) => { // 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) => { // GET /image - console.dir(req.params) + console.dir(req.params); // => [Object: null prototype] { file: 'image' } -}) +}); ```

req.query

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..8f78a06422 --- /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](/en/4x/api#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..5e5c52fbae --- /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](/en/starter/basic-routing). + +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](/en/5x/api#app.METHOD). You can also use [app.all()](/en/5x/api#app.all) to handle all HTTP methods and [app.use()](/en/5x/api#app.use) to +specify middleware as the callback function (See [Using middleware](/en/guide/using-middleware) 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](/en/5x/api#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](/en/guide/migrating-5#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](/en/guide/migrating-5#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](/en/guide/migrating-5#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](/en/guide/using-middleware) 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()](/en/4x/api#res.download) | Gibt eine Eingabeaufforderung zum Herunterladen einer Datei aus. | +| [res.end()](/en/4x/api#res.end) | End the response process. | +| [res.json()](/en/4x/api#res.json) | Sendet eine JSON-Antwort. | +| [res.jsonp()](/en/4x/api#res.jsonp) | Sendet eine JSON-Antwort mit JSONP-Unterstützung. | +| [res.redirect()](/en/4x/api#res.redirect) | Leitet eine Anforderung um. | +| [res.render()](/en/4x/api#res.render) | Render a view template. | +| [res.send()](/en/4x/api#res.send) | Sendet eine Antwort mit unterschiedlichen Typen. | +| [res.sendFile](/en/4x/api#res.sendFile) | Sendet eine Datei als Oktett-Stream. | +| [res.sendStatus()](/en/4x/api#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()](/en/4x/api#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](/en/5x/api#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..f5987bc806 --- /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](/en/5x/api#req) (`req`), the [response object](/en/5x/api#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](/en/5x/api#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](/en/guide/error-handling). + +

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#express.static) serves static assets such as HTML files, images, and so on. +- [express.json](/en/5x/api#express.json) parses incoming requests with JSON payloads. **NOTE: Available with Express 4.16.0+** +- [express.urlencoded](/en/5x/api#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). 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..0e99b8b839 --- /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](/en/starter/generator) 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](/en/4x/api#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..3bc5fbb2fb --- /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](/en/5x/api#req) (`req`), the [response object](/en/5x/api#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.
+ +
+ + +
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`](/en/resources/middleware/cookie-parser) 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](/en/guide/using-middleware). + +

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..633da3f660 --- /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"](/en/starter/hello-world) 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](/en/guide/routing). 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..1ab5b58628 --- /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](/en/guide/using-template-engines). + +## 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](/en/guide/error-handling). + +## 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](/en/4x/api) requires Node.js 0.10 or higher. +- [Express 5.x](/en/5x/api) 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..d6e9f141a6 --- /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](/en/starter/generator) 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](/en/starter/installing) 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..371e979f5f --- /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](/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 +``` + +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..fb36f85ca5 --- /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](/en/5x/api#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](/en/advanced/best-practice-performance#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](/en/5x/api#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](/en/resources/middleware/serve-static). 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..cf631586a0 --- /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) 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#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#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) 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). + +### 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). 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) 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..32fdb44395 --- /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#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. + +- [Best Practices in Produktionsumgebungen: Sicherheit](#best-practices-in-produktionsumgebungen-sicherheit) + - [Überblick](#überblick) + - [Verwenden Sie keine veralteten oder anfälligen Versionen von Express](#verwenden-sie-keine-veralteten-oder-anfälligen-versionen-von-express) + - [TLS verwenden](#tls-verwenden) + - [Do not trust user input](#do-not-trust-user-input) + - [Prevent open redirects](#prevent-open-redirects) + - ["Helmet" verwenden](#helmet-verwenden) + - [Reduce fingerprinting](#reduce-fingerprinting) + - [Cookies sicher verwenden](#cookies-sicher-verwenden) + - [Verwenden Sie nicht den standardmäßigen Namen des Sitzungscookies](#verwenden-sie-nicht-den-standardmäßigen-namen-des-sitzungscookies) + - [Cookie-Sicherheitsoptionen festlegen](#cookie-sicherheitsoptionen-festlegen) + - [Prevent brute-force attacks against authorization](#prevent-brute-force-attacks-against-authorization) + - [Ensure your dependencies are secure](#ensure-your-dependencies-are-secure) + - [Vermeiden Sie andere Schwachstellen](#vermeiden-sie-andere-schwachstellen) + - [Weitere Überlegungen](#weitere-überlegungen) + +## 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](/en/guide/migrating-4). + +Stellen Sie außerdem sicher, dass Sie keine anfälligen Express-Versionen verwenden, die auf der [Seite mit den Sicherheitsupdates](/en/advanced/security-updates) 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://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); +}); +``` + +## "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#how-do-i-handle-404-responses) +and +[writing your own error handler](/en/guide/error-handling#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..850aacf852 --- /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](/en/resources/contributing#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](/en/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/guide/behind-proxies.md b/astro/src/content/docs/de/5x/guide/behind-proxies.md new file mode 100644 index 0000000000..34def6bfcb --- /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()](/en/4x/api#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](/en/api#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](/en/api#req.protocol) abgebildet. +
  • +
  • Als Werte für [req.ip](/en/api#req.ip) und [req.ips](/en/api#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..1d69c7bda7 --- /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](/en/starter/generator) 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#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..6431405f27 --- /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](/en/resources/middleware). + +## 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..47fad43b6f --- /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()`](/en/4x/api#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..1d1d033413 --- /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](/en/4x/api#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 (): 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). + +

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..8f78a06422 --- /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](/en/4x/api#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..5e5c52fbae --- /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](/en/starter/basic-routing). + +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](/en/5x/api#app.METHOD). You can also use [app.all()](/en/5x/api#app.all) to handle all HTTP methods and [app.use()](/en/5x/api#app.use) to +specify middleware as the callback function (See [Using middleware](/en/guide/using-middleware) 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](/en/5x/api#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](/en/guide/migrating-5#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](/en/guide/migrating-5#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](/en/guide/migrating-5#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](/en/guide/using-middleware) 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()](/en/4x/api#res.download) | Gibt eine Eingabeaufforderung zum Herunterladen einer Datei aus. | +| [res.end()](/en/4x/api#res.end) | End the response process. | +| [res.json()](/en/4x/api#res.json) | Sendet eine JSON-Antwort. | +| [res.jsonp()](/en/4x/api#res.jsonp) | Sendet eine JSON-Antwort mit JSONP-Unterstützung. | +| [res.redirect()](/en/4x/api#res.redirect) | Leitet eine Anforderung um. | +| [res.render()](/en/4x/api#res.render) | Render a view template. | +| [res.send()](/en/4x/api#res.send) | Sendet eine Antwort mit unterschiedlichen Typen. | +| [res.sendFile](/en/4x/api#res.sendFile) | Sendet eine Datei als Oktett-Stream. | +| [res.sendStatus()](/en/4x/api#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()](/en/4x/api#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](/en/5x/api#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..f5987bc806 --- /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](/en/5x/api#req) (`req`), the [response object](/en/5x/api#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](/en/5x/api#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](/en/guide/error-handling). + +

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#express.static) serves static assets such as HTML files, images, and so on. +- [express.json](/en/5x/api#express.json) parses incoming requests with JSON payloads. **NOTE: Available with Express 4.16.0+** +- [express.urlencoded](/en/5x/api#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). 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..0e99b8b839 --- /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](/en/starter/generator) 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](/en/4x/api#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..3bc5fbb2fb --- /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](/en/5x/api#req) (`req`), the [response object](/en/5x/api#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.
+ +
+ + +
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`](/en/resources/middleware/cookie-parser) 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](/en/guide/using-middleware). + +

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..633da3f660 --- /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"](/en/starter/hello-world) 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](/en/guide/routing). 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..1ab5b58628 --- /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](/en/guide/using-template-engines). + +## 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](/en/guide/error-handling). + +## 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](/en/4x/api) requires Node.js 0.10 or higher. +- [Express 5.x](/en/5x/api) 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..d6e9f141a6 --- /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](/en/starter/generator) 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](/en/starter/installing) 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..371e979f5f --- /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](/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 +``` + +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..fb36f85ca5 --- /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](/en/5x/api#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](/en/advanced/best-practice-performance#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](/en/5x/api#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](/en/resources/middleware/serve-static). diff --git a/astro/src/content/docs/en/3x/api.md b/astro/src/content/docs/en/3x/api.md new file mode 100644 index 0000000000..53c2135058 --- /dev/null +++ b/astro/src/content/docs/en/3x/api.md @@ -0,0 +1,25 @@ +--- +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 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](/en/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/en/4x/advanced/best-practice-performance.md b/astro/src/content/docs/en/4x/advanced/best-practice-performance.md new file mode 100644 index 0000000000..74ee1b634e --- /dev/null +++ b/astro/src/content/docs/en/4x/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) 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#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#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#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). 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). + +### 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). 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) 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/4x/advanced/best-practice-security.md b/astro/src/content/docs/en/4x/advanced/best-practice-security.md new file mode 100644 index 0000000000..1341252dad --- /dev/null +++ b/astro/src/content/docs/en/4x/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#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](/en/guide/migrating-4) or consider [Commercial Support Options](/en/support#commercial-support-options). + +Also ensure you are not using any of the vulnerable Express versions listed on the [Security updates page](/en/advanced/security-updates). 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#how-do-i-handle-404-responses) +and +[writing your own error handler](/en/guide/error-handling#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/4x/advanced/developing-template-engines.md b/astro/src/content/docs/en/4x/advanced/developing-template-engines.md new file mode 100755 index 0000000000..80e28ba8c9 --- /dev/null +++ b/astro/src/content/docs/en/4x/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/4x/advanced/healthcheck-graceful-shutdown.md b/astro/src/content/docs/en/4x/advanced/healthcheck-graceful-shutdown.md new file mode 100644 index 0000000000..1018345076 --- /dev/null +++ b/astro/src/content/docs/en/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. + +### 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/4x/advanced/security-updates.md b/astro/src/content/docs/en/4x/advanced/security-updates.md new file mode 100755 index 0000000000..72d02e161c --- /dev/null +++ b/astro/src/content/docs/en/4x/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](/en/resources/contributing#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](/en/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/4x/api.md b/astro/src/content/docs/en/4x/api.md new file mode 100644 index 0000000000..0cc0143122 --- /dev/null +++ b/astro/src/content/docs/en/4x/api.md @@ -0,0 +1,8 @@ +--- +title: 4x API Reference +description: API Reference for version 4.x +--- + +# 4.x API + +Some content here... diff --git a/astro/src/content/docs/en/4x/guide/behind-proxies.md b/astro/src/content/docs/en/4x/guide/behind-proxies.md new file mode 100755 index 0000000000..7c217b3e2a --- /dev/null +++ b/astro/src/content/docs/en/4x/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](/en/api#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](/en/api#req.protocol). +
  • +
  • The [req.ip](/en/api#req.ip) and [req.ips](/en/api#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/4x/guide/database-integration.md b/astro/src/content/docs/en/4x/guide/database-integration.md new file mode 100644 index 0000000000..3c653355ad --- /dev/null +++ b/astro/src/content/docs/en/4x/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/4x/guide/debugging.md b/astro/src/content/docs/en/4x/guide/debugging.md new file mode 100755 index 0000000000..dfd3374883 --- /dev/null +++ b/astro/src/content/docs/en/4x/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](/en/starter/generator) 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#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/4x/guide/error-handling.md b/astro/src/content/docs/en/4x/guide/error-handling.md new file mode 100755 index 0000000000..2a8263931f --- /dev/null +++ b/astro/src/content/docs/en/4x/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](/en/resources/middleware). + +## 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/4x/guide/migrating-4.md b/astro/src/content/docs/en/4x/guide/migrating-4.md new file mode 100755 index 0000000000..3e35818153 --- /dev/null +++ b/astro/src/content/docs/en/4x/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](/en/4x/api#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/en/guide/migrating-5.md b/astro/src/content/docs/en/4x/guide/migrating-5.md similarity index 91% rename from en/guide/migrating-5.md rename to astro/src/content/docs/en/4x/guide/migrating-5.md index 4541a282c9..f042d5ffb4 100755 --- a/en/guide/migrating-5.md +++ b/astro/src/content/docs/en/4x/guide/migrating-5.md @@ -1,10 +1,6 @@ --- -layout: page 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 -redirect_from: "/guide/migrating-5.html" --- # Moving to Express 5 @@ -79,7 +75,6 @@ You can find the list of available codemods [here](https://codemod.link/express)
  • res.vary
  • - **Improvements**
      @@ -100,9 +95,10 @@ 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 %} @@ -110,13 +106,13 @@ npx codemod@latest @expressjs/route-del-to-delete ```js // v4 app.del('/user/:id', (req, res) => { - res.send(`DELETE /user/${req.params.id}`) -}) + res.send(`DELETE /user/${req.params.id}`); +}); // v5 app.delete('/user/:id', (req, res) => { - res.send(`DELETE /user/${req.params.id}`) -}) + res.send(`DELETE /user/${req.params.id}`); +}); ```

      app.param(fn)

      @@ -136,9 +132,10 @@ 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 %} @@ -146,28 +143,28 @@ npx codemod@latest @expressjs/pluralize-method-names ```js // v4 app.all('/', (req, res) => { - req.acceptsCharset('utf-8') - req.acceptsEncoding('br') - req.acceptsLanguage('en') + 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') + 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. +This should not affect your code if you follow the Express 4 documentation of [app.param](/en/4x/api#app.param), as it makes no mention of the leading colon.

      req.param(name)

      @@ -176,9 +173,10 @@ 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 %} @@ -186,21 +184,21 @@ npx codemod@latest @expressjs/explicit-request-params ```js // v4 app.post('/user', (req, res) => { - const id = req.param('id') - const body = req.param('body') - const query = req.param('query') + 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 + const id = req.params.id; + const body = req.body; + const query = req.query; // ... -}) +}); ```

      res.json(obj, status)

      @@ -210,9 +208,10 @@ 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 %} @@ -220,13 +219,13 @@ npx codemod@latest @expressjs/status-send-order ```js // v4 app.post('/user', (req, res) => { - res.json({ name: 'Ruben' }, 201) -}) + res.json({ name: 'Ruben' }, 201); +}); // v5 app.post('/user', (req, res) => { - res.status(201).json({ name: 'Ruben' }) -}) + res.status(201).json({ name: 'Ruben' }); +}); ```

      res.jsonp(obj, status)

      @@ -235,17 +234,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) -}) + res.jsonp({ name: 'Ruben' }, 201); +}); // v5 app.post('/user', (req, res) => { - res.status(201).jsonp({ name: 'Ruben' }) -}) + res.status(201).jsonp({ name: 'Ruben' }); +}); ```

      res.redirect(url, status)

      @@ -255,9 +253,10 @@ 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 %} @@ -265,16 +264,15 @@ npx codemod@latest @expressjs/redirect-arg-order ```js // v4 app.get('/user', (req, res) => { - res.redirect('/users', 301) -}) + res.redirect('/users', 301); +}); // v5 app.get('/user', (req, res) => { - res.redirect(301, '/users') -}) + 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,9 +280,10 @@ 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 %} @@ -292,13 +291,13 @@ npx codemod@latest @expressjs/back-redirect-deprecated ```js // v4 app.get('/user', (req, res) => { - res.redirect('back') -}) + res.redirect('back'); +}); // v5 app.get('/user', (req, res) => { - res.redirect(req.get('Referrer') || '/') -}) + res.redirect(req.get('Referrer') || '/'); +}); ```

      res.send(body, status)

      @@ -307,17 +306,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) -}) + res.send({ name: 'Ruben' }, 200); +}); // v5 app.get('/user', (req, res) => { - res.status(200).send({ name: 'Ruben' }) -}) + res.status(200).send({ name: 'Ruben' }); +}); ```

      res.send(status)

      @@ -327,17 +325,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) -}) + res.send(200); +}); // v5 app.get('/user', (req, res) => { - res.sendStatus(200) -}) + res.sendStatus(200); +}); ```

      res.sendfile()

      @@ -356,9 +353,10 @@ 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 %} @@ -366,13 +364,13 @@ npx codemod@latest @expressjs/camelcase-sendfile ```js // v4 app.get('/user', (req, res) => { - res.sendfile('/path/to/file') -}) + res.sendfile('/path/to/file'); +}); // v5 app.get('/user', (req, res) => { - res.sendFile('/path/to/file') -}) + res.sendFile('/path/to/file'); +}); ```

      router.param(fn)

      @@ -389,17 +387,17 @@ Use the [`mime-types` package](https://github.com/jshttp/mime-types) to work wit - 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" +- HTML files (): 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') +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

      @@ -432,13 +430,13 @@ 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') -}) + res.send('ok'); +}); // v5 app.get('/*splat', async (req, res) => { - res.send('ok') -}) + res.send('ok'); +}); ``` {% capture note_wildcard %} @@ -447,9 +445,10 @@ app.get('/*splat', async (req, res) => { ```js // v5 app.get('/{*splat}', async (req, res) => { - res.send('ok') -}) + res.send('ok'); +}); ``` + {% endcapture %} {% include admonitions/note.html content=note_wildcard %} @@ -458,26 +457,29 @@ app.get('/{*splat}', async (req, res) => { ```js // v4 app.get('/:file.:ext?', async (req, res) => { - res.send('ok') -}) + res.send('ok'); +}); // v5 app.get('/:file{.:ext}', async (req, res) => { - res.send('ok') -}) + res.send('ok'); +}); ``` - Regexp characters are not supported. For example: + ```js app.get('/[discussion|page]/:slug', async (req, res) => { - res.status(200).send('ok') -}) + res.status(200).send('ok'); +}); ``` + should be changed to: + ```js app.get(['/discussion/:slug', '/page/:slug'], async (req, res) => { - res.status(200).send('ok') -}) + res.status(200).send('ok'); +}); ``` - Some characters have been reserved to avoid confusion during upgrade (`()[]?+!`), use `\` to escape them. @@ -487,7 +489,7 @@ app.get(['/discussion/:slug', '/page/:slug'], async (req, res) => { 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). +Details of how Express handles errors is covered in the [error handling documentation](/en/guide/error-handling).

      express.urlencoded

      @@ -501,7 +503,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,13 +512,12 @@ 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. @@ -525,10 +526,10 @@ For example: ```js 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

      @@ -554,9 +555,9 @@ Wildcards (e.g., `/*splat`) capture path segments as an array instead of a singl ```js 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:** @@ -567,23 +568,23 @@ In Express 4, unmatched wildcards were empty strings (`''`) and optional `:` par // v4: unmatched wildcard is empty string 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) => { // 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) => { // GET /image - console.dir(req.params) + console.dir(req.params); // => [Object: null prototype] { file: 'image' } -}) +}); ```

      req.query

      diff --git a/astro/src/content/docs/en/4x/guide/overriding-express-api.md b/astro/src/content/docs/en/4x/guide/overriding-express-api.md new file mode 100644 index 0000000000..8f78a06422 --- /dev/null +++ b/astro/src/content/docs/en/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](/en/4x/api#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/4x/guide/routing.md b/astro/src/content/docs/en/4x/guide/routing.md new file mode 100755 index 0000000000..cb7868d359 --- /dev/null +++ b/astro/src/content/docs/en/4x/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](/en/starter/basic-routing). + +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](/en/5x/api#app.METHOD). You can also use [app.all()](/en/5x/api#app.all) to handle all HTTP methods and [app.use()](/en/5x/api#app.use) to +specify middleware as the callback function (See [Using middleware](/en/guide/using-middleware) 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](/en/5x/api#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](/en/guide/migrating-5#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](/en/guide/migrating-5#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](/en/guide/migrating-5#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](/en/guide/using-middleware) 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()](/en/5x/api#res.download) | Prompt a file to be downloaded. | +| [res.end()](/en/5x/api#res.end) | End the response process. | +| [res.json()](/en/5x/api#res.json) | Send a JSON response. | +| [res.jsonp()](/en/5x/api#res.jsonp) | Send a JSON response with JSONP support. | +| [res.redirect()](/en/5x/api#res.redirect) | Redirect a request. | +| [res.render()](/en/5x/api#res.render) | Render a view template. | +| [res.send()](/en/5x/api#res.send) | Send a response of various types. | +| [res.sendFile()](/en/5x/api#res.sendFile) | Send a file as an octet stream. | +| [res.sendStatus()](/en/5x/api#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](/en/5x/api#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](/en/5x/api#app.use). + +```js +const router = express.Router({ mergeParams: true }); +``` diff --git a/astro/src/content/docs/en/4x/guide/using-middleware.md b/astro/src/content/docs/en/4x/guide/using-middleware.md new file mode 100644 index 0000000000..f5e67a0b7d --- /dev/null +++ b/astro/src/content/docs/en/4x/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](/en/5x/api#req) (`req`), the [response object](/en/5x/api#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](/en/5x/api#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](/en/guide/error-handling). + +

      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#express.static) serves static assets such as HTML files, images, and so on. +- [express.json](/en/5x/api#express.json) parses incoming requests with JSON payloads. **NOTE: Available with Express 4.16.0+** +- [express.urlencoded](/en/5x/api#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). diff --git a/astro/src/content/docs/en/4x/guide/using-template-engines.md b/astro/src/content/docs/en/4x/guide/using-template-engines.md new file mode 100755 index 0000000000..a3c0cc1a6f --- /dev/null +++ b/astro/src/content/docs/en/4x/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](/en/starter/generator) 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](/en/4x/api#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/4x/guide/writing-middleware.md b/astro/src/content/docs/en/4x/guide/writing-middleware.md new file mode 100755 index 0000000000..b53215ad49 --- /dev/null +++ b/astro/src/content/docs/en/4x/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](/en/5x/api#req) (`req`), the [response object](/en/5x/api#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: + +
      + + + +
      + + +
      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`](/en/resources/middleware/cookie-parser) 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](/en/guide/using-middleware). + +

      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/4x/starter/basic-routing.md b/astro/src/content/docs/en/4x/starter/basic-routing.md new file mode 100755 index 0000000000..3bc26bc546 --- /dev/null +++ b/astro/src/content/docs/en/4x/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](/en/starter/hello-world). +
      + +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](/en/guide/routing). diff --git a/astro/src/content/docs/en/4x/starter/examples.md b/astro/src/content/docs/en/4x/starter/examples.md new file mode 100755 index 0000000000..a25a6d9834 --- /dev/null +++ b/astro/src/content/docs/en/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/en/4x/starter/faq.md b/astro/src/content/docs/en/4x/starter/faq.md new file mode 100755 index 0000000000..7c82d80c50 --- /dev/null +++ b/astro/src/content/docs/en/4x/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](/en/guide/using-template-engines). + +## 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](/en/guide/error-handling). + +## 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](/en/4x/api) requires Node.js 0.10 or higher. +- [Express 5.x](/en/5x/api) requires Node.js 18 or higher. diff --git a/astro/src/content/docs/en/4x/starter/generator.md b/astro/src/content/docs/en/4x/starter/generator.md new file mode 100755 index 0000000000..4ee5058a18 --- /dev/null +++ b/astro/src/content/docs/en/4x/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/4x/starter/hello-world.md b/astro/src/content/docs/en/4x/starter/hello-world.md new file mode 100755 index 0000000000..97da56d686 --- /dev/null +++ b/astro/src/content/docs/en/4x/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/4x/starter/installing.md b/astro/src/content/docs/en/4x/starter/installing.md new file mode 100755 index 0000000000..74b1d3ef6f --- /dev/null +++ b/astro/src/content/docs/en/4x/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/4x/starter/static-files.md b/astro/src/content/docs/en/4x/starter/static-files.md new file mode 100755 index 0000000000..652de2690e --- /dev/null +++ b/astro/src/content/docs/en/4x/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](/en/5x/api#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](/en/advanced/best-practice-performance#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](/en/5x/api#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](/en/resources/middleware/serve-static). 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..74ee1b634e --- /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) 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#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#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#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). 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). + +### 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). 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) 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..1341252dad --- /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#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](/en/guide/migrating-4) or consider [Commercial Support Options](/en/support#commercial-support-options). + +Also ensure you are not using any of the vulnerable Express versions listed on the [Security updates page](/en/advanced/security-updates). 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#how-do-i-handle-404-responses) +and +[writing your own error handler](/en/guide/error-handling#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..72d02e161c --- /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](/en/resources/contributing#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](/en/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/guide/behind-proxies.md b/astro/src/content/docs/en/5x/guide/behind-proxies.md new file mode 100755 index 0000000000..7c217b3e2a --- /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](/en/api#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](/en/api#req.protocol). +
      • +
      • The [req.ip](/en/api#req.ip) and [req.ips](/en/api#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..dfd3374883 --- /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](/en/starter/generator) 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#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..2a8263931f --- /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](/en/resources/middleware). + +## 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..3e35818153 --- /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](/en/4x/api#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..f042d5ffb4 --- /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](/en/4x/api#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 (): 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). + +

      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..8f78a06422 --- /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](/en/4x/api#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..cb7868d359 --- /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](/en/starter/basic-routing). + +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](/en/5x/api#app.METHOD). You can also use [app.all()](/en/5x/api#app.all) to handle all HTTP methods and [app.use()](/en/5x/api#app.use) to +specify middleware as the callback function (See [Using middleware](/en/guide/using-middleware) 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](/en/5x/api#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](/en/guide/migrating-5#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](/en/guide/migrating-5#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](/en/guide/migrating-5#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](/en/guide/using-middleware) 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()](/en/5x/api#res.download) | Prompt a file to be downloaded. | +| [res.end()](/en/5x/api#res.end) | End the response process. | +| [res.json()](/en/5x/api#res.json) | Send a JSON response. | +| [res.jsonp()](/en/5x/api#res.jsonp) | Send a JSON response with JSONP support. | +| [res.redirect()](/en/5x/api#res.redirect) | Redirect a request. | +| [res.render()](/en/5x/api#res.render) | Render a view template. | +| [res.send()](/en/5x/api#res.send) | Send a response of various types. | +| [res.sendFile()](/en/5x/api#res.sendFile) | Send a file as an octet stream. | +| [res.sendStatus()](/en/5x/api#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](/en/5x/api#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](/en/5x/api#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..f5e67a0b7d --- /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](/en/5x/api#req) (`req`), the [response object](/en/5x/api#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](/en/5x/api#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](/en/guide/error-handling). + +

      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#express.static) serves static assets such as HTML files, images, and so on. +- [express.json](/en/5x/api#express.json) parses incoming requests with JSON payloads. **NOTE: Available with Express 4.16.0+** +- [express.urlencoded](/en/5x/api#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). 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..a3c0cc1a6f --- /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](/en/starter/generator) 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](/en/4x/api#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..b53215ad49 --- /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](/en/5x/api#req) (`req`), the [response object](/en/5x/api#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: + +
      + + + +
      + + +
      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`](/en/resources/middleware/cookie-parser) 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](/en/guide/using-middleware). + +

      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..3bc26bc546 --- /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](/en/starter/hello-world). +
      + +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](/en/guide/routing). 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..7c82d80c50 --- /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](/en/guide/using-template-engines). + +## 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](/en/guide/error-handling). + +## 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](/en/4x/api) requires Node.js 0.10 or higher. +- [Express 5.x](/en/5x/api) 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.mdx b/astro/src/content/docs/en/5x/starter/installing.mdx new file mode 100755 index 0000000000..d989d04a60 --- /dev/null +++ b/astro/src/content/docs/en/5x/starter/installing.mdx @@ -0,0 +1,63 @@ +--- +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. +--- + +import Alert from '@components/primitives/Alert/Alert.astro'; + +# Installing + + + Express 5.x is still in beta. Some APIs may change before the final release. Avoid using it in + production without first reviewing the [migration guide](/en/guide/migrating-5). + + + + Never commit your `node_modules` directory to version control. Add it to your `.gitignore` to + prevent accidentally exposing local paths or platform-specific binaries. + + + + By default with 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. Afterwards, running `npm install` in the app directory will automatically install all + modules in the dependencies list. + + +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 +``` 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..652de2690e --- /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](/en/5x/api#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](/en/advanced/best-practice-performance#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](/en/5x/api#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](/en/resources/middleware/serve-static). 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..f7f2148877 --- /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](/en/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/advanced/best-practice-performance.md b/astro/src/content/docs/es/5x/advanced/best-practice-performance.md new file mode 100644 index 0000000000..e9e4134cee --- /dev/null +++ b/astro/src/content/docs/es/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 reliabilityss + +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) 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#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#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#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). 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). + +### 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). 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) 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/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..dc184b0a08 --- /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](/en/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..5b67aab027 --- /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](/en/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..10b409d997 --- /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](/en/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..a96c0ff8ae --- /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 이상으로 업그레이드할 수 없는 경우, [상업적 지원 옵션](/en/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..03eacd9177 --- /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](/en/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..bf93c23044 --- /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](/en/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..2c4796fc21 --- /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](/en/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/content/resources/de/community.md b/astro/src/content/resources/de/community.md new file mode 100755 index 0000000000..e40d97e421 --- /dev/null +++ b/astro/src/content/resources/de/community.md @@ -0,0 +1,70 @@ +--- +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. +--- + +# 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](/en/resources/middleware) 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](/en/resources/utils). +- [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. + + diff --git a/astro/src/content/resources/de/contributing.md b/astro/src/content/resources/de/contributing.md new file mode 100644 index 0000000000..82c6b8fed7 --- /dev/null +++ b/astro/src/content/resources/de/contributing.md @@ -0,0 +1,482 @@ +--- +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. +--- + +# 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](/en/resources/community/#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) +- 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/resources/de/glossary.md b/astro/src/content/resources/de/glossary.md new file mode 100755 index 0000000000..8b45bf01eb --- /dev/null +++ b/astro/src/content/resources/de/glossary.md @@ -0,0 +1,62 @@ +--- +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. +--- + +# 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](/en/api#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](/en/api#router) in the API reference. diff --git a/astro/src/content/resources/de/middleware/body-parser.md b/astro/src/content/resources/de/middleware/body-parser.md new file mode 100644 index 0000000000..e82649a95c --- /dev/null +++ b/astro/src/content/resources/de/middleware/body-parser.md @@ -0,0 +1,498 @@ +--- +title: Express body-parser middleware +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/resources/de/middleware/compression.md b/astro/src/content/resources/de/middleware/compression.md new file mode 100644 index 0000000000..6ac63fcb7a --- /dev/null +++ b/astro/src/content/resources/de/middleware/compression.md @@ -0,0 +1,314 @@ +--- +title: Express compression middleware +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/resources/de/middleware/cookie-parser.md b/astro/src/content/resources/de/middleware/cookie-parser.md new file mode 100644 index 0000000000..2a59496387 --- /dev/null +++ b/astro/src/content/resources/de/middleware/cookie-parser.md @@ -0,0 +1,124 @@ +--- +title: Express cookie-parser middleware +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/resources/de/middleware/cookie-session.md b/astro/src/content/resources/de/middleware/cookie-session.md new file mode 100644 index 0000000000..2d6d1f885b --- /dev/null +++ b/astro/src/content/resources/de/middleware/cookie-session.md @@ -0,0 +1,124 @@ +--- +title: Express cookie-session middleware +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/resources/de/middleware/cors.md b/astro/src/content/resources/de/middleware/cors.md new file mode 100644 index 0000000000..55d70922cb --- /dev/null +++ b/astro/src/content/resources/de/middleware/cors.md @@ -0,0 +1,261 @@ +--- +title: Express cors middleware +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/resources/de/middleware/errorhandler.md b/astro/src/content/resources/de/middleware/errorhandler.md new file mode 100644 index 0000000000..20df618320 --- /dev/null +++ b/astro/src/content/resources/de/middleware/errorhandler.md @@ -0,0 +1,133 @@ +--- +title: Express errorhandler middleware +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/resources/de/middleware/method-override.md b/astro/src/content/resources/de/middleware/method-override.md new file mode 100644 index 0000000000..7b97ab855e --- /dev/null +++ b/astro/src/content/resources/de/middleware/method-override.md @@ -0,0 +1,187 @@ +--- +title: Express method-override middleware +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/resources/de/middleware/morgan.md b/astro/src/content/resources/de/middleware/morgan.md new file mode 100644 index 0000000000..5319d93d57 --- /dev/null +++ b/astro/src/content/resources/de/middleware/morgan.md @@ -0,0 +1,458 @@ +--- +title: Express morgan middleware +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/resources/de/middleware/multer.md b/astro/src/content/resources/de/middleware/multer.md new file mode 100644 index 0000000000..326786ab3d --- /dev/null +++ b/astro/src/content/resources/de/middleware/multer.md @@ -0,0 +1,352 @@ +--- +title: Express multer middleware +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/resources/de/middleware/overview.md b/astro/src/content/resources/de/middleware/overview.md new file mode 100755 index 0000000000..46217759e7 --- /dev/null +++ b/astro/src/content/resources/de/middleware/overview.md @@ -0,0 +1,40 @@ +--- +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. +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](/en/resources/middleware/body-parser) | Parse HTTP request body. | +| [compression](/en/resources/middleware/compression) | Compress HTTP responses. | +| [cookie-parser](/en/resources/middleware/cookie-parser) | Parse cookie header and populate `req.cookies`. See also [cookies](https://github.com/jed/cookies). | +| [cookie-session](/en/resources/middleware/cookie-session) | Establish cookie-based sessions. | +| [cors](/en/resources/middleware/cors) | Enable cross-origin resource sharing (CORS) with various options. | +| [errorhandler](/en/resources/middleware/errorhandler) | Development error-handling/debugging. | +| [method-override](/en/resources/middleware/method-override) | Override HTTP methods using header. | +| [morgan](/en/resources/middleware/morgan) | HTTP request logger. | +| [multer](/en/resources/middleware/multer) | Handle multi-part form data. | +| [response-time](/en/resources/middleware/response-time) | Record HTTP response time. | +| [serve-favicon](/en/resources/middleware/serve-favicon) | Serve a favicon. | +| [serve-index](/en/resources/middleware/serve-index) | Serve directory listing for a given path. | +| [serve-static](/en/resources/middleware/serve-static) | Serve static files. | +| [session](/en/resources/middleware/session) | Establish server-based sessions (development only). | +| [timeout](/en/resources/middleware/timeout) | Set a timeout perioHTTP request processing. | +| [vhost](/en/resources/middleware/vhost) | 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/resources/de/middleware/response-time.md b/astro/src/content/resources/de/middleware/response-time.md new file mode 100644 index 0000000000..f911f480f5 --- /dev/null +++ b/astro/src/content/resources/de/middleware/response-time.md @@ -0,0 +1,314 @@ +--- +title: Express response-time middleware +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/resources/de/middleware/serve-favicon.md b/astro/src/content/resources/de/middleware/serve-favicon.md new file mode 100644 index 0000000000..7a77865c6b --- /dev/null +++ b/astro/src/content/resources/de/middleware/serve-favicon.md @@ -0,0 +1,156 @@ +--- +title: Express serve-favicon middleware +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/resources/de/middleware/serve-index.md b/astro/src/content/resources/de/middleware/serve-index.md new file mode 100644 index 0000000000..da03cf94b2 --- /dev/null +++ b/astro/src/content/resources/de/middleware/serve-index.md @@ -0,0 +1,156 @@ +--- +title: Express serve-index middleware +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/resources/de/middleware/serve-static.md b/astro/src/content/resources/de/middleware/serve-static.md new file mode 100644 index 0000000000..b048165d7b --- /dev/null +++ b/astro/src/content/resources/de/middleware/serve-static.md @@ -0,0 +1,260 @@ +--- +title: Express serve-static middleware +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/resources/de/middleware/session.md b/astro/src/content/resources/de/middleware/session.md new file mode 100644 index 0000000000..90f3837a42 --- /dev/null +++ b/astro/src/content/resources/de/middleware/session.md @@ -0,0 +1,1046 @@ +--- +title: Express session middleware +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/resources/de/middleware/timeout.md b/astro/src/content/resources/de/middleware/timeout.md new file mode 100644 index 0000000000..f6057aedfd --- /dev/null +++ b/astro/src/content/resources/de/middleware/timeout.md @@ -0,0 +1,176 @@ +--- +title: Express timeout middleware +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/resources/de/middleware/vhost.md b/astro/src/content/resources/de/middleware/vhost.md new file mode 100644 index 0000000000..72f49d7f93 --- /dev/null +++ b/astro/src/content/resources/de/middleware/vhost.md @@ -0,0 +1,174 @@ +--- +title: Express vhost middleware +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/resources/de/utils.md b/astro/src/content/resources/de/utils.md new file mode 100644 index 0000000000..546b2f09b4 --- /dev/null +++ b/astro/src/content/resources/de/utils.md @@ -0,0 +1,22 @@ +--- +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. +--- + +## 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](https://github.com/jshttp). diff --git a/astro/src/content/resources/en/community.md b/astro/src/content/resources/en/community.md new file mode 100755 index 0000000000..e40d97e421 --- /dev/null +++ b/astro/src/content/resources/en/community.md @@ -0,0 +1,70 @@ +--- +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. +--- + +# 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](/en/resources/middleware) 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](/en/resources/utils). +- [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. + + diff --git a/astro/src/content/resources/en/contributing.md b/astro/src/content/resources/en/contributing.md new file mode 100644 index 0000000000..82c6b8fed7 --- /dev/null +++ b/astro/src/content/resources/en/contributing.md @@ -0,0 +1,482 @@ +--- +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. +--- + +# 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](/en/resources/community/#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) +- 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/resources/en/glossary.md b/astro/src/content/resources/en/glossary.md new file mode 100755 index 0000000000..8b45bf01eb --- /dev/null +++ b/astro/src/content/resources/en/glossary.md @@ -0,0 +1,62 @@ +--- +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. +--- + +# 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](/en/api#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](/en/api#router) in the API reference. diff --git a/astro/src/content/resources/en/middleware/body-parser.md b/astro/src/content/resources/en/middleware/body-parser.md new file mode 100644 index 0000000000..e82649a95c --- /dev/null +++ b/astro/src/content/resources/en/middleware/body-parser.md @@ -0,0 +1,498 @@ +--- +title: Express body-parser middleware +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/resources/en/middleware/compression.md b/astro/src/content/resources/en/middleware/compression.md new file mode 100644 index 0000000000..6ac63fcb7a --- /dev/null +++ b/astro/src/content/resources/en/middleware/compression.md @@ -0,0 +1,314 @@ +--- +title: Express compression middleware +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/resources/en/middleware/cookie-parser.md b/astro/src/content/resources/en/middleware/cookie-parser.md new file mode 100644 index 0000000000..2a59496387 --- /dev/null +++ b/astro/src/content/resources/en/middleware/cookie-parser.md @@ -0,0 +1,124 @@ +--- +title: Express cookie-parser middleware +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/resources/en/middleware/cookie-session.md b/astro/src/content/resources/en/middleware/cookie-session.md new file mode 100644 index 0000000000..2d6d1f885b --- /dev/null +++ b/astro/src/content/resources/en/middleware/cookie-session.md @@ -0,0 +1,124 @@ +--- +title: Express cookie-session middleware +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/resources/en/middleware/cors.md b/astro/src/content/resources/en/middleware/cors.md new file mode 100644 index 0000000000..55d70922cb --- /dev/null +++ b/astro/src/content/resources/en/middleware/cors.md @@ -0,0 +1,261 @@ +--- +title: Express cors middleware +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/resources/en/middleware/errorhandler.md b/astro/src/content/resources/en/middleware/errorhandler.md new file mode 100644 index 0000000000..20df618320 --- /dev/null +++ b/astro/src/content/resources/en/middleware/errorhandler.md @@ -0,0 +1,133 @@ +--- +title: Express errorhandler middleware +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/resources/en/middleware/method-override.md b/astro/src/content/resources/en/middleware/method-override.md new file mode 100644 index 0000000000..7b97ab855e --- /dev/null +++ b/astro/src/content/resources/en/middleware/method-override.md @@ -0,0 +1,187 @@ +--- +title: Express method-override middleware +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/resources/en/middleware/morgan.md b/astro/src/content/resources/en/middleware/morgan.md new file mode 100644 index 0000000000..5319d93d57 --- /dev/null +++ b/astro/src/content/resources/en/middleware/morgan.md @@ -0,0 +1,458 @@ +--- +title: Express morgan middleware +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/resources/en/middleware/multer.md b/astro/src/content/resources/en/middleware/multer.md new file mode 100644 index 0000000000..326786ab3d --- /dev/null +++ b/astro/src/content/resources/en/middleware/multer.md @@ -0,0 +1,352 @@ +--- +title: Express multer middleware +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/resources/en/middleware/overview.md b/astro/src/content/resources/en/middleware/overview.md new file mode 100755 index 0000000000..46217759e7 --- /dev/null +++ b/astro/src/content/resources/en/middleware/overview.md @@ -0,0 +1,40 @@ +--- +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. +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](/en/resources/middleware/body-parser) | Parse HTTP request body. | +| [compression](/en/resources/middleware/compression) | Compress HTTP responses. | +| [cookie-parser](/en/resources/middleware/cookie-parser) | Parse cookie header and populate `req.cookies`. See also [cookies](https://github.com/jed/cookies). | +| [cookie-session](/en/resources/middleware/cookie-session) | Establish cookie-based sessions. | +| [cors](/en/resources/middleware/cors) | Enable cross-origin resource sharing (CORS) with various options. | +| [errorhandler](/en/resources/middleware/errorhandler) | Development error-handling/debugging. | +| [method-override](/en/resources/middleware/method-override) | Override HTTP methods using header. | +| [morgan](/en/resources/middleware/morgan) | HTTP request logger. | +| [multer](/en/resources/middleware/multer) | Handle multi-part form data. | +| [response-time](/en/resources/middleware/response-time) | Record HTTP response time. | +| [serve-favicon](/en/resources/middleware/serve-favicon) | Serve a favicon. | +| [serve-index](/en/resources/middleware/serve-index) | Serve directory listing for a given path. | +| [serve-static](/en/resources/middleware/serve-static) | Serve static files. | +| [session](/en/resources/middleware/session) | Establish server-based sessions (development only). | +| [timeout](/en/resources/middleware/timeout) | Set a timeout perioHTTP request processing. | +| [vhost](/en/resources/middleware/vhost) | 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/resources/en/middleware/response-time.md b/astro/src/content/resources/en/middleware/response-time.md new file mode 100644 index 0000000000..f911f480f5 --- /dev/null +++ b/astro/src/content/resources/en/middleware/response-time.md @@ -0,0 +1,314 @@ +--- +title: Express response-time middleware +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/resources/en/middleware/serve-favicon.md b/astro/src/content/resources/en/middleware/serve-favicon.md new file mode 100644 index 0000000000..7a77865c6b --- /dev/null +++ b/astro/src/content/resources/en/middleware/serve-favicon.md @@ -0,0 +1,156 @@ +--- +title: Express serve-favicon middleware +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/resources/en/middleware/serve-index.md b/astro/src/content/resources/en/middleware/serve-index.md new file mode 100644 index 0000000000..da03cf94b2 --- /dev/null +++ b/astro/src/content/resources/en/middleware/serve-index.md @@ -0,0 +1,156 @@ +--- +title: Express serve-index middleware +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/resources/en/middleware/serve-static.md b/astro/src/content/resources/en/middleware/serve-static.md new file mode 100644 index 0000000000..b048165d7b --- /dev/null +++ b/astro/src/content/resources/en/middleware/serve-static.md @@ -0,0 +1,260 @@ +--- +title: Express serve-static middleware +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/resources/en/middleware/session.md b/astro/src/content/resources/en/middleware/session.md new file mode 100644 index 0000000000..90f3837a42 --- /dev/null +++ b/astro/src/content/resources/en/middleware/session.md @@ -0,0 +1,1046 @@ +--- +title: Express session middleware +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/resources/en/middleware/timeout.md b/astro/src/content/resources/en/middleware/timeout.md new file mode 100644 index 0000000000..f6057aedfd --- /dev/null +++ b/astro/src/content/resources/en/middleware/timeout.md @@ -0,0 +1,176 @@ +--- +title: Express timeout middleware +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/resources/en/middleware/vhost.md b/astro/src/content/resources/en/middleware/vhost.md new file mode 100644 index 0000000000..72f49d7f93 --- /dev/null +++ b/astro/src/content/resources/en/middleware/vhost.md @@ -0,0 +1,174 @@ +--- +title: Express vhost middleware +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/resources/en/utils.md b/astro/src/content/resources/en/utils.md new file mode 100644 index 0000000000..546b2f09b4 --- /dev/null +++ b/astro/src/content/resources/en/utils.md @@ -0,0 +1,22 @@ +--- +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. +--- + +## 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](https://github.com/jshttp). diff --git a/astro/src/content/resources/es/community.md b/astro/src/content/resources/es/community.md new file mode 100755 index 0000000000..e40d97e421 --- /dev/null +++ b/astro/src/content/resources/es/community.md @@ -0,0 +1,70 @@ +--- +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. +--- + +# 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](/en/resources/middleware) 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](/en/resources/utils). +- [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. + + diff --git a/astro/src/content/resources/es/contributing.md b/astro/src/content/resources/es/contributing.md new file mode 100644 index 0000000000..96c92467ee --- /dev/null +++ b/astro/src/content/resources/es/contributing.md @@ -0,0 +1,482 @@ +--- +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. +--- + +# 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](/en/resources/community#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) +- 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/resources/es/glossary.md b/astro/src/content/resources/es/glossary.md new file mode 100755 index 0000000000..8b45bf01eb --- /dev/null +++ b/astro/src/content/resources/es/glossary.md @@ -0,0 +1,62 @@ +--- +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. +--- + +# 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](/en/api#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](/en/api#router) in the API reference. diff --git a/astro/src/content/resources/es/middleware/body-parser.md b/astro/src/content/resources/es/middleware/body-parser.md new file mode 100644 index 0000000000..e82649a95c --- /dev/null +++ b/astro/src/content/resources/es/middleware/body-parser.md @@ -0,0 +1,498 @@ +--- +title: Express body-parser middleware +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/resources/es/middleware/compression.md b/astro/src/content/resources/es/middleware/compression.md new file mode 100644 index 0000000000..6ac63fcb7a --- /dev/null +++ b/astro/src/content/resources/es/middleware/compression.md @@ -0,0 +1,314 @@ +--- +title: Express compression middleware +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/resources/es/middleware/cookie-parser.md b/astro/src/content/resources/es/middleware/cookie-parser.md new file mode 100644 index 0000000000..2a59496387 --- /dev/null +++ b/astro/src/content/resources/es/middleware/cookie-parser.md @@ -0,0 +1,124 @@ +--- +title: Express cookie-parser middleware +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/resources/es/middleware/cookie-session.md b/astro/src/content/resources/es/middleware/cookie-session.md new file mode 100644 index 0000000000..2d6d1f885b --- /dev/null +++ b/astro/src/content/resources/es/middleware/cookie-session.md @@ -0,0 +1,124 @@ +--- +title: Express cookie-session middleware +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/resources/es/middleware/cors.md b/astro/src/content/resources/es/middleware/cors.md new file mode 100644 index 0000000000..55d70922cb --- /dev/null +++ b/astro/src/content/resources/es/middleware/cors.md @@ -0,0 +1,261 @@ +--- +title: Express cors middleware +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/resources/es/middleware/errorhandler.md b/astro/src/content/resources/es/middleware/errorhandler.md new file mode 100644 index 0000000000..20df618320 --- /dev/null +++ b/astro/src/content/resources/es/middleware/errorhandler.md @@ -0,0 +1,133 @@ +--- +title: Express errorhandler middleware +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/resources/es/middleware/method-override.md b/astro/src/content/resources/es/middleware/method-override.md new file mode 100644 index 0000000000..7b97ab855e --- /dev/null +++ b/astro/src/content/resources/es/middleware/method-override.md @@ -0,0 +1,187 @@ +--- +title: Express method-override middleware +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/resources/es/middleware/morgan.md b/astro/src/content/resources/es/middleware/morgan.md new file mode 100644 index 0000000000..5319d93d57 --- /dev/null +++ b/astro/src/content/resources/es/middleware/morgan.md @@ -0,0 +1,458 @@ +--- +title: Express morgan middleware +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/resources/es/middleware/multer.md b/astro/src/content/resources/es/middleware/multer.md new file mode 100644 index 0000000000..326786ab3d --- /dev/null +++ b/astro/src/content/resources/es/middleware/multer.md @@ -0,0 +1,352 @@ +--- +title: Express multer middleware +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/resources/es/middleware/overview.md b/astro/src/content/resources/es/middleware/overview.md new file mode 100755 index 0000000000..46217759e7 --- /dev/null +++ b/astro/src/content/resources/es/middleware/overview.md @@ -0,0 +1,40 @@ +--- +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. +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](/en/resources/middleware/body-parser) | Parse HTTP request body. | +| [compression](/en/resources/middleware/compression) | Compress HTTP responses. | +| [cookie-parser](/en/resources/middleware/cookie-parser) | Parse cookie header and populate `req.cookies`. See also [cookies](https://github.com/jed/cookies). | +| [cookie-session](/en/resources/middleware/cookie-session) | Establish cookie-based sessions. | +| [cors](/en/resources/middleware/cors) | Enable cross-origin resource sharing (CORS) with various options. | +| [errorhandler](/en/resources/middleware/errorhandler) | Development error-handling/debugging. | +| [method-override](/en/resources/middleware/method-override) | Override HTTP methods using header. | +| [morgan](/en/resources/middleware/morgan) | HTTP request logger. | +| [multer](/en/resources/middleware/multer) | Handle multi-part form data. | +| [response-time](/en/resources/middleware/response-time) | Record HTTP response time. | +| [serve-favicon](/en/resources/middleware/serve-favicon) | Serve a favicon. | +| [serve-index](/en/resources/middleware/serve-index) | Serve directory listing for a given path. | +| [serve-static](/en/resources/middleware/serve-static) | Serve static files. | +| [session](/en/resources/middleware/session) | Establish server-based sessions (development only). | +| [timeout](/en/resources/middleware/timeout) | Set a timeout perioHTTP request processing. | +| [vhost](/en/resources/middleware/vhost) | 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/resources/es/middleware/response-time.md b/astro/src/content/resources/es/middleware/response-time.md new file mode 100644 index 0000000000..f911f480f5 --- /dev/null +++ b/astro/src/content/resources/es/middleware/response-time.md @@ -0,0 +1,314 @@ +--- +title: Express response-time middleware +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/resources/es/middleware/serve-favicon.md b/astro/src/content/resources/es/middleware/serve-favicon.md new file mode 100644 index 0000000000..7a77865c6b --- /dev/null +++ b/astro/src/content/resources/es/middleware/serve-favicon.md @@ -0,0 +1,156 @@ +--- +title: Express serve-favicon middleware +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/resources/es/middleware/serve-index.md b/astro/src/content/resources/es/middleware/serve-index.md new file mode 100644 index 0000000000..da03cf94b2 --- /dev/null +++ b/astro/src/content/resources/es/middleware/serve-index.md @@ -0,0 +1,156 @@ +--- +title: Express serve-index middleware +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/resources/es/middleware/serve-static.md b/astro/src/content/resources/es/middleware/serve-static.md new file mode 100644 index 0000000000..b048165d7b --- /dev/null +++ b/astro/src/content/resources/es/middleware/serve-static.md @@ -0,0 +1,260 @@ +--- +title: Express serve-static middleware +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/resources/es/middleware/session.md b/astro/src/content/resources/es/middleware/session.md new file mode 100644 index 0000000000..90f3837a42 --- /dev/null +++ b/astro/src/content/resources/es/middleware/session.md @@ -0,0 +1,1046 @@ +--- +title: Express session middleware +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/resources/es/middleware/timeout.md b/astro/src/content/resources/es/middleware/timeout.md new file mode 100644 index 0000000000..f6057aedfd --- /dev/null +++ b/astro/src/content/resources/es/middleware/timeout.md @@ -0,0 +1,176 @@ +--- +title: Express timeout middleware +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/resources/es/middleware/vhost.md b/astro/src/content/resources/es/middleware/vhost.md new file mode 100644 index 0000000000..72f49d7f93 --- /dev/null +++ b/astro/src/content/resources/es/middleware/vhost.md @@ -0,0 +1,174 @@ +--- +title: Express vhost middleware +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/resources/es/utils.md b/astro/src/content/resources/es/utils.md new file mode 100644 index 0000000000..546b2f09b4 --- /dev/null +++ b/astro/src/content/resources/es/utils.md @@ -0,0 +1,22 @@ +--- +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. +--- + +## 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](https://github.com/jshttp). diff --git a/astro/src/content/resources/fr/community.md b/astro/src/content/resources/fr/community.md new file mode 100755 index 0000000000..e40d97e421 --- /dev/null +++ b/astro/src/content/resources/fr/community.md @@ -0,0 +1,70 @@ +--- +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. +--- + +# 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](/en/resources/middleware) 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](/en/resources/utils). +- [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. + + diff --git a/astro/src/content/resources/fr/contributing.md b/astro/src/content/resources/fr/contributing.md new file mode 100644 index 0000000000..82c6b8fed7 --- /dev/null +++ b/astro/src/content/resources/fr/contributing.md @@ -0,0 +1,482 @@ +--- +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. +--- + +# 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](/en/resources/community/#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) +- 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/resources/fr/glossary.md b/astro/src/content/resources/fr/glossary.md new file mode 100755 index 0000000000..8b45bf01eb --- /dev/null +++ b/astro/src/content/resources/fr/glossary.md @@ -0,0 +1,62 @@ +--- +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. +--- + +# 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](/en/api#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](/en/api#router) in the API reference. diff --git a/astro/src/content/resources/fr/middleware/body-parser.md b/astro/src/content/resources/fr/middleware/body-parser.md new file mode 100644 index 0000000000..e82649a95c --- /dev/null +++ b/astro/src/content/resources/fr/middleware/body-parser.md @@ -0,0 +1,498 @@ +--- +title: Express body-parser middleware +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/resources/fr/middleware/compression.md b/astro/src/content/resources/fr/middleware/compression.md new file mode 100644 index 0000000000..6ac63fcb7a --- /dev/null +++ b/astro/src/content/resources/fr/middleware/compression.md @@ -0,0 +1,314 @@ +--- +title: Express compression middleware +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/resources/fr/middleware/cookie-parser.md b/astro/src/content/resources/fr/middleware/cookie-parser.md new file mode 100644 index 0000000000..2a59496387 --- /dev/null +++ b/astro/src/content/resources/fr/middleware/cookie-parser.md @@ -0,0 +1,124 @@ +--- +title: Express cookie-parser middleware +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/resources/fr/middleware/cookie-session.md b/astro/src/content/resources/fr/middleware/cookie-session.md new file mode 100644 index 0000000000..2d6d1f885b --- /dev/null +++ b/astro/src/content/resources/fr/middleware/cookie-session.md @@ -0,0 +1,124 @@ +--- +title: Express cookie-session middleware +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/resources/fr/middleware/cors.md b/astro/src/content/resources/fr/middleware/cors.md new file mode 100644 index 0000000000..55d70922cb --- /dev/null +++ b/astro/src/content/resources/fr/middleware/cors.md @@ -0,0 +1,261 @@ +--- +title: Express cors middleware +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/resources/fr/middleware/errorhandler.md b/astro/src/content/resources/fr/middleware/errorhandler.md new file mode 100644 index 0000000000..20df618320 --- /dev/null +++ b/astro/src/content/resources/fr/middleware/errorhandler.md @@ -0,0 +1,133 @@ +--- +title: Express errorhandler middleware +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/resources/fr/middleware/method-override.md b/astro/src/content/resources/fr/middleware/method-override.md new file mode 100644 index 0000000000..7b97ab855e --- /dev/null +++ b/astro/src/content/resources/fr/middleware/method-override.md @@ -0,0 +1,187 @@ +--- +title: Express method-override middleware +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/resources/fr/middleware/morgan.md b/astro/src/content/resources/fr/middleware/morgan.md new file mode 100644 index 0000000000..5319d93d57 --- /dev/null +++ b/astro/src/content/resources/fr/middleware/morgan.md @@ -0,0 +1,458 @@ +--- +title: Express morgan middleware +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/resources/fr/middleware/multer.md b/astro/src/content/resources/fr/middleware/multer.md new file mode 100644 index 0000000000..326786ab3d --- /dev/null +++ b/astro/src/content/resources/fr/middleware/multer.md @@ -0,0 +1,352 @@ +--- +title: Express multer middleware +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/resources/fr/middleware/overview.md b/astro/src/content/resources/fr/middleware/overview.md new file mode 100755 index 0000000000..46217759e7 --- /dev/null +++ b/astro/src/content/resources/fr/middleware/overview.md @@ -0,0 +1,40 @@ +--- +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. +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](/en/resources/middleware/body-parser) | Parse HTTP request body. | +| [compression](/en/resources/middleware/compression) | Compress HTTP responses. | +| [cookie-parser](/en/resources/middleware/cookie-parser) | Parse cookie header and populate `req.cookies`. See also [cookies](https://github.com/jed/cookies). | +| [cookie-session](/en/resources/middleware/cookie-session) | Establish cookie-based sessions. | +| [cors](/en/resources/middleware/cors) | Enable cross-origin resource sharing (CORS) with various options. | +| [errorhandler](/en/resources/middleware/errorhandler) | Development error-handling/debugging. | +| [method-override](/en/resources/middleware/method-override) | Override HTTP methods using header. | +| [morgan](/en/resources/middleware/morgan) | HTTP request logger. | +| [multer](/en/resources/middleware/multer) | Handle multi-part form data. | +| [response-time](/en/resources/middleware/response-time) | Record HTTP response time. | +| [serve-favicon](/en/resources/middleware/serve-favicon) | Serve a favicon. | +| [serve-index](/en/resources/middleware/serve-index) | Serve directory listing for a given path. | +| [serve-static](/en/resources/middleware/serve-static) | Serve static files. | +| [session](/en/resources/middleware/session) | Establish server-based sessions (development only). | +| [timeout](/en/resources/middleware/timeout) | Set a timeout perioHTTP request processing. | +| [vhost](/en/resources/middleware/vhost) | 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/resources/fr/middleware/response-time.md b/astro/src/content/resources/fr/middleware/response-time.md new file mode 100644 index 0000000000..f911f480f5 --- /dev/null +++ b/astro/src/content/resources/fr/middleware/response-time.md @@ -0,0 +1,314 @@ +--- +title: Express response-time middleware +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/resources/fr/middleware/serve-favicon.md b/astro/src/content/resources/fr/middleware/serve-favicon.md new file mode 100644 index 0000000000..7a77865c6b --- /dev/null +++ b/astro/src/content/resources/fr/middleware/serve-favicon.md @@ -0,0 +1,156 @@ +--- +title: Express serve-favicon middleware +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/resources/fr/middleware/serve-index.md b/astro/src/content/resources/fr/middleware/serve-index.md new file mode 100644 index 0000000000..da03cf94b2 --- /dev/null +++ b/astro/src/content/resources/fr/middleware/serve-index.md @@ -0,0 +1,156 @@ +--- +title: Express serve-index middleware +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/resources/fr/middleware/serve-static.md b/astro/src/content/resources/fr/middleware/serve-static.md new file mode 100644 index 0000000000..b048165d7b --- /dev/null +++ b/astro/src/content/resources/fr/middleware/serve-static.md @@ -0,0 +1,260 @@ +--- +title: Express serve-static middleware +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/resources/fr/middleware/session.md b/astro/src/content/resources/fr/middleware/session.md new file mode 100644 index 0000000000..90f3837a42 --- /dev/null +++ b/astro/src/content/resources/fr/middleware/session.md @@ -0,0 +1,1046 @@ +--- +title: Express session middleware +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/resources/fr/middleware/timeout.md b/astro/src/content/resources/fr/middleware/timeout.md new file mode 100644 index 0000000000..f6057aedfd --- /dev/null +++ b/astro/src/content/resources/fr/middleware/timeout.md @@ -0,0 +1,176 @@ +--- +title: Express timeout middleware +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/resources/fr/middleware/vhost.md b/astro/src/content/resources/fr/middleware/vhost.md new file mode 100644 index 0000000000..72f49d7f93 --- /dev/null +++ b/astro/src/content/resources/fr/middleware/vhost.md @@ -0,0 +1,174 @@ +--- +title: Express vhost middleware +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/resources/fr/utils.md b/astro/src/content/resources/fr/utils.md new file mode 100644 index 0000000000..546b2f09b4 --- /dev/null +++ b/astro/src/content/resources/fr/utils.md @@ -0,0 +1,22 @@ +--- +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. +--- + +## 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](https://github.com/jshttp). diff --git a/astro/src/content/resources/it/community.md b/astro/src/content/resources/it/community.md new file mode 100755 index 0000000000..2ba8985943 --- /dev/null +++ b/astro/src/content/resources/it/community.md @@ -0,0 +1,69 @@ +--- +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. +--- + +# 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](/en/resources/middleware) 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](/en/resources/utils). +- [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. +<-- TODO: add logos --> diff --git a/astro/src/content/resources/it/contributing.md b/astro/src/content/resources/it/contributing.md new file mode 100644 index 0000000000..82c6b8fed7 --- /dev/null +++ b/astro/src/content/resources/it/contributing.md @@ -0,0 +1,482 @@ +--- +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. +--- + +# 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](/en/resources/community/#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) +- 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/resources/it/glossary.md b/astro/src/content/resources/it/glossary.md new file mode 100755 index 0000000000..8b45bf01eb --- /dev/null +++ b/astro/src/content/resources/it/glossary.md @@ -0,0 +1,62 @@ +--- +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. +--- + +# 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](/en/api#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](/en/api#router) in the API reference. diff --git a/astro/src/content/resources/it/middleware/body-parser.md b/astro/src/content/resources/it/middleware/body-parser.md new file mode 100644 index 0000000000..e82649a95c --- /dev/null +++ b/astro/src/content/resources/it/middleware/body-parser.md @@ -0,0 +1,498 @@ +--- +title: Express body-parser middleware +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/resources/it/middleware/compression.md b/astro/src/content/resources/it/middleware/compression.md new file mode 100644 index 0000000000..6ac63fcb7a --- /dev/null +++ b/astro/src/content/resources/it/middleware/compression.md @@ -0,0 +1,314 @@ +--- +title: Express compression middleware +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/resources/it/middleware/cookie-parser.md b/astro/src/content/resources/it/middleware/cookie-parser.md new file mode 100644 index 0000000000..2a59496387 --- /dev/null +++ b/astro/src/content/resources/it/middleware/cookie-parser.md @@ -0,0 +1,124 @@ +--- +title: Express cookie-parser middleware +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/resources/it/middleware/cookie-session.md b/astro/src/content/resources/it/middleware/cookie-session.md new file mode 100644 index 0000000000..2d6d1f885b --- /dev/null +++ b/astro/src/content/resources/it/middleware/cookie-session.md @@ -0,0 +1,124 @@ +--- +title: Express cookie-session middleware +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/resources/it/middleware/cors.md b/astro/src/content/resources/it/middleware/cors.md new file mode 100644 index 0000000000..55d70922cb --- /dev/null +++ b/astro/src/content/resources/it/middleware/cors.md @@ -0,0 +1,261 @@ +--- +title: Express cors middleware +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/resources/it/middleware/errorhandler.md b/astro/src/content/resources/it/middleware/errorhandler.md new file mode 100644 index 0000000000..20df618320 --- /dev/null +++ b/astro/src/content/resources/it/middleware/errorhandler.md @@ -0,0 +1,133 @@ +--- +title: Express errorhandler middleware +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/resources/it/middleware/method-override.md b/astro/src/content/resources/it/middleware/method-override.md new file mode 100644 index 0000000000..7b97ab855e --- /dev/null +++ b/astro/src/content/resources/it/middleware/method-override.md @@ -0,0 +1,187 @@ +--- +title: Express method-override middleware +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/resources/it/middleware/morgan.md b/astro/src/content/resources/it/middleware/morgan.md new file mode 100644 index 0000000000..5319d93d57 --- /dev/null +++ b/astro/src/content/resources/it/middleware/morgan.md @@ -0,0 +1,458 @@ +--- +title: Express morgan middleware +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/resources/it/middleware/multer.md b/astro/src/content/resources/it/middleware/multer.md new file mode 100644 index 0000000000..326786ab3d --- /dev/null +++ b/astro/src/content/resources/it/middleware/multer.md @@ -0,0 +1,352 @@ +--- +title: Express multer middleware +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/resources/it/middleware/overview.md b/astro/src/content/resources/it/middleware/overview.md new file mode 100755 index 0000000000..46217759e7 --- /dev/null +++ b/astro/src/content/resources/it/middleware/overview.md @@ -0,0 +1,40 @@ +--- +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. +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](/en/resources/middleware/body-parser) | Parse HTTP request body. | +| [compression](/en/resources/middleware/compression) | Compress HTTP responses. | +| [cookie-parser](/en/resources/middleware/cookie-parser) | Parse cookie header and populate `req.cookies`. See also [cookies](https://github.com/jed/cookies). | +| [cookie-session](/en/resources/middleware/cookie-session) | Establish cookie-based sessions. | +| [cors](/en/resources/middleware/cors) | Enable cross-origin resource sharing (CORS) with various options. | +| [errorhandler](/en/resources/middleware/errorhandler) | Development error-handling/debugging. | +| [method-override](/en/resources/middleware/method-override) | Override HTTP methods using header. | +| [morgan](/en/resources/middleware/morgan) | HTTP request logger. | +| [multer](/en/resources/middleware/multer) | Handle multi-part form data. | +| [response-time](/en/resources/middleware/response-time) | Record HTTP response time. | +| [serve-favicon](/en/resources/middleware/serve-favicon) | Serve a favicon. | +| [serve-index](/en/resources/middleware/serve-index) | Serve directory listing for a given path. | +| [serve-static](/en/resources/middleware/serve-static) | Serve static files. | +| [session](/en/resources/middleware/session) | Establish server-based sessions (development only). | +| [timeout](/en/resources/middleware/timeout) | Set a timeout perioHTTP request processing. | +| [vhost](/en/resources/middleware/vhost) | 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/resources/it/middleware/response-time.md b/astro/src/content/resources/it/middleware/response-time.md new file mode 100644 index 0000000000..f911f480f5 --- /dev/null +++ b/astro/src/content/resources/it/middleware/response-time.md @@ -0,0 +1,314 @@ +--- +title: Express response-time middleware +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/resources/it/middleware/serve-favicon.md b/astro/src/content/resources/it/middleware/serve-favicon.md new file mode 100644 index 0000000000..7a77865c6b --- /dev/null +++ b/astro/src/content/resources/it/middleware/serve-favicon.md @@ -0,0 +1,156 @@ +--- +title: Express serve-favicon middleware +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/resources/it/middleware/serve-index.md b/astro/src/content/resources/it/middleware/serve-index.md new file mode 100644 index 0000000000..da03cf94b2 --- /dev/null +++ b/astro/src/content/resources/it/middleware/serve-index.md @@ -0,0 +1,156 @@ +--- +title: Express serve-index middleware +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/resources/it/middleware/serve-static.md b/astro/src/content/resources/it/middleware/serve-static.md new file mode 100644 index 0000000000..b048165d7b --- /dev/null +++ b/astro/src/content/resources/it/middleware/serve-static.md @@ -0,0 +1,260 @@ +--- +title: Express serve-static middleware +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/resources/it/middleware/session.md b/astro/src/content/resources/it/middleware/session.md new file mode 100644 index 0000000000..90f3837a42 --- /dev/null +++ b/astro/src/content/resources/it/middleware/session.md @@ -0,0 +1,1046 @@ +--- +title: Express session middleware +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/resources/it/middleware/timeout.md b/astro/src/content/resources/it/middleware/timeout.md new file mode 100644 index 0000000000..f6057aedfd --- /dev/null +++ b/astro/src/content/resources/it/middleware/timeout.md @@ -0,0 +1,176 @@ +--- +title: Express timeout middleware +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/resources/it/middleware/vhost.md b/astro/src/content/resources/it/middleware/vhost.md new file mode 100644 index 0000000000..72f49d7f93 --- /dev/null +++ b/astro/src/content/resources/it/middleware/vhost.md @@ -0,0 +1,174 @@ +--- +title: Express vhost middleware +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/resources/it/utils.md b/astro/src/content/resources/it/utils.md new file mode 100644 index 0000000000..546b2f09b4 --- /dev/null +++ b/astro/src/content/resources/it/utils.md @@ -0,0 +1,22 @@ +--- +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. +--- + +## 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](https://github.com/jshttp). diff --git a/astro/src/content/resources/ja/community.md b/astro/src/content/resources/ja/community.md new file mode 100755 index 0000000000..e40d97e421 --- /dev/null +++ b/astro/src/content/resources/ja/community.md @@ -0,0 +1,70 @@ +--- +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. +--- + +# 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](/en/resources/middleware) 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](/en/resources/utils). +- [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. + + diff --git a/astro/src/content/resources/ja/contributing.md b/astro/src/content/resources/ja/contributing.md new file mode 100644 index 0000000000..82c6b8fed7 --- /dev/null +++ b/astro/src/content/resources/ja/contributing.md @@ -0,0 +1,482 @@ +--- +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. +--- + +# 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](/en/resources/community/#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) +- 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/resources/ja/glossary.md b/astro/src/content/resources/ja/glossary.md new file mode 100755 index 0000000000..8b45bf01eb --- /dev/null +++ b/astro/src/content/resources/ja/glossary.md @@ -0,0 +1,62 @@ +--- +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. +--- + +# 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](/en/api#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](/en/api#router) in the API reference. diff --git a/astro/src/content/resources/ja/middleware/body-parser.md b/astro/src/content/resources/ja/middleware/body-parser.md new file mode 100644 index 0000000000..e82649a95c --- /dev/null +++ b/astro/src/content/resources/ja/middleware/body-parser.md @@ -0,0 +1,498 @@ +--- +title: Express body-parser middleware +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/resources/ja/middleware/compression.md b/astro/src/content/resources/ja/middleware/compression.md new file mode 100644 index 0000000000..6ac63fcb7a --- /dev/null +++ b/astro/src/content/resources/ja/middleware/compression.md @@ -0,0 +1,314 @@ +--- +title: Express compression middleware +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/resources/ja/middleware/cookie-parser.md b/astro/src/content/resources/ja/middleware/cookie-parser.md new file mode 100644 index 0000000000..2a59496387 --- /dev/null +++ b/astro/src/content/resources/ja/middleware/cookie-parser.md @@ -0,0 +1,124 @@ +--- +title: Express cookie-parser middleware +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/resources/ja/middleware/cookie-session.md b/astro/src/content/resources/ja/middleware/cookie-session.md new file mode 100644 index 0000000000..2d6d1f885b --- /dev/null +++ b/astro/src/content/resources/ja/middleware/cookie-session.md @@ -0,0 +1,124 @@ +--- +title: Express cookie-session middleware +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/resources/ja/middleware/cors.md b/astro/src/content/resources/ja/middleware/cors.md new file mode 100644 index 0000000000..55d70922cb --- /dev/null +++ b/astro/src/content/resources/ja/middleware/cors.md @@ -0,0 +1,261 @@ +--- +title: Express cors middleware +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/resources/ja/middleware/errorhandler.md b/astro/src/content/resources/ja/middleware/errorhandler.md new file mode 100644 index 0000000000..20df618320 --- /dev/null +++ b/astro/src/content/resources/ja/middleware/errorhandler.md @@ -0,0 +1,133 @@ +--- +title: Express errorhandler middleware +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/resources/ja/middleware/method-override.md b/astro/src/content/resources/ja/middleware/method-override.md new file mode 100644 index 0000000000..7b97ab855e --- /dev/null +++ b/astro/src/content/resources/ja/middleware/method-override.md @@ -0,0 +1,187 @@ +--- +title: Express method-override middleware +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/resources/ja/middleware/morgan.md b/astro/src/content/resources/ja/middleware/morgan.md new file mode 100644 index 0000000000..5319d93d57 --- /dev/null +++ b/astro/src/content/resources/ja/middleware/morgan.md @@ -0,0 +1,458 @@ +--- +title: Express morgan middleware +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/resources/ja/middleware/multer.md b/astro/src/content/resources/ja/middleware/multer.md new file mode 100644 index 0000000000..326786ab3d --- /dev/null +++ b/astro/src/content/resources/ja/middleware/multer.md @@ -0,0 +1,352 @@ +--- +title: Express multer middleware +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/resources/ja/middleware/overview.md b/astro/src/content/resources/ja/middleware/overview.md new file mode 100755 index 0000000000..46217759e7 --- /dev/null +++ b/astro/src/content/resources/ja/middleware/overview.md @@ -0,0 +1,40 @@ +--- +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. +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](/en/resources/middleware/body-parser) | Parse HTTP request body. | +| [compression](/en/resources/middleware/compression) | Compress HTTP responses. | +| [cookie-parser](/en/resources/middleware/cookie-parser) | Parse cookie header and populate `req.cookies`. See also [cookies](https://github.com/jed/cookies). | +| [cookie-session](/en/resources/middleware/cookie-session) | Establish cookie-based sessions. | +| [cors](/en/resources/middleware/cors) | Enable cross-origin resource sharing (CORS) with various options. | +| [errorhandler](/en/resources/middleware/errorhandler) | Development error-handling/debugging. | +| [method-override](/en/resources/middleware/method-override) | Override HTTP methods using header. | +| [morgan](/en/resources/middleware/morgan) | HTTP request logger. | +| [multer](/en/resources/middleware/multer) | Handle multi-part form data. | +| [response-time](/en/resources/middleware/response-time) | Record HTTP response time. | +| [serve-favicon](/en/resources/middleware/serve-favicon) | Serve a favicon. | +| [serve-index](/en/resources/middleware/serve-index) | Serve directory listing for a given path. | +| [serve-static](/en/resources/middleware/serve-static) | Serve static files. | +| [session](/en/resources/middleware/session) | Establish server-based sessions (development only). | +| [timeout](/en/resources/middleware/timeout) | Set a timeout perioHTTP request processing. | +| [vhost](/en/resources/middleware/vhost) | 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/resources/ja/middleware/response-time.md b/astro/src/content/resources/ja/middleware/response-time.md new file mode 100644 index 0000000000..f911f480f5 --- /dev/null +++ b/astro/src/content/resources/ja/middleware/response-time.md @@ -0,0 +1,314 @@ +--- +title: Express response-time middleware +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/resources/ja/middleware/serve-favicon.md b/astro/src/content/resources/ja/middleware/serve-favicon.md new file mode 100644 index 0000000000..7a77865c6b --- /dev/null +++ b/astro/src/content/resources/ja/middleware/serve-favicon.md @@ -0,0 +1,156 @@ +--- +title: Express serve-favicon middleware +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/resources/ja/middleware/serve-index.md b/astro/src/content/resources/ja/middleware/serve-index.md new file mode 100644 index 0000000000..da03cf94b2 --- /dev/null +++ b/astro/src/content/resources/ja/middleware/serve-index.md @@ -0,0 +1,156 @@ +--- +title: Express serve-index middleware +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/resources/ja/middleware/serve-static.md b/astro/src/content/resources/ja/middleware/serve-static.md new file mode 100644 index 0000000000..b048165d7b --- /dev/null +++ b/astro/src/content/resources/ja/middleware/serve-static.md @@ -0,0 +1,260 @@ +--- +title: Express serve-static middleware +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/resources/ja/middleware/session.md b/astro/src/content/resources/ja/middleware/session.md new file mode 100644 index 0000000000..90f3837a42 --- /dev/null +++ b/astro/src/content/resources/ja/middleware/session.md @@ -0,0 +1,1046 @@ +--- +title: Express session middleware +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/resources/ja/middleware/timeout.md b/astro/src/content/resources/ja/middleware/timeout.md new file mode 100644 index 0000000000..f6057aedfd --- /dev/null +++ b/astro/src/content/resources/ja/middleware/timeout.md @@ -0,0 +1,176 @@ +--- +title: Express timeout middleware +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/resources/ja/middleware/vhost.md b/astro/src/content/resources/ja/middleware/vhost.md new file mode 100644 index 0000000000..72f49d7f93 --- /dev/null +++ b/astro/src/content/resources/ja/middleware/vhost.md @@ -0,0 +1,174 @@ +--- +title: Express vhost middleware +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/resources/ja/utils.md b/astro/src/content/resources/ja/utils.md new file mode 100644 index 0000000000..546b2f09b4 --- /dev/null +++ b/astro/src/content/resources/ja/utils.md @@ -0,0 +1,22 @@ +--- +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. +--- + +## 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](https://github.com/jshttp). diff --git a/astro/src/content/resources/ko/community.md b/astro/src/content/resources/ko/community.md new file mode 100755 index 0000000000..e40d97e421 --- /dev/null +++ b/astro/src/content/resources/ko/community.md @@ -0,0 +1,70 @@ +--- +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. +--- + +# 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](/en/resources/middleware) 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](/en/resources/utils). +- [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. + + diff --git a/astro/src/content/resources/ko/contributing.md b/astro/src/content/resources/ko/contributing.md new file mode 100644 index 0000000000..82c6b8fed7 --- /dev/null +++ b/astro/src/content/resources/ko/contributing.md @@ -0,0 +1,482 @@ +--- +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. +--- + +# 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](/en/resources/community/#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) +- 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/resources/ko/glossary.md b/astro/src/content/resources/ko/glossary.md new file mode 100755 index 0000000000..8b45bf01eb --- /dev/null +++ b/astro/src/content/resources/ko/glossary.md @@ -0,0 +1,62 @@ +--- +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. +--- + +# 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](/en/api#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](/en/api#router) in the API reference. diff --git a/astro/src/content/resources/ko/middleware/body-parser.md b/astro/src/content/resources/ko/middleware/body-parser.md new file mode 100644 index 0000000000..e82649a95c --- /dev/null +++ b/astro/src/content/resources/ko/middleware/body-parser.md @@ -0,0 +1,498 @@ +--- +title: Express body-parser middleware +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/resources/ko/middleware/compression.md b/astro/src/content/resources/ko/middleware/compression.md new file mode 100644 index 0000000000..6ac63fcb7a --- /dev/null +++ b/astro/src/content/resources/ko/middleware/compression.md @@ -0,0 +1,314 @@ +--- +title: Express compression middleware +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/resources/ko/middleware/cookie-parser.md b/astro/src/content/resources/ko/middleware/cookie-parser.md new file mode 100644 index 0000000000..2a59496387 --- /dev/null +++ b/astro/src/content/resources/ko/middleware/cookie-parser.md @@ -0,0 +1,124 @@ +--- +title: Express cookie-parser middleware +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/resources/ko/middleware/cookie-session.md b/astro/src/content/resources/ko/middleware/cookie-session.md new file mode 100644 index 0000000000..2d6d1f885b --- /dev/null +++ b/astro/src/content/resources/ko/middleware/cookie-session.md @@ -0,0 +1,124 @@ +--- +title: Express cookie-session middleware +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/resources/ko/middleware/cors.md b/astro/src/content/resources/ko/middleware/cors.md new file mode 100644 index 0000000000..55d70922cb --- /dev/null +++ b/astro/src/content/resources/ko/middleware/cors.md @@ -0,0 +1,261 @@ +--- +title: Express cors middleware +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/resources/ko/middleware/errorhandler.md b/astro/src/content/resources/ko/middleware/errorhandler.md new file mode 100644 index 0000000000..20df618320 --- /dev/null +++ b/astro/src/content/resources/ko/middleware/errorhandler.md @@ -0,0 +1,133 @@ +--- +title: Express errorhandler middleware +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/resources/ko/middleware/method-override.md b/astro/src/content/resources/ko/middleware/method-override.md new file mode 100644 index 0000000000..7b97ab855e --- /dev/null +++ b/astro/src/content/resources/ko/middleware/method-override.md @@ -0,0 +1,187 @@ +--- +title: Express method-override middleware +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/resources/ko/middleware/morgan.md b/astro/src/content/resources/ko/middleware/morgan.md new file mode 100644 index 0000000000..5319d93d57 --- /dev/null +++ b/astro/src/content/resources/ko/middleware/morgan.md @@ -0,0 +1,458 @@ +--- +title: Express morgan middleware +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/resources/ko/middleware/multer.md b/astro/src/content/resources/ko/middleware/multer.md new file mode 100644 index 0000000000..326786ab3d --- /dev/null +++ b/astro/src/content/resources/ko/middleware/multer.md @@ -0,0 +1,352 @@ +--- +title: Express multer middleware +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/resources/ko/middleware/overview.md b/astro/src/content/resources/ko/middleware/overview.md new file mode 100755 index 0000000000..46217759e7 --- /dev/null +++ b/astro/src/content/resources/ko/middleware/overview.md @@ -0,0 +1,40 @@ +--- +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. +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](/en/resources/middleware/body-parser) | Parse HTTP request body. | +| [compression](/en/resources/middleware/compression) | Compress HTTP responses. | +| [cookie-parser](/en/resources/middleware/cookie-parser) | Parse cookie header and populate `req.cookies`. See also [cookies](https://github.com/jed/cookies). | +| [cookie-session](/en/resources/middleware/cookie-session) | Establish cookie-based sessions. | +| [cors](/en/resources/middleware/cors) | Enable cross-origin resource sharing (CORS) with various options. | +| [errorhandler](/en/resources/middleware/errorhandler) | Development error-handling/debugging. | +| [method-override](/en/resources/middleware/method-override) | Override HTTP methods using header. | +| [morgan](/en/resources/middleware/morgan) | HTTP request logger. | +| [multer](/en/resources/middleware/multer) | Handle multi-part form data. | +| [response-time](/en/resources/middleware/response-time) | Record HTTP response time. | +| [serve-favicon](/en/resources/middleware/serve-favicon) | Serve a favicon. | +| [serve-index](/en/resources/middleware/serve-index) | Serve directory listing for a given path. | +| [serve-static](/en/resources/middleware/serve-static) | Serve static files. | +| [session](/en/resources/middleware/session) | Establish server-based sessions (development only). | +| [timeout](/en/resources/middleware/timeout) | Set a timeout perioHTTP request processing. | +| [vhost](/en/resources/middleware/vhost) | 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/resources/ko/middleware/response-time.md b/astro/src/content/resources/ko/middleware/response-time.md new file mode 100644 index 0000000000..f911f480f5 --- /dev/null +++ b/astro/src/content/resources/ko/middleware/response-time.md @@ -0,0 +1,314 @@ +--- +title: Express response-time middleware +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/resources/ko/middleware/serve-favicon.md b/astro/src/content/resources/ko/middleware/serve-favicon.md new file mode 100644 index 0000000000..7a77865c6b --- /dev/null +++ b/astro/src/content/resources/ko/middleware/serve-favicon.md @@ -0,0 +1,156 @@ +--- +title: Express serve-favicon middleware +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/resources/ko/middleware/serve-index.md b/astro/src/content/resources/ko/middleware/serve-index.md new file mode 100644 index 0000000000..da03cf94b2 --- /dev/null +++ b/astro/src/content/resources/ko/middleware/serve-index.md @@ -0,0 +1,156 @@ +--- +title: Express serve-index middleware +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/resources/ko/middleware/serve-static.md b/astro/src/content/resources/ko/middleware/serve-static.md new file mode 100644 index 0000000000..b048165d7b --- /dev/null +++ b/astro/src/content/resources/ko/middleware/serve-static.md @@ -0,0 +1,260 @@ +--- +title: Express serve-static middleware +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/resources/ko/middleware/session.md b/astro/src/content/resources/ko/middleware/session.md new file mode 100644 index 0000000000..90f3837a42 --- /dev/null +++ b/astro/src/content/resources/ko/middleware/session.md @@ -0,0 +1,1046 @@ +--- +title: Express session middleware +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/resources/ko/middleware/timeout.md b/astro/src/content/resources/ko/middleware/timeout.md new file mode 100644 index 0000000000..f6057aedfd --- /dev/null +++ b/astro/src/content/resources/ko/middleware/timeout.md @@ -0,0 +1,176 @@ +--- +title: Express timeout middleware +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/resources/ko/middleware/vhost.md b/astro/src/content/resources/ko/middleware/vhost.md new file mode 100644 index 0000000000..72f49d7f93 --- /dev/null +++ b/astro/src/content/resources/ko/middleware/vhost.md @@ -0,0 +1,174 @@ +--- +title: Express vhost middleware +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/resources/ko/utils.md b/astro/src/content/resources/ko/utils.md new file mode 100644 index 0000000000..546b2f09b4 --- /dev/null +++ b/astro/src/content/resources/ko/utils.md @@ -0,0 +1,22 @@ +--- +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. +--- + +## 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](https://github.com/jshttp). diff --git a/astro/src/content/resources/pt-br/community.md b/astro/src/content/resources/pt-br/community.md new file mode 100755 index 0000000000..e40d97e421 --- /dev/null +++ b/astro/src/content/resources/pt-br/community.md @@ -0,0 +1,70 @@ +--- +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. +--- + +# 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](/en/resources/middleware) 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](/en/resources/utils). +- [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. + + diff --git a/astro/src/content/resources/pt-br/contributing.md b/astro/src/content/resources/pt-br/contributing.md new file mode 100644 index 0000000000..82c6b8fed7 --- /dev/null +++ b/astro/src/content/resources/pt-br/contributing.md @@ -0,0 +1,482 @@ +--- +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. +--- + +# 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](/en/resources/community/#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) +- 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/resources/pt-br/glossary.md b/astro/src/content/resources/pt-br/glossary.md new file mode 100755 index 0000000000..8b45bf01eb --- /dev/null +++ b/astro/src/content/resources/pt-br/glossary.md @@ -0,0 +1,62 @@ +--- +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. +--- + +# 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](/en/api#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](/en/api#router) in the API reference. diff --git a/astro/src/content/resources/pt-br/middleware/body-parser.md b/astro/src/content/resources/pt-br/middleware/body-parser.md new file mode 100644 index 0000000000..e82649a95c --- /dev/null +++ b/astro/src/content/resources/pt-br/middleware/body-parser.md @@ -0,0 +1,498 @@ +--- +title: Express body-parser middleware +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/resources/pt-br/middleware/compression.md b/astro/src/content/resources/pt-br/middleware/compression.md new file mode 100644 index 0000000000..6ac63fcb7a --- /dev/null +++ b/astro/src/content/resources/pt-br/middleware/compression.md @@ -0,0 +1,314 @@ +--- +title: Express compression middleware +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/resources/pt-br/middleware/cookie-parser.md b/astro/src/content/resources/pt-br/middleware/cookie-parser.md new file mode 100644 index 0000000000..2a59496387 --- /dev/null +++ b/astro/src/content/resources/pt-br/middleware/cookie-parser.md @@ -0,0 +1,124 @@ +--- +title: Express cookie-parser middleware +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/resources/pt-br/middleware/cookie-session.md b/astro/src/content/resources/pt-br/middleware/cookie-session.md new file mode 100644 index 0000000000..2d6d1f885b --- /dev/null +++ b/astro/src/content/resources/pt-br/middleware/cookie-session.md @@ -0,0 +1,124 @@ +--- +title: Express cookie-session middleware +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/resources/pt-br/middleware/cors.md b/astro/src/content/resources/pt-br/middleware/cors.md new file mode 100644 index 0000000000..55d70922cb --- /dev/null +++ b/astro/src/content/resources/pt-br/middleware/cors.md @@ -0,0 +1,261 @@ +--- +title: Express cors middleware +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/resources/pt-br/middleware/errorhandler.md b/astro/src/content/resources/pt-br/middleware/errorhandler.md new file mode 100644 index 0000000000..20df618320 --- /dev/null +++ b/astro/src/content/resources/pt-br/middleware/errorhandler.md @@ -0,0 +1,133 @@ +--- +title: Express errorhandler middleware +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/resources/pt-br/middleware/method-override.md b/astro/src/content/resources/pt-br/middleware/method-override.md new file mode 100644 index 0000000000..7b97ab855e --- /dev/null +++ b/astro/src/content/resources/pt-br/middleware/method-override.md @@ -0,0 +1,187 @@ +--- +title: Express method-override middleware +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/resources/pt-br/middleware/morgan.md b/astro/src/content/resources/pt-br/middleware/morgan.md new file mode 100644 index 0000000000..5319d93d57 --- /dev/null +++ b/astro/src/content/resources/pt-br/middleware/morgan.md @@ -0,0 +1,458 @@ +--- +title: Express morgan middleware +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/resources/pt-br/middleware/multer.md b/astro/src/content/resources/pt-br/middleware/multer.md new file mode 100644 index 0000000000..326786ab3d --- /dev/null +++ b/astro/src/content/resources/pt-br/middleware/multer.md @@ -0,0 +1,352 @@ +--- +title: Express multer middleware +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/resources/pt-br/middleware/overview.md b/astro/src/content/resources/pt-br/middleware/overview.md new file mode 100755 index 0000000000..46217759e7 --- /dev/null +++ b/astro/src/content/resources/pt-br/middleware/overview.md @@ -0,0 +1,40 @@ +--- +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. +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](/en/resources/middleware/body-parser) | Parse HTTP request body. | +| [compression](/en/resources/middleware/compression) | Compress HTTP responses. | +| [cookie-parser](/en/resources/middleware/cookie-parser) | Parse cookie header and populate `req.cookies`. See also [cookies](https://github.com/jed/cookies). | +| [cookie-session](/en/resources/middleware/cookie-session) | Establish cookie-based sessions. | +| [cors](/en/resources/middleware/cors) | Enable cross-origin resource sharing (CORS) with various options. | +| [errorhandler](/en/resources/middleware/errorhandler) | Development error-handling/debugging. | +| [method-override](/en/resources/middleware/method-override) | Override HTTP methods using header. | +| [morgan](/en/resources/middleware/morgan) | HTTP request logger. | +| [multer](/en/resources/middleware/multer) | Handle multi-part form data. | +| [response-time](/en/resources/middleware/response-time) | Record HTTP response time. | +| [serve-favicon](/en/resources/middleware/serve-favicon) | Serve a favicon. | +| [serve-index](/en/resources/middleware/serve-index) | Serve directory listing for a given path. | +| [serve-static](/en/resources/middleware/serve-static) | Serve static files. | +| [session](/en/resources/middleware/session) | Establish server-based sessions (development only). | +| [timeout](/en/resources/middleware/timeout) | Set a timeout perioHTTP request processing. | +| [vhost](/en/resources/middleware/vhost) | 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/resources/pt-br/middleware/response-time.md b/astro/src/content/resources/pt-br/middleware/response-time.md new file mode 100644 index 0000000000..f911f480f5 --- /dev/null +++ b/astro/src/content/resources/pt-br/middleware/response-time.md @@ -0,0 +1,314 @@ +--- +title: Express response-time middleware +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/resources/pt-br/middleware/serve-favicon.md b/astro/src/content/resources/pt-br/middleware/serve-favicon.md new file mode 100644 index 0000000000..7a77865c6b --- /dev/null +++ b/astro/src/content/resources/pt-br/middleware/serve-favicon.md @@ -0,0 +1,156 @@ +--- +title: Express serve-favicon middleware +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/resources/pt-br/middleware/serve-index.md b/astro/src/content/resources/pt-br/middleware/serve-index.md new file mode 100644 index 0000000000..da03cf94b2 --- /dev/null +++ b/astro/src/content/resources/pt-br/middleware/serve-index.md @@ -0,0 +1,156 @@ +--- +title: Express serve-index middleware +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/resources/pt-br/middleware/serve-static.md b/astro/src/content/resources/pt-br/middleware/serve-static.md new file mode 100644 index 0000000000..b048165d7b --- /dev/null +++ b/astro/src/content/resources/pt-br/middleware/serve-static.md @@ -0,0 +1,260 @@ +--- +title: Express serve-static middleware +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/resources/pt-br/middleware/session.md b/astro/src/content/resources/pt-br/middleware/session.md new file mode 100644 index 0000000000..90f3837a42 --- /dev/null +++ b/astro/src/content/resources/pt-br/middleware/session.md @@ -0,0 +1,1046 @@ +--- +title: Express session middleware +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/resources/pt-br/middleware/timeout.md b/astro/src/content/resources/pt-br/middleware/timeout.md new file mode 100644 index 0000000000..f6057aedfd --- /dev/null +++ b/astro/src/content/resources/pt-br/middleware/timeout.md @@ -0,0 +1,176 @@ +--- +title: Express timeout middleware +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/resources/pt-br/middleware/vhost.md b/astro/src/content/resources/pt-br/middleware/vhost.md new file mode 100644 index 0000000000..72f49d7f93 --- /dev/null +++ b/astro/src/content/resources/pt-br/middleware/vhost.md @@ -0,0 +1,174 @@ +--- +title: Express vhost middleware +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/resources/pt-br/utils.md b/astro/src/content/resources/pt-br/utils.md new file mode 100644 index 0000000000..546b2f09b4 --- /dev/null +++ b/astro/src/content/resources/pt-br/utils.md @@ -0,0 +1,22 @@ +--- +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. +--- + +## 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](https://github.com/jshttp). diff --git a/astro/src/content/resources/zh-cn/community.md b/astro/src/content/resources/zh-cn/community.md new file mode 100755 index 0000000000..e40d97e421 --- /dev/null +++ b/astro/src/content/resources/zh-cn/community.md @@ -0,0 +1,70 @@ +--- +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. +--- + +# 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](/en/resources/middleware) 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](/en/resources/utils). +- [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. + + diff --git a/astro/src/content/resources/zh-cn/contributing.md b/astro/src/content/resources/zh-cn/contributing.md new file mode 100644 index 0000000000..96c92467ee --- /dev/null +++ b/astro/src/content/resources/zh-cn/contributing.md @@ -0,0 +1,482 @@ +--- +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. +--- + +# 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](/en/resources/community#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) +- 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/resources/zh-cn/glossary.md b/astro/src/content/resources/zh-cn/glossary.md new file mode 100755 index 0000000000..8b45bf01eb --- /dev/null +++ b/astro/src/content/resources/zh-cn/glossary.md @@ -0,0 +1,62 @@ +--- +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. +--- + +# 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](/en/api#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](/en/api#router) in the API reference. diff --git a/astro/src/content/resources/zh-cn/middleware/body-parser.md b/astro/src/content/resources/zh-cn/middleware/body-parser.md new file mode 100644 index 0000000000..e82649a95c --- /dev/null +++ b/astro/src/content/resources/zh-cn/middleware/body-parser.md @@ -0,0 +1,498 @@ +--- +title: Express body-parser middleware +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/resources/zh-cn/middleware/compression.md b/astro/src/content/resources/zh-cn/middleware/compression.md new file mode 100644 index 0000000000..6ac63fcb7a --- /dev/null +++ b/astro/src/content/resources/zh-cn/middleware/compression.md @@ -0,0 +1,314 @@ +--- +title: Express compression middleware +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/resources/zh-cn/middleware/cookie-parser.md b/astro/src/content/resources/zh-cn/middleware/cookie-parser.md new file mode 100644 index 0000000000..2a59496387 --- /dev/null +++ b/astro/src/content/resources/zh-cn/middleware/cookie-parser.md @@ -0,0 +1,124 @@ +--- +title: Express cookie-parser middleware +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/resources/zh-cn/middleware/cookie-session.md b/astro/src/content/resources/zh-cn/middleware/cookie-session.md new file mode 100644 index 0000000000..2d6d1f885b --- /dev/null +++ b/astro/src/content/resources/zh-cn/middleware/cookie-session.md @@ -0,0 +1,124 @@ +--- +title: Express cookie-session middleware +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/resources/zh-cn/middleware/cors.md b/astro/src/content/resources/zh-cn/middleware/cors.md new file mode 100644 index 0000000000..55d70922cb --- /dev/null +++ b/astro/src/content/resources/zh-cn/middleware/cors.md @@ -0,0 +1,261 @@ +--- +title: Express cors middleware +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/resources/zh-cn/middleware/errorhandler.md b/astro/src/content/resources/zh-cn/middleware/errorhandler.md new file mode 100644 index 0000000000..20df618320 --- /dev/null +++ b/astro/src/content/resources/zh-cn/middleware/errorhandler.md @@ -0,0 +1,133 @@ +--- +title: Express errorhandler middleware +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/resources/zh-cn/middleware/method-override.md b/astro/src/content/resources/zh-cn/middleware/method-override.md new file mode 100644 index 0000000000..7b97ab855e --- /dev/null +++ b/astro/src/content/resources/zh-cn/middleware/method-override.md @@ -0,0 +1,187 @@ +--- +title: Express method-override middleware +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/resources/zh-cn/middleware/morgan.md b/astro/src/content/resources/zh-cn/middleware/morgan.md new file mode 100644 index 0000000000..5319d93d57 --- /dev/null +++ b/astro/src/content/resources/zh-cn/middleware/morgan.md @@ -0,0 +1,458 @@ +--- +title: Express morgan middleware +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/resources/zh-cn/middleware/multer.md b/astro/src/content/resources/zh-cn/middleware/multer.md new file mode 100644 index 0000000000..326786ab3d --- /dev/null +++ b/astro/src/content/resources/zh-cn/middleware/multer.md @@ -0,0 +1,352 @@ +--- +title: Express multer middleware +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/resources/zh-cn/middleware/overview.md b/astro/src/content/resources/zh-cn/middleware/overview.md new file mode 100755 index 0000000000..46217759e7 --- /dev/null +++ b/astro/src/content/resources/zh-cn/middleware/overview.md @@ -0,0 +1,40 @@ +--- +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. +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](/en/resources/middleware/body-parser) | Parse HTTP request body. | +| [compression](/en/resources/middleware/compression) | Compress HTTP responses. | +| [cookie-parser](/en/resources/middleware/cookie-parser) | Parse cookie header and populate `req.cookies`. See also [cookies](https://github.com/jed/cookies). | +| [cookie-session](/en/resources/middleware/cookie-session) | Establish cookie-based sessions. | +| [cors](/en/resources/middleware/cors) | Enable cross-origin resource sharing (CORS) with various options. | +| [errorhandler](/en/resources/middleware/errorhandler) | Development error-handling/debugging. | +| [method-override](/en/resources/middleware/method-override) | Override HTTP methods using header. | +| [morgan](/en/resources/middleware/morgan) | HTTP request logger. | +| [multer](/en/resources/middleware/multer) | Handle multi-part form data. | +| [response-time](/en/resources/middleware/response-time) | Record HTTP response time. | +| [serve-favicon](/en/resources/middleware/serve-favicon) | Serve a favicon. | +| [serve-index](/en/resources/middleware/serve-index) | Serve directory listing for a given path. | +| [serve-static](/en/resources/middleware/serve-static) | Serve static files. | +| [session](/en/resources/middleware/session) | Establish server-based sessions (development only). | +| [timeout](/en/resources/middleware/timeout) | Set a timeout perioHTTP request processing. | +| [vhost](/en/resources/middleware/vhost) | 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/resources/zh-cn/middleware/response-time.md b/astro/src/content/resources/zh-cn/middleware/response-time.md new file mode 100644 index 0000000000..f911f480f5 --- /dev/null +++ b/astro/src/content/resources/zh-cn/middleware/response-time.md @@ -0,0 +1,314 @@ +--- +title: Express response-time middleware +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/resources/zh-cn/middleware/serve-favicon.md b/astro/src/content/resources/zh-cn/middleware/serve-favicon.md new file mode 100644 index 0000000000..7a77865c6b --- /dev/null +++ b/astro/src/content/resources/zh-cn/middleware/serve-favicon.md @@ -0,0 +1,156 @@ +--- +title: Express serve-favicon middleware +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/resources/zh-cn/middleware/serve-index.md b/astro/src/content/resources/zh-cn/middleware/serve-index.md new file mode 100644 index 0000000000..da03cf94b2 --- /dev/null +++ b/astro/src/content/resources/zh-cn/middleware/serve-index.md @@ -0,0 +1,156 @@ +--- +title: Express serve-index middleware +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/resources/zh-cn/middleware/serve-static.md b/astro/src/content/resources/zh-cn/middleware/serve-static.md new file mode 100644 index 0000000000..b048165d7b --- /dev/null +++ b/astro/src/content/resources/zh-cn/middleware/serve-static.md @@ -0,0 +1,260 @@ +--- +title: Express serve-static middleware +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/resources/zh-cn/middleware/session.md b/astro/src/content/resources/zh-cn/middleware/session.md new file mode 100644 index 0000000000..90f3837a42 --- /dev/null +++ b/astro/src/content/resources/zh-cn/middleware/session.md @@ -0,0 +1,1046 @@ +--- +title: Express session middleware +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/resources/zh-cn/middleware/timeout.md b/astro/src/content/resources/zh-cn/middleware/timeout.md new file mode 100644 index 0000000000..f6057aedfd --- /dev/null +++ b/astro/src/content/resources/zh-cn/middleware/timeout.md @@ -0,0 +1,176 @@ +--- +title: Express timeout middleware +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/resources/zh-cn/middleware/vhost.md b/astro/src/content/resources/zh-cn/middleware/vhost.md new file mode 100644 index 0000000000..72f49d7f93 --- /dev/null +++ b/astro/src/content/resources/zh-cn/middleware/vhost.md @@ -0,0 +1,174 @@ +--- +title: Express vhost middleware +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/resources/zh-cn/utils.md b/astro/src/content/resources/zh-cn/utils.md new file mode 100644 index 0000000000..546b2f09b4 --- /dev/null +++ b/astro/src/content/resources/zh-cn/utils.md @@ -0,0 +1,22 @@ +--- +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. +--- + +## 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](https://github.com/jshttp). diff --git a/astro/src/content/resources/zh-tw/community.md b/astro/src/content/resources/zh-tw/community.md new file mode 100755 index 0000000000..e40d97e421 --- /dev/null +++ b/astro/src/content/resources/zh-tw/community.md @@ -0,0 +1,70 @@ +--- +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. +--- + +# 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](/en/resources/middleware) 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](/en/resources/utils). +- [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. + + diff --git a/astro/src/content/resources/zh-tw/contributing.md b/astro/src/content/resources/zh-tw/contributing.md new file mode 100644 index 0000000000..82c6b8fed7 --- /dev/null +++ b/astro/src/content/resources/zh-tw/contributing.md @@ -0,0 +1,482 @@ +--- +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. +--- + +# 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](/en/resources/community/#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) +- 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/resources/zh-tw/glossary.md b/astro/src/content/resources/zh-tw/glossary.md new file mode 100755 index 0000000000..8b45bf01eb --- /dev/null +++ b/astro/src/content/resources/zh-tw/glossary.md @@ -0,0 +1,62 @@ +--- +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. +--- + +# 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](/en/api#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](/en/api#router) in the API reference. diff --git a/astro/src/content/resources/zh-tw/middleware/body-parser.md b/astro/src/content/resources/zh-tw/middleware/body-parser.md new file mode 100644 index 0000000000..e82649a95c --- /dev/null +++ b/astro/src/content/resources/zh-tw/middleware/body-parser.md @@ -0,0 +1,498 @@ +--- +title: Express body-parser middleware +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/resources/zh-tw/middleware/compression.md b/astro/src/content/resources/zh-tw/middleware/compression.md new file mode 100644 index 0000000000..6ac63fcb7a --- /dev/null +++ b/astro/src/content/resources/zh-tw/middleware/compression.md @@ -0,0 +1,314 @@ +--- +title: Express compression middleware +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/resources/zh-tw/middleware/cookie-parser.md b/astro/src/content/resources/zh-tw/middleware/cookie-parser.md new file mode 100644 index 0000000000..2a59496387 --- /dev/null +++ b/astro/src/content/resources/zh-tw/middleware/cookie-parser.md @@ -0,0 +1,124 @@ +--- +title: Express cookie-parser middleware +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/resources/zh-tw/middleware/cookie-session.md b/astro/src/content/resources/zh-tw/middleware/cookie-session.md new file mode 100644 index 0000000000..2d6d1f885b --- /dev/null +++ b/astro/src/content/resources/zh-tw/middleware/cookie-session.md @@ -0,0 +1,124 @@ +--- +title: Express cookie-session middleware +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/resources/zh-tw/middleware/cors.md b/astro/src/content/resources/zh-tw/middleware/cors.md new file mode 100644 index 0000000000..55d70922cb --- /dev/null +++ b/astro/src/content/resources/zh-tw/middleware/cors.md @@ -0,0 +1,261 @@ +--- +title: Express cors middleware +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/resources/zh-tw/middleware/errorhandler.md b/astro/src/content/resources/zh-tw/middleware/errorhandler.md new file mode 100644 index 0000000000..20df618320 --- /dev/null +++ b/astro/src/content/resources/zh-tw/middleware/errorhandler.md @@ -0,0 +1,133 @@ +--- +title: Express errorhandler middleware +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/resources/zh-tw/middleware/method-override.md b/astro/src/content/resources/zh-tw/middleware/method-override.md new file mode 100644 index 0000000000..7b97ab855e --- /dev/null +++ b/astro/src/content/resources/zh-tw/middleware/method-override.md @@ -0,0 +1,187 @@ +--- +title: Express method-override middleware +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/resources/zh-tw/middleware/morgan.md b/astro/src/content/resources/zh-tw/middleware/morgan.md new file mode 100644 index 0000000000..5319d93d57 --- /dev/null +++ b/astro/src/content/resources/zh-tw/middleware/morgan.md @@ -0,0 +1,458 @@ +--- +title: Express morgan middleware +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/resources/zh-tw/middleware/multer.md b/astro/src/content/resources/zh-tw/middleware/multer.md new file mode 100644 index 0000000000..326786ab3d --- /dev/null +++ b/astro/src/content/resources/zh-tw/middleware/multer.md @@ -0,0 +1,352 @@ +--- +title: Express multer middleware +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/resources/zh-tw/middleware/overview.md b/astro/src/content/resources/zh-tw/middleware/overview.md new file mode 100755 index 0000000000..46217759e7 --- /dev/null +++ b/astro/src/content/resources/zh-tw/middleware/overview.md @@ -0,0 +1,40 @@ +--- +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. +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](/en/resources/middleware/body-parser) | Parse HTTP request body. | +| [compression](/en/resources/middleware/compression) | Compress HTTP responses. | +| [cookie-parser](/en/resources/middleware/cookie-parser) | Parse cookie header and populate `req.cookies`. See also [cookies](https://github.com/jed/cookies). | +| [cookie-session](/en/resources/middleware/cookie-session) | Establish cookie-based sessions. | +| [cors](/en/resources/middleware/cors) | Enable cross-origin resource sharing (CORS) with various options. | +| [errorhandler](/en/resources/middleware/errorhandler) | Development error-handling/debugging. | +| [method-override](/en/resources/middleware/method-override) | Override HTTP methods using header. | +| [morgan](/en/resources/middleware/morgan) | HTTP request logger. | +| [multer](/en/resources/middleware/multer) | Handle multi-part form data. | +| [response-time](/en/resources/middleware/response-time) | Record HTTP response time. | +| [serve-favicon](/en/resources/middleware/serve-favicon) | Serve a favicon. | +| [serve-index](/en/resources/middleware/serve-index) | Serve directory listing for a given path. | +| [serve-static](/en/resources/middleware/serve-static) | Serve static files. | +| [session](/en/resources/middleware/session) | Establish server-based sessions (development only). | +| [timeout](/en/resources/middleware/timeout) | Set a timeout perioHTTP request processing. | +| [vhost](/en/resources/middleware/vhost) | 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/resources/zh-tw/middleware/response-time.md b/astro/src/content/resources/zh-tw/middleware/response-time.md new file mode 100644 index 0000000000..f911f480f5 --- /dev/null +++ b/astro/src/content/resources/zh-tw/middleware/response-time.md @@ -0,0 +1,314 @@ +--- +title: Express response-time middleware +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/resources/zh-tw/middleware/serve-favicon.md b/astro/src/content/resources/zh-tw/middleware/serve-favicon.md new file mode 100644 index 0000000000..7a77865c6b --- /dev/null +++ b/astro/src/content/resources/zh-tw/middleware/serve-favicon.md @@ -0,0 +1,156 @@ +--- +title: Express serve-favicon middleware +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/resources/zh-tw/middleware/serve-index.md b/astro/src/content/resources/zh-tw/middleware/serve-index.md new file mode 100644 index 0000000000..da03cf94b2 --- /dev/null +++ b/astro/src/content/resources/zh-tw/middleware/serve-index.md @@ -0,0 +1,156 @@ +--- +title: Express serve-index middleware +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/resources/zh-tw/middleware/serve-static.md b/astro/src/content/resources/zh-tw/middleware/serve-static.md new file mode 100644 index 0000000000..b048165d7b --- /dev/null +++ b/astro/src/content/resources/zh-tw/middleware/serve-static.md @@ -0,0 +1,260 @@ +--- +title: Express serve-static middleware +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/resources/zh-tw/middleware/session.md b/astro/src/content/resources/zh-tw/middleware/session.md new file mode 100644 index 0000000000..90f3837a42 --- /dev/null +++ b/astro/src/content/resources/zh-tw/middleware/session.md @@ -0,0 +1,1046 @@ +--- +title: Express session middleware +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/resources/zh-tw/middleware/timeout.md b/astro/src/content/resources/zh-tw/middleware/timeout.md new file mode 100644 index 0000000000..f6057aedfd --- /dev/null +++ b/astro/src/content/resources/zh-tw/middleware/timeout.md @@ -0,0 +1,176 @@ +--- +title: Express timeout middleware +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/resources/zh-tw/middleware/vhost.md b/astro/src/content/resources/zh-tw/middleware/vhost.md new file mode 100644 index 0000000000..72f49d7f93 --- /dev/null +++ b/astro/src/content/resources/zh-tw/middleware/vhost.md @@ -0,0 +1,174 @@ +--- +title: Express vhost middleware +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/resources/zh-tw/utils.md b/astro/src/content/resources/zh-tw/utils.md new file mode 100644 index 0000000000..546b2f09b4 --- /dev/null +++ b/astro/src/content/resources/zh-tw/utils.md @@ -0,0 +1,22 @@ +--- +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. +--- + +## 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](https://github.com/jshttp). 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/de.json b/astro/src/i18n/ui/de.json new file mode 100644 index 0000000000..a2ad0b9cdc --- /dev/null +++ b/astro/src/i18n/ui/de.json @@ -0,0 +1,79 @@ +{ + "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", + "hero.tagline": "Schnelles, unvoreingenommenes, minimalistisches Web-Framework für Node.js", + "hero.getStarted": "Erste Schritte", + "hero.videoPause": "Hintergrundvideo anhalten", + "hero.videoPlay": "Hintergrundvideo abspielen" +} diff --git a/astro/src/i18n/ui/en.json b/astro/src/i18n/ui/en.json new file mode 100644 index 0000000000..635c3f1d3d --- /dev/null +++ b/astro/src/i18n/ui/en.json @@ -0,0 +1,92 @@ +{ + "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": "Start typing to search", + "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.events": "Events", + "menu.overviewAria": "Overview", + "menu.expressOverviewAria": "Express overview", + "menu.expressMethodsAria": "Express methods", + "menu.application": "Application", + "menu.applicationOverviewAria": "Application overview", + "menu.properties": "Properties", + "menu.applicationPropertiesAria": "Application properties", + "menu.applicationEventAria": "Application events", + "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", + "hero.tagline": "Fast, unopinionated, minimalist web framework for Node.js", + "hero.getStarted": "Get Started", + "hero.videoPause": "Pause background video", + "hero.videoPlay": "Play background video", + "features.title": "Clarity over complexity. For every developer.", + "features.performance.title": "Performance", + "features.performance.body": "Express provides a thin layer of fundamental web application features, without obscuring Node.js features that you know and love.", + "features.api.title": "APIs", + "features.api.body": "With a myriad of HTTP utility methods and middleware at your disposal, creating a robust API is quick and easy.", + "features.middleware.title": "Middleware", + "features.middleware.body": "Express is a lightweight and flexible routing framework with minimal core features meant to be augmented through the use of Express middleware modules.", + "features.webapplication.title": "Web Applications", + "features.webapplication.body": "Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications." +} diff --git a/astro/src/i18n/ui/es.json b/astro/src/i18n/ui/es.json new file mode 100644 index 0000000000..d4923ad3dd --- /dev/null +++ b/astro/src/i18n/ui/es.json @@ -0,0 +1,79 @@ +{ + "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", + "hero.tagline": "Framework web rápido, sin opiniones y minimalista para Node.js", + "hero.getStarted": "Comenzar", + "hero.videoPause": "Pausar video de fondo", + "hero.videoPlay": "Reproducir video de fondo" +} diff --git a/astro/src/i18n/ui/fr.json b/astro/src/i18n/ui/fr.json new file mode 100644 index 0000000000..428e87af0e --- /dev/null +++ b/astro/src/i18n/ui/fr.json @@ -0,0 +1,79 @@ +{ + "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", + "hero.tagline": "Framework web rapide, sans opinion et minimaliste pour Node.js", + "hero.getStarted": "Commencer", + "hero.videoPause": "Mettre en pause la vidéo de fond", + "hero.videoPlay": "Lire la vidéo de fond" +} diff --git a/astro/src/i18n/ui/it.json b/astro/src/i18n/ui/it.json new file mode 100644 index 0000000000..9a85677fe6 --- /dev/null +++ b/astro/src/i18n/ui/it.json @@ -0,0 +1,79 @@ +{ + "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", + "hero.tagline": "Framework web veloce, non prescrittivo e minimalista per Node.js", + "hero.getStarted": "Inizia", + "hero.videoPause": "Metti in pausa il video in background", + "hero.videoPlay": "Riproduci il video in background" +} diff --git a/astro/src/i18n/ui/ja.json b/astro/src/i18n/ui/ja.json new file mode 100644 index 0000000000..ba78dcff99 --- /dev/null +++ b/astro/src/i18n/ui/ja.json @@ -0,0 +1,79 @@ +{ + "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": "ホームに戻る", + "hero.tagline": "Node.js向けの高速で中立的なミニマリストWebフレームワーク", + "hero.getStarted": "始める", + "hero.videoPause": "背景動画を一時停止", + "hero.videoPlay": "背景動画を再生" +} diff --git a/astro/src/i18n/ui/ko.json b/astro/src/i18n/ui/ko.json new file mode 100644 index 0000000000..23561f5f63 --- /dev/null +++ b/astro/src/i18n/ui/ko.json @@ -0,0 +1,79 @@ +{ + "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": "홈으로 이동", + "hero.tagline": "Node.js를 위한 빠르고 독단적이지 않은 미니멀리스트 웹 프레임워크", + "hero.getStarted": "시작하기", + "hero.videoPause": "배경 비디오 일시정지", + "hero.videoPlay": "배경 비디오 재생" +} diff --git a/astro/src/i18n/ui/pt-br.json b/astro/src/i18n/ui/pt-br.json new file mode 100644 index 0000000000..17cc03007b --- /dev/null +++ b/astro/src/i18n/ui/pt-br.json @@ -0,0 +1,79 @@ +{ + "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", + "hero.tagline": "Framework web rápido, sem opinião e minimalista para Node.js", + "hero.getStarted": "Começar", + "hero.videoPause": "Pausar vídeo de fundo", + "hero.videoPlay": "Reproduzir vídeo de fundo" +} diff --git a/astro/src/i18n/ui/zh-cn.json b/astro/src/i18n/ui/zh-cn.json new file mode 100644 index 0000000000..05a9699a36 --- /dev/null +++ b/astro/src/i18n/ui/zh-cn.json @@ -0,0 +1,79 @@ +{ + "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": "返回主页", + "hero.tagline": "快速、无偏见、极简主义的 Node.js Web 框架", + "hero.getStarted": "开始使用", + "hero.videoPause": "暂停背景视频", + "hero.videoPlay": "播放背景视频" +} diff --git a/astro/src/i18n/ui/zh-tw.json b/astro/src/i18n/ui/zh-tw.json new file mode 100644 index 0000000000..10c42eaa88 --- /dev/null +++ b/astro/src/i18n/ui/zh-tw.json @@ -0,0 +1,79 @@ +{ + "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": "返回首頁", + "hero.tagline": "快速、無偏見、極簡主義的 Node.js Web 框架", + "hero.getStarted": "開始使用", + "hero.videoPause": "暫停背景影片", + "hero.videoPlay": "播放背景影片" +} diff --git a/astro/src/i18n/utils.ts b/astro/src/i18n/utils.ts new file mode 100644 index 0000000000..21d3b1b620 --- /dev/null +++ b/astro/src/i18n/utils.ts @@ -0,0 +1,45 @@ +import { ui, defaultLang, languages } from './locales'; + +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] | 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/icons/bsky.svg b/astro/src/icons/bsky.svg new file mode 100644 index 0000000000..470288aa8c --- /dev/null +++ b/astro/src/icons/bsky.svg @@ -0,0 +1,3 @@ + + + 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/logo-dark.svg b/astro/src/icons/logo-dark.svg new file mode 100644 index 0000000000..0dc200a93c --- /dev/null +++ b/astro/src/icons/logo-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/astro/src/icons/logo-express-black.svg b/astro/src/icons/logo-express-black.svg new file mode 100644 index 0000000000..d9dace678c --- /dev/null +++ b/astro/src/icons/logo-express-black.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/astro/src/icons/logo-express-white.svg b/astro/src/icons/logo-express-white.svg new file mode 100644 index 0000000000..6b14ccf672 --- /dev/null +++ b/astro/src/icons/logo-express-white.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/astro/src/icons/logo-light.svg b/astro/src/icons/logo-light.svg new file mode 100644 index 0000000000..1ba7920fd9 --- /dev/null +++ b/astro/src/icons/logo-light.svg @@ -0,0 +1 @@ + \ No newline at end of file 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/DocLayout.astro b/astro/src/layouts/DocLayout.astro new file mode 100644 index 0000000000..42d7260a04 --- /dev/null +++ b/astro/src/layouts/DocLayout.astro @@ -0,0 +1,24 @@ +--- +import Layout from './Layout.astro'; +import type { BreadcrumbItem } from '@utils/content'; +import { Breadcrumbs } from '@components/patterns'; +import { Container } from '@/components/primitives'; + +interface Props { + title: string; + description?: string; + 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..5e075a3a2d --- /dev/null +++ b/astro/src/layouts/Layout.astro @@ -0,0 +1,117 @@ +--- +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; + description?: string; +} + +const { + title = 'Express - Node.js web application framework', + description = 'Fast, unopinionated, minimalist web framework for Node.js', +} = Astro.props; + +const isNetlify = import.meta.env.DEPLOY_PRIME_URL; + +const lang = getLangFromUrl(Astro.url); +--- + + + + + + + + + + + + + + + + + { + Object.keys(languages).map((altLang) => ( + + )) + } + + {title} + + + + + + + + + + +
      + + + + +
      + +
      +