Follows the portal: the noun is "instance" everywhere the app says it — UI strings, CLI output, error details, docs and comments. The wire keys (`instance_id`, `instance_token`) and the hub route this calls move with it. An existing cloud.json is adopted rather than refused: without the key alias the dataclass fails to parse, which the caller swallows and reads as "never enrolled" instead of "reconnect". `instance_key` on a node type becomes `target_key`. It means the outside thing a node points at, which is a different sense of the word, and keeping both would put two meanings of "instance" in one codebase. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015YrQnKV3bnQd4K342y8tKj
46 lines
1.7 KiB
JavaScript
46 lines
1.7 KiB
JavaScript
/**
|
|
* The service worker, which exists only so a push can arrive when no tab is
|
|
* open. There is deliberately no `fetch` handler and nothing is cached: the
|
|
* page this app is served from carries a credential and is sent `no-store`,
|
|
* so caching it would hand the next visitor somebody else's session.
|
|
*
|
|
* `registration.scope` is the app's root in both places it runs — `/` on an
|
|
* instance of its own, `/i/{id}/` through the portal — which is why the
|
|
* push payload does not carry a URL.
|
|
*/
|
|
|
|
self.addEventListener("push", (event) => {
|
|
const alert = event.data ? event.data.json() : {}
|
|
const scope = new URL(self.registration.scope)
|
|
event.waitUntil(
|
|
self.registration.showNotification(alert.title || "Fluksio", {
|
|
body: alert.body || "",
|
|
// Under the portal the icons are the shared bundle's, not this
|
|
// instance's path.
|
|
icon: scope.pathname.startsWith("/i/")
|
|
? "/app-shell/icon-192.png"
|
|
: `${scope.pathname}icon-192.png`,
|
|
// The same fault repeating replaces its notification rather than
|
|
// stacking another one up.
|
|
tag: alert.flow || alert.title || "fluksio",
|
|
timestamp: Date.now(),
|
|
}),
|
|
)
|
|
})
|
|
|
|
self.addEventListener("notificationclick", (event) => {
|
|
event.notification.close()
|
|
const scope = self.registration.scope
|
|
event.waitUntil(
|
|
self.clients
|
|
.matchAll({ type: "window", includeUncontrolled: true })
|
|
.then((clients) => {
|
|
// A tab on this instance is already open: raise it rather than
|
|
// opening a second one.
|
|
const open = clients.find((client) => client.url.startsWith(scope))
|
|
if (open) return open.focus()
|
|
return self.clients.openWindow(scope)
|
|
}),
|
|
)
|
|
})
|