fix(node-player): use IndexedDB for SW token instead of postMessage
postMessage is unreliable on first load — SW may not be active yet. IndexedDB is shared between page and SW, so the token is always available regardless of SW lifecycle timing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,22 +1,44 @@
|
||||
let bearerToken = null
|
||||
const DB_NAME = 'furumi-sw'
|
||||
const STORE = 'auth'
|
||||
const KEY = 'bearer'
|
||||
|
||||
self.addEventListener('message', (e) => {
|
||||
if (e.data?.type === 'SET_TOKEN') {
|
||||
bearerToken = e.data.token
|
||||
function openDB() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const req = indexedDB.open(DB_NAME, 1)
|
||||
req.onupgradeneeded = () => req.result.createObjectStore(STORE)
|
||||
req.onsuccess = () => resolve(req.result)
|
||||
req.onerror = () => reject(req.error)
|
||||
})
|
||||
}
|
||||
|
||||
async function getToken() {
|
||||
try {
|
||||
const db = await openDB()
|
||||
return new Promise((resolve) => {
|
||||
const tx = db.transaction(STORE, 'readonly')
|
||||
const req = tx.objectStore(STORE).get(KEY)
|
||||
req.onsuccess = () => resolve(req.result || null)
|
||||
req.onerror = () => resolve(null)
|
||||
})
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
self.addEventListener('fetch', (e) => {
|
||||
const url = new URL(e.request.url)
|
||||
// Only intercept /api/ requests to the same origin
|
||||
if (url.origin !== self.location.origin || !url.pathname.startsWith('/api/')) return
|
||||
if (!bearerToken) return
|
||||
|
||||
const authedRequest = new Request(e.request, {
|
||||
headers: new Headers(e.request.headers),
|
||||
})
|
||||
authedRequest.headers.set('Authorization', `Bearer ${bearerToken}`)
|
||||
e.respondWith(fetch(authedRequest))
|
||||
e.respondWith(
|
||||
(async () => {
|
||||
const token = await getToken()
|
||||
if (!token) return fetch(e.request)
|
||||
|
||||
const headers = new Headers(e.request.headers)
|
||||
headers.set('Authorization', `Bearer ${token}`)
|
||||
return fetch(new Request(e.request, { headers }))
|
||||
})()
|
||||
)
|
||||
})
|
||||
|
||||
self.addEventListener('install', () => self.skipWaiting())
|
||||
|
||||
@@ -9,11 +9,14 @@ export const furumiApi = axios.create({
|
||||
})
|
||||
|
||||
function sendTokenToSW(token: string) {
|
||||
navigator.serviceWorker?.controller?.postMessage({ type: 'SET_TOKEN', token })
|
||||
// Also send to waiting/installing SW
|
||||
navigator.serviceWorker?.ready.then((reg) => {
|
||||
reg.active?.postMessage({ type: 'SET_TOKEN', token })
|
||||
})
|
||||
try {
|
||||
const req = indexedDB.open('furumi-sw', 1)
|
||||
req.onupgradeneeded = () => req.result.createObjectStore('auth')
|
||||
req.onsuccess = () => {
|
||||
const tx = req.result.transaction('auth', 'readwrite')
|
||||
tx.objectStore('auth').put(token, 'bearer')
|
||||
}
|
||||
} catch { /* ignore */ }
|
||||
}
|
||||
|
||||
export function setAuthToken(token: string) {
|
||||
|
||||
Reference in New Issue
Block a user