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.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015YrQnKV3bnQd4K342y8tKj
This commit is contained in:
2026-08-31 10:12:01 +02:00
co-authored by Claude Opus 5
parent 6534855492
commit d01a8dad37
101 changed files with 374 additions and 375 deletions
+7 -7
View File
@@ -1,11 +1,11 @@
"""Web Push: an alert reaching a phone that has this installation installed.
"""Web Push: an alert reaching a phone that has this instance installed.
The browser hands us a subscription — an endpoint URL at its own push service,
plus two keys — and from then on the engine can wake that device without it
holding a connection open. Two pieces of crypto are involved and both are
specified: the payload is encrypted to the subscription's keys (RFC 8291,
aes128gcm) so the push service carries something it cannot read, and the
request is signed with this installation's own keypair (VAPID, RFC 8292) so the
request is signed with this instance's own keypair (VAPID, RFC 8292) so the
service knows who is sending.
Only ``http-ece`` is new here; the signing is `pyjwt` and the request is
@@ -13,7 +13,7 @@ Only ``http-ece`` is new here; the signing is `pyjwt` and the request is
this in one call, but brings `requests` *and* `aiohttp` with it — two more HTTP
stacks on a machine that may well be a Raspberry Pi.
The keypair is this installation's identity to the push services and lives with
The keypair is this instance's identity to the push services and lives with
the subscriptions in one file. Losing it means every browser has to subscribe
again; it is regenerated on the spot if the file goes missing.
"""
@@ -62,7 +62,7 @@ class Subscription(BaseModel):
class _Store(BaseModel):
#: This installation's VAPID private key: the raw P-256 scalar, base64url.
#: This instance's VAPID private key: the raw P-256 scalar, base64url.
private_key: str = ""
subscriptions: list[Subscription] = Field(default_factory=list)
@@ -113,7 +113,7 @@ def _public_bytes(key: ec.EllipticCurvePrivateKey) -> bytes:
def public_key() -> str:
"""This installation's VAPID public key, generating the pair on first ask.
"""This instance's VAPID public key, generating the pair on first ask.
Base64url of the uncompressed point, which is the shape
`pushManager.subscribe` wants for `applicationServerKey`. Blocking.
@@ -126,7 +126,7 @@ def public_key() -> str:
key.private_numbers().private_value.to_bytes(32, "big")
)
_write(store)
logger.info("Generated this installation's web push keypair")
logger.info("Generated this instance's web push keypair")
return _b64url(_public_bytes(_private_key(store)))
@@ -156,7 +156,7 @@ def subscriptions() -> list[Subscription]:
def _vapid_headers(key: ec.EllipticCurvePrivateKey, endpoint: str) -> dict[str, str]:
"""Prove to the push service which installation is sending (RFC 8292)."""
"""Prove to the push service which instance is sending (RFC 8292)."""
origin = urlparse(endpoint)
token = jwt.encode(
{