Some checks failed
Veza CI / Notify on failure (push) Blocked by required conditions
Veza CI / Rust (Stream Server) (push) Successful in 5m12s
Security Scan / Secret Scanning (gitleaks) (push) Failing after 48s
Veza CI / Backend (Go) (push) Failing after 8m51s
E2E Playwright / e2e (full) (push) Has been cancelled
Veza CI / Frontend (Web) (push) Has been cancelled
Service worker now applies the strategies the roadmap asks for :
* Static assets : StaleWhileRevalidate (already in place)
* HLS segments : CacheFirst, max-age 7d, max 50 entries
* API GET : NetworkFirst, 3s timeout
Stayed on the hand-rolled fetch handlers rather than migrating to
Workbox — the existing implementation already covers push notifications
+ background sync + notificationclick, and Workbox would bring 200+ KB
of runtime + a build-step dependency for a feature set we already have.
Changes
- public/sw.js
* HLS_CACHE_MAX_ENTRIES (50) + HLS_CACHE_MAX_AGE_MS (7d) +
NETWORK_FIRST_TIMEOUT_MS (3s) tunable at the top of the file.
* cacheAudio : reads the cached response's date header to skip
stale entries (>7d), and prunes the cache FIFO after every put
so the entry count never exceeds 50. Network-down path still
serves stale entries (the offline-playback acceptance).
* networkFirst : races the network against a 3s timer ; if the
timer fires AND a cached entry exists, serve cached + let the
network keep updating in the background. Timeout without a
cached fallback lets the network race continue.
* isAudioRequest now matches .ts and .m4s segments too (HLS).
- scripts/stamp-sw-version.mjs (new) : postbuild step that replaces
the literal __BUILD_VERSION__ placeholder in dist/sw.js with
YYYYMMDDHHMM-<short-sha>. Pre-Day 16 the placeholder shipped
literally — same string across every deploy meant browser caches
were never invalidated. Wired into npm run build + build:ci.
- tests/e2e/31-sw-offline-cache.spec.ts : 2 tests gated behind
E2E_SW_TESTS=1 (SW only registers in prod builds — dev server
skips registration via import.meta.env.DEV check). When enabled :
(1) registration + activation, (2) cached resource served while
context.setOffline(true).
Acceptance (Day 16) : strategies match spec ; offline playback works
once the user has played the segment once before going offline. The
e2e self-skips on dev unless E2E_SW_TESTS=1 is set against vite preview.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
60 lines
1.9 KiB
JavaScript
60 lines
1.9 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Replace the __BUILD_VERSION__ placeholder in the built sw.js with a
|
|
* deterministic version string : the short git SHA + the build timestamp.
|
|
*
|
|
* Why : the service worker uses CACHE_VERSION to namespace caches and
|
|
* prune stale ones at activate. If __BUILD_VERSION__ stays literal,
|
|
* every deploy ships the same `veza-platform-__BUILD_VERSION__` cache
|
|
* name and pre-existing browser caches never get invalidated.
|
|
*
|
|
* v1.0.9 W4 Day 16.
|
|
*/
|
|
|
|
import { readFile, writeFile } from 'node:fs/promises';
|
|
import { execSync } from 'node:child_process';
|
|
import { resolve } from 'node:path';
|
|
|
|
async function main() {
|
|
const target = process.env.SW_PATH || resolve(process.cwd(), 'dist/sw.js');
|
|
|
|
let sha = 'dev';
|
|
try {
|
|
sha = execSync('git rev-parse --short HEAD', { stdio: ['pipe', 'pipe', 'ignore'] })
|
|
.toString()
|
|
.trim();
|
|
} catch {
|
|
// Not a git checkout (e.g. CI building a tarball) — fall back to env var.
|
|
sha = process.env.GITHUB_SHA?.slice(0, 7) || process.env.CI_COMMIT_SHA?.slice(0, 7) || 'dev';
|
|
}
|
|
|
|
const ts = new Date().toISOString().replace(/[-:.TZ]/g, '').slice(0, 12); // YYYYMMDDHHMM
|
|
const version = `${ts}-${sha}`;
|
|
|
|
let content;
|
|
try {
|
|
content = await readFile(target, 'utf8');
|
|
} catch (err) {
|
|
if (err.code === 'ENOENT') {
|
|
console.warn(`[stamp-sw-version] ${target} not found — skipping (run vite build first).`);
|
|
return;
|
|
}
|
|
throw err;
|
|
}
|
|
|
|
if (!content.includes('__BUILD_VERSION__')) {
|
|
console.warn(
|
|
`[stamp-sw-version] no __BUILD_VERSION__ placeholder in ${target} — already stamped or sw.js was rewritten without one.`,
|
|
);
|
|
return;
|
|
}
|
|
|
|
const stamped = content.replaceAll('__BUILD_VERSION__', version);
|
|
await writeFile(target, stamped, 'utf8');
|
|
console.log(`[stamp-sw-version] sw.js stamped with ${version}`);
|
|
}
|
|
|
|
main().catch((err) => {
|
|
console.error('[stamp-sw-version] failed:', err);
|
|
process.exit(1);
|
|
});
|