Files
store/sw.sune
2025-09-03 13:25:05 -07:00

28 lines
8.9 KiB
JSON

[
{
"id": "tbkc6m5",
"name": "SW",
"pinned": false,
"avatar": "",
"url": "gh://sune-org/store@main/sw.sune",
"updatedAt": 1756931099525,
"settings": {
"model": "openai/gpt-5-chat",
"temperature": 1,
"top_p": 0.97,
"top_k": 0,
"frequency_penalty": 0,
"presence_penalty": 0,
"repetition_penalty": 1,
"min_p": 0,
"top_a": 0,
"max_tokens": 0,
"verbosity": "",
"reasoning_effort": "default",
"system_prompt": "",
"html": "<!-- Sune: Service Worker detector + UI -->\n<div id=\"sune-sw-detector\" data-sw=\"/sw.js\" class=\"max-w-md mx-auto p-3\">\n <div class=\"flex items-center gap-3\">\n <div id=\"swdot\" class=\"h-3 w-3 rounded-full bg-gray-300\"></div>\n <div class=\"flex-1\">\n <div class=\"text-sm font-medium\" id=\"sw-status\">Checking service worker…</div>\n <div class=\"text-xs text-gray-500\" id=\"sw-sub\">—</div>\n </div>\n <button id=\"sw-toggle\" class=\"ml-2 px-2 py-1 rounded-lg bg-gray-100 text-sm\">…</button>\n </div>\n\n <div class=\"mt-3 grid grid-cols-3 gap-2\">\n <button id=\"sw-register\" class=\"col-span-1 rounded-lg bg-black text-white py-2 text-sm\">Register</button>\n <button id=\"sw-unregister\" class=\"col-span-1 rounded-lg bg-red-50 text-red-700 py-2 text-sm hidden\">Unregister</button>\n <button id=\"sw-ping\" class=\"col-span-1 rounded-lg bg-gray-100 py-2 text-sm\">Ping SW</button>\n </div>\n\n <div class=\"mt-3 text-xs text-gray-600\">\n <div class=\"flex items-center gap-2\">\n <i data-lucide=\"info\" class=\"h-4 w-4\"></i>\n <span>SW file: <code id=\"sw-path\" class=\"text-xs font-mono\"></code></span>\n </div>\n <div class=\"mt-2\">\n <div class=\"text-xs font-medium\">Message log</div>\n <div id=\"sw-log\" class=\"mt-1 text-xs bg-gray-50 border border-gray-200 rounded-lg p-2 max-h-32 overflow-auto\"></div>\n </div>\n </div>\n</div>\n\n<script>\n(() => {\n const root = document.getElementById('sune-sw-detector');\n if (!root) return;\n const swPath = root.dataset.sw || '/sw.js';\n const el = {\n dot: root.querySelector('#swdot'),\n status: root.querySelector('#sw-status'),\n sub: root.querySelector('#sw-sub'),\n toggle: root.querySelector('#sw-toggle'),\n regBtn: root.querySelector('#sw-register'),\n unregBtn: root.querySelector('#sw-unregister'),\n pingBtn: root.querySelector('#sw-ping'),\n path: root.querySelector('#sw-path'),\n log: root.querySelector('#sw-log')\n };\n\n el.path.textContent = swPath;\n\n const log = (t, cls = '') => {\n const d = document.createElement('div');\n d.className = 'leading-5 ' + cls;\n d.textContent = (new Date()).toLocaleTimeString() + ' — ' + t;\n el.log.prepend(d);\n };\n\n const setStatus = ({supported,falseMsg,registered,active,scope,controller}) => {\n if (!supported) {\n el.dot.className = 'h-3 w-3 rounded-full bg-red-200';\n el.status.textContent = 'Service workers not supported';\n el.sub.textContent = falseMsg || 'Requires HTTPS or localhost.';\n el.regBtn.classList.add('hidden');\n el.unregBtn.classList.add('hidden');\n el.pingBtn.classList.add('hidden');\n el.toggle.textContent = 'n/a';\n return;\n }\n if (registered) {\n el.dot.className = active ? 'h-3 w-3 rounded-full bg-emerald-400' : 'h-3 w-3 rounded-full bg-yellow-300';\n el.status.textContent = active ? 'Service worker active' : 'Service worker registered (not controlling page)';\n el.sub.textContent = scope ? `scope: ${scope}` : 'registered';\n el.regBtn.classList.add('hidden');\n el.unregBtn.classList.remove('hidden');\n el.pingBtn.classList.remove('hidden');\n el.toggle.textContent = 'Registered';\n } else {\n el.dot.className = 'h-3 w-3 rounded-full bg-gray-300';\n el.status.textContent = 'No service worker registered';\n el.sub.textContent = 'Click Register to add one at ' + swPath;\n el.regBtn.classList.remove('hidden');\n el.unregBtn.classList.add('hidden');\n el.pingBtn.classList.remove('hidden');\n el.toggle.textContent = 'Not registered';\n }\n };\n\n // Detect support + current registration\n async function detect() {\n const supported = 'serviceWorker' in navigator;\n if (!supported) {\n setStatus({supported:false, falseMsg:'Service workers are not supported by this browser.'});\n log('ServiceWorker API not available');\n return;\n }\n try {\n // find a registration that matches the URL (fallback to getRegistrations)\n let reg = await navigator.serviceWorker.getRegistration(swPath);\n if (!reg) {\n const all = await navigator.serviceWorker.getRegistrations();\n // if multiple registered, prefer one that contains swPath in its scope or scriptURL\n reg = all.find(r => r?.scope?.includes('/') || r?.active?.scriptURL?.includes(swPath)) || null;\n }\n const active = !!(reg && (reg.active || navigator.serviceWorker.controller));\n const controlling = !!navigator.serviceWorker.controller;\n setStatus({supported:true, registered:!!reg, active:controlling || active, scope: reg?.scope || ''});\n log('Detected registration: ' + (reg ? (reg.scope || reg.active?.scriptURL || 'registered') : 'none'));\n } catch (err) {\n setStatus({supported:true, registered:false, active:false});\n log('Error detecting registration: ' + (err && err.message ? err.message : String(err)), 'text-red-600');\n }\n }\n\n // register sw\n async function registerSW() {\n if (!('serviceWorker' in navigator)) return;\n try {\n log('Registering ' + swPath + ' …');\n const reg = await navigator.serviceWorker.register(swPath, {scope: undefined});\n log('Registered: ' + (reg.scope || reg.installing?.scriptURL || 'ok'));\n // optionally wait until it's active\n await navigator.serviceWorker.ready;\n log('Service worker ready');\n await detect();\n } catch (err) {\n log('Register failed: ' + err.message, 'text-red-600');\n console.error(err);\n }\n }\n\n // unregister any registration matching swPath or all\n async function unregisterSW() {\n if (!('serviceWorker' in navigator)) return;\n try {\n log('Unregistering registrations…');\n const regs = await navigator.serviceWorker.getRegistrations();\n let count = 0;\n for (const r of regs) {\n // try to only remove the ones whose scriptURL includes swPath (fallback: remove all)\n if (!swPath || (r?.active?.scriptURL && r.active.scriptURL.includes(swPath)) || (r?.scope && r.scope.includes('/'))) {\n const ok = await r.unregister();\n if (ok) count++;\n }\n }\n log('Unregistered ' + count + ' registration(s)');\n await detect();\n } catch (err) {\n log('Unregister failed: ' + err.message, 'text-red-600');\n console.error(err);\n }\n }\n\n // Ping SW via MessageChannel and wait for reply\n function pingSW() {\n if (!('serviceWorker' in navigator)) return log('No SW support', 'text-red-600');\n const controller = navigator.serviceWorker.controller;\n if (!controller) {\n log('No controller (page not controlled by a SW). A reload might be required.', 'text-yellow-600');\n return;\n }\n const mc = new MessageChannel();\n const timeout = setTimeout(() => {\n log('Ping timed out (no response)', 'text-red-600');\n mc.port1.onmessage = null;\n }, 4000);\n mc.port1.onmessage = ev => {\n clearTimeout(timeout);\n log('PONG from SW: ' + JSON.stringify(ev.data));\n };\n try {\n controller.postMessage({type: 'PING', ts: Date.now()}, [mc.port2]);\n log('PING -> SW');\n } catch (err) {\n clearTimeout(timeout);\n log('Ping failed: ' + err.message, 'text-red-600');\n }\n }\n\n // listeners\n el.regBtn.addEventListener('click', async () => { await registerSW(); });\n el.unregBtn.addEventListener('click', async () => {\n if (!confirm('Unregister service workers for this origin?')) return;\n await unregisterSW();\n });\n el.pingBtn.addEventListener('click', () => pingSW());\n\n // react to controllerchange (page becomes controlled)\n navigator.serviceWorker && navigator.serviceWorker.addEventListener && navigator.serviceWorker.addEventListener('controllerchange', () => {\n log('controllerchange event');\n setTimeout(detect, 300);\n });\n\n // listen for messages from SW (fallback path if service worker broadcasts)\n navigator.serviceWorker && navigator.serviceWorker.addEventListener && navigator.serviceWorker.addEventListener('message', ev => {\n log('Message from SW: ' + JSON.stringify(ev.data));\n });\n\n // initial detect\n detect();\n\n // expose for debugging (optional)\n root.sune = {detect, registerSW, unregisterSW, pingSW};\n})();\n</script>",
"extension_html": "<sune src='https://raw.githubusercontent.com/sune-org/store/refs/heads/main/sync.sune' private />",
"script": ""
}
}
]