UNPKG

browser-extension-manager

Version:
327 lines (269 loc) 8.92 kB
// Libraries // Variables const serviceWorker = self; // Class function Manager() { const self = this; // Properties self.extension = null; self.logger = null; // Defaults self.config = {}; self.version = '%%% version %%%'; self.brand = { name: '%%% brand.name %%%', }; self.app = '%%% app.id %%%'; self.environment = '%%% environment %%%'; self.libraries = { firebase: false, messaging: false, promoServer: false, cachePolyfill: false, }; self.cache = { breaker: '', name: '' }; // Return return self; } // Initialize Manager.prototype.initialize = function () { const self = this; return new Promise(function(resolve, reject) { // Properties self.extension = require('./lib/extension'); self.logger = new (require('./lib/logger-lite'))('background'); // Parse config file parseConfiguration(self); // Setup listeners setupListeners(self); // Import firebase // importFirebase(self); // Setup livereload setupLiveReload(self); // Log self.logger.log('Initialized!', self.version, self.cache.name, self); // Return return resolve(self); }); }; // Parse configuration function parseConfiguration(self) { try { // Log self.cache.breaker = new Date().getTime(); self.cache.name = `${self.app}-${self.cache.breaker}`; self.logger.log('Parsed configuration', self.config); } catch (e) { self.logger.error('Error parsing configuration', e); } } // Setup listeners function setupListeners(self) { // Force service worker to use the latest version serviceWorker.addEventListener('install', (event) => { event.waitUntil(serviceWorker.skipWaiting()); }); serviceWorker.addEventListener('activate', (event) => { event.waitUntil(serviceWorker.clients.claim()); }); // Handle clicks on notifications // Open the URL of the notification // ⚠️⚠️⚠️ THIS MUST BE PLACED BEFORE THE FIREBASE IMPORTS HANDLER ⚠️⚠️⚠️ // https://stackoverflow.com/questions/78270541/cant-catch-fcm-notificationclick-event-in-background-using-firebase-messa serviceWorker.addEventListener('notificationclick', (event) => { // Get the properties of the notification const notification = event.notification; const data = (notification.data && notification.data.FCM_MSG ? notification.data.FCM_MSG.data : null) || {}; const payload = (notification.data && notification.data.FCM_MSG ? notification.data.FCM_MSG.notification : null) || {}; // Get the click action const clickAction = payload.click_action || data.click_action || '/'; // Log self.logger.log('Event: notificationclick event', event); self.logger.log('Event: notificationclick data', data); self.logger.log('Event: notificationclick payload', payload); self.logger.log('Event: notificationclick clickAction', clickAction); // Handle the click event.waitUntil( clients.openWindow(clickAction) ); // Close the notification notification.close(); }); // Send messages: https://stackoverflow.com/questions/35725594/how-do-i-pass-data-like-a-user-id-to-a-web-worker-for-fetching-additional-push // more messaging: http://craig-russell.co.uk/2016/01/29/background-messaging.html#.XSKpRZNKiL8 serviceWorker.addEventListener('message', (event) => { try { // Get the data const data = event.data || {}; const response = { status: 'success', command: '', data: {} }; // Parse the data data.command = data.command || ''; data.args = data.args || {}; response.command = data.command; // Quit if no command if (data.command === '') { return }; // Log self.logger.log('Event: postMessage', data); // Handle the command if (data.command === 'function') { data.args.function = data.args.function || function() {}; data.args.function(); } else if (data.command === 'debug') { self.logger.log('Debug data =', data); event.ports[0].postMessage(response); } else if (data.command === 'skipWaiting') { self.skipWaiting(); event.ports[0].postMessage(response); } else if (data.command === 'unregister') { self.registration.unregister() .then(() => { event.ports[0].postMessage(response); }) .catch(() => { response.status = 'fail'; event.ports[0].postMessage(response); }); } else if (data.command === 'cache') { data.args.pages = data.args.pages || []; var defaultPages = [ '/', '/index.html', /* '/?homescreen=1', */ '/assets/css/main.css', '/assets/js/main.js', ]; var pagesToCache = arrayUnique(data.args.pages.concat(defaultPages)); caches.open(SWManager.cache.name).then(cache => { return cache.addAll( pagesToCache ) .then(() => { self.logger.log('Cached resources.'); event.ports[0].postMessage(response); }) .catch(() => { response.status = 'fail'; event.ports[0].postMessage(response); self.logger.log('Failed to cache resources.') }); }) } event.ports[0].postMessage(response); } catch (e) { // Set up a response response.success = 'fail'; // Try to send a response try { event.ports[0].postMessage(response) } catch (e) {} // Log self.logger.log('Failed to receive message:', data, e); } }); // Log self.logger.log('Set up listeners'); } // Import Firebase function importFirebase(self) { // Import Firebase libraries // importScripts( // 'https://www.gstatic.com/firebasejs/%%% firebaseVersion %%%/firebase-app-compat.js', // 'https://www.gstatic.com/firebasejs/%%% firebaseVersion %%%/firebase-messaging-compat.js', // 'https://www.gstatic.com/firebasejs/%%% firebaseVersion %%%/firebase-database-compat.js', // 'https://www.gstatic.com/firebasejs/%%% firebaseVersion %%%/firebase-firestore-compat.js', // ); console.error('---0'); console.error('---1', __dirname); // const firebase = require('web-manager/node_modules/firebase/firebase-app-compat.js'); // const firebase = require('web-manager'); // const firebase = require('firebase/firebase-auth-compat.js'); console.error('---2', firebase); // Initialize app const app = firebase.initializeApp(self.config.firebase); // Initialize messaging self.libraries.messaging = firebase.messaging(); // Attach firebase to SWManager self.libraries.firebase = firebase; } function setupLiveReload(self) { // Quit if not in dev mode if (self.environment !== 'development') { return }; // Setup livereload const address = `ws://localhost:%%% liveReloadPort %%%/livereload`; let connection; let isReconnecting = false; // Flag to track reconnections // Function to establish a connection function connect() { connection = new WebSocket(address); // Log connection self.logger.log(`Reload connecting to ${address}...`); // Log connection errors connection.onerror = (e) => { self.logger.error('Reload connection got error:', e); }; // Log when set up correctly connection.onopen = () => { self.logger.log('Reload connection set up!'); // Reload the extension only on reconnections if (isReconnecting) { // reload(); } // Reset the reconnection flag isReconnecting = false; }; // Handle connection close and attempt to reconnect connection.onclose = () => { // Set time const seconds = 1; // Log self.logger.log(`Reload connection closed. Attempting to reconnect in ${seconds} second(s)...`); // Set the reconnection flag isReconnecting = true; // Reconnect setTimeout(connect, seconds * 1000); // Retry }; // Handle incoming messages connection.onmessage = function (event) { if (!event.data) { return; } // Get data const data = JSON.parse(event.data); // Log self.logger.log('Reload connection got message:', data); // Handle reload command if (data && data.command === 'reload') { reload(); } }; } function reload() { self.logger.log('Reloading extension...'); setTimeout(() => { self.extension.runtime.reload(); }, 1000); } // Start the initial connection connect(); } function arrayUnique(array) { var a = array.concat(); // Loop through array for(var i=0; i<a.length; ++i) { for(var j=i+1; j<a.length; ++j) { if(a[i] === a[j]) { a.splice(j--, 1); } } } // Return return a; } // Export module.exports = Manager;