Repository navigation
Warm the full level cache in the background for offline play - #96
Conversation
Previously only the current + next level were prefetched, so offline players hit a load failure on the third unplayed level. sw.js now backfills all 500 level files into the SHELL cache in batches of 20, triggered by postMessage from main.js (not activate, which would queue fetch events and freeze the app for ~2MB of downloads). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
PR Summary by QodoWarm all level JSON into the SW cache in background for offline play
AI Description
Diagram
High-Level Assessment
Files changed (5)
|
Code Review by Qodo
1. requestLevelWarm bypasses bridge
|
| const requestLevelWarm = () => | ||
| navigator.serviceWorker?.controller?.postMessage("warm-levels"); |
There was a problem hiding this comment.
1. requestlevelwarm bypasses bridge 📘 Rule violation ⌂ Architecture
The new requestLevelWarm directly calls navigator.serviceWorker?.controller?.postMessage(...) from src/main.js instead of routing platform/native API access through bridge.js. This violates the platform abstraction requirement and makes future non-web platform swaps harder.
Agent Prompt
## Issue description
`src/main.js` introduces a new direct `navigator.serviceWorker` usage (`postMessage("warm-levels")`). Per the compliance rule, game/runtime code under `src/` must not call platform/native APIs directly and must route them via `bridge.js`.
## Issue Context
`src/main.js` already imports `bridge`, so the new service-worker warm trigger can be exposed as a `bridge` method (e.g., `bridge.requestLevelWarm()`), which encapsulates `navigator.serviceWorker` usage.
## Fix Focus Areas
- src/main.js[972-988]
- src/bridge.js[32-85]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| const index = await cache.match("data/levels/index.json"); | ||
| if (!index) return; // install 沒成功,別瞎猜關卡數;下一次 activate 會再來 | ||
| const { count } = await index.json(); | ||
| const ids = Array.from({ length: count }, (_, i) => i + 1); |
There was a problem hiding this comment.
2. Unvalidated level count 🐞 Bug ☼ Reliability
In sw.js warmLevels(), the cached index.json count is used directly to size `Array.from({ length:
count })` with no validation, so a malformed/non-integer value can result in warming 0 levels
(silent no-op) and an unexpectedly large value can cause excessive work or a RangeError. Because the
message handler swallows errors, this can silently prevent the cache warm from completing and leave
offline progression dependent only on the normal current+next prefetch.
Agent Prompt
### Issue description
`warmLevels()` trusts `index.json`'s `count` and uses it to size an array and drive fetching without validating that it is a finite, reasonable integer. This can make warming silently do nothing (e.g., non-integer / missing count coerces to length 0) or do excessive work / throw (e.g., huge count), and the failure is swallowed.
### Issue Context
- `src/main.js` already validates `count` when reading `data/levels/index.json` for gameplay.
- `sw.js` should apply similar validation before allocating/looping.
### Fix Focus Areas
- sw.js[78-95]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
Summary
sw.jsnow backfills all 500 level files into the SHELL cache in batches of 20 via a newwarmLevels(), triggered bypostMessagefrommain.js(onloadandcontrollerchange, deduped behind a single shared promise), notactivate— filling ~2MB there would queuefetchevents and freeze the app.Test plan
bun run check(lint + unit tests) passeswarmLevels()completes (DevTools → Application → Cache Storage shows 500 level entries) → airplane mode → play 3+ unplayed levels in a row