@universal-middleware/h3
Version:
h3 adapter for universal middlewares
151 lines (149 loc) • 4.23 kB
JavaScript
// src/common.ts
import {
bindUniversal,
contextSymbol,
getAdapterRuntime,
isBodyInit,
mergeHeadersInto,
nodeHeadersToWeb,
universalSymbol
} from "@universal-middleware/core";
import {
defineResponseMiddleware,
eventHandler,
getResponseHeaders,
getResponseStatus,
getResponseStatusText,
sendWebResponse,
toWebRequest
} from "h3";
var pendingMiddlewaresSymbol = Symbol.for("unPendingMiddlewares");
var wrappedResponseSymbol = Symbol.for("unWrappedResponse");
function memToWebRequest(event) {
if (!event.web?.request) {
event.web ??= {};
event.web.request = toWebRequest(event);
}
return event.web.request;
}
function createHandler(handlerFactory) {
return (...args) => {
const handler = handlerFactory(...args);
return bindUniversal(
handler,
eventHandler(function universalHandlerH3(event) {
const ctx = initContext(event);
return this[universalSymbol](memToWebRequest(event), ctx, getRuntime(event));
}),
eventHandler
);
};
}
var universalOnBeforeResponse = defineResponseMiddleware(
async (event, response) => {
if (response.body instanceof Error) return;
if (event.context[wrappedResponseSymbol] !== false) return;
event.context[wrappedResponseSymbol] = true;
if (response.body instanceof Response) {
mergeHeadersInto(response.body.headers, nodeHeadersToWeb(getResponseHeaders(event)));
} else if (isBodyInit(response.body)) {
response.body = new Response(response.body, {
headers: nodeHeadersToWeb(getResponseHeaders(event)),
status: getResponseStatus(event),
statusText: getResponseStatusText(event)
});
} else {
throw new TypeError("Payload is not a Response or BodyInit compatible");
}
const middlewares = event.context[pendingMiddlewaresSymbol];
delete event.context[pendingMiddlewaresSymbol];
const newResponse = await middlewares?.reduce(
async (prev, curr) => {
const p = await prev;
const newR = await curr(p);
return newR ?? p;
},
Promise.resolve(response.body)
);
if (newResponse) {
await sendWebResponse(event, newResponse);
}
}
);
function createMiddleware(middlewareFactory) {
return (...args) => {
const middleware = middlewareFactory(...args);
return bindUniversal(
middleware,
eventHandler(async function universalMiddlewareH3(event) {
const ctx = initContext(event);
const response = await this[universalSymbol](memToWebRequest(event), ctx, getRuntime(event));
if (typeof response === "function") {
event.context[pendingMiddlewaresSymbol] ??= [];
event.context[wrappedResponseSymbol] = false;
event.context[pendingMiddlewaresSymbol].push(response);
} else if (response !== null && typeof response === "object") {
if (response instanceof Response) {
return response;
}
event.context[contextSymbol] = response;
}
}),
eventHandler
);
};
}
function initContext(event) {
event.context[contextSymbol] ??= {};
return event.context[contextSymbol];
}
function getContext(event) {
return event.context[contextSymbol];
}
function getRuntime(event) {
return getAdapterRuntime(
"h3",
{
params: event.context.params,
h3: event
},
{
req: event.node.req,
res: event.node.res
}
);
}
// src/router.ts
import {
apply as applyCore,
getUniversal,
UniversalRouter,
universalSymbol as universalSymbol2
} from "@universal-middleware/core";
var UniversalH3Router = class extends UniversalRouter {
#app;
constructor(app) {
super(false);
this.#app = app;
}
use(middleware) {
this.#app.use(createMiddleware(() => getUniversal(middleware))());
return this;
}
applyCatchAll() {
this.#app.use(createHandler(() => this[universalSymbol2])());
return this;
}
};
function apply(app, middlewares) {
app.options.onBeforeResponse = universalOnBeforeResponse;
const router = new UniversalH3Router(app);
applyCore(router, middlewares);
}
export {
apply,
createHandler,
createMiddleware,
getContext,
universalOnBeforeResponse
};