nitro-nightly 4.0.0-20251030-122606-56e83836 → 4.0.0-20251030-135442-97badaa1

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.
package/dist/_dev.mjs CHANGED
@@ -555,7 +555,8 @@ var NitroDevServer = class NitroDevServer extends NitroDevApp {
555
555
  listen(opts) {
556
556
  const server = serve({
557
557
  ...opts,
558
- fetch: this.fetch
558
+ fetch: this.fetch,
559
+ gracefulShutdown: false
559
560
  });
560
561
  this.#listeners.push(server);
561
562
  if (server.node?.server) server.node.server.on("upgrade", (req, sock, head) => this.upgrade(req, sock, head));
package/dist/_presets.mjs CHANGED
@@ -890,15 +890,18 @@ const denoServer = defineNitroPreset({
890
890
  entry: "./deno/runtime/deno-server",
891
891
  serveStatic: true,
892
892
  exportConditions: ["deno"],
893
- commands: { preview: "deno task --config ./deno.json start" },
893
+ commands: { preview: "deno -A ./server/index.mjs" },
894
894
  rollupConfig: {
895
895
  external: (id) => id.startsWith("https://"),
896
896
  output: { hoistTransitiveImports: false }
897
897
  },
898
898
  hooks: { async compiled(nitro) {
899
- await writeFile$1(resolve$1(nitro.options.output.dir, "deno.json"), JSON.stringify({ tasks: { start: "deno run --allow-net --allow-read --allow-write --allow-env --unstable-byonm --unstable-node-globals ./server/index.mjs" } }, null, 2));
899
+ await writeFile$1(resolve$1(nitro.options.output.dir, "deno.json"), JSON.stringify({ tasks: { start: "deno run -A ./server/index.mjs" } }, null, 2));
900
900
  } }
901
- }, { name: "deno-server" });
901
+ }, {
902
+ aliases: ["deno"],
903
+ name: "deno-server"
904
+ });
902
905
  var preset_default$9 = [denoDeploy, denoServer];
903
906
 
904
907
  //#endregion
@@ -1268,7 +1271,10 @@ const nodeServer = defineNitroPreset({
1268
1271
  entry: "./node/runtime/node-server",
1269
1272
  serveStatic: true,
1270
1273
  commands: { preview: "node ./server/index.mjs" }
1271
- }, { name: "node-server" });
1274
+ }, {
1275
+ name: "node-server",
1276
+ aliases: ["node"]
1277
+ });
1272
1278
  const nodeMiddleware = defineNitroPreset({ entry: "./node/runtime/node-middleware" }, { name: "node-middleware" });
