171 lines
5.2 KiB
JavaScript
171 lines
5.2 KiB
JavaScript
import destr from "destr";
|
|
import {
|
|
createApp,
|
|
createRouter,
|
|
fetchWithEvent,
|
|
isEvent,
|
|
lazyEventHandler,
|
|
toNodeListener
|
|
} from "h3";
|
|
import { createHooks } from "hookable";
|
|
import { Headers, createFetch } from "ofetch";
|
|
import {
|
|
fetchNodeRequestHandler,
|
|
callNodeRequestHandler
|
|
} from "node-mock-http";
|
|
import { cachedEventHandler } from "./cache.mjs";
|
|
import { useRuntimeConfig } from "./config.mjs";
|
|
import { nitroAsyncContext } from "./context.mjs";
|
|
import { createRouteRulesHandler, getRouteRulesForPath } from "./route-rules.mjs";
|
|
import { normalizeFetchResponse } from "./utils.mjs";
|
|
import errorHandler from "#nitro-internal-virtual/error-handler";
|
|
import { plugins } from "#nitro-internal-virtual/plugins";
|
|
import { handlers } from "#nitro-internal-virtual/server-handlers";
|
|
function createNitroApp() {
|
|
const config = useRuntimeConfig();
|
|
const hooks = createHooks();
|
|
const captureError = (error, context = {}) => {
|
|
const promise = hooks.callHookParallel("error", error, context).catch((error_) => {
|
|
console.error("Error while capturing another error", error_);
|
|
});
|
|
if (context.event && isEvent(context.event)) {
|
|
const errors = context.event.context.nitro?.errors;
|
|
if (errors) {
|
|
errors.push({ error, context });
|
|
}
|
|
if (context.event.waitUntil) {
|
|
context.event.waitUntil(promise);
|
|
}
|
|
}
|
|
};
|
|
const h3App = createApp({
|
|
debug: destr(process.env.DEBUG),
|
|
onError: (error, event) => {
|
|
captureError(error, { event, tags: ["request"] });
|
|
return errorHandler(error, event);
|
|
},
|
|
onRequest: async (event) => {
|
|
event.context.nitro = event.context.nitro || { errors: [] };
|
|
const fetchContext = event.node.req?.__unenv__;
|
|
if (fetchContext?._platform) {
|
|
event.context = {
|
|
_platform: fetchContext?._platform,
|
|
// #3335
|
|
...fetchContext._platform,
|
|
...event.context
|
|
};
|
|
}
|
|
if (!event.context.waitUntil && fetchContext?.waitUntil) {
|
|
event.context.waitUntil = fetchContext.waitUntil;
|
|
}
|
|
event.fetch = (req, init) => fetchWithEvent(event, req, init, { fetch: localFetch });
|
|
event.$fetch = (req, init) => fetchWithEvent(event, req, init, {
|
|
fetch: $fetch
|
|
});
|
|
event.waitUntil = (promise) => {
|
|
if (!event.context.nitro._waitUntilPromises) {
|
|
event.context.nitro._waitUntilPromises = [];
|
|
}
|
|
event.context.nitro._waitUntilPromises.push(promise);
|
|
if (event.context.waitUntil) {
|
|
event.context.waitUntil(promise);
|
|
}
|
|
};
|
|
event.captureError = (error, context) => {
|
|
captureError(error, { event, ...context });
|
|
};
|
|
await nitroApp.hooks.callHook("request", event).catch((error) => {
|
|
captureError(error, { event, tags: ["request"] });
|
|
});
|
|
},
|
|
onBeforeResponse: async (event, response) => {
|
|
await nitroApp.hooks.callHook("beforeResponse", event, response).catch((error) => {
|
|
captureError(error, { event, tags: ["request", "response"] });
|
|
});
|
|
},
|
|
onAfterResponse: async (event, response) => {
|
|
await nitroApp.hooks.callHook("afterResponse", event, response).catch((error) => {
|
|
captureError(error, { event, tags: ["request", "response"] });
|
|
});
|
|
}
|
|
});
|
|
const router = createRouter({
|
|
preemptive: true
|
|
});
|
|
const nodeHandler = toNodeListener(h3App);
|
|
const localCall = (aRequest) => callNodeRequestHandler(
|
|
nodeHandler,
|
|
aRequest
|
|
);
|
|
const localFetch = (input, init) => {
|
|
if (!input.toString().startsWith("/")) {
|
|
return globalThis.fetch(input, init);
|
|
}
|
|
return fetchNodeRequestHandler(
|
|
nodeHandler,
|
|
input,
|
|
init
|
|
).then((response) => normalizeFetchResponse(response));
|
|
};
|
|
const $fetch = createFetch({
|
|
fetch: localFetch,
|
|
Headers,
|
|
defaults: { baseURL: config.app.baseURL }
|
|
});
|
|
globalThis.$fetch = $fetch;
|
|
h3App.use(createRouteRulesHandler({ localFetch }));
|
|
for (const h of handlers) {
|
|
let handler = h.lazy ? lazyEventHandler(h.handler) : h.handler;
|
|
if (h.middleware || !h.route) {
|
|
const middlewareBase = (config.app.baseURL + (h.route || "/")).replace(
|
|
/\/+/g,
|
|
"/"
|
|
);
|
|
h3App.use(middlewareBase, handler);
|
|
} else {
|
|
const routeRules = getRouteRulesForPath(
|
|
h.route.replace(/:\w+|\*\*/g, "_")
|
|
);
|
|
if (routeRules.cache) {
|
|
handler = cachedEventHandler(handler, {
|
|
group: "nitro/routes",
|
|
...routeRules.cache
|
|
});
|
|
}
|
|
router.use(h.route, handler, h.method);
|
|
}
|
|
}
|
|
h3App.use(config.app.baseURL, router.handler);
|
|
if (import.meta._asyncContext) {
|
|
const _handler = h3App.handler;
|
|
h3App.handler = (event) => {
|
|
const ctx = { event };
|
|
return nitroAsyncContext.callAsync(ctx, () => _handler(event));
|
|
};
|
|
}
|
|
const app = {
|
|
hooks,
|
|
h3App,
|
|
router,
|
|
localCall,
|
|
localFetch,
|
|
captureError
|
|
};
|
|
return app;
|
|
}
|
|
function runNitroPlugins(nitroApp2) {
|
|
for (const plugin of plugins) {
|
|
try {
|
|
plugin(nitroApp2);
|
|
} catch (error) {
|
|
nitroApp2.captureError(error, { tags: ["plugin"] });
|
|
throw error;
|
|
}
|
|
}
|
|
}
|
|
export const nitroApp = createNitroApp();
|
|
export function useNitroApp() {
|
|
return nitroApp;
|
|
}
|
|
runNitroPlugins(nitroApp);
|