Skip to content

Commit

Permalink
feat: import DT types (#169)
Browse files Browse the repository at this point in the history
  • Loading branch information
Marsup committed Mar 13, 2023
1 parent 9741cea commit 72e461f
Show file tree
Hide file tree
Showing 3 changed files with 280 additions and 3 deletions.
166 changes: 166 additions & 0 deletions lib/index.d.ts
@@ -0,0 +1,166 @@
// Type definitions for @hapi/inert
// Project: https://github.com/hapijs/inert/
// Definitions by: Steve Ognibene <https://github.com/nycdotnet>
// Alexander James Phillips <https://github.com/AJamesPhillips>
// Silas Rech <https://github.com/lenovouser>

import { Plugin, Request, ResponseObject } from '@hapi/hapi';

declare namespace inert {
type RequestHandler<T> = (request: Request) => T;

interface ReplyFileHandlerOptions {
/**
* confine - serve file relative to this directory and returns 403 Forbidden if the path resolves outside the confine directory.
* Defaults to true which uses the relativeTo route option as the confine. Set to false to disable this security feature.
*/
confine?: boolean | string | undefined;
/**
* filename - an optional filename to specify if sending a 'Content-Disposition' header, defaults to the basename of path
*/
filename?: string | undefined;
/**
* mode - specifies whether to include the 'Content-Disposition' header with the response. Available values:
* * false - header is not included. This is the default value.
* * 'attachment'
* *'inline'
*/
mode?: false | 'attachment' | 'inline' | undefined;
/**
* lookupCompressed - if true, looks for for a pre-compressed version of the file with the same filename with an extension, depending on the accepted encoding. Defaults to false.
*/
lookupCompressed?: boolean | undefined;
/**
* lookupMap - an object which maps content encoding to expected file name extension. Defaults to `{ gzip: '.gz' }.
*/
lookupMap?: { [index: string]: string } | undefined;
/**
* etagMethod - specifies the method used to calculate the ETag header response. Available values:
* * 'hash' - SHA1 sum of the file contents, suitable for distributed deployments. Default value.
* * 'simple' - Hex encoded size and modification date, suitable when files are stored on a single server.
* * false - Disable ETag computation.
*/
etagMethod?: 'hash' | 'simple' | false | undefined;
/**
* start - offset in file to reading from, defaults to 0.
*/
start?: number | undefined;
/**
* end - offset in file to stop reading from. If not set, will read to end of file.
*/
end?: number | undefined;
}

interface FileHandlerRouteObject extends ReplyFileHandlerOptions {
/**
* path - a path string or function as described above (required).
*/
path: string | RequestHandler<string>;
}

interface DirectoryHandlerRouteObject {
/**
* path - (required) the directory root path (relative paths are resolved based on the route files configuration). Value can be:
* * a single path string used as the prefix for any resources requested by appending the request path parameter to the provided string.
* * an array of path strings. Each path will be attempted in order until a match is found (by following the same process as the single path string).
* * a function with the signature function(request) which returns the path string or an array of path strings.
* If the function returns an error, the error is passed back to the client in the response.
*/
path: string | string[] | RequestHandler<string | string[] | Error>;
/**
* index - optional boolean|string|string[], determines if an index file will be served if found in the folder when requesting a directory.
* The given string or strings specify the name(s) of the index file to look for. If true, looks for 'index.html'.
* Any falsy value disables index file lookup. Defaults to true.
*/
index?: boolean | string | string[] | undefined;
/**
* listing - optional boolean, determines if directory listing is generated when a directory is requested without an index document. Defaults to false.
*/
listing?: boolean | undefined;
/**
* showHidden - optional boolean, determines if hidden files will be shown and served. Defaults to false.
*/
showHidden?: boolean | undefined;
/**
* redirectToSlash - optional boolean, determines if requests for a directory without a trailing slash are redirected to the same path with the missing slash.
* Useful for ensuring relative links inside the response are resolved correctly.
* Disabled when the server config router.stripTrailingSlash is true.Defaults to false.
*/
redirectToSlash?: boolean | undefined;
/**
* lookupCompressed - optional boolean, instructs the file processor to look for the same filename with the '.gz' suffix for a pre-compressed
* version of the file to serve if the request supports content encoding. Defaults to false.
*/
lookupCompressed?: boolean | undefined;
/**
* etagMethod - specifies the method used to calculate the ETag header response. Available values:
* * 'hash' - SHA1 sum of the file contents, suitable for distributed deployments. Default value.
* * 'simple' - Hex encoded size and modification date, suitable when files are stored on a single server.
* * false - Disable ETag computation.
*/
etagMethod?: 'hash' | 'simple' | false | undefined;
/**
* defaultExtension - optional string, appended to file requests if the requested file is not found. Defaults to no extension.
*/
defaultExtension?: string | undefined;
}

/**
* inert accepts the following registration options
* @see {@link https://github.com/hapijs/inert#registration-options}
*/
interface OptionalRegistrationOptions {
/**
* sets the maximum number of file etag hash values stored in the etags cache. Defaults to 10000.
*/
etagsCacheMaxSize?: number | undefined;
}
}

declare const inert: { plugin: Plugin<inert.OptionalRegistrationOptions> };

export = inert;

declare module '@hapi/hapi' {
interface HandlerDecorations {
/**
* The file handler
*
* Generates a static file endpoint for serving a single file. file can be set to:
* * a relative or absolute file path string (relative paths are resolved based on the route files configuration).
* * a function with the signature function(request) which returns the relative or absolute file path.
* * an object with one or more of the following options @see IFileHandler
* @see {@link https://github.com/hapijs/inert#the-file-handler}
*/
file?: string | inert.RequestHandler<string> | inert.FileHandlerRouteObject | undefined;
/**
* The directory handler
*
* Generates a directory endpoint for serving static content from a directory.
* Routes using the directory handler must include a path parameter at the end of the path string
* (e.g. /path/to/somewhere/{param} where the parameter name does not matter).
* The path parameter can use any of the parameter options (e.g. {param} for one level files only,
* {param?} for one level files or the directory root, {param*} for any level, or {param*3} for a specific level).
* If additional path parameters are present, they are ignored for the purpose of selecting the file system resource.
* The directory handler is an object with the following options:
* @see {@link https://github.com/hapijs/inert#the-directory-handler}
*/
directory?: inert.DirectoryHandlerRouteObject | undefined;
files?:
| {
/**
* Set the relative path
*/
relativeTo: string;
}
| undefined;
}

interface ResponseToolkit {
/**
* Transmits a file from the file system. The 'Content-Type' header defaults to the matching mime type based on filename extension.
* @see {@link https://github.com/hapijs/inert#replyfilepath-options}
*/
file(path: string, options?: inert.ReplyFileHandlerOptions): ResponseObject;
}
}
10 changes: 7 additions & 3 deletions package.json
Expand Up @@ -4,6 +4,7 @@
"version": "7.0.1",
"repository": "https://github.com/hapijs/inert.git",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"files": [
"lib"
],
Expand Down Expand Up @@ -31,11 +32,14 @@
"@hapi/code": "^9.0.3",
"@hapi/eslint-plugin": "*",
"@hapi/file": "^3.0.0",
"@hapi/hapi": "^21.2.1",
"@hapi/lab": "^25.1.2"
"@hapi/hapi": "^21.3.0",
"@hapi/lab": "^25.1.2",
"@types/node": "^14.18.37",
"joi": "^17.8.3",
"typescript": "^4.9.5"
},
"scripts": {
"test": "lab -f -a @hapi/code -t 100 -L",
"test": "lab -f -a @hapi/code -t 100 -L -Y",
"test-cov-html": "lab -f -a @hapi/code -r html -o coverage.html"
},
"license": "BSD-3-Clause"
Expand Down
107 changes: 107 additions & 0 deletions test/index.ts
@@ -0,0 +1,107 @@
import * as path from 'path';

