feat: init
This commit is contained in:
19
node_modules/srvx/dist/adapters/aws-lambda.d.mts
generated
vendored
Normal file
19
node_modules/srvx/dist/adapters/aws-lambda.d.mts
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
import { FetchHandler, ServerOptions } from "../types.mjs";
|
||||
import * as AWS from "aws-lambda";
|
||||
|
||||
//#region src/adapters/_aws/utils.d.ts
|
||||
type AWSLambdaResponseStream = NodeJS.WritableStream & {
|
||||
setContentType(contentType: string): void;
|
||||
};
|
||||
//#endregion
|
||||
//#region src/adapters/aws-lambda.d.ts
|
||||
type MaybePromise<T> = T | Promise<T>;
|
||||
type AwsLambdaEvent = AWS.APIGatewayProxyEvent | AWS.APIGatewayProxyEventV2;
|
||||
type AWSLambdaHandler = (event: AwsLambdaEvent, context: AWS.Context) => MaybePromise<AWS.APIGatewayProxyResult | AWS.APIGatewayProxyResultV2>;
|
||||
type AWSLambdaStreamingHandler = (event: AwsLambdaEvent, responseStream: AWSLambdaResponseStream, context: AWS.Context) => MaybePromise<void>;
|
||||
declare function toLambdaHandler(options: ServerOptions): AWSLambdaHandler;
|
||||
declare function handleLambdaEvent(fetchHandler: FetchHandler, event: AwsLambdaEvent, context: AWS.Context): Promise<AWS.APIGatewayProxyResult | AWS.APIGatewayProxyResultV2>;
|
||||
declare function handleLambdaEventWithStream(fetchHandler: FetchHandler, event: AwsLambdaEvent, responseStream: AWSLambdaResponseStream, context: AWS.Context): Promise<void>;
|
||||
declare function invokeLambdaHandler(handler: AWSLambdaHandler, request: Request): Promise<Response>;
|
||||
//#endregion
|
||||
export { AWSLambdaHandler, type AWSLambdaResponseStream, AWSLambdaStreamingHandler, AwsLambdaEvent, handleLambdaEvent, handleLambdaEventWithStream, invokeLambdaHandler, toLambdaHandler };
|
||||
292
node_modules/srvx/dist/adapters/aws-lambda.mjs
generated
vendored
Normal file
292
node_modules/srvx/dist/adapters/aws-lambda.mjs
generated
vendored
Normal file
@@ -0,0 +1,292 @@
|
||||
import { r as wrapFetch, t as errorPlugin } from "../_chunks/_plugins.mjs";
|
||||
function awsRequest(event, context) {
|
||||
const req = new Request(awsEventURL(event), {
|
||||
method: awsEventMethod(event),
|
||||
headers: awsEventHeaders(event),
|
||||
body: awsEventBody(event)
|
||||
});
|
||||
req.runtime = {
|
||||
name: "aws-lambda",
|
||||
awsLambda: {
|
||||
event,
|
||||
context
|
||||
}
|
||||
};
|
||||
req.ip = awsEventIP(event);
|
||||
return req;
|
||||
}
|
||||
function awsEventMethod(event) {
|
||||
return event.httpMethod || event.requestContext?.http?.method || "GET";
|
||||
}
|
||||
function awsEventIP(event) {
|
||||
return event.requestContext?.http?.sourceIp || event.requestContext?.identity?.sourceIp;
|
||||
}
|
||||
function awsEventURL(event) {
|
||||
const hostname = event.headers.host || event.headers.Host || event.requestContext?.domainName || ".";
|
||||
const path = event.path || event.rawPath;
|
||||
const query = awsEventQuery(event);
|
||||
const protocol = (event.headers["X-Forwarded-Proto"] || event.headers["x-forwarded-proto"]) === "http" ? "http" : "https";
|
||||
return new URL(`${path}${query ? `?${query}` : ""}`, `${protocol}://${hostname}`);
|
||||
}
|
||||
function awsEventQuery(event) {
|
||||
if (typeof event.rawQueryString === "string") return event.rawQueryString;
|
||||
return stringifyQuery({
|
||||
...event.queryStringParameters,
|
||||
...event.multiValueQueryStringParameters
|
||||
});
|
||||
}
|
||||
function awsEventHeaders(event) {
|
||||
const headers = new Headers();
|
||||
for (const [key, value] of Object.entries(event.headers)) if (value) headers.set(key, value);
|
||||
if ("cookies" in event && event.cookies) for (const cookie of event.cookies) headers.append("cookie", cookie);
|
||||
return headers;
|
||||
}
|
||||
function awsEventBody(event) {
|
||||
if (!event.body) return;
|
||||
if (event.isBase64Encoded) return Buffer.from(event.body || "", "base64");
|
||||
return event.body;
|
||||
}
|
||||
function awsResponseHeaders(response, event) {
|
||||
const headers = Object.create(null);
|
||||
for (const [key, value] of response.headers) if (value) headers[key] = Array.isArray(value) ? value.join(",") : String(value);
|
||||
const cookies = response.headers.getSetCookie();
|
||||
if (cookies.length === 0) return { headers };
|
||||
return event?.version === "2.0" || !!event?.requestContext?.http ? {
|
||||
headers,
|
||||
cookies
|
||||
} : {
|
||||
headers,
|
||||
cookies,
|
||||
multiValueHeaders: { "set-cookie": cookies }
|
||||
};
|
||||
}
|
||||
async function awsResponseBody(response) {
|
||||
if (!response.body) return { body: "" };
|
||||
const buffer = await toBuffer(response.body);
|
||||
return isTextType(response.headers.get("content-type") || "") ? { body: buffer.toString("utf8") } : {
|
||||
body: buffer.toString("base64"),
|
||||
isBase64Encoded: true
|
||||
};
|
||||
}
|
||||
async function awsStreamResponse(response, responseStream, event) {
|
||||
const metadata = {
|
||||
statusCode: response.status,
|
||||
...awsResponseHeaders(response, event)
|
||||
};
|
||||
if (!metadata.headers["transfer-encoding"]) metadata.headers["transfer-encoding"] = "chunked";
|
||||
const writer = globalThis.awslambda.HttpResponseStream.from(responseStream, metadata);
|
||||
if (!response.body) {
|
||||
writer.end();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await streamToNodeStream(response.body, writer);
|
||||
} finally {
|
||||
writer.end();
|
||||
}
|
||||
}
|
||||
async function streamToNodeStream(body, writer) {
|
||||
const reader = body.getReader();
|
||||
try {
|
||||
let result = await reader.read();
|
||||
while (!result.done) {
|
||||
if (!writer.write(result.value)) await new Promise((resolve) => writer.once("drain", resolve));
|
||||
result = await reader.read();
|
||||
}
|
||||
} finally {
|
||||
reader.releaseLock();
|
||||
}
|
||||
}
|
||||
function isTextType(contentType = "") {
|
||||
return /^text\/|\/(javascript|json|xml)|utf-?8/i.test(contentType);
|
||||
}
|
||||
function toBuffer(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const chunks = [];
|
||||
data.pipeTo(new WritableStream({
|
||||
write(chunk) {
|
||||
chunks.push(chunk);
|
||||
},
|
||||
close() {
|
||||
resolve(Buffer.concat(chunks));
|
||||
},
|
||||
abort(reason) {
|
||||
reject(reason);
|
||||
}
|
||||
})).catch(reject);
|
||||
});
|
||||
}
|
||||
function stringifyQuery(obj) {
|
||||
const params = new URLSearchParams();
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
if (value == null) continue;
|
||||
if (Array.isArray(value)) for (const v of value) params.append(key, String(v));
|
||||
else params.append(key, String(value));
|
||||
}
|
||||
return params.toString();
|
||||
}
|
||||
async function requestToAwsEvent(request) {
|
||||
const url = new URL(request.url);
|
||||
const headers = {};
|
||||
const cookies = [];
|
||||
for (const [key, value] of request.headers) {
|
||||
if (key.toLowerCase() === "cookie") cookies.push(value);
|
||||
headers[key] = value;
|
||||
}
|
||||
let body;
|
||||
let isBase64Encoded = false;
|
||||
if (request.body) {
|
||||
const buffer = await toBuffer(request.body);
|
||||
if (isTextType(request.headers.get("content-type") || "")) body = buffer.toString("utf8");
|
||||
else {
|
||||
body = buffer.toString("base64");
|
||||
isBase64Encoded = true;
|
||||
}
|
||||
}
|
||||
const now = Date.now();
|
||||
return {
|
||||
httpMethod: request.method,
|
||||
path: url.pathname,
|
||||
resource: url.pathname,
|
||||
queryStringParameters: Object.fromEntries(url.searchParams),
|
||||
multiValueQueryStringParameters: parseMultiValueQuery(url.searchParams),
|
||||
pathParameters: void 0,
|
||||
stageVariables: void 0,
|
||||
multiValueHeaders: Object.fromEntries([...request.headers].map(([k, v]) => [k, [v]])),
|
||||
version: "2.0",
|
||||
rawPath: url.pathname,
|
||||
rawQueryString: url.search.slice(1),
|
||||
cookies: cookies.length > 0 ? cookies : void 0,
|
||||
routeKey: `${request.method} ${url.pathname}`,
|
||||
headers,
|
||||
body: body ?? null,
|
||||
isBase64Encoded,
|
||||
requestContext: {
|
||||
accountId: "000000000000",
|
||||
apiId: "local",
|
||||
resourceId: "local",
|
||||
stage: "$default",
|
||||
requestId: crypto.randomUUID(),
|
||||
identity: {
|
||||
sourceIp: "127.0.0.1",
|
||||
userAgent: request.headers.get("user-agent") || "",
|
||||
accessKey: null,
|
||||
accountId: null,
|
||||
apiKey: null,
|
||||
apiKeyId: null,
|
||||
caller: null,
|
||||
clientCert: null,
|
||||
cognitoAuthenticationProvider: null,
|
||||
cognitoAuthenticationType: null,
|
||||
cognitoIdentityId: null,
|
||||
cognitoIdentityPoolId: null,
|
||||
principalOrgId: null,
|
||||
user: null,
|
||||
userArn: null
|
||||
},
|
||||
resourcePath: url.pathname,
|
||||
httpMethod: request.method,
|
||||
path: url.pathname,
|
||||
protocol: "HTTP/1.1",
|
||||
requestTimeEpoch: now,
|
||||
authorizer: void 0,
|
||||
domainName: url.hostname,
|
||||
http: {
|
||||
method: request.method,
|
||||
path: url.pathname,
|
||||
protocol: "HTTP/1.1",
|
||||
sourceIp: "127.0.0.1",
|
||||
userAgent: request.headers.get("user-agent") || ""
|
||||
},
|
||||
routeKey: `${request.method} ${url.pathname}`,
|
||||
time: new Date(now).toISOString(),
|
||||
timeEpoch: now,
|
||||
domainPrefix: url.hostname.split(".")[0]
|
||||
}
|
||||
};
|
||||
}
|
||||
function parseMultiValueQuery(params) {
|
||||
const result = {};
|
||||
for (const [key, value] of params) {
|
||||
if (!result[key]) result[key] = [];
|
||||
result[key].push(value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function awsResultToResponse(result) {
|
||||
if (typeof result === "string") return new Response(result, { status: 200 });
|
||||
const headers = new Headers();
|
||||
if (result.headers) {
|
||||
for (const [key, value] of Object.entries(result.headers)) if (value !== void 0) headers.set(key, String(value));
|
||||
}
|
||||
if ("multiValueHeaders" in result && result.multiValueHeaders) {
|
||||
for (const [key, values] of Object.entries(result.multiValueHeaders)) if (values) for (const value of values) headers.append(key, String(value));
|
||||
}
|
||||
if ("cookies" in result && result.cookies) for (const cookie of result.cookies) headers.append("set-cookie", cookie);
|
||||
let body;
|
||||
if (typeof result.body === "string") if (result.isBase64Encoded) body = Buffer.from(result.body, "base64");
|
||||
else body = result.body;
|
||||
const statusCode = typeof result.statusCode === "number" ? result.statusCode : 200;
|
||||
return new Response(body, {
|
||||
status: statusCode,
|
||||
headers
|
||||
});
|
||||
}
|
||||
function createMockContext() {
|
||||
const id = crypto.randomUUID();
|
||||
return {
|
||||
callbackWaitsForEmptyEventLoop: true,
|
||||
functionName: "local",
|
||||
functionVersion: "$LATEST",
|
||||
invokedFunctionArn: `arn:aws:lambda:us-east-1:000000000000:function:local`,
|
||||
memoryLimitInMB: "128",
|
||||
awsRequestId: id,
|
||||
logGroupName: "/aws/lambda/local",
|
||||
logStreamName: `${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}/[$LATEST]${id}`,
|
||||
getRemainingTimeInMillis: () => 3e4,
|
||||
done: () => {},
|
||||
fail: () => {},
|
||||
succeed: () => {}
|
||||
};
|
||||
}
|
||||
function toLambdaHandler(options) {
|
||||
const server = new AWSLambdaServer(options);
|
||||
return (event, context) => server.fetch(event, context);
|
||||
}
|
||||
async function handleLambdaEvent(fetchHandler, event, context) {
|
||||
const response = await fetchHandler(awsRequest(event, context));
|
||||
return {
|
||||
statusCode: response.status,
|
||||
...awsResponseHeaders(response, event),
|
||||
...await awsResponseBody(response)
|
||||
};
|
||||
}
|
||||
async function handleLambdaEventWithStream(fetchHandler, event, responseStream, context) {
|
||||
await awsStreamResponse(await fetchHandler(awsRequest(event, context)), responseStream, event);
|
||||
}
|
||||
async function invokeLambdaHandler(handler, request) {
|
||||
return awsResultToResponse(await handler(await requestToAwsEvent(request), createMockContext()));
|
||||
}
|
||||
var AWSLambdaServer = class {
|
||||
runtime = "aws-lambda";
|
||||
options;
|
||||
fetch;
|
||||
constructor(options) {
|
||||
this.options = {
|
||||
...options,
|
||||
middleware: [...options.middleware || []]
|
||||
};
|
||||
for (const plugin of options.plugins || []) plugin(this);
|
||||
errorPlugin(this);
|
||||
const fetchHandler = wrapFetch(this);
|
||||
this.fetch = (event, context) => handleLambdaEvent(fetchHandler, event, context);
|
||||
}
|
||||
serve() {}
|
||||
ready() {
|
||||
return Promise.resolve().then(() => this);
|
||||
}
|
||||
close() {
|
||||
return Promise.resolve();
|
||||
}
|
||||
};
|
||||
export { handleLambdaEvent, handleLambdaEventWithStream, invokeLambdaHandler, toLambdaHandler };
|
||||
22
node_modules/srvx/dist/adapters/bun.d.mts
generated
vendored
Normal file
22
node_modules/srvx/dist/adapters/bun.d.mts
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
import { BunFetchHandler, Server, ServerOptions } from "../types.mjs";
|
||||
import { t as FastURL } from "../_chunks/_url.mjs";
|
||||
import * as bun from "bun";
|
||||
|
||||
//#region src/adapters/bun.d.ts
|
||||
declare const FastResponse: typeof globalThis.Response;
|
||||
declare function serve(options: ServerOptions): BunServer;
|
||||
declare class BunServer implements Server<BunFetchHandler> {
|
||||
#private;
|
||||
readonly runtime = "bun";
|
||||
readonly options: Server["options"];
|
||||
readonly bun: Server["bun"];
|
||||
readonly serveOptions: bun.Serve.Options<any> | undefined;
|
||||
readonly fetch: BunFetchHandler;
|
||||
constructor(options: ServerOptions);
|
||||
serve(): Promise<this>;
|
||||
get url(): string | undefined;
|
||||
ready(): Promise<this>;
|
||||
close(closeAll?: boolean): Promise<void>;
|
||||
}
|
||||
//#endregion
|
||||
export { FastResponse, FastURL, serve };
|
||||
84
node_modules/srvx/dist/adapters/bun.mjs
generated
vendored
Normal file
84
node_modules/srvx/dist/adapters/bun.mjs
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
import { t as FastURL } from "../_chunks/_url.mjs";
|
||||
import { a as resolveTLSOptions, i as resolvePortAndHost, n as fmtURL, r as printListening, t as createWaitUntil } from "../_chunks/_utils2.mjs";
|
||||
import { n as gracefulShutdownPlugin, r as wrapFetch } from "../_chunks/_plugins.mjs";
|
||||
const FastResponse = Response;
|
||||
function serve(options) {
|
||||
return new BunServer(options);
|
||||
}
|
||||
var BunServer = class {
|
||||
runtime = "bun";
|
||||
options;
|
||||
bun = {};
|
||||
serveOptions;
|
||||
fetch;
|
||||
#wait;
|
||||
constructor(options) {
|
||||
this.options = {
|
||||
...options,
|
||||
middleware: [...options.middleware || []]
|
||||
};
|
||||
for (const plugin of options.plugins || []) plugin(this);
|
||||
gracefulShutdownPlugin(this);
|
||||
const fetchHandler = wrapFetch(this);
|
||||
const loader = globalThis.__srvxLoader__;
|
||||
if (loader) {
|
||||
this.fetch = fetchHandler;
|
||||
loader(fetchHandler);
|
||||
return;
|
||||
}
|
||||
this.#wait = createWaitUntil();
|
||||
this.fetch = (request, server) => {
|
||||
Object.defineProperties(request, {
|
||||
waitUntil: { value: this.#wait?.waitUntil },
|
||||
runtime: {
|
||||
enumerable: true,
|
||||
value: {
|
||||
name: "bun",
|
||||
bun: { server }
|
||||
}
|
||||
},
|
||||
ip: {
|
||||
enumerable: true,
|
||||
get() {
|
||||
return server?.requestIP(request)?.address;
|
||||
}
|
||||
}
|
||||
});
|
||||
return fetchHandler(request);
|
||||
};
|
||||
const tls = resolveTLSOptions(this.options);
|
||||
this.serveOptions = {
|
||||
...resolvePortAndHost(this.options),
|
||||
reusePort: this.options.reusePort,
|
||||
error: this.options.error,
|
||||
...this.options.bun,
|
||||
tls: {
|
||||
cert: tls?.cert,
|
||||
key: tls?.key,
|
||||
passphrase: tls?.passphrase,
|
||||
...this.options.bun?.tls
|
||||
},
|
||||
fetch: this.fetch
|
||||
};
|
||||
if (!options.manual) this.serve();
|
||||
}
|
||||
serve() {
|
||||
if (!this.bun.server) this.bun.server = Bun.serve(this.serveOptions);
|
||||
printListening(this.options, this.url);
|
||||
return Promise.resolve(this);
|
||||
}
|
||||
get url() {
|
||||
const server = this.bun?.server;
|
||||
if (!server) return;
|
||||
const address = server.address;
|
||||
if (address) return fmtURL(address.address, address.port, server.protocol === "https");
|
||||
return server.url.href;
|
||||
}
|
||||
ready() {
|
||||
return Promise.resolve(this);
|
||||
}
|
||||
async close(closeAll) {
|
||||
await Promise.all([this.#wait?.wait(), Promise.resolve(this.bun?.server?.stop(closeAll))]);
|
||||
}
|
||||
};
|
||||
export { FastResponse, FastURL, serve };
|
||||
9
node_modules/srvx/dist/adapters/cloudflare.d.mts
generated
vendored
Normal file
9
node_modules/srvx/dist/adapters/cloudflare.d.mts
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import { Server, ServerOptions } from "../types.mjs";
|
||||
import * as CF from "@cloudflare/workers-types";
|
||||
|
||||
//#region src/adapters/cloudflare.d.ts
|
||||
declare const FastURL: typeof globalThis.URL;
|
||||
declare const FastResponse: typeof globalThis.Response;
|
||||
declare function serve(options: ServerOptions): Server<CF.ExportedHandlerFetchHandler>;
|
||||
//#endregion
|
||||
export { FastResponse, FastURL, serve };
|
||||
57
node_modules/srvx/dist/adapters/cloudflare.mjs
generated
vendored
Normal file
57
node_modules/srvx/dist/adapters/cloudflare.mjs
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
import { r as wrapFetch, t as errorPlugin } from "../_chunks/_plugins.mjs";
|
||||
const FastURL = URL;
|
||||
const FastResponse = Response;
|
||||
function serve(options) {
|
||||
return new CloudflareServer(options);
|
||||
}
|
||||
var CloudflareServer = class {
|
||||
runtime = "cloudflare";
|
||||
options;
|
||||
serveOptions;
|
||||
fetch;
|
||||
constructor(options) {
|
||||
this.options = {
|
||||
...options,
|
||||
middleware: [...options.middleware || []]
|
||||
};
|
||||
for (const plugin of options.plugins || []) plugin(this);
|
||||
errorPlugin(this);
|
||||
const fetchHandler = wrapFetch(this);
|
||||
this.fetch = (request, env, context) => {
|
||||
Object.defineProperties(request, {
|
||||
waitUntil: { value: context.waitUntil.bind(context) },
|
||||
runtime: {
|
||||
enumerable: true,
|
||||
value: {
|
||||
name: "cloudflare",
|
||||
cloudflare: {
|
||||
env,
|
||||
context
|
||||
}
|
||||
}
|
||||
},
|
||||
ip: {
|
||||
enumerable: true,
|
||||
get() {
|
||||
return request.headers.get("cf-connecting-ip");
|
||||
}
|
||||
}
|
||||
});
|
||||
return fetchHandler(request);
|
||||
};
|
||||
this.serveOptions = { fetch: this.fetch };
|
||||
if (!options.manual) this.serve();
|
||||
}
|
||||
serve() {
|
||||
addEventListener("fetch", (event) => {
|
||||
event.respondWith(this.fetch(event.request, {}, event));
|
||||
});
|
||||
}
|
||||
ready() {
|
||||
return Promise.resolve().then(() => this);
|
||||
}
|
||||
close() {
|
||||
return Promise.resolve();
|
||||
}
|
||||
};
|
||||
export { FastResponse, FastURL, serve };
|
||||
21
node_modules/srvx/dist/adapters/deno.d.mts
generated
vendored
Normal file
21
node_modules/srvx/dist/adapters/deno.d.mts
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
import { DenoFetchHandler, Server, ServerOptions } from "../types.mjs";
|
||||
import { t as FastURL } from "../_chunks/_url.mjs";
|
||||
|
||||
//#region src/adapters/deno.d.ts
|
||||
declare const FastResponse: typeof globalThis.Response;
|
||||
declare function serve(options: ServerOptions): DenoServer;
|
||||
declare class DenoServer implements Server<DenoFetchHandler> {
|
||||
#private;
|
||||
readonly runtime = "deno";
|
||||
readonly options: Server["options"];
|
||||
readonly deno: Server["deno"];
|
||||
readonly serveOptions: Deno.ServeTcpOptions | (Deno.ServeTcpOptions & Deno.TlsCertifiedKeyPem) | undefined;
|
||||
readonly fetch: DenoFetchHandler;
|
||||
constructor(options: ServerOptions);
|
||||
serve(): Promise<this>;
|
||||
get url(): string | undefined;
|
||||
ready(): Promise<Server>;
|
||||
close(): Promise<void>;
|
||||
}
|
||||
//#endregion
|
||||
export { FastResponse, FastURL, serve };
|
||||
93
node_modules/srvx/dist/adapters/deno.mjs
generated
vendored
Normal file
93
node_modules/srvx/dist/adapters/deno.mjs
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
import { t as FastURL } from "../_chunks/_url.mjs";
|
||||
import { a as resolveTLSOptions, i as resolvePortAndHost, n as fmtURL, r as printListening, t as createWaitUntil } from "../_chunks/_utils2.mjs";
|
||||
import { n as gracefulShutdownPlugin, r as wrapFetch } from "../_chunks/_plugins.mjs";
|
||||
const FastResponse = Response;
|
||||
function serve(options) {
|
||||
return new DenoServer(options);
|
||||
}
|
||||
var DenoServer = class {
|
||||
runtime = "deno";
|
||||
options;
|
||||
deno = {};
|
||||
serveOptions;
|
||||
fetch;
|
||||
#listeningPromise;
|
||||
#listeningInfo;
|
||||
#wait;
|
||||
constructor(options) {
|
||||
this.options = {
|
||||
...options,
|
||||
middleware: [...options.middleware || []]
|
||||
};
|
||||
for (const plugin of options.plugins || []) plugin(this);
|
||||
gracefulShutdownPlugin(this);
|
||||
const fetchHandler = wrapFetch(this);
|
||||
const loader = globalThis.__srvxLoader__;
|
||||
if (loader) {
|
||||
this.fetch = fetchHandler;
|
||||
loader(fetchHandler);
|
||||
return;
|
||||
}
|
||||
this.#wait = createWaitUntil();
|
||||
this.fetch = (request, info) => {
|
||||
Object.defineProperties(request, {
|
||||
waitUntil: { value: this.#wait?.waitUntil },
|
||||
runtime: {
|
||||
enumerable: true,
|
||||
value: {
|
||||
name: "deno",
|
||||
deno: {
|
||||
info,
|
||||
server: this.deno?.server
|
||||
}
|
||||
}
|
||||
},
|
||||
ip: {
|
||||
enumerable: true,
|
||||
get() {
|
||||
return (info?.remoteAddr)?.hostname;
|
||||
}
|
||||
}
|
||||
});
|
||||
return fetchHandler(request);
|
||||
};
|
||||
const tls = resolveTLSOptions(this.options);
|
||||
this.serveOptions = {
|
||||
...resolvePortAndHost(this.options),
|
||||
reusePort: this.options.reusePort,
|
||||
onError: this.options.error,
|
||||
...tls ? {
|
||||
key: tls.key,
|
||||
cert: tls.cert,
|
||||
passphrase: tls.passphrase
|
||||
} : {},
|
||||
...this.options.deno
|
||||
};
|
||||
if (!options.manual) this.serve();
|
||||
}
|
||||
serve() {
|
||||
if (this.deno?.server) return Promise.resolve(this.#listeningPromise).then(() => this);
|
||||
const onListenPromise = Promise.withResolvers();
|
||||
this.#listeningPromise = onListenPromise.promise;
|
||||
this.deno.server = Deno.serve({
|
||||
...this.serveOptions,
|
||||
onListen: (info) => {
|
||||
this.#listeningInfo = info;
|
||||
if (this.options.deno?.onListen) this.options.deno.onListen(info);
|
||||
printListening(this.options, this.url);
|
||||
onListenPromise.resolve();
|
||||
}
|
||||
}, this.fetch);
|
||||
return Promise.resolve(this.#listeningPromise).then(() => this);
|
||||
}
|
||||
get url() {
|
||||
return this.#listeningInfo ? fmtURL(this.#listeningInfo.hostname, this.#listeningInfo.port, !!this.serveOptions.cert) : void 0;
|
||||
}
|
||||
ready() {
|
||||
return Promise.resolve(this.#listeningPromise).then(() => this);
|
||||
}
|
||||
async close() {
|
||||
await Promise.all([this.#wait?.wait(), Promise.resolve(this.deno?.server?.shutdown())]);
|
||||
}
|
||||
};
|
||||
export { FastResponse, FastURL, serve };
|
||||
8
node_modules/srvx/dist/adapters/generic.d.mts
generated
vendored
Normal file
8
node_modules/srvx/dist/adapters/generic.d.mts
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import { Server, ServerOptions } from "../types.mjs";
|
||||
|
||||
//#region src/adapters/generic.d.ts
|
||||
declare const FastURL: typeof globalThis.URL;
|
||||
declare const FastResponse: typeof globalThis.Response;
|
||||
declare function serve(options: ServerOptions): Server;
|
||||
//#endregion
|
||||
export { FastResponse, FastURL, serve };
|
||||
35
node_modules/srvx/dist/adapters/generic.mjs
generated
vendored
Normal file
35
node_modules/srvx/dist/adapters/generic.mjs
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
import { t as createWaitUntil } from "../_chunks/_utils2.mjs";
|
||||
import { r as wrapFetch, t as errorPlugin } from "../_chunks/_plugins.mjs";
|
||||
const FastURL = URL;
|
||||
const FastResponse = Response;
|
||||
function serve(options) {
|
||||
return new GenericServer(options);
|
||||
}
|
||||
var GenericServer = class {
|
||||
runtime = "generic";
|
||||
options;
|
||||
fetch;
|
||||
#wait;
|
||||
constructor(options) {
|
||||
this.options = {
|
||||
...options,
|
||||
middleware: [...options.middleware || []]
|
||||
};
|
||||
for (const plugin of options.plugins || []) plugin(this);
|
||||
errorPlugin(this);
|
||||
this.#wait = createWaitUntil();
|
||||
const fetchHandler = wrapFetch(this);
|
||||
this.fetch = (request) => {
|
||||
Object.defineProperties(request, { waitUntil: { value: this.#wait.waitUntil } });
|
||||
return Promise.resolve(fetchHandler(request));
|
||||
};
|
||||
}
|
||||
serve() {}
|
||||
ready() {
|
||||
return Promise.resolve(this);
|
||||
}
|
||||
async close() {
|
||||
await this.#wait.wait();
|
||||
}
|
||||
};
|
||||
export { FastResponse, FastURL, serve };
|
||||
78
node_modules/srvx/dist/adapters/node.d.mts
generated
vendored
Normal file
78
node_modules/srvx/dist/adapters/node.d.mts
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
import { FetchHandler, NodeHttpHandler, NodeServerRequest, NodeServerResponse, Server, ServerOptions, ServerRequest } from "../types.mjs";
|
||||
import { t as FastURL } from "../_chunks/_url.mjs";
|
||||
import { Readable } from "node:stream";
|
||||
|
||||
//#region src/adapters/_node/request.d.ts
|
||||
type NodeRequestContext = {
|
||||
req: NodeServerRequest;
|
||||
res?: NodeServerResponse;
|
||||
};
|
||||
declare const NodeRequest: {
|
||||
new (nodeCtx: NodeRequestContext): ServerRequest;
|
||||
};
|
||||
/**
|
||||
* Undici uses an incompatible Request constructor depending on private property accessors.
|
||||
*
|
||||
* This utility, patches global Request to support `new Request(req)` in Node.js.
|
||||
*
|
||||
* Alternatively you can use `new Request(req._request || req)` instead of patching global Request.
|
||||
*/
|
||||
declare function patchGlobalRequest(): typeof Request;
|
||||
//#endregion
|
||||
//#region src/adapters/_node/response.d.ts
|
||||
type PreparedNodeResponseBody = string | Buffer | Uint8Array | DataView | ReadableStream | Readable | undefined | null;
|
||||
interface PreparedNodeResponse {
|
||||
status: number;
|
||||
statusText: string;
|
||||
headers: [string, string][];
|
||||
body: PreparedNodeResponseBody;
|
||||
}
|
||||
/**
|
||||
* Fast Response for Node.js runtime
|
||||
*
|
||||
* It is faster because in most cases it doesn't create a full Response instance.
|
||||
*/
|
||||
declare const NodeResponse: {
|
||||
new (body?: BodyInit | null, init?: ResponseInit): globalThis.Response & {
|
||||
_toNodeResponse: () => PreparedNodeResponse;
|
||||
};
|
||||
};
|
||||
type NodeResponse = InstanceType<typeof NodeResponse>;
|
||||
//#endregion
|
||||
//#region src/adapters/_node/send.d.ts
|
||||
declare function sendNodeResponse(nodeRes: NodeServerResponse, webRes: Response | NodeResponse): Promise<void>;
|
||||
//#endregion
|
||||
//#region src/adapters/_node/web/fetch.d.ts
|
||||
/**
|
||||
* Calls a Node.js HTTP Request handler with a Fetch API Request object and returns a Response object.
|
||||
*
|
||||
* If the web Request contains an existing Node.js req/res pair (indicating it originated from a Node.js server from srvx/node), it will be called directly.
|
||||
*
|
||||
* Otherwise, new Node.js IncomingMessage and ServerResponse objects are created and linked to a custom Duplex stream that bridges the Fetch API streams with Node.js streams.
|
||||
*
|
||||
* The handler is invoked with these objects, and the response is constructed from the ServerResponse once it is finished.
|
||||
*
|
||||
* @experimental Behavior might be unstable.
|
||||
*/
|
||||
declare function fetchNodeHandler(handler: NodeHttpHandler, req: ServerRequest): Promise<Response>;
|
||||
//#endregion
|
||||
//#region src/adapters/_node/adapter.d.ts
|
||||
type AdapterMeta = {
|
||||
__nodeHandler?: NodeHttpHandler;
|
||||
__fetchHandler?: FetchHandler;
|
||||
};
|
||||
/**
|
||||
* Converts a Fetch API handler to a Node.js HTTP handler.
|
||||
*/
|
||||
declare function toNodeHandler(handler: FetchHandler & AdapterMeta): NodeHttpHandler & AdapterMeta;
|
||||
/**
|
||||
* Converts a Node.js HTTP handler into a Fetch API handler.
|
||||
*
|
||||
* @experimental Behavior might be unstable and won't work in Bun and Deno currently (tracker: https://github.com/h3js/srvx/issues/132)
|
||||
*/
|
||||
declare function toFetchHandler(handler: NodeHttpHandler & AdapterMeta): FetchHandler & AdapterMeta;
|
||||
//#endregion
|
||||
//#region src/adapters/node.d.ts
|
||||
declare function serve(options: ServerOptions): Server;
|
||||
//#endregion
|
||||
export { type AdapterMeta, NodeResponse as FastResponse, NodeResponse, FastURL, NodeRequest, fetchNodeHandler, patchGlobalRequest, sendNodeResponse, serve, toFetchHandler, toNodeHandler };
|
||||
744
node_modules/srvx/dist/adapters/node.mjs
generated
vendored
Normal file
744
node_modules/srvx/dist/adapters/node.mjs
generated
vendored
Normal file
@@ -0,0 +1,744 @@
|
||||
import { n as lazyInherit, t as FastURL } from "../_chunks/_url.mjs";
|
||||
import { a as resolveTLSOptions, i as resolvePortAndHost, n as fmtURL, r as printListening, t as createWaitUntil } from "../_chunks/_utils2.mjs";
|
||||
import { n as gracefulShutdownPlugin, r as wrapFetch, t as errorPlugin } from "../_chunks/_plugins.mjs";
|
||||
import nodeHTTP, { IncomingMessage, ServerResponse } from "node:http";
|
||||
import { Duplex, PassThrough, Readable } from "node:stream";
|
||||
import nodeHTTPS from "node:https";
|
||||
import nodeHTTP2 from "node:http2";
|
||||
async function sendNodeResponse(nodeRes, webRes) {
|
||||
if (!webRes) {
|
||||
nodeRes.statusCode = 500;
|
||||
return endNodeResponse(nodeRes);
|
||||
}
|
||||
if (webRes._toNodeResponse) {
|
||||
const res = webRes._toNodeResponse();
|
||||
writeHead(nodeRes, res.status, res.statusText, res.headers);
|
||||
if (res.body) {
|
||||
if (res.body instanceof ReadableStream) return streamBody(res.body, nodeRes);
|
||||
else if (typeof res.body?.pipe === "function") {
|
||||
res.body.pipe(nodeRes);
|
||||
return new Promise((resolve) => nodeRes.on("close", resolve));
|
||||
}
|
||||
nodeRes.write(res.body);
|
||||
}
|
||||
return endNodeResponse(nodeRes);
|
||||
}
|
||||
const rawHeaders = [...webRes.headers];
|
||||
writeHead(nodeRes, webRes.status, webRes.statusText, rawHeaders);
|
||||
return webRes.body ? streamBody(webRes.body, nodeRes) : endNodeResponse(nodeRes);
|
||||
}
|
||||
function writeHead(nodeRes, status, statusText, rawHeaders) {
|
||||
const writeHeaders = globalThis.Deno ? rawHeaders : rawHeaders.flat();
|
||||
if (!nodeRes.headersSent) if (nodeRes.req?.httpVersion === "2.0") nodeRes.writeHead(status, writeHeaders);
|
||||
else nodeRes.writeHead(status, statusText, writeHeaders);
|
||||
}
|
||||
function endNodeResponse(nodeRes) {
|
||||
return new Promise((resolve) => nodeRes.end(resolve));
|
||||
}
|
||||
function streamBody(stream, nodeRes) {
|
||||
if (nodeRes.destroyed) {
|
||||
stream.cancel();
|
||||
return;
|
||||
}
|
||||
const reader = stream.getReader();
|
||||
function streamCancel(error) {
|
||||
reader.cancel(error).catch(() => {});
|
||||
if (error) nodeRes.destroy(error);
|
||||
}
|
||||
function streamHandle({ done, value }) {
|
||||
try {
|
||||
if (done) nodeRes.end();
|
||||
else if (nodeRes.write(value)) reader.read().then(streamHandle, streamCancel);
|
||||
else nodeRes.once("drain", () => reader.read().then(streamHandle, streamCancel));
|
||||
} catch (error) {
|
||||
streamCancel(error instanceof Error ? error : void 0);
|
||||
}
|
||||
}
|
||||
nodeRes.on("close", streamCancel);
|
||||
nodeRes.on("error", streamCancel);
|
||||
reader.read().then(streamHandle, streamCancel);
|
||||
return reader.closed.catch(streamCancel).finally(() => {
|
||||
nodeRes.off("close", streamCancel);
|
||||
nodeRes.off("error", streamCancel);
|
||||
});
|
||||
}
|
||||
var NodeRequestURL = class extends FastURL {
|
||||
#req;
|
||||
constructor({ req }) {
|
||||
const path = req.url || "/";
|
||||
if (path[0] === "/") {
|
||||
const qIndex = path.indexOf("?");
|
||||
const pathname = qIndex === -1 ? path : path?.slice(0, qIndex) || "/";
|
||||
const search = qIndex === -1 ? "" : path?.slice(qIndex) || "";
|
||||
const host = req.headers.host || req.headers[":authority"] || `${req.socket.localFamily === "IPv6" ? "[" + req.socket.localAddress + "]" : req.socket.localAddress}:${req.socket?.localPort || "80"}`;
|
||||
const protocol = req.socket?.encrypted || req.headers["x-forwarded-proto"] === "https" || req.headers[":scheme"] === "https" ? "https:" : "http:";
|
||||
super({
|
||||
protocol,
|
||||
host,
|
||||
pathname,
|
||||
search
|
||||
});
|
||||
} else super(path);
|
||||
this.#req = req;
|
||||
}
|
||||
get pathname() {
|
||||
return super.pathname;
|
||||
}
|
||||
set pathname(value) {
|
||||
this._url.pathname = value;
|
||||
this.#req.url = this._url.pathname + this._url.search;
|
||||
}
|
||||
};
|
||||
const NodeRequestHeaders = /* @__PURE__ */ (() => {
|
||||
const NativeHeaders = globalThis.Headers;
|
||||
class Headers {
|
||||
#req;
|
||||
#headers;
|
||||
constructor(req) {
|
||||
this.#req = req;
|
||||
}
|
||||
static [Symbol.hasInstance](val) {
|
||||
return val instanceof NativeHeaders;
|
||||
}
|
||||
get _headers() {
|
||||
if (!this.#headers) {
|
||||
const headers = new NativeHeaders();
|
||||
const rawHeaders = this.#req.rawHeaders;
|
||||
const len = rawHeaders.length;
|
||||
for (let i = 0; i < len; i += 2) {
|
||||
const key = rawHeaders[i];
|
||||
if (key.charCodeAt(0) === 58) continue;
|
||||
const value = rawHeaders[i + 1];
|
||||
headers.append(key, value);
|
||||
}
|
||||
this.#headers = headers;
|
||||
}
|
||||
return this.#headers;
|
||||
}
|
||||
get(name) {
|
||||
if (this.#headers) return this.#headers.get(name);
|
||||
const value = this.#req.headers[name.toLowerCase()];
|
||||
return Array.isArray(value) ? value.join(", ") : value || null;
|
||||
}
|
||||
has(name) {
|
||||
if (this.#headers) return this.#headers.has(name);
|
||||
return name.toLowerCase() in this.#req.headers;
|
||||
}
|
||||
getSetCookie() {
|
||||
if (this.#headers) return this.#headers.getSetCookie();
|
||||
const value = this.#req.headers["set-cookie"];
|
||||
return Array.isArray(value) ? value : value ? [value] : [];
|
||||
}
|
||||
*_entries() {
|
||||
const rawHeaders = this.#req.rawHeaders;
|
||||
const len = rawHeaders.length;
|
||||
for (let i = 0; i < len; i += 2) {
|
||||
const key = rawHeaders[i];
|
||||
if (key.charCodeAt(0) === 58) continue;
|
||||
yield [key.toLowerCase(), rawHeaders[i + 1]];
|
||||
}
|
||||
}
|
||||
entries() {
|
||||
return this.#headers ? this.#headers.entries() : this._entries();
|
||||
}
|
||||
[Symbol.iterator]() {
|
||||
return this.entries();
|
||||
}
|
||||
}
|
||||
lazyInherit(Headers.prototype, NativeHeaders.prototype, "_headers");
|
||||
Object.setPrototypeOf(Headers, NativeHeaders);
|
||||
Object.setPrototypeOf(Headers.prototype, NativeHeaders.prototype);
|
||||
return Headers;
|
||||
})();
|
||||
const NodeRequest = /* @__PURE__ */ (() => {
|
||||
const NativeRequest = globalThis.Request;
|
||||
class Request {
|
||||
runtime;
|
||||
#req;
|
||||
#url;
|
||||
#bodyStream;
|
||||
#request;
|
||||
#headers;
|
||||
#abortController;
|
||||
constructor(ctx) {
|
||||
this.#req = ctx.req;
|
||||
this.runtime = {
|
||||
name: "node",
|
||||
node: ctx
|
||||
};
|
||||
}
|
||||
static [Symbol.hasInstance](val) {
|
||||
return val instanceof NativeRequest;
|
||||
}
|
||||
get ip() {
|
||||
return this.#req.socket?.remoteAddress;
|
||||
}
|
||||
get method() {
|
||||
if (this.#request) return this.#request.method;
|
||||
return this.#req.method || "GET";
|
||||
}
|
||||
get _url() {
|
||||
return this.#url ||= new NodeRequestURL({ req: this.#req });
|
||||
}
|
||||
set _url(url) {
|
||||
this.#url = url;
|
||||
}
|
||||
get url() {
|
||||
if (this.#request) return this.#request.url;
|
||||
return this._url.href;
|
||||
}
|
||||
get headers() {
|
||||
if (this.#request) return this.#request.headers;
|
||||
return this.#headers ||= new NodeRequestHeaders(this.#req);
|
||||
}
|
||||
get _abortController() {
|
||||
if (!this.#abortController) {
|
||||
this.#abortController = new AbortController();
|
||||
const { req, res } = this.runtime.node;
|
||||
const abortController = this.#abortController;
|
||||
const abort = (err) => abortController.abort?.(err);
|
||||
if (res) res.once("close", () => {
|
||||
const reqError = req.errored;
|
||||
if (reqError) abort(reqError);
|
||||
else if (!res.writableEnded) abort();
|
||||
});
|
||||
else req.once("close", () => {
|
||||
if (!req.complete) abort();
|
||||
});
|
||||
}
|
||||
return this.#abortController;
|
||||
}
|
||||
get signal() {
|
||||
return this.#request ? this.#request.signal : this._abortController.signal;
|
||||
}
|
||||
get body() {
|
||||
if (this.#request) return this.#request.body;
|
||||
if (this.#bodyStream === void 0) {
|
||||
const method = this.method;
|
||||
this.#bodyStream = !(method === "GET" || method === "HEAD") ? Readable.toWeb(this.#req) : null;
|
||||
}
|
||||
return this.#bodyStream;
|
||||
}
|
||||
text() {
|
||||
if (this.#request) return this.#request.text();
|
||||
if (this.#bodyStream !== void 0) return this.#bodyStream ? new Response(this.#bodyStream).text() : Promise.resolve("");
|
||||
return readBody(this.#req).then((buf) => buf.toString());
|
||||
}
|
||||
json() {
|
||||
if (this.#request) return this.#request.json();
|
||||
return this.text().then((text) => JSON.parse(text));
|
||||
}
|
||||
get _request() {
|
||||
if (!this.#request) {
|
||||
const body = this.body;
|
||||
this.#request = new NativeRequest(this.url, {
|
||||
method: this.method,
|
||||
headers: this.headers,
|
||||
signal: this._abortController.signal,
|
||||
body,
|
||||
duplex: body ? "half" : void 0
|
||||
});
|
||||
this.#headers = void 0;
|
||||
this.#bodyStream = void 0;
|
||||
}
|
||||
return this.#request;
|
||||
}
|
||||
}
|
||||
lazyInherit(Request.prototype, NativeRequest.prototype, "_request");
|
||||
Object.setPrototypeOf(Request.prototype, NativeRequest.prototype);
|
||||
return Request;
|
||||
})();
|
||||
function patchGlobalRequest() {
|
||||
const NativeRequest = globalThis[Symbol.for("srvx.nativeRequest")] ??= globalThis.Request;
|
||||
const PatchedRequest = class Request extends NativeRequest {
|
||||
static _srvx = true;
|
||||
static [Symbol.hasInstance](instance) {
|
||||
if (this === PatchedRequest) return instance instanceof NativeRequest;
|
||||
else return Object.prototype.isPrototypeOf.call(this.prototype, instance);
|
||||
}
|
||||
constructor(input, options) {
|
||||
if (typeof input === "object" && "_request" in input) input = input._request;
|
||||
super(input, options);
|
||||
}
|
||||
};
|
||||
if (!globalThis.Request._srvx) globalThis.Request = PatchedRequest;
|
||||
return PatchedRequest;
|
||||
}
|
||||
function readBody(req) {
|
||||
if ("rawBody" in req && Buffer.isBuffer(req.rawBody)) return Promise.resolve(req.rawBody);
|
||||
return new Promise((resolve, reject) => {
|
||||
const chunks = [];
|
||||
const onData = (chunk) => {
|
||||
chunks.push(chunk);
|
||||
};
|
||||
const onError = (err) => {
|
||||
reject(err);
|
||||
};
|
||||
const onEnd = () => {
|
||||
req.off("error", onError);
|
||||
req.off("data", onData);
|
||||
resolve(Buffer.concat(chunks));
|
||||
};
|
||||
req.on("data", onData).once("end", onEnd).once("error", onError);
|
||||
});
|
||||
}
|
||||
const NodeResponse = /* @__PURE__ */ (() => {
|
||||
const NativeResponse = globalThis.Response;
|
||||
const STATUS_CODES = globalThis.process?.getBuiltinModule?.("node:http")?.STATUS_CODES || {};
|
||||
class NodeResponse {
|
||||
#body;
|
||||
#init;
|
||||
#headers;
|
||||
#response;
|
||||
constructor(body, init) {
|
||||
this.#body = body;
|
||||
this.#init = init;
|
||||
}
|
||||
static [Symbol.hasInstance](val) {
|
||||
return val instanceof NativeResponse;
|
||||
}
|
||||
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;
|
||||
let body = this.#body;
|
||||
if (body && typeof body.pipe === "function" && !(body instanceof Readable)) {
|
||||
const stream = new PassThrough();
|
||||
body.pipe(stream);
|
||||
const abort = body.abort;
|
||||
if (abort) stream.once("close", () => abort());
|
||||
body = stream;
|
||||
}
|
||||
this.#response = new NativeResponse(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;
|
||||
}
|
||||
_toNodeResponse() {
|
||||
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 headers = [];
|
||||
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 (Array.isArray(value)) for (const v of value) headers.push([key, v]);
|
||||
else headers.push([key, value]);
|
||||
if (key === "content-type") hasContentTypeHeader = true;
|
||||
else if (key === "content-length") hasContentLength = true;
|
||||
}
|
||||
if (contentType && !hasContentTypeHeader) headers.push(["content-type", contentType]);
|
||||
if (contentLength && !hasContentLength) headers.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,
|
||||
body
|
||||
};
|
||||
}
|
||||
}
|
||||
lazyInherit(NodeResponse.prototype, NativeResponse.prototype, "_response");
|
||||
Object.setPrototypeOf(NodeResponse, NativeResponse);
|
||||
Object.setPrototypeOf(NodeResponse.prototype, NativeResponse.prototype);
|
||||
return NodeResponse;
|
||||
})();
|
||||
var WebRequestSocket = class extends Duplex {
|
||||
_httpMessage;
|
||||
autoSelectFamilyAttemptedAddresses = [];
|
||||
bufferSize = 0;
|
||||
bytesRead = 0;
|
||||
bytesWritten = 0;
|
||||
connecting = false;
|
||||
pending = false;
|
||||
readyState = "open";
|
||||
remoteAddress = "";
|
||||
remoteFamily = "";
|
||||
remotePort = 0;
|
||||
#request;
|
||||
#timeoutTimer;
|
||||
#reqReader;
|
||||
#headersWritten;
|
||||
#_writeBody;
|
||||
_webResBody;
|
||||
constructor(request) {
|
||||
super({
|
||||
signal: request.signal,
|
||||
allowHalfOpen: true
|
||||
});
|
||||
this.#request = request;
|
||||
this._webResBody = new ReadableStream({ start: (controller) => {
|
||||
this.#_writeBody = controller.enqueue.bind(controller);
|
||||
this.once("finish", () => {
|
||||
this.readyState = "closed";
|
||||
controller.close();
|
||||
});
|
||||
} });
|
||||
}
|
||||
setTimeout(ms, cb) {
|
||||
if (typeof ms !== "number" || !Number.isFinite(ms) || ms < 0) return this;
|
||||
if (cb) this.on("timeout", cb);
|
||||
if (this.#timeoutTimer) clearTimeout(this.#timeoutTimer);
|
||||
if (ms > 0) this.#timeoutTimer = setTimeout(() => this.emit("timeout"), ms);
|
||||
return this;
|
||||
}
|
||||
setNoDelay() {
|
||||
return this;
|
||||
}
|
||||
setKeepAlive() {
|
||||
return this;
|
||||
}
|
||||
ref() {
|
||||
return this;
|
||||
}
|
||||
unref() {
|
||||
return this;
|
||||
}
|
||||
destroySoon() {
|
||||
this.destroy();
|
||||
}
|
||||
connect() {
|
||||
return this;
|
||||
}
|
||||
resetAndDestroy() {
|
||||
this.destroy();
|
||||
return this;
|
||||
}
|
||||
address() {
|
||||
return {
|
||||
address: "",
|
||||
family: "",
|
||||
port: 0
|
||||
};
|
||||
}
|
||||
_read(_size) {
|
||||
const reader = this.#reqReader ??= this.#request.body?.getReader();
|
||||
if (!reader) {
|
||||
this.push(null);
|
||||
return;
|
||||
}
|
||||
reader.read().then((res) => this._onRead(res)).catch((error) => {
|
||||
this.emit("error", error);
|
||||
});
|
||||
}
|
||||
_onRead(res) {
|
||||
if (res.done) {
|
||||
this.push(null);
|
||||
return;
|
||||
}
|
||||
if (res.value) {
|
||||
this.bytesRead += res.value.byteLength;
|
||||
this.push(res.value);
|
||||
}
|
||||
}
|
||||
_write(chunk, encoding, callback) {
|
||||
if (this.#headersWritten) this.#_writeBody(typeof chunk === "string" ? Buffer.from(chunk, encoding) : chunk);
|
||||
else if (chunk?.length > 0) {
|
||||
this.#headersWritten = true;
|
||||
const headerEnd = chunk.lastIndexOf("\r\n\r\n");
|
||||
if (headerEnd === -1) throw new Error("Invalid HTTP headers chunk!");
|
||||
if (headerEnd < chunk.length - 4) {
|
||||
this._write(chunk.slice(headerEnd + 4), encoding, () => {
|
||||
callback(null);
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
callback(null);
|
||||
}
|
||||
_final(callback) {
|
||||
callback(null);
|
||||
}
|
||||
_destroy(err, cb) {
|
||||
if (this.#timeoutTimer) clearTimeout(this.#timeoutTimer);
|
||||
if (this.#reqReader) this.#reqReader.cancel().catch((error) => {
|
||||
console.error(error);
|
||||
});
|
||||
this.readyState = "closed";
|
||||
cb(err ?? void 0);
|
||||
}
|
||||
};
|
||||
var WebIncomingMessage = class extends IncomingMessage {
|
||||
constructor(req, socket) {
|
||||
super(socket);
|
||||
this.method = req.method;
|
||||
const url = req._url ??= new FastURL(req.url);
|
||||
this.url = url.pathname + url.search;
|
||||
for (const [key, value] of req.headers.entries()) this.headers[key.toLowerCase()] = value;
|
||||
if (req.method !== "GET" && req.method !== "HEAD" && !this.headers["content-length"] && !this.headers["transfer-encoding"]) this.headers["transfer-encoding"] = "chunked";
|
||||
const onData = (chunk) => {
|
||||
this.push(chunk);
|
||||
};
|
||||
socket.on("data", onData);
|
||||
socket.once("end", () => {
|
||||
this.emit("end");
|
||||
this.off("data", onData);
|
||||
});
|
||||
}
|
||||
};
|
||||
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) {
|
||||
const headerEntries = [];
|
||||
const rawHeaders = nodeRes.getHeaders();
|
||||
for (const [name, value] of Object.entries(rawHeaders)) if (Array.isArray(value)) for (const v of value) headerEntries.push([name, v]);
|
||||
else if (value) headerEntries.push([name, String(value)]);
|
||||
_headers = new Headers(headerEntries);
|
||||
}
|
||||
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) => {
|
||||
stream.once("end", () => resolve(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);
|
||||
}
|
||||
});
|
||||
}
|
||||
var WebServerResponse = class extends ServerResponse {
|
||||
#socket;
|
||||
constructor(req, socket) {
|
||||
super(req);
|
||||
this.assignSocket(socket);
|
||||
this.once("finish", () => {
|
||||
socket.end();
|
||||
});
|
||||
this.#socket = socket;
|
||||
this.waitToFinish = this.waitToFinish.bind(this);
|
||||
this.toWebResponse = this.toWebResponse.bind(this);
|
||||
}
|
||||
waitToFinish() {
|
||||
if (this.writableEnded) return Promise.resolve();
|
||||
return new Promise((resolve, reject) => {
|
||||
this.on("finish", () => resolve());
|
||||
this.on("error", (err) => reject(err));
|
||||
});
|
||||
}
|
||||
async toWebResponse() {
|
||||
await this.waitToFinish();
|
||||
const headers = [];
|
||||
const httpHeader = this._header?.split("\r\n");
|
||||
for (let i = 1; httpHeader && i < httpHeader.length; i++) {
|
||||
const sepIndex = httpHeader[i].indexOf(": ");
|
||||
if (sepIndex === -1) continue;
|
||||
const key = httpHeader[i].slice(0, Math.max(0, sepIndex));
|
||||
const value = httpHeader[i].slice(Math.max(0, sepIndex + 2));
|
||||
if (!key) continue;
|
||||
headers.push([key, value]);
|
||||
}
|
||||
return new Response(this.#socket._webResBody, {
|
||||
status: this.statusCode,
|
||||
statusText: this.statusMessage,
|
||||
headers
|
||||
});
|
||||
}
|
||||
};
|
||||
async function fetchNodeHandler(handler, req) {
|
||||
const nodeRuntime = req.runtime?.node;
|
||||
if (nodeRuntime && nodeRuntime.req && nodeRuntime.res) return await callNodeHandler(handler, req);
|
||||
const socket = new WebRequestSocket(req);
|
||||
const nodeReq = new WebIncomingMessage(req, socket);
|
||||
const nodeRes = new WebServerResponse(nodeReq, socket);
|
||||
try {
|
||||
await handler(nodeReq, nodeRes);
|
||||
return await nodeRes.toWebResponse();
|
||||
} catch (error) {
|
||||
console.error(error, { cause: {
|
||||
req,
|
||||
handler
|
||||
} });
|
||||
return new Response(null, {
|
||||
status: 500,
|
||||
statusText: "Internal Server Error"
|
||||
});
|
||||
}
|
||||
}
|
||||
function toNodeHandler(handler) {
|
||||
if (handler.__nodeHandler) return handler.__nodeHandler;
|
||||
function convertedNodeHandler(nodeReq, nodeRes) {
|
||||
const res = handler(new NodeRequest({
|
||||
req: nodeReq,
|
||||
res: nodeRes
|
||||
}));
|
||||
return res instanceof Promise ? res.then((resolvedRes) => sendNodeResponse(nodeRes, resolvedRes)) : sendNodeResponse(nodeRes, res);
|
||||
}
|
||||
convertedNodeHandler.__fetchHandler = handler;
|
||||
assignFnName(convertedNodeHandler, handler, " (converted to Node handler)");
|
||||
return convertedNodeHandler;
|
||||
}
|
||||
function toFetchHandler(handler) {
|
||||
if (handler.__fetchHandler) return handler.__fetchHandler;
|
||||
function convertedNodeHandler(req) {
|
||||
return fetchNodeHandler(handler, req);
|
||||
}
|
||||
convertedNodeHandler.__nodeHandler = handler;
|
||||
assignFnName(convertedNodeHandler, handler, " (converted to Web handler)");
|
||||
return convertedNodeHandler;
|
||||
}
|
||||
function assignFnName(target, source, suffix) {
|
||||
if (source.name) try {
|
||||
Object.defineProperty(target, "name", { value: `${source.name}${suffix}` });
|
||||
} catch {}
|
||||
}
|
||||
function serve(options) {
|
||||
return new NodeServer(options);
|
||||
}
|
||||
var NodeServer = class {
|
||||
runtime = "node";
|
||||
options;
|
||||
node;
|
||||
serveOptions;
|
||||
fetch;
|
||||
#isSecure;
|
||||
#listeningPromise;
|
||||
#wait;
|
||||
constructor(options) {
|
||||
this.options = {
|
||||
...options,
|
||||
middleware: [...options.middleware || []]
|
||||
};
|
||||
for (const plugin of options.plugins || []) plugin(this);
|
||||
errorPlugin(this);
|
||||
const fetchHandler = this.fetch = wrapFetch(this);
|
||||
const loader = globalThis.__srvxLoader__;
|
||||
if (loader) {
|
||||
loader(fetchHandler);
|
||||
return;
|
||||
}
|
||||
gracefulShutdownPlugin(this);
|
||||
this.#wait = createWaitUntil();
|
||||
const handler = (nodeReq, nodeRes) => {
|
||||
const request = new NodeRequest({
|
||||
req: nodeReq,
|
||||
res: nodeRes
|
||||
});
|
||||
request.waitUntil = this.#wait?.waitUntil;
|
||||
const res = fetchHandler(request);
|
||||
return res instanceof Promise ? res.then((resolvedRes) => sendNodeResponse(nodeRes, resolvedRes)) : sendNodeResponse(nodeRes, res);
|
||||
};
|
||||
const tls = resolveTLSOptions(this.options);
|
||||
const { port, hostname: host } = resolvePortAndHost(this.options);
|
||||
this.serveOptions = {
|
||||
port,
|
||||
host,
|
||||
exclusive: !this.options.reusePort,
|
||||
...tls ? {
|
||||
cert: tls.cert,
|
||||
key: tls.key,
|
||||
passphrase: tls.passphrase
|
||||
} : {},
|
||||
...this.options.node
|
||||
};
|
||||
let server;
|
||||
this.#isSecure = !!this.serveOptions.cert && this.options.protocol !== "http";
|
||||
if (this.options.node?.http2 ?? this.#isSecure) if (this.#isSecure) server = nodeHTTP2.createSecureServer({
|
||||
allowHTTP1: true,
|
||||
...this.serveOptions
|
||||
}, handler);
|
||||
else throw new Error("node.http2 option requires tls certificate!");
|
||||
else if (this.#isSecure) server = nodeHTTPS.createServer(this.serveOptions, handler);
|
||||
else server = nodeHTTP.createServer(this.serveOptions, handler);
|
||||
this.node = {
|
||||
server,
|
||||
handler
|
||||
};
|
||||
if (!options.manual) this.serve();
|
||||
}
|
||||
serve() {
|
||||
if (this.#listeningPromise) return Promise.resolve(this.#listeningPromise).then(() => this);
|
||||
this.#listeningPromise = new Promise((resolve) => {
|
||||
this.node.server.listen(this.serveOptions, () => {
|
||||
printListening(this.options, this.url);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
get url() {
|
||||
const addr = this.node?.server?.address();
|
||||
if (!addr) return;
|
||||
return typeof addr === "string" ? addr : fmtURL(addr.address, addr.port, this.#isSecure);
|
||||
}
|
||||
ready() {
|
||||
return Promise.resolve(this.#listeningPromise).then(() => this);
|
||||
}
|
||||
async close(closeAll) {
|
||||
await Promise.all([this.#wait?.wait(), new Promise((resolve, reject) => {
|
||||
const server = this.node?.server;
|
||||
if (server && closeAll && "closeAllConnections" in server) server.closeAllConnections();
|
||||
if (!server || !server.listening) return resolve();
|
||||
server.close((error) => error ? reject(error) : resolve());
|
||||
})]);
|
||||
}
|
||||
};
|
||||
export { NodeResponse as FastResponse, NodeResponse, FastURL, NodeRequest, fetchNodeHandler, patchGlobalRequest, sendNodeResponse, serve, toFetchHandler, toNodeHandler };
|
||||
9
node_modules/srvx/dist/adapters/service-worker.d.mts
generated
vendored
Normal file
9
node_modules/srvx/dist/adapters/service-worker.d.mts
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import { Server, ServerOptions, ServerRequest } from "../types.mjs";
|
||||
|
||||
//#region src/adapters/service-worker.d.ts
|
||||
declare const FastURL: typeof globalThis.URL;
|
||||
declare const FastResponse: typeof globalThis.Response;
|
||||
type ServiceWorkerHandler = (request: ServerRequest, event: FetchEvent) => Response | Promise<Response>;
|
||||
declare function serve(options: ServerOptions): Server<ServiceWorkerHandler>;
|
||||
//#endregion
|
||||
export { FastResponse, FastURL, ServiceWorkerHandler, serve };
|
||||
76
node_modules/srvx/dist/adapters/service-worker.mjs
generated
vendored
Normal file
76
node_modules/srvx/dist/adapters/service-worker.mjs
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
import { r as wrapFetch, t as errorPlugin } from "../_chunks/_plugins.mjs";
|
||||
const FastURL = URL;
|
||||
const FastResponse = Response;
|
||||
const isBrowserWindow = typeof window !== "undefined" && typeof navigator !== "undefined";
|
||||
const isServiceWorker = typeof self !== "undefined" && "skipWaiting" in self;
|
||||
function serve(options) {
|
||||
return new ServiceWorkerServer(options);
|
||||
}
|
||||
var ServiceWorkerServer = class {
|
||||
runtime = "service-worker";
|
||||
options;
|
||||
fetch;
|
||||
#fetchListener;
|
||||
#listeningPromise;
|
||||
constructor(options) {
|
||||
this.options = {
|
||||
...options,
|
||||
middleware: [...options.middleware || []]
|
||||
};
|
||||
for (const plugin of options.plugins || []) plugin(this);
|
||||
errorPlugin(this);
|
||||
const fetchHandler = wrapFetch(this);
|
||||
this.fetch = (request, event) => {
|
||||
Object.defineProperties(request, { runtime: {
|
||||
enumerable: true,
|
||||
value: {
|
||||
name: "service-worker",
|
||||
serviceWorker: { event }
|
||||
}
|
||||
} });
|
||||
return Promise.resolve(fetchHandler(request));
|
||||
};
|
||||
if (!options.manual) this.serve();
|
||||
}
|
||||
serve() {
|
||||
if (isBrowserWindow) {
|
||||
if (!navigator.serviceWorker) throw new Error("Service worker is not supported in the current window.");
|
||||
const swURL = this.options.serviceWorker?.url;
|
||||
if (!swURL) throw new Error("Service worker URL is not provided. Please set the `serviceWorker.url` serve option or manually register.");
|
||||
this.#listeningPromise = navigator.serviceWorker.register(swURL, {
|
||||
type: "module",
|
||||
scope: this.options.serviceWorker?.scope
|
||||
}).then((registration) => {
|
||||
if (registration.active) location.replace(location.href);
|
||||
else registration.addEventListener("updatefound", () => {
|
||||
location.replace(location.href);
|
||||
});
|
||||
});
|
||||
} else if (isServiceWorker) {
|
||||
this.#fetchListener = async (event) => {
|
||||
if (/\/[^/]*\.[a-zA-Z0-9]+$/.test(new URL(event.request.url).pathname)) return;
|
||||
Object.defineProperty(event.request, "waitUntil", { value: event.waitUntil.bind(event) });
|
||||
const response = await this.fetch(event.request, event);
|
||||
if (response.status !== 404) event.respondWith(response);
|
||||
};
|
||||
addEventListener("fetch", this.#fetchListener);
|
||||
self.addEventListener("install", () => {
|
||||
self.skipWaiting();
|
||||
});
|
||||
self.addEventListener("activate", () => {
|
||||
self.clients?.claim?.();
|
||||
});
|
||||
}
|
||||
}
|
||||
ready() {
|
||||
return Promise.resolve(this.#listeningPromise).then(() => this);
|
||||
}
|
||||
async close() {
|
||||
if (this.#fetchListener) removeEventListener("fetch", this.#fetchListener);
|
||||
if (isBrowserWindow) {
|
||||
const registrations = await navigator.serviceWorker.getRegistrations();
|
||||
for (const registration of registrations) if (registration.active) await registration.unregister();
|
||||
} else if (isServiceWorker) await self.registration.unregister();
|
||||
}
|
||||
};
|
||||
export { FastResponse, FastURL, serve };
|
||||
Reference in New Issue
Block a user