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 @@
@@ -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 @@
@@ -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