@jebcode-dev/jebcode-tunnel 1.0.0 → 1.0.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/LICENSE CHANGED
@@ -1,9 +1,9 @@
1
- Licença MIT
2
-
3
- Copyright (c) 2026 JEBCODE SOFTWARE E TECNOLOGIA LTDA
4
-
5
- A permissão é concedida, gratuitamente, a qualquer pessoa que obtenha uma cópia deste software e dos arquivos de documentação associados (o "Software"), para lidar com o Software sem restrições, incluindo, sem limitação, os direitos de usar, copiar, modificar, mesclar, publicar, distribuir, sublicenciar e/ou vender cópias do Software, e permitir que as pessoas a quem o Software é fornecido o façam, sujeito às seguintes condições:
6
-
7
- O aviso de copyright acima e este aviso de permissão devem ser incluídos em todas as cópias ou partes substanciais do Software.
8
-
9
- O SOFTWARE É FORNECIDO "COMO ESTÁ", SEM GARANTIA DE QUALQUER TIPO, EXPRESSA OU IMPLÍCITA, INCLUINDO, MAS NÃO SE LIMITANDO ÀS GARANTIAS DE COMERCIALIZAÇÃO, ADEQUAÇÃO A UM DETERMINADO FIM E NÃO VIOLAÇÃO. EM NENHUM CASO OS AUTORES OU DETENTORES DE DIREITOS DE AUTOR SERÃO RESPONSÁVEIS POR QUALQUER RECLAMAÇÃO, DANOS OU OUTRA RESPONSABILIDADE, SEJA EM UMA AÇÃO DE CONTRATO, ILÍCITO OU DE OUTRA FORMA, DECORRENTE DE, FORA DE OU EM CONEXÃO COM O SOFTWARE OU O USO OU OUTRAS NEGOCIAÇÕES NO SOFTWARE.
1
+ Licença MIT
2
+
3
+ Copyright (c) 2026 JEBCODE SOFTWARE E TECNOLOGIA LTDA
4
+
5
+ A permissão é concedida, gratuitamente, a qualquer pessoa que obtenha uma cópia deste software e dos arquivos de documentação associados (o "Software"), para lidar com o Software sem restrições, incluindo, sem limitação, os direitos de usar, copiar, modificar, mesclar, publicar, distribuir, sublicenciar e/ou vender cópias do Software, e permitir que as pessoas a quem o Software é fornecido o façam, sujeito às seguintes condições:
6
+
7
+ O aviso de copyright acima e este aviso de permissão devem ser incluídos em todas as cópias ou partes substanciais do Software.
8
+
9
+ O SOFTWARE É FORNECIDO "COMO ESTÁ", SEM GARANTIA DE QUALQUER TIPO, EXPRESSA OU IMPLÍCITA, INCLUINDO, MAS NÃO SE LIMITANDO ÀS GARANTIAS DE COMERCIALIZAÇÃO, ADEQUAÇÃO A UM DETERMINADO FIM E NÃO VIOLAÇÃO. EM NENHUM CASO OS AUTORES OU DETENTORES DE DIREITOS DE AUTOR SERÃO RESPONSÁVEIS POR QUALQUER RECLAMAÇÃO, DANOS OU OUTRA RESPONSABILIDADE, SEJA EM UMA AÇÃO DE CONTRATO, ILÍCITO OU DE OUTRA FORMA, DECORRENTE DE, FORA DE OU EM CONEXÃO COM O SOFTWARE OU O USO OU OUTRAS NEGOCIAÇÕES NO SOFTWARE.
package/README.md CHANGED
@@ -1,71 +1,71 @@
1
- ```text
2
- ██╗███████╗██████╗ ██████╗ ██████╗ ██████╗ ███████╗
3
- ██║██╔════╝██╔══██╗██╔════╝ ██╔═══██╗██╔══██╗██╔════╝
4
- ██║█████╗ ██████╔╝██║ ██║ ██║██║ ██║█████╗
5
- ██╗ ██║██╔══╝ ██╔══██╗██║ ██║ ██║██║ ██║██╔══╝
6
- ╚██████╔╝███████╗██████╔╝╚██████╗ ╚██████╔╝██████╔╝███████╗ ®
7
- ╚═════╝ ╚══════╝╚═════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝
8
- Infraestrutura de Tunelamento de Alta Performance
9
- ```
10
-
11
- # 🚀 JebCode Tunnel CLI
12
-
13
- Interface de linha de comando oficial da **JebCode Software e Tecnologia LTDA** para expor seus serviços locais ao mundo.
14
-
15
- ## 💾 Instalação
16
-
17
- Para utilizar o CLI em qualquer lugar do seu sistema:
18
- ```bash
19
- npm install -g "@jebcode-dev/jebcode-tunnel"
20
- ```
21
-
22
- ## 🛠️ Comandos Principais
23
-
24
- ### 1. Login
25
- Autenticação interativa com e-mail e senha.
26
- ```bash
27
- jebcode-tunnel login
28
- ```
29
-
30
- ### 2. Authtoken (Manual)
31
- Configura seu token manualmente se preferir.
32
- ```bash
33
- jebcode-tunnel authtoken <seu_token>
34
- ```
35
-
36
- ### 3. Inicializar Túnel
37
- Inicia o encaminhamento de tráfego para uma porta local.
38
- ```bash
39
- jebcode-tunnel http 3000
40
- ```
41
- *Dica: Use `--subdomain projeto-x` para usar um subdomínio específico.*
42
-
43
- ### 4. Verificar Status
44
- Visualize sua versão, estado de autenticação e servidor.
45
- ```bash
46
- jebcode-tunnel status
47
- ```
48
-
49
- ### 5. Logout
50
- Remove as credenciais e encerra a sessão local.
51
- ```bash
52
- jebcode-tunnel logout
53
- ```
54
-
55
- ---
56
-
57
- ## 📦 Desenvolvimento
58
-
59
- Para instalar as dependências:
60
- ```bash
61
- npm install
62
- ```
63
-
64
- Para vincular o comando globalmente durante o desenvolvimento:
65
- ```bash
66
- npm link
67
- ```
68
-
69
- ---
70
- © 2026 JEBCODE SOFTWARE E TECNOLOGIA LTDA.
71
- **JebCode Infrastructure v1.0.1**
1
+ ```text
2
+ ██╗███████╗██████╗ ██████╗ ██████╗ ██████╗ ███████╗
3
+ ██║██╔════╝██╔══██╗██╔════╝ ██╔═══██╗██╔══██╗██╔════╝
4
+ ██║█████╗ ██████╔╝██║ ██║ ██║██║ ██║█████╗
5
+ ██╗ ██║██╔══╝ ██╔══██╗██║ ██║ ██║██║ ██║██╔══╝
6
+ ╚██████╔╝███████╗██████╔╝╚██████╗ ╚██████╔╝██████╔╝███████╗ ®
7
+ ╚═════╝ ╚══════╝╚═════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝
8
+ Infraestrutura de Tunelamento de Alta Performance
9
+ ```
10
+
11
+ # 🚀 JebCode Tunnel CLI
12
+
13
+ Interface de linha de comando oficial da **JebCode Software e Tecnologia LTDA** para expor seus serviços locais ao mundo.
14
+
15
+ ## 💾 Instalação
16
+
17
+ Para utilizar o CLI em qualquer lugar do seu sistema:
18
+ ```bash
19
+ npm install -g "@jebcode-dev/jebcode-tunnel"
20
+ ```
21
+
22
+ ## 🛠️ Comandos Principais
23
+
24
+ ### 1. Login
25
+ Autenticação interativa com e-mail e senha.
26
+ ```bash
27
+ jebcode-tunnel login
28
+ ```
29
+
30
+ ### 2. Authtoken (Manual)
31
+ Configura seu token manualmente se preferir.
32
+ ```bash
33
+ jebcode-tunnel authtoken <seu_token>
34
+ ```
35
+
36
+ ### 3. Inicializar Túnel
37
+ Inicia o encaminhamento de tráfego para uma porta local.
38
+ ```bash
39
+ jebcode-tunnel http 3000
40
+ ```
41
+ *Dica: Use `--subdomain projeto-x` para usar um subdomínio específico.*
42
+
43
+ ### 4. Verificar Status
44
+ Visualize sua versão, estado de autenticação e servidor.
45
+ ```bash
46
+ jebcode-tunnel status
47
+ ```
48
+
49
+ ### 5. Logout
50
+ Remove as credenciais e encerra a sessão local.
51
+ ```bash
52
+ jebcode-tunnel logout
53
+ ```
54
+
55
+ ---
56
+
57
+ ## 📦 Desenvolvimento
58
+
59
+ Para instalar as dependências:
60
+ ```bash
61
+ npm install
62
+ ```
63
+
64
+ Para vincular o comando globalmente durante o desenvolvimento:
65
+ ```bash
66
+ npm link
67
+ ```
68
+
69
+ ---
70
+ © 2026 JEBCODE SOFTWARE E TECNOLOGIA LTDA.
71
+ **JebCode Infrastructure v1.0.4**
package/bin.js CHANGED
@@ -1,48 +1,48 @@
1
1
  #!/usr/bin/env node
