Fix production web API routing

This commit is contained in:
2026-04-23 14:29:47 -05:00
parent 51074d08c6
commit a96907b684
14 changed files with 45 additions and 21 deletions
+6 -1
View File
@@ -2,10 +2,15 @@
## Versión actual ## Versión actual
- Versión base: `1.2.2` - Versión base: `1.2.3`
## Historial ## Historial
### 1.2.3 - 2026-04-23
- La web fuerza uso de `/api` y `/api/downloads/android-apk` cuando corre en `sign.linkedcorp.net`, evitando compilar enlaces de producción con IPs de desarrollo.
- Se corrigen referencias heredadas del servidor `192.168.222.72` hacia `192.168.222.40` en configuraciones y documentación de desarrollo.
### 1.2.2 - 2026-04-23 ### 1.2.2 - 2026-04-23
- Android vuelve a ofrecer activar huella después del login siempre que el acceso biométrico no esté activo. - Android vuelve a ofrecer activar huella después del login siempre que el acceso biométrico no esté activo.
+1 -1
View File
@@ -1 +1 @@
1.2.2 1.2.3
+1 -1
View File
@@ -58,7 +58,7 @@ android/
Por defecto la app apunta a: Por defecto la app apunta a:
```text ```text
http://192.168.222.72:4000 http://192.168.222.40:4000
``` ```
Ese valor está en: Ese valor está en:
+2 -2
View File
@@ -18,8 +18,8 @@ android {
applicationId "net.linkedcorp.linkedsign" applicationId "net.linkedcorp.linkedsign"
minSdk 26 minSdk 26
targetSdk 35 targetSdk 35
versionCode 10202 versionCode 10203
versionName "1.2.2" versionName "1.2.3"
buildConfigField "String", "API_BASE_URL", "\"${apiBaseUrl}\"" buildConfigField "String", "API_BASE_URL", "\"${apiBaseUrl}\""
} }
+1 -1
View File
@@ -61,7 +61,7 @@ Valor actual:
{ {
"expo": { "expo": {
"extra": { "extra": {
"apiBaseUrl": "http://192.168.222.72:4000" "apiBaseUrl": "http://192.168.222.40:4000"
} }
} }
} }
+1 -1
View File
@@ -16,7 +16,7 @@
"package": "net.linkedcorp.linkedsign" "package": "net.linkedcorp.linkedsign"
}, },
"extra": { "extra": {
"apiBaseUrl": "http://192.168.222.72:4000" "apiBaseUrl": "http://192.168.222.40:4000"
} }
} }
} }
+1 -1
View File
@@ -5,4 +5,4 @@ const extra = Constants.expoConfig?.extra || {};
export const API_BASE_URL = export const API_BASE_URL =
process.env.EXPO_PUBLIC_API_BASE_URL || process.env.EXPO_PUBLIC_API_BASE_URL ||
extra.apiBaseUrl || extra.apiBaseUrl ||
'http://192.168.222.72:4000'; 'http://192.168.222.40:4000';
+7 -7
View File
@@ -33,8 +33,8 @@ Variables importantes:
```env ```env
PORT=4000 PORT=4000
CORS_ORIGIN=http://192.168.222.72:5173 CORS_ORIGIN=http://192.168.222.40:5173
FRONTEND_URL=http://192.168.222.72:5173 FRONTEND_URL=http://192.168.222.40:5173
MAIL_HOST= MAIL_HOST=
MAIL_PORT=587 MAIL_PORT=587
MAIL_SECURE=false MAIL_SECURE=false
@@ -73,7 +73,7 @@ DB_NAME=
Registra usuario y envía correo de validación. Registra usuario y envía correo de validación.
```bash ```bash
curl -X POST http://192.168.222.72:4000/auth/register \ curl -X POST http://192.168.222.40:4000/auth/register \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{ -d '{
"email": "usuario@correo.com", "email": "usuario@correo.com",
@@ -86,7 +86,7 @@ curl -X POST http://192.168.222.72:4000/auth/register \
Inicia sesión. Si el correo no está validado, reenvía el enlace. Inicia sesión. Si el correo no está validado, reenvía el enlace.
```bash ```bash
curl -X POST http://192.168.222.72:4000/auth/login \ curl -X POST http://192.168.222.40:4000/auth/login \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{ -d '{
"email": "usuario@correo.com", "email": "usuario@correo.com",
@@ -117,7 +117,7 @@ Devuelve usuario autenticado y preferencias visuales de firma.
Sube un PDF original. Sube un PDF original.
```bash ```bash
curl -X POST http://192.168.222.72:4000/documents \ curl -X POST http://192.168.222.40:4000/documents \
-H "Authorization: Bearer TU_ACCESS_TOKEN" \ -H "Authorization: Bearer TU_ACCESS_TOKEN" \
-F "file=@/ruta/documento.pdf" -F "file=@/ruta/documento.pdf"
``` ```
@@ -137,7 +137,7 @@ Descarga un documento original.
Sube un certificado `.p12` o `.pfx`. Sube un certificado `.p12` o `.pfx`.
```bash ```bash
curl -X POST http://192.168.222.72:4000/certificates \ curl -X POST http://192.168.222.40:4000/certificates \
-H "Authorization: Bearer TU_ACCESS_TOKEN" \ -H "Authorization: Bearer TU_ACCESS_TOKEN" \
-F "file=@/ruta/certificado.p12" \ -F "file=@/ruta/certificado.p12" \
-F "alias=MPGH 2026" \ -F "alias=MPGH 2026" \
@@ -155,7 +155,7 @@ Lista certificados del usuario, incluyendo datos de cadena embebida.
Firma un documento con un certificado del usuario. Firma un documento con un certificado del usuario.
```bash ```bash
curl -X POST http://192.168.222.72:4000/signatures/sign \ curl -X POST http://192.168.222.40:4000/signatures/sign \
-H "Authorization: Bearer TU_ACCESS_TOKEN" \ -H "Authorization: Bearer TU_ACCESS_TOKEN" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{ -d '{
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "linkedsign-backend", "name": "linkedsign-backend",
"version": "1.2.2", "version": "1.2.3",
"private": true, "private": true,
"description": "Initial backend for LinkedSign", "description": "Initial backend for LinkedSign",
"main": "src/server.js", "main": "src/server.js",
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "frontend", "name": "frontend",
"private": true, "private": true,
"version": "1.2.2", "version": "1.2.3",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
+2 -1
View File
@@ -5,8 +5,9 @@ import {
getAccessToken, getAccessToken,
setAccessToken, setAccessToken,
} from '../utils/session'; } from '../utils/session';
import { resolveApiUrl } from '../config/api';
const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:4000'; const API_URL = resolveApiUrl();
const client = axios.create({ const client = axios.create({
baseURL: API_URL, baseURL: API_URL,
+2 -1
View File
@@ -1,6 +1,7 @@
import axios from 'axios'; import axios from 'axios';
import { resolveApiUrl } from '../config/api';
const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:4000'; const API_URL = resolveApiUrl();
export const verifySignature = (code) => axios.get(`${API_URL}/signatures/verify/${code}`); export const verifySignature = (code) => axios.get(`${API_URL}/signatures/verify/${code}`);
export const getLegalTemplates = () => axios.get(`${API_URL}/legal/templates`); export const getLegalTemplates = () => axios.get(`${API_URL}/legal/templates`);
+17
View File
@@ -0,0 +1,17 @@
const normalize = (value) => String(value || '').replace(/\/$/, '');
export const resolveApiUrl = () => {
if (typeof window !== 'undefined' && window.location?.hostname === 'sign.linkedcorp.net') {
return '/api';
}
return normalize(import.meta.env.VITE_API_URL || 'http://192.168.222.40:4000');
};
export const resolveAndroidApkUrl = () => {
if (typeof window !== 'undefined' && window.location?.hostname === 'sign.linkedcorp.net') {
return '/api/downloads/android-apk';
}
return `${resolveApiUrl()}/downloads/android-apk`;
};
+2 -2
View File
@@ -4,6 +4,7 @@ import { useAuth } from '../../contexts/AuthContext';
import { Download, PenTool } from 'lucide-react'; import { Download, PenTool } from 'lucide-react';
import toast from 'react-hot-toast'; import toast from 'react-hot-toast';
import { SESSION_EXPIRED_MESSAGE, translateApiError } from '../../utils/session'; import { SESSION_EXPIRED_MESSAGE, translateApiError } from '../../utils/session';
import { resolveAndroidApkUrl } from '../../config/api';
import packageInfo from '../../../package.json'; import packageInfo from '../../../package.json';
export default function LoginPage() { export default function LoginPage() {
@@ -12,8 +13,7 @@ export default function LoginPage() {
const [searchParams, setSearchParams] = useSearchParams(); const [searchParams, setSearchParams] = useSearchParams();
const [form, setForm] = useState({ email: '', password: '' }); const [form, setForm] = useState({ email: '', password: '' });
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const apiBaseUrl = (import.meta.env.VITE_API_URL || 'http://localhost:4000').replace(/\/$/, ''); const androidApkUrl = resolveAndroidApkUrl();
const androidApkUrl = `${apiBaseUrl}/downloads/android-apk`;
const showAndroidDownload = useMemo(() => { const showAndroidDownload = useMemo(() => {
if (typeof navigator === 'undefined') return false; if (typeof navigator === 'undefined') return false;
return /Android/i.test(navigator.userAgent || ''); return /Android/i.test(navigator.userAgent || '');