tsoa
This commit is contained in:
186
node_modules/@hapi/shot/lib/index.d.ts
generated
vendored
Normal file
186
node_modules/@hapi/shot/lib/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import {
|
||||
IncomingHttpHeaders,
|
||||
IncomingMessage,
|
||||
OutgoingHttpHeaders,
|
||||
ServerResponse
|
||||
} from 'http';
|
||||
import { Readable, Stream } from 'stream';
|
||||
import { UrlObject } from 'url';
|
||||
|
||||
interface MockSocket extends EventEmitter {
|
||||
readonly remoteAddress: string;
|
||||
end(): void;
|
||||
setTimeout(): void;
|
||||
}
|
||||
|
||||
export interface InjectedRequest extends Readonly<Readable> {
|
||||
readonly httpVersion: '1.1';
|
||||
readonly method: string;
|
||||
readonly url: string;
|
||||
readonly headers: Readonly<IncomingHttpHeaders>;
|
||||
readonly socket: MockSocket;
|
||||
readonly connection: MockSocket;
|
||||
}
|
||||
|
||||
export type MaybeInjectedRequest = InjectedRequest | IncomingMessage;
|
||||
|
||||
export interface ResponseObject {
|
||||
/**
|
||||
* An object containing the raw request and response objects.
|
||||
*/
|
||||
raw: {
|
||||
/**
|
||||
* The simulated request object.
|
||||
*/
|
||||
req: InjectedRequest;
|
||||
|
||||
/**
|
||||
* The simulated response object.
|
||||
*/
|
||||
res: ServerResponse;
|
||||
};
|
||||
|
||||
/**
|
||||
* An object containing the response headers.
|
||||
*/
|
||||
headers: OutgoingHttpHeaders;
|
||||
|
||||
/**
|
||||
* The HTTP status code. If response is aborted before headers are sent, the code is `499`.
|
||||
*/
|
||||
statusCode: number;
|
||||
|
||||
/**
|
||||
* The HTTP status message.
|
||||
*/
|
||||
statusMessage: string;
|
||||
|
||||
/**
|
||||
* The payload as a UTF-8 encoded string.
|
||||
*/
|
||||
payload: string;
|
||||
|
||||
/**
|
||||
* The raw payload as a Buffer.
|
||||
*/
|
||||
rawPayload: Buffer;
|
||||
|
||||
/**
|
||||
* An object containing the response trailers
|
||||
*/
|
||||
trailers: NodeJS.Dict<string>;
|
||||
|
||||
/**
|
||||
* A boolean which is `true` for aborted, ie. not fully transmitted, responses.
|
||||
*/
|
||||
aborted?: true;
|
||||
}
|
||||
|
||||
type PartialURL = Pick<UrlObject, 'protocol' | 'hostname' | 'port' | 'query'> & { pathname: string };
|
||||
|
||||
export interface RequestOptions {
|
||||
|
||||
/**
|
||||
* The request URL.
|
||||
*/
|
||||
url: string | PartialURL;
|
||||
|
||||
/**
|
||||
* The HTTP request method.
|
||||
*
|
||||
* @default 'GET'
|
||||
*/
|
||||
method?: string;
|
||||
|
||||
/**
|
||||
* The HTTP HOST header value to be used if no header is provided,
|
||||
* and the url does not include an authority component.
|
||||
*
|
||||
* @default 'localhost'
|
||||
*/
|
||||
authority?: string;
|
||||
|
||||
/**
|
||||
* The request headers.
|
||||
*/
|
||||
headers?: OutgoingHttpHeaders;
|
||||
|
||||
/**
|
||||
* The client remote address.
|
||||
*
|
||||
* @default '127.0.0.1'
|
||||
*/
|
||||
remoteAddress?: string;
|
||||
|
||||
/**
|
||||
* A request payload. Can be a string, Buffer, Stream or object that will be stringified.
|
||||
*/
|
||||
payload?: string | Buffer | Stream | object;
|
||||
|
||||
/**
|
||||
* an object containing flags to simulate various conditions:
|
||||
*/
|
||||
simulate?: {
|
||||
|
||||
/**
|
||||
* indicates whether the request will fire an end event.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
end?: boolean;
|
||||
|
||||
/**
|
||||
* indicates whether the request payload will be split into chunks.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
split?: boolean;
|
||||
|
||||
/**
|
||||
* whether the request will emit an error event.
|
||||
* If set to true, the emitted error will have a message of 'Simulated'.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
error?: boolean;
|
||||
|
||||
/**
|
||||
* whether the request will emit a close event.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
close?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Optional flag to validate this options object.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
validate?: boolean;
|
||||
}
|
||||
|
||||
type InjectionListener = (req: InjectedRequest, res: ServerResponse) => void;
|
||||
|
||||
type MaybeInjectionListener = (req: MaybeInjectedRequest, res: ServerResponse) => void;
|
||||
|
||||
/**
|
||||
* Injects a fake request into an HTTP server.
|
||||
*
|
||||
* @param dispatchFunc - Listener function. Similar as you would pass to Http.createServer when making a node HTTP server.
|
||||
* @param options - Request options object or string with request url.
|
||||
*
|
||||
* @return A Promise that resolves with a ResponseObject object
|
||||
*/
|
||||
export function inject(dispatchFunc: InjectionListener, options: RequestOptions | string): Promise<ResponseObject>;
|
||||
export function inject(dispatchFunc: MaybeInjectionListener, options: RequestOptions | string): Promise<ResponseObject>;
|
||||
|
||||
/**
|
||||
* Checks if given object is a Shot Request object.
|
||||
*
|
||||
* @param obj - the req or res object to test
|
||||
*
|
||||
* @return true if the object is a shot request, otherwise false.
|
||||
*/
|
||||
export function isInjection(obj: MaybeInjectedRequest | ServerResponse): boolean;
|
||||
63
node_modules/@hapi/shot/lib/index.js
generated
vendored
Executable file
63
node_modules/@hapi/shot/lib/index.js
generated
vendored
Executable file
@@ -0,0 +1,63 @@
|
||||
'use strict';
|
||||
|
||||
const Hoek = require('@hapi/hoek');
|
||||
const Validate = require('@hapi/validate');
|
||||
|
||||
const Request = require('./request');
|
||||
const Response = require('./response');
|
||||
const Symbols = require('./symbols');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
internals.options = Validate.object().keys({
|
||||
url: Validate.alternatives([
|
||||
Validate.string(),
|
||||
Validate.object().keys({
|
||||
protocol: Validate.string(),
|
||||
hostname: Validate.string(),
|
||||
port: Validate.any(),
|
||||
pathname: Validate.string().required(),
|
||||
query: Validate.any()
|
||||
})
|
||||
])
|
||||
.required(),
|
||||
headers: Validate.object(),
|
||||
payload: Validate.any(),
|
||||
simulate: {
|
||||
end: Validate.boolean(),
|
||||
split: Validate.boolean(),
|
||||
error: Validate.boolean(),
|
||||
close: Validate.boolean()
|
||||
},
|
||||
authority: Validate.string(),
|
||||
remoteAddress: Validate.string(),
|
||||
method: Validate.string(),
|
||||
validate: Validate.boolean()
|
||||
});
|
||||
|
||||
|
||||
exports.inject = async function (dispatchFunc, options) { // eslint-disable-line require-await
|
||||
|
||||
options = (typeof options === 'string' ? { url: options } : options);
|
||||
|
||||
if (options?.validate !== false) { // Defaults to true
|
||||
Hoek.assert(typeof dispatchFunc === 'function', 'Invalid or missing dispatch function');
|
||||
Validate.assert(options ?? null, internals.options, 'Invalid options:');
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
|
||||
const req = new Request(options);
|
||||
const res = new Response(req, resolve);
|
||||
|
||||
req.prepare(() => dispatchFunc(req, res));
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
exports.isInjection = function (obj) {
|
||||
|
||||
return !!obj[Symbols.injection];
|
||||
};
|
||||
168
node_modules/@hapi/shot/lib/request.js
generated
vendored
Executable file
168
node_modules/@hapi/shot/lib/request.js
generated
vendored
Executable file
@@ -0,0 +1,168 @@
|
||||
'use strict';
|
||||
|
||||
const Events = require('events');
|
||||
const Stream = require('stream');
|
||||
const Url = require('url');
|
||||
|
||||
const Symbols = require('./symbols');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
exports = module.exports = internals.Request = class extends Stream.Readable {
|
||||
|
||||
constructor(options) {
|
||||
|
||||
super({
|
||||
emitClose: !!(options.simulate?.close),
|
||||
autoDestroy: true // This is the default in node 14+
|
||||
});
|
||||
|
||||
// options: method, url, payload, headers, remoteAddress
|
||||
|
||||
let url = options.url;
|
||||
if (typeof url === 'object') {
|
||||
url = Url.format(url);
|
||||
}
|
||||
|
||||
const uri = Url.parse(url);
|
||||
this.url = uri.path;
|
||||
|
||||
this.httpVersion = '1.1';
|
||||
this.method = (options.method ? options.method.toUpperCase() : 'GET');
|
||||
|
||||
this.headers = {};
|
||||
const headers = options.headers ?? {};
|
||||
const fields = Object.keys(headers);
|
||||
fields.forEach((field) => {
|
||||
|
||||
this.headers[field.toLowerCase()] = headers[field];
|
||||
});
|
||||
|
||||
this.headers['user-agent'] = this.headers['user-agent'] ?? 'shot';
|
||||
|
||||
const hostHeaderFromUri = function () {
|
||||
|
||||
if (uri.port) {
|
||||
return uri.host;
|
||||
}
|
||||
|
||||
if (uri.protocol) {
|
||||
return uri.hostname + (uri.protocol === 'https:' ? ':443' : ':80');
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
this.headers.host = this.headers.host ?? hostHeaderFromUri() ?? options.authority ?? 'localhost:80';
|
||||
|
||||
// NOTE connection is deprecated in favor of socket as of node v13
|
||||
|
||||
this.socket = this.connection = new internals.MockSocket(options);
|
||||
|
||||
let payload = options.payload ?? null;
|
||||
if (payload &&
|
||||
typeof payload !== 'string' &&
|
||||
!(payload instanceof Stream) &&
|
||||
!Buffer.isBuffer(payload)) {
|
||||
|
||||
payload = JSON.stringify(payload);
|
||||
this.headers['content-type'] = this.headers['content-type'] || 'application/json';
|
||||
}
|
||||
|
||||
// Set the content-length for the corresponding payload if none set
|
||||
|
||||
if (payload &&
|
||||
!(payload instanceof Stream) &&
|
||||
!this.headers.hasOwnProperty('content-length')) {
|
||||
|
||||
this.headers['content-length'] = (Buffer.isBuffer(payload) ? payload.length : Buffer.byteLength(payload)).toString();
|
||||
}
|
||||
|
||||
// Use _shot namespace to avoid collision with Node
|
||||
|
||||
this._shot = {
|
||||
payload,
|
||||
isDone: false,
|
||||
simulate: options.simulate ?? {}
|
||||
};
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
prepare(next) {
|
||||
|
||||
if (this._shot.payload instanceof Stream === false) {
|
||||
return next();
|
||||
}
|
||||
|
||||
const chunks = [];
|
||||
|
||||
this._shot.payload.on('data', (chunk) => chunks.push(Buffer.from(chunk)));
|
||||
|
||||
this._shot.payload.on('end', () => {
|
||||
|
||||
const payload = Buffer.concat(chunks);
|
||||
this.headers['content-length'] = this.headers['content-length'] || payload.length;
|
||||
this._shot.payload = payload;
|
||||
return next();
|
||||
});
|
||||
}
|
||||
|
||||
_read(size) {
|
||||
|
||||
setImmediate(() => {
|
||||
|
||||
if (this._shot.isDone) {
|
||||
/* $lab:coverage:off$ */
|
||||
if (this._shot.simulate.end !== false) { // 'end' defaults to true
|
||||
this.push(null);
|
||||
}
|
||||
/* $lab:coverage:on$ */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this._shot.isDone = true;
|
||||
|
||||
if (this._shot.payload) {
|
||||
if (this._shot.simulate.split) {
|
||||
this.push(this._shot.payload.slice(0, 1));
|
||||
this.push(this._shot.payload.slice(1));
|
||||
}
|
||||
else {
|
||||
this.push(this._shot.payload);
|
||||
}
|
||||
}
|
||||
|
||||
if (this._shot.simulate.error) {
|
||||
this.destroy(new Error('Simulated'));
|
||||
}
|
||||
else if (this._shot.simulate.end !== false) { // 'end' defaults to true
|
||||
this.push(null);
|
||||
}
|
||||
else if (this._shot.simulate.close) { // manually close (out of spec)
|
||||
this.emit('close');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
internals.Request.prototype[Symbols.injection] = true;
|
||||
|
||||
internals.MockSocket = class MockSocket extends Events.EventEmitter {
|
||||
|
||||
constructor({ remoteAddress }) {
|
||||
|
||||
super();
|
||||
|
||||
this.remoteAddress = remoteAddress ?? '127.0.0.1';
|
||||
}
|
||||
|
||||
// Net.Socket APIs used by hapi
|
||||
|
||||
end() {}
|
||||
setTimeout() {}
|
||||
};
|
||||
162
node_modules/@hapi/shot/lib/response.js
generated
vendored
Executable file
162
node_modules/@hapi/shot/lib/response.js
generated
vendored
Executable file
@@ -0,0 +1,162 @@
|
||||
'use strict';
|
||||
|
||||
const Http = require('http');
|
||||
const Stream = require('stream');
|
||||
|
||||
const Hoek = require('@hapi/hoek');
|
||||
|
||||
const Symbols = require('./symbols');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
exports = module.exports = internals.Response = class extends Http.ServerResponse {
|
||||
|
||||
constructor(req, onEnd) {
|
||||
|
||||
super({ method: req.method, httpVersionMajor: 1, httpVersionMinor: 1 });
|
||||
this._shot = { headers: null, trailers: {}, payloadChunks: [] };
|
||||
this.assignSocket(internals.nullSocket());
|
||||
|
||||
this.socket.on('error', Hoek.ignore); // The socket can be destroyed with an error
|
||||
|
||||
if (req._shot.simulate.close) {
|
||||
// Ensure premature, manual close is forwarded to res.
|
||||
// In HttpServer the socket closing actually triggers close on both req and res.
|
||||
req.once('close', () => {
|
||||
|
||||
process.nextTick(() => this.destroy());
|
||||
});
|
||||
}
|
||||
|
||||
const finalize = (aborted) => {
|
||||
|
||||
const res = internals.payload(this);
|
||||
res.raw.req = req;
|
||||
if (aborted) {
|
||||
res.aborted = aborted;
|
||||
if (!this.headersSent) {
|
||||
res.statusCode = 499;
|
||||
}
|
||||
}
|
||||
|
||||
this.removeListener('close', abort);
|
||||
|
||||
process.nextTick(() => onEnd(res));
|
||||
};
|
||||
|
||||
const abort = () => finalize(true);
|
||||
|
||||
this.once('finish', finalize);
|
||||
|
||||
// Add fallback listener that will not be called if 'finish' is emitted first
|
||||
|
||||
this.on('close', abort);
|
||||
}
|
||||
|
||||
writeHead(...args) {
|
||||
|
||||
// Find the headers object if one was provided. If a headers object is present, call setHeader()
|
||||
// on the first valid header, and then break out of the loop and call writeHead(). By calling
|
||||
// setHeader(), Node will materialize a headers object.
|
||||
|
||||
const headers = args[args.length - 1];
|
||||
|
||||
if (typeof headers === 'object' && headers !== null) {
|
||||
const headerNames = Object.keys(headers);
|
||||
|
||||
for (let i = 0; i < headerNames.length; ++i) {
|
||||
const name = headerNames[i];
|
||||
|
||||
try {
|
||||
this.setHeader(name, headers[name]);
|
||||
break;
|
||||
}
|
||||
catch (ignoreErr) {} // Let the real writeHead() handle errors.
|
||||
}
|
||||
}
|
||||
|
||||
const result = super.writeHead(...args);
|
||||
|
||||
this._shot.headers = this.getHeaders();
|
||||
|
||||
// Add raw headers
|
||||
|
||||
['Date', 'Connection', 'Transfer-Encoding'].forEach((name) => {
|
||||
|
||||
const regex = new RegExp('\\r\\n' + name + ': ([^\\r]*)\\r\\n');
|
||||
const field = this._header.match(regex);
|
||||
if (field) {
|
||||
this._shot.headers[name.toLowerCase()] = field[1];
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
write(data, encoding, callback) {
|
||||
|
||||
super.write(data, encoding, callback);
|
||||
this._shot.payloadChunks.push(Buffer.from(data, encoding));
|
||||
return true; // Write always returns false when disconnected
|
||||
}
|
||||
|
||||
end(data, encoding, callback) {
|
||||
|
||||
if (data) {
|
||||
this.write(data, encoding);
|
||||
}
|
||||
|
||||
super.end(callback);
|
||||
this.emit('finish');
|
||||
}
|
||||
|
||||
addTrailers(trailers) {
|
||||
|
||||
for (const key in trailers) {
|
||||
this._shot.trailers[key.toLowerCase().trim()] = trailers[key].toString().trim();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
internals.Response.prototype[Symbols.injection] = true;
|
||||
|
||||
|
||||
internals.payload = function (response) {
|
||||
|
||||
// Prepare response object
|
||||
|
||||
const res = {
|
||||
raw: {
|
||||
res: response
|
||||
},
|
||||
headers: response._shot.headers,
|
||||
statusCode: response.statusCode,
|
||||
statusMessage: response.statusMessage,
|
||||
trailers: {}
|
||||
};
|
||||
|
||||
// Prepare payload and trailers
|
||||
|
||||
const rawBuffer = Buffer.concat(response._shot.payloadChunks);
|
||||
res.rawPayload = rawBuffer;
|
||||
res.payload = rawBuffer.toString();
|
||||
res.trailers = response._shot.trailers;
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
|
||||
// Throws away all written data to prevent response from buffering payload
|
||||
|
||||
internals.nullSocket = function () {
|
||||
|
||||
return new Stream.Writable({
|
||||
write(chunk, encoding, callback) {
|
||||
|
||||
setImmediate(callback);
|
||||
}
|
||||
});
|
||||
};
|
||||
6
node_modules/@hapi/shot/lib/symbols.js
generated
vendored
Executable file
6
node_modules/@hapi/shot/lib/symbols.js
generated
vendored
Executable file
@@ -0,0 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
exports.injection = Symbol('injection');
|
||||
Reference in New Issue
Block a user