From 6fad46fd9528979b0ae11dd12ce515e443ba52f9 Mon Sep 17 00:00:00 2001 From: Flummi Date: Tue, 18 Mar 2025 11:30:53 +0100 Subject: [PATCH] typescript lol --- .gitignore | 1 + dist/index.js | 63 ++++++++++++++++++++++++++++++++++ package-lock.json | 48 ++++++++++++++++++++++++++ package.json | 18 ++++++---- src/index.mjs | 34 ------------------ src/index.ts | 87 +++++++++++++++++++++++++++++++++++++++++++++++ tsconfig.json | 14 ++++++++ 7 files changed, 225 insertions(+), 40 deletions(-) create mode 100644 .gitignore create mode 100644 dist/index.js create mode 100644 package-lock.json delete mode 100644 src/index.mjs create mode 100644 src/index.ts create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b512c09 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 0000000..1229f14 --- /dev/null +++ b/dist/index.js @@ -0,0 +1,63 @@ +import http from "http"; +import https from "https"; +import { URL } from "url"; +import querystring from "querystring"; +const readData = (res, mode) => new Promise((resolve, reject) => { + const chunks = []; + res + .on("data", chunk => chunks.push(chunk)) + .on("end", () => { + const data = Buffer.concat(chunks); + try { + if (mode === "json") + resolve(JSON.parse(data.toString("utf8"))); + else if (mode === "buffer") + resolve(data); + else if (mode === "arraybuffer") + resolve(new Uint8Array(data).buffer); + else + resolve(data.toString("utf8")); + } + catch (err) { + reject(err); + } + }) + .on("error", reject); +}); +export default async (urlString, options = {}) => { + const { protocol, hostname, pathname, search, port } = new URL(urlString); + const body = options.method === "POST" && options.body + ? options.headers?.["Content-Type"] === "application/json" + ? JSON.stringify(options.body) + : querystring.stringify(options.body) + : null; + const requestOptions = { + hostname, + port: port || (protocol === "https:" ? 443 : 80), + path: pathname + search, + method: options.method || "GET", + headers: { + ...options.headers, + ...(body ? { "Content-Length": Buffer.byteLength(body) } : {}), + } + }; + return new Promise((resolve, reject) => { + const requester = protocol === "https:" ? https : http; + const req = requester.request(requestOptions, res => { + if (res.statusCode && (res.statusCode < 200 || res.statusCode >= 300)) + return reject(new Error(`Request failed with status code ${res.statusCode}`)); + resolve({ + body: res, + headers: res.headers, + text: () => readData(res, "text"), + json: () => readData(res, "json"), + buffer: () => readData(res, "buffer"), + arrayBuffer: () => readData(res, "arraybuffer") + }); + }); + req.on("error", reject); + if (body) + req.write(body); + req.end(); + }); +}; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..f50335c --- /dev/null +++ b/package-lock.json @@ -0,0 +1,48 @@ +{ + "name": "flumm-fetch", + "version": "2.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "flumm-fetch", + "version": "2.0.0", + "license": "MIT", + "devDependencies": { + "@types/node": "^22.13.10", + "typescript": "^5.8.2" + } + }, + "node_modules/@types/node": { + "version": "22.13.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.10.tgz", + "integrity": "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "node_modules/typescript": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", + "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + } + } +} diff --git a/package.json b/package.json index 55bfeee..445716f 100644 --- a/package.json +++ b/package.json @@ -1,22 +1,28 @@ { "name": "flumm-fetch", - "version": "1.0.2", + "version": "2.0.0", "description": "", - "main": "src/index.mjs", + "main": "dist/index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "build": "tsc", + "test": "node src/test.mjs" }, "repository": { "type": "git", - "url": "git+https://github.com/kein-Bot/flumm-fetch.git" + "url": "git+https://git.lat/keinBot/flumm-fetch.git" }, "keywords": [ "fetch" ], "author": "Flummi", "license": "MIT", + "type": "module", "bugs": { - "url": "https://github.com/kein-Bot/flumm-fetch/issues" + "url": "https://git.lat/keinBot/flumm-fetch/issues" }, - "homepage": "https://github.com/kein-Bot/flumm-fetch#readme" + "homepage": "https://git.lat/keinBot/flumm-fetch#readme", + "devDependencies": { + "@types/node": "^22.13.10", + "typescript": "^5.8.2" + } } diff --git a/src/index.mjs b/src/index.mjs deleted file mode 100644 index 7a0bfe3..0000000 --- a/src/index.mjs +++ /dev/null @@ -1,34 +0,0 @@ -import http from "http"; -import https from "https"; -import url from "url"; -import querystring from "querystring"; - -const readdata = (res, mode, data = "") => new Promise((resolve, reject) => res - .setEncoding("utf8") - .on("data", chunk => data += chunk) - .on("end", () => { - switch(mode) { - case "text": resolve(data); break; - case "json": try { resolve(JSON.parse(data)); } catch(err) { reject(data); } break; - case "buffer": resolve(new Buffer.from(data)); break; - default: reject("lol no D:"); break; - } - })); -export default (a, options = {}, link = url.parse(a), body = "") => new Promise((resolve, reject) => { - options = {...{ hostname: link.hostname, path: link.path, method: "GET" }, ...options}; - if(options.method === "POST") { - body = typeof options.body === "object" ? querystring.stringify(options.body) : options.body; - delete options.body; - options.headers = {...{ - "Content-Type": "application/x-www-form-urlencoded", - "Content-Length": Buffer.byteLength(body) - }, ...options.headers}; - } - (link.protocol === "https:"?https:http).request(options, res => resolve({ - body: res, - headers: res.headers, - text: () => readdata(res, "text"), - json: () => readdata(res, "json"), - buffer: () => readdata(res, "buffer") - })).on("error", err => reject(err)).end(body); -}); diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..c9ccae6 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,87 @@ +import http from "http"; +import https from "https"; +import { URL } from "url"; +import querystring from "querystring"; + +type ResponseData = { + body: http.IncomingMessage; + headers: http.IncomingHttpHeaders; + text: () => Promise; + json: () => Promise; + buffer: () => Promise; + arrayBuffer: () => Promise; +}; + +interface ExtendedRequestOptions extends http.RequestOptions { + body?: any; +} + +const readData = ( + res: http.IncomingMessage, + mode: "text" | "json" | "buffer" | "arraybuffer" +): Promise => + new Promise((resolve, reject) => { + const chunks: Buffer[] = []; + res + .on("data", chunk => chunks.push(chunk)) + .on("end", () => { + const data = Buffer.concat(chunks); + try { + if(mode === "json") + resolve(JSON.parse(data.toString("utf8"))); + else if(mode === "buffer") + resolve(data); + else if(mode === "arraybuffer") + resolve(new Uint8Array(data).buffer); + else + resolve(data.toString("utf8")); + } + catch(err: any) { + reject(err); + } + }) + .on("error", reject); + }); + +export default async (urlString: string, options: ExtendedRequestOptions = {}): Promise => { + const { protocol, hostname, pathname, search, port } = new URL(urlString); + + const body = + options.method === "POST" && options.body + ? options.headers?.["Content-Type"] === "application/json" + ? JSON.stringify(options.body) + : querystring.stringify(options.body as querystring.ParsedUrlQueryInput) + : null; + + const requestOptions: http.RequestOptions = { + hostname, + port: port || (protocol === "https:" ? 443 : 80), + path: pathname + search, + method: options.method || "GET", + headers: { + ...options.headers, + ...(body ? { "Content-Length": Buffer.byteLength(body) } : {}), + } + }; + + return new Promise((resolve, reject) => { + const requester = protocol === "https:" ? https : http; + const req = requester.request(requestOptions, res => { + if(res.statusCode && (res.statusCode < 200 || res.statusCode >= 300)) + return reject(new Error(`Request failed with status code ${res.statusCode}`)); + resolve({ + body: res, + headers: res.headers, + text: () => readData(res, "text"), + json: () => readData(res, "json"), + buffer: () => readData(res, "buffer"), + arrayBuffer: () => readData(res, "arraybuffer") + }); + }); + + req.on("error", reject); + if(body) + req.write(body); + req.end(); + }); +}; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..510781e --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "es2024", + "module": "ESNext", + "moduleResolution": "node", + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "removeComments": true + }, + "include": ["src"], + "exclude": ["node_modules"] +}