peep-proxy 0.1.0
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/dist/app.d.ts +9 -0
- package/dist/app.js +162 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +98 -0
- package/dist/components/BorderedBox.d.ts +10 -0
- package/dist/components/BorderedBox.js +13 -0
- package/dist/components/DetailPanel.d.ts +13 -0
- package/dist/components/DetailPanel.js +8 -0
- package/dist/components/DetailView.d.ts +12 -0
- package/dist/components/DetailView.js +151 -0
- package/dist/components/DomainSidebar.d.ts +12 -0
- package/dist/components/DomainSidebar.js +36 -0
- package/dist/components/RequestList.d.ts +22 -0
- package/dist/components/RequestList.js +30 -0
- package/dist/components/RequestRow.d.ts +15 -0
- package/dist/components/RequestRow.js +84 -0
- package/dist/components/SortModal.d.ts +8 -0
- package/dist/components/SortModal.js +56 -0
- package/dist/components/SpinnerContext.d.ts +5 -0
- package/dist/components/SpinnerContext.js +20 -0
- package/dist/components/StatusBar.d.ts +11 -0
- package/dist/components/StatusBar.js +21 -0
- package/dist/hooks/useActivePanel.d.ts +11 -0
- package/dist/hooks/useActivePanel.js +36 -0
- package/dist/hooks/useDetailScroll.d.ts +11 -0
- package/dist/hooks/useDetailScroll.js +59 -0
- package/dist/hooks/useDetailTabs.d.ts +14 -0
- package/dist/hooks/useDetailTabs.js +50 -0
- package/dist/hooks/useDomainFilter.d.ts +30 -0
- package/dist/hooks/useDomainFilter.js +103 -0
- package/dist/hooks/useListNavigation.d.ts +12 -0
- package/dist/hooks/useListNavigation.js +105 -0
- package/dist/hooks/useSorting.d.ts +20 -0
- package/dist/hooks/useSorting.js +71 -0
- package/dist/hooks/useTerminalDimensions.d.ts +6 -0
- package/dist/hooks/useTerminalDimensions.js +25 -0
- package/dist/hooks/useTrafficEntries.d.ts +2 -0
- package/dist/hooks/useTrafficEntries.js +16 -0
- package/dist/proxy/ca.d.ts +4 -0
- package/dist/proxy/ca.js +72 -0
- package/dist/proxy/cert-trust.d.ts +20 -0
- package/dist/proxy/cert-trust.js +181 -0
- package/dist/proxy/index.d.ts +3 -0
- package/dist/proxy/index.js +2 -0
- package/dist/proxy/proxy-server.d.ts +9 -0
- package/dist/proxy/proxy-server.js +262 -0
- package/dist/proxy/system-proxy.d.ts +2 -0
- package/dist/proxy/system-proxy.js +64 -0
- package/dist/proxy/types.d.ts +45 -0
- package/dist/proxy/types.js +1 -0
- package/dist/store/index.d.ts +2 -0
- package/dist/store/index.js +1 -0
- package/dist/store/traffic-store.d.ts +14 -0
- package/dist/store/traffic-store.js +87 -0
- package/dist/store/types.d.ts +14 -0
- package/dist/store/types.js +1 -0
- package/dist/theme.d.ts +1 -0
- package/dist/theme.js +1 -0
- package/dist/utils/contentType.d.ts +7 -0
- package/dist/utils/contentType.js +46 -0
- package/dist/utils/copyToClipboard.d.ts +1 -0
- package/dist/utils/copyToClipboard.js +21 -0
- package/dist/utils/decompress.d.ts +2 -0
- package/dist/utils/decompress.js +25 -0
- package/dist/utils/formatBytes.d.ts +1 -0
- package/dist/utils/formatBytes.js +14 -0
- package/dist/utils/getTabText.d.ts +3 -0
- package/dist/utils/getTabText.js +96 -0
- package/dist/utils/highlightBody.d.ts +3 -0
- package/dist/utils/highlightBody.js +43 -0
- package/package.json +57 -0
- package/readme.md +73 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { useInput } from "ink";
|
|
2
|
+
import { useCallback, useMemo, useState } from "react";
|
|
3
|
+
function getResponseSize(entry) {
|
|
4
|
+
if (entry.state === "pending" || !entry.response)
|
|
5
|
+
return null;
|
|
6
|
+
return entry.response.body.length;
|
|
7
|
+
}
|
|
8
|
+
function compareEntries(a, b, column) {
|
|
9
|
+
switch (column) {
|
|
10
|
+
case "id":
|
|
11
|
+
return a.seq - b.seq;
|
|
12
|
+
case "method":
|
|
13
|
+
return a.request.method.localeCompare(b.request.method);
|
|
14
|
+
case "url":
|
|
15
|
+
return a.request.path.localeCompare(b.request.path);
|
|
16
|
+
case "status": {
|
|
17
|
+
const aCode = a.response?.statusCode ?? Number.MAX_SAFE_INTEGER;
|
|
18
|
+
const bCode = b.response?.statusCode ?? Number.MAX_SAFE_INTEGER;
|
|
19
|
+
return aCode - bCode;
|
|
20
|
+
}
|
|
21
|
+
case "duration": {
|
|
22
|
+
const aDur = a.response?.duration ?? Number.MAX_SAFE_INTEGER;
|
|
23
|
+
const bDur = b.response?.duration ?? Number.MAX_SAFE_INTEGER;
|
|
24
|
+
return aDur - bDur;
|
|
25
|
+
}
|
|
26
|
+
case "size": {
|
|
27
|
+
const aSize = getResponseSize(a) ?? Number.MAX_SAFE_INTEGER;
|
|
28
|
+
const bSize = getResponseSize(b) ?? Number.MAX_SAFE_INTEGER;
|
|
29
|
+
return aSize - bSize;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export function useSorting({ entries, isActive = true }) {
|
|
34
|
+
const [sortConfig, setSortConfig] = useState(null);
|
|
35
|
+
const [modalOpen, setModalOpen] = useState(false);
|
|
36
|
+
const selectColumn = useCallback((column) => {
|
|
37
|
+
setSortConfig((prev) => {
|
|
38
|
+
if (prev?.column === column) {
|
|
39
|
+
return {
|
|
40
|
+
column,
|
|
41
|
+
direction: prev.direction === "asc" ? "desc" : "asc",
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return { column, direction: "asc" };
|
|
45
|
+
});
|
|
46
|
+
setModalOpen(false);
|
|
47
|
+
}, []);
|
|
48
|
+
const closeModal = useCallback(() => {
|
|
49
|
+
setModalOpen(false);
|
|
50
|
+
}, []);
|
|
51
|
+
useInput((input) => {
|
|
52
|
+
if (modalOpen)
|
|
53
|
+
return;
|
|
54
|
+
if (input === "s") {
|
|
55
|
+
setModalOpen(true);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (input === "S") {
|
|
59
|
+
setSortConfig(null);
|
|
60
|
+
}
|
|
61
|
+
}, { isActive });
|
|
62
|
+
const sortedEntries = useMemo(() => {
|
|
63
|
+
const config = sortConfig ?? {
|
|
64
|
+
column: "id",
|
|
65
|
+
direction: "desc",
|
|
66
|
+
};
|
|
67
|
+
const multiplier = config.direction === "asc" ? 1 : -1;
|
|
68
|
+
return [...entries].sort((a, b) => multiplier * compareEntries(a, b, config.column));
|
|
69
|
+
}, [entries, sortConfig]);
|
|
70
|
+
return { sortedEntries, sortConfig, modalOpen, selectColumn, closeModal };
|
|
71
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useStdout } from "ink";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
const FALLBACK = { columns: 80, rows: 24 };
|
|
4
|
+
export function useTerminalDimensions() {
|
|
5
|
+
const { stdout } = useStdout();
|
|
6
|
+
const [dimensions, setDimensions] = useState(() => ({
|
|
7
|
+
columns: stdout?.columns ?? FALLBACK.columns,
|
|
8
|
+
rows: stdout?.rows ?? FALLBACK.rows,
|
|
9
|
+
}));
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (!stdout)
|
|
12
|
+
return;
|
|
13
|
+
const onResize = () => {
|
|
14
|
+
setDimensions({
|
|
15
|
+
columns: stdout.columns,
|
|
16
|
+
rows: stdout.rows,
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
stdout.on("resize", onResize);
|
|
20
|
+
return () => {
|
|
21
|
+
stdout.off("resize", onResize);
|
|
22
|
+
};
|
|
23
|
+
}, [stdout]);
|
|
24
|
+
return dimensions;
|
|
25
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
export function useTrafficEntries(store) {
|
|
3
|
+
const [entries, setEntries] = useState(() => store.entries);
|
|
4
|
+
useEffect(() => {
|
|
5
|
+
const refresh = () => setEntries(store.entries);
|
|
6
|
+
store.on("add", refresh);
|
|
7
|
+
store.on("update", refresh);
|
|
8
|
+
store.on("clear", refresh);
|
|
9
|
+
return () => {
|
|
10
|
+
store.off("add", refresh);
|
|
11
|
+
store.off("update", refresh);
|
|
12
|
+
store.off("clear", refresh);
|
|
13
|
+
};
|
|
14
|
+
}, [store]);
|
|
15
|
+
return entries;
|
|
16
|
+
}
|
package/dist/proxy/ca.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import forge from "node-forge";
|
|
4
|
+
export function generateCA() {
|
|
5
|
+
const keys = forge.pki.rsa.generateKeyPair(2048);
|
|
6
|
+
const cert = forge.pki.createCertificate();
|
|
7
|
+
cert.publicKey = keys.publicKey;
|
|
8
|
+
cert.serialNumber = "01";
|
|
9
|
+
cert.validity.notBefore = new Date();
|
|
10
|
+
cert.validity.notAfter = new Date();
|
|
11
|
+
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 10);
|
|
12
|
+
const attrs = [{ name: "commonName", value: "Peep Proxy CA" }];
|
|
13
|
+
cert.setSubject(attrs);
|
|
14
|
+
cert.setIssuer(attrs);
|
|
15
|
+
cert.setExtensions([
|
|
16
|
+
{ name: "basicConstraints", cA: true },
|
|
17
|
+
{
|
|
18
|
+
name: "keyUsage",
|
|
19
|
+
keyCertSign: true,
|
|
20
|
+
cRLSign: true,
|
|
21
|
+
},
|
|
22
|
+
]);
|
|
23
|
+
cert.sign(keys.privateKey, forge.md.sha256.create());
|
|
24
|
+
return {
|
|
25
|
+
certPem: forge.pki.certificateToPem(cert),
|
|
26
|
+
keyPem: forge.pki.privateKeyToPem(keys.privateKey),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export async function loadOrCreateCA(dir) {
|
|
30
|
+
const certPath = path.join(dir, "ca-cert.pem");
|
|
31
|
+
const keyPath = path.join(dir, "ca-key.pem");
|
|
32
|
+
try {
|
|
33
|
+
const [certPem, keyPem] = await Promise.all([
|
|
34
|
+
fs.readFile(certPath, "utf-8"),
|
|
35
|
+
fs.readFile(keyPath, "utf-8"),
|
|
36
|
+
]);
|
|
37
|
+
return { certPem, keyPem };
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
await fs.mkdir(dir, { recursive: true });
|
|
41
|
+
const ca = generateCA();
|
|
42
|
+
await Promise.all([
|
|
43
|
+
fs.writeFile(certPath, ca.certPem),
|
|
44
|
+
fs.writeFile(keyPath, ca.keyPem),
|
|
45
|
+
]);
|
|
46
|
+
return ca;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
export function generateHostCert(host, ca) {
|
|
50
|
+
const caCert = forge.pki.certificateFromPem(ca.certPem);
|
|
51
|
+
const caKey = forge.pki.privateKeyFromPem(ca.keyPem);
|
|
52
|
+
const keys = forge.pki.rsa.generateKeyPair(2048);
|
|
53
|
+
const cert = forge.pki.createCertificate();
|
|
54
|
+
cert.publicKey = keys.publicKey;
|
|
55
|
+
cert.serialNumber = forge.util.bytesToHex(forge.random.getBytesSync(16));
|
|
56
|
+
cert.validity.notBefore = new Date();
|
|
57
|
+
cert.validity.notAfter = new Date();
|
|
58
|
+
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1);
|
|
59
|
+
cert.setSubject([{ name: "commonName", value: host }]);
|
|
60
|
+
cert.setIssuer(caCert.subject.attributes);
|
|
61
|
+
cert.setExtensions([
|
|
62
|
+
{
|
|
63
|
+
name: "subjectAltName",
|
|
64
|
+
altNames: [{ type: 2, value: host }],
|
|
65
|
+
},
|
|
66
|
+
]);
|
|
67
|
+
cert.sign(caKey, forge.md.sha256.create());
|
|
68
|
+
return {
|
|
69
|
+
certPem: forge.pki.certificateToPem(cert),
|
|
70
|
+
keyPem: forge.pki.privateKeyToPem(keys.privateKey),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare function isCaTrusted(certPemPath: string): boolean;
|
|
2
|
+
export declare function trustCa(certPemPath: string): boolean;
|
|
3
|
+
export declare function findNssProfiles(): string[];
|
|
4
|
+
export declare function isNssTrusted(): boolean;
|
|
5
|
+
export type NssTrustResult = {
|
|
6
|
+
status: "no-profiles";
|
|
7
|
+
} | {
|
|
8
|
+
status: "ok";
|
|
9
|
+
count: number;
|
|
10
|
+
} | {
|
|
11
|
+
status: "no-certutil";
|
|
12
|
+
hasBrew: boolean;
|
|
13
|
+
} | {
|
|
14
|
+
status: "install-failed";
|
|
15
|
+
} | {
|
|
16
|
+
status: "partial";
|
|
17
|
+
trusted: number;
|
|
18
|
+
total: number;
|
|
19
|
+
};
|
|
20
|
+
export declare function trustNssStores(certPemPath: string): NssTrustResult;
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { execFileSync, spawnSync } from "node:child_process";
|
|
2
|
+
import { existsSync, readdirSync } from "node:fs";
|
|
3
|
+
import { homedir, platform } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
export function isCaTrusted(certPemPath) {
|
|
6
|
+
if (platform() === "darwin") {
|
|
7
|
+
try {
|
|
8
|
+
execFileSync("security", ["verify-cert", "-c", certPemPath, "-l", "-L", "-q"], { stdio: "pipe" });
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
if (platform() === "linux") {
|
|
16
|
+
return [
|
|
17
|
+
"/etc/pki/ca-trust/source/anchors/peep.pem",
|
|
18
|
+
"/usr/local/share/ca-certificates/peep.crt",
|
|
19
|
+
"/etc/ca-certificates/trust-source/anchors/peep.crt",
|
|
20
|
+
"/usr/share/pki/trust/anchors/peep.pem",
|
|
21
|
+
].some((p) => existsSync(p));
|
|
22
|
+
}
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
export function trustCa(certPemPath) {
|
|
26
|
+
if (platform() === "darwin") {
|
|
27
|
+
const result = spawnSync("sudo", [
|
|
28
|
+
"--prompt=Password: ",
|
|
29
|
+
"--",
|
|
30
|
+
"security",
|
|
31
|
+
"add-trusted-cert",
|
|
32
|
+
"-d",
|
|
33
|
+
"-r",
|
|
34
|
+
"trustRoot",
|
|
35
|
+
"-k",
|
|
36
|
+
"/Library/Keychains/System.keychain",
|
|
37
|
+
certPemPath,
|
|
38
|
+
], { stdio: "inherit" });
|
|
39
|
+
return result.status === 0;
|
|
40
|
+
}
|
|
41
|
+
if (platform() === "linux") {
|
|
42
|
+
let trustFile;
|
|
43
|
+
let updateCmd;
|
|
44
|
+
if (existsSync("/etc/pki/ca-trust/source/anchors/")) {
|
|
45
|
+
trustFile = "/etc/pki/ca-trust/source/anchors/peep.pem";
|
|
46
|
+
updateCmd = ["update-ca-trust", "extract"];
|
|
47
|
+
}
|
|
48
|
+
else if (existsSync("/usr/local/share/ca-certificates/")) {
|
|
49
|
+
trustFile = "/usr/local/share/ca-certificates/peep.crt";
|
|
50
|
+
updateCmd = ["update-ca-certificates"];
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
const cp = spawnSync("sudo", ["--prompt=Password: ", "--", "cp", certPemPath, trustFile], { stdio: "inherit" });
|
|
56
|
+
if (cp.status !== 0)
|
|
57
|
+
return false;
|
|
58
|
+
const update = spawnSync("sudo", ["--prompt=Password: ", "--", ...updateCmd], { stdio: "inherit" });
|
|
59
|
+
return update.status === 0;
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
function findCertutil() {
|
|
64
|
+
try {
|
|
65
|
+
return execFileSync("which", ["certutil"], { stdio: "pipe" })
|
|
66
|
+
.toString()
|
|
67
|
+
.trim();
|
|
68
|
+
}
|
|
69
|
+
catch { }
|
|
70
|
+
if (platform() === "darwin") {
|
|
71
|
+
const cellarBin = "/opt/homebrew/opt/nss/bin/certutil";
|
|
72
|
+
if (existsSync(cellarBin))
|
|
73
|
+
return cellarBin;
|
|
74
|
+
const intelBin = "/usr/local/opt/nss/bin/certutil";
|
|
75
|
+
if (existsSync(intelBin))
|
|
76
|
+
return intelBin;
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
function hasHomebrew() {
|
|
81
|
+
try {
|
|
82
|
+
execFileSync("which", ["brew"], { stdio: "pipe" });
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function installNssViaHomebrew() {
|
|
90
|
+
if (platform() !== "darwin" || !hasHomebrew())
|
|
91
|
+
return false;
|
|
92
|
+
process.stderr.write("Installing nss (needed for Firefox/Zen certificate trust)...\n");
|
|
93
|
+
const result = spawnSync("brew", ["install", "nss"], {
|
|
94
|
+
stdio: "inherit",
|
|
95
|
+
env: { ...process.env, HOMEBREW_NO_AUTO_UPDATE: "1" },
|
|
96
|
+
});
|
|
97
|
+
return result.status === 0;
|
|
98
|
+
}
|
|
99
|
+
export function findNssProfiles() {
|
|
100
|
+
const profiles = [];
|
|
101
|
+
const home = homedir();
|
|
102
|
+
const browserDirs = platform() === "darwin"
|
|
103
|
+
? [
|
|
104
|
+
join(home, "Library/Application Support/Firefox/Profiles"),
|
|
105
|
+
join(home, "Library/Application Support/zen/Profiles"),
|
|
106
|
+
]
|
|
107
|
+
: [join(home, ".mozilla/firefox"), join(home, ".zen")];
|
|
108
|
+
for (const dir of browserDirs) {
|
|
109
|
+
if (!existsSync(dir))
|
|
110
|
+
continue;
|
|
111
|
+
try {
|
|
112
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
113
|
+
if (!entry.isDirectory())
|
|
114
|
+
continue;
|
|
115
|
+
const certDb = join(dir, entry.name, "cert9.db");
|
|
116
|
+
if (existsSync(certDb)) {
|
|
117
|
+
profiles.push(join(dir, entry.name));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
catch { }
|
|
122
|
+
}
|
|
123
|
+
return profiles;
|
|
124
|
+
}
|
|
125
|
+
export function isNssTrusted() {
|
|
126
|
+
const profiles = findNssProfiles();
|
|
127
|
+
if (profiles.length === 0)
|
|
128
|
+
return true;
|
|
129
|
+
const certutil = findCertutil();
|
|
130
|
+
if (!certutil)
|
|
131
|
+
return false;
|
|
132
|
+
return profiles.every((profile) => {
|
|
133
|
+
try {
|
|
134
|
+
execFileSync(certutil, ["-L", "-d", `sql:${profile}`, "-n", "Peep Proxy CA"], { stdio: "pipe" });
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
export function trustNssStores(certPemPath) {
|
|
143
|
+
const profiles = findNssProfiles();
|
|
144
|
+
if (profiles.length === 0)
|
|
145
|
+
return { status: "no-profiles" };
|
|
146
|
+
let certutil = findCertutil();
|
|
147
|
+
if (!certutil) {
|
|
148
|
+
if (!hasHomebrew()) {
|
|
149
|
+
return { status: "no-certutil", hasBrew: false };
|
|
150
|
+
}
|
|
151
|
+
if (!installNssViaHomebrew()) {
|
|
152
|
+
return { status: "install-failed" };
|
|
153
|
+
}
|
|
154
|
+
certutil = findCertutil();
|
|
155
|
+
if (!certutil) {
|
|
156
|
+
return { status: "install-failed" };
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
let trusted = 0;
|
|
160
|
+
for (const profile of profiles) {
|
|
161
|
+
try {
|
|
162
|
+
execFileSync(certutil, [
|
|
163
|
+
"-A",
|
|
164
|
+
"-d",
|
|
165
|
+
`sql:${profile}`,
|
|
166
|
+
"-t",
|
|
167
|
+
"CT,,",
|
|
168
|
+
"-n",
|
|
169
|
+
"Peep Proxy CA",
|
|
170
|
+
"-i",
|
|
171
|
+
certPemPath,
|
|
172
|
+
], { stdio: "pipe" });
|
|
173
|
+
trusted++;
|
|
174
|
+
}
|
|
175
|
+
catch { }
|
|
176
|
+
}
|
|
177
|
+
if (trusted === profiles.length) {
|
|
178
|
+
return { status: "ok", count: trusted };
|
|
179
|
+
}
|
|
180
|
+
return { status: "partial", trusted, total: profiles.length };
|
|
181
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ProxyConfig, ProxyEventMap } from "./types.js";
|
|
2
|
+
export declare class ProxyServer {
|
|
3
|
+
#private;
|
|
4
|
+
constructor(config: ProxyConfig);
|
|
5
|
+
start(): Promise<void>;
|
|
6
|
+
stop(): Promise<void>;
|
|
7
|
+
on<K extends keyof ProxyEventMap>(event: K, listener: (...args: ProxyEventMap[K]) => void): void;
|
|
8
|
+
off<K extends keyof ProxyEventMap>(event: K, listener: (...args: ProxyEventMap[K]) => void): void;
|
|
9
|
+
}
|