(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]; 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 middle ware 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 waitingList = []; this.middleware.forEach(function(mw) { if (typeof mw.onInstall !== 'undefined') { waitingList.push(mw.onInstall()); } }); evt.waitUntil(Promise.all(waitingList)); }; /** * 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}],6:[function(require,module,exports){ /* global caches, fetch, Promise, Request, module*/ (function() { 'use strict'; var CacheHelper = { defaultCacheName: 'offline', getCache: function getCache(name) { return caches.open(name); }, getDefaultCache: function getDefaultCache() { return this.getCache(this.defaultCacheName); }, fetchAndCache: function fetchAndChache(request, cache) { return fetch(request.clone()).then(function(response) { var clone = response.clone(); if (parseInt(clone.status) < 400) { cache.put(request.clone(), response.clone()); } return response.clone(); }); }, addAll: function addAll(cache, urls) { if (!cache) { throw new Error('Need a cache to store things'); } // Polyfill until chrome implements it if (typeof cache.addAll !== 'undefined') { return cache.addAll(urls); } var promises = []; var self = this; urls.forEach(function(url) { promises.push(self.fetchAndCache(new Request(url), cache)); }); return Promise.all(promises); } }; module.exports = CacheHelper; })(); },{}]},{},[1]) //# sourceMappingURL=sww.js.map