diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 8505d9a5f..2db9dc995 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -8,3 +8,7 @@ updates: timezone: Europe/Berlin open-pull-requests-limit: 10 versioning-strategy: lockfile-only + groups: + dependencies: + patterns: + - "*" diff --git a/.husky/commit-msg b/.husky/commit-msg index fd2bf708e..dbce4f4cf 100755 --- a/.husky/commit-msg +++ b/.husky/commit-msg @@ -1 +1 @@ -npx --no-install commitlint --edit $1 +commitlint --edit $1 diff --git a/.husky/pre-commit b/.husky/pre-commit index 2312dc587..c27d8893a 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1 +1 @@ -npx lint-staged +lint-staged diff --git a/CHANGELOG.md b/CHANGELOG.md index fcd4ae31c..119fe55cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [7.4.0](https://github.com/webpack/webpack-dev-middleware/compare/v7.3.0...v7.4.0) (2024-08-15) + + +### Features + +* added the cacheImmutable option to cache immutable assets (assets with a hash in file name like `image.e12ab567.jpg`) ([5ed629d](https://github.com/webpack/webpack-dev-middleware/commit/5ed629da0d432fefdd3b5191985ce93c3aab2624)) +* allow to configure the `Cache-Control` header ([#1923](https://github.com/webpack/webpack-dev-middleware/issues/1923)) ([f7529c3](https://github.com/webpack/webpack-dev-middleware/commit/f7529c3188efa1885593993d912155ef2188fda5)) + + +### Bug Fixes + +* support `devServer: false` ([b443f4d](https://github.com/webpack/webpack-dev-middleware/commit/b443f4df9f38502b73707073a6e2a21e1a9c684a)) + ## [7.3.0](https://github.com/webpack/webpack-dev-middleware/compare/v7.2.1...v7.3.0) (2024-07-18) diff --git a/README.md b/README.md index 99c8e0f88..ef6ed5be2 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ First thing's first, install the module: npm install webpack-dev-middleware --save-dev ``` -> **Warning** +> [!WARNING] > > _We do not recommend installing this module globally._ @@ -60,20 +60,23 @@ See [below](#other-servers) for an example of use with fastify. ## Options -| Name | Type | Default | Description | -| :---------------------------------------------: | :---------------------------: | :-------------------------------------------: | :------------------------------------------------------------------------------------------------------------------- | -| **[`methods`](#methods)** | `Array` | `[ 'GET', 'HEAD' ]` | Allows to pass the list of HTTP request methods accepted by the middleware | -| **[`headers`](#headers)** | `Array\|Object\|Function` | `undefined` | Allows to pass custom HTTP headers on each request. | -| **[`index`](#index)** | `Boolean\|String` | `index.html` | If `false` (but not `undefined`), the server will not respond to requests to the root URL. | -| **[`mimeTypes`](#mimetypes)** | `Object` | `undefined` | Allows to register custom mime types or extension mappings. | -| **[`mimeTypeDefault`](#mimetypedefault)** | `String` | `undefined` | Allows to register a default mime type when we can't determine the content type. | -| **[`etag`](#tag)** | `boolean\| "weak"\| "strong"` | `undefined` | Enable or disable etag generation. | -| **[`publicPath`](#publicpath)** | `String` | `output.publicPath` (from a configuration) | The public path that the middleware is bound to. | -| **[`stats`](#stats)** | `Boolean\|String\|Object` | `stats` (from a configuration) | Stats options object or preset name. | -| **[`serverSideRender`](#serversiderender)** | `Boolean` | `undefined` | Instructs the module to enable or disable the server-side rendering mode. | -| **[`writeToDisk`](#writetodisk)** | `Boolean\|Function` | `false` | Instructs the module to write files to the configured location on disk as specified in your `webpack` configuration. | -| **[`outputFileSystem`](#outputfilesystem)** | `Object` | [`memfs`](https://github.com/streamich/memfs) | Set the default file system which will be used by webpack as primary destination of generated files. | -| **[`modifyResponseData`](#modifyresponsedata)** | `Function` | `undefined` | Allows to set up a callback to change the response data. | +| Name | Type | Default | Description | +| :---------------------------------------------: | :-------------------------------: | :-------------------------------------------: | :------------------------------------------------------------------------------------------------------------------- | +| **[`methods`](#methods)** | `Array` | `[ 'GET', 'HEAD' ]` | Allows to pass the list of HTTP request methods accepted by the middleware | +| **[`headers`](#headers)** | `Array\|Object\|Function` | `undefined` | Allows to pass custom HTTP headers on each request. | +| **[`index`](#index)** | `boolean\|string` | `index.html` | If `false` (but not `undefined`), the server will not respond to requests to the root URL. | +| **[`mimeTypes`](#mimetypes)** | `Object` | `undefined` | Allows to register custom mime types or extension mappings. | +| **[`mimeTypeDefault`](#mimetypedefault)** | `string` | `undefined` | Allows to register a default mime type when we can't determine the content type. | +| **[`etag`](#tag)** | `boolean\| "weak"\| "strong"` | `undefined` | Enable or disable etag generation. | +| **[`lastModified`](#lastmodified)** | `boolean` | `undefined` | Enable or disable `Last-Modified` header. Uses the file system's last modified value. | +| **[`cacheControl`](#cachecontrol)** | `boolean\|number\|string\|Object` | `undefined` | Enable or disable setting `Cache-Control` response header. | +| **[`cacheImmutable`](#cacheimmutable)** | `boolean\` | `undefined` | Enable or disable setting `Cache-Control: public, max-age=31536000, immutable` response header for immutable assets. | +| **[`publicPath`](#publicpath)** | `string` | `undefined` | The public path that the middleware is bound to. | +| **[`stats`](#stats)** | `boolean\|string\|Object` | `stats` (from a configuration) | Stats options object or preset name. | +| **[`serverSideRender`](#serversiderender)** | `boolean` | `undefined` | Instructs the module to enable or disable the server-side rendering mode. | +| **[`writeToDisk`](#writetodisk)** | `boolean\|Function` | `false` | Instructs the module to write files to the configured location on disk as specified in your `webpack` configuration. | +| **[`outputFileSystem`](#outputfilesystem)** | `Object` | [`memfs`](https://github.com/streamich/memfs) | Set the default file system which will be used by webpack as primary destination of generated files. | +| **[`modifyResponseData`](#modifyresponsedata)** | `Function` | `undefined` | Allows to set up a callback to change the response data. | The middleware accepts an `options` Object. The following is a property reference for the Object. @@ -186,6 +189,29 @@ Default: `undefined` Enable or disable `Last-Modified` header. Uses the file system's last modified value. +### cacheControl + +Type: `Boolean | Number | String | { maxAge?: number, immutable?: boolean }` +Default: `undefined` + +Depending on the setting, the following headers will be generated: + +- `Boolean` - `Cache-Control: public, max-age=31536000000` +- `Number` - `Cache-Control: public, max-age=YOUR_NUMBER` +- `String` - `Cache-Control: YOUR_STRING` +- `{ maxAge?: number, immutable?: boolean }` - `Cache-Control: public, max-age=YOUR_MAX_AGE_or_31536000000`, also `, immutable` can be added if you set the `immutable` option to `true` + +Enable or disable setting `Cache-Control` response header. + +### cacheImmutable + +Type: `Boolean` +Default: `undefined` + +Enable or disable setting `Cache-Control: public, max-age=31536000, immutable` response header for immutable assets (i.e. asset with a hash like `image.a4c12bde.jpg`). +Immutable assets are assets that have their hash in the file name therefore they can be cached, because if you change their contents the file name will be changed. +Take preference over the `cacheControl` option if the asset was defined as immutable. + ### publicPath Type: `String` diff --git a/package-lock.json b/package-lock.json index 28589cbef..7570ce803 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "webpack-dev-middleware", - "version": "7.3.0", + "version": "7.4.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "webpack-dev-middleware", - "version": "7.3.0", + "version": "7.4.0", "license": "MIT", "dependencies": { "colorette": "^2.0.10", @@ -22,13 +22,13 @@ "@babel/preset-env": "^7.16.7", "@commitlint/cli": "^19.0.3", "@commitlint/config-conventional": "^19.0.3", - "@fastify/express": "^2.3.0", + "@fastify/express": "^3.0.0", "@hapi/hapi": "^21.3.7", "@hono/node-server": "^1.12.0", "@types/connect": "^3.4.35", "@types/express": "^4.17.13", "@types/mime-types": "^2.1.1", - "@types/node": "^20.11.16", + "@types/node": "^22.3.0", "@types/on-finished": "^2.3.4", "@webpack-contrib/eslint-config-webpack": "^3.0.0", "babel-jest": "^29.3.1", @@ -37,7 +37,6 @@ "cross-env": "^7.0.3", "cspell": "^8.3.2", "deepmerge": "^4.2.2", - "del": "^6.0.0", "del-cli": "^5.0.0", "eslint": "^8.28.0", "eslint-config-prettier": "^9.1.0", @@ -48,7 +47,7 @@ "file-loader": "^6.2.0", "finalhandler": "^1.2.0", "hono": "^4.4.13", - "husky": "^9.0.10", + "husky": "^9.1.3", "jest": "^29.3.1", "joi": "^17.12.2", "koa": "^2.15.2", @@ -58,7 +57,7 @@ "router": "^1.3.8", "standard-version": "^9.3.0", "strip-ansi": "^6.0.0", - "supertest": "^6.1.3", + "supertest": "^7.0.0", "typescript": "^5.3.3", "webpack": "^5.93.0" }, @@ -134,30 +133,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.8.tgz", - "integrity": "sha512-c4IM7OTg6k1Q+AJ153e2mc2QVTezTwnb4VzquwcyiEzGnW0Kedv4do/TrkU98qPeC5LNiMt/QXwIjzYXLBpyZg==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.2.tgz", + "integrity": "sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.9.tgz", - "integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.9", - "@babel/helper-compilation-targets": "^7.24.8", - "@babel/helper-module-transforms": "^7.24.9", - "@babel/helpers": "^7.24.8", - "@babel/parser": "^7.24.8", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.8", - "@babel/types": "^7.24.9", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -173,12 +172,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.9.tgz", - "integrity": "sha512-G8v3jRg+z8IwY1jHFxvCNhOPYPterE4XljNgdGTYfSTtzzwjIswIzIaSPSLs3R7yFuqnqNeay5rjICfqVr+/6A==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz", + "integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==", "dev": true, "dependencies": { - "@babel/types": "^7.24.9", + "@babel/types": "^7.25.0", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" @@ -213,12 +212,12 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz", - "integrity": "sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", + "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.24.8", + "@babel/compat-data": "^7.25.2", "@babel/helper-validator-option": "^7.24.8", "browserslist": "^4.23.1", "lru-cache": "^5.1.1", @@ -252,9 +251,9 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.24.7.tgz", - "integrity": "sha512-03TCmXy2FtXJEZfbXDTSqq1fRJArk7lX9DOFC/47VthYcxyIOx+eXQmdo6DOQvrbpIix+KfXwvuXdFDZHxt+rA==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.0.tgz", + "integrity": "sha512-q0T+dknZS+L5LDazIP+02gEZITG5unzvb6yIjcmj5i0eFrs5ToBV2m2JGH4EsE/gtP8ygEGLGApBgRIZkTm7zg==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", @@ -309,26 +308,14 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", - "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.7.tgz", - "integrity": "sha512-LGeMaf5JN4hAT471eJdBs/GK1DoYIJ5GCtZN/EsL6KUiiDZOvO/eKE11AMZJa2zP4zk4qe9V2O/hxAmkRc8p6w==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", + "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", "dev": true, "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.24.8", + "@babel/types": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -348,16 +335,15 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.9.tgz", - "integrity": "sha512-oYbh+rtFKj/HwBQkFlUzvcybzklmVdVV3UU+mN7n2t/q3yGHbuVdNxyFvSBO1tfvjyArpHNcWMAzsSPdyI46hw==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", + "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", "@babel/helper-module-imports": "^7.24.7", "@babel/helper-simple-access": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.2" }, "engines": { "node": ">=6.9.0" @@ -388,14 +374,14 @@ } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.24.7.tgz", - "integrity": "sha512-9pKLcTlZ92hNZMQfGCHImUpDOlAgkkpqalWEeftW5FBya75k8Li2ilerxkM/uBEj01iBZXcCIB/bwvDYgWyibA==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.0.tgz", + "integrity": "sha512-NhavI2eWEIz/H9dbrG0TuOicDhNexze43i5z7lEqwYm0WEZVTwnPpA0EafUTP7+6/W79HWIP2cTe3Z5NiSTVpw==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-wrap-function": "^7.24.7" + "@babel/helper-wrap-function": "^7.25.0", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -405,14 +391,14 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.7.tgz", - "integrity": "sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.0.tgz", + "integrity": "sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-member-expression-to-functions": "^7.24.7", - "@babel/helper-optimise-call-expression": "^7.24.7" + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -487,28 +473,27 @@ } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.7.tgz", - "integrity": "sha512-N9JIYk3TD+1vq/wn77YnJOqMtfWhNewNE+DJV4puD2X7Ew9J4JvrzrFDfTfyv5EgEXVy9/Wt8QiOErzEmv5Ifw==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.0.tgz", + "integrity": "sha512-s6Q1ebqutSiZnEjaofc/UKDyC4SbzV5n5SrA2Gq8UawLycr3i04f1dX4OzoQVnexm6aOCh37SQNYlJ/8Ku+PMQ==", "dev": true, "dependencies": { - "@babel/helper-function-name": "^7.24.7", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.0", + "@babel/types": "^7.25.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.8.tgz", - "integrity": "sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.0.tgz", + "integrity": "sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==", "dev": true, "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.8" + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -530,10 +515,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.8.tgz", - "integrity": "sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==", + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.3.tgz", + "integrity": "sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==", "dev": true, + "dependencies": { + "@babel/types": "^7.25.2" + }, "bin": { "parser": "bin/babel-parser.js" }, @@ -542,13 +530,28 @@ } }, "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.7.tgz", - "integrity": "sha512-TiT1ss81W80eQsN+722OaeQMY/G4yTb4G9JrqeiDADs3N8lbPMGldWi9x8tyqCW5NLx1Jh2AvkE6r6QvEltMMQ==", + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.3.tgz", + "integrity": "sha512-wUrcsxZg6rqBXG05HG1FPYgsP6EvwF4WpBbxIpWIIYnH8wG0gzx3yZY3dtEHas4sTAOGkbTsc9EGPxwff8lRoA==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.0.tgz", + "integrity": "sha512-Bm4bH2qsX880b/3ziJ8KD711LT7z4u8CFudmjqle65AZj/HNUFhEf90dqYv6O86buWvSBmeQDjv0Tn2aF/bIBA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -558,12 +561,12 @@ } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.7.tgz", - "integrity": "sha512-unaQgZ/iRu/By6tsjMZzpeBZjChYfLYry6HrEXPoz3KmfF0sVBQ1l8zKMQ4xRGLWVsjuvB8nQfjNP/DcfEOCsg==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.0.tgz", + "integrity": "sha512-lXwdNZtTmeVOOFtwM/WDe7yg1PL8sYhRk/XH0FzbR2HDQ0xC+EnQ/JHeoMYSavtU115tnUk0q9CDyq8si+LMAA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -590,13 +593,13 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.7.tgz", - "integrity": "sha512-utA4HuR6F4Vvcr+o4DnjL8fCOlgRFGbeeBEGNg3ZTrLFw6VWG5XmUrvcQ0FjIYMU2ST4XcR2Wsp7t9qOAPnxMg==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.0.tgz", + "integrity": "sha512-tggFrk1AIShG/RUQbEwt2Tr/E+ObkfwrPjR6BjbRvsx24+PSjK8zrq0GWPNCjo8qpRx4DuJzlcvWJqlm+0h3kw==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -910,15 +913,15 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.7.tgz", - "integrity": "sha512-o+iF77e3u7ZS4AoAuJvapz9Fm001PuD2V3Lp6OSE4FYQke+cSewYtnek+THqGRWyQloRCyvWL1OkyfNEl9vr/g==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.0.tgz", + "integrity": "sha512-uaIi2FdqzjpAMvVqvB51S42oC2JEVgh0LDsGfZVDysWE8LrJtQC2jvKmOqEYThKyB7bDEb7BP1GYWDm7tABA0Q==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-remap-async-to-generator": "^7.24.7", - "@babel/plugin-syntax-async-generators": "^7.8.4" + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-remap-async-to-generator": "^7.25.0", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -960,12 +963,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.7.tgz", - "integrity": "sha512-Nd5CvgMbWc+oWzBsuaMcbwjJWAcp5qzrbg69SZdHSP7AMY0AbWFqFO0WTFCA1jxhMCwodRwvRec8k0QUbZk7RQ==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.0.tgz", + "integrity": "sha512-yBQjYoOjXlFv9nlXb3f1casSHOZkWr29NX+zChVanLg5Nc157CrbEX9D7hxxtTpuFy7Q0YzmmWfJxzvps4kXrQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -1008,18 +1011,16 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.8.tgz", - "integrity": "sha512-VXy91c47uujj758ud9wx+OMgheXm4qJfyhj1P18YvlrQkNOSrwsteHk+EFS3OMGfhMhpZa0A+81eE7G4QC+3CA==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.0.tgz", + "integrity": "sha512-xyi6qjr/fYU304fiRwFbekzkqVJZ6A7hOjWZd+89FVcBqPV3S9Wuozz82xdpLspckeaafntbzglaW4pqpzvtSw==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-compilation-targets": "^7.24.8", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-replace-supers": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-replace-supers": "^7.25.0", + "@babel/traverse": "^7.25.0", "globals": "^11.1.0" }, "engines": { @@ -1091,6 +1092,22 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.0.tgz", + "integrity": "sha512-YLpb4LlYSc3sCUa35un84poXoraOiQucUTTu8X1j18JV+gNa8E0nyUf/CjZ171IRGr4jEguF+vzJU66QZhn29g==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/plugin-transform-dynamic-import": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", @@ -1156,14 +1173,14 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.7.tgz", - "integrity": "sha512-U9FcnA821YoILngSmYkW6FjyQe2TyZD5pHt4EVIhmcTkrJw/3KqcrRSxuOo5tFZJi7TE19iDyI1u+weTI7bn2w==", + "version": "7.25.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.1.tgz", + "integrity": "sha512-TVVJVdW9RKMNgJJlLtHsKDTydjZAbwIsn6ySBPQaEAUU5+gVvlJt/9nRmqVbsV/IBanRjzWoaAQKLoamWVOUuA==", "dev": true, "dependencies": { - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.1" }, "engines": { "node": ">=6.9.0" @@ -1189,12 +1206,12 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.7.tgz", - "integrity": "sha512-vcwCbb4HDH+hWi8Pqenwnjy+UiklO4Kt1vfspcQYFhJdpthSnW8XvWGyDZWKNVrVbVViI/S7K9PDJZiUmP2fYQ==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.2.tgz", + "integrity": "sha512-HQI+HcTbm9ur3Z2DkO+jgESMAMcYLuN/A7NRw9juzxAezN9AvqvUTnpKP/9kkYANz6u7dFlAyOu44ejuGySlfw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -1268,15 +1285,15 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.7.tgz", - "integrity": "sha512-GYQE0tW7YoaN13qFh3O1NCY4MPkUiAH3fiF7UcV/I3ajmDKEdG3l+UOcbAm4zUE3gnvUU+Eni7XrVKo9eO9auw==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.0.tgz", + "integrity": "sha512-YPJfjQPDXxyQWg/0+jHKj1llnY5f/R6a0p/vP4lPymxLu7Lvl4k2WMitqi08yxwQcCVUUdG9LCUj4TNEgAp3Jw==", "dev": true, "dependencies": { - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -1666,19 +1683,20 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.8.tgz", - "integrity": "sha512-vObvMZB6hNWuDxhSaEPTKCwcqkAIuDtE+bQGn4XMXne1DSLzFVY8Vmj1bm+mUQXYNN8NmaQEO+r8MMbzPr1jBQ==", + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.3.tgz", + "integrity": "sha512-QsYW7UeAaXvLPX9tdVliMJE7MD7M6MLYVTovRTIwhoYQVFHR1rM4wO8wqAezYi3/BpSD+NzVCZ69R6smWiIi8g==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.24.8", - "@babel/helper-compilation-targets": "^7.24.8", + "@babel/compat-data": "^7.25.2", + "@babel/helper-compilation-targets": "^7.25.2", "@babel/helper-plugin-utils": "^7.24.8", "@babel/helper-validator-option": "^7.24.8", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.7", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.3", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.0", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.0", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.0", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", @@ -1699,29 +1717,30 @@ "@babel/plugin-syntax-top-level-await": "^7.14.5", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.24.7", - "@babel/plugin-transform-async-generator-functions": "^7.24.7", + "@babel/plugin-transform-async-generator-functions": "^7.25.0", "@babel/plugin-transform-async-to-generator": "^7.24.7", "@babel/plugin-transform-block-scoped-functions": "^7.24.7", - "@babel/plugin-transform-block-scoping": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.25.0", "@babel/plugin-transform-class-properties": "^7.24.7", "@babel/plugin-transform-class-static-block": "^7.24.7", - "@babel/plugin-transform-classes": "^7.24.8", + "@babel/plugin-transform-classes": "^7.25.0", "@babel/plugin-transform-computed-properties": "^7.24.7", "@babel/plugin-transform-destructuring": "^7.24.8", "@babel/plugin-transform-dotall-regex": "^7.24.7", "@babel/plugin-transform-duplicate-keys": "^7.24.7", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.0", "@babel/plugin-transform-dynamic-import": "^7.24.7", "@babel/plugin-transform-exponentiation-operator": "^7.24.7", "@babel/plugin-transform-export-namespace-from": "^7.24.7", "@babel/plugin-transform-for-of": "^7.24.7", - "@babel/plugin-transform-function-name": "^7.24.7", + "@babel/plugin-transform-function-name": "^7.25.1", "@babel/plugin-transform-json-strings": "^7.24.7", - "@babel/plugin-transform-literals": "^7.24.7", + "@babel/plugin-transform-literals": "^7.25.2", "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", "@babel/plugin-transform-member-expression-literals": "^7.24.7", "@babel/plugin-transform-modules-amd": "^7.24.7", "@babel/plugin-transform-modules-commonjs": "^7.24.8", - "@babel/plugin-transform-modules-systemjs": "^7.24.7", + "@babel/plugin-transform-modules-systemjs": "^7.25.0", "@babel/plugin-transform-modules-umd": "^7.24.7", "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", "@babel/plugin-transform-new-target": "^7.24.7", @@ -1793,33 +1812,30 @@ } }, "node_modules/@babel/template": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", - "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", + "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", "dev": true, "dependencies": { "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/parser": "^7.25.0", + "@babel/types": "^7.25.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.8.tgz", - "integrity": "sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ==", + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.3.tgz", + "integrity": "sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ==", "dev": true, "dependencies": { "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.8", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/parser": "^7.24.8", - "@babel/types": "^7.24.8", + "@babel/generator": "^7.25.0", + "@babel/parser": "^7.25.3", + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.2", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -1828,9 +1844,9 @@ } }, "node_modules/@babel/types": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.9.tgz", - "integrity": "sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz", + "integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.24.8", @@ -1848,15 +1864,15 @@ "dev": true }, "node_modules/@commitlint/cli": { - "version": "19.3.0", - "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-19.3.0.tgz", - "integrity": "sha512-LgYWOwuDR7BSTQ9OLZ12m7F/qhNY+NpAyPBgo4YNMkACE7lGuUnuQq1yi9hz1KA4+3VqpOYl8H1rY/LYK43v7g==", + "version": "19.4.0", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-19.4.0.tgz", + "integrity": "sha512-sJX4J9UioVwZHq7JWM9tjT5bgWYaIN3rC4FP7YwfEwBYiIO+wMyRttRvQLNkow0vCdM0D67r9NEWU0Ui03I4Eg==", "dev": true, "dependencies": { "@commitlint/format": "^19.3.0", "@commitlint/lint": "^19.2.2", - "@commitlint/load": "^19.2.0", - "@commitlint/read": "^19.2.1", + "@commitlint/load": "^19.4.0", + "@commitlint/read": "^19.4.0", "@commitlint/types": "^19.0.3", "execa": "^8.0.1", "yargs": "^17.0.0" @@ -2120,9 +2136,9 @@ } }, "node_modules/@commitlint/load": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-19.2.0.tgz", - "integrity": "sha512-XvxxLJTKqZojCxaBQ7u92qQLFMMZc4+p9qrIq/9kJDy8DOrEa7P1yx7Tjdc2u2JxIalqT4KOGraVgCE7eCYJyQ==", + "version": "19.4.0", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-19.4.0.tgz", + "integrity": "sha512-I4lCWaEZYQJ1y+Y+gdvbGAx9pYPavqZAZ3/7/8BpWh+QjscAn8AjsUpLV2PycBsEx7gupq5gM4BViV9xwTIJuw==", "dev": true, "dependencies": { "@commitlint/config-validator": "^19.0.3", @@ -2176,9 +2192,9 @@ } }, "node_modules/@commitlint/read": { - "version": "19.2.1", - "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-19.2.1.tgz", - "integrity": "sha512-qETc4+PL0EUv7Q36lJbPG+NJiBOGg7SSC7B5BsPWOmei+Dyif80ErfWQ0qXoW9oCh7GTpTNRoaVhiI8RbhuaNw==", + "version": "19.4.0", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-19.4.0.tgz", + "integrity": "sha512-r95jLOEZzKDakXtnQub+zR3xjdnrl2XzerPwm7ch1/cc5JGq04tyaNpa6ty0CRCWdVrk4CZHhqHozb8yZwy2+g==", "dev": true, "dependencies": { "@commitlint/top-level": "^19.0.0", @@ -2539,16 +2555,16 @@ } }, "node_modules/@cspell/cspell-bundled-dicts": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-8.11.0.tgz", - "integrity": "sha512-SYAW1oT9jjnbwju5P6luTnKogEe8DGUVmUO0O02LxYNmgE2eJt8pKZcy3RtR9V7Q5WW8PWsXXq0Xvoseji0olg==", + "version": "8.13.3", + "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-8.13.3.tgz", + "integrity": "sha512-OfCxUBMyayxKyeDaUZG3LQpiyH8MFUbg9nbIZCGh2x8U6N0fHaP9uR6R+gPzdi/bJp32Kr+RC/Yebojd+AQCGA==", "dev": true, "dependencies": { "@cspell/dict-ada": "^4.0.2", "@cspell/dict-aws": "^4.0.3", "@cspell/dict-bash": "^4.1.3", - "@cspell/dict-companies": "^3.1.2", - "@cspell/dict-cpp": "^5.1.10", + "@cspell/dict-companies": "^3.1.4", + "@cspell/dict-cpp": "^5.1.12", "@cspell/dict-cryptocurrencies": "^5.0.0", "@cspell/dict-csharp": "^4.0.2", "@cspell/dict-css": "^4.0.12", @@ -2558,12 +2574,12 @@ "@cspell/dict-dotnet": "^5.0.2", "@cspell/dict-elixir": "^4.0.3", "@cspell/dict-en_us": "^4.3.23", - "@cspell/dict-en-common-misspellings": "^2.0.3", + "@cspell/dict-en-common-misspellings": "^2.0.4", "@cspell/dict-en-gb": "1.1.33", "@cspell/dict-filetypes": "^3.0.4", "@cspell/dict-fonts": "^4.0.0", "@cspell/dict-fsharp": "^1.0.1", - "@cspell/dict-fullstack": "^3.1.8", + "@cspell/dict-fullstack": "^3.2.0", "@cspell/dict-gaming-terms": "^1.0.5", "@cspell/dict-git": "^3.0.0", "@cspell/dict-golang": "^6.0.9", @@ -2573,28 +2589,28 @@ "@cspell/dict-html-symbol-entities": "^4.0.0", "@cspell/dict-java": "^5.0.7", "@cspell/dict-julia": "^1.0.1", - "@cspell/dict-k8s": "^1.0.5", + "@cspell/dict-k8s": "^1.0.6", "@cspell/dict-latex": "^4.0.0", "@cspell/dict-lorem-ipsum": "^4.0.0", "@cspell/dict-lua": "^4.0.3", "@cspell/dict-makefile": "^1.0.0", "@cspell/dict-monkeyc": "^1.0.6", "@cspell/dict-node": "^5.0.1", - "@cspell/dict-npm": "^5.0.16", + "@cspell/dict-npm": "^5.0.18", "@cspell/dict-php": "^4.0.8", - "@cspell/dict-powershell": "^5.0.4", + "@cspell/dict-powershell": "^5.0.5", "@cspell/dict-public-licenses": "^2.0.7", - "@cspell/dict-python": "^4.2.1", + "@cspell/dict-python": "^4.2.4", "@cspell/dict-r": "^2.0.1", "@cspell/dict-ruby": "^5.0.2", - "@cspell/dict-rust": "^4.0.4", - "@cspell/dict-scala": "^5.0.2", - "@cspell/dict-software-terms": "^3.4.10", - "@cspell/dict-sql": "^2.1.3", + "@cspell/dict-rust": "^4.0.5", + "@cspell/dict-scala": "^5.0.3", + "@cspell/dict-software-terms": "^4.0.6", + "@cspell/dict-sql": "^2.1.5", "@cspell/dict-svelte": "^1.0.2", "@cspell/dict-swift": "^2.0.1", "@cspell/dict-terraform": "^1.0.0", - "@cspell/dict-typescript": "^3.1.5", + "@cspell/dict-typescript": "^3.1.6", "@cspell/dict-vue": "^3.0.0" }, "engines": { @@ -2602,30 +2618,30 @@ } }, "node_modules/@cspell/cspell-json-reporter": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/@cspell/cspell-json-reporter/-/cspell-json-reporter-8.11.0.tgz", - "integrity": "sha512-GSk2dKZHak4EuRXRKpyW3EsxmJmirkcZoM6sJQh6ZaFXSffMPgydNNIeL2xH/2hnwE7yWcP0ryq8hOxlrl9mVw==", + "version": "8.13.3", + "resolved": "https://registry.npmjs.org/@cspell/cspell-json-reporter/-/cspell-json-reporter-8.13.3.tgz", + "integrity": "sha512-QrHxWkm0cfD+rTjFOxm5lpE4+wBANDzMIM8NOeQC6v8Dc1L8PUkm6hF6CsEv2tKmuwvdVr+jy6GilDMkPXalCg==", "dev": true, "dependencies": { - "@cspell/cspell-types": "8.11.0" + "@cspell/cspell-types": "8.13.3" }, "engines": { "node": ">=18" } }, "node_modules/@cspell/cspell-pipe": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-8.11.0.tgz", - "integrity": "sha512-VNWoAb2Y5VO87O8FipQZfk7H5aDhjE2HbGInVWC1x+qNMyQvnh3WYexa5r0Z4g3WqdTPhhpZdeBHnEfcdBwmOw==", + "version": "8.13.3", + "resolved": "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-8.13.3.tgz", + "integrity": "sha512-6a9Zd+fDltgXoJ0fosWqEMx0UdXBXZ7iakhslMNPRmv7GhVAoHBoIXzMVilOE4kYT2Mh/9NM/QW/NbNEpneZIQ==", "dev": true, "engines": { "node": ">=18" } }, "node_modules/@cspell/cspell-resolver": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/@cspell/cspell-resolver/-/cspell-resolver-8.11.0.tgz", - "integrity": "sha512-4qqYBct6wsdoDCnTvt7rfpBE3ARegLDTeYOxglZLE3xZj0vpI1LZiGc3jgroTql866Lqy+IeRCwnQd5GXrqtmg==", + "version": "8.13.3", + "resolved": "https://registry.npmjs.org/@cspell/cspell-resolver/-/cspell-resolver-8.13.3.tgz", + "integrity": "sha512-vlwtMTEWsPPtWfktzT75eGQ0n+0M+9kN+89eSvUUYdCfvY9XAS6z+bTmhS2ULJgntgWtX6gUjABQK0PYYVedOg==", "dev": true, "dependencies": { "global-directory": "^4.0.1" @@ -2635,18 +2651,18 @@ } }, "node_modules/@cspell/cspell-service-bus": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/@cspell/cspell-service-bus/-/cspell-service-bus-8.11.0.tgz", - "integrity": "sha512-W7BBouT5prXvvh9javWTzZN3vvnSujS3agrOjRQ5BuimOgLonUwydimuSTDFIkyvT6ZwzyIVO4r984w3OcYyzg==", + "version": "8.13.3", + "resolved": "https://registry.npmjs.org/@cspell/cspell-service-bus/-/cspell-service-bus-8.13.3.tgz", + "integrity": "sha512-mFkeWXwGQSDxRiN6Kez77GaMNGNgG7T6o9UE42jyXEgf/bLJTpefbUy4fY5pU3p2mA0eoMzmnJX8l+TC5YJpbA==", "dev": true, "engines": { "node": ">=18" } }, "node_modules/@cspell/cspell-types": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-8.11.0.tgz", - "integrity": "sha512-WNscRYt7MHhJhv2E8GbNoyUVZnRvWsz8O+OFrMjmGO6PxokQRnuKRp3rgHpZxL0NR4xw+2xyZKYC/9iOQ6yCnQ==", + "version": "8.13.3", + "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-8.13.3.tgz", + "integrity": "sha512-lA5GbhLOL6FlKCWNMbooRFgNGfTsM6NJnHz60+EEN7XD9OgpFc7w+MBcK4aHsVCxcrIvnejIc8xQDqPnrdmN3w==", "dev": true, "engines": { "node": ">=18" @@ -2671,15 +2687,15 @@ "dev": true }, "node_modules/@cspell/dict-companies": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-companies/-/dict-companies-3.1.2.tgz", - "integrity": "sha512-OwR5i1xbYuJX7FtHQySmTy3iJtPV1rZQ3jFCxFGwrA1xRQ4rtRcDQ+sTXBCIAoJHkXa84f9J3zsngOKmMGyS/w==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-companies/-/dict-companies-3.1.4.tgz", + "integrity": "sha512-y9e0amzEK36EiiKx3VAA+SHQJPpf2Qv5cCt5eTUSggpTkiFkCh6gRKQ97rVlrKh5GJrqinDwYIJtTsxuh2vy2Q==", "dev": true }, "node_modules/@cspell/dict-cpp": { - "version": "5.1.10", - "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-5.1.10.tgz", - "integrity": "sha512-BmIF0sAz2BgGEOwzYIeEm9ALneDjd1tcTbFbo+A1Hcq3zOKP8yViSgxS9CEN30KOZIyph6Tldp531UPEpoEl0Q==", + "version": "5.1.12", + "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-5.1.12.tgz", + "integrity": "sha512-6lXLOFIa+k/qBcu0bjaE/Kc6v3sh9VhsDOXD1Dalm3zgd0QIMjp5XBmkpSdCAK3pWCPV0Se7ysVLDfCea1BuXg==", "dev": true }, "node_modules/@cspell/dict-cryptocurrencies": { @@ -2695,9 +2711,9 @@ "dev": true }, "node_modules/@cspell/dict-css": { - "version": "4.0.12", - "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-4.0.12.tgz", - "integrity": "sha512-vGBgPM92MkHQF5/2jsWcnaahOZ+C6OE/fPvd5ScBP72oFY9tn5GLuomcyO0z8vWCr2e0nUSX1OGimPtcQAlvSw==", + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-4.0.13.tgz", + "integrity": "sha512-WfOQkqlAJTo8eIQeztaH0N0P+iF5hsJVKFuhy4jmARPISy8Efcv8QXk2/IVbmjJH0/ZV7dKRdnY5JFVXuVz37g==", "dev": true }, "node_modules/@cspell/dict-dart": { @@ -2743,9 +2759,9 @@ "dev": true }, "node_modules/@cspell/dict-en-common-misspellings": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@cspell/dict-en-common-misspellings/-/dict-en-common-misspellings-2.0.3.tgz", - "integrity": "sha512-8nF1z9nUiSgMyikL66HTbDO7jCGtB24TxKBasXIBwkBKMDZgA2M883iXdeByy6m1JJUcCGFkSftVYp2W0bUgjw==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-en-common-misspellings/-/dict-en-common-misspellings-2.0.4.tgz", + "integrity": "sha512-lvOiRjV/FG4pAGZL3PN2GCVHSTCE92cwhfLGGkOsQtxSmef6WCHfHwp9auafkBlX0yFQSKDfq6/TlpQbjbJBtQ==", "dev": true }, "node_modules/@cspell/dict-en-gb": { @@ -2773,9 +2789,9 @@ "dev": true }, "node_modules/@cspell/dict-fullstack": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@cspell/dict-fullstack/-/dict-fullstack-3.1.8.tgz", - "integrity": "sha512-YRlZupL7uqMCtEBK0bDP9BrcPnjDhz7m4GBqCc1EYqfXauHbLmDT8ELha7T/E7wsFKniHSjzwDZzhNXo2lusRQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-fullstack/-/dict-fullstack-3.2.0.tgz", + "integrity": "sha512-sIGQwU6G3rLTo+nx0GKyirR5dQSFeTIzFTOrURw51ISf+jKG9a3OmvsVtc2OANfvEAOLOC9Wfd8WYhmsO8KRDQ==", "dev": true }, "node_modules/@cspell/dict-gaming-terms": { @@ -2833,9 +2849,9 @@ "dev": true }, "node_modules/@cspell/dict-k8s": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-k8s/-/dict-k8s-1.0.5.tgz", - "integrity": "sha512-Cj+/ZV4S+MKlwfocSJZqe/2UAd/sY8YtlZjbK25VN1nCnrsKrBjfkX29vclwSj1U9aJg4Z9jw/uMjoaKu9ZrpQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-k8s/-/dict-k8s-1.0.6.tgz", + "integrity": "sha512-srhVDtwrd799uxMpsPOQqeDJY+gEocgZpoK06EFrb4GRYGhv7lXo9Fb+xQMyQytzOW9dw4DNOEck++nacDuymg==", "dev": true }, "node_modules/@cspell/dict-latex": { @@ -2875,9 +2891,9 @@ "dev": true }, "node_modules/@cspell/dict-npm": { - "version": "5.0.16", - "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-5.0.16.tgz", - "integrity": "sha512-ZWPnLAziEcSCvV0c8k9Qj88pfMu+wZwM5Qks87ShsfBgI8uLZ9tGHravA7gmjH1Gd7Bgxy2ulvXtSqIWPh1lew==", + "version": "5.0.18", + "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-5.0.18.tgz", + "integrity": "sha512-weMTyxWpzz19q4wv9n183BtFvdD5fCjtze+bFKpl+4rO/YlPhHL2cXLAeexJz/VDSBecwX4ybTZYoknd1h2J4w==", "dev": true }, "node_modules/@cspell/dict-php": { @@ -2887,9 +2903,9 @@ "dev": true }, "node_modules/@cspell/dict-powershell": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@cspell/dict-powershell/-/dict-powershell-5.0.4.tgz", - "integrity": "sha512-eosDShapDgBWN9ULF7+sRNdUtzRnUdsfEdBSchDm8FZA4HOqxUSZy3b/cX/Rdw0Fnw0AKgk0kzgXw7tS6vwJMQ==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-powershell/-/dict-powershell-5.0.5.tgz", + "integrity": "sha512-3JVyvMoDJesAATYGOxcUWPbQPUvpZmkinV3m8HL1w1RrjeMVXXuK7U1jhopSneBtLhkU+9HKFwgh9l9xL9mY2Q==", "dev": true }, "node_modules/@cspell/dict-public-licenses": { @@ -2899,9 +2915,9 @@ "dev": true }, "node_modules/@cspell/dict-python": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-python/-/dict-python-4.2.1.tgz", - "integrity": "sha512-9X2jRgyM0cxBoFQRo4Zc8oacyWnXi+0/bMI5FGibZNZV4y/o9UoFEr6agjU260/cXHTjIdkX233nN7eb7dtyRg==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-python/-/dict-python-4.2.4.tgz", + "integrity": "sha512-sCtLBqMreb+8zRW2bXvFsfSnRUVU6IFm4mT6Dc4xbz0YajprbaPPh/kOUTw5IJRP8Uh+FFb7Xp2iH03CNWRq/A==", "dev": true, "dependencies": { "@cspell/dict-data-science": "^2.0.1" @@ -2920,27 +2936,27 @@ "dev": true }, "node_modules/@cspell/dict-rust": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@cspell/dict-rust/-/dict-rust-4.0.4.tgz", - "integrity": "sha512-v9/LcZknt/Xq7m1jdTWiQEtmkVVKdE1etAfGL2sgcWpZYewEa459HeWndNA0gfzQrpWX9sYay18mt7pqClJEdA==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-rust/-/dict-rust-4.0.5.tgz", + "integrity": "sha512-DIvlPRDemjKQy8rCqftAgGNZxY5Bg+Ps7qAIJjxkSjmMETyDgl0KTVuaJPt7EK4jJt6uCZ4ILy96npsHDPwoXA==", "dev": true }, "node_modules/@cspell/dict-scala": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-scala/-/dict-scala-5.0.2.tgz", - "integrity": "sha512-v97ClgidZt99JUm7OjhQugDHmhx4U8fcgunHvD/BsXWjXNj4cTr0m0YjofyZoL44WpICsNuFV9F/sv9OM5HUEw==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-scala/-/dict-scala-5.0.3.tgz", + "integrity": "sha512-4yGb4AInT99rqprxVNT9TYb1YSpq58Owzq7zi3ZS5T0u899Y4VsxsBiOgHnQ/4W+ygi+sp+oqef8w8nABR2lkg==", "dev": true }, "node_modules/@cspell/dict-software-terms": { - "version": "3.4.10", - "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-3.4.10.tgz", - "integrity": "sha512-S5S2sz98v4GWJ9TMo62Vp4L5RM/329e5UQfFn7yJfieTcrfXRH4IweVdz34rZcK9o5coGptgBUIv/Jcrd4cMpg==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-4.0.6.tgz", + "integrity": "sha512-UDhUzNSf7GN529a0Ip9hlSoGbpscz0YlUYBEJmZBXi8otpkrbCJqs50T74Ppd+SWqNil04De8urv4af2c6SY5Q==", "dev": true }, "node_modules/@cspell/dict-sql": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@cspell/dict-sql/-/dict-sql-2.1.3.tgz", - "integrity": "sha512-SEyTNKJrjqD6PAzZ9WpdSu6P7wgdNtGV2RV8Kpuw1x6bV+YsSptuClYG+JSdRExBTE6LwIe1bTklejUp3ZP8TQ==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-sql/-/dict-sql-2.1.5.tgz", + "integrity": "sha512-FmxanytHXss7GAWAXmgaxl3icTCW7YxlimyOSPNfm+njqeUDjw3kEv4mFNDDObBJv8Ec5AWCbUDkWIpkE3IpKg==", "dev": true }, "node_modules/@cspell/dict-svelte": { @@ -2962,9 +2978,9 @@ "dev": true }, "node_modules/@cspell/dict-typescript": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-3.1.5.tgz", - "integrity": "sha512-EkIwwNV/xqEoBPJml2S16RXj65h1kvly8dfDLgXerrKw6puybZdvAHerAph6/uPTYdtLcsPyJYkPt5ISOJYrtw==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-3.1.6.tgz", + "integrity": "sha512-1beC6O4P/j23VuxX+i0+F7XqPVc3hhiAzGJHEKqnWf5cWAXQtg0xz3xQJ5MvYx2a7iLaSa+lu7+05vG9UHyu9Q==", "dev": true }, "node_modules/@cspell/dict-vue": { @@ -2974,9 +2990,9 @@ "dev": true }, "node_modules/@cspell/dynamic-import": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/@cspell/dynamic-import/-/dynamic-import-8.11.0.tgz", - "integrity": "sha512-Xk5iQQZ23Q9IR9N5YQb4J0mXOegIBw2/aJ7mYjMQZ24I5fL47Ir45cd5a8m5UEMheZppfrolVsDoTEgXnAfPDQ==", + "version": "8.13.3", + "resolved": "https://registry.npmjs.org/@cspell/dynamic-import/-/dynamic-import-8.13.3.tgz", + "integrity": "sha512-YN83CFWnMkt9B0q0RBadfEoptUaDRqBikh8b91MOQ0haEnUo6t57j4jAaLnbIEP4ynzMhgruWFKpIC/QaEtCuA==", "dev": true, "dependencies": { "import-meta-resolve": "^4.1.0" @@ -2986,18 +3002,18 @@ } }, "node_modules/@cspell/strong-weak-map": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/@cspell/strong-weak-map/-/strong-weak-map-8.11.0.tgz", - "integrity": "sha512-XumxAVA1Pi5U8d+qqo2//KPrsOINOHnHpal/yPu8FwfZhkRzpDnNPdgiMNKBVmZMFxmSCEJwc7AUUMnfyuGuLg==", + "version": "8.13.3", + "resolved": "https://registry.npmjs.org/@cspell/strong-weak-map/-/strong-weak-map-8.13.3.tgz", + "integrity": "sha512-/QYUEthesPuDarOHa6kcWKJmVq0HIotjPrmAWQ5QpH+dDik1Qin4G/9QdnWX75ueR4DC4WFjBNBU14C4TVSwHQ==", "dev": true, "engines": { "node": ">=18" } }, "node_modules/@cspell/url": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/@cspell/url/-/url-8.11.0.tgz", - "integrity": "sha512-X0l/WJmavRqRKDgsgEjXHGizmvYt40omMTmNOLPHUa2jxL+a2ayuQD3GMFC8Omassjk3bSyFByftmgJDI+P2ZA==", + "version": "8.13.3", + "resolved": "https://registry.npmjs.org/@cspell/url/-/url-8.13.3.tgz", + "integrity": "sha512-hsxoTnZHwtdR2x9QEE6yfDBB1LUwAj67o1GyKTvI8A2OE/AfzAttirZs+9sxgOGWoBdTOxM9sMLtqB3SxtDB3A==", "dev": true, "engines": { "node": ">=18.0" @@ -3144,9 +3160,9 @@ "dev": true }, "node_modules/@fastify/express": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@fastify/express/-/express-2.3.0.tgz", - "integrity": "sha512-jvvjlPPCfJsSHfF6tQDyARJ3+c3xXiqcxVZu6bi3xMWCWB3fl07vrjFDeaqnwqKhLZ9+m6cog5dw7gIMKEsTnQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@fastify/express/-/express-3.0.0.tgz", + "integrity": "sha512-Ug6aulXCUiHgMyrHVYQqnQbGdsAV0aTad6nZxbOr6w3QjKn1mdQS3Kyzvc+I0xMjZ9yIyMUWHSooHgZ0l7nOng==", "dev": true, "dependencies": { "express": "^4.17.1", @@ -4422,9 +4438,9 @@ } }, "node_modules/@jsonjoy.com/util": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.2.0.tgz", - "integrity": "sha512-4B8B+3vFsY4eo33DMKyJPlQ3sBMpPFUZK2dr3O3rXrOGKKbYG44J0XSFkDo1VOQiri5HFEhIeVvItjR2xcazmg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.3.0.tgz", + "integrity": "sha512-Cebt4Vk7k1xHy87kHY7KSPLT77A7Ev7IfOblyLZhtYEhrdQ6fX4EoLq3xOQ3O/DRMEh2ok5nyC180E+ABS8Wmw==", "engines": { "node": ">=10.0" }, @@ -4717,12 +4733,12 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.14.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz", - "integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==", + "version": "22.3.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.3.0.tgz", + "integrity": "sha512-nrWpWVaDZuaVc5X84xJ0vNrLvomM205oQyLsRt7OHNZbSHslcWsvgFR7O7hire2ZonjLrWBbedmotmIlJDVd6g==", "dev": true, "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.18.2" } }, "node_modules/@types/normalize-package-data": { @@ -5037,19 +5053,6 @@ "integrity": "sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==", "dev": true }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/ajv": { "version": "8.16.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", @@ -5204,15 +5207,6 @@ "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==", "dev": true }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/array.prototype.findlastindex": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", @@ -5934,15 +5928,6 @@ "integrity": "sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==", "dev": true }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/clear-module": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/clear-module/-/clear-module-4.1.2.tgz", @@ -5960,15 +5945,15 @@ } }, "node_modules/cli-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", - "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "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, "dependencies": { - "restore-cursor": "^4.0.0" + "restore-cursor": "^5.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -6141,9 +6126,9 @@ } }, "node_modules/comment-json": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.2.4.tgz", - "integrity": "sha512-E5AjpSW+O+N5T2GsOQMHLLsJvrYw6G/AFt9GvU6NguEAfzKShh7hRiLtVo6S9KbRpFMGqE5ojo0/hE+sdteWvQ==", + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.2.5.tgz", + "integrity": "sha512-bKw/r35jR3HGt5PEPm1ljsQQGyCrR8sFGNiN5L+ykDHdpO8Smxkrkla9Yi6NkQyUrb8V54PGhfMs6NrIwtxtdw==", "dev": true, "dependencies": { "array-timsort": "^1.0.3", @@ -7725,29 +7710,30 @@ } }, "node_modules/cspell": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/cspell/-/cspell-8.11.0.tgz", - "integrity": "sha512-nyzeSk/Rj4dcuXIV9a3Ri9pJW5gAVDJtTUhyNW9a5rjNcQn+k8uxV8eBgx5s42ESSQrmUh3HhocYy2jLEolunw==", + "version": "8.13.3", + "resolved": "https://registry.npmjs.org/cspell/-/cspell-8.13.3.tgz", + "integrity": "sha512-2wv4Eby7g8wDB553fI8IoZjyitoKrD2kmtdeoYUN2EjVs3RMpIOver3fL+0VaFAaN0uLfAoeAAIB5xJEakvZYQ==", "dev": true, "dependencies": { - "@cspell/cspell-json-reporter": "8.11.0", - "@cspell/cspell-pipe": "8.11.0", - "@cspell/cspell-types": "8.11.0", - "@cspell/dynamic-import": "8.11.0", + "@cspell/cspell-json-reporter": "8.13.3", + "@cspell/cspell-pipe": "8.13.3", + "@cspell/cspell-types": "8.13.3", + "@cspell/dynamic-import": "8.13.3", + "@cspell/url": "8.13.3", "chalk": "^5.3.0", "chalk-template": "^1.1.0", "commander": "^12.1.0", - "cspell-gitignore": "8.11.0", - "cspell-glob": "8.11.0", - "cspell-io": "8.11.0", - "cspell-lib": "8.11.0", + "cspell-dictionary": "8.13.3", + "cspell-gitignore": "8.13.3", + "cspell-glob": "8.13.3", + "cspell-io": "8.13.3", + "cspell-lib": "8.13.3", "fast-glob": "^3.3.2", "fast-json-stable-stringify": "^2.1.0", - "file-entry-cache": "^8.0.0", + "file-entry-cache": "^9.0.0", "get-stdin": "^9.0.0", - "semver": "^7.6.2", - "strip-ansi": "^7.1.0", - "vscode-uri": "^3.0.8" + "semver": "^7.6.3", + "strip-ansi": "^7.1.0" }, "bin": { "cspell": "bin.mjs", @@ -7761,44 +7747,43 @@ } }, "node_modules/cspell-config-lib": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/cspell-config-lib/-/cspell-config-lib-8.11.0.tgz", - "integrity": "sha512-8AE1qm/nuD+aiN+mZXQIGp0ESHyQ9uowbKaB5+qi261HEEhuFPceP/3u0yq0kc1YPtnKxEfYHrLukvQIMlDshA==", + "version": "8.13.3", + "resolved": "https://registry.npmjs.org/cspell-config-lib/-/cspell-config-lib-8.13.3.tgz", + "integrity": "sha512-dzVdar8Kenwxho0PnUxOxwjUvyFYn6Q9mQAMHcQNXQrvo32bdpoF+oNtWC/5FfrQgUgyl19CVQ607bRigYWoOQ==", "dev": true, "dependencies": { - "@cspell/cspell-types": "8.11.0", - "comment-json": "^4.2.4", - "yaml": "^2.4.5" + "@cspell/cspell-types": "8.13.3", + "comment-json": "^4.2.5", + "yaml": "^2.5.0" }, "engines": { "node": ">=18" } }, "node_modules/cspell-dictionary": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/cspell-dictionary/-/cspell-dictionary-8.11.0.tgz", - "integrity": "sha512-h5AVFuTeP+NLBRZbaX6sFGZ/wnvnyeeGtnNiYU0f4dVB3Yq0K9c7QXM8PllIpcbe+SBDoQ15ZlbECzUlGt/Ysg==", + "version": "8.13.3", + "resolved": "https://registry.npmjs.org/cspell-dictionary/-/cspell-dictionary-8.13.3.tgz", + "integrity": "sha512-DQ3Tee7LIoy+9Mu52ht32O/MNBZ6i4iUeSTY2sMDDwogno3361BLRyfEjyiYNo3Fqf0Pcnt5MqY2DqIhrF/H/Q==", "dev": true, "dependencies": { - "@cspell/cspell-pipe": "8.11.0", - "@cspell/cspell-types": "8.11.0", - "cspell-trie-lib": "8.11.0", - "fast-equals": "^5.0.1", - "gensequence": "^7.0.0" + "@cspell/cspell-pipe": "8.13.3", + "@cspell/cspell-types": "8.13.3", + "cspell-trie-lib": "8.13.3", + "fast-equals": "^5.0.1" }, "engines": { "node": ">=18" } }, "node_modules/cspell-gitignore": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-8.11.0.tgz", - "integrity": "sha512-r+buXvm3NqU/5N1zmiXSgo7DQLZyKR5sr6McepWlGBmT4DDm7s22yojS8LSusIthJ2k3tvLFDI9O4Rs0DnzK2Q==", + "version": "8.13.3", + "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-8.13.3.tgz", + "integrity": "sha512-0OZXuP33CXV4P95ySHGNqhq3VR5RaLwpyo0nGvLHOjPm3mCsQSjURLBKHvyQ3r2M7LWsGV1Xc81FfTx30FBZLg==", "dev": true, "dependencies": { - "@cspell/url": "8.11.0", - "cspell-glob": "8.11.0", - "cspell-io": "8.11.0", + "@cspell/url": "8.13.3", + "cspell-glob": "8.13.3", + "cspell-io": "8.13.3", "find-up-simple": "^1.0.0" }, "bin": { @@ -7809,12 +7794,12 @@ } }, "node_modules/cspell-glob": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-8.11.0.tgz", - "integrity": "sha512-X0cEErrQdrVLXDMse84QH/iV2Q+f7AsXxIjlSt+6PPEoDz8yRO8xD71iaaeE/8+cMFrKMl0uDpIpBQ5OlvcIyQ==", + "version": "8.13.3", + "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-8.13.3.tgz", + "integrity": "sha512-+jGIMYyKDLmoOJIxNPXRdI7utcvw+9FMSmj1ApIdEff5dCkehi0gtzK4H7orXGYEvRdKQvfaXiyduVi79rXsZQ==", "dev": true, "dependencies": { - "@cspell/url": "8.11.0", + "@cspell/url": "8.13.3", "micromatch": "^4.0.7" }, "engines": { @@ -7822,13 +7807,13 @@ } }, "node_modules/cspell-grammar": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/cspell-grammar/-/cspell-grammar-8.11.0.tgz", - "integrity": "sha512-fIq7/KDjNMfBBqKTnnp4dhjNmbvnl019bPwecddkQOpx5H9Vn4WVDTiAZbI6/5Li/VU+h1Ld2+pIOKYql/7DBg==", + "version": "8.13.3", + "resolved": "https://registry.npmjs.org/cspell-grammar/-/cspell-grammar-8.13.3.tgz", + "integrity": "sha512-xPSgKk9HY5EsI8lkMPC9hiZCeAUs+RY/IVliUBW1xEicAJhP4RZIGRdIwtDNNJGwKfNXazjqYhcS4LS0q7xPAQ==", "dev": true, "dependencies": { - "@cspell/cspell-pipe": "8.11.0", - "@cspell/cspell-types": "8.11.0" + "@cspell/cspell-pipe": "8.13.3", + "@cspell/cspell-types": "8.13.3" }, "bin": { "cspell-grammar": "bin.mjs" @@ -7838,45 +7823,45 @@ } }, "node_modules/cspell-io": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-8.11.0.tgz", - "integrity": "sha512-R6ZCNh2RrOkP3/OIpFHmtg6vztxMMsl6/t5kY1nTcmWv/1Ltw56G3q357KN6e+8epFiqFm4gMFmvzImFeR34Yw==", + "version": "8.13.3", + "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-8.13.3.tgz", + "integrity": "sha512-AeMIkz7+4VuJaPKO/v1pUpyUSOOTyLOAfzeTRRAXEt+KRKOUe36MyUmBMza6gzNcX2yD04VgJukRL408TY9ntw==", "dev": true, "dependencies": { - "@cspell/cspell-service-bus": "8.11.0", - "@cspell/url": "8.11.0" + "@cspell/cspell-service-bus": "8.13.3", + "@cspell/url": "8.13.3" }, "engines": { "node": ">=18" } }, "node_modules/cspell-lib": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-8.11.0.tgz", - "integrity": "sha512-msdfqJLIhJE1whfGXC2J669dKWrnWdFI18nR2OTXipWdiwZDDQEFT3q2Pq56+bhxwtoqAZKrez/zhRB/JbpUuA==", - "dev": true, - "dependencies": { - "@cspell/cspell-bundled-dicts": "8.11.0", - "@cspell/cspell-pipe": "8.11.0", - "@cspell/cspell-resolver": "8.11.0", - "@cspell/cspell-types": "8.11.0", - "@cspell/dynamic-import": "8.11.0", - "@cspell/strong-weak-map": "8.11.0", - "@cspell/url": "8.11.0", + "version": "8.13.3", + "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-8.13.3.tgz", + "integrity": "sha512-aEqxIILeqDtNoCa47/oSl5c926b50ue3PobYs4usn0Ymf0434RopCP+DCGsF7BPtog4j4XWnEmvkcJs57DYWDg==", + "dev": true, + "dependencies": { + "@cspell/cspell-bundled-dicts": "8.13.3", + "@cspell/cspell-pipe": "8.13.3", + "@cspell/cspell-resolver": "8.13.3", + "@cspell/cspell-types": "8.13.3", + "@cspell/dynamic-import": "8.13.3", + "@cspell/strong-weak-map": "8.13.3", + "@cspell/url": "8.13.3", "clear-module": "^4.1.2", - "comment-json": "^4.2.4", - "cspell-config-lib": "8.11.0", - "cspell-dictionary": "8.11.0", - "cspell-glob": "8.11.0", - "cspell-grammar": "8.11.0", - "cspell-io": "8.11.0", - "cspell-trie-lib": "8.11.0", + "comment-json": "^4.2.5", + "cspell-config-lib": "8.13.3", + "cspell-dictionary": "8.13.3", + "cspell-glob": "8.13.3", + "cspell-grammar": "8.13.3", + "cspell-io": "8.13.3", + "cspell-trie-lib": "8.13.3", "env-paths": "^3.0.0", "fast-equals": "^5.0.1", "gensequence": "^7.0.0", "import-fresh": "^3.3.0", "resolve-from": "^5.0.0", - "vscode-languageserver-textdocument": "^1.0.11", + "vscode-languageserver-textdocument": "^1.0.12", "vscode-uri": "^3.0.8", "xdg-basedir": "^5.1.0" }, @@ -7897,13 +7882,13 @@ } }, "node_modules/cspell-trie-lib": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-8.11.0.tgz", - "integrity": "sha512-PRW2ve2F3LBN1a/AwuuxHJ+VHPh9mN01qDAnyQojfqoF7ckRBe7+8Jb+7V9GonBS/oFQJ7AwObXtM2j0FP/DnQ==", + "version": "8.13.3", + "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-8.13.3.tgz", + "integrity": "sha512-Z0iLGi9HI+Vf+WhVVeru6dYgQdtaYCKWRlc1SayLfAZhw9BcjrXL8KTXDfAfv/lUgnRu6xwP1isLlDNZECsKVQ==", "dev": true, "dependencies": { - "@cspell/cspell-pipe": "8.11.0", - "@cspell/cspell-types": "8.11.0", + "@cspell/cspell-pipe": "8.13.3", + "@cspell/cspell-types": "8.13.3", "gensequence": "^7.0.0" }, "engines": { @@ -7944,9 +7929,9 @@ } }, "node_modules/cspell/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -8043,9 +8028,9 @@ } }, "node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -8162,28 +8147,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/del": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", - "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", - "dev": true, - "dependencies": { - "globby": "^11.0.1", - "graceful-fs": "^4.2.4", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.2", - "p-map": "^4.0.0", - "rimraf": "^3.0.2", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/del-cli": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/del-cli/-/del-cli-5.1.0.tgz", @@ -8642,15 +8605,6 @@ "node": ">=10" } }, - "node_modules/del/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -8901,6 +8855,18 @@ "node": ">=6" } }, + "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, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -9920,15 +9886,15 @@ } }, "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==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-9.0.0.tgz", + "integrity": "sha512-6MgEugi8p2tiUhqO7GnPsmbCCzj0YRCwwaTbpGRyKZesjRSzkqkAE9fPp7V2yMs5hwfgbQLgdvSSkGNg1s5Uvw==", "dev": true, "dependencies": { - "flat-cache": "^4.0.0" + "flat-cache": "^5.0.0" }, "engines": { - "node": ">=16.0.0" + "node": ">=18" } }, "node_modules/file-loader": { @@ -10089,16 +10055,16 @@ } }, "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==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-5.0.0.tgz", + "integrity": "sha512-JrqFmyUl2PnPi1OvLyTVHnQvwQ0S+e6lGSwu8OkAZlSaNIZciTY2H/cOOROxsBA1m/LZNHDsqAgDZt6akWcjsQ==", "dev": true, "dependencies": { - "flatted": "^3.2.9", + "flatted": "^3.3.1", "keyv": "^4.5.4" }, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/flatted": { @@ -10131,15 +10097,14 @@ } }, "node_modules/formidable": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", - "integrity": "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.1.tgz", + "integrity": "sha512-WJWKelbRHN41m5dumb0/k8TeAx7Id/y3a+Z7QfhxP/htI9Js5zYaEDtG8uMgG0vM0lOlqnmjE99/kfpOYi/0Og==", "dev": true, "dependencies": { "dezalgo": "^1.0.4", "hexoid": "^1.0.0", - "once": "^1.4.0", - "qs": "^6.11.0" + "once": "^1.4.0" }, "funding": { "url": "https://ko-fi.com/tunnckoCore/commissions" @@ -10934,35 +10899,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -11117,9 +11053,9 @@ } }, "node_modules/hono": { - "version": "4.4.13", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.4.13.tgz", - "integrity": "sha512-c6qqenclmQ6wpXzqiElMa2jt423PVCmgBreDfC5s2lPPpGk7d0lOymd8QTzFZyYC5mSSs6imiTMPip+gLwuW/g==", + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.5.5.tgz", + "integrity": "sha512-fXBXHqaVfimWofbelLXci8pZyIwBMkDIwCa4OwZvK+xVbEyYLELVP4DfbGaj1aEM6ZY3hHgs4qLvCO2ChkhgQw==", "dev": true, "engines": { "node": ">=16.0.0" @@ -11210,12 +11146,12 @@ } }, "node_modules/husky": { - "version": "9.0.11", - "resolved": "https://registry.npmjs.org/husky/-/husky-9.0.11.tgz", - "integrity": "sha512-AB6lFlbwwyIqMdHYhwPe+kjOC3Oc5P3nThEoW/AaO2BX3vJDjWPFxYLxokUZOo6RNX20He3AaT8sESs9NJcmEw==", + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.4.tgz", + "integrity": "sha512-bho94YyReb4JV7LYWRWxZ/xr6TtOTt8cMfmQ39MQYJ7f/YE268s3GdghGwi+y4zAeqewE5zYLvuhV0M0ijsDEA==", "dev": true, "bin": { - "husky": "bin.mjs" + "husky": "bin.js" }, "engines": { "node": ">=18" @@ -11627,15 +11563,6 @@ "node": ">=8" } }, - "node_modules/is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/is-path-inside": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", @@ -13820,21 +13747,21 @@ "dev": true }, "node_modules/lint-staged": { - "version": "15.2.7", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.7.tgz", - "integrity": "sha512-+FdVbbCZ+yoh7E/RosSdqKJyUM2OEjTciH0TFNkawKgvFp1zbGlEC39RADg+xKBG1R4mhoH2j85myBQZ5wR+lw==", + "version": "15.2.9", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.9.tgz", + "integrity": "sha512-BZAt8Lk3sEnxw7tfxM7jeZlPRuT4M68O0/CwZhhaw6eeWu0Lz5eERE3m386InivXB64fp/mDID452h48tvKlRQ==", "dev": true, "dependencies": { "chalk": "~5.3.0", "commander": "~12.1.0", - "debug": "~4.3.4", + "debug": "~4.3.6", "execa": "~8.0.1", - "lilconfig": "~3.1.1", - "listr2": "~8.2.1", + "lilconfig": "~3.1.2", + "listr2": "~8.2.4", "micromatch": "~4.0.7", "pidtree": "~0.6.0", "string-argv": "~0.3.2", - "yaml": "~2.4.2" + "yaml": "~2.5.0" }, "bin": { "lint-staged": "bin/lint-staged.js" @@ -14002,15 +13929,15 @@ } }, "node_modules/listr2": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.3.tgz", - "integrity": "sha512-Lllokma2mtoniUOS94CcOErHWAug5iu7HOmDrvWgpw8jyQH2fomgB+7lZS4HWZxytUuQwkGOwe49FvwVaA85Xw==", + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.4.tgz", + "integrity": "sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==", "dev": true, "dependencies": { "cli-truncate": "^4.0.0", "colorette": "^2.0.20", "eventemitter3": "^5.0.1", - "log-update": "^6.0.0", + "log-update": "^6.1.0", "rfdc": "^1.4.1", "wrap-ansi": "^9.0.0" }, @@ -14175,14 +14102,14 @@ "dev": true }, "node_modules/log-update": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.0.0.tgz", - "integrity": "sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==", + "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, "dependencies": { - "ansi-escapes": "^6.2.0", - "cli-cursor": "^4.0.0", - "slice-ansi": "^7.0.0", + "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" }, @@ -14194,12 +14121,15 @@ } }, "node_modules/log-update/node_modules/ansi-escapes": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", - "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", + "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", "dev": true, + "dependencies": { + "environment": "^1.0.0" + }, "engines": { - "node": ">=14.16" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -14337,12 +14267,12 @@ } }, "node_modules/memfs": { - "version": "4.9.3", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.9.3.tgz", - "integrity": "sha512-bsYSSnirtYTWi1+OPMFb0M048evMKyUYe0EbtuGQgq6BVQM1g1W8/KIUJCCvjgI/El0j6Q4WsmMiBwLUBSw8LA==", + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.11.1.tgz", + "integrity": "sha512-LZcMTBAgqUUKNXZagcZxvXXfgF1bHX7Y7nQ0QyEiNbRJgE29GhgPd8Yna1VQcLlPiHt/5RFJMWYN9Uv/VPNvjQ==", "dependencies": { "@jsonjoy.com/json-pack": "^1.0.3", - "@jsonjoy.com/util": "^1.1.2", + "@jsonjoy.com/util": "^1.3.0", "tree-dump": "^1.0.1", "tslib": "^2.0.0" }, @@ -14458,6 +14388,18 @@ "node": ">=6" } }, + "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, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", @@ -14914,21 +14856,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -15741,21 +15668,48 @@ } }, "node_modules/restore-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", - "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "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, "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/restore-cursor/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, + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/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, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/ret": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/ret/-/ret-0.4.3.tgz", @@ -16728,10 +16682,9 @@ } }, "node_modules/superagent": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.1.2.tgz", - "integrity": "sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==", - "deprecated": "Please upgrade to v9.0.0+ as we have fixed a public vulnerability with formidable dependency. Note that v9.0.0+ requires Node.js v14.18.0+. See https://github.com/ladjs/superagent/pull/1800 for insight. This project is supported and maintained by the team at Forward Email @ https://forwardemail.net", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-9.0.2.tgz", + "integrity": "sha512-xuW7dzkUpcJq7QnhOsnNUgtYp3xRwpt2F7abdRYIpCsAt0hhUqia0EdxyXZQQpNmGtsCzYHryaKSV3q3GJnq7w==", "dev": true, "dependencies": { "component-emitter": "^1.3.0", @@ -16739,14 +16692,13 @@ "debug": "^4.3.4", "fast-safe-stringify": "^2.1.1", "form-data": "^4.0.0", - "formidable": "^2.1.2", + "formidable": "^3.5.1", "methods": "^1.1.2", "mime": "2.6.0", - "qs": "^6.11.0", - "semver": "^7.3.8" + "qs": "^6.11.0" }, "engines": { - "node": ">=6.4.0 <13 || >=14" + "node": ">=14.18.0" } }, "node_modules/superagent/node_modules/mime": { @@ -16761,29 +16713,17 @@ "node": ">=4.0.0" } }, - "node_modules/superagent/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/supertest": { - "version": "6.3.4", - "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.4.tgz", - "integrity": "sha512-erY3HFDG0dPnhw4U+udPfrzXa4xhSG+n4rxfRuZWCUvjFWwKl+OxWf/7zk50s84/fAAs7vf5QAb9uRa0cCykxw==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.0.0.tgz", + "integrity": "sha512-qlsr7fIC0lSddmA3tzojvzubYxvlGtzumcdHgPwbFWMISQwL22MhM2Y3LNt+6w9Yyx7559VW5ab70dgphm8qQA==", "dev": true, "dependencies": { "methods": "^1.1.2", - "superagent": "^8.1.2" + "superagent": "^9.0.1" }, "engines": { - "node": ">=6.4.0" + "node": ">=14.18.0" } }, "node_modules/supports-color": { @@ -17297,9 +17237,9 @@ "dev": true }, "node_modules/typescript": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", - "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -17338,9 +17278,9 @@ } }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "version": "6.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.18.2.tgz", + "integrity": "sha512-5ruQbENj95yDYJNS3TvcaxPMshV7aizdv/hWYjGIKoANWKjhWNBsr2YEuYZKodQulB1b8l7ILOuDQep3afowQQ==", "dev": true }, "node_modules/unicode-canonical-property-names-ecmascript": { @@ -17491,9 +17431,9 @@ } }, "node_modules/vscode-languageserver-textdocument": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.11.tgz", - "integrity": "sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA==", + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", + "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", "dev": true }, "node_modules/vscode-uri": { @@ -17828,9 +17768,9 @@ "dev": true }, "node_modules/yaml": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz", - "integrity": "sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz", + "integrity": "sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==", "dev": true, "bin": { "yaml": "bin.mjs" diff --git a/package.json b/package.json index c24f0946d..93a6665eb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "webpack-dev-middleware", - "version": "7.3.0", + "version": "7.4.0", "description": "A development middleware for webpack", "license": "MIT", "repository": "webpack/webpack-dev-middleware", @@ -66,13 +66,13 @@ "@babel/preset-env": "^7.16.7", "@commitlint/cli": "^19.0.3", "@commitlint/config-conventional": "^19.0.3", - "@fastify/express": "^2.3.0", + "@fastify/express": "^3.0.0", "@hapi/hapi": "^21.3.7", "@hono/node-server": "^1.12.0", "@types/connect": "^3.4.35", "@types/express": "^4.17.13", "@types/mime-types": "^2.1.1", - "@types/node": "^20.11.16", + "@types/node": "^22.3.0", "@types/on-finished": "^2.3.4", "@webpack-contrib/eslint-config-webpack": "^3.0.0", "babel-jest": "^29.3.1", @@ -81,7 +81,6 @@ "cross-env": "^7.0.3", "cspell": "^8.3.2", "deepmerge": "^4.2.2", - "del": "^6.0.0", "del-cli": "^5.0.0", "eslint": "^8.28.0", "eslint-config-prettier": "^9.1.0", @@ -92,7 +91,7 @@ "file-loader": "^6.2.0", "finalhandler": "^1.2.0", "hono": "^4.4.13", - "husky": "^9.0.10", + "husky": "^9.1.3", "jest": "^29.3.1", "joi": "^17.12.2", "koa": "^2.15.2", @@ -102,7 +101,7 @@ "router": "^1.3.8", "standard-version": "^9.3.0", "strip-ansi": "^6.0.0", - "supertest": "^6.1.3", + "supertest": "^7.0.0", "typescript": "^5.3.3", "webpack": "^5.93.0" }, diff --git a/src/index.js b/src/index.js index dc54a75e9..6f9e8ad10 100644 --- a/src/index.js +++ b/src/index.js @@ -118,6 +118,8 @@ const noop = () => {}; * @property {ModifyResponseData} [modifyResponseData] * @property {"weak" | "strong"} [etag] * @property {boolean} [lastModified] + * @property {boolean | number | string | { maxAge?: number, immutable?: boolean }} [cacheControl] + * @property {boolean} [cacheImmutable] */ /** diff --git a/src/middleware.js b/src/middleware.js index 2438df9da..2b4bdcb60 100644 --- a/src/middleware.js +++ b/src/middleware.js @@ -118,6 +118,8 @@ const parseRangeHeaders = memorize( }, ); +const MAX_MAX_AGE = 31536000000; + /** * @template {IncomingMessage} Request * @template {ServerResponse} Response @@ -519,9 +521,9 @@ function wrapper(context) { headers = allHeaders; } - headers.forEach((header) => { - setResponseHeader(res, header.key, header.value); - }); + for (const { key, value } of headers) { + setResponseHeader(res, key, value); + } } if ( @@ -549,6 +551,45 @@ function wrapper(context) { setResponseHeader(res, "Accept-Ranges", "bytes"); } + if (!getResponseHeader(res, "Cache-Control")) { + // TODO enable the `cacheImmutable` by default for the next major release + const cacheControl = + context.options.cacheImmutable && extra.immutable + ? { immutable: true } + : context.options.cacheControl; + + if (cacheControl) { + let cacheControlValue; + + if (typeof cacheControl === "boolean") { + cacheControlValue = "public, max-age=31536000"; + } else if (typeof cacheControl === "number") { + const maxAge = Math.floor( + Math.min(Math.max(0, cacheControl), MAX_MAX_AGE) / 1000, + ); + + cacheControlValue = `public, max-age=${maxAge}`; + } else if (typeof cacheControl === "string") { + cacheControlValue = cacheControl; + } else { + const maxAge = cacheControl.maxAge + ? Math.floor( + Math.min(Math.max(0, cacheControl.maxAge), MAX_MAX_AGE) / + 1000, + ) + : MAX_MAX_AGE / 1000; + + cacheControlValue = `public, max-age=${maxAge}`; + + if (cacheControl.immutable) { + cacheControlValue += ", immutable"; + } + } + + setResponseHeader(res, "Cache-Control", cacheControlValue); + } + } + if ( context.options.lastModified && !getResponseHeader(res, "Last-Modified") @@ -567,7 +608,7 @@ function wrapper(context) { /** @type {undefined | Buffer | ReadStream} */ let bufferOrStream; - /** @type {number} */ + /** @type {number | undefined} */ let byteLength; const rangeHeader = getRangeHeader(); @@ -744,13 +785,17 @@ function wrapper(context) { req, res, bufferOrStream, - // @ts-ignore - byteLength, + /** @type {number} */ + (byteLength), )); } - // @ts-ignore - setResponseHeader(res, "Content-Length", byteLength); + setResponseHeader( + res, + "Content-Length", + /** @type {number} */ + (byteLength), + ); if (method === "HEAD") { if (!isPartialContent) { diff --git a/src/options.json b/src/options.json index 50443e268..0a55b69c9 100644 --- a/src/options.json +++ b/src/options.json @@ -139,6 +139,39 @@ "description": "Enable or disable `Last-Modified` header. Uses the file system's last modified value.", "link": "https://github.com/webpack/webpack-dev-middleware#lastmodified", "type": "boolean" + }, + "cacheControl": { + "description": "Enable or disable setting `Cache-Control` response header.", + "link": "https://github.com/webpack/webpack-dev-middleware#cachecontrol", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string", + "minLength": 1 + }, + { + "type": "object", + "properties": { + "maxAge": { + "type": "number" + }, + "immutable": { + "type": "boolean" + } + }, + "additionalProperties": false + } + ] + }, + "cacheImmutable": { + "description": "Enable or disable setting `Cache-Control: public, max-age=31536000, immutable` response header for immutable assets (i.e. asset with a hash in file name like `image.a4c12bde.jpg`).", + "link": "https://github.com/webpack/webpack-dev-middleware#cacheimmutable", + "type": "boolean" } }, "additionalProperties": false diff --git a/src/utils/getFilenameFromUrl.js b/src/utils/getFilenameFromUrl.js index 7dd7ddb80..2f034060f 100644 --- a/src/utils/getFilenameFromUrl.js +++ b/src/utils/getFilenameFromUrl.js @@ -24,6 +24,7 @@ const UP_PATH_REGEXP = /(?:^|[\\/])\.\.(?:[\\/]|$)/; * @typedef {Object} Extra * @property {import("fs").Stats=} stats * @property {number=} errorCode + * @property {boolean=} immutable */ /** @@ -65,7 +66,7 @@ function getFilenameFromUrl(context, url, extra = {}) { return; } - for (const { publicPath, outputPath } of paths) { + for (const { publicPath, outputPath, assetsInfo } of paths) { /** @type {string | undefined} */ let filename; /** @type {URL} */ @@ -122,6 +123,12 @@ function getFilenameFromUrl(context, url, extra = {}) { if (extra.stats.isFile()) { foundFilename = filename; + const assetInfo = assetsInfo.get( + pathname.slice(publicPathObject.pathname.length), + ); + + extra.immutable = assetInfo ? assetInfo.immutable : false; + break; } else if ( extra.stats.isDirectory() && diff --git a/src/utils/getPaths.js b/src/utils/getPaths.js index 93dafa82f..9ccd72852 100644 --- a/src/utils/getPaths.js +++ b/src/utils/getPaths.js @@ -20,6 +20,11 @@ function getPaths(context) { const publicPaths = []; for (const { compilation } of childStats) { + if (compilation.options.devServer === false) { + // eslint-disable-next-line no-continue + continue; + } + // The `output.path` is always present and always absolute const outputPath = compilation.getPath( compilation.outputOptions.path || "", @@ -30,7 +35,11 @@ function getPaths(context) { ? compilation.getPath(compilation.outputOptions.publicPath) : ""; - publicPaths.push({ outputPath, publicPath }); + publicPaths.push({ + outputPath, + publicPath, + assetsInfo: compilation.assetsInfo, + }); } return publicPaths; diff --git a/src/utils/ready.js b/src/utils/ready.js index 741bcaa9e..a3a4ef97e 100644 --- a/src/utils/ready.js +++ b/src/utils/ready.js @@ -19,7 +19,6 @@ function ready(context, callback, req) { const name = (req && req.url) || callback.name; context.logger.info(`wait until bundle finished${name ? `: ${name}` : ""}`); - context.callbacks.push(callback); } diff --git a/src/utils/setupHooks.js b/src/utils/setupHooks.js index 7fe71435e..38bd5bc8a 100644 --- a/src/utils/setupHooks.js +++ b/src/utils/setupHooks.js @@ -144,14 +144,9 @@ function setupHooks(context) { context.callbacks = []; // Execute callback that are delayed - callbacks.forEach( - /** - * @param {(...args: any[]) => Stats | MultiStats} callback - */ - (callback) => { - callback(stats); - }, - ); + for (const callback of callbacks) { + callback(stats); + } }); } diff --git a/src/utils/setupOutputFileSystem.js b/src/utils/setupOutputFileSystem.js index 9fb315b31..9c6bbc316 100644 --- a/src/utils/setupOutputFileSystem.js +++ b/src/utils/setupOutputFileSystem.js @@ -30,8 +30,10 @@ function setupOutputFileSystem(context) { // TODO we need to support webpack-dev-server as a plugin or revisit it const compiler = /** @type {MultiCompiler} */ - (context.compiler).compilers.filter((item) => - Object.prototype.hasOwnProperty.call(item.options, "devServer"), + (context.compiler).compilers.filter( + (item) => + Object.prototype.hasOwnProperty.call(item.options, "devServer") && + item.options.devServer !== false, ); ({ outputFileSystem } = @@ -48,6 +50,11 @@ function setupOutputFileSystem(context) { (context.compiler).compilers || [context.compiler]; for (const compiler of compilers) { + if (compiler.options.devServer === false) { + // eslint-disable-next-line no-continue + continue; + } + // @ts-ignore compiler.outputFileSystem = outputFileSystem; } diff --git a/src/utils/setupWriteToDisk.js b/src/utils/setupWriteToDisk.js index e70becffa..94bfedce7 100644 --- a/src/utils/setupWriteToDisk.js +++ b/src/utils/setupWriteToDisk.js @@ -21,6 +21,11 @@ function setupWriteToDisk(context) { (context.compiler).compilers || [context.compiler]; for (const compiler of compilers) { + if (compiler.options.devServer === false) { + // eslint-disable-next-line no-continue + continue; + } + compiler.hooks.emit.tap("DevMiddleware", () => { // @ts-ignore if (compiler.hasWebpackDevMiddlewareAssetEmittedCallback) { diff --git a/test/__snapshots__/logging.test.js.snap.webpack5 b/test/__snapshots__/logging.test.js.snap.webpack5 index 86d30f333..dd3bd29a4 100644 --- a/test/__snapshots__/logging.test.js.snap.webpack5 +++ b/test/__snapshots__/logging.test.js.snap.webpack5 @@ -47,8 +47,6 @@ success (webpack x.x.x) compiled successfully in x ms" exports[`logging should logging in multi-compiler and respect the "stats" option from configuration #3: stderr 1`] = `""`; -exports[`logging should logging in multi-compiler and respect the "stats" option from configuration #3: stderr 2`] = `""`; - exports[`logging should logging in multi-compiler and respect the "stats" option from configuration #3: stdout 1`] = ` "asset bundle.js x KiB [emitted] (name: main) ./broken.js x bytes [built] [code generated] [1 error] @@ -79,7 +77,9 @@ cacheable modules x bytes webpack x.x.x compiled successfully in x ms" `; -exports[`logging should logging in multi-compiler and respect the "stats" option from configuration #3: stdout 2`] = ` +exports[`logging should logging in multi-compiler and respect the "stats" option from configuration #4: stderr 1`] = `""`; + +exports[`logging should logging in multi-compiler and respect the "stats" option from configuration #4: stdout 1`] = ` "asset bundle.js x KiB [emitted] (name: main) ./broken.js x bytes [built] [code generated] [1 error] @@ -103,6 +103,24 @@ asset svg.svg x KiB [emitted] [from: svg.svg] (auxiliary name: main) asset index.html x bytes [emitted] [from: index.html] (auxiliary name: main)" `; +exports[`logging should logging in multi-compiler and respect the "stats" option from configuration #5: stderr 1`] = `""`; + +exports[`logging should logging in multi-compiler and respect the "stats" option from configuration #5: stdout 1`] = ` +"asset bundle.js x KiB [emitted] (name: main) +./bar.js x bytes [built] [code generated] +webpack x.x.x compiled successfully in x ms + +asset bundle.js x KiB [emitted] (name: main) +asset svg.svg x KiB [emitted] [from: svg.svg] (auxiliary name: main) +asset index.html x bytes [emitted] [from: index.html] (auxiliary name: main) +runtime modules x bytes x modules +cacheable modules x bytes +./foo.js x bytes [built] [code generated] +./svg.svg x bytes [built] [code generated] +./index.html x bytes [built] [code generated] +webpack x.x.x compiled successfully in x ms" +`; + exports[`logging should logging in multi-compiler and respect the "stats" option from configuration: stderr 1`] = `""`; exports[`logging should logging in multi-compiler and respect the "stats" option from configuration: stdout 1`] = ` diff --git a/test/__snapshots__/validation-options.test.js.snap.webpack5 b/test/__snapshots__/validation-options.test.js.snap.webpack5 index aa4d0dfef..eb08c61a2 100644 --- a/test/__snapshots__/validation-options.test.js.snap.webpack5 +++ b/test/__snapshots__/validation-options.test.js.snap.webpack5 @@ -1,5 +1,25 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`validation should throw an error on the "cacheControl" option with "{"unknown":true,"maxAge":10000}" value 1`] = ` +"Invalid options object. Dev Middleware has been initialized using an options object that does not match the API schema. + - options.cacheControl has an unknown property 'unknown'. These properties are valid: + object { maxAge?, immutable? }" +`; + +exports[`validation should throw an error on the "cacheImmutable" option with "0" value 1`] = ` +"Invalid options object. Dev Middleware has been initialized using an options object that does not match the API schema. + - options.cacheImmutable should be a boolean. + -> Enable or disable setting \`Cache-Control: public, max-age=31536000, immutable\` response header for immutable assets (i.e. asset with a hash in file name like \`image.a4c12bde.jpg\`). + -> Read more at https://github.com/webpack/webpack-dev-middleware#cacheimmutable" +`; + +exports[`validation should throw an error on the "cacheImmutable" option with "foo" value 1`] = ` +"Invalid options object. Dev Middleware has been initialized using an options object that does not match the API schema. + - options.cacheImmutable should be a boolean. + -> Enable or disable setting \`Cache-Control: public, max-age=31536000, immutable\` response header for immutable assets (i.e. asset with a hash in file name like \`image.a4c12bde.jpg\`). + -> Read more at https://github.com/webpack/webpack-dev-middleware#cacheimmutable" +`; + exports[`validation should throw an error on the "etag" option with "0" value 1`] = ` "Invalid options object. Dev Middleware has been initialized using an options object that does not match the API schema. - options.etag should be one of these: diff --git a/test/fixtures/immutable.js b/test/fixtures/immutable.js new file mode 100644 index 000000000..699af94dd --- /dev/null +++ b/test/fixtures/immutable.js @@ -0,0 +1 @@ +new URL("./svg.svg", import.meta.url); diff --git a/test/fixtures/webpack.array.dev-server-false.js b/test/fixtures/webpack.array.dev-server-false.js new file mode 100644 index 000000000..e23d44a2b --- /dev/null +++ b/test/fixtures/webpack.array.dev-server-false.js @@ -0,0 +1,44 @@ +'use strict'; + +const path = require('path'); + +module.exports = [ + { + mode: 'development', + context: path.resolve(__dirname), + entry: './bar.js', + output: { + filename: 'bundle.js', + path: path.resolve(__dirname, '../outputs/dev-server-false/js3'), + publicPath: '/static-two/', + }, + infrastructureLogging: { + level: 'none' + }, + stats: 'normal', + devServer: false, + }, + { + mode: 'development', + context: path.resolve(__dirname), + entry: './foo.js', + output: { + filename: 'bundle.js', + path: path.resolve(__dirname, '../outputs/dev-server-false/js4'), + publicPath: '/static-one/', + }, + module: { + rules: [ + { + test: /\.(svg|html)$/, + loader: 'file-loader', + options: { name: '[name].[ext]' }, + }, + ], + }, + infrastructureLogging: { + level: 'none' + }, + stats: 'normal' + } +]; diff --git a/test/fixtures/webpack.immutable.config.js b/test/fixtures/webpack.immutable.config.js new file mode 100644 index 000000000..4d4cdfc93 --- /dev/null +++ b/test/fixtures/webpack.immutable.config.js @@ -0,0 +1,17 @@ +'use strict'; + +const path = require('path'); + +module.exports = { + mode: 'development', + context: path.resolve(__dirname), + entry: './immutable.js', + output: { + publicPath: "/static/", + path: path.resolve(__dirname, '../outputs/basic'), + }, + infrastructureLogging: { + level: 'none' + }, + stats: 'normal' +}; diff --git a/test/helpers/clearDirectory.js b/test/helpers/clearDirectory.js deleted file mode 100644 index 73037fc36..000000000 --- a/test/helpers/clearDirectory.js +++ /dev/null @@ -1,26 +0,0 @@ -import fs from "fs"; - -function clearDirectory(dirPath) { - let files; - - try { - files = fs.readdirSync(dirPath); - } catch (e) { - return; - } - if (files.length > 0) { - for (let i = 0; i < files.length; i++) { - const filePath = `${dirPath}/${files[i]}`; - - if (fs.statSync(filePath).isFile()) { - fs.unlinkSync(filePath); - } else { - clearDirectory(filePath); - } - } - } - - fs.rmdirSync(dirPath); -} - -export default clearDirectory; diff --git a/test/logging.test.js b/test/logging.test.js index 0e3ab411a..c905206eb 100644 --- a/test/logging.test.js +++ b/test/logging.test.js @@ -46,6 +46,7 @@ function stdoutToSnapshot(stdout) { cleanedStdout = cleanedStdout.replace(/ +/g, " "); cleanedStdout = cleanedStdout.replace(/^ +/gm, ""); cleanedStdout = cleanedStdout.replace(/ +$/gm, ""); + cleanedStdout = cleanedStdout.replace(/\[compared for emit\]/g, "[emitted]"); return cleanedStdout; } @@ -854,7 +855,7 @@ describe("logging", () => { }); }); - it('should logging in multi-compiler and respect the "stats" option from configuration #3', (done) => { + it('should logging in multi-compiler and respect the "stats" option from configuration #4', (done) => { let proc; try { @@ -898,6 +899,50 @@ describe("logging", () => { }); }); + it('should logging in multi-compiler and respect the "stats" option from configuration #5', (done) => { + let proc; + + try { + proc = execa(runner, [], { + stdio: "pipe", + env: { + WEBPACK_CONFIG: "webpack.array.dev-server-false", + FORCE_COLOR: true, + }, + }); + } catch (error) { + throw error; + } + + let stdout = ""; + let stderr = ""; + + proc.stdout.on("data", (chunk) => { + stdout += chunk.toString(); + + if (/compiled-for-tests/gi.test(stdout)) { + proc.stdin.write("|exit|"); + } + }); + + proc.stderr.on("data", (chunk) => { + stderr += chunk.toString(); + proc.stdin.write("|exit|"); + }); + + proc.on("error", (error) => { + done(error); + }); + + proc.on("exit", () => { + expect(stdout).toContain("\u001b[1m"); + expect(stdoutToSnapshot(stdout)).toMatchSnapshot("stdout"); + expect(stderrToSnapshot(stderr)).toMatchSnapshot("stderr"); + + done(); + }); + }); + it('should logging an error in "watch" method', (done) => { let proc; @@ -932,17 +977,12 @@ describe("logging", () => { if (os.platform() !== "win32") { it('should logging an error from the fs error when the "writeToDisk" option is "true"', (done) => { - // eslint-disable-next-line global-require - const clearDirectory = require("./helpers/clearDirectory").default; const outputDir = path.resolve( __dirname, "./outputs/write-to-disk-mkdir-error", ); - if (!fs.existsSync(outputDir)) { - fs.mkdirSync(outputDir, { recursive: true }); - } - + fs.mkdirSync(outputDir, { recursive: true }); fs.chmodSync(outputDir, 0o400); let proc; @@ -977,7 +1017,7 @@ describe("logging", () => { expect(extractErrorEntry(stderr)).toMatch("Error: EACCES"); fs.chmodSync(outputDir, 0o700); - clearDirectory(outputDir); + fs.rmSync(outputDir, { recursive: true, force: true }); done(); }); diff --git a/test/middleware.test.js b/test/middleware.test.js index a52c4a77c..64ec0821c 100644 --- a/test/middleware.test.js +++ b/test/middleware.test.js @@ -12,7 +12,6 @@ import { Hono } from "hono"; import { serve } from "@hono/node-server"; import request from "supertest"; import memfs, { createFsFromVolume, Volume } from "memfs"; -import del from "del"; import { Stats } from "webpack"; @@ -28,6 +27,8 @@ import webpackQueryStringConfig from "./fixtures/webpack.querystring.config"; import webpackClientServerConfig from "./fixtures/webpack.client.server.config"; import getCompilerHooks from "./helpers/getCompilerHooks"; import webpackPublicPathConfig from "./fixtures/webpack.public-path.config"; +import webpackMultiDevServerFalseConfig from "./fixtures/webpack.array.dev-server-false"; +import webpackConfigImmutable from "./fixtures/webpack.immutable.config"; // Suppress unnecessary stats output global.console.log = jest.fn(); @@ -1416,6 +1417,112 @@ describe.each([ }); }); + describe.only("should work in multi-compiler mode with `devServer` false", () => { + const outputPath = path.resolve( + __dirname, + "./outputs/dev-server-false", + ); + + beforeAll(async () => { + const compiler = getCompiler(webpackMultiDevServerFalseConfig); + + [server, req, instance] = await frameworkFactory( + name, + framework, + compiler, + ); + }); + + afterAll(async () => { + await fs.promises.rm(outputPath, { + recursive: true, + force: true, + }); + await close(server, instance); + }); + + it('should return "200" code for GET request to the bundle file for the first compiler', async () => { + const bundlePath = path.resolve( + __dirname, + "./outputs/dev-server-false/js4/", + ); + + expect(fs.existsSync(path.resolve(bundlePath, "bundle.js"))).toBe( + false, + ); + + const response = await req.get("/static-one/bundle.js"); + + expect(response.statusCode).toEqual(200); + }); + + it('should return "404" code for GET request to a non existing file for the first compiler', async () => { + const response = await req.get("/static-one/invalid.js"); + + expect(response.statusCode).toEqual(404); + }); + + it('should return "200" code for GET request to the "public" path for the first compiler', async () => { + const response = await req.get("/static-one/"); + + expect(response.statusCode).toEqual(200); + expect(response.headers["content-type"]).toEqual( + "text/html; charset=utf-8", + ); + }); + + it('should return "200" code for GET request to the "index" option for the first compiler', async () => { + const response = await req.get("/static-one/index.html"); + + expect(response.statusCode).toEqual(200); + expect(response.headers["content-type"]).toEqual( + "text/html; charset=utf-8", + ); + }); + + it('should return "200" code for GET request for the bundle file for the second compiler', async () => { + const bundlePath = path.resolve( + __dirname, + "./outputs/dev-server-false/js3/", + ); + + expect(fs.existsSync(path.resolve(bundlePath, "bundle.js"))).toBe( + true, + ); + + const response = await req.get("/static-two/bundle.js"); + + expect(response.statusCode).toEqual(404); + }); + + it('should return "404" code for GET request to a non existing file for the second compiler', async () => { + const response = await req.get("/static-two/invalid.js"); + + expect(response.statusCode).toEqual(404); + }); + + it('should return "404" code for GET request to the "public" path for the second compiler', async () => { + const response = await req.get("/static-two/"); + + expect(response.statusCode).toEqual(404); + }); + + it('should return "404" code for GET request to the "index" option for the second compiler', async () => { + const response = await req.get("/static-two/index.html"); + + expect(response.statusCode).toEqual(404); + }); + + it('should return "404" code for GET request to the non-public path', async () => { + const response = await req.get("/static-three/"); + + expect(response.statusCode).toEqual(404); + expect(response.headers["content-type"]).toEqual( + get404ContentTypeHeader(name), + ); + }); + }); + describe("should work with difference requests", () => { const basicOutputPath = path.resolve(__dirname, "./outputs/basic"); const fixtures = [ @@ -3353,7 +3460,9 @@ describe.each([ const response = await req.get("/file.jpg"); expect(response.statusCode).toEqual(200); - expect(response.headers["content-type"]).toMatch(/text\/html/); + expect(response.headers["content-type"]).toMatch( + name === "fastify" ? /text\/plain; charset=utf-8/ : /text\/html/, + ); }); }); }); @@ -3512,12 +3621,17 @@ describe.each([ describe('should work with "true" value', () => { let compiler; + const outputPath = path.resolve( + __dirname, + "./outputs/write-to-disk-true", + ); + beforeAll(async () => { compiler = getCompiler({ ...webpackConfig, output: { filename: "bundle.js", - path: path.resolve(__dirname, "./outputs/write-to-disk-true"), + path: outputPath, publicPath: "/public/", }, }); @@ -3531,10 +3645,10 @@ describe.each([ }); afterAll(async () => { - del.sync( - path.posix.resolve(__dirname, "./outputs/write-to-disk-true"), - ); - + await fs.promises.rm(outputPath, { + recursive: true, + force: true, + }); await close(server, instance); }); @@ -3625,8 +3739,10 @@ describe.each([ }); afterAll(async () => { - del.sync(outputPath); - + await fs.promises.rm(outputPath, { + recursive: true, + force: true, + }); await close(server, instance); }); @@ -3730,15 +3846,17 @@ describe.each([ describe('should work with "Function" value when it returns "true"', () => { let compiler; + const outputPath = path.resolve( + __dirname, + "./outputs/write-to-disk-function-true", + ); + beforeAll(async () => { compiler = getCompiler({ ...webpackConfig, output: { filename: "bundle.js", - path: path.resolve( - __dirname, - "./outputs/write-to-disk-function-true", - ), + path: outputPath, }, }); @@ -3753,13 +3871,10 @@ describe.each([ }); afterAll(async () => { - del.sync( - path.posix.resolve( - __dirname, - "./outputs/write-to-disk-function-true", - ), - ); - + await fs.promises.rm(outputPath, { + recursive: true, + force: true, + }); await close(server, instance); }); @@ -3780,15 +3895,17 @@ describe.each([ describe('should work with "Function" value when it returns "false"', () => { let compiler; + const outputPath = path.resolve( + __dirname, + "./outputs/write-to-disk-function-false", + ); + beforeAll(async () => { compiler = getCompiler({ ...webpackConfig, output: { filename: "bundle.js", - path: path.resolve( - __dirname, - "./outputs/write-to-disk-function-false", - ), + path: outputPath, }, }); @@ -3803,13 +3920,10 @@ describe.each([ }); afterAll(async () => { - del.sync( - path.posix.resolve( - __dirname, - "./outputs/write-to-disk-function-false", - ), - ); - + await fs.promises.rm(outputPath, { + recursive: true, + force: true, + }); await close(server, instance); }); @@ -3830,15 +3944,17 @@ describe.each([ describe("should work when assets have query string", () => { let compiler; + const outputPath = path.resolve( + __dirname, + "./outputs/write-to-disk-query-string", + ); + beforeAll(async () => { compiler = getCompiler({ ...webpackQueryStringConfig, output: { filename: "bundle.js?[contenthash]", - path: path.resolve( - __dirname, - "./outputs/write-to-disk-query-string", - ), + path: outputPath, }, }); @@ -3851,13 +3967,10 @@ describe.each([ }); afterAll(async () => { - del.sync( - path.posix.resolve( - __dirname, - "./outputs/write-to-disk-query-string", - ), - ); - + await fs.promises.rm(outputPath, { + recursive: true, + force: true, + }); await close(server, instance); }); @@ -3878,6 +3991,11 @@ describe.each([ describe("should work in multi-compiler mode", () => { let compiler; + const outputPath = path.resolve( + __dirname, + "./outputs/write-to-disk-multi-compiler/", + ); + beforeAll(async () => { compiler = getCompiler([ { @@ -3913,13 +4031,10 @@ describe.each([ }); afterAll(async () => { - del.sync( - path.posix.resolve( - __dirname, - "./outputs/write-to-disk-multi-compiler/", - ), - ); - + await fs.promises.rm(outputPath, { + recursive: true, + force: true, + }); await close(server, instance); }); @@ -3951,6 +4066,11 @@ describe.each([ let compiler; let hash; + const outputPath = path.resolve( + __dirname, + "./outputs/write-to-disk-with-hash/", + ); + beforeAll(async () => { compiler = getCompiler({ ...webpackConfig, @@ -3988,10 +4108,10 @@ describe.each([ }); afterAll(async () => { - del.sync( - path.posix.resolve(__dirname, "./outputs/write-to-disk-with-hash/"), - ); - + await fs.promises.rm(outputPath, { + recursive: true, + force: true, + }); await close(server, instance); }); @@ -5392,5 +5512,345 @@ describe.each([ }); }); }); + + describe("cacheControl", () => { + describe("should work and don't generate `Cache-Control` header by default", () => { + beforeEach(async () => { + const compiler = getCompiler(webpackConfig); + + [server, req, instance] = await frameworkFactory( + name, + framework, + compiler, + ); + }); + + afterEach(async () => { + await close(server, instance); + }); + + it('should return the "200" code for the "GET" request to the bundle file and don\'t generate `Cache-Control` header', async () => { + const response = await req.get(`/bundle.js`); + + expect(response.statusCode).toEqual(200); + expect(response.headers["cache-control"]).toBeUndefined(); + }); + }); + + describe("should work and generate `Cache-Control` header when it is `true`", () => { + beforeEach(async () => { + const compiler = getCompiler(webpackConfig); + + [server, req, instance] = await frameworkFactory( + name, + framework, + compiler, + { cacheControl: true }, + ); + }); + + afterEach(async () => { + await close(server, instance); + }); + + it('should return the "200" code for the "GET" request to the bundle file and don\'t generate `Cache-Control` header', async () => { + const response = await req.get(`/bundle.js`); + + expect(response.statusCode).toEqual(200); + expect(response.headers["cache-control"]).toBeDefined(); + expect(response.headers["cache-control"]).toBe( + "public, max-age=31536000", + ); + }); + }); + + describe("should work and generate `Cache-Control` header when it is a number", () => { + beforeEach(async () => { + const compiler = getCompiler(webpackConfig); + + [server, req, instance] = await frameworkFactory( + name, + framework, + compiler, + { cacheControl: 100000 }, + ); + }); + + afterEach(async () => { + await close(server, instance); + }); + + it('should return the "200" code for the "GET" request to the bundle file and don\'t generate `Cache-Control` header', async () => { + const response = await req.get(`/bundle.js`); + + expect(response.statusCode).toEqual(200); + expect(response.headers["cache-control"]).toBeDefined(); + expect(response.headers["cache-control"]).toBe("public, max-age=100"); + }); + }); + + describe("should work and generate `Cache-Control` header when it is a string", () => { + beforeEach(async () => { + const compiler = getCompiler(webpackConfig); + + [server, req, instance] = await frameworkFactory( + name, + framework, + compiler, + { cacheControl: "max-age=123456" }, + ); + }); + + afterEach(async () => { + await close(server, instance); + }); + + it('should return the "200" code for the "GET" request to the bundle file and don\'t generate `Cache-Control` header', async () => { + const response = await req.get(`/bundle.js`); + + expect(response.statusCode).toEqual(200); + expect(response.headers["cache-control"]).toBeDefined(); + expect(response.headers["cache-control"]).toBe("max-age=123456"); + }); + }); + + describe("should work and generate `Cache-Control` header when it is an object with max-age and immutable", () => { + beforeEach(async () => { + const compiler = getCompiler(webpackConfig); + + [server, req, instance] = await frameworkFactory( + name, + framework, + compiler, + { + cacheControl: { + maxAge: 100000, + immutable: true, + }, + }, + ); + }); + + afterEach(async () => { + await close(server, instance); + }); + + it('should return the "200" code for the "GET" request to the bundle file and don\'t generate `Cache-Control` header', async () => { + const response = await req.get(`/bundle.js`); + + expect(response.statusCode).toEqual(200); + expect(response.headers["cache-control"]).toBeDefined(); + expect(response.headers["cache-control"]).toBe( + "public, max-age=100, immutable", + ); + }); + }); + + describe("should work and generate `Cache-Control` header when it is an object without max-age, but with immutable", () => { + beforeEach(async () => { + const compiler = getCompiler(webpackConfig); + + [server, req, instance] = await frameworkFactory( + name, + framework, + compiler, + { + cacheControl: { + immutable: true, + }, + }, + ); + }); + + afterEach(async () => { + await close(server, instance); + }); + + it('should return the "200" code for the "GET" request to the bundle file and don\'t generate `Cache-Control` header', async () => { + const response = await req.get(`/bundle.js`); + + expect(response.statusCode).toEqual(200); + expect(response.headers["cache-control"]).toBeDefined(); + expect(response.headers["cache-control"]).toBe( + "public, max-age=31536000, immutable", + ); + }); + }); + + describe("should work and generate `Cache-Control` header when it is an object with max-age, but without immutable", () => { + beforeEach(async () => { + const compiler = getCompiler(webpackConfig); + + [server, req, instance] = await frameworkFactory( + name, + framework, + compiler, + { + cacheControl: { + maxAge: 100000, + }, + }, + ); + }); + + afterEach(async () => { + await close(server, instance); + }); + + it('should return the "200" code for the "GET" request to the bundle file and don\'t generate `Cache-Control` header', async () => { + const response = await req.get(`/bundle.js`); + + expect(response.statusCode).toEqual(200); + expect(response.headers["cache-control"]).toBeDefined(); + expect(response.headers["cache-control"]).toBe("public, max-age=100"); + }); + }); + + describe("should work and generate `Cache-Control` header when it is an object without max-age and immutable", () => { + beforeEach(async () => { + const compiler = getCompiler(webpackConfig); + + [server, req, instance] = await frameworkFactory( + name, + framework, + compiler, + { + cacheControl: {}, + }, + ); + }); + + afterEach(async () => { + await close(server, instance); + }); + + it('should return the "200" code for the "GET" request to the bundle file and don\'t generate `Cache-Control` header', async () => { + const response = await req.get(`/bundle.js`); + + expect(response.statusCode).toEqual(200); + expect(response.headers["cache-control"]).toBeDefined(); + expect(response.headers["cache-control"]).toBe( + "public, max-age=31536000", + ); + }); + }); + }); + + describe("cacheImmutable", () => { + describe("should work and generate `Cache-Control` header for immutable assets with publicPath", () => { + beforeEach(async () => { + const compiler = getCompiler(webpackConfigImmutable); + + [server, req, instance] = await frameworkFactory( + name, + framework, + compiler, + { cacheImmutable: true }, + ); + }); + + afterEach(async () => { + await close(server, instance); + }); + + it('should return the "200" code for the "GET" request to the bundle file and don\'t generate `Cache-Control` header', async () => { + const response = await req.get(`/static/main.js`); + + expect(response.statusCode).toEqual(200); + expect(response.headers["cache-control"]).toBeUndefined(); + }); + + it('should return the "200" code for the "GET" request to the bundle file and generate `Cache-Control` header', async () => { + const response = await req.get(`/static/6076fc274f403ebb2d09.svg`); + + expect(response.statusCode).toEqual(200); + expect(response.headers["cache-control"]).toBeDefined(); + expect(response.headers["cache-control"]).toBe( + "public, max-age=31536000, immutable", + ); + }); + }); + + describe("should work and generate `Cache-Control` header for immutable assets without publicPath", () => { + beforeEach(async () => { + const compiler = getCompiler({ + ...webpackConfigImmutable, + output: { + path: path.resolve(__dirname, "./outputs/basic"), + }, + }); + + [server, req, instance] = await frameworkFactory( + name, + framework, + compiler, + { cacheImmutable: true }, + ); + }); + + afterEach(async () => { + await close(server, instance); + }); + + it('should return the "200" code for the "GET" request to the bundle file and don\'t generate `Cache-Control` header', async () => { + const response = await req.get(`/main.js`); + + expect(response.statusCode).toEqual(200); + expect(response.headers["cache-control"]).toBeUndefined(); + }); + + it('should return the "200" code for the "GET" request to the bundle file and `Cache-Control` header', async () => { + const response = await req.get(`/6076fc274f403ebb2d09.svg`); + + expect(response.statusCode).toEqual(200); + expect(response.headers["cache-control"]).toBeDefined(); + expect(response.headers["cache-control"]).toBe( + "public, max-age=31536000, immutable", + ); + }); + }); + + describe("should work and generate `Cache-Control` header for immutable assets and take preference over the `cacheControl` option", () => { + beforeEach(async () => { + const compiler = getCompiler({ + ...webpackConfigImmutable, + output: { + path: path.resolve(__dirname, "./outputs/basic"), + }, + }); + + [server, req, instance] = await frameworkFactory( + name, + framework, + compiler, + { cacheImmutable: true, cacheControl: 1000000 }, + ); + }); + + afterEach(async () => { + await close(server, instance); + }); + + it('should return the "200" code for the "GET" request to the bundle file and generate `Cache-Control` header', async () => { + const response = await req.get(`/main.js`); + + expect(response.statusCode).toEqual(200); + expect(response.headers["cache-control"]).toBeDefined(); + expect(response.headers["cache-control"]).toBe( + "public, max-age=1000", + ); + }); + + it('should return the "200" code for the "GET" request to the bundle file and generate `Cache-Control` header', async () => { + const response = await req.get(`/6076fc274f403ebb2d09.svg`); + + expect(response.statusCode).toEqual(200); + expect(response.headers["cache-control"]).toBeDefined(); + expect(response.headers["cache-control"]).toBe( + "public, max-age=31536000, immutable", + ); + }); + }); + }); }); }); diff --git a/test/utils/getPaths.test.js b/test/utils/getPaths.test.js deleted file mode 100644 index 0416b0d99..000000000 --- a/test/utils/getPaths.test.js +++ /dev/null @@ -1,90 +0,0 @@ -import path from "path"; - -import express from "express"; - -import middleware from "../../src"; -import getPaths from "../../src/utils/getPaths"; - -import getCompiler from "../helpers/getCompiler"; -import listenAndCompile from "../helpers/listenAndCompile"; -import webpackSimpleConfig from "../fixtures/webpack.simple.config"; -import webpackPublicPathConfig from "../fixtures/webpack.public-path.config"; -import webpackMultiConfig from "../fixtures/webpack.array.config"; - -// Suppress unnecessary stats output -global.console.log = jest.fn(); - -describe("getPaths", () => { - const configs = [ - { - title: "simple config", - config: webpackSimpleConfig, - expected: [ - { - outputPath: path.resolve(__dirname, "../outputs/simple"), - publicPath: "auto", - }, - ], - }, - { - title: "publicPath config", - config: webpackPublicPathConfig, - expected: [ - { - outputPath: path.resolve(__dirname, "../outputs/public-path"), - publicPath: "/public/path/", - }, - ], - }, - { - title: "multi config", - config: webpackMultiConfig, - expected: [ - { - outputPath: path.resolve(__dirname, "../outputs/array/js1"), - publicPath: "/static-one/", - }, - { - outputPath: path.resolve(__dirname, "../outputs/array/js2"), - publicPath: "/static-two/", - }, - ], - }, - ]; - - configs.forEach((config) => { - describe(config.title, () => { - let instance; - let listen; - let app; - let compiler; - - beforeEach((done) => { - compiler = getCompiler(config.config); - - instance = middleware(compiler); - - app = express(); - app.use(instance); - - listen = listenAndCompile(app, compiler, done); - }); - - afterEach((done) => { - if (instance) { - instance.close(); - } - - if (listen) { - listen.close(done); - } else { - done(); - } - }); - - it("should return correct paths", () => { - expect(getPaths(instance.context)).toEqual(config.expected); - }); - }); - }); -}); diff --git a/test/utils/setupOutputFileSystem.test.js b/test/utils/setupOutputFileSystem.test.js index efcb71520..ce681bf57 100644 --- a/test/utils/setupOutputFileSystem.test.js +++ b/test/utils/setupOutputFileSystem.test.js @@ -17,7 +17,7 @@ describe("setupOutputFileSystem", () => { it("should create default fs if not provided", () => { const context = { - compiler: {}, + compiler: { options: {} }, options: {}, }; @@ -32,7 +32,7 @@ describe("setupOutputFileSystem", () => { it("should set fs for multi compiler", () => { const context = { compiler: { - compilers: [{}, {}], + compilers: [{ options: {} }, { options: {} }], }, options: {}, }; @@ -46,7 +46,7 @@ describe("setupOutputFileSystem", () => { it("should use provided fs with correct methods", () => { const context = { - compiler: {}, + compiler: { options: {} }, options: { outputFileSystem: { join: () => {}, diff --git a/test/validation-options.test.js b/test/validation-options.test.js index 62632f001..addf2b8f8 100644 --- a/test/validation-options.test.js +++ b/test/validation-options.test.js @@ -75,6 +75,20 @@ describe("validation", () => { success: [true, false], failure: ["foo", 0], }, + cacheControl: { + success: [ + true, + false, + 10000, + "max-age=100", + { immutable: true, maxAge: 10000 }, + ], + failure: [{ unknown: true, maxAge: 10000 }], + }, + cacheImmutable: { + success: [true, false], + failure: ["foo", 0], + }, }; function stringifyValue(value) { diff --git a/types/index.d.ts b/types/index.d.ts index 750074985..f6886e1bd 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -90,6 +90,8 @@ export = wdm; * @property {ModifyResponseData} [modifyResponseData] * @property {"weak" | "strong"} [etag] * @property {boolean} [lastModified] + * @property {boolean | number | string | { maxAge?: number, immutable?: boolean }} [cacheControl] + * @property {boolean} [cacheImmutable] */ /** * @template {IncomingMessage} [RequestInternal=IncomingMessage] @@ -354,6 +356,16 @@ type Options< | undefined; etag?: "strong" | "weak" | undefined; lastModified?: boolean | undefined; + cacheControl?: + | string + | number + | boolean + | { + maxAge?: number; + immutable?: boolean; + } + | undefined; + cacheImmutable?: boolean | undefined; }; type Middleware< RequestInternal extends IncomingMessage = import("http").IncomingMessage, diff --git a/types/utils/getFilenameFromUrl.d.ts b/types/utils/getFilenameFromUrl.d.ts index 18ff67ff6..08fc1dcb6 100644 --- a/types/utils/getFilenameFromUrl.d.ts +++ b/types/utils/getFilenameFromUrl.d.ts @@ -21,6 +21,7 @@ declare namespace getFilenameFromUrl { type Extra = { stats?: import("fs").Stats | undefined; errorCode?: number | undefined; + immutable?: boolean | undefined; }; type IncomingMessage = import("../index.js").IncomingMessage; type ServerResponse = import("../index.js").ServerResponse; diff --git a/types/utils/getPaths.d.ts b/types/utils/getPaths.d.ts index ecf88cbdd..ace131cd1 100644 --- a/types/utils/getPaths.d.ts +++ b/types/utils/getPaths.d.ts @@ -17,6 +17,7 @@ declare function getPaths< ): { outputPath: string; publicPath: string; + assetsInfo: Map; }[]; declare namespace getPaths { export { Compiler, Stats, MultiStats, IncomingMessage, ServerResponse };