@mhome/app-facade-protocol 1.34.1 → 1.36.0

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.
@@ -119,20 +119,18 @@ Candidates come from the shared discovery (`/local/pod/discovery/*`) with
119
119
  | `/local/host/provision/code` | `{"sessionId","code"}` | session snapshot |
120
120
  | `/local/host/provision/wifi` | `{"sessionId","ssid","password"?}` | session snapshot |
121
121
  | `/local/host/provision/wifi/scan` | `{"sessionId"}` | session snapshot |
122
- | `/local/host/provision/cancel` | `{"sessionId"}` | session snapshot |
123
- | `/local/host/provision/renew` | `{"sessionId"}` | session snapshot |
124
122
  | `/local/host/provision/status` | `{}` | `{"session": snapshot or null}` |
125
123
 
126
124
  Event `/local/host/provision/changed` carries a session snapshot. One session
127
125
  per native Client, and none while a pod session is active; discovery scanning
128
126
  pauses during either. Rejected requests use the error envelope and the stable
129
127
  `details.reason` values of `pod-commissioning-v1.md` section 7. The session is
130
- owned through the same 30-second lease, renewed with
131
- `/local/host/provision/renew` every 10 seconds; an expired lease cancels it.
128
+ owned by the native core until success, failure or the session deadline.
129
+ There is no cancellation or renewal endpoint; leaving the UI does not end it.
132
130
 
133
131
  Session states, in order: `connecting`, `awaiting_code`, `securing`,
134
132
  `reading_info`, `awaiting_wifi`, `joining_wifi`, `completed`; terminal `failed`,
135
- `cancelled`, `timed_out`. `completed` carries `host`, the reported `addresses`
133
+ `timed_out`. `completed` carries `host`, the reported `addresses`
136
134
  (IPv4 only, possibly empty) and `claimToken` from the `finish` response; the
137
135
  commissioner sends `finish` (up to 3 times while the secure session lasts)
138
136
  before reporting it. `claimToken` is absent when `finish` could not be
@@ -8,7 +8,8 @@ call the `/local/pod/*` targets of their native Client.
8
8
 
9
9
  Commissioning order is fixed: secure BLE session, Wi-Fi joined, user
10
10
  authorization, credential issue, delivery, activation. A credential is issued only
11
- after the pod reports a joined network. Any failure after issue revokes it.
11
+ after the pod reports a joined network. Failed setup releases the connection;
12
+ pending cloud credentials expire, and a fresh successful claim cleans up old credentials.
12
13
 
13
14
  ## 1. Device identity
14
15
 
@@ -24,7 +25,7 @@ after the pod reports a joined network. Any failure after issue revokes it.
24
25
  ## 2. BLE advertising
25
26
 
26
27
  Pods advertise only while unprovisioned, while re-commissioning after logout or
27
- revocation, or inside a re-provision window. A commissioned pod does not advertise.
28
+ credential invalidation, or inside a re-provision window. A commissioned pod does not advertise.
28
29
 
29
30
  - Service UUID (128-bit, shared by every MeowLink commissionable device):
30
31
  `a17a7ad5-9b2f-4010-9cf0-aa15ac54c40e`.
@@ -157,7 +158,7 @@ unprovisioned ──connect──▶ session_open ──handshake──▶ secur
157
158
  secured ──prov-config apply──▶ wifi_joining ──▶ wifi_connected | wifi_failed
158
159
  wifi_failed ──retry──▶ wifi_joining
159
160
  wifi_connected ──deliver──▶ activating ──time sync, refresh, commit──▶ commissioned | failed
