first commit

This commit is contained in:
2026-01-17 14:17:42 +05:30
commit 0f194eb9e7
328 changed files with 73544 additions and 0 deletions

211
lib/cache-manager.ts Normal file
View File

@@ -0,0 +1,211 @@
// Client-side cache management and service worker utilities
interface CacheManager {
clearAllCaches: () => Promise<void>
checkForUpdates: () => Promise<boolean>
forceReload: () => void
registerUpdateHandler: (callback: () => void) => void
}
class PWACacheManager implements CacheManager {
private updateCallback: (() => void) | null = null
private registration: ServiceWorkerRegistration | null = null
constructor() {
this.initializeServiceWorker()
}
private async initializeServiceWorker() {
// Only initialize in browser environment
if (typeof window === 'undefined') return
if ('serviceWorker' in navigator) {
try {
// Register service worker
this.registration = await navigator.serviceWorker.register('/sw.js', {
scope: '/',
updateViaCache: 'none' // Always check for updates
})
console.log('Service Worker registered successfully:', this.registration)
// Listen for service worker updates
this.registration.addEventListener('updatefound', () => {
console.log('Service Worker update found')
const newWorker = this.registration?.installing
if (newWorker) {
newWorker.addEventListener('statechange', () => {
if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {
// New version available
console.log('New version available!')
if (this.updateCallback) {
this.updateCallback()
}
}
})
}
})
// Listen for messages from service worker
navigator.serviceWorker.addEventListener('message', (event) => {
console.log('Message from Service Worker:', event.data)
if (event.data && event.data.type === 'SW_UPDATED') {
console.log('Service Worker updated to version:', event.data.version)
if (this.updateCallback) {
this.updateCallback()
}
}
})
// Check for updates every 30 seconds
setInterval(() => {
this.checkForUpdates()
}, 30000)
} catch (error) {
console.error('Service Worker registration failed:', error)
}
}
}
// Clear all caches
async clearAllCaches(): Promise<void> {
try {
// Clear browser caches
if ('caches' in window) {
const cacheNames = await caches.keys()
await Promise.all(
cacheNames.map(cacheName => caches.delete(cacheName))
)
console.log('All caches cleared')
}
// Send message to service worker to clear its caches
if (navigator.serviceWorker.controller) {
const messageChannel = new MessageChannel()
return new Promise<void>((resolve) => {
messageChannel.port1.onmessage = (event) => {
if (event.data.success) {
console.log('Service Worker caches cleared')
resolve()
}
}
// Safe to call postMessage since we checked controller is not null
navigator.serviceWorker.controller!.postMessage(
{ type: 'CACHE_INVALIDATE' },
[messageChannel.port2]
)
})
}
} catch (error) {
console.error('Failed to clear caches:', error)
throw error
}
}
// Check for service worker updates
async checkForUpdates(): Promise<boolean> {
if (this.registration) {
try {
await this.registration.update()
return true
} catch (error) {
console.error('Failed to check for updates:', error)
return false
}
}
return false
}
// Force reload the page
forceReload(): void {
// Clear caches first, then reload
this.clearAllCaches().then(() => {
window.location.reload()
}).catch(() => {
// Fallback: just reload
window.location.reload()
})
}
// Register callback for updates
registerUpdateHandler(callback: () => void): void {
this.updateCallback = callback
}
// Skip waiting and activate new service worker
async skipWaiting(): Promise<void> {
if (this.registration && this.registration.waiting) {
// Send message to service worker to skip waiting
this.registration.waiting.postMessage({ type: 'SKIP_WAITING' })
}
}
}
// Singleton instance
const cacheManager = new PWACacheManager()
// Export utility functions
export const clearAllCaches = () => cacheManager.clearAllCaches()
export const checkForUpdates = () => cacheManager.checkForUpdates()
export const forceReload = () => cacheManager.forceReload()
export const registerUpdateHandler = (callback: () => void) => cacheManager.registerUpdateHandler(callback)
// Development helpers
export const isDevelopment = process.env.NODE_ENV === 'development'
export const enableDevCacheBypass = () => {
if (isDevelopment) {
// Disable caching in development
if ('serviceWorker' in navigator) {
navigator.serviceWorker.getRegistrations().then(registrations => {
registrations.forEach(registration => {
registration.unregister()
})
})
}
}
}
// Auto-update notification component data
export const createUpdateNotification = () => {
return {
title: 'New Version Available!',
message: 'A new version of the app is available. Refresh to get the latest features.',
actions: [
{
label: 'Refresh Now',
action: forceReload
},
{
label: 'Later',
action: () => console.log('Update dismissed')
}
]
}
}
// Cache status utilities
export const getCacheStatus = async () => {
if ('caches' in window) {
const cacheNames = await caches.keys()
const cacheDetails = await Promise.all(
cacheNames.map(async (name) => {
const cache = await caches.open(name)
const keys = await cache.keys()
return {
name,
size: keys.length
}
})
)
return cacheDetails
}
return []
}
export default cacheManager