├── .gitignore ├── images └── lightfetch.png ├── prettier.config.cjs ├── eslint.config.cjs ├── src ├── index.js └── utils │ ├── cookieParser.js │ └── request.js ├── rollup.config.cjs ├── tests ├── esm.test.mjs └── common.test.cjs ├── LICENSE ├── package.json ├── CONTRIBUTING.md ├── README.md ├── dist ├── lightfetch.mjs └── lightfetch.cjs └── CODE_OF_CONDUCT.md /.gitignore: -------------------------------------------------------------------------------- 1 | # npm 2 | node_modules/ 3 | 4 | # replit 5 | .replit 6 | replit.nix -------------------------------------------------------------------------------- /images/lightfetch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rayhanadev/lightfetch/HEAD/images/lightfetch.png -------------------------------------------------------------------------------- /prettier.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | trailingComma: 'all', 3 | useTabs: true, 4 | tabWidth: 4, 5 | singleQuote: true, 6 | embeddedLanguageFormatting: 'off', 7 | }; 8 | -------------------------------------------------------------------------------- /eslint.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | es2021: true, 4 | node: true, 5 | }, 6 | extends: 'eslint:recommended', 7 | parserOptions: { 8 | ecmaVersion: 12, 9 | sourceType: 'module', 10 | }, 11 | rules: {}, 12 | }; 13 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import requestFunc from './utils/request.js'; 2 | 3 | export const lightfetch = async (url, options = { method: 'GET' }) => { 4 | const { method, headers, body } = options; 5 | return requestFunc(method, url, headers, body); 6 | }; 7 | -------------------------------------------------------------------------------- /rollup.config.cjs: -------------------------------------------------------------------------------- 1 | const { builtinModules } = require('module'); 2 | 3 | module.exports = { 4 | input: 'src/index.js', 5 | output: [ 6 | { 7 | file: 'dist/lightfetch.cjs', 8 | format: 'cjs', 9 | preferConst: true, 10 | }, 11 | { 12 | file: 'dist/lightfetch.mjs', 13 | format: 'esm', 14 | preferConst: true, 15 | }, 16 | ], 17 | external: [...builtinModules], 18 | }; 19 | -------------------------------------------------------------------------------- /tests/esm.test.mjs: -------------------------------------------------------------------------------- 1 | import { lightfetch } from '../dist/lightfetch.mjs'; 2 | 3 | (async function () { 4 | console.log('ESM Test. URL: https://postman-echo.com/get?foo=bar.'); 5 | const getResponse = await lightfetch( 6 | 'https://postman-echo.com/get?foo=bar', 7 | { 8 | method: 'GET', 9 | headers: { 10 | 'X-Requested-With': 'RayhanADev', 11 | }, 12 | }, 13 | ); 14 | console.log('Status:', getResponse.status); 15 | console.log('Response:', getResponse.toJSON()); 16 | console.log('Cookies:', getResponse.cookies); 17 | console.log('---'); 18 | console.log('ESM Test. URL: https://postman-echo.com/post.'); 19 | const postResponse = await lightfetch( 20 | 'https://postman-echo.com/post?foo=bar', 21 | { 22 | method: 'POST', 23 | headers: { 24 | 'X-Requested-With': 'RayhanADev', 25 | }, 26 | body: { foo: 'bar', x: 'y' }, 27 | }, 28 | ); 29 | console.log('Status:', postResponse.status); 30 | console.log('Response:', postResponse.toJSON()); 31 | console.log('Cookies:', postResponse.cookies); 32 | console.log('---'); 33 | })(lightfetch); 34 | -------------------------------------------------------------------------------- /tests/common.test.cjs: -------------------------------------------------------------------------------- 1 | const { lightfetch } = require('../dist/lightfetch.cjs'); 2 | 3 | (async function () { 4 | console.log('CommonJS Test. URL: https://postman-echo.com/get?foo=bar.'); 5 | const getResponse = await lightfetch( 6 | 'https://postman-echo.com/get?foo=bar', 7 | { 8 | method: 'GET', 9 | headers: { 10 | 'X-Requested-With': 'RayhanADev', 11 | }, 12 | }, 13 | ); 14 | console.log('Status:', getResponse.status); 15 | console.log('Response:', getResponse.toJSON()); 16 | console.log('Cookies:', getResponse.cookies); 17 | console.log('---'); 18 | console.log('CommonJS Test. URL: https://postman-echo.com/post.'); 19 | const postResponse = await lightfetch( 20 | 'https://postman-echo.com/post?foo=bar', 21 | { 22 | method: 'POST', 23 | headers: { 24 | 'X-Requested-With': 'RayhanADev', 25 | }, 26 | body: { foo: 'bar', x: 'y' }, 27 | }, 28 | ); 29 | console.log('Status:', postResponse.status); 30 | console.log('Response:', postResponse.toJSON()); 31 | console.log('Cookies:', postResponse.cookies); 32 | console.log('---'); 33 | })(lightfetch); 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Ray Arayilakath 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/utils/cookieParser.js: -------------------------------------------------------------------------------- 1 | const parseCookieString = (cookieValue) => { 2 | const parts = cookieValue 3 | .split(';') 4 | .filter((str) => typeof str === 'string' && !!str.trim()); 5 | const item = parts.shift().split('='); 6 | const name = item.shift(); 7 | const value = decodeURIComponent(item.join('=')); 8 | 9 | const cookie = { 10 | name: name, 11 | value: value, 12 | }; 13 | 14 | parts.forEach((part) => { 15 | const args = part.split('='); 16 | const key = args.shift().trimLeft().toLowerCase(); 17 | const value = args.join('='); 18 | switch (key) { 19 | case 'path': { 20 | cookie['Path'] = value; 21 | break; 22 | } 23 | case 'expires': { 24 | cookie['Expires'] = new Date(value); 25 | break; 26 | } 27 | case 'max-age': { 28 | cookie['Max-Age'] = parseInt(value, 10); 29 | break; 30 | } 31 | case 'secure': { 32 | cookie['Secure'] = true; 33 | break; 34 | } 35 | case 'httponly': { 36 | cookie['HttpOnly'] = true; 37 | break; 38 | } 39 | case 'samesite': { 40 | cookie['SameSite'] = value; 41 | break; 42 | } 43 | default: { 44 | cookie[key] = value; 45 | } 46 | } 47 | }); 48 | 49 | return cookie; 50 | }; 51 | 52 | const parseCookie = ({ headers: { 'set-cookie': input } }) => { 53 | if (!Array.isArray(input)) input = [input]; 54 | 55 | const cookies = {}; 56 | return input 57 | .filter((str) => typeof str === 'string' && !!str.trim()) 58 | .reduce((cookies, str) => { 59 | const cookie = parseCookieString(str); 60 | cookies[cookie.name] = cookie; 61 | return cookies; 62 | }, cookies); 63 | }; 64 | 65 | export default parseCookie; 66 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lightfetch-node", 3 | "version": "1.1.1", 4 | "description": "Zero dependencies, lightweight, and asynchronous requests package.", 5 | "sideEffects": false, 6 | "type": "module", 7 | "main": "./dist/lightfetch.cjs", 8 | "module": "./dist/lightfetch.mjs", 9 | "exports": { 10 | ".": { 11 | "import": "./dist/lightfetch.mjs", 12 | "require": "./dist/lightfetch.cjs", 13 | "default": "./dist/lightfetch.cjs" 14 | } 15 | }, 16 | "files": [ 17 | "dist" 18 | ], 19 | "scripts": { 20 | "test": "node tests/common.test.cjs && node tests/esm.test.mjs", 21 | "test:cjs": "node tests/common.test.cjs", 22 | "test:mjs": "node tests/esm.test.mjs", 23 | "lint": "eslint src --config ./eslint.config.cjs --ext .js", 24 | "lint:fix": "eslint src --config ./eslint.config.cjs --ext .js --fix", 25 | "format": "prettier --check .", 26 | "format:fix": "prettier --write .", 27 | "build": "rimraf ./dist/** && rollup --config", 28 | "build:cjs": "rimraf ./dist/lightfetch.cjs && rollup src/index.js --file dist/lightfetch.cjs --format cjs", 29 | "build:mjs": "rimraf ./dist/lightfetch.mjs && rollup src/index.js --file dist/lightfetch.mjs --format esm" 30 | }, 31 | "repository": { 32 | "type": "git", 33 | "url": "https://github.com/RayhanADev/lightfetch.git" 34 | }, 35 | "keywords": [ 36 | "fetch", 37 | "https", 38 | "async", 39 | "request" 40 | ], 41 | "author": "Ray Arayilakath (https://rayhanadev.vercel.app)", 42 | "license": "MIT", 43 | "bugs": { 44 | "url": "https://github.com/RayhanADev/lightfetch/issues" 45 | }, 46 | "homepage": "https://github.com/RayhanADev/lightfetch", 47 | "devDependencies": { 48 | "eslint": "^7.28.0", 49 | "prettier": "^2.3.1", 50 | "rimraf": "^3.0.2", 51 | "rollup": "^2.51.2" 52 | }, 53 | "dependencies": {} 54 | } 55 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | When contributing to this repository, please first discuss the change you wish to make via issue, email, or any other method with the owners of this repository before making a change. 4 | 5 | Please note the following: 6 | 7 | - We have a code of conduct, please follow it in all your interactions with the project. 8 | - We use 'eslint' and 'prettier' to lint and format our code respectively. We have included scripts and configuration files to help you maintain similar code: 9 | ```sh 10 | $ npm run lint:fix 11 | $ npm run format:fix 12 | ``` 13 | please run these before building. 14 | - We use 'reollup' to bundle our ESM code to ESM and CommonJS compatible distributions. We have included scripts and configuration files to help you build similar code: 15 | ```sh 16 | $ npm run build 17 | ``` 18 | please run this before submitting a pull request. 19 | - We follow the 'Conventional Commits' commit convention. If your pull request does not adhere to the convention, it will not be merged. 20 | 21 | ## Pull Request Process 22 | 23 | 1. Complete a quick code review for your code, you might catch any errors before you submit. 24 | 2. Make sure your pull request uses the most recent version of the code. 25 | 3. Ensure any dependencies match with current dependencies or have essential dependencies. 26 | 4. Update the README.md with changes if necessary. This includes any major changes to the features, usage of the package, etc. 27 | 5. Increase the version numbers in any examples files and the README.md to the new version that this Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/). 28 | 6. You may merge the Pull Request in once you have the approval of repository maintainer or owner, or if you do not have permission to do that, you may request a reviewer to merge it for you. 29 | -------------------------------------------------------------------------------- /src/utils/request.js: -------------------------------------------------------------------------------- 1 | import { request as req } from 'https'; 2 | import parseCookie from './cookieParser.js'; 3 | 4 | const requestFunc = (method, url, headers = {}, body) => { 5 | const urlPieces = new URL(url); 6 | const formRegex = /^(([\w\s.])+=([\w\s.])+&?)+/; 7 | 8 | let requestSafeBody = ''; 9 | if (method.toLowerCase() !== 'get' && !headers['Content-Type']) { 10 | if (typeof body === 'object') { 11 | headers['Content-Type'] = 'application/json'; 12 | requestSafeBody = JSON.stringify(body); 13 | } else if ( 14 | typeof body === 'string' && 15 | formRegex.test(decodeURI(body)) 16 | ) { 17 | headers['Content-Type'] = 'application/x-www-form-urlencoded'; 18 | requestSafeBody = body; 19 | } else { 20 | headers['Content-Type'] = 'text/plain'; 21 | requestSafeBody = body; 22 | } 23 | } 24 | 25 | if (method.toLowerCase() !== 'get') 26 | headers['Content-Length'] = Buffer.byteLength(requestSafeBody); 27 | 28 | const requestOptions = { 29 | hostname: urlPieces.host, 30 | port: urlPieces.port || 443, 31 | path: urlPieces.pathname + urlPieces.search, 32 | method: method.toUpperCase(), 33 | headers, 34 | }; 35 | 36 | const requestPromise = new Promise((resolve, reject) => { 37 | const request = req(requestOptions, (response) => { 38 | let responseData = ''; 39 | 40 | response.on('data', (dataBuffer) => { 41 | responseData += dataBuffer; 42 | }); 43 | 44 | response.on('end', () => { 45 | const returnable = { 46 | response, 47 | cookies: parseCookie(response), 48 | status: response.statusCode, 49 | headers: { 50 | ...response.headers, 51 | get: (header) => response.headers[header.toLowerCase()], 52 | }, 53 | json: () => { 54 | try { 55 | return JSON.parse(responseData); 56 | } catch (error) { 57 | throw new Error(error); 58 | } 59 | }, 60 | text: () => { 61 | try { 62 | return responseData; 63 | } catch (error) { 64 | throw new Error(error); 65 | } 66 | }, 67 | }; 68 | resolve(returnable); 69 | }); 70 | }); 71 | 72 | request.on('error', (error) => { 73 | reject(error); 74 | }); 75 | 76 | if (method.toLowerCase() !== 'get') request.write(requestSafeBody); 77 | request.end(); 78 | }); 79 | return requestPromise; 80 | }; 81 | 82 | export default requestFunc; 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > This project is a **Work in Progress** and currently in development. The API is 2 | > subject to change without warning. 3 | 4 |
5 | 6 | Lightfetch Banner 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |

