mirror of
https://github.com/harvard-edge/cs249r_book.git
synced 2026-07-17 16:34:48 -05:00
[PR #1945] feat(staffml): make the app an installable PWA #34669
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/harvard-edge/cs249r_book/pull/1945
Author: @farhan523
Created: 7/7/2026
Status: 🔄 Open
Base:
dev← Head:feat/staffml-pwa📝 Commits (1)
54cd9ccfeat(staffml): make the app an installable PWA📊 Changes
10 files changed (+306 additions, -10 deletions)
View changed files
➕
interviews/staffml/public/icons/apple-touch-icon.png(+0 -0)➕
interviews/staffml/public/icons/icon-192.png(+0 -0)➕
interviews/staffml/public/icons/icon-512.png(+0 -0)➕
interviews/staffml/public/icons/icon-maskable-192.png(+0 -0)➕
interviews/staffml/public/icons/icon-maskable-512.png(+0 -0)📝
interviews/staffml/public/sw.js(+171 -0)📝
interviews/staffml/src/app/layout.tsx(+4 -0)➕
interviews/staffml/src/app/manifest.ts(+44 -0)➕
interviews/staffml/src/lib/__tests__/pwa-manifest.test.ts(+62 -0)📝
interviews/staffml/src/lib/corpus-provider.tsx(+25 -10)📄 Description
Summary
Makes StaffML installable as a Progressive Web App with offline support — a natural fit for an app that already runs 100% client-side.
src/app/manifest.ts— Next.js manifest route (force-staticso it works withoutput: export).start_url/scope/id/icon URLs carryNEXT_PUBLIC_BASE_PATHexplicitly, following the same convention as the og-image URLs inlayout.tsx. Theme/background match the light default fromtheme-bootstrap.js.public/icons/—any+maskableicons (192/512) plus a 180×180apple-touch-icon, rasterized from the roofline mark infavicon.svg. Maskable/apple variants are full-bleed so Android's circle/squircle masks and iOS's corner radius never clip the mark.layout.tsxmetadata now links the apple icon (iOS ignores SVG favicons).public/sw.js— new, clearly-delimited app-shell section appended below the existing vault-API cache. The two sections never compete for a request: the vault handler exits early unless the URL starts with the vault API origin (cross-origin); the app-shell handler exits early unless the request is same-origin and inside the worker's scope (so the surrounding Quarto book's assets are left alone). Strategy:_next/static/*is content-hashed so staleness is impossible there).VersionDriftToast.staffml-app-is disjoint fromstaffml-vault-, so the vault section's release-keyed pruning and the app section's version pruning can never delete each other's caches. No changes to any existing vault logic.corpus-provider.tsx— the service worker now registers unconditionally instead of only after a successful vault probe: offline support must not depend on the vault API being reachable, since offline is exactly when the probe fails. TheSET_VAULT_API_ORIGINmessage stays gated on probe success, so the vault section stays inert until then (preserving the Chip R4-C-2 message-hardening path unchanged).Regression test
src/lib/__tests__/pwa-manifest.test.tsguards the manifest↔icons contract: the manifest declares the fields installability requires (name,short_name,display: standalone, scope containing start_url, bothanyandmaskableat 192+512), and every icon it references exists inpublic/with exactly the pixel dimensions it advertises (PNG IHDR check) — a mismatch there doesn't fail the build, it just silently breaks installability in the field.Testing
vitest: 133/133 passing (7 new).next buildclean both with and withoutNEXT_PUBLIC_BASE_PATH=/staffml; verified exported HTML links the manifest and apple-touch-icon with the correct prefix in both configurations, and the manifest'sstart_url/scope/icon URLs all carry the base path.SET_VAULT_API_ORIGINafter a successful probe.npm run lintcurrently crashes ondevas well (ESLint 10 /eslint-plugin-reactincompatibility insideeslint-config-next, triggered onanalytics-worker/worker.js) — pre-existing and unrelated; scoped lint can't run either since the crash happens at rule-load time.🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.