@portpowered/reference-data 0.4.5 → 0.4.6

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.
@@ -50,7 +50,7 @@
50
50
  {
51
51
  "id": "lighting",
52
52
  "title": "Control lights and distinguish switches and plugs",
53
- "content": "# Control lights and distinguish switches and plugs\n\nStart with authorized endpoint discovery and inspect capability declarations. A room name can be ambiguous; select by full ID and group path or ask the user. A power-capable plug or switch is not automatically a light.\n\nFor one bulb, read its power/brightness/color message schemas in [the capability directory](/docs/for-ai/capability-interfaces.md). Use the exact namespace, version, message name, units and constraints returned. [The quickstart](/docs/for-ai/guides/quickstart.md) shows the generic dispatch envelope.\n\nFor “all lights,” include explicitly authorized shared lights and the user-requested home/group scope. Complete pagination, exclude disabled/unavailable unsupported targets as documented and deduplicate nested groups. Do not broaden the set to every power-capable endpoint. Use the existing query/dispatch contract if it supports the selection; otherwise enumerate the fixed target set and report each result.\n\nA batch can partially succeed. Report selected, accepted, failed and unresolved targets separately. Read fresh state before claiming all lights changed. A lost response does not justify repeating relative brightness adjustments. See [authorization rules](/docs/for-ai/guides/authorization-rules.md).\n",
53
+ "content": "# Control lights and distinguish switches and plugs\n\nStart with authorized endpoint discovery and inspect capability declarations. A room name can be ambiguous; select by full ID and group path or ask the user. A power-capable plug or switch is not automatically a light.\n\nFor one bulb, read its power/brightness/color message schemas in [the capability directory](/docs/for-ai/capability-interfaces.md). Use the exact namespace, version, message name, units and constraints returned. [The quickstart](/docs/for-ai/guides/quickstart.md) shows the generic dispatch envelope.\n\nFor “all lights,” use [endpointQuery](/docs/for-ai/operations/endpointQuery.md): POST /endpoint-query with endpoint:read. Its results include readable shared endpoints from other owners. Start with the LIGHT and LIGHTBULB types below, then limit the results to the user's requested home or group.\n\n```json\n{\n \"query\": {\n \"or\": [\n {\"match\": {\"key\": \"type\", \"value\": \"LIGHT\"}},\n {\"match\": {\"key\": \"type\", \"value\": \"LIGHTBULB\"}}\n ]\n },\n \"paginationContext\": {\"maxResults\": 25}\n}\n```\n\nFor a room, first resolve its full group ID using [group discovery](/docs/for-ai/guides/managing-groups.md). Intersect the type predicate with `{\"match\":{\"key\":\"groupId\",\"value\":\"<resolved-full-group-id>\"}}` inside query.and. This additionally requires group:read and permission to read that group. A group filter uses its returned member endpoints; resolve the requested nested groups as needed and deduplicate full endpoint IDs. Reading a group does not grant control of its members.\n\nRepeat the same query, page size and authenticated grant with paginationContext.nextToken from each response. Continue until that token is absent, including after an empty page. Disabled endpoints are excluded by default. Inspect declared capabilities for the selected endpoints and exclude unsupported targets; do not broaden the selection to every power-capable plug or switch. Freeze the discovered target set before dispatch and report each result.\n\nA batch can partially succeed. Report selected, accepted, failed and unresolved targets separately. For fresh readback, repeat endpointQuery with expand:[\"interfaces.attributes\"] and forceDeviceQuery:true. Inspect observation sample times and response errors before claiming all lights changed. A lost response does not justify repeating relative brightness adjustments. See [authorization rules](/docs/for-ai/guides/authorization-rules.md).\n",
54
54
  "setupPrompt": null
55
55
  },
56
56
  {
@@ -128,7 +128,7 @@
128
128
  {
129
129
  "id": "using-the-api",
130
130
  "title": "Using the REST API",
131
- "content": "# Using the REST API\n\nDiscover authorization metadata, then use [OAuth setup](/docs/for-ai/guides/authentication-and-dcr.md). Obtain exact REST paths and schemas from [OpenAPI](/docs/references/openapi.yaml) or [small operation pages](/docs/for-ai/operations/index.md).\n\nEnumerate endpoints with endpoint:read. Follow returned pagination links/tokens exactly and stop only when continuation is absent. Inspect declared capabilities and versions; retrieve one message/attribute schema as needed. Send messages through POST /messages (the existing /messages/send alias also works). Never invent target IDs or message fields.\n\nREST dispatch and subsequent physical observation are separate facts. A 202 describes unfinished work. A timeout can mean the operation already acted; inspect existing results/state before repeating. IR/Bluetooth fire-and-forget and long-delay devices may never provide immediate confirmation. Use bounded polling and report unresolved state. An endpoint edit marked committed with cleanup pending must not be repeated as though it failed.\n\nUse documented idempotency/correlation and version preconditions only where the operation guarantees them. Setting a value and incrementing it have different replay risks. On an ambiguous lost relative-command response, report unknown or read back rather than blindly send again.\n\nRead [authorization rules](/docs/for-ai/guides/authorization-rules.md), [lighting](/docs/for-ai/guides/lighting.md) or the relevant task guide.\n",
131
+ "content": "# Using the REST API\n\nDiscover authorization metadata, then use [OAuth setup](/docs/for-ai/guides/authentication-and-dcr.md).\nStart with the [compact API catalog](/docs/for-ai/api-catalog.md). It\ncontains auth context, public operation links, parameter names and top-level JSON\nkeys. Obtain exact REST paths from its links or the [small operation index](/docs/for-ai/operations/index.md).\nFollow one operation's linked schemas for required/conditional fields and\nnested payloads. It does not inline all schemas or examples.\n\nFor SDK generation or a comprehensive contract download, request the\n[full OpenAPI document](/docs/references/openapi.yaml).\n\nThe website's `/api/` route serves this compact Markdown when the request puts\n`text/markdown` first in `Accept` (for example,\n`text/markdown, text/plain;q=0.9, text/html;q=0.8`). Browser HTML requests keep the\ninteractive reference. Add `?full=1` to explicitly retrieve the complete HTML\ncatalog; keep HTML in your accepted formats for that request. Both variants\ninclude `Vary: Accept` for caches. The direct compact Markdown URL works on both\nthe website and API host and does not depend on negotiation.\n\nEnumerate endpoints with endpoint:read. Follow returned pagination links/tokens exactly and stop only when continuation is absent. Inspect declared capabilities and versions; retrieve one message/attribute schema as needed. Send messages through POST /messages (the existing /messages/send alias also works). Never invent target IDs or message fields.\n\nFor filtered inventory including readable shared endpoints, use [POST /endpoint-query](/docs/for-ai/operations/endpointQuery.md). Its query accepts exact match and nested and/or/not predicates; read the request schema's supported fields rather than inventing comparisons or text search. A groupId predicate additionally needs group:read and access to that group. Keep the query, page size, expansions, forceDeviceQuery setting and grant unchanged while following paginationContext.nextToken. Empty pages can have a continuation. Cursors expire after fifteen minutes; restart without nextToken on a 400 cursor error.\n\nREST dispatch and subsequent physical observation are separate facts. A 202 describes unfinished work. A timeout can mean the operation already acted; inspect existing results/state before repeating. IR/Bluetooth fire-and-forget and long-delay devices may never provide immediate confirmation. Use bounded polling and report unresolved state. An endpoint edit marked committed with cleanup pending must not be repeated as though it failed.\n\nUse documented idempotency/correlation and version preconditions only where the operation guarantees them. Setting a value and incrementing it have different replay risks. On an ambiguous lost relative-command response, report unknown or read back rather than blindly send again.\n\nRead [authorization rules](/docs/for-ai/guides/authorization-rules.md), [lighting](/docs/for-ai/guides/lighting.md) or the relevant task guide.\n",
132
132
  "setupPrompt": null
133
133
  },
134
134
  {
@@ -1086,7 +1086,12 @@
1086
1086
  "tags": [
1087
1087
  "Endpoints"
1088
1088
  ],
1089
- "description": "Query for endpoints",
1089
+ "description": "Return a bounded page of authorized endpoints matching the shared Query expression, including endpoints shared by other owners. Read permission is evaluated before filtering, pagination and state expansion. See the request schema for supported fields and operators. Use groupId to select members of a readable room/group, then intersect type or declared interfaces to select lights. Group predicates additionally require group:read for delegated OAuth. Repeat the complete query settings and grant when following nextToken; cursors expire after fifteen minutes. Device attributes are returned only when expanded. Report per-target command acceptance and observed state separately; querying a group does not grant permission to control its members.",
1090
+ "x-portos-conditional-scopes": {
1091
+ "groupId": [
1092
+ "group:read"
1093
+ ]
1094
+ },
1090
1095
  "requestBody": {
1091
1096
  "required": true,
1092
1097
  "content": {
@@ -1097,9 +1102,12 @@
1097
1102
  "example": {
1098
1103
  "query": {
1099
1104
  "match": {
1100
- "key": "name",
1101
- "value": "test"
1105
+ "key": "type",
1106
+ "value": "LIGHT"
1102
1107
  }
1108
+ },
1109
+ "paginationContext": {
1110
+ "maxResults": 10
1103
1111
  }
1104
1112
  }
1105
1113
  }
@@ -1114,16 +1122,13 @@
1114
1122
  "$ref": "#/components/schemas/EndpointQueryResponse"
1115
1123
  },
1116
1124
  "example": {
1117
- "results": [],
1118
- "paginationContext": {
1119
- "nextToken": "abc123"
1120
- }
1125
+ "results": []
1121
1126
  }
1122
1127
  }
1123
1128
  }
