UNPKG

@powership/server

Version:
260 lines (257 loc) 7.06 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.isHttpError = exports.HttpError = exports.BaseRequestHandler = exports.BaseRequest = void 0; var _utils = require("@powership/utils"); var _httpErrors = _interopRequireDefault(require("http-errors")); var _httpStatusCodes = require("http-status-codes"); var _qs = _interopRequireDefault(require("qs")); var _ServerLogs = require("./ServerLogs.cjs"); var _Symbol = require("./Symbol.cjs"); var _routeMatch = require("./routeMatch.cjs"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } const { HttpError, InternalServerError, isHttpError, PreconditionFailed } = _httpErrors.default; exports.isHttpError = isHttpError; exports.HttpError = HttpError; class BaseRequest { constructor(init) { this.replace(init); } replace = init => { this.input = init; const { // query, method, host, headers, pathname, port, urlObject } = this.parseInit(init); this.query = query; this.method = method; this.headers = headers; this.host = host; this.pathname = pathname; this.port = port; this.urlObject = urlObject; return this; }; parseInit = init => { const headers = BaseRequest.parseHeaders(init.headers); const host = headers.get('host') || 'UNKNOWN'; const method = (init.method || 'UNKNOWN').toUpperCase(); const urlObject = new URL(init.url || '', `http://${host}` // fixme get protocol ); const query = _qs.default.parse(urlObject.search); const pathname = urlObject.pathname; const port = urlObject.port; return { headers, host, method, query, pathname, port, urlObject }; }; static parseHeaders = input => { if (input === undefined) return new Headers(); if (input instanceof Headers) return input; if (input && typeof input === 'object') { const headers = new Headers(); Object.entries(input).forEach(([name, v]) => { // if (Array.isArray(v)) { v.forEach(el => { if (typeof el !== 'string') { throw new Error(`INVALID_HEADER_TYPE: ${typeof el}`); } headers.append(name, `${v}`); }); return; } switch (typeof v) { case 'boolean': case 'string': { headers.append(name, `${v}`); break; } default: { throw new Error(`INVALID_HEADER_TYPE: ${typeof v}`); } } }); return headers; } throw new Error('INVALID_HEADERS_CONFIG'); }; } exports.BaseRequest = BaseRequest; class BaseRequestHandler extends BaseRequest { constructor(input = {}) { super(input); const { body = _Symbol.UnhandledSymbol, headers, statusCode = 404 } = input; this.statusCode = statusCode; this.body = body; this.headers = BaseRequestHandler.parseHeaders(headers); } graphQLData() { const { data, errors } = this.graphQLResponse(); if (errors?.length) { throw new PreconditionFailed(errors.map(el => el.message).join('. ')); } return data; } graphQLResponse() { try { const response = BaseRequestHandler.jsonBody(this.body); const { errors, data } = response; if (!errors && !('data' in response)) { return { errors: [{ message: 'Empty response.', path: '' }], data: {} }; } return { errors, data }; } catch (e) { return { errors: [{ message: e.message, path: '' }], data: {} }; } } toHttpResponse = () => { return BaseRequestHandler.toHttp(this, 'RESPONSE'); }; toHttpRequest = () => { return BaseRequestHandler.toHttp(this, 'REQUEST'); }; /** * Return the matched routePattern parameters or null * if the route has no parameters, an empty object is returned * https://github.com/snd/url-pattern * @param routePattern */ testRoute = routePattern => { return BaseRequestHandler.createRouteMatcher(routePattern).match(this.urlObject.pathname.replace(/\/$/, '')); }; static createRouteMatcher(routePattern) { return (0, _routeMatch.createRouteMatcher)(routePattern); } static httpStatusCode(statusCode) { if (statusCode in _httpStatusCodes.StatusCodes) { if (statusCode?.toString().match(/^\d*$/)) { return +statusCode; } return +_httpStatusCodes.StatusCodes[statusCode]; } return _httpStatusCodes.StatusCodes.INTERNAL_SERVER_ERROR; } static httpResponseBody(body) { if (typeof body === 'string') return body; if (body === _Symbol.UnhandledSymbol) return ''; if (!body) return ''; if (isStream(body)) { return body; } if (typeof body === 'object') { try { return JSON.stringify(body); } catch (e) { _ServerLogs.ServerLogs.fatal(e); throw new InternalServerError(); } } return ''; } static jsonBody(body) { const constructorName = (0, _utils.getTypeName)(body); if (constructorName === 'String') { try { return JSON.parse(body); } catch (e) { console.error(`Failed to parse json.`); if (!(0, _utils.isProduction)()) { console.error((0, _utils.inspectObject)(e)); } } } if (constructorName === 'Object') { return body; } _ServerLogs.ServerLogs.fatal(`Invalid body`, (0, _utils.inspectObject)(body)); return {}; } static headersNamed(headers) { const parsed = BaseRequestHandler.parseHeaders(headers); // @ts-ignore return [...parsed.entries()].reduce((acc, [name, value]) => { return [...acc, { name, value }]; }, []); } static httpHeaders(headers) { return BaseRequestHandler.headersNamed(headers).reduce((acc, { name, value }) => ({ ...acc, [name]: value }), {}); } static toHttp(input, type) { const req = new BaseRequest(input); const { body: bodyInit } = input; const body = type === 'RESPONSE' ? this.httpResponseBody(bodyInit ?? _Symbol.UnhandledSymbol) : bodyInit === _Symbol.UnhandledSymbol ? '' : bodyInit ?? ''; return { body, streamBody: isStream(body) ? body : undefined, headers: this.httpHeaders(input.headers), statusCode: this.httpStatusCode(input.statusCode ?? 404), headersNamed: this.headersNamed(input.headers), payload: {}, method: req.method, query: req.query, type }; } } exports.BaseRequestHandler = BaseRequestHandler; function isStream(value) { return typeof value?.pipe === 'function' && typeof value?.abort === 'function' && typeof value?.on === 'function'; } //# sourceMappingURL=BaseRequestHandler.cjs.map