Update app and tooling

This commit is contained in:
Lawrence Chen 2026-01-29 17:36:26 -08:00
parent 3046531bdd
commit e620ec7349
4950 changed files with 2975120 additions and 10 deletions

View file

@ -0,0 +1,13 @@
//#region src/_middleware.ts
function wrapFetch(server) {
const fetchHandler = server.options.fetch;
const middleware = server.options.middleware || [];
return middleware.length === 0 ? fetchHandler : (request) => callMiddleware(request, fetchHandler, middleware, 0);
}
function callMiddleware(request, fetchHandler, middleware, index) {
if (index === middleware.length) return fetchHandler(request);
return middleware[index](request, () => callMiddleware(request, fetchHandler, middleware, index + 1));
}
//#endregion
export { wrapFetch };

16
node_modules/srvx/dist/_chunks/_plugins-DOhVIkXu.mjs generated vendored Normal file
View file

@ -0,0 +1,16 @@
//#region src/_plugins.ts
const errorPlugin = (server) => {
const errorHandler = server.options.error;
if (!errorHandler) return;
server.options.middleware.unshift((_req, next) => {
try {
const res = next();
return res instanceof Promise ? res.catch((error) => errorHandler(error)) : res;
} catch (error) {
return errorHandler(error);
}
});
};
//#endregion
export { errorPlugin };

91
node_modules/srvx/dist/_chunks/_url-CdE4ce6F.mjs generated vendored Normal file
View file

