import "#nitro-internal-pollyfills"; import { tmpdir } from "node:os"; import { useNitroApp } from "nitropack/runtime"; import { runTask } from "nitropack/runtime"; import { trapUnhandledNodeErrors } from "nitropack/runtime/internal"; import { startScheduleRunner } from "nitropack/runtime/internal"; import { scheduledTasks, tasks } from "#nitro-internal-virtual/tasks"; import { Server } from "node:http"; import { join } from "node:path"; import nodeCrypto from "node:crypto"; import { parentPort, threadId } from "node:worker_threads"; import wsAdapter from "crossws/adapters/node"; import { defineEventHandler, getQuery, getRouterParam, readBody, toNodeListener } from "h3"; if (!globalThis.crypto) { globalThis.crypto = nodeCrypto; } const { NITRO_NO_UNIX_SOCKET, NITRO_DEV_WORKER_ID } = process.env; trapUnhandledNodeErrors(); parentPort?.on("message", (msg) => { if (msg && msg.event === "shutdown") { shutdown(); } }); const nitroApp = useNitroApp(); const server = new Server(toNodeListener(nitroApp.h3App)); let listener; listen().catch(() => listen( true /* use random port */ )).catch((error) => { console.error("Dev worker failed to listen:", error); return shutdown(); }); if (import.meta._websocket) { const { handleUpgrade } = wsAdapter(nitroApp.h3App.websocket); server.on("upgrade", handleUpgrade); } nitroApp.router.get( "/_nitro/tasks", defineEventHandler(async (event) => { const _tasks = await Promise.all( Object.entries(tasks).map(async ([name, task]) => { const _task = await task.resolve?.(); return [name, { description: _task?.meta?.description }]; }) ); return { tasks: Object.fromEntries(_tasks), scheduledTasks }; }) ); nitroApp.router.use( "/_nitro/tasks/:name", defineEventHandler(async (event) => { const name = getRouterParam(event, "name"); const payload = { ...getQuery(event), ...await readBody(event).then((r) => r?.payload).catch(() => ({})) }; return await runTask(name, { payload }); }) ); if (import.meta._tasks) { startScheduleRunner(); } function listen(useRandomPort = Boolean( NITRO_NO_UNIX_SOCKET || process.versions.webcontainer || "Bun" in globalThis && process.platform === "win32" )) { return new Promise((resolve, reject) => { try { listener = server.listen(useRandomPort ? 0 : getSocketAddress(), () => { const address = server.address(); parentPort?.postMessage({ event: "listen", address: typeof address === "string" ? { socketPath: address } : { host: "localhost", port: address?.port } }); resolve(); }); } catch (error) { reject(error); } }); } function getSocketAddress() { const socketName = `nitro-worker-${process.pid}-${threadId}-${NITRO_DEV_WORKER_ID}-${Math.round(Math.random() * 1e4)}.sock`; if (process.platform === "win32") { return join(String.raw`\\.\pipe`, socketName); } if (process.platform === "linux") { const nodeMajor = Number.parseInt(process.versions.node.split(".")[0], 10); if (nodeMajor >= 20) { return `\0${socketName}`; } } return join(tmpdir(), socketName); } async function shutdown() { server.closeAllConnections?.(); await Promise.all([ new Promise((resolve) => listener?.close(resolve)), nitroApp.hooks.callHook("close").catch(console.error) ]); parentPort?.postMessage({ event: "exit" }); }