Website Structure

This commit is contained in:
supalerk-ar66 2026-01-13 10:46:40 +07:00
parent 62812f2090
commit 71f0676a62
22365 changed files with 4265753 additions and 791 deletions

21
Frontend-Learner/node_modules/get-port-please/LICENSE generated vendored Normal file
View 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.

118
Frontend-Learner/node_modules/get-port-please/README.md generated vendored Normal file
View file

@ -0,0 +1,118 @@
# 🔌 get-port-please
Get an available TCP port to listen
[![npm version][npm-version-src]][npm-version-href]
[![npm downloads][npm-downloads-src]][npm-downloads-href]
[![License][license-src]][license-href]
[![JSDocs][jsdocs-src]][jsdocs-href]
## Usage
Install package:
```bash
npm i get-port-please
```
```js
// ESM
import {
getPort,
checkPort,
getRandomPort,
waitForPort,
getSocketAddress,
isSocketSupported,
cleanSocket
} from "get-port-please";
// CommonJS
const {
getPort,
checkPort,
getRandomPort,
waitForPort,
getSocketAddress,
isSocketSupported,
cleanSocket
} = require("get-port-please");
```
```
getPort(options: GetPortOptions): Promise<number>;
checkPort(port: number, host?: string): Promise<number | false>
waitForPort(port: number, options): Promise<number | false>
```
Try sequence is: port > ports > random
## Options
```ts
interface GetPortOptions {
name?: string;
random?: boolean;
port?: number;
portRange?: [fromInclusive: number, toInclusive: number];
ports?: number[];
host?: string;
memoDir?: string;
memoName?: string;
}
```
### `name`
Unique name for port memorizing. Default is `default`.
### `random`
If enabled, `port` and `ports` will be ignored. Default is `false`.
### `port`
First port to check. Default is `process.env.PORT || 3000`
### `ports`
Extended ports to check.
### `portRange`
Extended port range to check.
The range's start and end are **inclusive**, i.e. it is `[start, end]` in the mathematical notion.
Reversed port ranges are not supported. If `start > end`, then an empty range will be returned.
### `alternativePortRange`
Alternative port range to check as fallback when none of the ports are available.
The range's start and end are **inclusive**, i.e. it is `[start, end]` in the mathematical notion.
Reversed port ranges are not supported. If `start > end`, then an empty range will be returned.
The default range is `[3000, 3100]` (only when `port` is unspecified).
### `host`
The host to check. Default is `process.env.HOST` otherwise all available hosts will be checked.
## License
MIT
<!-- Badges -->
[npm-version-src]: https://img.shields.io/npm/v/get-port-please?style=flat&colorA=18181B&colorB=F0DB4F
[npm-version-href]: https://npmjs.com/package/get-port-please
[npm-downloads-src]: https://img.shields.io/npm/dm/get-port-please?style=flat&colorA=18181B&colorB=F0DB4F
[npm-downloads-href]: https://npmjs.com/package/get-port-please
[codecov-src]: https://img.shields.io/codecov/c/gh/unjs/get-port-please/main?style=flat&colorA=18181B&colorB=F0DB4F
[codecov-href]: https://codecov.io/gh/unjs/get-port-please
[license-src]: https://img.shields.io/github/license/unjs/get-port-please.svg?style=flat&colorA=18181B&colorB=F0DB4F
[license-href]: https://github.com/unjs/get-port-please/blob/main/LICENSE
[jsdocs-src]: https://img.shields.io/badge/jsDocs.io-reference-18181B?style=flat&colorA=18181B&colorB=F0DB4F
[jsdocs-href]: https://www.jsdocs.io/package/get-port-please

View file

