@kusinta/iot-schema 0.1.0-beta.9 → 0.2.0-beta.10

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.
Files changed (53) hide show
  1. package/package.json +19 -2
  2. package/src/kusinta/iot/access/v1/acl_pb.d.ts +230 -11
  3. package/src/kusinta/iot/access/v1/acl_pb.js +26 -5
  4. package/src/kusinta/iot/access/v1/roles_pb.d.ts +95 -2
  5. package/src/kusinta/iot/access/v1/roles_pb.js +37 -1
  6. package/src/kusinta/iot/common/v1/pairing_pb.d.ts +201 -0
  7. package/src/kusinta/iot/common/v1/pairing_pb.js +50 -0
  8. package/src/kusinta/iot/connector/v1/connector_pb.d.ts +481 -34
  9. package/src/kusinta/iot/connector/v1/connector_pb.js +81 -22
  10. package/src/kusinta/iot/connector/v1/connector_service_pb.d.ts +5 -5
  11. package/src/kusinta/iot/connector/v1/connector_service_pb.js +1 -1
  12. package/src/kusinta/iot/device/v1/cluster_state_pb.d.ts +263 -0
  13. package/src/kusinta/iot/device/v1/cluster_state_pb.js +54 -0
  14. package/src/kusinta/iot/device/v1/descriptor_pb.d.ts +53 -9
  15. package/src/kusinta/iot/device/v1/descriptor_pb.js +3 -1
  16. package/src/kusinta/iot/device/v1/device_event_pb.d.ts +162 -0
  17. package/src/kusinta/iot/device/v1/device_event_pb.js +45 -0
  18. package/src/kusinta/iot/device/v1/device_pb.d.ts +185 -28
  19. package/src/kusinta/iot/device/v1/device_pb.js +10 -2
  20. package/src/kusinta/iot/device/v1/matter_options_pb.d.ts +110 -0
  21. package/src/kusinta/iot/device/v1/matter_options_pb.js +118 -0
  22. package/src/kusinta/iot/device/v1/properties_pb.d.ts +240 -205
  23. package/src/kusinta/iot/device/v1/properties_pb.js +9 -1
  24. package/src/kusinta/iot/device/v1/property_update_pb.d.ts +197 -8
  25. package/src/kusinta/iot/device/v1/property_update_pb.js +20 -2
  26. package/src/kusinta/iot/link/v1/link_pb.d.ts +419 -0
  27. package/src/kusinta/iot/link/v1/link_pb.js +121 -0
  28. package/src/kusinta/iot/registration/v1/registration_pb.d.ts +170 -0
  29. package/src/kusinta/iot/registration/v1/registration_pb.js +61 -0
  30. package/src/kusinta/iot/registration/v1/registration_service_pb.d.ts +34 -0
  31. package/src/kusinta/iot/registration/v1/registration_service_pb.js +19 -0
  32. package/src/kusinta/iot/signaling/v1/signaling_pb.d.ts +320 -0
  33. package/src/kusinta/iot/signaling/v1/signaling_pb.js +83 -0
  34. package/src/kusinta/iot/signaling/v1/signaling_service_pb.d.ts +34 -0
  35. package/src/kusinta/iot/signaling/v1/signaling_service_pb.js +19 -0
  36. package/src/kusinta/iot/vendor/homematic/v1/homematic_pb.d.ts +202 -35
  37. package/src/kusinta/iot/vendor/homematic/v1/homematic_pb.js +14 -6
  38. package/src/kusinta/iot/vendor/v1/vendor_options_pb.d.ts +71 -0
  39. package/src/kusinta/iot/vendor/v1/vendor_options_pb.js +75 -0
  40. package/src/kusinta/iot/webrtc/v1/app_token_pb.d.ts +152 -0
  41. package/src/kusinta/iot/webrtc/v1/app_token_pb.js +28 -0
  42. package/src/kusinta/iot/webrtc/v1/command_pb.d.ts +277 -39
  43. package/src/kusinta/iot/webrtc/v1/command_pb.js +29 -2
  44. package/src/kusinta/iot/webrtc/v1/device_state_pb.d.ts +76 -7
  45. package/src/kusinta/iot/webrtc/v1/device_state_pb.js +20 -5
  46. package/src/kusinta/iot/webrtc/v1/envelope_pb.d.ts +603 -25
  47. package/src/kusinta/iot/webrtc/v1/envelope_pb.js +99 -5
  48. package/src/kusinta/iot/webrtc/v1/management_pb.d.ts +627 -0
  49. package/src/kusinta/iot/webrtc/v1/management_pb.js +135 -0
  50. package/src/kusinta/iot/webrtc/v1/permission_push_pb.d.ts +7 -1
  51. package/src/kusinta/iot/webrtc/v1/permission_push_pb.js +2 -2
  52. package/src/kusinta/iot/webrtc/v1/setpoint_mode_pb.d.ts +63 -0
  53. package/src/kusinta/iot/webrtc/v1/setpoint_mode_pb.js +45 -0