1273
1279
  const nodeCluster = defineNitroPreset({
1274
1280
  extends: "node-server",
@@ -1,14 +1,11 @@
1
1
  import "#nitro-internal-pollyfills";
2
2
  import { useNitroApp, useNitroHooks } from "nitro/runtime";
3
- import { trapUnhandledNodeErrors } from "nitro/runtime/internal";
4
3
  import { startScheduleRunner } from "nitro/runtime/internal";
5
4
  import { Server } from "node:http";
6
5
  import { parentPort, threadId } from "node:worker_threads";
7
6
  import wsAdapter from "crossws/adapters/node";
8
7
  import { toNodeHandler } from "srvx/node";
9
8
  import { getSocketAddress, isSocketSupported } from "get-port-please";
10
- // Trap unhandled errors
11
- trapUnhandledNodeErrors();
12
9
  // Listen for shutdown signal from runner
13
10
  parentPort?.on("message", (msg) => {
14
11
  if (msg && msg.event === "shutdown") {
@@ -1,7 +1,6 @@
1
1
  import "#nitro-internal-pollyfills";
2
2
  import consola from "consola";
3
3
  import { useNitroApp, useNitroHooks } from "nitro/runtime";
4
- import { trapUnhandledNodeErrors } from "nitro/runtime/internal";
5
4
  const nitroApp = useNitroApp();
6
5
  const nitroHooks = useNitroHooks();
7
6
  export const appFetch = nitroApp.request;
@@ -11,5 +10,3 @@ nitroHooks.hook("error", (error, context) => {
11
10
  consola.error(`[prerender error]`, `[${context.event.req.method}]`, `[${context.event.req.url}]`, error);
12
11
  }
13
12
  });
14
- // Trap unhandled errors
15
- trapUnhandledNodeErrors();
@@ -1,2 +1,3 @@
1
1
  import "#nitro-internal-pollyfills";
2
- export {};
2
+ declare const _default: {};
3
+ export default _default;
@@ -1,28 +1,25 @@
1
1
  import "#nitro-internal-pollyfills";
2
+ import { serve } from "srvx/bun";
2
3
  import { useNitroApp } from "nitro/runtime";
3
- import { startScheduleRunner } from "nitro/runtime/internal";
4
- import wsAdapter from "crossws/adapters/bun";
4
+ const port = Number.parseInt(process.env.NITRO_PORT || process.env.PORT || "") || 3e3;
5
+ const host = process.env.NITRO_HOST || process.env.HOST;
6
+ const cert = process.env.NITRO_SSL_CERT;
7
+ const key = process.env.NITRO_SSL_KEY;
8
+ // const socketPath = process.env.NITRO_UNIX_SOCKET; // TODO
9
+ // if (import.meta._websocket) // TODO
5
10
  const nitroApp = useNitroApp();
6
- const ws = import.meta._websocket ? wsAdapter(nitroApp.h3App.websocket) : undefined;
7
- // @ts-expect-error
8
- const server = Bun.serve({
9
- port: process.env.NITRO_PORT || process.env.PORT || 3e3,
10
- hostname: process.env.NITRO_HOST || process.env.HOST,
11
- websocket: import.meta._websocket ? ws.websocket : undefined,
12
- async fetch(bunReq, server) {
13
- // srvx compatibility
14
- const req = bunReq;
15
- req.runtime ??= { name: "bun" };
16
- req.runtime.bun ??= { server };
17
- // https://crossws.unjs.io/adapters/bun
18
- if (import.meta._websocket && req.headers.get("upgrade") === "websocket") {
19
- return ws.handleUpgrade(req, server);
20
- }
21
- return nitroApp.fetch(req);
22
- }
11
+ serve({
12
+ port,
13
+ hostname: host,
14
+ tls: cert && key ? {
15
+ cert,
16
+ key
17
+ } : undefined,
18
+ fetch: nitroApp.fetch
23
19
  });
24
- console.log(`Listening on ${server.url}...`);
25
20
  // Scheduled tasks
26
21
  if (import.meta._tasks) {
22
+ const { startScheduleRunner } = await import("nitro/runtime/internal");
27
23
  startScheduleRunner();
28
24
  }
25
+ export default {};
@@ -1,2 +1,4 @@
1
1
  import "#nitro-internal-pollyfills";
2
- export {};
2
+ declare global {
3
+ const Deno: typeof import("@deno/types").Deno;
4
+ }
@@ -1,7 +1,3 @@
1
1
  import "#nitro-internal-pollyfills";
2
- // TODO: Declare conflict with crossws
3
- declare global {
4
- const Deno: typeof import("@deno/types").Deno;
5
- }
6
2
  declare const _default: {};
7
3
  export default _default;
@@ -1,51 +1,25 @@
1
1
  import "#nitro-internal-pollyfills";
2
+ import { serve } from "srvx/deno";
2
3
  import { useNitroApp } from "nitro/runtime";
3
- import { useRuntimeConfig } from "nitro/runtime";
4
- import { startScheduleRunner } from "nitro/runtime/internal";
5
- import wsAdapter from "crossws/adapters/deno";
6
- import destr from "destr";
4
+ const port = Number.parseInt(process.env.NITRO_PORT || process.env.PORT || "") || 3e3;
5
+ const host = process.env.NITRO_HOST || process.env.HOST;
6
+ const cert = process.env.NITRO_SSL_CERT;
7
+ const key = process.env.NITRO_SSL_KEY;
8
+ // const socketPath = process.env.NITRO_UNIX_SOCKET; // TODO
7
9
  const nitroApp = useNitroApp();
8
- if (Deno.env.get("DEBUG")) {
9
- addEventListener("unhandledrejection", (event) => console.error("[unhandledRejection]", event.reason));
10
- addEventListener("error", (event) => console.error("[uncaughtException]", event.error));
11
- } else {
12
- addEventListener("unhandledrejection", (err) => console.error("[unhandledRejection] " + err));
13
- addEventListener("error", (event) => console.error("[uncaughtException] " + event.error));
14
- }
15
- // https://deno.land/api@v1.42.4?s=Deno.serve
16
- const serveOptions = {
17
- key: Deno.env.get("NITRO_SSL_KEY"),
18
- cert: Deno.env.get("NITRO_SSL_CERT"),
19
- port: destr(Deno.env.get("NITRO_PORT") || Deno.env.get("PORT")) || 3e3,
20
- hostname: Deno.env.get("NITRO_HOST") || Deno.env.get("HOST"),
21
- onListen: (opts) => {
22
- const baseURL = (useRuntimeConfig().app.baseURL || "").replace(/\/$/, "");
23
- const url = `${opts.hostname}:${opts.port}${baseURL}`;
24
- console.log(`Listening ${url}`);
25
- }
26
- };
27
- // https://github.com/nitrojs/nitro/pull/2373
28
- if (!serveOptions.key || !serveOptions.cert) {
29
- delete serveOptions.key;
30
- delete serveOptions.cert;
31
- }
32
- Deno.serve(serveOptions, handler);
33
- // Websocket support
34
- const ws = import.meta._websocket ? wsAdapter(nitroApp.h3App.websocket) : undefined;
35
- async function handler(denoReq, info) {
36
- // srvx compatibility
37
- const req = denoReq;
38
- req.runtime ??= { name: "deno" };
39
- req.runtime.deno ??= { info };
40
- // TODO: Support remoteAddr
41
- // https://crossws.unjs.io/adapters/deno
42
- if (import.meta._websocket && req.headers.get("upgrade") === "websocket") {
43
- return ws.handleUpgrade(req, info);
44
- }
45
- return nitroApp.fetch(req);
46
- }
10
+ // if (import.meta._websocket) // TODO
11
+ serve({
12
+ port,
13
+ hostname: host,
14
+ tls: cert && key ? {
15
+ cert,
16
+ key
17
+ } : undefined,
18
+ fetch: nitroApp.fetch
19
+ });
47
20
  // Scheduled tasks
48
21
  if (import.meta._tasks) {
22
+ const { startScheduleRunner } = await import("nitro/runtime/internal");
49
23
  startScheduleRunner();
50
24
  }
51
25
  export default {};
@@ -1,46 +1,9 @@
1
1
  import cluster from "node:cluster";
2
2
  import os from "node:os";
3
- import { getGracefulShutdownConfig, trapUnhandledNodeErrors } from "nitro/runtime/internal";
4
3
  function runMaster() {
5
4
  const numberOfWorkers = Number.parseInt(process.env.NITRO_CLUSTER_WORKERS || "") || (os.cpus().length > 0 ? os.cpus().length : 1);
6
5
  for (let i = 0; i < numberOfWorkers; i++) {
7
- cluster.fork();
8
- }
9
- // Restore worker on exit
10
- let isShuttingDown = false;
11
- cluster.on("exit", () => {
12
- if (!isShuttingDown) {
13
- cluster.fork();
14
- }
15
- });
16
- // Graceful shutdown
17
- const shutdownConfig = getGracefulShutdownConfig();
18
- if (!shutdownConfig.disabled) {
19
- async function onShutdown() {
20
- if (isShuttingDown) {
21
- return;
22
- }
23
- isShuttingDown = true;
24
- await new Promise((resolve) => {
25
- const timeout = setTimeout(() => {
26
- console.warn("Timeout reached for graceful shutdown. Forcing exit.");
27
- resolve();
28
- }, shutdownConfig.timeout);
29
- cluster.on("exit", () => {
30
- if (Object.values(cluster.workers || {}).every((w) => !w || w.isDead())) {
31
- clearTimeout(timeout);
32
- resolve();
33
- } else {}
34
- });
35
- });
36
- if (shutdownConfig.forceExit) {
37
- // eslint-disable-next-line unicorn/no-process-exit
38
- process.exit(0);
39
- }
40
- }
41
- for (const signal of shutdownConfig.signals) {
42
- process.once(signal, onShutdown);
43
- }
6
+ cluster.fork({ WORKER_ID: i + 1 });
44
7
  }
45
8
  }
46
9
  function runWorker() {
@@ -50,8 +13,6 @@ function runWorker() {
50
13
  process.exit(1);
51
14
  });
52
15
  }
53
- // Trap unhandled errors
54
- trapUnhandledNodeErrors();
55
16
  if (cluster.isPrimary) {
56
17
  runMaster();
57
18
  } else {
@@ -1,14 +1,12 @@
1
1
  import "#nitro-internal-pollyfills";
2
2
  import { toNodeHandler } from "srvx/node";
3
3
  import { useNitroApp } from "nitro/runtime";
4
- import { startScheduleRunner, trapUnhandledNodeErrors } from "nitro/runtime/internal";
4
+ import { startScheduleRunner } from "nitro/runtime/internal";
5
5
  const nitroApp = useNitroApp();
6
6
  export const middleware = toNodeHandler(nitroApp.fetch);
7
7
  // TODO
8
8
  /** @experimental */
9
9
  export const websocket = import.meta._websocket ? undefined : undefined;
10
- // Trap unhandled errors
11
- trapUnhandledNodeErrors();
12
10
  // Scheduled tasks
13
11
  if (import.meta._tasks) {
14
12
  startScheduleRunner();
@@ -1,54 +1,32 @@
1
1
  import "#nitro-internal-pollyfills";
2
- import { Server as HttpServer } from "node:http";
3
- import { Server as HttpsServer } from "node:https";
4
- import wsAdapter from "crossws/adapters/node";
5
- import destr from "destr";
6
- import { toNodeHandler } from "srvx/node";
7
- import { useNitroApp, useRuntimeConfig } from "nitro/runtime";
8
- import { setupGracefulShutdown, startScheduleRunner, trapUnhandledNodeErrors } from "nitro/runtime/internal";
2
+ import cluster from "node:cluster";
3
+ import { serve } from "srvx/node";
4
+ import { useNitroApp } from "nitro/runtime";
5
+ const port = Number.parseInt(process.env.NITRO_PORT || process.env.PORT || "") || 3e3;
6
+ const host = process.env.NITRO_HOST || process.env.HOST;
9
7
  const cert = process.env.NITRO_SSL_CERT;
10
8
  const key = process.env.NITRO_SSL_KEY;
9
+ // const socketPath = process.env.NITRO_UNIX_SOCKET; // TODO
10
+ const clusterId = cluster.isWorker && process.env.WORKER_ID;
11
+ if (clusterId) {
12
+ console.log(`Worker #${clusterId} started`);
13
+ }
14
+ // if (import.meta._websocket) // TODO
11
15
  const nitroApp = useNitroApp();
12
- const server = cert && key ? new HttpsServer({
13
- key,
14
- cert
15
- }, toNodeHandler(nitroApp.fetch)) : new HttpServer(toNodeHandler(nitroApp.fetch));
16
- const port = destr(process.env.NITRO_PORT || process.env.PORT) || 3e3;
17
- const host = process.env.NITRO_HOST || process.env.HOST;
18
- const path = process.env.NITRO_UNIX_SOCKET;
19
- // @ts-ignore
20
- const listener = server.listen(path ? { path } : {
16
+ const server = serve({
21
17
  port,
22
- host
23
- }, (err) => {
24
- if (err) {
25
- console.error(err);
26
- // eslint-disable-next-line unicorn/no-process-exit
27
- process.exit(1);
28
- }
29
- const protocol = cert && key ? "https" : "http";
30
- const addressInfo = listener.address();
31
- if (typeof addressInfo === "string") {
32
- console.log(`Listening on unix socket ${addressInfo}`);
33
- return;
34
- }
35
- const baseURL = (useRuntimeConfig().app.baseURL || "").replace(/\/$/, "");
36
- const url = `${protocol}://${addressInfo.family === "IPv6" ? `[${addressInfo.address}]` : addressInfo.address}:${addressInfo.port}${baseURL}`;
37
- console.log(`Listening on ${url}`);
18
+ hostname: host,
19
+ tls: cert && key ? {
20
+ cert,
21
+ key
22
+ } : undefined,
23
+ node: { reusePort: !!clusterId },
24
+ silent: clusterId ? clusterId !== "1" : undefined,
25
+ fetch: nitroApp.fetch
38
26
  });
39
- // Trap unhandled errors
40
- trapUnhandledNodeErrors();
41
- // Graceful shutdown
42
- setupGracefulShutdown(listener);
43
- // Websocket support
44
- // https://crossws.unjs.io/adapters/node
45
- if (import.meta._websocket) {
46
- // @ts-expect-error
47
- const { handleUpgrade } = wsAdapter(nitroApp.h3App.websocket);
48
- server.on("upgrade", handleUpgrade);
49
- }
50
27
  // Scheduled tasks
51
28
  if (import.meta._tasks) {
29
+ const { startScheduleRunner } = await import("nitro/runtime/internal");
52
30
  startScheduleRunner();
53
31
  }
54
32
  export default {};
@@ -1,5 +1,3 @@
1
1
  // Limited INTERNAL exports used by the presets runtime
2
2
  // Please don't use these in your project code!
3
- export { trapUnhandledNodeErrors } from "./utils.mjs";
4
3
  export { startScheduleRunner, runCronTasks } from "./task.mjs";
5
- export { getGracefulShutdownConfig, setupGracefulShutdown } from "./shutdown.mjs";
@@ -1,5 +1,3 @@
1
1
  // Limited INTERNAL exports used by the presets runtime
2
2
  // Please don't use these in your project code!
3
- export { trapUnhandledNodeErrors } from "./utils.mjs";
4
3
  export { startScheduleRunner, runCronTasks } from "./task.mjs";
5
- export { getGracefulShutdownConfig, setupGracefulShutdown } from "./shutdown.mjs";
@@ -1799,8 +1799,8 @@ interface PresetOptions {
1799
1799
  netlify?: NetlifyOptions;
1800
1800
  vercel?: VercelOptions;
1801
1801
  }
1802
- type PresetName = "alwaysdata" | "aws-amplify" | "aws-lambda" | "azure-swa" | "base-worker" | "bun" | "cleavr" | "cloudflare-dev" | "cloudflare-durable" | "cloudflare-module" | "cloudflare-pages" | "cloudflare-pages-static" | "deno-deploy" | "deno-server" | "digital-ocean" | "firebase-app-hosting" | "flight-control" | "genezio" | "github-pages" | "gitlab-pages" | "heroku" | "iis-handler" | "iis-node" | "koyeb" | "netlify" | "netlify-edge" | "netlify-static" | "nitro-dev" | "nitro-prerender" | "node-cluster" | "node-middleware" | "node-server" | "platform-sh" | "render-com" | "standard" | "static" | "stormkit" | "vercel" | "vercel-static" | "winterjs" | "zeabur" | "zeabur-static" | "zerops" | "zerops-static";
1803
- type PresetNameInput = "alwaysdata" | "aws-amplify" | "awsAmplify" | "aws_amplify" | "aws-lambda" | "awsLambda" | "aws_lambda" | "azure-swa" | "azureSwa" | "azure_swa" | "base-worker" | "baseWorker" | "base_worker" | "bun" | "cleavr" | "cloudflare-dev" | "cloudflareDev" | "cloudflare_dev" | "cloudflare-durable" | "cloudflareDurable" | "cloudflare_durable" | "cloudflare-module" | "cloudflareModule" | "cloudflare_module" | "cloudflare-pages" | "cloudflarePages" | "cloudflare_pages" | "cloudflare-pages-static" | "cloudflarePagesStatic" | "cloudflare_pages_static" | "deno-deploy" | "denoDeploy" | "deno_deploy" | "deno-server" | "denoServer" | "deno_server" | "digital-ocean" | "digitalOcean" | "digital_ocean" | "firebase-app-hosting" | "firebaseAppHosting" | "firebase_app_hosting" | "flight-control" | "flightControl" | "flight_control" | "genezio" | "github-pages" | "githubPages" | "github_pages" | "gitlab-pages" | "gitlabPages" | "gitlab_pages" | "heroku" | "iis-handler" | "iisHandler" | "iis_handler" | "iis-node" | "iisNode" | "iis_node" | "koyeb" | "netlify" | "netlify-edge" | "netlifyEdge" | "netlify_edge" | "netlify-static" | "netlifyStatic" | "netlify_static" | "nitro-dev" | "nitroDev" | "nitro_dev" | "nitro-prerender" | "nitroPrerender" | "nitro_prerender" | "node-cluster" | "nodeCluster" | "node_cluster" | "node-middleware" | "nodeMiddleware" | "node_middleware" | "node-server" | "nodeServer" | "node_server" | "platform-sh" | "platformSh" | "platform_sh" | "render-com" | "renderCom" | "render_com" | "standard" | "static" | "stormkit" | "vercel" | "vercel-static" | "vercelStatic" | "vercel_static" | "winterjs" | "zeabur" | "zeabur-static" | "zeaburStatic" | "zeabur_static" | "zerops" | "zerops-static" | "zeropsStatic" | "zerops_static" | (string & {});
1802
+ type PresetName = "alwaysdata" | "aws-amplify" | "aws-lambda" | "azure-swa" | "base-worker" | "bun" | "cleavr" | "cloudflare-dev" | "cloudflare-durable" | "cloudflare-module" | "cloudflare-pages" | "cloudflare-pages-static" | "deno" | "deno-deploy" | "deno-server" | "digital-ocean" | "firebase-app-hosting" | "flight-control" | "genezio" | "github-pages" | "gitlab-pages" | "heroku" | "iis-handler" | "iis-node" | "koyeb" | "netlify" | "netlify-edge" | "netlify-static" | "nitro-dev" | "nitro-prerender" | "node" | "node-cluster" | "node-middleware" | "node-server" | "platform-sh" | "render-com" | "standard" | "static" | "stormkit" | "vercel" | "vercel-static" | "winterjs" | "zeabur" | "zeabur-static" | "zerops" | "zerops-static";
1803
+ type PresetNameInput = "alwaysdata" | "aws-amplify" | "awsAmplify" | "aws_amplify" | "aws-lambda" | "awsLambda" | "aws_lambda" | "azure-swa" | "azureSwa" | "azure_swa" | "base-worker" | "baseWorker" | "base_worker" | "bun" | "cleavr" | "cloudflare-dev" | "cloudflareDev" | "cloudflare_dev" | "cloudflare-durable" | "cloudflareDurable" | "cloudflare_durable" | "cloudflare-module" | "cloudflareModule" | "cloudflare_module" | "cloudflare-pages" | "cloudflarePages" | "cloudflare_pages" | "cloudflare-pages-static" | "cloudflarePagesStatic" | "cloudflare_pages_static" | "deno" | "deno-deploy" | "denoDeploy" | "deno_deploy" | "deno-server" | "denoServer" | "deno_server" | "digital-ocean" | "digitalOcean" | "digital_ocean" | "firebase-app-hosting" | "firebaseAppHosting" | "firebase_app_hosting" | "flight-control" | "flightControl" | "flight_control" | "genezio" | "github-pages" | "githubPages" | "github_pages" | "gitlab-pages" | "gitlabPages" | "gitlab_pages" | "heroku" | "iis-handler" | "iisHandler" | "iis_handler" | "iis-node" | "iisNode" | "iis_node" | "koyeb" | "netlify" | "netlify-edge" | "netlifyEdge" | "netlify_edge" | "netlify-static" | "netlifyStatic" | "netlify_static" | "nitro-dev" | "nitroDev" | "nitro_dev" | "nitro-prerender" | "nitroPrerender" | "nitro_prerender" | "node" | "node-cluster" | "nodeCluster" | "node_cluster" | "node-middleware" | "nodeMiddleware" | "node_middleware" | "node-server" | "nodeServer" | "node_server" | "platform-sh" | "platformSh" | "platform_sh" | "render-com" | "renderCom" | "render_com" | "standard" | "static" | "stormkit" | "vercel" | "vercel-static" | "vercelStatic" | "vercel_static" | "winterjs" | "zeabur" | "zeabur-static" | "zeaburStatic" | "zeabur_static" | "zerops" | "zerops-static" | "zeropsStatic" | "zerops_static" | (string & {});
1804
1804
  //#endregion
1805
1805
  //#region src/types/_utils.d.ts
1806
1806
  type Enumerate<N extends number, Acc extends number[] = []> = Acc["length"] extends N ? Acc[number] : Enumerate<N, [...Acc, Acc["length"]]>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nitro-nightly",
3
- "version": "4.0.0-20251030-122606-56e83836",
3
+ "version": "4.0.0-20251030-135442-97badaa1",
4
4
  "description": "Build and Deploy Universal JavaScript Servers",
5
5
  "homepage": "https://nitro.build",
6
6
  "repository": "nitrojs/nitro",
@@ -63,7 +63,7 @@
63
63
  "ofetch": "^2.0.0-alpha.3",
64
64
  "ohash": "^2.0.11",
65
65
  "rollup": "^4.52.5",
66
- "srvx": "^0.9.2",
66
+ "srvx": "^0.9.4",
67
67
  "undici": "^7.16.0",
68
68
  "unenv": "^2.0.0-rc.24",
69
69
  "unstorage": "^2.0.0-alpha.4"
@@ -1,16 +0,0 @@
1
- /**
2
- * Gracefully shuts down `server` when the process receives
3
- * the passed signals
4
- *
5
- * @param {http.Server} server
6
- * @param {object} opts
7
- * signals: string (each signal separated by SPACE)
8
- * timeout: timeout value for forceful shutdown in ms
9
- * forceExit: force process.exit() - otherwise just let event loop clear
10
- * development: boolean value (if true, no graceful shutdown to speed up development
11
- * preShutdown: optional function. Needs to return a promise. - HTTP sockets are still available and untouched
12
- * onShutdown: optional function. Needs to return a promise.
13
- * finally: optional function, handled at the end of the shutdown.
14
- */
15
- declare function GracefulShutdown(server, opts);
16
- export default GracefulShutdown;
@@ -1,252 +0,0 @@
1
- // @ts-nocheck
2
- // =============================================================================
3
- // gracefully shuts downs http server
4
- // can be used with http, express, koa, ...
5
- // (c) 2023 Sebastian Hildebrandt
6
- // License: MIT
7
- // https://github.com/sebhildebrandt/http-graceful-shutdown/blob/master/LICENSE
8
- // https://github.com/sebhildebrandt/http-graceful-shutdown/blob/master/lib/index.js
9
- // =============================================================================
10
- import http from "node:http";
11
- const debug = (...args) => {};
12
- /**
13
- * Gracefully shuts down `server` when the process receives
14
- * the passed signals
15
- *
16
- * @param {http.Server} server
17
- * @param {object} opts
18
- * signals: string (each signal separated by SPACE)
19
- * timeout: timeout value for forceful shutdown in ms
20
- * forceExit: force process.exit() - otherwise just let event loop clear
21
- * development: boolean value (if true, no graceful shutdown to speed up development
22
- * preShutdown: optional function. Needs to return a promise. - HTTP sockets are still available and untouched
23
- * onShutdown: optional function. Needs to return a promise.
24
- * finally: optional function, handled at the end of the shutdown.
25
- */
26
- function GracefulShutdown(server, opts) {
27
- // option handling
28
- // ----------------------------------
29
- opts = opts || {};
30
- // merge opts with default options
31
- const options = Object.assign({
32
- signals: "SIGINT SIGTERM",
33
- timeout: 3e4,
34
- development: false,
35
- forceExit: true,
36
- onShutdown: (signal) => Promise.resolve(signal),
37
- preShutdown: (signal) => Promise.resolve(signal)
38
- }, opts);
39
- let isShuttingDown = false;
40
- const connections = {};
41
- let connectionCounter = 0;
42
- const secureConnections = {};
43
- let secureConnectionCounter = 0;
44
- let failed = false;
45
- let finalRun = false;
46
- function onceFactory() {
47
- let called = false;
48
- return (emitter, events, callback) => {
49
- function call() {
50
- if (!called) {
51
- called = true;
52
- // eslint-disable-next-line prefer-rest-params
53
- return Reflect.apply(callback, this, arguments);
54
- }
55
- }
56
- for (const e of events) {
57
- emitter.on(e, call);
58
- }
59
- };
60
- }
61
- const signals = options.signals.split(" ").map((s) => s.trim()).filter((s) => s.length > 0);
62
- const once = onceFactory();
63
- once(process, signals, (signal) => {
64
- debug("received shut down signal", signal);
65
- shutdown(signal).then(() => {
66
- if (options.forceExit) {
67
- // eslint-disable-next-line unicorn/no-process-exit
68
- process.exit(failed ? 1 : 0);
69
- }
70
- }).catch((error) => {
71
- debug("server shut down error occurred", error);
72
- // eslint-disable-next-line unicorn/no-process-exit
73
- process.exit(1);
74
- });
75
- });
76
- // helper function
77
- // ----------------------------------
78
- function isFunction(functionToCheck) {
79
- const getType = Object.prototype.toString.call(functionToCheck);
80
- return /^\[object\s([A-Za-z]+)?Function]$/.test(getType);
81
- }
82
- function destroy(socket, force = false) {
83
- if (socket._isIdle && isShuttingDown || force) {
84
- socket.destroy();
85
- if (socket.server instanceof http.Server) {
86
- delete connections[socket._connectionId];
87
- } else {
88
- delete secureConnections[socket._connectionId];
89
- }
90
- }
91
- }
92
- function destroyAllConnections(force = false) {
93
- // destroy empty and idle connections / all connections (if force = true)
94
- debug("Destroy Connections : " + (force ? "forced close" : "close"));
95
- let counter = 0;
96
- let secureCounter = 0;
97
- for (const key of Object.keys(connections)) {
98
- const socket = connections[key];
99
- const serverResponse = socket._httpMessage;
100
- // send connection close header to open connections
101
- if (serverResponse && !force) {
102
- if (!serverResponse.headersSent) {
103
- serverResponse.setHeader("connection", "close");
104
- }
105
- } else {
106
- counter++;
107
- destroy(socket);
108
- }
109
- }
110
- debug("Connections destroyed : " + counter);
111
- debug("Connection Counter : " + connectionCounter);
112
- for (const key of Object.keys(secureConnections)) {
113
- const socket = secureConnections[key];
114
- const serverResponse = socket._httpMessage;
115
- // send connection close header to open connections
116
- if (serverResponse && !force) {
117
- if (!serverResponse.headersSent) {
118
- serverResponse.setHeader("connection", "close");
119
- }
120
- } else {
121
- secureCounter++;
122
- destroy(socket);
123
- }
124
- }
125
- debug("Secure Connections destroyed : " + secureCounter);
126
- debug("Secure Connection Counter : " + secureConnectionCounter);
127
- }
128
- // set up server/process events
129
- // ----------------------------------
130
- server.on("request", (req, res) => {
131
- req.socket._isIdle = false;
132
- if (isShuttingDown && !res.headersSent) {
133
- res.setHeader("connection", "close");
134
- }
135
- res.on("finish", () => {
136
- req.socket._isIdle = true;
137
- destroy(req.socket);
138
- });
139
- });
140
- server.on("connection", (socket) => {
141
- if (isShuttingDown) {
142
- socket.destroy();
143
- } else {
144
- const id = connectionCounter++;
145
- socket._isIdle = true;
146
- socket._connectionId = id;
147
- connections[id] = socket;
148
- socket.once("close", () => {
149
- delete connections[socket._connectionId];
150
- });
151
- }
152
- });
153
- server.on("secureConnection", (socket) => {
154
- if (isShuttingDown) {
155
- socket.destroy();
156
- } else {
157
- const id = secureConnectionCounter++;
158
- socket._isIdle = true;
159
- socket._connectionId = id;
160
- secureConnections[id] = socket;
161
- socket.once("close", () => {
162
- delete secureConnections[socket._connectionId];
163
- });
164
- }
165
- });
166
- process.on("close", () => {
167
- debug("closed");
168
- });
169
- // shutdown event (per signal)
170
- // ----------------------------------
171
- function shutdown(sig) {
172
- function cleanupHttp() {
173
- destroyAllConnections();
174
- debug("Close http server");
175
- return new Promise((resolve, reject) => {
176
- server.close((err) => {
177
- if (err) {
178
- return reject(err);
179
- }
180
- return resolve(true);
181
- });
182
- });
183
- }
184
- debug("shutdown signal - " + sig);
185
- // Don't bother with graceful shutdown on development to speed up round trip
186
- if (options.development) {
187
- debug("DEV-Mode - immediate forceful shutdown");
188
- // eslint-disable-next-line unicorn/no-process-exit
189
- return process.exit(0);
190
- }
191
- function finalHandler() {
192
- if (!finalRun) {
193
- finalRun = true;
194
- if (options.finally && isFunction(options.finally)) {
195
- debug("executing finally()");
196
- options.finally();
197
- }
198
- }
199
- return Promise.resolve();
200
- }
201
- // returns true if should force shut down. returns false for shut down without force
202
- function waitForReadyToShutDown(totalNumInterval) {
203
- debug(`waitForReadyToShutDown... ${totalNumInterval}`);
204
- if (totalNumInterval === 0) {
205
- // timeout reached
206
- debug(`Could not close connections in time (${options.timeout}ms), will forcefully shut down`);
207
- return Promise.resolve(true);
208
- }
209
- // test all connections closed already?
210
- const allConnectionsClosed = Object.keys(connections).length === 0 && Object.keys(secureConnections).length === 0;
211
- if (allConnectionsClosed) {
212
- debug("All connections closed. Continue to shutting down");
213
- return Promise.resolve(false);
214
- }
215
- debug("Schedule the next waitForReadyToShutdown");
216
- return new Promise((resolve) => {
217
- setTimeout(() => {
218
- resolve(waitForReadyToShutDown(totalNumInterval - 1));
219
- }, 250);
220
- });
221
- }
222
- if (isShuttingDown) {
223
- return Promise.resolve();
224
- }
225
- debug("shutting down");
226
- return options.preShutdown(sig).then(() => {
227
- isShuttingDown = true;
228
- cleanupHttp();
229
- }).then(() => {
230
- const pollIterations = options.timeout ? Math.round(options.timeout / 250) : 0;
231
- return waitForReadyToShutDown(pollIterations);
232
- }).then((force) => {
233
- debug("Do onShutdown now");
234
- // if after waiting for connections to drain within timeout period
235
- // or if timeout has reached, we forcefully disconnect all sockets
236
- if (force) {
237
- destroyAllConnections(force);
238
- }
239
- return options.onShutdown(sig);
240
- }).then(finalHandler).catch((error) => {
241
- const errString = typeof error === "string" ? error : JSON.stringify(error);
242
- debug(errString);
243
- failed = true;
244
- throw errString;
245
- });
246
- }
247
- function shutdownManual() {
248
- return shutdown("manual");
249
- }
250
- return shutdownManual;
251
- }
252
- export default GracefulShutdown;
@@ -1,3 +0,0 @@
1
- import type { Server as HttpServer } from "node:http";
2
- export declare function getGracefulShutdownConfig(): {};
3
- export declare function setupGracefulShutdown(listener: HttpServer);
@@ -1,36 +0,0 @@
1
- import gracefulShutdown from "./lib/http-graceful-shutdown.mjs";
2
- import { useNitroHooks } from "./app.mjs";
3
- export function getGracefulShutdownConfig() {
4
- return {
5
- disabled: !!process.env.NITRO_SHUTDOWN_DISABLED,
6
- signals: (process.env.NITRO_SHUTDOWN_SIGNALS || "SIGTERM SIGINT").split(" ").map((s) => s.trim()),
7
- timeout: Number.parseInt(process.env.NITRO_SHUTDOWN_TIMEOUT || "", 10) || 3e4,
8
- forceExit: !process.env.NITRO_SHUTDOWN_NO_FORCE_EXIT
9
- };
10
- }
11
- export function setupGracefulShutdown(listener) {
12
- const shutdownConfig = getGracefulShutdownConfig();
13
- if (shutdownConfig.disabled) {
14
- return;
15
- }
16
- // https://github.com/sebhildebrandt/http-graceful-shutdown
17
- gracefulShutdown(listener, {
18
- signals: shutdownConfig.signals.join(" "),
19
- timeout: shutdownConfig.timeout,
20
- forceExit: shutdownConfig.forceExit,
21
- onShutdown: async () => {
22
- await new Promise((resolve) => {
23
- const timeout = setTimeout(() => {
24
- console.warn("Graceful shutdown timeout, force exiting...");
25
- resolve();
26
- }, shutdownConfig.timeout);
27
- Promise.resolve(useNitroHooks().callHook("close")).catch((error) => {
28
- console.error(error);
29
- }).finally(() => {
30
- clearTimeout(timeout);
31
- resolve();
32
- });
33
- });
34
- }
35
- });
36
- }
@@ -1 +0,0 @@
1
- export declare function trapUnhandledNodeErrors();
@@ -1,9 +0,0 @@
1
- import { useNitroApp } from "./app.mjs";
2
- function _captureError(error, type) {
3
- console.error(`[${type}]`, error);
4
- useNitroApp().captureError(error, { tags: [type] });
5
- }
6
- export function trapUnhandledNodeErrors() {
7
- process.on("unhandledRejection", (error) => _captureError(error, "unhandledRejection"));
8
- process.on("uncaughtException", (error) => _captureError(error, "uncaughtException"));
9
- }