nitro-nightly 3.1.0-20251028-004953-57503e42 → 3.1.0-20251028-110430-e607b753

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/dist/_build/assets.mjs +235 -0
  2. package/dist/_build/build.mjs +21 -0
  3. package/dist/_build/config.mjs +124 -0
  4. package/dist/_build/info.mjs +39 -0
  5. package/dist/_build/plugins.mjs +1041 -0
  6. package/dist/_build/prepare.mjs +17 -0
  7. package/dist/{_chunks/build2.mjs → _build/rolldown.mjs} +238 -64
  8. package/dist/_build/rollup.mjs +404 -0
  9. package/dist/_build/snapshot.mjs +61 -0
  10. package/dist/_build/types.mjs +268 -0
  11. package/dist/_build/vite.mjs +3266 -0
  12. package/dist/{cli → _cli}/build.mjs +2 -3
  13. package/dist/_cli/dev.mjs +205 -0
  14. package/dist/{cli/index2.mjs → _cli/index.mjs} +1 -2
  15. package/dist/{cli → _cli}/list.mjs +2 -3
  16. package/dist/{cli → _cli}/prepare.mjs +2 -3
  17. package/dist/{cli → _cli}/run.mjs +2 -3
  18. package/dist/_deps/@jridgewell/gen-mapping.mjs +189 -0
  19. package/dist/_deps/@jridgewell/remapping.mjs +137 -0
  20. package/dist/_deps/@jridgewell/resolve-uri.mjs +231 -0
  21. package/dist/_deps/@jridgewell/sourcemap-codec.mjs +173 -0
  22. package/dist/_deps/@jridgewell/trace-mapping.mjs +170 -0
  23. package/dist/_deps/@pi0/vite-plugin-fullstack.mjs +575 -0
  24. package/dist/_deps/@rollup/plugin-alias.mjs +89 -0
  25. package/dist/_deps/@rollup/plugin-commonjs.mjs +2376 -0
  26. package/dist/{_chunks/index2.mjs → _deps/@rollup/plugin-inject.mjs} +5 -90
  27. package/dist/_deps/@rollup/plugin-json.mjs +37 -0
  28. package/dist/_deps/@rollup/plugin-node-resolve.mjs +1386 -0
  29. package/dist/_deps/@rollup/plugin-replace.mjs +133 -0
  30. package/dist/_deps/@rollup/pluginutils.mjs +346 -0
  31. package/dist/_deps/acorn.mjs +6225 -0
  32. package/dist/_deps/c12.mjs +510 -0
  33. package/dist/_deps/chokidar.mjs +1428 -0
  34. package/dist/_deps/citty.mjs +460 -0
  35. package/dist/_deps/commondir.mjs +77 -0
  36. package/dist/_deps/compatx.mjs +76 -0
  37. package/dist/_deps/confbox.mjs +300 -0
  38. package/dist/_deps/debug.mjs +885 -0
  39. package/dist/_deps/deepmerge.mjs +147 -0
  40. package/dist/_deps/depd.mjs +550 -0
  41. package/dist/_deps/dot-prop.mjs +282 -0
  42. package/dist/_deps/dotenv.mjs +555 -0
  43. package/dist/_deps/duplexer.mjs +1 -0
  44. package/dist/_deps/ee-first.mjs +104 -0
  45. package/dist/_deps/encodeurl.mjs +69 -0
  46. package/dist/_deps/escape-html.mjs +87 -0
  47. package/dist/_deps/escape-string-regexp.mjs +13 -0
  48. package/dist/_deps/estree-walker.mjs +433 -0
  49. package/dist/_deps/etag.mjs +147 -0
  50. package/dist/_deps/exsolve.mjs +1416 -0
  51. package/dist/_deps/fdir.mjs +569 -0
  52. package/dist/_deps/fresh.mjs +145 -0
  53. package/dist/_deps/function-bind.mjs +106 -0
  54. package/dist/{_chunks/index4.mjs → _deps/giget.mjs} +21 -776
  55. package/dist/_deps/gzip-size.mjs +19 -0
  56. package/dist/_deps/hasown.mjs +19 -0
  57. package/dist/_deps/http-errors.mjs +307 -0
  58. package/dist/_deps/httpxy.mjs +580 -0
  59. package/dist/_deps/inherits.mjs +57 -0
  60. package/dist/_deps/is-core-module.mjs +596 -0
  61. package/dist/_deps/is-module.mjs +25 -0
  62. package/dist/_deps/is-reference.mjs +31 -0
  63. package/dist/_deps/js-tokens.mjs +411 -0
  64. package/dist/_deps/knitwork.mjs +172 -0
  65. package/dist/_deps/local-pkg.mjs +163 -0
  66. package/dist/_deps/magic-string.mjs +1296 -0
  67. package/dist/_deps/mime-db.mjs +11685 -0
  68. package/dist/_deps/mime-types.mjs +287 -0
  69. package/dist/_deps/mime.mjs +1172 -0
  70. package/dist/_deps/mlly.mjs +2413 -0
  71. package/dist/_deps/ms.mjs +172 -0
  72. package/dist/_deps/node-fetch-native.mjs +3 -0
  73. package/dist/_deps/nypm.mjs +219 -0
  74. package/dist/_deps/on-finished.mjs +246 -0
  75. package/dist/_deps/parseurl.mjs +168 -0
  76. package/dist/_deps/path-parse.mjs +85 -0
  77. package/dist/{_chunks/pathe.M-eThtNZ.mjs → _deps/pathe.mjs} +48 -1
  78. package/dist/_deps/perfect-debounce.mjs +88 -0
  79. package/dist/_deps/picomatch.mjs +2144 -0
  80. package/dist/_deps/pkg-types.mjs +247 -0
  81. package/dist/_deps/pretty-bytes.mjs +180 -0
  82. package/dist/_deps/quansync.mjs +99 -0
  83. package/dist/_deps/range-parser.mjs +171 -0
  84. package/dist/_deps/rc9.mjs +219 -0
  85. package/dist/_deps/readdirp.mjs +245 -0
  86. package/dist/_deps/resolve.mjs +1260 -0
  87. package/dist/_deps/rou3.mjs +326 -0
  88. package/dist/_deps/send.mjs +1022 -0
  89. package/dist/_deps/serve-static.mjs +228 -0
  90. package/dist/_deps/setprototypeof.mjs +26 -0
  91. package/dist/_deps/statuses.mjs +457 -0
  92. package/dist/_deps/strip-literal.mjs +67 -0
  93. package/dist/_deps/supports-color.mjs +44 -0
  94. package/dist/_deps/tinyexec.mjs +552 -0
  95. package/dist/_deps/tinyglobby.mjs +293 -0
  96. package/dist/_deps/toidentifier.mjs +41 -0
  97. package/dist/_deps/ultrahtml.mjs +3 -0
  98. package/dist/_deps/unimport.mjs +2267 -0
  99. package/dist/_deps/unplugin-utils.mjs +65 -0
  100. package/dist/_deps/unplugin.mjs +1294 -0
  101. package/dist/_deps/untyped.mjs +375 -0
  102. package/dist/{_chunks/info.mjs → _deps/unwasm.mjs} +8 -4122
  103. package/dist/_deps/webpack-virtual-modules.mjs +360 -0
  104. package/dist/_presets/_all.mjs +59 -0
  105. package/dist/_presets/_nitro.mjs +74 -0
  106. package/dist/_presets/_resolve.mjs +64 -0
  107. package/dist/_presets/_static.mjs +69 -0
  108. package/dist/_presets/_types.mjs +3 -0
  109. package/dist/_presets/_utils.mjs +31 -0
  110. package/dist/_presets/alwaysdata.mjs +17 -0
  111. package/dist/_presets/aws-amplify.mjs +111 -0
  112. package/dist/_presets/aws-lambda.mjs +23 -0
  113. package/dist/_presets/azure.mjs +162 -0
  114. package/dist/_presets/bun.mjs +19 -0
  115. package/dist/_presets/cleavr.mjs +15 -0
  116. package/dist/_presets/cloudflare.mjs +608 -0
  117. package/dist/_presets/deno.mjs +196 -0
  118. package/dist/_presets/digitalocean.mjs +14 -0
  119. package/dist/_presets/firebase.mjs +47 -0
  120. package/dist/_presets/flightcontrol.mjs +14 -0
  121. package/dist/_presets/genezio.mjs +13 -0
  122. package/dist/_presets/heroku.mjs +14 -0
  123. package/dist/_presets/iis.mjs +194 -0
  124. package/dist/_presets/index.mjs +62 -0
  125. package/dist/_presets/koyeb.mjs +14 -0
  126. package/dist/_presets/netlify.mjs +241 -0
  127. package/dist/_presets/node.mjs +54 -0
  128. package/dist/_presets/platform.mjs +14 -0
  129. package/dist/_presets/render.mjs +14 -0
  130. package/dist/_presets/standard.mjs +23 -0
  131. package/dist/_presets/stormkit.mjs +18 -0
  132. package/dist/_presets/vercel.mjs +365 -0
  133. package/dist/_presets/winterjs.mjs +22 -0
  134. package/dist/_presets/zeabur.mjs +69 -0
  135. package/dist/_presets/zerops.mjs +27 -0
  136. package/dist/cli/index.mjs +7 -464
  137. package/dist/index.mjs +122 -34
  138. package/dist/vite.mjs +118 -44
  139. package/package.json +1 -1
  140. package/dist/_chunks/app.mjs +0 -19797
  141. package/dist/_chunks/build.mjs +0 -86
  142. package/dist/_chunks/build3.mjs +0 -6538
  143. package/dist/_chunks/detect-acorn.mjs +0 -503
  144. package/dist/_chunks/index.mjs +0 -22256
  145. package/dist/_chunks/index3.mjs +0 -1062
  146. package/dist/_chunks/json5.mjs +0 -68
  147. package/dist/_chunks/jsonc.mjs +0 -51
  148. package/dist/_chunks/plugin.mjs +0 -1560
  149. package/dist/_chunks/server.mjs +0 -254
  150. package/dist/_chunks/snapshot.mjs +0 -376
  151. package/dist/_chunks/toml.mjs +0 -259
  152. package/dist/_chunks/yaml.mjs +0 -86
  153. package/dist/cli/dev.mjs +0 -95
  154. package/dist/presets.mjs +0 -2494
  155. /package/dist/{cli → _cli}/common.mjs +0 -0
