This commit is contained in:
2026-03-03 15:23:00 +00:00
parent 5e3726de39
commit 8e223bfbec
3689 changed files with 955330 additions and 1011 deletions

10
node_modules/@hapi/shot/LICENSE.md generated vendored Executable file
View File

@@ -0,0 +1,10 @@
Copyright (c) 2012-2021, Sideway Inc, and project contributors
Copyright (c) 2012-2014, Walmart.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* The names of any contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS OFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

17
node_modules/@hapi/shot/README.md generated vendored Executable file
View File

@@ -0,0 +1,17 @@
<a href="https://hapi.dev"><img src="https://raw.githubusercontent.com/hapijs/assets/master/images/family.png" width="180px" align="right" /></a>
# @hapi/shot
#### Injects a fake HTTP request/response into your node server logic.
**shot** is part of the **hapi** ecosystem and was designed to work seamlessly with the [hapi web framework](https://hapi.dev) and its other components (but works great on its own or with other frameworks). If you are using a different web framework and find this module useful, check out [hapi](https://hapi.dev) they work even better together.
### Visit the [hapi.dev](https://hapi.dev) Developer Portal for tutorials, documentation, and support
## Useful resources
- [Documentation and API](https://hapi.dev/family/shot/)
- [Versions status](https://hapi.dev/resources/status/#shot) (builds, dependencies, node versions, licenses, eol)
- [Changelog](https://hapi.dev/family/shot/changelog/)
- [Project policies](https://hapi.dev/policies/)
- [Free and commercial support options](https://hapi.dev/support/)

186
node_modules/@hapi/shot/lib/index.d.ts generated vendored Normal file
View 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
View 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
View 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
View 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
View File

@@ -0,0 +1,6 @@
'use strict';
const internals = {};
exports.injection = Symbol('injection');

38
node_modules/@hapi/shot/package.json generated vendored Normal file
View File

@@ -0,0 +1,38 @@
{
"name": "@hapi/shot",
"description": "Injects a fake HTTP request/response into a node HTTP server",
"version": "6.0.2",
"repository": "git://github.com/hapijs/shot",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"files": [
"lib"
],
"keywords": [
"utilities",
"http",
"debug",
"test"
],
"eslintConfig": {
"extends": [
"plugin:@hapi/module"
]
},
"dependencies": {
"@hapi/hoek": "^11.0.2",
"@hapi/validate": "^2.0.1"
},
"devDependencies": {
"@hapi/code": "^9.0.3",
"@hapi/eslint-plugin": "^6.0.0",
"@hapi/lab": "^25.1.2",
"@types/node": "^17.0.31",
"typescript": "~4.6.4"
},
"scripts": {
"test": "lab -a @hapi/code -t 100 -L -Y",
"test-cov-html": "lab -a @hapi/code -r html -o coverage.html -L"
},
"license": "BSD-3-Clause"
}