Add hoxy type definitions (#43177)

This commit is contained in:
TrueLecter 2020-03-25 02:34:10 +02:00 committed by GitHub
parent d2be412d2b
commit 028f391902
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 539 additions and 0 deletions

34
types/hoxy/hoxy-tests.ts Normal file
View File

@ -0,0 +1,34 @@
import { createServer } from 'hoxy';
const a = createServer(); // $ExpectType Proxy
a.listen(1); // $ExpectType Proxy
a.listen(1, () => {}); // $ExpectType Proxy
a.listen(2, '0.0.0.0'); // $ExpectType Proxy
a.listen(2, '0.0.0.0', () => {}); // $ExpectType Proxy
a.listen(2, '0.0.0.0', 22); // $ExpectType Proxy
a.listen(3, '0.0.0.0', () => {}); // $ExpectType Proxy
a.log('error'); // $ExpectType Proxy
a.log('error', process.stderr); // $ExpectType Proxy
a.log('info', log => {
log; // $ExpectType Log
});
a.close(); // $ExpectType void
a.intercept('request', (request, response, cycle) => {
request; // $ExpectType Request
request.protocol; // $ExpectType string
request.hostname; // $ExpectType string
request.port; // $ExpectType number
response; // $ExpectType Response
response.statusCode; // $ExpectType number
cycle; // $ExpectType Cycle
});
a.close(); // $ExpectType void

479
types/hoxy/index.d.ts vendored Normal file
View File

@ -0,0 +1,479 @@
// Type definitions for hoxy 3.3
// Project: https://github.com/greim/hoxy#readme
// Definitions by: _TrueLecter_ <https://github.com/TrueLecter>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
import { Writable } from 'stream';
import cheerio = require('cheerio');
/**
* Key and certificate to be passed to https.createServer()
* See supported formats [here](https://nodejs.org/api/tls.html#tls_tls_createsecurecontext_options)
*/
export interface CertificateParams {
cert: string | string[] | Buffer | Buffer[];
key: string | string[] | Buffer | Buffer[] | object[];
}
export interface Slow {
/**
* Imposes a delay (in milliseconds) between all requests and responses
*/
rate: number;
/**
* Imposes a single rate-limiting bottleneck (in bytes per second) on all throughput
*/
latency: number;
/**
* Imposes a single rate-limiting bottleneck (in bytes per second) on all uploads
*/
up: number;
/**
* Imposes a single rate-limiting bottleneck (in bytes per second) on all downloads
*/
down: number;
}
export interface CreateServerOptions {
/**
* If present, this proxy will in turn use another proxy.
* This allows Hoxy to play well with other proxies.
* This value should take the form host:port
*/
upstreamProxy?: string;
/**
* If present, this proxy will run as a reverse proxy for the given server.
* This allows you to point your client directly at the proxy, instead of
* configuring it in the client's proxy settings.
* This value should take the form scheme://host:port.
*/
reverse?: string;
/**
* If present, this should contain a key/cert combo representing a certificate
* authority that your client trusts. See these instructions for how to
* generate these files. You'll then need to configure your client to use this
* proxy for https in addition to http. Once you've got all of that set up,
* Hoxy will generate fake keys/cert combos for every hostname you visit,
* caching them in memory for subsequent visits, thus allowing the proxy to
* handle https requests as cleartext
*/
certAuthority?: CertificateParams;
/**
* Should only be used in combination with reverse. If present, causes Hoxy to
* run as an https server. Passed as opts to https.createServer(opts, function)
*/
tls?: CertificateParams;
/**
* Latency emulation
*/
slow?: Slow;
}
/**
* Factory for a new proxy with given options
* @param opts - Options to be passed in constructor
*/
export function createServer(opts?: CreateServerOptions): Proxy;
/**
* Request phase
*/
export type Phase = 'request' | 'request-sent' | 'response' | 'response-sent';
/**
* Body parsers
*/
export type BodyParser = '$' | 'json' | 'params' | 'buffer' | 'string';
export type TesterFunction<T> = (arg: T) => boolean;
export type Filter<T> = RegExp | TesterFunction<T> | T;
export interface InterceptOptions {
/**
* Request phase to listen to
*/
phase: Phase;
/**
* Body-parsers
*/
as?: BodyParser;
/**
* Match the request protocol
*/
protocol?: Filter<string>;
/**
* Match the all-uppercase HTTP request method
*/
method?: Filter<HttpMethod>;
/**
* Match the host, not including :port.
*/
hostname?: Filter<string>;
/**
* Match the port number.
*/
port?: Filter<number | string>;
/**
* Match the request URL. Patterns like /foo/* are allowed
*/
url?: Filter<string>;
/**
* Match the full request URL including protocol and hostname.
* Patterns like /foo/* are allowed
*/
fullUrl?: Filter<string>;
/**
* Match the full content-type header of the request or
* response (depending on the phase)
*/
contentType?: Filter<string>;
/**
* Same as contentType but only matches request
*/
requestContentType?: Filter<string>;
/**
* Same as contentType but only matches response
*/
responseContentType?: Filter<string>;
/**
* Match just the mime type portion of the content-type header
* of the request or response (depending on the phase). I.e.,
* if the entire header is "text/html; charset=utf-8", just
* match the "text/html" part
*/
mimeType?: Filter<string>;
/**
* Same as mimeType but only matches request
*/
requestMimeType?: Filter<string>;
/**
* Same as mimeType but only matches response
*/
responseMimeType?: Filter<string>;
}
/**
* Request method
*/
export type HttpMethod = 'POST' | 'GET' | 'PUT' | 'PATCH' | 'DELETE';
export class Request {
private constructor();
/**
* Protocol of the request
*/
protocol: string;
/**
* Destination server hostname, sans port
*/
hostname: string;
/**
* Destination server port
*/
port: number;
/**
* All-caps HTTP method used. Lowercase values are converted to uppercase
*/
method: HttpMethod;
/**
* HTTP request header name/value JS object. These are all-lowercase, e.g. accept-encoding
*/
headers: Record<string, string>;
/**
* Root-relative request URL, including query string, like /foo/bar?baz=qux
*/
url: string;
/**
* An object representing querystring params in the URL.
* For example if the URL is /foo/bar?baz=qux, then this
* object will look like { baz: 'qux' }.
*/
query: Record<string, string>;
/**
* Request body parsed as JSON. This is only present if you intercept the
* request as:'json'. Changes made to this object will be seen by the server.
*/
json?: Record<string, any>;
/**
* Request body parsed as form-url-encoded params. This will be a key/value
* object. This object will only present if you intercept the request
* as:'params'. Changes made to this object will be seen by the server.
*
* Note: parameters from the URL querystring are not included in this object.
*/
params?: Record<string, string>;
/**
* Request body string. This is only present if you intercept the request
* as:'string'. Overwriting this will overwrite the request body sent to
* the server.
*/
string?: string;
/**
* Request body binary buffer. This is only present if you intercept the
* request as:'buffer'. Changes made to this object will be seen by the server.
*/
buffer?: Buffer;
/**
* Simulates slowness during request phase. With this method you can set a minimum
* latency and/or maximum transfer rate. Since these are minimum/maximum, if your
* native connection is already slower than these values, this method will have no
* effect.
*/
slow(opts: Partial<Slow>): void;
/**
* If url is provided, sets the request's absolute protocol, hostname, port and
* url. Otherwise it returns the absolute URL of this request. This is mainly a
* convenience method.
*/
fullUrl(url?: string): string;
/**
* Whatever request body gets sent to the server, tee() pipes an identical copy
* to your writable stream. Your stream is held in memory, and only gets written
* to if and when the request is sent to the server. In other words, your stream
* sees whatever the server sees. If the server sees nothing, your stream sees
* nothing. You can tee() as many times as you want.
*
* @param stream - target stream
*/
tee(stream: Writable): void;
}
export class Response {
private constructor();
/**
* HTTP status code being sent to the client.
*/
statusCode: number;
/**
* HTTP response header name/value JS object. Header names are all-lowercase,
* such as 'content-type'.
*/
headers: Record<string, string>;
/**
* Response body parsed as DOM. This object is only present if you intercept
* the response as:'$'. This is a cheerio object, which provides a jQuery-like
* API. Changes made to it will be seen by the client.
*/
$?: ReturnType<typeof cheerio>;
/**
* Response body parsed as JSON. This is only present if you intercept the
* response as:'json'. Changes to this object will be seen by the client.
*/
json?: any;
/**
* Response body string. This is only present if you intercept the response
* as:'string'. Overwriting this will overwrite the response body sent to the
* client.
*/
string?: string;
/**
* Response body binary buffer. This is only present if you intercept the
* response as:'buffer'. Changes made to this object will be seen by the client.
*/
buffer?: Buffer;
/**
* Simulates slowness during request phase. With this method you can set a minimum
* latency and/or maximum transfer rate. Since these are minimum/maximum, if your
* native connection is already slower than these values, this method will have no
* effect.
*/
slow(opts: Partial<Slow>): void;
/**
* Whatever request body gets sent to the server, tee() pipes an identical copy
* to your writable stream. Your stream is held in memory, and only gets written
* to if and when the request is sent to the server. In other words, your stream
* sees whatever the server sees. If the server sees nothing, your stream sees
* nothing. You can tee() as many times as you want.
*
* @param stream - target stream
*/
tee(stream: Writable): void;
}
export type ServeStrategy = 'replace' | 'overlay' | 'mirror';
export interface ServeOptions {
/**
* Which file to serve. Defaults to the request URL. Normally this would
* be used in mutual exclusion with docroot. Strictly speaking, path is
* always rooted to docroot, which defaults to "/"
*/
path?: string;
/**
* Which local directory to serve out of. Defaults to filesystem root "/"
*/
docroot?: string;
/**
* Mainly relevant when using the docroot option. Describes the relationship
* between the local docroot and the remote one. Strictly speaking, this
* controls what happens when the local docroot is missing a requested file.
* Accepted values:
* * replace - (default) Replaces the remote docroot with the local one. In
* other words, if a requested file doesn't exist locally, it populates the
* response with a 404, even if it would have been found remotely.
* * overlay - Overlays the local docroot on top of the remote one. In other
* words, if a requested file doesn't exist locally, the request will
* transparently fall through to the remote server.
* * mirror - Automatically mirror the remote docroot locally. In other words,
* if a requested file doesn't exist locally, it's copied to the local docroot
* from the remote one, and will be found locally on subsequent requests.
*/
strategy?: ServeStrategy;
}
/**
* Represents a whole request/response cycle. A Cycle instance is this in all
* interceptor calls, and the same instance is shared across an entire
* request/response cycle. It's also passed as the third argument, in order
* to support arrow functions. It provides a small number of methods not
* associated specifically to either the request or response.
*/
export class Cycle {
private constructor();
/**
* Provisions responses from the local filesystem. Generally, the reason you'd do
* this is to be able to edit those files locally and test them as if they were
* live on the remote server. This action populates the response object; see
* response population for more info. The completion of this action is asynchronous,
* so serve() returns a promise.
*
* The returned promise resolves after the response has been populated. There are at
* least three use cases worth mentioning.
*/
serve(opts?: string | ServeOptions): Promise<void>;
/**
* Stores and retrieves data on a cycle instance. This is useful since the same
* instance is shared across all interceptors for a given request/response cycle,
* allowing you to share related data across disparate scopes. With two params this
* method behaves as a setter, with one param as a getter.
*/
data(name: string, value?: any): any;
}
export type InterceptionHandler = (this: Proxy, req: Request, res: Response, cycle: Cycle) => Promise<void> | void;
export type LogLevel = 'error' | 'warn' | 'info' | 'debug';
export interface Log {
level: LogLevel;
error?: Error;
message: string;
}
export type LoggerCallbackFunction = (log: Log) => any;
export type PossibleErrorCallback = (err?: Error) => any;
export class Proxy {
protected constructor(opts: CreateServerOptions);
/**
* Starts proxy listening on port. Returns itself.
* A callback may be provided, to run when the proxy has started listening.
* This method simply passes its arguments to Node's server.listen() method.
*/
listen(port: number, callback?: () => void): this;
listen(port: number, host: string, callback?: () => void): this;
listen(port: number, host: string, backlog: number, callback?: () => void): this;
/**
* This is the entry point for intercepting and operating on requests and responses.
* This first example intercepts all requests:
* ```javascript
* proxy.intercept('request', req => console.log(req.url));
* ```
* This is more verbose, but identical to the above:
* ```javascript
* proxy.intercept({
* phase: 'request'
* }, function(req, resp, cycle) {
* console.log(req.url);
* });
* ```
*/
intercept(opts: string | InterceptOptions, handler: InterceptionHandler): void;
/**
* Get/set proxy-level slow options. If options is provided, it's a setter.
* If options is not provided, it's a getter.
* @param opts
*/
slow(opts: Slow): this;
/**
* Deals with various logging events.
*
* This first example listens for error,
* warn, and debug logging events, and prints them to stderr:
* ```javascript
* proxy.log('error warn debug');
* ```
* Or, print logging events to various writable streams:
* ```javascript
* proxy.log('error warn debug', process.stderr);
* proxy.log('info', process.stdout);
* ```
*
* Or, explicitly handle logging event:
* ```javascript
* proxy.log('error warn', function(event) {
* console.error(event.level + ': ' + event.message);
* if (event.error) console.error(event.error.stack);
* });
* ```
*/
log(levels: string, cb?: LoggerCallbackFunction | Writable): this;
/**
* Stops proxy receiving requests. Finalizes and/or cleans up any
* resources the proxy uses internally.
*/
close(cb?: PossibleErrorCallback): void;
}

25
types/hoxy/tsconfig.json Normal file
View File

@ -0,0 +1,25 @@
{
"compilerOptions": {
"target": "es6",
"esModuleInterop": true,
"module": "commonjs",
"lib": [
"es6"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictFunctionTypes": true,
"strictNullChecks": true,
"baseUrl": "../",
"typeRoots": [
"../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"hoxy-tests.ts"
]
}

1
types/hoxy/tslint.json Normal file
View File

@ -0,0 +1 @@
{ "extends": "dtslint/dt.json" }