@@ -0,0 +1,3266 @@
1
+ import { pathToFileURL } from 'node:url';
2
+ import { colors } from 'consola/utils';
3
+ import defu$1, { defu } from 'defu';
4
+ import { m as mime } from '../_deps/mime.mjs';
5
+ import { r as resolveNitroPath, p as prettyPath, s as scanUnprefixedPublicAssets, c as compressPublicAssets, w as writeFile, a as copyPublicAssets } from './assets.mjs';
6
+ import { c as createRouter, a as addRoute, b as compileRouterToString, f as findRoute, d as findAllRoutes } from '../_deps/rou3.mjs';
7
+ import { withLeadingSlash, withoutTrailingSlash, withTrailingSlash, parseURL, withBase, joinURL, withoutBase } from 'ufo';
8
+ import { b as build$1 } from './build.mjs';
9
+ import { a as scanAndSyncOptions, s as scanHandlers, r as runParallel } from './rolldown.mjs';
10
+ import { z, P } from '../_deps/ultrahtml.mjs';
11
+ import { a as resolve, j as join, n as normalize, r as relative, d as dirname$1, c as basename, i as isAbsolute } from '../_deps/pathe.mjs';
12
+ import { fromNodeHandler, HTTPError, defineHandler, getRequestIP, getRequestURL, H3, toEventHandler, withBase as withBase$1 } from 'h3';
13
+ import { version } from 'nitro/meta';
14
+ import consola, { consola as consola$1 } from 'consola';
15
+ import { readFile, rm, writeFile as writeFile$1, mkdir, readlink } from 'node:fs/promises';
16
+ import { watch } from '../_deps/chokidar.mjs';
17
+ import { serve, NodeRequest, sendNodeResponse } from 'srvx/node';
18
+ import { d as debounce } from '../_deps/perfect-debounce.mjs';
19
+ import { isDebug, isTest, isCI } from 'std-env';
20
+ import { p as prepare } from './prepare.mjs';
21
+ import './types.mjs';
22
+ import { Hookable, createDebugger } from 'hookable';
23
+ import { w as watchConfig, l as loadConfig } from '../_deps/c12.mjs';
24
+ import { r as resolveCompatibilityDatesFromEnv, a as resolveCompatibilityDates, f as formatCompatibilityDate } from '../_deps/compatx.mjs';
25
+ import { klona } from 'klona/full';
26
+ import { runtimeDir, pkgDir, runtimeDependencies } from 'nitro/runtime/meta';
27
+ import { existsSync, watch as watch$1 } from 'node:fs';
28
+ import { e as escapeStringRegexp } from '../_deps/escape-string-regexp.mjs';
29
+ import { r as resolveModuleExportNames, s as sanitizeFilePath } from '../_deps/mlly.mjs';
30
+ import { f as findWorkspaceDir } from '../_deps/pkg-types.mjs';
31
+ import { r as resolveModulePath } from '../_deps/exsolve.mjs';
32
+ import { createJiti } from 'jiti';
33
+ import { ofetch } from 'ofetch';
34
+ import { c as createStorage } from './snapshot.mjs';
35
+ import { hash } from 'ohash';
36
+ import { c as createUnimport } from '../_deps/unimport.mjs';
37
+ import 'node:zlib';
38
+ import { Worker } from 'node:worker_threads';
39
+ import { Agent } from 'undici';
40
+ import { s as serveStatic } from '../_deps/serve-static.mjs';
41
+ import { c as createProxyServer } from '../_deps/httpxy.mjs';
42
+ import { resolve as resolve$1, dirname, join as join$1 } from 'node:path';
43
+ import { ErrorParser } from 'youch-core';
44
+ import { Youch } from 'youch';
45
+ import { SourceMapConsumer } from 'source-map';
46
+ import { FastResponse } from 'srvx';
47
+ import { a as alias } from '../_deps/@rollup/plugin-alias.mjs';
48
+ import { i as inject } from '../_deps/@rollup/plugin-inject.mjs';
49
+ import { b as baseBuildPlugins, r as replace } from './plugins.mjs';
50
+ import { b as baseBuildConfig } from './config.mjs';
51
+ import 'klona';
52
+ import 'unstorage';
53
+ import { w as writeBuildInfo } from './info.mjs';
54
+ import { DevEnvironment } from 'vite';
55
+ import { getRandomPort } from 'get-port-please';
56
+ import { spawn } from 'node:child_process';
57
+ import { a as assetsPlugin } from '../_deps/@pi0/vite-plugin-fullstack.mjs';
58
+
59
+ const NitroDefaults = {
60
+ // General
61
+ compatibilityDate: "latest",
62
+ debug: isDebug,
63
+ logLevel: isTest ? 1 : 3,
64
+ runtimeConfig: { app: {}, nitro: {} },
65
+ // Dirs
66
+ scanDirs: [],
67
+ buildDir: ".nitro",
68
+ output: {
69
+ dir: "{{ rootDir }}/.output",
70
+ serverDir: "{{ output.dir }}/server",
71
+ publicDir: "{{ output.dir }}/public"
72
+ },
73
+ // Features
74
+ experimental: {},
75
+ future: {},
76
+ storage: {},
77
+ devStorage: {},
78
+ bundledStorage: [],
79
+ publicAssets: [],
80
+ serverAssets: [],
81
+ plugins: [],
82
+ tasks: {},
83
+ scheduledTasks: {},
84
+ imports: false,
85
+ virtual: {},
86
+ compressPublicAssets: false,
87
+ ignore: [],
88
+ // Dev
89
+ dev: false,
90
+ devServer: { watch: [] },
91
+ watchOptions: { ignoreInitial: true },
92
+ devProxy: {},
93
+ // Logging
94
+ logging: {
95
+ compressedSizes: true,
96
+ buildSuccess: true
97
+ },
98
+ // Routing
99
+ baseURL: process.env.NITRO_APP_BASE_URL || "/",
100
+ handlers: [],
101
+ devHandlers: [],
102
+ errorHandler: void 0,
103
+ routeRules: {},
104
+ prerender: {
105
+ autoSubfolderIndex: true,
106
+ concurrency: 1,
107
+ interval: 0,
108
+ retry: 3,
109
+ retryDelay: 500,
110
+ failOnError: false,
111
+ crawlLinks: false,
112
+ ignore: [],
113
+ routes: []
114
+ },
115
+ // Rollup
116
+ builder: void 0,
117
+ moduleSideEffects: ["unenv/polyfill/", resolve(runtimeDir, "polyfill/")],
118
+ replace: {},
119
+ node: true,
120
+ sourceMap: true,
121
+ esbuild: {
122
+ options: {
123
+ jsxFactory: "h",
124
+ jsxFragment: "Fragment"
125
+ }
126
+ },
127
+ // Advanced
128
+ typescript: {
129
+ strict: true,
130
+ generateRuntimeConfigTypes: false,
131
+ generateTsConfig: false,
132
+ tsconfigPath: "types/tsconfig.json",
133
+ internalPaths: false,
134
+ tsConfig: {}
135
+ },
136
+ nodeModulesDirs: [],
137
+ hooks: {},
138
+ commands: {},
139
+ // Framework
140
+ framework: {
141
+ name: "nitro",
142
+ version: ""
143
+ }
144
+ };
145
+
146
+ async function resolveAssetsOptions(options) {
147
+ for (const publicAsset of options.publicAssets) {
148
+ publicAsset.dir = resolve(options.srcDir, publicAsset.dir);
149
+ publicAsset.baseURL = withLeadingSlash(
150
+ withoutTrailingSlash(publicAsset.baseURL || "/")
151
+ );
152
+ }
153
+ for (const dir of options.scanDirs) {
154
+ const publicDir = resolve(dir, "public");
155
+ if (!existsSync(publicDir)) {
156
+ continue;
157
+ }
158
+ if (options.publicAssets.some((asset) => asset.dir === publicDir)) {
159
+ continue;
160
+ }
161
+ options.publicAssets.push({ dir: publicDir });
162
+ }
163
+ for (const serverAsset of options.serverAssets) {
164
+ serverAsset.dir = resolve(options.srcDir, serverAsset.dir);
165
+ }
166
+ options.serverAssets.push({
167
+ baseName: "server",
168
+ dir: resolve(options.srcDir, "assets")
169
+ });
170
+ for (const asset of options.publicAssets) {
171
+ asset.baseURL = asset.baseURL || "/";
172
+ const isTopLevel = asset.baseURL === "/";
173
+ asset.fallthrough = asset.fallthrough ?? isTopLevel;
174
+ const routeRule = options.routeRules[asset.baseURL + "/**"];
175
+ asset.maxAge = routeRule?.cache?.maxAge ?? asset.maxAge ?? 0;
176
+ if (asset.maxAge && !asset.fallthrough) {
177
+ options.routeRules[asset.baseURL + "/**"] = defu(routeRule, {
178
+ headers: {
179
+ "cache-control": `public, max-age=${asset.maxAge}, immutable`
180
+ }
181
+ });
182
+ }
183
+ }
184
+ }
185
+
186
+ async function resolveCompatibilityOptions(options) {
187
+ options.compatibilityDate = resolveCompatibilityDatesFromEnv(
188
+ options.compatibilityDate
189
+ );
190
+ }
191
+
192
+ async function resolveDatabaseOptions(options) {
193
+ if (options.experimental.database && options.imports) {
194
+ options.imports.presets.push({
195
+ from: "nitro/runtime/internal/database",
196
+ imports: ["useDatabase"]
197
+ });
198
+ if (options.dev && !options.database && !options.devDatabase) {
199
+ options.devDatabase = {
200
+ default: {
201
+ connector: "sqlite",
202
+ options: {
203
+ cwd: options.rootDir
204
+ }
205
+ }
206
+ };
207
+ } else if (options.node && !options.database) {
208
+ options.database = {
209
+ default: {
210
+ connector: "sqlite",
211
+ options: {}
212
+ }
213
+ };
214
+ }
215
+ }
216
+ }
217
+
218
+ async function resolveExportConditionsOptions(options) {
219
+ options.exportConditions = _resolveExportConditions(
220
+ options.exportConditions || [],
221
+ { dev: options.dev, node: options.node, wasm: options.experimental.wasm }
222
+ );
223
+ }
224
+ function _resolveExportConditions(conditions, opts) {
225
+ const resolvedConditions = [];
226
+ resolvedConditions.push(opts.dev ? "development" : "production");
227
+ resolvedConditions.push(...conditions);
228
+ if (opts.node) {
229
+ resolvedConditions.push("node");
230
+ } else {
231
+ resolvedConditions.push(
232
+ "wintercg",
233
+ "worker",
234
+ "web",
235
+ "browser",
236
+ "workerd",
237
+ "edge-light",
238
+ "netlify",
239
+ "edge-routine",
240
+ "deno"
241
+ );
242
+ }
243
+ if (opts.wasm) {
244
+ resolvedConditions.push("wasm", "unwasm");
245
+ }
246
+ resolvedConditions.push("import", "default");
247
+ return resolvedConditions.filter(
248
+ (c, i) => resolvedConditions.indexOf(c) === i
249
+ );
250
+ }
251
+
252
+ async function resolveImportsOptions(options) {
253
+ if (options.imports === false) {
254
+ return;
255
+ }
256
+ options.imports.presets ??= [];
257
+ options.imports.presets.push(...getNitroImportsPreset());
258
+ const h3Exports = await resolveModuleExportNames("h3", {
259
+ url: import.meta.url
260
+ });
261
+ options.imports.presets ??= [];
262
+ options.imports.presets.push({
263
+ from: "h3",
264
+ imports: h3Exports.filter((n) => !/^[A-Z]/.test(n) && n !== "use")
265
+ });
266
+ options.imports.dirs ??= [];
267
+ options.imports.dirs.push(
268
+ ...options.scanDirs.map((dir) => join(dir, "utils/**/*"))
269
+ );
270
+ if (Array.isArray(options.imports.exclude) && options.imports.exclude.length === 0) {
271
+ options.imports.exclude.push(/[/\\]\.git[/\\]/);
272
+ options.imports.exclude.push(options.buildDir);
273
+ const scanDirsInNodeModules = options.scanDirs.map((dir) => dir.match(/(?<=\/)node_modules\/(.+)$/)?.[1]).filter(Boolean);
274
+ options.imports.exclude.push(
275
+ scanDirsInNodeModules.length > 0 ? new RegExp(
276
+ `node_modules\\/(?!${scanDirsInNodeModules.map((dir) => escapeStringRegexp(dir)).join("|")})`
277
+ ) : /[/\\]node_modules[/\\]/
278
+ );
279
+ }
280
+ }
281
+ function getNitroImportsPreset() {
282
+ return [
283
+ {
284
+ from: "nitro/runtime/internal/app",
285
+ imports: ["useNitroApp"]
286
+ },
287
+ {
288
+ from: "nitro/runtime/internal/runtime-config",
289
+ imports: ["useRuntimeConfig"]
290
+ },
291
+ {
292
+ from: "nitro/runtime/internal/plugin",
293
+ imports: ["defineNitroPlugin", "nitroPlugin"]
294
+ },
295
+ {
296
+ from: "nitro/runtime/internal/cache",
297
+ imports: [
298
+ "defineCachedFunction",
299
+ "defineCachedEventHandler",
300
+ "defineCachedHandler",
301
+ "cachedFunction",
302
+ "cachedEventHandler"
303
+ ]
304
+ },
305
+ {
306
+ from: "nitro/runtime/internal/storage",
307
+ imports: ["useStorage"]
308
+ },
309
+ {
310
+ from: "nitro/runtime/internal/renderer",
311
+ imports: ["defineRenderHandler"]
312
+ },
313
+ {
314
+ from: "nitro/runtime/internal/meta",
315
+ imports: ["defineRouteMeta"]
316
+ },
317
+ {
318
+ from: "nitro/runtime/internal/route-rules",
319
+ imports: ["getRouteRules"]
320
+ },
321
+ {
322
+ from: "nitro/runtime/internal/context",
323
+ imports: ["useRequest"]
324
+ },
325
+ {
326
+ from: "nitro/runtime/internal/task",
327
+ imports: ["defineTask", "runTask"]
328
+ },
329
+ {
330
+ from: "nitro/runtime/internal/error/utils",
331
+ imports: ["defineNitroErrorHandler"]
332
+ },
333
+ {
334
+ from: "nitro/deps/ofetch",
335
+ imports: ["$fetch"]
336
+ }
337
+ ];
338
+ }
339
+
340
+ async function resolveOpenAPIOptions(options) {
341
+ if (!options.experimental.openAPI) {
342
+ return;
343
+ }
344
+ if (!options.dev && !options.openAPI?.production) {
345
+ return;
346
+ }
347
+ const shouldPrerender = !options.dev && options.openAPI?.production === "prerender";
348
+ const handlersEnv = shouldPrerender ? "prerender" : "";
349
+ const prerenderRoutes = [];
350
+ const jsonRoute = options.openAPI?.route || "/_openapi.json";
351
+ prerenderRoutes.push(jsonRoute);
352
+ options.handlers.push({
353
+ route: jsonRoute,
354
+ env: handlersEnv,
355
+ handler: join(runtimeDir, "internal/routes/openapi")
356
+ });
357
+ if (options.openAPI?.ui?.scalar !== false) {
358
+ const scalarRoute = options.openAPI?.ui?.scalar?.route || "/_scalar";
359
+ prerenderRoutes.push(scalarRoute);
360
+ options.handlers.push({
361
+ route: options.openAPI?.ui?.scalar?.route || "/_scalar",
362
+ env: handlersEnv,
363
+ handler: join(runtimeDir, "internal/routes/scalar")
364
+ });
365
+ }
366
+ if (options.openAPI?.ui?.swagger !== false) {
367
+ const swaggerRoute = options.openAPI?.ui?.swagger?.route || "/_swagger";
368
+ prerenderRoutes.push(swaggerRoute);
369
+ options.handlers.push({
370
+ route: swaggerRoute,
371
+ env: handlersEnv,
372
+ handler: join(runtimeDir, "internal/routes/swagger")
373
+ });
374
+ }
375
+ if (shouldPrerender) {
376
+ options.prerender ??= {};
377
+ options.prerender.routes ??= [];
378
+ options.prerender.routes.push(...prerenderRoutes);
379
+ }
380
+ }
381
+
382
+ const RESOLVE_EXTENSIONS = [".ts", ".js", ".mts", ".mjs", ".tsx", ".jsx"];
383
+ async function resolvePathOptions(options) {
384
+ options.rootDir = resolve(options.rootDir || ".") + "/";
385
+ options.workspaceDir ||= await findWorkspaceDir(options.rootDir).catch(() => options.rootDir) + "/";
386
+ for (const key of ["srcDir", "buildDir"]) {
387
+ options[key] = resolve(options.rootDir, options[key] || ".");
388
+ }
389
+ options.alias ??= {};
390
+ if (!options.static && !options.entry) {
391
+ throw new Error(
392
+ `Nitro entry is missing! Is "${options.preset}" preset correct?`
393
+ );
394
+ }
395
+ if (options.entry) {
396
+ options.entry = resolveNitroPath(options.entry, options);
397
+ }
398
+ options.output.dir = resolveNitroPath(
399
+ options.output.dir || NitroDefaults.output.dir,
400
+ options,
401
+ options.rootDir
402
+ ) + "/";
403
+ options.output.publicDir = resolveNitroPath(
404
+ options.output.publicDir || NitroDefaults.output.publicDir,
405
+ options,
406
+ options.rootDir
407
+ ) + "/";
408
+ options.output.serverDir = resolveNitroPath(
409
+ options.output.serverDir || NitroDefaults.output.serverDir,
410
+ options,
411
+ options.rootDir
412
+ ) + "/";
413
+ options.nodeModulesDirs.push(resolve(options.rootDir, "node_modules"));
414
+ options.nodeModulesDirs.push(resolve(options.workspaceDir, "node_modules"));
415
+ options.nodeModulesDirs.push(resolve(pkgDir, "dist/node_modules"));
416
+ options.nodeModulesDirs.push(resolve(pkgDir, "node_modules"));
417
+ options.nodeModulesDirs.push(resolve(pkgDir, ".."));
418
+ options.nodeModulesDirs = [
419
+ ...new Set(
420
+ // Adding trailing slash to optimize resolve performance (path is explicitly a dir)
421
+ options.nodeModulesDirs.map((dir) => resolve(options.rootDir, dir) + "/")
422
+ )
423
+ ];
424
+ options.plugins = options.plugins.map((p) => resolveNitroPath(p, options));
425
+ options.scanDirs.unshift(options.srcDir);
426
+ options.scanDirs = options.scanDirs.map(
427
+ (dir) => resolve(options.srcDir, dir)
428
+ );
429
+ options.scanDirs = [...new Set(options.scanDirs.map((dir) => dir + "/"))];
430
+ if (options.serverEntry) {
431
+ options.serverEntry = resolveModulePath(
432
+ resolveNitroPath(options.serverEntry, options),
433
+ {
434
+ from: options.scanDirs,
435
+ extensions: RESOLVE_EXTENSIONS
436
+ }
437
+ );
438
+ } else {
439
+ const defaultServerEntry = resolveModulePath("./server", {
440
+ from: options.scanDirs,
441
+ extensions: RESOLVE_EXTENSIONS,
442
+ try: true
443
+ });
444
+ if (defaultServerEntry) {
445
+ options.serverEntry = defaultServerEntry;
446
+ consola.info(
447
+ `Using \`${prettyPath(defaultServerEntry)}\` as server entry.`
448
+ );
449
+ }
450
+ }
451
+ if (options.renderer?.entry) {
452
+ options.renderer.entry = resolveModulePath(
453
+ resolveNitroPath(options.renderer?.entry, options),
454
+ {
455
+ from: options.scanDirs,
456
+ extensions: RESOLVE_EXTENSIONS
457
+ }
458
+ );
459
+ }
460
+ if (options.renderer?.template) {
461
+ options.renderer.template = resolveModulePath(
462
+ resolveNitroPath(options.renderer?.template, options),
463
+ {
464
+ from: options.scanDirs,
465
+ extensions: [".html"]
466
+ }
467
+ );
468
+ } else if (!options.renderer?.entry) {
469
+ const defaultIndex = resolveModulePath("./index.html", {
470
+ from: options.scanDirs,
471
+ extensions: [".html"],
472
+ try: true
473
+ });
474
+ if (defaultIndex) {
475
+ options.renderer ??= {};
476
+ options.renderer.template = defaultIndex;
477
+ consola.info(
478
+ `Using \`${prettyPath(defaultIndex)}\` as renderer template.`
479
+ );
480
+ }
481
+ }
482
+ if (options.renderer?.template && !options.renderer?.entry) {
483
+ options.renderer ??= {};
484
+ options.renderer.entry = join(
485
+ runtimeDir,
486
+ "internal/routes/renderer-template" + (options.dev ? ".dev" : "")
487
+ );
488
+ }
489
+ }
490
+
491
+ async function resolveRouteRulesOptions(options) {
492
+ options.routeRules = defu(options.routeRules, options.routes || {});
493
+ options.routeRules = normalizeRouteRules(options);
494
+ }
495
+ function normalizeRouteRules(config) {
496
+ const normalizedRules = {};
497
+ for (let path in config.routeRules) {
498
+ const routeConfig = config.routeRules[path];
499
+ path = withLeadingSlash(path);
500
+ const routeRules = {
501
+ ...routeConfig,
502
+ redirect: void 0,
503
+ proxy: void 0
504
+ };
505
+ if (routeConfig.redirect) {
506
+ routeRules.redirect = {
507
+ // @ts-ignore
508
+ to: "/",
509
+ status: 307,
510
+ ...typeof routeConfig.redirect === "string" ? { to: routeConfig.redirect } : routeConfig.redirect
511
+ };
512
+ if (path.endsWith("/**")) {
513
+ routeRules.redirect._redirectStripBase = path.slice(0, -3);
514
+ }
515
+ }
516
+ if (routeConfig.proxy) {
517
+ routeRules.proxy = typeof routeConfig.proxy === "string" ? { to: routeConfig.proxy } : routeConfig.proxy;
518
+ if (path.endsWith("/**")) {
519
+ routeRules.proxy._proxyStripBase = path.slice(0, -3);
520
+ }
521
+ }
522
+ if (routeConfig.cors) {
523
+ routeRules.headers = {
524
+ "access-control-allow-origin": "*",
525
+ "access-control-allow-methods": "*",
526
+ "access-control-allow-headers": "*",
527
+ "access-control-max-age": "0",
528
+ ...routeRules.headers
529
+ };
530
+ }
531
+ if (routeConfig.swr) {
532
+ routeRules.cache = routeRules.cache || {};
533
+ routeRules.cache.swr = true;
534
+ if (typeof routeConfig.swr === "number") {
535
+ routeRules.cache.maxAge = routeConfig.swr;
536
+ }
537
+ }
538
+ if (routeConfig.cache === false) {
539
+ routeRules.cache = false;
540
+ }
541
+ normalizedRules[path] = routeRules;
542
+ }
543
+ return normalizedRules;
544
+ }
545
+
546
+ async function resolveRuntimeConfigOptions(options) {
547
+ options.runtimeConfig = normalizeRuntimeConfig(options);
548
+ }
549
+ function normalizeRuntimeConfig(config) {
550
+ provideFallbackValues(config.runtimeConfig || {});
551
+ const runtimeConfig = defu$1(
552
+ config.runtimeConfig,
553
+ {
554
+ app: {
555
+ baseURL: config.baseURL
556
+ },
557
+ nitro: {
558
+ envExpansion: config.experimental?.envExpansion,
559
+ openAPI: config.openAPI
560
+ }
561
+ }
562
+ );
563
+ runtimeConfig.nitro.routeRules = config.routeRules;
564
+ checkSerializableRuntimeConfig(runtimeConfig);
565
+ return runtimeConfig;
566
+ }
567
+ function provideFallbackValues(obj) {
568
+ for (const key in obj) {
569
+ if (obj[key] === void 0 || obj[key] === null) {
570
+ obj[key] = "";
571
+ } else if (typeof obj[key] === "object") {
572
+ provideFallbackValues(obj[key]);
573
+ }
574
+ }
575
+ }
576
+ function checkSerializableRuntimeConfig(obj, path = []) {
577
+ if (isPrimitiveValue(obj)) {
578
+ return;
579
+ }
580
+ for (const key in obj) {
581
+ const value = obj[key];
582
+ if (value === null || value === void 0 || isPrimitiveValue(value)) {
583
+ continue;
584
+ }
585
+ if (Array.isArray(value)) {
586
+ for (const [index, item] of value.entries())
587
+ checkSerializableRuntimeConfig(item, [...path, `${key}[${index}]`]);
588
+ } else if (typeof value === "object" && value.constructor === Object && (!value.constructor?.name || value.constructor.name === "Object")) {
589
+ checkSerializableRuntimeConfig(value, [...path, key]);
590
+ } else {
591
+ console.warn(
592
+ `Runtime config option \`${[...path, key].join(".")}\` may not be able to be serialized.`
593
+ );
594
+ }
595
+ }
596
+ }
597
+ function isPrimitiveValue(value) {
598
+ return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
599
+ }
600
+
601
+ async function resolveStorageOptions(options) {
602
+ const fsMounts = {
603
+ root: resolve(options.rootDir),
604
+ src: resolve(options.srcDir),
605
+ build: resolve(options.buildDir),
606
+ cache: resolve(options.buildDir, "cache")
607
+ };
608
+ for (const p in fsMounts) {
609
+ options.devStorage[p] = options.devStorage[p] || {
610
+ driver: "fs",
611
+ readOnly: p === "root" || p === "src",
612
+ base: fsMounts[p]
613
+ };
614
+ }
615
+ if (options.dev && options.storage.data === void 0 && options.devStorage.data === void 0) {
616
+ options.devStorage.data = {
617
+ driver: "fs",
618
+ base: resolve(options.rootDir, ".data/kv")
619
+ };
620
+ } else if (options.node && options.storage.data === void 0) {
621
+ options.storage.data = {
622
+ driver: "fsLite",
623
+ base: "./.data/kv"
624
+ };
625
+ }
626
+ }
627
+
628
+ async function resolveURLOptions(options) {
629
+ options.baseURL = withLeadingSlash(withTrailingSlash(options.baseURL));
630
+ }
631
+
632
+ async function resolveErrorOptions(options) {
633
+ if (!options.errorHandler) {
634
+ options.errorHandler = [];
635
+ } else if (!Array.isArray(options.errorHandler)) {
636
+ options.errorHandler = [options.errorHandler];
637
+ }
638
+ options.errorHandler.push(
639
+ join(runtimeDir, `internal/error/${options.dev ? "dev" : "prod"}`)
640
+ );
641
+ }
642
+
643
+ const common = {
644
+ meta: {
645
+ name: "nitro-common",
646
+ url: import.meta.url
647
+ },
648
+ alias: {
649
+ "buffer/": "node:buffer",
650
+ "buffer/index": "node:buffer",
651
+ "buffer/index.js": "node:buffer",
652
+ "string_decoder/": "node:string_decoder",
653
+ "process/": "node:process"
654
+ }
655
+ };
656
+ const nodeless = {
657
+ meta: {
658
+ name: "nitro-nodeless",
659
+ url: import.meta.url
660
+ },
661
+ inject: {
662
+ global: "unenv/polyfill/globalthis",
663
+ process: "node:process",
664
+ Buffer: ["node:buffer", "Buffer"],
665
+ clearImmediate: ["node:timers", "clearImmediate"],
666
+ setImmediate: ["node:timers", "setImmediate"],
667
+ performance: "unenv/polyfill/performance",
668
+ PerformanceObserver: ["node:perf_hooks", "PerformanceObserver"],
669
+ BroadcastChannel: ["node:worker_threads", "BroadcastChannel"]
670
+ },
671
+ polyfill: [
672
+ "unenv/polyfill/globalthis-global",
673
+ "unenv/polyfill/process",
674
+ "unenv/polyfill/buffer",
675
+ "unenv/polyfill/timers"
676
+ ]
677
+ };
678
+ async function resolveUnenv(options) {
679
+ options.unenv ??= [];
680
+ if (!Array.isArray(options.unenv)) {
681
+ options.unenv = [options.unenv];
682
+ }
683
+ options.unenv = options.unenv.filter(Boolean);
684
+ if (!options.node) {
685
+ options.unenv.unshift(nodeless);
686
+ }
687
+ options.unenv.unshift(common);
688
+ }
689
+
690
+ async function resolveBuilder(options) {
691
+ if (!options.builder) {
692
+ options.builder = process.env.NITRO_BUILDER || "rollup";
693
+ }
694
+ if (options.builder === "rolldown") {
695
+ try {
696
+ await import('rolldown');
697
+ } catch {
698
+ throw new Error(
699
+ `Builder "rolldown" is not available. Make sure to install "rolldown" package.`
700
+ );
701
+ }
702
+ } else if (options.builder === "vite") {
703
+ try {
704
+ await import('vite');
705
+ } catch {
706
+ throw new Error(
707
+ `Builder "vite" is not available. Make sure to install "vite" package.`
708
+ );
709
+ }
710
+ }
711
+ if (!["rollup", "rolldown", "vite"].includes(options.builder)) {
712
+ throw new Error(`Builder "${options.builder}" is not supported.`);
713
+ }
714
+ }
715
+
716
+ const configResolvers = [
717
+ resolveCompatibilityOptions,
718
+ resolvePathOptions,
719
+ resolveImportsOptions,
720
+ resolveRouteRulesOptions,
721
+ resolveDatabaseOptions,
722
+ resolveExportConditionsOptions,
723
+ resolveRuntimeConfigOptions,
724
+ resolveOpenAPIOptions,
725
+ resolveURLOptions,
726
+ resolveAssetsOptions,
727
+ resolveStorageOptions,
728
+ resolveErrorOptions,
729
+ resolveUnenv,
730
+ resolveBuilder
731
+ ];
732
+ async function loadOptions(configOverrides = {}, opts = {}) {
733
+ const options = await _loadUserConfig(configOverrides, opts);
734
+ for (const resolver of configResolvers) {
735
+ await resolver(options);
736
+ }
737
+ return options;
738
+ }
739
+ async function _loadUserConfig(configOverrides = {}, opts = {}) {
740
+ configOverrides = klona(configOverrides);
741
+ globalThis.defineNitroConfig = globalThis.defineNitroConfig || ((c) => c);
742
+ let compatibilityDate = configOverrides.compatibilityDate || opts.compatibilityDate || (process.env.NITRO_COMPATIBILITY_DATE || process.env.SERVER_COMPATIBILITY_DATE || process.env.COMPATIBILITY_DATE);
743
+ const { resolvePreset } = await import('../_presets/index.mjs');
744
+ let preset = configOverrides.preset || process.env.NITRO_PRESET || process.env.SERVER_PRESET;
745
+ const _dotenv = opts.dotenv ?? (configOverrides.dev && { fileName: [".env", ".env.local"] });
746
+ const loadedConfig = await (opts.watch ? watchConfig : loadConfig)({
747
+ name: "nitro",
748
+ cwd: configOverrides.rootDir,
749
+ dotenv: _dotenv,
750
+ extend: { extendKey: ["extends", "preset"] },
751
+ defaults: NitroDefaults,
752
+ jitiOptions: {
753
+ alias: {
754
+ nitropack: "nitro/config",
755
+ "nitro/config": "nitro/config"
756
+ }
757
+ },
758
+ async overrides({ rawConfigs }) {
759
+ const getConf = (key) => configOverrides[key] ?? rawConfigs.main?.[key] ?? rawConfigs.rc?.[key] ?? rawConfigs.packageJson?.[key];
760
+ if (!compatibilityDate) {
761
+ compatibilityDate = getConf("compatibilityDate");
762
+ }
763
+ const framework = getConf("framework");
764
+ const isCustomFramework = framework?.name && framework.name !== "nitro";
765
+ if (!preset) {
766
+ preset = getConf("preset");
767
+ }
768
+ if (configOverrides.dev) {
769
+ preset = preset && preset !== "nitro-dev" ? await resolvePreset(preset, {
770
+ static: getConf("static"),
771
+ dev: true,
772
+ compatibilityDate: compatibilityDate || "latest"
773
+ }).then((p) => p?._meta?.name || "nitro-dev").catch(() => "nitro-dev") : "nitro-dev";
774
+ } else if (!preset) {
775
+ preset = await resolvePreset("", {
776
+ static: getConf("static"),
777
+ dev: false,
778
+ compatibilityDate: compatibilityDate || "latest"
779
+ }).then((p) => p?._meta?.name);
780
+ }
781
+ return {
782
+ ...configOverrides,
783
+ preset,
784
+ typescript: {
785
+ generateRuntimeConfigTypes: !isCustomFramework,
786
+ ...getConf("typescript"),
787
+ ...configOverrides.typescript
788
+ }
789
+ };
790
+ },
791
+ async resolve(id) {
792
+ const preset2 = await resolvePreset(id, {
793
+ static: configOverrides.static,
794
+ compatibilityDate: compatibilityDate || "latest",
795
+ dev: configOverrides.dev
796
+ });
797
+ if (preset2) {
798
+ return {
799
+ config: klona(preset2)
800
+ };
801
+ }
802
+ },
803
+ ...opts.c12
804
+ });
805
+ const options = klona(loadedConfig.config);
806
+ options._config = configOverrides;
807
+ options._c12 = loadedConfig;
808
+ const _presetName = (loadedConfig.layers || []).find((l) => l.config?._meta?.name)?.config?._meta?.name || preset;
809
+ options.preset = _presetName;
810
+ options.compatibilityDate = resolveCompatibilityDates(
811
+ compatibilityDate,
812
+ options.compatibilityDate
813
+ );
814
+ if (options.dev && options.preset !== "nitro-dev") {
815
+ consola.info(`Using \`${options.preset}\` emulation in development mode.`);
816
+ }
817
+ return options;
818
+ }
819
+
820
+ async function updateNitroConfig(nitro, config) {
821
+ nitro.options.routeRules = normalizeRouteRules(
822
+ config.routeRules ? config : nitro.options
823
+ );
824
+ nitro.options.runtimeConfig = normalizeRuntimeConfig(
825
+ config.runtimeConfig ? config : nitro.options
826
+ );
827
+ await nitro.hooks.callHook("rollup:reload");
828
+ consola.success("Nitro config hot reloaded!");
829
+ }
830
+
831
+ async function installModules(nitro) {
832
+ const _modules = [...nitro.options.modules || []];
833
+ const modules = await Promise.all(
834
+ _modules.map((mod) => _resolveNitroModule(mod, nitro.options))
835
+ );
836
+ const _installedURLs = /* @__PURE__ */ new Set();
837
+ for (const mod of modules) {
838
+ if (mod._url) {
839
+ if (_installedURLs.has(mod._url)) {
840
+ continue;
841
+ }
842
+ _installedURLs.add(mod._url);
843
+ }
844
+ await mod.setup(nitro);
845
+ }
846
+ }
847
+ async function _resolveNitroModule(mod, nitroOptions) {
848
+ let _url;
849
+ if (typeof mod === "string") {
850
+ globalThis.defineNitroModule = // @ts-ignore
851
+ globalThis.defineNitroModule || ((mod2) => mod2);
852
+ const jiti = createJiti(nitroOptions.rootDir, {
853
+ alias: nitroOptions.alias
854
+ });
855
+ const _modPath = jiti.esmResolve(mod);
856
+ _url = _modPath;
857
+ mod = await jiti.import(_modPath, { default: true });
858
+ }
859
+ if (typeof mod === "function") {
860
+ mod = { setup: mod };
861
+ }
862
+ if (!mod.setup) {
863
+ mod.setup = () => {
864
+ };
865
+ }
866
+ return {
867
+ _url,
868
+ ...mod
869
+ };
870
+ }
871
+
872
+ async function runTask(taskEvent, opts) {
873
+ const ctx = await _getTasksContext(opts);
874
+ const result = await ctx.devFetch(`/_nitro/tasks/${taskEvent.name}`, {
875
+ method: "POST",
876
+ body: taskEvent
877
+ });
878
+ return result;
879
+ }
880
+ async function listTasks(opts) {
881
+ const ctx = await _getTasksContext(opts);
882
+ const res = await ctx.devFetch("/_nitro/tasks");
883
+ return res.tasks;
884
+ }
885
+ function addNitroTasksVirtualFile(nitro) {
886
+ nitro.options.virtual["#nitro-internal-virtual/tasks"] = () => {
887
+ const _scheduledTasks = Object.entries(nitro.options.scheduledTasks || {}).map(([cron, _tasks]) => {
888
+ const tasks = (Array.isArray(_tasks) ? _tasks : [_tasks]).filter(
889
+ (name) => {
890
+ if (!nitro.options.tasks[name]) {
891
+ nitro.logger.warn(`Scheduled task \`${name}\` is not defined!`);
892
+ return false;
893
+ }
894
+ return true;
895
+ }
896
+ );
897
+ return { cron, tasks };
898
+ }).filter((e) => e.tasks.length > 0);
899
+ const scheduledTasks = _scheduledTasks.length > 0 ? _scheduledTasks : false;
900
+ return (
901
+ /* js */
902
+ `
903
+ export const scheduledTasks = ${JSON.stringify(scheduledTasks)};
904
+
905
+ export const tasks = {
906
+ ${Object.entries(nitro.options.tasks).map(
907
+ ([name, task]) => `"${name}": {
908
+ meta: {
909
+ description: ${JSON.stringify(task.description)},
910
+ },
911
+ resolve: ${task.handler ? `() => import("${normalize(
912
+ task.handler
913
+ )}").then(r => r.default || r)` : "undefined"},
914
+ }`
915
+ ).join(",\n")}
916
+ };`
917
+ );
918
+ };
919
+ }
920
+ const _devHint = `(is dev server running?)`;
921
+ async function _getTasksContext(opts) {
922
+ const cwd = resolve(process.cwd(), opts?.cwd || ".");
923
+ const outDir = resolve(cwd, opts?.buildDir || ".nitro");
924
+ const buildInfoPath = resolve(outDir, "nitro.json");
925
+ if (!existsSync(buildInfoPath)) {
926
+ throw new Error(`Missing info file: \`${buildInfoPath}\` ${_devHint}`);
927
+ }
928
+ const buildInfo = JSON.parse(
929
+ await readFile(buildInfoPath, "utf8")
930
+ );
931
+ if (!buildInfo.dev?.pid || !buildInfo.dev?.workerAddress) {
932
+ throw new Error(
933
+ `Missing dev server info in: \`${buildInfoPath}\` ${_devHint}`
934
+ );
935
+ }
936
+ if (!_pidIsRunning(buildInfo.dev.pid)) {
937
+ throw new Error(`Dev server is not running (pid: ${buildInfo.dev.pid})`);
938
+ }
939
+ const devFetch = ofetch.create({
940
+ baseURL: `http://${buildInfo.dev.workerAddress.host || "localhost"}:${buildInfo.dev.workerAddress.port || "3000"}`,
941
+ // @ts-expect-error
942
+ socketPath: buildInfo.dev.workerAddress.socketPath
943
+ });
944
+ return {
945
+ buildInfo,
946
+ devFetch
947
+ };
948
+ }
949
+ function _pidIsRunning(pid) {
950
+ try {
951
+ process.kill(pid, 0);
952
+ return true;
953
+ } catch {
954
+ return false;
955
+ }
956
+ }
957
+
958
+ const isGlobalMiddleware = (h) => !h.method && (!h.route || h.route === "/**");
959
+ function initNitroRouting(nitro) {
960
+ const envConditions = new Set(
961
+ [
962
+ nitro.options.dev ? "dev" : "prod",
963
+ nitro.options.preset,
964
+ nitro.options.preset === "nitro-prerender" ? "prerender" : void 0
965
+ ].filter(Boolean)
966
+ );
967
+ const matchesEnv = (h) => {
968
+ const hEnv = Array.isArray(h.env) ? h.env : [h.env];
969
+ const envs = hEnv.filter(Boolean);
970
+ return envs.length === 0 || envs.some((env) => envConditions.has(env));
971
+ };
972
+ const routes = new Router();
973
+ const routeRules = new Router(
974
+ true
975
+ /* matchAll */
976
+ );
977
+ const globalMiddleware = [];
978
+ const routedMiddleware = new Router(
979
+ true
980
+ /* matchAll */
981
+ );
982
+ const warns = /* @__PURE__ */ new Set();
983
+ const sync = () => {
984
+ routeRules._update(
985
+ Object.entries(nitro.options.routeRules).map(([route, data]) => ({
986
+ route,
987
+ method: "",
988
+ data: {
989
+ ...data,
990
+ _route: route
991
+ }
992
+ }))
993
+ );
994
+ const _routes = [
995
+ ...nitro.scannedHandlers,
996
+ ...nitro.options.handlers
997
+ ].filter((h) => h && !h.middleware && matchesEnv(h));
998
+ if (nitro.options.renderer?.entry) {
999
+ const existingWildcard = _routes.findIndex(
1000
+ (h) => /^\/\*\*(:.+)?$/.test(h.route) && (!h.method || h.method === "GET")
1001
+ );
1002
+ if (existingWildcard !== -1) {
1003
+ const h = _routes[existingWildcard];
1004
+ const warn = `The renderer will override \`${relative(".", h.handler)}\` (route: \`${h.route}\`). Use a more specific route or different HTTP method.`;
1005
+ if (!warns.has(warn)) {
1006
+ warns.add(warn);
1007
+ nitro.logger.warn(warn);
1008
+ }
1009
+ _routes.splice(existingWildcard, 1);
1010
+ }
1011
+ _routes.push({
1012
+ route: "/**",
1013
+ lazy: true,
1014
+ handler: nitro.options.renderer?.entry
1015
+ });
1016
+ }
1017
+ routes._update(
1018
+ _routes.map((h) => ({
1019
+ ...h,
1020
+ method: h.method || "",
1021
+ data: handlerWithImportHash(h)
1022
+ }))
1023
+ );
1024
+ const _middleware = [
1025
+ ...nitro.scannedHandlers,
1026
+ ...nitro.options.handlers
1027
+ ].filter((h) => h && h.middleware && matchesEnv(h));
1028
+ if (nitro.options.serveStatic) {
1029
+ _middleware.unshift({
1030
+ route: "/**",
1031
+ middleware: true,
1032
+ handler: join(runtimeDir, "internal/static")
1033
+ });
1034
+ }
1035
+ globalMiddleware.splice(
1036
+ 0,
1037
+ globalMiddleware.length,
1038
+ ..._middleware.filter((h) => isGlobalMiddleware(h)).map((m) => handlerWithImportHash(m))
1039
+ );
1040
+ routedMiddleware._update(
1041
+ _middleware.filter((h) => !isGlobalMiddleware(h)).map((h) => ({
1042
+ ...h,
1043
+ method: h.method || "",
1044
+ data: handlerWithImportHash(h)
1045
+ }))
1046
+ );
1047
+ };
1048
+ nitro.routing = Object.freeze({
1049
+ sync,
1050
+ routes,
1051
+ routeRules,
1052
+ globalMiddleware,
1053
+ routedMiddleware
1054
+ });
1055
+ }
1056
+ function handlerWithImportHash(h) {
1057
+ const id = (h.lazy ? "_lazy_" : "_") + hash(h.handler).replace(/-/g, "").slice(0, 6);
1058
+ return { ...h, _importHash: id };
1059
+ }
1060
+ class Router {
1061
+ #routes;
1062
+ #router;
1063
+ #compiled;
1064
+ constructor(matchAll) {
1065
+ this._update([]);
1066
+ }
1067
+ get routes() {
1068
+ return this.#routes;
1069
+ }
1070
+ _update(routes) {
1071
+ this.#routes = routes;
1072
+ this.#router = createRouter();
1073
+ this.#compiled = void 0;
1074
+ for (const route of routes) {
1075
+ addRoute(this.#router, route.method, route.route, route.data);
1076
+ }
1077
+ }
1078
+ hasRoutes() {
1079
+ return this.#routes.length > 0;
1080
+ }
1081
+ compileToString(opts) {
1082
+ return this.#compiled || (this.#compiled = compileRouterToString(this.#router, void 0, opts));
1083
+ }
1084
+ match(method, path) {
1085
+ return findRoute(this.#router, method, path)?.data;
1086
+ }
1087
+ matchAll(method, path) {
1088
+ return findAllRoutes(this.#router, method, path).map(
1089
+ (route) => route.data
1090
+ );
1091
+ }
1092
+ }
1093
+
1094
+ async function createNitro(config = {}, opts = {}) {
1095
+ const options = await loadOptions(config, opts);
1096
+ const nitro = {
1097
+ options,
1098
+ hooks: new Hookable(),
1099
+ vfs: {},
1100
+ routing: {},
1101
+ logger: consola$1.withTag("nitro"),
1102
+ scannedHandlers: [],
1103
+ close: () => nitro.hooks.callHook("close"),
1104
+ storage: void 0,
1105
+ async updateConfig(config2) {
1106
+ updateNitroConfig(nitro, config2);
1107
+ }
1108
+ };
1109
+ initNitroRouting(nitro);
1110
+ await scanAndSyncOptions(nitro);
1111
+ nitro.storage = await createStorage(nitro);
1112
+ nitro.hooks.hook("close", async () => {
1113
+ await nitro.storage.dispose();
1114
+ });
1115
+ if (nitro.options.debug) {
1116
+ createDebugger(nitro.hooks, { tag: "nitro" });
1117
+ }
1118
+ if (nitro.options.logLevel !== void 0) {
1119
+ nitro.logger.level = nitro.options.logLevel;
1120
+ }
1121
+ nitro.hooks.addHooks(nitro.options.hooks);
1122
+ addNitroTasksVirtualFile(nitro);
1123
+ await installModules(nitro);
1124
+ if (nitro.options.imports) {
1125
+ nitro.unimport = createUnimport(nitro.options.imports);
1126
+ await nitro.unimport.init();
1127
+ nitro.options.virtual["#imports"] = () => nitro.unimport?.toExports() || "";
1128
+ nitro.options.virtual["#nitro"] = 'export * from "#imports"';
1129
+ }
1130
+ await scanHandlers(nitro);
1131
+ nitro.routing.sync();
1132
+ return nitro;
1133
+ }
1134
+
1135
+ const allowedExtensions = /* @__PURE__ */ new Set(["", ".json"]);
1136
+ const linkParents$1 = /* @__PURE__ */ new Map();
1137
+ const HTML_ENTITIES = {
1138
+ "&lt;": "<",
1139
+ "&gt;": ">",
1140
+ "&amp;": "&",
1141
+ "&apos;": "'",
1142
+ "&quot;": '"'
1143
+ };
1144
+ function escapeHtml(text) {
1145
+ return text.replace(
1146
+ /&(lt|gt|amp|apos|quot);/g,
1147
+ (ch) => HTML_ENTITIES[ch] || ch
1148
+ );
1149
+ }
1150
+ async function extractLinks(html, from, res, crawlLinks) {
1151
+ const links = [];
1152
+ const _links = [];
1153
+ if (crawlLinks) {
1154
+ await z(P(html), (node) => {
1155
+ if (!node.attributes?.href) {
1156
+ return;
1157
+ }
1158
+ const link = escapeHtml(node.attributes.href);
1159
+ if (!decodeURIComponent(link).startsWith("#") && allowedExtensions.has(getExtension(link))) {
1160
+ _links.push(link);
1161
+ }
1162
+ });
1163
+ }
1164
+ const header = res.headers.get("x-nitro-prerender") || "";
1165
+ _links.push(...header.split(",").map((i) => decodeURIComponent(i.trim())));
1166
+ for (const link of _links.filter(Boolean)) {
1167
+ const _link = parseURL(link);
1168
+ if (_link.protocol || _link.host) {
1169
+ continue;
1170
+ }
1171
+ if (!_link.pathname.startsWith("/")) {
1172
+ const fromURL = new URL(from, "http://localhost");
1173
+ _link.pathname = new URL(_link.pathname, fromURL).pathname;
1174
+ }
1175
+ links.push(_link.pathname + _link.search);
1176
+ }
1177
+ for (const link of links) {
1178
+ const _parents = linkParents$1.get(link);
1179
+ if (_parents) {
1180
+ _parents.add(from);
1181
+ } else {
1182
+ linkParents$1.set(link, /* @__PURE__ */ new Set([from]));
1183
+ }
1184
+ }
1185
+ return links;
1186
+ }
1187
+ const EXT_REGEX = /\.[\da-z]+$/;
1188
+ function getExtension(link) {
1189
+ const pathname = parseURL(link).pathname;
1190
+ return (pathname.match(EXT_REGEX) || [])[0] || "";
1191
+ }
1192
+ function formatPrerenderRoute(route) {
1193
+ let str = ` \u251C\u2500 ${route.route} (${route.generateTimeMS}ms)`;
1194
+ if (route.error) {
1195
+ const parents = linkParents$1.get(route.route);
1196
+ const errorColor = colors[route.error.status === 404 ? "yellow" : "red"];
1197
+ const errorLead = parents?.size ? "\u251C\u2500\u2500" : "\u2514\u2500\u2500";
1198
+ str += `
1199
+ \u2502 ${errorLead} ${errorColor(route.error.message)}`;
1200
+ if (parents?.size) {
1201
+ str += `
1202
+ ${[...parents.values()].map((link) => ` \u2502 \u2514\u2500\u2500 Linked from ${link}`).join("\n")}`;
1203
+ }
1204
+ }
1205
+ if (route.skip) {
1206
+ str += colors.gray(" (skipped)");
1207
+ }
1208
+ return colors.gray(str);
1209
+ }
1210
+ function matchesIgnorePattern(path, pattern) {
1211
+ if (typeof pattern === "string") {
1212
+ return path.startsWith(pattern);
1213
+ }
1214
+ if (typeof pattern === "function") {
1215
+ return pattern(path) === true;
1216
+ }
1217
+ if (pattern instanceof RegExp) {
1218
+ return pattern.test(path);
1219
+ }
1220
+ return false;
1221
+ }
1222
+
1223
+ const JsonSigRx = /^\s*["[{]|^\s*-?\d{1,16}(\.\d{1,17})?([Ee][+-]?\d+)?\s*$/;
1224
+ const linkParents = /* @__PURE__ */ new Map();
1225
+ async function prerender(nitro) {
1226
+ if (nitro.options.noPublicDir) {
1227
+ nitro.logger.warn(
1228
+ "Skipping prerender since `noPublicDir` option is enabled."
1229
+ );
1230
+ return;
1231
+ }
1232
+ if (nitro.options.builder === "vite") {
1233
+ nitro.logger.warn(
1234
+ "Skipping prerender since not supported with vite builder yet..."
1235
+ );
1236
+ return;
1237
+ }
1238
+ const routes = new Set(nitro.options.prerender.routes);
1239
+ const prerenderRulePaths = Object.entries(nitro.options.routeRules).filter(([path2, options]) => options.prerender && !path2.includes("*")).map((e) => e[0]);
1240
+ for (const route of prerenderRulePaths) {
1241
+ routes.add(route);
1242
+ }
1243
+ await nitro.hooks.callHook("prerender:routes", routes);
1244
+ if (routes.size === 0) {
1245
+ if (nitro.options.prerender.crawlLinks) {
1246
+ routes.add("/");
1247
+ } else {
1248
+ return;
1249
+ }
1250
+ }
1251
+ nitro.logger.info("Initializing prerenderer");
1252
+ nitro._prerenderedRoutes = [];
1253
+ nitro._prerenderMeta = nitro._prerenderMeta || {};
1254
+ const prerendererConfig = {
1255
+ ...nitro.options._config,
1256
+ static: false,
1257
+ rootDir: nitro.options.rootDir,
1258
+ logLevel: 0,
1259
+ preset: "nitro-prerender"
1260
+ };
1261
+ await nitro.hooks.callHook("prerender:config", prerendererConfig);
1262
+ const nitroRenderer = await createNitro(prerendererConfig);
1263
+ const prerenderStartTime = Date.now();
1264
+ await nitro.hooks.callHook("prerender:init", nitroRenderer);
1265
+ let path = relative(nitro.options.output.dir, nitro.options.output.publicDir);
1266
+ if (!path.startsWith(".")) {
1267
+ path = `./${path}`;
1268
+ }
1269
+ nitroRenderer.options.commands.preview = `npx serve ${path}`;
1270
+ nitroRenderer.options.output.dir = nitro.options.output.dir;
1271
+ await build$1(nitroRenderer);
1272
+ const serverFilename = typeof nitroRenderer.options.rollupConfig?.output?.entryFileNames === "string" ? nitroRenderer.options.rollupConfig.output.entryFileNames : "index.mjs";
1273
+ const serverEntrypoint = resolve(
1274
+ nitroRenderer.options.output.serverDir,
1275
+ serverFilename
1276
+ );
1277
+ const { closePrerenderer, appFetch } = await import(pathToFileURL(serverEntrypoint).href);
1278
+ const routeRules = createRouter();
1279
+ for (const [route, rules] of Object.entries(nitro.options.routeRules)) {
1280
+ addRoute(routeRules, void 0, route, rules);
1281
+ }
1282
+ const _getRouteRules = (path2) => defu(
1283
+ {},
1284
+ ...findAllRoutes(routeRules, void 0, path2).map((r) => r.data).reverse()
1285
+ );
1286
+ const generatedRoutes = /* @__PURE__ */ new Set();
1287
+ const failedRoutes = /* @__PURE__ */ new Set();
1288
+ const skippedRoutes = /* @__PURE__ */ new Set();
1289
+ const displayedLengthWarns = /* @__PURE__ */ new Set();
1290
+ const publicAssetBases = nitro.options.publicAssets.filter(
1291
+ (a) => !!a.baseURL && a.baseURL !== "/" && !a.fallthrough
1292
+ ).map((a) => withTrailingSlash(a.baseURL));
1293
+ const scannedPublicAssets = nitro.options.prerender.ignoreUnprefixedPublicAssets ? new Set(await scanUnprefixedPublicAssets(nitro)) : /* @__PURE__ */ new Set();
1294
+ const canPrerender = (route = "/") => {
1295
+ if (generatedRoutes.has(route) || skippedRoutes.has(route)) {
1296
+ return false;
1297
+ }
1298
+ for (const pattern of nitro.options.prerender.ignore) {
1299
+ if (matchesIgnorePattern(route, pattern)) {
1300
+ return false;
1301
+ }
1302
+ }
1303
+ if (publicAssetBases.some((base) => route.startsWith(base))) {
1304
+ return false;
1305
+ }
1306
+ if (scannedPublicAssets.has(route)) {
1307
+ return false;
1308
+ }
1309
+ if (_getRouteRules(route).prerender === false) {
1310
+ return false;
1311
+ }
1312
+ return true;
1313
+ };
1314
+ const canWriteToDisk = (route) => {
1315
+ if (route.route.includes("?")) {
1316
+ return false;
1317
+ }
1318
+ const FS_MAX_SEGMENT = 255;
1319
+ const FS_MAX_PATH = 1024;
1320
+ const FS_MAX_PATH_PUBLIC_HTML = FS_MAX_PATH - (nitro.options.output.publicDir.length + 10);
1321
+ if ((route.route.length >= FS_MAX_PATH_PUBLIC_HTML || route.route.split("/").some((s) => s.length > FS_MAX_SEGMENT)) && !displayedLengthWarns.has(route)) {
1322
+ displayedLengthWarns.add(route);
1323
+ const _route = route.route.slice(0, 60) + "...";
1324
+ if (route.route.length >= FS_MAX_PATH_PUBLIC_HTML) {
1325
+ nitro.logger.warn(
1326
+ `Prerendering long route "${_route}" (${route.route.length}) can cause filesystem issues since it exceeds ${FS_MAX_PATH_PUBLIC_HTML}-character limit when writing to \`${nitro.options.output.publicDir}\`.`
1327
+ );
1328
+ } else {
1329
+ nitro.logger.warn(
1330
+ `Skipping prerender of the route "${_route}" since it exceeds the ${FS_MAX_SEGMENT}-character limit in one of the path segments and can cause filesystem issues.`
1331
+ );
1332
+ return false;
1333
+ }
1334
+ }
1335
+ return true;
1336
+ };
1337
+ const generateRoute = async (route) => {
1338
+ const start = Date.now();
1339
+ route = decodeURI(route);
1340
+ if (!canPrerender(route)) {
1341
+ skippedRoutes.add(route);
1342
+ return;
1343
+ }
1344
+ generatedRoutes.add(route);
1345
+ const _route = { route };
1346
+ const encodedRoute = encodeURI(route);
1347
+ const res = await appFetch(withBase(encodedRoute, nitro.options.baseURL), {
1348
+ headers: [["x-nitro-prerender", encodedRoute]]
1349
+ // TODO
1350
+ // retry: nitro.options.prerender.retry,
1351
+ // retryDelay: nitro.options.prerender.retryDelay,
1352
+ });
1353
+ let dataBuff = Buffer.from(await res.arrayBuffer());
1354
+ Object.defineProperty(_route, "contents", {
1355
+ get: () => {
1356
+ return dataBuff ? dataBuff.toString("utf8") : void 0;
1357
+ },
1358
+ set(value) {
1359
+ if (dataBuff) {
1360
+ dataBuff = Buffer.from(value);
1361
+ }
1362
+ }
1363
+ });
1364
+ Object.defineProperty(_route, "data", {
1365
+ get: () => {
1366
+ return dataBuff ? dataBuff.buffer : void 0;
1367
+ },
1368
+ set(value) {
1369
+ if (dataBuff) {
1370
+ dataBuff = Buffer.from(value);
1371
+ }
1372
+ }
1373
+ });
1374
+ const redirectCodes = [301, 302, 303, 304, 307, 308];
1375
+ if (![200, ...redirectCodes].includes(res.status)) {
1376
+ _route.error = new Error(`[${res.status}] ${res.statusText}`);
1377
+ _route.error.status = res.status;
1378
+ _route.error.statusText = res.statusText;
1379
+ }
1380
+ _route.generateTimeMS = Date.now() - start;
1381
+ const contentType = res.headers.get("content-type") || "";
1382
+ const isImplicitHTML = !route.endsWith(".html") && contentType.includes("html") && !JsonSigRx.test(dataBuff.subarray(0, 32).toString("utf8"));
1383
+ const routeWithIndex = route.endsWith("/") ? route + "index" : route;
1384
+ const htmlPath = route.endsWith("/") || nitro.options.prerender.autoSubfolderIndex ? joinURL(route, "index.html") : route + ".html";
1385
+ _route.fileName = withoutBase(
1386
+ isImplicitHTML ? htmlPath : routeWithIndex,
1387
+ nitro.options.baseURL
1388
+ );
1389
+ const inferredContentType = mime.getType(_route.fileName) || "text/plain";
1390
+ _route.contentType = contentType || inferredContentType;
1391
+ await nitro.hooks.callHook("prerender:generate", _route, nitro);
1392
+ if (_route.contentType !== inferredContentType) {
1393
+ nitro._prerenderMeta[_route.fileName] ||= {};
1394
+ nitro._prerenderMeta[_route.fileName].contentType = _route.contentType;
1395
+ }
1396
+ if (_route.error) {
1397
+ failedRoutes.add(_route);
1398
+ }
1399
+ if (_route.skip || _route.error) {
1400
+ await nitro.hooks.callHook("prerender:route", _route);
1401
+ nitro.logger.log(formatPrerenderRoute(_route));
1402
+ dataBuff = void 0;
1403
+ return _route;
1404
+ }
1405
+ if (canWriteToDisk(_route)) {
1406
+ const filePath = join(nitro.options.output.publicDir, _route.fileName);
1407
+ await writeFile(filePath, dataBuff);
1408
+ nitro._prerenderedRoutes.push(_route);
1409
+ } else {
1410
+ _route.skip = true;
1411
+ }
1412
+ if (!_route.error && (isImplicitHTML || route.endsWith(".html"))) {
1413
+ const extractedLinks = await extractLinks(
1414
+ dataBuff.toString("utf8"),
1415
+ route,
1416
+ res,
1417
+ nitro.options.prerender.crawlLinks
1418
+ );
1419
+ for (const _link of extractedLinks) {
1420
+ if (canPrerender(_link)) {
1421
+ routes.add(_link);
1422
+ }
1423
+ }
1424
+ }
1425
+ await nitro.hooks.callHook("prerender:route", _route);
1426
+ nitro.logger.log(formatPrerenderRoute(_route));
1427
+ dataBuff = void 0;
1428
+ return _route;
1429
+ };
1430
+ nitro.logger.info(
1431
+ nitro.options.prerender.crawlLinks ? `Prerendering ${routes.size} initial routes with crawler` : `Prerendering ${routes.size} routes`
1432
+ );
1433
+ await runParallel(routes, generateRoute, {
1434
+ concurrency: nitro.options.prerender.concurrency,
1435
+ interval: nitro.options.prerender.interval
1436
+ });
1437
+ await closePrerenderer();
1438
+ await nitro.hooks.callHook("prerender:done", {
1439
+ prerenderedRoutes: nitro._prerenderedRoutes,
1440
+ failedRoutes: [...failedRoutes]
1441
+ });
1442
+ if (nitro.options.prerender.failOnError && failedRoutes.size > 0) {
1443
+ nitro.logger.log("\nErrors prerendering:");
1444
+ for (const route of failedRoutes) {
1445
+ const parents = linkParents.get(route.route);
1446
+ parents?.size ? `
1447
+ ${[...parents.values()].map((link) => colors.gray(` \u2502 \u2514\u2500\u2500 Linked from ${link}`)).join("\n")}` : "";
1448
+ nitro.logger.log(formatPrerenderRoute(route));
1449
+ }
1450
+ nitro.logger.log("");
1451
+ throw new Error("Exiting due to prerender errors.");
1452
+ }
1453
+ const prerenderTimeInMs = Date.now() - prerenderStartTime;
1454
+ nitro.logger.info(
1455
+ `Prerendered ${nitro._prerenderedRoutes.length} routes in ${prerenderTimeInMs / 1e3} seconds`
1456
+ );
1457
+ if (nitro.options.compressPublicAssets) {
1458
+ await compressPublicAssets(nitro);
1459
+ }
1460
+ }
1461
+
1462
+ function createHTTPProxy(defaults = {}) {
1463
+ const proxy = createProxyServer(defaults);
1464
+ proxy.on("proxyReq", (proxyReq, req) => {
1465
+ if (!proxyReq.hasHeader("x-forwarded-for")) {
1466
+ const address = req.socket.remoteAddress;
1467
+ if (address) {
1468
+ proxyReq.appendHeader("x-forwarded-for", address);
1469
+ }
1470
+ }
1471
+ if (!proxyReq.hasHeader("x-forwarded-port")) {
1472
+ const localPort = req?.socket?.localPort;
1473
+ if (localPort) {
1474
+ proxyReq.setHeader("x-forwarded-port", req.socket.localPort);
1475
+ }
1476
+ }
1477
+ if (!proxyReq.hasHeader("x-forwarded-Proto")) {
1478
+ const encrypted = req?.connection?.encrypted;
1479
+ proxyReq.setHeader("x-forwarded-proto", encrypted ? "https" : "http");
1480
+ }
1481
+ });
1482
+ return {
1483
+ proxy,
1484
+ async handleEvent(event, opts) {
1485
+ try {
1486
+ return await fromNodeHandler(
1487
+ (req, res) => proxy.web(req, res, opts)
1488
+ )(event);
1489
+ } catch (error) {
1490
+ event.res.headers.set("refresh", "3");
1491
+ throw new HTTPError({
1492
+ status: 503,
1493
+ message: "Dev server is unavailable.",
1494
+ cause: error
1495
+ });
1496
+ }
1497
+ }
1498
+ };
1499
+ }
1500
+ function fetchAddress(addr, input, inputInit) {
1501
+ let url;
1502
+ let init;
1503
+ if (input instanceof Request) {
1504
+ url = new URL(input.url);
1505
+ init = {
1506
+ method: input.method,
1507
+ headers: input.headers,
1508
+ body: input.body,
1509
+ ...inputInit
1510
+ };
1511
+ } else {
1512
+ url = new URL(input);
1513
+ init = inputInit;
1514
+ }
1515
+ init = {
1516
+ duplex: "half",
1517
+ redirect: "manual",
1518
+ ...init
1519
+ };
1520
+ if (addr.socketPath) {
1521
+ url.protocol = "http:";
1522
+ return fetch(url, {
1523
+ ...init,
1524
+ ...fetchSocketOptions(addr.socketPath)
1525
+ });
1526
+ }
1527
+ const origin = `http://${addr.host}${addr.port ? `:${addr.port}` : ""}`;
1528
+ const outURL = new URL(url.pathname + url.search, origin);
1529
+ return fetch(outURL, init);
1530
+ }
1531
+ function fetchSocketOptions(socketPath) {
1532
+ if ("Bun" in globalThis) {
1533
+ return { unix: socketPath };
1534
+ }
1535
+ if ("Deno" in globalThis) {
1536
+ return {
1537
+ // @ts-ignore
1538
+ client: Deno.createHttpClient({
1539
+ // @ts-ignore Missing types?
1540
+ transport: "unix",
1541
+ path: socketPath
1542
+ })
1543
+ };
1544
+ }
1545
+ return {
1546
+ dispatcher: new Agent({ connect: { socketPath } })
1547
+ };
1548
+ }
1549
+
1550
+ class NodeDevWorker {
1551
+ closed = false;
1552
+ #name;
1553
+ #entry;
1554
+ #data;
1555
+ #hooks;
1556
+ #worker;
1557
+ #address;
1558
+ #proxy;
1559
+ #messageListeners;
1560
+ constructor(opts) {
1561
+ this.#name = opts.name;
1562
+ this.#entry = opts.entry;
1563
+ this.#data = opts.data;
1564
+ this.#hooks = opts.hooks;
1565
+ this.#proxy = createHTTPProxy();
1566
+ this.#messageListeners = /* @__PURE__ */ new Set();
1567
+ this.#initWorker();
1568
+ }
1569
+ get ready() {
1570
+ return Boolean(
1571
+ !this.closed && this.#address && this.#proxy && this.#worker
1572
+ );
1573
+ }
1574
+ // #region Public methods
1575
+ async fetch(input, init) {
1576
+ for (let i = 0; i < 5 && !(this.#address && this.#proxy); i++) {
1577
+ await new Promise((r) => setTimeout(r, 100 * Math.pow(2, i)));
1578
+ }
1579
+ if (!(this.#address && this.#proxy)) {
1580
+ return new Response("Dev worker is unavailable", { status: 503 });
1581
+ }
1582
+ return fetchAddress(this.#address, input, init);
1583
+ }
1584
+ upgrade(req, socket, head) {
1585
+ if (!this.ready) {
1586
+ return;
1587
+ }
1588
+ return this.#proxy.proxy.ws(
1589
+ req,
1590
+ socket,
1591
+ { target: this.#address, xfwd: true },
1592
+ head
1593
+ );
1594
+ }
1595
+ sendMessage(message) {
1596
+ if (!this.#worker) {
1597
+ throw new Error(
1598
+ "Dev worker should be initialized before sending messages."
1599
+ );
1600
+ }
1601
+ this.#worker.postMessage(message);
1602
+ }
1603
+ onMessage(listener) {
1604
+ this.#messageListeners.add(listener);
1605
+ }
1606
+ offMessage(listener) {
1607
+ this.#messageListeners.delete(listener);
1608
+ }
1609
+ async close(cause) {
1610
+ if (this.closed) {
1611
+ return;
1612
+ }
1613
+ this.closed = true;
1614
+ this.#hooks.onClose?.(this, cause);
1615
+ this.#hooks = {};
1616
+ const onError = (error) => consola.error(error);
1617
+ await this.#closeWorker().catch(onError);
1618
+ await this.#closeProxy().catch(onError);
1619
+ await this.#closeSocket().catch(onError);
1620
+ }
1621
+ [Symbol.for("nodejs.util.inspect.custom")]() {
1622
+ const status = this.closed ? "closed" : this.ready ? "ready" : "pending";
1623
+ return `NodeDevWorker#${this.#name}(${status})`;
1624
+ }
1625
+ // #endregion
1626
+ // #region Private methods
1627
+ #initWorker() {
1628
+ if (!existsSync(this.#entry)) {
1629
+ this.close(`worker entry not found in "${this.#entry}".`);
1630
+ return;
1631
+ }
1632
+ const worker = new Worker(this.#entry, {
1633
+ env: {
1634
+ ...process.env
1635
+ },
1636
+ workerData: {
1637
+ name: this.#name,
1638
+ ...this.#data
1639
+ }
1640
+ });
1641
+ worker.once("exit", (code) => {
1642
+ worker._exitCode = code;
1643
+ this.close(`worker exited with code ${code}`);
1644
+ });
1645
+ worker.once("error", (error) => {
1646
+ consola.error(`Worker error:`, error);
1647
+ this.close(error);
1648
+ });
1649
+ worker.on("message", (message) => {
1650
+ if (message?.address) {
1651
+ this.#address = message.address;
1652
+ this.#hooks.onReady?.(this, this.#address);
1653
+ }
1654
+ for (const listener of this.#messageListeners) {
1655
+ listener(message);
1656
+ }
1657
+ });
1658
+ this.#worker = worker;
1659
+ }
1660
+ async #closeProxy() {
1661
+ this.#proxy?.proxy?.close(() => {
1662
+ });
1663
+ this.#proxy = void 0;
1664
+ }
1665
+ async #closeSocket() {
1666
+ const socketPath = this.#address?.socketPath;
1667
+ if (socketPath && socketPath[0] !== "\0" && !socketPath.startsWith(String.raw`\\.\pipe`)) {
1668
+ await rm(socketPath).catch(() => {
1669
+ });
1670
+ }
1671
+ this.#address = void 0;
1672
+ }
1673
+ async #closeWorker() {
1674
+ if (!this.#worker) {
1675
+ return;
1676
+ }
1677
+ this.#worker.postMessage({ event: "shutdown" });
1678
+ if (!this.#worker._exitCode && !isTest && !isCI) {
1679
+ await new Promise((resolve) => {
1680
+ const gracefulShutdownTimeoutMs = Number.parseInt(process.env.NITRO_SHUTDOWN_TIMEOUT || "", 10) || 5e3;
1681
+ const timeout = setTimeout(() => {
1682
+ if (process.env.DEBUG) {
1683
+ consola.warn(`force closing dev worker...`);
1684
+ }
1685
+ }, gracefulShutdownTimeoutMs);
1686
+ this.#worker?.on("message", (message) => {
1687
+ if (message.event === "exit") {
1688
+ clearTimeout(timeout);
1689
+ resolve();
1690
+ }
1691
+ });
1692
+ });
1693
+ }
1694
+ this.#worker.removeAllListeners();
1695
+ await this.#worker.terminate().catch((error) => {
1696
+ consola.error(error);
1697
+ });
1698
+ this.#worker = void 0;
1699
+ }
1700
+ // #endregion
1701
+ }
1702
+
1703
+ function createVFSHandler(nitro) {
1704
+ return defineHandler(async (event) => {
1705
+ const { socket } = event.runtime?.node?.req || {};
1706
+ const isUnixSocket = (
1707
+ // No network addresses
1708
+ !socket?.remoteAddress && !socket?.localAddress && // Empty address object
1709
+ Object.keys(socket?.address?.() || {}).length === 0 && // Socket is readable/writable but has no port info
1710
+ socket?.readable && socket?.writable && !socket?.remotePort
1711
+ );
1712
+ const ip = getRequestIP(event, { xForwardedFor: isUnixSocket });
1713
+ const isLocalRequest = ip && /^::1$|^127\.\d+\.\d+\.\d+$/.test(ip);
1714
+ if (!isLocalRequest) {
1715
+ throw new HTTPError({
1716
+ statusText: `Forbidden IP: "${ip || "?"}"`,
1717
+ status: 403
1718
+ });
1719
+ }
1720
+ const vfsEntries = {
1721
+ ...nitro.vfs,
1722
+ ...nitro.options.virtual
1723
+ };
1724
+ const url = event.context.params?._ || "";
1725
+ const isJson = url.endsWith(".json") || event.req.headers.get("accept")?.includes("application/json");
1726
+ const id = decodeURIComponent(url.replace(/^(\.json)?\/?/, "") || "");
1727
+ if (id && !(id in vfsEntries)) {
1728
+ throw new HTTPError({ message: "File not found", status: 404 });
1729
+ }
1730
+ let content = id ? vfsEntries[id] : void 0;
1731
+ if (typeof content === "function") {
1732
+ content = await content();
1733
+ }
1734
+ if (isJson) {
1735
+ return {
1736
+ rootDir: nitro.options.rootDir,
1737
+ entries: Object.keys(vfsEntries).map((id2) => ({
1738
+ id: id2,
1739
+ path: "/_vfs.json/" + encodeURIComponent(id2)
1740
+ })),
1741
+ current: id ? {
1742
+ id,
1743
+ content
1744
+ } : null
1745
+ };
1746
+ }
1747
+ const directories = { [nitro.options.rootDir]: {} };
1748
+ const fpaths = Object.keys(vfsEntries);
1749
+ for (const item of fpaths) {
1750
+ const segments = item.replace(nitro.options.rootDir, "").split("/").filter(Boolean);
1751
+ let currentDir = item.startsWith(nitro.options.rootDir) ? directories[nitro.options.rootDir] : directories;
1752
+ for (const segment of segments) {
1753
+ if (!currentDir[segment]) {
1754
+ currentDir[segment] = {};
1755
+ }
1756
+ currentDir = currentDir[segment];
1757
+ }
1758
+ }
1759
+ const generateHTML = (directory, path = []) => Object.entries(directory).map(([fname, value = {}]) => {
1760
+ const subpath = [...path, fname];
1761
+ const key = subpath.join("/");
1762
+ const encodedUrl = encodeURIComponent(key);
1763
+ const linkClass = url === `/${encodedUrl}` ? "bg-gray-700 text-white" : "hover:bg-gray-800 text-gray-200";
1764
+ return Object.keys(value).length === 0 ? `
1765
+ <li class="flex flex-nowrap">
1766
+ <a href="/_vfs/${encodedUrl}" class="w-full text-sm px-2 py-1 border-b border-gray-10 ${linkClass}">
1767
+ ${fname}
1768
+ </a>
1769
+ </li>
1770
+ ` : `
1771
+ <li>
1772
+ <details ${url.startsWith(`/${encodedUrl}`) ? "open" : ""}>
1773
+ <summary class="w-full text-sm px-2 py-1 border-b border-gray-10 hover:bg-gray-800 text-gray-200">
1774
+ ${fname}
1775
+ </summary>
1776
+ <ul class="ml-4">
1777
+ ${generateHTML(value, subpath)}
1778
+ </ul>
1779
+ </details>
1780
+ </li>
1781
+ `;
1782
+ }).join("");
1783
+ const rootDirectory = directories[nitro.options.rootDir];
1784
+ delete directories[nitro.options.rootDir];
1785
+ const items = generateHTML(rootDirectory, [nitro.options.rootDir]) + generateHTML(directories);
1786
+ const files = `
1787
+ <div class="h-full overflow-auto border-r border-gray:10">
1788
+ <p class="text-white text-bold text-center py-1 opacity-50">Virtual Files</p>
1789
+ <ul class="flex flex-col">${items}</ul>
1790
+ </div>
1791
+ `;
1792
+ const file = id ? editorTemplate({
1793
+ readOnly: true,
1794
+ language: id.endsWith("html") ? "html" : "javascript",
1795
+ theme: "vs-dark",
1796
+ value: content,
1797
+ wordWrap: "wordWrapColumn",
1798
+ wordWrapColumn: 80
1799
+ }) : `
1800
+ <div class="w-full h-full flex opacity-50">
1801
+ <h1 class="text-white m-auto">Select a virtual file to inspect</h1>
1802
+ </div>
1803
+ `;
1804
+ event.res.headers.set("Content-Type", "text/html; charset=utf-8");
1805
+ return (
1806
+ /* html */
1807
+ `
1808
+ <!doctype html>
1809
+ <html>
1810
+ <head>
1811
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@unocss/reset/tailwind.min.css" />
1812
+ <link rel="stylesheet" data-name="vs/editor/editor.main" href="${vsUrl}/editor/editor.main.min.css">
1813
+ <script src="https://cdn.jsdelivr.net/npm/@unocss/runtime"><\/script>
1814
+ <style>
1815
+ html {
1816
+ background: #1E1E1E;
1817
+ color: white;
1818
+ }
1819
+ [un-cloak] {
1820
+ display: none;
1821
+ }
1822
+ </style>
1823
+ </head>
1824
+ <body class="bg-[#1E1E1E]">
1825
+ <div un-cloak class="h-screen grid grid-cols-[300px_1fr]">
1826
+ ${files}
1827
+ ${file}
1828
+ </div>
1829
+ </body>
1830
+ </html>`
1831
+ );
1832
+ });
1833
+ }
1834
+ const monacoVersion = "0.30.0";
1835
+ const monacoUrl = `https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/${monacoVersion}/min`;
1836
+ const vsUrl = `${monacoUrl}/vs`;
1837
+ const editorTemplate = (options) => `
1838
+ <div id="editor" class="min-h-screen w-full h-full"></div>
1839
+ <script src="${vsUrl}/loader.min.js"><\/script>
1840
+ <script>
1841
+ require.config({ paths: { vs: '${vsUrl}' } })
1842
+
1843
+ const proxy = URL.createObjectURL(new Blob([\`
1844
+ self.MonacoEnvironment = { baseUrl: '${monacoUrl}' }
1845
+ importScripts('${vsUrl}/base/worker/workerMain.min.js')
1846
+ \`], { type: 'text/javascript' }))
1847
+ window.MonacoEnvironment = { getWorkerUrl: () => proxy }
1848
+
1849
+ setTimeout(() => {
1850
+ require(['vs/editor/editor.main'], function () {
1851
+ monaco.editor.create(document.getElementById('editor'), ${JSON.stringify(
1852
+ options
1853
+ )})
1854
+ })
1855
+ }, 0);
1856
+ <\/script>
1857
+ `;
1858
+
1859
+ function defineNitroErrorHandler(handler) {
1860
+ return handler;
1861
+ }
1862
+
1863
+ const devErrorHandler = defineNitroErrorHandler(
1864
+ async function defaultNitroErrorHandler(error, event) {
1865
+ const res = await defaultHandler(error, event);
1866
+ return new FastResponse(
1867
+ typeof res.body === "string" ? res.body : JSON.stringify(res.body, null, 2),
1868
+ res
1869
+ );
1870
+ }
1871
+ );
1872
+ async function defaultHandler(error, event, opts) {
1873
+ const isSensitive = error.unhandled;
1874
+ const status = error.status || 500;
1875
+ const url = getRequestURL(event, { xForwardedHost: true, xForwardedProto: true });
1876
+ if (status === 404) {
1877
+ const baseURL = import.meta.baseURL || "/";
1878
+ if (/^\/[^/]/.test(baseURL) && !url.pathname.startsWith(baseURL)) {
1879
+ const redirectTo = `${baseURL}${url.pathname.slice(1)}${url.search}`;
1880
+ return {
1881
+ status: 302,
1882
+ statusText: "Found",
1883
+ headers: { location: redirectTo },
1884
+ body: `Redirecting...`
1885
+ };
1886
+ }
1887
+ }
1888
+ await loadStackTrace(error).catch(consola.error);
1889
+ const youch = new Youch();
1890
+ if (isSensitive && !opts?.silent) {
1891
+ const tags = [error.unhandled && "[unhandled]"].filter(Boolean).join(" ");
1892
+ const ansiError = await (await youch.toANSI(error)).replaceAll(process.cwd(), ".");
1893
+ consola.error(
1894
+ `[request error] ${tags} [${event.req.method}] ${url}
1895
+
1896
+ `,
1897
+ ansiError
1898
+ );
1899
+ }
1900
+ const useJSON = opts?.json || !event.req.headers.get("accept")?.includes("text/html");
1901
+ const headers = {
1902
+ "content-type": useJSON ? "application/json" : "text/html",
1903
+ // Prevent browser from guessing the MIME types of resources.
1904
+ "x-content-type-options": "nosniff",
1905
+ // Prevent error page from being embedded in an iframe
1906
+ "x-frame-options": "DENY",
1907
+ // Prevent browsers from sending the Referer header
1908
+ "referrer-policy": "no-referrer",
1909
+ // Disable the execution of any js
1910
+ "content-security-policy": "script-src 'self' 'unsafe-inline'; object-src 'none'; base-uri 'self';"
1911
+ };
1912
+ if (status === 404 || !event.res.headers.has("cache-control")) {
1913
+ headers["cache-control"] = "no-cache";
1914
+ }
1915
+ const body = useJSON ? {
1916
+ error: true,
1917
+ url,
1918
+ status,
1919
+ statusText: error.statusText,
1920
+ message: error.message,
1921
+ data: error.data,
1922
+ stack: error.stack?.split("\n").map((line) => line.trim())
1923
+ } : await youch.toHTML(error, {
1924
+ request: {
1925
+ url: url.href,
1926
+ method: event.req.method,
1927
+ headers: Object.fromEntries(event.req.headers.entries())
1928
+ }
1929
+ });
1930
+ return {
1931
+ status,
1932
+ statusText: error.statusText,
1933
+ headers,
1934
+ body
1935
+ };
1936
+ }
1937
+ async function loadStackTrace(error) {
1938
+ if (!(error instanceof Error)) {
1939
+ return;
1940
+ }
1941
+ const parsed = await new ErrorParser().defineSourceLoader(sourceLoader).parse(error);
1942
+ const stack = error.message + "\n" + parsed.frames.map((frame) => fmtFrame(frame)).join("\n");
1943
+ Object.defineProperty(error, "stack", { value: stack });
1944
+ if (error.cause) {
1945
+ await loadStackTrace(error.cause).catch(consola.error);
1946
+ }
1947
+ }
1948
+ async function sourceLoader(frame) {
1949
+ if (!frame.fileName || frame.fileType !== "fs" || frame.type === "native") {
1950
+ return;
1951
+ }
1952
+ if (frame.type === "app") {
1953
+ const rawSourceMap = await readFile(`${frame.fileName}.map`, "utf8").catch(() => {
1954
+ });
1955
+ if (rawSourceMap) {
1956
+ const consumer = await new SourceMapConsumer(rawSourceMap);
1957
+ const originalPosition = consumer.originalPositionFor({ line: frame.lineNumber, column: frame.columnNumber });
1958
+ if (originalPosition.source && originalPosition.line) {
1959
+ frame.fileName = resolve$1(dirname(frame.fileName), originalPosition.source);
1960
+ frame.lineNumber = originalPosition.line;
1961
+ frame.columnNumber = originalPosition.column || 0;
1962
+ }
1963
+ }
1964
+ }
1965
+ const contents = await readFile(frame.fileName, "utf8").catch(() => {
1966
+ });
1967
+ return contents ? { contents } : void 0;
1968
+ }
1969
+ function fmtFrame(frame) {
1970
+ if (frame.type === "native") {
1971
+ return frame.raw;
1972
+ }
1973
+ const src = `${frame.fileName || ""}:${frame.lineNumber}:${frame.columnNumber})`;
1974
+ return frame.functionName ? `at ${frame.functionName} (${src}` : `at ${src}`;
1975
+ }
1976
+
1977
+ class NitroDevApp {
1978
+ nitro;
1979
+ fetch;
1980
+ constructor(nitro, catchAllHandler) {
1981
+ this.nitro = nitro;
1982
+ const app = this.#createApp(catchAllHandler);
1983
+ this.fetch = app.fetch.bind(app);
1984
+ }
1985
+ #createApp(catchAllHandler) {
1986
+ const app = new H3({
1987
+ debug: true,
1988
+ onError: async (error, event) => {
1989
+ const errorHandler = this.nitro.options.devErrorHandler || devErrorHandler;
1990
+ await loadStackTrace(error).catch(() => {
1991
+ });
1992
+ return errorHandler(error, event, {
1993
+ defaultHandler: defaultHandler
1994
+ });
1995
+ }
1996
+ });
1997
+ for (const h of this.nitro.options.devHandlers) {
1998
+ const handler = toEventHandler(h.handler);
1999
+ if (!handler) {
2000
+ this.nitro.logger.warn("Invalid dev handler:", h);
2001
+ continue;
2002
+ }
2003
+ if (h.middleware || !h.route) {
2004
+ if (h.route) {
2005
+ app.use(h.route, handler, { method: h.method });
2006
+ } else {
2007
+ app.use(handler, { method: h.method });
2008
+ }
2009
+ } else {
2010
+ app.on(h.method || "", h.route, handler, { meta: h.meta });
2011
+ }
2012
+ }
2013
+ app.get("/_vfs/**", createVFSHandler(this.nitro));
2014
+ for (const asset of this.nitro.options.publicAssets) {
2015
+ const assetRoute = joinURL(
2016
+ this.nitro.options.runtimeConfig.app.baseURL,
2017
+ asset.baseURL || "/",
2018
+ "**"
2019
+ );
2020
+ let handler = fromNodeHandler(
2021
+ // @ts-expect-error (HTTP2 types)
2022
+ serveStatic(asset.dir, { dotfiles: "allow" })
2023
+ );
2024
+ if (asset.baseURL?.length || 0 > 1) {
2025
+ handler = withBase$1(asset.baseURL, handler);
2026
+ }
2027
+ app.use(assetRoute, handler);
2028
+ }
2029
+ const routes = Object.keys(this.nitro.options.devProxy).sort().reverse();
2030
+ for (const route of routes) {
2031
+ let opts = this.nitro.options.devProxy[route];
2032
+ if (typeof opts === "string") {
2033
+ opts = { target: opts };
2034
+ }
2035
+ const proxy = createHTTPProxy(opts);
2036
+ app.all(route, proxy.handleEvent);
2037
+ }
2038
+ if (catchAllHandler) {
2039
+ app.all("/**", catchAllHandler);
2040
+ }
2041
+ return app;
2042
+ }
2043
+ }
2044
+
2045
+ function createDevServer(nitro) {
2046
+ return new NitroDevServer(nitro);
2047
+ }
2048
+ class NitroDevServer extends NitroDevApp {
2049
+ #entry;
2050
+ #workerData = {};
2051
+ #listeners = [];
2052
+ #watcher;
2053
+ #workers = [];
2054
+ #workerIdCtr = 0;
2055
+ #workerError;
2056
+ #building = true;
2057
+ // Assume initial build will start soon
2058
+ #buildError;
2059
+ #messageListeners = /* @__PURE__ */ new Set();
2060
+ constructor(nitro) {
2061
+ super(nitro, async (event) => {
2062
+ const worker = await this.#getWorker();
2063
+ if (!worker) {
2064
+ return this.#generateError();
2065
+ }
2066
+ return worker.fetch(event.req);
2067
+ });
2068
+ for (const key of Object.getOwnPropertyNames(NitroDevServer.prototype)) {
2069
+ const value = this[key];
2070
+ if (typeof value === "function" && key !== "constructor") {
2071
+ this[key] = value.bind(this);
2072
+ }
2073
+ }
2074
+ this.#entry = resolve(
2075
+ nitro.options.output.dir,
2076
+ nitro.options.output.serverDir,
2077
+ "index.mjs"
2078
+ );
2079
+ nitro.hooks.hook("close", () => this.close());
2080
+ nitro.hooks.hook("dev:start", () => {
2081
+ this.#building = true;
2082
+ this.#buildError = void 0;
2083
+ });
2084
+ nitro.hooks.hook("dev:reload", (payload) => {
2085
+ this.#buildError = void 0;
2086
+ this.#building = false;
2087
+ if (payload?.entry) {
2088
+ this.#entry = payload.entry;
2089
+ }
2090
+ if (payload?.workerData) {
2091
+ this.#workerData = payload.workerData;
2092
+ }
2093
+ this.reload();
2094
+ });
2095
+ nitro.hooks.hook("dev:error", (cause) => {
2096
+ this.#buildError = cause;
2097
+ this.#building = false;
2098
+ for (const worker of this.#workers) {
2099
+ worker.close();
2100
+ }
2101
+ });
2102
+ if (nitro.options.devServer.watch.length > 0) {
2103
+ const debouncedReload = debounce(() => this.reload());
2104
+ this.#watcher = watch(
2105
+ nitro.options.devServer.watch,
2106
+ nitro.options.watchOptions
2107
+ );
2108
+ this.#watcher.on("add", debouncedReload).on("change", debouncedReload);
2109
+ }
2110
+ }
2111
+ // #region Public Methods
2112
+ async upgrade(req, socket, head) {
2113
+ const worker = await this.#getWorker();
2114
+ if (!worker) {
2115
+ throw new HTTPError({
2116
+ status: 503,
2117
+ statusText: "No worker available."
2118
+ });
2119
+ }
2120
+ return worker.upgrade(req, socket, head);
2121
+ }
2122
+ listen(opts) {
2123
+ const server = serve({
2124
+ ...opts,
2125
+ fetch: this.fetch
2126
+ });
2127
+ this.#listeners.push(server);
2128
+ if (server.node?.server) {
2129
+ server.node.server.on(
2130
+ "upgrade",
2131
+ (req, sock, head) => this.upgrade(req, sock, head)
2132
+ );
2133
+ }
2134
+ return server;
2135
+ }
2136
+ async close() {
2137
+ await Promise.all(
2138
+ [
2139
+ Promise.all(this.#listeners.map((l) => l.close())).then(() => {
2140
+ this.#listeners = [];
2141
+ }),
2142
+ Promise.all(this.#workers.map((w) => w.close())).then(() => {
2143
+ this.#workers = [];
2144
+ }),
2145
+ Promise.resolve(this.#watcher?.close()).then(() => {
2146
+ this.#watcher = void 0;
2147
+ })
2148
+ ].map(
2149
+ (p) => p.catch((error) => {
2150
+ consola.error(error);
2151
+ })
2152
+ )
2153
+ );
2154
+ }
2155
+ reload() {
2156
+ for (const worker2 of this.#workers) {
2157
+ worker2.close();
2158
+ }
2159
+ const worker = new NodeDevWorker({
2160
+ name: `Nitro_${this.#workerIdCtr++}`,
2161
+ entry: this.#entry,
2162
+ data: {
2163
+ ...this.#workerData,
2164
+ globals: {
2165
+ __NITRO_RUNTIME_CONFIG__: this.nitro.options.runtimeConfig,
2166
+ ...this.#workerData.globals
2167
+ }
2168
+ },
2169
+ hooks: {
2170
+ onClose: (worker2, cause) => {
2171
+ this.#workerError = cause;
2172
+ const index = this.#workers.indexOf(worker2);
2173
+ if (index !== -1) {
2174
+ this.#workers.splice(index, 1);
2175
+ }
2176
+ },
2177
+ onReady: (worker2, addr) => {
2178
+ this.#writeBuildInfo(worker2, addr);
2179
+ }
2180
+ }
2181
+ });
2182
+ if (!worker.closed) {
2183
+ for (const listener of this.#messageListeners) {
2184
+ worker.onMessage(listener);
2185
+ }
2186
+ this.#workers.unshift(worker);
2187
+ }
2188
+ }
2189
+ sendMessage(message) {
2190
+ for (const worker of this.#workers) {
2191
+ if (!worker.closed) {
2192
+ worker.sendMessage(message);
2193
+ }
2194
+ }
2195
+ }
2196
+ onMessage(listener) {
2197
+ this.#messageListeners.add(listener);
2198
+ for (const worker of this.#workers) {
2199
+ worker.onMessage(listener);
2200
+ }
2201
+ }
2202
+ offMessage(listener) {
2203
+ this.#messageListeners.delete(listener);
2204
+ for (const worker of this.#workers) {
2205
+ worker.offMessage(listener);
2206
+ }
2207
+ }
2208
+ // #endregion
2209
+ // #region Private Methods
2210
+ #writeBuildInfo(_worker, addr) {
2211
+ const buildInfoPath = resolve(this.nitro.options.buildDir, "nitro.json");
2212
+ const buildInfo = {
2213
+ date: (/* @__PURE__ */ new Date()).toJSON(),
2214
+ preset: this.nitro.options.preset,
2215
+ framework: this.nitro.options.framework,
2216
+ versions: {
2217
+ nitro: version
2218
+ },
2219
+ dev: {
2220
+ pid: process.pid,
2221
+ workerAddress: addr
2222
+ }
2223
+ };
2224
+ writeFile$1(buildInfoPath, JSON.stringify(buildInfo, null, 2)).catch(
2225
+ (error) => {
2226
+ consola.error(error);
2227
+ }
2228
+ );
2229
+ }
2230
+ async #getWorker() {
2231
+ let retry = 0;
2232
+ const maxRetries = isTest || isCI ? 100 : 10;
2233
+ while (this.#building || ++retry < maxRetries) {
2234
+ if ((this.#workers.length === 0 || this.#buildError) && !this.#building) {
2235
+ return;
2236
+ }
2237
+ const activeWorker = this.#workers.find((w) => w.ready);
2238
+ if (activeWorker) {
2239
+ return activeWorker;
2240
+ }
2241
+ await new Promise((resolve2) => setTimeout(resolve2, 600));
2242
+ }
2243
+ }
2244
+ #generateError() {
2245
+ const error = this.#buildError || this.#workerError;
2246
+ if (error) {
2247
+ try {
2248
+ error.unhandled = false;
2249
+ let id = error.id || error.path;
2250
+ if (id) {
2251
+ const cause = error.errors?.[0];
2252
+ const loc = error.location || error.loc || cause?.location || cause?.loc;
2253
+ if (loc) {
2254
+ id += `:${loc.line}:${loc.column}`;
2255
+ }
2256
+ error.stack = (error.stack || "").replace(
2257
+ /(^\s*at\s+.+)/m,
2258
+ ` at ${id}
2259
+ $1`
2260
+ );
2261
+ }
2262
+ } catch {
2263
+ }
2264
+ return new HTTPError(error);
2265
+ }
2266
+ return new Response(
2267
+ JSON.stringify(
2268
+ {
2269
+ error: "Dev server is unavailable.",
2270
+ hint: "Please reload the page and check the console for errors if the issue persists."
2271
+ },
2272
+ null,
2273
+ 2
2274
+ ),
2275
+ {
2276
+ status: 503,
2277
+ statusText: "Dev server is unavailable",
2278
+ headers: {
2279
+ "Content-Type": "application/json",
2280
+ "Cache-Control": "no-store",
2281
+ Refresh: "3"
2282
+ }
2283
+ }
2284
+ );
2285
+ }
2286
+ // #endregion
2287
+ }
2288
+
2289
+ const getViteRollupConfig = (ctx) => {
2290
+ const nitro = ctx.nitro;
2291
+ const base = baseBuildConfig(nitro);
2292
+ const chunkNamePrefixes = [
2293
+ [nitro.options.buildDir, "build"],
2294
+ [base.buildServerDir, "app"],
2295
+ [runtimeDir, "nitro"],
2296
+ [base.presetsDir, "nitro"],
2297
+ ["\0nitro-wasm:", "wasm"],
2298
+ ["\0", "virtual"]
2299
+ ];
2300
+ function getChunkGroup(id) {
2301
+ if (id.startsWith(runtimeDir) || id.startsWith(base.presetsDir)) {
2302
+ return "nitro";
2303
+ }
2304
+ }
2305
+ let config = {
2306
+ input: nitro.options.entry,
2307
+ external: [...base.env.external],
2308
+ plugins: [
2309
+ ctx.pluginConfig.experimental?.virtualBundle && virtualBundlePlugin(ctx._serviceBundles),
2310
+ ...baseBuildPlugins(nitro, base),
2311
+ alias({ entries: base.aliases }),
2312
+ replace({
2313
+ delimiters: base.replaceDelimiters,
2314
+ preventAssignment: true,
2315
+ values: base.replacements
2316
+ }),
2317
+ inject(base.env.inject)
2318
+ ].filter(Boolean),
2319
+ treeshake: {
2320
+ moduleSideEffects(id) {
2321
+ const normalizedId = normalize(id);
2322
+ const idWithoutNodeModules = normalizedId.split("node_modules/").pop();
2323
+ if (!idWithoutNodeModules) {
2324
+ return false;
2325
+ }
2326
+ if (normalizedId.startsWith(runtimeDir) || idWithoutNodeModules.startsWith(runtimeDir)) {
2327
+ return true;
2328
+ }
2329
+ return nitro.options.moduleSideEffects.some(
2330
+ (m) => normalizedId.startsWith(m) || idWithoutNodeModules.startsWith(m)
2331
+ );
2332
+ }
2333
+ },
2334
+ output: {
2335
+ dir: nitro.options.output.serverDir,
2336
+ entryFileNames: "index.mjs",
2337
+ chunkFileNames(chunk) {
2338
+ const id = normalize(chunk.moduleIds.at(-1) || "");
2339
+ for (const [dir, name] of chunkNamePrefixes) {
2340
+ if (id.startsWith(dir)) {
2341
+ return `chunks/${name}/[name].mjs`;
2342
+ }
2343
+ }
2344
+ const routeHandler = nitro.options.handlers.find(
2345
+ (h) => id.startsWith(h.handler)
2346
+ ) || nitro.scannedHandlers.find((h) => id.startsWith(h.handler));
2347
+ if (routeHandler?.route) {
2348
+ const path = routeHandler.route.replace(/:([^/]+)/g, "_$1").replace(/\/[^/]+$/g, "") || "/";
2349
+ return `chunks/routes/${path}/[name].mjs`.replace(/\/+/g, "/");
2350
+ }
2351
+ const taskHandler = Object.entries(nitro.options.tasks).find(
2352
+ ([_, task]) => task.handler === id
2353
+ );
2354
+ if (taskHandler) {
2355
+ return `chunks/tasks/[name].mjs`;
2356
+ }
2357
+ return `chunks/_/[name].mjs`;
2358
+ },
2359
+ manualChunks(id) {
2360
+ return getChunkGroup(id);
2361
+ },
2362
+ inlineDynamicImports: nitro.options.inlineDynamicImports,
2363
+ format: "esm",
2364
+ exports: "auto",
2365
+ intro: "",
2366
+ outro: "",
2367
+ generatedCode: {
2368
+ constBindings: true
2369
+ },
2370
+ sanitizeFileName: sanitizeFilePath,
2371
+ sourcemapExcludeSources: true,
2372
+ sourcemapIgnoreList(relativePath) {
2373
+ return relativePath.includes("node_modules");
2374
+ }
2375
+ }
2376
+ };
2377
+ config = defu(nitro.options.rollupConfig, config);
2378
+ if (config.output.inlineDynamicImports) {
2379
+ delete config.output.manualChunks;
2380
+ }
2381
+ return { config, base };
2382
+ };
2383
+ function virtualBundlePlugin(bundles) {
2384
+ let _modules = null;
2385
+ const getModules = () => {
2386
+ if (_modules) {
2387
+ return _modules;
2388
+ }
2389
+ _modules = /* @__PURE__ */ new Map();
2390
+ for (const bundle of Object.values(bundles)) {
2391
+ for (const [fileName, content] of Object.entries(bundle)) {
2392
+ if (content.type === "chunk") {
2393
+ const virtualModule = {
2394
+ code: content.code,
2395
+ map: null
2396
+ };
2397
+ const maybeMap = bundle[`${fileName}.map`];
2398
+ if (maybeMap && maybeMap.type === "asset") {
2399
+ virtualModule.map = maybeMap.source;
2400
+ }
2401
+ _modules.set(fileName, virtualModule);
2402
+ _modules.set(resolve(fileName), virtualModule);
2403
+ }
2404
+ }
2405
+ }
2406
+ return _modules;
2407
+ };
2408
+ return {
2409
+ name: "virtual-bundle",
2410
+ resolveId(id, importer) {
2411
+ const modules = getModules();
2412
+ if (modules.has(id)) {
2413
+ return resolve(id);
2414
+ }
2415
+ if (importer) {
2416
+ const resolved = resolve(dirname$1(importer), id);
2417
+ if (modules.has(resolved)) {
2418
+ return resolved;
2419
+ }
2420
+ }
2421
+ return null;
2422
+ },
2423
+ load(id) {
2424
+ const modules = getModules();
2425
+ const m = modules.get(id);
2426
+ if (!m) {
2427
+ return null;
2428
+ }
2429
+ return m;
2430
+ }
2431
+ };
2432
+ }
2433
+
2434
+ const BuilderNames = {
2435
+ nitro: colors.magenta("Nitro"),
2436
+ client: colors.green("Client"),
2437
+ ssr: colors.blue("SSR")
2438
+ };
2439
+ async function buildEnvironments(ctx, builder) {
2440
+ const nitro = ctx.nitro;
2441
+ for (const [envName, env] of Object.entries(builder.environments)) {
2442
+ const fmtName = BuilderNames[envName] || (envName.length <= 3 ? envName.toUpperCase() : envName[0].toUpperCase() + envName.slice(1));
2443
+ if (envName === "nitro" || !env.config.build.rollupOptions.input || env.isBuilt) {
2444
+ if (!["nitro", "ssr", "client"].includes(envName)) {
2445
+ nitro.logger.info(
2446
+ env.isBuilt ? `Skipping ${fmtName} (already built)` : `Skipping ${fmtName} (no input defined)`
2447
+ );
2448
+ }
2449
+ continue;
2450
+ }
2451
+ if (!isTest && !isCI) console.log();
2452
+ nitro.logger.start(`Building [${fmtName}]`);
2453
+ await builder.build(env);
2454
+ }
2455
+ const nitroOptions = ctx.nitro.options;
2456
+ const clientInput = builder.environments.client?.config?.build?.rollupOptions?.input;
2457
+ if (nitroOptions.renderer?.template && nitroOptions.renderer?.template === clientInput) {
2458
+ const outputPath = resolve(
2459
+ nitroOptions.output.publicDir,
2460
+ basename(clientInput)
2461
+ );
2462
+ if (existsSync(outputPath)) {
2463
+ const html = await readFile(outputPath, "utf8").then(
2464
+ (r) => r.replace(
2465
+ "<!--ssr-outlet-->",
2466
+ `{{{ fetch($REQUEST, { viteEnv: "ssr" }) }}}`
2467
+ )
2468
+ );
2469
+ await rm(outputPath);
2470
+ const tmp = resolve(nitroOptions.buildDir, "vite/index.html");
2471
+ await mkdir(dirname$1(tmp), { recursive: true });
2472
+ await writeFile$1(tmp, html, "utf8");
2473
+ nitroOptions.renderer.template = tmp;
2474
+ }
2475
+ }
2476
+ await builder.writeAssetsManifest?.();
2477
+ if (!isTest && !isCI) console.log();
2478
+ const buildInfo = [
2479
+ ["preset", nitro.options.preset],
2480
+ ["compatibility", formatCompatibilityDate(nitro.options.compatibilityDate)]
2481
+ ].filter((e) => e[1]);
2482
+ nitro.logger.start(
2483
+ `Building [${BuilderNames.nitro}] ${colors.dim(`(${buildInfo.map(([k, v]) => `${k}: \`${v}\``).join(", ")})`)}`
2484
+ );
2485
+ await copyPublicAssets(nitro);
2486
+ await builder.build(builder.environments.nitro);
2487
+ await nitro.close();
2488
+ await nitro.hooks.callHook("compiled", nitro);
2489
+ await writeBuildInfo(nitro);
2490
+ const rOutput = relative(process.cwd(), nitro.options.output.dir);
2491
+ const rewriteRelativePaths = (input) => {
2492
+ return input.replace(/([\s:])\.\/(\S*)/g, `$1${rOutput}/$2`);
2493
+ };
2494
+ if (!isTest && !isCI) console.log();
2495
+ if (nitro.options.commands.preview) {
2496
+ nitro.logger.success(
2497
+ `You can preview this build using \`${rewriteRelativePaths(
2498
+ nitro.options.commands.preview
2499
+ )}\``
2500
+ );
2501
+ }
2502
+ if (nitro.options.commands.deploy) {
2503
+ nitro.logger.success(
2504
+ `You can deploy this build using \`${rewriteRelativePaths(
2505
+ nitro.options.commands.deploy
2506
+ )}\``
2507
+ );
2508
+ }
2509
+ }
2510
+ function prodSetup(ctx) {
2511
+ const services = ctx.pluginConfig.services || {};
2512
+ const serviceNames = Object.keys(services);
2513
+ const serviceEntries = serviceNames.map((name) => {
2514
+ let entry;
2515
+ if (ctx.pluginConfig.experimental?.virtualBundle) {
2516
+ entry = ctx._entryPoints[name];
2517
+ } else {
2518
+ entry = resolve(
2519
+ ctx.nitro.options.buildDir,
2520
+ "vite/services",
2521
+ name,
2522
+ ctx._entryPoints[name]
2523
+ );
2524
+ }
2525
+ return [name, entry];
2526
+ });
2527
+ return (
2528
+ /* js */
2529
+ `
2530
+ import { setupVite } from "${resolve(runtimeDir, "internal/vite/prod-setup.mjs")}";
2531
+
2532
+ const manifest = ${JSON.stringify(ctx._manifest || {})};
2533
+
2534
+ function lazyService(loader) {
2535
+ let promise, mod
2536
+ return {
2537
+ fetch(req) {
2538
+ if (mod) { return mod.fetch(req) }
2539
+ if (!promise) {
2540
+ promise = loader().then(_mod => (mod = _mod.default || _mod))
2541
+ }
2542
+ return promise.then(mod => mod.fetch(req))
2543
+ }
2544
+ }
2545
+ }
2546
+
2547
+ const services = {
2548
+ ${serviceEntries.map(
2549
+ ([name, entry]) => (
2550
+ /* js */
2551
+ `[${JSON.stringify(name)}]: lazyService(() => import(${JSON.stringify(entry)}))`
2552
+ )
2553
+ ).join(",\n")}
2554
+ };
2555
+
2556
+ setupVite({ manifest, services });
2557
+ `
2558
+ );
2559
+ }
2560
+
2561
+ function createFetchableDevEnvironment(name, config, devServer, entry) {
2562
+ const transport = createTransport(name, devServer);
2563
+ const context = { hot: true, transport };
2564
+ return new FetchableDevEnvironment(name, config, context, devServer, entry);
2565
+ }
2566
+ class FetchableDevEnvironment extends DevEnvironment {
2567
+ devServer;
2568
+ constructor(name, config, context, devServer, entry) {
2569
+ super(name, config, context);
2570
+ this.devServer = devServer;
2571
+ this.devServer.sendMessage({
2572
+ type: "custom",
2573
+ event: "nitro:vite-env",
2574
+ data: { name, entry }
2575
+ });
2576
+ }
2577
+ async dispatchFetch(request) {
2578
+ return this.devServer.fetch(request);
2579
+ }
2580
+ async init(...args) {
2581
+ await this.devServer.init?.();
2582
+ return super.init(...args);
2583
+ }
2584
+ }
2585
+ function createTransport(name, hooks) {
2586
+ const listeners = /* @__PURE__ */ new WeakMap();
2587
+ return {
2588
+ send: (data) => hooks.sendMessage({ ...data, viteEnv: name }),
2589
+ on: (event, handler) => {
2590
+ if (event === "connection") return;
2591
+ const listener = (value) => {
2592
+ if (value?.type === "custom" && value.event === event && value.viteEnv === name) {
2593
+ handler(value.data, {
2594
+ send: (payload) => hooks.sendMessage({ ...payload, viteEnv: name })
2595
+ });
2596
+ }
2597
+ };
2598
+ listeners.set(handler, listener);
2599
+ hooks.onMessage(listener);
2600
+ },
2601
+ off: (event, handler) => {
2602
+ if (event === "connection") return;
2603
+ const listener = listeners.get(handler);
2604
+ if (listener) {
2605
+ hooks.offMessage(listener);
2606
+ listeners.delete(handler);
2607
+ }
2608
+ }
2609
+ };
2610
+ }
2611
+ async function configureViteDevServer(ctx, server) {
2612
+ const nitro = ctx.nitro;
2613
+ const nitroEnv = server.environments.nitro;
2614
+ const nitroConfigFile = nitro.options._c12.configFile;
2615
+ if (nitroConfigFile) {
2616
+ server.config.configFileDependencies.push(nitroConfigFile);
2617
+ }
2618
+ const reload = debounce(async () => {
2619
+ await scanHandlers(nitro);
2620
+ nitro.routing.sync();
2621
+ nitroEnv.moduleGraph.invalidateAll();
2622
+ nitroEnv.hot.send({ type: "full-reload" });
2623
+ });
2624
+ const scanDirs = nitro.options.scanDirs.flatMap((dir) => [
2625
+ join(dir, nitro.options.apiDir || "api"),
2626
+ join(dir, nitro.options.routesDir || "routes"),
2627
+ join(dir, "middleware"),
2628
+ join(dir, "plugins"),
2629
+ join(dir, "modules")
2630
+ ]);
2631
+ const watchReloadEvents = /* @__PURE__ */ new Set(["add", "addDir", "unlink", "unlinkDir"]);
2632
+ const scanDirsWatcher = watch(scanDirs, {
2633
+ ignoreInitial: true
2634
+ }).on("all", (event, path, stat) => {
2635
+ if (watchReloadEvents.has(event)) {
2636
+ reload();
2637
+ }
2638
+ });
2639
+ const srcDirWatcher = watch$1(
2640
+ nitro.options.srcDir,
2641
+ { persistent: false },
2642
+ (_event, filename) => {
2643
+ if (filename && /^server\.[mc]?[jt]sx?$/.test(filename)) {
2644
+ reload();
2645
+ }
2646
+ }
2647
+ );
2648
+ nitro.hooks.hook("close", () => {
2649
+ scanDirsWatcher.close();
2650
+ srcDirWatcher.close();
2651
+ });
2652
+ const hostIPC = {
2653
+ async transformHTML(html) {
2654
+ return server.transformIndexHtml("/", html).then(
2655
+ (r) => r.replace(
2656
+ "<!--ssr-outlet-->",
2657
+ `{{{ fetch($REQUEST, { viteEnv: "ssr" }) }}}`
2658
+ )
2659
+ );
2660
+ }
2661
+ };
2662
+ nitroEnv.devServer.onMessage(async (payload) => {
2663
+ if (payload.type === "custom" && payload.event === "nitro:vite-invoke") {
2664
+ const methodName = payload.data.name;
2665
+ const res = await hostIPC[methodName](payload.data.data).then((data) => ({ data })).catch((error) => ({ error }));
2666
+ nitroEnv.devServer.sendMessage({
2667
+ type: "custom",
2668
+ event: "nitro:vite-invoke-response",
2669
+ data: { id: payload.data.id, data: res }
2670
+ });
2671
+ }
2672
+ });
2673
+ const nitroDevMiddleware = async (nodeReq, nodeRes, next) => {
2674
+ if (/^\/@(?:vite|fs|id)\//.test(nodeReq.url) || nodeReq._nitroHandled) {
2675
+ return next();
2676
+ }
2677
+ nodeReq._nitroHandled = true;
2678
+ const req = new NodeRequest({ req: nodeReq, res: nodeRes });
2679
+ const devAppRes = await ctx.devApp.fetch(req);
2680
+ if (nodeRes.writableEnded || nodeRes.headersSent) {
2681
+ return;
2682
+ }
2683
+ if (devAppRes.status !== 404) {
2684
+ return await sendNodeResponse(nodeRes, devAppRes);
2685
+ }
2686
+ const envRes = await nitroEnv.dispatchFetch(req);
2687
+ if (nodeRes.writableEnded || nodeRes.headersSent) {
2688
+ return;
2689
+ }
2690
+ if (envRes.status !== 404) {
2691
+ return await sendNodeResponse(nodeRes, envRes);
2692
+ }
2693
+ return next();
2694
+ };
2695
+ server.middlewares.use(function nitroDevMiddlewarePre(req, res, next) {
2696
+ const fetchDest = req.headers["sec-fetch-dest"];
2697
+ if (fetchDest) {
2698
+ res.setHeader("vary", "sec-fetch-dest");
2699
+ }
2700
+ const ext = (req.url || "").match(/\.([a-z0-9]+)(?:[?#]|$)/i)?.[1] || "";
2701
+ if (!ext && (!fetchDest || /^(document|iframe|frame|empty)$/.test(fetchDest))) {
2702
+ nitroDevMiddleware(req, res, next);
2703
+ } else {
2704
+ next();
2705
+ }
2706
+ });
2707
+ return () => {
2708
+ server.middlewares.use(nitroDevMiddleware);
2709
+ };
2710
+ }
2711
+
2712
+ function createDevWorker(ctx) {
2713
+ return new NodeDevWorker({
2714
+ name: "nitro-vite",
2715
+ entry: resolve$1(runtimeDir, "internal/vite/dev-worker.mjs"),
2716
+ hooks: {},
2717
+ data: {
2718
+ server: true,
2719
+ globals: {
2720
+ __NITRO_RUNTIME_CONFIG__: ctx.nitro.options.runtimeConfig
2721
+ }
2722
+ }
2723
+ });
2724
+ }
2725
+ function createNitroEnvironment(ctx) {
2726
+ return {
2727
+ consumer: "server",
2728
+ build: {
2729
+ rollupOptions: ctx.rollupConfig.config,
2730
+ minify: ctx.nitro.options.minify,
2731
+ emptyOutDir: false,
2732
+ commonjsOptions: {
2733
+ strictRequires: "auto",
2734
+ // TODO: set to true (default) in v3
2735
+ esmExternals: (id) => !id.startsWith("unenv/"),
2736
+ requireReturnsDefault: "auto",
2737
+ ...ctx.nitro.options.commonJS
2738
+ }
2739
+ },
2740
+ resolve: {
2741
+ noExternal: ctx.nitro.options.dev ? (
2742
+ // Workaround for dev: external dependencies are not resolvable with respect to nodeModulePaths
2743
+ new RegExp(runtimeDependencies.join("|"))
2744
+ ) : void 0,
2745
+ conditions: ctx.nitro.options.exportConditions,
2746
+ externalConditions: ctx.nitro.options.exportConditions
2747
+ },
2748
+ dev: {
2749
+ createEnvironment: (envName, envConfig) => createFetchableDevEnvironment(
2750
+ envName,
2751
+ envConfig,
2752
+ ctx.devWorker,
2753
+ resolve$1(runtimeDir, "internal/vite/dev-entry.mjs")
2754
+ )
2755
+ }
2756
+ };
2757
+ }
2758
+ function createServiceEnvironment(ctx, name, serviceConfig) {
2759
+ return {
2760
+ consumer: "server",
2761
+ build: {
2762
+ rollupOptions: { input: serviceConfig.entry },
2763
+ minify: ctx.nitro.options.minify,
2764
+ outDir: join$1(ctx.nitro.options.buildDir, "vite", "services", name),
2765
+ emptyOutDir: true
2766
+ },
2767
+ resolve: {
2768
+ conditions: ctx.nitro.options.exportConditions,
2769
+ externalConditions: ctx.nitro.options.exportConditions
2770
+ },
2771
+ dev: {
2772
+ createEnvironment: (envName, envConfig) => createFetchableDevEnvironment(
2773
+ envName,
2774
+ envConfig,
2775
+ ctx.devWorker,
2776
+ tryResolve(serviceConfig.entry)
2777
+ )
2778
+ }
2779
+ };
2780
+ }
2781
+ function createServiceEnvironments(ctx) {
2782
+ return Object.fromEntries(
2783
+ Object.entries(ctx.pluginConfig.services || {}).map(([name, config]) => [
2784
+ name,
2785
+ createServiceEnvironment(ctx, name, config)
2786
+ ])
2787
+ );
2788
+ }
2789
+ function tryResolve(id) {
2790
+ if (/^[~#/\0]/.test(id) || isAbsolute(id)) {
2791
+ return id;
2792
+ }
2793
+ const resolved = resolveModulePath(id, {
2794
+ suffixes: ["", "/index"],
2795
+ extensions: ["", ".ts", ".mjs", ".cjs", ".js", ".mts", ".cts"],
2796
+ try: true
2797
+ });
2798
+ return resolved || id;
2799
+ }
2800
+
2801
+ function nitroPreviewPlugin(ctx) {
2802
+ return {
2803
+ name: "nitro:preview",
2804
+ apply: (_config, configEnv) => !!configEnv.isPreview,
2805
+ config(config) {
2806
+ return {
2807
+ preview: {
2808
+ port: config.preview?.port || 3e3
2809
+ }
2810
+ };
2811
+ },
2812
+ async configurePreviewServer(server) {
2813
+ const buildInfoPath = resolve(
2814
+ server.config.root,
2815
+ "node_modules/.nitro/last-build",
2816
+ "nitro.json"
2817
+ );
2818
+ if (!existsSync(buildInfoPath)) {
2819
+ console.warn(
2820
+ `[nitro] No build found. Please build your project before previewing.`
2821
+ );
2822
+ return;
2823
+ }
2824
+ const realBuildDir = await readlink("node_modules/.nitro/last-build");
2825
+ const buildInfo = JSON.parse(
2826
+ await readFile(buildInfoPath, "utf8")
2827
+ );
2828
+ const info = [
2829
+ ["Build Directory:", prettyPath(realBuildDir)],
2830
+ ["Date:", buildInfo.date && new Date(buildInfo.date).toLocaleString()],
2831
+ ["Nitro Version:", buildInfo.versions.nitro],
2832
+ ["Nitro Preset:", buildInfo.preset],
2833
+ buildInfo.framework?.name !== "nitro" && [
2834
+ "Framework:",
2835
+ buildInfo.framework?.name + (buildInfo.framework?.version ? ` (v${buildInfo.framework.version})` : "")
2836
+ ]
2837
+ ].filter((i) => i && i[1]);
2838
+ consola.box({
2839
+ title: " [Build Info] ",
2840
+ message: info.map((i) => `- ${i[0]} ${i[1]}`).join("\n")
2841
+ });
2842
+ if (!buildInfo.commands?.preview) {
2843
+ consola.warn("[nitro] No preview command found for this preset..");
2844
+ return;
2845
+ }
2846
+ const randomPort = await getRandomPort();
2847
+ consola.info(`Spawning preview server...`);
2848
+ const [command, ...args] = buildInfo.commands.preview.split(" ");
2849
+ let child;
2850
+ consola.info(buildInfo.commands?.preview);
2851
+ child = spawn(command, args, {
2852
+ stdio: "inherit",
2853
+ cwd: realBuildDir,
2854
+ env: {
2855
+ ...process.env,
2856
+ PORT: String(randomPort)
2857
+ }
2858
+ });
2859
+ process.on("exit", () => {
2860
+ child?.kill();
2861
+ child = void 0;
2862
+ });
2863
+ child.on("exit", (code) => {
2864
+ if (code && code !== 0) {
2865
+ consola.error(`[nitro] Preview server exited with code ${code}`);
2866
+ }
2867
+ });
2868
+ const proxy = createProxyServer({
2869
+ target: `http://localhost:${randomPort}`
2870
+ });
2871
+ server.middlewares.use((req, res, next) => {
2872
+ if (child && !child.killed) {
2873
+ proxy.web(req, res).catch(next);
2874
+ } else {
2875
+ res.end(`Nitro preview server is not running.`);
2876
+ }
2877
+ });
2878
+ }
2879
+ };
2880
+ }
2881
+
2882
+ const DEFAULT_EXTENSIONS = [".ts", ".js", ".mts", ".mjs", ".tsx", ".jsx"];
2883
+ const debug = process.env.NITRO_DEBUG ? (...args) => console.log("[nitro]", ...args) : () => {
2884
+ };
2885
+ function nitro(pluginConfig = {}) {
2886
+ const ctx = createContext(pluginConfig);
2887
+ return [
2888
+ nitroInit(ctx),
2889
+ nitroEnv(ctx),
2890
+ nitroMain(ctx),
2891
+ nitroPrepare(ctx),
2892
+ nitroService(ctx),
2893
+ nitroPreviewPlugin(),
2894
+ pluginConfig.experimental?.assetsImport !== false && assetsPlugin({
2895
+ experimental: {
2896
+ // See https://github.com/hi-ogawa/vite-plugins/pull/1289
2897
+ clientBuildFallback: false
2898
+ }
2899
+ })
2900
+ ];
2901
+ }
2902
+ function nitroInit(ctx) {
2903
+ return {
2904
+ name: "nitro:init",
2905
+ sharedDuringBuild: true,
2906
+ apply: (_config, configEnv) => !configEnv.isPreview,
2907
+ async config(config, configEnv) {
2908
+ if (!ctx._initialized) {
2909
+ debug("[init] Initializing nitro");
2910
+ ctx._initialized = true;
2911
+ await setupNitroContext(ctx, configEnv, config);
2912
+ }
2913
+ },
2914
+ applyToEnvironment(env) {
2915
+ if (env.name === "nitro" && ctx.nitro?.options.dev) {
2916
+ debug("[init] Adding rollup plugins for dev");
2917
+ return [...ctx.rollupConfig?.config.plugins || []];
2918
+ }
2919
+ }
2920
+ };
2921
+ }
2922
+ function nitroEnv(ctx) {
2923
+ return {
2924
+ name: "nitro:env",
2925
+ sharedDuringBuild: true,
2926
+ apply: (_config, configEnv) => !configEnv.isPreview,
2927
+ async config(userConfig, _configEnv) {
2928
+ debug("[env] Extending config (environments)");
2929
+ const environments = {
2930
+ ...createServiceEnvironments(ctx),
2931
+ nitro: createNitroEnvironment(ctx)
2932
+ };
2933
+ environments.client = {
2934
+ consumer: userConfig.environments?.client?.consumer ?? "client",
2935
+ build: {
2936
+ rollupOptions: {
2937
+ input: userConfig.environments?.client?.build?.rollupOptions?.input ?? useNitro(ctx).options.renderer?.template
2938
+ }
2939
+ }
2940
+ };
2941
+ debug("[env] Environments:", Object.keys(environments).join(", "));
2942
+ return {
2943
+ environments
2944
+ };
2945
+ },
2946
+ configEnvironment(name, config) {
2947
+ if (config.consumer === "client") {
2948
+ debug(
2949
+ "[env] Configuring client environment",
2950
+ name === "client" ? "" : ` (${name})`
2951
+ );
2952
+ config.build.emptyOutDir = false;
2953
+ config.build.outDir = useNitro(ctx).options.output.publicDir;
2954
+ } else {
2955
+ if (ctx.pluginConfig.experimental?.virtualBundle && name in (ctx.pluginConfig.services || {})) {
2956
+ debug("[env] Configuring service environment for virtual:", name);
2957
+ config.build ??= {};
2958
+ config.build.write = config.build.write ?? false;
2959
+ }
2960
+ }
2961
+ }
2962
+ };
2963
+ }
2964
+ function nitroMain(ctx) {
2965
+ return {
2966
+ name: "nitro:main",
2967
+ sharedDuringBuild: true,
2968
+ apply: (_config, configEnv) => !configEnv.isPreview,
2969
+ async config(userConfig, _configEnv) {
2970
+ debug("[main] Extending config (appType, resolve, server)");
2971
+ if (!ctx.rollupConfig) {
2972
+ throw new Error("Nitro rollup config is not initialized yet.");
2973
+ }
2974
+ return {
2975
+ appType: userConfig.appType || "custom",
2976
+ resolve: {
2977
+ // TODO: environment specific aliases not working
2978
+ // https://github.com/vitejs/vite/pull/17583 (seems not effective)
2979
+ alias: ctx.rollupConfig.base.aliases
2980
+ },
2981
+ builder: {
2982
+ sharedConfigBuild: true
2983
+ },
2984
+ server: {
2985
+ port: Number.parseInt(process.env.PORT || "") || userConfig.server?.port || useNitro(ctx).options.devServer?.port || 3e3
2986
+ }
2987
+ };
2988
+ },
2989
+ configResolved(config) {
2990
+ if (config.command === "build") {
2991
+ debug("[main] Inferring caching routes");
2992
+ for (const env of Object.values(config.environments)) {
2993
+ if (env.consumer === "client") {
2994
+ const rule = ctx.nitro.options.routeRules[`/${env.build.assetsDir}/**`] ??= {};
2995
+ if (!rule.headers?.["cache-control"]) {
2996
+ rule.headers = {
2997
+ ...rule.headers,
2998
+ "cache-control": `public, max-age=31536000, immutable`
2999
+ };
3000
+ }
3001
+ }
3002
+ }
3003
+ }
3004
+ debug("[main] Syncing nitro routes");
3005
+ ctx.nitro.routing.sync();
3006
+ },
3007
+ buildApp: {
3008
+ order: "post",
3009
+ handler(builder) {
3010
+ debug("[main] Building environments");
3011
+ return buildEnvironments(ctx, builder);
3012
+ }
3013
+ },
3014
+ generateBundle: {
3015
+ handler(_options, bundle) {
3016
+ const environment = this.environment;
3017
+ debug(
3018
+ "[main] Generating manifest and entry points for environment:",
3019
+ environment.name
3020
+ );
3021
+ const { root } = environment.config;
3022
+ const services = ctx.pluginConfig.services || {};
3023
+ const serviceNames = Object.keys(services);
3024
+ const isRegisteredService = serviceNames.includes(environment.name);
3025
+ let entryFile;
3026
+ for (const [_name, file] of Object.entries(bundle)) {
3027
+ if (file.type === "chunk") {
3028
+ if (isRegisteredService && file.isEntry) {
3029
+ if (entryFile === void 0) {
3030
+ entryFile = file.fileName;
3031
+ } else {
3032
+ this.warn(
3033
+ `Multiple entry points found for service "${environment.name}"`
3034
+ );
3035
+ }
3036
+ }
3037
+ const filteredModuleIds = file.moduleIds.filter(
3038
+ (id) => id.startsWith(root)
3039
+ );
3040
+ for (const id of filteredModuleIds) {
3041
+ const originalFile = relative(root, id);
3042
+ ctx._manifest[originalFile] = { file: file.fileName };
3043
+ }
3044
+ }
3045
+ }
3046
+ if (isRegisteredService) {
3047
+ if (entryFile === void 0) {
3048
+ this.error(
3049
+ `No entry point found for service "${this.environment.name}".`
3050
+ );
3051
+ }
3052
+ ctx._entryPoints[this.environment.name] = entryFile;
3053
+ ctx._serviceBundles[this.environment.name] = bundle;
3054
+ }
3055
+ }
3056
+ },
3057
+ configureServer: (server) => {
3058
+ debug("[main] Configuring dev server");
3059
+ return configureViteDevServer(ctx, server);
3060
+ }
3061
+ };
3062
+ }
3063
+ function nitroPrepare(ctx) {
3064
+ return {
3065
+ name: "nitro:prepare",
3066
+ sharedDuringBuild: true,
3067
+ applyToEnvironment: (env) => env.name === "nitro",
3068
+ buildApp: {
3069
+ // Clean the output directory before any environment is built
3070
+ order: "pre",
3071
+ async handler() {
3072
+ debug("[prepare] Preparing output directory");
3073
+ const nitro2 = ctx.nitro;
3074
+ await prepare(nitro2);
3075
+ }
3076
+ }
3077
+ };
3078
+ }
3079
+ function nitroService(ctx) {
3080
+ return {
3081
+ name: "nitro:service",
3082
+ enforce: "pre",
3083
+ sharedDuringBuild: true,
3084
+ applyToEnvironment: (env) => env.name === "nitro",
3085
+ resolveId: {
3086
+ async handler(id, importer, options) {
3087
+ if (id === "#nitro-vite-setup") {
3088
+ return { id, moduleSideEffects: true };
3089
+ }
3090
+ if (id === "#nitro-vite-services") {
3091
+ return id;
3092
+ }
3093
+ if (runtimeDependencies.some(
3094
+ (dep) => id === dep || id.startsWith(`${dep}/`)
3095
+ )) {
3096
+ const resolved = await this.resolve(id, importer, {
3097
+ ...options,
3098
+ skipSelf: true
3099
+ });
3100
+ return resolved || resolveModulePath(id, {
3101
+ from: ctx.nitro.options.nodeModulesDirs,
3102
+ conditions: ctx.nitro.options.exportConditions,
3103
+ try: true
3104
+ });
3105
+ }
3106
+ if (importer?.startsWith("\0virtual:#nitro-internal-virtual")) {
3107
+ const internalRes = await this.resolve(id, import.meta.url, {
3108
+ ...options,
3109
+ custom: { ...options.custom, skipNoExternals: true }
3110
+ });
3111
+ if (internalRes) {
3112
+ return internalRes;
3113
+ }
3114
+ const resolvedFromRoot = await this.resolve(
3115
+ id,
3116
+ ctx.nitro.options.rootDir,
3117
+ { ...options, custom: { ...options.custom, skipNoExternals: true } }
3118
+ );
3119
+ if (resolvedFromRoot) {
3120
+ return resolvedFromRoot;
3121
+ }
3122
+ const ids = [id];
3123
+ if (!/^[./@#]/.test(id)) {
3124
+ ids.push(`./${id}`);
3125
+ }
3126
+ for (const _id of ids) {
3127
+ const resolved = resolveModulePath(_id, {
3128
+ from: process.cwd(),
3129
+ extensions: DEFAULT_EXTENSIONS,
3130
+ suffixes: ["", "/index"],
3131
+ try: true
3132
+ });
3133
+ if (resolved) {
3134
+ return resolved;
3135
+ }
3136
+ }
3137
+ }
3138
+ }
3139
+ },
3140
+ load: {
3141
+ async handler(id) {
3142
+ if (id === "#nitro-vite-setup") {
3143
+ return prodSetup(ctx);
3144
+ }
3145
+ }
3146
+ }
3147
+ };
3148
+ }
3149
+ function createContext(pluginConfig) {
3150
+ return {
3151
+ pluginConfig,
3152
+ _entryPoints: {},
3153
+ _manifest: {},
3154
+ _serviceBundles: {}
3155
+ };
3156
+ }
3157
+ function useNitro(ctx) {
3158
+ if (!ctx.nitro) {
3159
+ throw new Error("Nitro instance is not initialized yet.");
3160
+ }
3161
+ return ctx.nitro;
3162
+ }
3163
+ async function setupNitroContext(ctx, configEnv, userConfig) {
3164
+ ctx.nitro = ctx.pluginConfig._nitro || await createNitro({
3165
+ dev: configEnv.mode === "development",
3166
+ rootDir: userConfig.root,
3167
+ ...defu(ctx.pluginConfig.config, userConfig.nitro)
3168
+ });
3169
+ if (!ctx.pluginConfig.services?.ssr) {
3170
+ ctx.pluginConfig.services ??= {};
3171
+ if (userConfig.environments?.ssr === void 0) {
3172
+ const ssrEntry = resolveModulePath("./entry-server", {
3173
+ from: ["", "app", "src"].flatMap(
3174
+ (d) => ctx.nitro.options.scanDirs.map((s) => join(s, d) + "/")
3175
+ ),
3176
+ extensions: DEFAULT_EXTENSIONS,
3177
+ try: true
3178
+ });
3179
+ if (ssrEntry) {
3180
+ ctx.pluginConfig.services.ssr = { entry: ssrEntry };
3181
+ ctx.nitro.logger.info(
3182
+ `Using \`${prettyPath(ssrEntry)}\` as vite ssr entry.`
3183
+ );
3184
+ }
3185
+ } else {
3186
+ let ssrEntry = getEntry(
3187
+ userConfig.environments.ssr.build?.rollupOptions?.input
3188
+ );
3189
+ if (typeof ssrEntry === "string") {
3190
+ ssrEntry = resolveModulePath(ssrEntry, {
3191
+ from: ctx.nitro.options.scanDirs,
3192
+ extensions: DEFAULT_EXTENSIONS,
3193
+ suffixes: ["", "/index"],
3194
+ try: true
3195
+ }) || ssrEntry;
3196
+ ctx.pluginConfig.services.ssr = { entry: ssrEntry };
3197
+ } else {
3198
+ throw new TypeError(`Invalid input type for SSR entry point.`);
3199
+ }
3200
+ }
3201
+ }
3202
+ if (!ctx.nitro.options.renderer?.entry && !ctx.nitro.options.renderer?.template && ctx.pluginConfig.services.ssr?.entry) {
3203
+ ctx.nitro.options.renderer ??= {};
3204
+ ctx.nitro.options.renderer.entry = resolve(
3205
+ runtimeDir,
3206
+ "internal/vite/ssr-renderer"
3207
+ );
3208
+ }
3209
+ const publicDistDir = ctx._publicDistDir = userConfig.build?.outDir || resolve(ctx.nitro.options.buildDir, "vite/public");
3210
+ ctx.nitro.options.publicAssets.push({
3211
+ dir: publicDistDir,
3212
+ maxAge: 0,
3213
+ baseURL: "/",
3214
+ fallthrough: true
3215
+ });
3216
+ if (!ctx.nitro.options.dev) {
3217
+ ctx.nitro.options.unenv.push({
3218
+ meta: { name: "nitro-vite" },
3219
+ polyfill: ["#nitro-vite-setup"]
3220
+ });
3221
+ }
3222
+ await ctx.nitro.hooks.callHook("build:before", ctx.nitro);
3223
+ ctx.rollupConfig = await getViteRollupConfig(ctx);
3224
+ await ctx.nitro.hooks.callHook(
3225
+ "rollup:before",
3226
+ ctx.nitro,
3227
+ ctx.rollupConfig.config
3228
+ );
3229
+ if (ctx.nitro.options.dev && !ctx.devWorker) {
3230
+ ctx.devWorker = createDevWorker(ctx);
3231
+ }
3232
+ if (ctx.nitro.options.dev && !ctx.devApp) {
3233
+ ctx.devApp = new NitroDevApp(ctx.nitro);
3234
+ }
3235
+ }
3236
+ function getEntry(input) {
3237
+ if (typeof input === "string") {
3238
+ return input;
3239
+ } else if (Array.isArray(input) && input.length > 0) {
3240
+ return input[0];
3241
+ } else if (input && "index" in input) {
3242
+ return input.index;
3243
+ }
3244
+ }
3245
+
3246
+ async function viteBuild(nitro$1) {
3247
+ if (nitro$1.options.dev) {
3248
+ throw new Error(
3249
+ "Nitro vite builder is not supported in development mode. Please use `vite dev` instead."
3250
+ );
3251
+ }
3252
+ const { createBuilder } = await import('vite');
3253
+ const builder = await createBuilder({
3254
+ base: nitro$1.options.rootDir,
3255
+ plugins: [await nitro({ _nitro: nitro$1 })],
3256
+ logLevel: isTest ? "warn" : void 0
3257
+ });
3258
+ await builder.buildApp();
3259
+ }
3260
+
3261
+ const build = {
3262
+ __proto__: null,
3263
+ viteBuild: viteBuild
3264
+ };
3265
+
3266
+ export { NitroDevServer as N, createDevServer as a, listTasks as b, createNitro as c, build as d, loadOptions as l, nitro as n, prerender as p, runTask as r };