@nuxt/cli
Advanced tools
| import { a as legacyRootDirArgs, i as extendsArgs, n as dotEnvArgs, o as logLevelArgs, r as envNameArgs, s as profileArgs, t as cwdArgs } from "./_shared-B6XhZQ-m.mjs"; | ||
| import { n as logger } from "./logger-C1qVsppt.mjs"; | ||
| import { t as overrideEnv } from "./env-BfWVBvy7.mjs"; | ||
| import { a as stopCpuProfile, i as startCpuProfile, n as formatLockError, t as acquireLock } from "./lockfile-BXsNI9ve.mjs"; | ||
| import { t as loadKit } from "./kit-BzPscsEd.mjs"; | ||
| import { n as showBanner } from "./banner-CTtM2dxO.mjs"; | ||
| import { t as clearBuildDir } from "./fs-B0HqP3GX.mjs"; | ||
| import process from "node:process"; | ||
| import { defineCommand } from "citty"; | ||
| import { colors } from "consola/utils"; | ||
| import { intro, outro } from "@clack/prompts"; | ||
| import { relative, resolve } from "pathe"; | ||
| //#region ../nuxi/src/commands/build.ts | ||
| var build_default = defineCommand({ | ||
| meta: { | ||
| name: "build", | ||
| description: "Build Nuxt for production deployment" | ||
| }, | ||
| args: { | ||
| ...cwdArgs, | ||
| ...logLevelArgs, | ||
| prerender: { | ||
| type: "boolean", | ||
| description: "Build Nuxt and prerender static routes" | ||
| }, | ||
| preset: { | ||
| type: "string", | ||
| description: "Nitro server preset" | ||
| }, | ||
| ...dotEnvArgs, | ||
| ...envNameArgs, | ||
| ...extendsArgs, | ||
| ...profileArgs, | ||
| ...legacyRootDirArgs | ||
| }, | ||
| async run(ctx) { | ||
| overrideEnv("production"); | ||
| const cwd = resolve(ctx.args.cwd || ctx.args.rootDir); | ||
| const profileArg = ctx.args.profile; | ||
| const perfValue = profileArg === "verbose" ? true : profileArg ? "quiet" : void 0; | ||
| if (profileArg) await startCpuProfile(); | ||
| let releaseLock; | ||
| try { | ||
| intro(colors.cyan("Building Nuxt for production...")); | ||
| const kit = await loadKit(cwd); | ||
| const nuxt = await kit.loadNuxt({ | ||
| cwd, | ||
| ready: false, | ||
| dotenv: { | ||
| cwd, | ||
| fileName: ctx.args.dotenv | ||
| }, | ||
| envName: ctx.args.envName, | ||
| overrides: { | ||
| logLevel: ctx.args.logLevel, | ||
| _generate: ctx.args.prerender, | ||
| nitro: { | ||
| static: ctx.args.prerender, | ||
| preset: ctx.args.preset || process.env.NITRO_PRESET || process.env.SERVER_PRESET | ||
| }, | ||
| ...ctx.args.extends && { extends: ctx.args.extends }, | ||
| ...ctx.data?.overrides, | ||
| ...(perfValue || ctx.data?.overrides?.debug) && { debug: { | ||
| ...ctx.data?.overrides?.debug, | ||
| ...perfValue && { perf: perfValue } | ||
| } } | ||
| } | ||
| }); | ||
| showBanner(nuxt); | ||
| await nuxt.ready(); | ||
| const lock = acquireLock(nuxt.options.buildDir, { | ||
| command: "build", | ||
| cwd | ||
| }); | ||
| if (lock.existing) { | ||
| logger.error(formatLockError(lock.existing)); | ||
| throw new Error(`Another Nuxt ${lock.existing.command} is already running (PID ${lock.existing.pid}).`); | ||
| } | ||
| releaseLock = lock.release; | ||
| let nitro; | ||
| try { | ||
| nitro = kit.useNitro?.(); | ||
| if (nitro) logger.info(`Nitro preset: ${colors.cyan(nitro.options.preset)}`); | ||
| } catch {} | ||
| await clearBuildDir(nuxt.options.buildDir); | ||
| await kit.writeTypes(nuxt); | ||
| nuxt.hook("build:error", async (err) => { | ||
| logger.error(`Nuxt build error: ${err}`); | ||
| if (profileArg) await stopCpuProfile(cwd, "build"); | ||
| process.exit(1); | ||
| }); | ||
| await kit.buildNuxt(nuxt); | ||
| if (ctx.args.prerender) { | ||
| if (!nuxt.options.ssr) { | ||
| logger.warn(`HTML content not prerendered because ${colors.cyan("ssr: false")} was set.`); | ||
| logger.info(`You can read more in ${colors.cyan("https://nuxt.com/docs/getting-started/deployment#static-hosting")}.`); | ||
| } | ||
| const dir = nitro?.options.output.publicDir; | ||
| const publicDir = dir ? relative(process.cwd(), dir) : ".output/public"; | ||
| outro(`✨ You can now deploy ${colors.cyan(publicDir)} to any static hosting!`); | ||
| } else outro("✨ Build complete!"); | ||
| } finally { | ||
| releaseLock?.(); | ||
| if (profileArg) await stopCpuProfile(cwd, "build"); | ||
| } | ||
| } | ||
| }); | ||
| //#endregion | ||
| export { build_default as default }; |
| import { a as legacyRootDirArgs, i as extendsArgs, n as dotEnvArgs, o as logLevelArgs, r as envNameArgs, s as profileArgs, t as cwdArgs } from "./_shared-B6XhZQ-m.mjs"; | ||
| import { n as logger, t as debug } from "./logger-C1qVsppt.mjs"; | ||
| import { n as initialize } from "./dev-CttXIKD2.mjs"; | ||
| import process from "node:process"; | ||
| import { defineCommand } from "citty"; | ||
| import { colors } from "consola/utils"; | ||
| import { isBun, isDeno, isTest } from "std-env"; | ||
| import { resolve } from "pathe"; | ||
| import { satisfies } from "semver"; | ||
| import { getArgs, parseArgs } from "listhen/cli"; | ||
| import { fork } from "node:child_process"; | ||
| //#region ../nuxi/src/dev/pool.ts | ||
| var ForkPool = class { | ||
| pool = []; | ||
| poolSize; | ||
| rawArgs; | ||
| listenOverrides; | ||
| warming = false; | ||
| constructor(options) { | ||
| this.rawArgs = options.rawArgs; | ||
| this.poolSize = options.poolSize ?? 2; | ||
| this.listenOverrides = options.listenOverrides; | ||
| for (const signal of [ | ||
| "exit", | ||
| "SIGTERM", | ||
| "SIGINT", | ||
| "SIGQUIT" | ||
| ]) process.once(signal, () => { | ||
| this.killAll(signal === "exit" ? 0 : signal); | ||
| }); | ||
| } | ||
| startWarming() { | ||
| if (this.warming) return; | ||
| this.warming = true; | ||
| for (let i = 0; i < this.poolSize; i++) this.warmFork(); | ||
| } | ||
| async getFork(context, onMessage) { | ||
| const readyFork = this.pool.find((f) => f.state === "ready"); | ||
| if (readyFork) { | ||
| readyFork.state = "active"; | ||
| if (onMessage) this.attachMessageHandler(readyFork.process, onMessage); | ||
| await this.sendContext(readyFork.process, context); | ||
| if (this.warming) this.warmFork(); | ||
| return () => this.killFork(readyFork); | ||
| } | ||
| const warmingFork = this.pool.find((f) => f.state === "warming"); | ||
| if (warmingFork) { | ||
| await warmingFork.ready; | ||
| warmingFork.state = "active"; | ||
| if (onMessage) this.attachMessageHandler(warmingFork.process, onMessage); | ||
| await this.sendContext(warmingFork.process, context); | ||
| if (this.warming) this.warmFork(); | ||
| return () => this.killFork(warmingFork); | ||
| } | ||
| debug("No pre-warmed forks available, starting cold fork"); | ||
| const coldFork = this.createFork(); | ||
| await coldFork.ready; | ||
| coldFork.state = "active"; | ||
| if (onMessage) this.attachMessageHandler(coldFork.process, onMessage); | ||
| await this.sendContext(coldFork.process, context); | ||
| return () => this.killFork(coldFork); | ||
| } | ||
| attachMessageHandler(childProc, onMessage) { | ||
| childProc.on("message", (message) => { | ||
| if (message.type !== "nuxt:internal:dev:fork-ready") onMessage(message); | ||
| }); | ||
| } | ||
| warmFork() { | ||
| const fork = this.createFork(); | ||
| fork.ready.then(() => { | ||
| if (fork.state === "warming") fork.state = "ready"; | ||
| }).catch(() => { | ||
| this.removeFork(fork); | ||
| }); | ||
| this.pool.push(fork); | ||
| } | ||
| createFork() { | ||
| const childProc = fork(globalThis.__nuxt_cli__.devEntry, this.rawArgs, { | ||
| execArgv: ["--enable-source-maps", process.argv.find((a) => a.includes("--inspect"))].filter(Boolean), | ||
| env: { | ||
| ...process.env, | ||
| __NUXT__FORK: "true" | ||
| } | ||
| }); | ||
| let readyResolve; | ||
| let readyReject; | ||
| const pooledFork = { | ||
| process: childProc, | ||
| ready: new Promise((resolve, reject) => { | ||
| readyResolve = resolve; | ||
| readyReject = reject; | ||
| }), | ||
| state: "warming" | ||
| }; | ||
| childProc.on("message", (message) => { | ||
| if (message.type === "nuxt:internal:dev:fork-ready") readyResolve(); | ||
| }); | ||
| childProc.on("error", (err) => { | ||
| readyReject(err); | ||
| this.removeFork(pooledFork); | ||
| }); | ||
| childProc.on("close", (errorCode) => { | ||
| if (pooledFork.state === "active" && errorCode) process.exit(errorCode); | ||
| this.removeFork(pooledFork); | ||
| }); | ||
| return pooledFork; | ||
| } | ||
| async sendContext(childProc, context) { | ||
| childProc.send({ | ||
| type: "nuxt:internal:dev:context", | ||
| listenOverrides: this.listenOverrides, | ||
| context | ||
| }); | ||
| } | ||
| killFork(fork, signal = "SIGTERM") { | ||
| fork.state = "dead"; | ||
| if (fork.process) fork.process.kill(signal === 0 && isDeno ? "SIGTERM" : signal); | ||
| this.removeFork(fork); | ||
| } | ||
| removeFork(fork) { | ||
| const index = this.pool.indexOf(fork); | ||
| if (index > -1) this.pool.splice(index, 1); | ||
| } | ||
| killAll(signal) { | ||
| for (const fork of this.pool) this.killFork(fork, signal); | ||
| } | ||
| getStats() { | ||
| return { | ||
| total: this.pool.length, | ||
| warming: this.pool.filter((f) => f.state === "warming").length, | ||
| ready: this.pool.filter((f) => f.state === "ready").length, | ||
| active: this.pool.filter((f) => f.state === "active").length | ||
| }; | ||
| } | ||
| }; | ||
| //#endregion | ||
| //#region ../nuxi/src/commands/dev.ts | ||
| const startTime = Date.now(); | ||
| const forkSupported = !isTest && (!isBun || isBunForkSupported()); | ||
| const listhenArgs = getArgs(); | ||
| const command = defineCommand({ | ||
| meta: { | ||
| name: "dev", | ||
| description: "Run Nuxt development server" | ||
| }, | ||
| args: { | ||
| ...cwdArgs, | ||
| ...logLevelArgs, | ||
| ...dotEnvArgs, | ||
| ...legacyRootDirArgs, | ||
| ...envNameArgs, | ||
| ...extendsArgs, | ||
| clear: { | ||
| type: "boolean", | ||
| description: "Clear console on restart", | ||
| default: false | ||
| }, | ||
| fork: { | ||
| type: "boolean", | ||
| description: forkSupported ? "Disable forked mode" : "Enable forked mode", | ||
| negativeDescription: "Disable forked mode", | ||
| default: forkSupported, | ||
| alias: ["f"] | ||
| }, | ||
| ...listhenArgs, | ||
| port: { | ||
| ...listhenArgs.port, | ||
| description: "Port to listen on (default: `NUXT_PORT || NITRO_PORT || PORT || nuxtOptions.devServer.port`)", | ||
| alias: ["p"] | ||
| }, | ||
| open: { | ||
| ...listhenArgs.open, | ||
| alias: ["o"], | ||
| default: false | ||
| }, | ||
| host: { | ||
| ...listhenArgs.host, | ||
| alias: ["h"], | ||
| description: "Host to listen on (default: `NUXT_HOST || NITRO_HOST || HOST || nuxtOptions.devServer?.host`)" | ||
| }, | ||
| clipboard: { | ||
| ...listhenArgs.clipboard, | ||
| default: false | ||
| }, | ||
| ...profileArgs, | ||
| sslCert: { | ||
| type: "string", | ||
| description: "(DEPRECATED) Use `--https.cert` instead." | ||
| }, | ||
| sslKey: { | ||
| type: "string", | ||
| description: "(DEPRECATED) Use `--https.key` instead." | ||
| } | ||
| }, | ||
| async run(ctx) { | ||
| const cwd = resolve(ctx.args.cwd || ctx.args.rootDir); | ||
| const listenOverrides = resolveListenOverrides(ctx.args); | ||
| const { listener, close, onRestart, onReady } = await initialize({ | ||
| cwd, | ||
| args: ctx.args | ||
| }, { | ||
| data: ctx.data, | ||
| listenOverrides, | ||
| showBanner: true | ||
| }); | ||
| if (!ctx.args.fork || ctx.args.profile) return { | ||
| listener, | ||
| close | ||
| }; | ||
| const pool = new ForkPool({ | ||
| rawArgs: ctx.rawArgs, | ||
| poolSize: 2, | ||
| listenOverrides | ||
| }); | ||
| onReady((_address) => { | ||
| pool.startWarming(); | ||
| if (startTime) debug(`Dev server ready for connections in ${Date.now() - startTime}ms`); | ||
| }); | ||
| let cleanupCurrentFork; | ||
| async function restartWithFork() { | ||
| const context = { | ||
| cwd, | ||
| args: ctx.args | ||
| }; | ||
| cleanupCurrentFork?.(); | ||
| cleanupCurrentFork = await pool.getFork(context, (message) => { | ||
| if (message.type === "nuxt:internal:dev:ready") { | ||
| if (startTime) debug(`Dev server ready for connections in ${Date.now() - startTime}ms`); | ||
| } else if (message.type === "nuxt:internal:dev:restart") restartWithFork(); | ||
| else if (message.type === "nuxt:internal:dev:rejection") { | ||
| logger.info(`Restarting Nuxt due to error: ${colors.cyan(message.message)}`); | ||
| restartWithFork(); | ||
| } | ||
| }); | ||
| } | ||
| onRestart(async () => { | ||
| await close(); | ||
| await restartWithFork(); | ||
| }); | ||
| return { async close() { | ||
| cleanupCurrentFork?.(); | ||
| await Promise.all([listener.close(), close()]); | ||
| } }; | ||
| } | ||
| }); | ||
| function resolveListenOverrides(args) { | ||
| if (process.env._PORT) return { | ||
| port: process.env._PORT || 0, | ||
| hostname: "127.0.0.1", | ||
| showURL: false | ||
| }; | ||
| const options = parseArgs({ | ||
| ...args, | ||
| "host": args.host || process.env.NUXT_HOST || process.env.NITRO_HOST || process.env.HOST, | ||
| "port": args.port || process.env.NUXT_PORT || process.env.NITRO_PORT || process.env.PORT, | ||
| "https": args.https !== false && args.https !== "false", | ||
| "https.cert": args["https.cert"] || args.sslCert || process.env.NUXT_SSL_CERT || process.env.NITRO_SSL_CERT, | ||
| "https.key": args["https.key"] || args.sslKey || process.env.NUXT_SSL_KEY || process.env.NITRO_SSL_KEY | ||
| }); | ||
| return { | ||
| ...options, | ||
| _https: args.https, | ||
| get https() { | ||
| const httpsArg = this._https; | ||
| if (httpsArg === false || httpsArg === "false") return false; | ||
| return httpsArg ? options.https : false; | ||
| } | ||
| }; | ||
| } | ||
| function isBunForkSupported() { | ||
| const bunVersion = globalThis.Bun.version; | ||
| return satisfies(bunVersion, ">=1.2"); | ||
| } | ||
| //#endregion | ||
| export { command as default }; |
| import { a as legacyRootDirArgs, n as dotEnvArgs, o as logLevelArgs, r as envNameArgs, t as cwdArgs } from "./_shared-B6XhZQ-m.mjs"; | ||
| import process from "node:process"; | ||
| import { defineCommand } from "citty"; | ||
| import { isTest } from "std-env"; | ||
| import { resolve } from "pathe"; | ||
| //#region ../nuxi/src/commands/dev-child.ts | ||
| var dev_child_default = defineCommand({ | ||
| meta: { | ||
| name: "_dev", | ||
| description: "Run Nuxt development server (internal command to start child process)" | ||
| }, | ||
| args: { | ||
| ...cwdArgs, | ||
| ...logLevelArgs, | ||
| ...envNameArgs, | ||
| ...dotEnvArgs, | ||
| ...legacyRootDirArgs, | ||
| clear: { | ||
| type: "boolean", | ||
| description: "Clear console on restart", | ||
| negativeDescription: "Disable clear console on restart" | ||
| } | ||
| }, | ||
| async run(ctx) { | ||
| if (!process.send && !isTest) console.warn("`nuxi _dev` is an internal command and should not be used directly. Please use `nuxi dev` instead."); | ||
| const cwd = resolve(ctx.args.cwd || ctx.args.rootDir); | ||
| const { initialize } = await import("./dev-CttXIKD2.mjs").then((n) => n.t); | ||
| await initialize({ | ||
| cwd, | ||
| args: ctx.args | ||
| }, ctx); | ||
| } | ||
| }); | ||
| //#endregion | ||
| export { dev_child_default as default }; |
| import { t as __exportAll } from "./rolldown-runtime-wcPFST8Q.mjs"; | ||
| import { t as overrideEnv } from "./env-BfWVBvy7.mjs"; | ||
| import { a as stopCpuProfile, i as startCpuProfile, n as formatLockError, r as updateLock, t as acquireLock } from "./lockfile-BXsNI9ve.mjs"; | ||
| import { i as withNodePath, t as loadKit } from "./kit-BzPscsEd.mjs"; | ||
| import { n as showBanner } from "./banner-CTtM2dxO.mjs"; | ||
| import { t as clearBuildDir } from "./fs-B0HqP3GX.mjs"; | ||
| import { a as writeNuxtManifest, i as resolveNuxtManifest, n as loadNuxtManifest } from "./nuxt-CBsjK3fQ.mjs"; | ||
| import process from "node:process"; | ||
| import { provider } from "std-env"; | ||
| import { pathToFileURL } from "node:url"; | ||
| import defu from "defu"; | ||
| import { existsSync, readdirSync, statSync, watch } from "node:fs"; | ||
| import { join, resolve } from "pathe"; | ||
| import EventEmitter from "node:events"; | ||
| import { mkdir } from "node:fs/promises"; | ||
| import { resolveModulePath } from "exsolve"; | ||
| import { joinURL } from "ufo"; | ||
| import { listen } from "listhen"; | ||
| import { debounce } from "perfect-debounce"; | ||
| import { toNodeHandler } from "srvx/node"; | ||
| import { Youch } from "youch"; | ||
| //#region ../../node_modules/.pnpm/h3@1.15.11/node_modules/h3/dist/index.mjs | ||
| function hasProp(obj, prop) { | ||
| try { | ||
| return prop in obj; | ||
| } catch { | ||
| return false; | ||
| } | ||
| } | ||
| var H3Error = class extends Error { | ||
| static __h3_error__ = true; | ||
| statusCode = 500; | ||
| fatal = false; | ||
| unhandled = false; | ||
| statusMessage; | ||
| data; | ||
| cause; | ||
| constructor(message, opts = {}) { | ||
| super(message, opts); | ||
| if (opts.cause && !this.cause) this.cause = opts.cause; | ||
| } | ||
| toJSON() { | ||
| const obj = { | ||
| message: this.message, | ||
| statusCode: sanitizeStatusCode(this.statusCode, 500) | ||
| }; | ||
| if (this.statusMessage) obj.statusMessage = sanitizeStatusMessage(this.statusMessage); | ||
| if (this.data !== void 0) obj.data = this.data; | ||
| return obj; | ||
| } | ||
| }; | ||
| function createError(input) { | ||
| if (typeof input === "string") return new H3Error(input); | ||
| if (isError(input)) return input; | ||
| const err = new H3Error(input.message ?? input.statusMessage ?? "", { cause: input.cause || input }); | ||
| if (hasProp(input, "stack")) try { | ||
| Object.defineProperty(err, "stack", { get() { | ||
| return input.stack; | ||
| } }); | ||
| } catch { | ||
| try { | ||
| err.stack = input.stack; | ||
| } catch {} | ||
| } | ||
| if (input.data) err.data = input.data; | ||
| if (input.statusCode) err.statusCode = sanitizeStatusCode(input.statusCode, err.statusCode); | ||
| else if (input.status) err.statusCode = sanitizeStatusCode(input.status, err.statusCode); | ||
| if (input.statusMessage) err.statusMessage = input.statusMessage; | ||
| else if (input.statusText) err.statusMessage = input.statusText; | ||
| if (err.statusMessage) { | ||
| const originalMessage = err.statusMessage; | ||
| if (sanitizeStatusMessage(err.statusMessage) !== originalMessage) console.warn("[h3] Please prefer using `message` for longer error messages instead of `statusMessage`. In the future, `statusMessage` will be sanitized by default."); | ||
| } | ||
| if (input.fatal !== void 0) err.fatal = input.fatal; | ||
| if (input.unhandled !== void 0) err.unhandled = input.unhandled; | ||
| return err; | ||
| } | ||
| function sendError(event, error, debug) { | ||
| if (event.handled) return; | ||
| const h3Error = isError(error) ? error : createError(error); | ||
| const responseBody = { | ||
| statusCode: h3Error.statusCode, | ||
| statusMessage: h3Error.statusMessage, | ||
| stack: [], | ||
| data: h3Error.data | ||
| }; | ||
| if (debug) responseBody.stack = (h3Error.stack || "").split("\n").map((l) => l.trim()); | ||
| if (event.handled) return; | ||
| setResponseStatus(event, Number.parseInt(h3Error.statusCode), h3Error.statusMessage); | ||
| event.node.res.setHeader("content-type", MIMES.json); | ||
| event.node.res.end(JSON.stringify(responseBody, void 0, 2)); | ||
| } | ||
| function isError(input) { | ||
| return input?.constructor?.__h3_error__ === true; | ||
| } | ||
| const MIMES = { | ||
| html: "text/html", | ||
| json: "application/json" | ||
| }; | ||
| const DISALLOWED_STATUS_CHARS = /[^\u0009\u0020-\u007E]/g; | ||
| function sanitizeStatusMessage(statusMessage = "") { | ||
| return statusMessage.replace(DISALLOWED_STATUS_CHARS, ""); | ||
| } | ||
| function sanitizeStatusCode(statusCode, defaultStatusCode = 200) { | ||
| if (!statusCode) return defaultStatusCode; | ||
| if (typeof statusCode === "string") statusCode = Number.parseInt(statusCode, 10); | ||
| if (statusCode < 100 || statusCode > 999) return defaultStatusCode; | ||
| return statusCode; | ||
| } | ||
| function splitCookiesString(cookiesString) { | ||
| if (Array.isArray(cookiesString)) return cookiesString.flatMap((c) => splitCookiesString(c)); | ||
| if (typeof cookiesString !== "string") return []; | ||
| const cookiesStrings = []; | ||
| let pos = 0; | ||
| let start; | ||
| let ch; | ||
| let lastComma; | ||
| let nextStart; | ||
| let cookiesSeparatorFound; | ||
| const skipWhitespace = () => { | ||
| while (pos < cookiesString.length && /\s/.test(cookiesString.charAt(pos))) pos += 1; | ||
| return pos < cookiesString.length; | ||
| }; | ||
| const notSpecialChar = () => { | ||
| ch = cookiesString.charAt(pos); | ||
| return ch !== "=" && ch !== ";" && ch !== ","; | ||
| }; | ||
| while (pos < cookiesString.length) { | ||
| start = pos; | ||
| cookiesSeparatorFound = false; | ||
| while (skipWhitespace()) { | ||
| ch = cookiesString.charAt(pos); | ||
| if (ch === ",") { | ||
| lastComma = pos; | ||
| pos += 1; | ||
| skipWhitespace(); | ||
| nextStart = pos; | ||
| while (pos < cookiesString.length && notSpecialChar()) pos += 1; | ||
| if (pos < cookiesString.length && cookiesString.charAt(pos) === "=") { | ||
| cookiesSeparatorFound = true; | ||
| pos = nextStart; | ||
| cookiesStrings.push(cookiesString.slice(start, lastComma)); | ||
| start = pos; | ||
| } else pos = lastComma + 1; | ||
| } else pos += 1; | ||
| } | ||
| if (!cookiesSeparatorFound || pos >= cookiesString.length) cookiesStrings.push(cookiesString.slice(start)); | ||
| } | ||
| return cookiesStrings; | ||
| } | ||
| function setResponseStatus(event, code, text) { | ||
| if (code) event.node.res.statusCode = sanitizeStatusCode(code, event.node.res.statusCode); | ||
| if (text) event.node.res.statusMessage = sanitizeStatusMessage(text); | ||
| } | ||
| function sendStream(event, stream) { | ||
| if (!stream || typeof stream !== "object") throw new Error("[h3] Invalid stream provided."); | ||
| event.node.res._data = stream; | ||
| if (!event.node.res.socket) { | ||
| event._handled = true; | ||
| return Promise.resolve(); | ||
| } | ||
| if (hasProp(stream, "pipeTo") && typeof stream.pipeTo === "function") return stream.pipeTo(new WritableStream({ write(chunk) { | ||
| event.node.res.write(chunk); | ||
| } })).then(() => { | ||
| event.node.res.end(); | ||
| }); | ||
| if (hasProp(stream, "pipe") && typeof stream.pipe === "function") return new Promise((resolve, reject) => { | ||
| stream.pipe(event.node.res); | ||
| if (stream.on) { | ||
| stream.on("end", () => { | ||
| event.node.res.end(); | ||
| resolve(); | ||
| }); | ||
| stream.on("error", (error) => { | ||
| reject(error); | ||
| }); | ||
| } | ||
| event.node.res.on("close", () => { | ||
| if (stream.abort) stream.abort(); | ||
| }); | ||
| }); | ||
| throw new Error("[h3] Invalid or incompatible stream provided."); | ||
| } | ||
| function sendWebResponse(event, response) { | ||
| for (const [key, value] of response.headers) if (key === "set-cookie") event.node.res.appendHeader(key, splitCookiesString(value)); | ||
| else event.node.res.setHeader(key, value); | ||
| if (response.status) event.node.res.statusCode = sanitizeStatusCode(response.status, event.node.res.statusCode); | ||
| if (response.statusText) event.node.res.statusMessage = sanitizeStatusMessage(response.statusText); | ||
| if (response.redirected) event.node.res.setHeader("location", response.url); | ||
| if (!response.body) { | ||
| event.node.res.end(); | ||
| return; | ||
| } | ||
| return sendStream(event, response.body); | ||
| } | ||
| var H3Event = class { | ||
| "__is_event__" = true; | ||
| node; | ||
| web; | ||
| context = {}; | ||
| _method; | ||
| _path; | ||
| _headers; | ||
| _requestBody; | ||
| _handled = false; | ||
| _onBeforeResponseCalled; | ||
| _onAfterResponseCalled; | ||
| constructor(req, res) { | ||
| this.node = { | ||
| req, | ||
| res | ||
| }; | ||
| } | ||
| get method() { | ||
| if (!this._method) this._method = (this.node.req.method || "GET").toUpperCase(); | ||
| return this._method; | ||
| } | ||
| get path() { | ||
| return this._path || this.node.req.url || "/"; | ||
| } | ||
| get headers() { | ||
| if (!this._headers) this._headers = _normalizeNodeHeaders(this.node.req.headers); | ||
| return this._headers; | ||
| } | ||
| get handled() { | ||
| return this._handled || this.node.res.writableEnded || this.node.res.headersSent; | ||
| } | ||
| respondWith(response) { | ||
| return Promise.resolve(response).then((_response) => sendWebResponse(this, _response)); | ||
| } | ||
| toString() { | ||
| return `[${this.method}] ${this.path}`; | ||
| } | ||
| toJSON() { | ||
| return this.toString(); | ||
| } | ||
| /** @deprecated Please use `event.node.req` instead. */ | ||
| get req() { | ||
| return this.node.req; | ||
| } | ||
| /** @deprecated Please use `event.node.res` instead. */ | ||
| get res() { | ||
| return this.node.res; | ||
| } | ||
| }; | ||
| function createEvent(req, res) { | ||
| return new H3Event(req, res); | ||
| } | ||
| function _normalizeNodeHeaders(nodeHeaders) { | ||
| const headers = new Headers(); | ||
| for (const [name, value] of Object.entries(nodeHeaders)) if (Array.isArray(value)) for (const item of value) headers.append(name, item); | ||
| else if (value) headers.set(name, value); | ||
| return headers; | ||
| } | ||
| globalThis.Headers; | ||
| globalThis.Response; | ||
| function toNodeListener(app) { | ||
| const toNodeHandle = async function(req, res) { | ||
| const event = createEvent(req, res); | ||
| try { | ||
| await app.handler(event); | ||
| } catch (_error) { | ||
| const error = createError(_error); | ||
| if (!isError(_error)) error.unhandled = true; | ||
| setResponseStatus(event, error.statusCode, error.statusMessage); | ||
| if (app.options.onError) await app.options.onError(error, event); | ||
| if (event.handled) return; | ||
| if (error.unhandled || error.fatal) console.error("[h3]", error.fatal ? "[fatal]" : "[unhandled]", error); | ||
| if (app.options.onBeforeResponse && !event._onBeforeResponseCalled) await app.options.onBeforeResponse(event, { body: error }); | ||
| await sendError(event, error, !!app.options.debug); | ||
| if (app.options.onAfterResponse && !event._onAfterResponseCalled) await app.options.onAfterResponse(event, { body: error }); | ||
| } | ||
| }; | ||
| return toNodeHandle; | ||
| } | ||
| //#endregion | ||
| //#region ../nuxi/src/dev/error.ts | ||
| async function renderError(req, res, error) { | ||
| if (res.headersSent) { | ||
| if (!res.writableEnded) res.end(); | ||
| return; | ||
| } | ||
| const youch = new Youch(); | ||
| res.statusCode = 500; | ||
| res.setHeader("Content-Type", "text/html"); | ||
| res.setHeader("Cache-Control", "no-store"); | ||
| res.setHeader("Refresh", "3"); | ||
| const html = await youch.toHTML(error, { request: { | ||
| url: req.url, | ||
| method: req.method, | ||
| headers: req.headers | ||
| } }); | ||
| res.end(html); | ||
| } | ||
| //#endregion | ||
| //#region ../nuxi/src/dev/utils.ts | ||
| const RESTART_RE = /^(?:nuxt\.config\.[a-z0-9]+|\.nuxtignore|\.nuxtrc|\.config\/nuxt(?:\.config)?\.[a-z0-9]+)$/; | ||
| const TRAILING_SLASH_RE = /\/$/; | ||
| var FileChangeTracker = class { | ||
| mtimes = /* @__PURE__ */ new Map(); | ||
| shouldEmitChange(filePath) { | ||
| const resolved = resolve(filePath); | ||
| try { | ||
| const currentMtime = statSync(resolved).mtimeMs; | ||
| const lastMtime = this.mtimes.get(resolved); | ||
| this.mtimes.set(resolved, currentMtime); | ||
| return lastMtime === void 0 || currentMtime !== lastMtime; | ||
| } catch { | ||
| this.mtimes.delete(resolved); | ||
| return true; | ||
| } | ||
| } | ||
| prime(filePath, recursive = false) { | ||
| const resolved = resolve(filePath); | ||
| const stat = statSync(resolved); | ||
| this.mtimes.set(resolved, stat.mtimeMs); | ||
| if (stat.isDirectory()) { | ||
| const entries = readdirSync(resolved); | ||
| for (const entry of entries) { | ||
| const fullPath = resolve(resolved, entry); | ||
| try { | ||
| const stats = statSync(fullPath); | ||
| this.mtimes.set(fullPath, stats.mtimeMs); | ||
| if (recursive && stats.isDirectory()) this.prime(fullPath, recursive); | ||
| } catch {} | ||
| } | ||
| } | ||
| } | ||
| }; | ||
| var NuxtDevServer = class extends EventEmitter { | ||
| #handler; | ||
| #distWatcher; | ||
| #configWatcher; | ||
| #currentNuxt; | ||
| #loadingMessage; | ||
| #loadingError; | ||
| #fileChangeTracker = new FileChangeTracker(); | ||
| #cwd; | ||
| #websocketConnections = /* @__PURE__ */ new Set(); | ||
| #lockCleanup; | ||
| #lockedBuildDir; | ||
| loadDebounced; | ||
| handler; | ||
| listener; | ||
| constructor(options) { | ||
| super(); | ||
| this.options = options; | ||
| this.loadDebounced = debounce(this.load); | ||
| let _initResolve; | ||
| const _initPromise = new Promise((resolve) => { | ||
| _initResolve = resolve; | ||
| }); | ||
| this.once("ready", () => { | ||
| _initResolve(); | ||
| }); | ||
| this.#cwd = options.cwd; | ||
| this.handler = async (req, res) => { | ||
| if (this.#loadingError) { | ||
| renderError(req, res, this.#loadingError); | ||
| return; | ||
| } | ||
| await _initPromise; | ||
| if (this.#handler) this.#handler(req, res); | ||
| else this.#renderLoadingScreen(req, res); | ||
| }; | ||
| } | ||
| async #renderLoadingScreen(req, res) { | ||
| if (res.headersSent) { | ||
| if (!res.writableEnded) res.end(); | ||
| return; | ||
| } | ||
| res.statusCode = 503; | ||
| res.setHeader("Content-Type", "text/html"); | ||
| const loadingTemplate = this.options.loadingTemplate || this.#currentNuxt?.options.devServer.loadingTemplate || await resolveLoadingTemplate(this.#cwd); | ||
| res.end(loadingTemplate({ loading: this.#loadingMessage || "Loading..." })); | ||
| } | ||
| async init() { | ||
| const action = "Starting"; | ||
| this.#loadingMessage = `${action} Nuxt...`; | ||
| this.#handler = void 0; | ||
| this.emit("loading", this.#loadingMessage); | ||
| await this.#loadNuxtInstance(); | ||
| this.#acquireDevLock(this.#currentNuxt.options.buildDir); | ||
| if (this.options.showBanner) showBanner(this.#currentNuxt); | ||
| await this.#createListener(); | ||
| await this.#initializeNuxt(false); | ||
| this.#watchConfig(); | ||
| } | ||
| closeWatchers() { | ||
| this.#distWatcher?.close(); | ||
| this.#configWatcher?.(); | ||
| } | ||
| async load(reload, reason) { | ||
| try { | ||
| this.closeWatchers(); | ||
| await this.#load(reload, reason); | ||
| this.#loadingError = void 0; | ||
| } catch (error) { | ||
| console.error(`Cannot ${reload ? "restart" : "start"} nuxt: `, error); | ||
| this.#handler = void 0; | ||
| this.#loadingError = error; | ||
| this.#loadingMessage = "Error while loading Nuxt. Please check console and fix errors."; | ||
| this.emit("loading:error", error); | ||
| } | ||
| this.#watchConfig(); | ||
| } | ||
| async #loadNuxtInstance(urls) { | ||
| const kit = await loadKit(this.options.cwd); | ||
| const loadOptions = { | ||
| cwd: this.options.cwd, | ||
| dev: true, | ||
| ready: false, | ||
| envName: this.options.envName, | ||
| dotenv: { | ||
| cwd: this.options.cwd, | ||
| fileName: this.options.dotenv.fileName | ||
| }, | ||
| overrides: { | ||
| logLevel: this.options.logLevel, | ||
| ...this.options.overrides, | ||
| vite: { | ||
| clearScreen: this.options.clear, | ||
| ...this.options.overrides.vite | ||
| } | ||
| } | ||
| }; | ||
| if (urls) { | ||
| const overrides = this.options.listenOverrides || {}; | ||
| const hostname = overrides.hostname; | ||
| const https = overrides.https; | ||
| loadOptions.defaults = resolveDevServerDefaults({ | ||
| hostname, | ||
| https | ||
| }, urls); | ||
| } | ||
| this.#currentNuxt = await kit.loadNuxt(loadOptions); | ||
| } | ||
| async #createListener() { | ||
| if (!this.#currentNuxt) throw new Error("Nuxt must be loaded before creating listener"); | ||
| const listenOptions = this.#resolveListenOptions(); | ||
| this.listener = await listen(this.handler, listenOptions); | ||
| if (listenOptions.public) { | ||
| this.#currentNuxt.options.devServer.cors = { origin: "*" }; | ||
| if (this.#currentNuxt.options.vite?.server) this.#currentNuxt.options.vite.server.allowedHosts = true; | ||
| return; | ||
| } | ||
| const urls = await this.listener.getURLs().then((r) => r.map((r) => r.url)); | ||
| if (urls && urls.length > 0) this.#currentNuxt.options.vite = defu(this.#currentNuxt.options.vite, { server: { allowedHosts: urls.map((u) => new URL(u).hostname) } }); | ||
| } | ||
| #resolveListenOptions() { | ||
| if (!this.#currentNuxt) throw new Error("Nuxt must be loaded before resolving listen options"); | ||
| const nuxtConfig = this.#currentNuxt.options; | ||
| const overrides = this.options.listenOverrides || {}; | ||
| const port = overrides.port ?? nuxtConfig.devServer?.port; | ||
| const hostname = overrides.hostname ?? nuxtConfig.devServer?.host; | ||
| const isPublic = provider === "codesandbox" || (overrides.public ?? (isPublicHostname(hostname) ? true : void 0)); | ||
| const httpsFromConfig = typeof nuxtConfig.devServer?.https !== "boolean" && nuxtConfig.devServer?.https ? nuxtConfig.devServer.https : {}; | ||
| overrides._https ??= !!nuxtConfig.devServer?.https; | ||
| const httpsOptions = overrides.https && defu(typeof overrides.https === "object" ? overrides.https : {}, httpsFromConfig); | ||
| const baseURL = nuxtConfig.app?.baseURL?.startsWith?.("./") ? nuxtConfig.app.baseURL.slice(1) : nuxtConfig.app?.baseURL; | ||
| return { | ||
| ...overrides, | ||
| port, | ||
| hostname, | ||
| public: isPublic, | ||
| https: httpsOptions || void 0, | ||
| baseURL | ||
| }; | ||
| } | ||
| async #initializeNuxt(reload) { | ||
| if (!this.#currentNuxt) throw new Error("Nuxt must be loaded before configuration"); | ||
| if (!process.env.NUXI_DISABLE_VITE_HMR) this.#currentNuxt.hooks.hook("vite:extend", ({ config }) => { | ||
| if (config.server) config.server.hmr = { | ||
| protocol: void 0, | ||
| ...config.server.hmr, | ||
| port: void 0, | ||
| host: void 0, | ||
| server: this.listener.server | ||
| }; | ||
| }); | ||
| this.#currentNuxt.hooks.hookOnce("close", () => { | ||
| this.#closeWebSocketConnections(); | ||
| this.listener.server.removeAllListeners("upgrade"); | ||
| }); | ||
| if (!reload) { | ||
| const previousManifest = await loadNuxtManifest(this.#currentNuxt.options.buildDir); | ||
| const newManifest = resolveNuxtManifest(this.#currentNuxt); | ||
| const promise = writeNuxtManifest(this.#currentNuxt, newManifest); | ||
| this.#currentNuxt.hooks.hookOnce("ready", async () => { | ||
| await promise; | ||
| }); | ||
| if (previousManifest && newManifest && previousManifest._hash !== newManifest._hash) await clearBuildDir(this.#currentNuxt.options.buildDir); | ||
| } | ||
| await this.#currentNuxt.ready(); | ||
| const unsub = this.#currentNuxt.hooks.hook("restart", async (options) => { | ||
| unsub(); | ||
| if (options?.hard) { | ||
| this.emit("restart"); | ||
| return; | ||
| } | ||
| await this.load(true); | ||
| }); | ||
| if (this.#currentNuxt.server && "upgrade" in this.#currentNuxt.server) this.listener.server.on("upgrade", (req, socket, head) => { | ||
| const nuxt = this.#currentNuxt; | ||
| if (!nuxt || !nuxt.server) return; | ||
| const viteHmrPath = joinURL(nuxt.options.app.baseURL.startsWith("./") ? nuxt.options.app.baseURL.slice(1) : nuxt.options.app.baseURL, nuxt.options.app.buildAssetsDir); | ||
| if (req.url?.startsWith(viteHmrPath)) return; | ||
| nuxt.server.upgrade(req, socket, head); | ||
| this.#websocketConnections.add(socket); | ||
| socket.on("close", () => { | ||
| this.#websocketConnections.delete(socket); | ||
| }); | ||
| }); | ||
| await this.#currentNuxt.hooks.callHook("listen", this.listener.server, this.listener); | ||
| const addr = this.listener.address; | ||
| this.#currentNuxt.options.devServer.host = addr.address; | ||
| this.#currentNuxt.options.devServer.port = addr.port; | ||
| this.#currentNuxt.options.devServer.url = getAddressURL(addr, !!this.listener.https); | ||
| this.#currentNuxt.options.devServer.https = this.listener.https; | ||
| if (this.listener.https && !process.env.NODE_TLS_REJECT_UNAUTHORIZED) console.warn("You might need `NODE_TLS_REJECT_UNAUTHORIZED=0` environment variable to make https work."); | ||
| const kit = await loadKit(this.options.cwd); | ||
| const typesPromise = existsSync(join(this.#currentNuxt.options.buildDir, "tsconfig.json")) ? kit.writeTypes(this.#currentNuxt).catch(console.error) : await kit.writeTypes(this.#currentNuxt).catch(console.error); | ||
| await Promise.all([typesPromise, kit.buildNuxt(this.#currentNuxt)]); | ||
| if (!this.#currentNuxt.server) throw new Error("Nitro server has not been initialized."); | ||
| const distDir = join(this.#currentNuxt.options.buildDir, "dist"); | ||
| await mkdir(distDir, { recursive: true }); | ||
| this.#fileChangeTracker.prime(distDir); | ||
| this.#distWatcher = watch(distDir); | ||
| this.#distWatcher.on("change", (_event, file) => { | ||
| if (!this.#fileChangeTracker.shouldEmitChange(resolve(distDir, file || ""))) return; | ||
| this.loadDebounced(true, ".nuxt/dist directory has been removed"); | ||
| }); | ||
| if ("handler" in this.#currentNuxt.server) this.#handler = this.#currentNuxt.server.handler; | ||
| else if ("fetch" in this.#currentNuxt.server) this.#handler = toNodeHandler(this.#currentNuxt.server.fetch); | ||
| else this.#handler = toNodeListener(this.#currentNuxt.server.app); | ||
| const serverUrl = getAddressURL(addr, !!this.listener.https).replace(TRAILING_SLASH_RE, ""); | ||
| const currentBuildDir = this.#currentNuxt.options.buildDir; | ||
| if (this.#lockedBuildDir !== currentBuildDir) this.#acquireDevLock(currentBuildDir); | ||
| updateLock(currentBuildDir, { | ||
| command: "dev", | ||
| cwd: this.options.cwd, | ||
| port: addr.port, | ||
| hostname: addr.address, | ||
| url: serverUrl | ||
| }); | ||
| this.emit("ready", serverUrl); | ||
| } | ||
| async close() { | ||
| if (this.#currentNuxt) await this.#currentNuxt.close(); | ||
| } | ||
| /** Release the lock file. Call only on final shutdown, not during reloads. */ | ||
| releaseLock() { | ||
| this.#lockCleanup?.(); | ||
| this.#lockCleanup = void 0; | ||
| this.#lockedBuildDir = void 0; | ||
| } | ||
| #acquireDevLock(buildDir) { | ||
| const lock = acquireLock(buildDir, { | ||
| command: "dev", | ||
| cwd: this.options.cwd | ||
| }); | ||
| if (lock.existing) { | ||
| console.error(formatLockError(lock.existing)); | ||
| throw new Error(`Another Nuxt ${lock.existing.command} is already running (PID ${lock.existing.pid}).`); | ||
| } | ||
| const previousRelease = this.#lockCleanup; | ||
| this.#lockCleanup = lock.release; | ||
| this.#lockedBuildDir = buildDir; | ||
| previousRelease?.(); | ||
| } | ||
| #closeWebSocketConnections() { | ||
| for (const socket of this.#websocketConnections) socket.destroy(); | ||
| this.#websocketConnections.clear(); | ||
| } | ||
| async #load(reload, reason) { | ||
| const action = reload ? "Restarting" : "Starting"; | ||
| this.#loadingMessage = `${reason ? `${reason}. ` : ""}${action} Nuxt...`; | ||
| this.#handler = void 0; | ||
| this.emit("loading", this.#loadingMessage); | ||
| if (reload) console.info(this.#loadingMessage); | ||
| await this.close(); | ||
| const urls = await this.listener.getURLs().then((r) => r.map((r) => r.url)); | ||
| await this.#loadNuxtInstance(urls); | ||
| await this.#initializeNuxt(!!reload); | ||
| } | ||
| #watchConfig() { | ||
| this.#configWatcher = createConfigWatcher(this.#cwd, this.options.dotenv.fileName, () => this.emit("restart"), (file) => this.loadDebounced(true, `${file} updated`)); | ||
| } | ||
| }; | ||
| function getAddressURL(addr, https) { | ||
| const proto = https ? "https" : "http"; | ||
| let host = addr.address.includes(":") ? `[${addr.address}]` : addr.address; | ||
| if (host === "[::]") host = "localhost"; | ||
| const port = addr.port || 3e3; | ||
| return `${proto}://${host}:${port}/`; | ||
| } | ||
| function resolveDevServerDefaults(listenOptions, urls = []) { | ||
| const defaultConfig = {}; | ||
| if (urls && urls.length > 0) defaultConfig.vite = { server: { allowedHosts: urls.map((u) => new URL(u).hostname) } }; | ||
| if (listenOptions.hostname) { | ||
| defaultConfig.devServer = { cors: { origin: [`${listenOptions.https ? "https" : "http"}://${listenOptions.hostname}`, ...urls] } }; | ||
| defaultConfig.vite = defu(defaultConfig.vite, { server: { allowedHosts: [listenOptions.hostname] } }); | ||
| } | ||
| return defaultConfig; | ||
| } | ||
| function createConfigWatcher(cwd, dotenvFileName = ".env", onRestart, onReload) { | ||
| const fileWatcher = new FileChangeTracker(); | ||
| fileWatcher.prime(cwd); | ||
| const configWatcher = watch(cwd); | ||
| let configDirWatcher = existsSync(join(cwd, ".config")) ? createConfigDirWatcher(cwd, onReload) : void 0; | ||
| const dotenvFileNames = new Set(Array.isArray(dotenvFileName) ? dotenvFileName : [dotenvFileName]); | ||
| configWatcher.on("change", (_event, file) => { | ||
| if (!fileWatcher.shouldEmitChange(resolve(cwd, file))) return; | ||
| if (dotenvFileNames.has(file)) onRestart(); | ||
| if (RESTART_RE.test(file)) onReload(file); | ||
| if (file === ".config") configDirWatcher ||= createConfigDirWatcher(cwd, onReload); | ||
| }); | ||
| return () => { | ||
| configWatcher.close(); | ||
| configDirWatcher?.(); | ||
| }; | ||
| } | ||
| function createConfigDirWatcher(cwd, onReload) { | ||
| const configDir = join(cwd, ".config"); | ||
| const fileWatcher = new FileChangeTracker(); | ||
| fileWatcher.prime(configDir); | ||
| const configDirWatcher = watch(configDir); | ||
| configDirWatcher.on("change", (_event, file) => { | ||
| if (!fileWatcher.shouldEmitChange(resolve(configDir, file))) return; | ||
| if (RESTART_RE.test(file)) onReload(file); | ||
| }); | ||
| return () => configDirWatcher.close(); | ||
| } | ||
| async function resolveLoadingTemplate(cwd) { | ||
| return (await import(pathToFileURL(resolveModulePath("@nuxt/ui-templates", { from: withNodePath(resolveModulePath("nuxt", { | ||
| from: withNodePath(cwd), | ||
| try: true | ||
| }) || cwd) })).href)).loading || ((params) => `<h2>${params.loading}</h2>`); | ||
| } | ||
| function isPublicHostname(hostname) { | ||
| return !!hostname && ![ | ||
| "localhost", | ||
| "127.0.0.1", | ||
| "::1" | ||
| ].includes(hostname); | ||
| } | ||
| //#endregion | ||
| //#region ../nuxi/src/dev/index.ts | ||
| var dev_exports = /* @__PURE__ */ __exportAll({ initialize: () => initialize }); | ||
| const start = Date.now(); | ||
| var IPC = class { | ||
| enabled = !!process.send && !process.title?.includes("vitest") && process.env.__NUXT__FORK; | ||
| constructor() { | ||
| if (this.enabled) process.once("unhandledRejection", (reason) => { | ||
| this.send({ | ||
| type: "nuxt:internal:dev:rejection", | ||
| message: reason instanceof Error ? reason.toString() : "Unhandled Rejection" | ||
| }); | ||
| process.exit(); | ||
| }); | ||
| process.on("message", (message) => { | ||
| if (message.type === "nuxt:internal:dev:context") initialize(message.context, { listenOverrides: message.listenOverrides }); | ||
| }); | ||
| this.send({ type: "nuxt:internal:dev:fork-ready" }); | ||
| } | ||
| send(message) { | ||
| if (this.enabled) process.send?.(message); | ||
| } | ||
| }; | ||
| const ipc = new IPC(); | ||
| async function initialize(devContext, ctx = {}) { | ||
| overrideEnv("development"); | ||
| const profileArg = devContext.args.profile; | ||
| const perfValue = profileArg === "verbose" ? true : profileArg ? "quiet" : void 0; | ||
| const perfOverrides = perfValue ? { debug: { perf: perfValue } } : {}; | ||
| if (profileArg) await startCpuProfile(); | ||
| const devServer = new NuxtDevServer({ | ||
| cwd: devContext.cwd, | ||
| overrides: defu(ctx.data?.overrides, { extends: devContext.args.extends }, perfOverrides), | ||
| logLevel: devContext.args.logLevel, | ||
| clear: devContext.args.clear, | ||
| dotenv: { | ||
| cwd: devContext.cwd, | ||
| fileName: devContext.args.dotenv | ||
| }, | ||
| envName: devContext.args.envName, | ||
| showBanner: ctx.showBanner !== false && !ipc.enabled, | ||
| listenOverrides: ctx.listenOverrides | ||
| }); | ||
| let address; | ||
| if (ipc.enabled) { | ||
| devServer.on("loading:error", (_error) => { | ||
| ipc.send({ | ||
| type: "nuxt:internal:dev:loading:error", | ||
| error: { | ||
| message: _error.message, | ||
| stack: _error.stack, | ||
| name: _error.name, | ||
| code: "code" in _error ? _error.code : void 0 | ||
| } | ||
| }); | ||
| }); | ||
| devServer.on("loading", (message) => { | ||
| ipc.send({ | ||
| type: "nuxt:internal:dev:loading", | ||
| message | ||
| }); | ||
| }); | ||
| devServer.on("restart", () => { | ||
| ipc.send({ type: "nuxt:internal:dev:restart" }); | ||
| }); | ||
| devServer.on("ready", (payload) => { | ||
| ipc.send({ | ||
| type: "nuxt:internal:dev:ready", | ||
| address: payload | ||
| }); | ||
| }); | ||
| } else devServer.on("ready", (payload) => { | ||
| address = payload; | ||
| }); | ||
| await devServer.init(); | ||
| if (process.env.DEBUG) console.debug(`Dev server (internal) initialized in ${Date.now() - start}ms`); | ||
| if (profileArg) for (const signal of [ | ||
| "exit", | ||
| "SIGTERM", | ||
| "SIGINT", | ||
| "SIGQUIT" | ||
| ]) process.once(signal, () => stopCpuProfile(devContext.cwd, "dev")); | ||
| return { | ||
| listener: devServer.listener, | ||
| close: async () => { | ||
| devServer.closeWatchers(); | ||
| await Promise.all([devServer.listener.close(), devServer.close()]); | ||
| devServer.releaseLock(); | ||
| }, | ||
| onReady: (callback) => { | ||
| if (address) callback(address); | ||
| else devServer.once("ready", (payload) => callback(payload)); | ||
| }, | ||
| onRestart: (callback) => { | ||
| let restarted = false; | ||
| function restart() { | ||
| if (!restarted) { | ||
| restarted = true; | ||
| callback(devServer); | ||
| } | ||
| } | ||
| devServer.once("restart", restart); | ||
| process.once("uncaughtException", restart); | ||
| process.once("unhandledRejection", restart); | ||
| } | ||
| }; | ||
| } | ||
| //#endregion | ||
| export { initialize as n, dev_exports as t }; |
| import { a as legacyRootDirArgs, i as extendsArgs, n as dotEnvArgs, o as logLevelArgs, r as envNameArgs, s as profileArgs, t as cwdArgs } from "./_shared-B6XhZQ-m.mjs"; | ||
| import build_default from "./build-d7zHMQ9n.mjs"; | ||
| import { defineCommand } from "citty"; | ||
| //#region ../nuxi/src/commands/generate.ts | ||
| var generate_default = defineCommand({ | ||
| meta: { | ||
| name: "generate", | ||
| description: "Build Nuxt and prerender all routes" | ||
| }, | ||
| args: { | ||
| ...cwdArgs, | ||
| ...logLevelArgs, | ||
| preset: { | ||
| type: "string", | ||
| description: "Nitro server preset" | ||
| }, | ||
| ...dotEnvArgs, | ||
| ...envNameArgs, | ||
| ...extendsArgs, | ||
| ...profileArgs, | ||
| ...legacyRootDirArgs | ||
| }, | ||
| async run(ctx) { | ||
| ctx.args.prerender = true; | ||
| await build_default.run(ctx); | ||
| } | ||
| }); | ||
| //#endregion | ||
| export { generate_default as default }; |
| import { a as legacyRootDirArgs, t as cwdArgs } from "./_shared-B6XhZQ-m.mjs"; | ||
| import { n as logger } from "./logger-C1qVsppt.mjs"; | ||
| import { n as tryResolveNuxt } from "./kit-BzPscsEd.mjs"; | ||
| import { t as getBuilder } from "./banner-CTtM2dxO.mjs"; | ||
| import { t as formatInfoBox } from "./formatting-BobJCzk9.mjs"; | ||
| import { t as getPackageManagerVersion } from "./packageManagers-Y5z0Pi7r.mjs"; | ||
| import process from "node:process"; | ||
| import { defineCommand } from "citty"; | ||
| import { colors } from "consola/utils"; | ||
| import { isBun, isDeno, isMinimal } from "std-env"; | ||
| import { box } from "@clack/prompts"; | ||
| import { resolve } from "pathe"; | ||
| import { readPackageJSON } from "pkg-types"; | ||
| import os from "node:os"; | ||
| import { detectPackageManager } from "nypm"; | ||
| import { writeText } from "tinyclip"; | ||
| //#region ../nuxi/package.json | ||
| var version = "3.35.1"; | ||
| //#endregion | ||
| //#region ../nuxi/src/commands/info.ts | ||
| const LEADING_SLASH_RE = /^\//; | ||
| var info_default = defineCommand({ | ||
| meta: { | ||
| name: "info", | ||
| description: "Get information about Nuxt project" | ||
| }, | ||
| args: { | ||
| ...cwdArgs, | ||
| ...legacyRootDirArgs | ||
| }, | ||
| async run(ctx) { | ||
| const cwd = resolve(ctx.args.cwd || ctx.args.rootDir); | ||
| const nuxtConfig = await getNuxtConfig(cwd); | ||
| const { dependencies = {}, devDependencies = {} } = await readPackageJSON(cwd).catch(() => ({})); | ||
| const nuxtPath = tryResolveNuxt(cwd); | ||
| async function getDepVersion(name) { | ||
| for (const url of [cwd, nuxtPath]) { | ||
| if (!url) continue; | ||
| const pkg = await readPackageJSON(name, { url }).catch(() => null); | ||
| if (pkg) return pkg.version; | ||
| } | ||
| return dependencies[name] || devDependencies[name]; | ||
| } | ||
| async function listModules(arr = []) { | ||
| const info = []; | ||
| for (let m of arr) { | ||
| if (Array.isArray(m)) m = m[0]; | ||
| const name = normalizeConfigModule(m, cwd); | ||
| if (name) { | ||
| const v = await getDepVersion(name.split("/").splice(0, 2).join("/")); | ||
| info.push(`\`${v ? `${name}@${v}` : name}\``); | ||
| } | ||
| } | ||
| return info.join(", "); | ||
| } | ||
| const nuxtVersion = await getDepVersion("nuxt") || await getDepVersion("nuxt-nightly") || await getDepVersion("nuxt-edge") || await getDepVersion("nuxt3") || "-"; | ||
| const isLegacy = nuxtVersion.startsWith("2"); | ||
| const builder = !isLegacy ? nuxtConfig.builder || "vite" : nuxtConfig.bridge?.vite ? "vite" : nuxtConfig.buildModules?.includes("nuxt-vite") ? "vite" : "webpack"; | ||
| let packageManager = (await detectPackageManager(cwd))?.name; | ||
| if (packageManager) packageManager += `@${getPackageManagerVersion(packageManager)}`; | ||
| const osType = os.type(); | ||
| const builderInfo = typeof builder === "string" ? getBuilder(cwd, builder) : { | ||
| name: "custom", | ||
| version: "0.0.0" | ||
| }; | ||
| const infoObj = { | ||
| "Operating system": osType === "Darwin" ? `macOS ${os.release()}` : osType === "Windows_NT" ? `Windows ${os.release()}` : `${osType} ${os.release()}`, | ||
| "CPU": `${os.cpus()[0]?.model || "unknown"} (${os.cpus().length} cores)`, | ||
| ...isBun ? { "Bun version": Bun?.version } : isDeno ? { "Deno version": Deno?.version.deno } : { "Node.js version": process.version }, | ||
| "nuxt/cli version": version, | ||
| "Package manager": packageManager ?? "unknown", | ||
| "Nuxt version": nuxtVersion, | ||
| "Nitro version": await getDepVersion("nitropack") || await getDepVersion("nitro"), | ||
| "Builder": builderInfo.name === "custom" ? "custom" : `${builderInfo.name.toLowerCase()}@${builderInfo.version}`, | ||
| "Config": Object.keys(nuxtConfig).map((key) => `\`${key}\``).sort().join(", "), | ||
| "Modules": await listModules(nuxtConfig.modules), | ||
| ...isLegacy ? { "Build modules": await listModules(nuxtConfig.buildModules || []) } : {} | ||
| }; | ||
| logger.info(`Nuxt root directory: ${colors.cyan(nuxtConfig.rootDir || cwd)}\n`); | ||
| const boxStr = formatInfoBox(infoObj); | ||
| let firstColumnLength = 0; | ||
| let secondColumnLength = 0; | ||
| const entries = Object.entries(infoObj).map(([label, val]) => { | ||
| if (label.length > firstColumnLength) firstColumnLength = label.length + 4; | ||
| if ((val || "").length > secondColumnLength) secondColumnLength = (val || "").length + 2; | ||
| return [label, val || "-"]; | ||
| }); | ||
| let copyStr = `| ${" ".repeat(firstColumnLength)} | ${" ".repeat(secondColumnLength)} |\n| ${"-".repeat(firstColumnLength)} | ${"-".repeat(secondColumnLength)} |\n`; | ||
| for (const [label, value] of entries) if (!isMinimal) copyStr += `| ${`**${label}**`.padEnd(firstColumnLength)} | ${(value.includes("`") ? value : `\`${value}\``).padEnd(secondColumnLength)} |\n`; | ||
| if (!isMinimal && await writeText(copyStr).then(() => true).catch(() => false)) box(`\n${boxStr}`, ` Nuxt project info ${colors.gray("(copied to clipboard) ")}`, { | ||
| contentAlign: "left", | ||
| titleAlign: "left", | ||
| width: "auto", | ||
| titlePadding: 2, | ||
| contentPadding: 2, | ||
| rounded: true | ||
| }); | ||
| else logger.info(`Nuxt project info:\n${copyStr}`, { withGuide: false }); | ||
| const isNuxt3 = !isLegacy; | ||
| const isBridge = !isNuxt3 && infoObj["Build modules"]?.includes("bridge"); | ||
| const repo = isBridge ? "nuxt/bridge" : "nuxt/nuxt"; | ||
| const docsURL = isNuxt3 || isBridge ? "https://nuxt.com" : "https://v2.nuxt.com"; | ||
| logger.info(`👉 Read documentation: ${colors.cyan(docsURL)}`); | ||
| if (isNuxt3 || isBridge) { | ||
| logger.info(`👉 Report an issue: ${colors.cyan(`https://github.com/${repo}/issues/new?template=bug-report.yml`)}`, { spacing: 0 }); | ||
| logger.info(`👉 Suggest an improvement: ${colors.cyan(`https://github.com/${repo}/discussions/new`)}`, { spacing: 0 }); | ||
| } | ||
| } | ||
| }); | ||
| function normalizeConfigModule(module, rootDir) { | ||
| if (!module) return null; | ||
| if (typeof module === "string") return module.split(rootDir).pop().split("node_modules").pop().replace(LEADING_SLASH_RE, ""); | ||
| if (typeof module === "function") return `${module.name}()`; | ||
| if (Array.isArray(module)) return normalizeConfigModule(module[0], rootDir); | ||
| return null; | ||
| } | ||
| async function getNuxtConfig(rootDir) { | ||
| try { | ||
| const { createJiti } = await import("jiti"); | ||
| const jiti = createJiti(rootDir, { | ||
| interopDefault: true, | ||
| alias: { | ||
| "~": rootDir, | ||
| "@": rootDir | ||
| } | ||
| }); | ||
| globalThis.defineNuxtConfig = (c) => c; | ||
| const result = await jiti.import("./nuxt.config", { default: true }); | ||
| delete globalThis.defineNuxtConfig; | ||
| return result; | ||
| } catch { | ||
| return {}; | ||
| } | ||
| } | ||
| //#endregion | ||
| export { info_default as default }; |
| import { n as themeColor } from "./ascii-B6JJ3B2W.mjs"; | ||
| import process from "node:process"; | ||
| import { colors } from "consola/utils"; | ||
| import { isAgent } from "std-env"; | ||
| import { box } from "@clack/prompts"; | ||
| import { mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs"; | ||
| import { join, relative } from "pathe"; | ||
| //#region ../nuxi/src/utils/profile.ts | ||
| const RELATIVE_PATH_RE = /^(?![^.]{1,2}\/)/; | ||
| let session; | ||
| let profileCount = 0; | ||
| async function startCpuProfile() { | ||
| const cli = globalThis.__nuxt_cli__; | ||
| if (cli?.cpuProfileSession) { | ||
| session = cli.cpuProfileSession; | ||
| delete cli.cpuProfileSession; | ||
| return; | ||
| } | ||
| session = new (await (import("node:inspector"))).Session(); | ||
| session.connect(); | ||
| try { | ||
| await new Promise((res, rej) => { | ||
| session.post("Profiler.enable", (err) => { | ||
| if (err) return rej(err); | ||
| session.post("Profiler.start", (err) => { | ||
| if (err) return rej(err); | ||
| res(); | ||
| }); | ||
| }); | ||
| }); | ||
| } catch (err) { | ||
| session.disconnect(); | ||
| session = void 0; | ||
| throw err; | ||
| } | ||
| } | ||
| async function stopCpuProfile(outDir, command) { | ||
| if (!session) return; | ||
| const s = session; | ||
| session = void 0; | ||
| const count = profileCount++; | ||
| const outPath = join(outDir, `nuxt-${command}${count ? `-${count}` : ""}.cpuprofile`); | ||
| const relativeOutPath = relative(process.cwd(), outPath).replace(RELATIVE_PATH_RE, "./"); | ||
| try { | ||
| await new Promise((resolve, reject) => { | ||
| s.post("Profiler.stop", (err, params) => { | ||
| if (err) return reject(err); | ||
| if (!params?.profile) return resolve(params); | ||
| try { | ||
| mkdirSync(outDir, { recursive: true }); | ||
| writeFileSync(outPath, JSON.stringify(params.profile)); | ||
| box(`\n${[`CPU profile written to ${colors.cyan(relativeOutPath)}.`, `Open it in a CPU profile viewer like your IDE, or ${colors.cyan("https://discoveryjs.github.io/cpupro")}.`].map((step) => ` › ${step}`).join("\n")}\n`, "", { | ||
| contentAlign: "left", | ||
| titleAlign: "left", | ||
| width: "auto", | ||
| titlePadding: 2, | ||
| contentPadding: 2, | ||
| rounded: true, | ||
| withGuide: false, | ||
| formatBorder: (text) => `${themeColor + text}\x1B[0m` | ||
| }); | ||
| } catch {} | ||
| resolve(params); | ||
| }); | ||
| }); | ||
| } finally { | ||
| s.disconnect(); | ||
| } | ||
| } | ||
| //#endregion | ||
| //#region ../nuxi/src/utils/lockfile.ts | ||
| const LOCK_FILENAME = "nuxt.lock"; | ||
| const MAX_LOCK_AGE_MS = 1440 * 60 * 1e3; | ||
| function isProcessAlive(pid) { | ||
| try { | ||
| process.kill(pid, 0); | ||
| return true; | ||
| } catch (err) { | ||
| return err.code === "EPERM"; | ||
| } | ||
| } | ||
| function readLockFile(lockPath) { | ||
| try { | ||
| return JSON.parse(readFileSync(lockPath, "utf-8")); | ||
| } catch { | ||
| return; | ||
| } | ||
| } | ||
| function tryUnlink(lockPath) { | ||
| try { | ||
| unlinkSync(lockPath); | ||
| } catch {} | ||
| } | ||
| function isLockActive(info) { | ||
| if (info.pid === process.pid) return false; | ||
| if (!isProcessAlive(info.pid)) return false; | ||
| if (Date.now() - info.startedAt > MAX_LOCK_AGE_MS) return false; | ||
| return true; | ||
| } | ||
| /** | ||
| * Locking is enabled for agents by default. `NUXT_LOCK=1` forces it on for | ||
| * non-agents; `NUXT_IGNORE_LOCK=1` forces it off. | ||
| */ | ||
| function isLockEnabled() { | ||
| if (process.env.NUXT_IGNORE_LOCK) return false; | ||
| if (process.env.NUXT_LOCK === "1" || process.env.NUXT_LOCK === "true") return true; | ||
| return isAgent; | ||
| } | ||
| /** | ||
| * Atomically acquire a build/dev lock. | ||
| * Returns `{ existing }` if another live process holds the lock, otherwise | ||
| * `{ release }` to be invoked on shutdown. No-op when locking is disabled. | ||
| */ | ||
| function acquireLock(buildDir, info) { | ||
| if (!isLockEnabled()) return { release: () => {} }; | ||
| const lockPath = join(buildDir, LOCK_FILENAME); | ||
| const fullInfo = { | ||
| pid: process.pid, | ||
| startedAt: Date.now(), | ||
| ...info | ||
| }; | ||
| try { | ||
| mkdirSync(buildDir, { recursive: true }); | ||
| } catch {} | ||
| for (let attempt = 0; attempt < 2; attempt++) try { | ||
| writeFileSync(lockPath, JSON.stringify(fullInfo, null, 2), { flag: "wx" }); | ||
| return { release: makeRelease(lockPath) }; | ||
| } catch (err) { | ||
| if (err.code !== "EEXIST") throw err; | ||
| const existing = readLockFile(lockPath); | ||
| if (existing && isLockActive(existing)) return { existing }; | ||
| tryUnlink(lockPath); | ||
| } | ||
| const existing = readLockFile(lockPath); | ||
| if (existing && isLockActive(existing)) return { existing }; | ||
| return { release: () => {} }; | ||
| } | ||
| /** | ||
| * Overwrite an existing lock we already own with updated metadata (e.g. port | ||
| * information learned after the listener binds). Callers must hold the lock | ||
| * via a prior successful `acquireLock`. Does nothing when locking is disabled. | ||
| */ | ||
| function updateLock(buildDir, info) { | ||
| if (!isLockEnabled()) return; | ||
| const lockPath = join(buildDir, LOCK_FILENAME); | ||
| const current = readLockFile(lockPath); | ||
| if (current && current.pid !== process.pid) return; | ||
| const next = { | ||
| pid: process.pid, | ||
| startedAt: current?.startedAt ?? Date.now(), | ||
| ...info | ||
| }; | ||
| try { | ||
| writeFileSync(lockPath, JSON.stringify(next, null, 2)); | ||
| } catch {} | ||
| } | ||
| function makeRelease(lockPath) { | ||
| let released = false; | ||
| function release() { | ||
| if (released) return; | ||
| released = true; | ||
| process.off("exit", release); | ||
| const current = readLockFile(lockPath); | ||
| if (!current || current.pid === process.pid) tryUnlink(lockPath); | ||
| } | ||
| process.on("exit", release); | ||
| return release; | ||
| } | ||
| /** | ||
| * Format an error message when a Nuxt process is already running. | ||
| * Designed to be actionable for both humans and LLM agents. | ||
| */ | ||
| function formatLockError(info) { | ||
| const killCmd = process.platform === "win32" ? `taskkill /PID ${info.pid} /F` : `kill ${info.pid}`; | ||
| const lines = [ | ||
| "", | ||
| `Another Nuxt ${info.command === "dev" ? "dev server" : "build"} is already running:`, | ||
| "" | ||
| ]; | ||
| if (info.url) lines.push(` URL: ${info.url}`); | ||
| lines.push(` PID: ${info.pid}`); | ||
| lines.push(` Dir: ${info.cwd}`); | ||
| lines.push(` Started: ${new Date(info.startedAt).toLocaleString()}`); | ||
| lines.push(""); | ||
| if (info.command === "dev" && info.url) lines.push(`Run \`${killCmd}\` to stop it, or connect to ${info.url}`); | ||
| else lines.push(`Run \`${killCmd}\` to stop it.`); | ||
| lines.push(`Set NUXT_IGNORE_LOCK=1 to bypass this check.`); | ||
| lines.push(""); | ||
| return lines.join("\n"); | ||
| } | ||
| //#endregion | ||
| export { stopCpuProfile as a, startCpuProfile as i, formatLockError as n, updateLock as r, acquireLock as t }; |
@@ -1,2 +0,2 @@ | ||
| import { n as initialize } from "../dev-Cr4PgS_f.mjs"; | ||
| import { n as initialize } from "../dev-CttXIKD2.mjs"; | ||
| export { initialize }; |
+6
-6
@@ -17,9 +17,9 @@ import { t as cwdArgs } from "./_shared-B6XhZQ-m.mjs"; | ||
| "analyze": () => import("./analyze-DDeJFzIp.mjs").then(_rDefault), | ||
| "build": () => import("./build-BPupc27P.mjs").then(_rDefault), | ||
| "build": () => import("./build-d7zHMQ9n.mjs").then(_rDefault), | ||
| "cleanup": () => import("./cleanup-2TBoIdxA.mjs").then(_rDefault), | ||
| "_dev": () => import("./dev-child-BXXy_yXk.mjs").then(_rDefault), | ||
| "dev": () => import("./dev--5SloLZS.mjs").then(_rDefault), | ||
| "_dev": () => import("./dev-child-wGNUrf3U.mjs").then(_rDefault), | ||
| "dev": () => import("./dev-BpSDPS5S.mjs").then(_rDefault), | ||
| "devtools": () => import("./devtools-DisdwL4R.mjs").then(_rDefault), | ||
| "generate": () => import("./generate-DxFBnyuA.mjs").then(_rDefault), | ||
| "info": () => import("./info-BZyQLUOt.mjs").then(_rDefault), | ||
| "generate": () => import("./generate-C-mar7u8.mjs").then(_rDefault), | ||
| "info": () => import("./info-CJN0ENPm.mjs").then(_rDefault), | ||
| "init": () => import("./init-GY9-KoBe.mjs").then(_rDefault), | ||
@@ -66,3 +66,3 @@ "module": () => import("./module-DSnyWgzL.mjs").then(_rDefault), | ||
| var name = "@nuxt/cli"; | ||
| var version = "3.35.0"; | ||
| var version = "3.35.1"; | ||
| var description = "Nuxt CLI"; | ||
@@ -69,0 +69,0 @@ //#endregion |
+1
-1
| { | ||
| "name": "@nuxt/cli", | ||
| "type": "module", | ||
| "version": "3.35.0", | ||
| "version": "3.35.1", | ||
| "description": "Nuxt CLI", | ||
@@ -6,0 +6,0 @@ "license": "MIT", |
| import { a as legacyRootDirArgs, i as extendsArgs, n as dotEnvArgs, o as logLevelArgs, r as envNameArgs, s as profileArgs, t as cwdArgs } from "./_shared-B6XhZQ-m.mjs"; | ||
| import { n as logger } from "./logger-C1qVsppt.mjs"; | ||
| import { t as overrideEnv } from "./env-BfWVBvy7.mjs"; | ||
| import { a as stopCpuProfile, i as startCpuProfile, n as formatLockError, t as acquireLock } from "./lockfile-B0hNFb_C.mjs"; | ||
| import { t as loadKit } from "./kit-BzPscsEd.mjs"; | ||
| import { n as showBanner } from "./banner-CTtM2dxO.mjs"; | ||
| import { t as clearBuildDir } from "./fs-B0HqP3GX.mjs"; | ||
| import process from "node:process"; | ||
| import { defineCommand } from "citty"; | ||
| import { colors } from "consola/utils"; | ||
| import { intro, outro } from "@clack/prompts"; | ||
| import { relative, resolve } from "pathe"; | ||
| //#region ../nuxi/src/commands/build.ts | ||
| var build_default = defineCommand({ | ||
| meta: { | ||
| name: "build", | ||
| description: "Build Nuxt for production deployment" | ||
| }, | ||
| args: { | ||
| ...cwdArgs, | ||
| ...logLevelArgs, | ||
| prerender: { | ||
| type: "boolean", | ||
| description: "Build Nuxt and prerender static routes" | ||
| }, | ||
| preset: { | ||
| type: "string", | ||
| description: "Nitro server preset" | ||
| }, | ||
| ...dotEnvArgs, | ||
| ...envNameArgs, | ||
| ...extendsArgs, | ||
| ...profileArgs, | ||
| ...legacyRootDirArgs | ||
| }, | ||
| async run(ctx) { | ||
| overrideEnv("production"); | ||
| const cwd = resolve(ctx.args.cwd || ctx.args.rootDir); | ||
| const profileArg = ctx.args.profile; | ||
| const perfValue = profileArg === "verbose" ? true : profileArg ? "quiet" : void 0; | ||
| if (profileArg) await startCpuProfile(); | ||
| let releaseLock; | ||
| try { | ||
| intro(colors.cyan("Building Nuxt for production...")); | ||
| const kit = await loadKit(cwd); | ||
| const nuxt = await kit.loadNuxt({ | ||
| cwd, | ||
| ready: false, | ||
| dotenv: { | ||
| cwd, | ||
| fileName: ctx.args.dotenv | ||
| }, | ||
| envName: ctx.args.envName, | ||
| overrides: { | ||
| logLevel: ctx.args.logLevel, | ||
| _generate: ctx.args.prerender, | ||
| nitro: { | ||
| static: ctx.args.prerender, | ||
| preset: ctx.args.preset || process.env.NITRO_PRESET || process.env.SERVER_PRESET | ||
| }, | ||
| ...ctx.args.extends && { extends: ctx.args.extends }, | ||
| ...ctx.data?.overrides, | ||
| ...(perfValue || ctx.data?.overrides?.debug) && { debug: { | ||
| ...ctx.data?.overrides?.debug, | ||
| ...perfValue && { perf: perfValue } | ||
| } } | ||
| } | ||
| }); | ||
| showBanner(nuxt); | ||
| await nuxt.ready(); | ||
| const lock = acquireLock(nuxt.options.buildDir, { | ||
| command: "build", | ||
| cwd | ||
| }); | ||
| if (lock.existing) { | ||
| logger.error(formatLockError(lock.existing)); | ||
| throw new Error(`Another Nuxt ${lock.existing.command} is already running (PID ${lock.existing.pid}).`); | ||
| } | ||
| releaseLock = lock.release; | ||
| let nitro; | ||
| try { | ||
| nitro = kit.useNitro?.(); | ||
| if (nitro) logger.info(`Nitro preset: ${colors.cyan(nitro.options.preset)}`); | ||
| } catch {} | ||
| await clearBuildDir(nuxt.options.buildDir); | ||
| await kit.writeTypes(nuxt); | ||
| nuxt.hook("build:error", async (err) => { | ||
| logger.error(`Nuxt build error: ${err}`); | ||
| if (profileArg) await stopCpuProfile(cwd, "build"); | ||
| process.exit(1); | ||
| }); | ||
| await kit.buildNuxt(nuxt); | ||
| if (ctx.args.prerender) { | ||
| if (!nuxt.options.ssr) { | ||
| logger.warn(`HTML content not prerendered because ${colors.cyan("ssr: false")} was set.`); | ||
| logger.info(`You can read more in ${colors.cyan("https://nuxt.com/docs/getting-started/deployment#static-hosting")}.`); | ||
| } | ||
| const dir = nitro?.options.output.publicDir; | ||
| const publicDir = dir ? relative(process.cwd(), dir) : ".output/public"; | ||
| outro(`✨ You can now deploy ${colors.cyan(publicDir)} to any static hosting!`); | ||
| } else outro("✨ Build complete!"); | ||
| } finally { | ||
| releaseLock?.(); | ||
| if (profileArg) await stopCpuProfile(cwd, "build"); | ||
| } | ||
| } | ||
| }); | ||
| //#endregion | ||
| export { build_default as default }; |
| import { a as legacyRootDirArgs, i as extendsArgs, n as dotEnvArgs, o as logLevelArgs, r as envNameArgs, s as profileArgs, t as cwdArgs } from "./_shared-B6XhZQ-m.mjs"; | ||
| import { n as logger, t as debug } from "./logger-C1qVsppt.mjs"; | ||
| import { n as initialize } from "./dev-Cr4PgS_f.mjs"; | ||
| import process from "node:process"; | ||
| import { defineCommand } from "citty"; | ||
| import { colors } from "consola/utils"; | ||
| import { isBun, isDeno, isTest } from "std-env"; | ||
| import { resolve } from "pathe"; | ||
| import { satisfies } from "semver"; | ||
| import { getArgs, parseArgs } from "listhen/cli"; | ||
| import { fork } from "node:child_process"; | ||
| //#region ../nuxi/src/dev/pool.ts | ||
| var ForkPool = class { | ||
| pool = []; | ||
| poolSize; | ||
| rawArgs; | ||
| listenOverrides; | ||
| warming = false; | ||
| constructor(options) { | ||
| this.rawArgs = options.rawArgs; | ||
| this.poolSize = options.poolSize ?? 2; | ||
| this.listenOverrides = options.listenOverrides; | ||
| for (const signal of [ | ||
| "exit", | ||
| "SIGTERM", | ||
| "SIGINT", | ||
| "SIGQUIT" | ||
| ]) process.once(signal, () => { | ||
| this.killAll(signal === "exit" ? 0 : signal); | ||
| }); | ||
| } | ||
| startWarming() { | ||
| if (this.warming) return; | ||
| this.warming = true; | ||
| for (let i = 0; i < this.poolSize; i++) this.warmFork(); | ||
| } | ||
| async getFork(context, onMessage) { | ||
| const readyFork = this.pool.find((f) => f.state === "ready"); | ||
| if (readyFork) { | ||
| readyFork.state = "active"; | ||
| if (onMessage) this.attachMessageHandler(readyFork.process, onMessage); | ||
| await this.sendContext(readyFork.process, context); | ||
| if (this.warming) this.warmFork(); | ||
| return () => this.killFork(readyFork); | ||
| } | ||
| const warmingFork = this.pool.find((f) => f.state === "warming"); | ||
| if (warmingFork) { | ||
| await warmingFork.ready; | ||
| warmingFork.state = "active"; | ||
| if (onMessage) this.attachMessageHandler(warmingFork.process, onMessage); | ||
| await this.sendContext(warmingFork.process, context); | ||
| if (this.warming) this.warmFork(); | ||
| return () => this.killFork(warmingFork); | ||
| } | ||
| debug("No pre-warmed forks available, starting cold fork"); | ||
| const coldFork = this.createFork(); | ||
| await coldFork.ready; | ||
| coldFork.state = "active"; | ||
| if (onMessage) this.attachMessageHandler(coldFork.process, onMessage); | ||
| await this.sendContext(coldFork.process, context); | ||
| return () => this.killFork(coldFork); | ||
| } | ||
| attachMessageHandler(childProc, onMessage) { | ||
| childProc.on("message", (message) => { | ||
| if (message.type !== "nuxt:internal:dev:fork-ready") onMessage(message); | ||
| }); | ||
| } | ||
| warmFork() { | ||
| const fork = this.createFork(); | ||
| fork.ready.then(() => { | ||
| if (fork.state === "warming") fork.state = "ready"; | ||
| }).catch(() => { | ||
| this.removeFork(fork); | ||
| }); | ||
| this.pool.push(fork); | ||
| } | ||
| createFork() { | ||
| const childProc = fork(globalThis.__nuxt_cli__.devEntry, this.rawArgs, { | ||
| execArgv: ["--enable-source-maps", process.argv.find((a) => a.includes("--inspect"))].filter(Boolean), | ||
| env: { | ||
| ...process.env, | ||
| __NUXT__FORK: "true" | ||
| } | ||
| }); | ||
| let readyResolve; | ||
| let readyReject; | ||
| const pooledFork = { | ||
| process: childProc, | ||
| ready: new Promise((resolve, reject) => { | ||
| readyResolve = resolve; | ||
| readyReject = reject; | ||
| }), | ||
| state: "warming" | ||
| }; | ||
| childProc.on("message", (message) => { | ||
| if (message.type === "nuxt:internal:dev:fork-ready") readyResolve(); | ||
| }); | ||
| childProc.on("error", (err) => { | ||
| readyReject(err); | ||
| this.removeFork(pooledFork); | ||
| }); | ||
| childProc.on("close", (errorCode) => { | ||
| if (pooledFork.state === "active" && errorCode) process.exit(errorCode); | ||
| this.removeFork(pooledFork); | ||
| }); | ||
| return pooledFork; | ||
| } | ||
| async sendContext(childProc, context) { | ||
| childProc.send({ | ||
| type: "nuxt:internal:dev:context", | ||
| listenOverrides: this.listenOverrides, | ||
| context | ||
| }); | ||
| } | ||
| killFork(fork, signal = "SIGTERM") { | ||
| fork.state = "dead"; | ||
| if (fork.process) fork.process.kill(signal === 0 && isDeno ? "SIGTERM" : signal); | ||
| this.removeFork(fork); | ||
| } | ||
| removeFork(fork) { | ||
| const index = this.pool.indexOf(fork); | ||
| if (index > -1) this.pool.splice(index, 1); | ||
| } | ||
| killAll(signal) { | ||
| for (const fork of this.pool) this.killFork(fork, signal); | ||
| } | ||
| getStats() { | ||
| return { | ||
| total: this.pool.length, | ||
| warming: this.pool.filter((f) => f.state === "warming").length, | ||
| ready: this.pool.filter((f) => f.state === "ready").length, | ||
| active: this.pool.filter((f) => f.state === "active").length | ||
| }; | ||
| } | ||
| }; | ||
| //#endregion | ||
| //#region ../nuxi/src/commands/dev.ts | ||
| const startTime = Date.now(); | ||
| const forkSupported = !isTest && (!isBun || isBunForkSupported()); | ||
| const listhenArgs = getArgs(); | ||
| const command = defineCommand({ | ||
| meta: { | ||
| name: "dev", | ||
| description: "Run Nuxt development server" | ||
| }, | ||
| args: { | ||
| ...cwdArgs, | ||
| ...logLevelArgs, | ||
| ...dotEnvArgs, | ||
| ...legacyRootDirArgs, | ||
| ...envNameArgs, | ||
| ...extendsArgs, | ||
| clear: { | ||
| type: "boolean", | ||
| description: "Clear console on restart", | ||
| default: false | ||
| }, | ||
| fork: { | ||
| type: "boolean", | ||
| description: forkSupported ? "Disable forked mode" : "Enable forked mode", | ||
| negativeDescription: "Disable forked mode", | ||
| default: forkSupported, | ||
| alias: ["f"] | ||
| }, | ||
| ...listhenArgs, | ||
| port: { | ||
| ...listhenArgs.port, | ||
| description: "Port to listen on (default: `NUXT_PORT || NITRO_PORT || PORT || nuxtOptions.devServer.port`)", | ||
| alias: ["p"] | ||
| }, | ||
| open: { | ||
| ...listhenArgs.open, | ||
| alias: ["o"], | ||
| default: false | ||
| }, | ||
| host: { | ||
| ...listhenArgs.host, | ||
| alias: ["h"], | ||
| description: "Host to listen on (default: `NUXT_HOST || NITRO_HOST || HOST || nuxtOptions.devServer?.host`)" | ||
| }, | ||
| clipboard: { | ||
| ...listhenArgs.clipboard, | ||
| default: false | ||
| }, | ||
| ...profileArgs, | ||
| sslCert: { | ||
| type: "string", | ||
| description: "(DEPRECATED) Use `--https.cert` instead." | ||
| }, | ||
| sslKey: { | ||
| type: "string", | ||
| description: "(DEPRECATED) Use `--https.key` instead." | ||
| } | ||
| }, | ||
| async run(ctx) { | ||
| const cwd = resolve(ctx.args.cwd || ctx.args.rootDir); | ||
| const listenOverrides = resolveListenOverrides(ctx.args); | ||
| const { listener, close, onRestart, onReady } = await initialize({ | ||
| cwd, | ||
| args: ctx.args | ||
| }, { | ||
| data: ctx.data, | ||
| listenOverrides, | ||
| showBanner: true | ||
| }); | ||
| if (!ctx.args.fork || ctx.args.profile) return { | ||
| listener, | ||
| close | ||
| }; | ||
| const pool = new ForkPool({ | ||
| rawArgs: ctx.rawArgs, | ||
| poolSize: 2, | ||
| listenOverrides | ||
| }); | ||
| onReady((_address) => { | ||
| pool.startWarming(); | ||
| if (startTime) debug(`Dev server ready for connections in ${Date.now() - startTime}ms`); | ||
| }); | ||
| let cleanupCurrentFork; | ||
| async function restartWithFork() { | ||
| const context = { | ||
| cwd, | ||
| args: ctx.args | ||
| }; | ||
| cleanupCurrentFork?.(); | ||
| cleanupCurrentFork = await pool.getFork(context, (message) => { | ||
| if (message.type === "nuxt:internal:dev:ready") { | ||
| if (startTime) debug(`Dev server ready for connections in ${Date.now() - startTime}ms`); | ||
| } else if (message.type === "nuxt:internal:dev:restart") restartWithFork(); | ||
| else if (message.type === "nuxt:internal:dev:rejection") { | ||
| logger.info(`Restarting Nuxt due to error: ${colors.cyan(message.message)}`); | ||
| restartWithFork(); | ||
| } | ||
| }); | ||
| } | ||
| onRestart(async () => { | ||
| await close(); | ||
| await restartWithFork(); | ||
| }); | ||
| return { async close() { | ||
| cleanupCurrentFork?.(); | ||
| await Promise.all([listener.close(), close()]); | ||
| } }; | ||
| } | ||
| }); | ||
| function resolveListenOverrides(args) { | ||
| if (process.env._PORT) return { | ||
| port: process.env._PORT || 0, | ||
| hostname: "127.0.0.1", | ||
| showURL: false | ||
| }; | ||
| const options = parseArgs({ | ||
| ...args, | ||
| "host": args.host || process.env.NUXT_HOST || process.env.NITRO_HOST || process.env.HOST, | ||
| "port": args.port || process.env.NUXT_PORT || process.env.NITRO_PORT || process.env.PORT, | ||
| "https": args.https !== false && args.https !== "false", | ||
| "https.cert": args["https.cert"] || args.sslCert || process.env.NUXT_SSL_CERT || process.env.NITRO_SSL_CERT, | ||
| "https.key": args["https.key"] || args.sslKey || process.env.NUXT_SSL_KEY || process.env.NITRO_SSL_KEY | ||
| }); | ||
| return { | ||
| ...options, | ||
| _https: args.https, | ||
| get https() { | ||
| const httpsArg = this._https; | ||
| if (httpsArg === false || httpsArg === "false") return false; | ||
| return httpsArg ? options.https : false; | ||
| } | ||
| }; | ||
| } | ||
| function isBunForkSupported() { | ||
| const bunVersion = globalThis.Bun.version; | ||
| return satisfies(bunVersion, ">=1.2"); | ||
| } | ||
| //#endregion | ||
| export { command as default }; |
| import { a as legacyRootDirArgs, n as dotEnvArgs, o as logLevelArgs, r as envNameArgs, t as cwdArgs } from "./_shared-B6XhZQ-m.mjs"; | ||
| import process from "node:process"; | ||
| import { defineCommand } from "citty"; | ||
| import { isTest } from "std-env"; | ||
| import { resolve } from "pathe"; | ||
| //#region ../nuxi/src/commands/dev-child.ts | ||
| var dev_child_default = defineCommand({ | ||
| meta: { | ||
| name: "_dev", | ||
| description: "Run Nuxt development server (internal command to start child process)" | ||
| }, | ||
| args: { | ||
| ...cwdArgs, | ||
| ...logLevelArgs, | ||
| ...envNameArgs, | ||
| ...dotEnvArgs, | ||
| ...legacyRootDirArgs, | ||
| clear: { | ||
| type: "boolean", | ||
| description: "Clear console on restart", | ||
| negativeDescription: "Disable clear console on restart" | ||
| } | ||
| }, | ||
| async run(ctx) { | ||
| if (!process.send && !isTest) console.warn("`nuxi _dev` is an internal command and should not be used directly. Please use `nuxi dev` instead."); | ||
| const cwd = resolve(ctx.args.cwd || ctx.args.rootDir); | ||
| const { initialize } = await import("./dev-Cr4PgS_f.mjs").then((n) => n.t); | ||
| await initialize({ | ||
| cwd, | ||
| args: ctx.args | ||
| }, ctx); | ||
| } | ||
| }); | ||
| //#endregion | ||
| export { dev_child_default as default }; |
| import { t as __exportAll } from "./rolldown-runtime-wcPFST8Q.mjs"; | ||
| import { t as overrideEnv } from "./env-BfWVBvy7.mjs"; | ||
| import { a as stopCpuProfile, i as startCpuProfile, n as formatLockError, r as updateLock, t as acquireLock } from "./lockfile-B0hNFb_C.mjs"; | ||
| import { i as withNodePath, t as loadKit } from "./kit-BzPscsEd.mjs"; | ||
| import { n as showBanner } from "./banner-CTtM2dxO.mjs"; | ||
| import { t as clearBuildDir } from "./fs-B0HqP3GX.mjs"; | ||
| import { a as writeNuxtManifest, i as resolveNuxtManifest, n as loadNuxtManifest } from "./nuxt-CBsjK3fQ.mjs"; | ||
| import process from "node:process"; | ||
| import { provider } from "std-env"; | ||
| import { pathToFileURL } from "node:url"; | ||
| import defu from "defu"; | ||
| import { existsSync, readdirSync, statSync, watch } from "node:fs"; | ||
| import { join, resolve } from "pathe"; | ||
| import EventEmitter from "node:events"; | ||
| import { mkdir } from "node:fs/promises"; | ||
| import { resolveModulePath } from "exsolve"; | ||
| import { joinURL } from "ufo"; | ||
| import { listen } from "listhen"; | ||
| import { debounce } from "perfect-debounce"; | ||
| import { toNodeHandler } from "srvx/node"; | ||
| import { Youch } from "youch"; | ||
| //#region ../../node_modules/.pnpm/h3@1.15.11/node_modules/h3/dist/index.mjs | ||
| function hasProp(obj, prop) { | ||
| try { | ||
| return prop in obj; | ||
| } catch { | ||
| return false; | ||
| } | ||
| } | ||
| var H3Error = class extends Error { | ||
| static __h3_error__ = true; | ||
| statusCode = 500; | ||
| fatal = false; | ||
| unhandled = false; | ||
| statusMessage; | ||
| data; | ||
| cause; | ||
| constructor(message, opts = {}) { | ||
| super(message, opts); | ||
| if (opts.cause && !this.cause) this.cause = opts.cause; | ||
| } | ||
| toJSON() { | ||
| const obj = { | ||
| message: this.message, | ||
| statusCode: sanitizeStatusCode(this.statusCode, 500) | ||
| }; | ||
| if (this.statusMessage) obj.statusMessage = sanitizeStatusMessage(this.statusMessage); | ||
| if (this.data !== void 0) obj.data = this.data; | ||
| return obj; | ||
| } | ||
| }; | ||
| function createError(input) { | ||
| if (typeof input === "string") return new H3Error(input); | ||
| if (isError(input)) return input; | ||
| const err = new H3Error(input.message ?? input.statusMessage ?? "", { cause: input.cause || input }); | ||
| if (hasProp(input, "stack")) try { | ||
| Object.defineProperty(err, "stack", { get() { | ||
| return input.stack; | ||
| } }); | ||
| } catch { | ||
| try { | ||
| err.stack = input.stack; | ||
| } catch {} | ||
| } | ||
| if (input.data) err.data = input.data; | ||
| if (input.statusCode) err.statusCode = sanitizeStatusCode(input.statusCode, err.statusCode); | ||
| else if (input.status) err.statusCode = sanitizeStatusCode(input.status, err.statusCode); | ||
| if (input.statusMessage) err.statusMessage = input.statusMessage; | ||
| else if (input.statusText) err.statusMessage = input.statusText; | ||
| if (err.statusMessage) { | ||
| const originalMessage = err.statusMessage; | ||
| if (sanitizeStatusMessage(err.statusMessage) !== originalMessage) console.warn("[h3] Please prefer using `message` for longer error messages instead of `statusMessage`. In the future, `statusMessage` will be sanitized by default."); | ||
| } | ||
| if (input.fatal !== void 0) err.fatal = input.fatal; | ||
| if (input.unhandled !== void 0) err.unhandled = input.unhandled; | ||
| return err; | ||
| } | ||
| function sendError(event, error, debug) { | ||
| if (event.handled) return; | ||
| const h3Error = isError(error) ? error : createError(error); | ||
| const responseBody = { | ||
| statusCode: h3Error.statusCode, | ||
| statusMessage: h3Error.statusMessage, | ||
| stack: [], | ||
| data: h3Error.data | ||
| }; | ||
| if (debug) responseBody.stack = (h3Error.stack || "").split("\n").map((l) => l.trim()); | ||
| if (event.handled) return; | ||
| setResponseStatus(event, Number.parseInt(h3Error.statusCode), h3Error.statusMessage); | ||
| event.node.res.setHeader("content-type", MIMES.json); | ||
| event.node.res.end(JSON.stringify(responseBody, void 0, 2)); | ||
| } | ||
| function isError(input) { | ||
| return input?.constructor?.__h3_error__ === true; | ||
| } | ||
| const MIMES = { | ||
| html: "text/html", | ||
| json: "application/json" | ||
| }; | ||
| const DISALLOWED_STATUS_CHARS = /[^\u0009\u0020-\u007E]/g; | ||
| function sanitizeStatusMessage(statusMessage = "") { | ||
| return statusMessage.replace(DISALLOWED_STATUS_CHARS, ""); | ||
| } | ||
| function sanitizeStatusCode(statusCode, defaultStatusCode = 200) { | ||
| if (!statusCode) return defaultStatusCode; | ||
| if (typeof statusCode === "string") statusCode = Number.parseInt(statusCode, 10); | ||
| if (statusCode < 100 || statusCode > 999) return defaultStatusCode; | ||
| return statusCode; | ||
| } | ||
| function splitCookiesString(cookiesString) { | ||
| if (Array.isArray(cookiesString)) return cookiesString.flatMap((c) => splitCookiesString(c)); | ||
| if (typeof cookiesString !== "string") return []; | ||
| const cookiesStrings = []; | ||
| let pos = 0; | ||
| let start; | ||
| let ch; | ||
| let lastComma; | ||
| let nextStart; | ||
| let cookiesSeparatorFound; | ||
| const skipWhitespace = () => { | ||
| while (pos < cookiesString.length && /\s/.test(cookiesString.charAt(pos))) pos += 1; | ||
| return pos < cookiesString.length; | ||
| }; | ||
| const notSpecialChar = () => { | ||
| ch = cookiesString.charAt(pos); | ||
| return ch !== "=" && ch !== ";" && ch !== ","; | ||
| }; | ||
| while (pos < cookiesString.length) { | ||
| start = pos; | ||
| cookiesSeparatorFound = false; | ||
| while (skipWhitespace()) { | ||
| ch = cookiesString.charAt(pos); | ||
| if (ch === ",") { | ||
| lastComma = pos; | ||
| pos += 1; | ||
| skipWhitespace(); | ||
| nextStart = pos; | ||
| while (pos < cookiesString.length && notSpecialChar()) pos += 1; | ||
| if (pos < cookiesString.length && cookiesString.charAt(pos) === "=") { | ||
| cookiesSeparatorFound = true; | ||
| pos = nextStart; | ||
| cookiesStrings.push(cookiesString.slice(start, lastComma)); | ||
| start = pos; | ||
| } else pos = lastComma + 1; | ||
| } else pos += 1; | ||
| } | ||
| if (!cookiesSeparatorFound || pos >= cookiesString.length) cookiesStrings.push(cookiesString.slice(start)); | ||
| } | ||
| return cookiesStrings; | ||
| } | ||
| function setResponseStatus(event, code, text) { | ||
| if (code) event.node.res.statusCode = sanitizeStatusCode(code, event.node.res.statusCode); | ||
| if (text) event.node.res.statusMessage = sanitizeStatusMessage(text); | ||
| } | ||
| function sendStream(event, stream) { | ||
| if (!stream || typeof stream !== "object") throw new Error("[h3] Invalid stream provided."); | ||
| event.node.res._data = stream; | ||
| if (!event.node.res.socket) { | ||
| event._handled = true; | ||
| return Promise.resolve(); | ||
| } | ||
| if (hasProp(stream, "pipeTo") && typeof stream.pipeTo === "function") return stream.pipeTo(new WritableStream({ write(chunk) { | ||
| event.node.res.write(chunk); | ||
| } })).then(() => { | ||
| event.node.res.end(); | ||
| }); | ||
| if (hasProp(stream, "pipe") && typeof stream.pipe === "function") return new Promise((resolve, reject) => { | ||
| stream.pipe(event.node.res); | ||
| if (stream.on) { | ||
| stream.on("end", () => { | ||
| event.node.res.end(); | ||
| resolve(); | ||
| }); | ||
| stream.on("error", (error) => { | ||
| reject(error); | ||
| }); | ||
| } | ||
| event.node.res.on("close", () => { | ||
| if (stream.abort) stream.abort(); | ||
| }); | ||
| }); | ||
| throw new Error("[h3] Invalid or incompatible stream provided."); | ||
| } | ||
| function sendWebResponse(event, response) { | ||
| for (const [key, value] of response.headers) if (key === "set-cookie") event.node.res.appendHeader(key, splitCookiesString(value)); | ||
| else event.node.res.setHeader(key, value); | ||
| if (response.status) event.node.res.statusCode = sanitizeStatusCode(response.status, event.node.res.statusCode); | ||
| if (response.statusText) event.node.res.statusMessage = sanitizeStatusMessage(response.statusText); | ||
| if (response.redirected) event.node.res.setHeader("location", response.url); | ||
| if (!response.body) { | ||
| event.node.res.end(); | ||
| return; | ||
| } | ||
| return sendStream(event, response.body); | ||
| } | ||
| var H3Event = class { | ||
| "__is_event__" = true; | ||
| node; | ||
| web; | ||
| context = {}; | ||
| _method; | ||
| _path; | ||
| _headers; | ||
| _requestBody; | ||
| _handled = false; | ||
| _onBeforeResponseCalled; | ||
| _onAfterResponseCalled; | ||
| constructor(req, res) { | ||
| this.node = { | ||
| req, | ||
| res | ||
| }; | ||
| } | ||
| get method() { | ||
| if (!this._method) this._method = (this.node.req.method || "GET").toUpperCase(); | ||
| return this._method; | ||
| } | ||
| get path() { | ||
| return this._path || this.node.req.url || "/"; | ||
| } | ||
| get headers() { | ||
| if (!this._headers) this._headers = _normalizeNodeHeaders(this.node.req.headers); | ||
| return this._headers; | ||
| } | ||
| get handled() { | ||
| return this._handled || this.node.res.writableEnded || this.node.res.headersSent; | ||
| } | ||
| respondWith(response) { | ||
| return Promise.resolve(response).then((_response) => sendWebResponse(this, _response)); | ||
| } | ||
| toString() { | ||
| return `[${this.method}] ${this.path}`; | ||
| } | ||
| toJSON() { | ||
| return this.toString(); | ||
| } | ||
| /** @deprecated Please use `event.node.req` instead. */ | ||
| get req() { | ||
| return this.node.req; | ||
| } | ||
| /** @deprecated Please use `event.node.res` instead. */ | ||
| get res() { | ||
| return this.node.res; | ||
| } | ||
| }; | ||
| function createEvent(req, res) { | ||
| return new H3Event(req, res); | ||
| } | ||
| function _normalizeNodeHeaders(nodeHeaders) { | ||
| const headers = new Headers(); | ||
| for (const [name, value] of Object.entries(nodeHeaders)) if (Array.isArray(value)) for (const item of value) headers.append(name, item); | ||
| else if (value) headers.set(name, value); | ||
| return headers; | ||
| } | ||
| globalThis.Headers; | ||
| globalThis.Response; | ||
| function toNodeListener(app) { | ||
| const toNodeHandle = async function(req, res) { | ||
| const event = createEvent(req, res); | ||
| try { | ||
| await app.handler(event); | ||
| } catch (_error) { | ||
| const error = createError(_error); | ||
| if (!isError(_error)) error.unhandled = true; | ||
| setResponseStatus(event, error.statusCode, error.statusMessage); | ||
| if (app.options.onError) await app.options.onError(error, event); | ||
| if (event.handled) return; | ||
| if (error.unhandled || error.fatal) console.error("[h3]", error.fatal ? "[fatal]" : "[unhandled]", error); | ||
| if (app.options.onBeforeResponse && !event._onBeforeResponseCalled) await app.options.onBeforeResponse(event, { body: error }); | ||
| await sendError(event, error, !!app.options.debug); | ||
| if (app.options.onAfterResponse && !event._onAfterResponseCalled) await app.options.onAfterResponse(event, { body: error }); | ||
| } | ||
| }; | ||
| return toNodeHandle; | ||
| } | ||
| //#endregion | ||
| //#region ../nuxi/src/dev/error.ts | ||
| async function renderError(req, res, error) { | ||
| if (res.headersSent) { | ||
| if (!res.writableEnded) res.end(); | ||
| return; | ||
| } | ||
| const youch = new Youch(); | ||
| res.statusCode = 500; | ||
| res.setHeader("Content-Type", "text/html"); | ||
| res.setHeader("Cache-Control", "no-store"); | ||
| res.setHeader("Refresh", "3"); | ||
| const html = await youch.toHTML(error, { request: { | ||
| url: req.url, | ||
| method: req.method, | ||
| headers: req.headers | ||
| } }); | ||
| res.end(html); | ||
| } | ||
| //#endregion | ||
| //#region ../nuxi/src/dev/utils.ts | ||
| const RESTART_RE = /^(?:nuxt\.config\.[a-z0-9]+|\.nuxtignore|\.nuxtrc|\.config\/nuxt(?:\.config)?\.[a-z0-9]+)$/; | ||
| const TRAILING_SLASH_RE = /\/$/; | ||
| var FileChangeTracker = class { | ||
| mtimes = /* @__PURE__ */ new Map(); | ||
| shouldEmitChange(filePath) { | ||
| const resolved = resolve(filePath); | ||
| try { | ||
| const currentMtime = statSync(resolved).mtimeMs; | ||
| const lastMtime = this.mtimes.get(resolved); | ||
| this.mtimes.set(resolved, currentMtime); | ||
| return lastMtime === void 0 || currentMtime !== lastMtime; | ||
| } catch { | ||
| this.mtimes.delete(resolved); | ||
| return true; | ||
| } | ||
| } | ||
| prime(filePath, recursive = false) { | ||
| const resolved = resolve(filePath); | ||
| const stat = statSync(resolved); | ||
| this.mtimes.set(resolved, stat.mtimeMs); | ||
| if (stat.isDirectory()) { | ||
| const entries = readdirSync(resolved); | ||
| for (const entry of entries) { | ||
| const fullPath = resolve(resolved, entry); | ||
| try { | ||
| const stats = statSync(fullPath); | ||
| this.mtimes.set(fullPath, stats.mtimeMs); | ||
| if (recursive && stats.isDirectory()) this.prime(fullPath, recursive); | ||
| } catch {} | ||
| } | ||
| } | ||
| } | ||
| }; | ||
| var NuxtDevServer = class extends EventEmitter { | ||
| #handler; | ||
| #distWatcher; | ||
| #configWatcher; | ||
| #currentNuxt; | ||
| #loadingMessage; | ||
| #loadingError; | ||
| #fileChangeTracker = new FileChangeTracker(); | ||
| #cwd; | ||
| #websocketConnections = /* @__PURE__ */ new Set(); | ||
| #lockCleanup; | ||
| #lockedBuildDir; | ||
| loadDebounced; | ||
| handler; | ||
| listener; | ||
| constructor(options) { | ||
| super(); | ||
| this.options = options; | ||
| this.loadDebounced = debounce(this.load); | ||
| let _initResolve; | ||
| const _initPromise = new Promise((resolve) => { | ||
| _initResolve = resolve; | ||
| }); | ||
| this.once("ready", () => { | ||
| _initResolve(); | ||
| }); | ||
| this.#cwd = options.cwd; | ||
| this.handler = async (req, res) => { | ||
| if (this.#loadingError) { | ||
| renderError(req, res, this.#loadingError); | ||
| return; | ||
| } | ||
| await _initPromise; | ||
| if (this.#handler) this.#handler(req, res); | ||
| else this.#renderLoadingScreen(req, res); | ||
| }; | ||
| } | ||
| async #renderLoadingScreen(req, res) { | ||
| if (res.headersSent) { | ||
| if (!res.writableEnded) res.end(); | ||
| return; | ||
| } | ||
| res.statusCode = 503; | ||
| res.setHeader("Content-Type", "text/html"); | ||
| const loadingTemplate = this.options.loadingTemplate || this.#currentNuxt?.options.devServer.loadingTemplate || await resolveLoadingTemplate(this.#cwd); | ||
| res.end(loadingTemplate({ loading: this.#loadingMessage || "Loading..." })); | ||
| } | ||
| async init() { | ||
| const action = "Starting"; | ||
| this.#loadingMessage = `${action} Nuxt...`; | ||
| this.#handler = void 0; | ||
| this.emit("loading", this.#loadingMessage); | ||
| await this.#loadNuxtInstance(); | ||
| this.#acquireDevLock(this.#currentNuxt.options.buildDir); | ||
| if (this.options.showBanner) showBanner(this.#currentNuxt); | ||
| await this.#createListener(); | ||
| await this.#initializeNuxt(false); | ||
| this.#watchConfig(); | ||
| } | ||
| closeWatchers() { | ||
| this.#distWatcher?.close(); | ||
| this.#configWatcher?.(); | ||
| } | ||
| async load(reload, reason) { | ||
| try { | ||
| this.closeWatchers(); | ||
| await this.#load(reload, reason); | ||
| this.#loadingError = void 0; | ||
| } catch (error) { | ||
| console.error(`Cannot ${reload ? "restart" : "start"} nuxt: `, error); | ||
| this.#handler = void 0; | ||
| this.#loadingError = error; | ||
| this.#loadingMessage = "Error while loading Nuxt. Please check console and fix errors."; | ||
| this.emit("loading:error", error); | ||
| } | ||
| this.#watchConfig(); | ||
| } | ||
| async #loadNuxtInstance(urls) { | ||
| const kit = await loadKit(this.options.cwd); | ||
| const loadOptions = { | ||
| cwd: this.options.cwd, | ||
| dev: true, | ||
| ready: false, | ||
| envName: this.options.envName, | ||
| dotenv: { | ||
| cwd: this.options.cwd, | ||
| fileName: this.options.dotenv.fileName | ||
| }, | ||
| overrides: { | ||
| logLevel: this.options.logLevel, | ||
| ...this.options.overrides, | ||
| vite: { | ||
| clearScreen: this.options.clear, | ||
| ...this.options.overrides.vite | ||
| } | ||
| } | ||
| }; | ||
| if (urls) { | ||
| const overrides = this.options.listenOverrides || {}; | ||
| const hostname = overrides.hostname; | ||
| const https = overrides.https; | ||
| loadOptions.defaults = resolveDevServerDefaults({ | ||
| hostname, | ||
| https | ||
| }, urls); | ||
| } | ||
| this.#currentNuxt = await kit.loadNuxt(loadOptions); | ||
| } | ||
| async #createListener() { | ||
| if (!this.#currentNuxt) throw new Error("Nuxt must be loaded before creating listener"); | ||
| const listenOptions = this.#resolveListenOptions(); | ||
| this.listener = await listen(this.handler, listenOptions); | ||
| if (listenOptions.public) { | ||
| this.#currentNuxt.options.devServer.cors = { origin: "*" }; | ||
| if (this.#currentNuxt.options.vite?.server) this.#currentNuxt.options.vite.server.allowedHosts = true; | ||
| return; | ||
| } | ||
| const urls = await this.listener.getURLs().then((r) => r.map((r) => r.url)); | ||
| if (urls && urls.length > 0) this.#currentNuxt.options.vite = defu(this.#currentNuxt.options.vite, { server: { allowedHosts: urls.map((u) => new URL(u).hostname) } }); | ||
| } | ||
| #resolveListenOptions() { | ||
| if (!this.#currentNuxt) throw new Error("Nuxt must be loaded before resolving listen options"); | ||
| const nuxtConfig = this.#currentNuxt.options; | ||
| const overrides = this.options.listenOverrides || {}; | ||
| const port = overrides.port ?? nuxtConfig.devServer?.port; | ||
| const hostname = overrides.hostname ?? nuxtConfig.devServer?.host; | ||
| const isPublic = provider === "codesandbox" || (overrides.public ?? (isPublicHostname(hostname) ? true : void 0)); | ||
| const httpsFromConfig = typeof nuxtConfig.devServer?.https !== "boolean" && nuxtConfig.devServer?.https ? nuxtConfig.devServer.https : {}; | ||
| overrides._https ??= !!nuxtConfig.devServer?.https; | ||
| const httpsOptions = overrides.https && defu(typeof overrides.https === "object" ? overrides.https : {}, httpsFromConfig); | ||
| const baseURL = nuxtConfig.app?.baseURL?.startsWith?.("./") ? nuxtConfig.app.baseURL.slice(1) : nuxtConfig.app?.baseURL; | ||
| return { | ||
| ...overrides, | ||
| port, | ||
| hostname, | ||
| public: isPublic, | ||
| https: httpsOptions || void 0, | ||
| baseURL | ||
| }; | ||
| } | ||
| async #initializeNuxt(reload) { | ||
| if (!this.#currentNuxt) throw new Error("Nuxt must be loaded before configuration"); | ||
| if (!process.env.NUXI_DISABLE_VITE_HMR) this.#currentNuxt.hooks.hook("vite:extend", ({ config }) => { | ||
| if (config.server) config.server.hmr = { | ||
| protocol: void 0, | ||
| ...config.server.hmr, | ||
| port: void 0, | ||
| host: void 0, | ||
| server: this.listener.server | ||
| }; | ||
| }); | ||
| this.#currentNuxt.hooks.hookOnce("close", () => { | ||
| this.#closeWebSocketConnections(); | ||
| this.listener.server.removeAllListeners("upgrade"); | ||
| }); | ||
| if (!reload) { | ||
| const previousManifest = await loadNuxtManifest(this.#currentNuxt.options.buildDir); | ||
| const newManifest = resolveNuxtManifest(this.#currentNuxt); | ||
| const promise = writeNuxtManifest(this.#currentNuxt, newManifest); | ||
| this.#currentNuxt.hooks.hookOnce("ready", async () => { | ||
| await promise; | ||
| }); | ||
| if (previousManifest && newManifest && previousManifest._hash !== newManifest._hash) await clearBuildDir(this.#currentNuxt.options.buildDir); | ||
| } | ||
| await this.#currentNuxt.ready(); | ||
| const unsub = this.#currentNuxt.hooks.hook("restart", async (options) => { | ||
| unsub(); | ||
| if (options?.hard) { | ||
| this.emit("restart"); | ||
| return; | ||
| } | ||
| await this.load(true); | ||
| }); | ||
| if (this.#currentNuxt.server && "upgrade" in this.#currentNuxt.server) this.listener.server.on("upgrade", (req, socket, head) => { | ||
| const nuxt = this.#currentNuxt; | ||
| if (!nuxt || !nuxt.server) return; | ||
| const viteHmrPath = joinURL(nuxt.options.app.baseURL.startsWith("./") ? nuxt.options.app.baseURL.slice(1) : nuxt.options.app.baseURL, nuxt.options.app.buildAssetsDir); | ||
| if (req.url?.startsWith(viteHmrPath)) return; | ||
| nuxt.server.upgrade(req, socket, head); | ||
| this.#websocketConnections.add(socket); | ||
| socket.on("close", () => { | ||
| this.#websocketConnections.delete(socket); | ||
| }); | ||
| }); | ||
| await this.#currentNuxt.hooks.callHook("listen", this.listener.server, this.listener); | ||
| const addr = this.listener.address; | ||
| this.#currentNuxt.options.devServer.host = addr.address; | ||
| this.#currentNuxt.options.devServer.port = addr.port; | ||
| this.#currentNuxt.options.devServer.url = getAddressURL(addr, !!this.listener.https); | ||
| this.#currentNuxt.options.devServer.https = this.listener.https; | ||
| if (this.listener.https && !process.env.NODE_TLS_REJECT_UNAUTHORIZED) console.warn("You might need `NODE_TLS_REJECT_UNAUTHORIZED=0` environment variable to make https work."); | ||
| const kit = await loadKit(this.options.cwd); | ||
| const typesPromise = existsSync(join(this.#currentNuxt.options.buildDir, "tsconfig.json")) ? kit.writeTypes(this.#currentNuxt).catch(console.error) : await kit.writeTypes(this.#currentNuxt).catch(console.error); | ||
| await Promise.all([typesPromise, kit.buildNuxt(this.#currentNuxt)]); | ||
| if (!this.#currentNuxt.server) throw new Error("Nitro server has not been initialized."); | ||
| const distDir = join(this.#currentNuxt.options.buildDir, "dist"); | ||
| await mkdir(distDir, { recursive: true }); | ||
| this.#fileChangeTracker.prime(distDir); | ||
| this.#distWatcher = watch(distDir); | ||
| this.#distWatcher.on("change", (_event, file) => { | ||
| if (!this.#fileChangeTracker.shouldEmitChange(resolve(distDir, file || ""))) return; | ||
| this.loadDebounced(true, ".nuxt/dist directory has been removed"); | ||
| }); | ||
| if ("handler" in this.#currentNuxt.server) this.#handler = this.#currentNuxt.server.handler; | ||
| else if ("fetch" in this.#currentNuxt.server) this.#handler = toNodeHandler(this.#currentNuxt.server.fetch); | ||
| else this.#handler = toNodeListener(this.#currentNuxt.server.app); | ||
| const serverUrl = getAddressURL(addr, !!this.listener.https).replace(TRAILING_SLASH_RE, ""); | ||
| const currentBuildDir = this.#currentNuxt.options.buildDir; | ||
| if (this.#lockedBuildDir !== currentBuildDir) this.#acquireDevLock(currentBuildDir); | ||
| updateLock(currentBuildDir, { | ||
| command: "dev", | ||
| cwd: this.options.cwd, | ||
| port: addr.port, | ||
| hostname: addr.address, | ||
| url: serverUrl | ||
| }); | ||
| this.emit("ready", serverUrl); | ||
| } | ||
| async close() { | ||
| if (this.#currentNuxt) await this.#currentNuxt.close(); | ||
| } | ||
| /** Release the lock file. Call only on final shutdown, not during reloads. */ | ||
| releaseLock() { | ||
| this.#lockCleanup?.(); | ||
| this.#lockCleanup = void 0; | ||
| this.#lockedBuildDir = void 0; | ||
| } | ||
| #acquireDevLock(buildDir) { | ||
| const lock = acquireLock(buildDir, { | ||
| command: "dev", | ||
| cwd: this.options.cwd | ||
| }); | ||
| if (lock.existing) { | ||
| console.error(formatLockError(lock.existing)); | ||
| throw new Error(`Another Nuxt ${lock.existing.command} is already running (PID ${lock.existing.pid}).`); | ||
| } | ||
| const previousRelease = this.#lockCleanup; | ||
| this.#lockCleanup = lock.release; | ||
| this.#lockedBuildDir = buildDir; | ||
| previousRelease?.(); | ||
| } | ||
| #closeWebSocketConnections() { | ||
| for (const socket of this.#websocketConnections) socket.destroy(); | ||
| this.#websocketConnections.clear(); | ||
| } | ||
| async #load(reload, reason) { | ||
| const action = reload ? "Restarting" : "Starting"; | ||
| this.#loadingMessage = `${reason ? `${reason}. ` : ""}${action} Nuxt...`; | ||
| this.#handler = void 0; | ||
| this.emit("loading", this.#loadingMessage); | ||
| if (reload) console.info(this.#loadingMessage); | ||
| await this.close(); | ||
| const urls = await this.listener.getURLs().then((r) => r.map((r) => r.url)); | ||
| await this.#loadNuxtInstance(urls); | ||
| await this.#initializeNuxt(!!reload); | ||
| } | ||
| #watchConfig() { | ||
| this.#configWatcher = createConfigWatcher(this.#cwd, this.options.dotenv.fileName, () => this.emit("restart"), (file) => this.loadDebounced(true, `${file} updated`)); | ||
| } | ||
| }; | ||
| function getAddressURL(addr, https) { | ||
| const proto = https ? "https" : "http"; | ||
| let host = addr.address.includes(":") ? `[${addr.address}]` : addr.address; | ||
| if (host === "[::]") host = "localhost"; | ||
| const port = addr.port || 3e3; | ||
| return `${proto}://${host}:${port}/`; | ||
| } | ||
| function resolveDevServerDefaults(listenOptions, urls = []) { | ||
| const defaultConfig = {}; | ||
| if (urls && urls.length > 0) defaultConfig.vite = { server: { allowedHosts: urls.map((u) => new URL(u).hostname) } }; | ||
| if (listenOptions.hostname) { | ||
| defaultConfig.devServer = { cors: { origin: [`${listenOptions.https ? "https" : "http"}://${listenOptions.hostname}`, ...urls] } }; | ||
| defaultConfig.vite = defu(defaultConfig.vite, { server: { allowedHosts: [listenOptions.hostname] } }); | ||
| } | ||
| return defaultConfig; | ||
| } | ||
| function createConfigWatcher(cwd, dotenvFileName = ".env", onRestart, onReload) { | ||
| const fileWatcher = new FileChangeTracker(); | ||
| fileWatcher.prime(cwd); | ||
| const configWatcher = watch(cwd); | ||
| let configDirWatcher = existsSync(join(cwd, ".config")) ? createConfigDirWatcher(cwd, onReload) : void 0; | ||
| const dotenvFileNames = new Set(Array.isArray(dotenvFileName) ? dotenvFileName : [dotenvFileName]); | ||
| configWatcher.on("change", (_event, file) => { | ||
| if (!fileWatcher.shouldEmitChange(resolve(cwd, file))) return; | ||
| if (dotenvFileNames.has(file)) onRestart(); | ||
| if (RESTART_RE.test(file)) onReload(file); | ||
| if (file === ".config") configDirWatcher ||= createConfigDirWatcher(cwd, onReload); | ||
| }); | ||
| return () => { | ||
| configWatcher.close(); | ||
| configDirWatcher?.(); | ||
| }; | ||
| } | ||
| function createConfigDirWatcher(cwd, onReload) { | ||
| const configDir = join(cwd, ".config"); | ||
| const fileWatcher = new FileChangeTracker(); | ||
| fileWatcher.prime(configDir); | ||
| const configDirWatcher = watch(configDir); | ||
| configDirWatcher.on("change", (_event, file) => { | ||
| if (!fileWatcher.shouldEmitChange(resolve(configDir, file))) return; | ||
| if (RESTART_RE.test(file)) onReload(file); | ||
| }); | ||
| return () => configDirWatcher.close(); | ||
| } | ||
| async function resolveLoadingTemplate(cwd) { | ||
| return (await import(pathToFileURL(resolveModulePath("@nuxt/ui-templates", { from: withNodePath(resolveModulePath("nuxt", { | ||
| from: withNodePath(cwd), | ||
| try: true | ||
| }) || cwd) })).href)).loading || ((params) => `<h2>${params.loading}</h2>`); | ||
| } | ||
| function isPublicHostname(hostname) { | ||
| return !!hostname && ![ | ||
| "localhost", | ||
| "127.0.0.1", | ||
| "::1" | ||
| ].includes(hostname); | ||
| } | ||
| //#endregion | ||
| //#region ../nuxi/src/dev/index.ts | ||
| var dev_exports = /* @__PURE__ */ __exportAll({ initialize: () => initialize }); | ||
| const start = Date.now(); | ||
| var IPC = class { | ||
| enabled = !!process.send && !process.title?.includes("vitest") && process.env.__NUXT__FORK; | ||
| constructor() { | ||
| if (this.enabled) process.once("unhandledRejection", (reason) => { | ||
| this.send({ | ||
| type: "nuxt:internal:dev:rejection", | ||
| message: reason instanceof Error ? reason.toString() : "Unhandled Rejection" | ||
| }); | ||
| process.exit(); | ||
| }); | ||
| process.on("message", (message) => { | ||
| if (message.type === "nuxt:internal:dev:context") initialize(message.context, { listenOverrides: message.listenOverrides }); | ||
| }); | ||
| this.send({ type: "nuxt:internal:dev:fork-ready" }); | ||
| } | ||
| send(message) { | ||
| if (this.enabled) process.send?.(message); | ||
| } | ||
| }; | ||
| const ipc = new IPC(); | ||
| async function initialize(devContext, ctx = {}) { | ||
| overrideEnv("development"); | ||
| const profileArg = devContext.args.profile; | ||
| const perfValue = profileArg === "verbose" ? true : profileArg ? "quiet" : void 0; | ||
| const perfOverrides = perfValue ? { debug: { perf: perfValue } } : {}; | ||
| if (profileArg) await startCpuProfile(); | ||
| const devServer = new NuxtDevServer({ | ||
| cwd: devContext.cwd, | ||
| overrides: defu(ctx.data?.overrides, { extends: devContext.args.extends }, perfOverrides), | ||
| logLevel: devContext.args.logLevel, | ||
| clear: devContext.args.clear, | ||
| dotenv: { | ||
| cwd: devContext.cwd, | ||
| fileName: devContext.args.dotenv | ||
| }, | ||
| envName: devContext.args.envName, | ||
| showBanner: ctx.showBanner !== false && !ipc.enabled, | ||
| listenOverrides: ctx.listenOverrides | ||
| }); | ||
| let address; | ||
| if (ipc.enabled) { | ||
| devServer.on("loading:error", (_error) => { | ||
| ipc.send({ | ||
| type: "nuxt:internal:dev:loading:error", | ||
| error: { | ||
| message: _error.message, | ||
| stack: _error.stack, | ||
| name: _error.name, | ||
| code: "code" in _error ? _error.code : void 0 | ||
| } | ||
| }); | ||
| }); | ||
| devServer.on("loading", (message) => { | ||
| ipc.send({ | ||
| type: "nuxt:internal:dev:loading", | ||
| message | ||
| }); | ||
| }); | ||
| devServer.on("restart", () => { | ||
| ipc.send({ type: "nuxt:internal:dev:restart" }); | ||
| }); | ||
| devServer.on("ready", (payload) => { | ||
| ipc.send({ | ||
| type: "nuxt:internal:dev:ready", | ||
| address: payload | ||
| }); | ||
| }); | ||
| } else devServer.on("ready", (payload) => { | ||
| address = payload; | ||
| }); | ||
| await devServer.init(); | ||
| if (process.env.DEBUG) console.debug(`Dev server (internal) initialized in ${Date.now() - start}ms`); | ||
| if (profileArg) for (const signal of [ | ||
| "exit", | ||
| "SIGTERM", | ||
| "SIGINT", | ||
| "SIGQUIT" | ||
| ]) process.once(signal, () => stopCpuProfile(devContext.cwd, "dev")); | ||
| return { | ||
| listener: devServer.listener, | ||
| close: async () => { | ||
| devServer.closeWatchers(); | ||
| await Promise.all([devServer.listener.close(), devServer.close()]); | ||
| devServer.releaseLock(); | ||
| }, | ||
| onReady: (callback) => { | ||
| if (address) callback(address); | ||
| else devServer.once("ready", (payload) => callback(payload)); | ||
| }, | ||
| onRestart: (callback) => { | ||
| let restarted = false; | ||
| function restart() { | ||
| if (!restarted) { | ||
| restarted = true; | ||
| callback(devServer); | ||
| } | ||
| } | ||
| devServer.once("restart", restart); | ||
| process.once("uncaughtException", restart); | ||
| process.once("unhandledRejection", restart); | ||
| } | ||
| }; | ||
| } | ||
| //#endregion | ||
| export { initialize as n, dev_exports as t }; |
| import { a as legacyRootDirArgs, i as extendsArgs, n as dotEnvArgs, o as logLevelArgs, r as envNameArgs, s as profileArgs, t as cwdArgs } from "./_shared-B6XhZQ-m.mjs"; | ||
| import build_default from "./build-BPupc27P.mjs"; | ||
| import { defineCommand } from "citty"; | ||
| //#region ../nuxi/src/commands/generate.ts | ||
| var generate_default = defineCommand({ | ||
| meta: { | ||
| name: "generate", | ||
| description: "Build Nuxt and prerender all routes" | ||
| }, | ||
| args: { | ||
| ...cwdArgs, | ||
| ...logLevelArgs, | ||
| preset: { | ||
| type: "string", | ||
| description: "Nitro server preset" | ||
| }, | ||
| ...dotEnvArgs, | ||
| ...envNameArgs, | ||
| ...extendsArgs, | ||
| ...profileArgs, | ||
| ...legacyRootDirArgs | ||
| }, | ||
| async run(ctx) { | ||
| ctx.args.prerender = true; | ||
| await build_default.run(ctx); | ||
| } | ||
| }); | ||
| //#endregion | ||
| export { generate_default as default }; |
| import { a as legacyRootDirArgs, t as cwdArgs } from "./_shared-B6XhZQ-m.mjs"; | ||
| import { n as logger } from "./logger-C1qVsppt.mjs"; | ||
| import { n as tryResolveNuxt } from "./kit-BzPscsEd.mjs"; | ||
| import { t as getBuilder } from "./banner-CTtM2dxO.mjs"; | ||
| import { t as formatInfoBox } from "./formatting-BobJCzk9.mjs"; | ||
| import { t as getPackageManagerVersion } from "./packageManagers-Y5z0Pi7r.mjs"; | ||
| import process from "node:process"; | ||
| import { defineCommand } from "citty"; | ||
| import { colors } from "consola/utils"; | ||
| import { isBun, isDeno, isMinimal } from "std-env"; | ||
| import { box } from "@clack/prompts"; | ||
| import { resolve } from "pathe"; | ||
| import { readPackageJSON } from "pkg-types"; | ||
| import os from "node:os"; | ||
| import { detectPackageManager } from "nypm"; | ||
| import { writeText } from "tinyclip"; | ||
| //#region ../nuxi/package.json | ||
| var version = "3.35.0"; | ||
| //#endregion | ||
| //#region ../nuxi/src/commands/info.ts | ||
| const LEADING_SLASH_RE = /^\//; | ||
| var info_default = defineCommand({ | ||
| meta: { | ||
| name: "info", | ||
| description: "Get information about Nuxt project" | ||
| }, | ||
| args: { | ||
| ...cwdArgs, | ||
| ...legacyRootDirArgs | ||
| }, | ||
| async run(ctx) { | ||
| const cwd = resolve(ctx.args.cwd || ctx.args.rootDir); | ||
| const nuxtConfig = await getNuxtConfig(cwd); | ||
| const { dependencies = {}, devDependencies = {} } = await readPackageJSON(cwd).catch(() => ({})); | ||
| const nuxtPath = tryResolveNuxt(cwd); | ||
| async function getDepVersion(name) { | ||
| for (const url of [cwd, nuxtPath]) { | ||
| if (!url) continue; | ||
| const pkg = await readPackageJSON(name, { url }).catch(() => null); | ||
| if (pkg) return pkg.version; | ||
| } | ||
| return dependencies[name] || devDependencies[name]; | ||
| } | ||
| async function listModules(arr = []) { | ||
| const info = []; | ||
| for (let m of arr) { | ||
| if (Array.isArray(m)) m = m[0]; | ||
| const name = normalizeConfigModule(m, cwd); | ||
| if (name) { | ||
| const v = await getDepVersion(name.split("/").splice(0, 2).join("/")); | ||
| info.push(`\`${v ? `${name}@${v}` : name}\``); | ||
| } | ||
| } | ||
| return info.join(", "); | ||
| } | ||
| const nuxtVersion = await getDepVersion("nuxt") || await getDepVersion("nuxt-nightly") || await getDepVersion("nuxt-edge") || await getDepVersion("nuxt3") || "-"; | ||
| const isLegacy = nuxtVersion.startsWith("2"); | ||
| const builder = !isLegacy ? nuxtConfig.builder || "vite" : nuxtConfig.bridge?.vite ? "vite" : nuxtConfig.buildModules?.includes("nuxt-vite") ? "vite" : "webpack"; | ||
| let packageManager = (await detectPackageManager(cwd))?.name; | ||
| if (packageManager) packageManager += `@${getPackageManagerVersion(packageManager)}`; | ||
| const osType = os.type(); | ||
| const builderInfo = typeof builder === "string" ? getBuilder(cwd, builder) : { | ||
| name: "custom", | ||
| version: "0.0.0" | ||
| }; | ||
| const infoObj = { | ||
| "Operating system": osType === "Darwin" ? `macOS ${os.release()}` : osType === "Windows_NT" ? `Windows ${os.release()}` : `${osType} ${os.release()}`, | ||
| "CPU": `${os.cpus()[0]?.model || "unknown"} (${os.cpus().length} cores)`, | ||
| ...isBun ? { "Bun version": Bun?.version } : isDeno ? { "Deno version": Deno?.version.deno } : { "Node.js version": process.version }, | ||
| "nuxt/cli version": version, | ||
| "Package manager": packageManager ?? "unknown", | ||
| "Nuxt version": nuxtVersion, | ||
| "Nitro version": await getDepVersion("nitropack") || await getDepVersion("nitro"), | ||
| "Builder": builderInfo.name === "custom" ? "custom" : `${builderInfo.name.toLowerCase()}@${builderInfo.version}`, | ||
| "Config": Object.keys(nuxtConfig).map((key) => `\`${key}\``).sort().join(", "), | ||
| "Modules": await listModules(nuxtConfig.modules), | ||
| ...isLegacy ? { "Build modules": await listModules(nuxtConfig.buildModules || []) } : {} | ||
| }; | ||
| logger.info(`Nuxt root directory: ${colors.cyan(nuxtConfig.rootDir || cwd)}\n`); | ||
| const boxStr = formatInfoBox(infoObj); | ||
| let firstColumnLength = 0; | ||
| let secondColumnLength = 0; | ||
| const entries = Object.entries(infoObj).map(([label, val]) => { | ||
| if (label.length > firstColumnLength) firstColumnLength = label.length + 4; | ||
| if ((val || "").length > secondColumnLength) secondColumnLength = (val || "").length + 2; | ||
| return [label, val || "-"]; | ||
| }); | ||
| let copyStr = `| ${" ".repeat(firstColumnLength)} | ${" ".repeat(secondColumnLength)} |\n| ${"-".repeat(firstColumnLength)} | ${"-".repeat(secondColumnLength)} |\n`; | ||
| for (const [label, value] of entries) if (!isMinimal) copyStr += `| ${`**${label}**`.padEnd(firstColumnLength)} | ${(value.includes("`") ? value : `\`${value}\``).padEnd(secondColumnLength)} |\n`; | ||
| if (!isMinimal && await writeText(copyStr).then(() => true).catch(() => false)) box(`\n${boxStr}`, ` Nuxt project info ${colors.gray("(copied to clipboard) ")}`, { | ||
| contentAlign: "left", | ||
| titleAlign: "left", | ||
| width: "auto", | ||
| titlePadding: 2, | ||
| contentPadding: 2, | ||
| rounded: true | ||
| }); | ||
| else logger.info(`Nuxt project info:\n${copyStr}`, { withGuide: false }); | ||
| const isNuxt3 = !isLegacy; | ||
| const isBridge = !isNuxt3 && infoObj["Build modules"]?.includes("bridge"); | ||
| const repo = isBridge ? "nuxt/bridge" : "nuxt/nuxt"; | ||
| const docsURL = isNuxt3 || isBridge ? "https://nuxt.com" : "https://v2.nuxt.com"; | ||
| logger.info(`👉 Read documentation: ${colors.cyan(docsURL)}`); | ||
| if (isNuxt3 || isBridge) { | ||
| logger.info(`👉 Report an issue: ${colors.cyan(`https://github.com/${repo}/issues/new?template=bug-report.yml`)}`, { spacing: 0 }); | ||
| logger.info(`👉 Suggest an improvement: ${colors.cyan(`https://github.com/${repo}/discussions/new`)}`, { spacing: 0 }); | ||
| } | ||
| } | ||
| }); | ||
| function normalizeConfigModule(module, rootDir) { | ||
| if (!module) return null; | ||
| if (typeof module === "string") return module.split(rootDir).pop().split("node_modules").pop().replace(LEADING_SLASH_RE, ""); | ||
| if (typeof module === "function") return `${module.name}()`; | ||
| if (Array.isArray(module)) return normalizeConfigModule(module[0], rootDir); | ||
| return null; | ||
| } | ||
| async function getNuxtConfig(rootDir) { | ||
| try { | ||
| const { createJiti } = await import("jiti"); | ||
| const jiti = createJiti(rootDir, { | ||
| interopDefault: true, | ||
| alias: { | ||
| "~": rootDir, | ||
| "@": rootDir | ||
| } | ||
| }); | ||
| globalThis.defineNuxtConfig = (c) => c; | ||
| const result = await jiti.import("./nuxt.config", { default: true }); | ||
| delete globalThis.defineNuxtConfig; | ||
| return result; | ||
| } catch { | ||
| return {}; | ||
| } | ||
| } | ||
| //#endregion | ||
| export { info_default as default }; |
| import { n as themeColor } from "./ascii-B6JJ3B2W.mjs"; | ||
| import process from "node:process"; | ||
| import { colors } from "consola/utils"; | ||
| import { isAgent } from "std-env"; | ||
| import { box } from "@clack/prompts"; | ||
| import { mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs"; | ||
| import { join, relative } from "pathe"; | ||
| //#region ../nuxi/src/utils/profile.ts | ||
| const RELATIVE_PATH_RE = /^(?![^.]{1,2}\/)/; | ||
| let session; | ||
| let profileCount = 0; | ||
| async function startCpuProfile() { | ||
| const cli = globalThis.__nuxt_cli__; | ||
| if (cli?.cpuProfileSession) { | ||
| session = cli.cpuProfileSession; | ||
| delete cli.cpuProfileSession; | ||
| return; | ||
| } | ||
| session = new (await (import("node:inspector"))).Session(); | ||
| session.connect(); | ||
| try { | ||
| await new Promise((res, rej) => { | ||
| session.post("Profiler.enable", (err) => { | ||
| if (err) return rej(err); | ||
| session.post("Profiler.start", (err) => { | ||
| if (err) return rej(err); | ||
| res(); | ||
| }); | ||
| }); | ||
| }); | ||
| } catch (err) { | ||
| session.disconnect(); | ||
| session = void 0; | ||
| throw err; | ||
| } | ||
| } | ||
| async function stopCpuProfile(outDir, command) { | ||
| if (!session) return; | ||
| const s = session; | ||
| session = void 0; | ||
| const count = profileCount++; | ||
| const outPath = join(outDir, `nuxt-${command}${count ? `-${count}` : ""}.cpuprofile`); | ||
| const relativeOutPath = relative(process.cwd(), outPath).replace(RELATIVE_PATH_RE, "./"); | ||
| try { | ||
| await new Promise((resolve, reject) => { | ||
| s.post("Profiler.stop", (err, params) => { | ||
| if (err) return reject(err); | ||
| if (!params?.profile) return resolve(params); | ||
| try { | ||
| mkdirSync(outDir, { recursive: true }); | ||
| writeFileSync(outPath, JSON.stringify(params.profile)); | ||
| box(`\n${[`CPU profile written to ${colors.cyan(relativeOutPath)}.`, `Open it in a CPU profile viewer like your IDE, or ${colors.cyan("https://discoveryjs.github.io/cpupro")}.`].map((step) => ` › ${step}`).join("\n")}\n`, "", { | ||
| contentAlign: "left", | ||
| titleAlign: "left", | ||
| width: "auto", | ||
| titlePadding: 2, | ||
| contentPadding: 2, | ||
| rounded: true, | ||
| withGuide: false, | ||
| formatBorder: (text) => `${themeColor + text}\x1B[0m` | ||
| }); | ||
| } catch {} | ||
| resolve(params); | ||
| }); | ||
| }); | ||
| } finally { | ||
| s.disconnect(); | ||
| } | ||
| } | ||
| //#endregion | ||
| //#region ../nuxi/src/utils/lockfile.ts | ||
| const LOCK_FILENAME = "nuxt.lock"; | ||
| const MAX_LOCK_AGE_MS = 1440 * 60 * 1e3; | ||
| function isProcessAlive(pid) { | ||
| try { | ||
| process.kill(pid, 0); | ||
| return true; | ||
| } catch (err) { | ||
| return err.code === "EPERM"; | ||
| } | ||
| } | ||
| function readLockFile(lockPath) { | ||
| try { | ||
| return JSON.parse(readFileSync(lockPath, "utf-8")); | ||
| } catch { | ||
| return; | ||
| } | ||
| } | ||
| function tryUnlink(lockPath) { | ||
| try { | ||
| unlinkSync(lockPath); | ||
| } catch {} | ||
| } | ||
| function isLockActive(info) { | ||
| if (info.pid === process.pid) return false; | ||
| if (!isProcessAlive(info.pid)) return false; | ||
| if (Date.now() - info.startedAt > MAX_LOCK_AGE_MS) return false; | ||
| return true; | ||
| } | ||
| /** | ||
| * Locking is enabled for agents by default. `NUXT_LOCK=1` forces it on for | ||
| * non-agents; `NUXT_IGNORE_LOCK=1` forces it off. | ||
| */ | ||
| function isLockEnabled() { | ||
| if (process.env.NUXT_IGNORE_LOCK) return false; | ||
| if (process.env.NUXT_LOCK === "1" || process.env.NUXT_LOCK === "true") return true; | ||
| return isAgent; | ||
| } | ||
| /** | ||
| * Atomically acquire a build/dev lock. | ||
| * Returns `{ existing }` if another live process holds the lock, otherwise | ||
| * `{ release }` to be invoked on shutdown. No-op when locking is disabled. | ||
| */ | ||
| function acquireLock(buildDir, info) { | ||
| if (!isLockEnabled()) return { release: () => {} }; | ||
| const lockPath = join(buildDir, LOCK_FILENAME); | ||
| const fullInfo = { | ||
| pid: process.pid, | ||
| startedAt: Date.now(), | ||
| ...info | ||
| }; | ||
| for (let attempt = 0; attempt < 2; attempt++) try { | ||
| writeFileSync(lockPath, JSON.stringify(fullInfo, null, 2), { flag: "wx" }); | ||
| return { release: makeRelease(lockPath) }; | ||
| } catch (err) { | ||
| if (err.code !== "EEXIST") throw err; | ||
| const existing = readLockFile(lockPath); | ||
| if (existing && isLockActive(existing)) return { existing }; | ||
| tryUnlink(lockPath); | ||
| } | ||
| const existing = readLockFile(lockPath); | ||
| if (existing && isLockActive(existing)) return { existing }; | ||
| return { release: () => {} }; | ||
| } | ||
| /** | ||
| * Overwrite an existing lock we already own with updated metadata (e.g. port | ||
| * information learned after the listener binds). Callers must hold the lock | ||
| * via a prior successful `acquireLock`. Does nothing when locking is disabled. | ||
| */ | ||
| function updateLock(buildDir, info) { | ||
| if (!isLockEnabled()) return; | ||
| const lockPath = join(buildDir, LOCK_FILENAME); | ||
| const current = readLockFile(lockPath); | ||
| if (current && current.pid !== process.pid) return; | ||
| const next = { | ||
| pid: process.pid, | ||
| startedAt: current?.startedAt ?? Date.now(), | ||
| ...info | ||
| }; | ||
| try { | ||
| writeFileSync(lockPath, JSON.stringify(next, null, 2)); | ||
| } catch {} | ||
| } | ||
| function makeRelease(lockPath) { | ||
| let released = false; | ||
| function release() { | ||
| if (released) return; | ||
| released = true; | ||
| process.off("exit", release); | ||
| const current = readLockFile(lockPath); | ||
| if (!current || current.pid === process.pid) tryUnlink(lockPath); | ||
| } | ||
| process.on("exit", release); | ||
| return release; | ||
| } | ||
| /** | ||
| * Format an error message when a Nuxt process is already running. | ||
| * Designed to be actionable for both humans and LLM agents. | ||
| */ | ||
| function formatLockError(info) { | ||
| const killCmd = process.platform === "win32" ? `taskkill /PID ${info.pid} /F` : `kill ${info.pid}`; | ||
| const lines = [ | ||
| "", | ||
| `Another Nuxt ${info.command === "dev" ? "dev server" : "build"} is already running:`, | ||
| "" | ||
| ]; | ||
| if (info.url) lines.push(` URL: ${info.url}`); | ||
| lines.push(` PID: ${info.pid}`); | ||
| lines.push(` Dir: ${info.cwd}`); | ||
| lines.push(` Started: ${new Date(info.startedAt).toLocaleString()}`); | ||
| lines.push(""); | ||
| if (info.command === "dev" && info.url) lines.push(`Run \`${killCmd}\` to stop it, or connect to ${info.url}`); | ||
| else lines.push(`Run \`${killCmd}\` to stop it.`); | ||
| lines.push(`Set NUXT_IGNORE_LOCK=1 to bypass this check.`); | ||
| lines.push(""); | ||
| return lines.join("\n"); | ||
| } | ||
| //#endregion | ||
| export { stopCpuProfile as a, startCpuProfile as i, formatLockError as n, updateLock as r, acquireLock as t }; |
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 29 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 29 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
182022
0.03%5295
0.06%23
-4.17%