{"id":15479842,"url":"https://github.com/gr2m/appcache-nanny","last_synced_at":"2025-12-12T03:12:40.303Z","repository":{"id":13974846,"uuid":"16675572","full_name":"gr2m/appcache-nanny","owner":"gr2m","description":"Auto Updates for Offline First Applications","archived":false,"fork":false,"pushed_at":"2021-03-05T06:38:40.000Z","size":1144,"stargazers_count":210,"open_issues_count":1,"forks_count":19,"subscribers_count":8,"default_branch":"main","last_synced_at":"2025-10-29T06:39:13.505Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gr2m.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-02-09T21:01:05.000Z","updated_at":"2025-05-19T12:02:34.000Z","dependencies_parsed_at":"2022-07-31T17:08:57.169Z","dependency_job_id":null,"html_url":"https://github.com/gr2m/appcache-nanny","commit_stats":null,"previous_names":["gr2m/appcache-autoupdate"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/gr2m/appcache-nanny","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gr2m%2Fappcache-nanny","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gr2m%2Fappcache-nanny/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gr2m%2Fappcache-nanny/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gr2m%2Fappcache-nanny/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gr2m","download_url":"https://codeload.github.com/gr2m/appcache-nanny/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gr2m%2Fappcache-nanny/sbom","scorecard":{"id":442862,"data":{"date":"2025-08-11","repo":{"name":"github.com/gr2m/appcache-nanny","commit":"2edfeddc711885d33dc040cf5723081aae07e384"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.9,"checks":[{"name":"Code-Review","score":2,"reason":"Found 8/27 approved changesets -- score normalized to 2","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 11 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-19T05:57:04.358Z","repository_id":13974846,"created_at":"2025-08-19T05:57:04.358Z","updated_at":"2025-08-19T05:57:04.358Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27675324,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-12T02:00:06.775Z","response_time":129,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-02T04:27:57.609Z","updated_at":"2025-12-12T03:12:40.272Z","avatar_url":"https://github.com/gr2m.png","language":"JavaScript","funding_links":[],"categories":["Tools"],"sub_categories":["Slides"],"readme":"The appCache Nanny\n==================\n\n\u003e Teaches the applicationCache douchebag some manners!\n\n[![Build Status](https://travis-ci.org/gr2m/appcache-nanny.svg?branch=main)](https://travis-ci.org/gr2m/appcache-nanny)\n[![Dependency Status](https://david-dm.org/gr2m/appcache-nanny.svg)](https://david-dm.org/gr2m/appcache-nanny)\n[![devDependency Status](https://david-dm.org/gr2m/appcache-nanny/dev-status.svg)](https://david-dm.org/gr2m/appcache-nanny#info=devDependencies)\n\nAs we all know, the [Application Cache is a Douchebag](http://alistapart.com/article/application-cache-is-a-douchebag).\nIt's time to teach it some manners – The appCache Nanny for Rescue!\n\nNo more manifest attributes on your HTML files. Whether you want to cache\nyour assets offline or not, when to start ... You Are In Control™\n\nHave a glance:\n\n```js\n// start to check for updates every 30s\nappCacheNanny.start()\n\n// optionally, pass intervals in ms\nappCacheNanny.start({checkInterval: 10000})\n\n// you can also check for updates at any time\nappCacheNanny.update()\n\n// The appCache nanny tells you if there is a new update available\nappCacheNanny.hasUpdate()\n\n// She tells you about all relevant applicationCache events\nappCacheNanny.on('update', handleUpdate)\nappCacheNanny.on('error', handleError)\nappCacheNanny.on('obsolete', handleObsolete)\nappCacheNanny.on('noupdate', handleNoupdate)\nappCacheNanny.on('downloading', handleDownloading)\nappCacheNanny.on('progress', handleProgress)\nappCacheNanny.on('cached', handleCached)\nappCacheNanny.on('updateready', handleUpdateready)\n\n// plus some extra ones\nappCacheNanny.on('init:downloading', handleInitDownloading)\nappCacheNanny.on('init:progress', handleInitProgress)\nappCacheNanny.on('init:cached', handleInitCached)\nappCacheNanny.on('start', handleStart)\nappCacheNanny.on('stop', handleStop)\n\n// options\nappCacheNanny.set('loaderPath', '/path/to/my-custom-loader.html')\nappCacheNanny.set({ 'loaderPath': '/path/to/my-custom-loader.html' })\nappCacheNanny.get('loaderPath')\nappCacheNanny.get() // returns all options\n```\n\nSetup\n-----\n\n1. Copy `appcache-loader.html` into the root directory of your app,\n   so that it's accessible at `/appcache-loader.html`.\n2. Create the `manifest.appcache` file and put it in the root directory\n   of your app, next to `/appcache-loader.html`. If you use a different\n   name, make sure to set it accordingly in `appcache-loader.html`.\n\nThen load the `appcache-nanny.js` on your HTML pages.\n\n```html\n\u003cscript src=\"appcache-nanny.js\" async\u003e\u003c/script\u003e\n```\n\nIf you use [bower](http://bower.io/), you can install it using:\n\n```\nbower install --save appcache-nanny\n```\n\nOr install via [npm](https://www.npmjs.com/)\n\n```\nnpm install --save appcache-nanny\n```\n\nBackground\n----------\n\nI extracted `appcache-nanny.js` from [minutes.io](https://minutes.io), which is an [Offline First](http://offlinefirst.org/)\nweb application, anno 2011. It's battle tested by a ton of users, devices, internet environments.\n\nminutes.io checks every 30 seconds if an update is available. And whenever the user navigates\nfrom one view to another, it reloads the page in case there is. As the assets are all cached,\nthe user cannot tell that their page got just reloaded. It's silent, without any notification,\nor a prompt asking the user to reload the page. And it works very well so far.\n\nDemo\n----\n\n![appCacheNanny demo screencast](https://raw.github.com/gr2m/appcache-nanny/main/demo/demo.gif)\n\nThe appCache Nanny comes with a simple server for testing. Start it using Node:\n\n```js\nnpm start\n```\n\nIt will start a local server at http://localhost:8888.\n\nThis is a static server with a few hidden features:\n\n- `GET /bump-version` increases the app version, so an update gets triggered\n  on next check\n- `GET /remove-manifest` makes `GET /manifest.appcache` return 404, so it\n  becomes obsolete on next check\n- `GET /recreate-manifest` undoes the previous step.\n\n\nGotchas\n-------\n\n### Unlisted paths get loaded from the server, not from cache (via FALLBACK)\n\nThanks to the [iframe hack](http://labs.ft.com/category/tutorial/), your HTML pages do\nnot get added to the list of cached assets locally, and won't get checked for updates\neach time. Which is great especially for a Single Page Application with pushState enabled.\nBut if your app has paths like `/welcome`, `/Dashboard`, `Meeting/123` and your `manifest.appcache`\nlooks something like\n\n```\nCACHE MANIFEST\n\n/\n/app.js\n/styles.css\n\nFALLBACK:\n/ /\n```\n\nBeware that opening `http://yourapp.com` will always show the currently cached\nversion, as it is explicetly listed, while `http://yourapp.com/welcome` and\nother paths will load the page from the server, unless the user is offline.\n\nYou might have learned that assets that are not listed in the cache manifest\ncannot be loaded at all, even when online. But that's not the case if the\nloaded HTML page does not have the `manifest` property on the `html` tag.\n\n\nAcknowledgement\n---------------\n\nThe appCache Nanny is based on tremendeous amount of research others have done\non applicationCache. I'd like to highlight\n\n* **[Jake Archibald](https://twitter.com/jaffathecake)**: [Application Cache is a Douchebag](http://alistapart.com/article/application-cache-is-a-douchebag)\n  and for some great laughs: [Network connectivity: optional](http://www.youtube.com/watch?v=Z7sRMg0f5Hk)\n* **[Financial Times Lab Team](http://labs.ft.com)**: [Tutorial: How to make an offline HTML5 web app](http://labs.ft.com/category/tutorial/),\n  also recommended: [Andrew Betts – Offline rules](http://www.youtube.com/watch?v=Ut4R4udJ4Gw)\n* **[Eric Bidelman](https://twitter.com/ebidel)**: [A Beginner's Guide to Using the Application Cache](http://www.html5rocks.com/en/tutorials/appcache/beginner/)\n* [Appcache Facts](http://appcache.offline.technology/) by [Mark Christian](https://twitter.com/shinypb) \u0026 [Peter Lubbers](https://twitter.com/peterlubbers)\n\n\nTODOs / IDEAs\n-------------\n\n* on obsolete, remove the iframe, load it again to check if a new *.appcache path\n  has been set. If yes, update and trigger `updateready` event, otherwise trigger\n  `obsolete` event\n\nFine Print\n----------\n\nThe appCache Nanny has been authored by [Gregor Martynus](https://github.com/gr2m),\nproud member of the [Hoodie Community](http://hood.ie/).\n\nLicense: MIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgr2m%2Fappcache-nanny","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgr2m%2Fappcache-nanny","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgr2m%2Fappcache-nanny/lists"}