PageSourceSearch

https://floraflor.lovable.app/sw.js

js floraflor.lovable.app collected 2026-10-03 03:32:47 UTC 5,209 bytes, 165 lines download raw bytes

1const CACHE_VERSION = 'v3';
2const STATIC_CACHE = 'floraflor-static-' + CACHE_VERSION;
3const DYNAMIC_CACHE = 'floraflor-dynamic-' + CACHE_VERSION;
4const APP_SHELL_CACHE = 'floraflor-shell-' + CACHE_VERSION;
5
6// Core app shell - cached aggressively for instant loads
7const APP_SHELL = [
8  '/',
9  '/manifest.json',
10  '/favicon.png',
11  '/apple-touch-icon.png',
12  '/icon-192x192.png',
13  '/icon-512x512.png'
14];
15
16// Install - cache app shell immediately
17self.addEventListener('install', function(event) {
18  console.log('[SW] Installing v3...');
19  event.waitUntil(
20    caches.open(APP_SHELL_CACHE)
21      .then(function(cache) {
22        console.log('[SW] Caching app shell');
23        return cache.addAll(APP_SHELL);
24      })
25      .then(() => self.skipWaiting())
26  );
27});
28
29// Activate - clean ALL old caches
30self.addEventListener('activate', function(event) {
31  console.log('[SW] Activating v3...');
32  const currentCaches = [STATIC_CACHE, DYNAMIC_CACHE, APP_SHELL_CACHE];
33  event.waitUntil(
34    caches.keys().then(function(cacheNames) {
35      return Promise.all(
36        cacheNames
37          .filter(name => !currentCaches.includes(name))
38          .map(name => {
39            console.log('[SW] Deleting old cache:', name);
40            return caches.delete(name);
41          })
42      );
43    }).then(() => self.clients.claim())
44  );
45});
46
47// Fetch strategy
48self.addEventListener('fetch', function(event) {
49  const url = new URL(event.request.url);
50
51  // Skip non-GET
52  if (event.request.method !== 'GET') return;
53
54  // Skip external origins we don't own
55  const isOwnOrigin = url.origin === self.location.origin ||
56    url.origin.includes('lovableproject.com') ||
57    url.origin.includes('lovable.app') ||
58    url.origin.includes('floraflor.vercel.app');
59  if (!isOwnOrigin) return;
60
61  // Never cache API / auth / edge functions
62  if (url.pathname.includes('/rest/') ||
63      url.pathname.includes('/auth/') ||
64      url.pathname.includes('/functions/') ||
65      url.hostname.includes('supabase')) {
66    return;
67  }
68
69  // Navigation: stale-while-revalidate (show cache instantly, update in bg)
70  if (event.request.mode === 'navigate') {
71    event.respondWith(
72      caches.match(event.request).then(cached => {
73        const networkFetch = fetch(event.request).then(response => {
74          const clone = response.clone();
75          caches.open(APP_SHELL_CACHE).then(c => c.put(event.request, clone));
76          return response;
77        }).catch(() => {
78          // Offline fallback
79          if (cached) return cached;
80          return caches.match('/').then(index => {
81            if (index) return index;
82            return new Response('Offline - Por favor verifica tu conexión', {
83              headers: { 'Content-Type': 'text/html; charset=utf-8' }
84            });
85          });
86        });
87        return cached || networkFetch;
88      })
89    );
90    return;
91  }
92
93  // JS/CSS bundles with hashes - cache forever (immutable)
94  if (url.pathname.match(/\/assets\/.*\.[a-f0-9]{8,}\.(js|css)$/)) {
95    event.respondWith(
96      caches.match(event.request).then(cached => {
97        if (cached) return cached;
98        return fetch(event.request).then(response => {
99          if (response.ok) {
100            const clone = response.clone();
101            caches.open(STATIC_CACHE).then(c => c.put(event.request, clone));
102          }
103          return response;
104        });
105      })
106    );
107    return;
108  }
109
110  // Images - cache first with network fallback
111  if (url.pathname.match(/\.(png|jpg|jpeg|svg|ico|webp|gif)$/)) {
112    event.respondWith(
113      caches.match(event.request).then(cached => {
114        if (cached) return cached;
115        return fetch(event.request).then(response => {
116          if (response.ok) {
117            const clone = response.clone();
118            caches.open(STATIC_CACHE).then(c => c.put(event.request, clone));
119          }
120          return response;
121        }).catch(() => new Response('', { status: 404 }));
122      })
123    );
124    return;
125  }
126
127  // Everything else: network first, cache fallback
128  event.respondWith(
129    fetch(event.request).then(response => {
130      if (response.ok) {
131        const clone = response.clone();
132        caches.open(DYNAMIC_CACHE).then(c => c.put(event.request, clone));
133      }
134      return response;
135    }).catch(() => caches.match(event.request))
136  );
137});
138
139// Push notifications
140self.addEventListener('push', function(event) {
141  const data = event.data ? event.data.json() : {};
142  const title = data.title || 'Floraflor';
143  const options = {
144    body: data.body || 'Nueva notificación',
145    icon: '/favicon.png',
146    badge: '/favicon.png',
147    data: data.data || {},
148    tag: data.tag || 'default',
149    requireInteraction: data.requireInteraction || false,
150    actions: data.actions || []
151  };
152  event.waitUntil(self.registration.showNotification(title, options));
153});
154
155self.addEventListener('notificationclick', function(event) {
156  event.notification.close();
157  event.waitUntil(clients.openWindow(event.notification.data.url || '/'));
158});
159
160self.addEventListener('message', function(event) {
161  if (event.data === 'skipWaiting') self.skipWaiting();
162  if (event.data === 'clearCache') {
163    caches.keys().then(names => Promise.all(names.map(n => caches.delete(n))));
164  }
165});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.