import { Server, Lifecycle } from '@hapi/hapi';
import * as inert from '../';
import * as Lab from '@hapi/lab';

const { expect: check } = Lab.types;

const server = new Server({
port: 3000,
routes: {
files: {
relativeTo: path.join(__dirname, 'public'),
},
},
});

const provision = async () => {
await server.register(inert);
await server.register({ plugin: inert.plugin, options: { etagsCacheMaxSize: 100 } });

server.route({
method: 'GET',
path: '/{param*}',
handler: {
directory: {
path: '.',
redirectToSlash: true,
index: true,
},
},
});

server.route({
method: 'GET',
path: '/{param*}',
handler(request, h) {
check.type<Function>(h.file);
return h.file('awesome.png', {
confine: './images',
});
},
});

// https://github.com/hapijs/inert#serving-a-single-file
server.route({
method: 'GET',
path: '/{path*}',
handler: {
file: 'page.html',
},
});

// https://github.com/hapijs/inert#customized-file-response
server.route({
method: 'GET',
path: '/file',
handler(request, h) {
let path = 'plain.txt';
if (request.headers['x-magic'] === 'sekret') {
path = 'awesome.png';
}

return h.file(path).vary('x-magic');
},
});

const handler: Lifecycle.Method = (request, h) => {
const response = request.response;
if (response instanceof Error && response.output.statusCode === 404) {
return h.file('404.html').code(404);
}

return h.continue;
};

server.ext('onPostHandler', handler);

const file: inert.FileHandlerRouteObject = {
path: '',
confine: true,
};

const directory: inert.DirectoryHandlerRouteObject = {
path: '',
listing: true,
};

server.route({
path: '',
method: 'GET',
handler: {
file,
directory: {
path() {
if (Math.random() > 0.5) {
return '';
} else if (Math.random() > 0) {
return [''];
}
return new Error('');
},
},
},
options: { files: { relativeTo: __dirname } },
});
};

0 comments on commit 72e461f

Please sign in to comment.