const CACHE_NAME = 'fs-v51'
const STATIC_ASSETS = [
'/',
'/styles.css',
'/auth.js',
'/settings.js',
'/signals.js',
'/densities.js',
'/mini-charts.js',
'/alerts.js',
'/manifest.json',
]
self.addEventListener('install', (e) => {
e.waitUntil(
caches.open(CACHE_NAME).then(c =>
Promise.all(STATIC_ASSETS.map(url =>
fetch(url, { cache: 'no-store' }).then(res => c.put(url, res))
))
)
)
self.skipWaiting()
})
self.addEventListener('activate', (e) => {
e.waitUntil(
Promise.all([
caches.keys().then(keys =>
Promise.all(keys.filter(k => k !== CACHE_NAME).map(k => caches.delete(k)))
),
// Clear all existing notifications on SW update
self.registration.getNotifications().then(nots => nots.forEach(n => n.close())),
])
)
self.clients.claim()
// Notify all open tabs that a new SW version is active
self.clients.matchAll({ type: 'window' }).then(cls => {
for (const c of cls) c.postMessage({ type: 'SW_UPDATED', version: CACHE_NAME })
})
})
// Notification click β open PWA and navigate to coin modal
self.addEventListener('notificationclick', (e) => {
e.notification.close()
const symbol = e.notification.data?.symbol
const signalId = e.notification.data?.signalId
const url = symbol ? `/?signal=${symbol}` : '/'
e.waitUntil(
clients.matchAll({ type: 'window', includeUncontrolled: true }).then(cls => {
// Focus existing window if open
for (const client of cls) {
if (client.url.includes(self.registration.scope) || client.url.includes(self.location.origin)) {
client.postMessage({ type: 'OPEN_SIGNAL', symbol, signalId })
return client.focus()
}
}
// No window open β open new one with signalId
const openUrl = signalId ? `/?signal=${symbol}&sid=${signalId}` : url
return clients.openWindow(openUrl)
})
)
})
// Web Push β receive server-sent push and show notification (works even when browser closed)
self.addEventListener('push', (e) => {
if (!e.data) return
let payload
try { payload = e.data.json() } catch { return }
const options = {
body: payload.body || '',
icon: payload.icon || '/icon-192.svg',
badge: payload.badge || '/icon-192.svg',
tag: payload.tag || 'signal',
data: payload.data || {},
vibrate: payload.vibrate || [200, 100, 200],
requireInteraction: false,
}
e.waitUntil(
self.registration.showNotification(payload.title || 'Signal', options)
)
})
self.addEventListener('fetch', (e) => {
const url = new URL(e.request.url)
// API/WS calls β network only
if (url.pathname.startsWith('/api/') || url.pathname.startsWith('/densities/') ||
url.pathname.startsWith('/depth/') || url.pathname === '/health') {
return
}
// Navigation (HTML) β ALWAYS bypass HTTP cache to get fresh version checks
if (e.request.mode === 'navigate') {
e.respondWith(
fetch(e.request, { cache: 'no-store' }).then(res => {
const clone = res.clone()
caches.open(CACHE_NAME).then(c => c.put(e.request, clone))
return res
}).catch(() => caches.match(e.request))
)
return
}
// Static assets β network first (force bypass HTTP cache + nginx immutable), fallback to SW cache
e.respondWith(
fetch(e.request, { cache: 'no-store' }).then(res => {
const clone = res.clone()
caches.open(CACHE_NAME).then(c => c.put(e.request, clone))
return res
}).catch(() => caches.match(e.request))
)
})
π Git History
d91bbbdfeat(ui): separate Min Confidence slider for Order-Flow signals4 weeks ago
13b7aedfix(ui): add Order-Flow section to Signals settings (push toggle)4 weeks ago
c35f030feat(ui): order-flow signal type in feed β filter, push, paper ticket4 weeks ago
7a5cb1ffix: drawing tools β touch support, future area, magnet snap, SW cache7 weeks ago
ddf9d20fix: cache bust + channel typeFilter migration for signals tab8 weeks ago
e9524b7feat: Alerts tab + price alert drawing tool + deploy stability fixes8 weeks ago
b505391fix: bump SW cache to fs-v36 for cache invalidation8 weeks ago
354f8e3feat: Liquidity Sweep + Pin Bar signal detection, settings accordion UI, signal markers on charts, sort buttons9 weeks ago
4381cbafix: migrate WS to /market/stream endpoint + TF switch reconnect10 weeks ago
ccd2c26perf: 3-tier klines cache (MemoryβIndexedDBβServer) + infinite scroll2 months ago
Show last diff
Loading...