@mhome/app-facade-protocol 1.47.0 → 1.49.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -49,6 +49,13 @@ timings and request reasons are in `manifest/pod-targets.v1.json`; snapshots use
49
49
  `schema/pod-discovery.v1.schema.json` and `schema/pod-commission.v1.schema.json`;
50
50
  User Pod enrollment uses a one-time login approval; activation is confirmed on the paired device.
51
51
 
52
+ `/app/pod/list` reads registered Pod Clients in the active Space, including
53
+ connections that are currently absent. `/app/host/list` reads historical Host
54
+ registrations without granting management access; see the
55
+ [Host directory contract](contract/host-directory-v1.md). Native commissioning
56
+ uses the existing device protocols; the Agent resumes only after verifying the
57
+ resulting registration. Host completion identifies both `hostId` and `env`.
58
+
52
59
  `host_provision` (1.34.0) defines BLE Wi-Fi provisioning of embedded Hosts
53
60
  (`/local/host/provision/*`) on the same BLE layer; discovery candidates carry
54
61
  `kind`. A completed session carries the one-time `claimToken` that the first
@@ -247,8 +247,15 @@ stores the resulting refresh token, and refresh uses the standard User login
247
247
  endpoint. A failed attempt is retried with a new approval; no old protocol is
248
248
  accepted.
249
249
 
250
- `podId` identifies the enrollment/device-list entry, not the authenticated User.
251
- `POST /api/v1/pod/list` and `/api/v1/pod/rename` use the ordinary User login.
250
+ `podId` identifies a single approval attempt, not the durable device or authenticated
251
+ User. The durable `registrationId` derives from the business User and the validated
252
+ persistent device-key fingerprint. `POST /api/v1/pod/list` returns that ID;
253
+ `/api/v1/pod/rename` accepts `{registrationId, name}` with ordinary User login.
254
+ Successful authentication atomically creates the registration if absent and records
255
+ completion on the consumed approval. Retries preserve the initial registration and
256
+ current display name. Unauthenticated attempts create no device-list entry.
257
+ The attempt receipt remains readable for one day after the approval's expiry;
258
+ `expiresAt` still controls its ten-minute, single-use authentication window.
252
259
  There is no cloud credential-status polling or server-side Pod revocation flow.
253
260
  Factory reset clears device credentials and rotates the pairing identity.
254
261
 
@@ -359,7 +366,9 @@ scans for networks once on entering `awaiting_wifi`; a scan request while that
359
366
  scan runs waits for it. `revision` increases on every observable change.
360
367
 
361
368
  `expiresAtMs` is 10 minutes after `start` until delivery starts; from
362
- `delivering` on it is `activateBefore` plus 30 seconds.
369
+ `delivering` on, User approval uses `activateBefore` plus 30 seconds; Space delivery
370
+ gets a separate two-minute confirmation deadline. An active Space credential has no
371
+ first-use deadline and never causes immediate completion or an expired attempt.
363
372
 
364
373
  Only the device's durable `commissioned` response confirms successful setup.
365
374
  Lost LAN confirmation triggers at most three reconnections to this attempt's
@@ -398,8 +407,10 @@ The schemas are `schema/pod-discovery.v1.schema.json` and
398
407
  `Authorization` and `ScopeId`, with the same device identity request as personal
399
408
  issuance. Only the current Space owner may assist. The Space must be local and have one
400
409
  published Hub with business and Host TLS identities. Cloud Spaces must complete
401
- Hub setup first. The issuer creates a fresh `appClientId` (`a:<random id>`) and
402
- signs a local JWT using the existing Space signing key and local-client audience.
410
+ Hub setup first. The issuer derives `appClientId` from tenant, Space and the validated
411
+ persistent device-key fingerprint. The same device in the same Space retains this
412
+ ID across retries; a factory reset rotates its key. Candidate local JWTs use the
413
+ existing Space signing key and local-client audience.
403
414
 
404
415
  Claims are `token_type: local_space_client_access`, `sub: <scopeId>`,
405
416
  `tenant_id`, `scope_id`, `hub_id`, `app_client_id`, `jti`, `iat`, `exp`, `is_test`.
@@ -410,11 +421,17 @@ Personal Pod issuance no longer stores `issuedScopeId`.
410
421
 
411
422
  Lion sends `{jwtToken, clientSource:"pod"}` to the authenticated Hub Bridge
