fix: Switch to Tailwind v3 - v4 incompatible with Astro
This commit is contained in:
606
node_modules/serve/build/main.js
generated
vendored
Executable file
606
node_modules/serve/build/main.js
generated
vendored
Executable file
@@ -0,0 +1,606 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// source/main.ts
|
||||
import { cwd as getPwd, exit, env as env2, stdout } from "node:process";
|
||||
import path from "node:path";
|
||||
import chalk4 from "chalk";
|
||||
import boxen from "boxen";
|
||||
import clipboard from "clipboardy";
|
||||
|
||||
// package.json
|
||||
var package_default = {
|
||||
name: "serve",
|
||||
version: "14.2.6",
|
||||
description: "Static file serving and directory listing",
|
||||
keywords: [
|
||||
"vercel",
|
||||
"serve",
|
||||
"micro",
|
||||
"http-server"
|
||||
],
|
||||
repository: "vercel/serve",
|
||||
license: "MIT",
|
||||
type: "module",
|
||||
bin: {
|
||||
serve: "./build/main.js"
|
||||
},
|
||||
files: [
|
||||
"build/"
|
||||
],
|
||||
engines: {
|
||||
node: ">= 14"
|
||||
},
|
||||
scripts: {
|
||||
develop: "tsx watch ./source/main.ts",
|
||||
start: "node ./build/main.js",
|
||||
compile: "tsup ./source/main.ts",
|
||||
"test:tsc": "tsc --project tsconfig.json",
|
||||
"test:unit": "vitest run --config config/vitest.ts",
|
||||
"test:watch": "vitest watch --config config/vitest.ts",
|
||||
test: "pnpm test:tsc && pnpm test:unit",
|
||||
"lint:code": "eslint --max-warnings 0 source/**/*.ts",
|
||||
"lint:style": "prettier --check --ignore-path .gitignore .",
|
||||
lint: "pnpm lint:code && pnpm lint:style",
|
||||
format: "prettier --write --ignore-path .gitignore .",
|
||||
prepare: "husky install config/husky && pnpm compile",
|
||||
changeset: "changeset",
|
||||
"version-packages": "changeset version",
|
||||
release: "pnpm compile && changeset publish"
|
||||
},
|
||||
dependencies: {
|
||||
"@zeit/schemas": "2.36.0",
|
||||
ajv: "8.18.0",
|
||||
arg: "5.0.2",
|
||||
boxen: "7.0.0",
|
||||
chalk: "5.0.1",
|
||||
"chalk-template": "0.4.0",
|
||||
clipboardy: "3.0.0",
|
||||
compression: "1.8.1",
|
||||
"is-port-reachable": "4.0.0",
|
||||
"serve-handler": "6.1.7",
|
||||
"update-check": "1.5.4"
|
||||
},
|
||||
devDependencies: {
|
||||
"@changesets/cli": "2.29.6",
|
||||
"@types/compression": "1.7.2",
|
||||
"@types/serve-handler": "6.1.1",
|
||||
"@vercel/style-guide": "3.0.0",
|
||||
"@vitest/coverage-v8": "2.1.3",
|
||||
eslint: "8.19.0",
|
||||
got: "12.1.0",
|
||||
husky: "8.0.1",
|
||||
"lint-staged": "13.0.3",
|
||||
prettier: "2.7.1",
|
||||
tsup: "8.3.0",
|
||||
tsx: "4.19.1",
|
||||
typescript: "5.6.3",
|
||||
vitest: "2.1.3"
|
||||
},
|
||||
tsup: {
|
||||
target: "esnext",
|
||||
format: [
|
||||
"esm"
|
||||
],
|
||||
outDir: "./build/"
|
||||
},
|
||||
prettier: "@vercel/style-guide/prettier",
|
||||
eslintConfig: {
|
||||
extends: [
|
||||
"./node_modules/@vercel/style-guide/eslint/node.js",
|
||||
"./node_modules/@vercel/style-guide/eslint/typescript.js"
|
||||
],
|
||||
parserOptions: {
|
||||
project: "tsconfig.json"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"*": [
|
||||
"prettier --ignore-unknown --write"
|
||||
],
|
||||
"source/**/*.ts": [
|
||||
"eslint --max-warnings 0 --fix",
|
||||
"vitest related --run"
|
||||
],
|
||||
tests: [
|
||||
"vitest --run"
|
||||
]
|
||||
},
|
||||
packageManager: "pnpm@9.12.1+sha512.e5a7e52a4183a02d5931057f7a0dbff9d5e9ce3161e33fa68ae392125b79282a8a8a470a51dfc8a0ed86221442eb2fb57019b0990ed24fab519bf0e1bc5ccfc4"
|
||||
};
|
||||
|
||||
// source/utilities/promise.ts
|
||||
import { promisify } from "node:util";
|
||||
var resolve = async (promiseLike) => {
|
||||
try {
|
||||
const data = await promiseLike;
|
||||
return [void 0, data];
|
||||
} catch (error2) {
|
||||
return [error2, void 0];
|
||||
}
|
||||
};
|
||||
|
||||
// source/utilities/server.ts
|
||||
import http2 from "node:http";
|
||||
import https from "node:https";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import handler from "serve-handler";
|
||||
import compression from "compression";
|
||||
import isPortReachable from "is-port-reachable";
|
||||
import chalk2 from "chalk";
|
||||
|
||||
// source/utilities/http.ts
|
||||
import { networkInterfaces as getNetworkInterfaces } from "node:os";
|
||||
var networkInterfaces = getNetworkInterfaces();
|
||||
var registerCloseListener = (fn) => {
|
||||
let run = false;
|
||||
const wrapper = () => {
|
||||
if (!run) {
|
||||
run = true;
|
||||
fn();
|
||||
}
|
||||
};
|
||||
process.on("SIGINT", wrapper);
|
||||
process.on("SIGTERM", wrapper);
|
||||
process.on("exit", wrapper);
|
||||
};
|
||||
var getNetworkAddress = () => {
|
||||
for (const interfaceDetails of Object.values(networkInterfaces)) {
|
||||
if (!interfaceDetails) continue;
|
||||
for (const details of interfaceDetails) {
|
||||
const { address, family, internal } = details;
|
||||
if (family === "IPv4" && !internal) return address;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// source/utilities/logger.ts
|
||||
import chalk from "chalk";
|
||||
var http = (...message) => console.info(chalk.bgBlue.bold(" HTTP "), ...message);
|
||||
var info = (...message) => console.info(chalk.bgMagenta.bold(" INFO "), ...message);
|
||||
var warn = (...message) => console.error(chalk.bgYellow.bold(" WARN "), ...message);
|
||||
var error = (...message) => console.error(chalk.bgRed.bold(" ERROR "), ...message);
|
||||
var log = console.log;
|
||||
var logger = { http, info, warn, error, log };
|
||||
|
||||
// source/utilities/server.ts
|
||||
var compress = promisify(compression());
|
||||
var startServer = async (endpoint, config2, args2, previous) => {
|
||||
const serverHandler = (request, response) => {
|
||||
const run = async () => {
|
||||
const requestTime = /* @__PURE__ */ new Date();
|
||||
const formattedTime = `${requestTime.toLocaleDateString()} ${requestTime.toLocaleTimeString()}`;
|
||||
const ipAddress = request.socket.remoteAddress?.replace("::ffff:", "") ?? "unknown";
|
||||
const requestUrl = `${request.method ?? "GET"} ${request.url ?? "/"}`;
|
||||
if (!args2["--no-request-logging"])
|
||||
logger.http(
|
||||
chalk2.dim(formattedTime),
|
||||
chalk2.yellow(ipAddress),
|
||||
chalk2.cyan(requestUrl)
|
||||
);
|
||||
if (args2["--cors"]) {
|
||||
response.setHeader("Access-Control-Allow-Origin", "*");
|
||||
response.setHeader("Access-Control-Allow-Headers", "*");
|
||||
response.setHeader("Access-Control-Allow-Credentials", "true");
|
||||
response.setHeader("Access-Control-Allow-Private-Network", "true");
|
||||
}
|
||||
if (!args2["--no-compression"])
|
||||
await compress(request, response);
|
||||
await handler(request, response, config2);
|
||||
const responseTime = Date.now() - requestTime.getTime();
|
||||
if (!args2["--no-request-logging"])
|
||||
logger.http(
|
||||
chalk2.dim(formattedTime),
|
||||
chalk2.yellow(ipAddress),
|
||||
chalk2[response.statusCode < 400 ? "green" : "red"](
|
||||
`Returned ${response.statusCode} in ${responseTime} ms`
|
||||
)
|
||||
);
|
||||
};
|
||||
run().catch((error2) => {
|
||||
throw error2;
|
||||
});
|
||||
};
|
||||
const sslCert = args2["--ssl-cert"];
|
||||
const sslKey = args2["--ssl-key"];
|
||||
const sslPass = args2["--ssl-pass"];
|
||||
const isPFXFormat = sslCert && /[.](?<extension>pfx|p12)$/.exec(sslCert) !== null;
|
||||
const useSsl = sslCert && (sslKey || sslPass || isPFXFormat);
|
||||
let serverConfig = {};
|
||||
if (useSsl && sslCert && sslKey) {
|
||||
serverConfig = {
|
||||
key: await readFile(sslKey),
|
||||
cert: await readFile(sslCert),
|
||||
passphrase: sslPass ? await readFile(sslPass, "utf8") : ""
|
||||
};
|
||||
} else if (useSsl && sslCert && isPFXFormat) {
|
||||
serverConfig = {
|
||||
pfx: await readFile(sslCert),
|
||||
passphrase: sslPass ? await readFile(sslPass, "utf8") : ""
|
||||
};
|
||||
}
|
||||
const server = useSsl ? https.createServer(serverConfig, serverHandler) : http2.createServer(serverHandler);
|
||||
const getServerDetails = () => {
|
||||
registerCloseListener(() => server.close());
|
||||
const details = server.address();
|
||||
let local;
|
||||
let network;
|
||||
if (typeof details === "string") {
|
||||
local = details;
|
||||
} else if (typeof details === "object" && details.port) {
|
||||
let address;
|
||||
if (details.address === "::") address = "localhost";
|
||||
else if (details.family === "IPv6") address = `[${details.address}]`;
|
||||
else address = details.address;
|
||||
const ip = getNetworkAddress();
|
||||
const protocol = useSsl ? "https" : "http";
|
||||
local = `${protocol}://${address}:${details.port}`;
|
||||
network = ip ? `${protocol}://${ip}:${details.port}` : void 0;
|
||||
}
|
||||
return {
|
||||
local,
|
||||
network,
|
||||
previous
|
||||
};
|
||||
};
|
||||
server.on("error", (error2) => {
|
||||
throw new Error(
|
||||
`Failed to serve: ${error2.stack?.toString() ?? error2.message}`
|
||||
);
|
||||
});
|
||||
if (typeof endpoint.port === "number" && !isNaN(endpoint.port) && endpoint.port !== 0) {
|
||||
const port = endpoint.port;
|
||||
const isClosed = await isPortReachable(port, {
|
||||
host: endpoint.host ?? "localhost"
|
||||
});
|
||||
if (isClosed) return startServer({ port: 0 }, config2, args2, port);
|
||||
}
|
||||
return new Promise((resolve2, _reject) => {
|
||||
if (typeof endpoint.port !== "undefined" && typeof endpoint.host === "undefined")
|
||||
server.listen(endpoint.port, () => resolve2(getServerDetails()));
|
||||
else if (typeof endpoint.port === "undefined" && typeof endpoint.host !== "undefined")
|
||||
server.listen(endpoint.host, () => resolve2(getServerDetails()));
|
||||
else if (typeof endpoint.port !== "undefined" && typeof endpoint.host !== "undefined")
|
||||
server.listen(
|
||||
endpoint.port,
|
||||
endpoint.host,
|
||||
() => resolve2(getServerDetails())
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
// source/utilities/cli.ts
|
||||
import { parse as parseUrl } from "node:url";
|
||||
import { env } from "node:process";
|
||||
import chalk3 from "chalk";
|
||||
import chalkTemplate from "chalk-template";
|
||||
import parseArgv from "arg";
|
||||
import checkForUpdate from "update-check";
|
||||
var helpText = chalkTemplate`
|
||||
{bold.cyan serve} - Static file serving and directory listing
|
||||
|
||||
{bold USAGE}
|
||||
|
||||
{bold $} {cyan serve} --help
|
||||
{bold $} {cyan serve} --version
|
||||
{bold $} {cyan serve} folder_name
|
||||
{bold $} {cyan serve} [-l {underline listen_uri} [-l ...]] [{underline directory}]
|
||||
|
||||
By default, {cyan serve} will listen on {bold 0.0.0.0:3000} and serve the
|
||||
current working directory on that address.
|
||||
|
||||
Specifying a single {bold --listen} argument will overwrite the default, not supplement it.
|
||||
|
||||
{bold OPTIONS}
|
||||
|
||||
--help Shows this help message
|
||||
|
||||
-v, --version Displays the current version of serve
|
||||
|
||||
-l, --listen {underline listen_uri} Specify a URI endpoint on which to listen (see below) -
|
||||
more than one may be specified to listen in multiple places
|
||||
|
||||
-p Specify custom port
|
||||
|
||||
-s, --single Rewrite all not-found requests to \`index.html\`
|
||||
|
||||
-d, --debug Show debugging information
|
||||
|
||||
-c, --config Specify custom path to \`serve.json\`
|
||||
|
||||
-L, --no-request-logging Do not log any request information to the console.
|
||||
|
||||
-C, --cors Enable CORS, sets \`Access-Control-Allow-Origin\` to \`*\`
|
||||
|
||||
-n, --no-clipboard Do not copy the local address to the clipboard
|
||||
|
||||
-u, --no-compression Do not compress files
|
||||
|
||||
--no-etag Send \`Last-Modified\` header instead of \`ETag\`
|
||||
|
||||
-S, --symlinks Resolve symlinks instead of showing 404 errors
|
||||
|
||||
--ssl-cert Optional path to an SSL/TLS certificate to serve with HTTPS
|
||||
{grey Supported formats: PEM (default) and PKCS12 (PFX)}
|
||||
|
||||
--ssl-key Optional path to the SSL/TLS certificate\'s private key
|
||||
{grey Applicable only for PEM certificates}
|
||||
|
||||
--ssl-pass Optional path to the SSL/TLS certificate\'s passphrase
|
||||
|
||||
--no-port-switching Do not open a port other than the one specified when it\'s taken.
|
||||
|
||||
{bold ENDPOINTS}
|
||||
|
||||
Listen endpoints (specified by the {bold --listen} or {bold -l} options above) instruct {cyan serve}
|
||||
to listen on one or more interfaces/ports, UNIX domain sockets, or Windows named pipes.
|
||||
|
||||
For TCP ports on hostname "localhost":
|
||||
|
||||
{bold $} {cyan serve} -l {underline 1234}
|
||||
|
||||
For TCP (traditional host/port) endpoints:
|
||||
|
||||
{bold $} {cyan serve} -l tcp://{underline hostname}:{underline 1234}
|
||||
|
||||
For UNIX domain socket endpoints:
|
||||
|
||||
{bold $} {cyan serve} -l unix:{underline /path/to/socket.sock}
|
||||
|
||||
For Windows named pipe endpoints:
|
||||
|
||||
{bold $} {cyan serve} -l pipe:\\\\.\\pipe\\{underline PipeName}
|
||||
`;
|
||||
var getHelpText = () => helpText;
|
||||
var parseEndpoint = (uriOrPort) => {
|
||||
if (!isNaN(Number(uriOrPort))) return { port: Number(uriOrPort) };
|
||||
const endpoint = uriOrPort;
|
||||
const url = parseUrl(endpoint);
|
||||
switch (url.protocol) {
|
||||
case "pipe:": {
|
||||
const pipe = endpoint.replace(/^pipe:/, "");
|
||||
if (!pipe.startsWith("\\\\.\\"))
|
||||
throw new Error(`Invalid Windows named pipe endpoint: ${endpoint}`);
|
||||
return { host: pipe };
|
||||
}
|
||||
case "unix:":
|
||||
if (!url.pathname)
|
||||
throw new Error(`Invalid UNIX domain socket endpoint: ${endpoint}`);
|
||||
return { host: url.pathname };
|
||||
case "tcp:":
|
||||
url.port = url.port ?? "3000";
|
||||
url.hostname = url.hostname ?? "localhost";
|
||||
return {
|
||||
port: Number(url.port),
|
||||
host: url.hostname
|
||||
};
|
||||
default:
|
||||
throw new Error(
|
||||
`Unknown --listen endpoint scheme (protocol): ${url.protocol ?? "undefined"}`
|
||||
);
|
||||
}
|
||||
};
|
||||
var options = {
|
||||
"--help": Boolean,
|
||||
"--version": Boolean,
|
||||
"--listen": [parseEndpoint],
|
||||
"--single": Boolean,
|
||||
"--debug": Boolean,
|
||||
"--config": String,
|
||||
"--no-clipboard": Boolean,
|
||||
"--no-compression": Boolean,
|
||||
"--no-etag": Boolean,
|
||||
"--symlinks": Boolean,
|
||||
"--cors": Boolean,
|
||||
"--no-port-switching": Boolean,
|
||||
"--ssl-cert": String,
|
||||
"--ssl-key": String,
|
||||
"--ssl-pass": String,
|
||||
"--no-request-logging": Boolean,
|
||||
// A list of aliases for the above options.
|
||||
"-h": "--help",
|
||||
"-v": "--version",
|
||||
"-l": "--listen",
|
||||
"-s": "--single",
|
||||
"-d": "--debug",
|
||||
"-c": "--config",
|
||||
"-n": "--no-clipboard",
|
||||
"-u": "--no-compression",
|
||||
"-S": "--symlinks",
|
||||
"-C": "--cors",
|
||||
"-L": "--no-request-logging",
|
||||
// The `-p` option is deprecated and is kept only for backwards-compatibility.
|
||||
"-p": "--listen"
|
||||
};
|
||||
var parseArguments = () => parseArgv(options);
|
||||
var checkForUpdates = async (manifest) => {
|
||||
if (env.NO_UPDATE_CHECK) return;
|
||||
const [error2, update] = await resolve(checkForUpdate(manifest));
|
||||
if (error2) throw error2;
|
||||
if (!update) return;
|
||||
logger.log(
|
||||
chalk3.bgRed.white(" UPDATE "),
|
||||
`The latest version of \`serve\` is ${update.latest}`
|
||||
);
|
||||
};
|
||||
|
||||
// source/utilities/config.ts
|
||||
import {
|
||||
resolve as resolvePath,
|
||||
relative as resolveRelativePath
|
||||
} from "node:path";
|
||||
import { readFile as readFile2 } from "node:fs/promises";
|
||||
import Ajv from "ajv";
|
||||
import schema from "@zeit/schemas/deployment/config-static.js";
|
||||
var loadConfiguration = async (presentDirectory2, directoryToServe2, args2) => {
|
||||
const files = ["serve.json", "now.json", "package.json"];
|
||||
if (args2["--config"]) files.unshift(args2["--config"]);
|
||||
const config2 = {};
|
||||
for (const file of files) {
|
||||
const location = resolvePath(directoryToServe2, file);
|
||||
const [error2, rawContents] = await resolve(
|
||||
readFile2(location, "utf8")
|
||||
);
|
||||
if (error2) {
|
||||
if (error2.code === "ENOENT" && file !== args2["--config"]) continue;
|
||||
else
|
||||
throw new Error(
|
||||
`Could not read configuration from file ${location}: ${error2.message}`
|
||||
);
|
||||
}
|
||||
let parsedJson;
|
||||
try {
|
||||
parsedJson = JSON.parse(rawContents);
|
||||
if (typeof parsedJson !== "object")
|
||||
throw new Error("configuration is not an object");
|
||||
} catch (parserError) {
|
||||
throw new Error(
|
||||
`Could not parse ${location} as JSON: ${parserError.message}`
|
||||
);
|
||||
}
|
||||
if (file === "now.json") {
|
||||
parsedJson = parsedJson;
|
||||
parsedJson = parsedJson.now.static;
|
||||
} else if (file === "package.json") {
|
||||
parsedJson = parsedJson;
|
||||
parsedJson = parsedJson.static;
|
||||
}
|
||||
if (!parsedJson) continue;
|
||||
Object.assign(config2, parsedJson);
|
||||
if (file === "now.json" || file === "package.json")
|
||||
logger.warn(
|
||||
"The config files `now.json` and `package.json` are deprecated. Please use `serve.json`."
|
||||
);
|
||||
break;
|
||||
}
|
||||
if (directoryToServe2) {
|
||||
const staticDirectory = config2.public;
|
||||
config2.public = resolveRelativePath(
|
||||
presentDirectory2,
|
||||
staticDirectory ? resolvePath(directoryToServe2, staticDirectory) : directoryToServe2
|
||||
);
|
||||
}
|
||||
if (Object.keys(config2).length !== 0) {
|
||||
const ajv = new Ajv({ allowUnionTypes: true });
|
||||
const validate = ajv.compile(schema);
|
||||
if (!validate(config2) && validate.errors) {
|
||||
const defaultMessage = "The configuration you provided is invalid:";
|
||||
const error2 = validate.errors[0];
|
||||
throw new Error(
|
||||
`${defaultMessage}
|
||||
${error2.message ?? ""}
|
||||
${JSON.stringify(
|
||||
error2.params
|
||||
)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
config2.etag = !args2["--no-etag"];
|
||||
config2.symlinks = args2["--symlinks"] || config2.symlinks;
|
||||
return config2;
|
||||
};
|
||||
|
||||
// source/main.ts
|
||||
var [parseError, args] = await resolve(parseArguments());
|
||||
if (parseError || !args) {
|
||||
logger.error(parseError.message);
|
||||
exit(1);
|
||||
}
|
||||
var [updateError] = await resolve(checkForUpdates(package_default));
|
||||
if (updateError) {
|
||||
const suffix = args["--debug"] ? ":" : " (use `--debug` to see full error)";
|
||||
logger.warn(`Checking for updates failed${suffix}`);
|
||||
if (args["--debug"]) logger.error(updateError.message);
|
||||
}
|
||||
if (args["--version"]) {
|
||||
logger.log(package_default.version);
|
||||
exit(0);
|
||||
}
|
||||
if (args["--help"]) {
|
||||
logger.log(getHelpText());
|
||||
exit(0);
|
||||
}
|
||||
if (!args["--listen"])
|
||||
args["--listen"] = [{ port: parseInt(env2.PORT ?? "3000", 10) }];
|
||||
if (args._.length > 1) {
|
||||
logger.error("Please provide one path argument at maximum");
|
||||
exit(1);
|
||||
}
|
||||
var presentDirectory = getPwd();
|
||||
var directoryToServe = args._[0] ? path.resolve(args._[0]) : presentDirectory;
|
||||
var [configError, config] = await resolve(
|
||||
loadConfiguration(presentDirectory, directoryToServe, args)
|
||||
);
|
||||
if (configError || !config) {
|
||||
logger.error(configError.message);
|
||||
exit(1);
|
||||
}
|
||||
if (args["--single"]) {
|
||||
const { rewrites } = config;
|
||||
const existingRewrites = Array.isArray(rewrites) ? rewrites : [];
|
||||
config.rewrites = [
|
||||
{
|
||||
source: "**",
|
||||
destination: "/index.html"
|
||||
},
|
||||
...existingRewrites
|
||||
];
|
||||
}
|
||||
for (const endpoint of args["--listen"]) {
|
||||
const { local, network, previous } = await startServer(
|
||||
endpoint,
|
||||
config,
|
||||
args
|
||||
);
|
||||
const copyAddress = !args["--no-clipboard"];
|
||||
if (!stdout.isTTY || env2.NODE_ENV === "production") {
|
||||
const suffix = local ? ` at ${local}` : "";
|
||||
logger.info(`Accepting connections${suffix}`);
|
||||
continue;
|
||||
}
|
||||
let message = chalk4.green("Serving!");
|
||||
if (local) {
|
||||
const prefix = network ? "- " : "";
|
||||
const space = network ? " " : " ";
|
||||
message += `
|
||||
|
||||
${chalk4.bold(`${prefix}Local:`)}${space}${local}`;
|
||||
}
|
||||
if (network) message += `
|
||||
${chalk4.bold("- Network:")} ${network}`;
|
||||
if (previous)
|
||||
message += chalk4.red(
|
||||
`
|
||||
|
||||
This port was picked because ${chalk4.underline(
|
||||
previous.toString()
|
||||
)} is in use.`
|
||||
);
|
||||
if (copyAddress && local) {
|
||||
try {
|
||||
await clipboard.write(local);
|
||||
message += `
|
||||
|
||||
${chalk4.grey("Copied local address to clipboard!")}`;
|
||||
} catch (error2) {
|
||||
logger.error(
|
||||
`Cannot copy server address to clipboard: ${error2.message}.`
|
||||
);
|
||||
}
|
||||
}
|
||||
logger.log(
|
||||
boxen(message, {
|
||||
padding: 1,
|
||||
borderColor: "green",
|
||||
margin: 1
|
||||
})
|
||||
);
|
||||
}
|
||||
registerCloseListener(() => {
|
||||
logger.log();
|
||||
logger.info("Gracefully shutting down. Please wait...");
|
||||
process.on("SIGINT", () => {
|
||||
logger.log();
|
||||
logger.warn("Force-closing all open sockets...");
|
||||
exit(0);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user