@ -0,0 +1,91 @@
//#region src/_url.ts
/**
* Wrapper for URL with fast path access to `.pathname` and `.search` props.
*
* **NOTE:** It is assumed that the input URL is already ecoded and formatted from an HTTP request and contains no hash.
*
* **NOTE:** Triggering the setters or getters on other props will deoptimize to full URL parsing.
*/
const FastURL = /* @__PURE__ */ (() => {
const FastURL$1 = class URL {
#originalURL;
#parsedURL;
_pathname;
_urlqindex;
_query;
_search;
constructor(url) {
this.#originalURL = url;
}
get _url() {
if (!this.#parsedURL) this.#parsedURL = new globalThis.URL(this.#originalURL);
return this.#parsedURL;
}
toString() {
return this._url.toString();
}
toJSON() {
return this.toString();
}
get pathname() {
if (this.#parsedURL) return this.#parsedURL.pathname;
if (this._pathname === void 0) {
const url = this.#originalURL;
const protoIndex = url.indexOf("://");
if (protoIndex === -1) return this._url.pathname;
const pIndex = url.indexOf("/", protoIndex + 4);
if (pIndex === -1) return this._url.pathname;
const qIndex = this._urlqindex = url.indexOf("?", pIndex);
this._pathname = url.slice(pIndex, qIndex === -1 ? void 0 : qIndex);
}
return this._pathname;
}
set pathname(value) {
this._pathname = void 0;
this._url.pathname = value;
}
get searchParams() {
if (this.#parsedURL) return this.#parsedURL.searchParams;
if (!this._query) this._query = new URLSearchParams(this.search);
return this._query;
}
get search() {
if (this.#parsedURL) return this.#parsedURL.search;
if (this._search === void 0) {
const qIndex = this._urlqindex;
if (qIndex === -1 || qIndex === this.#originalURL.length - 1) this._search = "";
else this._search = qIndex === void 0 ? this._url.search : this.#originalURL.slice(qIndex);
}
return this._search;
}
set search(value) {
this._search = void 0;
this._query = void 0;
this._url.search = value;
}
};
const slowProps = [
"hash",
"host",
"hostname",
"href",
"origin",
"password",
"port",
"protocol",
"username"
];
for (const prop of slowProps) Object.defineProperty(FastURL$1.prototype, prop, {
get() {
return this._url[prop];
},
set(value) {
this._url[prop] = value;
}
});
Object.setPrototypeOf(FastURL$1, globalThis.URL);
return FastURL$1;
})();
//#endregion
export { FastURL as FastURL$1 };

13
node_modules/srvx/dist/_chunks/_url-D8u5OAto.d.mts generated vendored Normal file
View file

@ -0,0 +1,13 @@
//#region src/_url.d.ts
/**
* Wrapper for URL with fast path access to `.pathname` and `.search` props.
*
* **NOTE:** It is assumed that the input URL is already ecoded and formatted from an HTTP request and contains no hash.
*
* **NOTE:** Triggering the setters or getters on other props will deoptimize to full URL parsing.
*/
declare const FastURL: {
new (url: string): URL;
};
//#endregion
export { FastURL as FastURL$2 };

70
node_modules/srvx/dist/_chunks/_utils-DRF_4b_y.mjs generated vendored Normal file
View file

@ -0,0 +1,70 @@
//#region src/_utils.ts
function resolvePortAndHost(opts) {
const _port = opts.port ?? globalThis.process?.env.PORT ?? 3e3;
const port = typeof _port === "number" ? _port : Number.parseInt(_port, 10);
const hostname = opts.hostname ?? globalThis.process?.env.HOST;
return {
port,
hostname
};
}
function fmtURL(host, port, secure) {
if (!host || !port) return void 0;
if (host.includes(":")) host = `[${host}]`;
return `http${secure ? "s" : ""}://${host}:${port}/`;
}
function printListening(opts, url) {
if (!url || (opts.silent ?? globalThis.process?.env?.TEST)) return;
const _url = new URL(url);
const allInterfaces = _url.hostname === "[::]" || _url.hostname === "0.0.0.0";
if (allInterfaces) {
_url.hostname = "localhost";
url = _url.href;
}
let listeningOn = `➜ Listening on:`;
let additionalInfo = allInterfaces ? " (all interfaces)" : "";
if (globalThis.process.stdout?.isTTY) {
listeningOn = `\u001B[32m${listeningOn}\u001B[0m`;
url = `\u001B[36m${url}\u001B[0m`;
additionalInfo = `\u001B[2m${additionalInfo}\u001B[0m`;
}
console.log(`${listeningOn} ${url}${additionalInfo}`);
}
function resolveTLSOptions(opts) {
if (!opts.tls || opts.protocol === "http") return;
const cert = resolveCertOrKey(opts.tls.cert);
const key = resolveCertOrKey(opts.tls.key);
if (!cert && !key) {
if (opts.protocol === "https") throw new TypeError("TLS `cert` and `key` must be provided for `https` protocol.");
return;
}
if (!cert || !key) throw new TypeError("TLS `cert` and `key` must be provided together.");
return {
cert,
key,
passphrase: opts.tls.passphrase
};
}
function resolveCertOrKey(value) {
if (!value) return;
if (typeof value !== "string") throw new TypeError("TLS certificate and key must be strings in PEM format or file paths.");
if (value.startsWith("-----BEGIN ")) return value;
const { readFileSync } = process.getBuiltinModule("node:fs");
return readFileSync(value, "utf8");
}
function createWaitUntil() {
const promises = new Set();
return {
waitUntil: (promise) => {
promises.add(promise.catch(console.error).finally(() => {
promises.delete(promise);
}));
},
wait: () => {
return Promise.all(promises);
}
};
}
//#endregion
export { createWaitUntil, fmtURL, printListening, resolvePortAndHost, resolveTLSOptions };

31
node_modules/srvx/dist/_chunks/_utils.cli-B2YzwlOv.mjs generated vendored Normal file
View file

@ -0,0 +1,31 @@
//#region src/_utils.cli.ts
const noColor = globalThis.process?.env?.NO_COLOR === "1" || globalThis.process?.env?.TERM === "dumb";
const resets = {
1: 22,
31: 39,
32: 39,
33: 39,
34: 39,
35: 39,
36: 39,
90: 39
};
const _c = (c) => (text) => {
if (noColor) return text;
const off = resets[c] ?? 0;
return `\u001B[${c}m${text}\u001B[${off}m`;
};
const Colors = {
bold: _c(1),
red: _c(31),
green: _c(32),
yellow: _c(33),
blue: _c(34),
magenta: _c(35),
cyan: _c(36),
gray: _c(90),
url: (title, url) => noColor ? `[${title}](${url})` : `\u001B]8;;${url}\u001B\\${title}\u001B]8;;\u001B\\`
};
//#endregion
export { Colors };

43
node_modules/srvx/dist/_chunks/call-LB9MY5Dv.mjs generated vendored Normal file
View file

@ -0,0 +1,43 @@
import { NodeResponse, NodeResponseHeaders } from "./response-6LJL3Qlz.mjs";
//#region src/adapters/_node/call.ts
function callNodeHandler(handler, req) {
const isMiddleware = handler.length > 2;
const nodeCtx = req.runtime?.node;
if (!nodeCtx || !nodeCtx.req || !nodeCtx.res) throw new Error("Node.js runtime context is not available.");
const { req: nodeReq, res: nodeRes } = nodeCtx;
let _headers;
const webRes = new NodeResponse(void 0, {
get status() {
return nodeRes.statusCode;
},
get statusText() {
return nodeRes.statusMessage;
},
get headers() {
if (!_headers) _headers = new NodeResponseHeaders(nodeCtx);
return _headers;
}
});
return new Promise((resolve, reject) => {
nodeRes.once("close", () => resolve(webRes));
nodeRes.once("finish", () => resolve(webRes));
nodeRes.once("error", (error) => reject(error));
let streamPromise;
nodeRes.once("pipe", (stream) => {
streamPromise = new Promise((resolve$1) => {
stream.once("end", () => resolve$1(webRes));
stream.once("error", (error) => reject(error));
});
});
try {
if (isMiddleware) Promise.resolve(handler(nodeReq, nodeRes, (error) => error ? reject(error) : streamPromise || resolve(webRes))).catch((error) => reject(error));
else Promise.resolve(handler(nodeReq, nodeRes)).then(() => streamPromise || webRes);
} catch (error) {
reject(error);
}
});
}
//#endregion
export { callNodeHandler };

293
node_modules/srvx/dist/_chunks/response-6LJL3Qlz.mjs generated vendored Normal file
View file

@ -0,0 +1,293 @@
import { splitSetCookieString } from "cookie-es";
//#region src/adapters/_node/_common.ts
const kNodeInspect = /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom");
function inheritProps(target, source, sourceKey) {
for (const key of Object.getOwnPropertyNames(source)) {
if (key in target) continue;
const desc = Object.getOwnPropertyDescriptor(source, key);
if (desc.get) Object.defineProperty(target, key, {
...desc,
get() {
return this[sourceKey][key];
}
});
else if (typeof desc.value === "function") Object.defineProperty(target, key, {
...desc,
value(...args) {
return this[sourceKey][key](...args);
}
});
else Object.defineProperty(target, key, desc);
}
}
//#endregion
//#region src/adapters/_node/headers.ts
const NodeRequestHeaders = /* @__PURE__ */ (() => {
const _Headers = class Headers$1 {
_node;
constructor(nodeCtx) {
this._node = nodeCtx;
}
append(name, value) {
name = validateHeader(name);
const _headers = this._node.req.headers;
const _current = _headers[name];
if (_current) if (Array.isArray(_current)) _current.push(value);
else _headers[name] = [_current, value];
else _headers[name] = value;
}
delete(name) {
name = validateHeader(name);
this._node.req.headers[name] = void 0;
}
get(name) {
name = validateHeader(name);
const rawValue = this._node.req.headers[name];
if (rawValue === void 0) return null;
return _normalizeValue(this._node.req.headers[name]);
}
getSetCookie() {
const setCookie = this._node.req.headers["set-cookie"];
if (!setCookie || setCookie.length === 0) return [];
return splitSetCookieString(setCookie);
}
has(name) {
name = validateHeader(name);
return !!this._node.req.headers[name];
}
set(name, value) {
name = validateHeader(name);
this._node.req.headers[name] = value;
}
get count() {
throw new Error("Method not implemented.");
}
getAll(_name) {
throw new Error("Method not implemented.");
}
toJSON() {
const _headers = this._node.req.headers;
const result = {};
for (const key in _headers) if (_headers[key]) result[key] = _normalizeValue(_headers[key]);
return result;
}
forEach(cb, thisArg) {
const _headers = this._node.req.headers;
for (const key in _headers) if (_headers[key]) cb.call(thisArg, _normalizeValue(_headers[key]), key, this);
}
*entries() {
const headers = this._node.req.headers;
const isHttp2 = this._node.req.httpVersion === "2.0";
for (const key in headers) if (!isHttp2 || key[0] !== ":") yield [key, _normalizeValue(headers[key])];
}
*keys() {
const keys = Object.keys(this._node.req.headers);
for (const key of keys) yield key;
}
*values() {
const values = Object.values(this._node.req.headers);
for (const value of values) yield _normalizeValue(value);
}
[Symbol.iterator]() {
return this.entries()[Symbol.iterator]();
}
get [Symbol.toStringTag]() {
return "Headers";
}
[kNodeInspect]() {
return Object.fromEntries(this.entries());
}
};
Object.setPrototypeOf(_Headers.prototype, globalThis.Headers.prototype);
return _Headers;
})();
const NodeResponseHeaders = /* @__PURE__ */ (() => {
const _Headers = class Headers$1 {
_node;
constructor(nodeCtx) {
this._node = nodeCtx;
}
append(name, value) {
this._node.res.appendHeader(name, value);
}
delete(name) {
this._node.res.removeHeader(name);
}
get(name) {
const rawValue = this._node.res.getHeader(name);
if (rawValue === void 0) return null;
return _normalizeValue(rawValue);
}
getSetCookie() {
const setCookie = _normalizeValue(this._node.res.getHeader("set-cookie"));
if (!setCookie) return [];
return splitSetCookieString(setCookie);
}
has(name) {
return this._node.res.hasHeader(name);
}
set(name, value) {
this._node.res.setHeader(name, value);
}
get count() {
throw new Error("Method not implemented.");
}
getAll(_name) {
throw new Error("Method not implemented.");
}
toJSON() {
const _headers = this._node.res.getHeaders();
const result = {};
for (const key in _headers) if (_headers[key]) result[key] = _normalizeValue(_headers[key]);
return result;
}
forEach(cb, thisArg) {
const _headers = this._node.res.getHeaders();
for (const key in _headers) if (_headers[key]) cb.call(thisArg, _normalizeValue(_headers[key]), key, this);
}
*entries() {
const _headers = this._node.res.getHeaders();
for (const key in _headers) yield [key, _normalizeValue(_headers[key])];
}
*keys() {
const keys = this._node.res.getHeaderNames();
for (const key of keys) yield key;
}
*values() {
const values = Object.values(this._node.res.getHeaders());
for (const value of values) yield _normalizeValue(value);
}
[Symbol.iterator]() {
return this.entries()[Symbol.iterator]();
}
get [Symbol.toStringTag]() {
return "Headers";
}
[kNodeInspect]() {
return Object.fromEntries(this.entries());
}
};
Object.setPrototypeOf(_Headers.prototype, globalThis.Headers.prototype);
return _Headers;
})();
function _normalizeValue(value) {
if (Array.isArray(value)) return value.join(", ");
return typeof value === "string" ? value : String(value ?? "");
}
function validateHeader(name) {
if (name[0] === ":") throw new TypeError(`${JSON.stringify(name)} is an invalid header name.`);
return name.toLowerCase();
}
//#endregion
//#region src/adapters/_node/response.ts
/**
* Fast Response for Node.js runtime
*
* It is faster because in most cases it doesn't create a full Response instance.
*/
const NodeResponse = /* @__PURE__ */ (() => {
const NativeResponse = globalThis.Response;
const STATUS_CODES = globalThis.process?.getBuiltinModule("node:http")?.STATUS_CODES || {};
class NodeResponse$1 {
#body;
#init;
#headers;
#response;
constructor(body, init) {
this.#body = body;
this.#init = init;
}
get status() {
return this.#response?.status || this.#init?.status || 200;
}
get statusText() {
return this.#response?.statusText || this.#init?.statusText || STATUS_CODES[this.status] || "";
}
get headers() {
if (this.#response) return this.#response.headers;
if (this.#headers) return this.#headers;
const initHeaders = this.#init?.headers;
return this.#headers = initHeaders instanceof Headers ? initHeaders : new Headers(initHeaders);
}
get ok() {
if (this.#response) return this.#response.ok;
const status = this.status;
return status >= 200 && status < 300;
}
get _response() {
if (this.#response) return this.#response;
this.#response = new NativeResponse(this.#body, this.#headers ? {
...this.#init,
headers: this.#headers
} : this.#init);
this.#init = void 0;
this.#headers = void 0;
this.#body = void 0;
return this.#response;
}
nodeResponse() {
const status = this.status;
const statusText = this.statusText;
let body;
let contentType;
let contentLength;
if (this.#response) body = this.#response.body;
else if (this.#body) if (this.#body instanceof ReadableStream) body = this.#body;
else if (typeof this.#body === "string") {
body = this.#body;
contentType = "text/plain; charset=UTF-8";
contentLength = Buffer.byteLength(this.#body);
} else if (this.#body instanceof ArrayBuffer) {
body = Buffer.from(this.#body);
contentLength = this.#body.byteLength;
} else if (this.#body instanceof Uint8Array) {
body = this.#body;
contentLength = this.#body.byteLength;
} else if (this.#body instanceof DataView) {
body = Buffer.from(this.#body.buffer);
contentLength = this.#body.byteLength;
} else if (this.#body instanceof Blob) {
body = this.#body.stream();
contentType = this.#body.type;
contentLength = this.#body.size;
} else if (typeof this.#body.pipe === "function") body = this.#body;
else body = this._response.body;
const rawNodeHeaders = [];
const initHeaders = this.#init?.headers;
const headerEntries = this.#response?.headers || this.#headers || (initHeaders ? Array.isArray(initHeaders) ? initHeaders : initHeaders?.entries ? initHeaders.entries() : Object.entries(initHeaders).map(([k, v]) => [k.toLowerCase(), v]) : void 0);
let hasContentTypeHeader;
let hasContentLength;
if (headerEntries) for (const [key, value] of headerEntries) {
if (key === "set-cookie") {
for (const setCookie of splitSetCookieString(value)) rawNodeHeaders.push(["set-cookie", setCookie]);
continue;
}
rawNodeHeaders.push([key, value]);
if (key === "content-type") hasContentTypeHeader = true;
else if (key === "content-length") hasContentLength = true;
}
if (contentType && !hasContentTypeHeader) rawNodeHeaders.push(["content-type", contentType]);
if (contentLength && !hasContentLength) rawNodeHeaders.push(["content-length", String(contentLength)]);
this.#init = void 0;
this.#headers = void 0;
this.#response = void 0;
this.#body = void 0;
return {
status,
statusText,
headers: rawNodeHeaders,
body
};
}
}
inheritProps(NodeResponse$1.prototype, NativeResponse.prototype, "_response");
Object.setPrototypeOf(NodeResponse$1, NativeResponse);
Object.setPrototypeOf(NodeResponse$1.prototype, NativeResponse.prototype);
return NodeResponse$1;
})();
//#endregion
export { NodeRequestHeaders, NodeResponse, NodeResponseHeaders, inheritProps, kNodeInspect };

268
node_modules/srvx/dist/_chunks/types-BtByT9ny.d.mts generated vendored Normal file
View file

@ -0,0 +1,268 @@
import * as cloudflare_workers0 from "cloudflare:workers";
import * as NodeHttp$1 from "node:http";
import * as NodeHttps from "node:https";
import * as NodeHttp2 from "node:http2";
import * as NodeNet from "node:net";
import * as Bun from "bun";
import * as CF from "@cloudflare/workers-types";
//#region src/types.d.ts
// Utils
type MaybePromise<T> = T | Promise<T>;
type IsAny<T> = Equal<T, any> extends true ? true : false;
type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? true : false;
// ----------------------------------------------------------------------------
// srvx API
// ----------------------------------------------------------------------------
/**
* Faster URL constructor with lazy access to pathname and search params (For Node, Deno, and Bun).
*/
declare const FastURL: typeof globalThis.URL;
/**
* Faster Response constructor optimized for Node.js (same as Response for other runtimes).
*/
declare const FastResponse: typeof globalThis.Response;
/**
* Create a new server instance.
*/
declare function serve(options: ServerOptions): Server;
/**
* Web fetch compatible request handler
*/
type ServerHandler = (request: ServerRequest) => MaybePromise<Response>;
type ServerMiddleware = (request: ServerRequest, next: () => Response | Promise<Response>) => Response | Promise<Response>;
type ServerPlugin = (server: Server) => void;
/**
* Server options
*/
interface ServerOptions {
/**
* The fetch handler handles incoming requests.
*/
fetch: ServerHandler;
/**
* Handle lifecycle errors.
*
* @note This handler will set built-in Bun and Deno error handler.
*/
error?: ErrorHandler;
/**
* Server middleware handlers to run before the main fetch handler.
*/
middleware?: ServerMiddleware[];
/**
* Server plugins.
*/
plugins?: ServerPlugin[];
/**
* If set to `true`, server will not start listening automatically.
*/
manual?: boolean;
/**
* The port server should be listening to.
*
* Default is read from `PORT` environment variable or will be `3000`.
*
* **Tip:** You can set the port to `0` to use a random port.
*/
port?: string | number;
/**
* The hostname (IP or resolvable host) server listener should bound to.
*
* When not provided, server with listen to all network interfaces by default.
*
* **Important:** If you are running a server that is not expected to be exposed to the network, use `hostname: "localhost"`.
*/
hostname?: string;
/**
* Enabling this option allows multiple processes to bind to the same port, which is useful for load balancing.
*
* **Note:** Despite Node.js built-in behavior that has `exclusive` flag (opposite of `reusePort`) enabled by default, srvx uses non-exclusive mode for consistency.
*/
reusePort?: boolean;
/**
* The protocol to use for the server.
*
* Possible values are `http` and `https`.
*
* If `protocol` is not set, Server will use `http` as the default protocol or `https` if both `tls.cert` and `tls.key` options are provided.
*/
protocol?: "http" | "https";
/**
* If set to `true`, server will not print the listening address.
*/
silent?: boolean;
/**
* TLS server options.
*/
tls?: {
/**
* File path or inlined TLS certificate in PEM format (required).
*/
cert?: string;
/**
* File path or inlined TLS private key in PEM format (required).
*/
key?: string;
/**
* Passphrase for the private key (optional).
*/
passphrase?: string;
};
/**
* Node.js server options.
*/
node?: (NodeHttp$1.ServerOptions | NodeHttps.ServerOptions | NodeHttp2.ServerOptions) & NodeNet.ListenOptions & {
http2?: boolean;
};
/**
* Bun server options
*
* @docs https://bun.sh/docs/api/http
*/
bun?: Omit<Bun.ServeOptions | Bun.TLSServeOptions, "fetch">;
/**
* Deno server options
*
* @docs https://docs.deno.com/api/deno/~/Deno.serve
*/
deno?: Deno.ServeOptions;
/**
* Service worker options
*/
serviceWorker?: {
/**
* The path to the service worker file to be registered.
*/
url?: string;
/**
* The scope of the service worker.
*
*/
scope?: string;
};
}
interface Server<Handler = ServerHandler> {
/**
* Current runtime name
*/
readonly runtime: "node" | "deno" | "bun" | "cloudflare" | "service-worker" | "generic";
/**
* Server options
*/
readonly options: ServerOptions & {
middleware: ServerMiddleware[];
};
/**
* Server URL address.
*/
readonly url?: string;
/**
* Node.js context.
*/
readonly node?: {
server?: NodeHttp$1.Server | NodeHttp2.Http2Server;
handler: (req: NodeServerRequest, res: NodeServerResponse) => void | Promise<void>;
};
/**
* Bun context.
*/
readonly bun?: {
server?: Bun.Server;
};
/**
* Deno context.
*/
readonly deno?: {
server?: Deno.HttpServer;
};
/**
* Server fetch handler
*/
readonly fetch: Handler;
/**
* Start listening for incoming requests.
* When `manual` option is enabled, this method needs to be called explicitly to begin accepting connections.
*/
serve(): void | Promise<Server<Handler>>;
/**
* Returns a promise that resolves when the server is ready.
*/
ready(): Promise<Server<Handler>>;
/**
* Stop listening to prevent new connections from being accepted.
*
* By default, it does not cancel in-flight requests or websockets. That means it may take some time before all network activity stops.
*
* @param closeActiveConnections Immediately terminate in-flight requests, websockets, and stop accepting new connections.
* @default false
*/
close(closeActiveConnections?: boolean): Promise<void>;
}
// ----------------------------------------------------------------------------
// Request with runtime addons.
// ----------------------------------------------------------------------------
interface ServerRuntimeContext {
name: "node" | "deno" | "bun" | "cloudflare" | (string & {});
/**
* Underlying Node.js server request info.
*/
node?: {
req: NodeServerRequest;
res?: NodeServerResponse;
};
/**
* Underlying Deno server request info.
*/
deno?: {
info: Deno.ServeHandlerInfo<Deno.NetAddr>;
};
/**
* Underlying Bun server request context.
*/
bun?: {
server: Bun.Server;
};
/**
* Underlying Cloudflare request context.
*/
cloudflare?: {
context: CF.ExecutionContext;
env: IsAny<typeof cloudflare_workers0> extends true ? Record<string, unknown> : typeof cloudflare_workers0.env;
};
}
interface ServerRequestContext {
[key: string]: unknown;
}
interface ServerRequest extends Request {
/**
* Runtime specific request context.
*/
runtime?: ServerRuntimeContext;
/**
* IP address of the client.
*/
ip?: string | undefined;
/**
* Arbitrary context related to the request.
*/
context?: ServerRequestContext;
/**
* Tell the runtime about an ongoing operation that shouldn't close until the promise resolves.
*/
waitUntil?: (promise: Promise<unknown>) => void | Promise<void>;
}
// ----------------------------------------------------------------------------
// Different handler types
// ----------------------------------------------------------------------------
type FetchHandler = (request: Request) => Response | Promise<Response>;
type ErrorHandler = (error: unknown) => Response | Promise<Response>;
type BunFetchHandler = (request: Request, server?: Bun.Server) => Response | Promise<Response>;
type DenoFetchHandler = (request: Request, info?: Deno.ServeHandlerInfo<Deno.NetAddr>) => Response | Promise<Response>;
type NodeServerRequest = NodeHttp$1.IncomingMessage | NodeHttp2.Http2ServerRequest;
type NodeServerResponse = NodeHttp$1.ServerResponse | NodeHttp2.Http2ServerResponse;
type NodeHttpHandler = (req: NodeServerRequest, res: NodeServerResponse) => void | Promise<void>;
type NodeHTTPMiddleware = (req: NodeServerRequest, res: NodeServerResponse, next: (error?: Error) => void) => unknown | Promise<unknown>;
type CloudflareFetchHandler = CF.ExportedHandlerFetchHandler;
//#endregion
export { BunFetchHandler, CloudflareFetchHandler, DenoFetchHandler, ErrorHandler, FastResponse, FastURL, FetchHandler, NodeHTTPMiddleware, NodeHttpHandler, NodeServerRequest, NodeServerResponse, Server, ServerHandler, ServerMiddleware, ServerOptions, ServerPlugin, ServerRequest, ServerRequestContext, ServerRuntimeContext, serve };