@ -0,0 +1,440 @@
'use strict';
const node_net = require('node:net');
const node_os = require('node:os');
const node_path = require('node:path');
const promises = require('node:fs/promises');
const unsafePorts = /* @__PURE__ */ new Set([
1,
// tcpmux
7,
// echo
9,
// discard
11,
// systat
13,
// daytime
15,
// netstat
17,
// qotd
19,
// chargen
20,
// ftp data
21,
// ftp access
22,
// ssh
23,
// telnet
25,
// smtp
37,
// time
42,
// name
43,
// nicname
53,
// domain
69,
// tftp
77,
// priv-rjs
79,
// finger
87,
// ttylink
95,
// supdup
101,
// hostriame
102,
// iso-tsap
103,
// gppitnp
104,
// acr-nema
109,
// pop2
110,
// pop3
111,
// sunrpc
113,
// auth
115,
// sftp
117,
// uucp-path
119,
// nntp
123,
// NTP
135,
// loc-srv /epmap
137,
// netbios
139,
// netbios
143,
// imap2
161,
// snmp
179,
// BGP
389,
// ldap
427,
// SLP (Also used by Apple Filing Protocol)
465,
// smtp+ssl
512,
// print / exec
513,
// login
514,
// shell
515,
// printer
526,
// tempo
530,
// courier
531,
// chat
532,
// netnews
540,
// uucp
548,
// AFP (Apple Filing Protocol)
554,
// rtsp
556,
// remotefs
563,
// nntp+ssl
587,
// smtp (rfc6409)
601,
// syslog-conn (rfc3195)
636,
// ldap+ssl
989,
// ftps-data
990,
// ftps
993,
// ldap+ssl
995,
// pop3+ssl
1719,
// h323gatestat
1720,
// h323hostcall
1723,
// pptp
2049,
// nfs
3659,
// apple-sasl / PasswordServer
4045,
// lockd
5060,
// sip
5061,
// sips
6e3,
// X11
6566,
// sane-port
6665,
// Alternate IRC [Apple addition]
6666,
// Alternate IRC [Apple addition]
6667,
// Standard IRC [Apple addition]
6668,
// Alternate IRC [Apple addition]
6669,
// Alternate IRC [Apple addition]
6697,
// IRC + TLS
10080
// Amanda
]);
function isUnsafePort(port) {
return unsafePorts.has(port);
}
function isSafePort(port) {
return !isUnsafePort(port);
}
class GetPortError extends Error {
constructor(message, opts) {
super(message, opts);
this.message = message;
}
name = "GetPortError";
}
function _log(verbose, message) {
if (verbose) {
console.log(`[get-port] ${message}`);
}
}
function _generateRange(from, to) {
if (to < from) {
return [];
}
const r = [];
for (let index = from; index <= to; index++) {
r.push(index);
}
return r;
}
function _tryPort(port, host) {
return new Promise((resolve) => {
const server = node_net.createServer();
server.unref();
server.on("error", () => {
resolve(false);
});
server.listen({ port, host }, () => {
const { port: port2 } = server.address();
server.close(() => {
resolve(isSafePort(port2) && port2);
});
});
});
}
function _getLocalHosts(additional) {
const hosts = new Set(additional);
for (const _interface of Object.values(node_os.networkInterfaces())) {
for (const config of _interface || []) {
if (config.address && !config.internal && !config.address.startsWith("fe80::") && // Link-Local
!config.address.startsWith("169.254")) {
hosts.add(config.address);
}
}
}
return [...hosts];
}
async function _findPort(ports, host) {
for (const port of ports) {
const r = await _tryPort(port, host);
if (r) {
return r;
}
}
}
function _fmtOnHost(hostname) {
return hostname ? `on host ${JSON.stringify(hostname)}` : "on any host";
}
const HOSTNAME_RE = /^(?!-)[\d.:A-Za-z-]{1,63}(?<!-)$/;
function _validateHostname(hostname, _public, verbose) {
if (hostname && !HOSTNAME_RE.test(hostname)) {
const fallbackHost = _public ? "0.0.0.0" : "127.0.0.1";
_log(
verbose,
`Invalid hostname: ${JSON.stringify(hostname)}. Using ${JSON.stringify(
fallbackHost
)} as fallback.`
);
return fallbackHost;
}
return hostname;
}
async function getPort(_userOptions = {}) {
if (typeof _userOptions === "number" || typeof _userOptions === "string") {
_userOptions = { port: Number.parseInt(_userOptions + "") || 0 };
}
const _port = Number(_userOptions.port ?? process.env.PORT);
const _userSpecifiedAnyPort = Boolean(
_userOptions.port || _userOptions.ports?.length || _userOptions.portRange?.length
);
const options = {
random: _port === 0,
ports: [],
portRange: [],
alternativePortRange: _userSpecifiedAnyPort ? [] : [3e3, 3100],
verbose: false,
..._userOptions,
port: _port,
host: _validateHostname(
_userOptions.host ?? process.env.HOST,
_userOptions.public,
_userOptions.verbose
)
};
if (options.random && !_userSpecifiedAnyPort) {
return getRandomPort(options.host);
}
const portsToCheck = [
options.port,
...options.ports,
..._generateRange(...options.portRange)
].filter((port) => {
if (!port) {
return false;
}
if (!isSafePort(port)) {
_log(options.verbose, `Ignoring unsafe port: ${port}`);
return false;
}
return true;
});
if (portsToCheck.length === 0) {
portsToCheck.push(3e3);
}
let availablePort = await _findPort(portsToCheck, options.host);
if (!availablePort && options.alternativePortRange.length > 0) {
availablePort = await _findPort(
_generateRange(...options.alternativePortRange),
options.host
);
if (portsToCheck.length > 0) {
let message = `Unable to find an available port (tried ${portsToCheck.join(
"-"
)} ${_fmtOnHost(options.host)}).`;
if (availablePort) {
message += ` Using alternative port ${availablePort}.`;
}
_log(options.verbose, message);
}
}
if (!availablePort && _userOptions.random !== false) {
availablePort = await getRandomPort(options.host);
if (availablePort) {
_log(options.verbose, `Using random port ${availablePort}`);
}
}
if (!availablePort) {
const triedRanges = [
options.port,
options.portRange.join("-"),
options.alternativePortRange.join("-")
].filter(Boolean).join(", ");
throw new GetPortError(
`Unable to find an available port ${_fmtOnHost(
options.host
)} (tried ${triedRanges})`
);
}
return availablePort;
}
async function getRandomPort(host) {
const port = await checkPort(0, host);
if (port === false) {
throw new GetPortError(`Unable to find a random port ${_fmtOnHost(host)}`);
}
return port;
}
async function waitForPort(port, options = {}) {
const delay = options.delay || 500;
const retries = options.retries || 4;
for (let index = retries; index > 0; index--) {
if (await _tryPort(port, options.host) === false) {
return;
}
await new Promise((resolve) => setTimeout(resolve, delay));
}
throw new GetPortError(
`Timeout waiting for port ${port} after ${retries} retries with ${delay}ms interval.`
);
}
async function checkPort(port, host = process.env.HOST, verbose) {
if (!host) {
host = _getLocalHosts([void 0, "0.0.0.0"]);
}
if (!Array.isArray(host)) {
return _tryPort(port, host);
}
for (const _host of host) {
const _port = await _tryPort(port, _host);
if (_port === false) {
if (port < 1024 && verbose) {
_log(
verbose,
`Unable to listen to the privileged port ${port} ${_fmtOnHost(
_host
)}`
);
}
return false;
}
if (port === 0 && _port !== 0) {
port = _port;
}
}
return port;
}
let _nodeMajorVersion;
let _isSocketSupported;
function getSocketAddress(opts) {
const parts = [
opts.name,
opts.pid ? process.pid : void 0,
opts.random ? Math.round(Math.random() * 1e4) : void 0
].filter(Boolean);
const socketName = `${parts.join("-")}.sock`;
if (process.platform === "win32") {
return node_path.join(String.raw`\\.\pipe`, socketName);
}
if (process.platform === "linux") {
if (_nodeMajorVersion === void 0) {
_nodeMajorVersion = +process.versions.node.split(".")[0];
}
if (_nodeMajorVersion >= 20) {
return `\0${socketName}`;
}
}
return node_path.join(node_os.tmpdir(), socketName);
}
async function isSocketSupported() {
if (_isSocketSupported !== void 0) {
return _isSocketSupported;
}
if (globalThis.process?.versions?.webcontainer) {
return false;
}
const socketAddress = getSocketAddress({ name: "get-port", random: true });
const server = new node_net.Server();
try {
await new Promise((resolve, reject) => {
server.on("error", reject);
server.listen(socketAddress, resolve);
});
_isSocketSupported = true;
return true;
} catch {
_isSocketSupported = false;
return false;
} finally {
if (server.listening) {
server.close();
await cleanSocket(socketAddress);
}
}
}
async function cleanSocket(path) {
if (!path || path[0] === "\0" || path.startsWith(String.raw`\\.\pipe`)) {
return;
}
return promises.rm(path, { force: true, recursive: true }).catch(console.error);
}
exports.checkPort = checkPort;
exports.cleanSocket = cleanSocket;
exports.getPort = getPort;
exports.getRandomPort = getRandomPort;
exports.getSocketAddress = getSocketAddress;
exports.isSafePort = isSafePort;
exports.isSocketSupported = isSocketSupported;
exports.isUnsafePort = isUnsafePort;
exports.waitForPort = waitForPort;

