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
JavaScript
// 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
};