Rename Installation to Instance

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.
This commit is contained in:
2026-08-31 10:12:01 +02:00
parent 271d4513eb
commit 6c8a101d24
101 changed files with 374 additions and 375 deletions
+5 -5
View File
@@ -1,5 +1,5 @@
/**
* Whether the installation this page talks to is reachable right now.
* Whether the instance this page talks to is reachable right now.
*
* Transport state, kept apart from `liveStore` on purpose: that one holds what
* the engine is doing, this one holds whether we can hear it at all. Only
@@ -11,7 +11,7 @@
type Connection = {
offline: boolean
/** When the portal last heard from the installation, epoch ms. */
/** When the portal last heard from the instance, epoch ms. */
lastSeen: number | null
}
@@ -38,7 +38,7 @@ function emit(next: Connection) {
export const connectionStore = {
setOffline(lastSeen: string | number | null) {
// The socket is up, so the installation is reachable: this was one bad
// The socket is up, so the instance is reachable: this was one bad
// answer rather than a lost tunnel, and the banner would have nothing to
// take it back down again.
if (socketOpen) return
@@ -56,7 +56,7 @@ export const connectionStore = {
/**
* The live socket opened or closed.
*
* An open socket is proof the installation can be heard, so it also clears
* An open socket is proof the instance can be heard, so it also clears
* the banner — and since the socket reconnects on its own, that is the one
* release the offline state can always count on.
*/
@@ -76,7 +76,7 @@ export const connectionStore = {
/**
* The proxy's offline answer: a 503 carrying `{offline, last_seen}`.
*
* Told apart from every other 503 by that body, so an installation that is
* Told apart from every other 503 by that body, so an instance that is
* merely busy is not reported as unreachable.
*/
export function offlineDetail(
+6 -6
View File
@@ -1,26 +1,26 @@
/**
* Runtime configuration injected when this app is served through a portal.
*
* A normal installation ships the same bundle and finds nothing here, so every
* A normal instance ships the same bundle and finds nothing here, so every
* portal-aware branch in the app collapses to its ordinary behaviour. When a
* portal serves the page it writes this object into the document first: the
* API lives under the installation's own path, the credential comes with the
* API lives under the instance's own path, the credential comes with the
* page rather than from storage, and there is somewhere to go "back" to.
*
* Deliberately not localStorage: two installations open in one browser share
* Deliberately not localStorage: two instances open in one browser share
* an origin, and a single `access_token` key would have them overwrite each
* other's session.
*/
export type PortalConfig = {
installationId: string
installationName: string
instanceId: string
instanceName: string
/** Router basepath, e.g. `/i/{id}`. */
basePath: string
/** Origin-relative API base; the SDK appends `/api/v1/...`. */
apiBase: string
/** Where "back to portal" goes. */
portalUrl: string
/** Short-lived token scoped to this installation. */
/** Short-lived token scoped to this instance. */
token: string
}
+4 -4
View File
@@ -1,13 +1,13 @@
/**
* Subscribing this browser to the installation's notifications.
* Subscribing this browser to the instance's notifications.
*
* A push arrives through the service worker, so it reaches a phone with no tab
* open — which is the whole point, and the reason this is not the in-app
* notification stack. The engine decides *what* is worth sending in its alert
* rules; this only says which browsers hear it.
*
* Everything here is per browser and per installation: the subscription is
* stored by the installation it was made against, so a phone that opens two
* Everything here is per browser and per instance: the subscription is
* stored by the instance it was made against, so a phone that opens two
* houses through the portal is two subscriptions and hears each separately.
*/
@@ -62,7 +62,7 @@ function keyBytes(key: string): Uint8Array<ArrayBuffer> {
}
/**
* Ask permission, subscribe, and tell the installation where to reach us.
* Ask permission, subscribe, and tell the instance where to reach us.
*
* Throws with something worth reading if the person says no — the caller puts
* it on screen, because a silently ignored button is worse than a refusal.