{"_id":"@baryodev/pwa-kit","_rev":"5-64c98f67317cc3a7704f5ff5f82acb24","name":"@baryodev/pwa-kit","dist-tags":{"latest":"0.5.0"},"versions":{"0.1.0":{"name":"@baryodev/pwa-kit","version":"0.1.0","keywords":["pwa","service-worker","install","add-to-home-screen","offline","react"],"author":{"name":"BaryoDev"},"license":"MIT","_id":"@baryodev/pwa-kit@0.1.0","maintainers":[{"name":"arnelirobles","email":"arnelirobles@gmail.com"}],"homepage":"https://github.com/BaryoDev/pwa-kit","bugs":{"url":"https://github.com/BaryoDev/pwa-kit/issues"},"dist":{"shasum":"8f32893c973a30b0eb5be74fd6783405ef67ebb4","tarball":"https://registry.npmjs.org/@baryodev/pwa-kit/-/pwa-kit-0.1.0.tgz","fileCount":9,"integrity":"sha512-riGVnKWRPiFgnHo5blw2mKk0odntpjI94ZXYGHvN8ioFNXKROtydmsihNwJ8uBqC2u7lJRVe6QA7bhw+T/4IQA==","signatures":[{"sig":"MEYCIQCeloKAbX8jmOCYoFh25cTadNFc7dGjxKRm2SQtcYTtwwIhAM/MYL3joxC8DTQu4NeBgSll/aYCWL9nEbao3O5pX4ZS","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":61735},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"gitHead":"6bb547c7a648f055ae6cb691714677c39132848a","scripts":{"build":"tsup","prepublishOnly":"npm run build"},"_npmUser":{"name":"arnelirobles","email":"arnelirobles@gmail.com"},"repository":{"url":"git+https://github.com/BaryoDev/pwa-kit.git","type":"git"},"_npmVersion":"10.9.4","description":"Drop-in PWA kit: install prompt (Android + iOS), a secure network-first service worker, and helpers. Framework-agnostic React.","directories":{},"sideEffects":false,"_nodeVersion":"22.22.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.0","react":"^19.0.0","typescript":"^5.6.0","@types/react":"^19.0.0"},"peerDependencies":{"react":">=17"},"peerDependenciesMeta":{"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pwa-kit_0.1.0_1784269300812_0.1885530537590443","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@baryodev/pwa-kit","version":"0.2.0","keywords":["pwa","service-worker","install","add-to-home-screen","offline","react"],"author":{"name":"BaryoDev"},"license":"MIT","_id":"@baryodev/pwa-kit@0.2.0","maintainers":[{"name":"arnelirobles","email":"arnelirobles@gmail.com"}],"homepage":"https://github.com/BaryoDev/pwa-kit","bugs":{"url":"https://github.com/BaryoDev/pwa-kit/issues"},"dist":{"shasum":"4be0827e090b3c1e689e98cafcd07653b93d4a60","tarball":"https://registry.npmjs.org/@baryodev/pwa-kit/-/pwa-kit-0.2.0.tgz","fileCount":9,"integrity":"sha512-M3Ypli7BIwaYw41GrtSNJvZjXbX4AlAbgUE8ObH9GP3m/w02tRrV6GeeTTo4Ya/R3BTIoxNPJk2dRFNLjhK1cw==","signatures":[{"sig":"MEUCIQCxysghBoDcn6fkyBlcnW/KHS/EO5/PfrKwoBCqN5vtswIgbXx+62vpTqp4aZgpzhKznFXnnikhEkSGVBrsTXxaAwM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":71229},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"gitHead":"a234b30ed0bf6aebefaef47cc95f16d9667494ba","scripts":{"build":"tsup","prepublishOnly":"npm run build"},"_npmUser":{"name":"arnelirobles","email":"arnelirobles@gmail.com"},"repository":{"url":"git+https://github.com/BaryoDev/pwa-kit.git","type":"git"},"_npmVersion":"10.9.4","description":"Drop-in PWA kit: install prompt (Android + iOS), a secure network-first service worker, and helpers. Framework-agnostic React.","directories":{},"sideEffects":false,"_nodeVersion":"22.22.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.0","react":"^19.0.0","typescript":"^5.6.0","@types/react":"^19.0.0"},"peerDependencies":{"react":">=17"},"peerDependenciesMeta":{"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pwa-kit_0.2.0_1784345150024_0.17444978264911848","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@baryodev/pwa-kit","version":"0.3.0","keywords":["pwa","service-worker","install","add-to-home-screen","offline","react"],"author":{"name":"BaryoDev"},"license":"MIT","_id":"@baryodev/pwa-kit@0.3.0","maintainers":[{"name":"arnelirobles","email":"arnelirobles@gmail.com"}],"homepage":"https://github.com/BaryoDev/pwa-kit","bugs":{"url":"https://github.com/BaryoDev/pwa-kit/issues"},"dist":{"shasum":"bfd2582bb6d2ebeec6d311b705acea655938847c","tarball":"https://registry.npmjs.org/@baryodev/pwa-kit/-/pwa-kit-0.3.0.tgz","fileCount":9,"integrity":"sha512-nZtgxjLIC1sBIZG8RESyyijt4akRKg+2FM8Pt5aRy2pGFNuKIBTaisK4O9XLx570qV19mLQQtPsXhpUUySlHgA==","signatures":[{"sig":"MEQCIH0JatR2z36N49TuRya0cQccV7d5DIH6ijS5UiAQHXQgAiAuNFomcjH2hwjbqTgCLxaXvEB4TxiqsrY52ugFTnnLTQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@baryodev%2fpwa-kit@0.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":76459},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"gitHead":"a33c81201d8e3b43fcb6d4276dec5c0cd5e942fa","scripts":{"build":"tsup","prepublishOnly":"npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:2df98fd0-ab37-4b91-8cc2-b7aef66dc1e0"}},"repository":{"url":"git+https://github.com/BaryoDev/pwa-kit.git","type":"git"},"_npmVersion":"12.0.1","description":"Drop-in PWA kit: install prompt (Android + iOS), a secure network-first service worker, and helpers. Framework-agnostic React.","directories":{},"sideEffects":false,"_nodeVersion":"22.23.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.0","react":"^19.0.0","typescript":"^5.6.0","@types/react":"^19.0.0"},"peerDependencies":{"react":">=17"},"peerDependenciesMeta":{"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pwa-kit_0.3.0_1784451774720_0.11831729985520445","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@baryodev/pwa-kit","version":"0.4.0","keywords":["pwa","service-worker","install","add-to-home-screen","offline","react"],"author":{"name":"BaryoDev"},"license":"MIT","_id":"@baryodev/pwa-kit@0.4.0","maintainers":[{"name":"arnelirobles","email":"arnelirobles@gmail.com"}],"homepage":"https://github.com/BaryoDev/pwa-kit","bugs":{"url":"https://github.com/BaryoDev/pwa-kit/issues"},"dist":{"shasum":"a038c4773f11cccb8d012415ebefcd9744370ac0","tarball":"https://registry.npmjs.org/@baryodev/pwa-kit/-/pwa-kit-0.4.0.tgz","fileCount":9,"integrity":"sha512-KwG2Krj7ilcKpo6HOtBe+ZGYuN8QZJHfQBYL2U6gmC2BHok7DK/KRur0iecGirrGt2hnTOfc9ZLHK82DQMM2ew==","signatures":[{"sig":"MEUCIH9jcKWwNDA9P/JnRrwjPEdL0SBmbN6/d8lxEv6zTbeZAiEAxci7ILoFsTKtohmQybJ51oATAekqhcaoNuIHSioeu/g=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@baryodev%2fpwa-kit@0.4.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":93798},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"gitHead":"725777c006857a8c2dd47e5807f168c09df5ce49","scripts":{"build":"tsup","prepublishOnly":"npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:2df98fd0-ab37-4b91-8cc2-b7aef66dc1e0"}},"repository":{"url":"git+https://github.com/BaryoDev/pwa-kit.git","type":"git"},"_npmVersion":"12.0.1","description":"Drop-in PWA kit: install prompt (Android + iOS), a secure network-first service worker, and helpers. Framework-agnostic React.","directories":{},"sideEffects":false,"_nodeVersion":"22.23.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.0","react":"^19.0.0","typescript":"^5.6.0","@types/react":"^19.0.0"},"peerDependencies":{"react":">=17"},"peerDependenciesMeta":{"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pwa-kit_0.4.0_1784529517207_0.673198313198311","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@baryodev/pwa-kit","version":"0.5.0","description":"Drop-in PWA kit: install prompt (Android + iOS), a secure network-first service worker, and helpers. Framework-agnostic React.","keywords":["pwa","service-worker","install","add-to-home-screen","offline","react"],"license":"MIT","author":{"name":"BaryoDev"},"homepage":"https://github.com/BaryoDev/pwa-kit","repository":{"type":"git","url":"git+https://github.com/BaryoDev/pwa-kit.git"},"type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./report":{"types":"./dist/report.d.ts","import":"./dist/report.js","require":"./dist/report.cjs"}},"sideEffects":false,"scripts":{"build":"tsup","prepublishOnly":"npm run build"},"peerDependencies":{"react":">=17"},"peerDependenciesMeta":{"react":{"optional":true}},"devDependencies":{"@types/react":"^19.0.0","react":"^19.0.0","tsup":"^8.3.0","typescript":"^5.6.0"},"publishConfig":{"access":"public"},"gitHead":"2315e1214c50658396419610ee10c85216b5904a","_id":"@baryodev/pwa-kit@0.5.0","bugs":{"url":"https://github.com/BaryoDev/pwa-kit/issues"},"_nodeVersion":"22.23.2","_npmVersion":"12.0.2","dist":{"integrity":"sha512-fy9RH+pazPiG/o+gnkMq9C9V1l/2a5Kw4RcNZHbcTyA/ap6GxtcxDg4NTwiPPHbxnEmYzbxXZAlATMgq8ehf9w==","shasum":"dff8ac256dfa8e37146f4c3caaf6ed6bbf483189","tarball":"https://registry.npmjs.org/@baryodev/pwa-kit/-/pwa-kit-0.5.0.tgz","fileCount":16,"unpackedSize":116358,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@baryodev%2fpwa-kit@0.5.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIFZeUN89UknW6wjbjWL0D2epZniQIELNJOn4bbiJakapAiEAvmZezJSTyi+2NFIk/r2EcxaQLeaLNuM87SZ90UJi5jc="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:2df98fd0-ab37-4b91-8cc2-b7aef66dc1e0"}},"directories":{},"maintainers":[{"name":"arnelirobles","email":"arnelirobles@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/pwa-kit_0.5.0_1787819906852_0.9816726758255057"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-17T06:21:40.670Z","modified":"2026-08-27T08:38:27.286Z","0.1.0":"2026-07-17T06:21:40.937Z","0.2.0":"2026-07-18T03:25:50.168Z","0.3.0":"2026-07-19T09:02:54.853Z","0.4.0":"2026-07-20T06:38:37.355Z","0.5.0":"2026-08-27T08:38:26.979Z"},"bugs":{"url":"https://github.com/BaryoDev/pwa-kit/issues"},"author":{"name":"BaryoDev"},"license":"MIT","homepage":"https://github.com/BaryoDev/pwa-kit","keywords":["pwa","service-worker","install","add-to-home-screen","offline","react"],"repository":{"type":"git","url":"git+https://github.com/BaryoDev/pwa-kit.git"},"description":"Drop-in PWA kit: install prompt (Android + iOS), a secure network-first service worker, and helpers. Framework-agnostic React.","maintainers":[{"name":"arnelirobles","email":"arnelirobles@gmail.com"}],"readme":"<div align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/BaryoDev/pwa-kit/main/logo.svg\" alt=\"pwa-kit\" width=\"88\" height=\"88\" />\n  <h1>@baryodev/pwa-kit</h1>\n  <p><em>Drop-in PWA essentials: an install prompt for Android + iOS, a secure network-first service worker, and helpers.</em></p>\n</div>\n\nTurn any web app into an installable, offline-capable one. Framework-agnostic (the React component\nuses inline styles, so no CSS setup needed).\n\n## Why\n\nTurning a site into an installable, offline-capable app means three fiddly pieces every time: an\ninstall affordance (Android has a prompt event, iOS doesn't), a service worker with a sane caching\nstrategy, and cache hygiene so one user's data isn't served to another. This packages all three.\n\n## Install\n\n```sh\nnpm i @baryodev/pwa-kit\n```\n\n## 1. Service worker\n\nGenerate the worker source and write it to a file your site serves at the **root** (so its scope\ncovers the whole app):\n\n```ts\n// scripts/gen-sw.mjs\nimport { writeFileSync } from \"node:fs\";\nimport { generateServiceWorker } from \"@baryodev/pwa-kit\";\n\nwriteFileSync(\n  \"public/sw.js\",\n  generateServiceWorker({\n    cachePrefix: \"myapp\",          // -> myapp-shell-v1 / myapp-api-v1\n    apiPrefix: \"/api/\",            // requests treated as live data\n    skipPaths: [\"/api/auth/\", \"/api/files/\"], // never cached\n    navigationFallback: \"/\",       // shown when offline with nothing cached\n  }),\n);\n```\n\n```jsonc\n// package.json\n\"scripts\": { \"prebuild\": \"node scripts/gen-sw.mjs\" }\n```\n\n**Caching strategy**\n\n- App shell / static assets: cache-first (fast, works offline).\n- Navigations: network-first, cached page as an offline fallback.\n- API `GET`s: **network-first** — online always gets fresh data; the last good response is kept\n  only as an offline fallback, so lists still show like a native app with no signal.\n- Writes (`POST`/`PUT`/…) always hit the network.\n\n**Security**\n\n- Auth and file paths are never cached.\n- Only same-origin `200` responses are cached.\n- Call `clearApiCache()` on sign-in and sign-out so cached data from one account is never served\n  to another on a shared device (see below).\n\n## 2. Register + cache hygiene\n\n```ts\nimport { registerServiceWorker, clearApiCache } from \"@baryodev/pwa-kit\";\n\nregisterServiceWorker(); // defaults to \"/sw.js\"\n\n// in your auth code:\nfunction onLogin(session) { clearApiCache(); /* store token... */ }\nfunction onLogout() { clearApiCache(); /* drop token... */ }\n```\n\n## 3. Install prompt (React)\n\n```tsx\nimport { InstallHint } from \"@baryodev/pwa-kit\";\n\nexport default function App() {\n  return (\n    <>\n      {/* ...your app... */}\n      <InstallHint appName=\"MyApp\" iconUrl=\"/icon-192.png\" accentColor=\"#2563eb\" />\n    </>\n  );\n}\n```\n\n- **Android/Chrome:** shows an **Install app** button wired to `beforeinstallprompt`.\n- **iOS Safari:** shows **Share → Add to Home Screen** instructions (iOS has no install event).\n- Hidden when already installed; dismissible (remembered in `localStorage`).\n\n## 4. Native feel when installed (React)\n\nBrowsers let users pinch- and double-tap-zoom any page — great for the web, but it makes an\ninstalled app feel like a website. Mount `StandaloneViewport` once near your root: when the app is\nlaunched as an installed PWA it locks the viewport so zoom is disabled; in a normal browser tab it\ndoes nothing, so accessibility zoom still works there.\n\n```tsx\nimport { StandaloneViewport } from \"@baryodev/pwa-kit\";\n\nexport default function RootLayout({ children }) {\n  return (\n    <html>\n      <body>\n        {children}\n        <StandaloneViewport />\n      </body>\n    </html>\n  );\n}\n```\n\nNot using React? Call the helper directly (e.g. in a client entry). It's a no-op on the server and\nin a browser tab, and returns a cleanup function:\n\n```ts\nimport { lockViewportWhenStandalone } from \"@baryodev/pwa-kit\";\n\nconst cleanup = lockViewportWhenStandalone();\n```\n\nYour base viewport should still allow zoom (so the browser tab stays accessible) — Next.js:\n\n```ts\nexport const viewport = { width: \"device-width\", initialScale: 1 };\n```\n\n## 5. Who installed it (adoption tracking)\n\nThere is no cross-browser API that answers \"is this PWA installed?\" from a normal browser tab.\n`navigator.getInstalledRelatedApps()` is Chromium-only and needs `related_applications` in your\nmanifest; iOS has no install API at all. What every platform *can* tell you is whether the current\nlaunch is the installed app, so record that and keep it.\n\n`reportPwaStatus` fires once on launch, and again if the user installs during the session\n(`appinstalled`). You supply `send`, so the report goes through your own authenticated API:\n\n```ts\nimport { reportPwaStatus } from \"@baryodev/pwa-kit/report\";\n\nreportPwaStatus((report) => api.post(\"/api/pwa/report\", report));\n// report: { deviceId, displayMode, platform, installed }\n```\n\nWant a one-off read instead of a subscription? Use `pwaStatus()`, which returns the same shape (or\n`null` on the server).\n\n**Import from `@baryodev/pwa-kit/report`, not the package root.** The root re-exports the React\ncomponents, so it pulls React in. This subpath carries only the reporting helpers: no dependencies,\nno React, and it builds to a single self-contained file. That means a non-React app, or a site with\nno bundler at all, can use it directly:\n\n```html\n<script type=\"module\">\n  import { reportPwaStatus } from \"/js/pwa-kit-report.js\"; // copied from dist/report.js\n  reportPwaStatus((r) => fetch(\"/api/pwa/report\", {\n    method: \"POST\",\n    headers: { \"Content-Type\": \"application/json\" },\n    body: JSON.stringify(r),\n  }));\n</script>\n```\n\nThings to design around:\n\n- `installed` means *currently running as installed*. Someone who installed but is in a browser tab\n  reports `false` on that launch, which is why the server should store the first `true` it sees.\n- `appinstalled` is Chromium-only. On iOS you find out at the next home-screen launch, not at the\n  moment of install.\n- `deviceId` is a random id in `localStorage`, so it is per browser, not per account. Private mode\n  or cleared storage yields a new one and the same person can be counted twice.\n\n## 6. Web manifest (you provide)\n\npwa-kit doesn't generate your manifest (icons/colors are yours), but it needs one. Minimum:\n\n```json\n{\n  \"name\": \"MyApp\",\n  \"short_name\": \"MyApp\",\n  \"start_url\": \"/\",\n  \"display\": \"standalone\",\n  \"theme_color\": \"#2563eb\",\n  \"background_color\": \"#ffffff\",\n  \"icons\": [\n    { \"src\": \"/icon-192.png\", \"sizes\": \"192x192\", \"type\": \"image/png\", \"purpose\": \"any maskable\" },\n    { \"src\": \"/icon-512.png\", \"sizes\": \"512x512\", \"type\": \"image/png\", \"purpose\": \"any maskable\" }\n  ]\n}\n```\n\nLink it and the Apple bits in your `<head>` (Next.js: use the metadata API):\n\n```html\n<link rel=\"manifest\" href=\"/manifest.webmanifest\" />\n<link rel=\"apple-touch-icon\" href=\"/apple-touch-icon.png\" />\n<meta name=\"apple-mobile-web-app-capable\" content=\"yes\" />\n<meta name=\"apple-mobile-web-app-title\" content=\"MyApp\" />\n```\n\n## API\n\n| Export | Description |\n|--------|-------------|\n| `generateServiceWorker(options)` | Returns the service-worker source as a string. |\n| `registerServiceWorker(url?)` | Registers the worker after `load`. No-op on the server. |\n| `clearApiCache()` | Tells the worker to drop cached API data. Call on sign-in/out. |\n| `isStandalone()` | `true` when running as an installed PWA. |\n| `lockViewportWhenStandalone()` | Disables zoom when installed (no-op in a browser tab). Returns a cleanup fn. |\n| `<InstallHint />` | Dismissible install prompt (Android button / iOS instructions). |\n| `<StandaloneViewport />` | Mounts `lockViewportWhenStandalone` for you. Renders nothing. |\n\n## License\n\n[MIT](LICENSE)\n","readmeFilename":"README.md"}