handmux 0.12.1 → 0.12.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/public/index.html
CHANGED
|
@@ -5,17 +5,21 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
|
|
6
6
|
<title>handmux</title>
|
|
7
7
|
|
|
8
|
-
<!-- Installable PWA: "Add to Home Screen" + standalone (no browser address bar).
|
|
9
|
-
|
|
8
|
+
<!-- Installable PWA: "Add to Home Screen" + standalone (no browser address bar).
|
|
9
|
+
?v=2 one-time cache-bust: pre-0.12.2 servers sent these stable-url assets as
|
|
10
|
+
`immutable, max-age=1y`, so returning browsers pinned the OLD icon/manifest for a year.
|
|
11
|
+
index.html is no-store (always fresh), so a new query on the refs escapes those poisoned
|
|
12
|
+
caches at once; staticCache.js now serves them `no-cache`, so no future bump is needed. -->
|
|
13
|
+
<link rel="manifest" href="/manifest.webmanifest?v=2" />
|
|
10
14
|
<meta name="theme-color" content="#1a1b1e" />
|
|
11
|
-
<link rel="icon" type="image/png" href="/icons/icon-192.png" />
|
|
15
|
+
<link rel="icon" type="image/png" href="/icons/icon-192.png?v=2" />
|
|
12
16
|
<!-- iOS Safari ignores the manifest's display mode, so these drive standalone + the
|
|
13
17
|
home-screen icon/label. "black" keeps the white status-bar text readable on the dark topbar. -->
|
|
14
18
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
15
19
|
<meta name="mobile-web-app-capable" content="yes" />
|
|
16
20
|
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
|
|
17
21
|
<meta name="apple-mobile-web-app-title" content="handmux" />
|
|
18
|
-
<link rel="apple-touch-icon" href="/icons/apple-touch-icon.png" />
|
|
22
|
+
<link rel="apple-touch-icon" href="/icons/apple-touch-icon.png?v=2" />
|
|
19
23
|
|
|
20
24
|
<!-- Inline boot splash: paints instantly (before the JS bundle loads) so a cold launch shows the
|
|
21
25
|
brand, not a blank dark screen. main.jsx calls window.__hideBootSplash() once React has painted;
|
|
@@ -44,7 +48,7 @@
|
|
|
44
48
|
@keyframes bootDot { 0%,100% { opacity: .22; transform: translateY(0); } 40% { opacity: 1; transform: translateY(-3px); } }
|
|
45
49
|
@media (prefers-reduced-motion: reduce) { .boot-glow, .boot-dots i { animation: none; opacity: .8; } }
|
|
46
50
|
</style>
|
|
47
|
-
<script type="module" crossorigin src="/assets/index-
|
|
51
|
+
<script type="module" crossorigin src="/assets/index-BXd3a0v9.js"></script>
|
|
48
52
|
<link rel="stylesheet" crossorigin href="/assets/index-DJNPeU_h.css" media="print" onload="this.media='all'"><noscript><link rel="stylesheet" crossorigin href="/assets/index-DJNPeU_h.css"></noscript>
|
|
49
53
|
</head>
|
|
50
54
|
<body>
|
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
"background_color": "#1a1b1e",
|
|
10
10
|
"theme_color": "#1a1b1e",
|
|
11
11
|
"icons": [
|
|
12
|
-
{ "src": "icons/icon-192.png", "sizes": "192x192", "type": "image/png", "purpose": "any" },
|
|
13
|
-
{ "src": "icons/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "any" },
|
|
14
|
-
{ "src": "icons/icon-192-maskable.png", "sizes": "192x192", "type": "image/png", "purpose": "maskable" },
|
|
15
|
-
{ "src": "icons/icon-512-maskable.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" }
|
|
12
|
+
{ "src": "icons/icon-192.png?v=2", "sizes": "192x192", "type": "image/png", "purpose": "any" },
|
|
13
|
+
{ "src": "icons/icon-512.png?v=2", "sizes": "512x512", "type": "image/png", "purpose": "any" },
|
|
14
|
+
{ "src": "icons/icon-192-maskable.png?v=2", "sizes": "192x192", "type": "image/png", "purpose": "maskable" },
|
|
15
|
+
{ "src": "icons/icon-512-maskable.png?v=2", "sizes": "512x512", "type": "image/png", "purpose": "maskable" }
|
|
16
16
|
],
|
|
17
17
|
"share_target": {
|
|
18
18
|
"action": "/share-target",
|
package/public/sw.js
CHANGED
|
@@ -81,11 +81,11 @@ self.addEventListener('push', (event) => {
|
|
|
81
81
|
// icon = the large right-side logo. We MUST set it: HyperOS/MIUI always reserves that slot, and an
|
|
82
82
|
// empty `icon` makes it back-fill the slot with the PWA's own icon at a stray size (the `>` reads as
|
|
83
83
|
// a lone "v") plus leaves a gap. An explicit app icon fills the slot cleanly.
|
|
84
|
-
icon: '/icons/icon-192.png',
|
|
84
|
+
icon: '/icons/icon-192.png?v=2',
|
|
85
85
|
// badge = the small monochrome status-bar icon. Android reads only its ALPHA and tints the
|
|
86
86
|
// silhouette; an opaque image (icon-192 has no alpha) can't be used, so it falls back to the
|
|
87
87
|
// browser's own Chrome logo. badge-96.png is a white `>▮` silhouette on transparent → our mark.
|
|
88
|
-
badge: '/icons/badge-96.png',
|
|
88
|
+
badge: '/icons/badge-96.png?v=2',
|
|
89
89
|
data: d.data || {},
|
|
90
90
|
}));
|
|
91
91
|
});
|
package/src/staticCache.js
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
|
-
// Cache-Control policy for the static web bundle.
|
|
2
|
-
// HTTP-cached — an installed PWA would otherwise
|
|
3
|
-
//
|
|
4
|
-
//
|
|
1
|
+
// Cache-Control policy for the static web bundle.
|
|
2
|
+
// • index.html + the service worker must NEVER be HTTP-cached — an installed PWA would otherwise
|
|
3
|
+
// keep loading a stale shell (pointing at missing hashed assets) or a stale service worker.
|
|
4
|
+
// • Vite build output under /assets/ carries a content hash in its filename, so the URL itself
|
|
5
|
+
// changes whenever the bytes change → safe to pin forever (immutable).
|
|
6
|
+
// • Everything else is a hand-authored public/ file served at a STABLE url whose bytes change in
|
|
7
|
+
// place across releases (icons, manifest.webmanifest, favicon, og cards, offline assets). Those
|
|
8
|
+
// must NOT be immutable — pinning them would freeze an old copy in every returning browser for a
|
|
9
|
+
// year (a changed app icon / manifest would never reach anyone who had visited before). They get
|
|
10
|
+
// `no-cache` = store but always revalidate; the ETag/Last-Modified express.static already sends
|
|
11
|
+
// make the recheck a cheap 304 when nothing changed, and an actual change is picked up at once.
|
|
12
|
+
// Pure so it unit-tests on its own.
|
|
5
13
|
export function cacheControlFor(filePath) {
|
|
6
14
|
if (filePath.endsWith('.html') || filePath.endsWith('/sw.js')) return 'no-store';
|
|
7
|
-
return 'public, max-age=31536000, immutable';
|
|
15
|
+
if (/[\\/]assets[\\/]/.test(filePath)) return 'public, max-age=31536000, immutable';
|
|
16
|
+
return 'no-cache';
|
|
8
17
|
}
|