View file

@ -0,0 +1,52 @@
interface GetPortOptions {
name: string;
random: boolean;
port: number;
ports: number[];
portRange: [fromInclusive: number, toInclusive: number];
alternativePortRange: [fromInclusive: number, toInclusive: number];
host: string;
verbose?: boolean;
public?: boolean;
}
interface WaitForPortOptions {
host?: HostAddress;
delay?: number;
retries?: number;
}
type GetPortInput = Partial<GetPortOptions> | number | string;
type HostAddress = undefined | string;
type PortNumber = number;
declare function getPort(_userOptions?: GetPortInput): Promise<PortNumber>;
declare function getRandomPort(host?: HostAddress): Promise<number>;
declare function waitForPort(port: PortNumber, options?: WaitForPortOptions): Promise<void>;
declare function checkPort(port: PortNumber, host?: HostAddress | HostAddress[], verbose?: boolean): Promise<PortNumber | false>;
declare function isUnsafePort(port: number): boolean;
declare function isSafePort(port: number): boolean;
interface GetSocketOptions {
name: string;
/**
* Use process ID in the socket name.
*/
pid?: boolean;
/**
* Use a random number in the socket name.
*
*/
random?: boolean;
}
/**
* Generates a socket address based on the provided options.
*/
declare function getSocketAddress(opts: GetSocketOptions): string;
/**
* Test if the current environment supports sockets.
*/
declare function isSocketSupported(): Promise<boolean>;
declare function cleanSocket(path: string): Promise<void>;
export { checkPort, cleanSocket, getPort, getRandomPort, getSocketAddress, isSafePort, isSocketSupported, isUnsafePort, waitForPort };
export type { GetPortInput, GetPortOptions, GetSocketOptions, HostAddress, PortNumber, WaitForPortOptions };

