Add Mode6Test: copy of Mode5Test running on port 3000
Build & Deploy / Test & Lint (push) Has been cancelled
Build & Deploy / Security Scan (push) Has been cancelled
Code Quality / Code Quality Checks (push) Has been cancelled
Code Quality / Dependency Vulnerabilities (push) Has been cancelled
Code Quality / Performance Testing (push) Has been cancelled
Build & Deploy / Build Docker Images (push) Has been cancelled
Build & Deploy / Deploy to Kubernetes (push) Has been cancelled
Build & Deploy / Test & Lint (push) Has been cancelled
Build & Deploy / Security Scan (push) Has been cancelled
Code Quality / Code Quality Checks (push) Has been cancelled
Code Quality / Dependency Vulnerabilities (push) Has been cancelled
Code Quality / Performance Testing (push) Has been cancelled
Build & Deploy / Build Docker Images (push) Has been cancelled
Build & Deploy / Deploy to Kubernetes (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
/**
|
||||
* UTILITY: Service Worker Manager
|
||||
*
|
||||
* PURPOSE: Register and communicate with Service Worker
|
||||
* FEATURES:
|
||||
* - Register Service Worker on app load
|
||||
* - Send messages to SW
|
||||
* - Receive messages from SW
|
||||
* - Handle token refresh via SW
|
||||
*/
|
||||
|
||||
export interface TokenCheckResult {
|
||||
needsRefresh: boolean;
|
||||
timeUntilExpiry: number;
|
||||
}
|
||||
|
||||
export interface TokenRefreshResult {
|
||||
success: boolean;
|
||||
accessToken?: string;
|
||||
expiresIn?: number;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* FUNCTION: registerServiceWorker
|
||||
*
|
||||
* Register the service worker on app load
|
||||
* Called once from App.svelte onMount
|
||||
*/
|
||||
export async function registerServiceWorker(): Promise<ServiceWorkerContainer | null> {
|
||||
// Service Workers only available in production (HTTPS) or localhost
|
||||
if (!('serviceWorker' in navigator)) {
|
||||
console.log('[SW Manager] Service Workers not supported');
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
console.log('[SW Manager] Registering Service Worker...');
|
||||
|
||||
const registration = await navigator.serviceWorker.register('/service-worker.js', {
|
||||
scope: '/',
|
||||
});
|
||||
|
||||
console.log('[SW Manager] Service Worker registered:', registration);
|
||||
|
||||
// Listen for messages from Service Worker
|
||||
navigator.serviceWorker.addEventListener('message', (event) => {
|
||||
console.log('[SW Manager] Message from Service Worker:', event.data);
|
||||
});
|
||||
|
||||
return registration;
|
||||
} catch (error) {
|
||||
console.error('[SW Manager] Failed to register Service Worker:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* FUNCTION: checkTokenExpiry
|
||||
*
|
||||
* Ask Service Worker if token needs refresh
|
||||
*
|
||||
* PARAMS:
|
||||
* - tokenExpiry: number - Token expiry timestamp (ms since epoch)
|
||||
*
|
||||
* RETURNS: TokenCheckResult
|
||||
*/
|
||||
export async function checkTokenExpiry(tokenExpiry: number): Promise<TokenCheckResult> {
|
||||
if (!navigator.serviceWorker.controller) {
|
||||
console.log('[SW Manager] Service Worker not active');
|
||||
return { needsRefresh: false, timeUntilExpiry: tokenExpiry - Date.now() };
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const channel = new MessageChannel();
|
||||
|
||||
channel.port1.onmessage = (event) => {
|
||||
if (event.data.error) {
|
||||
reject(new Error(event.data.error));
|
||||
} else {
|
||||
resolve(event.data);
|
||||
}
|
||||
};
|
||||
|
||||
navigator.serviceWorker.controller?.postMessage(
|
||||
{
|
||||
type: 'CHECK_TOKEN',
|
||||
payload: { tokenExpiry },
|
||||
},
|
||||
[channel.port2]
|
||||
);
|
||||
|
||||
// Timeout after 5 seconds
|
||||
setTimeout(() => reject(new Error('Token check timeout')), 5000);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* FUNCTION: refreshTokenViaServiceWorker
|
||||
*
|
||||
* Ask Service Worker to refresh access token
|
||||
*
|
||||
* PARAMS:
|
||||
* - refreshToken: string - Refresh token
|
||||
* - apiUrl: string - Backend API URL
|
||||
*
|
||||
* RETURNS: TokenRefreshResult
|
||||
*/
|
||||
export async function refreshTokenViaServiceWorker(
|
||||
refreshToken: string,
|
||||
apiUrl: string
|
||||
): Promise<TokenRefreshResult> {
|
||||
if (!navigator.serviceWorker.controller) {
|
||||
console.log('[SW Manager] Service Worker not active');
|
||||
return { success: false, error: 'Service Worker not active' };
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const channel = new MessageChannel();
|
||||
|
||||
channel.port1.onmessage = (event) => {
|
||||
if (event.data.error) {
|
||||
resolve({ success: false, error: event.data.error });
|
||||
} else {
|
||||
resolve(event.data);
|
||||
}
|
||||
};
|
||||
|
||||
navigator.serviceWorker.controller?.postMessage(
|
||||
{
|
||||
type: 'REFRESH_TOKEN',
|
||||
payload: { refreshToken, apiUrl },
|
||||
},
|
||||
[channel.port2]
|
||||
);
|
||||
|
||||
// Timeout after 10 seconds
|
||||
setTimeout(() => reject(new Error('Token refresh timeout')), 10000);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* FUNCTION: getServiceWorkerStatus
|
||||
*
|
||||
* Get Service Worker status and version
|
||||
*
|
||||
* RETURNS: { active: boolean, version?: string }
|
||||
*/
|
||||
export async function getServiceWorkerStatus(): Promise<{ active: boolean; version?: string }> {
|
||||
if (!navigator.serviceWorker.controller) {
|
||||
return { active: false };
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const channel = new MessageChannel();
|
||||
|
||||
channel.port1.onmessage = (event) => {
|
||||
if (event.data.error) {
|
||||
reject(new Error(event.data.error));
|
||||
} else {
|
||||
resolve(event.data);
|
||||
}
|
||||
};
|
||||
|
||||
navigator.serviceWorker.controller?.postMessage(
|
||||
{ type: 'GET_STATUS' },
|
||||
[channel.port2]
|
||||
);
|
||||
|
||||
// Timeout after 5 seconds
|
||||
setTimeout(() => reject(new Error('Status check timeout')), 5000);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* FUNCTION: unregisterServiceWorker
|
||||
*
|
||||
* Unregister the service worker (for development)
|
||||
*/
|
||||
export async function unregisterServiceWorker(): Promise<void> {
|
||||
if (!('serviceWorker' in navigator)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const registrations = await navigator.serviceWorker.getRegistrations();
|
||||
for (const registration of registrations) {
|
||||
await registration.unregister();
|
||||
}
|
||||
console.log('[SW Manager] Service Worker unregistered');
|
||||
} catch (error) {
|
||||
console.error('[SW Manager] Failed to unregister Service Worker:', error);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user