magicserve 1.2.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.
Files changed (4) hide show
  1. package/README.es.md +123 -0
  2. package/README.md +122 -0
  3. package/package.json +30 -0
  4. package/run.sh +473 -0
package/README.es.md ADDED
@@ -0,0 +1,123 @@
1
+ # Magicserve 🪄
2
+
3
+ *[Read in English](README.md)*
4
+
5
+ Magicserve es una herramienta CLI para gestionar entornos de desarrollo web locales. Su objetivo es iniciar, detener y manejar el estado de múltiples servidores locales (`node` y `php`) al mismo tiempo, y automáticamente levantar un Reverse Proxy (Nginx) y generar certificados SSL vía `mkcert` para asignarle un dominio dinámico (ej. `tu-proyecto.test`).
6
+
7
+ ## Requisitos
8
+
9
+ Antes de utilizar `magicserve`, es necesario tener instalado en la computadora de desarrollo:
10
+ - [Node.js y npm](https://nodejs.org/)
11
+ - [jq](https://jqlang.github.io/jq/) (`brew install jq`)
12
+ - [mkcert](https://github.com/FiloSottile/mkcert) (`brew install mkcert`)
13
+ - Nginx (`brew install nginx`)
14
+ - PHP (si tu proyecto requiere servicios backend en php)
15
+
16
+ ## Instalación global
17
+
18
+ Si tienes los requisitos instalados, puedes instalar la utilidad de manera global usando npm:
19
+
20
+ ```bash
21
+ npm install -g davidlomas/magicserve
22
+ ```
23
+
24
+ > **Nota:** También puedes publicarlo en npm publico y usar `npm install -g magicserve` directamente.
25
+
26
+ ## Actualización
27
+
28
+ Si ya tienes `magicserve` instalado y quieres actualizarlo a la última versión, ejecuta el mismo comando de instalación:
29
+
30
+ ```bash
31
+ npm install -g davidlomas/magicserve
32
+ ```
33
+
34
+ Esto sobreescribirá la versión anterior con la más reciente directamente desde GitHub. Tus archivos `magicserve.json` en tus proyectos **no se verán afectados**.
35
+
36
+ > 💡 Puedes verificar la versión instalada ejecutando cualquier comando de `magicserve`, aparecerá al inicio.
37
+
38
+ ## ¿Cómo se usa?
39
+
40
+ Una vez instalado de manera global, dirígete a cualquier carpeta en tu computadora que servirá como "nodo central" o "espacio de trabajo" de tus proyectos, y ejecuta:
41
+
42
+ ```bash
43
+ magicserve init
44
+ ```
45
+
46
+ Este comando creará automáticamente un archivo base llamado **`magicserve.json`** en el directorio actual.
47
+
48
+ ### Archivo de configuración: `magicserve.json`
49
+
50
+ Tu directorio central gestiona y levanta las aplicaciones referenciadas dentro del **`magicserve.json`**. Su estructura es así de sencilla:
51
+
52
+ ```json
53
+ [
54
+ {
55
+ "path": "../tu-proyecto-frontal",
56
+ "domain": "tu-proyecto.test",
57
+ "type": "node",
58
+ "port": 3000
59
+ },
60
+ {
61
+ "path": "../tu-api-backend",
62
+ "domain": "api.tu-proyecto.test",
63
+ "type": "php",
64
+ "port": 3001,
65
+ "tunnel": "mi-super-api-dev"
66
+ }
67
+ ]
68
+ ```
69
+
70
+ **Propiedades:**
71
+ - **`path`**: Ruta relativa o absoluta hacia el directorio del proyecto donde se deberá correr el servidor.
72
+ - **`domain`**: El dominio de desarrollo local que se enlazará automáticamente (eg. `*.test`).
73
+ - **`type`**: `node` (Correrá usando `npm run dev`) o `php` (Correrá el built-in server usando `php -S`).
74
+ - **`port`**: El puerto interno que el servicio ocupará.
75
+ - **`tunnel`**: *(Opcional)* Subdominio para enlazar puerto interno y exponerlo a internet público a través de `localtunnel` (Ej. webhooks de Mercado Libre o pruebas móviles).
76
+
77
+ Una vez configurado o modificado a tu gusto, utiliza los comandos de control.
78
+
79
+ ## Comandos disponibles
80
+
81
+ ## Arquitectura: ¿Cómo funciona bajo la manga?
82
+
83
+ Magicserve orquesta en segundos varias herramientas subyacentes para que tú solo te preocupes por el código de tu proyecto.
84
+
85
+ ```mermaid
86
+ flowchart TD
87
+ Dev([👨‍💻 Desarrollador])
88
+ World([🌐 Webhooks Externos])
89
+
90
+ subgraph Tu Computadora Local
91
+ Nginx(Nginx Proxy Inverso SSL)
92
+ LT(LocalTunnel Túnel Reverso)
93
+ Node((Servidor Node\nEj. 3000))
94
+ PHP((Servidor PHP\nEj. 3001))
95
+ end
96
+
97
+ Dev -- "https://tu-proyecto.test" --> Nginx
98
+ World -- "https://mi-api.loca.lt" --> LT
99
+
100
+ Nginx -- "localhost:3000" --> Node
101
+ Nginx -- "localhost:3001" --> PHP
102
+ LT -- "Túnel" --> PHP
103
+ ```
104
+
105
+
106
+ Dentro del directorio donde está tu `magicserve.json`, dispones de los siguientes comandos mágicos:
107
+
108
+ - **`magicserve start`**: Inicia todos los servicios del `magicserve.json` en los puertos definidos, genera certificados SSL dinámicos de ser necesario y configura Nginx.
109
+ - **`magicserve stop`**: Detiene ordenadamente los servicios activos mencionados de tu `magicserve.json`.
110
+ - **`magicserve status`**: Te muestra en terminal cuáles de tus proyectos están activos actualmente y cuál es su PID.
111
+ - **`magicserve stopall`**: Comando de emergencia. Busca y destruye TODOS los demonios, configuraciones temporales nginx relacionadas, certificados, puertos y purga todas las entradas de localhost customizadas en todo el sistema, restaurando tu computadora.
112
+
113
+ ---
114
+
115
+ ### Novedades en v1.2.0 🚇
116
+
117
+ - **Localtunnel Integrado**: Expón de forma permanente y automática puertos de tu API al internet vía la nueva propiedad `tunnel` en el config json para recibir **Webhooks** de terceros (Mercado Libre, Stripe, etc).
118
+
119
+ ### Novedades en v1.1.0 🚀
120
+
121
+ - **Visualización de Versión**: Ahora puedes ver la versión de Magicserve directamente en la terminal al ejecutar cualquier comando.
122
+ - **Soporte para Archivos Grandes**: Nginx y PHP se configuran automáticamente para soportar payloads de hasta **100MB** (uploads y JSON), solucionando el error "413 Request Entity Too Large".
123
+ - **SSL Automático**: Soporte nativo para HTTPS vía `mkcert`.
package/README.md ADDED
@@ -0,0 +1,122 @@
1
+ # Magicserve 🪄
2
+
3
+ *[Leer en Español](README.es.md)*
4
+
5
+ Magicserve is a CLI tool for managing local web development environments. Its goal is to start, stop, and manage the state of multiple local servers (`node` and `php`) simultaneously, automatically set up a Reverse Proxy (Nginx), and generate SSL certificates via `mkcert` to assign them a dynamic local domain (e.g. `your-project.test`).
6
+
7
+ ## Requirements
8
+
9
+ Before using `magicserve`, you must have the following installed on your development machine:
10
+ - [Node.js and npm](https://nodejs.org/)
11
+ - [jq](https://jqlang.github.io/jq/) (`brew install jq`)
12
+ - [mkcert](https://github.com/FiloSottile/mkcert) (`brew install mkcert`)
13
+ - Nginx (`brew install nginx`)
14
+ - PHP (if your project requires a PHP backend service)
15
+
16
+ ## Global Installation
17
+
18
+ If you have the requirements installed, you can globally install the utility using npm directly from GitHub:
19
+
20
+ ```bash
21
+ npm install -g davidlomas/magicserve
22
+ ```
23
+
24
+ > **Note:** You can also publish it to the public npm registry and use `npm install -g magicserve`.
25
+
26
+ ## Updating
27
+
28
+ If you already have `magicserve` installed and want to update to the latest version, simply run the same install command again:
29
+
30
+ ```bash
31
+ npm install -g davidlomas/magicserve
32
+ ```
33
+
34
+ This will overwrite the previous version with the latest one directly from GitHub. Your `magicserve.json` files in your projects **will not be affected**.
35
+
36
+ > 💡 You can verify the installed version by running any `magicserve` command — it will be displayed at the top.
37
+
38
+ ## How to Use
39
+
40
+ Once installed globally, navigate to any folder on your computer that will serve as a "central hub" or "workspace" for your projects, and run:
41
+
42
+ ```bash
43
+ magicserve init
44
+ ```
45
+
46
+ This command will automatically create a base **`magicserve.json`** file in the current directory.
47
+
48
+ ### Configuration File: `magicserve.json`
49
+
50
+ Your central directory manages and starts the applications referenced within the **`magicserve.json`**. Its structure is this simple:
51
+
52
+ ```json
53
+ [
54
+ {
55
+ "path": "../your-frontend-project",
56
+ "domain": "your-project.test",
57
+ "type": "node",
58
+ "port": 3000
59
+ },
60
+ {
61
+ "path": "../your-backend-api",
62
+ "domain": "api.your-project.test",
63
+ "type": "php",
64
+ "port": 3001,
65
+ "tunnel": "my-cool-api-dev"
66
+ }
67
+ ]
68
+ ```
69
+
70
+ **Properties:**
71
+ - **`path`**: Relative or absolute path to the project's directory where the server should run.
72
+ - **`domain`**: The local development domain that will be automatically mapped (e.g. `*.test`).
73
+ - **`type`**: `node` (Runs using `npm run dev`) or `php` (Runs the PHP built-in server using `php -S`).
74
+ - **`port`**: The internal port the service will use.
75
+ - **`tunnel`**: *(Optional)* Subdomain to securely expose your internal port to the public internet via `localtunnel` (Great for testing third-party Webhooks like Mercado Libre or local mobile testing).
76
+
77
+ Once configured or modified to your liking, you can use the control commands.
78
+
79
+ ## Available Commands
80
+
81
+ ## Architecture: How it works under the hood
82
+
83
+ Magicserve instantly orchestrates multiple local tools so you don't have to manage them manually.
84
+
85
+ ```mermaid
86
+ flowchart TD
87
+ Dev([👨‍💻 Developer])
88
+ World([🌐 External Webhooks / Web])
89
+
90
+ subgraph Your Local Machine
91
+ Nginx(Nginx Reverse Proxy with HTTPS)
92
+ LT(LocalTunnel Reverse Tunnel)
93
+ Node((Node Server\ne.g. 3000))
94
+ PHP((PHP Server\ne.g. 3001))
95
+ end
96
+
97
+ Dev -- "https://your-project.test" --> Nginx
98
+ World -- "https://my-api.loca.lt" --> LT
99
+
100
+ Nginx -- "localhost:3000" --> Node
101
+ Nginx -- "localhost:3001" --> PHP
102
+ LT -- "Tunnel" --> PHP
103
+ ```
104
+
105
+ Within the directory where your `magicserve.json` is located, you have the following magic commands available:
106
+
107
+ - **`magicserve start`**: Starts all services declared in `magicserve.json` on the defined ports, generates dynamic SSL certificates if necessary, and configures Nginx.
108
+ - **`magicserve stop`**: Orderly stops the active services mentioned in your `magicserve.json`.
109
+ - **`magicserve status`**: Shows a terminal output of which projects are currently active and their PIDs.
110
+ - **`magicserve stopall`**: Emergency command. Finds and destroys ALL active daemons, related Nginx configurations, certificates, processes, and purges all custom localhost entries system-wide, restoring your computer's clean state.
111
+
112
+ ---
113
+
114
+ ### Features in v1.2.0 🚇
115
+
116
+ - **Integrated Localtunnel**: Permanently and automatically expose any of your API ports to the internet via the new `tunnel` property in config JSON to seamlessly receive third-party **Webhooks** (Mercado Libre, Stripe, etc).
117
+
118
+ ### Features in v1.1.0 🚀
119
+
120
+ - **Version Display**: Now you can see the Magicserve version directly in the terminal.
121
+ - **Large Body Support**: Nginx and PHP are automatically configured to support up to **100MB** payloads (JSON and file uploads), fixing the "413 Request Entity Too Large" error.
122
+ - **Automatic SSL**: Native support for HTTPS via `mkcert`.
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "magicserve",
3
+ "version": "1.2.0",
4
+ "description": "Script to run local environments via magicserve.json",
5
+ "files": [
6
+ "run.sh"
7
+ ],
8
+ "bin": {
9
+ "magicserve": "./run.sh"
10
+ },
11
+ "scripts": {
12
+ "test": "echo \"Error: no test specified\" && exit 1"
13
+ },
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/davidlomas/magicserve.git"
17
+ },
18
+ "keywords": [
19
+ "local",
20
+ "run",
21
+ "env",
22
+ "magicompras"
23
+ ],
24
+ "author": "",
25
+ "license": "ISC",
26
+ "bugs": {
27
+ "url": "https://github.com/davidlomas/magicserve/issues"
28
+ },
29
+ "homepage": "https://github.com/davidlomas/magicserve#readme"
30
+ }
package/run.sh ADDED
@@ -0,0 +1,473 @@
1
+ #!/bin/bash
2
+
3
+ # run.sh
4
+
5
+ # El directorio de trabajo actual (donde se ejecuta el comando)
6
+ SCRIPT_DIR="$(pwd)"
7
+ CONFIG_FILE="$SCRIPT_DIR/magicserve.json"
8
+
9
+ # El directorio donde reside el script (para leer package.json)
10
+ REAL_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
+ VERSION=$(jq -r '.version' "$REAL_SCRIPT_DIR/package.json" 2>/dev/null || echo "1.1.0")
12
+
13
+ MAGICSERVE_DIR="$SCRIPT_DIR/.magicserve"
14
+ LOGS_DIR="$MAGICSERVE_DIR/logs"
15
+ PIDS_DIR="$MAGICSERVE_DIR/pids"
16
+
17
+ # Asegurar que los directorios internos existen
18
+ mkdir -p "$LOGS_DIR" "$PIDS_DIR"
19
+
20
+ echo "🪄 Magicserve v$VERSION"
21
+ echo ""
22
+
23
+ if [ "$1" != "stopall" ] && [ "$1" != "init" ] && [ ! -f "$CONFIG_FILE" ]; then
24
+ echo "❌ Error: magicserve.json no encontrado en el directorio actual."
25
+ echo "💡 Truco: Ejecuta 'magicserve init' para generar un template base."
26
+ exit 1
27
+ fi
28
+
29
+ if ! command -v jq &> /dev/null; then
30
+ echo "❌ jq no instalado → brew install jq"
31
+ exit 1
32
+ fi
33
+
34
+ ACTION=$1
35
+
36
+ usage() {
37
+ echo "Uso:"
38
+ echo " magicserve [start|stop|stopall|status|init]"
39
+ echo ""
40
+ echo " init - Crea un archivo magicserve.json de plantilla en la carpeta actual"
41
+ echo " start - Inicia todos los servicios del magicserve.json"
42
+ echo " stop - Detiene los servicios del magicserve.json"
43
+ echo " stopall - Busca y detiene TODOS los dominios (sin depender de magicserve.json) y borra todo rastro"
44
+ echo " status - Muestra el estado de los servicios"
45
+ exit 1
46
+ }
47
+
48
+ start_server() {
49
+ local PATH_DIR=$1
50
+ local DOMAIN=$2
51
+ local TYPE=$3
52
+ local PORT=$4
53
+
54
+ local PID_FILE="$PIDS_DIR/${DOMAIN}.pid"
55
+
56
+ echo "🚀 Iniciando $DOMAIN ($TYPE) en puerto $PORT..."
57
+
58
+ # Navegar al directorio del proyecto relativo al script
59
+ cd "$SCRIPT_DIR/$PATH_DIR" || {
60
+ echo "❌ Error: Directorio $PATH_DIR no encontrado para $DOMAIN"
61
+ return
62
+ }
63
+
64
+ if [ "$TYPE" == "node" ]; then
65
+ nohup npm run dev -- --port $PORT > "$LOGS_DIR/${DOMAIN}.log" 2>&1 &
66
+ local PID=$!
67
+ echo $PID > "$PID_FILE"
68
+ echo "✅ Node corriendo (PID: $PID)"
69
+ elif [ "$TYPE" == "php" ]; then
70
+ # El docroot por defecto para php es el directorio actual
71
+ nohup php -d upload_max_filesize=100M -d post_max_size=100M -S "localhost:$PORT" -t . > "$LOGS_DIR/${DOMAIN}.log" 2>&1 &
72
+ local PID=$!
73
+ echo $PID > "$PID_FILE"
74
+ echo "✅ PHP corriendo (PID: $PID)"
75
+ else
76
+ echo "❌ Tipo $TYPE no soportado (usa 'node' o 'php')"
77
+ fi
78
+ }
79
+
80
+ start_proxy() {
81
+ local DOMAIN=$1
82
+ local PORT=$2
83
+
84
+ echo "🔐 Configurando SSL y Proxy Nginx para $DOMAIN -> $PORT..."
85
+
86
+ local HOSTS_FILE="/etc/hosts"
87
+ local NGINX_SERVER_DIR="/opt/homebrew/etc/nginx/servers"
88
+ local NGINX_CONF="$NGINX_SERVER_DIR/${DOMAIN}.conf"
89
+ local CERT_DIR="$HOME/.ssl"
90
+ local CERT="$CERT_DIR/$DOMAIN.pem"
91
+ local KEY="$CERT_DIR/$DOMAIN-key.pem"
92
+
93
+ # Validar si mkcert y nginx están instalados
94
+ if ! command -v mkcert &> /dev/null; then
95
+ echo "❌ mkcert no instalado → brew install mkcert"
96
+ exit 1
97
+ fi
98
+ if ! command -v nginx &> /dev/null; then
99
+ echo "❌ nginx no instalado → brew install nginx"
100
+ exit 1
101
+ fi
102
+
103
+ # Generar carpeta de certificados si no existe
104
+ mkdir -p "$CERT_DIR" "$NGINX_SERVER_DIR"
105
+ sudo chown -R $(whoami) "$CERT_DIR"
106
+
107
+ # Instalar mkcert CA si no lo está (suave)
108
+ mkcert -install > /dev/null 2>&1
109
+
110
+ # Generar los certificados para el dominio si no existen
111
+ if [ ! -f "$CERT" ] || [ ! -f "$KEY" ]; then
112
+ echo "🆕 Generando certificado SSL para $DOMAIN..."
113
+ mkcert -cert-file "$CERT" -key-file "$KEY" "$DOMAIN"
114
+ fi
115
+
116
+ # Limpiar en /etc/hosts el dominio y volver a añadirlo
117
+ sudo sed -i '' "/[[:space:]]$DOMAIN$/d" "$HOSTS_FILE"
118
+ echo "127.0.0.1 $DOMAIN" | sudo tee -a "$HOSTS_FILE" > /dev/null
119
+
120
+ # Crear configuración de Nginx para el dominio
121
+ sudo tee "$NGINX_CONF" > /dev/null <<EOF
122
+ server {
123
+ listen 443 ssl;
124
+ server_name $DOMAIN;
125
+
126
+ ssl_certificate $CERT;
127
+ ssl_certificate_key $KEY;
128
+
129
+ client_max_body_size 100M;
130
+
131
+ location / {
132
+ proxy_pass http://localhost:$PORT;
133
+ proxy_set_header Host \$host;
134
+ proxy_set_header X-Real-IP \$remote_addr;
135
+ proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
136
+ proxy_set_header X-Forwarded-Proto https;
137
+
138
+ # WebSockets Support (Vite HMR)
139
+ proxy_http_version 1.1;
140
+ proxy_set_header Upgrade \$http_upgrade;
141
+ proxy_set_header Connection "upgrade";
142
+ }
143
+ }
144
+
145
+ server {
146
+ listen 80;
147
+ server_name $DOMAIN;
148
+ return 301 https://\$host\$request_uri;
149
+ }
150
+ EOF
151
+ }
152
+
153
+ start_tunnel() {
154
+ local DOMAIN=$1
155
+ local PORT=$2
156
+ local TUNNEL_SUBDOMAIN=$3
157
+
158
+ echo "🚇 Iniciando túnel para $DOMAIN en puerto $PORT..."
159
+ local TUNNEL_PID_FILE="$PIDS_DIR/${DOMAIN}_tunnel.pid"
160
+
161
+ # Si pasaron false o null, no hacer nada
162
+ if [ "$TUNNEL_SUBDOMAIN" == "false" ] || [ "$TUNNEL_SUBDOMAIN" == "null" ] || [ -z "$TUNNEL_SUBDOMAIN" ]; then
163
+ return
164
+ fi
165
+
166
+ local TUNNEL_LOG="$LOGS_DIR/${DOMAIN}_tunnel.log"
167
+
168
+ if [ "$TUNNEL_SUBDOMAIN" == "true" ]; then
169
+ nohup npx localtunnel --port $PORT > "$TUNNEL_LOG" 2>&1 &
170
+ else
171
+ nohup npx localtunnel --port $PORT --subdomain "$TUNNEL_SUBDOMAIN" > "$TUNNEL_LOG" 2>&1 &
172
+ fi
173
+
174
+ local PID=$!
175
+ echo $PID > "$TUNNEL_PID_FILE"
176
+ echo "✅ Túnel corriendo (PID: $PID)"
177
+ }
178
+
179
+ start_all() {
180
+ echo "🌟 Iniciando todos los servicios desde magicserve.json..."
181
+
182
+ local LENGTH=$(jq '. | length' "$CONFIG_FILE")
183
+ for (( i=0; i<$LENGTH; i++ )); do
184
+ local PATH_DIR=$(jq -r ".[$i].path" "$CONFIG_FILE")
185
+ local DOMAIN=$(jq -r ".[$i].domain" "$CONFIG_FILE")
186
+ local TYPE=$(jq -r ".[$i].type" "$CONFIG_FILE")
187
+ local PORT=$(jq -r ".[$i].port" "$CONFIG_FILE")
188
+ local TUNNEL=$(jq -r ".[$i].tunnel // empty" "$CONFIG_FILE")
189
+
190
+ start_server "$PATH_DIR" "$DOMAIN" "$TYPE" "$PORT"
191
+ start_proxy "$DOMAIN" "$PORT"
192
+
193
+ if [ -n "$TUNNEL" ]; then
194
+ start_tunnel "$DOMAIN" "$PORT" "$TUNNEL"
195
+ fi
196
+ done
197
+
198
+ echo "🔄 Recargando Nginx..."
199
+ if sudo nginx -t > /dev/null 2>&1; then
200
+ sudo nginx -s reload || sudo nginx
201
+ echo "✅ Nginx configurado exitosamente."
202
+ else
203
+ echo "❌ Error en configuración de Nginx. Revisa /opt/homebrew/etc/nginx/servers/"
204
+ fi
205
+ echo "🎉 ¡Todo listo!"
206
+ }
207
+
208
+ stop_all() {
209
+ echo "🛑 Deteniendo todos los servicios..."
210
+
211
+ local HOSTS_FILE="/etc/hosts"
212
+ local NGINX_SERVER_DIR="/opt/homebrew/etc/nginx/servers"
213
+
214
+ local LENGTH=$(jq '. | length' "$CONFIG_FILE")
215
+ for (( i=0; i<$LENGTH; i++ )); do
216
+ local DOMAIN=$(jq -r ".[$i].domain" "$CONFIG_FILE")
217
+ local PID_FILE="$PIDS_DIR/${DOMAIN}.pid"
218
+
219
+ if [ -f "$PID_FILE" ]; then
220
+ local PID=$(cat "$PID_FILE")
221
+ if ps -p $PID > /dev/null; then
222
+ kill $PID
223
+ echo "🛑 Servidor para $DOMAIN detenido (PID: $PID)."
224
+ else
225
+ echo "⚠️ Proceso para $DOMAIN no encontrado (el archivo PID será limpiado)."
226
+ fi
227
+ rm "$PID_FILE"
228
+ fi
229
+
230
+ local TUNNEL_PID_FILE="$PIDS_DIR/${DOMAIN}_tunnel.pid"
231
+ if [ -f "$TUNNEL_PID_FILE" ]; then
232
+ local TPID=$(cat "$TUNNEL_PID_FILE")
233
+ if ps -p $TPID > /dev/null; then
234
+ kill $TPID
235
+ echo "🛑 Túnel para $DOMAIN detenido (PID: $TPID)."
236
+ else
237
+ echo "⚠️ Proceso de túnel para $DOMAIN no encontrado."
238
+ fi
239
+ rm "$TUNNEL_PID_FILE"
240
+ fi
241
+
242
+ # Limpiar de /etc/hosts
243
+ sudo sed -i '' "/[[:space:]]$DOMAIN$/d" "$HOSTS_FILE"
244
+
245
+ # Eliminar configuración de nginx
246
+ local NGINX_CONF="$NGINX_SERVER_DIR/${DOMAIN}.conf"
247
+ if [ -f "$NGINX_CONF" ]; then
248
+ sudo rm "$NGINX_CONF"
249
+ fi
250
+ done
251
+
252
+ # Recargar nginx
253
+ if sudo nginx -t > /dev/null 2>&1; then
254
+ sudo nginx -s reload > /dev/null 2>&1
255
+ fi
256
+
257
+ echo "✅ Todo detenido."
258
+ }
259
+
260
+ status() {
261
+ echo "📊 Estado de los servicios:"
262
+ local LENGTH=$(jq '. | length' "$CONFIG_FILE")
263
+ for (( i=0; i<$LENGTH; i++ )); do
264
+ local DOMAIN=$(jq -r ".[$i].domain" "$CONFIG_FILE")
265
+ local PID_FILE="$PIDS_DIR/${DOMAIN}.pid"
266
+
267
+ if [ -f "$PID_FILE" ]; then
268
+ local PID=$(cat "$PID_FILE")
269
+ if ps -p $PID > /dev/null; then
270
+ echo "🟢 $DOMAIN: Corriendo (PID: $PID)"
271
+ else
272
+ echo "🔴 $DOMAIN: Archivo PID existe pero el proceso no está corriendo"
273
+ fi
274
+ else
275
+ echo "⚪️ $DOMAIN: Detenido"
276
+ fi
277
+
278
+ local TUNNEL_PID_FILE="$PIDS_DIR/${DOMAIN}_tunnel.pid"
279
+ if [ -f "$TUNNEL_PID_FILE" ]; then
280
+ local TPID=$(cat "$TUNNEL_PID_FILE")
281
+ if ps -p $TPID > /dev/null; then
282
+ echo " ↳ 🚇 Túnel expuesto (PID: $TPID)"
283
+ else
284
+ echo " ↳ 🔴 Túnel: Archivo PID existe pero no está corriendo"
285
+ fi
286
+ fi
287
+ done
288
+ }
289
+
290
+ stop_all_global() {
291
+ echo "🔥 STOPALL: Buscando y eliminando TODOS los dominios y rastros de la computadora..."
292
+ echo ""
293
+
294
+ local HOSTS_FILE="/etc/hosts"
295
+ local NGINX_SERVER_DIR="/opt/homebrew/etc/nginx/servers"
296
+ local CERT_DIR="$HOME/.ssl"
297
+ local FOUND_SOMETHING=false
298
+
299
+ # ─── 1. Limpiar archivos .pid locales ───
300
+ echo "🔍 Buscando archivos .pid locales..."
301
+ if [ -d "$PIDS_DIR" ]; then
302
+ for PID_FILE in "$PIDS_DIR"/*.pid; do
303
+ [ -f "$PID_FILE" ] || continue
304
+ FOUND_SOMETHING=true
305
+ local PID=$(cat "$PID_FILE")
306
+ local BASENAME=$(basename "$PID_FILE")
307
+ local DOMAIN_NAME=${BASENAME%.pid}
308
+
309
+ if ps -p $PID > /dev/null 2>&1; then
310
+ kill $PID 2>/dev/null
311
+ echo " 🛑 Proceso detenido: $DOMAIN_NAME (PID: $PID)"
312
+ else
313
+ echo " ⚠️ Proceso ya no existía: $DOMAIN_NAME (PID: $PID)"
314
+ fi
315
+ done
316
+ fi
317
+ if [ "$FOUND_SOMETHING" = false ]; then
318
+ echo " ✅ No se encontraron archivos .pid"
319
+ fi
320
+
321
+ # ─── 2. Matar TODOS los servidores PHP built-in de la computadora ───
322
+ echo ""
323
+ echo "🔍 Buscando servidores PHP built-in (php -S)..."
324
+ local PHP_PIDS=$(pgrep -f "php -S" 2>/dev/null)
325
+ if [ -n "$PHP_PIDS" ]; then
326
+ echo "$PHP_PIDS" | while read PID; do
327
+ local CMD=$(ps -p $PID -o args= 2>/dev/null)
328
+ kill $PID 2>/dev/null
329
+ echo " 🛑 PHP detenido (PID: $PID) → $CMD"
330
+ done
331
+ else
332
+ echo " ✅ No se encontraron servidores PHP"
333
+ fi
334
+
335
+ # ─── 3. Matar TODOS los servidores Node de desarrollo ───
336
+ echo ""
337
+ echo "🔍 Buscando servidores Node de desarrollo (vite, next, nuxt, webpack)..."
338
+ local NODE_PIDS=$(pgrep -f "(vite|next dev|nuxt|webpack-dev-server|node.*dev)" 2>/dev/null)
339
+ if [ -n "$NODE_PIDS" ]; then
340
+ echo "$NODE_PIDS" | while read PID; do
341
+ local CMD=$(ps -p $PID -o args= 2>/dev/null | head -c 120)
342
+ kill $PID 2>/dev/null
343
+ echo " 🛑 Node detenido (PID: $PID) → $CMD"
344
+ done
345
+ else
346
+ echo " ✅ No se encontraron servidores Node de desarrollo"
347
+ fi
348
+
349
+ # ─── 3.5. Matar procesos de localtunnel ───
350
+ echo ""
351
+ echo "🔍 Buscando procesos de localtunnel..."
352
+ local LT_PIDS=$(pgrep -f "localtunnel" 2>/dev/null)
353
+ if [ -n "$LT_PIDS" ]; then
354
+ echo "$LT_PIDS" | while read PID; do
355
+ kill $PID 2>/dev/null
356
+ echo " 🛑 localtunnel detenido (PID: $PID)"
357
+ done
358
+ else
359
+ echo " ✅ No se encontraron procesos de localtunnel"
360
+ fi
361
+
362
+ # ─── 4. Eliminar TODAS las configuraciones de nginx en servers/ ───
363
+ echo ""
364
+ echo "🔍 Buscando configuraciones de Nginx..."
365
+ FOUND_SOMETHING=false
366
+ if [ -d "$NGINX_SERVER_DIR" ]; then
367
+ for CONF_FILE in "$NGINX_SERVER_DIR"/*.conf; do
368
+ [ -f "$CONF_FILE" ] || continue
369
+ FOUND_SOMETHING=true
370
+ local CONF_NAME=$(basename "$CONF_FILE")
371
+ sudo rm -f "$CONF_FILE"
372
+ echo " 🗑️ Eliminado: $CONF_NAME"
373
+ done
374
+ fi
375
+ if [ "$FOUND_SOMETHING" = false ]; then
376
+ echo " ✅ No se encontraron configuraciones de Nginx"
377
+ fi
378
+
379
+ # ─── 5. Limpiar /etc/hosts (TODAS las entradas custom de 127.0.0.1) ───
380
+ echo ""
381
+ echo "🔍 Limpiando /etc/hosts (todas las entradas custom)..."
382
+ # Contar entradas de 127.0.0.1 que NO sean localhost
383
+ local HOSTS_BEFORE=$(grep -c '^127\.0\.0\.1' "$HOSTS_FILE" 2>/dev/null || echo 0)
384
+ # Eliminar todas las líneas 127.0.0.1 que NO sean localhost
385
+ sudo sed -i '' '/^127\.0\.0\.1[[:space:]]\{1,\}localhost$/!{ /^127\.0\.0\.1/d; }' "$HOSTS_FILE"
386
+ local HOSTS_AFTER=$(grep -c '^127\.0\.0\.1' "$HOSTS_FILE" 2>/dev/null || echo 0)
387
+ local REMOVED=$((HOSTS_BEFORE - HOSTS_AFTER))
388
+ if [ $REMOVED -gt 0 ]; then
389
+ echo " 🗑️ Se eliminaron $REMOVED entradas custom de /etc/hosts"
390
+ else
391
+ echo " ✅ No se encontraron entradas custom en /etc/hosts"
392
+ fi
393
+
394
+ # ─── 6. Eliminar TODO el contenido de ~/.ssl/ ───
395
+ echo ""
396
+ echo "🔍 Limpiando $CERT_DIR (todos los archivos)..."
397
+ if [ -d "$CERT_DIR" ] && [ "$(ls -A "$CERT_DIR" 2>/dev/null)" ]; then
398
+ local SSL_COUNT=$(ls -1 "$CERT_DIR" | wc -l | tr -d ' ')
399
+ rm -rf "$CERT_DIR"/*
400
+ echo " 🗑️ Se eliminaron $SSL_COUNT archivos de $CERT_DIR"
401
+ else
402
+ echo " ✅ No se encontraron archivos en $CERT_DIR"
403
+ fi
404
+
405
+ # ─── 7. Eliminar logs ───
406
+ echo ""
407
+ echo "🔍 Limpiando logs..."
408
+ if [ -d "$LOGS_DIR" ] && [ "$(ls -A "$LOGS_DIR" 2>/dev/null)" ]; then
409
+ rm -f "$LOGS_DIR"/*
410
+ echo " 🗑️ Logs eliminados"
411
+ else
412
+ echo " ✅ No se encontraron logs"
413
+ fi
414
+
415
+ # ─── 8. Detener Nginx completamente ───
416
+ echo ""
417
+ echo "🔍 Deteniendo Nginx..."
418
+ if pgrep -x nginx > /dev/null 2>&1; then
419
+ sudo nginx -s stop > /dev/null 2>&1
420
+ echo " 🛑 Nginx detenido"
421
+ else
422
+ echo " ✅ Nginx no estaba corriendo"
423
+ fi
424
+
425
+ echo ""
426
+ echo "🧹 ¡Todo limpio! No queda rastro."
427
+ }
428
+
429
+ init_config() {
430
+ if [ -f "$CONFIG_FILE" ]; then
431
+ echo "⚠️ El archivo magicserve.json ya existe en este directorio."
432
+ exit 1
433
+ fi
434
+ cat <<EOF > "$CONFIG_FILE"
435
+ [
436
+ {
437
+ "path": "../tu-proyecto-frontal",
438
+ "domain": "tu-proyecto.test",
439
+ "type": "node",
440
+ "port": 3000
441
+ },
442
+ {
443
+ "path": "../tu-api-backend",
444
+ "domain": "api.tu-proyecto.test",
445
+ "type": "php",
446
+ "port": 3001,
447
+ "tunnel": "mi-super-api-dev"
448
+ }
449
+ ]
450
+ EOF
451
+ echo "✅ Archivo magicserve.json base generado exitosamente."
452
+ }
453
+
454
+ case "$ACTION" in
455
+ init)
456
+ init_config
457
+ ;;
458
+ start)
459
+ start_all
460
+ ;;
461
+ stop)
462
+ stop_all
463
+ ;;
464
+ stopall)
465
+ stop_all_global
466
+ ;;
467
+ status)
468
+ status
469
+ ;;
470
+ *)
471
+ usage
472
+ ;;
473
+ esac