@danhachuel/pandanews 0.1.1 → 0.1.2
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/CHANGELOG.md +6 -0
- package/README.md +2 -2
- package/backend/app/main.py +4 -3
- package/frontend/README.md +1 -1
- package/package.json +1 -1
- package/scripts/start.js +30 -16
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
Todas as versões publicadas são registradas aqui antes do publish (regra em AGENTS.md). A etiqueta visual usa PATCH de dois dígitos (ex.: 0.1.00); o registry npm normaliza para a versão canônica (ex.: 0.1.0).
|
|
4
4
|
|
|
5
|
+
## 0.1.02 (2026-10-23)
|
|
6
|
+
|
|
7
|
+
- Porta padrão da UI alterada de 3030 para **4030** (sobrescrevível via `PANDANEWS_UI_PORT`)
|
|
8
|
+
- Fallback automático de porta: se 4030 estiver ocupada, o PandaNews tenta a seguinte (4031, 4032, ...) em até 20 tentativas, com mensagem clara se nenhuma estiver livre
|
|
9
|
+
- CORS do backend passa a aceitar localhost/127.0.0.1 em qualquer porta, acompanhando a porta dinâmica da UI
|
|
10
|
+
|
|
5
11
|
## 0.1.01 (2026-10-23)
|
|
6
12
|
|
|
7
13
|
- README reescrito para o fluxo de um único comando via npx (padrão Thunderbolt): `npx @danhachuel/pandanews` instala tudo junto e sobe o app; removidas as instruções manuais de desenvolvimento (pip, uvicorn, npm)
|
package/README.md
CHANGED
|
@@ -34,9 +34,9 @@ npx --yes @danhachuel/pandanews install
|
|
|
34
34
|
|
|
35
35
|
O runtime fica em `.runtime/` na raiz do pacote (sobrescreva com a variável de ambiente `PANDANEWS_HOME`).
|
|
36
36
|
|
|
37
|
-
## Status (versão 0.1.
|
|
37
|
+
## Status (versão 0.1.02)
|
|
38
38
|
|
|
39
|
-
- `npx @danhachuel/pandanews` instala tudo junto (Python portátil + dependências + banco local) e sobe o backend em 127.0.0.1:8000 com página em 127.0.0.1:
|
|
39
|
+
- `npx @danhachuel/pandanews` instala tudo junto (Python portátil + dependências + banco local) e sobe o backend em 127.0.0.1:8000 com página em 127.0.0.1:4030 — se a porta estiver ocupada, usa a seguinte automaticamente (4031, 4032, ...)
|
|
40
40
|
- A UI React completa (Dashboard, Blogs, Notícias, Imagens, Automação, Configurações) e o pipeline de notícias chegam nas próximas versões (Fases 1 a 3 do plano — ver `CHANGELOG.md`)
|
|
41
41
|
|
|
42
42
|
## Regras do projeto
|
package/backend/app/main.py
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
"""PandaNews API — FastAPI.
|
|
2
2
|
|
|
3
3
|
Fase 0/1: aplicação mínima com endpoint de health e CORS liberado para a UI
|
|
4
|
-
local (127.0.0.1
|
|
4
|
+
local (localhost/127.0.0.1 em qualquer porta — a UI usa porta dinâmica a partir
|
|
5
|
+
de 4030). CRUD de blogs e configurações chegam na Fase 1.
|
|
5
6
|
"""
|
|
6
7
|
from fastapi import FastAPI
|
|
7
8
|
from fastapi.middleware.cors import CORSMiddleware
|
|
8
9
|
|
|
9
|
-
app = FastAPI(title="PandaNews API", version="0.1.
|
|
10
|
+
app = FastAPI(title="PandaNews API", version="0.1.2")
|
|
10
11
|
|
|
11
12
|
app.add_middleware(
|
|
12
13
|
CORSMiddleware,
|
|
13
|
-
|
|
14
|
+
allow_origin_regex=r"^https?://(localhost|127\.0\.0\.1)(:\d+)?$",
|
|
14
15
|
allow_methods=["*"],
|
|
15
16
|
allow_headers=["*"],
|
|
16
17
|
)
|
package/frontend/README.md
CHANGED
|
@@ -5,4 +5,4 @@ UI do PandaNews (React + Vite + Tailwind), inicializada na Fase 2 do plano de im
|
|
|
5
5
|
- Páginas: Dashboard, Blogs, Notícias, Imagens, Automação, Configurações, Logs
|
|
6
6
|
- Sidebar + topbar no padrão Leadmaster
|
|
7
7
|
- 7 leis de usabilidade aplicadas (Fitts, Hick, Zeigarnik, Jakob, Gradiente de Meta, von Restorff, Miller)
|
|
8
|
-
- Build: `npm run build` → `dist/` servido em 127.0.0.1:
|
|
8
|
+
- Build: `npm run build` → `dist/` servido em 127.0.0.1:4030 (com fallback para 4031, 4032, ... se ocupada)
|
package/package.json
CHANGED
package/scripts/start.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
// Inicia o PandaNews: backend FastAPI (127.0.0.1:8000) + UI (127.0.0.1:
|
|
1
|
+
// Inicia o PandaNews: backend FastAPI (127.0.0.1:8000) + UI (127.0.0.1:4030+).
|
|
2
2
|
//
|
|
3
3
|
// Fluxo de um único comando (padrão Thunderbolt): se o runtime não estiver
|
|
4
4
|
// provisionado, executa o install completo (Python portátil + dependências)
|
|
5
|
-
// antes de subir os servidores.
|
|
5
|
+
// antes de subir os servidores. A UI começa em PANDANEWS_UI_PORT (padrão 4030)
|
|
6
|
+
// e, se a porta estiver ocupada, tenta automaticamente a seguinte (4031, ...).
|
|
6
7
|
import { existsSync, readFileSync } from 'node:fs';
|
|
7
8
|
import { spawn } from 'node:child_process';
|
|
8
9
|
import { createServer } from 'node:http';
|
|
@@ -10,7 +11,8 @@ import { join, extname } from 'node:path';
|
|
|
10
11
|
import { resolveHome, runInstall, PKG_ROOT } from './install.js';
|
|
11
12
|
|
|
12
13
|
const BACKEND_PORT = Number(process.env.PANDANEWS_API_PORT || 8000);
|
|
13
|
-
const
|
|
14
|
+
const UI_PORT_BASE = Number(process.env.PANDANEWS_UI_PORT || 4030);
|
|
15
|
+
const UI_PORT_MAX_TRIES = 20;
|
|
14
16
|
|
|
15
17
|
function venvBin(home) {
|
|
16
18
|
return process.platform === 'win32'
|
|
@@ -43,9 +45,11 @@ function placeholderPage() {
|
|
|
43
45
|
</html>`;
|
|
44
46
|
}
|
|
45
47
|
|
|
46
|
-
|
|
48
|
+
let uiServer = null;
|
|
49
|
+
|
|
50
|
+
function createUiServer() {
|
|
47
51
|
const distDir = join(PKG_ROOT, 'frontend', 'dist');
|
|
48
|
-
|
|
52
|
+
return createServer((req, res) => {
|
|
49
53
|
const url = req.url.split('?')[0];
|
|
50
54
|
const filePath = join(distDir, url === '/' ? 'index.html' : url.slice(1));
|
|
51
55
|
if (!existsSync(filePath)) {
|
|
@@ -56,16 +60,30 @@ function serveUi(onReady) {
|
|
|
56
60
|
res.writeHead(200, { 'Content-Type': MIME[extname(filePath)] || 'application/octet-stream' });
|
|
57
61
|
res.end(readFileSync(filePath));
|
|
58
62
|
});
|
|
59
|
-
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function listenUi(port, attempt) {
|
|
66
|
+
if (attempt > UI_PORT_MAX_TRIES) {
|
|
67
|
+
console.error(`Nenhuma porta livre entre ${UI_PORT_BASE} e ${UI_PORT_BASE + UI_PORT_MAX_TRIES - 1}.`);
|
|
68
|
+
console.error('Encerre algum processo que as ocupe ou defina PANDANEWS_UI_PORT.');
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
const server = createUiServer();
|
|
72
|
+
server.once('error', (err) => {
|
|
60
73
|
if (err && err.code === 'EADDRINUSE') {
|
|
61
|
-
console.
|
|
74
|
+
console.log(`Porta ${port} ocupada — tentando ${port + 1}...`);
|
|
75
|
+
listenUi(port + 1, attempt + 1);
|
|
62
76
|
} else {
|
|
63
77
|
console.error(`Erro no servidor de UI: ${err && err.message}`);
|
|
78
|
+
process.exit(1);
|
|
64
79
|
}
|
|
65
|
-
process.exit(1);
|
|
66
80
|
});
|
|
67
|
-
server.listen(
|
|
68
|
-
|
|
81
|
+
server.listen(port, '127.0.0.1', () => {
|
|
82
|
+
uiServer = server;
|
|
83
|
+
console.log(`PandaNews ativo em http://127.0.0.1:${port}`);
|
|
84
|
+
console.log('Pressione Ctrl+C para encerrar.');
|
|
85
|
+
openBrowser(`http://127.0.0.1:${port}`);
|
|
86
|
+
});
|
|
69
87
|
}
|
|
70
88
|
|
|
71
89
|
async function openBrowser(url) {
|
|
@@ -103,14 +121,10 @@ export async function runStart() {
|
|
|
103
121
|
}
|
|
104
122
|
});
|
|
105
123
|
|
|
106
|
-
|
|
107
|
-
console.log(`PandaNews ativo em http://127.0.0.1:${UI_PORT}`);
|
|
108
|
-
console.log('Pressione Ctrl+C para encerrar.');
|
|
109
|
-
openBrowser(`http://127.0.0.1:${UI_PORT}`);
|
|
110
|
-
});
|
|
124
|
+
listenUi(UI_PORT_BASE, 1);
|
|
111
125
|
|
|
112
126
|
process.on('exit', () => {
|
|
113
|
-
|
|
127
|
+
if (uiServer) uiServer.close();
|
|
114
128
|
uvicorn.kill();
|
|
115
129
|
});
|
|
116
130
|
process.on('SIGINT', () => process.exit(0));
|