Initial commit: notification-elements-demo app

Interactive Angular 19 demo for @sda/notification-elements-ui with
6 sections: Bell & Feed, Notification Center, Inbox, Comments &
Threads, Mention Input, and Full-Featured layout. Includes mock
data, dark mode toggle, and real-time event log.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Giuliano Silvestro
2026-02-13 21:49:19 +10:00
commit 5d0c9ec7eb
36473 changed files with 3778146 additions and 0 deletions

20
node_modules/webpack-dev-middleware/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,20 @@
Copyright JS Foundation and other contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

771
node_modules/webpack-dev-middleware/README.md generated vendored Normal file
View File

@@ -0,0 +1,771 @@
<div align="center">
<a href="https://github.com/webpack/webpack">
<img width="200" height="200" src="https://webpack.js.org/assets/icon-square-big.svg">
</a>
</div>
[![npm][npm]][npm-url]
[![node][node]][node-url]
[![tests][tests]][tests-url]
[![coverage][cover]][cover-url]
[![discussion][discussion]][discussion-url]
[![size][size]][size-url]
# webpack-dev-middleware
An express-style development middleware for use with [webpack](https://webpack.js.org)
bundles and allows for serving of the files emitted from webpack.
This should be used for **development only**.
Some of the benefits of using this middleware include:
- No files are written to disk, rather it handles files in memory
- If files changed in watch mode, the middleware delays requests until compiling
has completed.
- Supports hot module reload (HMR).
## Getting Started
First thing's first, install the module:
```console
npm install webpack-dev-middleware --save-dev
```
> [!WARNING]
>
> _We do not recommend installing this module globally._
## Usage
```js
const webpack = require("webpack");
const middleware = require("webpack-dev-middleware");
const compiler = webpack({
// webpack options
});
const express = require("express");
const app = express();
app.use(
middleware(compiler, {
// webpack-dev-middleware options
}),
);
app.listen(3000, () => console.log("Example app listening on port 3000!"));
```
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. |
| **[`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.
### methods
Type: `Array`
Default: `[ 'GET', 'HEAD' ]`
This property allows a user to pass the list of HTTP request methods accepted by the middleware\*\*.
### headers
Type: `Array|Object|Function`
Default: `undefined`
This property allows a user to pass custom HTTP headers on each request.
eg. `{ "X-Custom-Header": "yes" }`
or
```js
webpackDevMiddleware(compiler, {
headers: () => {
return {
"Last-Modified": new Date(),
};
},
});
```
or
```js
webpackDevMiddleware(compiler, {
headers: (req, res, context) => {
res.setHeader("Last-Modified", new Date());
},
});
```
or
```js
webpackDevMiddleware(compiler, {
headers: [
{
key: "X-custom-header",
value: "foo",
},
{
key: "Y-custom-header",
value: "bar",
},
],
});
```
or
```js
webpackDevMiddleware(compiler, {
headers: () => [
{
key: "X-custom-header",
value: "foo",
},
{
key: "Y-custom-header",
value: "bar",
},
],
});
```
### index
Type: `Boolean|String`
Default: `index.html`
If `false` (but not `undefined`), the server will not respond to requests to the root URL.
### mimeTypes
Type: `Object`
Default: `undefined`
This property allows a user to register custom mime types or extension mappings.
eg. `mimeTypes: { phtml: 'text/html' }`.
Please see the documentation for [`mime-types`](https://github.com/jshttp/mime-types) for more information.
### mimeTypeDefault
Type: `String`
Default: `undefined`
This property allows a user to register a default mime type when we can't determine the content type.
### etag
Type: `"weak" | "strong"`
Default: `undefined`
Enable or disable etag generation. Boolean value use
### lastModified
Type: `Boolean`
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`
Default: `output.publicPath` (from a configuration)
The public path that the middleware is bound to.
_Best Practice: use the same `publicPath` defined in your webpack config. For more information about `publicPath`, please see [the webpack documentation](https://webpack.js.org/guides/public-path)._
### stats
Type: `Boolean|String|Object`
Default: `stats` (from a configuration)
Stats options object or preset name.
### serverSideRender
Type: `Boolean`
Default: `undefined`
Instructs the module to enable or disable the server-side rendering mode.
Please see [Server-Side Rendering](#server-side-rendering) for more information.
### writeToDisk
Type: `Boolean|Function`
Default: `false`
If `true`, the option will instruct the module to write files to the configured location on disk as specified in your `webpack` config file.
_Setting `writeToDisk: true` won't change the behavior of the `webpack-dev-middleware`, and bundle files accessed through the browser will still be served from memory._
This option provides the same capabilities as the [`WriteFilePlugin`](https://github.com/gajus/write-file-webpack-plugin/pulls).
This option also accepts a `Function` value, which can be used to filter which files are written to disk.
The function follows the same premise as [`Array#filter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) in which a return value of `false` _will not_ write the file, and a return value of `true` _will_ write the file to disk. eg.
```js
const webpack = require("webpack");
const configuration = {
/* Webpack configuration */
};
const compiler = webpack(configuration);
middleware(compiler, {
writeToDisk: (filePath) => {
return /superman\.css$/.test(filePath);
},
});
```
### outputFileSystem
Type: `Object`
Default: [memfs](https://github.com/streamich/memfs)
Set the default file system which will be used by webpack as primary destination of generated files.
This option isn't affected by the [writeToDisk](#writeToDisk) option.
You have to provide `.join()` and `mkdirp` method to the `outputFileSystem` instance manually for compatibility with `webpack@4`.
This can be done simply by using `path.join`:
```js
const webpack = require("webpack");
const path = require("path");
const myOutputFileSystem = require("my-fs");
const mkdirp = require("mkdirp");
myOutputFileSystem.join = path.join.bind(path); // no need to bind
myOutputFileSystem.mkdirp = mkdirp.bind(mkdirp); // no need to bind
const compiler = webpack({
/* Webpack configuration */
});
middleware(compiler, { outputFileSystem: myOutputFileSystem });
```
### modifyResponseData
Allows to set up a callback to change the response data.
```js
const webpack = require("webpack");
const configuration = {
/* Webpack configuration */
};
const compiler = webpack(configuration);
middleware(compiler, {
// Note - if you send the `Range` header you will have `ReadStream`
// Also `data` can be `string` or `Buffer`
modifyResponseData: (req, res, data, byteLength) => {
// Your logic
// Don't use `res.end()` or `res.send()` here
return { data, byteLength };
},
});
```
## API
`webpack-dev-middleware` also provides convenience methods that can be use to
interact with the middleware at runtime:
### `close(callback)`
Instructs `webpack-dev-middleware` instance to stop watching for file changes.
#### Parameters
##### `callback`
Type: `Function`
Required: `No`
A function executed once the middleware has stopped watching.
```js
const express = require("express");
const webpack = require("webpack");
const compiler = webpack({
/* Webpack configuration */
});
const middleware = require("webpack-dev-middleware");
const instance = middleware(compiler);
const app = new express();
app.use(instance);
setTimeout(() => {
// Says `webpack` to stop watch changes
instance.close();
}, 1000);
```
### `invalidate(callback)`
Instructs `webpack-dev-middleware` instance to recompile the bundle, e.g. after a change to the configuration.
#### Parameters
##### `callback`
Type: `Function`
Required: `No`
A function executed once the middleware has invalidated.
```js
const express = require("express");
const webpack = require("webpack");
const compiler = webpack({
/* Webpack configuration */
});
const middleware = require("webpack-dev-middleware");
const instance = middleware(compiler);
const app = new express();
app.use(instance);
setTimeout(() => {
// After a short delay the configuration is changed and a banner plugin is added to the config
new webpack.BannerPlugin("A new banner").apply(compiler);
// Recompile the bundle with the banner plugin:
instance.invalidate();
}, 1000);
```
### `waitUntilValid(callback)`
Executes a callback function when the compiler bundle is valid, typically after
compilation.
#### Parameters
##### `callback`
Type: `Function`
Required: `No`
A function executed when the bundle becomes valid.
If the bundle is valid at the time of calling, the callback is executed immediately.
```js
const express = require("express");
const webpack = require("webpack");
const compiler = webpack({
/* Webpack configuration */
});
const middleware = require("webpack-dev-middleware");
const instance = middleware(compiler);
const app = new express();
app.use(instance);
instance.waitUntilValid(() => {
console.log("Package is in a valid state");
});
```
### `getFilenameFromUrl(url)`
Get filename from URL.
#### Parameters
##### `url`
Type: `String`
Required: `Yes`
URL for the requested file.
```js
const express = require("express");
const webpack = require("webpack");
const compiler = webpack({
/* Webpack configuration */
});
const middleware = require("webpack-dev-middleware");
const instance = middleware(compiler);
const app = new express();
app.use(instance);
instance.waitUntilValid(() => {
const filename = instance.getFilenameFromUrl("/bundle.js");
console.log(`Filename is ${filename}`);
});
```
## FAQ
### Avoid blocking requests to non-webpack resources.
Since `output.publicPath` and `output.filename`/`output.chunkFilename` can be dynamic, it's not possible to know which files are webpack bundles (and they public paths) and which are not, so we can't avoid blocking requests.
But there is a solution to avoid it - mount the middleware to a non-root route, for example:
```js
const webpack = require("webpack");
const middleware = require("webpack-dev-middleware");
const compiler = webpack({
// webpack options
});
const express = require("express");
const app = express();
// Mounting the middleware to the non-root route allows avoids this.
// Note - check your public path, if you want to handle `/dist/`, you need to setup `output.publicPath` to `/` value.
app.use(
"/dist/",
middleware(compiler, {
// webpack-dev-middleware options
}),
);
app.listen(3000, () => console.log("Example app listening on port 3000!"));
```
## Server-Side Rendering
_Note: this feature is experimental and may be removed or changed completely in the future._
In order to develop an app using server-side rendering, we need access to the
[`stats`](https://github.com/webpack/docs/wiki/node.js-api#stats), which is
generated with each build.
With server-side rendering enabled, `webpack-dev-middleware` sets the `stats` to `res.locals.webpack.devMiddleware.stats`
and the filesystem to `res.locals.webpack.devMiddleware.outputFileSystem` before invoking the next middleware,
allowing a developer to render the page body and manage the response to clients.
_Note: Requests for bundle files will still be handled by
`webpack-dev-middleware` and all requests will be pending until the build
process is finished with server-side rendering enabled._
Example Implementation:
```js
const express = require("express");
const webpack = require("webpack");
const compiler = webpack({
/* Webpack configuration */
});
const isObject = require("is-object");
const middleware = require("webpack-dev-middleware");
const app = new express();
// This function makes server rendering of asset references consistent with different webpack chunk/entry configurations
function normalizeAssets(assets) {
if (isObject(assets)) {
return Object.values(assets);
}
return Array.isArray(assets) ? assets : [assets];
}
app.use(middleware(compiler, { serverSideRender: true }));
// The following middleware would not be invoked until the latest build is finished.
app.use((req, res) => {
const { devMiddleware } = res.locals.webpack;
const outputFileSystem = devMiddleware.outputFileSystem;
const jsonWebpackStats = devMiddleware.stats.toJson();
const { assetsByChunkName, outputPath } = jsonWebpackStats;
// Then use `assetsByChunkName` for server-side rendering
// For example, if you have only one main chunk:
res.send(`
<html>
<head>
<title>My App</title>
<style>
${normalizeAssets(assetsByChunkName.main)
.filter((path) => path.endsWith(".css"))
.map((path) => outputFileSystem.readFileSync(path.join(outputPath, path)))
.join("\n")}
</style>
</head>
<body>
<div id="root"></div>
${normalizeAssets(assetsByChunkName.main)
.filter((path) => path.endsWith(".js"))
.map((path) => `<script src="${path}"></script>`)
.join("\n")}
</body>
</html>
`);
});
```
## Support
We do our best to keep Issues in the repository focused on bugs, features, and
needed modifications to the code for the module. Because of that, we ask users
with general support, "how-to", or "why isn't this working" questions to try one
of the other support channels that are available.
Your first-stop-shop for support for webpack-dev-server should by the excellent
[documentation][docs-url] for the module. If you see an opportunity for improvement
of those docs, please head over to the [webpack.js.org repo][wjo-url] and open a
pull request.
From there, we encourage users to visit the [webpack discussions][chat-url] and
talk to the fine folks there. If your quest for answers comes up dry in chat,
head over to [StackOverflow][stack-url] and do a quick search or open a new
question. Remember; It's always much easier to answer questions that include your
`webpack.config.js` and relevant files!
If you're twitter-savvy you can tweet [#webpack][hash-url] with your question
and someone should be able to reach out and lend a hand.
If you have discovered a :bug:, have a feature suggestion, or would like to see
a modification, please feel free to create an issue on Github. _Note: The issue
template isn't optional, so please be sure not to remove it, and please fill it
out completely._
## Other servers
Examples of use with other servers will follow here.
### Connect
```js
const connect = require("connect");
const http = require("http");
const webpack = require("webpack");
const webpackConfig = require("./webpack.config.js");
const devMiddleware = require("webpack-dev-middleware");
const compiler = webpack(webpackConfig);
const devMiddlewareOptions = {
/** Your webpack-dev-middleware-options */
};
const app = connect();
app.use(devMiddleware(compiler, devMiddlewareOptions));
http.createServer(app).listen(3000);
```
### Router
```js
const http = require("http");
const Router = require("router");
const finalhandler = require("finalhandler");
const webpack = require("webpack");
const webpackConfig = require("./webpack.config.js");
const devMiddleware = require("webpack-dev-middleware");
const compiler = webpack(webpackConfig);
const devMiddlewareOptions = {
/** Your webpack-dev-middleware-options */
};
const router = Router();
router.use(devMiddleware(compiler, devMiddlewareOptions));
var server = http.createServer((req, res) => {
router(req, res, finalhandler(req, res));
});
server.listen(3000);
```
### Express
```js
const express = require("express");
const webpack = require("webpack");
const webpackConfig = require("./webpack.config.js");
const devMiddleware = require("webpack-dev-middleware");
const compiler = webpack(webpackConfig);
const devMiddlewareOptions = {
/** Your webpack-dev-middleware-options */
};
const app = express();
app.use(devMiddleware(compiler, devMiddlewareOptions));
app.listen(3000, () => console.log("Example app listening on port 3000!"));
```
### Koa
```js
const Koa = require("koa");
const webpack = require("webpack");
const webpackConfig = require("./webpack.simple.config");
const middleware = require("webpack-dev-middleware");
const compiler = webpack(webpackConfig);
const devMiddlewareOptions = {
/** Your webpack-dev-middleware-options */
};
const app = new Koa();
app.use(middleware.koaWrapper(compiler, devMiddlewareOptions));
app.listen(3000);
```
### Hapi
```js
const Hapi = require("@hapi/hapi");
const webpack = require("webpack");
const webpackConfig = require("./webpack.config.js");
const devMiddleware = require("webpack-dev-middleware");
const compiler = webpack(webpackConfig);
const devMiddlewareOptions = {};
(async () => {
const server = Hapi.server({ port: 3000, host: "localhost" });
await server.register({
plugin: devMiddleware.hapiPlugin(),
options: {
// The `compiler` option is required
compiler,
...devMiddlewareOptions,
},
});
await server.start();
console.log("Server running on %s", server.info.uri);
})();
process.on("unhandledRejection", (err) => {
console.log(err);
process.exit(1);
});
```
### Fastify
Fastify interop will require the use of `fastify-express` instead of `middie` for providing middleware support. As the authors of `fastify-express` recommend, this should only be used as a stopgap while full Fastify support is worked on.
```js
const fastify = require("fastify")();
const webpack = require("webpack");
const webpackConfig = require("./webpack.config.js");
const devMiddleware = require("webpack-dev-middleware");
const compiler = webpack(webpackConfig);
const devMiddlewareOptions = {
/** Your webpack-dev-middleware-options */
};
(async () => {
await fastify.register(require("@fastify/express"));
await fastify.use(devMiddleware(compiler, devMiddlewareOptions));
await fastify.listen(3000);
})();
```
### Hono
```js
import webpack from "webpack";
import { serve } from "@hono/node-server";
import { Hono } from "hono";
import devMiddleware from "webpack-dev-middleware";
import webpackConfig from "./webpack.config.js";
const compiler = webpack(webpackConfig);
const devMiddlewareOptions = {
/** Your webpack-dev-middleware-options */
};
const app = new Hono();
app.use(devMiddleware.honoWrapper(compiler, devMiddlewareOptions));
serve(app);
```
## Contributing
Please take a moment to read our contributing guidelines if you haven't yet done so.
[CONTRIBUTING](./CONTRIBUTING.md)
## License
[MIT](./LICENSE)
[npm]: https://img.shields.io/npm/v/webpack-dev-middleware.svg
[npm-url]: https://npmjs.com/package/webpack-dev-middleware
[node]: https://img.shields.io/node/v/webpack-dev-middleware.svg
[node-url]: https://nodejs.org
[tests]: https://github.com/webpack/webpack-dev-middleware/workflows/webpack-dev-middleware/badge.svg
[tests-url]: https://github.com/webpack/webpack-dev-middleware/actions
[cover]: https://codecov.io/gh/webpack/webpack-dev-middleware/branch/master/graph/badge.svg
[cover-url]: https://codecov.io/gh/webpack/webpack-dev-middleware
[discussion]: https://img.shields.io/github/discussions/webpack/webpack
[discussion-url]: https://github.com/webpack/webpack/discussions
[size]: https://packagephobia.com/badge?p=webpack-dev-middleware
[size-url]: https://packagephobia.com/result?p=webpack-dev-middleware
[docs-url]: https://webpack.js.org/guides/development/#using-webpack-dev-middleware
[hash-url]: https://twitter.com/search?q=webpack
[middleware-url]: https://github.com/webpack/webpack-dev-middleware
[stack-url]: https://stackoverflow.com/questions/tagged/webpack-dev-middleware
[chat-url]: https://github.com/webpack/webpack/discussions
[wjo-url]: https://github.com/webpack/webpack.js.org

603
node_modules/webpack-dev-middleware/dist/index.js generated vendored Normal file
View File

@@ -0,0 +1,603 @@
"use strict";
const {
validate
} = require("schema-utils");
const mime = require("mime-types");
const middleware = require("./middleware");
const getFilenameFromUrl = require("./utils/getFilenameFromUrl");
const setupHooks = require("./utils/setupHooks");
const setupWriteToDisk = require("./utils/setupWriteToDisk");
const setupOutputFileSystem = require("./utils/setupOutputFileSystem");
const ready = require("./utils/ready");
const schema = require("./options.json");
const noop = () => {};
/** @typedef {import("schema-utils/declarations/validate").Schema} Schema */
/** @typedef {import("webpack").Compiler} Compiler */
/** @typedef {import("webpack").MultiCompiler} MultiCompiler */
/** @typedef {import("webpack").Configuration} Configuration */
/** @typedef {import("webpack").Stats} Stats */
/** @typedef {import("webpack").MultiStats} MultiStats */
/** @typedef {import("fs").ReadStream} ReadStream */
/**
* @typedef {Object} ExtendedServerResponse
* @property {{ webpack?: { devMiddleware?: Context<IncomingMessage, ServerResponse> } }} [locals]
*/
/** @typedef {import("http").IncomingMessage} IncomingMessage */
/** @typedef {import("http").ServerResponse & ExtendedServerResponse} ServerResponse */
/**
* @callback NextFunction
* @param {any} [err]
* @return {void}
*/
/**
* @typedef {NonNullable<Configuration["watchOptions"]>} WatchOptions
*/
/**
* @typedef {Compiler["watching"]} Watching
*/
/**
* @typedef {ReturnType<MultiCompiler["watch"]>} MultiWatching
*/
/**
* @typedef {import("webpack").OutputFileSystem & { createReadStream?: import("fs").createReadStream, statSync: import("fs").statSync, readFileSync: import("fs").readFileSync }} OutputFileSystem
*/
/** @typedef {ReturnType<Compiler["getInfrastructureLogger"]>} Logger */
/**
* @callback Callback
* @param {Stats | MultiStats} [stats]
*/
/**
* @typedef {Object} ResponseData
* @property {Buffer | ReadStream} data
* @property {number} byteLength
*/
/**
* @template {IncomingMessage} [RequestInternal=IncomingMessage]
* @template {ServerResponse} [ResponseInternal=ServerResponse]
* @callback ModifyResponseData
* @param {RequestInternal} req
* @param {ResponseInternal} res
* @param {Buffer | ReadStream} data
* @param {number} byteLength
* @return {ResponseData}
*/
/**
* @template {IncomingMessage} [RequestInternal=IncomingMessage]
* @template {ServerResponse} [ResponseInternal=ServerResponse]
* @typedef {Object} Context
* @property {boolean} state
* @property {Stats | MultiStats | undefined} stats
* @property {Callback[]} callbacks
* @property {Options<RequestInternal, ResponseInternal>} options
* @property {Compiler | MultiCompiler} compiler
* @property {Watching | MultiWatching | undefined} watching
* @property {Logger} logger
* @property {OutputFileSystem} outputFileSystem
*/
/**
* @template {IncomingMessage} [RequestInternal=IncomingMessage]
* @template {ServerResponse} [ResponseInternal=ServerResponse]
* @typedef {WithoutUndefined<Context<RequestInternal, ResponseInternal>, "watching">} FilledContext
*/
/** @typedef {Record<string, string | number> | Array<{ key: string, value: number | string }>} NormalizedHeaders */
/**
* @template {IncomingMessage} [RequestInternal=IncomingMessage]
* @template {ServerResponse} [ResponseInternal=ServerResponse]
* @typedef {NormalizedHeaders | ((req: RequestInternal, res: ResponseInternal, context: Context<RequestInternal, ResponseInternal>) => void | undefined | NormalizedHeaders) | undefined} Headers
*/
/**
* @template {IncomingMessage} [RequestInternal = IncomingMessage]
* @template {ServerResponse} [ResponseInternal = ServerResponse]
* @typedef {Object} Options
* @property {{[key: string]: string}} [mimeTypes]
* @property {string | undefined} [mimeTypeDefault]
* @property {boolean | ((targetPath: string) => boolean)} [writeToDisk]
* @property {string[]} [methods]
* @property {Headers<RequestInternal, ResponseInternal>} [headers]
* @property {NonNullable<Configuration["output"]>["publicPath"]} [publicPath]
* @property {Configuration["stats"]} [stats]
* @property {boolean} [serverSideRender]
* @property {OutputFileSystem} [outputFileSystem]
* @property {boolean | string} [index]
* @property {ModifyResponseData<RequestInternal, ResponseInternal>} [modifyResponseData]
* @property {"weak" | "strong"} [etag]
* @property {boolean} [lastModified]
* @property {boolean | number | string | { maxAge?: number, immutable?: boolean }} [cacheControl]
* @property {boolean} [cacheImmutable]
*/
/**
* @template {IncomingMessage} [RequestInternal=IncomingMessage]
* @template {ServerResponse} [ResponseInternal=ServerResponse]
* @callback Middleware
* @param {RequestInternal} req
* @param {ResponseInternal} res
* @param {NextFunction} next
* @return {Promise<void>}
*/
/** @typedef {import("./utils/getFilenameFromUrl").Extra} Extra */
/**
* @callback GetFilenameFromUrl
* @param {string} url
* @param {Extra=} extra
* @returns {string | undefined}
*/
/**
* @callback WaitUntilValid
* @param {Callback} callback
*/
/**
* @callback Invalidate
* @param {Callback} callback
*/
/**
* @callback Close
* @param {(err: Error | null | undefined) => void} callback
*/
/**
* @template {IncomingMessage} RequestInternal
* @template {ServerResponse} ResponseInternal
* @typedef {Object} AdditionalMethods
* @property {GetFilenameFromUrl} getFilenameFromUrl
* @property {WaitUntilValid} waitUntilValid
* @property {Invalidate} invalidate
* @property {Close} close
* @property {Context<RequestInternal, ResponseInternal>} context
*/
/**
* @template {IncomingMessage} [RequestInternal=IncomingMessage]
* @template {ServerResponse} [ResponseInternal=ServerResponse]
* @typedef {Middleware<RequestInternal, ResponseInternal> & AdditionalMethods<RequestInternal, ResponseInternal>} API
*/
/**
* @template T
* @template {keyof T} K
* @typedef {Omit<T, K> & Partial<T>} WithOptional
*/
/**
* @template T
* @template {keyof T} K
* @typedef {T & { [P in K]: NonNullable<T[P]> }} WithoutUndefined
*/
/**
* @template {IncomingMessage} [RequestInternal=IncomingMessage]
* @template {ServerResponse} [ResponseInternal=ServerResponse]
* @param {Compiler | MultiCompiler} compiler
* @param {Options<RequestInternal, ResponseInternal>} [options]
* @returns {API<RequestInternal, ResponseInternal>}
*/
function wdm(compiler, options = {}) {
validate( /** @type {Schema} */schema, options, {
name: "Dev Middleware",
baseDataPath: "options"
});
const {
mimeTypes
} = options;
if (mimeTypes) {
const {
types
} = mime;
// mimeTypes from user provided options should take priority
// over existing, known types
// @ts-ignore
mime.types = {
...types,
...mimeTypes
};
}
/**
* @type {WithOptional<Context<RequestInternal, ResponseInternal>, "watching" | "outputFileSystem">}
*/
const context = {
state: false,
// eslint-disable-next-line no-undefined
stats: undefined,
callbacks: [],
options,
compiler,
logger: compiler.getInfrastructureLogger("webpack-dev-middleware")
};
setupHooks(context);
if (options.writeToDisk) {
setupWriteToDisk(context);
}
setupOutputFileSystem(context);
// Start watching
if ( /** @type {Compiler} */context.compiler.watching) {
context.watching = /** @type {Compiler} */context.compiler.watching;
} else {
/**
* @param {Error | null | undefined} error
*/
const errorHandler = error => {
if (error) {
// TODO: improve that in future
// For example - `writeToDisk` can throw an error and right now it is ends watching.
// We can improve that and keep watching active, but it is require API on webpack side.
// Let's implement that in webpack@5 because it is rare case.
context.logger.error(error);
}
};
if (Array.isArray( /** @type {MultiCompiler} */context.compiler.compilers)) {
const c = /** @type {MultiCompiler} */context.compiler;
const watchOptions = c.compilers.map(childCompiler => childCompiler.options.watchOptions || {});
context.watching = compiler.watch(watchOptions, errorHandler);
} else {
const c = /** @type {Compiler} */context.compiler;
const watchOptions = c.options.watchOptions || {};
context.watching = compiler.watch(watchOptions, errorHandler);
}
}
const filledContext = /** @type {FilledContext<RequestInternal, ResponseInternal>} */
context;
const instance = /** @type {API<RequestInternal, ResponseInternal>} */
middleware(filledContext);
// API
instance.getFilenameFromUrl = (url, extra) => getFilenameFromUrl(filledContext, url, extra);
instance.waitUntilValid = (callback = noop) => {
ready(filledContext, callback);
};
instance.invalidate = (callback = noop) => {
ready(filledContext, callback);
filledContext.watching.invalidate();
};
instance.close = (callback = noop) => {
filledContext.watching.close(callback);
};
instance.context = filledContext;
return instance;
}
/**
* @template S
* @template O
* @typedef {Object} HapiPluginBase
* @property {(server: S, options: O) => void | Promise<void>} register
*/
/**
* @template S
* @template O
* @typedef {HapiPluginBase<S, O> & { pkg: { name: string }, multiple: boolean }} HapiPlugin
*/
/**
* @typedef {Options & { compiler: Compiler | MultiCompiler }} HapiOptions
*/
/**
* @template HapiServer
* @template {HapiOptions} HapiOptionsInternal
* @returns {HapiPlugin<HapiServer, HapiOptionsInternal>}
*/
function hapiWrapper() {
return {
pkg: {
name: "webpack-dev-middleware"
},
// Allow to have multiple middleware
multiple: true,
register(server, options) {
const {
compiler,
...rest
} = options;
if (!compiler) {
throw new Error("The compiler options is required.");
}
const devMiddleware = wdm(compiler, rest);
// @ts-ignore
if (!server.decorations.server.includes("webpackDevMiddleware")) {
// @ts-ignore
server.decorate("server", "webpackDevMiddleware", devMiddleware);
}
// @ts-ignore
server.ext("onRequest", (request, h) => new Promise((resolve, reject) => {
let isFinished = false;
/**
* @param {string | Buffer} [data]
*/
// eslint-disable-next-line no-param-reassign
request.raw.res.send = data => {
isFinished = true;
request.raw.res.end(data);
};
/**
* @param {string | Buffer} [data]
*/
// eslint-disable-next-line no-param-reassign
request.raw.res.finish = data => {
isFinished = true;
request.raw.res.end(data);
};
devMiddleware(request.raw.req, request.raw.res, error => {
if (error) {
reject(error);
return;
}
if (!isFinished) {
resolve(request);
}
});
}).then(() => h.continue).catch(error => {
throw error;
}));
}
};
}
wdm.hapiWrapper = hapiWrapper;
/**
* @template {IncomingMessage} [RequestInternal=IncomingMessage]
* @template {ServerResponse} [ResponseInternal=ServerResponse]
* @param {Compiler | MultiCompiler} compiler
* @param {Options<RequestInternal, ResponseInternal>} [options]
* @returns {(ctx: any, next: Function) => Promise<void> | void}
*/
function koaWrapper(compiler, options) {
const devMiddleware = wdm(compiler, options);
/**
* @param {{ req: RequestInternal, res: ResponseInternal & import("./utils/compatibleAPI").ExpectedServerResponse, status: number, body: string | Buffer | import("fs").ReadStream | { message: string }, state: Object }} ctx
* @param {Function} next
* @returns {Promise<void>}
*/
const wrapper = async function webpackDevMiddleware(ctx, next) {
const {
req,
res
} = ctx;
res.locals = ctx.state;
let {
status
} = ctx;
/**
* @returns {number} code
*/
res.getStatusCode = () => status;
/**
* @param {number} statusCode status code
*/
res.setStatusCode = statusCode => {
status = statusCode;
// eslint-disable-next-line no-param-reassign
ctx.status = statusCode;
};
res.getReadyReadableStreamState = () => "open";
try {
await new Promise(
/**
* @param {(value: void) => void} resolve
* @param {(reason?: any) => void} reject
*/
(resolve, reject) => {
/**
* @param {import("fs").ReadStream} stream readable stream
*/
res.stream = stream => {
// eslint-disable-next-line no-param-reassign
ctx.body = stream;
};
/**
* @param {string | Buffer} data data
*/
res.send = data => {
// eslint-disable-next-line no-param-reassign
ctx.body = data;
};
/**
* @param {string | Buffer} [data] data
*/
res.finish = data => {
// eslint-disable-next-line no-param-reassign
ctx.status = status;
res.end(data);
};
devMiddleware(req, res, err => {
if (err) {
reject(err);
return;
}
resolve();
});
});
} catch (err) {
// eslint-disable-next-line no-param-reassign
ctx.status = /** @type {Error & { statusCode: number }} */err.statusCode || /** @type {Error & { status: number }} */err.status || 500;
// eslint-disable-next-line no-param-reassign
ctx.body = {
message: /** @type {Error} */err.message
};
}
await next();
};
wrapper.devMiddleware = devMiddleware;
return wrapper;
}
wdm.koaWrapper = koaWrapper;
/**
* @template {IncomingMessage} [RequestInternal=IncomingMessage]
* @template {ServerResponse} [ResponseInternal=ServerResponse]
* @param {Compiler | MultiCompiler} compiler
* @param {Options<RequestInternal, ResponseInternal>} [options]
* @returns {(ctx: any, next: Function) => Promise<void> | void}
*/
function honoWrapper(compiler, options) {
const devMiddleware = wdm(compiler, options);
/**
* @param {{ env: any, body: any, json: any, status: any, set:any, req: RequestInternal & import("./utils/compatibleAPI").ExpectedIncomingMessage & { header: (name: string) => string }, res: ResponseInternal & import("./utils/compatibleAPI").ExpectedServerResponse & { headers: any, status: any } }} c
* @param {Function} next
* @returns {Promise<void>}
*/
// eslint-disable-next-line consistent-return
const wrapper = async function webpackDevMiddleware(c, next) {
const {
req,
res
} = c;
c.set("webpack", {
devMiddleware: devMiddleware.context
});
/**
* @returns {string | undefined}
*/
req.getMethod = () => c.req.method;
/**
* @param {string} name
* @returns {string | string[] | undefined}
*/
req.getHeader = name => c.req.header(name);
/**
* @returns {string | undefined}
*/
req.getURL = () => c.req.url;
let {
status
} = c.res;
/**
* @returns {number} code
*/
res.getStatusCode = () => status;
/**
* @param {number} code
*/
res.setStatusCode = code => {
status = code;
};
/**
* @param {string} name header name
*/
res.getHeader = name => c.res.headers.get(name);
/**
* @param {string} name
* @param {string | number | Readonly<string[]>} value
*/
res.setHeader = (name, value) => {
c.res.headers.append(name, value);
return c.res;
};
/**
* @param {string} name
*/
res.removeHeader = name => {
c.res.headers.delete(name);
};
/**
* @returns {string[]}
*/
res.getResponseHeaders = () => Array.from(c.res.headers.keys());
/**
* @returns {ServerResponse}
*/
res.getOutgoing = () => c.env.outgoing;
res.setState = () => {
// Do nothing, because we set it before
};
res.getReadyReadableStreamState = () => "readable";
res.getHeadersSent = () => c.env.outgoing.headersSent;
let body;
try {
await new Promise(
/**
* @param {(value: void) => void} resolve
* @param {(reason?: any) => void} reject
*/
(resolve, reject) => {
/**
* @param {import("fs").ReadStream} stream readable stream
*/
res.stream = stream => {
body = stream;
// responseHandler(stream);
};
/**
* @param {string | Buffer} data data
*/
res.send = data => {
body = data;
};
/**
* @param {string | Buffer} [data] data
*/
res.finish = data => {
body = typeof data !== "undefined" ? data : null;
};
devMiddleware(req, res, err => {
if (err) {
reject(err);
return;
}
resolve();
});
});
} catch (err) {
c.status(500);
return c.json({
message: /** @type {Error} */err.message
});
}
if (typeof body !== "undefined") {
return c.body(body, status);
}
await next();
};
wrapper.devMiddleware = devMiddleware;
return wrapper;
}
wdm.honoWrapper = honoWrapper;
module.exports = wdm;

677
node_modules/webpack-dev-middleware/dist/middleware.js generated vendored Normal file
View File

@@ -0,0 +1,677 @@
"use strict";
const path = require("path");
const mime = require("mime-types");
const onFinishedStream = require("on-finished");
const getFilenameFromUrl = require("./utils/getFilenameFromUrl");
const {
setStatusCode,
getStatusCode,
getRequestHeader,
getRequestMethod,
getRequestURL,
getResponseHeader,
setResponseHeader,
removeResponseHeader,
getResponseHeaders,
getHeadersSent,
send,
finish,
pipe,
createReadStreamOrReadFileSync,
getOutgoing,
initState,
setState,
getReadyReadableStreamState
} = require("./utils/compatibleAPI");
const ready = require("./utils/ready");
const parseTokenList = require("./utils/parseTokenList");
const memorize = require("./utils/memorize");
/** @typedef {import("./index.js").NextFunction} NextFunction */
/** @typedef {import("./index.js").IncomingMessage} IncomingMessage */
/** @typedef {import("./index.js").ServerResponse} ServerResponse */
/** @typedef {import("./index.js").NormalizedHeaders} NormalizedHeaders */
/** @typedef {import("fs").ReadStream} ReadStream */
const BYTES_RANGE_REGEXP = /^ *bytes/i;
/**
* @param {string} type
* @param {number} size
* @param {import("range-parser").Range} [range]
* @returns {string}
*/
function getValueContentRangeHeader(type, size, range) {
return `${type} ${range ? `${range.start}-${range.end}` : "*"}/${size}`;
}
/**
* Parse an HTTP Date into a number.
*
* @param {string} date
* @returns {number}
*/
function parseHttpDate(date) {
const timestamp = date && Date.parse(date);
// istanbul ignore next: guard against date.js Date.parse patching
return typeof timestamp === "number" ? timestamp : NaN;
}
const CACHE_CONTROL_NO_CACHE_REGEXP = /(?:^|,)\s*?no-cache\s*?(?:,|$)/;
/**
* @param {import("fs").ReadStream} stream stream
* @param {boolean} suppress do need suppress?
* @returns {void}
*/
function destroyStream(stream, suppress) {
if (typeof stream.destroy === "function") {
stream.destroy();
}
if (typeof stream.close === "function") {
// Node.js core bug workaround
stream.on("open",
/**
* @this {import("fs").ReadStream}
*/
function onOpenClose() {
// @ts-ignore
if (typeof this.fd === "number") {
// actually close down the fd
this.close();
}
});
}
if (typeof stream.addListener === "function" && suppress) {
stream.removeAllListeners("error");
stream.addListener("error", () => {});
}
}
/** @type {Record<number, string>} */
const statuses = {
400: "Bad Request",
403: "Forbidden",
404: "Not Found",
416: "Range Not Satisfiable",
500: "Internal Server Error"
};
const parseRangeHeaders = memorize(
/**
* @param {string} value
* @returns {import("range-parser").Result | import("range-parser").Ranges}
*/
value => {
const [len, rangeHeader] = value.split("|");
// eslint-disable-next-line global-require
return require("range-parser")(Number(len), rangeHeader, {
combine: true
});
});
const MAX_MAX_AGE = 31536000000;
/**
* @template {IncomingMessage} Request
* @template {ServerResponse} Response
* @typedef {Object} SendErrorOptions send error options
* @property {Record<string, number | string | string[] | undefined>=} headers headers
* @property {import("./index").ModifyResponseData<Request, Response>=} modifyResponseData modify response data callback
*/
/**
* @template {IncomingMessage} Request
* @template {ServerResponse} Response
* @param {import("./index.js").FilledContext<Request, Response>} context
* @return {import("./index.js").Middleware<Request, Response>}
*/
function wrapper(context) {
return async function middleware(req, res, next) {
const acceptedMethods = context.options.methods || ["GET", "HEAD"];
initState(res);
async function goNext() {
if (!context.options.serverSideRender) {
return next();
}
return new Promise(resolve => {
ready(context, () => {
setState(res, "webpack", {
devMiddleware: context
});
resolve(next());
}, req);
});
}
const method = getRequestMethod(req);
if (method && !acceptedMethods.includes(method)) {
await goNext();
return;
}
/**
* @param {number} status status
* @param {Partial<SendErrorOptions<Request, Response>>=} options options
* @returns {void}
*/
function sendError(status, options) {
// eslint-disable-next-line global-require
const escapeHtml = require("./utils/escapeHtml");
const content = statuses[status] || String(status);
let document = Buffer.from(`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>${escapeHtml(content)}</pre>
</body>
</html>`, "utf-8");
// Clear existing headers
const headers = getResponseHeaders(res);
for (let i = 0; i < headers.length; i++) {
removeResponseHeader(res, headers[i]);
}
if (options && options.headers) {
const keys = Object.keys(options.headers);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const value = options.headers[key];
if (typeof value !== "undefined") {
setResponseHeader(res, key, value);
}
}
}
// Send basic response
setStatusCode(res, status);
setResponseHeader(res, "Content-Type", "text/html; charset=utf-8");
setResponseHeader(res, "Content-Security-Policy", "default-src 'none'");
setResponseHeader(res, "X-Content-Type-Options", "nosniff");
let byteLength = Buffer.byteLength(document);
if (options && options.modifyResponseData) {
({
data: document,
byteLength
} = /** @type {{ data: Buffer, byteLength: number }} */
options.modifyResponseData(req, res, document, byteLength));
}
setResponseHeader(res, "Content-Length", byteLength);
finish(res, document);
}
/**
* @param {NodeJS.ErrnoException} error
*/
function errorHandler(error) {
switch (error.code) {
case "ENAMETOOLONG":
case "ENOENT":
case "ENOTDIR":
sendError(404, {
modifyResponseData: context.options.modifyResponseData
});
break;
default:
sendError(500, {
modifyResponseData: context.options.modifyResponseData
});
break;
}
}
function isConditionalGET() {
return getRequestHeader(req, "if-match") || getRequestHeader(req, "if-unmodified-since") || getRequestHeader(req, "if-none-match") || getRequestHeader(req, "if-modified-since");
}
function isPreconditionFailure() {
// if-match
const ifMatch = /** @type {string} */getRequestHeader(req, "if-match");
// A recipient MUST ignore If-Unmodified-Since if the request contains
// an If-Match header field; the condition in If-Match is considered to
// be a more accurate replacement for the condition in
// If-Unmodified-Since, and the two are only combined for the sake of
// interoperating with older intermediaries that might not implement If-Match.
if (ifMatch) {
const etag = getResponseHeader(res, "ETag");
return !etag || ifMatch !== "*" && parseTokenList(ifMatch).every(match => match !== etag && match !== `W/${etag}` && `W/${match}` !== etag);
}
// if-unmodified-since
const ifUnmodifiedSince = /** @type {string} */
getRequestHeader(req, "if-unmodified-since");
if (ifUnmodifiedSince) {
const unmodifiedSince = parseHttpDate(ifUnmodifiedSince);
// A recipient MUST ignore the If-Unmodified-Since header field if the
// received field-value is not a valid HTTP-date.
if (!isNaN(unmodifiedSince)) {
const lastModified = parseHttpDate( /** @type {string} */getResponseHeader(res, "Last-Modified"));
return isNaN(lastModified) || lastModified > unmodifiedSince;
}
}
return false;
}
/**
* @returns {boolean} is cachable
*/
function isCachable() {
const statusCode = getStatusCode(res);
return statusCode >= 200 && statusCode < 300 || statusCode === 304 ||
// For Koa and Hono, because by default status code is 404, but we already found a file
statusCode === 404;
}
/**
* @param {import("http").OutgoingHttpHeaders} resHeaders
* @returns {boolean}
*/
function isFresh(resHeaders) {
// Always return stale when Cache-Control: no-cache to support end-to-end reload requests
// https://tools.ietf.org/html/rfc2616#section-14.9.4
const cacheControl = /** @type {string} */
getRequestHeader(req, "cache-control");
if (cacheControl && CACHE_CONTROL_NO_CACHE_REGEXP.test(cacheControl)) {
return false;
}
// fields
const noneMatch = /** @type {string} */
getRequestHeader(req, "if-none-match");
const modifiedSince = /** @type {string} */
getRequestHeader(req, "if-modified-since");
// unconditional request
if (!noneMatch && !modifiedSince) {
return false;
}
// if-none-match
if (noneMatch && noneMatch !== "*") {
if (!resHeaders.etag) {
return false;
}
const matches = parseTokenList(noneMatch);
let etagStale = true;
for (let i = 0; i < matches.length; i++) {
const match = matches[i];
if (match === resHeaders.etag || match === `W/${resHeaders.etag}` || `W/${match}` === resHeaders.etag) {
etagStale = false;
break;
}
}
if (etagStale) {
return false;
}
}
// A recipient MUST ignore If-Modified-Since if the request contains an If-None-Match header field;
// the condition in If-None-Match is considered to be a more accurate replacement for the condition in If-Modified-Since,
// and the two are only combined for the sake of interoperating with older intermediaries that might not implement If-None-Match.
if (noneMatch) {
return true;
}
// if-modified-since
if (modifiedSince) {
const lastModified = resHeaders["last-modified"];
// A recipient MUST ignore the If-Modified-Since header field if the
// received field-value is not a valid HTTP-date, or if the request
// method is neither GET nor HEAD.
const modifiedStale = !lastModified || !(parseHttpDate(lastModified) <= parseHttpDate(modifiedSince));
if (modifiedStale) {
return false;
}
}
return true;
}
function isRangeFresh() {
const ifRange = /** @type {string | undefined} */
getRequestHeader(req, "if-range");
if (!ifRange) {
return true;
}
// if-range as etag
if (ifRange.indexOf('"') !== -1) {
const etag = /** @type {string | undefined} */
getResponseHeader(res, "ETag");
if (!etag) {
return true;
}
return Boolean(etag && ifRange.indexOf(etag) !== -1);
}
// if-range as modified date
const lastModified = /** @type {string | undefined} */
getResponseHeader(res, "Last-Modified");
if (!lastModified) {
return true;
}
return parseHttpDate(lastModified) <= parseHttpDate(ifRange);
}
/**
* @returns {string | undefined}
*/
function getRangeHeader() {
const range = /** @type {string} */getRequestHeader(req, "range");
if (range && BYTES_RANGE_REGEXP.test(range)) {
return range;
}
// eslint-disable-next-line no-undefined
return undefined;
}
/**
* @param {import("range-parser").Range} range
* @returns {[number, number]}
*/
function getOffsetAndLenFromRange(range) {
const offset = range.start;
const len = range.end - range.start + 1;
return [offset, len];
}
/**
* @param {number} offset
* @param {number} len
* @returns {[number, number]}
*/
function calcStartAndEnd(offset, len) {
const start = offset;
const end = Math.max(offset, offset + len - 1);
return [start, end];
}
async function processRequest() {
// Pipe and SendFile
/** @type {import("./utils/getFilenameFromUrl").Extra} */
const extra = {};
const filename = getFilenameFromUrl(context, /** @type {string} */getRequestURL(req), extra);
if (extra.errorCode) {
if (extra.errorCode === 403) {
context.logger.error(`Malicious path "${filename}".`);
}
sendError(extra.errorCode, {
modifyResponseData: context.options.modifyResponseData
});
await goNext();
return;
}
if (!filename) {
await goNext();
return;
}
if (getHeadersSent(res)) {
await goNext();
return;
}
const {
size
} = /** @type {import("fs").Stats} */extra.stats;
let len = size;
let offset = 0;
// Send logic
if (context.options.headers) {
let {
headers
} = context.options;
if (typeof headers === "function") {
headers = /** @type {NormalizedHeaders} */
headers(req, res, context);
}
/**
* @type {{key: string, value: string | number}[]}
*/
const allHeaders = [];
if (typeof headers !== "undefined") {
if (!Array.isArray(headers)) {
// eslint-disable-next-line guard-for-in
for (const name in headers) {
allHeaders.push({
key: name,
value: headers[name]
});
}
headers = allHeaders;
}
for (const {
key,
value
} of headers) {
setResponseHeader(res, key, value);
}
}
}
if (!getResponseHeader(res, "Accept-Ranges")) {
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")) {
const modified = /** @type {import("fs").Stats} */
extra.stats.mtime.toUTCString();
setResponseHeader(res, "Last-Modified", modified);
}
/** @type {number} */
let start;
/** @type {number} */
let end;
/** @type {undefined | Buffer | ReadStream} */
let bufferOrStream;
/** @type {number | undefined} */
let byteLength;
const rangeHeader = getRangeHeader();
if (context.options.etag && !getResponseHeader(res, "ETag")) {
/** @type {import("fs").Stats | Buffer | ReadStream | undefined} */
let value;
// TODO cache etag generation?
if (context.options.etag === "weak") {
value = /** @type {import("fs").Stats} */extra.stats;
} else {
if (rangeHeader) {
const parsedRanges = /** @type {import("range-parser").Ranges | import("range-parser").Result} */
parseRangeHeaders(`${size}|${rangeHeader}`);
if (parsedRanges !== -2 && parsedRanges !== -1 && parsedRanges.length === 1) {
[offset, len] = getOffsetAndLenFromRange(parsedRanges[0]);
}
}
[start, end] = calcStartAndEnd(offset, len);
try {
const result = createReadStreamOrReadFileSync(filename, context.outputFileSystem, start, end);
value = result.bufferOrStream;
({
bufferOrStream,
byteLength
} = result);
} catch (error) {
errorHandler( /** @type {NodeJS.ErrnoException} */error);
await goNext();
return;
}
}
if (value) {
// eslint-disable-next-line global-require
const result = await require("./utils/etag")(value);
// Because we already read stream, we can cache buffer to avoid extra read from fs
if (result.buffer) {
bufferOrStream = result.buffer;
}
setResponseHeader(res, "ETag", result.hash);
}
}
if (!getResponseHeader(res, "Content-Type") || getStatusCode(res) === 404) {
removeResponseHeader(res, "Content-Type");
// content-type name(like application/javascript; charset=utf-8) or false
const contentType = mime.contentType(path.extname(filename));
// Only set content-type header if media type is known
// https://tools.ietf.org/html/rfc7231#section-3.1.1.5
if (contentType) {
setResponseHeader(res, "Content-Type", contentType);
} else if (context.options.mimeTypeDefault) {
setResponseHeader(res, "Content-Type", context.options.mimeTypeDefault);
}
}
// Conditional GET support
if (isConditionalGET()) {
if (isPreconditionFailure()) {
sendError(412, {
modifyResponseData: context.options.modifyResponseData
});
await goNext();
return;
}
if (isCachable() && isFresh({
etag: ( /** @type {string | undefined} */
getResponseHeader(res, "ETag")),
"last-modified": ( /** @type {string | undefined} */
getResponseHeader(res, "Last-Modified"))
})) {
setStatusCode(res, 304);
// Remove content header fields
removeResponseHeader(res, "Content-Encoding");
removeResponseHeader(res, "Content-Language");
removeResponseHeader(res, "Content-Length");
removeResponseHeader(res, "Content-Range");
removeResponseHeader(res, "Content-Type");
finish(res);
await goNext();
return;
}
}
let isPartialContent = false;
if (rangeHeader) {
let parsedRanges = /** @type {import("range-parser").Ranges | import("range-parser").Result | []} */
parseRangeHeaders(`${size}|${rangeHeader}`);
// If-Range support
if (!isRangeFresh()) {
parsedRanges = [];
}
if (parsedRanges === -1) {
context.logger.error("Unsatisfiable range for 'Range' header.");
setResponseHeader(res, "Content-Range", getValueContentRangeHeader("bytes", size));
sendError(416, {
headers: {
"Content-Range": getResponseHeader(res, "Content-Range")
},
modifyResponseData: context.options.modifyResponseData
});
await goNext();
return;
} else if (parsedRanges === -2) {
context.logger.error("A malformed 'Range' header was provided. A regular response will be sent for this request.");
} else if (parsedRanges.length > 1) {
context.logger.error("A 'Range' header with multiple ranges was provided. Multiple ranges are not supported, so a regular response will be sent for this request.");
}
if (parsedRanges !== -2 && parsedRanges.length === 1) {
// Content-Range
setStatusCode(res, 206);
setResponseHeader(res, "Content-Range", getValueContentRangeHeader("bytes", size, /** @type {import("range-parser").Ranges} */parsedRanges[0]));
isPartialContent = true;
[offset, len] = getOffsetAndLenFromRange(parsedRanges[0]);
}
}
// When strong Etag generation is enabled we already read file, so we can skip extra fs call
if (!bufferOrStream) {
[start, end] = calcStartAndEnd(offset, len);
try {
({
bufferOrStream,
byteLength
} = createReadStreamOrReadFileSync(filename, context.outputFileSystem, start, end));
} catch (error) {
errorHandler( /** @type {NodeJS.ErrnoException} */error);
await goNext();
return;
}
}
if (context.options.modifyResponseData) {
({
data: bufferOrStream,
byteLength
} = context.options.modifyResponseData(req, res, bufferOrStream, /** @type {number} */
byteLength));
}
setResponseHeader(res, "Content-Length", /** @type {number} */
byteLength);
if (method === "HEAD") {
if (!isPartialContent) {
setStatusCode(res, 200);
}
finish(res);
await goNext();
return;
}
if (!isPartialContent) {
setStatusCode(res, 200);
}
const isPipeSupports = typeof ( /** @type {import("fs").ReadStream} */bufferOrStream.pipe) === "function";
if (!isPipeSupports) {
send(res, /** @type {Buffer} */bufferOrStream);
await goNext();
return;
}
// Cleanup
const cleanup = () => {
destroyStream( /** @type {import("fs").ReadStream} */bufferOrStream, true);
};
// Error handling
/** @type {import("fs").ReadStream} */
bufferOrStream.on("error", error => {
// clean up stream early
cleanup();
errorHandler(error);
goNext();
}).on(getReadyReadableStreamState(res), () => {
goNext();
});
pipe(res, /** @type {ReadStream} */bufferOrStream);
const outgoing = getOutgoing(res);
if (outgoing) {
// Response finished, cleanup
onFinishedStream(outgoing, cleanup);
}
}
ready(context, processRequest, req);
};
}
module.exports = wrapper;

178
node_modules/webpack-dev-middleware/dist/options.json generated vendored Normal file
View File

@@ -0,0 +1,178 @@
{
"type": "object",
"properties": {
"mimeTypes": {
"description": "Allows a user to register custom mime types or extension mappings.",
"link": "https://github.com/webpack/webpack-dev-middleware#mimetypes",
"type": "object"
},
"mimeTypeDefault": {
"description": "Allows a user to register a default mime type when we can't determine the content type.",
"link": "https://github.com/webpack/webpack-dev-middleware#mimetypedefault",
"type": "string"
},
"writeToDisk": {
"description": "Allows to write generated files on disk.",
"link": "https://github.com/webpack/webpack-dev-middleware#writetodisk",
"anyOf": [
{
"type": "boolean"
},
{
"instanceof": "Function"
}
]
},
"methods": {
"description": "Allows to pass the list of HTTP request methods accepted by the middleware.",
"link": "https://github.com/webpack/webpack-dev-middleware#methods",
"type": "array",
"items": {
"type": "string",
"minLength": 1
}
},
"headers": {
"anyOf": [
{
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"key": {
"description": "key of header.",
"type": "string"
},
"value": {
"description": "value of header.",
"type": "string"
}
}
},
"minItems": 1
},
{
"type": "object"
},
{
"instanceof": "Function"
}
],
"description": "Allows to pass custom HTTP headers on each request",
"link": "https://github.com/webpack/webpack-dev-middleware#headers"
},
"publicPath": {
"description": "The `publicPath` specifies the public URL address of the output files when referenced in a browser.",
"link": "https://github.com/webpack/webpack-dev-middleware#publicpath",
"anyOf": [
{
"enum": ["auto"]
},
{
"type": "string"
},
{
"instanceof": "Function"
}
]
},
"stats": {
"description": "Stats options object or preset name.",
"link": "https://github.com/webpack/webpack-dev-middleware#stats",
"anyOf": [
{
"enum": [
"none",
"summary",
"errors-only",
"errors-warnings",
"minimal",
"normal",
"detailed",
"verbose"
]
},
{
"type": "boolean"
},
{
"type": "object",
"additionalProperties": true
}
]
},
"serverSideRender": {
"description": "Instructs the module to enable or disable the server-side rendering mode.",
"link": "https://github.com/webpack/webpack-dev-middleware#serversiderender",
"type": "boolean"
},
"outputFileSystem": {
"description": "Set the default file system which will be used by webpack as primary destination of generated files.",
"link": "https://github.com/webpack/webpack-dev-middleware#outputfilesystem",
"type": "object"
},
"index": {
"description": "Allows to serve an index of the directory.",
"link": "https://github.com/webpack/webpack-dev-middleware#index",
"anyOf": [
{
"type": "boolean"
},
{
"type": "string",
"minLength": 1
}
]
},
"modifyResponseData": {
"description": "Allows to set up a callback to change the response data.",
"link": "https://github.com/webpack/webpack-dev-middleware#modifyresponsedata",
"instanceof": "Function"
},
"etag": {
"description": "Enable or disable etag generation.",
"link": "https://github.com/webpack/webpack-dev-middleware#etag",
"enum": ["weak", "strong"]
},
"lastModified": {
"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
}

View File

@@ -0,0 +1,318 @@
"use strict";
/** @typedef {import("../index.js").IncomingMessage} IncomingMessage */
/** @typedef {import("../index.js").ServerResponse} ServerResponse */
/** @typedef {import("../index").OutputFileSystem} OutputFileSystem */
/**
* @typedef {Object} ExpectedIncomingMessage
* @property {(name: string) => string | string[] | undefined} [getHeader]
* @property {() => string | undefined} [getMethod]
* @property {() => string | undefined} [getURL]
*/
/**
* @typedef {Object} ExpectedServerResponse
* @property {(status: number) => void} [setStatusCode]
* @property {() => number} [getStatusCode]
* @property {(name: string) => string | string[] | undefined | number} [getHeader]
* @property {(name: string, value: number | string | Readonly<string[]>) => ExpectedServerResponse} [setHeader]
* @property {(name: string) => void} [removeHeader]
* @property {(data: string | Buffer) => void} [send]
* @property {(data?: string | Buffer) => void} [finish]
* @property {() => string[]} [getResponseHeaders]
* @property {() => boolean} [getHeadersSent]
* @property {(data: any) => void} [stream]
* @property {() => any} [getOutgoing]
* @property {(name: string, value: any) => void} [setState]
* @property {() => "ready" | "open" | "readable"} [getReadyReadableStreamState]
*/
/**
* @template {IncomingMessage & ExpectedIncomingMessage} Request
* @param {Request} req
* @param {string} name
* @returns {string | string[] | undefined}
*/
function getRequestHeader(req, name) {
// Pseudo API
if (typeof req.getHeader === "function") {
return req.getHeader(name);
}
return req.headers[name];
}
/**
* @template {IncomingMessage & ExpectedIncomingMessage} Request
* @param {Request} req
* @returns {string | undefined}
*/
function getRequestMethod(req) {
// Pseudo API
if (typeof req.getMethod === "function") {
return req.getMethod();
}
return req.method;
}
/**
* @template {IncomingMessage & ExpectedIncomingMessage} Request
* @param {Request} req
* @returns {string | undefined}
*/
function getRequestURL(req) {
// Pseudo API
if (typeof req.getURL === "function") {
return req.getURL();
}
return req.url;
}
/**
* @template {ServerResponse & ExpectedServerResponse} Response
* @param {Response} res
* @param {number} code
*/
function setStatusCode(res, code) {
// Pseudo API
if (typeof res.setStatusCode === "function") {
res.setStatusCode(code);
return;
}
// Node.js API
// eslint-disable-next-line no-param-reassign
res.statusCode = code;
}
/**
* @template {ServerResponse & ExpectedServerResponse} Response
* @param {Response} res
* @returns {number}
*/
function getStatusCode(res) {
// Pseudo API
if (typeof res.getStatusCode === "function") {
return res.getStatusCode();
}
return res.statusCode;
}
/**
* @template {ServerResponse & ExpectedServerResponse} Response
* @param {Response} res
* @param {string} name
* @returns {string | string[] | undefined | number}
*/
function getResponseHeader(res, name) {
// Real and Pseudo API
return res.getHeader(name);
}
/**
* @template {ServerResponse & ExpectedServerResponse} Response
* @param {Response} res
* @param {string} name
* @param {number | string | Readonly<string[]>} value
* @returns {Response}
*/
function setResponseHeader(res, name, value) {
// Real and Pseudo API
return res.setHeader(name, value);
}
/**
* @template {ServerResponse & ExpectedServerResponse} Response
* @param {Response} res
* @param {string} name
*/
function removeResponseHeader(res, name) {
// Real and Pseudo API
res.removeHeader(name);
}
/**
* @template {ServerResponse & ExpectedServerResponse} Response
* @param {Response} res
* @returns {string[]}
*/
function getResponseHeaders(res) {
// Pseudo API
if (typeof res.getResponseHeaders === "function") {
return res.getResponseHeaders();
}
return res.getHeaderNames();
}
/**
* @template {ServerResponse & ExpectedServerResponse} Response
* @param {Response} res
* @returns {boolean}
*/
function getHeadersSent(res) {
// Pseudo API
if (typeof res.getHeadersSent === "function") {
return res.getHeadersSent();
}
return res.headersSent;
}
/**
* @template {ServerResponse & ExpectedServerResponse} Response
* @param {Response} res
* @param {import("fs").ReadStream} bufferOrStream
*/
function pipe(res, bufferOrStream) {
// Pseudo API and Koa API
if (typeof res.stream === "function") {
// Writable stream into Readable stream
res.stream(bufferOrStream);
return;
}
// Node.js API and Express API and Hapi API
bufferOrStream.pipe(res);
}
/**
* @template {ServerResponse & ExpectedServerResponse} Response
* @param {Response} res
* @param {string | Buffer} bufferOrString
*/
function send(res, bufferOrString) {
// Pseudo API and Express API and Koa API
if (typeof res.send === "function") {
res.send(bufferOrString);
return;
}
res.end(bufferOrString);
}
/**
* @template {ServerResponse & ExpectedServerResponse} Response
* @param {Response} res
* @param {string | Buffer} [data]
*/
function finish(res, data) {
// Pseudo API and Express API and Koa API
if (typeof res.finish === "function") {
res.finish(data);
return;
}
// Pseudo API and Express API and Koa API
res.end(data);
}
/**
* @param {string} filename
* @param {OutputFileSystem} outputFileSystem
* @param {number} start
* @param {number} end
* @returns {{ bufferOrStream: (Buffer | import("fs").ReadStream), byteLength: number }}
*/
function createReadStreamOrReadFileSync(filename, outputFileSystem, start, end) {
/** @type {string | Buffer | import("fs").ReadStream} */
let bufferOrStream;
/** @type {number} */
let byteLength;
// Stream logic
const isFsSupportsStream = typeof outputFileSystem.createReadStream === "function";
if (isFsSupportsStream) {
bufferOrStream = /** @type {import("fs").createReadStream} */
outputFileSystem.createReadStream(filename, {
start,
end
});
// Handle files with zero bytes
byteLength = end === 0 ? 0 : end - start + 1;
} else {
bufferOrStream = outputFileSystem.readFileSync(filename);
({
byteLength
} = bufferOrStream);
}
return {
bufferOrStream,
byteLength
};
}
/**
* @template {ServerResponse & ExpectedServerResponse} Response
* @param {Response} res
* @returns {Response} res
*/
function getOutgoing(res) {
// Pseudo API and Express API and Koa API
if (typeof res.getOutgoing === "function") {
return res.getOutgoing();
}
return res;
}
/**
* @template {ServerResponse & ExpectedServerResponse} Response
* @param {Response} res
*/
function initState(res) {
if (typeof res.setState === "function") {
return;
}
// fixes #282. credit @cexoso. in certain edge situations res.locals is undefined.
// eslint-disable-next-line no-param-reassign
res.locals = res.locals || {};
}
/**
* @template {ServerResponse & ExpectedServerResponse} Response
* @param {Response} res
* @param {string} name
* @param {any} value
*/
function setState(res, name, value) {
if (typeof res.setState === "function") {
res.setState(name, value);
return;
}
/** @type {any} */
// eslint-disable-next-line no-param-reassign
res.locals[name] = value;
}
/**
* @template {ServerResponse & ExpectedServerResponse} Response
* @param {Response} res
* @returns {"ready" | "open" | "readable"}
*/
function getReadyReadableStreamState(res) {
// Pseudo API and Express API and Koa API
if (typeof res.getReadyReadableStreamState === "function") {
return res.getReadyReadableStreamState();
}
return "ready";
}
module.exports = {
setStatusCode,
getStatusCode,
getRequestHeader,
getRequestMethod,
getRequestURL,
getResponseHeader,
setResponseHeader,
removeResponseHeader,
getResponseHeaders,
getHeadersSent,
pipe,
send,
finish,
createReadStreamOrReadFileSync,
getOutgoing,
initState,
setState,
getReadyReadableStreamState
};

View File

@@ -0,0 +1,55 @@
"use strict";
const matchHtmlRegExp = /["'&<>]/;
/**
* @param {string} string raw HTML
* @returns {string} escaped HTML
*/
function escapeHtml(string) {
const str = `${string}`;
const match = matchHtmlRegExp.exec(str);
if (!match) {
return str;
}
let escape;
let html = "";
let index = 0;
let lastIndex = 0;
for (({
index
} = match); index < str.length; index++) {
switch (str.charCodeAt(index)) {
// "
case 34:
escape = "&quot;";
break;
// &
case 38:
escape = "&amp;";
break;
// '
case 39:
escape = "&#39;";
break;
// <
case 60:
escape = "&lt;";
break;
// >
case 62:
escape = "&gt;";
break;
default:
// eslint-disable-next-line no-continue
continue;
}
if (lastIndex !== index) {
html += str.substring(lastIndex, index);
}
lastIndex = index + 1;
html += escape;
}
return lastIndex !== index ? html + str.substring(lastIndex, index) : html;
}
module.exports = escapeHtml;

78
node_modules/webpack-dev-middleware/dist/utils/etag.js generated vendored Normal file
View File

@@ -0,0 +1,78 @@
"use strict";
const crypto = require("crypto");
/** @typedef {import("fs").Stats} Stats */
/** @typedef {import("fs").ReadStream} ReadStream */
/**
* Generate a tag for a stat.
*
* @param {Stats} stat
* @return {{ hash: string, buffer?: Buffer }}
*/
function statTag(stat) {
const mtime = stat.mtime.getTime().toString(16);
const size = stat.size.toString(16);
return {
hash: `W/"${size}-${mtime}"`
};
}
/**
* Generate an entity tag.
*
* @param {Buffer | ReadStream} entity
* @return {Promise<{ hash: string, buffer?: Buffer }>}
*/
async function entityTag(entity) {
const sha1 = crypto.createHash("sha1");
if (!Buffer.isBuffer(entity)) {
let byteLength = 0;
/** @type {Buffer[]} */
const buffers = [];
await new Promise((resolve, reject) => {
entity.on("data", chunk => {
sha1.update(chunk);
buffers.push( /** @type {Buffer} */chunk);
byteLength += /** @type {Buffer} */chunk.byteLength;
}).on("end", () => {
resolve(sha1);
}).on("error", reject);
});
return {
buffer: Buffer.concat(buffers),
hash: `"${byteLength.toString(16)}-${sha1.digest("base64").substring(0, 27)}"`
};
}
if (entity.byteLength === 0) {
// Fast-path empty
return {
hash: '"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"'
};
}
// Compute hash of entity
const hash = sha1.update(entity).digest("base64").substring(0, 27);
// Compute length of entity
const {
byteLength
} = entity;
return {
hash: `"${byteLength.toString(16)}-${hash}"`
};
}
/**
* Create a simple ETag.
*
* @param {Buffer | ReadStream | Stats} entity
* @return {Promise<{ hash: string, buffer?: Buffer }>}
*/
async function etag(entity) {
const isStrong = Buffer.isBuffer(entity) || typeof ( /** @type {ReadStream} */entity.pipe) === "function";
return isStrong ? entityTag( /** @type {Buffer | ReadStream} */entity) : statTag( /** @type {import("fs").Stats} */entity);
}
module.exports = etag;

View File

@@ -0,0 +1,150 @@
"use strict";
const path = require("path");
const {
parse
} = require("url");
const querystring = require("querystring");
const getPaths = require("./getPaths");
const memorize = require("./memorize");
/** @typedef {import("../index.js").IncomingMessage} IncomingMessage */
/** @typedef {import("../index.js").ServerResponse} ServerResponse */
// eslint-disable-next-line no-undefined
const memoizedParse = memorize(parse, undefined, value => {
if (value.pathname) {
// eslint-disable-next-line no-param-reassign
value.pathname = decode(value.pathname);
}
return value;
});
const UP_PATH_REGEXP = /(?:^|[\\/])\.\.(?:[\\/]|$)/;
/**
* @typedef {Object} Extra
* @property {import("fs").Stats=} stats
* @property {number=} errorCode
* @property {boolean=} immutable
*/
/**
* decodeURIComponent.
*
* Allows V8 to only deoptimize this fn instead of all of send().
*
* @param {string} input
* @returns {string}
*/
function decode(input) {
return querystring.unescape(input);
}
// TODO refactor me in the next major release, this function should return `{ filename, stats, error }`
// TODO fix redirect logic when `/` at the end, like https://github.com/pillarjs/send/blob/master/index.js#L586
/**
* @template {IncomingMessage} Request
* @template {ServerResponse} Response
* @param {import("../index.js").FilledContext<Request, Response>} context
* @param {string} url
* @param {Extra=} extra
* @returns {string | undefined}
*/
function getFilenameFromUrl(context, url, extra = {}) {
const {
options
} = context;
const paths = getPaths(context);
/** @type {string | undefined} */
let foundFilename;
/** @type {URL} */
let urlObject;
try {
// The `url` property of the `request` is contains only `pathname`, `search` and `hash`
urlObject = memoizedParse(url, false, true);
} catch (_ignoreError) {
return;
}
for (const {
publicPath,
outputPath,
assetsInfo
} of paths) {
/** @type {string | undefined} */
let filename;
/** @type {URL} */
let publicPathObject;
try {
publicPathObject = memoizedParse(publicPath !== "auto" && publicPath ? publicPath : "/", false, true);
} catch (_ignoreError) {
// eslint-disable-next-line no-continue
continue;
}
const {
pathname
} = urlObject;
const {
pathname: publicPathPathname
} = publicPathObject;
if (pathname && pathname.startsWith(publicPathPathname)) {
// Null byte(s)
if (pathname.includes("\0")) {
// eslint-disable-next-line no-param-reassign
extra.errorCode = 400;
return;
}
// ".." is malicious
if (UP_PATH_REGEXP.test(path.normalize(`./${pathname}`))) {
// eslint-disable-next-line no-param-reassign
extra.errorCode = 403;
return;
}
// Strip the `pathname` property from the `publicPath` option from the start of requested url
// `/complex/foo.js` => `foo.js`
// and add outputPath
// `foo.js` => `/home/user/my-project/dist/foo.js`
filename = path.join(outputPath, pathname.slice(publicPathPathname.length));
try {
// eslint-disable-next-line no-param-reassign
extra.stats = context.outputFileSystem.statSync(filename);
} catch (_ignoreError) {
// eslint-disable-next-line no-continue
continue;
}
if (extra.stats.isFile()) {
foundFilename = filename;
// Rspack does not yet support `assetsInfo`, so we need to check if `assetsInfo` exists here
if (assetsInfo) {
const assetInfo = assetsInfo.get(pathname.slice(publicPathObject.pathname.length));
// eslint-disable-next-line no-param-reassign
extra.immutable = assetInfo ? assetInfo.immutable : false;
}
break;
} else if (extra.stats.isDirectory() && (typeof options.index === "undefined" || options.index)) {
const indexValue = typeof options.index === "undefined" || typeof options.index === "boolean" ? "index.html" : options.index;
filename = path.join(filename, indexValue);
try {
// eslint-disable-next-line no-param-reassign
extra.stats = context.outputFileSystem.statSync(filename);
} catch (__ignoreError) {
// eslint-disable-next-line no-continue
continue;
}
if (extra.stats.isFile()) {
foundFilename = filename;
break;
}
}
}
}
// eslint-disable-next-line consistent-return
return foundFilename;
}
module.exports = getFilenameFromUrl;

View File

@@ -0,0 +1,42 @@
"use strict";
/** @typedef {import("webpack").Compiler} Compiler */
/** @typedef {import("webpack").Stats} Stats */
/** @typedef {import("webpack").MultiStats} MultiStats */
/** @typedef {import("../index.js").IncomingMessage} IncomingMessage */
/** @typedef {import("../index.js").ServerResponse} ServerResponse */
/**
* @template {IncomingMessage} Request
* @template {ServerResponse} Response
* @param {import("../index.js").FilledContext<Request, Response>} context
*/
function getPaths(context) {
const {
stats,
options
} = context;
/** @type {Stats[]} */
const childStats = /** @type {MultiStats} */
stats.stats ? /** @type {MultiStats} */stats.stats : [( /** @type {Stats} */stats)];
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 || "");
const publicPath = options.publicPath ? compilation.getPath(options.publicPath) : compilation.outputOptions.publicPath ? compilation.getPath(compilation.outputOptions.publicPath) : "";
publicPaths.push({
outputPath,
publicPath,
assetsInfo: compilation.assetsInfo
});
}
return publicPaths;
}
module.exports = getPaths;

View File

@@ -0,0 +1,39 @@
"use strict";
const cacheStore = new WeakMap();
/**
* @template T
* @param {Function} fn
* @param {{ cache?: Map<string, { data: T }> } | undefined} cache
* @param {((value: T) => T)=} callback
* @returns {any}
*/
function memorize(fn, {
cache = new Map()
} = {}, callback) {
/**
* @param {any} arguments_
* @return {any}
*/
const memoized = (...arguments_) => {
const [key] = arguments_;
const cacheItem = cache.get(key);
if (cacheItem) {
return cacheItem.data;
}
// @ts-ignore
let result = fn.apply(this, arguments_);
if (callback) {
result = callback(result);
}
cache.set(key, {
data: result
});
return result;
};
cacheStore.set(memoized, cache);
return memoized;
}
module.exports = memorize;

View File

@@ -0,0 +1,42 @@
"use strict";
/**
* Parse a HTTP token list.
*
* @param {string} str
* @returns {string[]} tokens
*/
function parseTokenList(str) {
let end = 0;
let start = 0;
const list = [];
// gather tokens
for (let i = 0, len = str.length; i < len; i++) {
switch (str.charCodeAt(i)) {
case 0x20 /* */:
if (start === end) {
end = i + 1;
start = end;
}
break;
case 0x2c /* , */:
if (start !== end) {
list.push(str.substring(start, end));
}
end = i + 1;
start = end;
break;
default:
end = i + 1;
break;
}
}
// final token
if (start !== end) {
list.push(str.substring(start, end));
}
return list;
}
module.exports = parseTokenList;

View File

@@ -0,0 +1,23 @@
"use strict";
/** @typedef {import("../index.js").IncomingMessage} IncomingMessage */
/** @typedef {import("../index.js").ServerResponse} ServerResponse */
/**
* @template {IncomingMessage} Request
* @template {ServerResponse} Response
* @param {import("../index.js").FilledContext<Request, Response>} context
* @param {(...args: any[]) => any} callback
* @param {Request} [req]
* @returns {void}
*/
function ready(context, callback, req) {
if (context.state) {
callback(context.stats);
return;
}
const name = req && req.url || callback.name;
context.logger.info(`wait until bundle finished${name ? `: ${name}` : ""}`);
context.callbacks.push(callback);
}
module.exports = ready;

View File

@@ -0,0 +1,153 @@
"use strict";
/** @typedef {import("webpack").Configuration} Configuration */
/** @typedef {import("webpack").Compiler} Compiler */
/** @typedef {import("webpack").MultiCompiler} MultiCompiler */
/** @typedef {import("webpack").Stats} Stats */
/** @typedef {import("webpack").MultiStats} MultiStats */
/** @typedef {import("../index.js").IncomingMessage} IncomingMessage */
/** @typedef {import("../index.js").ServerResponse} ServerResponse */
/** @typedef {Configuration["stats"]} StatsOptions */
/** @typedef {{ children: Configuration["stats"][] }} MultiStatsOptions */
/** @typedef {Exclude<Configuration["stats"], boolean | string | undefined>} StatsObjectOptions */
/**
* @template {IncomingMessage} Request
* @template {ServerResponse} Response
* @param {import("../index.js").WithOptional<import("../index.js").Context<Request, Response>, "watching" | "outputFileSystem">} context
*/
function setupHooks(context) {
function invalid() {
if (context.state) {
context.logger.log("Compilation starting...");
}
// We are now in invalid state
// eslint-disable-next-line no-param-reassign
context.state = false;
// eslint-disable-next-line no-param-reassign, no-undefined
context.stats = undefined;
}
/**
* @param {StatsOptions} statsOptions
* @returns {StatsObjectOptions}
*/
function normalizeStatsOptions(statsOptions) {
if (typeof statsOptions === "undefined") {
// eslint-disable-next-line no-param-reassign
statsOptions = {
preset: "normal"
};
} else if (typeof statsOptions === "boolean") {
// eslint-disable-next-line no-param-reassign
statsOptions = statsOptions ? {
preset: "normal"
} : {
preset: "none"
};
} else if (typeof statsOptions === "string") {
// eslint-disable-next-line no-param-reassign
statsOptions = {
preset: statsOptions
};
}
return statsOptions;
}
/**
* @param {Stats | MultiStats} stats
*/
function done(stats) {
// We are now on valid state
// eslint-disable-next-line no-param-reassign
context.state = true;
// eslint-disable-next-line no-param-reassign
context.stats = stats;
// Do the stuff in nextTick, because bundle may be invalidated if a change happened while compiling
process.nextTick(() => {
const {
compiler,
logger,
options,
state,
callbacks
} = context;
// Check if still in valid state
if (!state) {
return;
}
logger.log("Compilation finished");
const isMultiCompilerMode = Boolean( /** @type {MultiCompiler} */
compiler.compilers);
/**
* @type {StatsOptions | MultiStatsOptions | undefined}
*/
let statsOptions;
if (typeof options.stats !== "undefined") {
statsOptions = isMultiCompilerMode ? {
children: /** @type {MultiCompiler} */
compiler.compilers.map(() => options.stats)
} : options.stats;
} else {
statsOptions = isMultiCompilerMode ? {
children: /** @type {MultiCompiler} */
compiler.compilers.map(child => child.options.stats)
} : /** @type {Compiler} */compiler.options.stats;
}
if (isMultiCompilerMode) {
/** @type {MultiStatsOptions} */
statsOptions.children = /** @type {MultiStatsOptions} */
statsOptions.children.map(
/**
* @param {StatsOptions} childStatsOptions
* @return {StatsObjectOptions}
*/
childStatsOptions => {
// eslint-disable-next-line no-param-reassign
childStatsOptions = normalizeStatsOptions(childStatsOptions);
if (typeof childStatsOptions.colors === "undefined") {
// eslint-disable-next-line no-param-reassign
childStatsOptions.colors =
// eslint-disable-next-line global-require
require("colorette").isColorSupported;
}
return childStatsOptions;
});
} else {
statsOptions = normalizeStatsOptions( /** @type {StatsOptions} */statsOptions);
if (typeof statsOptions.colors === "undefined") {
// eslint-disable-next-line global-require
statsOptions.colors = require("colorette").isColorSupported;
}
}
const printedStats = stats.toString( /** @type {StatsObjectOptions} */statsOptions);
// Avoid extra empty line when `stats: 'none'`
if (printedStats) {
// eslint-disable-next-line no-console
console.log(printedStats);
}
// eslint-disable-next-line no-param-reassign
context.callbacks = [];
// Execute callback that are delayed
for (const callback of callbacks) {
callback(stats);
}
});
}
// eslint-disable-next-line prefer-destructuring
const compiler = /** @type {import("../index.js").Context<Request, Response>} */
context.compiler;
compiler.hooks.watchRun.tap("webpack-dev-middleware", invalid);
compiler.hooks.invalid.tap("webpack-dev-middleware", invalid);
compiler.hooks.done.tap("webpack-dev-middleware", done);
}
module.exports = setupHooks;

View File

@@ -0,0 +1,59 @@
"use strict";
const memfs = require("memfs");
/** @typedef {import("webpack").MultiCompiler} MultiCompiler */
/** @typedef {import("../index.js").IncomingMessage} IncomingMessage */
/** @typedef {import("../index.js").ServerResponse} ServerResponse */
/**
* @template {IncomingMessage} Request
* @template {ServerResponse} Response
* @param {import("../index.js").WithOptional<import("../index.js").Context<Request, Response>, "watching" | "outputFileSystem">} context
*/
function setupOutputFileSystem(context) {
let outputFileSystem;
if (context.options.outputFileSystem) {
const {
outputFileSystem: outputFileSystemFromOptions
} = context.options;
outputFileSystem = outputFileSystemFromOptions;
}
// Don't use `memfs` when developer wants to write everything to a disk, because it doesn't make sense.
else if (context.options.writeToDisk !== true) {
outputFileSystem = memfs.createFsFromVolume(new memfs.Volume());
} else {
const isMultiCompiler = /** @type {MultiCompiler} */
context.compiler.compilers;
if (isMultiCompiler) {
// Prefer compiler with `devServer` option or fallback on the first
// 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") && item.options.devServer !== false);
({
outputFileSystem
} = compiler[0] || /** @type {MultiCompiler} */
context.compiler.compilers[0]);
} else {
({
outputFileSystem
} = context.compiler);
}
}
const compilers = /** @type {MultiCompiler} */
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;
}
// @ts-ignore
// eslint-disable-next-line no-param-reassign
context.outputFileSystem = outputFileSystem;
}
module.exports = setupOutputFileSystem;

View File

@@ -0,0 +1,70 @@
"use strict";
const fs = require("fs");
const path = require("path");
/** @typedef {import("webpack").Compiler} Compiler */
/** @typedef {import("webpack").MultiCompiler} MultiCompiler */
/** @typedef {import("webpack").Compilation} Compilation */
/** @typedef {import("../index.js").IncomingMessage} IncomingMessage */
/** @typedef {import("../index.js").ServerResponse} ServerResponse */
/**
* @template {IncomingMessage} Request
* @template {ServerResponse} Response
* @param {import("../index.js").WithOptional<import("../index.js").Context<Request, Response>, "watching" | "outputFileSystem">} context
*/
function setupWriteToDisk(context) {
/**
* @type {Compiler[]}
*/
const compilers = /** @type {MultiCompiler} */
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) {
return;
}
compiler.hooks.assetEmitted.tapAsync("DevMiddleware", (file, info, callback) => {
const {
targetPath,
content
} = info;
const {
writeToDisk: filter
} = context.options;
const allowWrite = filter && typeof filter === "function" ? filter(targetPath) : true;
if (!allowWrite) {
return callback();
}
const dir = path.dirname(targetPath);
const name = compiler.options.name ? `Child "${compiler.options.name}": ` : "";
return fs.mkdir(dir, {
recursive: true
}, mkdirError => {
if (mkdirError) {
context.logger.error(`${name}Unable to write "${dir}" directory to disk:\n${mkdirError}`);
return callback(mkdirError);
}
return fs.writeFile(targetPath, content, writeFileError => {
if (writeFileError) {
context.logger.error(`${name}Unable to write "${targetPath}" asset to disk:\n${writeFileError}`);
return callback(writeFileError);
}
context.logger.log(`${name}Asset written to disk: "${targetPath}"`);
return callback();
});
});
});
// @ts-ignore
compiler.hasWebpackDevMiddlewareAssetEmittedCallback = true;
});
}
}
module.exports = setupWriteToDisk;

113
node_modules/webpack-dev-middleware/package.json generated vendored Normal file
View File

@@ -0,0 +1,113 @@
{
"name": "webpack-dev-middleware",
"version": "7.4.2",
"description": "A development middleware for webpack",
"license": "MIT",
"repository": "webpack/webpack-dev-middleware",
"author": "Tobias Koppers @sokra",
"homepage": "https://github.com/webpack/webpack-dev-middleware",
"bugs": "https://github.com/webpack/webpack-dev-middleware/issues",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
},
"main": "dist/index.js",
"types": "types/index.d.ts",
"engines": {
"node": ">= 18.12.0"
},
"scripts": {
"commitlint": "commitlint --from=master",
"security": "npm audit --production",
"lint:prettier": "prettier --cache --list-different .",
"lint:js": "eslint --cache .",
"lint:spelling": "cspell --cache --no-must-find-files --quiet \"**/*.*\"",
"lint:types": "tsc --pretty --noEmit",
"lint": "npm-run-all -l -p \"lint:**\"",
"fix:js": "npm run lint:js -- --fix",
"fix:prettier": "npm run lint:prettier -- --write",
"fix": "npm-run-all -l fix:js fix:prettier",
"clean": "del-cli dist types",
"prebuild": "npm run clean",
"build:types": "tsc --declaration --emitDeclarationOnly --outDir types && prettier \"types/**/*.ts\" --write",
"build:code": "cross-env NODE_ENV=production babel src -d dist --copy-files",
"build": "npm-run-all -p \"build:**\"",
"test:only": "cross-env NODE_ENV=test jest",
"test:watch": "npm run test:only -- --watch",
"test:coverage": "npm run test:only -- --collectCoverageFrom=\"src/**/*.js\" --coverage",
"pretest": "npm run lint",
"test": "npm run test:coverage",
"prepare": "husky && npm run build",
"release": "standard-version"
},
"files": [
"dist",
"types"
],
"peerDependencies": {
"webpack": "^5.0.0"
},
"peerDependenciesMeta": {
"webpack": {
"optional": true
}
},
"dependencies": {
"colorette": "^2.0.10",
"memfs": "^4.6.0",
"mime-types": "^2.1.31",
"on-finished": "^2.4.1",
"range-parser": "^1.2.1",
"schema-utils": "^4.0.0"
},
"devDependencies": {
"@babel/cli": "^7.16.7",
"@babel/core": "^7.16.7",
"@babel/preset-env": "^7.16.7",
"@commitlint/cli": "^19.0.3",
"@commitlint/config-conventional": "^19.0.3",
"@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": "^22.3.0",
"@types/on-finished": "^2.3.4",
"@webpack-contrib/eslint-config-webpack": "^3.0.0",
"babel-jest": "^29.3.1",
"chokidar": "^3.5.1",
"connect": "^3.7.0",
"cross-env": "^7.0.3",
"cspell": "^8.3.2",
"deepmerge": "^4.2.2",
"del-cli": "^5.0.0",
"eslint": "^8.28.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.25.4",
"execa": "^5.1.1",
"express": "^4.17.1",
"fastify": "^4.26.2",
"file-loader": "^6.2.0",
"finalhandler": "^1.2.0",
"hono": "^4.4.13",
"husky": "^9.1.3",
"jest": "^29.3.1",
"joi": "^17.12.2",
"koa": "^2.15.2",
"lint-staged": "^15.2.0",
"npm-run-all": "^4.1.5",
"prettier": "^3.2.4",
"router": "^1.3.8",
"standard-version": "^9.3.0",
"strip-ansi": "^6.0.0",
"supertest": "^7.0.0",
"typescript": "^5.3.3",
"webpack": "^5.93.0"
},
"keywords": [
"webpack",
"middleware",
"development"
]
}

416
node_modules/webpack-dev-middleware/types/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,416 @@
export = wdm;
/** @typedef {import("schema-utils/declarations/validate").Schema} Schema */
/** @typedef {import("webpack").Compiler} Compiler */
/** @typedef {import("webpack").MultiCompiler} MultiCompiler */
/** @typedef {import("webpack").Configuration} Configuration */
/** @typedef {import("webpack").Stats} Stats */
/** @typedef {import("webpack").MultiStats} MultiStats */
/** @typedef {import("fs").ReadStream} ReadStream */
/**
* @typedef {Object} ExtendedServerResponse
* @property {{ webpack?: { devMiddleware?: Context<IncomingMessage, ServerResponse> } }} [locals]
*/
/** @typedef {import("http").IncomingMessage} IncomingMessage */
/** @typedef {import("http").ServerResponse & ExtendedServerResponse} ServerResponse */
/**
* @callback NextFunction
* @param {any} [err]
* @return {void}
*/
/**
* @typedef {NonNullable<Configuration["watchOptions"]>} WatchOptions
*/
/**
* @typedef {Compiler["watching"]} Watching
*/
/**
* @typedef {ReturnType<MultiCompiler["watch"]>} MultiWatching
*/
/**
* @typedef {import("webpack").OutputFileSystem & { createReadStream?: import("fs").createReadStream, statSync: import("fs").statSync, readFileSync: import("fs").readFileSync }} OutputFileSystem
*/
/** @typedef {ReturnType<Compiler["getInfrastructureLogger"]>} Logger */
/**
* @callback Callback
* @param {Stats | MultiStats} [stats]
*/
/**
* @typedef {Object} ResponseData
* @property {Buffer | ReadStream} data
* @property {number} byteLength
*/
/**
* @template {IncomingMessage} [RequestInternal=IncomingMessage]
* @template {ServerResponse} [ResponseInternal=ServerResponse]
* @callback ModifyResponseData
* @param {RequestInternal} req
* @param {ResponseInternal} res
* @param {Buffer | ReadStream} data
* @param {number} byteLength
* @return {ResponseData}
*/
/**
* @template {IncomingMessage} [RequestInternal=IncomingMessage]
* @template {ServerResponse} [ResponseInternal=ServerResponse]
* @typedef {Object} Context
* @property {boolean} state
* @property {Stats | MultiStats | undefined} stats
* @property {Callback[]} callbacks
* @property {Options<RequestInternal, ResponseInternal>} options
* @property {Compiler | MultiCompiler} compiler
* @property {Watching | MultiWatching | undefined} watching
* @property {Logger} logger
* @property {OutputFileSystem} outputFileSystem
*/
/**
* @template {IncomingMessage} [RequestInternal=IncomingMessage]
* @template {ServerResponse} [ResponseInternal=ServerResponse]
* @typedef {WithoutUndefined<Context<RequestInternal, ResponseInternal>, "watching">} FilledContext
*/
/** @typedef {Record<string, string | number> | Array<{ key: string, value: number | string }>} NormalizedHeaders */
/**
* @template {IncomingMessage} [RequestInternal=IncomingMessage]
* @template {ServerResponse} [ResponseInternal=ServerResponse]
* @typedef {NormalizedHeaders | ((req: RequestInternal, res: ResponseInternal, context: Context<RequestInternal, ResponseInternal>) => void | undefined | NormalizedHeaders) | undefined} Headers
*/
/**
* @template {IncomingMessage} [RequestInternal = IncomingMessage]
* @template {ServerResponse} [ResponseInternal = ServerResponse]
* @typedef {Object} Options
* @property {{[key: string]: string}} [mimeTypes]
* @property {string | undefined} [mimeTypeDefault]
* @property {boolean | ((targetPath: string) => boolean)} [writeToDisk]
* @property {string[]} [methods]
* @property {Headers<RequestInternal, ResponseInternal>} [headers]
* @property {NonNullable<Configuration["output"]>["publicPath"]} [publicPath]
* @property {Configuration["stats"]} [stats]
* @property {boolean} [serverSideRender]
* @property {OutputFileSystem} [outputFileSystem]
* @property {boolean | string} [index]
* @property {ModifyResponseData<RequestInternal, ResponseInternal>} [modifyResponseData]
* @property {"weak" | "strong"} [etag]
* @property {boolean} [lastModified]
* @property {boolean | number | string | { maxAge?: number, immutable?: boolean }} [cacheControl]
* @property {boolean} [cacheImmutable]
*/
/**
* @template {IncomingMessage} [RequestInternal=IncomingMessage]
* @template {ServerResponse} [ResponseInternal=ServerResponse]
* @callback Middleware
* @param {RequestInternal} req
* @param {ResponseInternal} res
* @param {NextFunction} next
* @return {Promise<void>}
*/
/** @typedef {import("./utils/getFilenameFromUrl").Extra} Extra */
/**
* @callback GetFilenameFromUrl
* @param {string} url
* @param {Extra=} extra
* @returns {string | undefined}
*/
/**
* @callback WaitUntilValid
* @param {Callback} callback
*/
/**
* @callback Invalidate
* @param {Callback} callback
*/
/**
* @callback Close
* @param {(err: Error | null | undefined) => void} callback
*/
/**
* @template {IncomingMessage} RequestInternal
* @template {ServerResponse} ResponseInternal
* @typedef {Object} AdditionalMethods
* @property {GetFilenameFromUrl} getFilenameFromUrl
* @property {WaitUntilValid} waitUntilValid
* @property {Invalidate} invalidate
* @property {Close} close
* @property {Context<RequestInternal, ResponseInternal>} context
*/
/**
* @template {IncomingMessage} [RequestInternal=IncomingMessage]
* @template {ServerResponse} [ResponseInternal=ServerResponse]
* @typedef {Middleware<RequestInternal, ResponseInternal> & AdditionalMethods<RequestInternal, ResponseInternal>} API
*/
/**
* @template T
* @template {keyof T} K
* @typedef {Omit<T, K> & Partial<T>} WithOptional
*/
/**
* @template T
* @template {keyof T} K
* @typedef {T & { [P in K]: NonNullable<T[P]> }} WithoutUndefined
*/
/**
* @template {IncomingMessage} [RequestInternal=IncomingMessage]
* @template {ServerResponse} [ResponseInternal=ServerResponse]
* @param {Compiler | MultiCompiler} compiler
* @param {Options<RequestInternal, ResponseInternal>} [options]
* @returns {API<RequestInternal, ResponseInternal>}
*/
declare function wdm<
RequestInternal extends IncomingMessage = import("http").IncomingMessage,
ResponseInternal extends ServerResponse = ServerResponse,
>(
compiler: Compiler | MultiCompiler,
options?: Options<RequestInternal, ResponseInternal> | undefined,
): API<RequestInternal, ResponseInternal>;
declare namespace wdm {
export {
hapiWrapper,
koaWrapper,
honoWrapper,
Schema,
Compiler,
MultiCompiler,
Configuration,
Stats,
MultiStats,
ReadStream,
ExtendedServerResponse,
IncomingMessage,
ServerResponse,
NextFunction,
WatchOptions,
Watching,
MultiWatching,
OutputFileSystem,
Logger,
Callback,
ResponseData,
ModifyResponseData,
Context,
FilledContext,
NormalizedHeaders,
Headers,
Options,
Middleware,
Extra,
GetFilenameFromUrl,
WaitUntilValid,
Invalidate,
Close,
AdditionalMethods,
API,
WithOptional,
WithoutUndefined,
HapiPluginBase,
HapiPlugin,
HapiOptions,
};
}
/**
* @template S
* @template O
* @typedef {Object} HapiPluginBase
* @property {(server: S, options: O) => void | Promise<void>} register
*/
/**
* @template S
* @template O
* @typedef {HapiPluginBase<S, O> & { pkg: { name: string }, multiple: boolean }} HapiPlugin
*/
/**
* @typedef {Options & { compiler: Compiler | MultiCompiler }} HapiOptions
*/
/**
* @template HapiServer
* @template {HapiOptions} HapiOptionsInternal
* @returns {HapiPlugin<HapiServer, HapiOptionsInternal>}
*/
declare function hapiWrapper<
HapiServer,
HapiOptionsInternal extends HapiOptions,
>(): HapiPlugin<HapiServer, HapiOptionsInternal>;
/**
* @template {IncomingMessage} [RequestInternal=IncomingMessage]
* @template {ServerResponse} [ResponseInternal=ServerResponse]
* @param {Compiler | MultiCompiler} compiler
* @param {Options<RequestInternal, ResponseInternal>} [options]
* @returns {(ctx: any, next: Function) => Promise<void> | void}
*/
declare function koaWrapper<
RequestInternal extends IncomingMessage = import("http").IncomingMessage,
ResponseInternal extends ServerResponse = ServerResponse,
>(
compiler: Compiler | MultiCompiler,
options?: Options<RequestInternal, ResponseInternal> | undefined,
): (ctx: any, next: Function) => Promise<void> | void;
/**
* @template {IncomingMessage} [RequestInternal=IncomingMessage]
* @template {ServerResponse} [ResponseInternal=ServerResponse]
* @param {Compiler | MultiCompiler} compiler
* @param {Options<RequestInternal, ResponseInternal>} [options]
* @returns {(ctx: any, next: Function) => Promise<void> | void}
*/
declare function honoWrapper<
RequestInternal extends IncomingMessage = import("http").IncomingMessage,
ResponseInternal extends ServerResponse = ServerResponse,
>(
compiler: Compiler | MultiCompiler,
options?: Options<RequestInternal, ResponseInternal> | undefined,
): (ctx: any, next: Function) => Promise<void> | void;
type Schema = import("schema-utils/declarations/validate").Schema;
type Compiler = import("webpack").Compiler;
type MultiCompiler = import("webpack").MultiCompiler;
type Configuration = import("webpack").Configuration;
type Stats = import("webpack").Stats;
type MultiStats = import("webpack").MultiStats;
type ReadStream = import("fs").ReadStream;
type ExtendedServerResponse = {
locals?:
| {
webpack?: {
devMiddleware?: Context<IncomingMessage, ServerResponse>;
};
}
| undefined;
};
type IncomingMessage = import("http").IncomingMessage;
type ServerResponse = import("http").ServerResponse & ExtendedServerResponse;
type NextFunction = (err?: any) => void;
type WatchOptions = NonNullable<Configuration["watchOptions"]>;
type Watching = Compiler["watching"];
type MultiWatching = ReturnType<MultiCompiler["watch"]>;
type OutputFileSystem = import("webpack").OutputFileSystem & {
createReadStream?: typeof import("fs").createReadStream;
statSync: import("fs").StatSyncFn;
readFileSync: typeof import("fs").readFileSync;
};
type Logger = ReturnType<Compiler["getInfrastructureLogger"]>;
type Callback = (
stats?: import("webpack").Stats | import("webpack").MultiStats | undefined,
) => any;
type ResponseData = {
data: Buffer | ReadStream;
byteLength: number;
};
type ModifyResponseData<
RequestInternal extends IncomingMessage = import("http").IncomingMessage,
ResponseInternal extends ServerResponse = ServerResponse,
> = (
req: RequestInternal,
res: ResponseInternal,
data: Buffer | ReadStream,
byteLength: number,
) => ResponseData;
type Context<
RequestInternal extends IncomingMessage = import("http").IncomingMessage,
ResponseInternal extends ServerResponse = ServerResponse,
> = {
state: boolean;
stats: Stats | MultiStats | undefined;
callbacks: Callback[];
options: Options<RequestInternal, ResponseInternal>;
compiler: Compiler | MultiCompiler;
watching: Watching | MultiWatching | undefined;
logger: Logger;
outputFileSystem: OutputFileSystem;
};
type FilledContext<
RequestInternal extends IncomingMessage = import("http").IncomingMessage,
ResponseInternal extends ServerResponse = ServerResponse,
> = WithoutUndefined<Context<RequestInternal, ResponseInternal>, "watching">;
type NormalizedHeaders =
| Record<string, string | number>
| Array<{
key: string;
value: number | string;
}>;
type Headers<
RequestInternal extends IncomingMessage = import("http").IncomingMessage,
ResponseInternal extends ServerResponse = ServerResponse,
> =
| NormalizedHeaders
| ((
req: RequestInternal,
res: ResponseInternal,
context: Context<RequestInternal, ResponseInternal>,
) => void | undefined | NormalizedHeaders)
| undefined;
type Options<
RequestInternal extends IncomingMessage = import("http").IncomingMessage,
ResponseInternal extends ServerResponse = ServerResponse,
> = {
mimeTypes?:
| {
[key: string]: string;
}
| undefined;
mimeTypeDefault?: string | undefined;
writeToDisk?: boolean | ((targetPath: string) => boolean) | undefined;
methods?: string[] | undefined;
headers?: Headers<RequestInternal, ResponseInternal>;
publicPath?: NonNullable<Configuration["output"]>["publicPath"];
stats?: Configuration["stats"];
serverSideRender?: boolean | undefined;
outputFileSystem?: OutputFileSystem | undefined;
index?: string | boolean | undefined;
modifyResponseData?:
| ModifyResponseData<RequestInternal, ResponseInternal>
| 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,
ResponseInternal extends ServerResponse = ServerResponse,
> = (
req: RequestInternal,
res: ResponseInternal,
next: NextFunction,
) => Promise<void>;
type Extra = import("./utils/getFilenameFromUrl").Extra;
type GetFilenameFromUrl = (
url: string,
extra?: Extra | undefined,
) => string | undefined;
type WaitUntilValid = (callback: Callback) => any;
type Invalidate = (callback: Callback) => any;
type Close = (callback: (err: Error | null | undefined) => void) => any;
type AdditionalMethods<
RequestInternal extends IncomingMessage,
ResponseInternal extends ServerResponse,
> = {
getFilenameFromUrl: GetFilenameFromUrl;
waitUntilValid: WaitUntilValid;
invalidate: Invalidate;
close: Close;
context: Context<RequestInternal, ResponseInternal>;
};
type API<
RequestInternal extends IncomingMessage = import("http").IncomingMessage,
ResponseInternal extends ServerResponse = ServerResponse,
> = Middleware<RequestInternal, ResponseInternal> &
AdditionalMethods<RequestInternal, ResponseInternal>;
type WithOptional<T, K extends keyof T> = Omit<T, K> & Partial<T>;
type WithoutUndefined<T, K extends keyof T> = T & {
[P in K]: NonNullable<T[P]>;
};
type HapiPluginBase<S, O> = {
register: (server: S, options: O) => void | Promise<void>;
};
type HapiPlugin<S, O> = HapiPluginBase<S, O> & {
pkg: {
name: string;
};
multiple: boolean;
};
type HapiOptions = Options & {
compiler: Compiler | MultiCompiler;
};

View File

@@ -0,0 +1,53 @@
export = wrapper;
/**
* @template {IncomingMessage} Request
* @template {ServerResponse} Response
* @typedef {Object} SendErrorOptions send error options
* @property {Record<string, number | string | string[] | undefined>=} headers headers
* @property {import("./index").ModifyResponseData<Request, Response>=} modifyResponseData modify response data callback
*/
/**
* @template {IncomingMessage} Request
* @template {ServerResponse} Response
* @param {import("./index.js").FilledContext<Request, Response>} context
* @return {import("./index.js").Middleware<Request, Response>}
*/
declare function wrapper<
Request extends IncomingMessage,
Response extends ServerResponse,
>(
context: import("./index.js").FilledContext<Request, Response>,
): import("./index.js").Middleware<Request, Response>;
declare namespace wrapper {
export {
SendErrorOptions,
NextFunction,
IncomingMessage,
ServerResponse,
NormalizedHeaders,
ReadStream,
};
}
/**
* send error options
*/
type SendErrorOptions<
Request extends IncomingMessage,
Response extends ServerResponse,
> = {
/**
* headers
*/
headers?: Record<string, number | string | string[] | undefined> | undefined;
/**
* modify response data callback
*/
modifyResponseData?:
| import("./index").ModifyResponseData<Request, Response>
| undefined;
};
type NextFunction = import("./index.js").NextFunction;
type IncomingMessage = import("./index.js").IncomingMessage;
type ServerResponse = import("./index.js").ServerResponse;
type NormalizedHeaders = import("./index.js").NormalizedHeaders;
type ReadStream = import("fs").ReadStream;

View File

@@ -0,0 +1,219 @@
export type IncomingMessage = import("../index.js").IncomingMessage;
export type ServerResponse = import("../index.js").ServerResponse;
export type OutputFileSystem = import("../index").OutputFileSystem;
export type ExpectedIncomingMessage = {
getHeader?: ((name: string) => string | string[] | undefined) | undefined;
getMethod?: (() => string | undefined) | undefined;
getURL?: (() => string | undefined) | undefined;
};
export type ExpectedServerResponse = {
setStatusCode?: ((status: number) => void) | undefined;
getStatusCode?: (() => number) | undefined;
getHeader?:
| ((name: string) => string | string[] | undefined | number)
| undefined;
setHeader?:
| ((
name: string,
value: number | string | Readonly<string[]>,
) => ExpectedServerResponse)
| undefined;
removeHeader?: ((name: string) => void) | undefined;
send?: ((data: string | Buffer) => void) | undefined;
finish?: ((data?: string | Buffer) => void) | undefined;
getResponseHeaders?: (() => string[]) | undefined;
getHeadersSent?: (() => boolean) | undefined;
stream?: ((data: any) => void) | undefined;
getOutgoing?: (() => any) | undefined;
setState?: ((name: string, value: any) => void) | undefined;
getReadyReadableStreamState?:
| (() => "ready" | "open" | "readable")
| undefined;
};
/**
* @template {ServerResponse & ExpectedServerResponse} Response
* @param {Response} res
* @param {number} code
*/
export function setStatusCode<
Response extends ServerResponse & ExpectedServerResponse,
>(res: Response, code: number): void;
/**
* @template {ServerResponse & ExpectedServerResponse} Response
* @param {Response} res
* @returns {number}
*/
export function getStatusCode<
Response extends ServerResponse & ExpectedServerResponse,
>(res: Response): number;
/** @typedef {import("../index.js").IncomingMessage} IncomingMessage */
/** @typedef {import("../index.js").ServerResponse} ServerResponse */
/** @typedef {import("../index").OutputFileSystem} OutputFileSystem */
/**
* @typedef {Object} ExpectedIncomingMessage
* @property {(name: string) => string | string[] | undefined} [getHeader]
* @property {() => string | undefined} [getMethod]
* @property {() => string | undefined} [getURL]
*/
/**
* @typedef {Object} ExpectedServerResponse
* @property {(status: number) => void} [setStatusCode]
* @property {() => number} [getStatusCode]
* @property {(name: string) => string | string[] | undefined | number} [getHeader]
* @property {(name: string, value: number | string | Readonly<string[]>) => ExpectedServerResponse} [setHeader]
* @property {(name: string) => void} [removeHeader]
* @property {(data: string | Buffer) => void} [send]
* @property {(data?: string | Buffer) => void} [finish]
* @property {() => string[]} [getResponseHeaders]
* @property {() => boolean} [getHeadersSent]
* @property {(data: any) => void} [stream]
* @property {() => any} [getOutgoing]
* @property {(name: string, value: any) => void} [setState]
* @property {() => "ready" | "open" | "readable"} [getReadyReadableStreamState]
*/
/**
* @template {IncomingMessage & ExpectedIncomingMessage} Request
* @param {Request} req
* @param {string} name
* @returns {string | string[] | undefined}
*/
export function getRequestHeader<
Request extends IncomingMessage & ExpectedIncomingMessage,
>(req: Request, name: string): string | string[] | undefined;
/**
* @template {IncomingMessage & ExpectedIncomingMessage} Request
* @param {Request} req
* @returns {string | undefined}
*/
export function getRequestMethod<
Request extends IncomingMessage & ExpectedIncomingMessage,
>(req: Request): string | undefined;
/**
* @template {IncomingMessage & ExpectedIncomingMessage} Request
* @param {Request} req
* @returns {string | undefined}
*/
export function getRequestURL<
Request extends IncomingMessage & ExpectedIncomingMessage,
>(req: Request): string | undefined;
/**
* @template {ServerResponse & ExpectedServerResponse} Response
* @param {Response} res
* @param {string} name
* @returns {string | string[] | undefined | number}
*/
export function getResponseHeader<
Response extends ServerResponse & ExpectedServerResponse,
>(res: Response, name: string): string | string[] | undefined | number;
/**
* @template {ServerResponse & ExpectedServerResponse} Response
* @param {Response} res
* @param {string} name
* @param {number | string | Readonly<string[]>} value
* @returns {Response}
*/
export function setResponseHeader<
Response extends ServerResponse & ExpectedServerResponse,
>(
res: Response,
name: string,
value: number | string | Readonly<string[]>,
): Response;
/**
* @template {ServerResponse & ExpectedServerResponse} Response
* @param {Response} res
* @param {string} name
*/
export function removeResponseHeader<
Response extends ServerResponse & ExpectedServerResponse,
>(res: Response, name: string): void;
/**
* @template {ServerResponse & ExpectedServerResponse} Response
* @param {Response} res
* @returns {string[]}
*/
export function getResponseHeaders<
Response extends ServerResponse & ExpectedServerResponse,
>(res: Response): string[];
/**
* @template {ServerResponse & ExpectedServerResponse} Response
* @param {Response} res
* @returns {boolean}
*/
export function getHeadersSent<
Response extends ServerResponse & ExpectedServerResponse,
>(res: Response): boolean;
/**
* @template {ServerResponse & ExpectedServerResponse} Response
* @param {Response} res
* @param {import("fs").ReadStream} bufferOrStream
*/
export function pipe<Response extends ServerResponse & ExpectedServerResponse>(
res: Response,
bufferOrStream: import("fs").ReadStream,
): void;
/**
* @template {ServerResponse & ExpectedServerResponse} Response
* @param {Response} res
* @param {string | Buffer} bufferOrString
*/
export function send<Response extends ServerResponse & ExpectedServerResponse>(
res: Response,
bufferOrString: string | Buffer,
): void;
/**
* @template {ServerResponse & ExpectedServerResponse} Response
* @param {Response} res
* @param {string | Buffer} [data]
*/
export function finish<
Response extends ServerResponse & ExpectedServerResponse,
>(res: Response, data?: string | Buffer | undefined): void;
/**
* @param {string} filename
* @param {OutputFileSystem} outputFileSystem
* @param {number} start
* @param {number} end
* @returns {{ bufferOrStream: (Buffer | import("fs").ReadStream), byteLength: number }}
*/
export function createReadStreamOrReadFileSync(
filename: string,
outputFileSystem: OutputFileSystem,
start: number,
end: number,
): {
bufferOrStream: Buffer | import("fs").ReadStream;
byteLength: number;
};
/**
* @template {ServerResponse & ExpectedServerResponse} Response
* @param {Response} res
* @returns {Response} res
*/
export function getOutgoing<
Response extends ServerResponse & ExpectedServerResponse,
>(res: Response): Response;
/**
* @template {ServerResponse & ExpectedServerResponse} Response
* @param {Response} res
*/
export function initState<
Response extends ServerResponse & ExpectedServerResponse,
>(res: Response): void;
/**
* @template {ServerResponse & ExpectedServerResponse} Response
* @param {Response} res
* @param {string} name
* @param {any} value
*/
export function setState<
Response extends ServerResponse & ExpectedServerResponse,
>(res: Response, name: string, value: any): void;
/**
* @template {ServerResponse & ExpectedServerResponse} Response
* @param {Response} res
* @returns {"ready" | "open" | "readable"}
*/
export function getReadyReadableStreamState<
Response extends ServerResponse & ExpectedServerResponse,
>(res: Response): "ready" | "open" | "readable";

View File

@@ -0,0 +1,6 @@
export = escapeHtml;
/**
* @param {string} string raw HTML
* @returns {string} escaped HTML
*/
declare function escapeHtml(string: string): string;

View File

@@ -0,0 +1,16 @@
export = etag;
/**
* Create a simple ETag.
*
* @param {Buffer | ReadStream | Stats} entity
* @return {Promise<{ hash: string, buffer?: Buffer }>}
*/
declare function etag(entity: Buffer | ReadStream | Stats): Promise<{
hash: string;
buffer?: Buffer;
}>;
declare namespace etag {
export { Stats, ReadStream };
}
type Stats = import("fs").Stats;
type ReadStream = import("fs").ReadStream;

View File

@@ -0,0 +1,27 @@
export = getFilenameFromUrl;
/**
* @template {IncomingMessage} Request
* @template {ServerResponse} Response
* @param {import("../index.js").FilledContext<Request, Response>} context
* @param {string} url
* @param {Extra=} extra
* @returns {string | undefined}
*/
declare function getFilenameFromUrl<
Request extends IncomingMessage,
Response extends ServerResponse,
>(
context: import("../index.js").FilledContext<Request, Response>,
url: string,
extra?: Extra | undefined,
): string | undefined;
declare namespace getFilenameFromUrl {
export { Extra, IncomingMessage, ServerResponse };
}
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;

View File

@@ -0,0 +1,29 @@
export = getPaths;
/** @typedef {import("webpack").Compiler} Compiler */
/** @typedef {import("webpack").Stats} Stats */
/** @typedef {import("webpack").MultiStats} MultiStats */
/** @typedef {import("../index.js").IncomingMessage} IncomingMessage */
/** @typedef {import("../index.js").ServerResponse} ServerResponse */
/**
* @template {IncomingMessage} Request
* @template {ServerResponse} Response
* @param {import("../index.js").FilledContext<Request, Response>} context
*/
declare function getPaths<
Request extends IncomingMessage,
Response extends ServerResponse,
>(
context: import("../index.js").FilledContext<Request, Response>,
): {
outputPath: string;
publicPath: string;
assetsInfo: Map<string, import("webpack").AssetInfo>;
}[];
declare namespace getPaths {
export { Compiler, Stats, MultiStats, IncomingMessage, ServerResponse };
}
type Compiler = import("webpack").Compiler;
type Stats = import("webpack").Stats;
type MultiStats = import("webpack").MultiStats;
type IncomingMessage = import("../index.js").IncomingMessage;
type ServerResponse = import("../index.js").ServerResponse;

View File

@@ -0,0 +1,24 @@
export = memorize;
/**
* @template T
* @param {Function} fn
* @param {{ cache?: Map<string, { data: T }> } | undefined} cache
* @param {((value: T) => T)=} callback
* @returns {any}
*/
declare function memorize<T>(
fn: Function,
{
cache,
}?:
| {
cache?: Map<
string,
{
data: T;
}
>;
}
| undefined,
callback?: ((value: T) => T) | undefined,
): any;

View File

@@ -0,0 +1,8 @@
export = parseTokenList;
/**
* Parse a HTTP token list.
*
* @param {string} str
* @returns {string[]} tokens
*/
declare function parseTokenList(str: string): string[];

View File

@@ -0,0 +1,24 @@
export = ready;
/** @typedef {import("../index.js").IncomingMessage} IncomingMessage */
/** @typedef {import("../index.js").ServerResponse} ServerResponse */
/**
* @template {IncomingMessage} Request
* @template {ServerResponse} Response
* @param {import("../index.js").FilledContext<Request, Response>} context
* @param {(...args: any[]) => any} callback
* @param {Request} [req]
* @returns {void}
*/
declare function ready<
Request extends IncomingMessage,
Response extends ServerResponse,
>(
context: import("../index.js").FilledContext<Request, Response>,
callback: (...args: any[]) => any,
req?: Request | undefined,
): void;
declare namespace ready {
export { IncomingMessage, ServerResponse };
}
type IncomingMessage = import("../index.js").IncomingMessage;
type ServerResponse = import("../index.js").ServerResponse;

View File

@@ -0,0 +1,54 @@
export = setupHooks;
/** @typedef {import("webpack").Configuration} Configuration */
/** @typedef {import("webpack").Compiler} Compiler */
/** @typedef {import("webpack").MultiCompiler} MultiCompiler */
/** @typedef {import("webpack").Stats} Stats */
/** @typedef {import("webpack").MultiStats} MultiStats */
/** @typedef {import("../index.js").IncomingMessage} IncomingMessage */
/** @typedef {import("../index.js").ServerResponse} ServerResponse */
/** @typedef {Configuration["stats"]} StatsOptions */
/** @typedef {{ children: Configuration["stats"][] }} MultiStatsOptions */
/** @typedef {Exclude<Configuration["stats"], boolean | string | undefined>} StatsObjectOptions */
/**
* @template {IncomingMessage} Request
* @template {ServerResponse} Response
* @param {import("../index.js").WithOptional<import("../index.js").Context<Request, Response>, "watching" | "outputFileSystem">} context
*/
declare function setupHooks<
Request extends IncomingMessage,
Response extends ServerResponse,
>(
context: import("../index.js").WithOptional<
import("../index.js").Context<Request, Response>,
"watching" | "outputFileSystem"
>,
): void;
declare namespace setupHooks {
export {
Configuration,
Compiler,
MultiCompiler,
Stats,
MultiStats,
IncomingMessage,
ServerResponse,
StatsOptions,
MultiStatsOptions,
StatsObjectOptions,
};
}
type Configuration = import("webpack").Configuration;
type Compiler = import("webpack").Compiler;
type MultiCompiler = import("webpack").MultiCompiler;
type Stats = import("webpack").Stats;
type MultiStats = import("webpack").MultiStats;
type IncomingMessage = import("../index.js").IncomingMessage;
type ServerResponse = import("../index.js").ServerResponse;
type StatsOptions = Configuration["stats"];
type MultiStatsOptions = {
children: Configuration["stats"][];
};
type StatsObjectOptions = Exclude<
Configuration["stats"],
boolean | string | undefined
>;

View File

@@ -0,0 +1,24 @@
export = setupOutputFileSystem;
/** @typedef {import("webpack").MultiCompiler} MultiCompiler */
/** @typedef {import("../index.js").IncomingMessage} IncomingMessage */
/** @typedef {import("../index.js").ServerResponse} ServerResponse */
/**
* @template {IncomingMessage} Request
* @template {ServerResponse} Response
* @param {import("../index.js").WithOptional<import("../index.js").Context<Request, Response>, "watching" | "outputFileSystem">} context
*/
declare function setupOutputFileSystem<
Request extends IncomingMessage,
Response extends ServerResponse,
>(
context: import("../index.js").WithOptional<
import("../index.js").Context<Request, Response>,
"watching" | "outputFileSystem"
>,
): void;
declare namespace setupOutputFileSystem {
export { MultiCompiler, IncomingMessage, ServerResponse };
}
type MultiCompiler = import("webpack").MultiCompiler;
type IncomingMessage = import("../index.js").IncomingMessage;
type ServerResponse = import("../index.js").ServerResponse;

View File

@@ -0,0 +1,34 @@
export = setupWriteToDisk;
/** @typedef {import("webpack").Compiler} Compiler */
/** @typedef {import("webpack").MultiCompiler} MultiCompiler */
/** @typedef {import("webpack").Compilation} Compilation */
/** @typedef {import("../index.js").IncomingMessage} IncomingMessage */
/** @typedef {import("../index.js").ServerResponse} ServerResponse */
/**
* @template {IncomingMessage} Request
* @template {ServerResponse} Response
* @param {import("../index.js").WithOptional<import("../index.js").Context<Request, Response>, "watching" | "outputFileSystem">} context
*/
declare function setupWriteToDisk<
Request extends IncomingMessage,
Response extends ServerResponse,
>(
context: import("../index.js").WithOptional<
import("../index.js").Context<Request, Response>,
"watching" | "outputFileSystem"
>,
): void;
declare namespace setupWriteToDisk {
export {
Compiler,
MultiCompiler,
Compilation,
IncomingMessage,
ServerResponse,
};
}
type Compiler = import("webpack").Compiler;
type MultiCompiler = import("webpack").MultiCompiler;
type Compilation = import("webpack").Compilation;
type IncomingMessage = import("../index.js").IncomingMessage;
type ServerResponse = import("../index.js").ServerResponse;