2
-
3
- const { program } = require("commander");
4
- const { version } = require("./package.json");
5
- const { authtoken, startTunnel, showStatus, login, logout } = require("./index");
6
-
7
- program
8
- .name("jebcode-tunnel")
9
- .description("CLI para expor seu serviço local ao mundo via JebCode Tunnel")
10
- .version(version);
11
-
12
- program
13
- .command("login")
14
- .description("Realiza login com e-mail e senha")
15
- .action(login);
16
-
17
- program
18
- .command("logout")
19
- .description("Remove as credenciais locais")
20
- .action(logout);
21
-
22
- program
23
- .command("authtoken")
24
- .description("Salva sua API Key do JebCode Tunnel localmente")
25
- .argument("<token>", "Sua API Key encontrada no Dashboard")
26
- .action(authtoken);
27
-
28
- program
29
- .command("status")
30
- .description("Exibe o status atual da configuração e autenticação")
31
- .action(showStatus);
32
-
33
- program
34
- .command("http")
35
- .description("Inicia um túnel HTTP para uma porta local")
36
- .argument("<port>", "Porta local (ex: 3000)")
37
- .option("-s, --subdomain <name>", "Subdomínio customizado já criado no Dashboard")
38
- .option("-i, --insecure", "Ignorar verificação de certificado SSL (útil para testes locais)", false)
39
- .action((port, options) => {
40
- startTunnel(port, options);
41
- });
42
-
43
- // Handle global help if no command is provided
44
- if (!process.argv.slice(2).length) {
45
- program.outputHelp();
46
- }
47
-
48
- program.parse();
2
+
3
+ const { program } = require("commander");
4
+ const { version } = require("./package.json");
5
+ const { authtoken, startTunnel, showStatus, login, logout } = require("./index");
6
+
7
+ program
8
+ .name("jebcode-tunnel")
9
+ .description("CLI para expor seu serviço local ao mundo via JebCode Tunnel")
10
+ .version(version);
11
+
12
+ program
13
+ .command("login")
14
+ .description("Realiza login com e-mail e senha")
15
+ .action(login);
16
+
17
+ program
18
+ .command("logout")
19
+ .description("Remove as credenciais locais")
20
+ .action(logout);
21
+
22
+ program
23
+ .command("authtoken")
24
+ .description("Salva sua API Key do JebCode Tunnel localmente")
25
+ .argument("<token>", "Sua API Key encontrada no Dashboard")
26
+ .action(authtoken);
27
+
28
+ program
29
+ .command("status")
30
+ .description("Exibe o status atual da configuração e autenticação")
31
+ .action(showStatus);
32
+
33
+ program
34
+ .command("http")
35
+ .description("Inicia um túnel HTTP para uma porta local")
36
+ .argument("<port>", "Porta local (ex: 3000)")
37
+ .option("-s, --subdomain <name>", "Subdomínio customizado já criado no Dashboard")
38
+ .option("-i, --insecure", "Ignorar verificação de certificado SSL (útil para testes locais)", false)
39
+ .action((port, options) => {
40
+ startTunnel(port, options);
41
+ });
42
+
43
+ // Handle global help if no command is provided
44
+ if (!process.argv.slice(2).length) {
45
+ program.outputHelp();
46
+ }
47
+
48
+ program.parse();
package/index.js CHANGED
@@ -1,249 +1,237 @@
1
- const fs = require("fs");
2
- const path = require("path");
3
- const os = require("os");
4
- const io = require("socket.io-client");
5
- const axios = require("axios");
6
- const chalk = require("chalk");
7
- const inquirer = require("inquirer");
8
- const { version } = require("./package.json");
9
-
10
- const CONFIG_PATH = path.join(os.homedir(), ".jebcode-tunnel");
11
- const SERVER_URL = process.env.JEB_SERVER_URL || "https://jebcodetunnel.com";
12
-
13
- function getHeader() {
14
- return chalk.bold.blue(`
15
- ██╗███████╗██████╗ ██████╗ ██████╗ ██████╗ ███████╗
16
- ██║██╔════╝██╔══██╗██╔════╝ ██╔═══██╗██╔══██╗██╔════╝
17
- ██║█████╗ ██████╔╝██║ ██║ ██║██║ ██║█████╗
18
- ██╗ ██║██╔══╝ ██╔══██╗██║ ██║ ██║██║ ██║██╔══╝
19
- ╚██████╔╝███████╗██████╔╝╚██████╗ ╚██████╔╝██████╔╝███████╗ ®
20
- ╚═════╝ ╚══════╝╚═════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝
21
- ${chalk.italic("Infraestrutura de Tunelamento de Alta Performance")}
22
- `);
23
- }
24
-
25
- async function login() {
26
- console.log(getHeader());
27
- console.log(chalk.white(" ENTRAR NA SUA CONTA JEBCODE:\n"));
28
-
29
- const answers = await inquirer.prompt([
30
- {
31
- type: "input",
32
- name: "email",
33
- message: "E-mail:",
34
- validate: (input) => input.includes("@") || "Por favor, insira um e-mail válido."
35
- },
36
- {
37
- type: "password",
38
- name: "password",
39
- message: "Senha:",
40
- mask: "*"
41
- }
42
- ]);
43
-
44
- process.stdout.write(chalk.blue("\n ☁ Autenticando... "));
45
-
46
- try {
47
- const response = await axios.post(`${SERVER_URL}/api/cli/login`, {
48
- email: answers.email,
49
- password: answers.password
50
- });
51
-
52
- const { api_key } = response.data;
53
- process.stdout.write(chalk.green("OK\n"));
54
-
55
- fs.writeFileSync(CONFIG_PATH, JSON.stringify({ token: api_key }));
56
- console.log(chalk.green("\n ✔ Login realizado com sucesso!"));
57
- console.log(chalk.gray(` Token salvo e pronto para uso.\n`));
58
- } catch (err) {
59
- process.stdout.write(chalk.red("FALHOU\n"));
60
- const errorMsg = err.response?.data?.error || err.message;
61
- console.error(chalk.red(" ✖ Erro:"), errorMsg);
62
- }
63
- }
64
-
65
- function logout() {
66
- if (fs.existsSync(CONFIG_PATH)) {
67
- fs.unlinkSync(CONFIG_PATH);
68
- console.log(getHeader());
69
- console.log(chalk.green("\n ✔ Logout realizado com sucesso. Até logo!"));
70
- console.log(chalk.gray(" Configurações locais removidas.\n"));
71
- } else {
72
- console.log(chalk.yellow("\n ⚠ Você não está logado atualmente."));
73
- }
74
- }
75
-
76
- function authtoken(token) {
77
- try {
78
- fs.writeFileSync(CONFIG_PATH, JSON.stringify({ token }));
79
- console.log("\n" + getHeader());
80
- console.log(chalk.green(" ✔ Authtoken salvo com sucesso!"));
81
- console.log(chalk.gray(` Configurado em: ${CONFIG_PATH}\n`));
82
- } catch (err) {
83
- console.error(chalk.red(" ✖ Erro ao salvar authtoken:"), err.message);
84
- }
85
- }
86
-
87
- function showStatus() {
88
- console.log(getHeader());
89
-
90
- if (fs.existsSync(CONFIG_PATH)) {
91
- try {
92
- const config = JSON.parse(fs.readFileSync(CONFIG_PATH));
93
- if (config.token) {
94
- const maskedToken = config.token.substring(0, 8) + "•".repeat(24);
95
- console.log(chalk.white("\n STATUS DA CONEXÃO"));
96
- console.log(chalk.blue(" ▪"), chalk.bold("Versão: "), chalk.yellow(`v${version}`));
97
- console.log(chalk.blue(" ▪"), chalk.bold("Autenticado:"), chalk.green("SIM"));
98
- console.log(chalk.blue(" ▪"), chalk.bold("Token: "), chalk.gray(maskedToken));
99
- console.log(chalk.blue(" ▪"), chalk.bold("Servidor: "), chalk.cyan(SERVER_URL));
100
- console.log(chalk.blue(" ▪"), chalk.bold("Config: "), chalk.gray(CONFIG_PATH));
101
- console.log(chalk.gray("\n © 2026 JEBCODE SOFTWARE E TECNOLOGIA LTDA\n"));
102
- } else {
103
- console.log(chalk.yellow("\n ⚠ Token não encontrado no arquivo de configuração."));
104
- }
105
- } catch (e) {
106
- console.error(chalk.red("\n ✖ Erro ao ler configuração:"), e.message);
107
- }
108
- } else {
109
- console.log(chalk.white("\n STATUS DA CONEXÃO"));
110
- console.log(chalk.blue(" ▪"), chalk.bold("Autenticado:"), chalk.red("NÃO"));
111
- console.log(chalk.gray("\n Use 'jebcode-tunnel login' or 'jebcode-tunnel authtoken <token>' para começar.\n"));
112
- console.log(chalk.gray(" © 2026 JEBCODE SOFTWARE E TECNOLOGIA LTDA\n"));
113
- }
114
- }
115
-
116
- function startTunnel(port, options = {}) {
117
- let config = {};
118
- if (fs.existsSync(CONFIG_PATH)) {
119
- try {
120
- config = JSON.parse(fs.readFileSync(CONFIG_PATH));
121
- } catch (e) {
122
- console.error(chalk.red(" ✖ Erro no arquivo de config:"), e.message);
123
- }
124
- }
125
-
126
- if (!config.token) {
127
- console.log(getHeader());
128
- console.error(chalk.red(" ✖ Erro: Authtoken não configurado."));
129
- console.log(chalk.gray(" Obtenha seu token no Dashboard: https://jebcodetunnel.com/dashboard"));
130
- console.log(chalk.gray(`\n Use: ${chalk.bold("jebcode-tunnel login")} ou ${chalk.bold("jebcode-tunnel authtoken <token>")}\n`));
131
- process.exit(1);
132
- }
133
-
134
- const subdomain = options.subdomain || "dev";
135
- const insecure = options.insecure || false;
136
-
137
- process.stdout.write(chalk.blue(" ☁ Conectando à infraestrutura JebCode... "));
138
-
139
- const socket = io(SERVER_URL, {
140
- transports: ["websocket", "polling"],
141
- reconnectionAttempts: 10,
142
- timeout: 15000,
143
- rejectUnauthorized: !insecure,
144
- pingInterval: 10000,
145
- pingTimeout: 5000
146
- });
147
-
148
- socket.on("connect", () => {
149
- process.stdout.write(chalk.green("OK\n"));
150
- socket.emit("authenticate", { token: config.token, subdomain });
151
- });
152
-
153
- socket.on("auth_result", (result) => {
154
- if (result.success) {
155
- console.clear();
156
- console.log(getHeader());
157
- console.log(chalk.white(" STATUS DO TÚNEL ATIVO"));
158
- console.log(chalk.blue(" ▪"), chalk.bold("URL Pública: "), chalk.yellow(`https://${subdomain}.jebcodetunnel.com`));
159
- console.log(chalk.blue(" ▪"), chalk.bold("Encaminhando:"), chalk.white(`http://localhost:${port}`), chalk.gray("➔"), chalk.cyan("jeb-gateway"));
160
- console.log(chalk.blue(" ▪"), chalk.bold("Dashboard: "), chalk.gray(`${SERVER_URL}/dashboard`));
161
-
162
- console.log(chalk.gray("\n Pressione CTRL+C para encerrar o túnel"));
163
- console.log(chalk.white("\n LOGS DE TRÁFEGO EM TEMPO REAL:"));
164
- console.log(chalk.gray(" " + "─".repeat(60)));
165
- } else {
166
- console.log(chalk.red("\n Falha na Autenticação:"), chalk.bold(result.message));
167
- console.log(chalk.gray(" Verifique seu token e se o subdomínio foi criado no dashboard.\n"));
168
- process.exit(1);
169
- }
170
- });
171
-
172
- socket.on("heartbeat_ping", () => {
173
- socket.emit("heartbeat_pong");
174
- });
175
-
176
- socket.on("incoming_request", async (reqData) => {
177
- const timestamp = new Date().toLocaleTimeString();
178
- const methodColor = reqData.method === "GET" ? chalk.green : reqData.method === "POST" ? chalk.blue : chalk.yellow;
179
-
180
- // Log imediato para feedback instantâneo no terminal
181
- const startLog = `${chalk.gray(` [${timestamp}]`)} ${methodColor(reqData.method.padEnd(7))} ${chalk.white(reqData.path.substring(0, 30).padEnd(30))} ${chalk.yellow("PROCESSANDO...")}`;
182
- process.stdout.write(startLog);
183
-
184
- const startTime = Date.now();
185
- try {
186
- const response = await axios({
187
- method: reqData.method,
188
- url: `http://localhost:${port}${reqData.path}`,
189
- headers: { ...reqData.headers, host: `localhost:${port}` },
190
- data: reqData.body ? Buffer.from(reqData.body, "base64") : undefined,
191
- responseType: "arraybuffer",
192
- validateStatus: () => true,
193
- timeout: 10000
194
- });
195
-
196
- const duration = Date.now() - startTime;
197
- const statusColor = response.status < 300 ? chalk.green : response.status < 400 ? chalk.cyan : chalk.red;
198
-
199
- // Limpa a linha atual e sobrescreve com o log final
200
- if (process.stdout.isTTY) {
201
- process.stdout.clearLine(0);
202
- process.stdout.cursorTo(0);
203
- } else {
204
- process.stdout.write("\n");
205
- }
206
-
207
- const logLine = [
208
- chalk.gray(` [${timestamp}]`),
209
- methodColor(reqData.method.padEnd(7)),
210
- chalk.white(reqData.path.substring(0, 30).padEnd(30)),
211
- statusColor(response.status.toString().padStart(3)),
212
- chalk.gray(`${duration.toString().padStart(5)}ms`)
213
- ].join(" ");
214
-
215
- console.log(logLine);
216
-
217
- socket.emit(`response_${reqData.id}`, {
218
- status: response.status,
219
- headers: response.headers,
220
- body: Buffer.from(response.data).toString("base64"),
221
- });
222
- } catch (err) {
223
- const duration = Date.now() - startTime;
224
- if (process.stdout.isTTY) {
225
- process.stdout.clearLine(0);
226
- process.stdout.cursorTo(0);
227
- } else {
228
- process.stdout.write("\n");
229
- }
230
- console.log(`${chalk.gray(` [${timestamp}]`)} ${methodColor(reqData.method.padEnd(7))} ${chalk.white(reqData.path.substring(0, 30).padEnd(30))} ${chalk.red("FALHOU")} ${chalk.gray(`${duration}ms`)}`);
231
-
232
- socket.emit(`response_${reqData.id}`, {
233
- status: 502,
234
- headers: { "Content-Type": "text/plain" },
235
- body: Buffer.from(`JebCode Gateway Error: Erro ao conectar no localhost:${port}. O serviço está rodando?`).toString("base64"),
236
- });
237
- }
238
- });
239
-
240
- socket.on("disconnect", () => {
241
- console.log(chalk.yellow("\n ⚠ Conexão perdida. Tentando reconectar..."));
242
- });
243
-
244
- socket.on("connect_error", (err) => {
245
- console.error(chalk.red("\n ✖ Erro Crítico de Conexão:"), err.message);
246
- });
247
- }
248
-
249
- module.exports = { authtoken, startTunnel, showStatus, login, logout };
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const os = require("os");
4
+ const io = require("socket.io-client");
5
+ const axios = require("axios");
6
+ const chalk = require("chalk");
7
+ const inquirer = require("inquirer");
8
+ const { version } = require("./package.json");
9
+
10
+ const CONFIG_PATH = path.join(os.homedir(), ".jebcode-tunnel");
11
+ const SERVER_URL = process.env.JEB_SERVER_URL || "https://jebcodetunnel.com";
12
+
13
+ function getHeader() {
14
+ return chalk.bold.blue(`
15
+ ██╗███████╗██████╗ ██████╗ ██████╗ ██████╗ ███████╗
16
+ ██║██╔════╝██╔══██╗██╔════╝ ██╔═══██╗██╔══██╗██╔════╝
17
+ ██║█████╗ ██████╔╝██║ ██║ ██║██║ ██║█████╗
18
+ ██╗ ██║██╔══╝ ██╔══██╗██║ ██║ ██║██║ ██║██╔══╝
19
+ ╚██████╔╝███████╗██████╔╝╚██████╗ ╚██████╔╝██████╔╝███████╗ ®
20
+ ╚═════╝ ╚══════╝╚═════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝
21
+ ${chalk.italic("Infraestrutura de Tunelamento de Alta Performance")}
22
+ `);
23
+ }
24
+
25
+ async function login() {
26
+ console.log(getHeader());
27
+ console.log(chalk.white(" ENTRAR NA SUA CONTA JEBCODE:\n"));
28
+
29
+ const answers = await inquirer.prompt([
30
+ {
31
+ type: "input",
32
+ name: "email",
33
+ message: "E-mail:",
34
+ validate: (input) => input.includes("@") || "Por favor, insira um e-mail válido."
35
+ },
36
+ {
37
+ type: "password",
38
+ name: "password",
39
+ message: "Senha:",
40
+ mask: "*"
41
+ }
42
+ ]);
43
+
44
+ process.stdout.write(chalk.blue("\n ☁ Autenticando... "));
45
+
46
+ try {
47
+ const response = await axios.post(`${SERVER_URL}/api/cli/login`, {
48
+ email: answers.email,
49
+ password: answers.password
50
+ });
51
+
52
+ const { api_key } = response.data;
53
+ process.stdout.write(chalk.green("OK\n"));
54
+
55
+ fs.writeFileSync(CONFIG_PATH, JSON.stringify({ token: api_key }));
56
+ console.log(chalk.green("\n ✔ Login realizado com sucesso!"));
57
+ console.log(chalk.gray(` Token salvo e pronto para uso.\n`));
58
+ } catch (err) {
59
+ process.stdout.write(chalk.red("FALHOU\n"));
60
+ const errorMsg = err.response?.data?.error || err.message;
61
+ console.error(chalk.red(" ✖ Erro:"), errorMsg);
62
+ }
63
+ }
64
+
65
+ function logout() {
66
+ if (fs.existsSync(CONFIG_PATH)) {
67
+ fs.unlinkSync(CONFIG_PATH);
68
+ console.log(getHeader());
69
+ console.log(chalk.green("\n ✔ Logout realizado com sucesso. Até logo!"));
70
+ console.log(chalk.gray(" Configurações locais removidas.\n"));
71
+ } else {
72
+ console.log(chalk.yellow("\n ⚠ Você não está logado atualmente."));
73
+ }
74
+ }
75
+
76
+ function authtoken(token) {
77
+ try {
78
+ fs.writeFileSync(CONFIG_PATH, JSON.stringify({ token }));
79
+ console.log("\n" + getHeader());
80
+ console.log(chalk.green(" ✔ Authtoken salvo com sucesso!"));
81
+ console.log(chalk.gray(` Configurado em: ${CONFIG_PATH}\n`));
82
+ } catch (err) {
83
+ console.error(chalk.red(" ✖ Erro ao salvar authtoken:"), err.message);
84
+ }
85
+ }
86
+
87
+ function showStatus() {
88
+ console.log(getHeader());
89
+
90
+ if (fs.existsSync(CONFIG_PATH)) {
91
+ try {
92
+ const config = JSON.parse(fs.readFileSync(CONFIG_PATH));
93
+ if (config.token) {
94
+ const maskedToken = config.token.substring(0, 8) + "•".repeat(24);
95
+ console.log(chalk.white("\n STATUS DA CONEXÃO"));
96
+ console.log(chalk.blue(" ▪"), chalk.bold("Versão: "), chalk.yellow(`v${version}`));
97
+ console.log(chalk.blue(" ▪"), chalk.bold("Autenticado:"), chalk.green("SIM"));
98
+ console.log(chalk.blue(" ▪"), chalk.bold("Token: "), chalk.gray(maskedToken));
99
+ console.log(chalk.blue(" ▪"), chalk.bold("Servidor: "), chalk.cyan(SERVER_URL));
100
+ console.log(chalk.blue(" ▪"), chalk.bold("Config: "), chalk.gray(CONFIG_PATH));
101
+ console.log(chalk.gray("\n © 2026 JEBCODE SOFTWARE E TECNOLOGIA LTDA\n"));
102
+ } else {
103
+ console.log(chalk.yellow("\n ⚠ Token não encontrado no arquivo de configuração."));
104
+ }
105
+ } catch (e) {
106
+ console.error(chalk.red("\n ✖ Erro ao ler configuração:"), e.message);
107
+ }
108
+ } else {
109
+ console.log(chalk.white("\n STATUS DA CONEXÃO"));
110
+ console.log(chalk.blue(" ▪"), chalk.bold("Autenticado:"), chalk.red("NÃO"));
111
+ console.log(chalk.gray("\n Use 'jebcode-tunnel login' or 'jebcode-tunnel authtoken <token>' para começar.\n"));
112
+ console.log(chalk.gray(" © 2026 JEBCODE SOFTWARE E TECNOLOGIA LTDA\n"));
113
+ }
114
+ }
115
+
116
+ function startTunnel(port, options = {}) {
117
+ let config = {};
118
+ if (fs.existsSync(CONFIG_PATH)) {
119
+ try {
120
+ config = JSON.parse(fs.readFileSync(CONFIG_PATH));
121
+ } catch (e) {
122
+ console.error(chalk.red(" ✖ Erro no arquivo de config:"), e.message);
123
+ }
124
+ }
125
+
126
+ if (!config.token) {
127
+ console.log(getHeader());
128
+ console.error(chalk.red(" ✖ Erro: Authtoken não configurado."));
129
+ console.log(chalk.gray(" Obtenha seu token no Dashboard: https://jebcodetunnel.com/dashboard"));
130
+ console.log(chalk.gray(`\n Use: ${chalk.bold("jebcode-tunnel login")} ou ${chalk.bold("jebcode-tunnel authtoken <token>")}\n`));
131
+ process.exit(1);
132
+ }
133
+
134
+ const subdomain = options.subdomain || "dev";
135
+ const insecure = options.insecure || false;
136
+
137
+ process.stdout.write(chalk.blue(" ☁ Conectando à infraestrutura JebCode... "));
138
+
139
+ const socket = io(SERVER_URL, {
140
+ transports: ["websocket", "polling"],
141
+ reconnectionAttempts: 10,
142
+ timeout: 15000,
143
+ rejectUnauthorized: !insecure,
144
+ pingInterval: 10000,
145
+ pingTimeout: 5000
146
+ });
147
+
148
+ socket.on("connect", () => {
149
+ process.stdout.write(chalk.green("OK\n"));
150
+ socket.emit("authenticate", { token: config.token, subdomain });
151
+ });
152
+
153
+ let hasShownHeader = false;
154
+ socket.on("auth_result", (result) => {
155
+ if (result.success) {
156
+ if (!hasShownHeader) {
157
+ console.clear();
158
+ console.log(getHeader());
159
+ console.log(chalk.white(" STATUS DO TÚNEL ATIVO"));
160
+ console.log(chalk.blue(" ▪"), chalk.bold("URL Pública: "), chalk.yellow(`https://${subdomain}.jebcodetunnel.com`));
161
+ console.log(chalk.blue(" ▪"), chalk.bold("Encaminhando:"), chalk.white(`http://localhost:${port}`), chalk.gray("➔"), chalk.cyan("jeb-gateway"));
162
+ console.log(chalk.blue(" ▪"), chalk.bold("Dashboard: "), chalk.gray(`${SERVER_URL}/dashboard`));
163
+
164
+ console.log(chalk.gray("\n Pressione CTRL+C para encerrar o túnel"));
165
+ console.log(chalk.white("\n LOGS DE TRÁFEGO EM TEMPO REAL:"));
166
+ console.log(chalk.gray(" " + "─".repeat(60)));
167
+ hasShownHeader = true;
168
+ } else {
169
+ console.log(chalk.green("\n ✔ Conexão Restabelecida!"));
170
+ }
171
+ } else {
172
+ console.log(chalk.red("\n ✖ Falha na Autenticação:"), chalk.bold(result.message));
173
+ console.log(chalk.gray(" Verifique seu token e se o subdomínio foi criado no dashboard.\n"));
174
+ process.exit(1);
175
+ }
176
+ });
177
+
178
+ socket.on("heartbeat_ping", () => {
179
+ socket.emit("heartbeat_pong");
180
+ });
181
+
182
+ socket.on("incoming_request", async (reqData) => {
183
+ const timestamp = new Date().toLocaleTimeString();
184
+ const methodColor = reqData.method === "GET" ? chalk.green : reqData.method === "POST" ? chalk.blue : chalk.yellow;
185
+ const startTime = Date.now();
186
+
187
+ try {
188
+ const response = await axios({
189
+ method: reqData.method,
190
+ url: `http://localhost:${port}${reqData.path}`,
191
+ headers: { ...reqData.headers, host: `localhost:${port}` },
192
+ data: reqData.body ? Buffer.from(reqData.body, "base64") : undefined,
193
+ responseType: "arraybuffer",
194
+ validateStatus: () => true,
195
+ timeout: 10000
196
+ });
197
+
198
+ const duration = Date.now() - startTime;
199
+ const statusColor = response.status < 300 ? chalk.green : response.status < 400 ? chalk.cyan : chalk.red;
200
+
201
+ const logLine = [
202
+ chalk.gray(` [${timestamp}]`),
203
+ methodColor(reqData.method.padEnd(7)),
204
+ chalk.white(reqData.path.substring(0, 30).padEnd(30)),
205
+ statusColor(response.status.toString().padStart(3)),
206
+ chalk.gray(`${duration.toString().padStart(5)}ms`)
207
+ ].join(" ");
208
+
209
+ console.log(logLine);
210
+
211
+ socket.emit(`response_${reqData.id}`, {
212
+ status: response.status,
213
+ headers: response.headers,
214
+ body: Buffer.from(response.data).toString("base64"),
215
+ });
216
+ } catch (err) {
217
+ const duration = Date.now() - startTime;
218
+ console.log(`${chalk.gray(` [${timestamp}]`)} ${methodColor(reqData.method.padEnd(7))} ${chalk.white(reqData.path.substring(0, 30).padEnd(30))} ${chalk.red("FALHOU")} ${chalk.gray(`${duration}ms`)}`);
219
+
220
+ socket.emit(`response_${reqData.id}`, {
221
+ status: 502,
222
+ headers: { "Content-Type": "text/plain" },
223
+ body: Buffer.from(`JebCode Gateway Error: Erro ao conectar no localhost:${port}. O serviço está rodando?`).toString("base64"),
224
+ });
225
+ }
226
+ });
227
+
228
+ socket.on("disconnect", () => {
229
+ console.log(chalk.yellow("\n ⚠ Conexão perdida. Tentando reconectar..."));
230
+ });
231
+
232
+ socket.on("connect_error", (err) => {
233
+ console.error(chalk.red("\n ✖ Erro Crítico de Conexão:"), err.message);
234
+ });
235
+ }
236
+
237
+ module.exports = { authtoken, startTunnel, showStatus, login, logout };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jebcode-dev/jebcode-tunnel",
3
- "version": "1.0.0",
3
+ "version": "1.0.5",
4
4
  "description": "CLI do JebCode Tunnel",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -22,6 +22,12 @@