View file

@ -0,0 +1,52 @@
interface GetPortOptions {
name: string;
random: boolean;
port: number;
ports: number[];
portRange: [fromInclusive: number, toInclusive: number];
alternativePortRange: [fromInclusive: number, toInclusive: number];
host: string;
verbose?: boolean;
public?: boolean;
}
interface WaitForPortOptions {
host?: HostAddress;
delay?: number;
retries?: number;
}
type GetPortInput = Partial<GetPortOptions> | number | string;
type HostAddress = undefined | string;
type PortNumber = number;
declare function getPort(_userOptions?: GetPortInput): Promise<PortNumber>;
declare function getRandomPort(host?: HostAddress): Promise<number>;
declare function waitForPort(port: PortNumber, options?: WaitForPortOptions): Promise<void>;
declare function checkPort(port: PortNumber, host?: HostAddress | HostAddress[], verbose?: boolean): Promise<PortNumber | false>;
declare function isUnsafePort(port: number): boolean;
declare function isSafePort(port: number): boolean;
interface GetSocketOptions {
name: string;
/**
* Use process ID in the socket name.
*/
pid?: boolean;
/**
* Use a random number in the socket name.
*
*/
random?: boolean;
}
/**
* Generates a socket address based on the provided options.
*/
declare function getSocketAddress(opts: GetSocketOptions): string;
/**
* Test if the current environment supports sockets.
*/
declare function isSocketSupported(): Promise<boolean>;
declare function cleanSocket(path: string): Promise<void>;
export { checkPort, cleanSocket, getPort, getRandomPort, getSocketAddress, isSafePort, isSocketSupported, isUnsafePort, waitForPort };
export type { GetPortInput, GetPortOptions, GetSocketOptions, HostAddress, PortNumber, WaitForPortOptions };

