Skip to content

Commit fda0c67

Browse files
dorlugasigalCopilot
andcommitted
fix(pwa): allow Safari to cache icons for home screen display
Safari iOS skips the apple-touch-icon entirely when the response has Cache-Control: no-store. Exempt /icons/* and /manifest.webmanifest from the no-store policy so Safari can retain them for Add to Home Screen. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 8c82f5d commit fda0c67

2 files changed

Lines changed: 15 additions & 1 deletion

File tree

src/server/index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,10 @@ function createTermBeamServer(overrides = {}) {
6363
res.setHeader('X-Content-Type-Options', 'nosniff');
6464
res.setHeader('X-Frame-Options', 'DENY');
6565
res.setHeader('Referrer-Policy', 'no-referrer');
66-
res.setHeader('Cache-Control', 'no-store');
66+
// PWA assets (icons, manifest) must be cacheable for Safari iOS home screen icons.
67+
// Safari skips apple-touch-icon entirely when Cache-Control: no-store is set.
68+
const isPwaAsset = req.path.startsWith('/icons/') || req.path === '/manifest.webmanifest';
69+
res.setHeader('Cache-Control', isPwaAsset ? 'public, max-age=86400' : 'no-store');
6770
res.setHeader(
6871
'Content-Security-Policy',
6972
"default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; img-src 'self' data:; connect-src 'self' ws: wss: https://cdn.jsdelivr.net; font-src 'self' https://cdn.jsdelivr.net",

test/integration.test.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,17 @@ describe('Integration', () => {
349349
assert.strictEqual(res.headers['referrer-policy'], 'no-referrer');
350350
assert.strictEqual(res.headers['cache-control'], 'no-store');
351351
});
352+
353+
it('PWA assets should have cacheable headers for Safari iOS', async () => {
354+
if (!inst) inst = await startServer();
355+
const res = await httpRequest({
356+
hostname: '127.0.0.1',
357+
port: inst.port,
358+
path: '/manifest.webmanifest',
359+
method: 'GET',
360+
});
361+
assert.strictEqual(res.headers['cache-control'], 'public, max-age=86400');
362+
});
352363
});
353364

354365
describe('Rate limiting on login', () => {

0 commit comments

Comments
 (0)