npm package: @hitchy/plugin-static
Description: Hitchy plugin serving static files
Author: Thomas Urban
Latest version: 0.5.2

# @hitchy/plugin-static [![pipeline status](https://gitlab.com/hitchy/plugin-static/badges/master/pipeline.svg)](https://gitlab.com/hitchy/plugin-static/-/commits/master)

_Hitchy plugin serving static files_

## License

[MIT](LICENSE)

## Install

In a Hitchy-based project run following command for adding this plugin as a dependency:

```bash
npm install @hitchy/plugin-static
```

## Configuration

Create a file **config/static.js** in your Hitchy-based project to export a list of folders for statically exposing any contained file.

```javascript
exports.static = [
	{
		prefix: "/files",
		folder: "./static/files",
	},
	{
		prefix: "/media",
		folder: "media",
		redirect: true,
	},
	{
		prefix: "/app",
		folder: "app",
		fallback: "index.html",
        maxAge: 3600, // default is 604800 seconds, set 0/false to disable caching
		mime: {
			// adding new MIME types
			".key": "application/x-my-custom-mime-type",

			// replacing existing ones
			".json": "text/json",
		},
		download: {
			// adding declarations for MIME types to be exposed for download
			"application/x-my-custom-mime-type": true,

			// adjusting existing records
			"application/xml": true,
		},
		filter( urlPath, filename, isRequested ) {
			// prevent access on files in folder private/
			if ( urlPath.startsWith( "private/" ) ) {
				throw new this.services.HttpException( 403, "this file is private!" );
			}
		},
		process( urlPath, filename, stream ) {
			// deliver any file's content converted to uppercase, only
			const transformed = new ( require( "stream" ).Transform )( {
				transform( chunk, encoding, callback ) {
					callback( null, chunk.toString( "utf8" ).toUpperCase() );
				}
			} );

			stream.pipe( transformed );

			return transformed;
		},
	},
];
```

On using a configuration like this, requesting pathname **/files/some/file.ext** will respond with content of file **<project-folder>/static/files/some/file.ext**. The plugin supports several common types of files while delivering any unknown type of file with announcing its content type as **application/octet-stream**.

The last example is including additionally supported configuration parameters:
 
* `fallback` selects a file to be delivered on requests for actually missing files. This is useful in combination with delivering files of web applications that handle routes themselves and thus require all its probable routes referring to the application's bootstrap file.

* `maxAge` is a positive number of seconds declared as maximum age of a delivered file to survive in a client's cache. It defaults to 604800 seconds which is seven days. When set to 0 or false, files are delivered without headers enabling their caching. 

* `mime` is a map of filename extensions into MIME types to be exposed when providing file matching either extension. This map is merged with an internal map and may extend the latter or replace existing records with different MIME types.

* `download` is a map of MIME types into booleans controlling whether files of either MIME type should be exposed for download or not. The provided map is merged with some internally defined one and may add new entries as well as replace existing ones.

* `filter` is an optional callback invoked per request to decide early whether some picked file may be delivered to the client or not.

  Any provided function is invoked with the [request's context](https://core.hitchy.org/api/hitchy.html#request-context) as `this`. In addition, provided arguments are 
  
  * the local path name used in requesting URL,
  * the path name of local file to deliver and
  * a boolean set true when tested file is the one actually requested in opposition to the fallback.
  
  The callback is meant to return if fetching the file is okay. It may throw to prevent retrieval of requested file. By throwing [HttpException](https://core.hitchy.org/api/components/services.html#httpexception) it may control status returned to the client. In addition, by throwing it with status 404 on the actually requested file the fallback retrieval can be triggered.
  
* `process` is another optional callback invoked on a request addressing some actual file after passing the optional `filter` callback. It is invoked every time that file's content is processed either for hashing it or for delivering it to the requesting client. It is meant to take the open file stream and either pass it or replace it with another stream to fetch file's content from instead.

  As an option, it might take the provided file stream and handle the request all by itself, returning a nullish replacement for provided stream.

  A promise for either result may be returned, too.
  
  The callback is invoked with the [request's context](https://core.hitchy.org/api/hitchy.html#request-context) as `this`. In addition, provided arguments are 
                                          
  * the local path name used in requesting URL,
  * the path name of local file to deliver,
  * the stream opened for reading and
  * a boolean indicating if file is processed for computing a hash of its content, only.

  The callback should handle errors on the replacing stream. It may throw an exception or return an eventually rejected promise in case of an error preventing the file from being delivered at all. When throwing an [HttpException](https://core.hitchy.org/api/components/services.html#httpexception) with status code **404** on the actually requested file, delivering some configured fallback is tried next. Any other status code is passed along to the client.

* `redirect` is a boolean switch controlling whether clients are redirected to existing **index.html** document on fetching URL of a folder rather than retrieving that found document's content implicitly. 

  This redirection was default behaviour in versions before v0.2.0 but has been changed then, so this option must be set true to explicitly keep the previous behaviour.