create-athenea-app 1.0.3 → 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/bin/index.js +8 -0
- package/package.json +5 -5
- package/template/AGENTS.md +23 -0
- package/template/README.md +2 -2
- package/template/gitignore +42 -0
- package/template/package.json +4 -4
- package/template/src/main/index.js +32 -2
- package/template/src/renderer/index.html +5 -1
- package/template/src/renderer/src/app.jsx +10 -10
- package/template/src/renderer/src/components/Counter/Counter.jsx +10 -10
- package/template/src/renderer/src/main.jsx +4 -4
- package/template/src/renderer/src/routes/Home/Home.jsx +13 -9
package/bin/index.js
CHANGED
|
@@ -266,6 +266,14 @@ async function main() {
|
|
|
266
266
|
await fsp.mkdir(targetDir, { recursive: true });
|
|
267
267
|
await fsp.cp(templateDir, targetDir, { recursive: true });
|
|
268
268
|
|
|
269
|
+
// npm elimina archivos ".gitignore" al publicar el paquete, por eso el
|
|
270
|
+
// template lo distribuye como "gitignore" (sin punto) y lo renombramos aca.
|
|
271
|
+
const gitignoreSrc = path.join(targetDir, "gitignore");
|
|
272
|
+
const gitignoreDest = path.join(targetDir, ".gitignore");
|
|
273
|
+
if (fs.existsSync(gitignoreSrc)) {
|
|
274
|
+
await fsp.rename(gitignoreSrc, gitignoreDest);
|
|
275
|
+
}
|
|
276
|
+
|
|
269
277
|
await updateAppPackageJson(targetDir, { npmName, productName, appId });
|
|
270
278
|
|
|
271
279
|
const tokenMap = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-athenea-app",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "CLI para scaffoldear apps de escritorio con Electron + Preact + Vite (DX rapida: dev server, hot reload, build y empaquetado)",
|
|
6
6
|
"keywords": [
|
|
@@ -13,16 +13,16 @@
|
|
|
13
13
|
"vite",
|
|
14
14
|
"desktop"
|
|
15
15
|
],
|
|
16
|
-
"homepage": "https://github.com/
|
|
16
|
+
"homepage": "https://github.com/ignadev/Athenea-Desktop#readme",
|
|
17
17
|
"repository": {
|
|
18
18
|
"type": "git",
|
|
19
|
-
"url": "git+https://github.com/
|
|
19
|
+
"url": "git+https://github.com/ignadev/Athenea-Desktop.git",
|
|
20
20
|
"directory": "create-athenea-app"
|
|
21
21
|
},
|
|
22
22
|
"bugs": {
|
|
23
|
-
"url": "https://github.com/
|
|
23
|
+
"url": "https://github.com/ignadev/Athenea-Desktop/issues"
|
|
24
24
|
},
|
|
25
|
-
"author": "
|
|
25
|
+
"author": "Ignacio Basilio (Ignadev)",
|
|
26
26
|
"bin": {
|
|
27
27
|
"create-athenea-app": "bin/index.js"
|
|
28
28
|
},
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# AGENTS - create-athenea-app/template/
|
|
2
|
+
|
|
3
|
+
## Alcance
|
|
4
|
+
|
|
5
|
+
- Aplica solo a `create-athenea-app/template/**`.
|
|
6
|
+
|
|
7
|
+
## Reglas especificas
|
|
8
|
+
|
|
9
|
+
- Esta carpeta es un proyecto generado para usuarios finales: mantenerla autocontenida y ejecutable tras scaffolding.
|
|
10
|
+
- Si se cambian rutas, nombres de archivos o placeholders, actualizar `create-athenea-app/bin/index.js` en la misma tarea.
|
|
11
|
+
- Mantener paridad funcional minima entre template y app de referencia (entrypoints electron-vite y estructura `src/main`, `src/preload`, `src/renderer`).
|
|
12
|
+
- No agregar archivos generados (`out/`, `release/`, `node_modules/`) dentro del template.
|
|
13
|
+
|
|
14
|
+
## Auto-invocacion de skills
|
|
15
|
+
|
|
16
|
+
- Invocar `skills/create-athenea-template-sync/SKILL.md` al tocar cualquier archivo del template.
|
|
17
|
+
- Si se modifica IPC en template, usar tambien `skills/electron-ipc-contract/SKILL.md`.
|
|
18
|
+
|
|
19
|
+
## Checklist obligatorio
|
|
20
|
+
|
|
21
|
+
- [ ] Verificar que el template siga resolviendo `src/main/index.js`, `src/preload/index.js` y `src/renderer/index.html`.
|
|
22
|
+
- [ ] Verificar que los placeholders esperados por el CLI sigan presentes donde corresponda.
|
|
23
|
+
- [ ] Validar scaffolding con `node create-athenea-app/bin/index.js demo --no-install` en carpeta temporal.
|
package/template/README.md
CHANGED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Logs
|
|
2
|
+
logs
|
|
3
|
+
*.log
|
|
4
|
+
npm-debug.log*
|
|
5
|
+
yarn-debug.log*
|
|
6
|
+
yarn-error.log*
|
|
7
|
+
pnpm-debug.log*
|
|
8
|
+
lerna-debug.log*
|
|
9
|
+
|
|
10
|
+
# npm and package manager caches
|
|
11
|
+
.npm/
|
|
12
|
+
.pnpm-store/
|
|
13
|
+
|
|
14
|
+
# Build artifacts
|
|
15
|
+
out/
|
|
16
|
+
release/
|
|
17
|
+
dist/
|
|
18
|
+
dist-ssr/
|
|
19
|
+
|
|
20
|
+
# Tooling caches
|
|
21
|
+
.vite/
|
|
22
|
+
.cache/
|
|
23
|
+
.eslintcache
|
|
24
|
+
coverage/
|
|
25
|
+
*.tsbuildinfo
|
|
26
|
+
|
|
27
|
+
node_modules/
|
|
28
|
+
*.local
|
|
29
|
+
|
|
30
|
+
# Environment variables
|
|
31
|
+
.env
|
|
32
|
+
|
|
33
|
+
# Editor directories and files
|
|
34
|
+
.vscode/*
|
|
35
|
+
!.vscode/extensions.json
|
|
36
|
+
.idea
|
|
37
|
+
.DS_Store
|
|
38
|
+
*.suo
|
|
39
|
+
*.ntvs*
|
|
40
|
+
*.njsproj
|
|
41
|
+
*.sln
|
|
42
|
+
*.sw?
|
package/template/package.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"type": "module",
|
|
8
8
|
"main": "./out/main/index.js",
|
|
9
9
|
"engines": {
|
|
10
|
-
"node": ">=22.
|
|
10
|
+
"node": ">=22.12.0"
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
13
|
"dev": "electron-vite dev",
|
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@preact/preset-vite": "^2.10.1",
|
|
28
|
-
"electron": "^
|
|
29
|
-
"electron-builder": "^26.
|
|
28
|
+
"electron": "^43.1.0",
|
|
29
|
+
"electron-builder": "^26.15.6",
|
|
30
30
|
"electron-vite": "^5.0.0",
|
|
31
|
-
"vite": "^7.
|
|
31
|
+
"vite": "^7.3.6"
|
|
32
32
|
},
|
|
33
33
|
"build": {
|
|
34
34
|
"appId": "com.example.app",
|
|
@@ -12,6 +12,31 @@ const childWindowsByRoute = new Map();
|
|
|
12
12
|
|
|
13
13
|
const settingsPath = path.join(app.getPath("userData"), "settings.json");
|
|
14
14
|
|
|
15
|
+
/** Origen permitido para navegación (dev server o file:// en producción). */
|
|
16
|
+
function isNavigationAllowed(targetUrl) {
|
|
17
|
+
try {
|
|
18
|
+
const target = new URL(targetUrl);
|
|
19
|
+
if (process.env.ELECTRON_RENDERER_URL) {
|
|
20
|
+
const devOrigin = new URL(process.env.ELECTRON_RENDERER_URL).origin;
|
|
21
|
+
return target.origin === devOrigin;
|
|
22
|
+
}
|
|
23
|
+
return target.protocol === "file:";
|
|
24
|
+
} catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Bloquea apertura de ventanas nuevas y navegación fuera del origen propio. */
|
|
30
|
+
function hardenWebContents(webContents) {
|
|
31
|
+
webContents.setWindowOpenHandler(() => ({ action: "deny" }));
|
|
32
|
+
|
|
33
|
+
webContents.on("will-navigate", (event, targetUrl) => {
|
|
34
|
+
if (!isNavigationAllowed(targetUrl)) {
|
|
35
|
+
event.preventDefault();
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
15
40
|
function createWindow() {
|
|
16
41
|
const { width: screenWidth, height: screenHeight } =
|
|
17
42
|
screen.getPrimaryDisplay().workAreaSize;
|
|
@@ -22,7 +47,7 @@ function createWindow() {
|
|
|
22
47
|
title: __APP_TITLE_JSON__,
|
|
23
48
|
webPreferences: {
|
|
24
49
|
preload: join(__dirname, "../preload/index.mjs"),
|
|
25
|
-
sandbox:
|
|
50
|
+
sandbox: true,
|
|
26
51
|
contextIsolation: true,
|
|
27
52
|
nodeIntegration: false,
|
|
28
53
|
},
|
|
@@ -32,6 +57,8 @@ function createWindow() {
|
|
|
32
57
|
mainWindow.setAutoHideMenuBar(true);
|
|
33
58
|
mainWindow.maximize();
|
|
34
59
|
|
|
60
|
+
hardenWebContents(mainWindow.webContents);
|
|
61
|
+
|
|
35
62
|
// electron-vite: usa ELECTRON_RENDERER_URL en dev
|
|
36
63
|
if (process.env.ELECTRON_RENDERER_URL) {
|
|
37
64
|
mainWindow.loadURL(process.env.ELECTRON_RENDERER_URL);
|
|
@@ -121,7 +148,7 @@ ipcMain.on("window:openRoute", (_event, options) => {
|
|
|
121
148
|
title: title || __APP_TITLE_JSON__,
|
|
122
149
|
webPreferences: {
|
|
123
150
|
preload: join(__dirname, "../preload/index.mjs"),
|
|
124
|
-
sandbox:
|
|
151
|
+
sandbox: true,
|
|
125
152
|
contextIsolation: true,
|
|
126
153
|
nodeIntegration: false,
|
|
127
154
|
},
|
|
@@ -129,6 +156,9 @@ ipcMain.on("window:openRoute", (_event, options) => {
|
|
|
129
156
|
|
|
130
157
|
child.setMenuBarVisibility(false);
|
|
131
158
|
child.setAutoHideMenuBar(true);
|
|
159
|
+
|
|
160
|
+
hardenWebContents(child.webContents);
|
|
161
|
+
|
|
132
162
|
if (mainWindow && !mainWindow.isDestroyed()) {
|
|
133
163
|
child.setParentWindow(mainWindow);
|
|
134
164
|
}
|
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
|
-
<
|
|
5
|
+
<meta
|
|
6
|
+
http-equiv="Content-Security-Policy"
|
|
7
|
+
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self' ws: wss:;"
|
|
8
|
+
/>
|
|
9
|
+
<link rel="icon" type="image/png" href="/logo.png" />
|
|
6
10
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
11
|
<title>__APP_TITLE__</title>
|
|
8
12
|
</head>
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { LocationProvider, Router, Route } from
|
|
2
|
-
import Home from
|
|
1
|
+
import { LocationProvider, Router, Route } from 'preact-iso'
|
|
2
|
+
import Home from './routes/Home/Home'
|
|
3
3
|
|
|
4
4
|
export default function App() {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
5
|
+
return (
|
|
6
|
+
<LocationProvider>
|
|
7
|
+
<Router>
|
|
8
|
+
<Route path="/" component={Home} />
|
|
9
|
+
<Route default component={Home} />
|
|
10
|
+
</Router>
|
|
11
|
+
</LocationProvider>
|
|
12
|
+
)
|
|
13
13
|
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { useState } from
|
|
2
|
-
import
|
|
1
|
+
import { useState } from 'preact/hooks'
|
|
2
|
+
import './style.css'
|
|
3
3
|
|
|
4
4
|
export function Counter() {
|
|
5
|
-
|
|
5
|
+
const [count, setCount] = useState(0)
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
return (
|
|
8
|
+
<div class="counter">
|
|
9
|
+
<button onClick={() => setCount(count - 1)}>-</button>
|
|
10
|
+
<p>{count}</p>
|
|
11
|
+
<button onClick={() => setCount(count + 1)}>+</button>
|
|
12
|
+
</div>
|
|
13
|
+
)
|
|
14
14
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { render } from
|
|
2
|
-
import App from
|
|
3
|
-
import
|
|
1
|
+
import { render } from 'preact'
|
|
2
|
+
import App from './app.jsx'
|
|
3
|
+
import './index.css'
|
|
4
4
|
|
|
5
|
-
render(<App />, document.getElementById(
|
|
5
|
+
render(<App />, document.getElementById('app'))
|
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
import { Counter } from
|
|
1
|
+
import { Counter } from '../../components/Counter/Counter'
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import './style.css'
|
|
4
4
|
|
|
5
5
|
export default function Home() {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
return (
|
|
7
|
+
<div className="home">
|
|
8
|
+
<h1 className="home-title">¡Bienvenido a __APP_TITLE__!</h1>
|
|
9
|
+
<img
|
|
10
|
+
className="home-logo"
|
|
11
|
+
src={`${import.meta.env.BASE_URL}logo.png`}
|
|
12
|
+
alt=""
|
|
13
|
+
/>
|
|
14
|
+
<Counter />
|
|
15
|
+
</div>
|
|
16
|
+
)
|
|
13
17
|
}
|