UNPKG

abi.js

Version:

[![typescript-icon]][typescript-link] [![license-icon]][license-link] [![status-icon]][status-link] [![ci-icon]][ci-link] [![twitter-icon]][twitter-link]

160 lines (155 loc) 4.6 kB
// src/serve.ts import { createServer } from "node:http"; // src/defaults.ts var defaultPort = 3e3; var defaultHost = "0.0.0.0"; // src/helpers.ts function isPort(port) { return typeof port === "number"; } function isHostname(host) { return typeof host === "string"; } function isAddress(address) { return typeof address === "object" && "port" in address && "hostname" in address && isPort(address.port) && isHostname(address.hostname); } function isHandler(handler) { return typeof handler === "function"; } function hasHandler(options) { return "handler" in options && isHandler(options.handler); } function isServeOptions(options) { return isAddress(options) && hasHandler(options); } function toServeOptions(arg1, arg2, arg3) { let options; if (typeof arg1 === "function") { options = { port: defaultPort, hostname: defaultHost, handler: arg1 }; } else if (isPort(arg1) && isHandler(arg2)) { options = { port: arg1, hostname: defaultHost, handler: arg2 }; } else if (isHostname(arg1) && isHandler(arg2)) { options = { port: defaultPort, hostname: arg1, handler: arg2 }; } else if (isPort(arg1) && isHostname(arg2) && isHandler(arg3)) { options = { port: arg1, hostname: arg2, handler: arg3 }; } else if (isAddress(arg1) && isHandler(arg2)) { options = { port: arg1.port, hostname: arg1.hostname, handler: arg2 }; } else if (isServeOptions(arg1)) { options = arg1; } else { throw new Error("Invalid arguments for serve function"); } return options; } // src/serve.ts function serve(arg1, arg2, arg3) { const { port, hostname, handler } = toServeOptions(arg1, arg2, arg3); const server = createServer((req, res) => { const data = []; req.on("error", (err) => { throw err; }).on("data", (chunk) => { data.push(chunk); }).on("end", async () => { const requestBody = Buffer.concat(data); const method = req.method?.toUpperCase() || "GET"; const url = new URL(req.url || "/", `http://${hostname}:${port}`); const requestOptions = { method, headers: Object.entries(req.headers).reduce( (headers, [key, value]) => { if (Array.isArray(value)) { for (const v of value) { headers.append(key, v); } } else if (value !== void 0) { headers.set(key, value); } return headers; }, new Headers() ) }; if (!(method === "GET" || method === "HEAD")) { requestOptions.body = requestBody; } const request = new Request(url.toString(), requestOptions); const response = await handler(request); let responseBody = null; if (response.body instanceof ReadableStream) { const reader = response.body.getReader(); const streamData = []; while (true) { const { done, value } = await reader.read(); if (done) { break; } streamData.push(value); } responseBody = Buffer.concat(streamData); } else if (response.body) { responseBody = Buffer.isBuffer(response.body) ? response.body : Buffer.from(response.body); } res.writeHead( response.status || 200, Object.fromEntries(response.headers.entries()) ); res.end(responseBody); }); }); server.listen(port, hostname); const address = server.address(); return address && typeof address === "object" ? { port: address.port, hostname: address.address } : { port, hostname }; } // src/server.ts var Server = class { constructor(root, assets = "") { this.root = root; this.assets = assets; this.fetch = this.fetch.bind(this); } #handlers = /* @__PURE__ */ new Set(); pipe(handler, ...handlers) { this.#handlers.add(handler); for (const _handler of handlers) { this.#handlers.add(_handler); } return this; } async fetch(request) { for (const handler of this.#handlers) { const response = await handler(request); if (response.ok) { return response; } } return this.error(`Cannot ${request.method} ${request.url}`); } start() { serve(this.fetch); } listen(arg1, arg2) { const args = [arg1, arg2].filter( (arg) => arg !== void 0 && arg !== null ); serve(...args, this.fetch); } error(err) { console.log(`Unexpected server error: ${err}`); return new Response("Error 500: Server error.", { status: 500 }); } }; export { Server };