(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o= middleware.length) { return Promise.resolve(response); } var mw = middleware[current]; if (request) { request.parameters = mw.__params; } var endWith = ServiceWorkerWare.endWith; var answer = mw(request, response, endWith); var normalized = ServiceWorkerWare.normalizeMwAnswer(answer, request, response); return normalized.then(function (info) { switch (info.nextAction) { case TERMINATE: return Promise.resolve(info.response); case ERROR: return Promise.reject(info.error); case CONTINUE: var next = current + 1; var request = info.request; var response = info.response; return this.runMiddleware(middleware, next, request, response); } }.bind(this)); }; /** * A function to force interruption of the pipeline. * * @param {Response} the response object that will be used to answer from the * service worker. */ ServiceWorkerWare.endWith = function (response) { if (arguments.length === 0) { throw new Error('Type error: endWith() must be called with a value.'); } return [TERMINATION_TOKEN, response]; }; /** * A middleware is supposed to return a promise resolving in a pair of request * and response for the next one or to indicate that it wants to answer * immediately. * * To allow flexibility, the middleware is allowed to return other values * rather than the promise. For instance, it is allowed to return only a * request meaning the next middleware will be passed that request but the * previous response untouched. * * The function takes into account all the scenarios to compute the request * and response for the next middleware or the intention to terminate * immediately. * * @param {Any} non normalized answer from the middleware. * @param {Request} request passed as parameter to the middleware. * @param {Response} response passed as parameter to the middleware. */ ServiceWorkerWare.normalizeMwAnswer = function (answer, request, response) { if (!answer || !answer.then) { answer = Promise.resolve(answer); } return answer.then(function (value) { var nextAction = CONTINUE; var error, nextRequest, nextResponse; var isArray = Array.isArray(value); if (isArray && value[0] === TERMINATION_TOKEN) { nextAction = TERMINATE; nextRequest = request; nextResponse = value[1] || response; } else if (value === null) { nextRequest = request; nextResponse = null; } else if (isArray && value.length === 2) { nextRequest = value[0]; nextResponse = value[1]; } else if (value instanceof Response) { nextRequest = request; nextResponse = value; } else if (value instanceof Request) { nextRequest = value; nextResponse = response; } else { var msg = 'Type error: middleware must return a Response, ' + 'a Request, a pair [Response, Request] or a Promise ' + 'resolving to one of these types.'; nextAction = ERROR; error = new Error(msg); } return { nextAction: nextAction, request: nextRequest, response: nextResponse, error: error }; }); }; /** * Walk all the middleware installed asking if they have prerequisites * (on the way of a promise to be resolved) when installing the SW. */ ServiceWorkerWare.prototype.onInstall = function sww_oninstall(evt) { var installation = this.getFromMiddleware('onInstall'); evt.waitUntil(installation); }; /** * Walk all the installed middleware asking if they have prerequisites * (on the way of a promise to be resolved) when SW activates. */ ServiceWorkerWare.prototype.onActivate = function sww_activate(evt) { var activation = this.getFromMiddleware('onActivate'); if (this.autoClaim) { activation = activation.then(function claim() { return self.clients.claim(); }); } evt.waitUntil(activation); }; /** * Returns a promise gathering the results for executing the same method for * all the middleware. * @param {Function} the method to be executed. * @param {Promise} a promise resolving once all the results have been gathered. */ ServiceWorkerWare.prototype.getFromMiddleware = function sww_getFromMiddleware(method) { var tasks = this.middleware.reduce(function (tasks, mw) { if (typeof mw[method] === 'function') { tasks.push(mw[method]()); } return tasks; }, []); return Promise.all(tasks); }; /** * Register a new middleware layer, they will treat the request in * the order that this layers have been defined. * A middleware layer can behave in the ServiceWorker in two ways: * - Listening to SW lifecycle events (install, activate, message). * - Handle a request. * To handle each case (or both) the middleware object should provide * the following methods: * - on: for listening to SW lifeciclye events * - onFetch: for handling fetch urls */ ServiceWorkerWare.prototype.use = function sww_use() { // If the first parameter is not a function we will understand that // is the path to handle, and the handler will be the second parameter if (arguments.length === 0) { throw new Error('No arguments given'); } var mw = arguments[0]; var path = '*'; var method = this.router.ALL_METHODS; if (typeof mw === 'string') { path = arguments[0]; mw = arguments[1]; var kind = typeof mw; if (!mw || !(kind === 'object' || kind === 'function')) { throw new Error('No middleware specified'); } if (Router.prototype.methods.indexOf(arguments[2]) !== -1) { method = arguments[2]; } } this.middleware.push(mw); // Add to the router just if middleware object is able to handle onFetch // or if we have a simple function var handler = null; if (typeof mw.onFetch === 'function') { handler = mw.onFetch.bind(mw); } else if (typeof mw === 'function') { handler = mw; } if (handler) { this.router.add(method, path, handler); } // XXX: Attaching the broadcastMessage to mw that implements onMessage. // We should provide a way to get a reference to the SWW object and do // the broadcast from there if (typeof mw.onMessage === 'function') { mw.broadcastMessage = this.broadcastMessage; } }; /** * Forward the event received to any middleware layer that has a 'on' * handler */ ServiceWorkerWare.prototype.forwardEvent = function sww_forwardEvent(evt) { this.middleware.forEach(function(mw) { var handlerName = 'on' + evt.type.replace(/^[a-z]/, function(m){ return m.toUpperCase(); } ); if (typeof mw[handlerName] !== 'undefined') { mw[handlerName].call(mw, evt); } }); }; /** * Broadcast a message to all worker clients * @param msg Object the message * @param channel String (Used just in Firefox Nightly) using broadcastchannel * api to deliver the message, this parameter can be undefined as we listen for * a channel undefined in the client. */ ServiceWorkerWare.prototype.broadcastMessage = function sww_broadcastMessage( msg, channel) { // XXX: Until https://bugzilla.mozilla.org/show_bug.cgi?id=1130685 is fixed // we can use BroadcastChannel API in Firefox Nightly if (typeof BroadcastChannel === 'function') { var bc = new BroadcastChannel(channel); bc.postMessage(msg); bc.close(); return Promise.resolve(); } else { // This is suppose to be the way of broadcasting a message, unfortunately // it's not working yet in Chrome Canary return clients.matchAll().then(function(consumers) { consumers.forEach(function(client) { client.postMessage(msg); }); }); } }; ServiceWorkerWare.decorators = { ifNoResponse: function (mw) { return function (req, res, endWith) { if (res) { return [req, res]; } return mw(req, res, endWith); }; }, stopAfter: function (mw) { return function (req, res, endWith) { var answer = mw(req, res, endWith); var normalized = ServiceWorkerWare.normalizeMwAnswer(answer, req, res); return normalized.then(function (info) { if (info.nextAction === 'error') { return Promise.reject(info.error); } return endWith(info.response); }); }; } }; module.exports = { ServiceWorkerWare: ServiceWorkerWare, StaticCacher: StaticCacher, SimpleOfflineCache: SimpleOfflineCache }; },{"./router.js":2,"./simpleofflinecache.js":3,"./staticcacher.js":4}]},{},[1]);