up
This commit is contained in:
@@ -231,3 +231,11 @@
|
||||
[2026-01-28 14:04:21] Send media by id response: {"messaging_product":"whatsapp","contacts":[{"input":"573168950803","wa_id":"573168950803"}],"messages":[{"id":"wamid.HBgMNTczMTY4OTUwODAzFQIAERgSREYzMUY2RUMwQTgxNERENTUwAA=="}]}
|
||||
[2026-01-28 14:04:21] WhatsApp response (successful): {"messaging_product":"whatsapp","contacts":[{"input":"573168950803","wa_id":"573168950803"}],"messages":[{"id":"wamid.HBgMNTczMTY4OTUwODAzFQIAERgSREYzMUY2RUMwQTgxNERENTUwAA=="}]}
|
||||
[2026-01-28 14:04:21] Saving to DB - content: record_1769627059068.webm, media_url: 1602247974444552, local_file: uploads/media_697a5db44d08f0.23171792.ogg, local_thumb: null
|
||||
[2026-01-29 11:39:39] Raw input: {"recipient":"573168950803","media_url":"http://localhost:8080/uploads/media_697b8d4b88a6c2.66006027.ogg","media_type":"audio","caption":null,"filename":"record_1769704778262.webm","is_voice":true}
|
||||
[2026-01-29 11:39:39] Input decoded: {"recipient":"573168950803","media_url":"http:\/\/localhost:8080\/uploads\/media_697b8d4b88a6c2.66006027.ogg","media_type":"audio","caption":null,"filename":"record_1769704778262.webm","is_voice":true}
|
||||
[2026-01-29 11:39:39] is_voice: true
|
||||
[2026-01-29 11:39:40] Upload result: {"id":"906365935662402"}
|
||||
[2026-01-29 11:39:40] Media ID obtained: 906365935662402
|
||||
[2026-01-29 11:39:41] Send media by id response: {"messaging_product":"whatsapp","contacts":[{"input":"573168950803","wa_id":"573168950803"}],"messages":[{"id":"wamid.HBgMNTczMTY4OTUwODAzFQIAERgSNzAyNEVCRkRGNUYwM0IzQURGAA=="}]}
|
||||
[2026-01-29 11:39:41] WhatsApp response (successful): {"messaging_product":"whatsapp","contacts":[{"input":"573168950803","wa_id":"573168950803"}],"messages":[{"id":"wamid.HBgMNTczMTY4OTUwODAzFQIAERgSNzAyNEVCRkRGNUYwM0IzQURGAA=="}]}
|
||||
[2026-01-29 11:39:41] Saving to DB - content: record_1769704778262.webm, media_url: 906365935662402, local_file: uploads/media_697b8d4b88a6c2.66006027.ogg, local_thumb: null
|
||||
|
||||
+1
-1
@@ -95,7 +95,7 @@ try {
|
||||
$lastEventId = $_SERVER['HTTP_LAST_EVENT_ID'] ?? null;
|
||||
$lastCheck = time();
|
||||
$connectionStart = time();
|
||||
$maxConnectionTime = 300; // 5 minutos máximo
|
||||
$maxConnectionTime = 1800; // 30 minutos máximo (aumentado para evitar desconexiones frecuentes)
|
||||
|
||||
// Loop principal - revisar eventos cada 2 segundos
|
||||
while (true) {
|
||||
|
||||
+116
-75
@@ -826,10 +826,6 @@ if (!isset($_SESSION['user_id'])) {
|
||||
.unread-badge { margin-left: 8px; font-size: 12px; }
|
||||
|
||||
</style>
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
<meta name="theme-color" content="#10b981">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
</head>
|
||||
<body>
|
||||
<div class="chat-container">
|
||||
@@ -839,7 +835,7 @@ if (!isset($_SESSION['user_id'])) {
|
||||
<div>
|
||||
<h5 class="mb-0">💬 Conversaciones
|
||||
<span class="badge bg-warning text-dark ms-2" style="font-size: 9px; padding: 2px 6px; animation: pulse 2s infinite;">
|
||||
v1.2.1-<?php echo substr(time(), -4); ?>
|
||||
v1.2.2-<?php echo substr(time(), -4); ?>
|
||||
</span>
|
||||
</h5>
|
||||
</div>
|
||||
@@ -910,8 +906,6 @@ if (!isset($_SESSION['user_id'])) {
|
||||
</div>
|
||||
<!-- Botón actualizar mensajes -->
|
||||
<button class="btn btn-sm btn-outline-light" id="refresh-messages-btn" title="Actualizar mensajes"><i class="fas fa-sync-alt"></i></button>
|
||||
<!-- PWA install button for conversations view -->
|
||||
<button id="pwa-install-btn" class="btn btn-sm btn-outline-primary d-none" style="display:none;">Instalar</button>
|
||||
<button class="btn btn-sm btn-outline-secondary" id="mark-unread-btn" title="Marcar conversación como no leída" style="display:none;">Marcar no leído</button>
|
||||
<button class="btn btn-sm btn-outline-danger" id="delete-conversation-btn" title="Eliminar conversación" style="display:none;"><i class="fas fa-trash"></i></button>
|
||||
</div>
|
||||
@@ -1218,23 +1212,35 @@ if (!isset($_SESSION['user_id'])) {
|
||||
if (this.currentUserId && String(this.currentUserId) === String(userId)) {
|
||||
console.log('♻️ Mensaje para conversación ACTIVA');
|
||||
|
||||
// SOLUCIÓN: Siempre usar staged messages + indicador
|
||||
// Esto evita el error que borra la pantalla al intentar recargar automáticamente
|
||||
if (!this._stagedMessages) this._stagedMessages = [];
|
||||
if (!this._stagedMessageIds) this._stagedMessageIds = new Set();
|
||||
// Verificar si el usuario está cerca del final del chat
|
||||
const container = document.getElementById('chat-conversations');
|
||||
const nearBottom = container ? ((container.scrollHeight - container.scrollTop - container.clientHeight) < 150) : true;
|
||||
|
||||
// Crear key única para evitar duplicados
|
||||
const msgKey = data.message_id || data.id || `${data.created_at}_${data.content?.substring(0,20)}`;
|
||||
|
||||
if (!this._stagedMessageIds.has(msgKey)) {
|
||||
this._stagedMessageIds.add(msgKey);
|
||||
this._stagedMessages.push(data);
|
||||
console.log('💾 Mensaje guardado en staging. Total:', this._stagedMessages.length);
|
||||
|
||||
// Mostrar indicador de nuevos mensajes
|
||||
this.showNewMessagesIndicator(this._stagedMessages.length);
|
||||
if (nearBottom && !this._userScrolling) {
|
||||
// Usuario está en el final: recargar mensajes automáticamente
|
||||
console.log('🔄 Usuario cerca del final, recargando mensajes...');
|
||||
this.loadMessages(this.currentUserId, true, true).catch(err => {
|
||||
console.error('Error recargando mensajes:', err);
|
||||
});
|
||||
} else {
|
||||
console.log('⏭️ Mensaje duplicado, omitiendo');
|
||||
// Usuario está leyendo historial: usar staged messages
|
||||
console.log('📜 Usuario leyendo historial, guardando en staging...');
|
||||
if (!this._stagedMessages) this._stagedMessages = [];
|
||||
if (!this._stagedMessageIds) this._stagedMessageIds = new Set();
|
||||
|
||||
// Crear key única para evitar duplicados
|
||||
const msgKey = data.message_id || data.id || `${data.created_at}_${data.content?.substring(0,20)}`;
|
||||
|
||||
if (!this._stagedMessageIds.has(msgKey)) {
|
||||
this._stagedMessageIds.add(msgKey);
|
||||
this._stagedMessages.push(data);
|
||||
console.log('💾 Mensaje guardado en staging. Total:', this._stagedMessages.length);
|
||||
|
||||
// Mostrar indicador de nuevos mensajes
|
||||
this.showNewMessagesIndicator(this._stagedMessages.length);
|
||||
} else {
|
||||
console.log('⏭️ Mensaje duplicado, omitiendo');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log('📋 Mensaje para OTRA conversación, solo actualizando lista');
|
||||
@@ -1380,7 +1386,7 @@ if (!isset($_SESSION['user_id'])) {
|
||||
*/
|
||||
updateConversationInList(data) {
|
||||
try {
|
||||
console.log('📝 Actualizando conversación en lista:', data);
|
||||
console.log('📝 updateConversationInList INICIADO:', data);
|
||||
|
||||
// Asegurar que conversations esté inicializado
|
||||
if (!this.conversations || !Array.isArray(this.conversations)) {
|
||||
@@ -1396,6 +1402,8 @@ if (!isset($_SESSION['user_id'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('👤 User ID extraído:', userId);
|
||||
|
||||
// Si no viene el mensaje, recargar la lista completa para obtener datos actualizados
|
||||
if (!data.message && !data.content && !data.text && !data.last_message) {
|
||||
console.log('⚠️ Evento SSE sin contenido de mensaje, recargando lista completa...');
|
||||
@@ -1412,11 +1420,14 @@ if (!isset($_SESSION['user_id'])) {
|
||||
const message = data.message || data.content || data.text || data.last_message || 'Nuevo mensaje';
|
||||
const timestamp = data.timestamp || data.created_at || new Date().toISOString();
|
||||
|
||||
console.log('💬 Mensaje extraído:', message);
|
||||
console.log('⏰ Timestamp:', timestamp);
|
||||
|
||||
// Buscar la conversación en el array
|
||||
const existingIndex = this.conversations.findIndex(c => String(c.user_id) === String(userId));
|
||||
|
||||
if (existingIndex !== -1) {
|
||||
console.log('✅ Conversación encontrada, actualizando...');
|
||||
console.log('✅ Conversación encontrada en índice:', existingIndex);
|
||||
// Actualizar conversación existente
|
||||
const conv = this.conversations[existingIndex];
|
||||
conv.last_message = message;
|
||||
@@ -1425,14 +1436,17 @@ if (!isset($_SESSION['user_id'])) {
|
||||
// Solo incrementar unread_count si no es la conversación activa
|
||||
if (String(this.currentUserId) !== String(userId)) {
|
||||
conv.unread_count = (conv.unread_count || 0) + 1;
|
||||
console.log('📬 unread_count incrementado a:', conv.unread_count);
|
||||
} else {
|
||||
// Si es la conversación activa, mantener unread_count en 0
|
||||
conv.unread_count = 0;
|
||||
console.log('✅ Conversación activa, unread_count = 0');
|
||||
}
|
||||
|
||||
// Mover al inicio de la lista
|
||||
this.conversations.splice(existingIndex, 1);
|
||||
this.conversations.unshift(conv);
|
||||
console.log('⬆️ Conversación movida al inicio');
|
||||
} else {
|
||||
console.log('➕ Conversación no existe, agregando nueva...');
|
||||
// Nueva conversación, agregar al inicio
|
||||
@@ -1444,22 +1458,25 @@ if (!isset($_SESSION['user_id'])) {
|
||||
last_time: timestamp,
|
||||
unread_count: String(this.currentUserId) !== String(userId) ? 1 : 0
|
||||
});
|
||||
console.log('✅ Nueva conversación agregada');
|
||||
}
|
||||
|
||||
// Re-renderizar solo la lista de conversaciones
|
||||
console.log('🔄 Re-renderizando lista de conversaciones...');
|
||||
console.log('📊 Total conversaciones:', this.conversations.length);
|
||||
console.log('🔍 Filtro activo:', this.conversationFilter);
|
||||
console.log('🔍 this.conversations:', this.conversations);
|
||||
|
||||
if (typeof this.renderConversations === 'function') {
|
||||
console.log('✅ Llamando a renderConversations()...');
|
||||
this.renderConversations();
|
||||
console.log('✅ renderConversations() ejecutado correctamente');
|
||||
} else {
|
||||
console.error('❌ renderConversations no es una función!');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Error actualizando conversación en lista:', error);
|
||||
console.error('❌ Error updateConversationInList:', error);
|
||||
console.error('Stack trace:', error.stack);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2110,49 +2127,6 @@ if (!isset($_SESSION['user_id'])) {
|
||||
};
|
||||
applyInitialMobile();
|
||||
window.addEventListener('resize', applyInitialMobile);
|
||||
|
||||
// PWA support (install prompt + SW)
|
||||
let _deferredPWA = null;
|
||||
const _pwaBtnConv = document.getElementById('pwa-install-btn');
|
||||
window.addEventListener('beforeinstallprompt', (e) => {
|
||||
e.preventDefault();
|
||||
_deferredPWA = e;
|
||||
if (_pwaBtnConv) { _pwaBtnConv.style.display = 'inline-block'; _pwaBtnConv.classList.remove('d-none'); }
|
||||
});
|
||||
if (_pwaBtnConv) {
|
||||
_pwaBtnConv.addEventListener('click', async () => {
|
||||
if (!_deferredPWA) return;
|
||||
_deferredPWA.prompt();
|
||||
const choice = await _deferredPWA.userChoice;
|
||||
console.debug('PWA install (conv):', choice);
|
||||
if (choice && choice.outcome === 'accepted') _pwaBtnConv.style.display = 'none';
|
||||
_deferredPWA = null;
|
||||
});
|
||||
}
|
||||
window.addEventListener('appinstalled', () => console.debug('PWA installed (conversations)'));
|
||||
if ('serviceWorker' in navigator) {
|
||||
(async () => {
|
||||
try {
|
||||
// Check if the service-worker script is actually reachable to avoid noisy 404 warnings
|
||||
const resp = await fetch('/service-worker.js', { method: 'GET', cache: 'no-store' });
|
||||
if (resp && resp.ok) {
|
||||
navigator.serviceWorker.register('/service-worker.js')
|
||||
.then(() => console.debug('SW reg (conv)'))
|
||||
.catch(e => console.warn('SW reg failed', e));
|
||||
} else {
|
||||
console.debug('Service worker not registered: script not found (status ' + (resp && resp.status) + ')');
|
||||
// Remove manifest link if it's missing to avoid extra 404s
|
||||
try {
|
||||
const link = document.querySelector('link[rel="manifest"]');
|
||||
if (link && (!resp || resp.status === 404)) link.parentNode && link.parentNode.removeChild(link);
|
||||
} catch(e) {}
|
||||
}
|
||||
} catch (e) {
|
||||
// Network or fetch failed — don't spam console with errors
|
||||
console.debug('Service worker check failed:', e);
|
||||
}
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
const stopRecBtn = document.getElementById('stop-recording');
|
||||
@@ -2524,7 +2498,9 @@ if (!isset($_SESSION['user_id'])) {
|
||||
|
||||
|
||||
renderConversations() {
|
||||
console.log('🎨 Renderizando conversaciones:', this.conversations.length);
|
||||
console.log('🎨 renderConversations INICIADO');
|
||||
console.log('📊 Total conversaciones:', this.conversations?.length || 0);
|
||||
|
||||
const container = document.getElementById('conversation-list');
|
||||
|
||||
if (!container) {
|
||||
@@ -2631,12 +2607,20 @@ if (!isset($_SESSION['user_id'])) {
|
||||
const wasNearTop = prevScrollTop < 60;
|
||||
|
||||
console.log('🔄 Actualizando innerHTML del container...');
|
||||
console.log('📏 Scroll antes - Top:', prevScrollTop, 'Height:', prevScrollHeight);
|
||||
|
||||
container.innerHTML = html;
|
||||
console.log('✅ DOM actualizado con', this.conversations.length, 'conversaciones');
|
||||
|
||||
console.log('✅ DOM actualizado');
|
||||
console.log('📊 Elementos en DOM:', container.children.length);
|
||||
|
||||
|
||||
// Forzar repaint del DOM
|
||||
void container.offsetHeight;
|
||||
|
||||
const newScrollHeight = container.scrollHeight;
|
||||
const scrollDelta = newScrollHeight - prevScrollHeight;
|
||||
|
||||
console.log('📏 Scroll después - Height:', newScrollHeight, 'Delta:', scrollDelta);
|
||||
|
||||
if (wasNearTop) {
|
||||
// keep at top
|
||||
@@ -2645,10 +2629,15 @@ if (!isset($_SESSION['user_id'])) {
|
||||
// preserve visual offset (avoid jumping) whether the user is scrolling or not
|
||||
container.scrollTop = Math.max(0, prevScrollTop + scrollDelta);
|
||||
}
|
||||
|
||||
console.log('✅ renderConversations COMPLETADO');
|
||||
} catch (e) {
|
||||
// fallback to naive replace if anything failed
|
||||
console.warn('renderConversations: scroll preservation failed', e);
|
||||
container.innerHTML = html;
|
||||
// Forzar repaint
|
||||
void container.offsetHeight;
|
||||
console.log('⚠️ renderConversations COMPLETADO con fallback');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4046,9 +4035,40 @@ if (!isset($_SESSION['user_id'])) {
|
||||
|
||||
this.startRecording = async function() {
|
||||
try {
|
||||
// Verificar que el navegador soporta MediaDevices
|
||||
if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
|
||||
throw new Error('Tu navegador no soporta grabación de audio');
|
||||
}
|
||||
|
||||
// Suspend periodic reload while recording
|
||||
this._suspendAutoRefresh = true;
|
||||
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
||||
|
||||
// Intentar obtener acceso al micrófono con diferentes configuraciones
|
||||
let stream = null;
|
||||
try {
|
||||
// Intento 1: Configuración básica sin especificar dispositivo
|
||||
stream = await navigator.mediaDevices.getUserMedia({
|
||||
audio: {
|
||||
echoCancellation: true,
|
||||
noiseSuppression: true,
|
||||
autoGainControl: true
|
||||
}
|
||||
});
|
||||
} catch (err1) {
|
||||
console.warn('Intento 1 falló, probando configuración más simple:', err1.message);
|
||||
try {
|
||||
// Intento 2: Configuración minimalista
|
||||
stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
||||
} catch (err2) {
|
||||
console.error('Todos los intentos fallaron');
|
||||
throw err2;
|
||||
}
|
||||
}
|
||||
|
||||
if (!stream) {
|
||||
throw new Error('No se pudo obtener acceso al micrófono');
|
||||
}
|
||||
|
||||
this._mediaRecorder = new MediaRecorder(stream);
|
||||
const chunks = [];
|
||||
this._mediaRecorder.ondataavailable = (e) => { if (e.data && e.data.size) chunks.push(e.data); };
|
||||
@@ -4114,8 +4134,29 @@ if (!isset($_SESSION['user_id'])) {
|
||||
update();
|
||||
this._recordingInterval = setInterval(update, 1000);
|
||||
} catch (err) {
|
||||
console.error('startRecording error', err);
|
||||
alert('No se pudo acceder al micrófono: ' + (err.message||err));
|
||||
console.error('startRecording error', err.name, err.message);
|
||||
|
||||
// Mensajes de error más específicos
|
||||
let errorMsg = 'No se pudo acceder al micrófono';
|
||||
|
||||
if (err.name === 'NotFoundError') {
|
||||
errorMsg = 'No se encontró ningún micrófono. Conecta un micrófono e intenta de nuevo.';
|
||||
} else if (err.name === 'NotAllowedError' || err.name === 'PermissionDeniedError') {
|
||||
errorMsg = 'Permiso denegado. Permite el acceso al micrófono en la configuración del navegador.';
|
||||
} else if (err.name === 'NotReadableError') {
|
||||
errorMsg = 'El micrófono está siendo usado por otra aplicación.';
|
||||
} else if (err.message) {
|
||||
errorMsg += ': ' + err.message;
|
||||
}
|
||||
|
||||
alert(errorMsg);
|
||||
|
||||
// Limpiar estado
|
||||
this._suspendAutoRefresh = false;
|
||||
const ind = document.getElementById('recording-indicator');
|
||||
if (ind) ind.style.display = 'none';
|
||||
const micEl = document.getElementById('mic-btn');
|
||||
if (micEl) micEl.classList.remove('recording', 'recording-cancel');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -5,6 +5,11 @@ server {
|
||||
root /var/www/html;
|
||||
index index.php index.html;
|
||||
|
||||
# 🚫 CACHE DESACTIVADO GLOBALMENTE
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0" always;
|
||||
add_header Pragma "no-cache" always;
|
||||
add_header Expires "0" always;
|
||||
|
||||
# Security headers
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
@@ -79,10 +84,12 @@ server {
|
||||
access_log off;
|
||||
}
|
||||
|
||||
# Static assets caching
|
||||
# Static assets - SIN CACHE para desarrollo
|
||||
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
|
||||
expires 30d;
|
||||
add_header Cache-Control "public, immutable";
|
||||
# CACHE DESACTIVADO
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate, max-age=0" always;
|
||||
add_header Pragma "no-cache" always;
|
||||
expires off;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
@@ -105,10 +112,12 @@ server {
|
||||
alias /var/www/html/uploads/;
|
||||
autoindex off;
|
||||
|
||||
# Security: solo permitir ciertos tipos de archivo
|
||||
# Security: solo permitir ciertos tipos de archivo - SIN CACHE
|
||||
location ~* \.(jpg|jpeg|png|gif|pdf|doc|docx|xls|xlsx|mp4|mp3|webp)$ {
|
||||
expires 7d;
|
||||
add_header Cache-Control "public";
|
||||
# CACHE DESACTIVADO
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate, max-age=0" always;
|
||||
add_header Pragma "no-cache" always;
|
||||
expires off;
|
||||
}
|
||||
|
||||
# Denegar ejecución de PHP en uploads
|
||||
|
||||
@@ -51,9 +51,9 @@ http {
|
||||
client_header_timeout 12;
|
||||
send_timeout 10;
|
||||
|
||||
# FastCGI cache (opcional)
|
||||
fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=whatsapp_cache:10m
|
||||
max_size=100m inactive=60m use_temp_path=off;
|
||||
# FastCGI cache DESACTIVADO para desarrollo
|
||||
# fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=whatsapp_cache:10m
|
||||
# max_size=100m inactive=60m use_temp_path=off;
|
||||
|
||||
# Include virtual hosts
|
||||
include /etc/nginx/http.d/*.conf;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
# Configuración SSL para bot.u-s.app
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
listen 443 ssl;
|
||||
listen [::]:443 ssl;
|
||||
http2 on;
|
||||
server_name bot.u-s.app localhost;
|
||||
root /var/www/html;
|
||||
index index.php index.html;
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"name": "WhatsApp Bot Manager",
|
||||
"short_name": "WA Bot",
|
||||
"start_url": "/",
|
||||
"display": "standalone",
|
||||
"background_color": "#ffffff",
|
||||
"theme_color": "#10b981",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/assets/icons/icon-192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
// Service worker - Force no-cache for API requests
|
||||
const CACHE_VERSION = 'v1.0.1';
|
||||
|
||||
self.addEventListener('install', (event) => {
|
||||
// activate immediately
|
||||
self.skipWaiting();
|
||||
});
|
||||
|
||||
self.addEventListener('activate', (event) => {
|
||||
event.waitUntil(
|
||||
caches.keys().then(keys => {
|
||||
// Clear all caches on activation
|
||||
return Promise.all(keys.map(key => caches.delete(key)));
|
||||
}).then(() => self.clients.claim())
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', (event) => {
|
||||
const url = new URL(event.request.url);
|
||||
|
||||
// For API requests, always go to network with no-cache
|
||||
if (url.pathname.startsWith('/api/') || url.pathname.includes('/api/')) {
|
||||
event.respondWith(
|
||||
fetch(event.request, {
|
||||
cache: 'no-store',
|
||||
headers: {
|
||||
...Object.fromEntries(event.request.headers),
|
||||
'Cache-Control': 'no-cache, no-store, must-revalidate',
|
||||
'Pragma': 'no-cache'
|
||||
}
|
||||
}).catch(err => {
|
||||
console.error('SW fetch error:', err);
|
||||
return new Response(JSON.stringify({ error: 'Network error' }), {
|
||||
status: 503,
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// For other requests, use default network behavior (no caching)
|
||||
});
|
||||
Reference in New Issue
Block a user