srvx 0.9.3 → 0.9.5

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.
@@ -0,0 +1,18 @@
1
+ //#region src/_color.ts
2
+ const noColor = /* @__PURE__ */ (() => {
3
+ const env = globalThis.process?.env;
4
+ return env.NO_COLOR === "1" || env.TERM === "dumb";
5
+ })();
6
+ const _c = (c, r = 39) => (t) => noColor ? t : `\u001B[${c}m${t}\u001B[${r}m`;
7
+ const bold = /* @__PURE__ */ _c(1, 22);
8
+ const red = /* @__PURE__ */ _c(31);
9
+ const green = /* @__PURE__ */ _c(32);
10
+ const yellow = /* @__PURE__ */ _c(33);
11
+ const blue = /* @__PURE__ */ _c(34);
12
+ const magenta = /* @__PURE__ */ _c(35);
13
+ const cyan = /* @__PURE__ */ _c(36);
14
+ const gray = /* @__PURE__ */ _c(90);
15
+ const url = (title, url$1) => noColor ? `[${title}](${url$1})` : `\u001B]8;;${url$1}\u001B\\${title}\u001B]8;;\u001B\\`;
16
+
17
+ //#endregion
18
+ export { blue, bold, cyan, gray, green, magenta, red, url, yellow };
@@ -1,4 +1,4 @@
1
- import { Colors } from "./_utils.cli-B2YzwlOv.mjs";
1
+ import { gray, red } from "./_color-Dtg6hRMg.mjs";
2
2
 
3
3
  //#region src/_middleware.ts
4
4
  function wrapFetch(server) {
@@ -34,23 +34,21 @@ const gracefulShutdownPlugin = (server) => {
34
34
  const shutdown = async () => {
35
35
  if (isShuttingDown) return;
36
36
  isShuttingDown = true;
37
- console.log(Colors.gray(`\nShutting down server... (timeout in ${gracefulShutdown}+${forceShutdown}s)`));
37
+ const w = process.stderr.write.bind(process.stderr);
38
+ w(gray(`\nShutting down server in ${gracefulShutdown}s...`));
38
39
  let timeout;
39
40
  await Promise.race([server.close().finally(() => {
40
41
  clearTimeout(timeout);
41
- console.log(Colors.green("Server closed all connections."));
42
+ w(gray(" Server closed.\n"));
42
43
  }), new Promise((resolve) => {
43
44
  timeout = setTimeout(() => {
44
- console.warn(Colors.yellow(`Forcing closing connections to exit... (timeout in ${forceShutdown}s)`));
45
+ w(gray(`\nForce closing connections in ${forceShutdown}s...`));
45
46
  timeout = setTimeout(() => {
46
- console.error(Colors.red("Could not close connections in time, force exiting."));
47
+ w(red("\nCould not close connections in time, force exiting."));
47
48
  resolve();
48
- }, 1e3);
49
- return server.close(true).finally(() => {
50
- clearTimeout(timeout);
51
- resolve();
52
- });
53
- }, 1e3);
49
+ }, forceShutdown * 1e3);
50
+ return server.close(true);
51
+ }, gracefulShutdown * 1e3);
54
52
  })]);
55
53
  globalThis.process.exit(0);
56
54
  };