View file

@ -0,0 +1,52 @@
interface GetPortOptions {
name: string;
random: boolean;
port: number;
ports: number[];
portRange: [fromInclusive: number, toInclusive: number];
alternativePortRange: [fromInclusive: number, toInclusive: number];
host: string;
verbose?: boolean;
public?: boolean;
}
interface WaitForPortOptions {
host?: HostAddress;
delay?: number;
retries?: number;
}
type GetPortInput = Partial<GetPortOptions> | number | string;
type HostAddress = undefined | string;
type PortNumber = number;
declare function getPort(_userOptions?: GetPortInput): Promise<PortNumber>;
declare function getRandomPort(host?: HostAddress): Promise<number>;
declare function waitForPort(port: PortNumber, options?: WaitForPortOptions): Promise<void>;
declare function checkPort(port: PortNumber, host?: HostAddress | HostAddress[], verbose?: boolean): Promise<PortNumber | false>;
declare function isUnsafePort(port: number): boolean;
declare function isSafePort(port: number): boolean;
interface GetSocketOptions {
name: string;
/**
* Use process ID in the socket name.
*/
pid?: boolean;
/**
* Use a random number in the socket name.
*
*/
random?: boolean;
}
/**
* Generates a socket address based on the provided options.
*/
declare function getSocketAddress(opts: GetSocketOptions): string;
/**
* Test if the current environment supports sockets.
*/
declare function isSocketSupported(): Promise<boolean>;
declare function cleanSocket(path: string): Promise<void>;
export { checkPort, cleanSocket, getPort, getRandomPort, getSocketAddress, isSafePort, isSocketSupported, isUnsafePort, waitForPort };
export type { GetPortInput, GetPortOptions, GetSocketOptions, HostAddress, PortNumber, WaitForPortOptions };

View file

