fluxy-bot 0.10.12 → 0.10.13

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxy-bot",
3
- "version": "0.10.12",
3
+ "version": "0.10.13",
4
4
  "releaseNotes": [
5
5
  "Adding a way for users to claim their fluxies on the fluxy.bot dashboard",
6
6
  "2. ",
@@ -53,21 +53,37 @@ const MIME_TYPES: Record<string, string> = {
53
53
  const SW_JS = `// Service worker — app-shell caching + push notifications
54
54
  // Caching strategy:
55
55
  // Hashed assets (/assets/*-AbCd12.js) → cache-first (immutable)
56
- // Navigation (HTML) → network-first, cache fallback
56
+ // Navigation (HTML) → stale-while-revalidate (precached on install)
57
57
  // Static assets (img/video/fonts) → stale-while-revalidate
58
58
  // JS/CSS modules → stale-while-revalidate
59
59
  // API, WebSocket, Vite internals → network-only (no cache)
60
60
 
61
- var CACHE = 'fluxy-v2';
61
+ var CACHE = 'fluxy-v4';
62
62
  var HASHED_RE = new RegExp('/assets/.+-[a-zA-Z0-9]{6,}[.](js|css)$');
63
63
 
64
- self.addEventListener('install', function() { self.skipWaiting(); });
64
+ // Precache the HTML shell on install so the cache is never empty.
65
+ // Without this, the first navigation isn't intercepted (SW wasn't
66
+ // controlling yet), so refresh would find an empty cache → white screen.
67
+ self.addEventListener('install', function(e) {
68
+ console.log('[SW] installing, cache:', CACHE);
69
+ e.waitUntil(
70
+ caches.open(CACHE)
71
+ .then(function(c) { return c.add('/'); })
72
+ .then(function() { console.log('[SW] precached / — calling skipWaiting'); return self.skipWaiting(); })
73
+ .catch(function(err) { console.error('[SW] install failed:', err); throw err; })
74
+ );
75
+ });
65
76
 
66
77
  self.addEventListener('activate', function(e) {
78
+ console.log('[SW] activating, cache:', CACHE);
67
79
  e.waitUntil(
68
80
  caches.keys()
69
- .then(function(keys) { return Promise.all(keys.filter(function(k) { return k !== CACHE; }).map(function(k) { return caches.delete(k); })); })
70
- .then(function() { return self.clients.claim(); })
81
+ .then(function(keys) {
82
+ var old = keys.filter(function(k) { return k !== CACHE; });
83
+ if (old.length) console.log('[SW] deleting old caches:', old);
84
+ return Promise.all(old.map(function(k) { return caches.delete(k); }));
85
+ })
86
+ .then(function() { console.log('[SW] claiming clients'); return self.clients.claim(); })
71
87
  );
72
88
  });
73
89
 
@@ -101,16 +117,24 @@ self.addEventListener('fetch', function(event) {
101
117
  return;
102
118
  }
103
119
 
104
- // Navigation (HTML pages) → network-first, cached shell fallback
120
+ // Navigation (HTML pages) → stale-while-revalidate
121
+ // Serves cached shell INSTANTLY (no white flash on refresh), then
122
+ // refreshes cache from network in the background.
105
123
  if (request.mode === 'navigate') {
106
- event.respondWith(
107
- fetch(request)
108
- .then(function(r) {
109
- if (r.ok) caches.open(CACHE).then(function(c) { c.put(request, r.clone()); });
110
- return r;
111
- })
112
- .catch(function() { return caches.match(request).then(function(r) { return r || caches.match('/'); }); })
113
- );
124
+ console.log('[SW] navigate →', url.pathname);
125
+ event.respondWith(caches.open(CACHE).then(function(c) {
126
+ return c.match('/').then(function(hit) {
127
+ console.log('[SW] cache hit for /:', !!hit);
128
+ var net = fetch(request)
129
+ .then(function(r) {
130
+ console.log('[SW] network response for /:', r.status);
131
+ if (r.ok) c.put('/', r.clone());
132
+ return r;
133
+ })
134
+ .catch(function(err) { console.warn('[SW] network failed, using cache:', err.message); return hit; });
135
+ return hit || net;
136
+ });
137
+ }));
114
138
  return;
115
139
  }
116
140
 
@@ -46,6 +46,7 @@
46
46
  // The last painted frame before teardown will be the dark splash
47
47
  // instead of a white gap.
48
48
  window.addEventListener('beforeunload', function () {
49
+ console.log('[splash] beforeunload — showing splash');
49
50
  var s = document.getElementById('splash');
50
51
  if (s) { s.style.transition = 'none'; s.style.display = 'flex'; s.style.opacity = '1'; }
51
52
  });
@@ -53,16 +54,38 @@
53
54
  <script type="module" src="/src/main.tsx"></script>
54
55
  <script>
55
56
  if('serviceWorker' in navigator){
57
+ console.log('[sw-reg] current controller:', navigator.serviceWorker.controller ? 'yes' : 'none');
58
+ // When a new SW takes control (update), show splash and reload
59
+ // so the new caching strategy kicks in immediately.
60
+ var swRefreshing=false;
61
+ navigator.serviceWorker.addEventListener('controllerchange',function(){
62
+ console.log('[sw-reg] controllerchange fired, refreshing:', swRefreshing);
63
+ if(swRefreshing)return;
64
+ swRefreshing=true;
65
+ var s=document.getElementById('splash');
66
+ if(s){s.style.transition='none';s.style.display='flex';s.style.opacity='1'}
67
+ console.log('[sw-reg] reloading after new SW took control');
68
+ location.reload();
69
+ });
56
70
  navigator.serviceWorker.register('/sw.js').then(function(r){
71
+ console.log('[sw-reg] registered, active:', r.active?.state, 'waiting:', !!r.waiting, 'installing:', !!r.installing);
57
72
  r.update();
58
- if(r.waiting){r.waiting.postMessage({type:'SKIP_WAITING'})}
73
+ if(r.waiting){
74
+ console.log('[sw-reg] found waiting SW — sending SKIP_WAITING');
75
+ r.waiting.postMessage({type:'SKIP_WAITING'});
76
+ }
59
77
  r.addEventListener('updatefound',function(){
78
+ console.log('[sw-reg] updatefound — new SW installing');
60
79
  var w=r.installing;
61
80
  if(w)w.addEventListener('statechange',function(){
62
- if(w.state==='installed'&&navigator.serviceWorker.controller)w.postMessage({type:'SKIP_WAITING'});
81
+ console.log('[sw-reg] installing SW state:', w.state);
82
+ if(w.state==='installed'&&navigator.serviceWorker.controller){
83
+ console.log('[sw-reg] new SW installed — sending SKIP_WAITING');
84
+ w.postMessage({type:'SKIP_WAITING'});
85
+ }
63
86
  });
64
87
  });
65
- });
88
+ }).catch(function(err){ console.error('[sw-reg] registration failed:', err); });
66
89
  }
67
90
  </script>
68
91
  <script src="/fluxy/widget.js"></script>
@@ -11,15 +11,28 @@ const CACHE = 'fluxy-v4';
11
11
  // Precache the HTML shell on install so the cache is never empty.
12
12
  // Without this, the first navigation isn't intercepted (SW wasn't
13
13
  // controlling yet), so refresh would find an empty cache → white screen.
14
- self.addEventListener('install', (e) => e.waitUntil(
15
- caches.open(CACHE).then(c => c.add('/')).then(() => self.skipWaiting())
16
- ));
14
+ self.addEventListener('install', (e) => {
15
+ console.log('[SW] installing, cache:', CACHE);
16
+ e.waitUntil(
17
+ caches.open(CACHE)
18
+ .then(c => c.add('/'))
19
+ .then(() => { console.log('[SW] precached / — calling skipWaiting'); return self.skipWaiting(); })
20
+ .catch(err => { console.error('[SW] install failed:', err); throw err; })
21
+ );
22
+ });
17
23
 
18
- self.addEventListener('activate', (e) => e.waitUntil(
19
- caches.keys()
20
- .then(keys => Promise.all(keys.filter(k => k !== CACHE).map(k => caches.delete(k))))
21
- .then(() => self.clients.claim())
22
- ));
24
+ self.addEventListener('activate', (e) => {
25
+ console.log('[SW] activating, cache:', CACHE);
26
+ e.waitUntil(
27
+ caches.keys()
28
+ .then(keys => {
29
+ const old = keys.filter(k => k !== CACHE);
30
+ if (old.length) console.log('[SW] deleting old caches:', old);
31
+ return Promise.all(old.map(k => caches.delete(k)));
32
+ })
33
+ .then(() => { console.log('[SW] claiming clients'); return self.clients.claim(); })
34
+ );
35
+ });
23
36
 
24
37
  self.addEventListener('message', (e) => {
25
38
  if (e.data?.type === 'SKIP_WAITING') self.skipWaiting();
@@ -56,11 +69,17 @@ self.addEventListener('fetch', (event) => {
56
69
  // refreshes cache from network in the background.
57
70
  // First visit has no cache → falls through to network.
58
71
  if (request.mode === 'navigate') {
72
+ console.log('[SW] navigate →', url.pathname);
59
73
  event.respondWith(caches.open(CACHE).then(c =>
60
74
  c.match('/').then(hit => {
75
+ console.log('[SW] cache hit for /:', !!hit);
61
76
  const net = fetch(request)
62
- .then(r => { if (r.ok) c.put('/', r.clone()); return r; })
63
- .catch(() => hit);
77
+ .then(r => {
78
+ console.log('[SW] network response for /:', r.status);
79
+ if (r.ok) c.put('/', r.clone());
80
+ return r;
81
+ })
82
+ .catch(err => { console.warn('[SW] network failed, using cache:', err.message); return hit; });
64
83
  return hit || net;
65
84
  })
66
85
  ));
@@ -12,10 +12,15 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
12
12
  // Fade out the HTML splash screen once React has actually painted.
13
13
  // React 18's createRoot().render() is async — wait for the next frame
14
14
  // to ensure the app is visible before removing the splash.
15
+ console.log('[main] React render called, waiting for paint to hide splash');
15
16
  requestAnimationFrame(() => requestAnimationFrame(() => {
17
+ console.log('[main] double-rAF fired — hiding splash');
16
18
  const splash = document.getElementById('splash');
17
19
  if (splash) {
18
20
  splash.style.opacity = '0';
19
- splash.addEventListener('transitionend', () => { splash.style.display = 'none'; }, { once: true });
21
+ splash.addEventListener('transitionend', () => {
22
+ splash.style.display = 'none';
23
+ console.log('[main] splash hidden');
24
+ }, { once: true });
20
25
  }
21
26
  }));