17 | A small fetching package for super simple usages. 18 |
19 | Built using zero dependencies to be lightweight 20 | and asynchronous. 21 |
22 | Lightfetch gives you the best of size, speed, and usability. 23 |

24 |
25 | 26 | --- 27 | 28 | ## Install 29 | 30 | ```sh 31 | npm install lightfetch-node 32 | ``` 33 | 34 | ## Usage 35 | 36 | ### Main API 37 | 38 | ```js 39 | await lightfetch(url, [options]); 40 | ``` 41 | 42 | which returns a [``](#response) 43 | 44 | ### Options 45 | 46 | - method: HTTP Request Method 47 | - headers: HTTP Headers to use in Request 48 | - body: Data to use in the Request\* 49 | 50 | \* _Data that can be used in body includes an Object, a string that's 51 | in x-www-form-urlencoded format, or plain text. Lightfetch will figure 52 | out what you pass in automagically and set the appropriate headers._ 53 | 54 | ### Response 55 | 56 | The items in a response include: 57 | 58 | - `.status`: The status code of a response 59 | - `.headers`: The headers in a response 60 | - `.cookies`: The cookies in a response (uses an API similar to [this](https://github.com/nfriedly/set-cookie-parser) internally) 61 | - `.json`: A function to parse the content of a response to JSON 62 | - `.text`: A function to parse the content of a response to text 63 | 64 | > If the above does not statisfy your needs, you can also use `.response` 65 | > to access the unmodified, raw response NodeJS outputs. 66 | 67 | ## Example 68 | 69 | ```js 70 | // using CommonJS 71 | const { lightfetch } = require('lightfetch-node'); 72 | 73 | // using ESM 74 | import { lightfetch } from 'lightfetch-node'; 75 | 76 | async function fetch(url) { 77 | const res = await lightfetch(url, { 78 | method: 'GET', 79 | headers: { 80 | 'X-Requested-With': 'RayhanADev', 81 | }, 82 | }); 83 | console.log('Status:', res.status); 84 | console.log('Response:', res.toJSON()); 85 | console.log('Cookies:', res.cookies); 86 | } 87 | 88 | fetch('https://postman-echo.com/get?foo=bar'); 89 | ``` 90 | -------------------------------------------------------------------------------- /dist/lightfetch.mjs: -------------------------------------------------------------------------------- 1 | import { request } from 'https'; 2 | 3 | const parseCookieString = (cookieValue) => { 4 | const parts = cookieValue 5 | .split(';') 6 | .filter((str) => typeof str === 'string' && !!str.trim()); 7 | const item = parts.shift().split('='); 8 | const name = item.shift(); 9 | const value = decodeURIComponent(item.join('=')); 10 | 11 | const cookie = { 12 | name: name, 13 | value: value, 14 | }; 15 | 16 | parts.forEach((part) => { 17 | const args = part.split('='); 18 | const key = args.shift().trimLeft().toLowerCase(); 19 | const value = args.join('='); 20 | switch (key) { 21 | case 'path': { 22 | cookie['Path'] = value; 23 | break; 24 | } 25 | case 'expires': { 26 | cookie['Expires'] = new Date(value); 27 | break; 28 | } 29 | case 'max-age': { 30 | cookie['Max-Age'] = parseInt(value, 10); 31 | break; 32 | } 33 | case 'secure': { 34 | cookie['Secure'] = true; 35 | break; 36 | } 37 | case 'httponly': { 38 | cookie['HttpOnly'] = true; 39 | break; 40 | } 41 | case 'samesite': { 42 | cookie['SameSite'] = value; 43 | break; 44 | } 45 | default: { 46 | cookie[key] = value; 47 | } 48 | } 49 | }); 50 | 51 | return cookie; 52 | }; 53 | 54 | const parseCookie = ({ headers: { 'set-cookie': input } }) => { 55 | if (!Array.isArray(input)) input = [input]; 56 | 57 | const cookies = {}; 58 | return input 59 | .filter((str) => typeof str === 'string' && !!str.trim()) 60 | .reduce((cookies, str) => { 61 | const cookie = parseCookieString(str); 62 | cookies[cookie.name] = cookie; 63 | return cookies; 64 | }, cookies); 65 | }; 66 | 67 | const requestFunc = (method, url, headers = {}, body) => { 68 | const urlPieces = new URL(url); 69 | const formRegex = /^(([\w\s.])+=([\w\s.])+&?)+/; 70 | 71 | let requestSafeBody = ''; 72 | if (method.toLowerCase() !== 'get' && !headers['Content-Type']) { 73 | if (typeof body === 'object') { 74 | headers['Content-Type'] = 'application/json'; 75 | requestSafeBody = JSON.stringify(body); 76 | } else if ( 77 | typeof body === 'string' && 78 | formRegex.test(decodeURI(body)) 79 | ) { 80 | headers['Content-Type'] = 'application/x-www-form-urlencoded'; 81 | requestSafeBody = body; 82 | } else { 83 | headers['Content-Type'] = 'text/plain'; 84 | requestSafeBody = body; 85 | } 86 | } 87 | 88 | if (method.toLowerCase() !== 'get') 89 | headers['Content-Length'] = Buffer.byteLength(requestSafeBody); 90 | 91 | const requestOptions = { 92 | hostname: urlPieces.host, 93 | port: urlPieces.port || 443, 94 | path: urlPieces.pathname + urlPieces.search, 95 | method: method.toUpperCase(), 96 | headers, 97 | }; 98 | 99 | const requestPromise = new Promise((resolve, reject) => { 100 | const request$1 = request(requestOptions, (response) => { 101 | let responseData = ''; 102 | 103 | response.on('data', (dataBuffer) => { 104 | responseData += dataBuffer; 105 | }); 106 | 107 | response.on('end', () => { 108 | const returnable = { 109 | response, 110 | cookies: parseCookie(response), 111 | status: response.statusCode, 112 | headers: { 113 | ...response.headers, 114 | get: (header) => response.headers[header.toLowerCase()], 115 | }, 116 | json: () => { 117 | try { 118 | return JSON.parse(responseData); 119 | } catch (error) { 120 | throw new Error(error); 121 | } 122 | }, 123 | text: () => { 124 | try { 125 | return responseData; 126 | } catch (error) { 127 | throw new Error(error); 128 | } 129 | }, 130 | }; 131 | resolve(returnable); 132 | }); 133 | }); 134 | 135 | request$1.on('error', (error) => { 136 | reject(error); 137 | }); 138 | 139 | if (method.toLowerCase() !== 'get') request$1.write(requestSafeBody); 140 | request$1.end(); 141 | }); 142 | return requestPromise; 143 | }; 144 | 145 | const lightfetch = async (url, options = { method: 'GET' }) => { 146 | const { method, headers, body } = options; 147 | return requestFunc(method, url, headers, body); 148 | }; 149 | 150 | export { lightfetch }; 151 | -------------------------------------------------------------------------------- /dist/lightfetch.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { value: true }); 4 | 5 | const https = require('https'); 6 | 7 | const parseCookieString = (cookieValue) => { 8 | const parts = cookieValue 9 | .split(';') 10 | .filter((str) => typeof str === 'string' && !!str.trim()); 11 | const item = parts.shift().split('='); 12 | const name = item.shift(); 13 | const value = decodeURIComponent(item.join('=')); 14 | 15 | const cookie = { 16 | name: name, 17 | value: value, 18 | }; 19 | 20 | parts.forEach((part) => { 21 | const args = part.split('='); 22 | const key = args.shift().trimLeft().toLowerCase(); 23 | const value = args.join('='); 24 | switch (key) { 25 | case 'path': { 26 | cookie['Path'] = value; 27 | break; 28 | } 29 | case 'expires': { 30 | cookie['Expires'] = new Date(value); 31 | break; 32 | } 33 | case 'max-age': { 34 | cookie['Max-Age'] = parseInt(value, 10); 35 | break; 36 | } 37 | case 'secure': { 38 | cookie['Secure'] = true; 39 | break; 40 | } 41 | case 'httponly': { 42 | cookie['HttpOnly'] = true; 43 | break; 44 | } 45 | case 'samesite': { 46 | cookie['SameSite'] = value; 47 | break; 48 | } 49 | default: { 50 | cookie[key] = value; 51 | } 52 | } 53 | }); 54 | 55 | return cookie; 56 | }; 57 | 58 | const parseCookie = ({ headers: { 'set-cookie': input } }) => { 59 | if (!Array.isArray(input)) input = [input]; 60 | 61 | const cookies = {}; 62 | return input 63 | .filter((str) => typeof str === 'string' && !!str.trim()) 64 | .reduce((cookies, str) => { 65 | const cookie = parseCookieString(str); 66 | cookies[cookie.name] = cookie; 67 | return cookies; 68 | }, cookies); 69 | }; 70 | 71 | const requestFunc = (method, url, headers = {}, body) => { 72 | const urlPieces = new URL(url); 73 | const formRegex = /^(([\w\s.])+=([\w\s.])+&?)+/; 74 | 75 | let requestSafeBody = ''; 76 | if (method.toLowerCase() !== 'get' && !headers['Content-Type']) { 77 | if (typeof body === 'object') { 78 | headers['Content-Type'] = 'application/json'; 79 | requestSafeBody = JSON.stringify(body); 80 | } else if ( 81 | typeof body === 'string' && 82 | formRegex.test(decodeURI(body)) 83 | ) { 84 | headers['Content-Type'] = 'application/x-www-form-urlencoded'; 85 | requestSafeBody = body; 86 | } else { 87 | headers['Content-Type'] = 'text/plain'; 88 | requestSafeBody = body; 89 | } 90 | } 91 | 92 | if (method.toLowerCase() !== 'get') 93 | headers['Content-Length'] = Buffer.byteLength(requestSafeBody); 94 | 95 | const requestOptions = { 96 | hostname: urlPieces.host, 97 | port: urlPieces.port || 443, 98 | path: urlPieces.pathname + urlPieces.search, 99 | method: method.toUpperCase(), 100 | headers, 101 | }; 102 | 103 | const requestPromise = new Promise((resolve, reject) => { 104 | const request = https.request(requestOptions, (response) => { 105 | let responseData = ''; 106 | 107 | response.on('data', (dataBuffer) => { 108 | responseData += dataBuffer; 109 | }); 110 | 111 | response.on('end', () => { 112 | const returnable = { 113 | response, 114 | cookies: parseCookie(response), 115 | status: response.statusCode, 116 | headers: { 117 | ...response.headers, 118 | get: (header) => response.headers[header.toLowerCase()], 119 | }, 120 | json: () => { 121 | try { 122 | return JSON.parse(responseData); 123 | } catch (error) { 124 | throw new Error(error); 125 | } 126 | }, 127 | text: () => { 128 | try { 129 | return responseData; 130 | } catch (error) { 131 | throw new Error(error); 132 | } 133 | }, 134 | }; 135 | resolve(returnable); 136 | }); 137 | }); 138 | 139 | request.on('error', (error) => { 140 | reject(error); 141 | }); 142 | 143 | if (method.toLowerCase() !== 'get') request.write(requestSafeBody); 144 | request.end(); 145 | }); 146 | return requestPromise; 147 | }; 148 | 149 | const lightfetch = async (url, options = { method: 'GET' }) => { 150 | const { method, headers, body } = options; 151 | return requestFunc(method, url, headers, body); 152 | }; 153 | 154 | exports.lightfetch = lightfetch; 155 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | - Demonstrating empathy and kindness toward other people 21 | - Being respectful of differing opinions, viewpoints, and experiences 22 | - Giving and gracefully accepting constructive feedback 23 | - Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | - Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | - The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | - Trolling, insulting or derogatory comments, and personal or political attacks 33 | - Public or private harassment 34 | - Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | - Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | rayhanadev@protonmail.com. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | --------------------------------------------------------------------------------