@silver886/mcp-proxy 0.2.3 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/host/agent.js +69 -22
- package/dist/proxy/core/constants.d.ts +2 -0
- package/dist/proxy/core/constants.js +8 -1
- package/dist/proxy/discovery/client.js +24 -11
- package/dist/proxy/pairing/controller.d.ts +3 -0
- package/dist/proxy/pairing/controller.js +56 -4
- package/dist/proxy/pairing/http.js +11 -0
- package/dist/proxy/runtime/forwarder.js +22 -0
- package/dist/proxy/runtime/handlers.d.ts +2 -2
- package/dist/proxy/runtime/handlers.js +10 -5
- package/dist/proxy/runtime/sse.js +6 -0
- package/dist/proxy/runtime/upstream-bridge.js +9 -3
- package/dist/proxy/server.js +10 -0
- package/dist/shared/protocol.d.ts +7 -0
- package/dist/shared/protocol.js +44 -0
- package/package.json +17 -3
- package/scripts/fetch.mjs +87 -0
- package/static/setup.js +86 -25
- package/node_modules/cloudflared/LICENSE +0 -21
- package/node_modules/cloudflared/README.md +0 -156
- package/node_modules/cloudflared/lib/cloudflared.js +0 -10
- package/node_modules/cloudflared/lib/constants.js +0 -58
- package/node_modules/cloudflared/lib/error.js +0 -32
- package/node_modules/cloudflared/lib/handler.js +0 -117
- package/node_modules/cloudflared/lib/index.js +0 -126
- package/node_modules/cloudflared/lib/install.js +0 -155
- package/node_modules/cloudflared/lib/lib.d.ts +0 -236
- package/node_modules/cloudflared/lib/lib.js +0 -45
- package/node_modules/cloudflared/lib/regex.js +0 -52
- package/node_modules/cloudflared/lib/service.js +0 -229
- package/node_modules/cloudflared/lib/tunnel.js +0 -164
- package/node_modules/cloudflared/lib/types.js +0 -16
- package/node_modules/cloudflared/package.json +0 -59
- package/node_modules/cloudflared/scripts/postinstall.mjs +0 -10
- package/node_modules/eventsource-parser/LICENSE +0 -21
- package/node_modules/eventsource-parser/README.md +0 -126
- package/node_modules/eventsource-parser/dist/index.cjs +0 -166
- package/node_modules/eventsource-parser/dist/index.cjs.map +0 -1
- package/node_modules/eventsource-parser/dist/index.d.cts +0 -146
- package/node_modules/eventsource-parser/dist/index.d.ts +0 -146
- package/node_modules/eventsource-parser/dist/index.js +0 -166
- package/node_modules/eventsource-parser/dist/index.js.map +0 -1
- package/node_modules/eventsource-parser/dist/stream.cjs +0 -28
- package/node_modules/eventsource-parser/dist/stream.cjs.map +0 -1
- package/node_modules/eventsource-parser/dist/stream.d.cts +0 -121
- package/node_modules/eventsource-parser/dist/stream.d.ts +0 -121
- package/node_modules/eventsource-parser/dist/stream.js +0 -29
- package/node_modules/eventsource-parser/dist/stream.js.map +0 -1
- package/node_modules/eventsource-parser/package.json +0 -92
- package/node_modules/eventsource-parser/src/errors.ts +0 -44
- package/node_modules/eventsource-parser/src/index.ts +0 -3
- package/node_modules/eventsource-parser/src/parse.ts +0 -395
- package/node_modules/eventsource-parser/src/stream.ts +0 -88
- package/node_modules/eventsource-parser/src/types.ts +0 -97
- package/node_modules/eventsource-parser/stream.js +0 -2
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Reads `lockedDependencies` from package.json, downloads each registry
|
|
3
|
+
// tarball over node:https, verifies the sha512 integrity recorded by
|
|
4
|
+
// `lockdeps.mjs` at pack time, and writes the verified tarballs to ./vendor/.
|
|
5
|
+
// Extraction is intentionally out of scope — pair with `tar -xzf` (system
|
|
6
|
+
// `tar` is on Win10 1803+, every Linux, every macOS) or your unpacker.
|
|
7
|
+
import { createHash } from "node:crypto";
|
|
8
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
9
|
+
import { request } from "node:https";
|
|
10
|
+
import { dirname, join, resolve } from "node:path";
|
|
11
|
+
import { fileURLToPath, URL } from "node:url";
|
|
12
|
+
|
|
13
|
+
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
14
|
+
const PKG_PATH = join(ROOT, "package.json");
|
|
15
|
+
const OUT_DIR = resolve(ROOT, process.argv[2] ?? "vendor");
|
|
16
|
+
const USER_AGENT = "mcp-proxy-fetch";
|
|
17
|
+
|
|
18
|
+
const pkg = JSON.parse(await readFile(PKG_PATH, "utf8"));
|
|
19
|
+
const locked = pkg.lockedDependencies ?? {};
|
|
20
|
+
const names = Object.keys(locked);
|
|
21
|
+
if (names.length === 0) {
|
|
22
|
+
console.log("No lockedDependencies in package.json; nothing to fetch.");
|
|
23
|
+
process.exit(0);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
await mkdir(OUT_DIR, { recursive: true });
|
|
27
|
+
|
|
28
|
+
for (const name of names) {
|
|
29
|
+
const info = locked[name];
|
|
30
|
+
console.log(`fetch ${name}@${info.version}`);
|
|
31
|
+
const buf = await fetchAndVerify(info.tarball, info.integrity);
|
|
32
|
+
// Slug the package name so scoped + unscoped packages don't collide on
|
|
33
|
+
// the registry's bare `<name>-<version>.tgz` filename.
|
|
34
|
+
const slug = name.replace(/^@/, "").replace(/\//g, "+");
|
|
35
|
+
const out = join(OUT_DIR, `${slug}-${info.version}.tgz`);
|
|
36
|
+
await writeFile(out, buf);
|
|
37
|
+
console.log(` -> ${out} (${buf.length} bytes)`);
|
|
38
|
+
}
|
|
39
|
+
console.log(`fetched ${names.length} package${names.length === 1 ? "" : "s"} into ${OUT_DIR}`);
|
|
40
|
+
|
|
41
|
+
async function fetchAndVerify(url, integrity) {
|
|
42
|
+
const buf = await fetchBuffer(url, 5);
|
|
43
|
+
const dash = integrity.indexOf("-");
|
|
44
|
+
const algo = integrity.slice(0, dash);
|
|
45
|
+
const expected = integrity.slice(dash + 1);
|
|
46
|
+
if (algo !== "sha512") throw new Error(`unsupported integrity algo: ${algo}`);
|
|
47
|
+
const actual = createHash("sha512").update(buf).digest("base64");
|
|
48
|
+
if (actual !== expected) {
|
|
49
|
+
throw new Error(`integrity mismatch for ${url}\n expected: ${expected}\n actual: ${actual}`);
|
|
50
|
+
}
|
|
51
|
+
return buf;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function fetchBuffer(url, redirectsLeft) {
|
|
55
|
+
return new Promise((resolveP, rejectP) => {
|
|
56
|
+
const u = new URL(url);
|
|
57
|
+
const req = request(
|
|
58
|
+
{
|
|
59
|
+
hostname: u.hostname,
|
|
60
|
+
port: u.port || (u.protocol === "https:" ? 443 : 80),
|
|
61
|
+
path: u.pathname + u.search,
|
|
62
|
+
method: "GET",
|
|
63
|
+
headers: { "user-agent": USER_AGENT, "accept": "*/*" },
|
|
64
|
+
},
|
|
65
|
+
(res) => {
|
|
66
|
+
const status = res.statusCode ?? 0;
|
|
67
|
+
if ([301, 302, 303, 307, 308].includes(status) && res.headers.location) {
|
|
68
|
+
if (redirectsLeft <= 0) return rejectP(new Error(`too many redirects: ${url}`));
|
|
69
|
+
const next = new URL(res.headers.location, url).toString();
|
|
70
|
+
res.resume();
|
|
71
|
+
fetchBuffer(next, redirectsLeft - 1).then(resolveP, rejectP);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (status !== 200) {
|
|
75
|
+
res.resume();
|
|
76
|
+
return rejectP(new Error(`HTTP ${status} for ${url}`));
|
|
77
|
+
}
|
|
78
|
+
const chunks = [];
|
|
79
|
+
res.on("data", (c) => chunks.push(c));
|
|
80
|
+
res.on("end", () => resolveP(Buffer.concat(chunks)));
|
|
81
|
+
res.on("error", rejectP);
|
|
82
|
+
},
|
|
83
|
+
);
|
|
84
|
+
req.on("error", rejectP);
|
|
85
|
+
req.end();
|
|
86
|
+
});
|
|
87
|
+
}
|
package/static/setup.js
CHANGED
|
@@ -92,22 +92,37 @@
|
|
|
92
92
|
const row = document.createElement('div');
|
|
93
93
|
row.className = 'host-row';
|
|
94
94
|
row.dataset.uid = host.uid;
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
95
|
+
|
|
96
|
+
const head = document.createElement('div');
|
|
97
|
+
head.className = 'host-head';
|
|
98
|
+
const title = document.createElement('div');
|
|
99
|
+
title.className = 'host-id';
|
|
100
|
+
title.dataset.role = 'title';
|
|
101
|
+
title.textContent = `Host ${host.id || '(unnamed)'}`;
|
|
102
|
+
head.appendChild(title);
|
|
103
|
+
const removeBtn = document.createElement('button');
|
|
104
|
+
removeBtn.type = 'button';
|
|
105
|
+
removeBtn.className = 'host-remove';
|
|
106
|
+
removeBtn.dataset.action = 'remove';
|
|
107
|
+
removeBtn.textContent = 'Remove';
|
|
108
|
+
head.appendChild(removeBtn);
|
|
109
|
+
row.appendChild(head);
|
|
110
|
+
|
|
111
|
+
appendHostField(row, host.uid, 'id', 'text', host.id, 'Host ID', 'dev-laptop', {
|
|
112
|
+
pattern: '(?!.*__)[A-Za-z0-9._\\-]+',
|
|
113
|
+
title: "Letters, digits, '.', '_', '-'. Must not contain '__' and must be unique across hosts.",
|
|
114
|
+
});
|
|
115
|
+
appendHostField(row, host.uid, 'tunnelUrl', 'url', host.tunnelUrl, 'Tunnel URL', 'https://abc-xyz.trycloudflare.com');
|
|
116
|
+
appendHostField(row, host.uid, 'authToken', 'text', host.authToken, 'Auth Token', 'Paste token from host agent');
|
|
117
|
+
|
|
118
|
+
const status = document.createElement('div');
|
|
119
|
+
const statusClass = host.status.startsWith('Error') ? 'error'
|
|
120
|
+
: host.status.startsWith('Partial') ? 'partial'
|
|
121
|
+
: host.status ? 'ok' : '';
|
|
122
|
+
status.className = statusClass ? `host-status ${statusClass}` : 'host-status';
|
|
123
|
+
status.textContent = host.status;
|
|
124
|
+
row.appendChild(status);
|
|
125
|
+
|
|
111
126
|
container.appendChild(row);
|
|
112
127
|
}
|
|
113
128
|
// Hide remove button when there's only one row.
|
|
@@ -119,6 +134,28 @@
|
|
|
119
134
|
validateHostIdUniqueness();
|
|
120
135
|
}
|
|
121
136
|
|
|
137
|
+
// Build a label + input pair via DOM properties so user-supplied values
|
|
138
|
+
// can't escape attribute context. Template-literal interpolation with
|
|
139
|
+
// esc() escapes <, >, & only — quotes and apostrophes pass through and
|
|
140
|
+
// would let an upstream-supplied token break out of value="…".
|
|
141
|
+
function appendHostField(row, uid, field, type, value, labelText, placeholder, extras) {
|
|
142
|
+
const id = `${field}-${uid}`;
|
|
143
|
+
const label = document.createElement('label');
|
|
144
|
+
label.htmlFor = id;
|
|
145
|
+
label.textContent = labelText;
|
|
146
|
+
row.appendChild(label);
|
|
147
|
+
const input = document.createElement('input');
|
|
148
|
+
input.id = id;
|
|
149
|
+
input.type = type;
|
|
150
|
+
input.dataset.field = field;
|
|
151
|
+
input.value = value;
|
|
152
|
+
input.placeholder = placeholder;
|
|
153
|
+
input.required = true;
|
|
154
|
+
if (extras?.pattern) input.pattern = extras.pattern;
|
|
155
|
+
if (extras?.title) input.title = extras.title;
|
|
156
|
+
row.appendChild(input);
|
|
157
|
+
}
|
|
158
|
+
|
|
122
159
|
document.getElementById('hosts-container').addEventListener('input', (e) => {
|
|
123
160
|
const row = e.target.closest('.host-row');
|
|
124
161
|
if (!row) return;
|
|
@@ -583,15 +620,39 @@
|
|
|
583
620
|
const checked = honorPriors && priorSelections.selectedTools
|
|
584
621
|
? priorSelections.selectedTools.has(toolKey)
|
|
585
622
|
: true;
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
623
|
+
|
|
624
|
+
// Build via DOM properties so tool.name (sourced from an upstream
|
|
625
|
+
// MCP server, untrusted) can't escape attribute context. esc() only
|
|
626
|
+
// covers text-node escaping; a quote in tool.name would break out
|
|
627
|
+
// of data-tool="…" / id="…" / for="…" if interpolated as HTML.
|
|
628
|
+
const checkWrap = document.createElement('div');
|
|
629
|
+
checkWrap.className = 'tool-check';
|
|
630
|
+
const cb = document.createElement('input');
|
|
631
|
+
cb.type = 'checkbox';
|
|
632
|
+
cb.id = cbId;
|
|
633
|
+
cb.dataset.role = 'tool';
|
|
634
|
+
cb.dataset.host = hostId;
|
|
635
|
+
cb.dataset.server = serverName;
|
|
636
|
+
cb.dataset.tool = tool.name;
|
|
637
|
+
cb.checked = checked;
|
|
638
|
+
checkWrap.appendChild(cb);
|
|
639
|
+
item.appendChild(checkWrap);
|
|
640
|
+
|
|
641
|
+
const label = document.createElement('label');
|
|
642
|
+
label.className = 'tool-label';
|
|
643
|
+
label.htmlFor = cbId;
|
|
644
|
+
const nameSpan = document.createElement('span');
|
|
645
|
+
nameSpan.className = 'tool-name';
|
|
646
|
+
nameSpan.textContent = tool.name;
|
|
647
|
+
label.appendChild(nameSpan);
|
|
648
|
+
if (tool.description) {
|
|
649
|
+
const descSpan = document.createElement('span');
|
|
650
|
+
descSpan.className = 'tool-desc';
|
|
651
|
+
descSpan.textContent = tool.description;
|
|
652
|
+
label.appendChild(descSpan);
|
|
653
|
+
}
|
|
654
|
+
item.appendChild(label);
|
|
655
|
+
|
|
595
656
|
list.appendChild(item);
|
|
596
657
|
}
|
|
597
658
|
wrapper.appendChild(list);
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2022 JacobLinCool
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
# cloudflared
|
|
2
|
-
|
|
3
|
-
A Node.js package that allows you to easily create HTTPS tunnels using Cloudflare's `cloudflared` command-line tool. It provides a typed API for creating tunnels and managing the `cloudflared` binary installation.
|
|
4
|
-
|
|
5
|
-
> This tool will automatically install the [latest version of `cloudflared`](https://github.com/cloudflare/cloudflared/releases/latest) (or `CLOUDFLARED_VERSION` env var if exists) at the first time.
|
|
6
|
-
> Then, it just passes down the command to `cloudflared`.
|
|
7
|
-
|
|
8
|
-
## Installation
|
|
9
|
-
|
|
10
|
-
You can install this package using your favorite package manager:
|
|
11
|
-
|
|
12
|
-
### PNPM
|
|
13
|
-
|
|
14
|
-
```sh
|
|
15
|
-
pnpm i -g cloudflared
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
### NPM
|
|
19
|
-
|
|
20
|
-
```sh
|
|
21
|
-
npm i -g cloudflared
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
### Yarn
|
|
25
|
-
|
|
26
|
-
```sh
|
|
27
|
-
yarn global add cloudflared
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
> If `CLOUDFLARED_VERSION` env var is set, it will install the specified version of `cloudflared`, otherwise it will install the latest version.
|
|
31
|
-
|
|
32
|
-
## CLI Usage
|
|
33
|
-
|
|
34
|
-
You can use the `cloudflared` command-line tool to create HTTPS tunnels. You can find the usage of `cloudflared` [here](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/tunnel-useful-commands/).
|
|
35
|
-
|
|
36
|
-
In addition to the standard `cloudflared` commands, this package also provides an extra subcommand: `cloudflared bin`. You can use it to manage the `cloudflared` binary version.
|
|
37
|
-
|
|
38
|
-
```sh
|
|
39
|
-
❯ cloudflared bin --help
|
|
40
|
-
cloudflared bin : Prints the path to the binary
|
|
41
|
-
cloudflared bin remove : Removes the binary
|
|
42
|
-
cloudflared bin install [version] : Installs the binary
|
|
43
|
-
cloudflared bin list : Lists 30 latest releases
|
|
44
|
-
cloudflared bin help : Prints this help message
|
|
45
|
-
Examples:
|
|
46
|
-
cloudflared bin install : Installs the latest version of cloudflared
|
|
47
|
-
cloudflared bin install 2023.4.1 : Installs cloudflared 2023.4.1
|
|
48
|
-
You can find releases at https://github.com/cloudflare/cloudflared/releases
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## Library Usage
|
|
52
|
-
|
|
53
|
-
You can also use it as a library in your TypeScript / JavaScript projects.
|
|
54
|
-
|
|
55
|
-
### Binary Path & Install
|
|
56
|
-
|
|
57
|
-
You can get the path of the `cloudflared` binary and install it using the `bin` and `install` functions, respectively.
|
|
58
|
-
|
|
59
|
-
```js
|
|
60
|
-
import { bin, install } from "cloudflared";
|
|
61
|
-
import fs from "node:fs";
|
|
62
|
-
import { spawn } from "node:child_process";
|
|
63
|
-
|
|
64
|
-
if (!fs.existsSync(bin)) {
|
|
65
|
-
// install cloudflared binary
|
|
66
|
-
await install(bin);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// run cloudflared
|
|
70
|
-
spawn(bin, ["--version"], { stdio: "inherit" });
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
- `bin`: The path of the binary.
|
|
74
|
-
- `install`: A function that installs the binary to the given path.
|
|
75
|
-
|
|
76
|
-
### Tunnel
|
|
77
|
-
|
|
78
|
-
Checkout [`examples/tunnel.js`](examples/tunnel.js).
|
|
79
|
-
|
|
80
|
-
`Tunnel` is inherited from `EventEmitter`, so you can listen to the events it emits, checkout [`examples/events.mjs`](examples/events.mjs).
|
|
81
|
-
|
|
82
|
-
```js
|
|
83
|
-
import { Tunnel } from "cloudflared";
|
|
84
|
-
|
|
85
|
-
console.log("Cloudflared Tunnel Example.");
|
|
86
|
-
main();
|
|
87
|
-
|
|
88
|
-
async function main() {
|
|
89
|
-
// run: cloudflared tunnel --hello-world
|
|
90
|
-
const tunnel = Tunnel.quick();
|
|
91
|
-
|
|
92
|
-
// show the url
|
|
93
|
-
const url = new Promise((resolve) => tunnel.once("url", resolve));
|
|
94
|
-
console.log("LINK:", await url);
|
|
95
|
-
|
|
96
|
-
// wait for connection to be established
|
|
97
|
-
const conn = new Promise((resolve) => tunnel.once("connected", resolve));
|
|
98
|
-
console.log("CONN:", await conn);
|
|
99
|
-
|
|
100
|
-
// stop the tunnel after 15 seconds
|
|
101
|
-
setTimeout(tunnel.stop, 15_000);
|
|
102
|
-
|
|
103
|
-
tunnel.on("exit", (code) => {
|
|
104
|
-
console.log("tunnel process exited with code", code);
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
```sh
|
|
110
|
-
❯ node examples/tunnel.js
|
|
111
|
-
Cloudflared Tunnel Example.
|
|
112
|
-
LINK: https://mailto-davis-wilderness-facts.trycloudflare.com
|
|
113
|
-
CONN: {
|
|
114
|
-
id: 'df1b8330-44ea-4ecb-bb93-8a32400f6d1c',
|
|
115
|
-
ip: '198.41.200.193',
|
|
116
|
-
location: 'tpe01'
|
|
117
|
-
}
|
|
118
|
-
tunnel process exited with code 0
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
### Service
|
|
122
|
-
|
|
123
|
-
Checkout [`examples/service.js`](examples/service.js).
|
|
124
|
-
|
|
125
|
-
```js
|
|
126
|
-
import { service } from "cloudflared";
|
|
127
|
-
|
|
128
|
-
console.log("Cloudflared Service Example.");
|
|
129
|
-
main();
|
|
130
|
-
|
|
131
|
-
async function main() {
|
|
132
|
-
if (service.exists()) {
|
|
133
|
-
console.log("Service is running.");
|
|
134
|
-
const current = service.current();
|
|
135
|
-
for (const { service, hostname } of current.config.ingress) {
|
|
136
|
-
console.log(` - ${service} -> ${hostname}`);
|
|
137
|
-
}
|
|
138
|
-
console.log("metrics server:", current.metrics);
|
|
139
|
-
} else {
|
|
140
|
-
console.log("Service is not running.");
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
```sh
|
|
146
|
-
❯ node examples/service.js
|
|
147
|
-
Cloudflared Service Example.
|
|
148
|
-
Service is running.
|
|
149
|
-
- http://localhost:12345 -> sub.example.com
|
|
150
|
-
- http_status:404 -> undefined
|
|
151
|
-
metrics server: 127.0.0.1:49177/metrics
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
NOTICE: On linux, service can only be installed and uninstalled by root.
|
|
155
|
-
|
|
156
|
-
Run service test on linux: `sudo -E env "PATH=$PATH" pnpm test`
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
|
-
var import_error = require("./error.js");
|
|
4
|
-
var import_index = require("./index.js");
|
|
5
|
-
(0, import_index.main)().catch((err) => {
|
|
6
|
-
if (err instanceof import_error.UnsupportedError) {
|
|
7
|
-
console.error(err.message);
|
|
8
|
-
process.exit(1);
|
|
9
|
-
}
|
|
10
|
-
});
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __export = (target, all) => {
|
|
9
|
-
for (var name in all)
|
|
10
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
-
};
|
|
12
|
-
var __copyProps = (to, from, except, desc) => {
|
|
13
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
-
for (let key of __getOwnPropNames(from))
|
|
15
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
-
}
|
|
18
|
-
return to;
|
|
19
|
-
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
-
var constants_exports = {};
|
|
30
|
-
__export(constants_exports, {
|
|
31
|
-
CLOUDFLARED_VERSION: () => CLOUDFLARED_VERSION,
|
|
32
|
-
DEFAULT_CLOUDFLARED_BIN: () => DEFAULT_CLOUDFLARED_BIN,
|
|
33
|
-
RELEASE_BASE: () => RELEASE_BASE,
|
|
34
|
-
bin: () => bin,
|
|
35
|
-
use: () => use
|
|
36
|
-
});
|
|
37
|
-
module.exports = __toCommonJS(constants_exports);
|
|
38
|
-
var import_node_path = __toESM(require("node:path"));
|
|
39
|
-
const DEFAULT_CLOUDFLARED_BIN = import_node_path.default.join(
|
|
40
|
-
__dirname,
|
|
41
|
-
"..",
|
|
42
|
-
"bin",
|
|
43
|
-
process.platform === "win32" ? "cloudflared.exe" : "cloudflared"
|
|
44
|
-
);
|
|
45
|
-
let bin = process.env.CLOUDFLARED_BIN || DEFAULT_CLOUDFLARED_BIN;
|
|
46
|
-
function use(executable) {
|
|
47
|
-
bin = executable;
|
|
48
|
-
}
|
|
49
|
-
const CLOUDFLARED_VERSION = process.env.CLOUDFLARED_VERSION || "latest";
|
|
50
|
-
const RELEASE_BASE = "https://github.com/cloudflare/cloudflared/releases/";
|
|
51
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
52
|
-
0 && (module.exports = {
|
|
53
|
-
CLOUDFLARED_VERSION,
|
|
54
|
-
DEFAULT_CLOUDFLARED_BIN,
|
|
55
|
-
RELEASE_BASE,
|
|
56
|
-
bin,
|
|
57
|
-
use
|
|
58
|
-
});
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
var error_exports = {};
|
|
20
|
-
__export(error_exports, {
|
|
21
|
-
UnsupportedError: () => UnsupportedError
|
|
22
|
-
});
|
|
23
|
-
module.exports = __toCommonJS(error_exports);
|
|
24
|
-
class UnsupportedError extends Error {
|
|
25
|
-
constructor(message) {
|
|
26
|
-
super(message);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
30
|
-
0 && (module.exports = {
|
|
31
|
-
UnsupportedError
|
|
32
|
-
});
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
var handler_exports = {};
|
|
20
|
-
__export(handler_exports, {
|
|
21
|
-
ConfigHandler: () => ConfigHandler,
|
|
22
|
-
ConnectionHandler: () => ConnectionHandler,
|
|
23
|
-
TryCloudflareHandler: () => TryCloudflareHandler
|
|
24
|
-
});
|
|
25
|
-
module.exports = __toCommonJS(handler_exports);
|
|
26
|
-
var import_node_stream = require("node:stream");
|
|
27
|
-
var import_regex = require("./regex");
|
|
28
|
-
class ConnectionHandler {
|
|
29
|
-
constructor(tunnel) {
|
|
30
|
-
this.connections = [];
|
|
31
|
-
this.connected_handler = (output, tunnel) => {
|
|
32
|
-
const conn_match = output.match(import_regex.conn_regex);
|
|
33
|
-
const ip_match = output.match(import_regex.ip_regex);
|
|
34
|
-
const location_match = output.match(import_regex.location_regex);
|
|
35
|
-
const index_match = output.match(import_regex.index_regex);
|
|
36
|
-
if (conn_match && ip_match && location_match && index_match) {
|
|
37
|
-
const connection = {
|
|
38
|
-
id: conn_match[1],
|
|
39
|
-
ip: ip_match[1],
|
|
40
|
-
location: location_match[1]
|
|
41
|
-
};
|
|
42
|
-
this.connections[Number(index_match[1])] = connection;
|
|
43
|
-
tunnel.emit("connected", connection);
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
this.disconnected_handler = (output, tunnel) => {
|
|
47
|
-
const index_match = output.includes("terminated") ? output.match(import_regex.index_regex) : null;
|
|
48
|
-
if (index_match) {
|
|
49
|
-
const index = Number(index_match[1]);
|
|
50
|
-
if (this.connections[index]) {
|
|
51
|
-
tunnel.emit("disconnected", this.connections[index]);
|
|
52
|
-
this.connections[index] = void 0;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
tunnel.addHandler(this.connected_handler.bind(this));
|
|
57
|
-
tunnel.addHandler(this.disconnected_handler.bind(this));
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
class TryCloudflareHandler {
|
|
61
|
-
constructor(tunnel) {
|
|
62
|
-
this.url_handler = (output, tunnel) => {
|
|
63
|
-
const url_match = output.match(/https:\/\/([a-z0-9-]+)\.trycloudflare\.com/);
|
|
64
|
-
if (url_match) {
|
|
65
|
-
tunnel.emit("url", url_match[0]);
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
tunnel.addHandler(this.url_handler.bind(this));
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
class ConfigHandler extends import_node_stream.EventEmitter {
|
|
72
|
-
constructor(tunnel) {
|
|
73
|
-
super();
|
|
74
|
-
this.config_handler = (output, tunnel) => {
|
|
75
|
-
const config_match = output.match(/\bconfig="(.+?)" version=(\d+)/);
|
|
76
|
-
if (config_match) {
|
|
77
|
-
try {
|
|
78
|
-
const config_str = config_match[1].replace(/\\"/g, '"');
|
|
79
|
-
const config = JSON.parse(config_str);
|
|
80
|
-
const version = parseInt(config_match[2], 10);
|
|
81
|
-
this.emit("config", {
|
|
82
|
-
config,
|
|
83
|
-
version
|
|
84
|
-
});
|
|
85
|
-
if (config && typeof config === "object" && "ingress" in config && Array.isArray(config.ingress)) {
|
|
86
|
-
for (const ingress of config.ingress) {
|
|
87
|
-
if ("hostname" in ingress) {
|
|
88
|
-
tunnel.emit("url", ingress.hostname);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
} catch (error) {
|
|
93
|
-
this.emit("error", new Error(`Failed to parse config: ${error}`));
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
tunnel.addHandler(this.config_handler.bind(this));
|
|
98
|
-
}
|
|
99
|
-
on(event, listener) {
|
|
100
|
-
return super.on(event, listener);
|
|
101
|
-
}
|
|
102
|
-
once(event, listener) {
|
|
103
|
-
return super.once(event, listener);
|
|
104
|
-
}
|
|
105
|
-
off(event, listener) {
|
|
106
|
-
return super.off(event, listener);
|
|
107
|
-
}
|
|
108
|
-
emit(event, ...args) {
|
|
109
|
-
return super.emit(event, ...args);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
113
|
-
0 && (module.exports = {
|
|
114
|
-
ConfigHandler,
|
|
115
|
-
ConnectionHandler,
|
|
116
|
-
TryCloudflareHandler
|
|
117
|
-
});
|