An in-browser wisp.place site explorer
1/**
2 * Service Worker Debug Component
3 *
4 * Displays service worker status for debugging purposes.
5 * Only shows in development mode.
6 */
7
8import { useState, useEffect } from 'react';
9
10export function ServiceWorkerDebug() {
11 const [status, setStatus] = useState<{
12 ready: boolean;
13 controlled: boolean;
14 scope: string | null;
15 hasManifest: boolean;
16 siteInfo: any;
17 }>({
18 ready: false,
19 controlled: false,
20 scope: null,
21 hasManifest: false,
22 siteInfo: null,
23 });
24
25 useEffect(() => {
26 const checkStatus = async () => {
27 if (!('serviceWorker' in navigator)) {
28 setStatus(prev => ({ ...prev, ready: false }));
29 return;
30 }
31
32 const ready = 'serviceWorker' in navigator;
33 const controlled = !!navigator.serviceWorker.controller;
34 const registration = await navigator.serviceWorker.getRegistration();
35 const scope = registration?.scope || null;
36
37 setStatus(prev => ({ ...prev, ready, controlled, scope }));
38
39 // Check with service worker for manifest status
40 if (navigator.serviceWorker.controller) {
41 const channel = new MessageChannel();
42 channel.port1.onmessage = (event) => {
43 setStatus(prev => ({
44 ...prev,
45 hasManifest: event.data.hasManifest || false,
46 siteInfo: event.data.siteInfo,
47 }));
48 };
49
50 navigator.serviceWorker.controller.postMessage(
51 { type: 'GET_STATUS' },
52 [channel.port2]
53 );
54 }
55 };
56
57 checkStatus();
58 const interval = setInterval(checkStatus, 2000);
59 return () => clearInterval(interval);
60 }, []);
61
62 // Only show in development
63 if (import.meta.env.PROD) {
64 return null;
65 }
66
67 return (
68 <div style={{
69 position: 'fixed',
70 bottom: 0,
71 right: 0,
72 backgroundColor: 'rgba(0, 0, 0, 0.8)',
73 color: 'white',
74 padding: '8px',
75 fontSize: '10px',
76 fontFamily: 'monospace',
77 zIndex: 999999,
78 maxWidth: '300px',
79 maxHeight: '200px',
80 overflow: 'auto',
81 }}>
82 <div><strong>Service Worker Debug</strong></div>
83 <div>Ready: {status.ready ? '✓' : '✗'}</div>
84 <div>Controlled: {status.controlled ? '✓' : '✗'}</div>
85 <div>Scope: {status.scope || 'none'}</div>
86 <div>Has Manifest: {status.hasManifest ? '✓' : '✗'}</div>
87 {status.siteInfo && (
88 <div>
89 <div>DID: {status.siteInfo.did?.substring(0, 20)}...</div>
90 <div>Site: {status.siteInfo.siteName}</div>
91 </div>
92 )}
93 </div>
94 );
95}