@purecore/one-server-4-all 0.3.0 → 0.3.1
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/cert-generator.js +62 -44
- package/dist/deployer.js +10 -11
- package/dist/index.js +1 -1
- package/dist/server.js +8 -8
- package/package.json +1 -1
- package/src/deployer.ts +10 -10
- package/src/index.ts +1 -1
package/dist/cert-generator.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import crypto from
|
|
3
|
-
import fs from
|
|
4
|
-
import path from
|
|
5
|
-
import { execFileSync } from
|
|
2
|
+
import crypto from "node:crypto";
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { execFileSync } from "node:child_process";
|
|
6
6
|
export class CertGenerator {
|
|
7
|
-
static CERT_DIR =
|
|
8
|
-
static KEY_FILE =
|
|
9
|
-
static CERT_FILE =
|
|
7
|
+
static CERT_DIR = ".one-server-4-all-certs";
|
|
8
|
+
static KEY_FILE = "localhost.key";
|
|
9
|
+
static CERT_FILE = "localhost.crt";
|
|
10
10
|
static async generateCerts() {
|
|
11
11
|
const certDir = path.join(process.cwd(), this.CERT_DIR);
|
|
12
12
|
const keyPath = path.join(certDir, this.KEY_FILE);
|
|
@@ -16,7 +16,7 @@ export class CertGenerator {
|
|
|
16
16
|
try {
|
|
17
17
|
await fs.access(keyPath);
|
|
18
18
|
await fs.access(certPath);
|
|
19
|
-
console.log(
|
|
19
|
+
console.log("📋 Certificados já existem em:", certDir);
|
|
20
20
|
return { keyPath, certPath };
|
|
21
21
|
}
|
|
22
22
|
catch {
|
|
@@ -24,7 +24,7 @@ export class CertGenerator {
|
|
|
24
24
|
}
|
|
25
25
|
// Criar diretório se não existir
|
|
26
26
|
await fs.mkdir(certDir, { recursive: true });
|
|
27
|
-
console.log(
|
|
27
|
+
console.log("🔐 Gerando certificados auto-assinados...");
|
|
28
28
|
// Observação importante:
|
|
29
29
|
// Gerar um X509 "de verdade" apenas com node:crypto (sem libs externas) não é trivial.
|
|
30
30
|
// Como este projeto roda no WSL, utilizamos o OpenSSL (toolchain padrão do Linux)
|
|
@@ -32,44 +32,58 @@ export class CertGenerator {
|
|
|
32
32
|
await this.generateWithOpenSSL({ keyPath, certPath });
|
|
33
33
|
// Validação do PEM (evita subir servidor com arquivo corrompido)
|
|
34
34
|
const [keyPem, certPem] = await Promise.all([
|
|
35
|
-
fs.readFile(keyPath,
|
|
36
|
-
fs.readFile(certPath,
|
|
35
|
+
fs.readFile(keyPath, "utf8"),
|
|
36
|
+
fs.readFile(certPath, "utf8"),
|
|
37
37
|
]);
|
|
38
38
|
this.validatePem({ keyPem, certPem, keyPath, certPath });
|
|
39
39
|
this.validateX509(certPem, certPath);
|
|
40
40
|
this.validateWithOpenSSL(certPath);
|
|
41
|
-
console.log(
|
|
42
|
-
console.log(
|
|
43
|
-
console.log(
|
|
44
|
-
console.log(
|
|
45
|
-
console.log(
|
|
46
|
-
console.log(
|
|
47
|
-
console.log(
|
|
41
|
+
console.log("✅ Certificados gerados com sucesso!");
|
|
42
|
+
console.log("📁 Localização:", certDir);
|
|
43
|
+
console.log("🔑 Chave privada:", keyPath);
|
|
44
|
+
console.log("📄 Certificado:", certPath);
|
|
45
|
+
console.log("");
|
|
46
|
+
console.log("⚠️ AVISO: Estes são certificados auto-assinados para desenvolvimento local.");
|
|
47
|
+
console.log(" Não use em produção!");
|
|
48
48
|
return { keyPath, certPath };
|
|
49
49
|
}
|
|
50
50
|
catch (error) {
|
|
51
|
-
console.error(
|
|
51
|
+
console.error("❌ Erro ao gerar certificados:", error);
|
|
52
52
|
throw error;
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
static generateWithOpenSSL(params) {
|
|
56
56
|
const { keyPath, certPath } = params;
|
|
57
|
-
const subj =
|
|
57
|
+
const subj = "/C=BR/ST=SP/L=Sao Paulo/O=Purecore/OU=Dev/CN=localhost";
|
|
58
58
|
// Preferimos SAN para evitar problemas em clients modernos.
|
|
59
59
|
// Nem todo OpenSSL antigo suporta -addext, então fazemos fallback.
|
|
60
|
-
const baseArgs = [
|
|
60
|
+
const baseArgs = [
|
|
61
|
+
"req",
|
|
62
|
+
"-x509",
|
|
63
|
+
"-newkey",
|
|
64
|
+
"rsa:2048",
|
|
65
|
+
"-keyout",
|
|
66
|
+
keyPath,
|
|
67
|
+
"-out",
|
|
68
|
+
certPath,
|
|
69
|
+
"-days",
|
|
70
|
+
"365",
|
|
71
|
+
"-nodes",
|
|
72
|
+
"-subj",
|
|
73
|
+
subj,
|
|
74
|
+
];
|
|
61
75
|
try {
|
|
62
|
-
execFileSync(
|
|
76
|
+
execFileSync("openssl", [...baseArgs, "-addext", "subjectAltName=DNS:localhost,IP:127.0.0.1"], { stdio: "inherit" });
|
|
63
77
|
}
|
|
64
78
|
catch {
|
|
65
|
-
execFileSync(
|
|
79
|
+
execFileSync("openssl", baseArgs, { stdio: "inherit" });
|
|
66
80
|
}
|
|
67
81
|
}
|
|
68
82
|
static validatePem(params) {
|
|
69
83
|
const { keyPem, certPem, keyPath, certPath } = params;
|
|
70
|
-
const keyOk = keyPem.includes(
|
|
71
|
-
keyPem.includes(
|
|
72
|
-
const certOk = certPem.includes(
|
|
84
|
+
const keyOk = keyPem.includes("-----BEGIN PRIVATE KEY-----") ||
|
|
85
|
+
keyPem.includes("-----BEGIN RSA PRIVATE KEY-----");
|
|
86
|
+
const certOk = certPem.includes("-----BEGIN CERTIFICATE-----");
|
|
73
87
|
if (!keyOk || !certOk) {
|
|
74
88
|
throw new Error(`PEM inválido gerado. ` +
|
|
75
89
|
`keyOk=${keyOk} certOk=${certOk}. ` +
|
|
@@ -83,7 +97,7 @@ export class CertGenerator {
|
|
|
83
97
|
// @ts-ignore - Bun/Node expõem X509Certificate em node:crypto
|
|
84
98
|
const x509 = new crypto.X509Certificate(certPem);
|
|
85
99
|
if (!x509.subject) {
|
|
86
|
-
throw new Error(
|
|
100
|
+
throw new Error("X509 sem subject");
|
|
87
101
|
}
|
|
88
102
|
}
|
|
89
103
|
catch (error) {
|
|
@@ -93,7 +107,9 @@ export class CertGenerator {
|
|
|
93
107
|
static validateWithOpenSSL(certPath) {
|
|
94
108
|
try {
|
|
95
109
|
// OpenSSL é a validação "ground truth" no WSL.
|
|
96
|
-
execFileSync(
|
|
110
|
+
execFileSync("openssl", ["x509", "-in", certPath, "-noout"], {
|
|
111
|
+
stdio: "ignore",
|
|
112
|
+
});
|
|
97
113
|
}
|
|
98
114
|
catch (error) {
|
|
99
115
|
throw new Error(`OpenSSL não conseguiu ler o certificado (${certPath}).`);
|
|
@@ -116,40 +132,42 @@ export class CertGenerator {
|
|
|
116
132
|
const certDir = path.join(process.cwd(), this.CERT_DIR);
|
|
117
133
|
try {
|
|
118
134
|
await fs.rm(certDir, { recursive: true, force: true });
|
|
119
|
-
console.log(
|
|
135
|
+
console.log("🗑️ Certificados removidos:", certDir);
|
|
120
136
|
}
|
|
121
137
|
catch (error) {
|
|
122
|
-
console.error(
|
|
138
|
+
console.error("❌ Erro ao remover certificados:", error);
|
|
123
139
|
}
|
|
124
140
|
}
|
|
125
141
|
}
|
|
126
142
|
// Executar se chamado diretamente
|
|
127
|
-
if (typeof require !==
|
|
143
|
+
if (typeof require !== "undefined" && require.main === module) {
|
|
128
144
|
const command = process.argv[2];
|
|
129
145
|
switch (command) {
|
|
130
|
-
case
|
|
146
|
+
case "generate":
|
|
131
147
|
case undefined:
|
|
132
148
|
CertGenerator.generateCerts().catch(console.error);
|
|
133
149
|
break;
|
|
134
|
-
case
|
|
150
|
+
case "clean":
|
|
135
151
|
CertGenerator.cleanCerts().catch(console.error);
|
|
136
152
|
break;
|
|
137
|
-
case
|
|
138
|
-
CertGenerator.getCertPaths()
|
|
153
|
+
case "info":
|
|
154
|
+
CertGenerator.getCertPaths()
|
|
155
|
+
.then((paths) => {
|
|
139
156
|
if (paths) {
|
|
140
|
-
console.log(
|
|
141
|
-
console.log(
|
|
142
|
-
console.log(
|
|
157
|
+
console.log("📋 Certificados encontrados:");
|
|
158
|
+
console.log("🔑 Chave:", paths.keyPath);
|
|
159
|
+
console.log("📄 Certificado:", paths.certPath);
|
|
143
160
|
}
|
|
144
161
|
else {
|
|
145
|
-
console.log(
|
|
162
|
+
console.log("❌ Nenhum certificado encontrado");
|
|
146
163
|
}
|
|
147
|
-
})
|
|
164
|
+
})
|
|
165
|
+
.catch(console.error);
|
|
148
166
|
break;
|
|
149
167
|
default:
|
|
150
|
-
console.log(
|
|
151
|
-
console.log(
|
|
152
|
-
console.log(
|
|
153
|
-
console.log(
|
|
168
|
+
console.log("Uso: cert-generator [generate|clean|info]");
|
|
169
|
+
console.log(" generate: Gera certificados auto-assinados (padrão)");
|
|
170
|
+
console.log(" clean: Remove certificados existentes");
|
|
171
|
+
console.log(" info: Mostra informações dos certificados");
|
|
154
172
|
}
|
|
155
173
|
}
|
package/dist/deployer.js
CHANGED
|
@@ -16,7 +16,7 @@ export class Deployer {
|
|
|
16
16
|
return new Promise((resolve) => this.rl.question(query, resolve));
|
|
17
17
|
}
|
|
18
18
|
printBanner() {
|
|
19
|
-
console.log(`\n ${bold(magenta("🚀
|
|
19
|
+
console.log(`\n ${bold(magenta("🚀 one-server-4-all DEPLOYER"))} ${gray("v0.4.0")}`);
|
|
20
20
|
console.log(` ${gray("─────────────────────────────────────────")}\n`);
|
|
21
21
|
}
|
|
22
22
|
async start() {
|
|
@@ -27,7 +27,7 @@ export class Deployer {
|
|
|
27
27
|
this.rl.close();
|
|
28
28
|
return;
|
|
29
29
|
}
|
|
30
|
-
const port = (await this.question(` ${cyan("➜")} ${bold("Qual a porta do servidor?")} ${gray("(padrão
|
|
30
|
+
const port = (await this.question(` ${cyan("➜")} ${bold("Qual a porta do servidor?")} ${gray("(padrão 7000)")}\n ${green("❯")} `)) || "7000";
|
|
31
31
|
const confirmNginx = await this.question(` ${cyan("➜")} ${bold("Deseja configurar Nginx + SSL (Certbot) agora?")} ${gray("(s/n)")}\n ${green("❯")} `);
|
|
32
32
|
let certPaths = { key: "", cert: "" };
|
|
33
33
|
if (confirmNginx.toLowerCase() === "s") {
|
|
@@ -40,18 +40,17 @@ export class Deployer {
|
|
|
40
40
|
}
|
|
41
41
|
const name = domain.split(".")[0];
|
|
42
42
|
// Monta o comando PM2
|
|
43
|
-
//
|
|
44
|
-
// O
|
|
45
|
-
//
|
|
46
|
-
let pm2Command
|
|
43
|
+
// Quando Nginx+Certbot está configurado, o Nginx faz terminação SSL
|
|
44
|
+
// O server roda em HTTP simples (Nginx faz proxy_pass http://localhost:porta)
|
|
45
|
+
// Argumentos devem estar DENTRO das aspas para PM2 processar corretamente
|
|
46
|
+
let pm2Command;
|
|
47
47
|
if (certPaths.key && certPaths.cert) {
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
pm2Command += ` --https=true --ssl-key="${certPaths.key}" --ssl-cert="${certPaths.cert}"`;
|
|
48
|
+
// Com Nginx+Certbot: server roda HTTP, Nginx cuida do SSL
|
|
49
|
+
pm2Command = `pm2 start "npx vai-server --port=${port} --open=false" --name "${domain}"`;
|
|
51
50
|
}
|
|
52
51
|
else {
|
|
53
|
-
//
|
|
54
|
-
pm2Command
|
|
52
|
+
// Sem Nginx: pode rodar HTTPS auto-assinado ou HTTP
|
|
53
|
+
pm2Command = `pm2 start "npx vai-server --port=${port} --open=false" --name "${domain}"`;
|
|
55
54
|
}
|
|
56
55
|
console.log(`\n ${bold("📦 Configuração Final:")}`);
|
|
57
56
|
console.log(` ${gray("────────────────────────")}`);
|
package/dist/index.js
CHANGED
|
@@ -21,7 +21,7 @@ else {
|
|
|
21
21
|
// Se o primeiro argumento não tiver --, assumimos que é a pasta
|
|
22
22
|
const rootArg = args[0] && !args[0].startsWith("--") ? args[0] : ".";
|
|
23
23
|
const rawConfig = {
|
|
24
|
-
port: parseInt(getArg("port", "
|
|
24
|
+
port: parseInt(getArg("port", "7000")),
|
|
25
25
|
root: path.resolve(process.cwd(), rootArg),
|
|
26
26
|
open: getArg("open", "true"), // 'true' por padrão
|
|
27
27
|
spa: getArg("spa", "false"), // 'false' por padrão
|
package/dist/server.js
CHANGED
|
@@ -12,22 +12,22 @@ const INJECTED_SCRIPT = `
|
|
|
12
12
|
<!-- Code injected by auto-server -->
|
|
13
13
|
<script>
|
|
14
14
|
(function() {
|
|
15
|
-
console.log('[
|
|
15
|
+
console.log('[one-server-4-all] Connected to hot reload');
|
|
16
16
|
const evtSource = new EventSource('/_hot_server_sse');
|
|
17
17
|
evtSource.onmessage = function(event) {
|
|
18
18
|
try {
|
|
19
19
|
const data = JSON.parse(event.data);
|
|
20
20
|
if (data.type === 'css') {
|
|
21
|
-
console.log('[
|
|
21
|
+
console.log('[one-server-4-all] CSS changed, injecting...');
|
|
22
22
|
injectCSS(data.file);
|
|
23
23
|
} else {
|
|
24
|
-
console.log('[
|
|
24
|
+
console.log('[one-server-4-all] Reloading...');
|
|
25
25
|
window.location.reload();
|
|
26
26
|
}
|
|
27
27
|
} catch (e) {
|
|
28
28
|
// Fallback para compatibilidade
|
|
29
29
|
if (event.data === 'reload') {
|
|
30
|
-
console.log('[
|
|
30
|
+
console.log('[one-server-4-all] Reloading...');
|
|
31
31
|
window.location.reload();
|
|
32
32
|
}
|
|
33
33
|
}
|
|
@@ -44,13 +44,13 @@ const INJECTED_SCRIPT = `
|
|
|
44
44
|
// Força reload do CSS adicionando/removendo timestamp
|
|
45
45
|
const newHref = href.split('?')[0] + '?v=' + timestamp;
|
|
46
46
|
link.setAttribute('href', newHref);
|
|
47
|
-
console.log('[
|
|
47
|
+
console.log('[one-server-4-all] CSS injected:', filePath);
|
|
48
48
|
}
|
|
49
49
|
});
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
evtSource.onerror = function() {
|
|
53
|
-
console.log('[
|
|
53
|
+
console.log('[one-server-4-all] Disconnected. Retrying...');
|
|
54
54
|
};
|
|
55
55
|
})();
|
|
56
56
|
</script>
|
|
@@ -325,7 +325,7 @@ export class HotServer {
|
|
|
325
325
|
const green = (text) => `\x1b[32m${text}\x1b[0m`;
|
|
326
326
|
const bold = (text) => `\x1b[1m${text}\x1b[0m`;
|
|
327
327
|
const gray = (text) => `\x1b[90m${text}\x1b[0m`;
|
|
328
|
-
console.log(`\n ${bold(cyan("
|
|
328
|
+
console.log(`\n ${bold(cyan("one-server-4-all"))} ${cyan("v" + version)} ${gray("ready in")} ${bold(green(readyTime + " ms"))}\n`);
|
|
329
329
|
console.log(` ${green("➜")} ${bold("Local")}: ${cyan(`${protocol}://localhost:${this.config.port}/`)}`);
|
|
330
330
|
const networks = this.getNetworkIPs();
|
|
331
331
|
networks.forEach((ip) => {
|
|
@@ -551,7 +551,7 @@ export class HotServer {
|
|
|
551
551
|
</div>
|
|
552
552
|
|
|
553
553
|
<div class="back">
|
|
554
|
-
Servido por <strong>purecore-
|
|
554
|
+
Servido por <strong>purecore-one-server-4-all</strong>
|
|
555
555
|
</div>
|
|
556
556
|
</div>
|
|
557
557
|
</body>
|
package/package.json
CHANGED
package/src/deployer.ts
CHANGED
|
@@ -45,9 +45,9 @@ export class Deployer {
|
|
|
45
45
|
const port =
|
|
46
46
|
(await this.question(
|
|
47
47
|
` ${cyan("➜")} ${bold("Qual a porta do servidor?")} ${gray(
|
|
48
|
-
"(padrão
|
|
48
|
+
"(padrão 7000)"
|
|
49
49
|
)}\n ${green("❯")} `
|
|
50
|
-
)) || "
|
|
50
|
+
)) || "7000";
|
|
51
51
|
|
|
52
52
|
const confirmNginx = await this.question(
|
|
53
53
|
` ${cyan("➜")} ${bold(
|
|
@@ -69,18 +69,18 @@ export class Deployer {
|
|
|
69
69
|
const name = domain.split(".")[0];
|
|
70
70
|
|
|
71
71
|
// Monta o comando PM2
|
|
72
|
-
//
|
|
73
|
-
//
|
|
72
|
+
// Quando Nginx+Certbot está configurado, o Nginx faz terminação SSL
|
|
73
|
+
// O server roda em HTTP simples (Nginx faz proxy_pass http://localhost:porta)
|
|
74
|
+
// Argumentos devem estar DENTRO das aspas para PM2 processar corretamente
|
|
74
75
|
|
|
75
|
-
let pm2Command
|
|
76
|
+
let pm2Command: string;
|
|
76
77
|
|
|
77
78
|
if (certPaths.key && certPaths.cert) {
|
|
78
|
-
//
|
|
79
|
-
|
|
80
|
-
pm2Command += ` --https=true --ssl-key="${certPaths.key}" --ssl-cert="${certPaths.cert}"`;
|
|
79
|
+
// Com Nginx+Certbot: server roda HTTP, Nginx cuida do SSL
|
|
80
|
+
pm2Command = `pm2 start "npx vai-server --port=${port} --open=false" --name "${domain}"`;
|
|
81
81
|
} else {
|
|
82
|
-
//
|
|
83
|
-
pm2Command
|
|
82
|
+
// Sem Nginx: pode rodar HTTPS auto-assinado ou HTTP
|
|
83
|
+
pm2Command = `pm2 start "npx vai-server --port=${port} --open=false" --name "${domain}"`;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
console.log(`\n ${bold("📦 Configuração Final:")}`);
|
package/src/index.ts
CHANGED
|
@@ -24,7 +24,7 @@ if (args[0] === "deploy") {
|
|
|
24
24
|
const rootArg = args[0] && !args[0].startsWith("--") ? args[0] : ".";
|
|
25
25
|
|
|
26
26
|
const rawConfig = {
|
|
27
|
-
port: parseInt(getArg("port", "
|
|
27
|
+
port: parseInt(getArg("port", "7000")),
|
|
28
28
|
root: path.resolve(process.cwd(), rootArg),
|
|
29
29
|
open: getArg("open", "true"), // 'true' por padrão
|
|
30
30
|
spa: getArg("spa", "false"), // 'false' por padrão
|