@ -0,0 +1,430 @@
import { createServer, Server } from 'node:net';
import { networkInterfaces, tmpdir } from 'node:os';
import { join } from 'node:path';
import { rm } from 'node:fs/promises';
const unsafePorts = /* @__PURE__ */ new Set([
1,
// tcpmux
7,
// echo
9,
// discard
11,
// systat
13,
// daytime
15,
// netstat
17,
// qotd
19,
// chargen
20,
// ftp data
21,
// ftp access
22,
// ssh
23,
// telnet
25,
// smtp
37,
// time
42,
// name
43,
// nicname
53,
// domain
69,
// tftp
77,
// priv-rjs
79,
// finger
87,
// ttylink
95,
// supdup
101,
// hostriame
102,
// iso-tsap
103,
// gppitnp
104,
// acr-nema
109,
// pop2
110,
// pop3
111,
// sunrpc
113,
// auth
115,
// sftp
117,
// uucp-path
119,
// nntp
123,
// NTP
135,
// loc-srv /epmap
137,
// netbios
139,
// netbios
143,
// imap2
161,
// snmp
179,
// BGP
389,
// ldap
427,
// SLP (Also used by Apple Filing Protocol)
465,
// smtp+ssl
512,
// print / exec
513,
// login
514,
// shell
515,
// printer
526,
// tempo
530,
// courier
531,
// chat
532,
// netnews
540,
// uucp
548,
// AFP (Apple Filing Protocol)
554,
// rtsp
556,
// remotefs
563,
// nntp+ssl
587,
// smtp (rfc6409)
601,
// syslog-conn (rfc3195)
636,
// ldap+ssl
989,
// ftps-data
990,
// ftps
993,
// ldap+ssl
995,
// pop3+ssl
1719,
// h323gatestat
1720,
// h323hostcall
1723,
// pptp
2049,
// nfs
3659,
// apple-sasl / PasswordServer
4045,
// lockd
5060,
// sip
5061,
// sips
6e3,
// X11
6566,
// sane-port
6665,
// Alternate IRC [Apple addition]
6666,
// Alternate IRC [Apple addition]
6667,
// Standard IRC [Apple addition]
6668,
// Alternate IRC [Apple addition]
6669,
// Alternate IRC [Apple addition]
6697,
// IRC + TLS
10080
// Amanda
]);
function isUnsafePort(port) {
return unsafePorts.has(port);
}
function isSafePort(port) {
return !isUnsafePort(port);
}
class GetPortError extends Error {
constructor(message, opts) {
super(message, opts);
this.message = message;
}
name = "GetPortError";
}
function _log(verbose, message) {
if (verbose) {
console.log(`[get-port] ${message}`);
}
}
function _generateRange(from, to) {
if (to < from) {
return [];
}
const r = [];
for (let index = from; index <= to; index++) {
r.push(index);
}
return r;
}
function _tryPort(port, host) {
return new Promise((resolve) => {
const server = createServer();
server.unref();
server.on("error", () => {
resolve(false);
});
server.listen({ port, host }, () => {
const { port: port2 } = server.address();
server.close(() => {
resolve(isSafePort(port2) && port2);
});
});
});
}
function _getLocalHosts(additional) {
const hosts = new Set(additional);
for (const _interface of Object.values(networkInterfaces())) {
for (const config of _interface || []) {
if (config.address && !config.internal && !config.address.startsWith("fe80::") && // Link-Local
!config.address.startsWith("169.254")) {
hosts.add(config.address);
}
}
}
return [...hosts];
}
async function _findPort(ports, host) {
for (const port of ports) {
const r = await _tryPort(port, host);
if (r) {
return r;
}
}
}
function _fmtOnHost(hostname) {
return hostname ? `on host ${JSON.stringify(hostname)}` : "on any host";
}
const HOSTNAME_RE = /^(?!-)[\d.:A-Za-z-]{1,63}(?<!-)$/;
function _validateHostname(hostname, _public, verbose) {
if (hostname && !HOSTNAME_RE.test(hostname)) {
const fallbackHost = _public ? "0.0.0.0" : "127.0.0.1";
_log(
verbose,
`Invalid hostname: ${JSON.stringify(hostname)}. Using ${JSON.stringify(
fallbackHost
)} as fallback.`
);
return fallbackHost;
}
return hostname;
}
async function getPort(_userOptions = {}) {
if (typeof _userOptions === "number" || typeof _userOptions === "string") {
_userOptions = { port: Number.parseInt(_userOptions + "") || 0 };
}
const _port = Number(_userOptions.port ?? process.env.PORT);
const _userSpecifiedAnyPort = Boolean(
_userOptions.port || _userOptions.ports?.length || _userOptions.portRange?.length
);
const options = {
random: _port === 0,
ports: [],
portRange: [],
alternativePortRange: _userSpecifiedAnyPort ? [] : [3e3, 3100],
verbose: false,
..._userOptions,
port: _port,
host: _validateHostname(
_userOptions.host ?? process.env.HOST,
_userOptions.public,
_userOptions.verbose
)
};
if (options.random && !_userSpecifiedAnyPort) {
return getRandomPort(options.host);
}
const portsToCheck = [
options.port,
...options.ports,
..._generateRange(...options.portRange)
].filter((port) => {
if (!port) {
return false;
}
if (!isSafePort(port)) {
_log(options.verbose, `Ignoring unsafe port: ${port}`);
return false;
}
return true;
});
if (portsToCheck.length === 0) {
portsToCheck.push(3e3);
}
let availablePort = await _findPort(portsToCheck, options.host);
if (!availablePort && options.alternativePortRange.length > 0) {
availablePort = await _findPort(
_generateRange(...options.alternativePortRange),
options.host
);
if (portsToCheck.length > 0) {
let message = `Unable to find an available port (tried ${portsToCheck.join(
"-"
)} ${_fmtOnHost(options.host)}).`;
if (availablePort) {
message += ` Using alternative port ${availablePort}.`;
}
_log(options.verbose, message);
}
}
if (!availablePort && _userOptions.random !== false) {
availablePort = await getRandomPort(options.host);
if (availablePort) {
_log(options.verbose, `Using random port ${availablePort}`);
}
}
if (!availablePort) {
const triedRanges = [
options.port,
options.portRange.join("-"),
options.alternativePortRange.join("-")
].filter(Boolean).join(", ");
throw new GetPortError(
`Unable to find an available port ${_fmtOnHost(
options.host
)} (tried ${triedRanges})`
);
}
return availablePort;
}
async function getRandomPort(host) {
const port = await checkPort(0, host);
if (port === false) {
throw new GetPortError(`Unable to find a random port ${_fmtOnHost(host)}`);
}
return port;
}
async function waitForPort(port, options = {}) {
const delay = options.delay || 500;
const retries = options.retries || 4;
for (let index = retries; index > 0; index--) {
if (await _tryPort(port, options.host) === false) {
return;
}
await new Promise((resolve) => setTimeout(resolve, delay));
}
throw new GetPortError(
`Timeout waiting for port ${port} after ${retries} retries with ${delay}ms interval.`
);
}
async function checkPort(port, host = process.env.HOST, verbose) {
if (!host) {
host = _getLocalHosts([void 0, "0.0.0.0"]);
}
if (!Array.isArray(host)) {
return _tryPort(port, host);
}
for (const _host of host) {
const _port = await _tryPort(port, _host);
if (_port === false) {
if (port < 1024 && verbose) {
_log(
verbose,
`Unable to listen to the privileged port ${port} ${_fmtOnHost(
_host
)}`
);
}
return false;
}
if (port === 0 && _port !== 0) {
port = _port;
}
}
return port;
}
let _nodeMajorVersion;
let _isSocketSupported;
function getSocketAddress(opts) {
const parts = [
opts.name,
opts.pid ? process.pid : void 0,
opts.random ? Math.round(Math.random() * 1e4) : void 0
].filter(Boolean);
const socketName = `${parts.join("-")}.sock`;
if (process.platform === "win32") {
return join(String.raw`\\.\pipe`, socketName);
}
if (process.platform === "linux") {
if (_nodeMajorVersion === void 0) {
_nodeMajorVersion = +process.versions.node.split(".")[0];
}
if (_nodeMajorVersion >= 20) {
return `\0${socketName}`;
}
}
return join(tmpdir(), socketName);
}
async function isSocketSupported() {
if (_isSocketSupported !== void 0) {
return _isSocketSupported;
}
if (globalThis.process?.versions?.webcontainer) {
return false;
}
const socketAddress = getSocketAddress({ name: "get-port", random: true });
const server = new Server();
try {
await new Promise((resolve, reject) => {
server.on("error", reject);
server.listen(socketAddress, resolve);
});
_isSocketSupported = true;
return true;
} catch {
_isSocketSupported = false;
return false;
} finally {
if (server.listening) {
server.close();
await cleanSocket(socketAddress);
}
}
}
async function cleanSocket(path) {
if (!path || path[0] === "\0" || path.startsWith(String.raw`\\.\pipe`)) {
return;
}
return rm(path, { force: true, recursive: true }).catch(console.error);
}
export { checkPort, cleanSocket, getPort, getRandomPort, getSocketAddress, isSafePort, isSocketSupported, isUnsafePort, waitForPort };

View file

@ -0,0 +1,39 @@
{
"name": "get-port-please",
"version": "3.2.0",
"description": "Get an available TCP port to listen",
"repository": "unjs/get-port-please",
"license": "MIT",
"exports": {
".": {
"import": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"require": "./dist/index.cjs"
}
},
"main": "./dist/index.cjs",
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"devDependencies": {
"@types/node": "^24.0.13",
"@vitest/coverage-v8": "^3.2.4",
"changelogen": "^0.6.2",
"eslint": "^9.30.1",
"eslint-config-unjs": "^0.5.0",
"jiti": "^2.4.2",
"prettier": "^3.6.2",
"typescript": "^5.8.3",
"unbuild": "^3.5.0",
"vitest": "^3.2.4"
},
"scripts": {
"build": "unbuild",
"dev": "vitest",
"lint": "eslint . && prettier -c src test",
"lint:fix": "eslint --fix . && prettier -w src test",
"release": "pnpm test && pnpm build && changelogen --release --push && pnpm publish",
"test": "pnpm lint && vitest run"
}
}