412
423
  `/hub/client/space/register`. Core verifies signature, audience, issuer, current
413
- Hub, environment, Space and canonical installation ID, and stores a pending
414
- credential. First authentication must occur within ten minutes of JWT issuance.
415
- The response is `{credentialId, status:"pending", activateBefore}`. Lion returns
416
- `{credentialId, appClientId, jwtToken, activateBefore, hubIdentity}` only after
417
- registration succeeds. The Hub identity includes its business P-256 key and
424
+ Hub, environment, Space and canonical installation ID. It reuses a valid current
425
+ pending or active credential, or atomically selects a replacement after fresh owner
426
+ authorization. Concurrent issuers receive the selected credential; a stale replacement
427
+ cannot overwrite activation or revocation. Pending reuse retains its original
428
+ first-authentication deadline, ten minutes after JWT issuance. Invalid, revoked,
429
+ expired or differently bound credentials are not reused. Signature/key infrastructure
430
+ failures propagate instead of being interpreted as absence.
431
+ The Bridge returns `{credentialId, appClientId, jwtToken, status, activateBefore}`.
432
+ Lion returns `{credentialId, appClientId, jwtToken, credentialState, activateBefore,
433
+ hubIdentity}`. State is `pending` with its epoch-millisecond first-use deadline, or
434
+ `active` with `activateBefore:null`. Issuance alone does not publish a device-list entry. The Hub identity includes its business P-256 key and
418
435
  Host TLS public key, bound to `tenantId`, `scopeId`, `hubId` and `hostId`.
419
436
 
420
437
  The secured LAN `pod-credential` delivery is:
@@ -430,8 +447,10 @@ bounded to 8192 bytes; BLE credential delivery remains disabled.
430
447
 
431
448
  The Pod discovers the matching runtime environment and Space's Hub, pins TLS,
432
449
  verifies the signed Hub proof, and authenticates with the local JWT and signed
433
- `appClientId`. Core atomically activates the pending credential after all binding
434
- checks. The Pod requires a Space principal for the same Space, installation and
450
+ `appClientId`. After authentication checks succeed, Core atomically activates the
451
+ credential and publishes the durable AppClient registration. Repeated authentication
452
+ preserves the first activation; later offline or revoked credentials do not erase the
453
+ registration. The Pod requires a Space principal for the same Space, installation and
435
454
  credential in the authenticated response, then durably saves the profile. Only
436
455
  then does LAN setup report completion. The LAN status field named `podId` is an
437
456
  enrollment correlation ID: for Space mode it carries `credentialId`, never the
@@ -450,3 +469,26 @@ MANAGE, personal resources and Host user administration are rejected. It joins
450
469
  the canonical Space-client conversation group, never an initializer's threads.
451
470
  The billing owner fallback is not an acting identity. Host management tokens are
452
471
  independent and are never issued by this flow.
472
+
473
+ ## Registered Pod list
474
+
475
+ `/app/pod/list` takes empty input and lists persisted Pod Clients in the current
476
+ Space, including disconnected registrations. A personal caller sees their own
477
+ User Pods and Space-owned Pods. Rows contain `appClientId`, `clientMode`,
478
+ `scopeId`, `registered`, `connected` and `observationSource` (`hub` or `cloud`);
479
+ the envelope includes `observedAtMs`. Connection status is observed from that
480
+ execution endpoint, not a statement about physical power or LAN reachability.
481
+ Native clients combine this result with their own discovery observations.
482
+ Never merge a Bluetooth short ID with a registered identity without proof.
483
+ This read does not issue credentials or change Pod identity.
484
+
485
+
486
+ `appClientId` identifies a registered application client; it is not the enrollment
487
+ `podId` used by native commissioning. The list does not invent that association.
488
+ `/app/pod/enrollment/get` takes `{podId}` and returns `{podId, clientMode: "user",
489
+ registered}` from the authenticated user's successful receipt for that exact attempt.
490
+ An older registration for the same device cannot complete a different attempt.
491
+ `/app/pod/space/enrollment/get` takes the same input and checks the current Space's
492
+ active local credential, returning `clientMode: "space"`; this read requires Space
493
+ MANAGE. A cloud Space has no such local enrollment and returns `registered:false`.
494
+ Both checks are read-only completion hooks. They do not issue or renew credentials.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "manifest": "mhome.app-facade.v1",
3
- "contractVersion": "1.47.0",
3
+ "contractVersion": "1.49.2",
4
4
  "callSchema": "schema/facade-call.v1.schema.json",