22
22
  "test": "echo \"Error: no test specified\" && exit 1",
23
23
  "release": "npm version patch && npm link"
24
24
  },
25
+ "files": [
26
+ "index.js",
27
+ "bin.js",
28
+ "README.md",
29
+ "LICENSE"
30
+ ],
25
31
  "dependencies": {
26
32
  "axios": "^1.7.9",
27
33
  "chalk": "^4.1.2",
@@ -29,4 +35,4 @@
29
35
  "inquirer": "^8.2.7",
30
36
  "socket.io-client": "^4.8.1"
31
37
  }
32
- }
38
+ }
@@ -1,20 +0,0 @@
1
- name: Publish to npm
2
-
3
- on:
4
- push:
5
- tags:
6
- - 'v*'
7
-
8
- jobs:
9
- publish:
10
- runs-on: ubuntu-latest
11
- permissions:
12
- id-token: write # Essencial para OIDC / Trusted Publishing
13
- contents: read
14
- steps:
15
- - uses: actions/checkout@v4
16
- - uses: actions/setup-node@v4
17
- with:
18
- node-version: "24"
19
- - run: npm install
20
- - run: npm publish --access public
package/editora.md DELETED
@@ -1,40 +0,0 @@
1
- # 🚀 Configuração da Editora de Confiança (npm + GitHub)
2
-
3
- Para configurar o **Trusted Publishing**, preencha os campos no npm exatamente assim:
4
-
5
- | Campo | Valor |
6
- | :--- | :--- |
7
- | **Organização ou usuário** | `JonathanBoza` |
8
- | **Repositório** | `cli-jebcode-tunnel` |
9
- | **Nome do arquivo do workflow** | `publish.yml` |
10
- | **Nome do ambiente** | (Deixe vazio) |
11
-
12
- ---
13
-
14
- ## 🛠️ O que fazer agora:
15
-
16
- 1. Eu já criei o arquivo `.github/workflows/publish.yml` na sua pasta `cli`.
17
- 2. Você precisa fazer o **Push** desse arquivo para o seu GitHub:
18
- ```powershell
19
- git add .
20
- git commit -m "Add npm publish workflow"
21
- git push origin main
22
- ```
23
- 3. No site do npm, clique em **"Configurar conexão"**.
24
-
25
- ---
26
-
27
- ## 📦 Como publicar uma nova versão:
28
-
29
- Agora você não precisa mais rodar `npm publish` na sua máquina. Basta:
30
-
31
- 1. Alterar a versão no `package.json`.
32
- 2. Criar uma **Tag** ou uma **Release** no GitHub (ex: `v1.0.1`).
33
- 3. O GitHub vai publicar sozinho para você! 😊
34
-
35
-
36
- # 1. Altera para a versão 1.0.7 no package.json (ou deixa eu fazer se preferir)
37
- # 2. Cria a tag de versão
38
- git tag v1.0.1
39
- # 3. Envia a tag para o GitHub
40
- git push origin v1.0.1
Binary file
package/img/image.png DELETED
Binary file