@mhome/app-facade-protocol 1.93.0 → 1.109.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 +13 -1
- package/contract/automation-presentation-v1.md +76 -0
- package/contract/automation-v1.md +28 -0
- package/contract/client-space-focus-v1.md +26 -0
- package/contract/entity-presentation-v1.md +24 -1
- package/contract/integration-presentation-v1.md +1 -1
- package/contract/plugin-preview-v1.md +16 -0
- package/contract/reference-presentation-v1.md +35 -0
- package/contract/resource-read-v1.md +2 -2
- package/contract/space-presentation-v1.md +45 -0
- package/contract/storage-v1.md +3 -1
- package/contract/widget-presentation-v1.md +36 -0
- package/contract/widget-writes-v1.md +44 -0
- package/fixtures/authorization/decisions.json +96 -0
- package/fixtures/entity-presentation.conformance.json +216 -0
- package/fixtures/nfc.conformance.json +442 -0
- package/fixtures/presentation/cases.json +48 -50
- package/fixtures/reference-presentation.v1.json +5 -0
- package/fixtures/routing/cases.json +192 -0
- package/fixtures/widget-presentation.v1.json +96 -0
- package/manifest/app-facade.v1.json +87 -6
- package/manifest/authorization.v1.json +75 -99
- package/manifest/host-provision-targets.v1.json +1 -1
- package/manifest/hub-targets.v1.json +1 -1
- package/manifest/pod-targets.v1.json +1 -1
- package/manifest/presentation-times.v1.json +50 -1
- package/manifest/routing.v1.json +14 -4
- package/manifest/targets.v1.json +1 -1
- package/package.json +1 -1
- package/protocol.json +1 -1
- package/schema/automation-presentation.v1.schema.json +602 -0
- package/schema/automation.v1.schema.json +142 -0
- package/schema/entity-presentation.v1.schema.json +111 -0
- package/schema/routing.v1.schema.json +5 -1
package/README.md
CHANGED
|
@@ -121,6 +121,16 @@ Room uses one `/app/room/list` read. Every Room has `roomId`, `roomName`,
|
|
|
121
121
|
`index`, `deviceCount`, and `deviceIds`; full and essential keep all five fields.
|
|
122
122
|
Membership IDs include Device groups without expanding their members or state.
|
|
123
123
|
|
|
124
|
+
Room writes use `/app/room/create`, `/rename`, `/delete`, `/reorder`,
|
|
125
|
+
`/devices/move`, and `/devices/remove` under the same `/app/room` prefix.
|
|
126
|
+
Reorder accepts every current Room ID exactly once in the desired order.
|
|
127
|
+
Moves require a destination for each unique member ID; removal explicitly unassigns
|
|
128
|
+
members. Repeating a move or removal is a successful no-op. Deleting a Room
|
|
129
|
+
unassigns its members without deleting Devices or Device groups. Only deletion
|
|
130
|
+
supports the prepared confirmation flow; other writes execute directly.
|
|
131
|
+
Room write inputs use their declared fields and JSON string IDs/names; legacy fields
|
|
132
|
+
and numeric or boolean IDs/names are rejected rather than silently converted.
|
|
133
|
+
|
|
124
134
|
Targets without a dedicated projection retain their business fields in YAML;
|
|
125
135
|
essential does not promise a smaller field set for every domain. Targets own that selection.
|
|
126
136
|
|
|
@@ -249,7 +259,7 @@ Space-bound `nodeId`, `version`, and Plugin-owned `payload`. The former
|
|
|
249
259
|
contains only the generic transport contract. Binding/offline observations come from
|
|
250
260
|
`/app/plugin/enabled/list`, independently of the runtime's status.
|
|
251
261
|
|
|
252
|
-
UI Integration metadata uses `/app/integration/
|
|
262
|
+
UI Integration metadata uses `/app/presentation/integration/get`; see
|
|
253
263
|
[the presentation contract](contract/integration-presentation-v1.md).
|
|
254
264
|
|
|
255
265
|
## Artifact delivery
|
|
@@ -268,3 +278,5 @@ still applies. Local file download remains a client workflow over ordinary resol
|
|
|
268
278
|
|
|
269
279
|
Agent Profile Markdown image ownership and canonical read-back are specified in
|
|
270
280
|
[Agent Profile media](contract/agent-profile-media-v1.md).
|
|
281
|
+
|
|
282
|
+
NFC management: [contract](contract/nfc-v1.md), [schema](schema/nfc.v1.schema.json).
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Automation UI presentation
|
|
2
|
+
|
|
3
|
+
All targets use the normal App Facade envelope. Reads require Space read authority; editor and mutation targets require Space write authority.
|
|
4
|
+
They are UI entrypoints, not Agent/CLI/MCP tools. Inputs reject unknown fields.
|
|
5
|
+
Full and Essential use the same business read scope; UI requests Full.
|
|
6
|
+
|
|
7
|
+
| Target | Input | Output and read boundary |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| `/app/presentation/automation/names/get` | `{ids}`: 1–100 selected, trimmed/deduplicated IDs | `{automations: {id: label}}`. Missing IDs omitted. Selected definition metadata only; no source downloads, parsing, state, history or graph reads. |
|
|
10
|
+
| `/app/presentation/automation/list` | `{type: "RECURRING" \| "TASK_FLOW"}` | `{automations}`: current-type regular user programs, with labels, runnable/health/expiry metadata, enabled/running/blocked, last-run `timestamp`, status timestamps and tags. No temporary-program, Group, Widget, snapshot, graph or authored-source expansion. |
|
|
11
|
+
| `/app/presentation/automation/overview/get` | `{automationId}`: nonblank, trimmed | `{id,name,type,enabled,runnable,corrupted,blocked,widgets}`. Selected metadata, status, cloud quota display state and owned Widget configuration/current values. No source, graph traversal, running history or snapshots. Missing definition is not-found. |
|
|
12
|
+
| `/app/presentation/automation/placements/get` | `{automationId}`: nonblank, trimmed | `{canvases:[{id,name,containsAutomation}]}`. Reads owned Widgets, Widget-to-Card relations and canvas metadata/card IDs; never loads Card bodies. Retains existing default-canvas initialization when the Space has none. |
|
|
13
|
+
|
|
14
|
+
Labels use saved preferredName, then the script-derived saved name, then the
|
|
15
|
+
existing unknown-label fallback. Metadata reads never require source storage to
|
|
16
|
+
be available. Names and overview permit generated-program inspection within the
|
|
17
|
+
authorized Space; this does not widen user-program mutation Facades. Group
|
|
18
|
+
management remains in the Group domain.
|
|
19
|
+
|
|
20
|
+
Core filters the regular definition table by type in SQL and uses selected state
|
|
21
|
+
reads. Cloud definition storage is partitioned by Space, so list reads that
|
|
22
|
+
partition's stored metadata and filters by type before loading state. It does not
|
|
23
|
+
hydrate source bodies or read the temporary/Group stores. This is not a promise
|
|
24
|
+
of a type-specific physical index. Billing display and lifecycle state retain
|
|
25
|
+
their existing authorities; enabled, runnable and running are independent.
|
|
26
|
+
|
|
27
|
+
List Full timestamps are milliseconds. Essential renders explicit timestamp
|
|
28
|
+
fields in the Space's Home timezone. Widget values retain their existing Widget
|
|
29
|
+
DTO semantics; their numbers are not interpreted as timestamps.
|
|
30
|
+
|
|
31
|
+
The frontend loads only the active list type, caches visited types within the
|
|
32
|
+
active Space, applies realtime events to loaded rows, and invalidates inactive
|
|
33
|
+
caches on incomplete updates or reconnect. Unloaded tab counts are unknown,
|
|
34
|
+
not zero. Overview and placements are separate on-demand reads. Snapshot panels
|
|
35
|
+
continue using `/app/automation/snapshot/list` only when opened.
|
|
36
|
+
|
|
37
|
+
Automation detail includes `runnable` from its already-loaded definition; Group
|
|
38
|
+
entries omit it. Automation status includes `corrupted` from the existing status
|
|
39
|
+
and temporary `expireAt` from creation/last-run timestamps. Ordinary configuration
|
|
40
|
+
editor initialization supplies the metadata it already loaded, so subsequent
|
|
41
|
+
runtime hydration only needs status.
|
|
42
|
+
|
|
43
|
+
## Selected summaries and configuration editing
|
|
44
|
+
|
|
45
|
+
`/app/presentation/automation/summaries/get` accepts the same bounded selected
|
|
46
|
+
`{ids}` as names. It returns `{items:[{requestedId,found,resource}]}` in normalized input
|
|
47
|
+
order. A found resource contains ListItem fields plus `automationId`, `temp`,
|
|
48
|
+
nullable `lastRunAt` and `expireAt`. Missing items omit resource. It supports
|
|
49
|
+
stored Standard, Temporary and generated programs; it does not load script
|
|
50
|
+
bodies, parse source, expand Widgets, snapshots or graphs. Public program status
|
|
51
|
+
also uses metadata rather than downloading authored source.
|
|
52
|
+
|
|
53
|
+
| Target | Input | Result / retained behavior |
|
|
54
|
+
| --- | --- | --- |
|
|
55
|
+
| `/app/presentation/automation/overview/init` | `{automationId?,inspireId?,inspireVersion?,snapshotId?,args?}` | Existing editor session, required installs, AutomationOverview and already-loaded metadata. Snapshot takes precedence over existing program, then Inspire. Uses the authenticated Client and existing staged-Inspire developer session. |
|
|
56
|
+
| `/app/presentation/automation/overview/config/provide` | `{sessionId,var,input}` | Existing option query and editor revision. |
|
|
57
|
+
| `/app/presentation/automation/overview/config/update` | `{sessionId,var,inputs?,widgetize?}` | Existing config evaluation, diagnostics and revision. |
|
|
58
|
+
| `/app/presentation/automation/overview/save` | `{sessionId,automationId?,inspireId?,inspireVersion?,snapshotId?,preferredName?,debug?,addCard?,canvasIds?}` | `{automationId,runnable,enabled}`. Existing single-save guard, Client ownership, prepare/save/complete revision checks and internal normalized-source persistence. Legacy snapshotId/addCard/canvasIds are accepted but do not perform placement; frontend creates placements separately. |
|
|
59
|
+
| `/app/presentation/automation/overview/cancel` | `{sessionId}` | Canonical acknowledgement without data. Existing Client ownership check and session cleanup. |
|
|
60
|
+
| `/app/presentation/automation/copy` | `{automationId,name?}` | `{automationId,runnable,enabled}`. Copies the existing script/template metadata using the internal save operation. |
|
|
61
|
+
| `/app/presentation/automation/enroll` | `{automationId,name?}` | `{automationId,runnable,enabled}`. Existing enrollment behavior. |
|
|
62
|
+
| `/app/presentation/automation/share` | `{automationId}` | Existing `{sharedId}` from the share service, using trusted caller identity. |
|
|
63
|
+
| `/app/presentation/automation/generated/enable` | `{automationId}` | Existing AutomationStatus for the selected generated program. Enables listening; does not force execution. |
|
|
64
|
+
| `/app/presentation/automation/generated/disable` | `{automationId}` | Existing AutomationStatus after disabling. |
|
|
65
|
+
| `/app/presentation/automation/generated/run` | `{automationId,timezone?,locationSymbol?}` | Canonical acknowledgement without data. Forces the existing stored generated program's threads, including Recurring programs. Runtime execution remains asynchronous. |
|
|
66
|
+
|
|
67
|
+
Generated control accepts only stored `P-`, `S-`, `G-` program IDs. It does not
|
|
68
|
+
rename generated programs, control Group entities, or widen public user-program
|
|
69
|
+
start/stop. Actor and Client come from trusted ingress, never arbitrary sideData.
|
|
70
|
+
Activity logging is best effort and cannot turn a successful control into a
|
|
71
|
+
failure. These UI targets are not automatically exposed to Agent/CLI/MCP.
|
|
72
|
+
|
|
73
|
+
The script-source editor and all legacy `/automation/*` Controller routes are
|
|
74
|
+
retired. Configuration editing retains the existing internal save behavior;
|
|
75
|
+
public `/app/automation/save` retains its independent validated-source contract
|
|
76
|
+
for Agent/CLI/MCP. Internal compiler/format capabilities remain available.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Automation controls and display names
|
|
2
|
+
|
|
3
|
+
These Space-scoped public operations accept user programs, including temporary Task Flows.
|
|
4
|
+
Generated Twin and Group programs remain internal resources.
|
|
5
|
+
|
|
6
|
+
- `/app/automation/start` accepts `automationId` and optional `timezone` and
|
|
7
|
+
`locationSymbol` for execution text. Authenticated actor information is server-owned.
|
|
8
|
+
Recurring programs are enabled; Task Flows are activated and triggered.
|
|
9
|
+
- `/app/automation/stop` accepts `automationId`, disables the program and cancels
|
|
10
|
+
all its instances, including durable waits. Completed actions are not undone.
|
|
11
|
+
- Both return Full `data: {automationId, enabled, running}` with observed state.
|
|
12
|
+
A short Task Flow may already be idle when start returns. Essential renders the
|
|
13
|
+
same fields as YAML. Failures use the canonical error envelope, never `success:false`
|
|
14
|
+
inside successful business data. State pushes may supersede a request result.
|
|
15
|
+
- `/app/automation/rename` accepts only Standard Automations (`AutomationUtil.is_std`),
|
|
16
|
+
excluding Group entity IDs. Twin, Group, Temporary and other prefixed internal
|
|
17
|
+
programs cannot be renamed here. Rename a Group through its Group operation.
|
|
18
|
+
It accepts `automationId` and a nonblank `name`, and returns
|
|
19
|
+
`{automationId, name}`. It changes display metadata without parsing, compiling,
|
|
20
|
+
replacing script source, creating a snapshot or restarting a generation. Public
|
|
21
|
+
list/detail and UI labels use this display name. Ordinary source edits preserve it;
|
|
22
|
+
snapshot rollback restores the snapshot's configuration.
|
|
23
|
+
- `/app/automation/description/update` accepts `automationId`, `expectedScriptHash`
|
|
24
|
+
and at least one of `description` or nonempty `varDescription`. It validates the
|
|
25
|
+
exact source hash and parses the rewritten description. `name` is rejected; use
|
|
26
|
+
rename. The script's authored root name remains available in the script itself.
|
|
27
|
+
|
|
28
|
+
Inputs are closed objects. The schema is `schema/automation.v1.schema.json`.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Client Space focus
|
|
2
|
+
|
|
3
|
+
`/app/client/space/focus` is a Client-only, connection-owned App Facade. It replaces
|
|
4
|
+
`/focus`; no legacy alias exists. It is not a user preference or an Agent/MCP tool.
|
|
5
|
+
The receiving transport must prove the live authenticated Client connection and
|
|
6
|
+
must never forward this call to a Space owner or accept a client ID in input.
|
|
7
|
+
|
|
8
|
+
Request: `{"control":{"mode":"direct"},"input":{"targetSpaceId":"space-b"}}`.
|
|
9
|
+
`targetSpaceId` is required: non-empty unpadded text selects a Space, explicit
|
|
10
|
+
`null` clears focus. User membership is checked authoritatively by Cloud; a local
|
|
11
|
+
Host accepts only its authenticated session's Space (or clear). A bound Space
|
|
12
|
+
Client can only affect its enrolled Space. No read of the old Space is required.
|
|
13
|
+
|
|
14
|
+
Both request-response (`arq`) and one-way state synchronization (`ad`) use this
|
|
15
|
+
same envelope. Native switch orchestration retains its existing ACK and session
|
|
16
|
+
fences. Background synchronization remains per physical connection and is not
|
|
17
|
+
an additional user switch. It never replays an obsolete clear after reconnect.
|
|
18
|
+
For Cloud clear, the existing envelope `scopeId`, when non-empty, is a condition:
|
|
19
|
+
a delayed clear for A cannot erase a newer focus on B. Omitted/blank scope clears
|
|
20
|
+
unconditionally. Local connections can only focus/clear their bound Space.
|
|
21
|
+
|
|
22
|
+
Full success: `{"status":"success","data":{"focusedSpaceId":"space-b"}}`;
|
|
23
|
+
clear returns `focusedSpaceId:null`. `essential` uses normal Facade projection.
|
|
24
|
+
One-way synchronization emits no response. Persistence failure retires the
|
|
25
|
+
connection; success never means that every other connection has synchronized.
|
|
26
|
+
Internal Host/Core presence events and `/bridge/app/focus` retain their own roles.
|
|
@@ -1,6 +1,29 @@
|
|
|
1
1
|
# Entity UI presentation
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## Selected reference metadata
|
|
4
|
+
|
|
5
|
+
`/app/presentation/entity/meta/get` accepts `{entityType, ids}` under the normal
|
|
6
|
+
Facade envelope. It is a Space-read UI operation, routed by Space mode, not an
|
|
7
|
+
Agent/MCP catalog entry. IDs are nonblank, trimmed, deduplicated in request order
|
|
8
|
+
and bounded to 100 input entries. Empty input and unknown fields are rejected.
|
|
9
|
+
The response is `{items: [{requestedId, found, resource? , reason?}]}`. A found
|
|
10
|
+
resource contains only `id`, `entityType`, `displayName`, and `group`. A missing,
|
|
11
|
+
deleted or wrong-type reference returns `found: false, reason: "not_found"`.
|
|
12
|
+
|
|
13
|
+
Automation uses definition metadata; Widget uses its own definition; other
|
|
14
|
+
entities use their stored Twin identity. `g:` IDs read the Group definition and
|
|
15
|
+
check its member type (an empty legacy member type accepts the requested type).
|
|
16
|
+
No Group members are resolved. All reads use authenticated tenant and Space.
|
|
17
|
+
No source refresh, room lookup, runtime status, history, card/relationship read or
|
|
18
|
+
script expansion is performed. Missing display names remain empty; the UI owns
|
|
19
|
+
its fallback label. Both response detail modes preserve these business fields.
|
|
20
|
+
|
|
21
|
+
This is a selected-reference resolver, not a replacement for the domain catalogs
|
|
22
|
+
of special entities such as AppClient or Location. It does not enumerate them.
|
|
23
|
+
|
|
24
|
+
## Entity renderer aggregate
|
|
25
|
+
|
|
26
|
+
`/app/presentation/entity/get` is a read-only App Facade for the UI. Its direct
|
|
4
27
|
input is `{entityType, entityId}`; tenant, Space and caller come from authenticated
|
|
5
28
|
context. It requires Space read access. It is not an Agent or MCP catalog entry.
|
|
6
29
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Integration UI presentation
|
|
2
2
|
|
|
3
|
-
`/app/integration/
|
|
3
|
+
`/app/presentation/integration/get` is a read-only App Facade for UI consumers.
|
|
4
4
|
Input is `{integrationId}` for one root Integration. Tenant, Space and caller
|
|
5
5
|
come from authenticated context; Space read membership is required. Empty IDs,
|
|
6
6
|
unknown fields and Provider IDs are rejected; missing Integrations are not found.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Native Plugin Preview preflight
|
|
2
|
+
|
|
3
|
+
`/app/plugin/preview/check` is a read-only App Facade on the selected Local
|
|
4
|
+
Space's Hub. It accepts the empty business input `{}` and requires Space Manage
|
|
5
|
+
access. Its business result is `{ "spaceId": "<selected-space>" }`, inside the
|
|
6
|
+
standard Facade response envelope. Unknown input fields are rejected.
|
|
7
|
+
|
|
8
|
+
The desktop CLI must complete this check before asking its local Host to install
|
|
9
|
+
or restart a native Preview. Cloud Spaces cannot route this Hub-only operation.
|
|
10
|
+
The check creates no session, token, reservation or persistent data. It does not
|
|
11
|
+
grant Host installation permission: the Host's existing local authorization still
|
|
12
|
+
applies. Binding rechecks Space authority after installation; this preflight does
|
|
13
|
+
not guarantee that permissions cannot change during the operation.
|
|
14
|
+
|
|
15
|
+
Integration Preview status remains a Space Read operation. Native Preview must
|
|
16
|
+
not use that status read as evidence of management permission.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Reference picker presentation
|
|
2
|
+
|
|
3
|
+
UI-only Space reads use the standard FacadeCall and success/data/error envelope.
|
|
4
|
+
Both targets require spaceRead and follow scopeMode routing. They are not native
|
|
5
|
+
Agent, CLI or MCP tools. Full and Essential preserve the same business fields;
|
|
6
|
+
Essential represents them as YAML.
|
|
7
|
+
|
|
8
|
+
| Target | Input | Business output |
|
|
9
|
+
| --- | --- | --- |
|
|
10
|
+
| `/app/presentation/reference/type/list` | `{}` | `{types:[{entityType,name,category}]}` |
|
|
11
|
+
| `/app/presentation/reference/item/list` | `{entityType}` | `{items:[{id,name,entityType,category,capabilities,group}]}` |
|
|
12
|
+
|
|
13
|
+
Inputs reject unknown fields. entityType is a nonblank string, trimmed at the
|
|
14
|
+
boundary. category is device, widget, automation or entity, derived by the server.
|
|
15
|
+
Candidate names do not replace IDs. Empty capabilities and false group values are
|
|
16
|
+
preserved. No business input selects another Space.
|
|
17
|
+
|
|
18
|
+
Types come from installed and auto-installed Integration standalone declarations,
|
|
19
|
+
deduplicated and sorted by entityType. Empty types are not hidden by counting their
|
|
20
|
+
instances. Item reads select one type only. Widget reads preserve the shared global
|
|
21
|
+
catalog (including global Automation-owned Widgets), not the narrower Widget-page
|
|
22
|
+
visibility rules. Device and Entity groups retain their existing capability
|
|
23
|
+
resolution. Automation references include regular and temporary programs and
|
|
24
|
+
Automation groups, with the existing internal-object exclusions and display names.
|
|
25
|
+
Location and AppClient retain their dedicated discovery rules.
|
|
26
|
+
|
|
27
|
+
Reference reads omit room/enablement enrichment, group runtime state, Automation
|
|
28
|
+
status and script hydration. They do not load Widget values, histories, owner
|
|
29
|
+
names or full configurations. Metadata reads may still require underlying stored
|
|
30
|
+
rows and group capability resolution; this contract does not promise one DB query.
|
|
31
|
+
|
|
32
|
+
The UI lazily caches types and items by Space/type and merges in-flight reads.
|
|
33
|
+
Search remains client-side. Failed requests are retryable and are not successful
|
|
34
|
+
empty catalogs. Space changes discard late results. Message reference identity and
|
|
35
|
+
serialization remain unchanged. Legacy `/reference/*` request routes are retired.
|
|
@@ -14,7 +14,7 @@ follow the Space execution authority on both local Core and cloud.
|
|
|
14
14
|
| `/app/widget/list` | `{}` | Summaries: id, displayName, description, type, tag; Data adds dataType/repeated. No list mode or full-definition catalog |
|
|
15
15
|
| `/app/widget/detail/get` | `{ids}` | Existing ordered `items` with `widget` configuration; no value, next or nextTimestamp |
|
|
16
16
|
| `/app/widget/value/get` | `{ids}` | Ordered `items` with `resource: {widgetId, revision, value, next?, nextTimestamp?}` |
|
|
17
|
-
| `/app/automation/status` | `{ids}` | Ordered `items` with `resource: {automationId, enabled, runnable, running, blocked, lastRunAt}` |
|
|
17
|
+
| `/app/automation/status` | `{ids}` | Ordered `items` with `resource: {automationId, enabled, runnable, corrupted, running, blocked, lastRunAt}`; temporary programs also include `expireAt` |
|
|
18
18
|
| `/app/graph/relations/get` | `{resource: {kind, id}}` | `{resource, relations: [{from, relation, to, capabilityIds?}]}` |
|
|
19
19
|
|
|
20
20
|
Device list and detail discriminate status using `group`: physical Devices (`false`)
|
|
@@ -101,7 +101,7 @@ open detail renderer; relationships by the view that displays them. Pushes recei
|
|
|
101
101
|
during a snapshot request are applied after it lands. Switching scopes or disposing
|
|
102
102
|
controllers prevents late responses from landing in another Space.
|
|
103
103
|
|
|
104
|
-
House continues to use `/app/entity/
|
|
104
|
+
House continues to use `/app/presentation/entity/get` and legacy Twin reads as its
|
|
105
105
|
separate development boundary. Pod Deck retains its existing complete Card content
|
|
106
106
|
reader. These consumers are not silently migrated to static Canvas responses.
|
|
107
107
|
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Space presentation and focused business readers
|
|
2
|
+
|
|
3
|
+
All calls use the standard App Facade envelope. These presentation targets are
|
|
4
|
+
UI reads, not Agent tools. They execute in the cloud and require user identity.
|
|
5
|
+
|
|
6
|
+
- `/app/presentation/space/list` accepts `{}` and returns `{spaces}`. Each item
|
|
7
|
+
has `spaceId`, `name`, `mode`, `llmMode`, `betaMode`, `defaultActive`,
|
|
8
|
+
`lifecycleState`, `connectionMode`, and `currentUserRole`. Nullable metadata
|
|
9
|
+
remains nullable. It reads enrolled memberships and Space metadata, then live
|
|
10
|
+
connection state; it never expands members, Locations, preferences or profiles.
|
|
11
|
+
- `/app/presentation/space/get` accepts `{includeMembers?: boolean}` (default
|
|
12
|
+
false) and returns `{space, members?}`. `space` has the same summary shape.
|
|
13
|
+
Only `includeMembers:true` reads the Space membership list and member profiles.
|
|
14
|
+
Each member has `userId`, `email`, `name`, `pending` and `role`. Active members
|
|
15
|
+
may read this presentation; management mutations still require their own grants.
|
|
16
|
+
- `/app/space/location/list` accepts `{}` and returns `{locations}`. Each Location
|
|
17
|
+
has `spaceId`, `locationId`, `name`, `address`, `timezone`, `countryCode`,
|
|
18
|
+
`latitude`, `longitude`, and `altitude`. It executes according to Space mode,
|
|
19
|
+
reading only the authoritative backend's Locations; it does not read Space
|
|
20
|
+
details, members or preferences and has no cloud fallback in local mode.
|
|
21
|
+
- `/app/space/delete/status` accepts `{operationId}` and returns `accepted`,
|
|
22
|
+
`operationId`, `spaceId`, `state`, `message`, and `deleted`. It queries the
|
|
23
|
+
existing durable operation and never starts or restarts deletion. Authorization
|
|
24
|
+
uses the operation initiator and authenticated user, so polling survives removal
|
|
25
|
+
of membership and Space data. The request retains the operation's Space ID.
|
|
26
|
+
- `/app/space/beta/update` accepts `{betaMode: boolean}` and returns
|
|
27
|
+
`{betaMode, poll}`. It saves through the existing Space Beta service. A true
|
|
28
|
+
`poll` means the Client must wait for the Hub to apply the selected mode.
|
|
29
|
+
|
|
30
|
+
Invitation accept/reject remain membership operations and never select a Client's
|
|
31
|
+
Space. The UI explicitly uses the connection focus protocol after joining when
|
|
32
|
+
its flow intends to enter the joined Space. Current-Space switches must not be
|
|
33
|
+
discarded by the previous Space's request guard.
|
|
34
|
+
|
|
35
|
+
Client handling of presentation replies unwraps successful Full Facade responses
|
|
36
|
+
before updating cloud-authoritative membership/connection caches. Presentation
|
|
37
|
+
wire DTOs (`spaceId`, `llmMode`) are explicitly projected into native state;
|
|
38
|
+
login and Hub authorization retain their independently owned wire DTOs.
|
|
39
|
+
|
|
40
|
+
Legacy `/scope/list`, `/scope/get`, `/scope/preference/get`, `/scope/agent/get`,
|
|
41
|
+
and `/scope/location/list` readers are retired, without fallback aliases. Native
|
|
42
|
+
UI membership refresh uses `/app/presentation/space/list`; the CLI uses
|
|
43
|
+
`/app/space/list` for identity-only listing and selection checks, and presentation
|
|
44
|
+
listing for its full management view. Neither lightweight flow expands per-Space
|
|
45
|
+
context. `/focus` remains connection control, not a business Facade.
|
package/contract/storage-v1.md
CHANGED
|
@@ -180,7 +180,9 @@ and removal-only cleanup authority.
|
|
|
180
180
|
|
|
181
181
|
## Physical backend and reads
|
|
182
182
|
|
|
183
|
-
`storage.backend.
|
|
183
|
+
`storage.backend.v1` remains separate from the public `storage.v1` capability.
|
|
184
|
+
Storage is in development: both protocols evolve in place as v1, with no legacy
|
|
185
|
+
readers, version negotiation or compatibility branches.
|
|
184
186
|
Describe reports capacity; grant authorizes stat/read/delete; prepare-write reserves
|
|
185
187
|
space for an immutable Blob before issuing a write grant. A lost reply can have
|
|
186
188
|
reserved bytes. Receipts are resolved before changing repositories. Issued grants survive temporary Core control disconnection until normal expiry;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Widget UI presentation reads
|
|
2
|
+
|
|
3
|
+
These are UI App Facades with the standard Full/Essential response and Space read
|
|
4
|
+
policy. They are not Agent/CLI/MCP tools. Inputs reject unknown fields.
|
|
5
|
+
|
|
6
|
+
| Target | Input | Business output and read boundary |
|
|
7
|
+
| --- | --- | --- |
|
|
8
|
+
| `/app/presentation/widget/list` | Required `{type: "data" \| "button" \| "circadian"}` | `{items, automationNames}`. Reads only that type's Widget table. Global standalone Widgets, defaults and Automation-owned parameters are included; card interiors, Twin and weather internals are excluded. Owner labels use one selected metadata batch, only for returned Automation owners. No script, relation, history or all-type reads. |
|
|
9
|
+
| `/app/presentation/widget/names/get` | `{ids}`: 1–100 selected, trimmed, deduplicated IDs | `{names: {id: displayName}}`. Missing/blank names omitted. Only selected Widget rows; no legacy `name` fallback. |
|
|
10
|
+
| `/app/presentation/widget/defaults/get` | `{}` | `{items, automationNames:{}}`. Preserves the existing default Widget lookup and lazy initialization, then reads the selected Data Widgets. |
|
|
11
|
+
|
|
12
|
+
Rows carry ID, revision, displayName, description, source/baseId, global, tag,
|
|
13
|
+
current value, and type-specific control configuration. Circadian rows contain
|
|
14
|
+
only `curve`, `curvePreview` (active curve's UI points), current/next values and
|
|
15
|
+
`nextTimestamp`; they omit complete schedules, location and internal state.
|
|
16
|
+
Complete configuration uses `/app/widget/detail/get`; runtime uses
|
|
17
|
+
`/app/widget/value/get`, both selected-ID reads. Full timestamps are milliseconds;
|
|
18
|
+
Essential renders explicit timestamps and typed Timestamp values in Home timezone.
|
|
19
|
+
|
|
20
|
+
`/app/widget/list` remains the shared summary catalog. Optional `type` limits the
|
|
21
|
+
physical Widget-table read; optional `excludeSources` filters known sources
|
|
22
|
+
(`widget`, `automation`, `special`, `twin`, `weather`). Omitted filters preserve
|
|
23
|
+
the existing global supported-type catalog. It never returns control values or
|
|
24
|
+
full definitions. Dashboard selection excludes Automation-owned parameters and
|
|
25
|
+
adds selected IDs directly without definition/value reads.
|
|
26
|
+
|
|
27
|
+
The UI loads only the active type, caches visited tabs within the Space and never
|
|
28
|
+
fetches inactive counts. Automation parameters are grouped by owning Automation;
|
|
29
|
+
users can operate them and open the owner but cannot edit/delete their definition.
|
|
30
|
+
Realtime changes update loaded rows, deletes remove them, and reconnect or
|
|
31
|
+
incomplete presentation changes refresh only the relevant active tab. Space
|
|
32
|
+
switches clear caches and reject late responses. All public Widget request
|
|
33
|
+
Controllers, including reads and writes, are removed. Writes use the shared
|
|
34
|
+
`/app/widget/*` Facades described in `widget-writes-v1.md`.
|
|
35
|
+
`/widget/reportUpdate` remains a push protocol; internal Automation dispatch
|
|
36
|
+
remains separate from public request routing.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Widget writes
|
|
2
|
+
|
|
3
|
+
Widget create and configuration Facades are shared by UI, Agent, CLI and MCP.
|
|
4
|
+
Creation requires displayName; description may be omitted. A supplied description
|
|
5
|
+
must remain nonblank. Existing text value inputs remain supported.
|
|
6
|
+
|
|
7
|
+
## Data runtime values
|
|
8
|
+
|
|
9
|
+
`/app/widget/data/update` accepts widgetId and exactly one non-null input:
|
|
10
|
+
|
|
11
|
+
- value: a text-encoded scalar, for example "false" or "25C".
|
|
12
|
+
- values: an array of text-encoded values, including an empty array.
|
|
13
|
+
- typedValue: typed JSON, for example false, 0, [], or
|
|
14
|
+
{"_type":"Temperature","value":25,"unit":"C"}.
|
|
15
|
+
|
|
16
|
+
Explicit typedValue:null is rejected; clearing is a separate Automation capability.
|
|
17
|
+
The stored definition determines type, scalar/array shape, options and bounds.
|
|
18
|
+
Object selections are restricted to stored Automation candidates. Only their type
|
|
19
|
+
and UID identify a candidate; stored business fields replace caller-supplied fields.
|
|
20
|
+
Both text and typed inputs use the same manager, write constraints, history and events.
|
|
21
|
+
The request never changes configuration, visibility or ownership.
|
|
22
|
+
|
|
23
|
+
## Circadian runtime controls
|
|
24
|
+
|
|
25
|
+
`/app/widget/circadian/runtime/update` accepts widgetId and at least one of curve,
|
|
26
|
+
offset, multiplier. Unknown fields and explicit null controls are rejected.
|
|
27
|
+
Curve must identify an existing schedule; offset must match the stored data type;
|
|
28
|
+
multiplier must be finite. Updates retain existing manual adjustment timing and
|
|
29
|
+
recompute the current and next values. Automation-owned parameters are operable.
|
|
30
|
+
Visibility, owner, name, location and schedule definitions remain unchanged.
|
|
31
|
+
This is a direct operation, independent of prepared definition edits.
|
|
32
|
+
|
|
33
|
+
Data value updates, Button triggers, Circadian runtime controls and delete return
|
|
34
|
+
an acknowledgement: {"status":"success"}, without business data.
|
|
35
|
+
Create/configuration responses retain action, widgetId, type and displayName.
|
|
36
|
+
|
|
37
|
+
## Deletion
|
|
38
|
+
|
|
39
|
+
`/app/widget/delete` retains the required explicit safe flag. The UI passes false
|
|
40
|
+
to preserve its previous deletion behavior. This migration does not change the
|
|
41
|
+
shared safe=true protection for Widgets referenced by Automations.
|
|
42
|
+
|
|
43
|
+
All legacy public /widget/* request Controllers are retired. /widget/reportUpdate
|
|
44
|
+
is a push event and internal /dispatch/widget/* operations retain their own roles.
|
|
@@ -826,5 +826,101 @@
|
|
|
826
826
|
"scopeId": "space",
|
|
827
827
|
"target": "/app/object-storage/folders/set-limit",
|
|
828
828
|
"allowed": false
|
|
829
|
+
},
|
|
830
|
+
{
|
|
831
|
+
"name": "space-ui:unscoped:/app/presentation/space/list",
|
|
832
|
+
"principal": {
|
|
833
|
+
"kind": "user",
|
|
834
|
+
"userId": "user"
|
|
835
|
+
},
|
|
836
|
+
"memberRole": null,
|
|
837
|
+
"tenantId": "tenant",
|
|
838
|
+
"scopeId": "space",
|
|
839
|
+
"target": "/app/presentation/space/list",
|
|
840
|
+
"allowed": true
|
|
841
|
+
},
|
|
842
|
+
{
|
|
843
|
+
"name": "space-ui:MEMBER:/app/presentation/space/get",
|
|
844
|
+
"principal": {
|
|
845
|
+
"kind": "user",
|
|
846
|
+
"userId": "user"
|
|
847
|
+
},
|
|
848
|
+
"memberRole": "MEMBER",
|
|
849
|
+
"tenantId": "tenant",
|
|
850
|
+
"scopeId": "space",
|
|
851
|
+
"target": "/app/presentation/space/get",
|
|
852
|
+
"allowed": true
|
|
853
|
+
},
|
|
854
|
+
{
|
|
855
|
+
"name": "space-ui:unscoped:/app/presentation/space/get",
|
|
856
|
+
"principal": {
|
|
857
|
+
"kind": "user",
|
|
858
|
+
"userId": "user"
|
|
859
|
+
},
|
|
860
|
+
"memberRole": null,
|
|
861
|
+
"tenantId": "tenant",
|
|
862
|
+
"scopeId": "space",
|
|
863
|
+
"target": "/app/presentation/space/get",
|
|
864
|
+
"allowed": false
|
|
865
|
+
},
|
|
866
|
+
{
|
|
867
|
+
"name": "space-ui:MEMBER:/app/space/location/list",
|
|
868
|
+
"principal": {
|
|
869
|
+
"kind": "user",
|
|
870
|
+
"userId": "user"
|
|
871
|
+
},
|
|
872
|
+
"memberRole": "MEMBER",
|
|
873
|
+
"tenantId": "tenant",
|
|
874
|
+
"scopeId": "space",
|
|
875
|
+
"target": "/app/space/location/list",
|
|
876
|
+
"allowed": true
|
|
877
|
+
},
|
|
878
|
+
{
|
|
879
|
+
"name": "space-ui:unscoped:/app/space/location/list",
|
|
880
|
+
"principal": {
|
|
881
|
+
"kind": "user",
|
|
882
|
+
"userId": "user"
|
|
883
|
+
},
|
|
884
|
+
"memberRole": null,
|
|
885
|
+
"tenantId": "tenant",
|
|
886
|
+
"scopeId": "space",
|
|
887
|
+
"target": "/app/space/location/list",
|
|
888
|
+
"allowed": false
|
|
889
|
+
},
|
|
890
|
+
{
|
|
891
|
+
"name": "space-ui:unscoped:/app/space/delete/status",
|
|
892
|
+
"principal": {
|
|
893
|
+
"kind": "user",
|
|
894
|
+
"userId": "user"
|
|
895
|
+
},
|
|
896
|
+
"memberRole": null,
|
|
897
|
+
"tenantId": "tenant",
|
|
898
|
+
"scopeId": "space",
|
|
899
|
+
"target": "/app/space/delete/status",
|
|
900
|
+
"allowed": true
|
|
901
|
+
},
|
|
902
|
+
{
|
|
903
|
+
"name": "space-ui:MEMBER:/app/space/beta/update",
|
|
904
|
+
"principal": {
|
|
905
|
+
"kind": "user",
|
|
906
|
+
"userId": "user"
|
|
907
|
+
},
|
|
908
|
+
"memberRole": "MEMBER",
|
|
909
|
+
"tenantId": "tenant",
|
|
910
|
+
"scopeId": "space",
|
|
911
|
+
"target": "/app/space/beta/update",
|
|
912
|
+
"allowed": false
|
|
913
|
+
},
|
|
914
|
+
{
|
|
915
|
+
"name": "space-ui:OWNER:/app/space/beta/update",
|
|
916
|
+
"principal": {
|
|
917
|
+
"kind": "user",
|
|
918
|
+
"userId": "user"
|
|
919
|
+
},
|
|
920
|
+
"memberRole": "OWNER",
|
|
921
|
+
"tenantId": "tenant",
|
|
922
|
+
"scopeId": "space",
|
|
923
|
+
"target": "/app/space/beta/update",
|
|
924
|
+
"allowed": true
|
|
829
925
|
}
|
|
830
926
|
]
|