1124
1129
  },
1125
1130
  "400": {
1126
- "description": "Bad request - missing required parameters",
1131
+ "description": "Invalid query, unsupported expansion, or invalid/expired/mismatched cursor.",
1127
1132
  "content": {
1128
1133
  "application/json": {
1129
1134
  "schema": {
@@ -1152,6 +1157,51 @@
1152
1157
  }
1153
1158
  }
1154
1159
  },
1160
+ "403": {
1161
+ "description": "Missing conditional OAuth scope or permission to read a referenced group.",
1162
+ "content": {
1163
+ "application/json": {
1164
+ "schema": {
1165
+ "$ref": "#/components/schemas/Error"
1166
+ },
1167
+ "example": {
1168
+ "message": "Permission to read the requested group is required.",
1169
+ "code": "FORBIDDEN",
1170
+ "family": "FORBIDDEN"
1171
+ }
1172
+ }
1173
+ }
1174
+ },
1175
+ "404": {
1176
+ "description": "A referenced group does not exist.",
1177
+ "content": {
1178
+ "application/json": {
1179
+ "schema": {
1180
+ "$ref": "#/components/schemas/Error"
1181
+ },
1182
+ "example": {
1183
+ "message": "Requested group was not found.",
1184
+ "code": "NOT_FOUND",
1185
+ "family": "NOT_FOUND"
1186
+ }
1187
+ }
1188
+ }
1189
+ },
1190
+ "409": {
1191
+ "description": "A selected disabled endpoint cannot be forcibly refreshed.",
1192
+ "content": {
1193
+ "application/json": {
1194
+ "schema": {
1195
+ "$ref": "#/components/schemas/Error"
1196
+ },
1197
+ "example": {
1198
+ "message": "endpoint messaging is disabled",
1199
+ "code": "ENDPOINT_DISABLED",
1200
+ "family": "CONFLICT"
1201
+ }
1202
+ }
1203
+ }
1204
+ },
1155
1205
  "500": {
1156
1206
  "description": "Internal server error",
1157
1207
  "content": {
@@ -23657,22 +23707,50 @@
23657
23707
  },
23658
23708
  "EndpointQueryRequest": {
23659
23709
  "type": "object",
23710
+ "additionalProperties": false,
23660
23711
  "required": [
23661
23712
  "query"
23662
23713
  ],
23663
23714
  "properties": {
23664
23715
  "query": {
23665
- "$ref": "#/components/schemas/Query"
23716
+ "$ref": "#/components/schemas/Query",
23717
+ "description": "A bounded shared Query expression. An empty object selects unfiltered readable inventory. This endpoint supports match, and, or, and not. Scalar match keys are id, name, type, ownerId, manufacturer, model, and enablement. interfaces matches membership in the endpoint's declared interface names; groupId matches membership in a readable endpoint group. Comparisons, patterns, freeform search, unknown keys, ambiguous nodes, expressions deeper than eight levels, or more than 64 nodes return 400. Values are exact strings. Collections hide disabled endpoints unless the expression explicitly filters enablement. Results include readable shared endpoints, regardless of their owner. A groupId predicate additionally requires group:read for delegated OAuth and read permission on that group."
23666
23718
  },
23667
23719
  "paginationContext": {
23668
- "$ref": "#/components/schemas/PaginationContext"
23720
+ "type": "object",
23721
+ "additionalProperties": false,
23722
+ "properties": {
23723
+ "maxResults": {
23724
+ "type": "integer",
23725
+ "minimum": 1,
23726
+ "maximum": 100,
23727
+ "default": 10,
23728
+ "description": "Maximum authorized matching endpoints in this page."
23729
+ },
23730
+ "nextToken": {
23731
+ "type": "string",
23732
+ "minLength": 1,
23733
+ "description": "Opaque server-issued continuation token. Repeat the same query, page size, expansions, forceDeviceQuery setting, and authenticated grant. Modified, expired, or differently bound tokens return 400; restart without nextToken. Follow nextToken until absent, including empty pages."
23734
+ }
23735
+ }
23669
23736
  },
23670
23737
  "expand": {
23671
23738
  "type": "array",
23672
- "description": "Expansion tokens that request related or computed endpoint fields.",
23739
+ "uniqueItems": true,
23740
+ "maxItems": 1,
23741
+ "description": "Optional reported state expansion; only interfaces.attributes is supported.",
23673
23742
  "items": {
23674
- "type": "string"
23743
+ "type": "string",
23744
+ "enum": [
23745
+ "interfaces.attributes"
23746
+ ],
23747
+ "x-enum-exempt": "Existing published REST expansion token shared with GET /endpoints."
23675
23748
  }
23749
+ },
23750
+ "forceDeviceQuery": {
23751
+ "type": "boolean",
23752
+ "default": false,
23753
+ "description": "Refresh reported device attributes for the selected page. Requires expand to contain interfaces.attributes. An accepted command is not proof of device state; inspect the returned sample times and partial errors. Disabled endpoints cannot be forcibly refreshed."
23676
23754
  }
23677
23755
  }
23678
23756
  },
@@ -0,0 +1,123 @@
1
+ # Port OS API catalog: compact reference
2
+
3
+ For a new connection, read [authentication and DCR/CIMD](/docs/for-ai/guides/authentication-and-dcr.md), then [the REST quickstart](/docs/for-ai/guides/quickstart.md). Registration grants no device access. Discover the issuer and endpoints; choose REST or MCP before consent, use PKCE, validate the callback, then exchange its code. REST uses the issuer as its OAuth resource; MCP uses its /mcp resource.
4
+
5
+ Operation scopes and resource permissions both apply. [Authorization rules](/docs/for-ai/guides/authorization-rules.md) explain consent, sharing, evaluation and denial. Bearer-session alternatives describe signed-in user sessions; they do not bypass delegated-token scopes.
6
+
7
+ This index lists public operations, parameter names and top-level JSON keys. Required, conditional and nested fields remain in each linked operation/schema contract. Read only the contract needed for your next request. [Capability index](/docs/for-ai/capability-interfaces.md).
8
+
9
+ To request the complete rendered catalog, fetch `/api/?full=1` with an HTML-compatible Accept header. [Full OpenAPI YAML](/docs/references/openapi.yaml) is available for comprehensive lookup and SDK generation.
10
+
11
+ | Operation contract | OAuth scopes / conditional scopes | Parameters | Top-level JSON body keys |
12
+ | --- | --- | --- | --- |
13
+ | [GET /.well-known/jwks.json](/docs/for-ai/operations/getJWKS.md) | Public | — | — |
14
+ | [GET /.well-known/oauth-authorization-server](/docs/for-ai/operations/getOAuthAuthorizationServerMetadata.md) | Public | — | — |
15
+ | [GET /.well-known/oauth-protected-resource](/docs/for-ai/operations/getOAuthProtectedResourceMetadata.md) | Public | — | — |
16
+ | [GET /.well-known/oauth-protected-resource/mcp](/docs/for-ai/operations/getMCPOAuthProtectedResourceMetadata.md) | Public | — | — |
17
+ | [GET /.well-known/openid-configuration](/docs/for-ai/operations/getOpenIDConfiguration.md) | Public | — | — |
18
+ | [DELETE /{namespace}/{principalType}/{principalId}](/docs/for-ai/operations/deletePrincipal.md) | OAuth (no scope) | path:namespace (required), path:principalType (required), path:principalId (required) | — |
19
+ | [DELETE /{namespace}/{principalType}/{principalId}/access-control-rules/{ruleId}](/docs/for-ai/operations/deleteAccessControlRule.md) | OAuth (no scope) | path:namespace (required), path:principalType (required), path:principalId (required), path:ruleId (required) | — |
20
+ | [GET /{namespace}/{principalType}/{principalId}/endpoint-groups/{groupId}](/docs/for-ai/operations/getEndpointGroup.md) | group:read | path:namespace (required), path:principalType (required), path:principalId (required), path:groupId (required), query:expand, query:forceDeviceAttributeQuery | — |
21
+ | [DELETE /{namespace}/{principalType}/{principalId}/endpoint-groups/{groupId}](/docs/for-ai/operations/deleteEndpointGroup.md) | group:manage | path:namespace (required), path:principalType (required), path:principalId (required), path:groupId (required), header:If-Match (required) | — |
22
+ | [POST /{namespace}/{principalType}/{principalId}/endpoint-groups/{groupId}/add-members](/docs/for-ai/operations/addEndpointGroupMembers.md) | group:manage | path:namespace (required), path:principalType (required), path:principalId (required), path:groupId (required), header:If-Match (required) | memberEndpointIds |
23
+ | [POST /{namespace}/{principalType}/{principalId}/endpoint-groups/{groupId}/remove-members](/docs/for-ai/operations/removeEndpointGroupMembers.md) | group:manage | path:namespace (required), path:principalType (required), path:principalId (required), path:groupId (required), header:If-Match (required) | memberEndpointIds |
24
+ | [POST /{namespace}/{principalType}/{principalId}/endpoint-groups/{groupId}/set-name](/docs/for-ai/operations/setEndpointGroupName.md) | group:manage | path:namespace (required), path:principalType (required), path:principalId (required), path:groupId (required), header:If-Match (required) | name |
25
+ | [DELETE /{namespace}/{principalType}/{principalId}/flow-runs/{runId}](/docs/for-ai/operations/deleteFlowRun.md) | See session/security contract | path:namespace (required), path:principalType (required), path:principalId (required), path:runId (required) | — |
26
+ | [GET /{namespace}/{principalType}/{principalId}/flows/{flowId}/runs](/docs/for-ai/operations/queryFlowRuns.md) | See session/security contract | path:namespace (required), path:principalType (required), path:principalId (required), path:flowId (required), query:pageToken, query:maxResults, query:expand, query:nextToken | — |
27
+ | [POST /{namespace}/{principalType}/{principalId}/flows/{flowId}/runs](/docs/for-ai/operations/createFlowRun.md) | See session/security contract | path:namespace (required), path:principalType (required), path:principalId (required), path:flowId (required) | flowRun |
28
+ | [POST /{namespace}/{principalType}/{principalId}/flows/{flowId}/runs/{runId}/messages](/docs/for-ai/operations/upsertFlowRunMessage.md) | See session/security contract | path:namespace (required), path:principalType (required), path:principalId (required), path:flowId (required), path:runId (required) | message, target |
29
+ | [POST /{namespace}/{principalType}/{principalId}/flows/{flowId}/runs/{runId}/set-status](/docs/for-ai/operations/setFlowRunStatus.md) | See session/security contract | path:namespace (required), path:principalType (required), path:principalId (required), path:flowId (required), path:runId (required) | status |
30
+ | [DELETE /{namespace}/{principalType}/{principalId}/group-routes/{groupId}](/docs/for-ai/operations/deleteGroupRoute.md) | group:manage | path:namespace (required), path:principalType (required), path:principalId (required), path:groupId (required) | — |
31
+ | [GET /{namespace}/{principalType}/{principalId}/subscriptions/{subscriptionId}](/docs/for-ai/operations/getSubscription.md) | subscription:read | path:namespace (required), path:principalType (required), path:principalId (required), path:subscriptionId (required), query:expand | — |
32
+ | [PATCH /{namespace}/{principalType}/{principalId}/subscriptions/{subscriptionId}](/docs/for-ai/operations/patchSubscription.md) | subscription:write | path:namespace (required), path:principalType (required), path:principalId (required), path:subscriptionId (required) | name |
33
+ | [DELETE /{namespace}/{principalType}/{principalId}/subscriptions/{subscriptionId}](/docs/for-ai/operations/deleteSubscription.md) | subscription:write | path:namespace (required), path:principalType (required), path:principalId (required), path:subscriptionId (required) | — |
34
+ | [DELETE /{namespace}/{principalType}/{principalId}/tokens/{tokenId}](/docs/for-ai/operations/invalidateToken.md) | OAuth (no scope) | path:tokenId (required), path:namespace (required), path:principalType (required), path:principalId (required) | — |
35
+ | [GET /{namespace}/{principalType}/{principalId}/views/{viewId}](/docs/for-ai/operations/getView.md) | OAuth (no scope) | path:namespace (required), path:principalType (required), path:principalId (required), path:viewId (required), query:expand | — |
36
+ | [PUT /{namespace}/{principalType}/{principalId}/views/{viewId}](/docs/for-ai/operations/updateView.md) | OAuth (no scope) | path:namespace (required), path:principalType (required), path:principalId (required), path:viewId (required) | positions, schemaVersion, title, widgets |
37
+ | [DELETE /{namespace}/{principalType}/{principalId}/views/{viewId}](/docs/for-ai/operations/deleteView.md) | OAuth (no scope) | path:namespace (required), path:principalType (required), path:principalId (required), path:viewId (required) | — |
38
+ | [DELETE /{principalType}/{principalId}/flows/{flowId}](/docs/for-ai/operations/deleteFlow.md) | See session/security contract | path:principalType (required), path:principalId (required), path:flowId (required) | — |
39
+ | [GET /access-control-rules](/docs/for-ai/operations/getAccessControlRules.md) | OAuth (no scope) | query:owner (required), query:nextToken, query:maxResults, query:expand | — |
40
+ | [POST /access-control-rules](/docs/for-ai/operations/upsertAccessControlRule.md) | OAuth (no scope) | — | effect, id, identity, operation, resource |
41
+ | [POST /access-control-rules/evaluate](/docs/for-ai/operations/evaluateAccessControlRule.md) | OAuth (no scope) | — | entities, operation, requesterContext, resourceContext |
42
+ | [GET /auth-links](/docs/for-ai/operations/enumerateAuthLinks.md) | OAuth (no scope) | query:expand, query:nextToken, query:maxResults | — |
43
+ | [POST /auth-links](/docs/for-ai/operations/upsertAuthLink.md) | OAuth (no scope) | — | authLink |
44
+ | [DELETE /auth-links](/docs/for-ai/operations/deleteAuthLink.md) | OAuth (no scope) | — | id |
45
+ | [POST /auth-links/establish](/docs/for-ai/operations/establishAuthLink.md) | See session/security contract | — | apiKey, applePushNotificationDeviceToken, authLinkId, oauthTokens, pluginId, usernamePassword |
46
+ | [POST /auth-links/refresh](/docs/for-ai/operations/refreshAuthLinkToken.md) | See session/security contract | — | authLinkId |
47
+ | [POST /auth/callback](/docs/for-ai/operations/handleOAuthCallback.md) | Public | — | code, id_token, state, user |
48
+ | [POST /auth/device-authorization](/docs/for-ai/operations/deviceAuthorize.md) | See session/security contract | — | client_id, scope |
49
+ | [POST /auth/raise](/docs/for-ai/operations/raiseAnonymousPrincipal.md) | Public | — | anonymous_refresh_token, subject_token, subject_token_type |
50
+ | [POST /auth/revoke](/docs/for-ai/operations/revokeOAuthGrant.md) | Public | — | client_id, token |
51
+ | [POST /auth/token](/docs/for-ai/operations/generateToken.md) | Public | — | client_id, client_secret, code, code_verifier, grant_type, redirect_uri, refresh_token, resource, scope |
52
+ | [POST /discovery](/docs/for-ai/operations/synchronizeRoutes.md) | See session/security contract | — | authLinkIdentity, groupRoutes, pluginIdentity, relationships, routes |
53
+ | [GET /endpoint-groups](/docs/for-ai/operations/enumerateEndpointGroups.md) | group:read | query:enablement, query:owner (required), query:nextToken, query:maxResults, query:expand, query:forceDeviceAttributeQuery | — |
54
+ | [POST /endpoint-groups](/docs/for-ai/operations/createEndpointGroup.md) | group:manage | — | item |
55
+ | [POST /endpoint-groups-manage](/docs/for-ai/operations/endpointGroupsManage.md) | group:manage | header:Idempotency-Key (required) | operations, validateOnly |
56
+ | [POST /endpoint-query](/docs/for-ai/operations/endpointQuery.md) | endpoint:read; groupId: group:read | — | expand, forceDeviceQuery, paginationContext, query |
57
+ | [GET /endpoint-simulators](/docs/for-ai/operations/enumerateSimulators.md) | See session/security contract | query:owner, query:maxResults, query:nextToken, query:expand | — |
58
+ | [POST /endpoint-simulators](/docs/for-ai/operations/upsertSimulator.md) | See session/security contract | — | configuration, device_type, id, name, state |
59
+ | [DELETE /endpoint-simulators](/docs/for-ai/operations/deleteSimulator.md) | See session/security contract | — | id |
60
+ | [GET /endpoints](/docs/for-ai/operations/enumerateEndpoints.md) | endpoint:read | query:enablement, query:owner, query:id, query:type, query:serialNumber, query:nextToken, query:maxResults, query:expand, query:forceDeviceAttributeQuery | — |
61
+ | [POST /endpoints](/docs/for-ai/operations/upsertEndpoint.md) | endpoint:write | — | id, name, type |
62
+ | [PATCH /endpoints](/docs/for-ai/operations/modifyEndpoint.md) | endpoint:write | — | enablement, id, mergeInto, name, type |
63
+ | [DELETE /endpoints](/docs/for-ai/operations/deleteEndpoint.md) | endpoint:write | — | id |
64
+ | [GET /event-dead-letters](/docs/for-ai/operations/enumerateEventDeadLetters.md) | See session/security contract | query:nextToken, query:maxResults, query:query, query:expand | — |
65
+ | [GET /event-dead-letters/{id}](/docs/for-ai/operations/getEventDeadLetter.md) | See session/security contract | path:id (required), query:expand | — |
66
+ | [DELETE /event-dead-letters/{id}](/docs/for-ai/operations/deleteEventDeadLetter.md) | See session/security contract | path:id (required) | — |
67
+ | [POST /event-dead-letters/{id}/redrives](/docs/for-ai/operations/redriveEventDeadLetter.md) | See session/security contract | path:id (required) | — |
68
+ | [POST /events](/docs/for-ai/operations/createSyntheticEvent.md) | See session/security contract | — | body, endpoint, header, requestId |
69
+ | [GET /events/receipts/{receiptId}](/docs/for-ai/operations/getEventReceipt.md) | See session/security contract | path:receiptId (required), query:expand | — |
70
+ | [GET /flow-node-specifications](/docs/for-ai/operations/enumerateFlowNodeSpecifications.md) | See session/security contract | query:nextToken, query:maxResults, query:expand | — |
71
+ | [GET /flow-nodes](/docs/for-ai/operations/enumerateFlowNodes.md) | See session/security contract | query:expand, query:nextToken, query:maxResults | — |
72
+ | [POST /flow-nodes](/docs/for-ai/operations/createFlowNode.md) | See session/security contract | — | flow |
73
+ | [DELETE /flow-nodes](/docs/for-ai/operations/deleteFlowNode.md) | See session/security contract | — | id |
74
+ | [GET /flows](/docs/for-ai/operations/queryFlows.md) | See session/security contract | query:owner, query:id, query:nextToken, query:maxResults, query:expand | — |
75
+ | [POST /flows](/docs/for-ai/operations/upsertFlow.md) | See session/security contract | — | flow |
76
+ | [POST /flows/trigger](/docs/for-ai/operations/triggerFlow.md) | See session/security contract | — | flow, triggers |
77
+ | [GET /group-relationships](/docs/for-ai/operations/enumerateGroupRelationships.md) | group:read | query:owner (required), query:groupId, query:routeId, query:endpointId, query:nextToken, query:maxResults, query:expand | — |
78
+ | [GET /group-routes](/docs/for-ai/operations/enumerateGroupRoutes.md) | group:read | query:owner (required), query:nextToken, query:maxResults, query:expand | — |
79
+ | [POST /integration-requests](/docs/for-ai/operations/requestFutureIntegration.md) | Public | — | consent, email, pluginId |
80
+ | [POST /messages](/docs/for-ai/operations/sendMessage.md) | message:send | — | message, responseType, target |
81
+ | [POST /messages-gateway](/docs/for-ai/operations/pushToMessageGateway.md) | OAuth (no scope) | — | auth-token, body, context, correlationToken, endpoint, header, ownerId, secrets, target, type |
82
+ | [POST /messages/send](/docs/for-ai/operations/sendMessageLegacyAlias.md) | message:send | — | message, responseType, target |
83
+ | [GET /metrics](/docs/for-ai/operations/getMetrics.md) | Public | — | — |
84
+ | [GET /oauth-clients](/docs/for-ai/operations/enumerateOAuthClients.md) | OAuth (no scope) | query:nextToken, query:maxResults, query:expand | — |
85
+ | [POST /oauth-clients](/docs/for-ai/operations/createOAuthClient.md) | OAuth (no scope) | — | allowedOrigins, clientName, clientUri, clientUriLocalized, contacts, grantTypes, jwks, jwksUri, logoUri, logoUriLocalized, policyUri, policyUriLocalized, redirectUris, responseTypes, scope, scopes, softwareId, softwareVersion, tokenEndpointAuthMethod, tokenEndpointAuthSigningAlg, tosUri, tosUriLocalized |
86
+ | [GET /oauth/authorization-request](/docs/for-ai/operations/getPendingOAuthConsent.md) | See session/security contract | query:request_id (required) | — |
87
+ | [GET /oauth/authorize](/docs/for-ai/operations/beginOAuthAuthorization.md) | Public | query:client_id (required), query:redirect_uri (required), query:response_type (required), query:scope (required), query:state (required), query:resource (required), query:code_challenge (required), query:code_challenge_method (required) | — |
88
+ | [POST /oauth/authorize](/docs/for-ai/operations/completeOAuthConsent.md) | See session/security contract | — | approved, request_id, scope |
89
+ | [POST /oauth/authorize-device](/docs/for-ai/operations/authorizeDevice.md) | OAuth (no scope) | — | scopes, user_code |
90
+ | [POST /oauth/generate-code](/docs/for-ai/operations/generateOAuthCode.md) | OAuth (no scope) | — | client_id, code_challenge, code_challenge_method, redirect_uri, scopes, state |
91
+ | [POST /oauth/register](/docs/for-ai/operations/registerDynamicOAuthClient.md) | Public | — | client_name, client_uri, grant_types, redirect_uris, response_types, scope, software_id, software_statement, software_version, token_endpoint_auth_method |
92
+ | [POST /oauth/validate-request](/docs/for-ai/operations/validateOAuthRequest.md) | See session/security contract | — | client_id, code_challenge, code_challenge_method, redirect_uri, scopes |
93
+ | [GET /oauth/verify-device](/docs/for-ai/operations/verifyDevice.md) | Public | query:user_code (required) | — |
94
+ | [GET /ping](/docs/for-ai/operations/ping.md) | Public | — | — |
95
+ | [POST /plugin-auth-code-exchange](/docs/for-ai/operations/pluginAuthCodeExchange.md) | OAuth (no scope) | — | pluginAuthenticationData, pluginId, principalId |
96
+ | [POST /plugin-auth-code-link](/docs/for-ai/operations/pluginAuthCodeLink.md) | OAuth (no scope) | — | pluginId, principalId |
97
+ | [POST /plugin-auth-multifactor-exchange](/docs/for-ai/operations/pluginAuthMultifactorExchange.md) | OAuth (no scope) | — | pluginAuthenticationData, pluginId, principalId |
98
+ | [GET /plugins](/docs/for-ai/operations/enumeratePlugins.md) | OAuth (no scope) | query:expand, query:id, query:nextToken, query:maxResults | — |
99
+ | [POST /plugins](/docs/for-ai/operations/upsertPluginRequest.md) | OAuth (no scope) | — | applePushNotificationSecret, plugin, secretReferenceId |
100
+ | [DELETE /plugins](/docs/for-ai/operations/deletePlugin.md) | OAuth (no scope) | — | id |
101
+ | [POST /plugins/establish](/docs/for-ai/operations/establishPlugin.md) | See session/security contract | — | plugin |
102
+ | [GET /port1/{principalType}/{principalId}/oauth-clients/{clientId}](/docs/for-ai/operations/getOAuthClient.md) | OAuth (no scope) | path:principalType (required), path:principalId (required), path:clientId (required), query:expand | — |
103
+ | [PUT /port1/{principalType}/{principalId}/oauth-clients/{clientId}](/docs/for-ai/operations/updateOAuthClient.md) | OAuth (no scope) | path:principalType (required), path:principalId (required), path:clientId (required) | allowedOrigins, clientName, clientUri, clientUriLocalized, contacts, grantTypes, jwks, jwksUri, logoUri, logoUriLocalized, policyUri, policyUriLocalized, redirectUris, responseTypes, scope, scopes, softwareId, softwareVersion, tokenEndpointAuthMethod, tokenEndpointAuthSigningAlg, tosUri, tosUriLocalized |
104
+ | [DELETE /port1/{principalType}/{principalId}/oauth-clients/{clientId}](/docs/for-ai/operations/deleteOAuthClient.md) | OAuth (no scope) | path:principalType (required), path:principalId (required), path:clientId (required) | — |
105
+ | [DELETE /port1/{principalType}/{principalId}/secrets/{secretId}](/docs/for-ai/operations/deleteSecret.md) | OAuth (no scope) | path:principalType (required), path:principalId (required), path:secretId (required) | — |
106
+ | [GET /principals](/docs/for-ai/operations/enumeratePrincipals.md) | OAuth (no scope) | query:expand, query:nextToken, query:maxResults | — |
107
+ | [POST /principals](/docs/for-ai/operations/upsertPrincipal.md) | OAuth (no scope) | — | item |
108
+ | [GET /routes](/docs/for-ai/operations/getRoutes.md) | endpoint:read | query:expand, query:nextToken, query:maxResults | — |
109
+ | [POST /routes](/docs/for-ai/operations/upsertRoute.md) | endpoint:write | — | endpointId, id, interfaces, metadata, pluginId |
110
+ | [DELETE /routes](/docs/for-ai/operations/deleteRoute.md) | endpoint:write | — | id |
111
+ | [GET /secrets](/docs/for-ai/operations/enumerateSecrets.md) | OAuth (no scope) | query:id, query:owner, query:nextToken, query:maxResults, query:expand | — |
112
+ | [POST /secrets](/docs/for-ai/operations/upsertSecret.md) | OAuth (no scope) | — | secret |
113
+ | [GET /subscriptions](/docs/for-ai/operations/enumerateSubscriptions.md) | subscription:read | query:expand, query:nextToken, query:maxResults | — |
114
+ | [POST /subscriptions](/docs/for-ai/operations/upsertSubscription.md) | subscription:write | — | subscription |
115
+ | [GET /tokens](/docs/for-ai/operations/enumerateTokens.md) | OAuth (no scope) | query:nextToken, query:maxResults, query:expand | — |
116
+ | [POST /tokens](/docs/for-ai/operations/createToken.md) | OAuth (no scope) | — | expires_in, label, scope, subject |
117
+ | [POST /tuya/qrcode](/docs/for-ai/operations/generateTuyaQrCode.md) | Public | — | accessCode, authenticationUrl, clientId, schema |
118
+ | [POST /tuya/validatetoken](/docs/for-ai/operations/validateTuyaLoginCode.md) | Public | — | authenticationUrl, clientId, loginCode, userCode |
119
+ | [GET /views](/docs/for-ai/operations/enumerateViews.md) | OAuth (no scope) | query:nextToken, query:maxResults, query:expand | — |
120
+ | [POST /views](/docs/for-ai/operations/createView.md) | OAuth (no scope) | — | positions, schemaVersion, title, widgets |
121
+ | [POST /webhooks/github](/docs/for-ai/operations/handleGitHubWebhook.md) | Public | header:X-Hub-Signature-256 (required), header:X-GitHub-Delivery, header:X-GitHub-Event | — |
122
+ | [POST /webhooks/google-cloud-scheduler](/docs/for-ai/operations/handleGoogleCloudSchedulerWebhook.md) | See session/security contract | — | flow_id, node_id |
123
+ | [POST /webhooks/smartthings](/docs/for-ai/operations/handleSmartThingsWebhook.md) | OAuth (no scope) | — | — |
@@ -4,6 +4,22 @@ Start with authorized endpoint discovery and inspect capability declarations. A
4
4
 
5
5
  For one bulb, read its power/brightness/color message schemas in [the capability directory](/docs/for-ai/capability-interfaces.md). Use the exact namespace, version, message name, units and constraints returned. [The quickstart](/docs/for-ai/guides/quickstart.md) shows the generic dispatch envelope.
6
6
 
7
- For “all lights,” include explicitly authorized shared lights and the user-requested home/group scope. Complete pagination, exclude disabled/unavailable unsupported targets as documented and deduplicate nested groups. Do not broaden the set to every power-capable endpoint. Use the existing query/dispatch contract if it supports the selection; otherwise enumerate the fixed target set and report each result.
7
+ For “all lights,” use [endpointQuery](/docs/for-ai/operations/endpointQuery.md): POST /endpoint-query with endpoint:read. Its results include readable shared endpoints from other owners. Start with the LIGHT and LIGHTBULB types below, then limit the results to the user's requested home or group.
8
8
 
9
- A batch can partially succeed. Report selected, accepted, failed and unresolved targets separately. Read fresh state before claiming all lights changed. A lost response does not justify repeating relative brightness adjustments. See [authorization rules](/docs/for-ai/guides/authorization-rules.md).
9
+ ```json
10
+ {
11
+ "query": {
12
+ "or": [
13
+ {"match": {"key": "type", "value": "LIGHT"}},
14
+ {"match": {"key": "type", "value": "LIGHTBULB"}}
15
+ ]
16
+ },
17
+ "paginationContext": {"maxResults": 25}
18
+ }
19
+ ```
20
+
21
+ For a room, first resolve its full group ID using [group discovery](/docs/for-ai/guides/managing-groups.md). Intersect the type predicate with `{"match":{"key":"groupId","value":"<resolved-full-group-id>"}}` inside query.and. This additionally requires group:read and permission to read that group. A group filter uses its returned member endpoints; resolve the requested nested groups as needed and deduplicate full endpoint IDs. Reading a group does not grant control of its members.
22
+
23
+ Repeat the same query, page size and authenticated grant with paginationContext.nextToken from each response. Continue until that token is absent, including after an empty page. Disabled endpoints are excluded by default. Inspect declared capabilities for the selected endpoints and exclude unsupported targets; do not broaden the selection to every power-capable plug or switch. Freeze the discovered target set before dispatch and report each result.
24
+
25
+ A batch can partially succeed. Report selected, accepted, failed and unresolved targets separately. For fresh readback, repeat endpointQuery with expand:["interfaces.attributes"] and forceDeviceQuery:true. Inspect observation sample times and response errors before claiming all lights changed. A lost response does not justify repeating relative brightness adjustments. See [authorization rules](/docs/for-ai/guides/authorization-rules.md).
@@ -1,9 +1,27 @@
1
1
  # Using the REST API
2
2
 
3
- Discover authorization metadata, then use [OAuth setup](/docs/for-ai/guides/authentication-and-dcr.md). Obtain exact REST paths and schemas from [OpenAPI](/docs/references/openapi.yaml) or [small operation pages](/docs/for-ai/operations/index.md).
3
+ Discover authorization metadata, then use [OAuth setup](/docs/for-ai/guides/authentication-and-dcr.md).
4
+ Start with the [compact API catalog](/docs/for-ai/api-catalog.md). It
5
+ contains auth context, public operation links, parameter names and top-level JSON
6
+ keys. Obtain exact REST paths from its links or the [small operation index](/docs/for-ai/operations/index.md).
7
+ Follow one operation's linked schemas for required/conditional fields and
8
+ nested payloads. It does not inline all schemas or examples.
9
+
10
+ For SDK generation or a comprehensive contract download, request the
11
+ [full OpenAPI document](/docs/references/openapi.yaml).
12
+
13
+ The website's `/api/` route serves this compact Markdown when the request puts
14
+ `text/markdown` first in `Accept` (for example,
15
+ `text/markdown, text/plain;q=0.9, text/html;q=0.8`). Browser HTML requests keep the
16
+ interactive reference. Add `?full=1` to explicitly retrieve the complete HTML
17
+ catalog; keep HTML in your accepted formats for that request. Both variants
18
+ include `Vary: Accept` for caches. The direct compact Markdown URL works on both
19
+ the website and API host and does not depend on negotiation.
4
20
 
5
21
  Enumerate endpoints with endpoint:read. Follow returned pagination links/tokens exactly and stop only when continuation is absent. Inspect declared capabilities and versions; retrieve one message/attribute schema as needed. Send messages through POST /messages (the existing /messages/send alias also works). Never invent target IDs or message fields.
6
22
 
23
+ For filtered inventory including readable shared endpoints, use [POST /endpoint-query](/docs/for-ai/operations/endpointQuery.md). Its query accepts exact match and nested and/or/not predicates; read the request schema's supported fields rather than inventing comparisons or text search. A groupId predicate additionally needs group:read and access to that group. Keep the query, page size, expansions, forceDeviceQuery setting and grant unchanged while following paginationContext.nextToken. Empty pages can have a continuation. Cursors expire after fifteen minutes; restart without nextToken on a 400 cursor error.
24
+
7
25
  REST dispatch and subsequent physical observation are separate facts. A 202 describes unfinished work. A timeout can mean the operation already acted; inspect existing results/state before repeating. IR/Bluetooth fire-and-forget and long-delay devices may never provide immediate confirmation. Use bounded polling and report unresolved state. An endpoint edit marked committed with cleanup pending must not be repeated as though it failed.
8
26
 
9
27
  Use documented idempotency/correlation and version preconditions only where the operation guarantees them. Setting a value and incrementing it have different replay risks. On an ambiguous lost relative-command response, report unknown or read back rather than blindly send again.
@@ -13,6 +13,7 @@ Use [the shared connection guide](/docs/for-ai/guides/connect-agent.md) to selec
13
13
  ## Documentation tree: look up what you need
14
14
 
15
15
  - [Task/component guide directory](/docs/for-ai/guides/index.md): alternatives, not a required reading checklist
16
+ - [Compact API catalog](/docs/for-ai/api-catalog.md): auth context and parameter/key index
16
17
  - [REST operation directory](/docs/for-ai/operations/index.md): individual operations and their scopes
17
18
  - [Small REST schema files](/docs/for-ai/schemas.md): linked request/response components
18
19
  - [Capability directory](/docs/for-ai/capability-interfaces.md): match the discovered namespace and version
@@ -4,7 +4,7 @@ POST `/endpoint-query`
4
4
 
5
5
 
6
6
 
7
- Query for endpoints
7
+ Return a bounded page of authorized endpoints matching the shared Query expression, including endpoints shared by other owners. Read permission is evaluated before filtering, pagination and state expansion. See the request schema for supported fields and operators. Use groupId to select members of a readable room/group, then intersect type or declared interfaces to select lights. Group predicates additionally require group:read for delegated OAuth. Repeat the complete query settings and grant when following nextToken; cursors expire after fifteen minutes. Device attributes are returned only when expanded. Report per-target command acceptance and observed state separately; querying a group does not grant permission to control its members.
8
8
 
9
9
  ## Authorization
10
10
 
@@ -19,6 +19,9 @@ security:
19
19
  - bearerAuth: []
20
20
  delegated: true
21
21
  resourcePermissionRequired: true
22
+ conditionalScopes:
23
+ groupId:
24
+ - group:read
22
25
  ```
23
26
 
24
27
  ## Complete operation contract
@@ -29,7 +32,19 @@ post:
29
32
  operationId: endpointQuery
30
33
  tags:
31
34
  - Endpoints
32
- description: Query for endpoints
35
+ description: >-
36
+ Return a bounded page of authorized endpoints matching the shared Query expression, including
37
+ endpoints shared by other owners. Read permission is evaluated before filtering, pagination and
38
+ state expansion. See the request schema for supported fields and operators. Use groupId to
39
+ select members of a readable room/group, then intersect type or declared interfaces to select
40
+ lights. Group predicates additionally require group:read for delegated OAuth. Repeat the
41
+ complete query settings and grant when following nextToken; cursors expire after fifteen
42
+ minutes. Device attributes are returned only when expanded. Report per-target command acceptance
43
+ and observed state separately; querying a group does not grant permission to control its
44
+ members.
45
+ x-portos-conditional-scopes:
46
+ groupId:
47
+ - group:read
33
48
  requestBody:
34
49
  required: true
35
50
  content:
@@ -39,8 +54,10 @@ post:
39
54
  example:
40
55
  query:
41
56
  match:
42
- key: name
43
- value: test
57
+ key: type
58
+ value: LIGHT
59
+ paginationContext:
60
+ maxResults: 10
44
61
  responses:
45
62
  '200':
46
63
  description: Endpoints retrieved successfully
@@ -50,10 +67,8 @@ post:
50
67
  $ref: /docs/references/schemas/EndpointQueryResponse.json
51
68
  example:
52
69
  results: []
53
- paginationContext:
54
- nextToken: abc123
55
70
  '400':
56
- description: Bad request - missing required parameters
71
+ description: Invalid query, unsupported expansion, or invalid/expired/mismatched cursor.
57
72
  content:
58
73
  application/json:
59
74
  schema:
@@ -72,6 +87,36 @@ post:
72
87
  message: Unauthorized - invalid or missing authentication token
73
88
  code: UNAUTHORIZED
74
89
  family: AUTHENTICATION
90
+ '403':
91
+ description: Missing conditional OAuth scope or permission to read a referenced group.
92
+ content:
93
+ application/json:
94
+ schema:
95
+ $ref: /docs/references/schemas/Error.json
96
+ example:
97
+ message: Permission to read the requested group is required.
98
+ code: FORBIDDEN
99
+ family: FORBIDDEN
100
+ '404':
101
+ description: A referenced group does not exist.
102
+ content:
103
+ application/json:
104
+ schema:
105
+ $ref: /docs/references/schemas/Error.json
106
+ example:
107
+ message: Requested group was not found.
108
+ code: NOT_FOUND
109
+ family: NOT_FOUND
110
+ '409':
111
+ description: A selected disabled endpoint cannot be forcibly refreshed.
112
+ content:
113
+ application/json:
114
+ schema:
115
+ $ref: /docs/references/schemas/Error.json
116
+ example:
117
+ message: endpoint messaging is disabled
118
+ code: ENDPOINT_DISABLED
119
+ family: CONFLICT
75
120
  '500':
76
121
  description: Internal server error
77
122
  content:
@@ -160,7 +160,12 @@
160
160
  }
161
161
  ],
162
162
  "delegated": true,
163
- "resourcePermissionRequired": true
163
+ "resourcePermissionRequired": true,
164
+ "conditionalScopes": {
165
+ "groupId": [
166
+ "group:read"
167
+ ]
168
+ }
164
169
  },
165
170
  {
166
171
  "path": "/events",
@@ -123,6 +123,9 @@ operations:
123
123
  - bearerAuth: []
124
124
  delegated: true
125
125
  resourcePermissionRequired: true
126
+ conditionalScopes:
127
+ groupId:
128
+ - group:read
126
129
  - path: /events
127
130
  runtimePath: /events
128
131
  method: POST
@@ -1,13 +1,137 @@
1
1
  {
2
2
  "package": "@portpowered/reference-data",
3
3
  "goModule": "github.com/portpowered/portos-reference-data",
4
- "version": "0.4.5",
5
- "sourceCommit": "07fdcc4ef4f322950ecb617ffaf47a79b9f0a122",
4
+ "version": "0.4.6",
5
+ "sourceCommit": "1a7e380ef931f684ad0c4dfb9e3d73b20a01bd69",
6
6
  "sourceInputState": "committed",
7
- "sourceInputSHA256": "d8183268527e9f3de34ec8374b1007a4ed48cc0d4255dd8c3bc5822f10e57818",
7
+ "sourceInputSHA256": "373c0f48bd6955157efd5047090454fbd7efa42313debb76229b413567102c22",
8
8
  "sourceInputCount": 735,
9
- "assetSetSHA256": "bae4942d5ad905c28c49cd3967c8e3c24f54db3dc36c90119208fd9c12ef1adc",
9
+ "assetSetSHA256": "c0d41f747be314cd29b19dd70b1a380818fc431b44e91cfb3bea90ebeed55efb",
10
10
  "files": [
11
+ {
12
+ "path": "/docs/for-ai/api-catalog.md",
13
+ "contentType": "text/plain; charset=utf-8",
14
+ "bytes": 21280,
15
+ "sha256": "d0ed50538f4f1ce2f7ec9d4eb17bb3d713a24252ae8af2fbf91bf447e233462d",
16
+ "links": [
17
+ "/docs/for-ai/capability-interfaces.md",
18
+ "/docs/for-ai/guides/authentication-and-dcr.md",
19
+ "/docs/for-ai/guides/authorization-rules.md",
20
+ "/docs/for-ai/guides/quickstart.md",
21
+ "/docs/for-ai/operations/addEndpointGroupMembers.md",
22
+ "/docs/for-ai/operations/authorizeDevice.md",
23
+ "/docs/for-ai/operations/beginOAuthAuthorization.md",
24
+ "/docs/for-ai/operations/completeOAuthConsent.md",
25
+ "/docs/for-ai/operations/createEndpointGroup.md",
26
+ "/docs/for-ai/operations/createFlowNode.md",
27
+ "/docs/for-ai/operations/createFlowRun.md",
28
+ "/docs/for-ai/operations/createOAuthClient.md",
29
+ "/docs/for-ai/operations/createSyntheticEvent.md",
30
+ "/docs/for-ai/operations/createToken.md",
31
+ "/docs/for-ai/operations/createView.md",
32
+ "/docs/for-ai/operations/deleteAccessControlRule.md",
33
+ "/docs/for-ai/operations/deleteAuthLink.md",
34
+ "/docs/for-ai/operations/deleteEndpoint.md",
35
+ "/docs/for-ai/operations/deleteEndpointGroup.md",
36
+ "/docs/for-ai/operations/deleteEventDeadLetter.md",
37
+ "/docs/for-ai/operations/deleteFlow.md",
38
+ "/docs/for-ai/operations/deleteFlowNode.md",
39
+ "/docs/for-ai/operations/deleteFlowRun.md",
40
+ "/docs/for-ai/operations/deleteGroupRoute.md",
41
+ "/docs/for-ai/operations/deleteOAuthClient.md",
42
+ "/docs/for-ai/operations/deletePlugin.md",
43
+ "/docs/for-ai/operations/deletePrincipal.md",
44
+ "/docs/for-ai/operations/deleteRoute.md",
45
+ "/docs/for-ai/operations/deleteSecret.md",
46
+ "/docs/for-ai/operations/deleteSimulator.md",
47
+ "/docs/for-ai/operations/deleteSubscription.md",
48
+ "/docs/for-ai/operations/deleteView.md",
49
+ "/docs/for-ai/operations/deviceAuthorize.md",
50
+ "/docs/for-ai/operations/endpointGroupsManage.md",
51
+ "/docs/for-ai/operations/endpointQuery.md",
52
+ "/docs/for-ai/operations/enumerateAuthLinks.md",
53
+ "/docs/for-ai/operations/enumerateEndpointGroups.md",
54
+ "/docs/for-ai/operations/enumerateEndpoints.md",
55
+ "/docs/for-ai/operations/enumerateEventDeadLetters.md",
56
+ "/docs/for-ai/operations/enumerateFlowNodeSpecifications.md",
57
+ "/docs/for-ai/operations/enumerateFlowNodes.md",
58
+ "/docs/for-ai/operations/enumerateGroupRelationships.md",
59
+ "/docs/for-ai/operations/enumerateGroupRoutes.md",
60
+ "/docs/for-ai/operations/enumerateOAuthClients.md",
61
+ "/docs/for-ai/operations/enumeratePlugins.md",
62
+ "/docs/for-ai/operations/enumeratePrincipals.md",
63
+ "/docs/for-ai/operations/enumerateSecrets.md",
64
+ "/docs/for-ai/operations/enumerateSimulators.md",
65
+ "/docs/for-ai/operations/enumerateSubscriptions.md",
66
+ "/docs/for-ai/operations/enumerateTokens.md",
67
+ "/docs/for-ai/operations/enumerateViews.md",
68
+ "/docs/for-ai/operations/establishAuthLink.md",
69
+ "/docs/for-ai/operations/establishPlugin.md",
70
+ "/docs/for-ai/operations/evaluateAccessControlRule.md",
71
+ "/docs/for-ai/operations/generateOAuthCode.md",
72
+ "/docs/for-ai/operations/generateToken.md",
73
+ "/docs/for-ai/operations/generateTuyaQrCode.md",
74
+ "/docs/for-ai/operations/getAccessControlRules.md",
75
+ "/docs/for-ai/operations/getEndpointGroup.md",
76
+ "/docs/for-ai/operations/getEventDeadLetter.md",
77
+ "/docs/for-ai/operations/getEventReceipt.md",
78
+ "/docs/for-ai/operations/getJWKS.md",
79
+ "/docs/for-ai/operations/getMCPOAuthProtectedResourceMetadata.md",
80
+ "/docs/for-ai/operations/getMetrics.md",
81
+ "/docs/for-ai/operations/getOAuthAuthorizationServerMetadata.md",
82
+ "/docs/for-ai/operations/getOAuthClient.md",
83
+ "/docs/for-ai/operations/getOAuthProtectedResourceMetadata.md",
84
+ "/docs/for-ai/operations/getOpenIDConfiguration.md",
85
+ "/docs/for-ai/operations/getPendingOAuthConsent.md",
86
+ "/docs/for-ai/operations/getRoutes.md",
87
+ "/docs/for-ai/operations/getSubscription.md",
88
+ "/docs/for-ai/operations/getView.md",
89
+ "/docs/for-ai/operations/handleGitHubWebhook.md",
90
+ "/docs/for-ai/operations/handleGoogleCloudSchedulerWebhook.md",
91
+ "/docs/for-ai/operations/handleOAuthCallback.md",
92
+ "/docs/for-ai/operations/handleSmartThingsWebhook.md",
93
+ "/docs/for-ai/operations/invalidateToken.md",
94
+ "/docs/for-ai/operations/modifyEndpoint.md",
95
+ "/docs/for-ai/operations/patchSubscription.md",
96
+ "/docs/for-ai/operations/ping.md",
97
+ "/docs/for-ai/operations/pluginAuthCodeExchange.md",
98
+ "/docs/for-ai/operations/pluginAuthCodeLink.md",
99
+ "/docs/for-ai/operations/pluginAuthMultifactorExchange.md",
100
+ "/docs/for-ai/operations/pushToMessageGateway.md",
101
+ "/docs/for-ai/operations/queryFlowRuns.md",
102
+ "/docs/for-ai/operations/queryFlows.md",
103
+ "/docs/for-ai/operations/raiseAnonymousPrincipal.md",
104
+ "/docs/for-ai/operations/redriveEventDeadLetter.md",
105
+ "/docs/for-ai/operations/refreshAuthLinkToken.md",
106
+ "/docs/for-ai/operations/registerDynamicOAuthClient.md",
107
+ "/docs/for-ai/operations/removeEndpointGroupMembers.md",
108
+ "/docs/for-ai/operations/requestFutureIntegration.md",
109
+ "/docs/for-ai/operations/revokeOAuthGrant.md",
110
+ "/docs/for-ai/operations/sendMessage.md",
111
+ "/docs/for-ai/operations/sendMessageLegacyAlias.md",
112
+ "/docs/for-ai/operations/setEndpointGroupName.md",
113
+ "/docs/for-ai/operations/setFlowRunStatus.md",
114
+ "/docs/for-ai/operations/synchronizeRoutes.md",
115
+ "/docs/for-ai/operations/triggerFlow.md",
116
+ "/docs/for-ai/operations/updateOAuthClient.md",
117
+ "/docs/for-ai/operations/updateView.md",
118
+ "/docs/for-ai/operations/upsertAccessControlRule.md",
119
+ "/docs/for-ai/operations/upsertAuthLink.md",
120
+ "/docs/for-ai/operations/upsertEndpoint.md",
121
+ "/docs/for-ai/operations/upsertFlow.md",
122
+ "/docs/for-ai/operations/upsertFlowRunMessage.md",
123
+ "/docs/for-ai/operations/upsertPluginRequest.md",
124
+ "/docs/for-ai/operations/upsertPrincipal.md",
125
+ "/docs/for-ai/operations/upsertRoute.md",
126
+ "/docs/for-ai/operations/upsertSecret.md",
127
+ "/docs/for-ai/operations/upsertSimulator.md",
128
+ "/docs/for-ai/operations/upsertSubscription.md",
129
+ "/docs/for-ai/operations/validateOAuthRequest.md",
130
+ "/docs/for-ai/operations/validateTuyaLoginCode.md",
131
+ "/docs/for-ai/operations/verifyDevice.md",
132
+ "/docs/references/openapi.yaml"
133
+ ]
134
+ },
11
135
  {
12
136
  "path": "/docs/for-ai/capability-interfaces.md",
13
137
  "contentType": "text/plain; charset=utf-8",
@@ -1303,12 +1427,14 @@
1303
1427
  {
1304
1428
  "path": "/docs/for-ai/guides/lighting.md",
1305
1429
  "contentType": "text/plain; charset=utf-8",
1306
- "bytes": 1290,
1307
- "sha256": "f393b36c9e149709185f18d4b7f2c29a6fae457d18c2d32e34c56040efb1fb3f",
1430
+ "bytes": 2462,
1431
+ "sha256": "4630b0541a7b9de1c605d4bbf9dee7946a0889ca0eb364c628a9878f868e27fe",
1308
1432
  "links": [
1309
1433
  "/docs/for-ai/capability-interfaces.md",
1310
1434
  "/docs/for-ai/guides/authorization-rules.md",
1311
- "/docs/for-ai/guides/quickstart.md"
1435
+ "/docs/for-ai/guides/managing-groups.md",
1436
+ "/docs/for-ai/guides/quickstart.md",
1437
+ "/docs/for-ai/operations/endpointQuery.md"
1312
1438
  ]
1313
1439
  },
1314
1440
  {
@@ -1454,12 +1580,14 @@
1454
1580
  {
1455
1581
  "path": "/docs/for-ai/guides/using-the-api.md",
1456
1582
  "contentType": "text/plain; charset=utf-8",
1457
- "bytes": 1490,
1458
- "sha256": "3d54f9aadddb70cfe6630f8a72cbf50f0163467768e09fc5beece88b8538e909",
1583
+ "bytes": 2995,
1584
+ "sha256": "13207d4668ca60055c5edc4ab4b9f582abdb5a676c9edaacc5c92c054672819d",
1459
1585
  "links": [
1586
+ "/docs/for-ai/api-catalog.md",
1460
1587
  "/docs/for-ai/guides/authentication-and-dcr.md",
1461
1588
  "/docs/for-ai/guides/authorization-rules.md",
1462
1589
  "/docs/for-ai/guides/lighting.md",
1590
+ "/docs/for-ai/operations/endpointQuery.md",
1463
1591
  "/docs/for-ai/operations/index.md",
1464
1592
  "/docs/references/openapi.yaml"
1465
1593
  ]
@@ -1477,9 +1605,10 @@
1477
1605
  {
1478
1606
  "path": "/docs/for-ai/index.md",
1479
1607
  "contentType": "text/plain; charset=utf-8",
1480
- "bytes": 1973,
1481
- "sha256": "303ac8481dfd46c092f1e9fe988740878d146d0194404b309eeb554f4eb2973c",
1608
+ "bytes": 2064,
1609
+ "sha256": "a34ccabe7c6f4b0b9d1b35eece14fdebbdf6ec638596232a8528d4d4714a9fa1",
1482
1610
  "links": [
1611
+ "/docs/for-ai/api-catalog.md",
1483
1612
  "/docs/for-ai/capability-interfaces.md",
1484
1613
  "/docs/for-ai/guides/authentication-and-dcr.md",
1485
1614
  "/docs/for-ai/guides/connect-agent.md",
@@ -1844,8 +1973,8 @@
1844
1973
  {
1845
1974
  "path": "/docs/for-ai/operations/endpointQuery.md",
1846
1975
  "contentType": "text/plain; charset=utf-8",
1847
- "bytes": 2554,
1848
- "sha256": "aac7b487054a992fa385bef6e8df068e79789a9c8d12e08678aa196f8c76af2f",
1976
+ "bytes": 5199,
1977
+ "sha256": "85bf525fe235fafa09159bb4437fcb543a4de8c99dcec57077601b3e7af958a2",
1849
1978
  "links": [
1850
1979
  "/docs/for-ai/guides/authentication-and-dcr.md",
1851
1980
  "/docs/for-ai/schemas.md",
@@ -3980,15 +4109,15 @@
3980
4109
  {
3981
4110
  "path": "/docs/references/authorization.json",
3982
4111
  "contentType": "application/json",
3983
- "bytes": 38378,
3984
- "sha256": "459c04391581ab68829ab3db1b89a99ec1bee41948afee6c314702a27d054370",
4112
+ "bytes": 38470,
4113
+ "sha256": "d989ea6620017866d148d85cea1b23754c66132e2a91d0263d17a315b3e7066e",
3985
4114
  "links": []
3986
4115
  },
3987
4116
  {
3988
4117
  "path": "/docs/references/authorization.yaml",
3989
4118
  "contentType": "application/yaml; charset=utf-8",
3990
- "bytes": 28365,
3991
- "sha256": "00ceec4850728a5e80577a592c132d3a881686b407c3fd2784b4fba1eaf8f57f",
4119
+ "bytes": 28424,
4120
+ "sha256": "49456bdf5aabc3dfcee05bb1dece7fe89e0d727eecc58bac510943d736a7345e",
3992
4121
  "links": []
3993
4122
  },
3994
4123
  {
@@ -7352,8 +7481,8 @@
7352
7481
  {
7353
7482
  "path": "/docs/references/openapi.yaml",
7354
7483
  "contentType": "application/yaml; charset=utf-8",
7355
- "bytes": 757609,
7356
- "sha256": "a6db7cfd7943b4298c07af9dbf1078bcccc15725fa3a4e7a329f92c18e19c89c",
7484
+ "bytes": 761899,
7485
+ "sha256": "a5ae633442765553a3fc97f5a14678290d8dee6d6458cd8975236659ef5537c8",
7357
7486
  "links": []
7358
7487
  },
7359
7488
  {
@@ -8759,8 +8888,8 @@
8759
8888
  {
8760
8889
  "path": "/docs/references/schemas/EndpointQueryRequest.json",
8761
8890
  "contentType": "application/json",
8762
- "bytes": 493,
8763
- "sha256": "7f3bc6e0aeca233394416f5edbf910f2caef13ab0817ecefc5a22dffaaf81239",
8891
+ "bytes": 2558,
8892
+ "sha256": "ace0583c690fcdce12a099f8d633322922dd51c428fc310e9dd33e0789a46074",
8764
8893
  "links": []
8765
8894
  },
8766
8895
  {
@@ -858,7 +858,19 @@ paths:
858
858
  operationId: endpointQuery
859
859
  tags:
860
860
  - Endpoints
861
- description: Query for endpoints
861
+ description: >-
862
+ Return a bounded page of authorized endpoints matching the shared Query expression,
863
+ including endpoints shared by other owners. Read permission is evaluated before filtering,
864
+ pagination and state expansion. See the request schema for supported fields and operators.
865
+ Use groupId to select members of a readable room/group, then intersect type or declared
866
+ interfaces to select lights. Group predicates additionally require group:read for delegated
867
+ OAuth. Repeat the complete query settings and grant when following nextToken; cursors expire
868
+ after fifteen minutes. Device attributes are returned only when expanded. Report per-target
869
+ command acceptance and observed state separately; querying a group does not grant permission
870
+ to control its members.
871
+ x-portos-conditional-scopes:
872
+ groupId:
873
+ - group:read
862
874
  requestBody:
863
875
  required: true
864
876
  content:
@@ -868,8 +880,10 @@ paths:
868
880
  example:
869
881
  query:
870
882
  match:
871
- key: name
872
- value: test
883
+ key: type
884
+ value: LIGHT
885
+ paginationContext:
886
+ maxResults: 10
873
887
  responses:
874
888
  '200':
875
889
  description: Endpoints retrieved successfully
@@ -879,10 +893,8 @@ paths:
879
893
  $ref: '#/components/schemas/EndpointQueryResponse'
880
894
  example:
881
895
  results: []
882
- paginationContext:
883
- nextToken: abc123
884
896
  '400':
885
- description: Bad request - missing required parameters
897
+ description: Invalid query, unsupported expansion, or invalid/expired/mismatched cursor.
886
898
  content:
887
899
  application/json:
888
900
  schema:
@@ -901,6 +913,36 @@ paths:
901
913
  message: Unauthorized - invalid or missing authentication token
902
914
  code: UNAUTHORIZED
903
915
  family: AUTHENTICATION
916
+ '403':
917
+ description: Missing conditional OAuth scope or permission to read a referenced group.
918
+ content:
919
+ application/json:
920
+ schema:
921
+ $ref: '#/components/schemas/Error'
922
+ example:
923
+ message: Permission to read the requested group is required.
924
+ code: FORBIDDEN
925
+ family: FORBIDDEN
926
+ '404':
927
+ description: A referenced group does not exist.
928
+ content:
929
+ application/json:
930
+ schema:
931
+ $ref: '#/components/schemas/Error'
932
+ example:
933
+ message: Requested group was not found.
934
+ code: NOT_FOUND
935
+ family: NOT_FOUND
936
+ '409':
937
+ description: A selected disabled endpoint cannot be forcibly refreshed.
938
+ content:
939
+ application/json:
940
+ schema:
941
+ $ref: '#/components/schemas/Error'
942
+ example:
943
+ message: endpoint messaging is disabled
944
+ code: ENDPOINT_DISABLED
945
+ family: CONFLICT
904
946
  '500':
905
947
  description: Internal server error
906
948
  content:
@@ -18543,18 +18585,59 @@ components:
18543
18585
  description: The value to match on
18544
18586
  EndpointQueryRequest:
18545
18587
  type: object
18588
+ additionalProperties: false
18546
18589
  required:
18547
18590
  - query
18548
18591
  properties:
18549
18592
  query:
18550
18593
  $ref: '#/components/schemas/Query'
18594
+ description: >-
18595
+ A bounded shared Query expression. An empty object selects unfiltered readable
18596
+ inventory. This endpoint supports match, and, or, and not. Scalar match keys are id,
18597
+ name, type, ownerId, manufacturer, model, and enablement. interfaces matches membership
18598
+ in the endpoint's declared interface names; groupId matches membership in a readable
18599
+ endpoint group. Comparisons, patterns, freeform search, unknown keys, ambiguous nodes,
18600
+ expressions deeper than eight levels, or more than 64 nodes return 400. Values are exact
18601
+ strings. Collections hide disabled endpoints unless the expression explicitly filters
18602
+ enablement. Results include readable shared endpoints, regardless of their owner. A
18603
+ groupId predicate additionally requires group:read for delegated OAuth and read
18604
+ permission on that group.
18551
18605
  paginationContext:
18552
- $ref: '#/components/schemas/PaginationContext'
18606
+ type: object
18607
+ additionalProperties: false
18608
+ properties:
18609
+ maxResults:
18610
+ type: integer
18611
+ minimum: 1
18612
+ maximum: 100
18613
+ default: 10
18614
+ description: Maximum authorized matching endpoints in this page.
18615
+ nextToken:
18616
+ type: string
18617
+ minLength: 1
18618
+ description: >-
18619
+ Opaque server-issued continuation token. Repeat the same query, page size,
18620
+ expansions, forceDeviceQuery setting, and authenticated grant. Modified, expired, or
18621
+ differently bound tokens return 400; restart without nextToken. Follow nextToken
18622
+ until absent, including empty pages.
18553
18623
  expand:
18554
18624
  type: array
18555
- description: Expansion tokens that request related or computed endpoint fields.
18625
+ uniqueItems: true
18626
+ maxItems: 1
18627
+ description: Optional reported state expansion; only interfaces.attributes is supported.
18556
18628
  items:
18557
18629
  type: string
18630
+ enum:
18631
+ - interfaces.attributes
18632
+ x-enum-exempt: Existing published REST expansion token shared with GET /endpoints.
18633
+ forceDeviceQuery:
18634
+ type: boolean
18635
+ default: false
18636
+ description: >-
18637
+ Refresh reported device attributes for the selected page. Requires expand to contain
18638
+ interfaces.attributes. An accepted command is not proof of device state; inspect the
18639
+ returned sample times and partial errors. Disabled endpoints cannot be forcibly
18640
+ refreshed.
18558
18641
  Simulator:
18559
18642
  description: Legacy string-name application/json projection; default representation remains unchanged.
18560
18643
  allOf:
@@ -1,22 +1,50 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
3
  "type": "object",
4
+ "additionalProperties": false,
4
5
  "required": [
5
6
  "query"
6
7
  ],
7
8
  "properties": {
8
9
  "query": {
9
- "$ref": "/docs/references/schemas/Query.json"
10
+ "$ref": "/docs/references/schemas/Query.json",
11
+ "description": "A bounded shared Query expression. An empty object selects unfiltered readable inventory. This endpoint supports match, and, or, and not. Scalar match keys are id, name, type, ownerId, manufacturer, model, and enablement. interfaces matches membership in the endpoint's declared interface names; groupId matches membership in a readable endpoint group. Comparisons, patterns, freeform search, unknown keys, ambiguous nodes, expressions deeper than eight levels, or more than 64 nodes return 400. Values are exact strings. Collections hide disabled endpoints unless the expression explicitly filters enablement. Results include readable shared endpoints, regardless of their owner. A groupId predicate additionally requires group:read for delegated OAuth and read permission on that group."
10
12
  },
11
13
  "paginationContext": {
12
- "$ref": "/docs/references/schemas/PaginationContext.json"
14
+ "type": "object",
15
+ "additionalProperties": false,
16
+ "properties": {
17
+ "maxResults": {
18
+ "type": "integer",
19
+ "minimum": 1,
20
+ "maximum": 100,
21
+ "default": 10,
22
+ "description": "Maximum authorized matching endpoints in this page."
23
+ },
24
+ "nextToken": {
25
+ "type": "string",
26
+ "minLength": 1,
27
+ "description": "Opaque server-issued continuation token. Repeat the same query, page size, expansions, forceDeviceQuery setting, and authenticated grant. Modified, expired, or differently bound tokens return 400; restart without nextToken. Follow nextToken until absent, including empty pages."
28
+ }
29
+ }
13
30
  },
14
31
  "expand": {
15
32
  "type": "array",
16
- "description": "Expansion tokens that request related or computed endpoint fields.",
33
+ "uniqueItems": true,
34
+ "maxItems": 1,
35
+ "description": "Optional reported state expansion; only interfaces.attributes is supported.",
17
36
  "items": {
18
- "type": "string"
37
+ "type": "string",
38
+ "enum": [
39
+ "interfaces.attributes"
40
+ ],
41
+ "x-enum-exempt": "Existing published REST expansion token shared with GET /endpoints."
19
42
  }
43
+ },
44
+ "forceDeviceQuery": {
45
+ "type": "boolean",
46
+ "default": false,
47
+ "description": "Refresh reported device attributes for the selected page. Requires expand to contain interfaces.attributes. An accepted command is not proof of device state; inspect the returned sample times and partial errors. Disabled endpoints cannot be forcibly refreshed."
20
48
  }
21
49
  }
22
50
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@portpowered/reference-data",
3
- "version": "0.4.5",
3
+ "version": "0.4.6",
4
4
  "private": false,
5
5
  "publishConfig": { "access": "public" },
6
6
  "repository": { "type": "git", "url": "https://github.com/portpowered/portos-reference-data.git" },