Browse Source
- Add web app manifest for standalone installation - Add service worker with offline-first caching for static assets - Add network-first caching with fallback for API calls - Generate PWA icons (192x192, 512x512) from favicon - Add Apple PWA meta tags for iOS support - Update rollup config to copy PWA files to dist Files modified: - app/web/public/manifest.json: New PWA manifest - app/web/public/sw.js: New service worker - app/web/public/icon-192.png: New PWA icon - app/web/public/icon-512.png: New PWA icon - app/web/public/index.html: Add manifest link, meta tags, SW registration - app/web/rollup.config.js: Add PWA files to copy targets - pkg/version/version: Bump to v0.43.1 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>main
9 changed files with 144 additions and 3 deletions
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 224 KiB |
@ -0,0 +1,22 @@ |
|||||||
|
{ |
||||||
|
"name": "ORLY Nostr Relay", |
||||||
|
"short_name": "ORLY", |
||||||
|
"description": "High-performance Nostr relay", |
||||||
|
"display": "standalone", |
||||||
|
"start_url": "/", |
||||||
|
"scope": "/", |
||||||
|
"theme_color": "#000000", |
||||||
|
"background_color": "#000000", |
||||||
|
"icons": [ |
||||||
|
{ |
||||||
|
"src": "/icon-192.png", |
||||||
|
"sizes": "192x192", |
||||||
|
"type": "image/png" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"src": "/icon-512.png", |
||||||
|
"sizes": "512x512", |
||||||
|
"type": "image/png" |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
@ -0,0 +1,95 @@ |
|||||||
|
const CACHE_VERSION = 'orly-v1'; |
||||||
|
const STATIC_ASSETS = [ |
||||||
|
'/', |
||||||
|
'/index.html', |
||||||
|
'/bundle.js', |
||||||
|
'/bundle.css', |
||||||
|
'/global.css', |
||||||
|
'/favicon.png', |
||||||
|
'/icon-192.png', |
||||||
|
'/icon-512.png', |
||||||
|
'/orly.png' |
||||||
|
]; |
||||||
|
|
||||||
|
self.addEventListener('install', (event) => { |
||||||
|
event.waitUntil( |
||||||
|
caches.open(CACHE_VERSION).then((cache) => { |
||||||
|
return cache.addAll(STATIC_ASSETS); |
||||||
|
}) |
||||||
|
); |
||||||
|
self.skipWaiting(); |
||||||
|
}); |
||||||
|
|
||||||
|
self.addEventListener('activate', (event) => { |
||||||
|
event.waitUntil( |
||||||
|
caches.keys().then((cacheNames) => { |
||||||
|
return Promise.all( |
||||||
|
cacheNames |
||||||
|
.filter((name) => name !== CACHE_VERSION) |
||||||
|
.map((name) => caches.delete(name)) |
||||||
|
); |
||||||
|
}) |
||||||
|
); |
||||||
|
self.clients.claim(); |
||||||
|
}); |
||||||
|
|
||||||
|
self.addEventListener('fetch', (event) => { |
||||||
|
const url = new URL(event.request.url); |
||||||
|
|
||||||
|
// Skip WebSocket requests
|
||||||
|
if (url.protocol === 'ws:' || url.protocol === 'wss:') { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// Skip non-GET requests
|
||||||
|
if (event.request.method !== 'GET') { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// API calls: network-first with cache fallback
|
||||||
|
if (url.pathname.startsWith('/api/')) { |
||||||
|
event.respondWith( |
||||||
|
fetch(event.request) |
||||||
|
.then((response) => { |
||||||
|
if (response.ok) { |
||||||
|
const clone = response.clone(); |
||||||
|
caches.open(CACHE_VERSION).then((cache) => { |
||||||
|
cache.put(event.request, clone); |
||||||
|
}); |
||||||
|
} |
||||||
|
return response; |
||||||
|
}) |
||||||
|
.catch(() => { |
||||||
|
return caches.match(event.request); |
||||||
|
}) |
||||||
|
); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// Static assets: cache-first with network fallback
|
||||||
|
event.respondWith( |
||||||
|
caches.match(event.request).then((cached) => { |
||||||
|
if (cached) { |
||||||
|
// Update cache in background
|
||||||
|
fetch(event.request).then((response) => { |
||||||
|
if (response.ok) { |
||||||
|
caches.open(CACHE_VERSION).then((cache) => { |
||||||
|
cache.put(event.request, response); |
||||||
|
}); |
||||||
|
} |
||||||
|
}).catch(() => {}); |
||||||
|
return cached; |
||||||
|
} |
||||||
|
|
||||||
|
return fetch(event.request).then((response) => { |
||||||
|
if (response.ok) { |
||||||
|
const clone = response.clone(); |
||||||
|
caches.open(CACHE_VERSION).then((cache) => { |
||||||
|
cache.put(event.request, clone); |
||||||
|
}); |
||||||
|
} |
||||||
|
return response; |
||||||
|
}); |
||||||
|
}) |
||||||
|
); |
||||||
|
}); |
||||||
Loading…
Reference in new issue