All files / src/services worker-service.ts

100% Statements 22/22
100% Branches 8/8
100% Functions 6/6
100% Lines 22/22

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110                                                                                                                                          2x     9x   1x     1x     1x     9x 9x 1x 1x   8x 8x 8x 7x 7x 7x   1x   8x 3x 2x 2x 1x       8x        
import { Logger } from '../utils/logger';
 
/**
 * Configuration interface for the worker service.
 * Defines properties and callbacks for service worker initialization.
 */
export type WorkerServiceConfig = {
    /**
     * Version identifier for the service worker.
     * Used to trigger service worker updates when the version changes.
     */
    version: string;
 
    /**
     * Optional callback triggered when a new version of the application is available.
     * Allows the application to notify the user and handle the update process.
     */
    onNewVersion?: () => void;
};
 
// Internal effective config for testability and browser API injection
// (not exported, just like PushServiceEffectiveConfig)
type WorkerServiceEffectiveConfig = WorkerServiceConfig & {
    navigator: Navigator;
};
 
/**
 * Service interface for managing the application's service worker.
 * Provides methods for initializing and accessing the service worker registration.
 */
export interface WorkerService {
    /**
     * Initializes the service worker with the provided configuration.
     * Registers the service worker and sets up update notification handling.
     *
     * @param config - Configuration with version and optional callbacks
     * @returns Promise that resolves when initialization is complete
     */
    initialize(config: WorkerServiceEffectiveConfig): Promise<void>;
 
    /**
     * Gets the service worker registration object, if available.
     *
     * @returns The service worker registration or undefined if not registered
     */
    get registration(): ServiceWorkerRegistration | undefined;
 
    /**
     * Gets the service worker container object, if available.
     *
     * @returns The service worker container or undefined if not supported
     */
    get container(): ServiceWorkerContainer | undefined;
 
    /**
     * Gets the active service worker controller, if available.
     *
     * @returns The active service worker controller or null/undefined if not controlling
     */
    get controller(): ServiceWorker | null | undefined;
}
 
/**
 * Factory function that creates and returns an implementation of the WorkerService interface.
 * Manages service worker registration, updates, and message handling.
 *
 * @param logger - Logger instance for error and debugging information
 * @returns An implementation of the WorkerService interface
 */
export function getWorkerService(logger: Logger): WorkerService {
    let serviceWorker: ServiceWorkerContainer | undefined;
    let registration: ServiceWorkerRegistration | undefined;
    return {
        get registration(): ServiceWorkerRegistration | undefined {
            return registration;
        },
        get container(): ServiceWorkerContainer | undefined {
            return serviceWorker;
        },
        get controller(): ServiceWorker | null | undefined {
            return serviceWorker?.controller;
        },
        async initialize(config: WorkerServiceEffectiveConfig): Promise<void> {
            const navigator = config.navigator;
            if (!('serviceWorker' in navigator)) {
                logger.warn('[worker-service] Service Worker is not supported in this browser.');
                return;
            }
            serviceWorker = navigator.serviceWorker;
            try {
                registration = await serviceWorker.register(`/service-worker.js?_=${config.version}`);
                logger.debug('[worker-service] Registered with scope:', registration.scope);
                registration = await serviceWorker.ready;
                logger.debug('[worker-service] Ready to use.');
            } catch (err) {
                logger.warn('[worker-service] Error registering:', err);
            }
            serviceWorker.addEventListener('message', (event: any) => {
                if (event.data && event.data.type === 'NEW_VERSION_AVAILABLE') {
                    logger.debug('[worker-service] New version is available.');
                    if (config.onNewVersion) {
                        config.onNewVersion();
                    }
                }
            });
            logger.debug('[worker-service] Initialized.');
        },
    };
}