Apply Bswup improvements (#12408)#12418
Conversation
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
WalkthroughAdds an install-failure UI and retry flow, hardens service-worker manifest loading and caching (validation, normalization, retries/backoff, strict/lax install modes), updates fetch/passive caching and prohibited-URL behavior, adds opt-in update polling and coordinated multi-tab reloads, expands runtime logging/options, and refreshes docs. ChangesBit.Bswup Service Worker Error Handling & Update Polling
Estimated code review effort🎯 4 (Complex) | ⏱️ ~65 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/Bswup/Bit.Bswup/Scripts/bit-bswup.sw.ts`:
- Around line 47-57: The manifest validation detects errors (MANIFEST_ERRORS
from validateAssetsManifest) but the code continues to run and later
dereferences self.assetsManifest.assets, causing a crash; after calling
sendError you should stop further startup: return/throw to prevent asset
enumeration, and guard any access to self.assetsManifest.assets (e.g., use
Array.isArray(self.assetsManifest.assets) before iterating) and ensure VERSION
fallback is computed safely (use (self.assetsManifest && typeof
self.assetsManifest.version === 'string') ? self.assetsManifest.version :
'0.0.0-invalid-manifest') so the service worker does not proceed when the
manifest is invalid; update the block around MANIFEST_ERRORS, sendError,
VERSION, and any asset-enumeration code that uses self.assetsManifest.assets to
enforce this early exit and safe checks.
In `@src/Bswup/Bit.Bswup/Scripts/bit-bswup.ts`:
- Around line 321-324: The catch block in checkForUpdate currently calls
handle(BswupMessage.error, ...) which routes transient registration.update()
failures into the blocking install-error path; change this to emit a
non-blocking message instead (e.g., add a new enum/value like
BswupMessage.updateCheckFailed or use a non-fatal level such as
BswupMessage.warn/info) and call handle(...) with that new message name,
preserving the payload ({ reason: 'update', message: String((err && (err as
any).message) || err), reload }) so callers can still react but the default
progress handler will not hide the app or show the install-failed UI. Ensure to
update any switch/handler that consumes BswupMessage.* to treat the new
updateCheckFailed value as non-blocking.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: ae99fd6f-8550-4920-b5b5-7982f9b3572d
📒 Files selected for processing (7)
src/Bswup/Bit.Bswup.Demo/wwwroot/service-worker.jssrc/Bswup/Bit.Bswup/BswupProgress.razorsrc/Bswup/Bit.Bswup/Scripts/bit-bswup.progress.tssrc/Bswup/Bit.Bswup/Scripts/bit-bswup.sw.tssrc/Bswup/Bit.Bswup/Scripts/bit-bswup.tssrc/Bswup/Bit.Bswup/Styles/bit-bswup.progress.csssrc/Bswup/README.md
|
@coderabbitai re-review |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
echo "=== bit-bswup.sw.ts ==="
fd "bit-bswup.sw.ts" --exec cat {}
echo ""
echo "=== bit-bswup.ts ==="
fd "bit-bswup.ts" -E "*.js" --exec cat {}
echo ""
echo "=== bit-bswup.progress.ts ==="
fd "bit-bswup.progress.ts" --exec cat {}
echo ""
echo "=== BswupProgress.razor ==="
fd "BswupProgress.razor" --exec cat {}
echo ""
echo "=== bit-bswup.progress.css ==="
fd "bit-bswup.progress.css" --exec cat {}
echo ""
echo "=== service-worker.js (demo) ==="
fd "service-worker.js" --search-path "Bit.Bswup.Demo" --exec cat {}
echo ""
echo "=== README.md (Bswup) ==="
cat src/Bswup/README.mdLength of output: 87174
🔴 Critical — Crash when
|
There was a problem hiding this comment.
Pull request overview
This PR improves Bit.Bswup’s update experience and robustness by adding user-visible install error reporting (with retry), introducing opt-in update polling (interval and/or tab visibility), improving multi-tab update consistency, and expanding Blazor script auto-detection to cover both Blazor Web App and standalone WebAssembly entry points.
Changes:
- Add update polling controls (
updateInterval,updateOnVisibility) and expose/extend JS API docs (BitBswup.checkForUpdate,skipWaiting,forceRefresh). - Improve service worker install reliability (manifest validation, retries/backoff, strict vs lax error tolerance, safer multi-tab activation/claim behavior).
- Enhance the progress UI with an error panel (message/details + retry) and corresponding styles.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Bswup/README.md | Documents new script attributes, error tolerance behavior, multi-tab behavior, security notes, and JS API. |
| src/Bswup/Bit.Bswup/Styles/bit-bswup.progress.css | Adds styling for the new install error panel and retry button behavior. |
| src/Bswup/Bit.Bswup/Scripts/bit-bswup.ts | Adds idempotent initialization, update polling, better controllerchange handling, richer logging levels, and expanded Blazor script detection. |
| src/Bswup/Bit.Bswup/Scripts/bit-bswup.sw.ts | Adds manifest validation + error reporting, retry/backoff for asset fetches, strict/lax install semantics, safer cache update sequencing, and RegExp parsing improvements. |
| src/Bswup/Bit.Bswup/Scripts/bit-bswup.progress.ts | Adds UI handling for install errors (message/details/retry) and keeps assets list visibility in sync with runtime config changes. |
| src/Bswup/Bit.Bswup/BswupProgress.razor | Updates the progress component markup to include an error panel and changes initialization to run via a <script> block. |
| src/Bswup/Bit.Bswup.Demo/wwwroot/service-worker.published.js | Removes demo precachedAssetsInclude config line. |
| src/Bswup/Bit.Bswup.Demo/wwwroot/service-worker.js | Adjusts demo config to use errorTolerance = 'lax' with explanatory comment. |
|
@coderabbitai re-review |
|
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/Bswup/Bit.Bswup/Scripts/bit-bswup.sw.ts (1)
333-362:⚠️ Potential issue | 🟠 Major | ⚡ Quick winUse
e.waitUntil()for async work in the service workermessagehandler.Returning a Promise from the
messagelistener doesn’t reliably keep the worker alive; useExtendableMessageEvent.waitUntil(...)forskipWaiting(),clients.claim(), cache deletion/filling, and the follow-uppostMessage.Suggested fix
-function handleMessage(e: MessageEvent<string>) { +function handleMessage(e: any) { diag('handleMessage:', e); if (e.data === 'SKIP_WAITING') { - return self.skipWaiting() - .then(() => self.clients.claim()) - .then(() => deleteOldCaches()) - .then(() => sendMessage('WAITING_SKIPPED')); + e.waitUntil( + self.skipWaiting() + .then(() => self.clients.claim()) + .then(() => deleteOldCaches()) + .then(() => sendMessage('WAITING_SKIPPED')) + ); + return; } if (e.data === 'CLAIM_CLIENTS') { - return self.clients.claim() - .then(() => deleteOldCaches()) - .then(() => e.source?.postMessage('CLIENTS_CLAIMED')); + e.waitUntil( + self.clients.claim() + .then(() => deleteOldCaches()) + .then(() => e.source?.postMessage('CLIENTS_CLAIMED')) + ); + return; } if (e.data === 'BLAZOR_STARTED') { - createAssetsCache(true); + e.waitUntil(createAssetsCache(true)); + return; } if (e.data === 'CLEAN_UP') { - deleteOldCaches(); // remove the old caches + e.waitUntil(deleteOldCaches()); // remove the old caches } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/Bswup/Bit.Bswup/Scripts/bit-bswup.sw.ts` around lines 333 - 362, The message handler currently returns Promises but must use e.waitUntil(...) to keep the service worker alive; wrap each async branch so that SKIP_WAITING uses e.waitUntil(self.skipWaiting().then(() => self.clients.claim()).then(() => deleteOldCaches()).then(() => sendMessage('WAITING_SKIPPED'))), CLAIM_CLIENTS uses e.waitUntil(self.clients.claim().then(() => deleteOldCaches()).then(() => e.source?.postMessage('CLIENTS_CLAIMED'))), BLAZOR_STARTED uses e.waitUntil(createAssetsCache(true)), and CLEAN_UP uses e.waitUntil(deleteOldCaches()), ensuring all calls to self.skipWaiting(), self.clients.claim(), deleteOldCaches(), createAssetsCache(true), sendMessage and e.source?.postMessage are inside the waitUntil chains.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/Bswup/Bit.Bswup/BswupProgress.razor`:
- Around line 37-39: The inline script in BswupProgress.razor calls
BitBswupProgress.start(...) unguarded which throws if bit-bswup.progress.js
hasn't loaded; update the init to check for the global before invoking (e.g.,
use window.BitBswupProgress?.start(...) or an explicit if
(window.BitBswupProgress) call) passing the same parameters (AutoReload,
ShowLogs, ShowAssets, AppContainer, HideApp, AutoHide, Handler), or
alternatively move the startup into the component lifecycle (OnAfterRenderAsync)
and call JS interop to invoke BitBswupProgress.start to guarantee ordering.
- Line 38: The call to BitBswupProgress.start injects AppContainer and Handler
as raw single-quoted JS literals which can be broken by
quotes/backslashes/newlines; change those embeddings to JSON-encoded JS-safe
strings instead (e.g., replace the single-quoted '@(AppContainer)' and
'@(Handler)' with the output of
System.Text.Json.JsonSerializer.Serialize(AppContainer) and
JsonSerializer.Serialize(Handler) so the values are properly escaped and already
quoted), update the BswupProgress.razor to use JsonSerializer.Serialize for both
AppContainer and Handler and add the required using/import for System.Text.Json
if missing.
In `@src/Bswup/Bit.Bswup/Scripts/bit-bswup.sw.ts`:
- Around line 86-94: The cache bucket currently uses only CACHE_VERSION (derived
from self.cacheVersion or VERSION) which allows different manifests to share a
bucket; change the cache naming so the manifest VERSION is always part of the
bucket identity. Keep the existing CACHE_VERSION calculation (using
self.cacheVersion fallback to VERSION) but construct CACHE_NAME to include both
VERSION and CACHE_VERSION (e.g. `${CACHE_NAME_PREFIX} - ${VERSION} -
${CACHE_VERSION}`), so the manifest VERSION remains in the cache bucket while
cacheVersion can still be used to pin/force refresh.
- Around line 516-540: The current logic sets isIntegrity true whenever
hasIntegrity && fetchErr instanceof TypeError, which treats all TypeError fetch
rejections as SRI failures and prevents retries; change the detection in the
addCache flow so a bare TypeError does NOT automatically mark an integrity
failure: remove fetchErr instanceof TypeError from the isIntegrity predicate and
instead only classify as integrity when there is a clear integrity signal (e.g.,
the error message matches the integrity/digest regex) or after explicitly
recomputing and comparing the response bytes to asset.hash; keep transient
TypeError cases as retryable (use lastError/continue while attempt <
MAX_RETRIES), and only increment integrityFailureCount, set sendError.reason to
'integrity', and skip retries when you have a confirmed integrity mismatch (use
the integrity regex or the explicit digest comparison to decide).
In `@src/Bswup/Bit.Bswup/Scripts/bit-bswup.ts`:
- Line 35: Guard runBswup against late script injection by checking
document.readyState before adding the listener: if the document is already
"interactive" or "complete" call runBswup() immediately, otherwise attach
window.addEventListener('DOMContentLoaded', runBswup) (refer to the runBswup
symbol). Also fix BitBswup.forceRefresh where cacheFilter.test(key) is used:
avoid inconsistent results when cacheFilter has the global (g) or sticky (y)
flags by resetting cacheFilter.lastIndex = 0 before each test or by creating a
non-global equivalent RegExp from cacheFilter (use cacheFilter.source with flags
stripped of g/y) and testing against that; reference the BitBswup.forceRefresh
method and the cacheFilter variable so the change is made exactly where repeated
RegExp.test calls occur.
- Around line 497-500: forceRefresh builds the shouldDelete predicate from
cacheFilter but when cacheFilter is a RegExp it calls cacheFilter.test()
repeatedly, which can misbehave for /.../g or /.../y because RegExp.lastIndex is
mutated; fix by updating the RegExp branch in the shouldDelete construction
(used in forceRefresh) to reset cacheFilter.lastIndex = 0 before calling
cacheFilter.test(key) so each key is tested from the start; reference the
shouldDelete variable and cacheFilter RegExp usage in forceRefresh when making
the change.
---
Outside diff comments:
In `@src/Bswup/Bit.Bswup/Scripts/bit-bswup.sw.ts`:
- Around line 333-362: The message handler currently returns Promises but must
use e.waitUntil(...) to keep the service worker alive; wrap each async branch so
that SKIP_WAITING uses e.waitUntil(self.skipWaiting().then(() =>
self.clients.claim()).then(() => deleteOldCaches()).then(() =>
sendMessage('WAITING_SKIPPED'))), CLAIM_CLIENTS uses
e.waitUntil(self.clients.claim().then(() => deleteOldCaches()).then(() =>
e.source?.postMessage('CLIENTS_CLAIMED'))), BLAZOR_STARTED uses
e.waitUntil(createAssetsCache(true)), and CLEAN_UP uses
e.waitUntil(deleteOldCaches()), ensuring all calls to self.skipWaiting(),
self.clients.claim(), deleteOldCaches(), createAssetsCache(true), sendMessage
and e.source?.postMessage are inside the waitUntil chains.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: d3c76fdc-5fec-4833-85fc-89e300ee0dd0
📒 Files selected for processing (8)
src/Bswup/Bit.Bswup.Demo/wwwroot/service-worker.jssrc/Bswup/Bit.Bswup.Demo/wwwroot/service-worker.published.jssrc/Bswup/Bit.Bswup/BswupProgress.razorsrc/Bswup/Bit.Bswup/Scripts/bit-bswup.progress.tssrc/Bswup/Bit.Bswup/Scripts/bit-bswup.sw.tssrc/Bswup/Bit.Bswup/Scripts/bit-bswup.tssrc/Bswup/Bit.Bswup/Styles/bit-bswup.progress.csssrc/Bswup/README.md
💤 Files with no reviewable changes (1)
- src/Bswup/Bit.Bswup.Demo/wwwroot/service-worker.published.js
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
| const oldRes = await oldCache.match(oldKey.url); | ||
| if(!oldRes) continue; | ||
| await newCache.put(oldKey.url, oldRes); |
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (1)
src/Bswup/README.md (1)
105-110: ⚡ Quick winConsider showing complete error details in the example.
The comment documents that
data.urlanddata.hashare available "when known", but the example only logsdata.reasonanddata.message. For a more complete reference example, consider showing all available fields.📝 Suggested enhancement
case BswupMessage.error: // Structured install failure. data.reason is one of 'manifest' | 'integrity' | // 'fetch' | 'cache' | 'request' | 'install-incomplete'; data.message is human // readable, and data.url / data.hash point at the offending asset when known. - console.error('Bswup install error:', data.reason, data.message); + console.error('Bswup install error:', data.reason, data.message, data.url, data.hash); return;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/Bswup/README.md` around lines 105 - 110, The example logging for the BswupMessage.error case only prints data.reason and data.message; update the handler for the BswupMessage.error branch (the switch case) to log all available error details (data.reason, data.message, and when present data.url and data.hash, plus the whole data object for unknown fields) so consumers see the complete failure context; use the existing BswupMessage.error case and data variable to append url and hash if defined and include a fallback of logging the entire data object.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/Bswup/Bit.Bswup/Scripts/bit-bswup.progress.ts`:
- Around line 129-149: The retry suppression omitted the 'install-incomplete'
reason so deterministic failures can still show the retry button; update the
nonRetriableReasons used where errorRetryButton is handled (the
nonRetriableReasons array and the isRetriable check in the same block) to
include 'install-incomplete' alongside 'manifest' and 'integrity' so isRetriable
becomes false for that reason, keep the existing behavior for invoking
data.reload() or window.location.reload() unchanged.
In `@src/Bswup/Bit.Bswup/Scripts/bit-bswup.ts`:
- Around line 388-425: The extract() function currently assigns options =
(window[optionsName] || defaultoptions) which replaces defaults when a partial
window[optionsName] exists; change it to merge defaults with any global config
(e.g. create options by combining defaultoptions and window[optionsName] such as
Object.assign({}, defaultoptions, window[optionsName]) or using the spread
operator) so missing keys in window[optionsName] fall back to defaultoptions;
keep the subsequent attribute overrides (log, sw, scope, handlerName,
blazorScript, updateInterval, updateOnVisibility) applied on top of the merged
options.
- Around line 427-438: The current handle function permanently replaces
options.handler with a noop when window[options.handlerName] is missing,
preventing later attachment from being picked up; change it so you do not
overwrite options.handler on missing handler — instead read
window[options.handlerName] into a local variable (e.g., foundHandler) or only
assign to options.handler when a real function is present, call that local/found
handler if available, and leave options.handler untouched (so future
registrations on window[options.handlerName] can be discovered); update the
logic in the handle function that references options.handlerName and
options.handler to reflect this non-destructive check.
In `@src/Bswup/Bit.Bswup/Styles/bit-bswup.progress.css`:
- Around line 74-89: Replace the deprecated word-break: break-word in the
.bit-bswup-error-message and .bit-bswup-error-details selectors by removing
those declarations and adding overflow-wrap: anywhere (leave existing
white-space: pre-wrap intact) so the stylesheet no longer triggers the Stylelint
warning.
In `@src/Bswup/README.md`:
- Line 218: Update the README entry for the `FullOffline` mode to correct the
grammar by changing "from first time the app is loaded" to "from the first time
the app is loaded" so the description reads: "Enables the full offline mode
where all assets are cached and served from the cache from the first time the
app is loaded."
- Around line 228-234: Update the "Polling for updates" paragraph to fix the
numeric inconsistency: change "There are three ways to check more often:" to
"There are two ways to check more often:" (since only the built-in options using
updateInterval/updateOnVisibility and calling BitBswup.checkForUpdate() are
listed), ensuring the section header "Polling for updates" and references to
updateInterval, updateOnVisibility and BitBswup.checkForUpdate() remain
unchanged.
- Line 213: The README wording incorrectly states that per-asset ?v= and SRI
derive from the manifest version; update the text to accurately reflect that
CACHE_VERSION / cacheVersion only affect the cache bucket name (computed into
CACHE_NAME) while per-asset cache-buster and integrity are set inside
createNewAssetRequest() using each asset's asset.hash (with fallback to
self.assetsManifest.version) and requestInit.integrity = asset.hash; replace the
sentence to mention that ?v= primarily comes from asset.hash (fallback to
manifest.version) and SRI uses asset.hash, and remove any implication that those
values reference self.cacheVersion or CACHE_VERSION.
---
Nitpick comments:
In `@src/Bswup/README.md`:
- Around line 105-110: The example logging for the BswupMessage.error case only
prints data.reason and data.message; update the handler for the
BswupMessage.error branch (the switch case) to log all available error details
(data.reason, data.message, and when present data.url and data.hash, plus the
whole data object for unknown fields) so consumers see the complete failure
context; use the existing BswupMessage.error case and data variable to append
url and hash if defined and include a fallback of logging the entire data
object.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 427f1025-c5ef-456e-b74d-6a2168e132d7
📒 Files selected for processing (9)
src/Bswup/Bit.Bswup.Demo/wwwroot/service-worker.jssrc/Bswup/Bit.Bswup.Demo/wwwroot/service-worker.published.jssrc/Bswup/Bit.Bswup/BswupProgress.razorsrc/Bswup/Bit.Bswup/Scripts/bit-bswup.progress.tssrc/Bswup/Bit.Bswup/Scripts/bit-bswup.sw-cleanup.tssrc/Bswup/Bit.Bswup/Scripts/bit-bswup.sw.tssrc/Bswup/Bit.Bswup/Scripts/bit-bswup.tssrc/Bswup/Bit.Bswup/Styles/bit-bswup.progress.csssrc/Bswup/README.md
💤 Files with no reviewable changes (1)
- src/Bswup/Bit.Bswup.Demo/wwwroot/service-worker.published.js
closes #12408
Summary by CodeRabbit
New Features
Bug Fixes
Documentation