feat: init
This commit is contained in:
47
node_modules/untun/LICENSE
generated
vendored
Normal file
47
node_modules/untun/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
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.
|
||||
|
||||
----
|
||||
|
||||
cloudflared forked from https://github.com/JacobLinCool/node-cloudflared/
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 JacobLinCool
|
||||
|
||||
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.
|
||||
128
node_modules/untun/README.md
generated
vendored
Normal file
128
node_modules/untun/README.md
generated
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
# 🚇 untun
|
||||
|
||||
[![npm version][npm-version-src]][npm-version-href]
|
||||
[![npm downloads][npm-downloads-src]][npm-downloads-href]
|
||||
[![bundle][bundle-src]][bundle-href]
|
||||
|
||||
[![License][license-src]][license-href]
|
||||
|
||||
Tunnel your local HTTP(s) server to the world!
|
||||
|
||||
Powered by 🔥 [Cloudflare Quick Tunnels](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/do-more-with-tunnels/trycloudflare/) and used by 👂 [unjs/listhen](https://github.com/unjs/listhen).
|
||||
|
||||
## Usage (CLI)
|
||||
|
||||
Globally run tunnel with `npx`:
|
||||
|
||||
```sh
|
||||
npx untun@latest tunnel http://localhost:3000
|
||||
```
|
||||
|
||||
```
|
||||
◐ Starting cloudflared tunnel to http://localhost:3000
|
||||
ℹ Waiting for tunnel URL...
|
||||
✔ Tunnel ready at https://unjs-is-awesome.trycloudflare.com
|
||||
```
|
||||
|
||||
Use `npx untun tunnel --help` for more usage info.
|
||||
|
||||
## Usage (API)
|
||||
|
||||
Install package:
|
||||
|
||||
```sh
|
||||
# npm
|
||||
npm install untun
|
||||
|
||||
# yarn
|
||||
yarn add untun
|
||||
|
||||
# pnpm
|
||||
pnpm install untun
|
||||
```
|
||||
|
||||
Import:
|
||||
|
||||
```ts
|
||||
// ESM
|
||||
import { startTunnel } from "untun";
|
||||
|
||||
// CommonJS
|
||||
const { startTunnel } = require("untun");
|
||||
```
|
||||
|
||||
Start tunnel:
|
||||
|
||||
```ts
|
||||
const tunnel = await startTunnel({ port: 3000 });
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
### `url`
|
||||
|
||||
- Default: `{protocol}://{hostname}:{port}`
|
||||
|
||||
The local server URL to tunnel.
|
||||
|
||||
### `port`
|
||||
|
||||
- Default: `3000`
|
||||
|
||||
The local server PORT (only effective if `url` is not provided).
|
||||
|
||||
### `hostname`
|
||||
|
||||
- Default: `localhost`
|
||||
|
||||
The local server hostname (only effective if `url` is not provided).
|
||||
|
||||
### `protocol`
|
||||
|
||||
- Default: `http`
|
||||
|
||||
The local server protocol (only effective if `url` is not provided).
|
||||
|
||||
### `verifyTLS`
|
||||
|
||||
- Default: `false`
|
||||
|
||||
Verify local server TLS certificate.
|
||||
|
||||
### `acceptCloudflareNotice`
|
||||
|
||||
- Default: `false`
|
||||
- Environment variable: `UNTUN_ACCEPT_CLOUDFLARE_NOTICE`
|
||||
|
||||
Accept cloudflare TOS by default.
|
||||
|
||||
## Development
|
||||
|
||||
- Clone this repository
|
||||
- Install latest LTS version of [Node.js](https://nodejs.org/en/)
|
||||
- Enable [Corepack](https://github.com/nodejs/corepack) using `corepack enable`
|
||||
- Install dependencies using `pnpm install`
|
||||
- Run interactive tests using `pnpm dev`
|
||||
|
||||
## License
|
||||
|
||||
Made with 💛
|
||||
|
||||
Published under [MIT License](./LICENSE).
|
||||
|
||||
cloudflared integration based on a fork of [JacobLinCool/node-cloudflared](https://github.com/JacobLinCool/node-cloudflared)
|
||||
|
||||
Your installation of cloudflared software constitutes a symbol of your signature indicating that you accept the terms of the Cloudflare [License](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/license/), [Terms](https://www.cloudflare.com/terms/) and [Privacy Policy](https://www.cloudflare.com/privacypolicy/).
|
||||
|
||||
<!-- Badges -->
|
||||
|
||||
[npm-version-src]: https://img.shields.io/npm/v/untun?style=flat&colorA=18181B&colorB=F0DB4F
|
||||
[npm-version-href]: https://npmjs.com/package/untun
|
||||
[npm-downloads-src]: https://img.shields.io/npm/dm/untun?style=flat&colorA=18181B&colorB=F0DB4F
|
||||
[npm-downloads-href]: https://npmjs.com/package/untun
|
||||
[codecov-src]: https://img.shields.io/codecov/c/gh/unjs/untun/main?style=flat&colorA=18181B&colorB=F0DB4F
|
||||
[codecov-href]: https://codecov.io/gh/unjs/untun
|
||||
[bundle-src]: https://img.shields.io/bundlephobia/minzip/untun?style=flat&colorA=18181B&colorB=F0DB4F
|
||||
[bundle-href]: https://bundlephobia.com/result?p=untun
|
||||
[license-src]: https://img.shields.io/github/license/unjs/untun.svg?style=flat&colorA=18181B&colorB=F0DB4F
|
||||
[license-href]: https://github.com/unjs/untun/blob/main/LICENSE
|
||||
5
node_modules/untun/bin/untun.mjs
generated
vendored
Executable file
5
node_modules/untun/bin/untun.mjs
generated
vendored
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { runMain } from "../dist/cli.mjs";
|
||||
|
||||
runMain();
|
||||
200
node_modules/untun/dist/chunks/index.cjs
generated
vendored
Normal file
200
node_modules/untun/dist/chunks/index.cjs
generated
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
'use strict';
|
||||
|
||||
const os = require('node:os');
|
||||
const path = require('pathe');
|
||||
const fs = require('node:fs');
|
||||
const path$1 = require('node:path');
|
||||
const https = require('node:https');
|
||||
const node_child_process = require('node:child_process');
|
||||
|
||||
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
||||
|
||||
const path__default = /*#__PURE__*/_interopDefaultCompat(path);
|
||||
const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
|
||||
const path__default$1 = /*#__PURE__*/_interopDefaultCompat(path$1);
|
||||
const https__default = /*#__PURE__*/_interopDefaultCompat(https);
|
||||
|
||||
const CLOUDFLARED_VERSION = process.env.CLOUDFLARED_VERSION || "2023.10.0";
|
||||
const RELEASE_BASE = "https://github.com/cloudflare/cloudflared/releases/";
|
||||
const cloudflaredBinPath = path__default.join(
|
||||
os.tmpdir(),
|
||||
"node-untun",
|
||||
process.platform === "win32" ? `cloudflared.${CLOUDFLARED_VERSION}.exe` : `cloudflared.${CLOUDFLARED_VERSION}`
|
||||
);
|
||||
const cloudflaredNotice = `
|
||||
\u{1F525} Your installation of cloudflared software constitutes a symbol of your signature
|
||||
indicating that you accept the terms of the Cloudflare License, Terms and Privacy Policy.
|
||||
|
||||
\u276F License: \`https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/license/\`
|
||||
\u276F Terms: \`https://www.cloudflare.com/terms/\`
|
||||
\u276F Privacy Policy: \`https://www.cloudflare.com/privacypolicy/\`
|
||||
`;
|
||||
const connRegex = /connection[ =]([\da-z-]+)/i;
|
||||
const ipRegex = /ip=([\d.]+)/;
|
||||
const locationRegex = /location=([A-Z]+)/;
|
||||
const indexRegex = /connIndex=(\d)/;
|
||||
|
||||
const LINUX_URL = {
|
||||
arm64: "cloudflared-linux-arm64",
|
||||
arm: "cloudflared-linux-arm",
|
||||
x64: "cloudflared-linux-amd64",
|
||||
ia32: "cloudflared-linux-386"
|
||||
};
|
||||
const MACOS_URL = {
|
||||
arm64: "cloudflared-darwin-amd64.tgz",
|
||||
x64: "cloudflared-darwin-amd64.tgz"
|
||||
};
|
||||
const WINDOWS_URL = {
|
||||
x64: "cloudflared-windows-amd64.exe",
|
||||
ia32: "cloudflared-windows-386.exe"
|
||||
};
|
||||
function resolveBase(version) {
|
||||
if (version === "latest") {
|
||||
return `${RELEASE_BASE}latest/download/`;
|
||||
}
|
||||
return `${RELEASE_BASE}download/${version}/`;
|
||||
}
|
||||
function installCloudflared(to = cloudflaredBinPath, version = CLOUDFLARED_VERSION) {
|
||||
switch (process.platform) {
|
||||
case "linux": {
|
||||
return installLinux(to, version);
|
||||
}
|
||||
case "darwin": {
|
||||
return installMacos(to, version);
|
||||
}
|
||||
case "win32": {
|
||||
return installWindows(to, version);
|
||||
}
|
||||
default: {
|
||||
throw new Error("Unsupported platform: " + process.platform);
|
||||
}
|
||||
}
|
||||
}
|
||||
async function installLinux(to, version = CLOUDFLARED_VERSION) {
|
||||
const file = LINUX_URL[process.arch];
|
||||
if (file === void 0) {
|
||||
throw new Error("Unsupported architecture: " + process.arch);
|
||||
}
|
||||
await download(resolveBase(version) + file, to);
|
||||
fs__default.chmodSync(to, "755");
|
||||
return to;
|
||||
}
|
||||
async function installMacos(to, version = CLOUDFLARED_VERSION) {
|
||||
const file = MACOS_URL[process.arch];
|
||||
if (file === void 0) {
|
||||
throw new Error("Unsupported architecture: " + process.arch);
|
||||
}
|
||||
await download(resolveBase(version) + file, `${to}.tgz`);
|
||||
process.env.DEBUG && console.log(`Extracting to ${to}`);
|
||||
node_child_process.execSync(`tar -xzf ${path__default$1.basename(`${to}.tgz`)}`, { cwd: path__default$1.dirname(to) });
|
||||
fs__default.unlinkSync(`${to}.tgz`);
|
||||
fs__default.renameSync(`${path__default$1.dirname(to)}/cloudflared`, to);
|
||||
return to;
|
||||
}
|
||||
async function installWindows(to, version = CLOUDFLARED_VERSION) {
|
||||
const file = WINDOWS_URL[process.arch];
|
||||
if (file === void 0) {
|
||||
throw new Error("Unsupported architecture: " + process.arch);
|
||||
}
|
||||
await download(resolveBase(version) + file, to);
|
||||
return to;
|
||||
}
|
||||
function download(url, to, redirect = 0) {
|
||||
if (redirect === 0) {
|
||||
process.env.DEBUG && console.log(`Downloading ${url} to ${to}`);
|
||||
} else {
|
||||
process.env.DEBUG && console.log(`Redirecting to ${url}`);
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!fs__default.existsSync(path__default$1.dirname(to))) {
|
||||
fs__default.mkdirSync(path__default$1.dirname(to), { recursive: true });
|
||||
}
|
||||
let done = true;
|
||||
const file = fs__default.createWriteStream(to);
|
||||
const request = https__default.get(url, (res) => {
|
||||
if (res.statusCode === 302 && res.headers.location !== void 0) {
|
||||
const redirection = res.headers.location;
|
||||
done = false;
|
||||
file.close(() => resolve(download(redirection, to, redirect + 1)));
|
||||
return;
|
||||
}
|
||||
res.pipe(file);
|
||||
});
|
||||
file.on("finish", () => {
|
||||
if (done) {
|
||||
file.close(() => resolve(to));
|
||||
}
|
||||
});
|
||||
request.on("error", (err) => {
|
||||
fs__default.unlink(to, () => reject(err));
|
||||
});
|
||||
file.on("error", (err) => {
|
||||
fs__default.unlink(to, () => reject(err));
|
||||
});
|
||||
request.end();
|
||||
});
|
||||
}
|
||||
|
||||
function startCloudflaredTunnel(options = {}) {
|
||||
const args = ["tunnel"];
|
||||
for (const [key, value] of Object.entries(options)) {
|
||||
if (typeof value === "string") {
|
||||
args.push(`${key}`, value);
|
||||
} else if (typeof value === "number") {
|
||||
args.push(`${key}`, value.toString());
|
||||
} else if (value === null) {
|
||||
args.push(`${key}`);
|
||||
}
|
||||
}
|
||||
if (args.length === 1) {
|
||||
args.push("--url", "localhost:8080");
|
||||
}
|
||||
const child = node_child_process.spawn(cloudflaredBinPath, args, {
|
||||
stdio: ["ignore", "pipe", "pipe"]
|
||||
});
|
||||
if (process.env.DEBUG) {
|
||||
child.stdout.pipe(process.stdout);
|
||||
child.stderr.pipe(process.stderr);
|
||||
}
|
||||
const urlRegex = /\|\s+(https?:\/\/\S+)/;
|
||||
let urlResolver = () => void 0;
|
||||
let urlRejector = () => void 0;
|
||||
const url = new Promise(
|
||||
(...pair) => [urlResolver, urlRejector] = pair
|
||||
);
|
||||
const connectionResolvers = [];
|
||||
const connectionRejectors = [];
|
||||
const connections = [];
|
||||
for (let i = 0; i < 1; i++) {
|
||||
connections.push(
|
||||
new Promise(
|
||||
(...pair) => [connectionResolvers[i], connectionRejectors[i]] = pair
|
||||
)
|
||||
);
|
||||
}
|
||||
const parser = (data) => {
|
||||
const str = data.toString();
|
||||
const urlMatch = str.match(urlRegex);
|
||||
urlMatch && urlResolver(urlMatch[1]);
|
||||
const connMatch = str.match(connRegex);
|
||||
const ipMatch = str.match(ipRegex);
|
||||
const locationMatch = str.match(locationRegex);
|
||||
const indexMatch = str.match(indexRegex);
|
||||
if (connMatch && ipMatch && locationMatch && indexMatch) {
|
||||
const [, id] = connMatch;
|
||||
const [, ip] = ipMatch;
|
||||
const [, location] = locationMatch;
|
||||
const [, idx] = indexMatch;
|
||||
connectionResolvers[+idx]?.({ id, ip, location });
|
||||
}
|
||||
};
|
||||
child.stdout.on("data", parser).on("error", urlRejector);
|
||||
child.stderr.on("data", parser).on("error", urlRejector);
|
||||
const stop = () => child.kill("SIGINT");
|
||||
return { url, connections, child, stop };
|
||||
}
|
||||
|
||||
exports.cloudflaredBinPath = cloudflaredBinPath;
|
||||
exports.cloudflaredNotice = cloudflaredNotice;
|
||||
exports.installCloudflared = installCloudflared;
|
||||
exports.startCloudflaredTunnel = startCloudflaredTunnel;
|
||||
188
node_modules/untun/dist/chunks/index.mjs
generated
vendored
Normal file
188
node_modules/untun/dist/chunks/index.mjs
generated
vendored
Normal file
@@ -0,0 +1,188 @@
|
||||
import { tmpdir } from 'node:os';
|
||||
import path from 'pathe';
|
||||
import fs from 'node:fs';
|
||||
import path$1 from 'node:path';
|
||||
import https from 'node:https';
|
||||
import { execSync, spawn } from 'node:child_process';
|
||||
|
||||
const CLOUDFLARED_VERSION = process.env.CLOUDFLARED_VERSION || "2023.10.0";
|
||||
const RELEASE_BASE = "https://github.com/cloudflare/cloudflared/releases/";
|
||||
const cloudflaredBinPath = path.join(
|
||||
tmpdir(),
|
||||
"node-untun",
|
||||
process.platform === "win32" ? `cloudflared.${CLOUDFLARED_VERSION}.exe` : `cloudflared.${CLOUDFLARED_VERSION}`
|
||||
);
|
||||
const cloudflaredNotice = `
|
||||
\u{1F525} Your installation of cloudflared software constitutes a symbol of your signature
|
||||
indicating that you accept the terms of the Cloudflare License, Terms and Privacy Policy.
|
||||
|
||||
\u276F License: \`https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/license/\`
|
||||
\u276F Terms: \`https://www.cloudflare.com/terms/\`
|
||||
\u276F Privacy Policy: \`https://www.cloudflare.com/privacypolicy/\`
|
||||
`;
|
||||
const connRegex = /connection[ =]([\da-z-]+)/i;
|
||||
const ipRegex = /ip=([\d.]+)/;
|
||||
const locationRegex = /location=([A-Z]+)/;
|
||||
const indexRegex = /connIndex=(\d)/;
|
||||
|
||||
const LINUX_URL = {
|
||||
arm64: "cloudflared-linux-arm64",
|
||||
arm: "cloudflared-linux-arm",
|
||||
x64: "cloudflared-linux-amd64",
|
||||
ia32: "cloudflared-linux-386"
|
||||
};
|
||||
const MACOS_URL = {
|
||||
arm64: "cloudflared-darwin-amd64.tgz",
|
||||
x64: "cloudflared-darwin-amd64.tgz"
|
||||
};
|
||||
const WINDOWS_URL = {
|
||||
x64: "cloudflared-windows-amd64.exe",
|
||||
ia32: "cloudflared-windows-386.exe"
|
||||
};
|
||||
function resolveBase(version) {
|
||||
if (version === "latest") {
|
||||
return `${RELEASE_BASE}latest/download/`;
|
||||
}
|
||||
return `${RELEASE_BASE}download/${version}/`;
|
||||
}
|
||||
function installCloudflared(to = cloudflaredBinPath, version = CLOUDFLARED_VERSION) {
|
||||
switch (process.platform) {
|
||||
case "linux": {
|
||||
return installLinux(to, version);
|
||||
}
|
||||
case "darwin": {
|
||||
return installMacos(to, version);
|
||||
}
|
||||
case "win32": {
|
||||
return installWindows(to, version);
|
||||
}
|
||||
default: {
|
||||
throw new Error("Unsupported platform: " + process.platform);
|
||||
}
|
||||
}
|
||||
}
|
||||
async function installLinux(to, version = CLOUDFLARED_VERSION) {
|
||||
const file = LINUX_URL[process.arch];
|
||||
if (file === void 0) {
|
||||
throw new Error("Unsupported architecture: " + process.arch);
|
||||
}
|
||||
await download(resolveBase(version) + file, to);
|
||||
fs.chmodSync(to, "755");
|
||||
return to;
|
||||
}
|
||||
async function installMacos(to, version = CLOUDFLARED_VERSION) {
|
||||
const file = MACOS_URL[process.arch];
|
||||
if (file === void 0) {
|
||||
throw new Error("Unsupported architecture: " + process.arch);
|
||||
}
|
||||
await download(resolveBase(version) + file, `${to}.tgz`);
|
||||
process.env.DEBUG && console.log(`Extracting to ${to}`);
|
||||
execSync(`tar -xzf ${path$1.basename(`${to}.tgz`)}`, { cwd: path$1.dirname(to) });
|
||||
fs.unlinkSync(`${to}.tgz`);
|
||||
fs.renameSync(`${path$1.dirname(to)}/cloudflared`, to);
|
||||
return to;
|
||||
}
|
||||
async function installWindows(to, version = CLOUDFLARED_VERSION) {
|
||||
const file = WINDOWS_URL[process.arch];
|
||||
if (file === void 0) {
|
||||
throw new Error("Unsupported architecture: " + process.arch);
|
||||
}
|
||||
await download(resolveBase(version) + file, to);
|
||||
return to;
|
||||
}
|
||||
function download(url, to, redirect = 0) {
|
||||
if (redirect === 0) {
|
||||
process.env.DEBUG && console.log(`Downloading ${url} to ${to}`);
|
||||
} else {
|
||||
process.env.DEBUG && console.log(`Redirecting to ${url}`);
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!fs.existsSync(path$1.dirname(to))) {
|
||||
fs.mkdirSync(path$1.dirname(to), { recursive: true });
|
||||
}
|
||||
let done = true;
|
||||
const file = fs.createWriteStream(to);
|
||||
const request = https.get(url, (res) => {
|
||||
if (res.statusCode === 302 && res.headers.location !== void 0) {
|
||||
const redirection = res.headers.location;
|
||||
done = false;
|
||||
file.close(() => resolve(download(redirection, to, redirect + 1)));
|
||||
return;
|
||||
}
|
||||
res.pipe(file);
|
||||
});
|
||||
file.on("finish", () => {
|
||||
if (done) {
|
||||
file.close(() => resolve(to));
|
||||
}
|
||||
});
|
||||
request.on("error", (err) => {
|
||||
fs.unlink(to, () => reject(err));
|
||||
});
|
||||
file.on("error", (err) => {
|
||||
fs.unlink(to, () => reject(err));
|
||||
});
|
||||
request.end();
|
||||
});
|
||||
}
|
||||
|
||||
function startCloudflaredTunnel(options = {}) {
|
||||
const args = ["tunnel"];
|
||||
for (const [key, value] of Object.entries(options)) {
|
||||
if (typeof value === "string") {
|
||||
args.push(`${key}`, value);
|
||||
} else if (typeof value === "number") {
|
||||
args.push(`${key}`, value.toString());
|
||||
} else if (value === null) {
|
||||
args.push(`${key}`);
|
||||
}
|
||||
}
|
||||
if (args.length === 1) {
|
||||
args.push("--url", "localhost:8080");
|
||||
}
|
||||
const child = spawn(cloudflaredBinPath, args, {
|
||||
stdio: ["ignore", "pipe", "pipe"]
|
||||
});
|
||||
if (process.env.DEBUG) {
|
||||
child.stdout.pipe(process.stdout);
|
||||
child.stderr.pipe(process.stderr);
|
||||
}
|
||||
const urlRegex = /\|\s+(https?:\/\/\S+)/;
|
||||
let urlResolver = () => void 0;
|
||||
let urlRejector = () => void 0;
|
||||
const url = new Promise(
|
||||
(...pair) => [urlResolver, urlRejector] = pair
|
||||
);
|
||||
const connectionResolvers = [];
|
||||
const connectionRejectors = [];
|
||||
const connections = [];
|
||||
for (let i = 0; i < 1; i++) {
|
||||
connections.push(
|
||||
new Promise(
|
||||
(...pair) => [connectionResolvers[i], connectionRejectors[i]] = pair
|
||||
)
|
||||
);
|
||||
}
|
||||
const parser = (data) => {
|
||||
const str = data.toString();
|
||||
const urlMatch = str.match(urlRegex);
|
||||
urlMatch && urlResolver(urlMatch[1]);
|
||||
const connMatch = str.match(connRegex);
|
||||
const ipMatch = str.match(ipRegex);
|
||||
const locationMatch = str.match(locationRegex);
|
||||
const indexMatch = str.match(indexRegex);
|
||||
if (connMatch && ipMatch && locationMatch && indexMatch) {
|
||||
const [, id] = connMatch;
|
||||
const [, ip] = ipMatch;
|
||||
const [, location] = locationMatch;
|
||||
const [, idx] = indexMatch;
|
||||
connectionResolvers[+idx]?.({ id, ip, location });
|
||||
}
|
||||
};
|
||||
child.stdout.on("data", parser).on("error", urlRejector);
|
||||
child.stderr.on("data", parser).on("error", urlRejector);
|
||||
const stop = () => child.kill("SIGINT");
|
||||
return { url, connections, child, stop };
|
||||
}
|
||||
|
||||
export { cloudflaredBinPath, cloudflaredNotice, installCloudflared, startCloudflaredTunnel };
|
||||
68
node_modules/untun/dist/cli.cjs
generated
vendored
Normal file
68
node_modules/untun/dist/cli.cjs
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
'use strict';
|
||||
|
||||
const citty = require('citty');
|
||||
const consola = require('consola');
|
||||
const index = require('./index.cjs');
|
||||
require('node:fs');
|
||||
|
||||
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
||||
|
||||
const consola__default = /*#__PURE__*/_interopDefaultCompat(consola);
|
||||
|
||||
const name = "untun";
|
||||
const version = "0.1.3";
|
||||
const description = "Tunnel your local HTTP(s) server to the world! Powered by Cloudflare Quick Tunnels.";
|
||||
|
||||
const tunnel = citty.defineCommand({
|
||||
meta: {
|
||||
name: "tunnel",
|
||||
description: "Create a tunnel to a local server"
|
||||
},
|
||||
args: {
|
||||
url: {
|
||||
type: "positional",
|
||||
description: "The URL of the tunnel",
|
||||
required: false
|
||||
},
|
||||
port: {
|
||||
type: "string",
|
||||
description: "The port of the tunnel (default: 3000)"
|
||||
},
|
||||
hostname: {
|
||||
type: "string",
|
||||
description: "The hostname of the tunnel (default: localhost)",
|
||||
valueHint: "localhost|example.com"
|
||||
},
|
||||
protocol: {
|
||||
type: "string",
|
||||
description: "The protocol of the tunnel (default: http)",
|
||||
valueHint: "http|https"
|
||||
}
|
||||
},
|
||||
async run({ args }) {
|
||||
const tunnel2 = await index.startTunnel({
|
||||
url: args.url
|
||||
});
|
||||
if (!tunnel2) {
|
||||
console.log("Tunnel not started.");
|
||||
process.exit(1);
|
||||
}
|
||||
consola__default.info("Waiting for tunnel URL...");
|
||||
consola__default.success(`Tunnel ready at \`${await tunnel2.getURL()}\``);
|
||||
}
|
||||
});
|
||||
const main = citty.defineCommand({
|
||||
meta: {
|
||||
name,
|
||||
description,
|
||||
version
|
||||
},
|
||||
subCommands: {
|
||||
tunnel
|
||||
}
|
||||
});
|
||||
const runMain = () => citty.runMain(main);
|
||||
|
||||
exports.main = main;
|
||||
exports.runMain = runMain;
|
||||
exports.tunnel = tunnel;
|
||||
27
node_modules/untun/dist/cli.d.cts
generated
vendored
Normal file
27
node_modules/untun/dist/cli.d.cts
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
import * as citty from 'citty';
|
||||
|
||||
declare const tunnel: citty.CommandDef<{
|
||||
url: {
|
||||
type: "positional";
|
||||
description: string;
|
||||
required: false;
|
||||
};
|
||||
port: {
|
||||
type: "string";
|
||||
description: string;
|
||||
};
|
||||
hostname: {
|
||||
type: "string";
|
||||
description: string;
|
||||
valueHint: string;
|
||||
};
|
||||
protocol: {
|
||||
type: "string";
|
||||
description: string;
|
||||
valueHint: string;
|
||||
};
|
||||
}>;
|
||||
declare const main: citty.CommandDef<citty.ArgsDef>;
|
||||
declare const runMain: () => Promise<void>;
|
||||
|
||||
export { main, runMain, tunnel };
|
||||
27
node_modules/untun/dist/cli.d.mts
generated
vendored
Normal file
27
node_modules/untun/dist/cli.d.mts
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
import * as citty from 'citty';
|
||||
|
||||
declare const tunnel: citty.CommandDef<{
|
||||
url: {
|
||||
type: "positional";
|
||||
description: string;
|
||||
required: false;
|
||||
};
|
||||
port: {
|
||||
type: "string";
|
||||
description: string;
|
||||
};
|
||||
hostname: {
|
||||
type: "string";
|
||||
description: string;
|
||||
valueHint: string;
|
||||
};
|
||||
protocol: {
|
||||
type: "string";
|
||||
description: string;
|
||||
valueHint: string;
|
||||
};
|
||||
}>;
|
||||
declare const main: citty.CommandDef<citty.ArgsDef>;
|
||||
declare const runMain: () => Promise<void>;
|
||||
|
||||
export { main, runMain, tunnel };
|
||||
27
node_modules/untun/dist/cli.d.ts
generated
vendored
Normal file
27
node_modules/untun/dist/cli.d.ts
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
import * as citty from 'citty';
|
||||
|
||||
declare const tunnel: citty.CommandDef<{
|
||||
url: {
|
||||
type: "positional";
|
||||
description: string;
|
||||
required: false;
|
||||
};
|
||||
port: {
|
||||
type: "string";
|
||||
description: string;
|
||||
};
|
||||
hostname: {
|
||||
type: "string";
|
||||
description: string;
|
||||
valueHint: string;
|
||||
};
|
||||
protocol: {
|
||||
type: "string";
|
||||
description: string;
|
||||
valueHint: string;
|
||||
};
|
||||
}>;
|
||||
declare const main: citty.CommandDef<citty.ArgsDef>;
|
||||
declare const runMain: () => Promise<void>;
|
||||
|
||||
export { main, runMain, tunnel };
|
||||
60
node_modules/untun/dist/cli.mjs
generated
vendored
Normal file
60
node_modules/untun/dist/cli.mjs
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
import { defineCommand, runMain as runMain$1 } from 'citty';
|
||||
import consola from 'consola';
|
||||
import { startTunnel } from './index.mjs';
|
||||
import 'node:fs';
|
||||
|
||||
const name = "untun";
|
||||
const version = "0.1.3";
|
||||
const description = "Tunnel your local HTTP(s) server to the world! Powered by Cloudflare Quick Tunnels.";
|
||||
|
||||
const tunnel = defineCommand({
|
||||
meta: {
|
||||
name: "tunnel",
|
||||
description: "Create a tunnel to a local server"
|
||||
},
|
||||
args: {
|
||||
url: {
|
||||
type: "positional",
|
||||
description: "The URL of the tunnel",
|
||||
required: false
|
||||
},
|
||||
port: {
|
||||
type: "string",
|
||||
description: "The port of the tunnel (default: 3000)"
|
||||
},
|
||||
hostname: {
|
||||
type: "string",
|
||||
description: "The hostname of the tunnel (default: localhost)",
|
||||
valueHint: "localhost|example.com"
|
||||
},
|
||||
protocol: {
|
||||
type: "string",
|
||||
description: "The protocol of the tunnel (default: http)",
|
||||
valueHint: "http|https"
|
||||
}
|
||||
},
|
||||
async run({ args }) {
|
||||
const tunnel2 = await startTunnel({
|
||||
url: args.url
|
||||
});
|
||||
if (!tunnel2) {
|
||||
console.log("Tunnel not started.");
|
||||
process.exit(1);
|
||||
}
|
||||
consola.info("Waiting for tunnel URL...");
|
||||
consola.success(`Tunnel ready at \`${await tunnel2.getURL()}\``);
|
||||
}
|
||||
});
|
||||
const main = defineCommand({
|
||||
meta: {
|
||||
name,
|
||||
description,
|
||||
version
|
||||
},
|
||||
subCommands: {
|
||||
tunnel
|
||||
}
|
||||
});
|
||||
const runMain = () => runMain$1(main);
|
||||
|
||||
export { main, runMain, tunnel };
|
||||
52
node_modules/untun/dist/index.cjs
generated
vendored
Normal file
52
node_modules/untun/dist/index.cjs
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('node:fs');
|
||||
const consola = require('consola');
|
||||
|
||||
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
||||
|
||||
const consola__default = /*#__PURE__*/_interopDefaultCompat(consola);
|
||||
|
||||
async function startTunnel(opts) {
|
||||
const {
|
||||
installCloudflared,
|
||||
startCloudflaredTunnel,
|
||||
cloudflaredBinPath,
|
||||
cloudflaredNotice
|
||||
} = await import('./chunks/index.cjs');
|
||||
const url = opts.url || `${opts.protocol || "http"}://${opts.hostname ?? "localhost"}:${opts.port ?? 3e3}`;
|
||||
consola__default.start(`Starting cloudflared tunnel to ${url}`);
|
||||
if (!fs.existsSync(cloudflaredBinPath)) {
|
||||
consola__default.log(cloudflaredNotice);
|
||||
const canInstall = opts.acceptCloudflareNotice || process.env.UNTUN_ACCEPT_CLOUDFLARE_NOTICE || await consola__default.prompt(
|
||||
`Do you agree with the above terms and wish to install the binary from GitHub?`,
|
||||
{
|
||||
type: "confirm"
|
||||
}
|
||||
);
|
||||
if (!canInstall) {
|
||||
consola__default.fail("Skipping tunnel setup.");
|
||||
return;
|
||||
}
|
||||
await installCloudflared();
|
||||
}
|
||||
const args = [
|
||||
["--url", url],
|
||||
opts.verifyTLS ? void 0 : ["--no-tls-verify", ""]
|
||||
].filter(Boolean);
|
||||
const tunnel = await startCloudflaredTunnel(Object.fromEntries(args));
|
||||
const cleanup = async () => {
|
||||
await tunnel.stop();
|
||||
};
|
||||
for (const signal of ["SIGINT", "SIGUSR1", "SIGUSR2"]) {
|
||||
process.once(signal, cleanup);
|
||||
}
|
||||
return {
|
||||
getURL: async () => await tunnel.url,
|
||||
close: async () => {
|
||||
await cleanup();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
exports.startTunnel = startTunnel;
|
||||
15
node_modules/untun/dist/index.d.cts
generated
vendored
Normal file
15
node_modules/untun/dist/index.d.cts
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
interface TunnelOptions {
|
||||
url?: string;
|
||||
port?: number | string;
|
||||
hostname?: string;
|
||||
protocol?: "http" | "https";
|
||||
verifyTLS?: boolean;
|
||||
acceptCloudflareNotice?: boolean;
|
||||
}
|
||||
interface Tunnel {
|
||||
getURL: () => Promise<string>;
|
||||
close: () => Promise<void>;
|
||||
}
|
||||
declare function startTunnel(opts: TunnelOptions): Promise<undefined | Tunnel>;
|
||||
|
||||
export { type Tunnel, type TunnelOptions, startTunnel };
|
||||
15
node_modules/untun/dist/index.d.mts
generated
vendored
Normal file
15
node_modules/untun/dist/index.d.mts
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
interface TunnelOptions {
|
||||
url?: string;
|
||||
port?: number | string;
|
||||
hostname?: string;
|
||||
protocol?: "http" | "https";
|
||||
verifyTLS?: boolean;
|
||||
acceptCloudflareNotice?: boolean;
|
||||
}
|
||||
interface Tunnel {
|
||||
getURL: () => Promise<string>;
|
||||
close: () => Promise<void>;
|
||||
}
|
||||
declare function startTunnel(opts: TunnelOptions): Promise<undefined | Tunnel>;
|
||||
|
||||
export { type Tunnel, type TunnelOptions, startTunnel };
|
||||
15
node_modules/untun/dist/index.d.ts
generated
vendored
Normal file
15
node_modules/untun/dist/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
interface TunnelOptions {
|
||||
url?: string;
|
||||
port?: number | string;
|
||||
hostname?: string;
|
||||
protocol?: "http" | "https";
|
||||
verifyTLS?: boolean;
|
||||
acceptCloudflareNotice?: boolean;
|
||||
}
|
||||
interface Tunnel {
|
||||
getURL: () => Promise<string>;
|
||||
close: () => Promise<void>;
|
||||
}
|
||||
declare function startTunnel(opts: TunnelOptions): Promise<undefined | Tunnel>;
|
||||
|
||||
export { type Tunnel, type TunnelOptions, startTunnel };
|
||||
46
node_modules/untun/dist/index.mjs
generated
vendored
Normal file
46
node_modules/untun/dist/index.mjs
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
import { existsSync } from 'node:fs';
|
||||
import consola from 'consola';
|
||||
|
||||
async function startTunnel(opts) {
|
||||
const {
|
||||
installCloudflared,
|
||||
startCloudflaredTunnel,
|
||||
cloudflaredBinPath,
|
||||
cloudflaredNotice
|
||||
} = await import('./chunks/index.mjs');
|
||||
const url = opts.url || `${opts.protocol || "http"}://${opts.hostname ?? "localhost"}:${opts.port ?? 3e3}`;
|
||||
consola.start(`Starting cloudflared tunnel to ${url}`);
|
||||
if (!existsSync(cloudflaredBinPath)) {
|
||||
consola.log(cloudflaredNotice);
|
||||
const canInstall = opts.acceptCloudflareNotice || process.env.UNTUN_ACCEPT_CLOUDFLARE_NOTICE || await consola.prompt(
|
||||
`Do you agree with the above terms and wish to install the binary from GitHub?`,
|
||||
{
|
||||
type: "confirm"
|
||||
}
|
||||
);
|
||||
if (!canInstall) {
|
||||
consola.fail("Skipping tunnel setup.");
|
||||
return;
|
||||
}
|
||||
await installCloudflared();
|
||||
}
|
||||
const args = [
|
||||
["--url", url],
|
||||
opts.verifyTLS ? void 0 : ["--no-tls-verify", ""]
|
||||
].filter(Boolean);
|
||||
const tunnel = await startCloudflaredTunnel(Object.fromEntries(args));
|
||||
const cleanup = async () => {
|
||||
await tunnel.stop();
|
||||
};
|
||||
for (const signal of ["SIGINT", "SIGUSR1", "SIGUSR2"]) {
|
||||
process.once(signal, cleanup);
|
||||
}
|
||||
return {
|
||||
getURL: async () => await tunnel.url,
|
||||
close: async () => {
|
||||
await cleanup();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export { startTunnel };
|
||||
60
node_modules/untun/package.json
generated
vendored
Normal file
60
node_modules/untun/package.json
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"name": "untun",
|
||||
"version": "0.1.3",
|
||||
"description": "Tunnel your local HTTP(s) server to the world! Powered by Cloudflare Quick Tunnels.",
|
||||
"repository": "unjs/untun",
|
||||
"license": "MIT",
|
||||
"sideEffects": false,
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.mjs",
|
||||
"require": "./dist/index.cjs"
|
||||
},
|
||||
"./cli": {
|
||||
"types": "./dist/cli.d.ts",
|
||||
"import": "./dist/cli.mjs",
|
||||
"require": "./dist/cli.cjs"
|
||||
}
|
||||
},
|
||||
"main": "./dist/index.cjs",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"bin": {
|
||||
"untun": "./bin/untun.mjs"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"bin"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "unbuild",
|
||||
"dev": "vitest dev",
|
||||
"lint": "eslint --cache --ext .ts,.js,.mjs,.cjs . && prettier -c src test",
|
||||
"lint:fix": "eslint --cache --ext .ts,.js,.mjs,.cjs . --fix && prettier -c src test -w",
|
||||
"prepack": "pnpm run build",
|
||||
"release": "pnpm test && changelogen --release && npm publish && git push --follow-tags",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"test": "pnpm lint &&pnpm typecheck && vitest run --coverage",
|
||||
"untun": "jiti ./scripts/untun.mjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"citty": "^0.1.5",
|
||||
"consola": "^3.2.3",
|
||||
"pathe": "^1.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.10.4",
|
||||
"@vitest/coverage-v8": "^1.0.4",
|
||||
"changelogen": "^0.5.5",
|
||||
"eslint": "^8.55.0",
|
||||
"eslint-config-unjs": "^0.2.1",
|
||||
"jiti": "^1.21.0",
|
||||
"prettier": "^3.1.1",
|
||||
"typescript": "^5.3.3",
|
||||
"unbuild": "^2.0.0",
|
||||
"vitest": "^1.0.4"
|
||||
},
|
||||
"packageManager": "pnpm@8.11.0"
|
||||
}
|
||||
Reference in New Issue
Block a user