5
5
  "routing": "manifest/routing.v1.json",
6
6
  "routingSchema": "schema/routing.v1.schema.json",
@@ -27,7 +27,12 @@
27
27
  },
28
28
  "pod": {
29
29
  "targets": "manifest/pod-targets.v1.json",
30
- "contract": "contract/pod-commissioning-v1.md"
30
+ "contract": "contract/pod-commissioning-v1.md",
31
+ "listTarget": "/app/pod/list",
32
+ "enrollmentTargets": [
33
+ "/app/pod/enrollment/get",
34
+ "/app/pod/space/enrollment/get"
35
+ ]
31
36
  },
32
37
  "hostProvision": {
33
38
  "targets": "manifest/host-provision-targets.v1.json",
@@ -150,7 +155,8 @@
150
155
  "issuer": "cloud",
151
156
  "firstClaimTransport": "directLanOnly",
152
157
  "authorizationTarget": "/app/host/authorization",
153
- "authorizationSchema": "schema/host-authorization.v1.schema.json"
158
+ "authorizationSchema": "schema/host-authorization.v1.schema.json",
159
+ "listTarget": "/app/host/list"
154
160
  },
155
161
  "clientAppearance": {
156
162
  "schema": "schema/client-appearance.v1.schema.json",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "manifest": "mhome.host-provision.targets.v1",
3
- "contractVersion": "1.47.0",
3
+ "contractVersion": "1.49.2",
4
4
  "contract": "contract/host-provisioning-v1.md",
5
5
  "localTargets": [
6
6
  "/local/host/provision/start",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "manifest": "mhome.hub.targets.v1",
3
- "contractVersion": "1.47.0",
3
+ "contractVersion": "1.49.2",
4
4
  "appTargets": [
5
5
  "/app/hub/get",
6
6
  "/app/hub/remove",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "manifest": "mhome.pod.targets.v1",
3
- "contractVersion": "1.47.0",
3
+ "contractVersion": "1.49.2",
4
4
  "contract": "contract/pod-commissioning-v1.md",
5
5
  "localTargets": [
6
6
  "/local/pod/discovery/start",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "manifest": "mhome.app-facade.routing.v1",
3
- "contractVersion": "1.47.0",
3
+ "contractVersion": "1.49.2",
4
4
  "targetPrefix": "/app/",
5
5
  "default": {
6
6
  "execution": "scopeMode"
@@ -31,7 +31,9 @@
31
31
  "/app/messaging/code/status",
32
32
  "/app/messaging/binding/list",
33
33
  "/app/messaging/bind/code/create",
34
- "/app/messaging/unbind"
34
+ "/app/messaging/unbind",
35
+ "/app/host/list",
36
+ "/app/pod/enrollment/get"
35
37
  ],
36
38
  "scopeModeTargets": [
37
39
  "/app/artifact/resolve",
@@ -43,7 +45,9 @@
43
45
  "/app/artifact/upload/complete",
44
46
  "/app/artifact/upload/cancel",
45
47
  "/app/system/instances/get",
46
- "/app/system/clients/get"
48
+ "/app/system/clients/get",
49
+ "/app/pod/list",
50
+ "/app/pod/space/enrollment/get"
47
51
  ],
48
52
  "hubPrefixes": [
49
53
  "/app/plugin/",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "manifest": "mhome.messaging.targets.v1",
3
- "contractVersion": "1.47.0",
3
+ "contractVersion": "1.49.2",
4
4
  "requestTargets": [
5
5
  "/app/messaging/provider/list",
6
6
  "/app/messaging/provider-account/list",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mhome/app-facade-protocol",
3
- "version": "1.47.0",
3
+ "version": "1.49.2",
4
4
  "description": "Build-time protocol artifacts for mhome.app-facade",
5
5
  "license": "MIT",
6
6
  "repository": {
package/protocol.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "protocol": "mhome.app-facade",
3
- "contractVersion": "1.47.0",
3
+ "contractVersion": "1.49.2",
4
4
  "manifest": "manifest/app-facade.v1.json",
5
5
  "schemas": {
6
6
  "hostAuthorization": "schema/host-authorization.v1.schema.json",