160
- any pre-commit state ──timeout/disconnect/cancel──▶ unprovisioned
161
+ any pre-commit state ──timeout/disconnect──▶ unprovisioned
161
162
  ```
162
163
 
163
164
  Runtime states after commit:
@@ -176,8 +177,9 @@ Runtime states after commit:
176
177
  - `needs_recommission`: logout, or refresh rejected because the credential was
177
178
  revoked or the user no longer exists. Credential and local JWTs are erased,
178
179
  Wi-Fi is kept, advertising resumes with the Wi-Fi-configured flag.
179
- - `factory_resetting`: best-effort self-revoke, erase all persisted data
180
- including the identity key, reboot to `unprovisioned`.
180
+ - `factory_resetting`: purely offline, erase all persisted data including the
181
+ identity key and cached Hub tokens, reboot to `unprovisioned`. No cloud
182
+ request is needed. Logout also clears local credentials without cloud revocation.
181
183
 
182
184
  Time sync uses SNTP; if NTP is unreachable the pod may use the `Date` header of a
183
185
  Lion HTTPS response. Activation proofs require a synced clock.
@@ -227,7 +229,7 @@ claims `iss` and `sub` = `podId`, a single-valued `aud` = `pod-token-refresh`,
227
229
  proof can be accepted; a reused `jti` in that window fails with
228
230
  `pod_proof_replayed`.
229
231
 
230
- The first successful refresh moves `pending` to `active` and revokes every other
232
+ Before the first successful refresh moves `pending` to `active`, Lion deletes every other
231
233
  credential with the same `identity.keyId` (whichever user holds it) and the same
232
234
  user's other credentials with the same `deviceId`. A `pending` credential past
233
235
  `activateBefore` is rejected and deleted. Revoked credentials are deleted, so a
@@ -241,17 +243,16 @@ later refresh fails with `pod_credential_invalid`. Response
241
243
  `absent` (schema `schema/pod-credential-status.v1.schema.json`). `absent`
242
244
  covers no such credential, revoked, pending past `activateBefore`, and a
243
245
  credential owned by another user, so the answer never reveals other users'
244
- pods. `activatedAt` (epoch ms) is present when `active`. Commissioners use it to
245
- decide the outcome of an activation they could not observe (section 7).
246
+ pods. `activatedAt` (epoch ms) is present when `active`. It is informational;
247
+ commissioning success requires the device confirmation described in section 7.
246
248
 
247
- ### Revoke
249
+ ### Reset and cleanup
248
250
 
249
- `POST /api/v1/pod/credential/revoke`, body `{"podId"}` with the owning user's
250
- `Authorization`, or `{"podId","refreshToken","proof"}` where the proof uses
251
- `aud` = `pod-credential-revoke` (pod logout and factory reset). Idempotent:
252
- revoking a pod that does not exist or that the caller does not own is a no-op
253
- that also answers `{"ok":true}`, so the answer never reveals other users' pods.
254
- Response `{"ok":true}`.
251
+ There is no public Pod credential revocation endpoint and no App action that
252
+ withdraws a Pod's access without contacting the device. Factory reset executes
253
+ on the Pod itself. Remote reset, when provided, must reach an online Pod; a
254
+ cloud-side deletion is not a successful reset. This contract currently exposes
255
+ no remote reset target. Each setup creates a new Pod credential.
255
256
 
256
257
  ### List and rename
257
258
 
@@ -284,15 +285,9 @@ and unexpired pending pods, each
284
285
  - `/api/v1/hub/token/exchange` with a pod access token returns a Hub JWT with
285
286
  `clientKind` = `pod` and `podId` claims and the same lifetime as a Hub JWT
286
287
  for a user token.
287
- - Revoking a pod credential, by any path, also revokes the pod on the Hubs of
288
- its user's local Spaces. Before committing the revocation Lion marks the
289
- `scope.pods` resource dirty for each such Space; after it commits, Lion
290
- notifies the Hub through the pull-sync contract. A Hub that is offline pulls
291
- the marker when its bridge reconnects. `scope.pods` is a snapshot
292
- `{"podIds":[…]}` of the active pods of the Space's members. The Hub revokes
293
- the local tokens it issued to any other pod before the pull, disables the
294
- local auth of that pod's app client once no active token is left, and refuses
295
- and stops renewing that pod's local connections.
288
+ - Pod and ordinary Client local Hub JWTs have the same 100-year lifetime
289
+ (100 * 365 days). There is no per-Pod Hub revocation list or cloud-to-Hub
290
+ revocation sync. Local tokens are cleared on the Pod by reset/logout.
296
291
 
297
292
  ## 6. Pod runtime authentication
298
293
 
@@ -358,8 +353,6 @@ never show these values or `message` verbatim.
358
353
  | `/local/pod/commission/wifi` | `{"sessionId","ssid","password"?}` | session snapshot |
359
354
  | `/local/pod/commission/wifi/scan` | `{"sessionId"}` | session snapshot |
360
355
  | `/local/pod/commission/authorize` | `{"sessionId","scopeId"}` | session snapshot |
361
- | `/local/pod/commission/cancel` | `{"sessionId"}` | session snapshot |
362
- | `/local/pod/commission/renew` | `{"sessionId"}` | session snapshot |
363
356
  | `/local/pod/commission/status` | `{}` | `{"session": snapshot or null}` |
364
357
  | `/local/pod/bluetooth/settings` | `{}` | `{"opened"}` |
365
358
 
@@ -381,10 +374,10 @@ UIs reconcile with `status` and discovery `list` on start, resume, reconnect and
381
374
  when they become visible, and a snapshot with a lower `revision` than one
382
375
  already seen for the same session is stale.
383
376
 
384
- The session that `start` creates is owned through a 30-second lease. The
385
- caller renews it with `/local/pod/commission/renew` every 10 seconds while it
386
- shows the session. An expired lease cancels the session, except in `delivering`
387
- and `activating`, which run to their conclusion.
377
+ The native core owns the session until success or failure, bounded by
378
+ `expiresAtMs`. There is no user cancellation or session renewal. Leaving the
379
+ page does not end setup; returning to it reads `status`. Waiting for user input
380
+ also counts toward the deadline. Discovery leases still control scanning.
388
381
 
389
382
  Sign-in and Spaces are checked at `start` (`not_signed_in`,
390
383
  `scope_not_offered`) and again when the authorization prompt is built.
@@ -403,7 +396,7 @@ pod's Wi-Fi rather than adding a pod.
403
396
  Session states, in order: `connecting`, `awaiting_code`, `securing`,
404
397
  `reading_info`, `awaiting_wifi`, `joining_wifi`, `awaiting_authorization`,
405
398
  `issuing`, `delivering`, `activating`, `completed`; terminal `failed`,
406
- `cancelled`, `timed_out`. Wi-Fi states are skipped when the pod reports a
399
+ `timed_out`. Wi-Fi states are skipped when the pod reports a
407
400
  configured network and `prov-config` status reports it connected; while that
408
401
  status is `connecting` the commissioner keeps polling, and only after a failure
409
402
  does it reset Wi-Fi (`prov-ctrl`) and offer new credentials. The commissioner
@@ -413,18 +406,15 @@ scan runs waits for it. `revision` increases on every observable change.
413
406
  `expiresAtMs` is 10 minutes after `start` until delivery starts; from
414
407
  `delivering` on it is `activateBefore` plus 30 seconds.
415
408
 
416
- Lion decides the outcome of activation. In `delivering` and `activating`, a
417
- lost BLE link, a failed status exchange or the deadline does not revoke by
418
- itself; the commissioner asks `/api/v1/pod/credential/status`:
419
-
420
- - `active`: `completed` with `podId`.
421
- - `pending`: ask again every 5 seconds until `activateBefore` plus 30 seconds,
422
- then revoke and fail with `activation_failed`.
423
- - `absent`: fail with `activation_failed`.
409
+ Only the device's durable `commissioned` response confirms successful setup.
410
+ Lost BLE delivery confirmation or activation status fails the attempt, even
411
+ when Lion has already activated its credential. Expiry fails or times out the
412
+ attempt. The commissioner does not recover interrupted setup through Lion's
413
+ credential status. The user resets the device and starts a fresh attempt.
424
414
 
425
415
  A refused `deliver` fails with `delivery_failed` carrying the pod's `reason`
426
- (`invalid_payload` or `wrong_state`) in `detail`, and revokes. When the pod
427
- itself reports `failed`, the commissioner revokes and fails with
416
+ (`invalid_payload` or `wrong_state`) in `detail`. When the pod
417
+ itself reports `failed`, the commissioner fails with
428
418
  `activation_failed` carrying the pod's code. `activation_failed` without a pod
429
419
  code carries `not_activated`. The commissioner records `completed` before
430
420
  sending `finish`. Native Clients keep a non-terminal session running while the
@@ -438,10 +428,9 @@ Session error codes: `bluetooth_unavailable`, `device_busy`, `disconnected`,
438
428
  `detail`), `session_timeout`. `code_locked` is terminal: the device shows a new
439
429
  code once it accepts handshakes again. `failed` and `timed_out` always carry `error`. A rejected
440
430
  code returns to `awaiting_code` with `code_rejected`; a failed join returns to
441
- `awaiting_wifi` with the `wifi_*` code. No other state carries `error`. After
442
- issue, every terminal state other than `completed` revokes the credential unless
443
- Lion already reported it `absent`; the revoke uses the account that issued the
444
- credential.
431
+ `awaiting_wifi` with the `wifi_*` code. No other state carries `error`. Terminal states release the link and radio
432
+ without revoking credentials. Reset the Pod and start over after an uncertain
433
+ activation outcome; unused pending cloud credentials expire automatically.
445
434
 
446
435
  The schemas are `schema/pod-discovery.v1.schema.json` and
447
436
  `schema/pod-commission.v1.schema.json`.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "manifest": "mhome.app-facade.v1",
3
- "contractVersion": "1.34.1",
3
+ "contractVersion": "1.36.0",
4
4
  "callSchema": "schema/facade-call.v1.schema.json",
5
5
  "routing": "manifest/routing.v1.json",
6
6
  "routingSchema": "schema/routing.v1.schema.json",
@@ -1,14 +1,12 @@
1
1
  {
2
2
  "manifest": "mhome.host-provision.targets.v1",
3
- "contractVersion": "1.34.1",
3
+ "contractVersion": "1.36.0",
4
4
  "contract": "contract/host-provisioning-v1.md",
5
5
  "localTargets": [
6
6
  "/local/host/provision/start",
7
7
  "/local/host/provision/code",
8
8
  "/local/host/provision/wifi",
9
9
  "/local/host/provision/wifi/scan",
10
- "/local/host/provision/cancel",
11
- "/local/host/provision/renew",
12
10
  "/local/host/provision/status"
13
11
  ],
14
12
  "eventTargets": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "manifest": "mhome.hub.targets.v1",
3
- "contractVersion": "1.34.1",
3
+ "contractVersion": "1.36.0",
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.34.1",
3
+ "contractVersion": "1.36.0",
4
4
  "contract": "contract/pod-commissioning-v1.md",
5
5
  "localTargets": [
6
6
  "/local/pod/discovery/start",
@@ -12,8 +12,6 @@
12
12
  "/local/pod/commission/wifi",
13
13
  "/local/pod/commission/wifi/scan",
14
14
  "/local/pod/commission/authorize",
15
- "/local/pod/commission/cancel",
16
- "/local/pod/commission/renew",
17
15
  "/local/pod/commission/status",
18
16
  "/local/pod/bluetooth/settings"
19
17
  ],
@@ -63,15 +61,12 @@
63
61
  },
64
62
  "session": {
65
63
  "lifetimeMs": 600000,
66
- "leaseMs": 30000,
67
- "renewIntervalMs": 10000,
68
64
  "activationGraceMs": 30000,
69
65
  "credentialStatusPollMs": 5000
70
66
  },
71
67
  "cloud": {
72
68
  "issue": "pod/credential/issue",
73
69
  "status": "pod/credential/status",
74
- "revoke": "pod/credential/revoke",
75
70
  "statusSchema": "schema/pod-credential-status.v1.schema.json"
76
71
  },
77
72
  "activationErrorCodes": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "manifest": "mhome.app-facade.routing.v1",
3
- "contractVersion": "1.34.1",
3
+ "contractVersion": "1.36.0",
4
4
  "targetPrefix": "/app/",
5
5
  "default": {
6
6
  "execution": "scopeMode",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "manifest": "mhome.messaging.targets.v1",
3
- "contractVersion": "1.34.1",
3
+ "contractVersion": "1.36.0",
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.34.1",
3
+ "version": "1.36.0",
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.34.1",
3
+ "contractVersion": "1.36.0",
4
4
  "manifest": "manifest/app-facade.v1.json",
5
5
  "schemas": {
6
6
  "capabilityDescriptor": "schema/capability-descriptor.v1.schema.json",
@@ -18,7 +18,6 @@
18
18
  "joining_wifi",
19
19
  "completed",
20
20
  "failed",
21
- "cancelled",
22
21
  "timed_out"
23
22
  ]
24
23
  },
@@ -22,7 +22,6 @@
22
22
  "activating",
23
23
  "completed",
24
24
  "failed",
25
- "cancelled",
26
25
  "timed_out"
27
26
  ]
28
27
  },