@@ -2,6 +2,7 @@
2
2
  function resolvePortAndHost(opts) {
3
3
  const _port = opts.port ?? globalThis.process?.env.PORT ?? 3e3;
4
4
  const port = typeof _port === "number" ? _port : Number.parseInt(_port, 10);
5
+ if (port < 0 || port > 65535) throw new RangeError(`Port must be between 0 and 65535 (got "${port}").`);
5
6
  const hostname = opts.hostname ?? globalThis.process?.env.HOST;
6
7
  return {
7
8
  port,
@@ -56,7 +57,8 @@ function createWaitUntil() {
56
57
  const promises = new Set();
57
58
  return {
58
59
  waitUntil: (promise) => {
59
- promises.add(promise.catch(console.error).finally(() => {
60
+ if (typeof promise?.then !== "function") return;
61
+ promises.add(Promise.resolve(promise).catch(console.error).finally(() => {
60
62
  promises.delete(promise);
61
63
  }));
62
64
  },
@@ -1,8 +1,8 @@
1
- import "../_chunks/_utils.cli-B2YzwlOv.mjs";
1
+ import "../_chunks/_color-Dtg6hRMg.mjs";
2
2
  import "../_chunks/_inherit-B9eAGP_O.mjs";
3
3
  import { FastURL$1 as FastURL } from "../_chunks/_url-DF-_pEPn.mjs";
4
- import { createWaitUntil, fmtURL, printListening, resolvePortAndHost, resolveTLSOptions } from "../_chunks/_utils-dqVgpDNy.mjs";
5
- import { gracefulShutdownPlugin, wrapFetch } from "../_chunks/_plugins-DBERsPAu.mjs";
4
+ import { createWaitUntil, fmtURL, printListening, resolvePortAndHost, resolveTLSOptions } from "../_chunks/_utils-DS1d5FUa.mjs";
5
+ import { gracefulShutdownPlugin, wrapFetch } from "../_chunks/_plugins-CPeJORNN.mjs";
6
6
 
7
7
  //#region src/adapters/bun.ts
8
8
  const FastResponse = Response;
@@ -1,5 +1,5 @@
1
- import "../_chunks/_utils.cli-B2YzwlOv.mjs";
2
- import { errorPlugin, wrapFetch } from "../_chunks/_plugins-DBERsPAu.mjs";
1
+ import "../_chunks/_color-Dtg6hRMg.mjs";
2
+ import { errorPlugin, wrapFetch } from "../_chunks/_plugins-CPeJORNN.mjs";
3
3
 
4
4
  //#region src/adapters/cloudflare.ts
5
5
  const FastURL = URL;
@@ -1,8 +1,8 @@
1
- import "../_chunks/_utils.cli-B2YzwlOv.mjs";
1
+ import "../_chunks/_color-Dtg6hRMg.mjs";
2
2
  import "../_chunks/_inherit-B9eAGP_O.mjs";
3
3
  import { FastURL$1 as FastURL } from "../_chunks/_url-DF-_pEPn.mjs";
4
- import { createWaitUntil, fmtURL, printListening, resolvePortAndHost, resolveTLSOptions } from "../_chunks/_utils-dqVgpDNy.mjs";
5
- import { gracefulShutdownPlugin, wrapFetch } from "../_chunks/_plugins-DBERsPAu.mjs";
4
+ import { createWaitUntil, fmtURL, printListening, resolvePortAndHost, resolveTLSOptions } from "../_chunks/_utils-DS1d5FUa.mjs";
5
+ import { gracefulShutdownPlugin, wrapFetch } from "../_chunks/_plugins-CPeJORNN.mjs";
6
6
 
7
7
  //#region src/adapters/deno.ts
8
8
  const FastResponse = Response;
@@ -1,6 +1,6 @@
1
- import "../_chunks/_utils.cli-B2YzwlOv.mjs";
2
- import { createWaitUntil } from "../_chunks/_utils-dqVgpDNy.mjs";
3
- import { errorPlugin, wrapFetch } from "../_chunks/_plugins-DBERsPAu.mjs";
1
+ import "../_chunks/_color-Dtg6hRMg.mjs";
2
+ import { createWaitUntil } from "../_chunks/_utils-DS1d5FUa.mjs";
3
+ import { errorPlugin, wrapFetch } from "../_chunks/_plugins-CPeJORNN.mjs";
4
4
 
5
5
  //#region src/adapters/generic.ts
6
6
  const FastURL = URL;
@@ -1,8 +1,8 @@
1
- import "../_chunks/_utils.cli-B2YzwlOv.mjs";
1
+ import "../_chunks/_color-Dtg6hRMg.mjs";
2
2
  import { lazyInherit } from "../_chunks/_inherit-B9eAGP_O.mjs";
3
3
  import { FastURL$1 as FastURL } from "../_chunks/_url-DF-_pEPn.mjs";
4
- import { createWaitUntil, fmtURL, printListening, resolvePortAndHost, resolveTLSOptions } from "../_chunks/_utils-dqVgpDNy.mjs";
5
- import { errorPlugin, gracefulShutdownPlugin, wrapFetch } from "../_chunks/_plugins-DBERsPAu.mjs";
4
+ import { createWaitUntil, fmtURL, printListening, resolvePortAndHost, resolveTLSOptions } from "../_chunks/_utils-DS1d5FUa.mjs";
5
+ import { errorPlugin, gracefulShutdownPlugin, wrapFetch } from "../_chunks/_plugins-CPeJORNN.mjs";
6
6
  import { NodeResponse, callNodeHandler } from "../_chunks/call-BUTAdRs1.mjs";
7
7
  import nodeHTTP, { IncomingMessage, ServerResponse } from "node:http";
8
8
  import { Duplex, Readable } from "node:stream";
@@ -1,5 +1,5 @@
1
- import "../_chunks/_utils.cli-B2YzwlOv.mjs";
2
- import { errorPlugin, wrapFetch } from "../_chunks/_plugins-DBERsPAu.mjs";
1
+ import "../_chunks/_color-Dtg6hRMg.mjs";
2
+ import { errorPlugin, wrapFetch } from "../_chunks/_plugins-CPeJORNN.mjs";
3
3
 
4
4
  //#region src/adapters/service-worker.ts
5
5
  const FastURL = URL;
package/dist/cli.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { Colors } from "./_chunks/_utils.cli-B2YzwlOv.mjs";
1
+ import { bold, cyan, gray, green, magenta, red, url, yellow } from "./_chunks/_color-Dtg6hRMg.mjs";
2
2
  import { parseArgs } from "node:util";
3
3
  import { fileURLToPath, pathToFileURL } from "node:url";
4
4
  import * as nodeHTTP$1 from "node:http";
@@ -156,8 +156,8 @@ async function loadEntry(opts) {
156
156
  } catch (error) {
157
157
  if (error?.code === "ERR_UNKNOWN_FILE_EXTENSION") {
158
158
  const message = String(error);
159
- if (/"\.(m|c)?ts"/g.test(message)) console.error(Colors.red(`\nMake sure you're using Node.js v22.18+ or v24+ for TypeScript support (current version: ${process.versions.node})\n\n`));
160
- else if (/"\.(m|c)?tsx"/g.test(message)) console.error(Colors.red(`\nYou need a compatible loader for JSX support (Deno, Bun or srvx --register jiti/register)\n\n`));
159
+ if (/"\.(m|c)?ts"/g.test(message)) console.error(red(`\nMake sure you're using Node.js v22.18+ or v24+ for TypeScript support (current version: ${process.versions.node})\n\n`));
160
+ else if (/"\.(m|c)?tsx"/g.test(message)) console.error(red(`\nYou need a compatible loader for JSX support (Deno, Bun or srvx --register jiti/register)\n\n`));
161
161
  }
162
162
  if (error instanceof Error) Error.captureStackTrace?.(error, serve);
163
163
  throw error;
@@ -183,14 +183,14 @@ function renderError(error, status = 500, title = "Server Error") {
183
183
  }
184
184
  function printInfo(entry) {
185
185
  let entryInfo;
186
- if (options._entry) entryInfo = Colors.cyan("./" + relative(".", options._entry));
187
- else entryInfo = Colors.gray(`(create ${Colors.bold(`server.ts`)} to enable)`);
188
- console.log(Colors.gray(`${Colors.bold(Colors.gray("λ"))} Server handler: ${entryInfo}`));
189
- if (options._entry && entry._error) console.error(Colors.red(` ${entry._error}`));
186
+ if (options._entry) entryInfo = cyan("./" + relative(".", options._entry));
187
+ else entryInfo = gray(`(create ${bold(`server.ts`)} to enable)`);
188
+ console.log(gray(`${bold(gray("λ"))} Server handler: ${entryInfo}`));
189
+ if (options._entry && entry._error) console.error(red(` ${entry._error}`));
190
190
  let staticInfo;
191
- if (options._static) staticInfo = Colors.cyan("./" + relative(".", options._static) + "/");
192
- else staticInfo = Colors.gray(`(add ${Colors.bold("public/")} dir to enable)`);
193
- console.log(Colors.gray(`${Colors.bold(Colors.gray("∘"))} Static files: ${staticInfo}`));
191
+ if (options._static) staticInfo = cyan("./" + relative(".", options._static) + "/");
192
+ else staticInfo = gray(`(add ${bold("public/")} dir to enable)`);
193
+ console.log(gray(`${bold(gray("∘"))} Static files: ${staticInfo}`));
194
194
  }
195
195
  async function interceptListen(cb) {
196
196
  const originalListen = nodeHTTP$1.Server.prototype.listen;
@@ -217,7 +217,7 @@ async function interceptListen(cb) {
217
217
  };
218
218
  }
219
219
  async function version() {
220
- const version$1 = "0.9.3";
220
+ const version$1 = "0.9.4";
221
221
  return `srvx ${version$1}\n${runtime()}`;
222
222
  }
223
223
  function runtime() {
@@ -266,7 +266,7 @@ function parseArgs$1(args$1) {
266
266
  dir = dirname(entry);
267
267
  }
268
268
  if (!existsSync(dir)) {
269
- console.error(Colors.red(`Directory "${dir}" does not exist.\n`));
269
+ console.error(red(`Directory "${dir}" does not exist.\n`));
270
270
  process.exit(1);
271
271
  }
272
272
  return {
@@ -287,55 +287,55 @@ function parseArgs$1(args$1) {
287
287
  }
288
288
  function example() {
289
289
  const useTs = !options._entry || options._entry.endsWith(".ts");
290
- return `${Colors.bold(Colors.gray("// server.ts"))}
291
- ${Colors.magenta("export default")} {
292
- ${Colors.cyan("fetch")}(req${useTs ? ": Request" : ""}) {
293
- ${Colors.magenta("return")} new Response(${Colors.green("\"Hello, World!\"")});
290
+ return `${bold(gray("// server.ts"))}
291
+ ${magenta("export default")} {
292
+ ${cyan("fetch")}(req${useTs ? ": Request" : ""}) {
293
+ ${magenta("return")} new Response(${green("\"Hello, World!\"")});
294
294
  }
295
295
  }`;
296
296
  }
297
297
  function usage(mainOpts) {
298
298
  const command = mainOpts.command;
299
299
  return `
300
- ${Colors.cyan(command)} - Start an HTTP server with the specified entry path.
300
+ ${cyan(command)} - Start an HTTP server with the specified entry path.
301
301
 
302
- ${Colors.bold("USAGE")}
302
+ ${bold("USAGE")}
303
303
  ${existsSync(options._entry) ? "" : `\n${example()}\n`}
304
- ${Colors.gray("# srvx [options] [entry]")}
305
- ${Colors.gray("$")} ${Colors.cyan(command)} ${Colors.gray("./server.ts")} ${Colors.gray("# Start development server")}
306
- ${Colors.gray("$")} ${Colors.cyan(command)} --prod ${Colors.gray("# Start production server")}
307
- ${Colors.gray("$")} ${Colors.cyan(command)} --port=8080 ${Colors.gray("# Listen on port 8080")}
308
- ${Colors.gray("$")} ${Colors.cyan(command)} --host=localhost ${Colors.gray("# Bind to localhost only")}
309
- ${Colors.gray("$")} ${Colors.cyan(command)} --import=jiti/register ${Colors.gray(`# Enable ${Colors.url("jiti", "https://github.com/unjs/jiti")} loader`)}
310
- ${Colors.gray("$")} ${Colors.cyan(command)} --tls --cert=cert.pem --key=key.pem ${Colors.gray("# Enable TLS (HTTPS/HTTP2)")}
304
+ ${gray("# srvx [options] [entry]")}
305
+ ${gray("$")} ${cyan(command)} ${gray("./server.ts")} ${gray("# Start development server")}
306
+ ${gray("$")} ${cyan(command)} --prod ${gray("# Start production server")}
307
+ ${gray("$")} ${cyan(command)} --port=8080 ${gray("# Listen on port 8080")}
308
+ ${gray("$")} ${cyan(command)} --host=localhost ${gray("# Bind to localhost only")}
309
+ ${gray("$")} ${cyan(command)} --import=jiti/register ${gray(`# Enable ${url("jiti", "https://github.com/unjs/jiti")} loader`)}
310
+ ${gray("$")} ${cyan(command)} --tls --cert=cert.pem --key=key.pem ${gray("# Enable TLS (HTTPS/HTTP2)")}
311
311
 
312
312
 
313
- ${Colors.bold("ARGUMENTS")}
313
+ ${bold("ARGUMENTS")}
314
314
 
315
- ${Colors.yellow("<entry>")} Server entry path to serve.
316
- Default: ${defaultEntries.map((e) => Colors.cyan(e)).join(", ")} ${Colors.gray(`(${defaultExts.join(",")})`)}
315
+ ${yellow("<entry>")} Server entry path to serve.
316
+ Default: ${defaultEntries.map((e) => cyan(e)).join(", ")} ${gray(`(${defaultExts.join(",")})`)}
317
317
 
318
- ${Colors.bold("OPTIONS")}
318
+ ${bold("OPTIONS")}
319
319
 
320
- ${Colors.green("-p, --port")} ${Colors.yellow("<port>")} Port to listen on (default: ${Colors.yellow("3000")})
321
- ${Colors.green("--host")} ${Colors.yellow("<host>")} Host to bind to (default: all interfaces)
322
- ${Colors.green("-s, --static")} ${Colors.yellow("<dir>")} Serve static files from the specified directory (default: ${Colors.yellow("public")})
323
- ${Colors.green("--prod")} Run in production mode (no watch, no debug)
324
- ${Colors.green("--import")} ${Colors.yellow("<loader>")} ES module to preload
325
- ${Colors.green("--tls")} Enable TLS (HTTPS/HTTP2)
326
- ${Colors.green("--cert")} ${Colors.yellow("<file>")} TLS certificate file
327
- ${Colors.green("--key")} ${Colors.yellow("<file>")} TLS private key file
328
- ${Colors.green("-h, --help")} Show this help message
329
- ${Colors.green("-v, --version")} Show server and runtime versions
320
+ ${green("-p, --port")} ${yellow("<port>")} Port to listen on (default: ${yellow("3000")})
321
+ ${green("--host")} ${yellow("<host>")} Host to bind to (default: all interfaces)
322
+ ${green("-s, --static")} ${yellow("<dir>")} Serve static files from the specified directory (default: ${yellow("public")})
323
+ ${green("--prod")} Run in production mode (no watch, no debug)
324
+ ${green("--import")} ${yellow("<loader>")} ES module to preload
325
+ ${green("--tls")} Enable TLS (HTTPS/HTTP2)
326
+ ${green("--cert")} ${yellow("<file>")} TLS certificate file
327
+ ${green("--key")} ${yellow("<file>")} TLS private key file
328
+ ${green("-h, --help")} Show this help message
329
+ ${green("-v, --version")} Show server and runtime versions
330
330
 
331
- ${Colors.bold("ENVIRONMENT")}
331
+ ${bold("ENVIRONMENT")}
332
332
 
333
- ${Colors.green("PORT")} Override port
334
- ${Colors.green("HOST")} Override host
335
- ${Colors.green("NODE_ENV")} Set to ${Colors.yellow("production")} for production mode.
333
+ ${green("PORT")} Override port
334
+ ${green("HOST")} Override host
335
+ ${green("NODE_ENV")} Set to ${yellow("production")} for production mode.
336
336
 
337
- ➤ ${Colors.url("Documentation", mainOpts.docs || "https://srvx.h3.dev")}
338
- ➤ ${Colors.url("Report issues", mainOpts.issues || "https://github.com/h3js/srvx/issues")}
337
+ ➤ ${url("Documentation", mainOpts.docs || "https://srvx.h3.dev")}
338
+ ➤ ${url("Report issues", mainOpts.issues || "https://github.com/h3js/srvx/issues")}
339
339
  `.trim();
340
340
  }
341
341
  function setupProcessErrorHandlers() {
package/dist/log.mjs CHANGED
@@ -1,18 +1,18 @@
1
- import { Colors } from "./_chunks/_utils.cli-B2YzwlOv.mjs";
1
+ import { blue, bold, gray, green, red, yellow } from "./_chunks/_color-Dtg6hRMg.mjs";
2
2
 
3
3
  //#region src/log.ts
4
4
  const statusColors = {
5
- 1: "blue",
6
- 2: "green",
7
- 3: "yellow"
5
+ 1: blue,
6
+ 2: green,
7
+ 3: yellow
8
8
  };
9
9
  const log = (_options = {}) => {
10
10
  return async (req, next) => {
11
11
  const start = performance.now();
12
12
  const res = await next();
13
13
  const duration = performance.now() - start;
14
- const statusColor = statusColors[Math.floor(res.status / 100)] || "red";
15
- console.log(`${Colors.gray(`[${new Date().toLocaleTimeString()}]`)} ${Colors.bold(req.method)} ${Colors.blue(req.url)} [${Colors[statusColor](res.status + "")}] ${Colors.gray(`(${duration.toFixed(2)}ms)`)}`);
14
+ const statusColor = statusColors[Math.floor(res.status / 100)] || red;
15
+ console.log(`${gray(`[${new Date().toLocaleTimeString()}]`)} ${bold(req.method)} ${blue(req.url)} [${statusColor(res.status + "")}] ${gray(`(${duration.toFixed(2)}ms)`)}`);
16
16
  return res;
17
17
  };
18
18
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "srvx",
3
- "version": "0.9.3",
3
+ "version": "0.9.5",
4
4
  "description": "Universal Server API based on web platform standards. Works seamlessly with Deno, Bun and Node.js.",
5
5
  "homepage": "https://srvx.h3.dev",
6
6
  "repository": "h3js/srvx",
@@ -1,31 +0,0 @@
1
- //#region src/_utils.cli.ts
2
- const noColor = globalThis.process?.env?.NO_COLOR === "1" || globalThis.process?.env?.TERM === "dumb";
3
- const resets = {
4
- 1: 22,
5
- 31: 39,
6
- 32: 39,
7
- 33: 39,
8
- 34: 39,
9
- 35: 39,
10
- 36: 39,
11
- 90: 39
12
- };
13
- const _c = (c) => (text) => {
14
- if (noColor) return text;
15
- const off = resets[c] ?? 0;
16
- return `\u001B[${c}m${text}\u001B[${off}m`;
17
- };
18
- const Colors = {
19
- bold: _c(1),
20
- red: _c(31),
21
- green: _c(32),
22
- yellow: _c(33),
23
- blue: _c(34),
24
- magenta: _c(35),
25
- cyan: _c(36),
26
- gray: _c(90),
27
- url: (title, url) => noColor ? `[${title}](${url})` : `\u001B]8;;${url}\u001B\\${title}\u001B]8;;\u001B\\`
28
- };
29
-
30
- //#endregion
31
- export { Colors };