initial commit
This commit is contained in:
21
node_modules/listhen/LICENSE
generated
vendored
Normal file
21
node_modules/listhen/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) Pooya Parsa <pooya@pi0.io>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
168
node_modules/listhen/README.md
generated
vendored
Normal file
168
node_modules/listhen/README.md
generated
vendored
Normal file
@@ -0,0 +1,168 @@
|
||||

|
||||
|
||||
# 👂 listhen
|
||||
|
||||
> Elegant http listener
|
||||
|
||||
[![npm version][npm-version-src]][npm-version-href]
|
||||
[![npm downloads][npm-downloads-src]][npm-downloads-href]
|
||||
[![Github Actions][github-actions-src]][github-actions-href]
|
||||
[![Codecov][codecov-src]][codecov-href]
|
||||
|
||||
✔️ Promisified interface for listening and closing server
|
||||
|
||||
✔️ Works with express/connect or plain http handle function
|
||||
|
||||
✔️ Support HTTP and HTTPS
|
||||
|
||||
✔️ Automatically assign a port or fallback to human friendly alternative (with [get-port-please](https://github.com/unjs/get-port-please))
|
||||
|
||||
✔️ Automatically generate listening URL and show on console
|
||||
|
||||
✔️ Automatically copy URL to clipboard
|
||||
|
||||
✔️ Automatically open in browser (opt-in)
|
||||
|
||||
✔️ Automatically generate self-signed certificate
|
||||
|
||||
✔️ Automatically detect test and production environments
|
||||
|
||||
✔️ Automatically close on exit signal
|
||||
|
||||
✔️ Gracefully shutdown server with [http-shutdown](https://github.com/thedillonb/http-shutdown)
|
||||
|
||||
## Install
|
||||
|
||||
Install using npm or yarn:
|
||||
|
||||
```bash
|
||||
npm i listhen
|
||||
# or
|
||||
yarn add listhen
|
||||
```
|
||||
|
||||
Import into your Node.js project:
|
||||
|
||||
```js
|
||||
// CommonJS
|
||||
const { listen } = require('listhen')
|
||||
|
||||
// ESM
|
||||
import { listen } from 'listhen'
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
**Function signature:**
|
||||
|
||||
```ts
|
||||
const { url, getURL, server, close } = await listen(handle, options?)
|
||||
```
|
||||
|
||||
**Plain handle function:**
|
||||
|
||||
```ts
|
||||
listen((_req, res) => {
|
||||
res.end('hi')
|
||||
})
|
||||
```
|
||||
|
||||
**With express/connect:**
|
||||
|
||||
```ts
|
||||
const express = require('express')
|
||||
const app = express()
|
||||
|
||||
app.use('/', ((_req, res) => {
|
||||
res.end('hi')
|
||||
})
|
||||
|
||||
listen(app)
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
### `port`
|
||||
|
||||
- Default: `process.env.PORT` or 3000 or memorized random (see [get-port-please](https://github.com/unjs/get-port-please))
|
||||
|
||||
Port to listen.
|
||||
|
||||
### `hostname`
|
||||
|
||||
- Default: `process.env.HOST || '0.0.0.0'`
|
||||
|
||||
Default hostname to listen.
|
||||
|
||||
### `https`
|
||||
|
||||
- Type: Boolean | Object
|
||||
- Default: `false`
|
||||
|
||||
Listen on https with SSL enabled.
|
||||
|
||||
#### Self Signed Certificate
|
||||
|
||||
By setting `https: true`, listhen will use an auto generated self-signed certificate.
|
||||
|
||||
You can set https to an object for custom options. Possible options:
|
||||
|
||||
- `domains`: (Array) Default is `['localhost', '127.0.0.1', '::1']`.
|
||||
- `validityDays`: (Number) Default is `1`.
|
||||
|
||||
#### User Provided Certificate
|
||||
|
||||
Set `https: { cert, key }` where cert and key are path to the ssl certificates.
|
||||
|
||||
You can also provide inline cert and key instead of reading from filesystem. In this case, they should start with `--`.
|
||||
|
||||
### `showURL`
|
||||
|
||||
- Default: `true` (force disabled on test environment)
|
||||
|
||||
Show a CLI message for listening URL.
|
||||
|
||||
### `baseURL`
|
||||
|
||||
- Default: `/`
|
||||
|
||||
### `open`
|
||||
|
||||
- Default: `false` (force disabled on test and production environments)
|
||||
|
||||
Open URL in browser. Silently ignores errors.
|
||||
|
||||
### `clipboard`
|
||||
|
||||
- Default: `false` (force disabled on test and production environments)
|
||||
|
||||
Copy URL to clipboard. Silently ignores errors.
|
||||
|
||||
### `isTest`
|
||||
|
||||
- Default: `process.env.NODE_ENV === 'test'`
|
||||
|
||||
Detect if running in a test environment to disable some features.
|
||||
|
||||
### `autoClose`
|
||||
|
||||
- Default: `true`
|
||||
|
||||
Automatically close when an exit signal is received on process.
|
||||
|
||||
## License
|
||||
|
||||
MIT. Made with 💖
|
||||
|
||||
<!-- Badges -->
|
||||
[npm-version-src]: https://img.shields.io/npm/v/listhen?style=flat-square
|
||||
[npm-version-href]: https://npmjs.com/package/listhen
|
||||
|
||||
[npm-downloads-src]: https://img.shields.io/npm/dm/listhen?style=flat-square
|
||||
[npm-downloads-href]: https://npmjs.com/package/listhen
|
||||
|
||||
[github-actions-src]: https://img.shields.io/github/workflow/status/unjs/listhen/ci/main?style=flat-square
|
||||
[github-actions-href]: https://github.com/unjs/listhen/actions?query=workflow%3Aci
|
||||
|
||||
[codecov-src]: https://img.shields.io/codecov/c/gh/unjs/listhen/main?style=flat-square
|
||||
[codecov-href]: https://codecov.io/gh/unjs/listhen
|
||||
78
node_modules/listhen/dist/chunks/cert.cjs
generated
vendored
Normal file
78
node_modules/listhen/dist/chunks/cert.cjs
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
'use strict';
|
||||
|
||||
const node_util = require('node:util');
|
||||
const forge = require('node-forge');
|
||||
const ipRegex = require('ip-regex');
|
||||
|
||||
async function generateSSLCert(options) {
|
||||
const attributes = [
|
||||
{ name: "commonName", value: options.commonName || options.domains[0] }
|
||||
];
|
||||
const extensions = [
|
||||
{ name: "basicConstraints", cA: false, critical: true },
|
||||
{ name: "keyUsage", digitalSignature: true, keyEncipherment: true, critical: true },
|
||||
{ name: "extKeyUsage", serverAuth: true, clientAuth: true },
|
||||
{
|
||||
name: "subjectAltName",
|
||||
altNames: options.domains.map((domain) => {
|
||||
const types = { domain: 2, ip: 7 };
|
||||
const isIp = ipRegex({ exact: true }).test(domain);
|
||||
if (isIp) {
|
||||
return { type: types.ip, ip: domain };
|
||||
}
|
||||
return { type: types.domain, value: domain };
|
||||
})
|
||||
}
|
||||
];
|
||||
const ca = forge.pki.certificateFromPem(options.caCert);
|
||||
return await generateCert({
|
||||
subject: attributes,
|
||||
issuer: ca.subject.attributes,
|
||||
extensions,
|
||||
validityDays: options.validityDays,
|
||||
signWith: options.caKey
|
||||
});
|
||||
}
|
||||
async function generateCA(options = {}) {
|
||||
const attributes = [
|
||||
options.commonName && { name: "commonName", value: options.commonName },
|
||||
options.countryCode && { name: "countryName", value: options.countryCode },
|
||||
options.state && { name: "stateOrProvinceName", value: options.state },
|
||||
options.locality && { name: "localityName", value: options.locality },
|
||||
options.organization && { name: "organizationName", value: options.organization }
|
||||
].filter(Boolean);
|
||||
const extensions = [
|
||||
{ name: "basicConstraints", cA: true, critical: true },
|
||||
{ name: "keyUsage", keyCertSign: true, critical: true }
|
||||
];
|
||||
return await generateCert({
|
||||
subject: attributes,
|
||||
issuer: attributes,
|
||||
extensions,
|
||||
validityDays: options.validityDays || 365
|
||||
});
|
||||
}
|
||||
async function generateCert(options) {
|
||||
const serial = Math.floor(Math.random() * 95e3 + 5e4).toString();
|
||||
const generateKeyPair = node_util.promisify(forge.pki.rsa.generateKeyPair.bind(forge.pki.rsa));
|
||||
const keyPair = await generateKeyPair({ bits: 2048, workers: 4 });
|
||||
const cert = forge.pki.createCertificate();
|
||||
cert.publicKey = keyPair.publicKey;
|
||||
cert.serialNumber = Buffer.from(serial).toString("hex");
|
||||
cert.validity.notBefore = new Date();
|
||||
cert.validity.notAfter = new Date();
|
||||
cert.validity.notAfter.setDate(cert.validity.notAfter.getDate() + options.validityDays);
|
||||
cert.setSubject(options.subject);
|
||||
cert.setIssuer(options.issuer);
|
||||
cert.setExtensions(options.extensions);
|
||||
const signWith = options.signWith ? forge.pki.privateKeyFromPem(options.signWith) : keyPair.privateKey;
|
||||
cert.sign(signWith, forge.md.sha256.create());
|
||||
return {
|
||||
key: forge.pki.privateKeyToPem(keyPair.privateKey),
|
||||
cert: forge.pki.certificateToPem(cert)
|
||||
};
|
||||
}
|
||||
|
||||
exports.generateCA = generateCA;
|
||||
exports.generateCert = generateCert;
|
||||
exports.generateSSLCert = generateSSLCert;
|
||||
74
node_modules/listhen/dist/chunks/cert.mjs
generated
vendored
Normal file
74
node_modules/listhen/dist/chunks/cert.mjs
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
import { promisify } from 'node:util';
|
||||
import forge from 'node-forge';
|
||||
import ipRegex from 'ip-regex';
|
||||
|
||||
async function generateSSLCert(options) {
|
||||
const attributes = [
|
||||
{ name: "commonName", value: options.commonName || options.domains[0] }
|
||||
];
|
||||
const extensions = [
|
||||
{ name: "basicConstraints", cA: false, critical: true },
|
||||
{ name: "keyUsage", digitalSignature: true, keyEncipherment: true, critical: true },
|
||||
{ name: "extKeyUsage", serverAuth: true, clientAuth: true },
|
||||
{
|
||||
name: "subjectAltName",
|
||||
altNames: options.domains.map((domain) => {
|
||||
const types = { domain: 2, ip: 7 };
|
||||
const isIp = ipRegex({ exact: true }).test(domain);
|
||||
if (isIp) {
|
||||
return { type: types.ip, ip: domain };
|
||||
}
|
||||
return { type: types.domain, value: domain };
|
||||
})
|
||||
}
|
||||
];
|
||||
const ca = forge.pki.certificateFromPem(options.caCert);
|
||||
return await generateCert({
|
||||
subject: attributes,
|
||||
issuer: ca.subject.attributes,
|
||||
extensions,
|
||||
validityDays: options.validityDays,
|
||||
signWith: options.caKey
|
||||
});
|
||||
}
|
||||
async function generateCA(options = {}) {
|
||||
const attributes = [
|
||||
options.commonName && { name: "commonName", value: options.commonName },
|
||||
options.countryCode && { name: "countryName", value: options.countryCode },
|
||||
options.state && { name: "stateOrProvinceName", value: options.state },
|
||||
options.locality && { name: "localityName", value: options.locality },
|
||||
options.organization && { name: "organizationName", value: options.organization }
|
||||
].filter(Boolean);
|
||||
const extensions = [
|
||||
{ name: "basicConstraints", cA: true, critical: true },
|
||||
{ name: "keyUsage", keyCertSign: true, critical: true }
|
||||
];
|
||||
return await generateCert({
|
||||
subject: attributes,
|
||||
issuer: attributes,
|
||||
extensions,
|
||||
validityDays: options.validityDays || 365
|
||||
});
|
||||
}
|
||||
async function generateCert(options) {
|
||||
const serial = Math.floor(Math.random() * 95e3 + 5e4).toString();
|
||||
const generateKeyPair = promisify(forge.pki.rsa.generateKeyPair.bind(forge.pki.rsa));
|
||||
const keyPair = await generateKeyPair({ bits: 2048, workers: 4 });
|
||||
const cert = forge.pki.createCertificate();
|
||||
cert.publicKey = keyPair.publicKey;
|
||||
cert.serialNumber = Buffer.from(serial).toString("hex");
|
||||
cert.validity.notBefore = new Date();
|
||||
cert.validity.notAfter = new Date();
|
||||
cert.validity.notAfter.setDate(cert.validity.notAfter.getDate() + options.validityDays);
|
||||
cert.setSubject(options.subject);
|
||||
cert.setIssuer(options.issuer);
|
||||
cert.setExtensions(options.extensions);
|
||||
const signWith = options.signWith ? forge.pki.privateKeyFromPem(options.signWith) : keyPair.privateKey;
|
||||
cert.sign(signWith, forge.md.sha256.create());
|
||||
return {
|
||||
key: forge.pki.privateKeyToPem(keyPair.privateKey),
|
||||
cert: forge.pki.certificateToPem(cert)
|
||||
};
|
||||
}
|
||||
|
||||
export { generateCA, generateCert, generateSSLCert };
|
||||
1071
node_modules/listhen/dist/chunks/xdg-open.cjs
generated
vendored
Normal file
1071
node_modules/listhen/dist/chunks/xdg-open.cjs
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1069
node_modules/listhen/dist/chunks/xdg-open.mjs
generated
vendored
Normal file
1069
node_modules/listhen/dist/chunks/xdg-open.mjs
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
451
node_modules/listhen/dist/index.cjs
generated
vendored
Normal file
451
node_modules/listhen/dist/index.cjs
generated
vendored
Normal file
@@ -0,0 +1,451 @@
|
||||
'use strict';
|
||||
|
||||
const node_http = require('node:http');
|
||||
const node_https = require('node:https');
|
||||
const node_util = require('node:util');
|
||||
const node_fs = require('node:fs');
|
||||
const os = require('node:os');
|
||||
const colorette = require('colorette');
|
||||
const getPortPlease = require('get-port-please');
|
||||
const addShutdown = require('http-shutdown');
|
||||
const defu = require('defu');
|
||||
const childProcess = require('node:child_process');
|
||||
const node_path = require('node:path');
|
||||
|
||||
const { platform, arch } = process;
|
||||
const getWslDrivesMountPoint = (() => {
|
||||
const defaultMountPoint = "/mnt/";
|
||||
let mountPoint;
|
||||
return async function() {
|
||||
if (mountPoint) {
|
||||
return mountPoint;
|
||||
}
|
||||
const configFilePath = "/etc/wsl.conf";
|
||||
let isConfigFileExists = false;
|
||||
try {
|
||||
await node_fs.promises.access(configFilePath, node_fs.constants.F_OK);
|
||||
isConfigFileExists = true;
|
||||
} catch {
|
||||
}
|
||||
if (!isConfigFileExists) {
|
||||
return defaultMountPoint;
|
||||
}
|
||||
const configContent = await node_fs.promises.readFile(configFilePath, { encoding: "utf8" });
|
||||
const configMountPoint = /(?<!#.*)root\s*=\s*(?<mountPoint>.*)/g.exec(configContent);
|
||||
if (!configMountPoint) {
|
||||
return defaultMountPoint;
|
||||
}
|
||||
mountPoint = configMountPoint.groups.mountPoint.trim();
|
||||
mountPoint = mountPoint.endsWith("/") ? mountPoint : `${mountPoint}/`;
|
||||
return mountPoint;
|
||||
};
|
||||
})();
|
||||
const pTryEach = async (array, mapper) => {
|
||||
let latestError;
|
||||
for (const item of array) {
|
||||
try {
|
||||
return await mapper(item);
|
||||
} catch (error) {
|
||||
latestError = error;
|
||||
}
|
||||
}
|
||||
throw latestError;
|
||||
};
|
||||
const baseOpen = async (options) => {
|
||||
options = {
|
||||
wait: false,
|
||||
background: false,
|
||||
newInstance: false,
|
||||
allowNonzeroExitCode: false,
|
||||
...options
|
||||
};
|
||||
if (Array.isArray(options.app)) {
|
||||
return pTryEach(options.app, (singleApp) => baseOpen({
|
||||
...options,
|
||||
app: singleApp
|
||||
}));
|
||||
}
|
||||
let { name: app, arguments: appArguments = [] } = options.app || {};
|
||||
appArguments = [...appArguments];
|
||||
if (Array.isArray(app)) {
|
||||
return pTryEach(app, (appName) => baseOpen({
|
||||
...options,
|
||||
app: {
|
||||
name: appName,
|
||||
arguments: appArguments
|
||||
}
|
||||
}));
|
||||
}
|
||||
let command;
|
||||
const cliArguments = [];
|
||||
const childProcessOptions = {};
|
||||
if (platform === "darwin") {
|
||||
command = "open";
|
||||
if (options.wait) {
|
||||
cliArguments.push("--wait-apps");
|
||||
}
|
||||
if (options.background) {
|
||||
cliArguments.push("--background");
|
||||
}
|
||||
if (options.newInstance) {
|
||||
cliArguments.push("--new");
|
||||
}
|
||||
if (app) {
|
||||
cliArguments.push("-a", app);
|
||||
}
|
||||
} else if (platform === "win32" || isWsl() && !isDocker()) {
|
||||
const mountPoint = await getWslDrivesMountPoint();
|
||||
command = isWsl() ? `${mountPoint}c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe` : `${process.env.SYSTEMROOT}\\System32\\WindowsPowerShell\\v1.0\\powershell`;
|
||||
cliArguments.push(
|
||||
"-NoProfile",
|
||||
"-NonInteractive",
|
||||
"\u2013ExecutionPolicy",
|
||||
"Bypass",
|
||||
"-EncodedCommand"
|
||||
);
|
||||
if (!isWsl()) {
|
||||
childProcessOptions.windowsVerbatimArguments = true;
|
||||
}
|
||||
const encodedArguments = ["Start"];
|
||||
if (options.wait) {
|
||||
encodedArguments.push("-Wait");
|
||||
}
|
||||
if (app) {
|
||||
encodedArguments.push(`"\`"${app}\`""`, "-ArgumentList");
|
||||
if (options.target) {
|
||||
appArguments.unshift(options.target);
|
||||
}
|
||||
} else if (options.target) {
|
||||
encodedArguments.push(`"${options.target}"`);
|
||||
}
|
||||
if (appArguments.length > 0) {
|
||||
appArguments = appArguments.map((argument) => `"\`"${argument}\`""`);
|
||||
encodedArguments.push(appArguments.join(","));
|
||||
}
|
||||
options.target = Buffer.from(encodedArguments.join(" "), "utf16le").toString("base64");
|
||||
} else {
|
||||
if (app) {
|
||||
command = app;
|
||||
} else {
|
||||
command = "xdg-open";
|
||||
const useSystemXdgOpen = process.versions.electron || platform === "android";
|
||||
if (!useSystemXdgOpen) {
|
||||
command = node_path.join(os.tmpdir(), "xdg-open");
|
||||
if (!node_fs.existsSync(command)) {
|
||||
try {
|
||||
node_fs.writeFileSync(
|
||||
node_path.join(os.tmpdir(), "xdg-open"),
|
||||
await import('./chunks/xdg-open.cjs').then((r) => r.xdgOpenScript()),
|
||||
"utf8"
|
||||
);
|
||||
node_fs.chmodSync(command, 493);
|
||||
} catch {
|
||||
command = "xdg-open";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (appArguments.length > 0) {
|
||||
cliArguments.push(...appArguments);
|
||||
}
|
||||
if (!options.wait) {
|
||||
childProcessOptions.stdio = "ignore";
|
||||
childProcessOptions.detached = true;
|
||||
}
|
||||
}
|
||||
if (options.target) {
|
||||
cliArguments.push(options.target);
|
||||
}
|
||||
if (platform === "darwin" && appArguments.length > 0) {
|
||||
cliArguments.push("--args", ...appArguments);
|
||||
}
|
||||
const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);
|
||||
if (options.wait) {
|
||||
return new Promise((resolve, reject) => {
|
||||
subprocess.once("error", reject);
|
||||
subprocess.once("close", (exitCode) => {
|
||||
if (options.allowNonzeroExitCode && exitCode > 0) {
|
||||
reject(new Error(`Exited with code ${exitCode}`));
|
||||
return;
|
||||
}
|
||||
resolve(subprocess);
|
||||
});
|
||||
});
|
||||
}
|
||||
subprocess.unref();
|
||||
return subprocess;
|
||||
};
|
||||
const open = (target, options = {}) => {
|
||||
if (typeof target !== "string") {
|
||||
throw new TypeError("Expected a `target`");
|
||||
}
|
||||
return baseOpen({
|
||||
...options,
|
||||
target
|
||||
});
|
||||
};
|
||||
const openApp = (name, options) => {
|
||||
if (typeof name !== "string") {
|
||||
throw new TypeError("Expected a `name`");
|
||||
}
|
||||
const { arguments: appArguments = [] } = options || {};
|
||||
if (appArguments !== void 0 && appArguments !== null && !Array.isArray(appArguments)) {
|
||||
throw new TypeError("Expected `appArguments` as Array type");
|
||||
}
|
||||
return baseOpen({
|
||||
...options,
|
||||
app: {
|
||||
name,
|
||||
arguments: appArguments
|
||||
}
|
||||
});
|
||||
};
|
||||
function detectArchBinary(binary) {
|
||||
if (typeof binary === "string" || Array.isArray(binary)) {
|
||||
return binary;
|
||||
}
|
||||
const { [arch]: archBinary } = binary;
|
||||
if (!archBinary) {
|
||||
throw new Error(`${arch} is not supported`);
|
||||
}
|
||||
return archBinary;
|
||||
}
|
||||
function detectPlatformBinary({ [platform]: platformBinary }, { wsl }) {
|
||||
if (wsl && isWsl()) {
|
||||
return detectArchBinary(wsl);
|
||||
}
|
||||
if (!platformBinary) {
|
||||
throw new Error(`${platform} is not supported`);
|
||||
}
|
||||
return detectArchBinary(platformBinary);
|
||||
}
|
||||
const apps = {};
|
||||
defineLazyProperty(apps, "chrome", () => detectPlatformBinary({
|
||||
darwin: "google chrome",
|
||||
win32: "chrome",
|
||||
linux: ["google-chrome", "google-chrome-stable", "chromium"]
|
||||
}, {
|
||||
wsl: {
|
||||
ia32: "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe",
|
||||
x64: ["/mnt/c/Program Files/Google/Chrome/Application/chrome.exe", "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe"]
|
||||
}
|
||||
}));
|
||||
defineLazyProperty(apps, "firefox", () => detectPlatformBinary({
|
||||
darwin: "firefox",
|
||||
win32: "C:\\Program Files\\Mozilla Firefox\\firefox.exe",
|
||||
linux: "firefox"
|
||||
}, {
|
||||
wsl: "/mnt/c/Program Files/Mozilla Firefox/firefox.exe"
|
||||
}));
|
||||
defineLazyProperty(apps, "edge", () => detectPlatformBinary({
|
||||
darwin: "microsoft edge",
|
||||
win32: "msedge",
|
||||
linux: ["microsoft-edge", "microsoft-edge-dev"]
|
||||
}, {
|
||||
wsl: "/mnt/c/Program Files (x86)/Microsoft/Edge/Application/msedge.exe"
|
||||
}));
|
||||
open.apps = apps;
|
||||
open.openApp = openApp;
|
||||
function defineLazyProperty(object, propertyName, valueGetter) {
|
||||
const define = (value) => Object.defineProperty(object, propertyName, { value, enumerable: true, writable: true });
|
||||
Object.defineProperty(object, propertyName, {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
get() {
|
||||
const result = valueGetter();
|
||||
define(result);
|
||||
return result;
|
||||
},
|
||||
set(value) {
|
||||
define(value);
|
||||
}
|
||||
});
|
||||
return object;
|
||||
}
|
||||
function _isWsl() {
|
||||
if (process.platform !== "linux") {
|
||||
return false;
|
||||
}
|
||||
if (os.release().toLowerCase().includes("microsoft")) {
|
||||
if (isDocker()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
return node_fs.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft") ? !isDocker() : false;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
let isWSLCached;
|
||||
function isWsl() {
|
||||
if (isWSLCached === void 0) {
|
||||
isWSLCached = _isWsl();
|
||||
}
|
||||
return isWSLCached;
|
||||
}
|
||||
function hasDockerEnvironment() {
|
||||
try {
|
||||
node_fs.statSync("/.dockerenv");
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
function hasDockerCGroup() {
|
||||
try {
|
||||
return node_fs.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
let isDockerCached;
|
||||
function isDocker() {
|
||||
if (isDockerCached === void 0) {
|
||||
isDockerCached = hasDockerEnvironment() || hasDockerCGroup();
|
||||
}
|
||||
return isDockerCached;
|
||||
}
|
||||
|
||||
async function listen(handle, options_ = {}) {
|
||||
options_ = defu.defu(options_, {
|
||||
port: process.env.PORT || 3e3,
|
||||
hostname: process.env.HOST || "",
|
||||
showURL: true,
|
||||
baseURL: "/",
|
||||
open: false,
|
||||
clipboard: false,
|
||||
isTest: process.env.NODE_ENV === "test",
|
||||
isProd: process.env.NODE_ENV === "production",
|
||||
autoClose: true
|
||||
});
|
||||
if (options_.isTest) {
|
||||
options_.showURL = false;
|
||||
}
|
||||
if (options_.isProd || options_.isTest) {
|
||||
options_.open = false;
|
||||
options_.clipboard = false;
|
||||
}
|
||||
const port = await getPortPlease.getPort({
|
||||
port: Number(options_.port),
|
||||
verbose: !options_.isTest,
|
||||
host: options_.hostname,
|
||||
...typeof options_.port === "object" && options_.port
|
||||
});
|
||||
let server;
|
||||
let addr;
|
||||
const getURL = (host, baseURL) => {
|
||||
const anyV4 = addr?.addr === "0.0.0.0";
|
||||
const anyV6 = addr?.addr === "[::]";
|
||||
return `${addr.proto}://${host || options_.hostname || (anyV4 || anyV6 ? "localhost" : addr.addr)}:${addr.port}${baseURL || options_.baseURL}`;
|
||||
};
|
||||
let https = false;
|
||||
if (options_.https) {
|
||||
const { key, cert } = await resolveCert({ ...options_.https }, options_.hostname);
|
||||
https = { key, cert };
|
||||
server = node_https.createServer({ key, cert }, handle);
|
||||
addShutdown(server);
|
||||
await node_util.promisify(server.listen.bind(server))(port, options_.hostname);
|
||||
const _addr = server.address();
|
||||
addr = { proto: "https", addr: formatAddress(_addr), port: _addr.port };
|
||||
} else {
|
||||
server = node_http.createServer(handle);
|
||||
addShutdown(server);
|
||||
await node_util.promisify(server.listen.bind(server))(port, options_.hostname);
|
||||
const _addr = server.address();
|
||||
addr = { proto: "http", addr: formatAddress(_addr), port: _addr.port };
|
||||
}
|
||||
let _closed = false;
|
||||
const close = () => {
|
||||
if (_closed) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
_closed = true;
|
||||
return node_util.promisify(server.shutdown)();
|
||||
};
|
||||
if (options_.clipboard) {
|
||||
const clipboardy = await import('clipboardy').then((r) => r.default || r);
|
||||
await clipboardy.write(getURL()).catch(() => {
|
||||
options_.clipboard = false;
|
||||
});
|
||||
}
|
||||
const showURL = (options) => {
|
||||
const add = options_.clipboard ? colorette.gray("(copied to clipboard)") : "";
|
||||
const lines = [];
|
||||
const baseURL = options?.baseURL || options_.baseURL || "";
|
||||
const name = options?.name ? ` (${options.name})` : "";
|
||||
const anyV4 = addr?.addr === "0.0.0.0";
|
||||
const anyV6 = addr?.addr === "[::]";
|
||||
if (anyV4 || anyV6) {
|
||||
lines.push(` > Local${name}: ${formatURL(getURL("localhost", baseURL))} ${add}`);
|
||||
for (const addr2 of getNetworkInterfaces(anyV4)) {
|
||||
lines.push(` > Network${name}: ${formatURL(getURL(addr2, baseURL))}`);
|
||||
}
|
||||
} else {
|
||||
lines.push(` > Listening${name}: ${formatURL(getURL(void 0, baseURL))} ${add}`);
|
||||
}
|
||||
console.log("\n" + lines.join("\n") + "\n");
|
||||
};
|
||||
if (options_.showURL) {
|
||||
showURL();
|
||||
}
|
||||
const _open = async () => {
|
||||
await open(getURL()).catch(() => {
|
||||
});
|
||||
};
|
||||
if (options_.open) {
|
||||
await _open();
|
||||
}
|
||||
if (options_.autoClose) {
|
||||
process.on("exit", () => close());
|
||||
}
|
||||
return {
|
||||
url: getURL(),
|
||||
https,
|
||||
server,
|
||||
open: _open,
|
||||
showURL,
|
||||
close
|
||||
};
|
||||
}
|
||||
async function resolveCert(options, host) {
|
||||
if (options.key && options.cert) {
|
||||
const isInline = (s = "") => s.startsWith("--");
|
||||
const r = (s) => isInline(s) ? s : node_fs.promises.readFile(s, "utf8");
|
||||
return {
|
||||
key: await r(options.key),
|
||||
cert: await r(options.cert)
|
||||
};
|
||||
}
|
||||
const { generateCA, generateSSLCert } = await import('./chunks/cert.cjs');
|
||||
const ca = await generateCA();
|
||||
const cert = await generateSSLCert({
|
||||
caCert: ca.cert,
|
||||
caKey: ca.key,
|
||||
domains: options.domains || ["localhost", "127.0.0.1", "::1", host].filter(Boolean),
|
||||
validityDays: options.validityDays || 1
|
||||
});
|
||||
return cert;
|
||||
}
|
||||
function getNetworkInterfaces(v4Only = true) {
|
||||
const addrs = /* @__PURE__ */ new Set();
|
||||
for (const details of Object.values(os.networkInterfaces())) {
|
||||
if (details) {
|
||||
for (const d of details) {
|
||||
if (!d.internal && !(d.mac === "00:00:00:00:00:00") && !d.address.startsWith("fe80::") && !(v4Only && (d.family === "IPv6" || +d.family === 6))) {
|
||||
addrs.add(formatAddress(d));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return [...addrs].sort();
|
||||
}
|
||||
function formatAddress(addr) {
|
||||
return addr.family === "IPv6" || addr.family === 6 ? `[${addr.address}]` : addr.address;
|
||||
}
|
||||
function formatURL(url) {
|
||||
return colorette.cyan(colorette.underline(decodeURI(url).replace(/:(\d+)\//g, `:${colorette.bold("$1")}/`)));
|
||||
}
|
||||
|
||||
exports.listen = listen;
|
||||
44
node_modules/listhen/dist/index.d.ts
generated
vendored
Normal file
44
node_modules/listhen/dist/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
import { Server, RequestListener } from 'node:http';
|
||||
import { Server as Server$1 } from 'node:https';
|
||||
import { GetPortInput } from 'get-port-please';
|
||||
|
||||
interface Certificate {
|
||||
key: string;
|
||||
cert: string;
|
||||
}
|
||||
interface HTTPSOptions {
|
||||
cert: string;
|
||||
key: string;
|
||||
domains?: string[];
|
||||
validityDays?: number;
|
||||
}
|
||||
interface ListenOptions {
|
||||
name: string;
|
||||
port?: GetPortInput;
|
||||
hostname: string;
|
||||
showURL: boolean;
|
||||
baseURL: string;
|
||||
open: boolean;
|
||||
https: boolean | HTTPSOptions;
|
||||
clipboard: boolean;
|
||||
isTest: Boolean;
|
||||
isProd: Boolean;
|
||||
autoClose: Boolean;
|
||||
autoCloseSignals: string[];
|
||||
}
|
||||
interface ShowURLOptions {
|
||||
baseURL: string;
|
||||
name?: string;
|
||||
}
|
||||
interface Listener {
|
||||
url: string;
|
||||
address: any;
|
||||
server: Server | Server$1;
|
||||
https: false | Certificate;
|
||||
close: () => Promise<void>;
|
||||
open: () => Promise<void>;
|
||||
showURL: (options?: Pick<ListenOptions, "baseURL">) => void;
|
||||
}
|
||||
declare function listen(handle: RequestListener, options_?: Partial<ListenOptions>): Promise<Listener>;
|
||||
|
||||
export { Certificate, HTTPSOptions, ListenOptions, Listener, ShowURLOptions, listen };
|
||||
449
node_modules/listhen/dist/index.mjs
generated
vendored
Normal file
449
node_modules/listhen/dist/index.mjs
generated
vendored
Normal file
@@ -0,0 +1,449 @@
|
||||
import { createServer as createServer$1 } from 'node:http';
|
||||
import { createServer } from 'node:https';
|
||||
import { promisify } from 'node:util';
|
||||
import { readFileSync, existsSync, writeFileSync, chmodSync, statSync, promises, constants } from 'node:fs';
|
||||
import os, { networkInterfaces } from 'node:os';
|
||||
import { gray, cyan, underline, bold } from 'colorette';
|
||||
import { getPort } from 'get-port-please';
|
||||
import addShutdown from 'http-shutdown';
|
||||
import { defu } from 'defu';
|
||||
import childProcess from 'node:child_process';
|
||||
import { join } from 'node:path';
|
||||
|
||||
const { platform, arch } = process;
|
||||
const getWslDrivesMountPoint = (() => {
|
||||
const defaultMountPoint = "/mnt/";
|
||||
let mountPoint;
|
||||
return async function() {
|
||||
if (mountPoint) {
|
||||
return mountPoint;
|
||||
}
|
||||
const configFilePath = "/etc/wsl.conf";
|
||||
let isConfigFileExists = false;
|
||||
try {
|
||||
await promises.access(configFilePath, constants.F_OK);
|
||||
isConfigFileExists = true;
|
||||
} catch {
|
||||
}
|
||||
if (!isConfigFileExists) {
|
||||
return defaultMountPoint;
|
||||
}
|
||||
const configContent = await promises.readFile(configFilePath, { encoding: "utf8" });
|
||||
const configMountPoint = /(?<!#.*)root\s*=\s*(?<mountPoint>.*)/g.exec(configContent);
|
||||
if (!configMountPoint) {
|
||||
return defaultMountPoint;
|
||||
}
|
||||
mountPoint = configMountPoint.groups.mountPoint.trim();
|
||||
mountPoint = mountPoint.endsWith("/") ? mountPoint : `${mountPoint}/`;
|
||||
return mountPoint;
|
||||
};
|
||||
})();
|
||||
const pTryEach = async (array, mapper) => {
|
||||
let latestError;
|
||||
for (const item of array) {
|
||||
try {
|
||||
return await mapper(item);
|
||||
} catch (error) {
|
||||
latestError = error;
|
||||
}
|
||||
}
|
||||
throw latestError;
|
||||
};
|
||||
const baseOpen = async (options) => {
|
||||
options = {
|
||||
wait: false,
|
||||
background: false,
|
||||
newInstance: false,
|
||||
allowNonzeroExitCode: false,
|
||||
...options
|
||||
};
|
||||
if (Array.isArray(options.app)) {
|
||||
return pTryEach(options.app, (singleApp) => baseOpen({
|
||||
...options,
|
||||
app: singleApp
|
||||
}));
|
||||
}
|
||||
let { name: app, arguments: appArguments = [] } = options.app || {};
|
||||
appArguments = [...appArguments];
|
||||
if (Array.isArray(app)) {
|
||||
return pTryEach(app, (appName) => baseOpen({
|
||||
...options,
|
||||
app: {
|
||||
name: appName,
|
||||
arguments: appArguments
|
||||
}
|
||||
}));
|
||||
}
|
||||
let command;
|
||||
const cliArguments = [];
|
||||
const childProcessOptions = {};
|
||||
if (platform === "darwin") {
|
||||
command = "open";
|
||||
if (options.wait) {
|
||||
cliArguments.push("--wait-apps");
|
||||
}
|
||||
if (options.background) {
|
||||
cliArguments.push("--background");
|
||||
}
|
||||
if (options.newInstance) {
|
||||
cliArguments.push("--new");
|
||||
}
|
||||
if (app) {
|
||||
cliArguments.push("-a", app);
|
||||
}
|
||||
} else if (platform === "win32" || isWsl() && !isDocker()) {
|
||||
const mountPoint = await getWslDrivesMountPoint();
|
||||
command = isWsl() ? `${mountPoint}c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe` : `${process.env.SYSTEMROOT}\\System32\\WindowsPowerShell\\v1.0\\powershell`;
|
||||
cliArguments.push(
|
||||
"-NoProfile",
|
||||
"-NonInteractive",
|
||||
"\u2013ExecutionPolicy",
|
||||
"Bypass",
|
||||
"-EncodedCommand"
|
||||
);
|
||||
if (!isWsl()) {
|
||||
childProcessOptions.windowsVerbatimArguments = true;
|
||||
}
|
||||
const encodedArguments = ["Start"];
|
||||
if (options.wait) {
|
||||
encodedArguments.push("-Wait");
|
||||
}
|
||||
if (app) {
|
||||
encodedArguments.push(`"\`"${app}\`""`, "-ArgumentList");
|
||||
if (options.target) {
|
||||
appArguments.unshift(options.target);
|
||||
}
|
||||
} else if (options.target) {
|
||||
encodedArguments.push(`"${options.target}"`);
|
||||
}
|
||||
if (appArguments.length > 0) {
|
||||
appArguments = appArguments.map((argument) => `"\`"${argument}\`""`);
|
||||
encodedArguments.push(appArguments.join(","));
|
||||
}
|
||||
options.target = Buffer.from(encodedArguments.join(" "), "utf16le").toString("base64");
|
||||
} else {
|
||||
if (app) {
|
||||
command = app;
|
||||
} else {
|
||||
command = "xdg-open";
|
||||
const useSystemXdgOpen = process.versions.electron || platform === "android";
|
||||
if (!useSystemXdgOpen) {
|
||||
command = join(os.tmpdir(), "xdg-open");
|
||||
if (!existsSync(command)) {
|
||||
try {
|
||||
writeFileSync(
|
||||
join(os.tmpdir(), "xdg-open"),
|
||||
await import('./chunks/xdg-open.mjs').then((r) => r.xdgOpenScript()),
|
||||
"utf8"
|
||||
);
|
||||
chmodSync(command, 493);
|
||||
} catch {
|
||||
command = "xdg-open";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (appArguments.length > 0) {
|
||||
cliArguments.push(...appArguments);
|
||||
}
|
||||
if (!options.wait) {
|
||||
childProcessOptions.stdio = "ignore";
|
||||
childProcessOptions.detached = true;
|
||||
}
|
||||
}
|
||||
if (options.target) {
|
||||
cliArguments.push(options.target);
|
||||
}
|
||||
if (platform === "darwin" && appArguments.length > 0) {
|
||||
cliArguments.push("--args", ...appArguments);
|
||||
}
|
||||
const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);
|
||||
if (options.wait) {
|
||||
return new Promise((resolve, reject) => {
|
||||
subprocess.once("error", reject);
|
||||
subprocess.once("close", (exitCode) => {
|
||||
if (options.allowNonzeroExitCode && exitCode > 0) {
|
||||
reject(new Error(`Exited with code ${exitCode}`));
|
||||
return;
|
||||
}
|
||||
resolve(subprocess);
|
||||
});
|
||||
});
|
||||
}
|
||||
subprocess.unref();
|
||||
return subprocess;
|
||||
};
|
||||
const open = (target, options = {}) => {
|
||||
if (typeof target !== "string") {
|
||||
throw new TypeError("Expected a `target`");
|
||||
}
|
||||
return baseOpen({
|
||||
...options,
|
||||
target
|
||||
});
|
||||
};
|
||||
const openApp = (name, options) => {
|
||||
if (typeof name !== "string") {
|
||||
throw new TypeError("Expected a `name`");
|
||||
}
|
||||
const { arguments: appArguments = [] } = options || {};
|
||||
if (appArguments !== void 0 && appArguments !== null && !Array.isArray(appArguments)) {
|
||||
throw new TypeError("Expected `appArguments` as Array type");
|
||||
}
|
||||
return baseOpen({
|
||||
...options,
|
||||
app: {
|
||||
name,
|
||||
arguments: appArguments
|
||||
}
|
||||
});
|
||||
};
|
||||
function detectArchBinary(binary) {
|
||||
if (typeof binary === "string" || Array.isArray(binary)) {
|
||||
return binary;
|
||||
}
|
||||
const { [arch]: archBinary } = binary;
|
||||
if (!archBinary) {
|
||||
throw new Error(`${arch} is not supported`);
|
||||
}
|
||||
return archBinary;
|
||||
}
|
||||
function detectPlatformBinary({ [platform]: platformBinary }, { wsl }) {
|
||||
if (wsl && isWsl()) {
|
||||
return detectArchBinary(wsl);
|
||||
}
|
||||
if (!platformBinary) {
|
||||
throw new Error(`${platform} is not supported`);
|
||||
}
|
||||
return detectArchBinary(platformBinary);
|
||||
}
|
||||
const apps = {};
|
||||
defineLazyProperty(apps, "chrome", () => detectPlatformBinary({
|
||||
darwin: "google chrome",
|
||||
win32: "chrome",
|
||||
linux: ["google-chrome", "google-chrome-stable", "chromium"]
|
||||
}, {
|
||||
wsl: {
|
||||
ia32: "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe",
|
||||
x64: ["/mnt/c/Program Files/Google/Chrome/Application/chrome.exe", "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe"]
|
||||
}
|
||||
}));
|
||||
defineLazyProperty(apps, "firefox", () => detectPlatformBinary({
|
||||
darwin: "firefox",
|
||||
win32: "C:\\Program Files\\Mozilla Firefox\\firefox.exe",
|
||||
linux: "firefox"
|
||||
}, {
|
||||
wsl: "/mnt/c/Program Files/Mozilla Firefox/firefox.exe"
|
||||
}));
|
||||
defineLazyProperty(apps, "edge", () => detectPlatformBinary({
|
||||
darwin: "microsoft edge",
|
||||
win32: "msedge",
|
||||
linux: ["microsoft-edge", "microsoft-edge-dev"]
|
||||
}, {
|
||||
wsl: "/mnt/c/Program Files (x86)/Microsoft/Edge/Application/msedge.exe"
|
||||
}));
|
||||
open.apps = apps;
|
||||
open.openApp = openApp;
|
||||
function defineLazyProperty(object, propertyName, valueGetter) {
|
||||
const define = (value) => Object.defineProperty(object, propertyName, { value, enumerable: true, writable: true });
|
||||
Object.defineProperty(object, propertyName, {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
get() {
|
||||
const result = valueGetter();
|
||||
define(result);
|
||||
return result;
|
||||
},
|
||||
set(value) {
|
||||
define(value);
|
||||
}
|
||||
});
|
||||
return object;
|
||||
}
|
||||
function _isWsl() {
|
||||
if (process.platform !== "linux") {
|
||||
return false;
|
||||
}
|
||||
if (os.release().toLowerCase().includes("microsoft")) {
|
||||
if (isDocker()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
return readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft") ? !isDocker() : false;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
let isWSLCached;
|
||||
function isWsl() {
|
||||
if (isWSLCached === void 0) {
|
||||
isWSLCached = _isWsl();
|
||||
}
|
||||
return isWSLCached;
|
||||
}
|
||||
function hasDockerEnvironment() {
|
||||
try {
|
||||
statSync("/.dockerenv");
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
function hasDockerCGroup() {
|
||||
try {
|
||||
return readFileSync("/proc/self/cgroup", "utf8").includes("docker");
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
let isDockerCached;
|
||||
function isDocker() {
|
||||
if (isDockerCached === void 0) {
|
||||
isDockerCached = hasDockerEnvironment() || hasDockerCGroup();
|
||||
}
|
||||
return isDockerCached;
|
||||
}
|
||||
|
||||
async function listen(handle, options_ = {}) {
|
||||
options_ = defu(options_, {
|
||||
port: process.env.PORT || 3e3,
|
||||
hostname: process.env.HOST || "",
|
||||
showURL: true,
|
||||
baseURL: "/",
|
||||
open: false,
|
||||
clipboard: false,
|
||||
isTest: process.env.NODE_ENV === "test",
|
||||
isProd: process.env.NODE_ENV === "production",
|
||||
autoClose: true
|
||||
});
|
||||
if (options_.isTest) {
|
||||
options_.showURL = false;
|
||||
}
|
||||
if (options_.isProd || options_.isTest) {
|
||||
options_.open = false;
|
||||
options_.clipboard = false;
|
||||
}
|
||||
const port = await getPort({
|
||||
port: Number(options_.port),
|
||||
verbose: !options_.isTest,
|
||||
host: options_.hostname,
|
||||
...typeof options_.port === "object" && options_.port
|
||||
});
|
||||
let server;
|
||||
let addr;
|
||||
const getURL = (host, baseURL) => {
|
||||
const anyV4 = addr?.addr === "0.0.0.0";
|
||||
const anyV6 = addr?.addr === "[::]";
|
||||
return `${addr.proto}://${host || options_.hostname || (anyV4 || anyV6 ? "localhost" : addr.addr)}:${addr.port}${baseURL || options_.baseURL}`;
|
||||
};
|
||||
let https = false;
|
||||
if (options_.https) {
|
||||
const { key, cert } = await resolveCert({ ...options_.https }, options_.hostname);
|
||||
https = { key, cert };
|
||||
server = createServer({ key, cert }, handle);
|
||||
addShutdown(server);
|
||||
await promisify(server.listen.bind(server))(port, options_.hostname);
|
||||
const _addr = server.address();
|
||||
addr = { proto: "https", addr: formatAddress(_addr), port: _addr.port };
|
||||
} else {
|
||||
server = createServer$1(handle);
|
||||
addShutdown(server);
|
||||
await promisify(server.listen.bind(server))(port, options_.hostname);
|
||||
const _addr = server.address();
|
||||
addr = { proto: "http", addr: formatAddress(_addr), port: _addr.port };
|
||||
}
|
||||
let _closed = false;
|
||||
const close = () => {
|
||||
if (_closed) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
_closed = true;
|
||||
return promisify(server.shutdown)();
|
||||
};
|
||||
if (options_.clipboard) {
|
||||
const clipboardy = await import('clipboardy').then((r) => r.default || r);
|
||||
await clipboardy.write(getURL()).catch(() => {
|
||||
options_.clipboard = false;
|
||||
});
|
||||
}
|
||||
const showURL = (options) => {
|
||||
const add = options_.clipboard ? gray("(copied to clipboard)") : "";
|
||||
const lines = [];
|
||||
const baseURL = options?.baseURL || options_.baseURL || "";
|
||||
const name = options?.name ? ` (${options.name})` : "";
|
||||
const anyV4 = addr?.addr === "0.0.0.0";
|
||||
const anyV6 = addr?.addr === "[::]";
|
||||
if (anyV4 || anyV6) {
|
||||
lines.push(` > Local${name}: ${formatURL(getURL("localhost", baseURL))} ${add}`);
|
||||
for (const addr2 of getNetworkInterfaces(anyV4)) {
|
||||
lines.push(` > Network${name}: ${formatURL(getURL(addr2, baseURL))}`);
|
||||
}
|
||||
} else {
|
||||
lines.push(` > Listening${name}: ${formatURL(getURL(void 0, baseURL))} ${add}`);
|
||||
}
|
||||
console.log("\n" + lines.join("\n") + "\n");
|
||||
};
|
||||
if (options_.showURL) {
|
||||
showURL();
|
||||
}
|
||||
const _open = async () => {
|
||||
await open(getURL()).catch(() => {
|
||||
});
|
||||
};
|
||||
if (options_.open) {
|
||||
await _open();
|
||||
}
|
||||
if (options_.autoClose) {
|
||||
process.on("exit", () => close());
|
||||
}
|
||||
return {
|
||||
url: getURL(),
|
||||
https,
|
||||
server,
|
||||
open: _open,
|
||||
showURL,
|
||||
close
|
||||
};
|
||||
}
|
||||
async function resolveCert(options, host) {
|
||||
if (options.key && options.cert) {
|
||||
const isInline = (s = "") => s.startsWith("--");
|
||||
const r = (s) => isInline(s) ? s : promises.readFile(s, "utf8");
|
||||
return {
|
||||
key: await r(options.key),
|
||||
cert: await r(options.cert)
|
||||
};
|
||||
}
|
||||
const { generateCA, generateSSLCert } = await import('./chunks/cert.mjs');
|
||||
const ca = await generateCA();
|
||||
const cert = await generateSSLCert({
|
||||
caCert: ca.cert,
|
||||
caKey: ca.key,
|
||||
domains: options.domains || ["localhost", "127.0.0.1", "::1", host].filter(Boolean),
|
||||
validityDays: options.validityDays || 1
|
||||
});
|
||||
return cert;
|
||||
}
|
||||
function getNetworkInterfaces(v4Only = true) {
|
||||
const addrs = /* @__PURE__ */ new Set();
|
||||
for (const details of Object.values(networkInterfaces())) {
|
||||
if (details) {
|
||||
for (const d of details) {
|
||||
if (!d.internal && !(d.mac === "00:00:00:00:00:00") && !d.address.startsWith("fe80::") && !(v4Only && (d.family === "IPv6" || +d.family === 6))) {
|
||||
addrs.add(formatAddress(d));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return [...addrs].sort();
|
||||
}
|
||||
function formatAddress(addr) {
|
||||
return addr.family === "IPv6" || addr.family === 6 ? `[${addr.address}]` : addr.address;
|
||||
}
|
||||
function formatURL(url) {
|
||||
return cyan(underline(decodeURI(url).replace(/:(\d+)\//g, `:${bold("$1")}/`)));
|
||||
}
|
||||
|
||||
export { listen };
|
||||
51
node_modules/listhen/package.json
generated
vendored
Normal file
51
node_modules/listhen/package.json
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"name": "listhen",
|
||||
"version": "1.0.1",
|
||||
"description": "",
|
||||
"repository": "unjs/listhen",
|
||||
"license": "MIT",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/index.mjs",
|
||||
"require": "./dist/index.cjs",
|
||||
"types": "./dist/index.d.ts"
|
||||
}
|
||||
},
|
||||
"main": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"files": [
|
||||
"dist",
|
||||
"lib"
|
||||
],
|
||||
"dependencies": {
|
||||
"clipboardy": "^3.0.0",
|
||||
"colorette": "^2.0.19",
|
||||
"defu": "^6.1.1",
|
||||
"get-port-please": "^2.6.1",
|
||||
"http-shutdown": "^1.2.2",
|
||||
"ip-regex": "^5.0.0",
|
||||
"node-forge": "^1.3.1",
|
||||
"ufo": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^18.11.9",
|
||||
"@types/node-forge": "^1.3.1",
|
||||
"@vitest/coverage-c8": "^0.25.3",
|
||||
"eslint": "^8.28.0",
|
||||
"eslint-config-unjs": "^0.0.2",
|
||||
"jiti": "^1.16.0",
|
||||
"standard-version": "^9.5.0",
|
||||
"typescript": "^4.9.3",
|
||||
"unbuild": "^1.0.1",
|
||||
"vitest": "^0.25.3"
|
||||
},
|
||||
"packageManager": "pnpm@7.17.1",
|
||||
"scripts": {
|
||||
"build": "unbuild",
|
||||
"dev": "vitest",
|
||||
"lint": "eslint --ext .ts .",
|
||||
"play": "jiti test/fixture/app",
|
||||
"release": "pnpm test && pnpm build && standard-version && git push --follow-tags && pnpm publish",
|
||||
"test": "pnpm lint && vitest run --coverage"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user