@@ -0,0 +1,152 @@
1
+ // @generated by protoc-gen-es v2.12.0 with parameter "target=js+dts,import_extension=js"
2
+ // @generated from file kusinta/iot/webrtc/v1/app_token.proto (package kusinta.iot.webrtc.v1, syntax proto3)
3
+ /* eslint-disable */
4
+
5
+ import type { GenFile, GenMessage } from "@bufbuild/protobuf/codegenv2";
6
+ import type { Message } from "@bufbuild/protobuf";
7
+ import type { Timestamp } from "@bufbuild/protobuf/wkt";
8
+ import type { Role } from "../../access/v1/roles_pb.js";
9
+
10
+ /**
11
+ * Describes the file kusinta/iot/webrtc/v1/app_token.proto.
12
+ */
13
+ export declare const file_kusinta_iot_webrtc_v1_app_token: GenFile;
14
+
15
+ /**
16
+ * AppTokenClaims is the contract for the payload of the JWT carried in
17
+ * AppHandshake.jwt. It is the single source of truth shared between the
18
+ * api-server (which mints the token) and the gateway (which validates it
19
+ * locally against the api-server's public key).
20
+ *
21
+ * This message is NOT sent on the wire — the wire value stays the signed,
22
+ * compact JWS string in AppHandshake.jwt. The fields here document the claim
23
+ * names and types each side must agree on. JWT libraries emit registered
24
+ * claims (iss/aud/sub) as flat strings and timestamps as NumericDate
25
+ * (seconds since the Unix epoch), so map to/from your native JWT library
26
+ * rather than serializing this message directly into the token.
27
+ *
28
+ * @generated from message kusinta.iot.webrtc.v1.AppTokenClaims
29
+ */
30
+ export declare type AppTokenClaims = Message<"kusinta.iot.webrtc.v1.AppTokenClaims"> & {
31
+ /**
32
+ * Registered claims (RFC 7519).
33
+ * Issuer: the api-server's issuer identifier, agreed out of band. A fixed
34
+ * string both sides compare exactly — not derived from anything here.
35
+ *
36
+ * @generated from field: string iss = 1;
37
+ */
38
+ iss: string;
39
+
40
+ /**
41
+ * audience: the target GatewayId value
42
+ *
43
+ * @generated from field: string aud = 2;
44
+ */
45
+ aud: string;
46
+
47
+ /**
48
+ * subject: the UserId value
49
+ *
50
+ * @generated from field: string sub = 3;
51
+ */
52
+ sub: string;
53
+
54
+ /**
55
+ * issued-at (JWT NumericDate on the wire)
56
+ *
57
+ * @generated from field: google.protobuf.Timestamp iat = 4;
58
+ */
59
+ iat?: Timestamp | undefined;
60
+
61
+ /**
62
+ * expiry (JWT NumericDate on the wire)
63
+ *
64
+ * @generated from field: google.protobuf.Timestamp exp = 5;
65
+ */
66
+ exp?: Timestamp | undefined;
67
+
68
+ /**
69
+ * Custom claims.
70
+ * A user may hold several roles at once (e.g. resident + gateway admin), so
71
+ * this is a list. Carried in the JWT as an array of enum NAME strings
72
+ * (e.g. ["ROLE_RESIDENT", "ROLE_GATEWAY_ADMIN"]), matching proto3 canonical
73
+ * JSON enum encoding — not integer values. This keeps the claim
74
+ * self-describing and aligns with text-typed role storage on the api-server.
75
+ *
76
+ * @generated from field: repeated kusinta.iot.access.v1.Role roles = 6;
77
+ */
78
+ roles: Role[];
79
+
80
+ /**
81
+ * RFC 7800 confirmation claim. Binds the token to the DTLS certificate of the
82
+ * connection it may be presented on: the validator compares this against the
83
+ * fingerprint of the live peer and rejects on mismatch, so a token replayed on
84
+ * a different connection is not usable. Without it the token is a pure bearer
85
+ * credential — possession alone is the whole proof.
86
+ *
87
+ * Carried in the JWT as the nested object RFC 7800 specifies:
88
+ * "cnf": { "x5t#S256": "<base64url SHA-256 thumbprint of the peer's DER certificate>" }
89
+ *
90
+ * MANDATORY. The issuer MUST set it on every token, and the validator MUST
91
+ * reject a token that arrives without one. proto3 cannot express that, and
92
+ * the claim is a JSON object in a JWT rather than a field on this message on
93
+ * the wire, so nothing mechanical enforces it — it is a contract both sides
94
+ * implement or the binding is worthless. A validator that treats an absent
95
+ * cnf as "fall back to bearer" reopens the exact replay this claim closes,
96
+ * and gives any holder of a stolen token a way to opt out of the check by
97
+ * stripping it.
98
+ *
99
+ * Rollout order, since a mandatory claim cannot appear on both sides at once:
100
+ * the api-server must be issuing cnf on every token BEFORE the gateway begins
101
+ * rejecting tokens that lack it. Reverse that order and every live session is
102
+ * refused. Tokens are short-TTL, so the gap between the two deployments need
103
+ * only exceed one token lifetime.
104
+ *
105
+ * @generated from field: kusinta.iot.webrtc.v1.Confirmation cnf = 7;
106
+ */
107
+ cnf?: Confirmation | undefined;
108
+ };
109
+
110
+ /**
111
+ * Describes the message kusinta.iot.webrtc.v1.AppTokenClaims.
112
+ * Use `create(AppTokenClaimsSchema)` to create a new message.
113
+ */
114
+ export declare const AppTokenClaimsSchema: GenMessage<AppTokenClaims>;
115
+
116
+ /**
117
+ * RFC 7800 confirmation, the value of the "cnf" claim. A separate message
118
+ * because the claim is a nested JSON object in the token, not a flat string.
119
+ *
120
+ * @generated from message kusinta.iot.webrtc.v1.Confirmation
121
+ */
122
+ export declare type Confirmation = Message<"kusinta.iot.webrtc.v1.Confirmation"> & {
123
+ /**
124
+ * JWT claim name "x5t#S256" — the proto field cannot carry the "#", so the
125
+ * mapping to and from the JWT is by hand on both sides.
126
+ *
127
+ * ENCODING, pinned deliberately: base64url (unpadded) of the SHA-256 digest
128
+ * over the peer's DER-encoded certificate. WebRTC stacks hand you the same
129
+ * digest in the SDP `a=fingerprint:sha-256` attribute in a DIFFERENT form —
130
+ * uppercase, colon-separated hex — and the two will never compare equal.
131
+ * Issuer and validator must both normalise to the base64url form here; left
132
+ * unstated, each side can derive a correct value and never match.
133
+ *
134
+ * A DTLS fingerprint names a CERTIFICATE, not a connection: WebRTC permits
135
+ * reusing one certificate across several peer connections, and a new
136
+ * connection normally brings a new certificate. It is therefore neither
137
+ * unique per connection nor stable across reconnects, and must not be used as
138
+ * a session or connection key. It is a credential — it proves the peer holds
139
+ * the private key for the certificate the token was issued against, which is
140
+ * exactly and only what a confirmation claim needs.
141
+ *
142
+ * @generated from field: string x5t_s256 = 1;
143
+ */
144
+ x5tS256: string;
145
+ };
146
+
147
+ /**
148
+ * Describes the message kusinta.iot.webrtc.v1.Confirmation.
149
+ * Use `create(ConfirmationSchema)` to create a new message.
150
+ */
151
+ export declare const ConfirmationSchema: GenMessage<Confirmation>;
152
+
@@ -0,0 +1,28 @@
1
+ // @generated by protoc-gen-es v2.12.0 with parameter "target=js+dts,import_extension=js"
2
+ // @generated from file kusinta/iot/webrtc/v1/app_token.proto (package kusinta.iot.webrtc.v1, syntax proto3)
3
+ /* eslint-disable */
4
+
5
+ import { fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv2";
6
+ import { file_google_protobuf_timestamp } from "@bufbuild/protobuf/wkt";
7
+ import { file_kusinta_iot_access_v1_roles } from "../../access/v1/roles_pb.js";
8
+
9
+ /**
10
+ * Describes the file kusinta/iot/webrtc/v1/app_token.proto.
11
+ */
12
+ export const file_kusinta_iot_webrtc_v1_app_token = /*@__PURE__*/
13
+ fileDesc("CiVrdXNpbnRhL2lvdC93ZWJydGMvdjEvYXBwX3Rva2VuLnByb3RvEhVrdXNpbnRhLmlvdC53ZWJydGMudjEi5wEKDkFwcFRva2VuQ2xhaW1zEgsKA2lzcxgBIAEoCRILCgNhdWQYAiABKAkSCwoDc3ViGAMgASgJEicKA2lhdBgEIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASJwoDZXhwGAUgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIqCgVyb2xlcxgGIAMoDjIbLmt1c2ludGEuaW90LmFjY2Vzcy52MS5Sb2xlEjAKA2NuZhgHIAEoCzIjLmt1c2ludGEuaW90LndlYnJ0Yy52MS5Db25maXJtYXRpb24iIAoMQ29uZmlybWF0aW9uEhAKCHg1dF9zMjU2GAEgASgJQgJIAWIGcHJvdG8z", [file_google_protobuf_timestamp, file_kusinta_iot_access_v1_roles]);
14
+
15
+ /**
16
+ * Describes the message kusinta.iot.webrtc.v1.AppTokenClaims.
17
+ * Use `create(AppTokenClaimsSchema)` to create a new message.
18
+ */
19
+ export const AppTokenClaimsSchema = /*@__PURE__*/
20
+ messageDesc(file_kusinta_iot_webrtc_v1_app_token, 0);
21
+
22
+ /**
23
+ * Describes the message kusinta.iot.webrtc.v1.Confirmation.
24
+ * Use `create(ConfirmationSchema)` to create a new message.
25
+ */
26
+ export const ConfirmationSchema = /*@__PURE__*/
27
+ messageDesc(file_kusinta_iot_webrtc_v1_app_token, 1);
28
+
@@ -2,10 +2,13 @@
2
2
  // @generated from file kusinta/iot/webrtc/v1/command.proto (package kusinta.iot.webrtc.v1, syntax proto3)
3
3
  /* eslint-disable */
4
4
 
5
- import type { GenFile, GenMessage } from "@bufbuild/protobuf/codegenv2";
5
+ import type { GenEnum, GenFile, GenMessage } from "@bufbuild/protobuf/codegenv2";
6
6
  import type { Message } from "@bufbuild/protobuf";
7
+ import type { SetpointAdjustMode } from "./setpoint_mode_pb.js";
7
8
  import type { DeviceId } from "../../identity/v1/identity_pb.js";
8
9
  import type { Timestamp } from "@bufbuild/protobuf/wkt";
10
+ import type { AttributeRef } from "../../access/v1/acl_pb.js";
11
+ import type { AttributeValue } from "../../device/v1/cluster_state_pb.js";
9
12
 
10
13
  /**
11
14
  * Describes the file kusinta/iot/webrtc/v1/command.proto.
@@ -13,17 +16,24 @@ import type { Timestamp } from "@bufbuild/protobuf/wkt";
13
16
  export declare const file_kusinta_iot_webrtc_v1_command: GenFile;
14
17
 
15
18
  /**
16
- * Maps to Matter SetpointRaiseLower command (Thermostat cluster 0x0201).
19
+ * Adjusts a setpoint by a delta. Maps to the Matter SetpointRaiseLower command
20
+ * (Thermostat cluster 0x0201).
21
+ *
22
+ * A delta needs a base, and only the producer holds one. On a battery-powered device
23
+ * that wakes on a multi-minute cycle the producer often has no current base and MUST
24
+ * refuse the command rather than guess at one — guessing moves a real radiator to a
25
+ * temperature nobody asked for. Prefer ThermostatSetpointWriteParams where the caller
26
+ * already knows the absolute value it wants; it has no such failure mode.
17
27
  *
18
28
  * @generated from message kusinta.iot.webrtc.v1.ThermostatSetpointParams
19
29
  */
20
30
  export declare type ThermostatSetpointParams = Message<"kusinta.iot.webrtc.v1.ThermostatSetpointParams"> & {
21
31
  /**
22
- * SetpointAdjustMode: Heat=1, Cool=2, Both=3
32
+ * absent = the producer stated no mode
23
33
  *
24
- * @generated from field: uint32 mode = 1;
34
+ * @generated from field: optional kusinta.iot.webrtc.v1.SetpointAdjustMode mode = 1;
25
35
  */
26
- mode: number;
36
+ mode?: SetpointAdjustMode | undefined;
27
37
 
28
38
  /**
29
39
  * centidegrees delta
@@ -67,20 +77,17 @@ export declare type LevelControlParams = Message<"kusinta.iot.webrtc.v1.LevelCon
67
77
  export declare const LevelControlParamsSchema: GenMessage<LevelControlParams>;
68
78
 
69
79
  /**
70
- * Maps to Matter On and Off commands (On/Off cluster 0x0006).
80
+ * Arguments for the Matter On/Off cluster's Off (0x00), On (0x01) and Toggle (0x02)
81
+ * commands — of which there are none: all three take no arguments.
82
+ *
83
+ * Which of the three is meant is DeviceCommand.matter_command_id, and only that. The
84
+ * message previously carried `on` and `toggle` booleans, a second encoding of the same
85
+ * choice in a different shape, so a command could say Toggle in one field and On in
86
+ * another and parse cleanly. Empty is the honest form.
71
87
  *
72
88
  * @generated from message kusinta.iot.webrtc.v1.OnOffParams
73
89
  */
74
90
  export declare type OnOffParams = Message<"kusinta.iot.webrtc.v1.OnOffParams"> & {
75
- /**
76
- * @generated from field: bool on = 1;
77
- */
78
- on: boolean;
79
-
80
- /**
81
- * @generated from field: bool toggle = 2;
82
- */
83
- toggle: boolean;
84
91
  };
85
92
 
86
93
  /**
@@ -110,18 +117,16 @@ export declare type WindowCoveringLiftParams = Message<"kusinta.iot.webrtc.v1.Wi
110
117
  export declare const WindowCoveringLiftParamsSchema: GenMessage<WindowCoveringLiftParams>;
111
118
 
112
119
  /**
113
- * Maps to Matter LockDoor/UnlockDoor commands (Door Lock cluster 0x0101).
120
+ * Arguments for the Matter Door Lock cluster's LockDoor (0x00) and UnlockDoor (0x01),
121
+ * which take an optional PIN and nothing else.
122
+ *
123
+ * lock_state is gone: it restated LockDoor/UnlockDoor as Locked=1/Unlocked=2, a second
124
+ * selector in a THIRD numbering, disagreeing with both Matter's command IDs and its
125
+ * LockState attribute. Which operation is meant is DeviceCommand.matter_command_id.
114
126
  *
115
127
  * @generated from message kusinta.iot.webrtc.v1.DoorLockParams
116
128
  */
117
129
  export declare type DoorLockParams = Message<"kusinta.iot.webrtc.v1.DoorLockParams"> & {
118
- /**
119
- * Locked=1, Unlocked=2
120
- *
121
- * @generated from field: uint32 lock_state = 1;
122
- */
123
- lockState: number;
124
-
125
130
  /**
126
131
  * optional PIN
127
132
  *
@@ -137,15 +142,41 @@ export declare type DoorLockParams = Message<"kusinta.iot.webrtc.v1.DoorLockPara
137
142
  export declare const DoorLockParamsSchema: GenMessage<DoorLockParams>;
138
143
 
139
144
  /**
145
+ * A command an app asks the gateway to run on a device.
146
+ *
147
+ * Authorization
148
+ *
149
+ * An app MAY send any command; it does not decide whether it is allowed. The gateway
150
+ * authorizes every DeviceCommand against the caller's access.v1.DeviceAcl for the target
151
+ * device before forwarding it to a connector: PERMISSION_ACTION_INVOKE must be granted,
152
+ * and allowed_command_refs must reach this (endpoint, cluster_id, matter_command_id).
153
+ *
154
+ * NOT allowed_attribute_refs, and NOT PropertyConstraint. Both name attributes, and a
155
+ * command is not an attribute — the two are numbered independently within a cluster, so an
156
+ * attribute ref cannot name a command at all. A constraint bounds an attribute's value;
157
+ * this message carries command arguments, and ThermostatSetpointParams.amount is a DELTA,
158
+ * which cannot be compared against a bound without first resolving it to an absolute using
159
+ * a base the gateway may not hold. Where a setpoint must be bounded, bound the write:
160
+ * AttributeWriteRequest carries the absolute value a PropertyConstraint can be applied to.
161
+ *
162
+ * A refusal comes back as an ordinary CommandResult with success = false and an error,
163
+ * NOT as a session-level GatewayError: one command being refused says nothing about the
164
+ * session, which continues. A command for a device the caller cannot reach is refused the
165
+ * same way whether or not it exists, so no result reveals a device the user may not see.
166
+ *
140
167
  * @generated from message kusinta.iot.webrtc.v1.DeviceCommand
141
168
  */
142
169
  export declare type DeviceCommand = Message<"kusinta.iot.webrtc.v1.DeviceCommand"> & {
143
170
  /**
144
- * UUID, matched in CommandResult
171
+ * Was command_id. Renamed because Matter has its own numeric command ID, added below,
172
+ * and two fields called "command id" meaning entirely different things in one message is
173
+ * a trap. Same name as AttributeWriteRequest.request_id, which correlates the same way.
174
+ *
175
+ * UUID, matched in the result
145
176
  *
146
- * @generated from field: string command_id = 1;
177
+ * @generated from field: string request_id = 1;
147
178
  */
148
- commandId: string;
179
+ requestId: string;
149
180
 
150
181
  /**
151
182
  * @generated from field: kusinta.iot.identity.v1.DeviceId device_id = 2;
@@ -153,16 +184,60 @@ export declare type DeviceCommand = Message<"kusinta.iot.webrtc.v1.DeviceCommand
153
184
  deviceId?: DeviceId | undefined;
154
185
 
155
186
  /**
156
- * @generated from field: string cluster_id_hex = 3;
187
+ * The command's own PascalCase spelling, for logs and rendering.
188
+ *
189
+ * ADVISORY, and not validated against anything: nothing reconciles it with
190
+ * matter_command_id, so it can say "Toggle" beside an ID meaning On. A consumer MUST NOT
191
+ * route or authorize on it, and where the two disagree the ID wins. It is here so a
192
+ * refused or unresolvable command is legible to whoever reads the log.
193
+ *
194
+ * @generated from field: string command_name = 4;
157
195
  */
158
- clusterIdHex: string;
196
+ commandName: string;
159
197
 
160
198
  /**
161
- * PascalCase Matter command name
199
+ * e.g. 0x0201 for Thermostat
162
200
  *
163
- * @generated from field: string command_name = 4;
201
+ * @generated from field: uint32 cluster_id = 12;
164
202
  */
165
- commandName: string;
203
+ clusterId: number;
204
+
205
+ /**
206
+ * The Matter command ID within that cluster, e.g. 0x02 for On/Off's Toggle.
207
+ *
208
+ * What a consumer routes and authorizes on, matching Matter's own wire and the numeric
209
+ * Endpoint.clusters[].accepted_command_ids — so "does this device accept this command"
210
+ * is answerable before sending it rather than by watching it fail.
211
+ *
212
+ * Where the parameters case declares a (matter_command_id), this MUST equal it; where it
213
+ * declares only a (matter_command_cluster) — because several commands share the same
214
+ * arguments — this is what picks the command. cluster_id MUST equal the case's
215
+ * (matter_command_cluster) either way. A mismatch is malformed and is refused with
216
+ * COMMAND_ERROR_CODE_INVALID_COMMAND.
217
+ *
218
+ * raw_tlv has no annotation to check against, so there this is simply required.
219
+ *
220
+ * @generated from field: optional uint32 matter_command_id = 13;
221
+ */
222
+ matterCommandId?: number | undefined;
223
+
224
+ /**
225
+ * Which endpoint of the device to command. Required by rule — proto3 has no `required`,
226
+ * and `optional` is what makes "not stated" representable so a consumer can reject it
227
+ * rather than decode an omission to endpoint 0, which is the Matter root node.
228
+ *
229
+ * A device presents several
230
+ * endpoints and a command with no destination has no correct one — on a 4-channel
231
+ * actuator, picking any of them moves real hardware. Refuse an unaddressed command
232
+ * rather than guessing.
233
+ *
234
+ * No exemption for single-endpoint devices. A rule where the same message is valid or
235
+ * invalid depending on the shape of its target is a rule that works until a device
236
+ * grows an endpoint.
237
+ *
238
+ * @generated from field: optional uint32 endpoint_id = 11;
239
+ */
240
+ endpointId?: number | undefined;
166
241
 
167
242
  /**
168
243
  * @generated from oneof kusinta.iot.webrtc.v1.DeviceCommand.parameters
@@ -219,14 +294,16 @@ export declare const DeviceCommandSchema: GenMessage<DeviceCommand>;
219
294
  */
220
295
  export declare type CommandError = Message<"kusinta.iot.webrtc.v1.CommandError"> & {
221
296
  /**
222
- * @generated from field: string code = 1;
297
+ * human-readable, for logs — never rendered to a user
298
+ *
299
+ * @generated from field: string message = 2;
223
300
  */
224
- code: string;
301
+ message: string;
225
302
 
226
303
  /**
227
- * @generated from field: string message = 2;
304
+ * @generated from field: kusinta.iot.webrtc.v1.CommandErrorCode code = 3;
228
305
  */
229
- message: string;
306
+ code: CommandErrorCode;
230
307
  };
231
308
 
232
309
  /**
@@ -236,16 +313,23 @@ export declare type CommandError = Message<"kusinta.iot.webrtc.v1.CommandError">
236
313
  export declare const CommandErrorSchema: GenMessage<CommandError>;
237
314
 
238
315
  /**
239
- * CommandResult travels gateway → Flutter app (GatewayMessage) and
240
- * connector → gateway (ConnectRequest via connector.proto import).
316
+ * CommandResult travels gateway → app (GatewayMessage) and
317
+ * connector → gateway (SessionRequest via connector.proto import).
318
+ *
319
+ * success = true means the command was ACCEPTED, not that the device confirmed it. For
320
+ * a battery-powered device that wakes on a multi-minute cycle, acceptance without
321
+ * confirmation is the normal path, not an edge case: waiting for the device would fail
322
+ * every write to a sleeping one.
241
323
  *
242
324
  * @generated from message kusinta.iot.webrtc.v1.CommandResult
243
325
  */
244
326
  export declare type CommandResult = Message<"kusinta.iot.webrtc.v1.CommandResult"> & {
245
327
  /**
246
- * @generated from field: string command_id = 1;
328
+ * matches DeviceCommand.request_id
329
+ *
330
+ * @generated from field: string request_id = 1;
247
331
  */
248
- commandId: string;
332
+ requestId: string;
249
333
 
250
334
  /**
251
335
  * @generated from field: bool success = 2;
@@ -261,6 +345,25 @@ export declare type CommandResult = Message<"kusinta.iot.webrtc.v1.CommandResult
261
345
  * @generated from field: google.protobuf.Timestamp completed_at = 4;
262
346
  */
263
347
  completedAt?: Timestamp | undefined;
348
+
349
+ /**
350
+ * When the producer's own optimistic window closes: by this time the value has either
351
+ * been confirmed by the device or restored to what it was, and either way the producer
352
+ * will have published a PropertyUpdate saying so.
353
+ *
354
+ * Set it when the producer applied the value optimistically and runs a rollback timer.
355
+ * It exists so a consumer can bound its wait without hardcoding a constant chasing a
356
+ * timer that lives in someone else's codebase and changes without notice.
357
+ *
358
+ * Absent means no claim — either the producer confirms synchronously, or it cannot
359
+ * state a bound. Absent is NOT "settles immediately".
360
+ *
361
+ * This bounds the wait; it does not label the values that arrive. Which update was the
362
+ * optimistic one is device.v1.PropertyUpdate.provenance.
363
+ *
364
+ * @generated from field: optional google.protobuf.Timestamp settles_by = 5;
365
+ */
366
+ settlesBy?: Timestamp | undefined;
264
367
  };
265
368
 
266
369
  /**
@@ -269,3 +372,138 @@ export declare type CommandResult = Message<"kusinta.iot.webrtc.v1.CommandResult
269
372
  */
270
373
  export declare const CommandResultSchema: GenMessage<CommandResult>;
271
374
 
375
+ /**
376
+ * Writes one attribute of one endpoint. The carrier for PERMISSION_ACTION_WRITE, which
377
+ * until it existed authorized an operation no message performed.
378
+ *
379
+ * Deliberately not a DeviceCommand case. A write and an invoke are different operations in
380
+ * Matter carrying different authority: a user who may toggle a light is not thereby a user
381
+ * who may rewrite its attributes. Routing both through one message made INVOKE imply WRITE
382
+ * and left the distinction unenforceable.
383
+ *
384
+ * Lives here beside DeviceCommand rather than in envelope.proto because both legs carry
385
+ * it — the app sends one, and the gateway forwards it to a connector. That is the same
386
+ * reason DeviceCommand is here.
387
+ *
388
+ * Addressed by AttributeRef, so an access.v1.PropertyConstraint bounds the value by
389
+ * matching target directly rather than needing a rule per writable attribute.
390
+ *
391
+ * A relative adjust is NOT this. Thermostat SetpointRaiseLower is a genuine Matter command
392
+ * and stays a DeviceCommand; this is for writing an absolute value.
393
+ *
394
+ * Answered by CommandResult, correlated on request_id.
395
+ *
396
+ * @generated from message kusinta.iot.webrtc.v1.AttributeWriteRequest
397
+ */
398
+ export declare type AttributeWriteRequest = Message<"kusinta.iot.webrtc.v1.AttributeWriteRequest"> & {
399
+ /**
400
+ * UUID, matched in CommandResult
401
+ *
402
+ * @generated from field: string request_id = 1;
403
+ */
404
+ requestId: string;
405
+
406
+ /**
407
+ * @generated from field: kusinta.iot.identity.v1.DeviceId device_id = 2;
408
+ */
409
+ deviceId?: DeviceId | undefined;
410
+
411
+ /**
412
+ * Which attribute to write. endpoint_id is required here — an unaddressed write has no
413
+ * correct destination, exactly as for a command.
414
+ *
415
+ * @generated from field: kusinta.iot.access.v1.AttributeRef target = 3;
416
+ */
417
+ target?: AttributeRef | undefined;
418
+
419
+ /**
420
+ * @generated from field: kusinta.iot.device.v1.AttributeValue value = 4;
421
+ */
422
+ value?: AttributeValue | undefined;
423
+ };
424
+
425
+ /**
426
+ * Describes the message kusinta.iot.webrtc.v1.AttributeWriteRequest.
427
+ * Use `create(AttributeWriteRequestSchema)` to create a new message.
428
+ */
429
+ export declare const AttributeWriteRequestSchema: GenMessage<AttributeWriteRequest>;
430
+
431
+ /**
432
+ * Why a command was refused or failed, so an app can branch without string-matching a
433
+ * human sentence. Closed vocabulary for the same reason as GatewayErrorCode: the app leg
434
+ * is versioned together with the gateway, so clients can switch exhaustively.
435
+ *
436
+ * @generated from enum kusinta.iot.webrtc.v1.CommandErrorCode
437
+ */
438
+ export enum CommandErrorCode {
439
+ /**
440
+ * Sender did not set a code, or sent one this client's schema does not know.
441
+ *
442
+ * @generated from enum value: COMMAND_ERROR_CODE_UNSPECIFIED = 0;
443
+ */
444
+ UNSPECIFIED = 0,
445
+
446
+ /**
447
+ * The caller's DeviceAcl does not permit this command. Permanent: do not retry, and do
448
+ * not reveal whether the device exists. Also the answer for a device out of reach.
449
+ *
450
+ * @generated from enum value: COMMAND_ERROR_CODE_NOT_ENTITLED = 1;
451
+ */
452
+ NOT_ENTITLED = 1,
453
+
454
+ /**
455
+ * The value is outside a PropertyConstraint bounding it — a resident asking for a
456
+ * setpoint above the property owner's limit. About the USER's request, not the app's
457
+ * correctness: worth telling the user, and the limit is readable from their permissions.
458
+ *
459
+ * @generated from enum value: COMMAND_ERROR_CODE_CONSTRAINT_VIOLATED = 2;
460
+ */
461
+ CONSTRAINT_VIOLATED = 2,
462
+
463
+ /**
464
+ * Malformed: no endpoint_id, an unknown parameters case, a cluster the device does not
465
+ * have. A client bug — log it, do not retry.
466
+ *
467
+ * @generated from enum value: COMMAND_ERROR_CODE_INVALID_COMMAND = 3;
468
+ */
469
+ INVALID_COMMAND = 3,
470
+
471
+ /**
472
+ * No route to the device right now: its connector is disconnected, or the device did
473
+ * not answer. Transient, retrying is reasonable. NOT a statement that the device is
474
+ * gone — that is webrtc.v1.DeviceRemoved.
475
+ *
476
+ * @generated from enum value: COMMAND_ERROR_CODE_UNREACHABLE = 4;
477
+ */
478
+ UNREACHABLE = 4,
479
+
480
+ /**
481
+ * The gateway's own deadline passed with no answer from the connector. The command MAY
482
+ * still have run: this is the one code that says nothing about what happened to the
483
+ * device, so it is never a reason to roll back a displayed value.
484
+ *
485
+ * @generated from enum value: COMMAND_ERROR_CODE_TIMEOUT = 5;
486
+ */
487
+ TIMEOUT = 5,
488
+
489
+ /**
490
+ * The connector or the device refused it for a reason of its own — a mode the hardware
491
+ * will not accept, a locked device. Read message for specifics.
492
+ *
493
+ * @generated from enum value: COMMAND_ERROR_CODE_REJECTED_BY_DEVICE = 6;
494
+ */
495
+ REJECTED_BY_DEVICE = 6,
496
+
497
+ /**
498
+ * Gateway-side fault. Not the app's doing; retry cautiously.
499
+ *
500
+ * @generated from enum value: COMMAND_ERROR_CODE_INTERNAL = 7;
501
+ */
502
+ INTERNAL = 7,
503
+ }
504
+
505
+ /**
506
+ * Describes the enum kusinta.iot.webrtc.v1.CommandErrorCode.
507
+ */
508
+ export declare const CommandErrorCodeSchema: GenEnum<CommandErrorCode>;
509
+
@@ -2,15 +2,19 @@
2
2
  // @generated from file kusinta/iot/webrtc/v1/command.proto (package kusinta.iot.webrtc.v1, syntax proto3)
3
3
  /* eslint-disable */
4
4
 
5
- import { fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv2";
5
+ import { enumDesc, fileDesc, messageDesc, tsEnum } from "@bufbuild/protobuf/codegenv2";
6
6
  import { file_google_protobuf_timestamp } from "@bufbuild/protobuf/wkt";
7
+ import { file_kusinta_iot_access_v1_acl } from "../../access/v1/acl_pb.js";
8
+ import { file_kusinta_iot_device_v1_cluster_state } from "../../device/v1/cluster_state_pb.js";
9
+ import { file_kusinta_iot_device_v1_matter_options } from "../../device/v1/matter_options_pb.js";
7
10
  import { file_kusinta_iot_identity_v1_identity } from "../../identity/v1/identity_pb.js";
11
+ import { file_kusinta_iot_webrtc_v1_setpoint_mode } from "./setpoint_mode_pb.js";
8
12
 
9
13
  /**
10
14
  * Describes the file kusinta/iot/webrtc/v1/command.proto.
11
15
  */
12
16
  export const file_kusinta_iot_webrtc_v1_command = /*@__PURE__*/
13
- fileDesc("CiNrdXNpbnRhL2lvdC93ZWJydGMvdjEvY29tbWFuZC5wcm90bxIVa3VzaW50YS5pb3Qud2VicnRjLnYxIjgKGFRoZXJtb3N0YXRTZXRwb2ludFBhcmFtcxIMCgRtb2RlGAEgASgNEg4KBmFtb3VudBgCIAEoESI8ChJMZXZlbENvbnRyb2xQYXJhbXMSDQoFbGV2ZWwYASABKA0SFwoPdHJhbnNpdGlvbl90aW1lGAIgASgNIikKC09uT2ZmUGFyYW1zEgoKAm9uGAEgASgIEg4KBnRvZ2dsZRgCIAEoCCI2ChhXaW5kb3dDb3ZlcmluZ0xpZnRQYXJhbXMSGgoSbGlmdF9wZXJjZW50MTAwdGhzGAEgASgNIjYKDkRvb3JMb2NrUGFyYW1zEhIKCmxvY2tfc3RhdGUYASABKA0SEAoIcGluX2NvZGUYAiABKAki/wMKDURldmljZUNvbW1hbmQSEgoKY29tbWFuZF9pZBgBIAEoCRI0CglkZXZpY2VfaWQYAiABKAsyIS5rdXNpbnRhLmlvdC5pZGVudGl0eS52MS5EZXZpY2VJZBIWCg5jbHVzdGVyX2lkX2hleBgDIAEoCRIUCgxjb21tYW5kX25hbWUYBCABKAkSTgoTdGhlcm1vc3RhdF9zZXRwb2ludBgFIAEoCzIvLmt1c2ludGEuaW90LndlYnJ0Yy52MS5UaGVybW9zdGF0U2V0cG9pbnRQYXJhbXNIABJCCg1sZXZlbF9jb250cm9sGAYgASgLMikua3VzaW50YS5pb3Qud2VicnRjLnYxLkxldmVsQ29udHJvbFBhcmFtc0gAEjQKBm9uX29mZhgHIAEoCzIiLmt1c2ludGEuaW90LndlYnJ0Yy52MS5Pbk9mZlBhcmFtc0gAEk8KFHdpbmRvd19jb3ZlcmluZ19saWZ0GAggASgLMi8ua3VzaW50YS5pb3Qud2VicnRjLnYxLldpbmRvd0NvdmVyaW5nTGlmdFBhcmFtc0gAEjoKCWRvb3JfbG9jaxgJIAEoCzIlLmt1c2ludGEuaW90LndlYnJ0Yy52MS5Eb29yTG9ja1BhcmFtc0gAEhEKB3Jhd190bHYYYyABKAxIAEIMCgpwYXJhbWV0ZXJzIi0KDENvbW1hbmRFcnJvchIMCgRjb2RlGAEgASgJEg8KB21lc3NhZ2UYAiABKAkimgEKDUNvbW1hbmRSZXN1bHQSEgoKY29tbWFuZF9pZBgBIAEoCRIPCgdzdWNjZXNzGAIgASgIEjIKBWVycm9yGAMgASgLMiMua3VzaW50YS5pb3Qud2VicnRjLnYxLkNvbW1hbmRFcnJvchIwCgxjb21wbGV0ZWRfYXQYBCABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wQgJIAWIGcHJvdG8z", [file_google_protobuf_timestamp, file_kusinta_iot_identity_v1_identity]);
17
+ fileDesc("CiNrdXNpbnRhL2lvdC93ZWJydGMvdjEvY29tbWFuZC5wcm90bxIVa3VzaW50YS5pb3Qud2VicnRjLnYxInwKGFRoZXJtb3N0YXRTZXRwb2ludFBhcmFtcxI8CgRtb2RlGAEgASgOMikua3VzaW50YS5pb3Qud2VicnRjLnYxLlNldHBvaW50QWRqdXN0TW9kZUgAiAEBEg4KBmFtb3VudBgCIAEoEToJuLUYgQTAtRgAQgcKBV9tb2RlIkYKEkxldmVsQ29udHJvbFBhcmFtcxINCgVsZXZlbBgBIAEoDRIXCg90cmFuc2l0aW9uX3RpbWUYAiABKA06CLi1GAjAtRgAIisKC09uT2ZmUGFyYW1zOgS4tRgGSgQIARACSgQIAhADUgJvblIGdG9nZ2xlIkEKGFdpbmRvd0NvdmVyaW5nTGlmdFBhcmFtcxIaChJsaWZ0X3BlcmNlbnQxMDB0aHMYASABKA06Cbi1GIICwLUYBSI7Cg5Eb29yTG9ja1BhcmFtcxIQCghwaW5fY29kZRgCIAEoCToFuLUYgQJKBAgBEAJSCmxvY2tfc3RhdGUikgUKDURldmljZUNvbW1hbmQSEgoKcmVxdWVzdF9pZBgBIAEoCRI0CglkZXZpY2VfaWQYAiABKAsyIS5rdXNpbnRhLmlvdC5pZGVudGl0eS52MS5EZXZpY2VJZBIUCgxjb21tYW5kX25hbWUYBCABKAkSEgoKY2x1c3Rlcl9pZBgMIAEoDRIeChFtYXR0ZXJfY29tbWFuZF9pZBgNIAEoDUgBiAEBEhgKC2VuZHBvaW50X2lkGAsgASgNSAKIAQESTgoTdGhlcm1vc3RhdF9zZXRwb2ludBgFIAEoCzIvLmt1c2ludGEuaW90LndlYnJ0Yy52MS5UaGVybW9zdGF0U2V0cG9pbnRQYXJhbXNIABJCCg1sZXZlbF9jb250cm9sGAYgASgLMikua3VzaW50YS5pb3Qud2VicnRjLnYxLkxldmVsQ29udHJvbFBhcmFtc0gAEjQKBm9uX29mZhgHIAEoCzIiLmt1c2ludGEuaW90LndlYnJ0Yy52MS5Pbk9mZlBhcmFtc0gAEk8KFHdpbmRvd19jb3ZlcmluZ19saWZ0GAggASgLMi8ua3VzaW50YS5pb3Qud2VicnRjLnYxLldpbmRvd0NvdmVyaW5nTGlmdFBhcmFtc0gAEjoKCWRvb3JfbG9jaxgJIAEoCzIlLmt1c2ludGEuaW90LndlYnJ0Yy52MS5Eb29yTG9ja1BhcmFtc0gAEhEKB3Jhd190bHYYYyABKAxIAEIMCgpwYXJhbWV0ZXJzQhQKEl9tYXR0ZXJfY29tbWFuZF9pZEIOCgxfZW5kcG9pbnRfaWRKBAgDEARKBAgKEAtSDmNsdXN0ZXJfaWRfaGV4Uhl0aGVybW9zdGF0X3NldHBvaW50X3dyaXRlIlwKDENvbW1hbmRFcnJvchIPCgdtZXNzYWdlGAIgASgJEjUKBGNvZGUYAyABKA4yJy5rdXNpbnRhLmlvdC53ZWJydGMudjEuQ29tbWFuZEVycm9yQ29kZUoECAEQAiLeAQoNQ29tbWFuZFJlc3VsdBISCgpyZXF1ZXN0X2lkGAEgASgJEg8KB3N1Y2Nlc3MYAiABKAgSMgoFZXJyb3IYAyABKAsyIy5rdXNpbnRhLmlvdC53ZWJydGMudjEuQ29tbWFuZEVycm9yEjAKDGNvbXBsZXRlZF9hdBgEIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASMwoKc2V0dGxlc19ieRgFIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXBIAIgBAUINCgtfc2V0dGxlc19ieSLMAQoVQXR0cmlidXRlV3JpdGVSZXF1ZXN0EhIKCnJlcXVlc3RfaWQYASABKAkSNAoJZGV2aWNlX2lkGAIgASgLMiEua3VzaW50YS5pb3QuaWRlbnRpdHkudjEuRGV2aWNlSWQSMwoGdGFyZ2V0GAMgASgLMiMua3VzaW50YS5pb3QuYWNjZXNzLnYxLkF0dHJpYnV0ZVJlZhI0CgV2YWx1ZRgEIAEoCzIlLmt1c2ludGEuaW90LmRldmljZS52MS5BdHRyaWJ1dGVWYWx1ZSq/AgoQQ29tbWFuZEVycm9yQ29kZRIiCh5DT01NQU5EX0VSUk9SX0NPREVfVU5TUEVDSUZJRUQQABIjCh9DT01NQU5EX0VSUk9SX0NPREVfTk9UX0VOVElUTEVEEAESKgomQ09NTUFORF9FUlJPUl9DT0RFX0NPTlNUUkFJTlRfVklPTEFURUQQAhImCiJDT01NQU5EX0VSUk9SX0NPREVfSU5WQUxJRF9DT01NQU5EEAMSIgoeQ09NTUFORF9FUlJPUl9DT0RFX1VOUkVBQ0hBQkxFEAQSHgoaQ09NTUFORF9FUlJPUl9DT0RFX1RJTUVPVVQQBRIpCiVDT01NQU5EX0VSUk9SX0NPREVfUkVKRUNURURfQllfREVWSUNFEAYSHwobQ09NTUFORF9FUlJPUl9DT0RFX0lOVEVSTkFMEAdCAkgBYgZwcm90bzM", [file_google_protobuf_timestamp, file_kusinta_iot_access_v1_acl, file_kusinta_iot_device_v1_cluster_state, file_kusinta_iot_device_v1_matter_options, file_kusinta_iot_identity_v1_identity, file_kusinta_iot_webrtc_v1_setpoint_mode]);
14
18
 
15
19
  /**
16
20
  * Describes the message kusinta.iot.webrtc.v1.ThermostatSetpointParams.
@@ -68,3 +72,26 @@ export const CommandErrorSchema = /*@__PURE__*/
68
72
  export const CommandResultSchema = /*@__PURE__*/
69
73
  messageDesc(file_kusinta_iot_webrtc_v1_command, 7);
70
74
 
75
+ /**
76
+ * Describes the message kusinta.iot.webrtc.v1.AttributeWriteRequest.
77
+ * Use `create(AttributeWriteRequestSchema)` to create a new message.
78
+ */
79
+ export const AttributeWriteRequestSchema = /*@__PURE__*/
80
+ messageDesc(file_kusinta_iot_webrtc_v1_command, 8);
81
+
82
+ /**
83
+ * Describes the enum kusinta.iot.webrtc.v1.CommandErrorCode.
84
+ */
85
+ export const CommandErrorCodeSchema = /*@__PURE__*/
86
+ enumDesc(file_kusinta_iot_webrtc_v1_command, 0);
87
+
88
+ /**
89
+ * Why a command was refused or failed, so an app can branch without string-matching a
90
+ * human sentence. Closed vocabulary for the same reason as GatewayErrorCode: the app leg
91
+ * is versioned together with the gateway, so clients can switch exhaustively.
92
+ *
93
+ * @generated from enum kusinta.iot.webrtc.v1.CommandErrorCode
94
+ */
95
+ export const CommandErrorCode = /*@__PURE__*/
96
+ tsEnum(CommandErrorCodeSchema);
97
+