[
  {
    "path": ".gitignore",
    "content": "node_modules/\n.grunt/\n.DS_Store\nnpm-debug.log\n"
  },
  {
    "path": ".npmrc",
    "content": "registry=http://registry.npmjs.org/\nsave-exact=true\n"
  },
  {
    "path": ".travis.yml",
    "content": "sudo: false\nlanguage: node_js\ncache:\n  directories:\n    - node_modules\nnotifications:\n  email: false\nnode_js:\n  - '4'\nbefore_install:\n  - npm i -g npm@^2.0.0\nbefore_script:\n  - npm prune\nafter_success:\n  - npm run semantic-release\nbranches:\n  except:\n    - \"/^v\\\\d+\\\\.\\\\d+\\\\.\\\\d+$/\"\n"
  },
  {
    "path": "Procfile",
    "content": "web: npm start\n"
  },
  {
    "path": "README.md",
    "content": "# bottle-service\n> Instant web applications restored from ServiceWorker cache\n\n[![NPM][bottle-service-icon] ][bottle-service-url]\n\n[![Build status][bottle-service-ci-image] ][bottle-service-ci-url]\n[![semantic-release][semantic-image] ][semantic-url]\n\n[Live demo](https://glebbahmutov.com/bottle-service/) - please use Chrome or Opera Desktop\n\n[Instant app demo](https://instant-todo.herokuapp.com/) - TodoMVC that is instant on\npage reload, hosted on free Heroku dyno, and needs Chrome browser for now\n\n![page source](page-source.png)\n\n## Browser support\n\n### Chrome \n\n* Nothing to do, `ServiceWorker` should be enabled by default\n\n### Firefox\n\n* Open `about:config`\n* Set the `dom.serviceWorkers.enabled` setting to **true**\n* Set the `dom.serviceWorkers.interception.enabled` setting to **true**\n\n## Api\n\nThis library attaches itself as `bottleService` object to the 'window'. Every time\nyou want to store HTML snapshot for an element with id 'myApp', call\n\n```js\n// \"my-app-name\" will be used in the future to allow separate parts of the\n// page to be saved separately\n// <div id=\"myApp\"> // controlled by the web app </div>\n// application has been rendered\nbottleService.refill('my-app-name', 'myApp')\n```\n\nThere are a couple of secondary api calls\n\n```js\nbottleService.clear('my-app-name'); // delete whatever is stored in the ServiceWorker cache\nbottleService.print('my-app-name'); // prints the stored text to console\n```\n\n## Example\n\nSee [dist/index.html](dist/index.html) that includes the \"application\" code.\nEvery time the user clicks \"Add item\" button, the application code adds a new DOM node,\nthen tells the bottle service to store the new snapshot\n\n```js\nvar applicationName = 'bottle-demo'\ndocument.getElementById('add').addEventListener('click', function () {\n  var el = document.getElementById('app')\n  var div = document.createElement('div')\n  var text = document.createTextNode('hi there')\n  div.appendChild(text)\n  el.appendChild(div)\n  // store HTML snapshot\n  bottleService.refill(applicationName, 'app')\n})\n```\n\nWhen the page loads, the ServiceWorker will intercept `index.html` and will insert\nthe saved HTML snapshot into the page before returning it back to the browser for rendering.\nThus there is no page rewriting on load, no flicker, etc.\n\n## Related\n\n* Instant web apps without page flicker or loading screens, \n  [blog post](http://glebbahmutov.com/blog/instant-web-application/), \n  [source repo](https://github.com/bahmutov/instant-vdom-todo)\n* Dynamic page rewriting on start [hydrate-vue-todo](https://github.com/bahmutov/hydrate-vue-todo)\n* Fast application start from pre-rendered HTML \n  [hydrate-vdom-todo](https://github.com/bahmutov/hydrate-vdom-todo)\n\n## Related projects using ServiceWorkers\n\n* [express-service](https://github.com/bahmutov/express-service) - run ExpressJS server\n  inside ServiceWorker\n* [service-turtle](https://github.com/bahmutov/service-turtle) - Flexible http request \n  interception using ServiceWorker\n\n### Small print\n\nAuthor: Gleb Bahmutov &copy; 2015\n\n* [@bahmutov](https://twitter.com/bahmutov)\n* [glebbahmutov.com](http://glebbahmutov.com)\n* [blog](http://glebbahmutov.com/blog/)\n\nLicense: MIT - do anything with the code, but don't blame me if it does not work.\n\nSpread the word: tweet, star on github, etc.\n\nSupport: if you find any problems with this module, email / tweet /\n[open issue](https://github.com/bahmutov/bottle-service/issues) on Github\n\n## MIT License\n\nCopyright (c) 2015 Gleb Bahmutov\n\nPermission is hereby granted, free of charge, to any person\nobtaining a copy of this software and associated documentation\nfiles (the \"Software\"), to deal in the Software without\nrestriction, including without limitation the rights to use,\ncopy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\nOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\nHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.\n\n[bottle-service-icon]: https://nodei.co/npm/bottle-service.png?downloads=true\n[bottle-service-url]: https://npmjs.org/package/bottle-service\n[bottle-service-ci-image]: https://travis-ci.org/bahmutov/bottle-service.png?branch=master\n[bottle-service-ci-url]: https://travis-ci.org/bahmutov/bottle-service\n[semantic-image]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg\n[semantic-url]: https://github.com/semantic-release/semantic-release\n"
  },
  {
    "path": "deploy.json",
    "content": "{\n  \"gh-pages\": {\n    \"options\": {\n      \"base\": \"dist\"\n    },\n    \"src\": [\n      \"index.html\",\n      \"*.js\",\n      \"*.css\"\n    ]\n  }\n}\n"
  },
  {
    "path": "dist/app.css",
    "content": ".hidden {\n  visibility: hidden;\n  display: none;\n}\nbody {\n  padding: 2em;\n  font-family: Didot, 'Didot LT STD', 'Hoefler Text', 'Garamond', 'Times New Roman', serif;\n  font-size: larger;\n  color: #333333;\n}\nbutton {\n  padding: 5px 5px;\n  background-color: white;\n  font-size: large;\n}\na {\n  text-decoration: none;\n  font-family: monospace;\n  font-size: large;\n}\n.controls {\n  margin-top: 1em;\n  padding: 1em 1em;\n  border: 1px solid #dddddd;\n  border-radius: 5px;\n  background-color: #fefefe;\n}\n"
  },
  {
    "path": "dist/bottle-service.js",
    "content": "/******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId])\n/******/ \t\t\treturn installedModules[moduleId].exports;\n\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\texports: {},\n/******/ \t\t\tid: moduleId,\n/******/ \t\t\tloaded: false\n/******/ \t\t};\n\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.loaded = true;\n\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n\n\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(0);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict'\n\n\t/*\n\t  This is ServiceWorker code\n\t*/\n\t/* global self, Response, Promise, location, fetch */\n\tvar myName = 'bottle-service'\n\tconsole.log(myName, 'startup')\n\n\tfunction dataStore () {\n\t  var cachesStorage = __webpack_require__(1)\n\t  return cachesStorage(myName)\n\t}\n\n\tself.addEventListener('install', function (event) {\n\t  console.log(myName, 'installed')\n\t})\n\n\tself.addEventListener('activate', function () {\n\t  console.log(myName, 'activated')\n\t})\n\n\tvar baseHref = location.href.substr(0, location.href.indexOf('bottle-service.js'))\n\tfunction isIndexPageRequest (event) {\n\t  return event &&\n\t    event.request &&\n\t    event.request.url === baseHref\n\t}\n\n\tself.addEventListener('fetch', function (event) {\n\t  if (!isIndexPageRequest(event)) {\n\t    return fetch(event.request)\n\t  }\n\n\t  console.log(myName, 'fetching index page', event.request.url)\n\n\t  event.respondWith(\n\t    fetch(event.request)\n\t      .then(function (response) {\n\t        return dataStore()\n\t          .then(function (store) {\n\t            return store.getItem('contents')\n\t          })\n\t          .then(function (contents) {\n\t            if (contents && contents.html && contents.id) {\n\t              console.log('fetched latest', response.url, 'need to update')\n\t              console.log('element \"%s\" with html \"%s\" ...',\n\t                contents.id, contents.html.substr(0, 15))\n\n\t              var copy = response.clone()\n\t              return copy.text().then(function (pageHtml) {\n\t                console.log('inserting our html')\n\t                // HACK using id in the CLOSING TAG to find fragment\n\t                var toReplaceStart = '<div id=\"' + contents.id + '\">'\n\t                var toReplaceFinish = '</div id=\"' + contents.id + '\">'\n\t                var startIndex = pageHtml.indexOf(toReplaceStart)\n\t                var finishIndex = pageHtml.indexOf(toReplaceFinish)\n\t                if (startIndex !== -1 && finishIndex > startIndex) {\n\t                  console.log('found fragment')\n\t                  pageHtml = pageHtml.substr(0, startIndex + toReplaceStart.length) +\n\t                    '\\n' + contents.html + '\\n' +\n\t                    pageHtml.substr(finishIndex)\n\t                }\n\n\t                // console.log('page html')\n\t                // console.log(pageHtml)\n\n\t                var responseOptions = {\n\t                  status: 200,\n\t                  headers: {\n\t                    'Content-Type': 'text/html charset=UTF-8'\n\t                  }\n\t                }\n\t                return new Response(pageHtml, responseOptions)\n\t              })\n\t            } else {\n\t              return response\n\t            }\n\t          }, function notFound () {\n\t            return response\n\t          })\n\t      })\n\t  )\n\t})\n\n\t// use window.navigator.serviceWorker.controller.postMessage('hi')\n\t// to communicate with this service worker\n\tself.onmessage = function onMessage (event) {\n\t  console.log('message to bottle-service worker cmd', event.data && event.data.cmd)\n\n\t  // TODO how to use application name?\n\n\t  dataStore().then(function (store) {\n\t    switch (event.data.cmd) {\n\t      case 'print': {\n\t        return store.getItem('contents')\n\t          .then(function (res) {\n\t            console.log('bottle service has contents')\n\t            console.log(res)\n\t          })\n\t      }\n\t      case 'clear': {\n\t        console.log('clearing the bottle')\n\t        return store.setItem('contents', {})\n\t      }\n\t      case 'refill': {\n\t        return store.setItem('contents', {\n\t          html: event.data.html,\n\t          id: event.data.id\n\t        }).then(function () {\n\t          console.log('saved new html for id', event.data.id)\n\t        })\n\t      }\n\t      default: {\n\t        console.error(myName, 'unknown command', event.data)\n\t      }\n\t    }\n\t  })\n\t}\n\n\n/***/ },\n/* 1 */\n/***/ function(module, exports) {\n\n\t// Poor man's async \"localStorage\" on top of Cache\n\t// https://developer.mozilla.org/en-US/docs/Web/API/Cache\n\tif (typeof caches === 'undefined') {\n\t  throw new Error('Cannot find object caches?! Cannot init cache-storage')\n\t}\n\t/* global caches, Response */\n\tfunction dataStore (name) {\n\t  var id = name ? name + '-v1' : 'cache-storage-v1'\n\t  return caches.open(id)\n\t    .then(function (cache) {\n\t      return {\n\t        setItem: function (key, data) {\n\t          return cache.put(key, new Response(JSON.stringify(data)))\n\t        },\n\t        getItem: function (key) {\n\t          return cache.match(key)\n\t            .then(function (res) {\n\t              return res &&\n\t                res.text().then(JSON.parse)\n\t            })\n\t        }\n\t      }\n\t    })\n\t}\n\n\tmodule.exports = dataStore\n\n\n/***/ }\n/******/ ]);"
  },
  {
    "path": "dist/bottle.js",
    "content": "!(function startBottleService (root) {\n  'use strict'\n\n  if (!root.navigator) {\n    console.error('Missing navigator')\n    return\n  }\n\n  if (!root.navigator.serviceWorker) {\n    console.error('Sorry, not ServiceWorker feature, maybe enable it?')\n    console.error('http://jakearchibald.com/2014/using-serviceworker-today/')\n    return\n  }\n\n  // TODO package lazy-ass and check-more-types using webpack\n\n  function toString (x) {\n    return typeof x === 'string' ? x : JSON.stringify(x)\n  }\n\n  function la (condition) {\n    if (!condition) {\n      var args = Array.prototype.slice.call(arguments, 1)\n        .map(toString)\n      throw new Error(args.join(' '))\n    }\n  }\n\n  function isFunction (f) {\n    return typeof f === 'function'\n  }\n\n  function getCurrentScriptFolder () {\n    var scriptEls = document.getElementsByTagName('script')\n    var thisScriptEl = scriptEls[scriptEls.length - 1]\n    var scriptPath = thisScriptEl.src\n    return scriptPath.substr(0, scriptPath.lastIndexOf('/') + 1)\n  }\n\n  var serviceScriptUrl = getCurrentScriptFolder() + 'bottle-service.js'\n  // assume we are running at <domain>/pathname\n  var scope = window.location.pathname\n\n  var send = function mockSend () {\n    console.error('Bottle service not initialized yet')\n  }\n\n  function registeredWorker (registration) {\n    la(registration, 'missing service worker registration')\n    la(registration.active, 'missing active service worker')\n    la(isFunction(registration.active.postMessage),\n      'expected function postMessage to communicate with service worker')\n\n    send = registration.active.postMessage.bind(registration.active)\n    var info = '\\nbottle-service - .\\n' +\n      'I have a valid service-turtle, use `bottleService` object to update cached page'\n    console.log(info)\n\n    registration.active.onmessage = function messageFromServiceWorker (e) {\n      console.log('received message from the service worker', e)\n    }\n  }\n\n  function onError (err) {\n    if (err.message.indexOf('missing active') !== -1) {\n      // the service worker is installed\n      window.location.reload()\n    } else {\n      console.error('bottle service error', err)\n    }\n  }\n\n  root.navigator.serviceWorker.register(serviceScriptUrl, { scope: scope })\n    .then(registeredWorker)\n    .catch(onError)\n\n  root.bottleService = {\n    refill: function refill (applicationName, id) {\n      console.log('bottle-service: html for app %s element %s', applicationName, id)\n\n      var el = document.getElementById(id)\n      la(el, 'could not find element with id', id)\n      var html = el.innerHTML.trim()\n      send({\n        cmd: 'refill',\n        html: html,\n        name: applicationName,\n        id: id\n      })\n    },\n    print: function print (applicationName) {\n      send({\n        cmd: 'print',\n        name: applicationName\n      })\n    },\n    clear: function clear (applicationName) {\n      send({\n        cmd: 'clear',\n        name: applicationName\n      })\n    }\n  }\n}(window))\n"
  },
  {
    "path": "dist/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n  <meta charset=\"utf-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n  <title>bottle-service</title>\n  <link rel=\"stylesheet\" href=\"app.css\">\n</head>\n\n<body>\n  <a href=\"http://github.com/bahmutov/bottle-service\" class=\"github-corner\"><svg width=\"80\" height=\"80\" viewBox=\"0 0 250 250\" style=\"fill:#70B7FD; color:#fff; position: absolute; top: 0; border: 0; right: 0;\"><path d=\"M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z\"></path><path d=\"M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2\" fill=\"currentColor\" style=\"transform-origin: 130px 106px;\" class=\"octo-arm\"></path><path d=\"M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z\" fill=\"currentColor\" class=\"octo-body\"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>\n\n  <h1>bottle-service (tested on Chrome Desktop only)</h1>\n\n  <p>This page can rewrite itself inside a ServiceWorker behind this website.\n  Try adding a couple of DOM nodes using a button below, then reload the page.\n  Notice that the page <strong>arrives with new DOM nodes</strong> to the browser,\n  thus there is no blinking / initial pause. If you inspect the fetched page's source\n  in the Network tab you will see the updated HTML on each reload.</p>\n  <p>The self-rewriting portion is below</p>\n  <!-- terrible hack to quickly remove inner contents - set the id on the closing tag -->\n  <div id=\"app\">some content here already</div id=\"app\">\n\n  <div class=\"controls\">\n    Controls\n    <button id=\"add\">Add new DOM node to the list</button>\n    <button id=\"print\">Print current bottle contents</button>\n    <button id=\"clear\">Clear cached HTML</button>\n    <ul>\n      <li>\"Add\" - inserts a new item into the rewritable portion of this page. Stores the dynamic\n      HTML portion in the ServiceWorker for the future reload</li>\n      <li>\"Print\" - prints what is currently stored for the rewritable portion of the page in the\n      ServiceWorker (open browser console to view)</li>\n      <li>\"Clear\" - clears the stored HTML from the ServiceWorker storage</li>\n    </ul>\n  </div>\n  <div class=\"instructions\">\n    <h3>How to use</h3>\n    <p>Load the page first - I assume you have already done this, if you are reading this</p>\n    <p>Click \"Add ...\" button several times, you should see new items in the list.</p>\n    <p>Reload the page - you should see the items you have added right away - they are part\n    of the loaded page, <strong>not added dynamically later</strong>. You can confirm\n    this by inspecting the downloaded page's source or the contents of the page in the Network tab.</p>\n    <h4>Note</h4>\n    <p>Open browser console to see any messages / errors</p>\n  </div>\n\n  <script src=\"bottle.js\"></script>\n\n  <script>\n    var applicationName = 'bottle-demo'\n    console.log('page code for', applicationName)\n    document.getElementById('add').addEventListener('click', function () {\n      console.log('adding item to the list')\n      var el = document.getElementById('app')\n      var div = document.createElement('div')\n      var text = document.createTextNode('hi there')\n      div.appendChild(text)\n      el.appendChild(div)\n      bottleService.refill(applicationName, 'app')\n    })\n\n    document.getElementById('print')\n      .addEventListener('click', function () {\n        console.log('open browser console to see the cached HTML source');\n        bottleService.print(applicationName)\n      })\n\n    document.getElementById('clear')\n      .addEventListener('click', function () {\n        var el = document.getElementById('app')\n        el.innerHTML = ''\n        bottleService.clear(applicationName)\n      })\n  </script>\n</body>\n</html>\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"bottle-service\",\n  \"description\": \"Instant web applications restored from ServiceWorker cache\",\n  \"main\": \"index.js\",\n  \"version\": \"0.0.0-semantic-release\",\n  \"files\": [\n    \"dist/*.js\"\n  ],\n  \"scripts\": {\n    \"test\": \"npm run lint\",\n    \"lint\": \"standard src/*.js\",\n    \"semantic-release\": \"semantic-release pre && npm publish && semantic-release post\",\n    \"build\": \"cp src/bottle.js dist/ && npm run webpack\",\n    \"webpack\": \"webpack\",\n    \"deploy\": \"grunty grunt-gh-pages gh-pages deploy.json\",\n    \"start\": \"http-server dist -c-1\",\n    \"dev-start\": \"http-server dist -c-1 -p 3006\",\n    \"commit\": \"commit-wizard\",\n    \"size\": \"t=\\\"$(npm pack .)\\\"; wc -c \\\"${t}\\\"; tar tvf \\\"${t}\\\"; rm \\\"${t}\\\";\",\n    \"issues\": \"git-issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/bahmutov/bottle-service.git\"\n  },\n  \"keywords\": [\n    \"service\",\n    \"worker\",\n    \"serviceWorker\",\n    \"cache\",\n    \"hydrate\",\n    \"web\",\n    \"performance\"\n  ],\n  \"author\": \"Gleb Bahmutov <gleb.bahmutov@gmail.com>\",\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/bahmutov/bottle-service/issues\"\n  },\n  \"homepage\": \"https://github.com/bahmutov/bottle-service#readme\",\n  \"dependencies\": {\n    \"caches-storage\": \"1.1.0\",\n    \"http-server\": \"0.8.5\"\n  },\n  \"devDependencies\": {\n    \"git-issues\": \"1.2.0\",\n    \"grunt\": \"0.4.5\",\n    \"grunt-gh-pages\": \"1.0.0\",\n    \"grunty\": \"0.2.0\",\n    \"pre-git\": \"3.1.1\",\n    \"semantic-release\": \"^4.3.5\",\n    \"standard\": \"5.4.1\",\n    \"webpack\": \"1.12.9\"\n  },\n  \"private\": false,\n  \"config\": {\n    \"pre-git\": {\n      \"commit-msg\": [\n        \"simple\"\n      ],\n      \"pre-commit\": [\n        \"npm run lint\"\n      ],\n      \"pre-push\": [\n        \"npm run size\"\n      ],\n      \"post-commit\": [],\n      \"post-merge\": []\n    }\n  }\n}\n"
  },
  {
    "path": "src/bottle-service.js",
    "content": "'use strict'\n\n/*\n  This is ServiceWorker code\n*/\n/* global self, Response, Promise, location, fetch */\nvar myName = 'bottle-service'\nconsole.log(myName, 'startup')\n\nfunction dataStore () {\n  var cachesStorage = require('caches-storage')\n  return cachesStorage(myName)\n}\n\nself.addEventListener('install', function (event) {\n  console.log(myName, 'installed')\n})\n\nself.addEventListener('activate', function () {\n  console.log(myName, 'activated')\n})\n\nvar baseHref = location.href.substr(0, location.href.indexOf('bottle-service.js'))\nfunction isIndexPageRequest (event) {\n  return event &&\n    event.request &&\n    event.request.url === baseHref\n}\n\nself.addEventListener('fetch', function (event) {\n  if (!isIndexPageRequest(event)) {\n    return fetch(event.request)\n  }\n\n  console.log(myName, 'fetching index page', event.request.url)\n\n  event.respondWith(\n    fetch(event.request)\n      .then(function (response) {\n        return dataStore()\n          .then(function (store) {\n            return store.getItem('contents')\n          })\n          .then(function (contents) {\n            if (contents && contents.html && contents.id) {\n              console.log('fetched latest', response.url, 'need to update')\n              console.log('element \"%s\" with html \"%s\" ...',\n                contents.id, contents.html.substr(0, 15))\n\n              var copy = response.clone()\n              return copy.text().then(function (pageHtml) {\n                console.log('inserting our html')\n                // HACK using id in the CLOSING TAG to find fragment\n                var toReplaceStart = '<div id=\"' + contents.id + '\">'\n                var toReplaceFinish = '</div id=\"' + contents.id + '\">'\n                var startIndex = pageHtml.indexOf(toReplaceStart)\n                var finishIndex = pageHtml.indexOf(toReplaceFinish)\n                if (startIndex !== -1 && finishIndex > startIndex) {\n                  console.log('found fragment')\n                  pageHtml = pageHtml.substr(0, startIndex + toReplaceStart.length) +\n                    '\\n' + contents.html + '\\n' +\n                    pageHtml.substr(finishIndex)\n                }\n\n                // console.log('page html')\n                // console.log(pageHtml)\n\n                var responseOptions = {\n                  status: 200,\n                  headers: {\n                    'Content-Type': 'text/html charset=UTF-8'\n                  }\n                }\n                return new Response(pageHtml, responseOptions)\n              })\n            } else {\n              return response\n            }\n          }, function notFound () {\n            return response\n          })\n      })\n  )\n})\n\n// use window.navigator.serviceWorker.controller.postMessage('hi')\n// to communicate with this service worker\nself.onmessage = function onMessage (event) {\n  console.log('message to bottle-service worker cmd', event.data && event.data.cmd)\n\n  // TODO how to use application name?\n\n  dataStore().then(function (store) {\n    switch (event.data.cmd) {\n      case 'print': {\n        return store.getItem('contents')\n          .then(function (res) {\n            console.log('bottle service has contents')\n            console.log(res)\n          })\n      }\n      case 'clear': {\n        console.log('clearing the bottle')\n        return store.setItem('contents', {})\n      }\n      case 'refill': {\n        return store.setItem('contents', {\n          html: event.data.html,\n          id: event.data.id\n        }).then(function () {\n          console.log('saved new html for id', event.data.id)\n        })\n      }\n      default: {\n        console.error(myName, 'unknown command', event.data)\n      }\n    }\n  })\n}\n"
  },
  {
    "path": "src/bottle.js",
    "content": "!(function startBottleService (root) {\n  'use strict'\n\n  if (!root.navigator) {\n    console.error('Missing navigator')\n    return\n  }\n\n  if (!root.navigator.serviceWorker) {\n    console.error('Sorry, not ServiceWorker feature, maybe enable it?')\n    console.error('http://jakearchibald.com/2014/using-serviceworker-today/')\n    return\n  }\n\n  // TODO package lazy-ass and check-more-types using webpack\n\n  function toString (x) {\n    return typeof x === 'string' ? x : JSON.stringify(x)\n  }\n\n  function la (condition) {\n    if (!condition) {\n      var args = Array.prototype.slice.call(arguments, 1)\n        .map(toString)\n      throw new Error(args.join(' '))\n    }\n  }\n\n  function isFunction (f) {\n    return typeof f === 'function'\n  }\n\n  function getCurrentScriptFolder () {\n    var scriptEls = document.getElementsByTagName('script')\n    var thisScriptEl = scriptEls[scriptEls.length - 1]\n    var scriptPath = thisScriptEl.src\n    return scriptPath.substr(0, scriptPath.lastIndexOf('/') + 1)\n  }\n\n  var serviceScriptUrl = getCurrentScriptFolder() + 'bottle-service.js'\n  // assume we are running at <domain>/pathname\n  var scope = window.location.pathname\n\n  var send = function mockSend () {\n    console.error('Bottle service not initialized yet')\n  }\n\n  function registeredWorker (registration) {\n    la(registration, 'missing service worker registration')\n    la(registration.active, 'missing active service worker')\n    la(isFunction(registration.active.postMessage),\n      'expected function postMessage to communicate with service worker')\n\n    send = registration.active.postMessage.bind(registration.active)\n    var info = '\\nbottle-service - .\\n' +\n      'I have a valid service-turtle, use `bottleService` object to update cached page'\n    console.log(info)\n\n    registration.active.onmessage = function messageFromServiceWorker (e) {\n      console.log('received message from the service worker', e)\n    }\n  }\n\n  function onError (err) {\n    if (err.message.indexOf('missing active') !== -1) {\n      // the service worker is installed\n      window.location.reload()\n    } else {\n      console.error('bottle service error', err)\n    }\n  }\n\n  root.navigator.serviceWorker.register(serviceScriptUrl, { scope: scope })\n    .then(registeredWorker)\n    .catch(onError)\n\n  root.bottleService = {\n    refill: function refill (applicationName, id) {\n      console.log('bottle-service: html for app %s element %s', applicationName, id)\n\n      var el = document.getElementById(id)\n      la(el, 'could not find element with id', id)\n      var html = el.innerHTML.trim()\n      send({\n        cmd: 'refill',\n        html: html,\n        name: applicationName,\n        id: id\n      })\n    },\n    print: function print (applicationName) {\n      send({\n        cmd: 'print',\n        name: applicationName\n      })\n    },\n    clear: function clear (applicationName) {\n      send({\n        cmd: 'clear',\n        name: applicationName\n      })\n    }\n  }\n}(window))\n"
  },
  {
    "path": "webpack.config.js",
    "content": "module.exports = {\n  output: {\n    path: './dist',\n    filename: 'bottle-service.js'\n  },\n  entry: {\n    library: './src/bottle-service'\n  }\n}\n"
  }
]