@vitrical/utils
Advanced tools
Comparing version 1.0.5 to 1.0.6
118
api.js
@@ -49,67 +49,61 @@ "use strict"; | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
exports.__esModule = true; | ||
exports.formRequest = exports.jsonRequest = exports.request = void 0; | ||
exports.isApiError = exports.requestImplementation = void 0; | ||
var superagent_1 = __importDefault(require("superagent")); | ||
var validation_1 = require("./validation"); | ||
var request = function (options) { return __awaiter(void 0, void 0, void 0, function () { | ||
var method, url, data, headers, res, returnHeaders, resData, contentType, returnData; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
method = options.method, url = options.url, data = options.data, headers = options.headers; | ||
return [4, fetch(url, { | ||
method: method, | ||
body: typeof data === 'object' ? JSON.stringify(data) : data, | ||
headers: __assign({}, headers) | ||
})]; | ||
case 1: | ||
res = _a.sent(); | ||
returnHeaders = res.headers; | ||
resData = {}; | ||
contentType = res.headers.get('Content-Type'); | ||
if (!(contentType === null || contentType === void 0 ? void 0 : contentType.includes('application/json'))) return [3, 3]; | ||
return [4, res.json()]; | ||
case 2: | ||
resData = _a.sent(); | ||
return [3, 5]; | ||
case 3: return [4, res.text()]; | ||
case 4: | ||
resData = _a.sent(); | ||
_a.label = 5; | ||
case 5: | ||
returnData = { | ||
status: res.status, | ||
data: resData, | ||
headers: returnHeaders | ||
}; | ||
if (res.status !== 200) { | ||
throw __assign(__assign({}, returnData), { stack: new Error().stack, message: (0, validation_1.objectHasProperty)(resData, 'msg') | ||
? resData.msg | ||
: (0, validation_1.objectHasProperty)(resData, 'message') | ||
? resData.message | ||
: "Request failed with status code ".concat(res.status) }); | ||
} | ||
return [2, returnData]; | ||
} | ||
}); | ||
}); }; | ||
exports.request = request; | ||
var jsonRequest = function (options) { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) { | ||
return [2, (0, exports.request)(__assign(__assign({}, options), { headers: __assign({ 'Content-Type': 'application/json' }, options.headers) }))]; | ||
var requestImplementation = function (agent) { | ||
return function (baseURL, key, method, url, options) { return __awaiter(void 0, void 0, void 0, function () { | ||
var req, res, returnData, error; | ||
var _a; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
req = agent(method, baseURL + url); | ||
req.set('Key', key); | ||
if (options === null || options === void 0 ? void 0 : options.headers) { | ||
req.set(options.headers); | ||
} | ||
if (options === null || options === void 0 ? void 0 : options.body) { | ||
req.set(options.body); | ||
} | ||
if (options === null || options === void 0 ? void 0 : options.query) { | ||
req.query(options.query); | ||
} | ||
return [4, req]; | ||
case 1: | ||
res = _b.sent(); | ||
returnData = { | ||
status: res.status, | ||
body: res.body, | ||
headers: res.headers | ||
}; | ||
if (res.status !== 200) { | ||
error = __assign(__assign({}, returnData), { stack: new Error().stack, message: ((_a = res.body) === null || _a === void 0 ? void 0 : _a.msg) || "Request failed with status code ".concat(res.status) }); | ||
throw error; | ||
} | ||
return [2, returnData]; | ||
} | ||
}); | ||
}); }; | ||
}; | ||
exports.requestImplementation = requestImplementation; | ||
var request = function (baseURL, key, method, url, options) { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) { | ||
return [2, (0, exports.requestImplementation)(superagent_1["default"])(baseURL, key, method, url, options)]; | ||
}); }); }; | ||
exports.jsonRequest = jsonRequest; | ||
var formRequest = function (options) { return __awaiter(void 0, void 0, void 0, function () { | ||
var formBody; | ||
return __generator(this, function (_a) { | ||
formBody = options.data | ||
? Object.entries(options.data) | ||
.map(function (_a) { | ||
var key = _a[0], value = _a[1]; | ||
return "".concat(encodeURIComponent(key), "=").concat(encodeURIComponent("".concat(value))); | ||
}) | ||
.join('&') | ||
: undefined; | ||
return [2, (0, exports.request)(__assign(__assign({}, options), { headers: __assign({ 'Content-Type': 'application/x-www-urlencoded' }, options.headers), data: formBody }))]; | ||
}); | ||
}); }; | ||
exports.formRequest = formRequest; | ||
exports["default"] = request; | ||
var isApiError = function (err) { | ||
if (typeof err !== 'object' || !err) | ||
return false; | ||
if (!(0, validation_1.objectHasProperty)(err, 'message') || typeof err.message !== 'string') | ||
return false; | ||
if (!(0, validation_1.objectHasProperty)(err, 'body') || typeof err.body !== 'object') | ||
return false; | ||
if (!(0, validation_1.objectHasProperty)(err, 'status') || typeof err.status !== 'number') | ||
return false; | ||
return true; | ||
}; | ||
exports.isApiError = isApiError; | ||
//# sourceMappingURL=api.js.map |
160
api.ts
@@ -0,114 +1,78 @@ | ||
import superagent from 'superagent' | ||
import { objectHasProperty } from './validation' | ||
export type DataMethod = 'POST' | 'DELETE' | 'PUT' | 'CONNECT' | 'OPTIONS' | 'TRACE' | 'PATCH' | ||
export type NoDataMethod = 'GET' | 'HEAD' | ||
export type RequestHeaders = { | ||
[key: string]: string | ||
export type CustomRequestOptions = { | ||
body?: { [key: string]: any } | ||
query?: string | { [key: string]: any } | ||
headers?: { [key: string]: any } | ||
} | ||
export type JSONRequestData = { | ||
[key: string]: any | ||
export type CustomRequestResponse = { | ||
status: superagent.Response['status'] | ||
body: superagent.Response['body'] | ||
headers: superagent.Response['headers'] | ||
} | ||
export type RequiredRequestOptions = { | ||
url: string | ||
method: DataMethod | NoDataMethod | ||
headers?: RequestHeaders | ||
export type CustomRequestError = CustomRequestResponse & { | ||
stack: string | ||
message: string | ||
} | ||
export type RequestOptions = RequiredRequestOptions & | ||
( | ||
| { | ||
method: DataMethod | ||
data?: any | ||
} | ||
| { | ||
method: NoDataMethod | ||
data?: never | ||
} | ||
) | ||
export const requestImplementation = | ||
(agent: (m: string, url: string) => any) => | ||
async ( | ||
baseURL: string, | ||
key: string, | ||
method: 'get' | 'post' | 'put' | 'delete', | ||
url: string, | ||
options?: CustomRequestOptions | ||
): Promise<CustomRequestResponse> => { | ||
const req = agent(method, baseURL + url) | ||
req.set('Key', key) | ||
if (options?.headers) { | ||
req.set(options.headers) | ||
} | ||
if (options?.body) { | ||
req.set(options.body) | ||
} | ||
if (options?.query) { | ||
req.query(options.query) | ||
} | ||
const res = await req | ||
export type RequestResponse = { | ||
status: number | ||
headers: Headers | ||
data: JSONRequestData | string | ||
} | ||
const returnData = { | ||
status: res.status, | ||
body: res.body, | ||
headers: res.headers, | ||
} | ||
export const request = async (options: RequestOptions): Promise<RequestResponse> => { | ||
const { method, url, data, headers } = options | ||
if (res.status !== 200) { | ||
const error: CustomRequestError = { | ||
...returnData, | ||
stack: new Error().stack, | ||
message: res.body?.msg || `Request failed with status code ${res.status}`, | ||
} | ||
throw error | ||
} | ||
const res = await fetch(url, { | ||
method, | ||
body: typeof data === 'object' ? JSON.stringify(data) : data, | ||
headers: { | ||
...headers, | ||
}, | ||
}) | ||
let returnHeaders: Headers = res.headers | ||
let resData: string | { [key: string]: any } = {} | ||
const contentType = res.headers.get('Content-Type') | ||
if (contentType?.includes('application/json')) { | ||
resData = await res.json() | ||
} else { | ||
resData = await res.text() | ||
return returnData | ||
} | ||
const returnData = { | ||
status: res.status, | ||
data: resData, | ||
headers: returnHeaders, | ||
} | ||
const request = async ( | ||
baseURL: string, | ||
key: string, | ||
method: 'get' | 'post' | 'put' | 'delete', | ||
url: string, | ||
options?: CustomRequestOptions | ||
): Promise<CustomRequestResponse> => | ||
requestImplementation(superagent)(baseURL, key, method, url, options) | ||
if (res.status !== 200) { | ||
throw { | ||
...returnData, | ||
stack: new Error().stack, | ||
message: objectHasProperty(resData, 'msg') | ||
? resData.msg | ||
: objectHasProperty(resData, 'message') | ||
? resData.message | ||
: `Request failed with status code ${res.status}`, | ||
} | ||
} | ||
export default request | ||
return returnData | ||
export const isApiError = (err: unknown): err is CustomRequestError => { | ||
if (typeof err !== 'object' || !err) return false | ||
if (!objectHasProperty(err, 'message') || typeof err.message !== 'string') return false | ||
if (!objectHasProperty(err, 'body') || typeof err.body !== 'object') return false | ||
if (!objectHasProperty(err, 'status') || typeof err.status !== 'number') return false | ||
return true | ||
} | ||
export type JSONRequestOptions = | ||
| (RequestOptions & { | ||
method: NoDataMethod | ||
data?: never | ||
}) | ||
| (RequestOptions & { | ||
method: DataMethod | ||
data?: JSONRequestData | ||
}) | ||
export const jsonRequest = async (options: JSONRequestOptions): Promise<RequestResponse> => | ||
request({ ...options, headers: { 'Content-Type': 'application/json', ...options.headers } }) | ||
export type FormRequestOptions = RequestOptions & { | ||
method: DataMethod | ||
data: { | ||
[key: string]: string | number | boolean | ||
} | ||
} | ||
export const formRequest = async (options: FormRequestOptions): Promise<RequestResponse> => { | ||
const formBody = options.data | ||
? Object.entries(options.data) | ||
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(`${value}`)}`) | ||
.join('&') | ||
: undefined | ||
return request({ | ||
...options, | ||
headers: { 'Content-Type': 'application/x-www-urlencoded', ...options.headers }, | ||
data: formBody, | ||
}) | ||
} |
import { Request, Response, NextFunction } from 'express' | ||
import { isApiError, objectHasProperty, validateObject, ValidateObjectOptions } from './validation' | ||
import { objectHasProperty, validateObject, ValidateObjectOptions } from './validation' | ||
import { isApiError } from './api' | ||
@@ -11,20 +12,21 @@ export const handleExpressError = ( | ||
if (!err) return next() | ||
if (!objectHasProperty(err, 'message') || !objectHasProperty(err, 'stack')) { | ||
res.status(isApiError(err) ? err.status : 500).send({ | ||
msg: 'Unknown Error', | ||
data: err, | ||
}) | ||
return | ||
} | ||
console.warn(err.message) | ||
console.warn(err.stack) | ||
if (isApiError(err)) { | ||
res.status(err.status || 500).send({ | ||
console.warn(err.message) | ||
console.warn(err.stack) | ||
res.status(err.status).send({ | ||
msg: err.message, | ||
data: err.data, | ||
body: err.body, | ||
}) | ||
} else { | ||
} else if (objectHasProperty(err, 'message')) { | ||
console.error(err.message) | ||
console.error(err.stack) | ||
res.status(500).send({ | ||
msg: err.message, | ||
}) | ||
} else { | ||
console.error(err) | ||
res.status(isApiError(err) ? err.status : 500).send({ | ||
msg: 'Unknown Error', | ||
err, | ||
}) | ||
} | ||
@@ -49,3 +51,3 @@ } | ||
export const validateBody = | ||
(schema: ValidateObjectOptions) => (req: Request, res: Response, next: NextFunction) => { | ||
(schema: ValidateObjectOptions) => (req: Request, _res: Response, next: NextFunction) => { | ||
const errors = validateObject(schema, req.body) | ||
@@ -52,0 +54,0 @@ if (errors.length === 0) { |
@@ -20,2 +20,3 @@ "use strict"; | ||
__exportStar(require("./validation"), exports); | ||
__exportStar(require("./express"), exports); | ||
//# sourceMappingURL=index.js.map |
export * from './api' | ||
export * from './jwt' | ||
export * from './validation' | ||
export * from './express' |
{ | ||
"name": "@vitrical/utils", | ||
"version": "1.0.5", | ||
"version": "1.0.6", | ||
"description": "Collection of useful functions and typings", | ||
@@ -22,2 +22,3 @@ "main": "index.js", | ||
"jsonwebtoken": "^9.0.0", | ||
"superagent": "^8.0.9", | ||
"typescript": "^4.9.5" | ||
@@ -28,4 +29,5 @@ }, | ||
"@types/jsonwebtoken": "^9.0.1", | ||
"@types/superagent": "^4.1.16", | ||
"ts-node": "^10.9.1" | ||
} | ||
} |
@@ -12,3 +12,3 @@ "use strict"; | ||
exports.__esModule = true; | ||
exports.objectMatchesSchema = exports.validateObject = exports.isValidationType = exports.getSeason = exports.capitalize = exports.isValidNAPhoneNumber = exports.formatPhoneNumber = exports.isValidEmail = exports.removeSpaces = exports.removeSpecialCharacters = exports.isApiError = exports.objectHasProperty = void 0; | ||
exports.objectMatchesSchema = exports.validateObject = exports.isValidationType = exports.getSeason = exports.capitalize = exports.isValidNAPhoneNumber = exports.formatPhoneNumber = exports.isValidEmail = exports.removeSpaces = exports.removeSpecialCharacters = exports.objectHasProperty = void 0; | ||
var objectHasProperty = function (obj, property) { | ||
@@ -18,14 +18,2 @@ return !!obj && typeof obj === 'object' && property in obj; | ||
exports.objectHasProperty = objectHasProperty; | ||
var isApiError = function (err) { | ||
if (typeof err !== 'object' || !err) | ||
return false; | ||
if (!(0, exports.objectHasProperty)(err, 'message') || typeof err.message !== 'string') | ||
return false; | ||
if (!(0, exports.objectHasProperty)(err, 'data') || typeof err.data !== 'object') | ||
return false; | ||
if (!(0, exports.objectHasProperty)(err, 'status') || typeof err.status !== 'number') | ||
return false; | ||
return true; | ||
}; | ||
exports.isApiError = isApiError; | ||
var removeSpecialCharacters = function (string) { | ||
@@ -32,0 +20,0 @@ return string.replace(/[^a-zA-Z0-9 ]/g, ''); |
@@ -8,19 +8,2 @@ export const objectHasProperty = ( | ||
export type HttpRequestError = { | ||
message: string | ||
status: number | ||
data: { [key: string]: unknown } | ||
headers: { [key: string]: unknown } | ||
stack: string | ||
} | ||
/** ApiError typeguard */ | ||
export const isApiError = (err: unknown): err is HttpRequestError => { | ||
if (typeof err !== 'object' || !err) return false | ||
if (!objectHasProperty(err, 'message') || typeof err.message !== 'string') return false | ||
if (!objectHasProperty(err, 'data') || typeof err.data !== 'object') return false | ||
if (!objectHasProperty(err, 'status') || typeof err.status !== 'number') return false | ||
return true | ||
} | ||
/* Removes the special characters in a string */ | ||
@@ -27,0 +10,0 @@ export const removeSpecialCharacters = (string: string): string => { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
48838
20
880
0
3
4
+ Addedsuperagent@^8.0.9
+ Addedasap@2.0.6(transitive)
+ Addedasynckit@0.4.0(transitive)
+ Addedcall-bind@1.0.7(transitive)
+ Addedcombined-stream@1.0.8(transitive)
+ Addedcomponent-emitter@1.3.1(transitive)
+ Addedcookiejar@2.1.4(transitive)
+ Addeddebug@4.3.7(transitive)
+ Addeddefine-data-property@1.1.4(transitive)
+ Addeddelayed-stream@1.0.0(transitive)
+ Addeddezalgo@1.0.4(transitive)
+ Addedes-define-property@1.0.0(transitive)
+ Addedes-errors@1.3.0(transitive)
+ Addedfast-safe-stringify@2.1.1(transitive)
+ Addedform-data@4.0.0(transitive)
+ Addedformidable@2.1.2(transitive)
+ Addedfunction-bind@1.1.2(transitive)
+ Addedget-intrinsic@1.2.4(transitive)
+ Addedgopd@1.0.1(transitive)
+ Addedhas-property-descriptors@1.0.2(transitive)
+ Addedhas-proto@1.0.3(transitive)
+ Addedhas-symbols@1.0.3(transitive)
+ Addedhasown@2.0.2(transitive)
+ Addedhexoid@1.0.0(transitive)
+ Addedmethods@1.1.2(transitive)
+ Addedmime@2.6.0(transitive)
+ Addedmime-db@1.52.0(transitive)
+ Addedmime-types@2.1.35(transitive)
+ Addedobject-inspect@1.13.2(transitive)
+ Addedonce@1.4.0(transitive)
+ Addedqs@6.13.0(transitive)
+ Addedset-function-length@1.2.2(transitive)
+ Addedside-channel@1.0.6(transitive)
+ Addedsuperagent@8.1.2(transitive)
+ Addedwrappy@1.0.2(transitive)