@fleetless/contracts 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (287) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +17 -0
  4. package/README.md +88 -0
  5. package/artifacts/constants.json +24 -0
  6. package/artifacts/openapi.json +17219 -0
  7. package/artifacts/routes.json +4605 -0
  8. package/artifacts/schema/accept-team-invite-request.schema.json +22 -0
  9. package/artifacts/schema/action-config.schema.json +198 -0
  10. package/artifacts/schema/alert-list-response.schema.json +172 -0
  11. package/artifacts/schema/api-error.schema.json +20 -0
  12. package/artifacts/schema/app-auth-config.schema.json +106 -0
  13. package/artifacts/schema/app-invitation-list-response.schema.json +57 -0
  14. package/artifacts/schema/app-invitation.schema.json +69 -0
  15. package/artifacts/schema/app-list-response.schema.json +82 -0
  16. package/artifacts/schema/app-mail-template-list-response.schema.json +68 -0
  17. package/artifacts/schema/app-mail-template.schema.json +54 -0
  18. package/artifacts/schema/app-oidc-provider-list-response.schema.json +93 -0
  19. package/artifacts/schema/app-oidc-provider.schema.json +80 -0
  20. package/artifacts/schema/app-user-list-response.schema.json +111 -0
  21. package/artifacts/schema/app-user.schema.json +98 -0
  22. package/artifacts/schema/app.schema.json +69 -0
  23. package/artifacts/schema/apply-error.schema.json +41 -0
  24. package/artifacts/schema/asset-list-response.schema.json +288 -0
  25. package/artifacts/schema/asset-sync-request.schema.json +17 -0
  26. package/artifacts/schema/asset-sync-response.schema.json +16 -0
  27. package/artifacts/schema/asset-sync-status.schema.json +136 -0
  28. package/artifacts/schema/asset.schema.json +68 -0
  29. package/artifacts/schema/audit-actor.schema.json +32 -0
  30. package/artifacts/schema/audit-event.schema.json +119 -0
  31. package/artifacts/schema/audit-list-response.schema.json +144 -0
  32. package/artifacts/schema/audit-query.schema.json +79 -0
  33. package/artifacts/schema/auth-error.schema.json +23 -0
  34. package/artifacts/schema/auth-me-response.schema.json +99 -0
  35. package/artifacts/schema/auth-ok.schema.json +115 -0
  36. package/artifacts/schema/authorization-server-metadata.schema.json +80 -0
  37. package/artifacts/schema/bridge-asset-progress.schema.json +99 -0
  38. package/artifacts/schema/bridge-assets-available.schema.json +25 -0
  39. package/artifacts/schema/bridge-camera-state.schema.json +78 -0
  40. package/artifacts/schema/bridge-config-applied.schema.json +67 -0
  41. package/artifacts/schema/bridge-hello.schema.json +65 -0
  42. package/artifacts/schema/bridge-introspect.schema.json +114 -0
  43. package/artifacts/schema/bridge-job-lost.schema.json +22 -0
  44. package/artifacts/schema/bridge-job-update.schema.json +100 -0
  45. package/artifacts/schema/bridge-pong.schema.json +19 -0
  46. package/artifacts/schema/bridge-pressure.schema.json +292 -0
  47. package/artifacts/schema/bridge-state.schema.json +24 -0
  48. package/artifacts/schema/bridge-type-definitions.schema.json +169 -0
  49. package/artifacts/schema/busy-details.schema.json +115 -0
  50. package/artifacts/schema/camera-descriptor.schema.json +45 -0
  51. package/artifacts/schema/camera-list-response.schema.json +58 -0
  52. package/artifacts/schema/camera-source.schema.json +240 -0
  53. package/artifacts/schema/cancel-request.schema.json +20 -0
  54. package/artifacts/schema/client-accept-invitation-request.schema.json +35 -0
  55. package/artifacts/schema/client-auth.schema.json +18 -0
  56. package/artifacts/schema/client-cancel.schema.json +45 -0
  57. package/artifacts/schema/client-identity.schema.json +103 -0
  58. package/artifacts/schema/client-invoke.schema.json +45 -0
  59. package/artifacts/schema/client-login-request.schema.json +29 -0
  60. package/artifacts/schema/client-logout-request.schema.json +14 -0
  61. package/artifacts/schema/client-mcp-interaction-decision-response.schema.json +15 -0
  62. package/artifacts/schema/client-mcp-interaction.schema.json +59 -0
  63. package/artifacts/schema/client-oidc-callback-query.schema.json +28 -0
  64. package/artifacts/schema/client-oidc-exchange-request.schema.json +21 -0
  65. package/artifacts/schema/client-oidc-start-query.schema.json +36 -0
  66. package/artifacts/schema/client-password-reset-confirm-request.schema.json +22 -0
  67. package/artifacts/schema/client-password-reset-request.schema.json +24 -0
  68. package/artifacts/schema/client-provider-list-query.schema.json +17 -0
  69. package/artifacts/schema/client-provider-list-response.schema.json +34 -0
  70. package/artifacts/schema/client-publish.schema.json +40 -0
  71. package/artifacts/schema/client-refresh-request.schema.json +14 -0
  72. package/artifacts/schema/client-register-request.schema.json +44 -0
  73. package/artifacts/schema/client-resend-verification-request.schema.json +24 -0
  74. package/artifacts/schema/client-subscribe.schema.json +43 -0
  75. package/artifacts/schema/client-unsubscribe.schema.json +26 -0
  76. package/artifacts/schema/client-verify-email-request.schema.json +15 -0
  77. package/artifacts/schema/cloud-asset-request.schema.json +37 -0
  78. package/artifacts/schema/cloud-camera-start.schema.json +41 -0
  79. package/artifacts/schema/cloud-camera-stop.schema.json +26 -0
  80. package/artifacts/schema/cloud-cancel.schema.json +33 -0
  81. package/artifacts/schema/cloud-config.schema.json +1635 -0
  82. package/artifacts/schema/cloud-hello-error.schema.json +23 -0
  83. package/artifacts/schema/cloud-hello-ok.schema.json +19 -0
  84. package/artifacts/schema/cloud-introspect-request.schema.json +19 -0
  85. package/artifacts/schema/cloud-invoke.schema.json +40 -0
  86. package/artifacts/schema/cloud-ping.schema.json +19 -0
  87. package/artifacts/schema/cloud-publish.schema.json +28 -0
  88. package/artifacts/schema/cloud-type-request.schema.json +30 -0
  89. package/artifacts/schema/command-result.schema.json +175 -0
  90. package/artifacts/schema/config-draft-response.schema.json +1695 -0
  91. package/artifacts/schema/config-state.schema.json +124 -0
  92. package/artifacts/schema/config-version-response.schema.json +1641 -0
  93. package/artifacts/schema/config-versions-response.schema.json +33 -0
  94. package/artifacts/schema/create-app-invitation-request.schema.json +40 -0
  95. package/artifacts/schema/create-app-oidc-provider-request.schema.json +70 -0
  96. package/artifacts/schema/create-app-request.schema.json +30 -0
  97. package/artifacts/schema/create-app-user-request.schema.json +42 -0
  98. package/artifacts/schema/create-robot-request.schema.json +14 -0
  99. package/artifacts/schema/create-robot-response.schema.json +44 -0
  100. package/artifacts/schema/create-server-key-response.schema.json +65 -0
  101. package/artifacts/schema/create-team-invite-request.schema.json +43 -0
  102. package/artifacts/schema/datapoint-alert-row.schema.json +160 -0
  103. package/artifacts/schema/datapoint-config.schema.json +366 -0
  104. package/artifacts/schema/datapoint-display.schema.json +31 -0
  105. package/artifacts/schema/datapoint-event.schema.json +34 -0
  106. package/artifacts/schema/datapoint-frame.schema.json +28 -0
  107. package/artifacts/schema/datapoint-list-response.schema.json +61 -0
  108. package/artifacts/schema/datapoint-value.schema.json +28 -0
  109. package/artifacts/schema/developer-login-request.schema.json +19 -0
  110. package/artifacts/schema/dynamic-client-registration-request.schema.json +60 -0
  111. package/artifacts/schema/dynamic-client-registration-response.schema.json +68 -0
  112. package/artifacts/schema/error-frame.schema.json +23 -0
  113. package/artifacts/schema/exposure-counts.schema.json +39 -0
  114. package/artifacts/schema/exposure-list-response.schema.json +43 -0
  115. package/artifacts/schema/fetch-types-request.schema.json +19 -0
  116. package/artifacts/schema/fetch-types-response.schema.json +163 -0
  117. package/artifacts/schema/fleetless-user-list-response.schema.json +73 -0
  118. package/artifacts/schema/fleetless-user.schema.json +60 -0
  119. package/artifacts/schema/history-buckets-response.schema.json +79 -0
  120. package/artifacts/schema/history-query.schema.json +58 -0
  121. package/artifacts/schema/history-response.schema.json +150 -0
  122. package/artifacts/schema/history-samples-response.schema.json +68 -0
  123. package/artifacts/schema/introspection-response.schema.json +118 -0
  124. package/artifacts/schema/invoke-or-service-response.schema.json +141 -0
  125. package/artifacts/schema/invoke-request.schema.json +23 -0
  126. package/artifacts/schema/invoke-response.schema.json +125 -0
  127. package/artifacts/schema/job-actor.schema.json +34 -0
  128. package/artifacts/schema/job-event.schema.json +158 -0
  129. package/artifacts/schema/job-response.schema.json +123 -0
  130. package/artifacts/schema/job-run-list-response.schema.json +222 -0
  131. package/artifacts/schema/job-run-query.schema.json +95 -0
  132. package/artifacts/schema/job-run-summary-query.schema.json +23 -0
  133. package/artifacts/schema/job-run-summary.schema.json +33 -0
  134. package/artifacts/schema/job-run.schema.json +195 -0
  135. package/artifacts/schema/job-state.schema.json +11 -0
  136. package/artifacts/schema/job.schema.json +106 -0
  137. package/artifacts/schema/latency-bucket.schema.json +63 -0
  138. package/artifacts/schema/live-session-response.schema.json +41 -0
  139. package/artifacts/schema/mail-outcome.schema.json +20 -0
  140. package/artifacts/schema/mail-template-preview-request.schema.json +35 -0
  141. package/artifacts/schema/mail-template-preview-response.schema.json +31 -0
  142. package/artifacts/schema/mail-template-problem-details.schema.json +24 -0
  143. package/artifacts/schema/mcp-consent-grant-list-response.schema.json +52 -0
  144. package/artifacts/schema/mcp-consent-grant.schema.json +39 -0
  145. package/artifacts/schema/mcp-robot-datasheet.schema.json +115 -0
  146. package/artifacts/schema/mcp-role-preview-response.schema.json +134 -0
  147. package/artifacts/schema/missing-asset-query.schema.json +11 -0
  148. package/artifacts/schema/oauth-authorize-query.schema.json +47 -0
  149. package/artifacts/schema/oauth-redirect-response.schema.json +15 -0
  150. package/artifacts/schema/oauth-token-request.schema.json +47 -0
  151. package/artifacts/schema/oauth-token-response.schema.json +38 -0
  152. package/artifacts/schema/org-alerts-query.schema.json +15 -0
  153. package/artifacts/schema/org-event-dropped.schema.json +26 -0
  154. package/artifacts/schema/org-event-replay.schema.json +97 -0
  155. package/artifacts/schema/org-event-subscribe.schema.json +14 -0
  156. package/artifacts/schema/org-event-unsubscribe.schema.json +14 -0
  157. package/artifacts/schema/org-event.schema.json +75 -0
  158. package/artifacts/schema/org-firing-alerts-response.schema.json +178 -0
  159. package/artifacts/schema/org-health-query.schema.json +13 -0
  160. package/artifacts/schema/org-latency-query.schema.json +42 -0
  161. package/artifacts/schema/org-latency-response.schema.json +124 -0
  162. package/artifacts/schema/org-quota-usage-counts.schema.json +42 -0
  163. package/artifacts/schema/org-quota-usage.schema.json +102 -0
  164. package/artifacts/schema/org-quotas.schema.json +51 -0
  165. package/artifacts/schema/org-usage-query.schema.json +19 -0
  166. package/artifacts/schema/org-usage-response.schema.json +77 -0
  167. package/artifacts/schema/org.schema.json +30 -0
  168. package/artifacts/schema/parameter-invalid-details.schema.json +37 -0
  169. package/artifacts/schema/parameter-spec.schema.json +120 -0
  170. package/artifacts/schema/parameter-violation.schema.json +24 -0
  171. package/artifacts/schema/password-change-request.schema.json +21 -0
  172. package/artifacts/schema/password-reset-confirm.schema.json +19 -0
  173. package/artifacts/schema/password-reset-request.schema.json +14 -0
  174. package/artifacts/schema/patch-app-oidc-provider-request.schema.json +50 -0
  175. package/artifacts/schema/patch-app-user-request.schema.json +34 -0
  176. package/artifacts/schema/patch-auth-me-request.schema.json +22 -0
  177. package/artifacts/schema/patch-fleetless-user-request.schema.json +20 -0
  178. package/artifacts/schema/patch-org-request.schema.json +15 -0
  179. package/artifacts/schema/patch-org-response.schema.json +40 -0
  180. package/artifacts/schema/patch-robot-request.schema.json +15 -0
  181. package/artifacts/schema/patch-robot-response.schema.json +40 -0
  182. package/artifacts/schema/pending-team-invite-list-response.schema.json +52 -0
  183. package/artifacts/schema/pending-team-invite.schema.json +39 -0
  184. package/artifacts/schema/protected-resource-metadata.schema.json +41 -0
  185. package/artifacts/schema/publish-config-response.schema.json +21 -0
  186. package/artifacts/schema/publish-request.schema.json +17 -0
  187. package/artifacts/schema/publisher-config.schema.json +285 -0
  188. package/artifacts/schema/put-app-auth-config-request.schema.json +93 -0
  189. package/artifacts/schema/put-app-mail-template-request.schema.json +35 -0
  190. package/artifacts/schema/put-config-draft-request.schema.json +13 -0
  191. package/artifacts/schema/put-datapoint-display-request.schema.json +31 -0
  192. package/artifacts/schema/put-robot-details-request.schema.json +41 -0
  193. package/artifacts/schema/put-robot-details-response.schema.json +43 -0
  194. package/artifacts/schema/rate-limit-details.schema.json +15 -0
  195. package/artifacts/schema/refresh-request.schema.json +13 -0
  196. package/artifacts/schema/release-live-query.schema.json +13 -0
  197. package/artifacts/schema/rename-slug-request.schema.json +23 -0
  198. package/artifacts/schema/rename-slug-response.schema.json +24 -0
  199. package/artifacts/schema/resource-health-event.schema.json +72 -0
  200. package/artifacts/schema/resource-health-list-response.schema.json +80 -0
  201. package/artifacts/schema/resource-health-state.schema.json +68 -0
  202. package/artifacts/schema/robot-config-doc.schema.json +1616 -0
  203. package/artifacts/schema/robot-delete-query.schema.json +12 -0
  204. package/artifacts/schema/robot-deletion-summary.schema.json +63 -0
  205. package/artifacts/schema/robot-detail-response.schema.json +262 -0
  206. package/artifacts/schema/robot-details-doc.schema.json +33 -0
  207. package/artifacts/schema/robot-jobs-response.schema.json +119 -0
  208. package/artifacts/schema/robot-latency-series.schema.json +81 -0
  209. package/artifacts/schema/robot-list-item.schema.json +94 -0
  210. package/artifacts/schema/robot-list-response.schema.json +106 -0
  211. package/artifacts/schema/robot.schema.json +30 -0
  212. package/artifacts/schema/role-list-response.schema.json +48 -0
  213. package/artifacts/schema/role-permissions.schema.json +61 -0
  214. package/artifacts/schema/role.schema.json +35 -0
  215. package/artifacts/schema/ros-graph.schema.json +99 -0
  216. package/artifacts/schema/server-key-list-response.schema.json +64 -0
  217. package/artifacts/schema/server-key.schema.json +51 -0
  218. package/artifacts/schema/service-call-response.schema.json +13 -0
  219. package/artifacts/schema/service-config.schema.json +198 -0
  220. package/artifacts/schema/session-tokens.schema.json +28 -0
  221. package/artifacts/schema/sign-up-request.schema.json +26 -0
  222. package/artifacts/schema/sign-up-response.schema.json +127 -0
  223. package/artifacts/schema/slug-usage-response.schema.json +32 -0
  224. package/artifacts/schema/snapshot-header.schema.json +44 -0
  225. package/artifacts/schema/snapshot-meta-response.schema.json +85 -0
  226. package/artifacts/schema/subscribe-error.schema.json +31 -0
  227. package/artifacts/schema/team-invite.schema.json +57 -0
  228. package/artifacts/schema/tier-change-request.schema.json +17 -0
  229. package/artifacts/schema/type-definition.schema.json +144 -0
  230. package/artifacts/schema/types-response.schema.json +156 -0
  231. package/artifacts/schema/update-app-request.schema.json +32 -0
  232. package/artifacts/schema/urdf-completeness.schema.json +50 -0
  233. package/artifacts/schema/validation-issue.schema.json +43 -0
  234. package/artifacts/schema/waitlist-request.schema.json +15 -0
  235. package/artifacts/schema-outgoing/bridge-asset-progress.schema.json +102 -0
  236. package/artifacts/schema-outgoing/bridge-assets-available.schema.json +26 -0
  237. package/artifacts/schema-outgoing/bridge-camera-state.schema.json +80 -0
  238. package/artifacts/schema-outgoing/bridge-config-applied.schema.json +69 -0
  239. package/artifacts/schema-outgoing/bridge-hello.schema.json +68 -0
  240. package/artifacts/schema-outgoing/bridge-introspect.schema.json +119 -0
  241. package/artifacts/schema-outgoing/bridge-job-lost.schema.json +23 -0
  242. package/artifacts/schema-outgoing/bridge-job-update.schema.json +102 -0
  243. package/artifacts/schema-outgoing/bridge-pong.schema.json +20 -0
  244. package/artifacts/schema-outgoing/bridge-type-definitions.schema.json +174 -0
  245. package/artifacts/schema-outgoing/datapoint-frame.schema.json +29 -0
  246. package/artifacts/schema-outgoing/snapshot-header.schema.json +45 -0
  247. package/dist/alerts.d.ts +255 -0
  248. package/dist/alerts.js +193 -0
  249. package/dist/app-users.d.ts +606 -0
  250. package/dist/app-users.js +696 -0
  251. package/dist/apps.d.ts +175 -0
  252. package/dist/apps.js +267 -0
  253. package/dist/assets.d.ts +434 -0
  254. package/dist/assets.js +546 -0
  255. package/dist/audit.d.ts +129 -0
  256. package/dist/audit.js +238 -0
  257. package/dist/client-auth.d.ts +409 -0
  258. package/dist/client-auth.js +487 -0
  259. package/dist/common.d.ts +186 -0
  260. package/dist/common.js +199 -0
  261. package/dist/config-issues.d.ts +175 -0
  262. package/dist/config-issues.js +339 -0
  263. package/dist/config.d.ts +862 -0
  264. package/dist/config.js +1988 -0
  265. package/dist/errors.d.ts +52 -0
  266. package/dist/errors.js +786 -0
  267. package/dist/identity.d.ts +549 -0
  268. package/dist/identity.js +503 -0
  269. package/dist/index.d.ts +51 -0
  270. package/dist/index.js +51 -0
  271. package/dist/introspection.d.ts +99 -0
  272. package/dist/introspection.js +97 -0
  273. package/dist/jobs.d.ts +334 -0
  274. package/dist/jobs.js +345 -0
  275. package/dist/mcp.d.ts +239 -0
  276. package/dist/mcp.js +153 -0
  277. package/dist/oauth.d.ts +344 -0
  278. package/dist/oauth.js +488 -0
  279. package/dist/protocol.d.ts +781 -0
  280. package/dist/protocol.js +715 -0
  281. package/dist/realtime.d.ts +494 -0
  282. package/dist/realtime.js +512 -0
  283. package/dist/rest.d.ts +1989 -0
  284. package/dist/rest.js +1963 -0
  285. package/dist/routes.d.ts +94 -0
  286. package/dist/routes.js +2298 -0
  287. package/package.json +61 -0
package/dist/rest.d.ts ADDED
@@ -0,0 +1,1989 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * REST shapes of the robot resource (spec §11.1). W1 scope: create, list,
4
+ * get, and the built-in `bridge_state` datapoint read.
5
+ */
6
+ export declare const robot: z.ZodObject<{
7
+ id: z.ZodUUID;
8
+ name: z.ZodString;
9
+ created_at: z.ZodISODateTime;
10
+ }, z.core.$strip>;
11
+ export type Robot = z.infer<typeof robot>;
12
+ /** What `PATCH /api/robots/:id` answers: the robot as it now stands. */
13
+ export declare const patchRobotResponse: z.ZodObject<{
14
+ robot: z.ZodObject<{
15
+ id: z.ZodUUID;
16
+ name: z.ZodString;
17
+ created_at: z.ZodISODateTime;
18
+ }, z.core.$strip>;
19
+ }, z.core.$strip>;
20
+ export type PatchRobotResponse = z.infer<typeof patchRobotResponse>;
21
+ export declare const createRobotRequest: z.ZodObject<{
22
+ name: z.ZodString;
23
+ }, z.core.$strip>;
24
+ export type CreateRobotRequest = z.infer<typeof createRobotRequest>;
25
+ /**
26
+ * The robot token binds one bridge to one robot (spec §5). It is returned
27
+ * exactly once, here; the cloud stores only a hash of it.
28
+ */
29
+ export declare const robotToken: z.ZodString;
30
+ export declare const createRobotResponse: z.ZodObject<{
31
+ robot: z.ZodObject<{
32
+ id: z.ZodUUID;
33
+ name: z.ZodString;
34
+ created_at: z.ZodISODateTime;
35
+ }, z.core.$strip>;
36
+ token: z.ZodString;
37
+ }, z.core.$strip>;
38
+ export type CreateRobotResponse = z.infer<typeof createRobotResponse>;
39
+ /**
40
+ * How many things a robot exposes, per kind (spec `2026-08-21-exposure-and-revoke-design` D1).
41
+ *
42
+ * **Five numbers, never a sum.** `robotDeletionSummary.slug_count` already made
43
+ * this call and wrote down why: fold cameras in and the sentence "this deletes
44
+ * N slugs and M cameras" counts them twice. A list row has the same problem.
45
+ *
46
+ * **Counted from the published configuration, and excluding the built-ins.**
47
+ * `GET /api/robots/:id/exposures` answers *which* slugs and prepends the
48
+ * three built-in datapoints — `bridge_state`, `robot_details` and
49
+ * `bridge_pressure` — as `builtin: true`; this answers *how many* and counts
50
+ * only what somebody configured. So a robot with an empty published config
51
+ * reports `datapoints: 0` here and three entries there. That is intentional,
52
+ * and it is written on both sides so the disagreement is never mistaken for a
53
+ * bug.
54
+ *
55
+ * The number is "three" and not "two" as of `bridge_pressure`; the cloud
56
+ * builds that prefix from `PLANE_BUILTIN_DATAPOINTS` rather than a literal,
57
+ * so a further built-in moves this count again. Read the count off that set,
58
+ * not off this sentence, before filing the bug this comment exists to
59
+ * prevent.
60
+ */
61
+ export declare const exposureCounts: z.ZodObject<{
62
+ datapoints: z.ZodNumber;
63
+ actions: z.ZodNumber;
64
+ services: z.ZodNumber;
65
+ publishers: z.ZodNumber;
66
+ cameras: z.ZodNumber;
67
+ }, z.core.$strip>;
68
+ export type ExposureCounts = z.infer<typeof exposureCounts>;
69
+ /** A robot as listed, with its current built-in `bridge_state`. */
70
+ export declare const robotListItem: z.ZodObject<{
71
+ bridge_state: z.ZodObject<{
72
+ online: z.ZodBoolean;
73
+ latency_ms: z.ZodNullable<z.ZodNumber>;
74
+ }, z.core.$strip>;
75
+ exposes: z.ZodObject<{
76
+ datapoints: z.ZodNumber;
77
+ actions: z.ZodNumber;
78
+ services: z.ZodNumber;
79
+ publishers: z.ZodNumber;
80
+ cameras: z.ZodNumber;
81
+ }, z.core.$strip>;
82
+ id: z.ZodUUID;
83
+ name: z.ZodString;
84
+ created_at: z.ZodISODateTime;
85
+ }, z.core.$strip>;
86
+ export type RobotListItem = z.infer<typeof robotListItem>;
87
+ export declare const robotListResponse: z.ZodObject<{
88
+ robots: z.ZodArray<z.ZodObject<{
89
+ bridge_state: z.ZodObject<{
90
+ online: z.ZodBoolean;
91
+ latency_ms: z.ZodNullable<z.ZodNumber>;
92
+ }, z.core.$strip>;
93
+ exposes: z.ZodObject<{
94
+ datapoints: z.ZodNumber;
95
+ actions: z.ZodNumber;
96
+ services: z.ZodNumber;
97
+ publishers: z.ZodNumber;
98
+ cameras: z.ZodNumber;
99
+ }, z.core.$strip>;
100
+ id: z.ZodUUID;
101
+ name: z.ZodString;
102
+ created_at: z.ZodISODateTime;
103
+ }, z.core.$strip>>;
104
+ }, z.core.$strip>;
105
+ export type RobotListResponse = z.infer<typeof robotListResponse>;
106
+ /**
107
+ * The REST read of one datapoint. For bridge-captured data `timestamp_ms`
108
+ * is the capture time at the bridge (spec §6.3); for the cloud-observed
109
+ * built-in `bridge_state` it is the time the cloud observed the state.
110
+ */
111
+ export declare const datapointValue: z.ZodObject<{
112
+ slug: z.ZodString;
113
+ value: z.ZodUnknown;
114
+ timestamp_ms: z.ZodNumber;
115
+ }, z.core.$strip>;
116
+ export type DatapointValue = z.infer<typeof datapointValue>;
117
+ /**
118
+ * One robot in full: what the list shows, plus what only the detail view
119
+ * needs — which bridge build is connected, why the last hello was refused,
120
+ * and where the configuration stands (spec §15.2, tab 1).
121
+ */
122
+ export declare const robotDetailResponse: z.ZodObject<{
123
+ bridge_version: z.ZodNullable<z.ZodString>;
124
+ last_hello_error: z.ZodNullable<z.ZodObject<{
125
+ code: z.ZodString;
126
+ message: z.ZodString;
127
+ at: z.ZodISODateTime;
128
+ }, z.core.$strip>>;
129
+ config: z.ZodObject<{
130
+ published_version: z.ZodNullable<z.ZodNumber>;
131
+ published_at: z.ZodNullable<z.ZodISODateTime>;
132
+ draft_updated_at: z.ZodNullable<z.ZodISODateTime>;
133
+ applied_version: z.ZodNullable<z.ZodNumber>;
134
+ applied_ok: z.ZodNullable<z.ZodBoolean>;
135
+ applied_errors: z.ZodNullable<z.ZodArray<z.ZodObject<{
136
+ slug: z.ZodString;
137
+ kind: z.ZodEnum<{
138
+ datapoint: "datapoint";
139
+ action: "action";
140
+ service: "service";
141
+ publisher: "publisher";
142
+ camera: "camera";
143
+ }>;
144
+ code: z.ZodString;
145
+ message: z.ZodString;
146
+ details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
147
+ }, z.core.$strip>>>;
148
+ }, z.core.$strip>;
149
+ bridge_state: z.ZodObject<{
150
+ online: z.ZodBoolean;
151
+ latency_ms: z.ZodNullable<z.ZodNumber>;
152
+ }, z.core.$strip>;
153
+ exposes: z.ZodObject<{
154
+ datapoints: z.ZodNumber;
155
+ actions: z.ZodNumber;
156
+ services: z.ZodNumber;
157
+ publishers: z.ZodNumber;
158
+ cameras: z.ZodNumber;
159
+ }, z.core.$strip>;
160
+ id: z.ZodUUID;
161
+ name: z.ZodString;
162
+ created_at: z.ZodISODateTime;
163
+ }, z.core.$strip>;
164
+ export type RobotDetailResponse = z.infer<typeof robotDetailResponse>;
165
+ /**
166
+ * The editable configuration. `issues` is recomputed on every read and
167
+ * write, so the editor never has to guess whether it may publish.
168
+ *
169
+ * **`source` is the author's text and `doc` is what it parses to.** Both are
170
+ * sent because they answer different questions: an editor renders the text a
171
+ * developer wrote, comments and key order intact, while every other consumer —
172
+ * the robot page, the MCP tools, the bridge frame — reads the parsed document
173
+ * and should never have to parse YAML to do it.
174
+ *
175
+ * **`doc` is null when the text is valid YAML but not a fleetless document.**
176
+ * A draft is saved whenever it parses as YAML; publish is the gate that asks
177
+ * for a document. So a stored draft can genuinely have no document, and `null`
178
+ * says exactly that: *this text does not currently parse to a configuration*.
179
+ * It does **not** mean "nothing is configured" — the last published version is
180
+ * untouched — and a reader that renders a tree from `doc` has to tell those two
181
+ * apart before it draws anything.
182
+ *
183
+ * The alternative was to put the raw parsed YAML value in `doc`. It was
184
+ * rejected because a reader could then no longer tell whether what it holds is
185
+ * a document: every consumer would have to re-validate to find out, and the one
186
+ * that forgot would render a stranger's mapping as a configuration. `null`
187
+ * forces the question at the point of reading.
188
+ *
189
+ * `source` is never null, and that is what makes the pair `doc: null,
190
+ * source: null` unrepresentable here rather than merely discouraged. A draft
191
+ * exists from the moment a robot does, before anyone has typed anything; for
192
+ * that one the server renders the document instead, so a reader always has text
193
+ * to show and — when there is no document — always has the text that failed to
194
+ * become one.
195
+ */
196
+ export declare const configDraftResponse: z.ZodObject<{
197
+ doc: z.ZodNullable<z.ZodObject<{
198
+ fleetless: z.ZodLiteral<1>;
199
+ messages: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
200
+ datapoints: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
201
+ topic: z.ZodString;
202
+ type: z.ZodString;
203
+ field: z.ZodOptional<z.ZodString>;
204
+ rate_throttle_hz: z.ZodOptional<z.ZodNumber>;
205
+ description: z.ZodOptional<z.ZodString>;
206
+ numeric: z.ZodOptional<z.ZodObject<{
207
+ scale: z.ZodOptional<z.ZodNumber>;
208
+ offset: z.ZodOptional<z.ZodNumber>;
209
+ unit: z.ZodOptional<z.ZodString>;
210
+ decimals: z.ZodOptional<z.ZodNumber>;
211
+ }, z.core.$strict>>;
212
+ retention: z.ZodOptional<z.ZodObject<{
213
+ enabled: z.ZodOptional<z.ZodBoolean>;
214
+ interval_seconds: z.ZodOptional<z.ZodNumber>;
215
+ max_buffer_values: z.ZodOptional<z.ZodNumber>;
216
+ }, z.core.$strict>>;
217
+ chart: z.ZodOptional<z.ZodObject<{
218
+ y_min: z.ZodOptional<z.ZodNumber>;
219
+ y_max: z.ZodOptional<z.ZodNumber>;
220
+ style: z.ZodOptional<z.ZodEnum<{
221
+ line: "line";
222
+ step: "step";
223
+ }>>;
224
+ default_window_minutes: z.ZodOptional<z.ZodNumber>;
225
+ }, z.core.$strict>>;
226
+ alerts: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
227
+ condition: z.ZodObject<{
228
+ fire_at: z.ZodUnion<readonly [z.ZodNumber, z.ZodString, z.ZodBoolean]>;
229
+ resolve_at: z.ZodOptional<z.ZodNumber>;
230
+ }, z.core.$strict>;
231
+ severity: z.ZodOptional<z.ZodEnum<{
232
+ error: "error";
233
+ warning: "warning";
234
+ }>>;
235
+ name: z.ZodOptional<z.ZodString>;
236
+ enabled: z.ZodOptional<z.ZodBoolean>;
237
+ }, z.core.$strict>>>;
238
+ }, z.core.$strict>>>;
239
+ actions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
240
+ ros_name: z.ZodString;
241
+ type: z.ZodString;
242
+ message: z.ZodOptional<z.ZodUnknown>;
243
+ parameters: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
244
+ type: z.ZodEnum<{
245
+ string: "string";
246
+ bool: "bool";
247
+ byte: "byte";
248
+ char: "char";
249
+ int8: "int8";
250
+ uint8: "uint8";
251
+ int16: "int16";
252
+ uint16: "uint16";
253
+ int32: "int32";
254
+ uint32: "uint32";
255
+ int64: "int64";
256
+ uint64: "uint64";
257
+ float32: "float32";
258
+ float64: "float64";
259
+ wstring: "wstring";
260
+ }>;
261
+ default: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodString, z.ZodBoolean]>>;
262
+ min_value: z.ZodOptional<z.ZodNumber>;
263
+ max_value: z.ZodOptional<z.ZodNumber>;
264
+ enum: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
265
+ regex: z.ZodOptional<z.ZodString>;
266
+ description: z.ZodOptional<z.ZodString>;
267
+ }, z.core.$strict>>>;
268
+ description: z.ZodOptional<z.ZodString>;
269
+ }, z.core.$strict>>>;
270
+ services: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
271
+ ros_name: z.ZodString;
272
+ type: z.ZodString;
273
+ message: z.ZodOptional<z.ZodUnknown>;
274
+ parameters: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
275
+ type: z.ZodEnum<{
276
+ string: "string";
277
+ bool: "bool";
278
+ byte: "byte";
279
+ char: "char";
280
+ int8: "int8";
281
+ uint8: "uint8";
282
+ int16: "int16";
283
+ uint16: "uint16";
284
+ int32: "int32";
285
+ uint32: "uint32";
286
+ int64: "int64";
287
+ uint64: "uint64";
288
+ float32: "float32";
289
+ float64: "float64";
290
+ wstring: "wstring";
291
+ }>;
292
+ default: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodString, z.ZodBoolean]>>;
293
+ min_value: z.ZodOptional<z.ZodNumber>;
294
+ max_value: z.ZodOptional<z.ZodNumber>;
295
+ enum: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
296
+ regex: z.ZodOptional<z.ZodString>;
297
+ description: z.ZodOptional<z.ZodString>;
298
+ }, z.core.$strict>>>;
299
+ description: z.ZodOptional<z.ZodString>;
300
+ }, z.core.$strict>>>;
301
+ publishers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
302
+ topic: z.ZodString;
303
+ type: z.ZodString;
304
+ message: z.ZodUnknown;
305
+ parameters: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
306
+ type: z.ZodEnum<{
307
+ string: "string";
308
+ bool: "bool";
309
+ byte: "byte";
310
+ char: "char";
311
+ int8: "int8";
312
+ uint8: "uint8";
313
+ int16: "int16";
314
+ uint16: "uint16";
315
+ int32: "int32";
316
+ uint32: "uint32";
317
+ int64: "int64";
318
+ uint64: "uint64";
319
+ float32: "float32";
320
+ float64: "float64";
321
+ wstring: "wstring";
322
+ }>;
323
+ default: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodString, z.ZodBoolean]>>;
324
+ min_value: z.ZodOptional<z.ZodNumber>;
325
+ max_value: z.ZodOptional<z.ZodNumber>;
326
+ enum: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
327
+ regex: z.ZodOptional<z.ZodString>;
328
+ description: z.ZodOptional<z.ZodString>;
329
+ }, z.core.$strict>>>;
330
+ failsafe: z.ZodObject<{
331
+ timeout_ms: z.ZodNumber;
332
+ message: z.ZodUnknown;
333
+ }, z.core.$strict>;
334
+ quiet_timeout_ms: z.ZodNumber;
335
+ description: z.ZodOptional<z.ZodString>;
336
+ }, z.core.$strict>>>;
337
+ cameras: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
338
+ source: z.ZodDiscriminatedUnion<[z.ZodObject<{
339
+ kind: z.ZodLiteral<"ros">;
340
+ topic: z.ZodString;
341
+ type: z.ZodString;
342
+ }, z.core.$strict>, z.ZodObject<{
343
+ kind: z.ZodLiteral<"rtsp">;
344
+ url: z.ZodString;
345
+ transport: z.ZodOptional<z.ZodEnum<{
346
+ tcp: "tcp";
347
+ udp: "udp";
348
+ }>>;
349
+ credentials: z.ZodOptional<z.ZodObject<{
350
+ username: z.ZodOptional<z.ZodString>;
351
+ password: z.ZodOptional<z.ZodString>;
352
+ }, z.core.$strict>>;
353
+ }, z.core.$strict>, z.ZodObject<{
354
+ kind: z.ZodLiteral<"mjpeg">;
355
+ url: z.ZodString;
356
+ credentials: z.ZodOptional<z.ZodObject<{
357
+ username: z.ZodOptional<z.ZodString>;
358
+ password: z.ZodOptional<z.ZodString>;
359
+ }, z.core.$strict>>;
360
+ }, z.core.$strict>, z.ZodObject<{
361
+ kind: z.ZodLiteral<"v4l2">;
362
+ device: z.ZodString;
363
+ }, z.core.$strict>], "kind">;
364
+ width: z.ZodNumber;
365
+ height: z.ZodNumber;
366
+ fps: z.ZodNumber;
367
+ bitrate_kbps: z.ZodNumber;
368
+ snapshot_interval_seconds: z.ZodNumber;
369
+ description: z.ZodOptional<z.ZodString>;
370
+ }, z.core.$strict>>>;
371
+ }, z.core.$strict>>;
372
+ source: z.ZodString;
373
+ updated_at: z.ZodNullable<z.ZodISODateTime>;
374
+ issues: z.ZodArray<z.ZodObject<{
375
+ path: z.ZodString;
376
+ slug: z.ZodNullable<z.ZodString>;
377
+ code: z.ZodString;
378
+ message: z.ZodString;
379
+ severity: z.ZodEnum<{
380
+ error: "error";
381
+ warning: "warning";
382
+ }>;
383
+ }, z.core.$strip>>;
384
+ }, z.core.$strip>;
385
+ export type ConfigDraftResponse = z.infer<typeof configDraftResponse>;
386
+ /**
387
+ * A write carries the **text only**, and that is the point.
388
+ *
389
+ * If it carried both the text and the parsed document, the two could
390
+ * disagree. Sending only the source makes that unrepresentable on the wire:
391
+ * the server parses it, and there is exactly one account of what the
392
+ * configuration says.
393
+ *
394
+ * It also settles who owns parsing, and **FL-005 D2 moved that line**. The
395
+ * sentence here used to read that the console refuses unparsable YAML before it
396
+ * sends, so a syntax error never reaches the server. That is no longer the
397
+ * rule: the **server** refuses text that is not valid YAML, with the line and
398
+ * column, and stores everything else — including valid YAML that is not a
399
+ * fleetless document, which comes back with `doc: null` and its issues. The
400
+ * console checks as you type so the answer is immediate; the server checks
401
+ * because it is the one that decides. Two checks of one question, and the
402
+ * server's is the one that binds.
403
+ *
404
+ * The pair that used to be called a defect — a stored source that does not
405
+ * parse to its stored document — is now a **represented state**: no document at
406
+ * all. See `configDraftResponse` above.
407
+ */
408
+ export declare const putConfigDraftRequest: z.ZodObject<{
409
+ source: z.ZodString;
410
+ }, z.core.$strip>;
411
+ export type PutConfigDraftRequest = z.infer<typeof putConfigDraftRequest>;
412
+ /** Publishing freezes the draft into the next immutable version. */
413
+ export declare const publishConfigResponse: z.ZodObject<{
414
+ version: z.ZodNumber;
415
+ published_at: z.ZodISODateTime;
416
+ }, z.core.$strip>;
417
+ export type PublishConfigResponse = z.infer<typeof publishConfigResponse>;
418
+ export declare const configVersionsResponse: z.ZodObject<{
419
+ versions: z.ZodArray<z.ZodObject<{
420
+ version: z.ZodNumber;
421
+ published_at: z.ZodISODateTime;
422
+ }, z.core.$strip>>;
423
+ }, z.core.$strip>;
424
+ export type ConfigVersionsResponse = z.infer<typeof configVersionsResponse>;
425
+ /**
426
+ * One published version, with the text it was published from.
427
+ *
428
+ * The text is what makes a version diff readable and a restore honest: a
429
+ * restore that returned only the document would hand back a configuration
430
+ * stripped of every comment the author wrote, which is the loss this format
431
+ * exists to prevent.
432
+ */
433
+ export declare const configVersionResponse: z.ZodObject<{
434
+ version: z.ZodNumber;
435
+ published_at: z.ZodISODateTime;
436
+ doc: z.ZodObject<{
437
+ fleetless: z.ZodLiteral<1>;
438
+ messages: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
439
+ datapoints: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
440
+ topic: z.ZodString;
441
+ type: z.ZodString;
442
+ field: z.ZodOptional<z.ZodString>;
443
+ rate_throttle_hz: z.ZodOptional<z.ZodNumber>;
444
+ description: z.ZodOptional<z.ZodString>;
445
+ numeric: z.ZodOptional<z.ZodObject<{
446
+ scale: z.ZodOptional<z.ZodNumber>;
447
+ offset: z.ZodOptional<z.ZodNumber>;
448
+ unit: z.ZodOptional<z.ZodString>;
449
+ decimals: z.ZodOptional<z.ZodNumber>;
450
+ }, z.core.$strict>>;
451
+ retention: z.ZodOptional<z.ZodObject<{
452
+ enabled: z.ZodOptional<z.ZodBoolean>;
453
+ interval_seconds: z.ZodOptional<z.ZodNumber>;
454
+ max_buffer_values: z.ZodOptional<z.ZodNumber>;
455
+ }, z.core.$strict>>;
456
+ chart: z.ZodOptional<z.ZodObject<{
457
+ y_min: z.ZodOptional<z.ZodNumber>;
458
+ y_max: z.ZodOptional<z.ZodNumber>;
459
+ style: z.ZodOptional<z.ZodEnum<{
460
+ line: "line";
461
+ step: "step";
462
+ }>>;
463
+ default_window_minutes: z.ZodOptional<z.ZodNumber>;
464
+ }, z.core.$strict>>;
465
+ alerts: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
466
+ condition: z.ZodObject<{
467
+ fire_at: z.ZodUnion<readonly [z.ZodNumber, z.ZodString, z.ZodBoolean]>;
468
+ resolve_at: z.ZodOptional<z.ZodNumber>;
469
+ }, z.core.$strict>;
470
+ severity: z.ZodOptional<z.ZodEnum<{
471
+ error: "error";
472
+ warning: "warning";
473
+ }>>;
474
+ name: z.ZodOptional<z.ZodString>;
475
+ enabled: z.ZodOptional<z.ZodBoolean>;
476
+ }, z.core.$strict>>>;
477
+ }, z.core.$strict>>>;
478
+ actions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
479
+ ros_name: z.ZodString;
480
+ type: z.ZodString;
481
+ message: z.ZodOptional<z.ZodUnknown>;
482
+ parameters: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
483
+ type: z.ZodEnum<{
484
+ string: "string";
485
+ bool: "bool";
486
+ byte: "byte";
487
+ char: "char";
488
+ int8: "int8";
489
+ uint8: "uint8";
490
+ int16: "int16";
491
+ uint16: "uint16";
492
+ int32: "int32";
493
+ uint32: "uint32";
494
+ int64: "int64";
495
+ uint64: "uint64";
496
+ float32: "float32";
497
+ float64: "float64";
498
+ wstring: "wstring";
499
+ }>;
500
+ default: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodString, z.ZodBoolean]>>;
501
+ min_value: z.ZodOptional<z.ZodNumber>;
502
+ max_value: z.ZodOptional<z.ZodNumber>;
503
+ enum: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
504
+ regex: z.ZodOptional<z.ZodString>;
505
+ description: z.ZodOptional<z.ZodString>;
506
+ }, z.core.$strict>>>;
507
+ description: z.ZodOptional<z.ZodString>;
508
+ }, z.core.$strict>>>;
509
+ services: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
510
+ ros_name: z.ZodString;
511
+ type: z.ZodString;
512
+ message: z.ZodOptional<z.ZodUnknown>;
513
+ parameters: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
514
+ type: z.ZodEnum<{
515
+ string: "string";
516
+ bool: "bool";
517
+ byte: "byte";
518
+ char: "char";
519
+ int8: "int8";
520
+ uint8: "uint8";
521
+ int16: "int16";
522
+ uint16: "uint16";
523
+ int32: "int32";
524
+ uint32: "uint32";
525
+ int64: "int64";
526
+ uint64: "uint64";
527
+ float32: "float32";
528
+ float64: "float64";
529
+ wstring: "wstring";
530
+ }>;
531
+ default: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodString, z.ZodBoolean]>>;
532
+ min_value: z.ZodOptional<z.ZodNumber>;
533
+ max_value: z.ZodOptional<z.ZodNumber>;
534
+ enum: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
535
+ regex: z.ZodOptional<z.ZodString>;
536
+ description: z.ZodOptional<z.ZodString>;
537
+ }, z.core.$strict>>>;
538
+ description: z.ZodOptional<z.ZodString>;
539
+ }, z.core.$strict>>>;
540
+ publishers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
541
+ topic: z.ZodString;
542
+ type: z.ZodString;
543
+ message: z.ZodUnknown;
544
+ parameters: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
545
+ type: z.ZodEnum<{
546
+ string: "string";
547
+ bool: "bool";
548
+ byte: "byte";
549
+ char: "char";
550
+ int8: "int8";
551
+ uint8: "uint8";
552
+ int16: "int16";
553
+ uint16: "uint16";
554
+ int32: "int32";
555
+ uint32: "uint32";
556
+ int64: "int64";
557
+ uint64: "uint64";
558
+ float32: "float32";
559
+ float64: "float64";
560
+ wstring: "wstring";
561
+ }>;
562
+ default: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodString, z.ZodBoolean]>>;
563
+ min_value: z.ZodOptional<z.ZodNumber>;
564
+ max_value: z.ZodOptional<z.ZodNumber>;
565
+ enum: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
566
+ regex: z.ZodOptional<z.ZodString>;
567
+ description: z.ZodOptional<z.ZodString>;
568
+ }, z.core.$strict>>>;
569
+ failsafe: z.ZodObject<{
570
+ timeout_ms: z.ZodNumber;
571
+ message: z.ZodUnknown;
572
+ }, z.core.$strict>;
573
+ quiet_timeout_ms: z.ZodNumber;
574
+ description: z.ZodOptional<z.ZodString>;
575
+ }, z.core.$strict>>>;
576
+ cameras: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
577
+ source: z.ZodDiscriminatedUnion<[z.ZodObject<{
578
+ kind: z.ZodLiteral<"ros">;
579
+ topic: z.ZodString;
580
+ type: z.ZodString;
581
+ }, z.core.$strict>, z.ZodObject<{
582
+ kind: z.ZodLiteral<"rtsp">;
583
+ url: z.ZodString;
584
+ transport: z.ZodOptional<z.ZodEnum<{
585
+ tcp: "tcp";
586
+ udp: "udp";
587
+ }>>;
588
+ credentials: z.ZodOptional<z.ZodObject<{
589
+ username: z.ZodOptional<z.ZodString>;
590
+ password: z.ZodOptional<z.ZodString>;
591
+ }, z.core.$strict>>;
592
+ }, z.core.$strict>, z.ZodObject<{
593
+ kind: z.ZodLiteral<"mjpeg">;
594
+ url: z.ZodString;
595
+ credentials: z.ZodOptional<z.ZodObject<{
596
+ username: z.ZodOptional<z.ZodString>;
597
+ password: z.ZodOptional<z.ZodString>;
598
+ }, z.core.$strict>>;
599
+ }, z.core.$strict>, z.ZodObject<{
600
+ kind: z.ZodLiteral<"v4l2">;
601
+ device: z.ZodString;
602
+ }, z.core.$strict>], "kind">;
603
+ width: z.ZodNumber;
604
+ height: z.ZodNumber;
605
+ fps: z.ZodNumber;
606
+ bitrate_kbps: z.ZodNumber;
607
+ snapshot_interval_seconds: z.ZodNumber;
608
+ description: z.ZodOptional<z.ZodString>;
609
+ }, z.core.$strict>>>;
610
+ }, z.core.$strict>;
611
+ source: z.ZodString;
612
+ }, z.core.$strip>;
613
+ export type ConfigVersionResponse = z.infer<typeof configVersionResponse>;
614
+ /**
615
+ * The cached ROS graph. It survives the bridge going offline on purpose —
616
+ * a developer keeps configuring while the robot is off; `stale` says the
617
+ * bridge is not connected right now, `fetched_at` how old the picture is.
618
+ */
619
+ export declare const introspectionResponse: z.ZodObject<{
620
+ graph: z.ZodObject<{
621
+ topics: z.ZodArray<z.ZodObject<{
622
+ name: z.ZodString;
623
+ types: z.ZodArray<z.ZodString>;
624
+ }, z.core.$strip>>;
625
+ services: z.ZodArray<z.ZodObject<{
626
+ name: z.ZodString;
627
+ types: z.ZodArray<z.ZodString>;
628
+ }, z.core.$strip>>;
629
+ actions: z.ZodArray<z.ZodObject<{
630
+ name: z.ZodString;
631
+ types: z.ZodArray<z.ZodString>;
632
+ }, z.core.$strip>>;
633
+ captured_at_ms: z.ZodNumber;
634
+ }, z.core.$strip>;
635
+ fetched_at: z.ZodISODateTime;
636
+ stale: z.ZodBoolean;
637
+ }, z.core.$strip>;
638
+ export type IntrospectionResponse = z.infer<typeof introspectionResponse>;
639
+ export declare const typesResponse: z.ZodObject<{
640
+ types: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
641
+ name: z.ZodString;
642
+ kind: z.ZodLiteral<"msg">;
643
+ fields: z.ZodArray<z.ZodType<import("./introspection.js").TypeField, unknown, z.core.$ZodTypeInternals<import("./introspection.js").TypeField, unknown>>>;
644
+ }, z.core.$strip>, z.ZodObject<{
645
+ name: z.ZodString;
646
+ kind: z.ZodLiteral<"srv">;
647
+ request: z.ZodArray<z.ZodType<import("./introspection.js").TypeField, unknown, z.core.$ZodTypeInternals<import("./introspection.js").TypeField, unknown>>>;
648
+ response: z.ZodArray<z.ZodType<import("./introspection.js").TypeField, unknown, z.core.$ZodTypeInternals<import("./introspection.js").TypeField, unknown>>>;
649
+ }, z.core.$strip>, z.ZodObject<{
650
+ name: z.ZodString;
651
+ kind: z.ZodLiteral<"action">;
652
+ goal: z.ZodArray<z.ZodType<import("./introspection.js").TypeField, unknown, z.core.$ZodTypeInternals<import("./introspection.js").TypeField, unknown>>>;
653
+ result: z.ZodArray<z.ZodType<import("./introspection.js").TypeField, unknown, z.core.$ZodTypeInternals<import("./introspection.js").TypeField, unknown>>>;
654
+ feedback: z.ZodArray<z.ZodType<import("./introspection.js").TypeField, unknown, z.core.$ZodTypeInternals<import("./introspection.js").TypeField, unknown>>>;
655
+ }, z.core.$strip>], "kind">>;
656
+ }, z.core.$strip>;
657
+ export type TypesResponse = z.infer<typeof typesResponse>;
658
+ /** Fetch (and store) type definitions for this robot from its bridge. */
659
+ export declare const fetchTypesRequest: z.ZodObject<{
660
+ type_names: z.ZodArray<z.ZodString>;
661
+ }, z.core.$strip>;
662
+ export type FetchTypesRequest = z.infer<typeof fetchTypesRequest>;
663
+ export declare const fetchTypesResponse: z.ZodObject<{
664
+ types: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
665
+ name: z.ZodString;
666
+ kind: z.ZodLiteral<"msg">;
667
+ fields: z.ZodArray<z.ZodType<import("./introspection.js").TypeField, unknown, z.core.$ZodTypeInternals<import("./introspection.js").TypeField, unknown>>>;
668
+ }, z.core.$strip>, z.ZodObject<{
669
+ name: z.ZodString;
670
+ kind: z.ZodLiteral<"srv">;
671
+ request: z.ZodArray<z.ZodType<import("./introspection.js").TypeField, unknown, z.core.$ZodTypeInternals<import("./introspection.js").TypeField, unknown>>>;
672
+ response: z.ZodArray<z.ZodType<import("./introspection.js").TypeField, unknown, z.core.$ZodTypeInternals<import("./introspection.js").TypeField, unknown>>>;
673
+ }, z.core.$strip>, z.ZodObject<{
674
+ name: z.ZodString;
675
+ kind: z.ZodLiteral<"action">;
676
+ goal: z.ZodArray<z.ZodType<import("./introspection.js").TypeField, unknown, z.core.$ZodTypeInternals<import("./introspection.js").TypeField, unknown>>>;
677
+ result: z.ZodArray<z.ZodType<import("./introspection.js").TypeField, unknown, z.core.$ZodTypeInternals<import("./introspection.js").TypeField, unknown>>>;
678
+ feedback: z.ZodArray<z.ZodType<import("./introspection.js").TypeField, unknown, z.core.$ZodTypeInternals<import("./introspection.js").TypeField, unknown>>>;
679
+ }, z.core.$strip>], "kind">>;
680
+ unresolved: z.ZodArray<z.ZodString>;
681
+ }, z.core.$strip>;
682
+ export type FetchTypesResponse = z.infer<typeof fetchTypesResponse>;
683
+ /**
684
+ * What a client can read on this robot: the built-ins plus everything the
685
+ * published configuration exposes. This is the seed of the generated
686
+ * per-robot API (§11.2).
687
+ *
688
+ * **The OpenAPI rendering exists since the route manifest (`routes.ts`):
689
+ * `artifacts/openapi.json`, derived from the manifest and these schemas by
690
+ * `scripts/export-schemas.ts`.**
691
+ */
692
+ export declare const datapointDescriptor: z.ZodObject<{
693
+ slug: z.ZodString;
694
+ builtin: z.ZodBoolean;
695
+ unit: z.ZodNullable<z.ZodString>;
696
+ rate_throttle_hz: z.ZodNullable<z.ZodNumber>;
697
+ }, z.core.$strip>;
698
+ export type DatapointDescriptor = z.infer<typeof datapointDescriptor>;
699
+ export declare const datapointListResponse: z.ZodObject<{
700
+ datapoints: z.ZodArray<z.ZodObject<{
701
+ slug: z.ZodString;
702
+ builtin: z.ZodBoolean;
703
+ unit: z.ZodNullable<z.ZodString>;
704
+ rate_throttle_hz: z.ZodNullable<z.ZodNumber>;
705
+ }, z.core.$strip>>;
706
+ }, z.core.$strip>;
707
+ export type DatapointListResponse = z.infer<typeof datapointListResponse>;
708
+ /**
709
+ * The built-in `robot_details` datapoint (spec §4.3): static properties the
710
+ * developer maintains. Bounded so one robot cannot become a document store.
711
+ */
712
+ export declare const robotDetailsDoc: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodUnknown>, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>;
713
+ export type RobotDetailsDoc = z.infer<typeof robotDetailsDoc>;
714
+ /** What `PUT /api/robots/:id/details` answers: the stored document, which is the one that was sent. */
715
+ export declare const putRobotDetailsResponse: z.ZodObject<{
716
+ details: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodUnknown>, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>;
717
+ }, z.core.$strip>;
718
+ export type PutRobotDetailsResponse = z.infer<typeof putRobotDetailsResponse>;
719
+ export declare const putRobotDetailsRequest: z.ZodObject<{
720
+ details: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodUnknown>, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>;
721
+ }, z.core.$strip>;
722
+ export type PutRobotDetailsRequest = z.infer<typeof putRobotDetailsRequest>;
723
+ /**
724
+ * Invoke an action or call a service; parameters by field path (§4.4).
725
+ *
726
+ * Flat, keyed by `parameterSpec.name` — see `cloudInvoke.params` for why the
727
+ * flat form is the one that makes a refusal legible.
728
+ */
729
+ export declare const invokeRequest: z.ZodObject<{
730
+ params: z.ZodRecord<z.ZodString, z.ZodUnknown>;
731
+ patience_ms: z.ZodOptional<z.ZodNumber>;
732
+ }, z.core.$strip>;
733
+ export type InvokeRequest = z.infer<typeof invokeRequest>;
734
+ /**
735
+ * The answer to an invoke. The job id is informative (§11.3): state is
736
+ * observed by slug afterwards, over polling or a subscription.
737
+ */
738
+ /**
739
+ * The body of a cancel (W6b). **Every field optional, and the body itself may
740
+ * be absent** — `POST .../cancel` was bodyless before this wave and every
741
+ * existing caller still sends nothing.
742
+ *
743
+ * That is not politeness, it is the W5 defect: a bodyless `POST` carrying
744
+ * `content-type: application/json` was rejected outright, which made
745
+ * `cameras.live()` unreachable through the SDK and took `cancel`, publish,
746
+ * restore, key rotation and member removal with it — unnoticed since W4. A
747
+ * schema that demands a body would reintroduce it on the one verb that stops
748
+ * a machine.
749
+ *
750
+ * **`.strict()`, and that is the whole point of the shape.** A plain object
751
+ * strips unknown keys, so a caller who *means* to name a job and misspells the
752
+ * field — `jobId` for `job_id` — has their id silently removed and gets the
753
+ * **slug-wide** cancel instead: the most destructive reading of a request they
754
+ * did not make. Measured in W6b's review: `{"jobId": "<some other job>"}`
755
+ * answered `200` and stopped the job that was actually running, which nobody
756
+ * had named. The `?force=true` precedent this route's design borrowed from
757
+ * fails *safe* on a typo — a misspelled `force` simply does not force.
758
+ * Stripping here fails unsafe, so unknown keys are refused instead.
759
+ *
760
+ * `job_id` absent and `job_id: null` mean the **same** thing here, and that is
761
+ * deliberate: over REST an absent body is how every caller written before this
762
+ * wave says "cancel whatever is running". On the socket, `clientCancel.job_id`
763
+ * is required-and-nullable instead, because a frame is assembled fresh by a
764
+ * client that has already been updated — there, `null` is a decision and an
765
+ * omission is a bug.
766
+ */
767
+ export declare const cancelRequest: z.ZodObject<{
768
+ job_id: z.ZodOptional<z.ZodNullable<z.ZodUUID>>;
769
+ }, z.core.$strict>;
770
+ export type CancelRequest = z.infer<typeof cancelRequest>;
771
+ /**
772
+ * The query of a live release (W6b): `DELETE .../live?session_id=<uuid>`.
773
+ *
774
+ * A query parameter rather than a body, following `?force=true` on robot
775
+ * deletion — the precedent this repo already set for "a DELETE that needs one
776
+ * more fact". A body on a DELETE is carried inconsistently by proxies and by
777
+ * `fetch` itself, and this call runs from a browser tab that is often closing.
778
+ *
779
+ * **`.strict()`, for the reason `cancelRequest` is** — `?sessionid=` instead of
780
+ * `?session_id=` was measured releasing **both** of an identity's holds and
781
+ * stranding the other tab, which is precisely the defect this field was added
782
+ * to remove. A refused typo costs a round trip; a stripped one stops a robot
783
+ * somebody else is watching.
784
+ *
785
+ * Absent means today's meaning: release **all** of this identity's holds on
786
+ * this camera. A client that has lost its id, or is going away entirely, still
787
+ * needs a way to let go — it is the blunt form, and it is the one that strands
788
+ * the identity's other tabs.
789
+ */
790
+ export declare const releaseLiveQuery: z.ZodObject<{
791
+ session_id: z.ZodOptional<z.ZodUUID>;
792
+ }, z.core.$strict>;
793
+ export type ReleaseLiveQuery = z.infer<typeof releaseLiveQuery>;
794
+ export declare const invokeResponse: z.ZodObject<{
795
+ job: z.ZodObject<{
796
+ id: z.ZodUUID;
797
+ robot_id: z.ZodUUID;
798
+ slug: z.ZodString;
799
+ state: z.ZodEnum<{
800
+ failed: "failed";
801
+ running: "running";
802
+ succeeded: "succeeded";
803
+ cancelled: "cancelled";
804
+ lost: "lost";
805
+ }>;
806
+ started_at: z.ZodISODateTime;
807
+ updated_at: z.ZodISODateTime;
808
+ seq: z.ZodNumber;
809
+ result: z.ZodNullable<z.ZodUnknown>;
810
+ error: z.ZodNullable<z.ZodObject<{
811
+ code: z.ZodString;
812
+ message: z.ZodString;
813
+ details: z.ZodOptional<z.ZodUnknown>;
814
+ }, z.core.$strip>>;
815
+ }, z.core.$strip>;
816
+ kind: z.ZodEnum<{
817
+ action: "action";
818
+ service: "service";
819
+ }>;
820
+ }, z.core.$strip>;
821
+ export type InvokeResponse = z.infer<typeof invokeResponse>;
822
+ /** A service call answers with its result directly — no job to observe. */
823
+ export declare const serviceCallResponse: z.ZodObject<{
824
+ result: z.ZodUnknown;
825
+ }, z.core.$strip>;
826
+ export type ServiceCallResponse = z.infer<typeof serviceCallResponse>;
827
+ /**
828
+ * **What `POST /api/robots/:id/jobs/:slug` answers, which is one of two
829
+ * shapes.**
830
+ *
831
+ * One route serves both kinds, because a path segment naming the kind would
832
+ * demand a fact a role grant does not carry. **The slug's kind decides, and
833
+ * nothing in the request does**: an *action* answers `202` with an
834
+ * `invokeResponse` the moment the job exists, a *service* answers `200` with
835
+ * a `serviceCallResponse` once the result is in. They differ only in what the
836
+ * cloud waits for before it answers.
837
+ *
838
+ * The two are told apart without inspecting the status code: `invokeResponse`
839
+ * carries `kind` and `job`, `serviceCallResponse` carries `result` alone.
840
+ *
841
+ * **This union exists so the route can name a response at all.** The entry
842
+ * carried `response: null` while the handler demonstrably answers something,
843
+ * which reads in the generated reference as *this route returns nothing* —
844
+ * the documented absence this project keeps paying for. A `null` there should
845
+ * mean `204`, and on this route it did not.
846
+ */
847
+ export declare const invokeOrServiceResponse: z.ZodUnion<readonly [z.ZodObject<{
848
+ job: z.ZodObject<{
849
+ id: z.ZodUUID;
850
+ robot_id: z.ZodUUID;
851
+ slug: z.ZodString;
852
+ state: z.ZodEnum<{
853
+ failed: "failed";
854
+ running: "running";
855
+ succeeded: "succeeded";
856
+ cancelled: "cancelled";
857
+ lost: "lost";
858
+ }>;
859
+ started_at: z.ZodISODateTime;
860
+ updated_at: z.ZodISODateTime;
861
+ seq: z.ZodNumber;
862
+ result: z.ZodNullable<z.ZodUnknown>;
863
+ error: z.ZodNullable<z.ZodObject<{
864
+ code: z.ZodString;
865
+ message: z.ZodString;
866
+ details: z.ZodOptional<z.ZodUnknown>;
867
+ }, z.core.$strip>>;
868
+ }, z.core.$strip>;
869
+ kind: z.ZodEnum<{
870
+ action: "action";
871
+ service: "service";
872
+ }>;
873
+ }, z.core.$strip>, z.ZodObject<{
874
+ result: z.ZodUnknown;
875
+ }, z.core.$strip>]>;
876
+ export type InvokeOrServiceResponse = z.infer<typeof invokeOrServiceResponse>;
877
+ export declare const publishRequest: z.ZodObject<{
878
+ message: z.ZodRecord<z.ZodString, z.ZodUnknown>;
879
+ }, z.core.$strip>;
880
+ export type PublishRequest = z.infer<typeof publishRequest>;
881
+ /**
882
+ * The **most recent** job on a slug — running or already finished — or null
883
+ * only when nothing has ever run there.
884
+ *
885
+ * It said "the job currently running" until W4's review, and that quietly
886
+ * made §11.3's first sentence false. The spec offers two equal ways to
887
+ * observe a slug — *"Polling (REST) oder Subscription (Realtime)"* — but a
888
+ * route that forgets a job the moment it settles lets a poller see only
889
+ * `running`, then `null`. Succeeded, failed, cancelled, `lost` and
890
+ * never-invoked all become the same answer, so §6.1's promise that a lost
891
+ * job is *said out loud* held for subscribers and silently did not hold for
892
+ * anyone polling. It is also the recovery `command_outcome_unknown` points
893
+ * a caller to.
894
+ *
895
+ * Read `job.state` to tell a live job from a finished one; that is what the
896
+ * field is for.
897
+ */
898
+ export declare const jobResponse: z.ZodObject<{
899
+ job: z.ZodNullable<z.ZodObject<{
900
+ id: z.ZodUUID;
901
+ robot_id: z.ZodUUID;
902
+ slug: z.ZodString;
903
+ state: z.ZodEnum<{
904
+ failed: "failed";
905
+ running: "running";
906
+ succeeded: "succeeded";
907
+ cancelled: "cancelled";
908
+ lost: "lost";
909
+ }>;
910
+ started_at: z.ZodISODateTime;
911
+ updated_at: z.ZodISODateTime;
912
+ seq: z.ZodNumber;
913
+ result: z.ZodNullable<z.ZodUnknown>;
914
+ error: z.ZodNullable<z.ZodObject<{
915
+ code: z.ZodString;
916
+ message: z.ZodString;
917
+ details: z.ZodOptional<z.ZodUnknown>;
918
+ }, z.core.$strip>>;
919
+ }, z.core.$strip>>;
920
+ }, z.core.$strip>;
921
+ export type JobResponse = z.infer<typeof jobResponse>;
922
+ /**
923
+ * Every job the platform currently believes this robot has — `GET
924
+ * /api/robots/:id/jobs` (W6b).
925
+ *
926
+ * `jobResponse` answers "what is on this slug", which requires knowing the
927
+ * slug first. That was enough while a job could only exist on a slug the
928
+ * published configuration named. W6b breaks that assumption twice: a
929
+ * reconnecting bridge can name a job the cloud has **no row for** and the
930
+ * cloud adopts it, and a configuration change can leave a job on a slug the
931
+ * document no longer contains. Both are jobs nobody can ask about, because
932
+ * asking requires already knowing what to ask for.
933
+ *
934
+ * So this route exists to answer the question the per-slug route cannot: not
935
+ * "is something running here", but "what is this robot doing". A restarted
936
+ * cloud that has just reconciled a robot's `hello.active_jobs` has exactly
937
+ * this list and, until now, no way to say it out loud.
938
+ *
939
+ * The array is ordered newest first and is **never null**: a robot doing
940
+ * nothing answers `{ jobs: [] }`. "Nothing is running" and "we did not look"
941
+ * are different facts, and a nullable list would merge them — the same
942
+ * distinction `robotDeletionSummary` was made all-required for.
943
+ *
944
+ * **At most one entry per slug: the current job there, exactly what
945
+ * `jobResponse` would answer for that slug.** This is not a history endpoint
946
+ * and must not become one. The first implementation returned every job the
947
+ * registry still held — six rows and four complete Fibonacci results after a
948
+ * few minutes of gate traffic, and unbounded in both count and payload for a
949
+ * robot that has been working all day. The list would have grown until a
950
+ * console page carried a robot's entire past, and the one thing it exists to
951
+ * answer — *what is this robot doing* — would have been the first line of a
952
+ * scroll.
953
+ *
954
+ * A settled job stays visible as its slug's current entry until something
955
+ * else runs there, which is what makes a job that just failed still findable.
956
+ * Read `state` to tell a live one from a finished one, exactly as with
957
+ * `jobResponse`.
958
+ */
959
+ /**
960
+ * What a `rate_limited` refusal tells the caller (W6c).
961
+ *
962
+ * One number, and it is the only one that matters: **when to come back.** A
963
+ * limit that says "too many" without saying "in 800 ms" produces a client that
964
+ * retries immediately, which is the behaviour the limit exists to stop — so
965
+ * omitting it would make the refusal part of the attack.
966
+ *
967
+ * Deliberately **not** carrying the limit, the window, or how many attempts
968
+ * remain: those describe the defence to whoever is probing it, and none of
969
+ * them changes what an honest caller does.
970
+ */
971
+ export declare const rateLimitDetails: z.ZodObject<{
972
+ retry_after_ms: z.ZodNumber;
973
+ }, z.core.$strip>;
974
+ export type RateLimitDetails = z.infer<typeof rateLimitDetails>;
975
+ /**
976
+ * Every job this robot's registry currently holds, **ordered newest first by
977
+ * `started_at`, with `seq` as the tiebreaker** (W7, register rows 2j and 2l).
978
+ *
979
+ * The field is named because the previous version of this comment claimed an
980
+ * order without saying what produced it, and the answer turned out to matter
981
+ * twice over:
982
+ *
983
+ * 1. **`started_at` alone is not a total order.** Two jobs minted in the same
984
+ * millisecond sorted against each other arbitrarily — differently on each
985
+ * query — so a reader could see one twice and the other not at all. `seq`
986
+ * is monotonic in mint order and settles it. Note its scope, which is in
987
+ * `job.seq`'s own comment: per cloud process, per run, because job state
988
+ * lives in memory and the counter restarts with the registry it orders.
989
+ * 2. **For an adopted job, `started_at` is adoption time, not the real
990
+ * start.** The cloud learns of it at `hello`, having never minted it, and
991
+ * has no other honest value to put there. So this list is newest-*known*
992
+ * first, and a job the robot has been running for an hour can sit above one
993
+ * started a minute ago. Stated rather than smoothed over: the console's own
994
+ * "Known running since" wording exists for the same reason, and a contract
995
+ * that quietly implies otherwise would send somebody to debug the sort.
996
+ */
997
+ export declare const robotJobsResponse: z.ZodObject<{
998
+ jobs: z.ZodArray<z.ZodObject<{
999
+ id: z.ZodUUID;
1000
+ robot_id: z.ZodUUID;
1001
+ slug: z.ZodString;
1002
+ state: z.ZodEnum<{
1003
+ failed: "failed";
1004
+ running: "running";
1005
+ succeeded: "succeeded";
1006
+ cancelled: "cancelled";
1007
+ lost: "lost";
1008
+ }>;
1009
+ started_at: z.ZodISODateTime;
1010
+ updated_at: z.ZodISODateTime;
1011
+ seq: z.ZodNumber;
1012
+ result: z.ZodNullable<z.ZodUnknown>;
1013
+ error: z.ZodNullable<z.ZodObject<{
1014
+ code: z.ZodString;
1015
+ message: z.ZodString;
1016
+ details: z.ZodOptional<z.ZodUnknown>;
1017
+ }, z.core.$strip>>;
1018
+ }, z.core.$strip>>;
1019
+ }, z.core.$strip>;
1020
+ export type RobotJobsResponse = z.infer<typeof robotJobsResponse>;
1021
+ /**
1022
+ * Every slug of a robot that a role can be granted, **with its kind**.
1023
+ *
1024
+ * The roles matrix was built in W3 against the datapoint list, which was the
1025
+ * only kind that existed. With four kinds it needs one list that names them,
1026
+ * or the matrix silently cannot grant an action.
1027
+ */
1028
+ export declare const exposure: z.ZodObject<{
1029
+ slug: z.ZodString;
1030
+ kind: z.ZodEnum<{
1031
+ datapoint: "datapoint";
1032
+ action: "action";
1033
+ service: "service";
1034
+ publisher: "publisher";
1035
+ camera: "camera";
1036
+ }>;
1037
+ builtin: z.ZodBoolean;
1038
+ }, z.core.$strip>;
1039
+ export type Exposure = z.infer<typeof exposure>;
1040
+ export declare const exposureListResponse: z.ZodObject<{
1041
+ exposures: z.ZodArray<z.ZodObject<{
1042
+ slug: z.ZodString;
1043
+ kind: z.ZodEnum<{
1044
+ datapoint: "datapoint";
1045
+ action: "action";
1046
+ service: "service";
1047
+ publisher: "publisher";
1048
+ camera: "camera";
1049
+ }>;
1050
+ builtin: z.ZodBoolean;
1051
+ }, z.core.$strip>>;
1052
+ }, z.core.$strip>;
1053
+ export type ExposureListResponse = z.infer<typeof exposureListResponse>;
1054
+ /**
1055
+ * The response headers a binary snapshot carries, named here so the cloud and
1056
+ * every client agree without negotiating:
1057
+ *
1058
+ * - `Content-Type` — the image's mime, standard rather than invented.
1059
+ * - `X-Fleetless-Age-Ms` — how old the frame is, **computed by the cloud**.
1060
+ * - `X-Fleetless-Timestamp-Ms`— the bridge's capture time.
1061
+ * - `X-Fleetless-Width` / `X-Fleetless-Height`.
1062
+ *
1063
+ * A client must take `age_ms` from the header and **never** recompute it as
1064
+ * `Date.now() - timestamp_ms`: the cloud is the one clock that knows how long
1065
+ * it has actually been holding the frame, and recomputing reintroduces the
1066
+ * viewer's clock skew as a source of lying about freshness.
1067
+ */
1068
+ export declare const SNAPSHOT_HEADERS: {
1069
+ readonly ageMs: "x-fleetless-age-ms";
1070
+ readonly timestampMs: "x-fleetless-timestamp-ms";
1071
+ readonly width: "x-fleetless-width";
1072
+ readonly height: "x-fleetless-height";
1073
+ };
1074
+ /**
1075
+ * The metadata an asset upload carries beside its raw body (W7).
1076
+ *
1077
+ * Here rather than as a convention documented on both sides, and the reason is
1078
+ * a scar. W5 shipped `x-fleetless-*` headers the CORS policy did not expose,
1079
+ * so `age_ms` was `null` in **every** browser while the SDK documented `null`
1080
+ * as "nothing captured yet" — a fresh frame reporting as no snapshot at all,
1081
+ * invisible to three test suites because none of them was a browser. And W6b
1082
+ * found the general form: three repos agreeing with each other about a payload
1083
+ * none of them exchanged, each right in its own tests.
1084
+ *
1085
+ * **A string shared by two repos and defined in both is a string that drifts.**
1086
+ * A zod schema cannot validate a header, which is an argument for writing the
1087
+ * names down once, not an argument for writing them down twice.
1088
+ *
1089
+ * `name` is the `package://` URI verbatim for a mesh — the same string
1090
+ * `asset.name` stores, and the same one `urdfCompleteness.missing` reports, so
1091
+ * a failed upload and a missing mesh can be matched by eye.
1092
+ */
1093
+ /**
1094
+ * **`name` travels percent-encoded, and that is a fix rather than a
1095
+ * convention** (W7a review, André's decision to fix rather than defer).
1096
+ *
1097
+ * HTTP header values are latin-1 (`http.client` in Python, and the same is
1098
+ * true on the other side). So a texture called `textures/日本語.png` raised a
1099
+ * `UnicodeEncodeError` **inside `urllib`** — a `ValueError`, caught by neither
1100
+ * `HTTPError` nor `URLError` — which propagated to the sync's broad handler
1101
+ * and marked **everything still remaining** as failed. One non-ASCII filename
1102
+ * cost a developer every mesh after it in that sync, with no cause on the
1103
+ * wire. R6 made it ordinary rather than exotic: `.dae` internal names come
1104
+ * from 3D-authoring tools, where non-ASCII is Tuesday.
1105
+ *
1106
+ * The encoding is not invented here. **`GET .../assets/missing?name=` already
1107
+ * carries this exact string percent-encoded**, because a query parameter is
1108
+ * percent-encoded by definition — same value, same wire, question already
1109
+ * answered.
1110
+ *
1111
+ * **It is a SECOND header, and that is the whole design rather than a
1112
+ * detail.** The first version overloaded `name` itself: the producer would
1113
+ * encode, the store would `decodeURIComponent`. That decodes identically for
1114
+ * every name without a `%`, so an **older bridge and a newer cloud agree by
1115
+ * luck** — right up until a name contains `%2f`, which the store would then
1116
+ * silently turn into a `/`. A wire change whose breakage is invisible in the
1117
+ * common case and silent in the uncommon one is the worst of both (Argus-W7a,
1118
+ * reading the contract rather than the code).
1119
+ *
1120
+ * So `name` keeps meaning exactly what it always meant, and `nameEncoded`
1121
+ * carries the percent-encoded UTF-8 form. **The store prefers `nameEncoded`
1122
+ * when present and uses `name` otherwise**, so:
1123
+ *
1124
+ * - an older bridge sends only `name` and behaves exactly as before;
1125
+ * - a newer bridge sends both, and a name it cannot express in latin-1 travels
1126
+ * intact for the first time;
1127
+ * - no value is ever ambiguous about which encoding it is in.
1128
+ *
1129
+ * A producer that can send `nameEncoded` should send both, so a store older
1130
+ * than this contract keeps working too. Agreement by construction, not by the
1131
+ * absence of a `%`.
1132
+ */
1133
+ export declare const ASSET_UPLOAD_HEADERS: {
1134
+ readonly kind: "x-fleetless-asset-kind";
1135
+ readonly name: "x-fleetless-asset-name";
1136
+ readonly nameEncoded: "x-fleetless-asset-name-encoded";
1137
+ readonly syncId: "x-fleetless-sync-id";
1138
+ /**
1139
+ * **Die angekündigte Größe, und sie ist der Grund, warum `asset_too_large`
1140
+ * überhaupt entstehen kann (W9b, DEF-116).**
1141
+ *
1142
+ * Fastifys `bodyLimit` greift im Content-Type-Parser, also **vor** dem
1143
+ * Handler — eine zu große Datei bekam damit ein blankes `413 bad_request`
1144
+ * ohne `limit_bytes` und ohne `size_bytes`, und der strukturierte Fehlercode,
1145
+ * den `assetTooLargeDetails` beschreibt, hatte schlicht keinen erreichbaren
1146
+ * Erzeuger (Momus-W7, M1, an den echten Routenoptionen reproduziert).
1147
+ *
1148
+ * Mit einer angekündigten Größe im Kopf kann die Ablehnung dort entstehen,
1149
+ * wo sie etwas sagen kann: bevor ein Byte gepuffert ist, mit beiden Zahlen.
1150
+ * Und die Bridge erfährt ihre Grenze, ohne 194 MB zu lesen, um sie zu
1151
+ * entdecken — was am 2026-08-18 auf rx1 genau so ausging (DEF-148).
1152
+ *
1153
+ * Der Kopf ist eine **Ankündigung, kein Beweis**: Ein Absender kann lügen.
1154
+ * Der Deckel gilt weiterhin auch am Körper — dies ersetzt die Durchsetzung
1155
+ * nicht, es macht die Absage nur beantwortbar.
1156
+ */
1157
+ readonly size: "x-fleetless-asset-size";
1158
+ };
1159
+ export declare const cameraDescriptor: z.ZodObject<{
1160
+ slug: z.ZodString;
1161
+ width: z.ZodNumber;
1162
+ height: z.ZodNumber;
1163
+ fps: z.ZodNumber;
1164
+ snapshot_interval_seconds: z.ZodNumber;
1165
+ }, z.core.$strip>;
1166
+ export type CameraDescriptor = z.infer<typeof cameraDescriptor>;
1167
+ export declare const cameraListResponse: z.ZodObject<{
1168
+ cameras: z.ZodArray<z.ZodObject<{
1169
+ slug: z.ZodString;
1170
+ width: z.ZodNumber;
1171
+ height: z.ZodNumber;
1172
+ fps: z.ZodNumber;
1173
+ snapshot_interval_seconds: z.ZodNumber;
1174
+ }, z.core.$strip>>;
1175
+ }, z.core.$strip>;
1176
+ export type CameraListResponse = z.infer<typeof cameraListResponse>;
1177
+ /**
1178
+ * What a viewer needs to join, and **what it costs them to hold**.
1179
+ *
1180
+ * `POST` takes a refcount hold and `DELETE` releases it; the first hold
1181
+ * starts the robot publishing and the last release stops it (§10). A client
1182
+ * that forgets to release keeps a robot streaming to nobody, so the SDK hands
1183
+ * back a `release()` rather than a bare token.
1184
+ *
1185
+ * **`expires_at` is a join deadline, not a session backstop.** A LiveKit
1186
+ * token is checked when a participant connects and not again afterwards, so a
1187
+ * viewer who has already joined keeps receiving video straight past this
1188
+ * moment. Do not design cleanup around it. What actually ends a session is
1189
+ * `release()` together with disconnecting the room, the cloud reconciling the
1190
+ * hold away against LiveKit's real participants, or a revocation kicking the
1191
+ * participant out. This comment previously claimed the opposite and the SDK
1192
+ * inherited the claim from here — a developer reading it would reasonably
1193
+ * have skipped cleanup on purpose.
1194
+ */
1195
+ export declare const liveSessionResponse: z.ZodObject<{
1196
+ session_id: z.ZodUUID;
1197
+ url: z.ZodString;
1198
+ room: z.ZodString;
1199
+ token: z.ZodString;
1200
+ expires_at: z.ZodISODateTime;
1201
+ }, z.core.$strip>;
1202
+ export type LiveSessionResponse = z.infer<typeof liveSessionResponse>;
1203
+ /**
1204
+ * The snapshot read **without the bytes**.
1205
+ *
1206
+ * A viewer polling at the camera's interval otherwise re-downloads a whole
1207
+ * image to discover whether a new one exists. This is the cheap question —
1208
+ * *how old is what you have?* — so a client can fetch pixels only when the
1209
+ * timestamp actually moved. It matters most on the console's snapshot view,
1210
+ * which polls continuously while a tab is open.
1211
+ *
1212
+ * `age_ms` is not a convenience: a cached frame served without its age is
1213
+ * indistinguishable from a live one, and §10 makes snapshots deliberately
1214
+ * cheap and therefore deliberately old. `null` values mean nothing has been
1215
+ * captured yet — which is an answer, not an error.
1216
+ */
1217
+ export declare const snapshotMetaResponse: z.ZodObject<{
1218
+ slug: z.ZodString;
1219
+ timestamp_ms: z.ZodNullable<z.ZodNumber>;
1220
+ age_ms: z.ZodNullable<z.ZodNumber>;
1221
+ width: z.ZodNullable<z.ZodNumber>;
1222
+ height: z.ZodNullable<z.ZodNumber>;
1223
+ mime: z.ZodNullable<z.ZodString>;
1224
+ }, z.core.$strip>;
1225
+ export type SnapshotMetaResponse = z.infer<typeof snapshotMetaResponse>;
1226
+ /**
1227
+ * **Both history shapes answer the same boundary the same way: `[from, to)`
1228
+ * (W9d, DEF-062 — decision pre-made at the W6 boundary so no wave
1229
+ * re-litigates it).**
1230
+ *
1231
+ * They did not. `samples` was inclusive of `to`, `buckets` exclusive — same
1232
+ * range, same data, opposite answers for a point landing exactly on `to`, and
1233
+ * the buckets answer rendered as a gap tooltipped *"empty — no samples"*.
1234
+ * `sdk/README.md` documented the inclusive notation for the half-open path,
1235
+ * so it was wrong for one of the two whichever way you read it.
1236
+ *
1237
+ * Half-open wins because it is the only rule under which **adjacent windows
1238
+ * tile without overlap**: `[0,10)` then `[10,20)` covers every instant once.
1239
+ * With an inclusive upper bound a sample at exactly `10` belongs to both
1240
+ * windows, and any consumer summing them counts it twice.
1241
+ *
1242
+ * This is a statement about behaviour, not a field — nothing in the shapes
1243
+ * below can enforce it. It is written here because this is the one place both
1244
+ * shapes are defined together, and the cloud's `history-store` and the SDK's
1245
+ * README are the two places that have to agree with it.
1246
+ */
1247
+ /**
1248
+ * A history query (§8). `from`/`to` accept **either** a relative expression
1249
+ * (`now-30s`, `now-5m`, `now-1h`) **or** absolute unix milliseconds, because
1250
+ * a chart asks the first way and a report asks the second, and making a
1251
+ * client convert is making it guess our clock.
1252
+ *
1253
+ * `window` without `agg` is meaningless and `agg` without `window` is
1254
+ * ambiguous — both are refused rather than assigned a default, since a
1255
+ * silently chosen aggregation is a chart that lies quietly.
1256
+ */
1257
+ export declare const historyQuery: z.ZodObject<{
1258
+ from: z.ZodString;
1259
+ to: z.ZodOptional<z.ZodString>;
1260
+ window: z.ZodOptional<z.ZodString>;
1261
+ agg: z.ZodOptional<z.ZodEnum<{
1262
+ min: "min";
1263
+ max: "max";
1264
+ avg: "avg";
1265
+ }>>;
1266
+ field: z.ZodOptional<z.ZodString>;
1267
+ limit: z.ZodOptional<z.ZodPipe<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>, z.ZodTransform<number, string | number>>, z.ZodNumber>>;
1268
+ }, z.core.$strip>;
1269
+ export type HistoryQuery = z.infer<typeof historyQuery>;
1270
+ /**
1271
+ * Raw samples. `timestamp_ms` is the **bridge's capture time** (§6.3) — the
1272
+ * same instant the live value carried, so a recorded point and a live one can
1273
+ * be placed on one axis without apology.
1274
+ *
1275
+ * `truncated` says the response was cut short. A short array that does not
1276
+ * admit it is indistinguishable from a quiet period, and the two lead a
1277
+ * developer to opposite conclusions.
1278
+ */
1279
+ export declare const historySamplesResponse: z.ZodObject<{
1280
+ slug: z.ZodString;
1281
+ kind: z.ZodLiteral<"samples">;
1282
+ samples: z.ZodArray<z.ZodObject<{
1283
+ timestamp_ms: z.ZodNumber;
1284
+ value: z.ZodUnknown;
1285
+ }, z.core.$strip>>;
1286
+ truncated: z.ZodBoolean;
1287
+ truncated_by: z.ZodNullable<z.ZodEnum<{
1288
+ limit: "limit";
1289
+ bytes: "bytes";
1290
+ }>>;
1291
+ }, z.core.$strip>;
1292
+ export type HistorySamplesResponse = z.infer<typeof historySamplesResponse>;
1293
+ /**
1294
+ * Aggregated buckets — a **separate shape**, not the samples shape with nulls
1295
+ * in it, so a client knows by type what it received rather than by
1296
+ * inspection.
1297
+ *
1298
+ * `sample_count` exists because an empty bucket and a bucket whose average is
1299
+ * zero are different facts. W5 established at some cost what happens when two
1300
+ * facts share one representation, and a chart is the easiest place in this
1301
+ * product to draw a gap as a line.
1302
+ */
1303
+ export declare const historyBucketsResponse: z.ZodObject<{
1304
+ slug: z.ZodString;
1305
+ kind: z.ZodLiteral<"buckets">;
1306
+ window_ms: z.ZodNumber;
1307
+ agg: z.ZodEnum<{
1308
+ min: "min";
1309
+ max: "max";
1310
+ avg: "avg";
1311
+ }>;
1312
+ buckets: z.ZodArray<z.ZodObject<{
1313
+ bucket_start_ms: z.ZodNumber;
1314
+ value: z.ZodNullable<z.ZodNumber>;
1315
+ sample_count: z.ZodNumber;
1316
+ }, z.core.$strip>>;
1317
+ }, z.core.$strip>;
1318
+ export type HistoryBucketsResponse = z.infer<typeof historyBucketsResponse>;
1319
+ /**
1320
+ * **What `GET /api/robots/:id/datapoints/:slug/history` answers, which is one
1321
+ * of two shapes.**
1322
+ *
1323
+ * **The query decides, and only the query**: without `window` it is a
1324
+ * `historySamplesResponse`, with one it is a `historyBucketsResponse`.
1325
+ * `window` and `agg` must be given together or not at all — one without the
1326
+ * other is refused rather than defaulted, since a silently chosen aggregation
1327
+ * is a chart that lies quietly.
1328
+ *
1329
+ * Told apart by `kind`, which is `'samples'` or `'buckets'`, so a client
1330
+ * branches on a field rather than on which other fields happen to be present.
1331
+ * The two are deliberately not one shape with nullable halves: an aggregate
1332
+ * and a raw reading answer different questions, and `sample_count` exists on
1333
+ * only one of them.
1334
+ *
1335
+ * **This union exists so the route can name a response at all.** The entry
1336
+ * carried `response: null` while the handler demonstrably answers something,
1337
+ * which reads in the generated reference as *this route returns nothing*.
1338
+ */
1339
+ export declare const historyResponse: z.ZodUnion<readonly [z.ZodObject<{
1340
+ slug: z.ZodString;
1341
+ kind: z.ZodLiteral<"samples">;
1342
+ samples: z.ZodArray<z.ZodObject<{
1343
+ timestamp_ms: z.ZodNumber;
1344
+ value: z.ZodUnknown;
1345
+ }, z.core.$strip>>;
1346
+ truncated: z.ZodBoolean;
1347
+ truncated_by: z.ZodNullable<z.ZodEnum<{
1348
+ limit: "limit";
1349
+ bytes: "bytes";
1350
+ }>>;
1351
+ }, z.core.$strip>, z.ZodObject<{
1352
+ slug: z.ZodString;
1353
+ kind: z.ZodLiteral<"buckets">;
1354
+ window_ms: z.ZodNumber;
1355
+ agg: z.ZodEnum<{
1356
+ min: "min";
1357
+ max: "max";
1358
+ avg: "avg";
1359
+ }>;
1360
+ buckets: z.ZodArray<z.ZodObject<{
1361
+ bucket_start_ms: z.ZodNumber;
1362
+ value: z.ZodNullable<z.ZodNumber>;
1363
+ sample_count: z.ZodNumber;
1364
+ }, z.core.$strip>>;
1365
+ }, z.core.$strip>]>;
1366
+ export type HistoryResponse = z.infer<typeof historyResponse>;
1367
+ /**
1368
+ * W6a — deletion, and the one channel that reports health.
1369
+ *
1370
+ * | Route | Body | Answer |
1371
+ * |---|---|---|
1372
+ * | `DELETE /api/robots/:id` | — | `204`. `?force=true` to proceed while a live session is open; without it, `409 robot_in_use` |
1373
+ * | `GET /api/robots/:id/deletion-preview` | — | `robotDeletionSummary` — the same shape the audit event carries |
1374
+ * | `GET /api/org/health` | — | `resourceHealthListResponse`; `?robot_id=` narrows it to one robot |
1375
+ *
1376
+ * Plus `resourceHealthEvent`, pushed on the **developer** realtime socket
1377
+ * and scoped to the org — not to a subscription, because its job is to reach
1378
+ * somebody who is *not* looking at the thing that broke.
1379
+ *
1380
+ * Two of these paths are worth stating rather than inferring:
1381
+ *
1382
+ * **The preview exists because a confirmation must be able to name what it
1383
+ * destroys.** `DELETE` answers `204` with no body, so the counts only ever
1384
+ * appear on the audit event — written *after* the irreversible click. A
1385
+ * dialog built on that can say nothing better than "are you sure?". The
1386
+ * preview returns the *same shape* as the audit record on purpose: the
1387
+ * warning and the receipt then agree by construction, and a disagreement
1388
+ * between them is a real finding rather than two estimates drifting.
1389
+ *
1390
+ * **The snapshot and the event share the org's scope**, and the snapshot
1391
+ * takes an optional `robot_id` filter rather than living at a per-robot
1392
+ * path.
1393
+ *
1394
+ * The first version of this table said the opposite, with a justification
1395
+ * that sounded right and was incomplete: it reasoned only from a page that
1396
+ * has just opened one robot. But the console shows health on the **robot
1397
+ * list** too, and a per-robot path makes that N requests to render one
1398
+ * screen — while the event that must keep it fresh arrives org-wide anyway.
1399
+ * A snapshot and a channel that disagree about scope are not two halves of
1400
+ * one thing; they are two things that have to be reconciled by every
1401
+ * consumer, separately, forever.
1402
+ *
1403
+ * So: same scope, one route, and `?robot_id=` for the narrow question. The
1404
+ * cloud owner proposed this while unblocking the console, and was right.
1405
+ *
1406
+ * This table was missing from the first W6a delta, and a teammate had to ask
1407
+ * three separate people for the paths — which is how a route becomes a fact
1408
+ * that lives only in an inbox.
1409
+ */
1410
+ /**
1411
+ * What a `robot.deleted` audit event carries (W6a).
1412
+ *
1413
+ * A deletion record that says only *that* something was destroyed is a
1414
+ * receipt for an unknown amount. This names it: how many configured slugs,
1415
+ * how many stored samples, how many bytes that freed against the retention
1416
+ * quota, which cameras existed, how much attributed run history went with
1417
+ * it, and whether somebody was watching at the time. Those are the questions
1418
+ * asked afterwards, and afterwards is the one moment the data cannot be
1419
+ * consulted.
1420
+ */
1421
+ export declare const robotDeletionSummary: z.ZodObject<{
1422
+ slug_count: z.ZodNumber;
1423
+ sample_rows: z.ZodNumber;
1424
+ bytes_freed: z.ZodNumber;
1425
+ cameras: z.ZodArray<z.ZodString>;
1426
+ asset_count: z.ZodNumber;
1427
+ asset_bytes_freed: z.ZodNumber;
1428
+ job_run_count: z.ZodNumber;
1429
+ had_live_session: z.ZodBoolean;
1430
+ had_unpublished_draft: z.ZodBoolean;
1431
+ }, z.core.$strip>;
1432
+ export type RobotDeletionSummary = z.infer<typeof robotDeletionSummary>;
1433
+ /**
1434
+ * The query of `DELETE /api/robots/:id`.
1435
+ *
1436
+ * **`force=true` or nothing, and every other value is refused.** The handler
1437
+ * parses the query with this schema and answers `400 validation_error` on
1438
+ * anything else, so `?force=1` and `?force=TRUE` are neither forced nor
1439
+ * quietly un-forced. That is the whole point of the strictness: silently
1440
+ * false was the worst answer available, because a caller who believes they
1441
+ * authorised a cascade and did not then gets a `409` naming the very flag
1442
+ * they passed, and cannot tell which of the two happened.
1443
+ *
1444
+ * Declared as the literal string because it is the only value that does
1445
+ * anything — a `z.boolean()` here would describe a wire shape a query string
1446
+ * cannot carry, and a `z.string()` would document nothing. The MCP door takes
1447
+ * a real boolean and cannot express the ambiguity at all, so the two are one
1448
+ * policy in two vocabularies rather than two policies.
1449
+ */
1450
+ export declare const robotDeleteQuery: z.ZodObject<{
1451
+ force: z.ZodOptional<z.ZodLiteral<"true">>;
1452
+ }, z.core.$strip>;
1453
+ export type RobotDeleteQuery = z.infer<typeof robotDeleteQuery>;
1454
+ /**
1455
+ * The seven health states, declared **once** (W6a review).
1456
+ *
1457
+ * `resourceHealthState` and `resourceHealthEvent` are the snapshot and the
1458
+ * push of the same thing, and they had the same seven values written out
1459
+ * twice, linked by nothing — the artifacts published two independent copies
1460
+ * with no `$ref`. They agreed only because whoever added `unknown` remembered
1461
+ * to add it in both places, on the wave's last contract commit.
1462
+ *
1463
+ * One concept rendering as two artifacts that nothing keeps in step is its
1464
+ * own class of artifact-versus-source defect, distinct from `.default()`
1465
+ * publishing as `required` and from `z.coerce`'s unrepresentable input.
1466
+ */
1467
+ export declare const RESOURCE_HEALTH_STATES: readonly ["ok", "unreachable", "auth_failed", "unreadable_credential", "credential_missing", "stopped_by_config_change", "publish_failed", "unknown"];
1468
+ /**
1469
+ * The health of one thing a developer configured, as the platform currently
1470
+ * sees it (W6a).
1471
+ *
1472
+ * This exists because four separate findings turned out to be one absence:
1473
+ * nothing carried the state of a camera, a source or a credential to a
1474
+ * developer who was not, at that exact moment, pressing a button. A publish
1475
+ * failure after the `201` never reached the viewer holding the token; a
1476
+ * source whose password was wrong failed at config-apply time with nobody
1477
+ * watching and stayed silent until someone pressed "Go live" days later; a
1478
+ * viewer could not learn *why* a stream ended, so the console had to offer
1479
+ * two possibilities and rank neither; and an undecryptable credential
1480
+ * reported as healthy.
1481
+ *
1482
+ * One shape, because four patches against four symptoms is how W5 nearly
1483
+ * wrote a failure report into `publishState` — a field the cloud writes and
1484
+ * reads in exactly one place, which would have been a dead end.
1485
+ *
1486
+ * `reason` is for a human and is **never** built from an exception message:
1487
+ * W6 found a camera password in a log through `log.exception`, and again in
1488
+ * `LiveStartError`'s message, which travels to the cloud on this very path.
1489
+ * Type names and fixed strings only.
1490
+ */
1491
+ export declare const resourceHealthState: z.ZodObject<{
1492
+ robot_id: z.ZodUUID;
1493
+ kind: z.ZodEnum<{
1494
+ camera: "camera";
1495
+ }>;
1496
+ ref: z.ZodString;
1497
+ facet: z.ZodEnum<{
1498
+ source: "source";
1499
+ publish: "publish";
1500
+ }>;
1501
+ state: z.ZodEnum<{
1502
+ unknown: "unknown";
1503
+ ok: "ok";
1504
+ unreachable: "unreachable";
1505
+ auth_failed: "auth_failed";
1506
+ unreadable_credential: "unreadable_credential";
1507
+ credential_missing: "credential_missing";
1508
+ stopped_by_config_change: "stopped_by_config_change";
1509
+ publish_failed: "publish_failed";
1510
+ }>;
1511
+ reason: z.ZodNullable<z.ZodString>;
1512
+ changed_at_ms: z.ZodNumber;
1513
+ }, z.core.$strip>;
1514
+ export type ResourceHealthState = z.infer<typeof resourceHealthState>;
1515
+ /**
1516
+ * The current state of everything in the **org**.
1517
+ *
1518
+ * This doc said "on one robot" until the W6a review found it: the route moved
1519
+ * to org scope in `2bb67c5` and the route table forty lines above spends a
1520
+ * paragraph explaining why the per-robot reading was wrong — while the schema
1521
+ * it describes still said the old thing. Cloud, console and SDK all implement
1522
+ * org-wide correctly; contracts was the only place still saying otherwise,
1523
+ * and it is the first place a fourth consumer reads.
1524
+ *
1525
+ * A channel with no snapshot cannot answer "what is the state now?" for a
1526
+ * page that just loaded — it can only report the next change, which may be
1527
+ * hours away. Both halves or neither.
1528
+ */
1529
+ export declare const resourceHealthListResponse: z.ZodObject<{
1530
+ resources: z.ZodArray<z.ZodObject<{
1531
+ robot_id: z.ZodUUID;
1532
+ kind: z.ZodEnum<{
1533
+ camera: "camera";
1534
+ }>;
1535
+ ref: z.ZodString;
1536
+ facet: z.ZodEnum<{
1537
+ source: "source";
1538
+ publish: "publish";
1539
+ }>;
1540
+ state: z.ZodEnum<{
1541
+ unknown: "unknown";
1542
+ ok: "ok";
1543
+ unreachable: "unreachable";
1544
+ auth_failed: "auth_failed";
1545
+ unreadable_credential: "unreadable_credential";
1546
+ credential_missing: "credential_missing";
1547
+ stopped_by_config_change: "stopped_by_config_change";
1548
+ publish_failed: "publish_failed";
1549
+ }>;
1550
+ reason: z.ZodNullable<z.ZodString>;
1551
+ changed_at_ms: z.ZodNumber;
1552
+ }, z.core.$strip>>;
1553
+ }, z.core.$strip>;
1554
+ export type ResourceHealthListResponse = z.infer<typeof resourceHealthListResponse>;
1555
+ /**
1556
+ * The query of `GET /api/org/health`: optionally one robot instead of the org.
1557
+ *
1558
+ * The narrowing lives in a query rather than at a per-robot path because the
1559
+ * console shows health on the robot list too, and a per-robot path would make
1560
+ * that N requests to render one screen.
1561
+ */
1562
+ export declare const orgHealthQuery: z.ZodObject<{
1563
+ robot_id: z.ZodOptional<z.ZodUUID>;
1564
+ }, z.core.$strip>;
1565
+ export type OrgHealthQuery = z.infer<typeof orgHealthQuery>;
1566
+ /**
1567
+ * Org protection quotas (§12.4) — generous, server-side adjustable, visible
1568
+ * in Settings. Protection against runaway use, not a business model; a later
1569
+ * one docks onto the same dials.
1570
+ */
1571
+ export declare const orgQuotas: z.ZodObject<{
1572
+ max_robots: z.ZodNumber;
1573
+ max_apps: z.ZodNumber;
1574
+ max_end_users: z.ZodNumber;
1575
+ max_retention_bytes: z.ZodNumber;
1576
+ max_retention_writes_per_minute: z.ZodNumber;
1577
+ max_realtime_connections: z.ZodNumber;
1578
+ max_asset_storage_bytes: z.ZodNumber;
1579
+ }, z.core.$strip>;
1580
+ export type OrgQuotas = z.infer<typeof orgQuotas>;
1581
+ /**
1582
+ * What an org is **actually using**, per quota.
1583
+ *
1584
+ * A separate shape rather than `orgQuotas.partial()`, which is what this was
1585
+ * first — and that was wrong in a way its own tests caught: a limit is
1586
+ * `positive()` because a quota of zero would forbid everything, but a
1587
+ * **usage** of zero is the honest answer for every org on the day it signs
1588
+ * up. Reusing one schema for a limit and a measurement is the same mistake as
1589
+ * letting an empty bucket and a zero average share a representation, which
1590
+ * this wave spent a lot of care avoiding one layer up.
1591
+ *
1592
+ * Every field is optional because a quota we do not measure must be
1593
+ * **absent**, never reported as `0` — "not measured" and "measured as zero"
1594
+ * are different facts, and a dashboard that renders the first as the second
1595
+ * is lying quietly.
1596
+ */
1597
+ export declare const orgQuotaUsageCounts: z.ZodObject<{
1598
+ max_robots: z.ZodOptional<z.ZodNumber>;
1599
+ max_apps: z.ZodOptional<z.ZodNumber>;
1600
+ max_end_users: z.ZodOptional<z.ZodNumber>;
1601
+ max_retention_bytes: z.ZodOptional<z.ZodNumber>;
1602
+ max_asset_storage_bytes: z.ZodOptional<z.ZodNumber>;
1603
+ max_retention_writes_per_minute: z.ZodOptional<z.ZodNumber>;
1604
+ max_realtime_connections: z.ZodOptional<z.ZodNumber>;
1605
+ }, z.core.$strip>;
1606
+ export type OrgQuotaUsageCounts = z.infer<typeof orgQuotaUsageCounts>;
1607
+ /** Limits beside what is actually used — a limit alone tells nobody where they stand. */
1608
+ export declare const orgQuotaUsage: z.ZodObject<{
1609
+ quotas: z.ZodObject<{
1610
+ max_robots: z.ZodNumber;
1611
+ max_apps: z.ZodNumber;
1612
+ max_end_users: z.ZodNumber;
1613
+ max_retention_bytes: z.ZodNumber;
1614
+ max_retention_writes_per_minute: z.ZodNumber;
1615
+ max_realtime_connections: z.ZodNumber;
1616
+ max_asset_storage_bytes: z.ZodNumber;
1617
+ }, z.core.$strip>;
1618
+ usage: z.ZodObject<{
1619
+ max_robots: z.ZodOptional<z.ZodNumber>;
1620
+ max_apps: z.ZodOptional<z.ZodNumber>;
1621
+ max_end_users: z.ZodOptional<z.ZodNumber>;
1622
+ max_retention_bytes: z.ZodOptional<z.ZodNumber>;
1623
+ max_asset_storage_bytes: z.ZodOptional<z.ZodNumber>;
1624
+ max_retention_writes_per_minute: z.ZodOptional<z.ZodNumber>;
1625
+ max_realtime_connections: z.ZodOptional<z.ZodNumber>;
1626
+ }, z.core.$strip>;
1627
+ }, z.core.$strip>;
1628
+ export type OrgQuotaUsage = z.infer<typeof orgQuotaUsage>;
1629
+ /** One bucket is one minute. Stated here so the cloud and any client agree without guessing. */
1630
+ export declare const LATENCY_BUCKET_MS = 60000;
1631
+ /**
1632
+ * Latency buckets are **platform telemetry, not a customer datapoint**, and
1633
+ * this short retention is why that distinction was worth making: the cloud
1634
+ * pings every bridge every 2 seconds, ~43 200 measurements per robot per day,
1635
+ * and a sparkline needs about 60 points per hour. Seven days is generous for
1636
+ * what reads it and costs the org's retention quota nothing, because it is not
1637
+ * counted against it.
1638
+ */
1639
+ export declare const BRIDGE_LATENCY_RETENTION_DAYS = 7;
1640
+ /**
1641
+ * Every read of the durable run history and the latency buckets: the three
1642
+ * org-wide ones the fleet overview is built on, and the one robot-scoped door
1643
+ * a client app has into the same table.
1644
+ *
1645
+ * | Route | Query | Answer |
1646
+ * |---|---|---|
1647
+ * | `GET /api/org/jobs` | `jobRunQuery` | `jobRunListResponse` — newest first, cursor-paged over the durable `seq` |
1648
+ * | `GET /api/org/jobs/summary` | `jobRunSummaryQuery` | `jobRunSummary` — three numbers over the window the caller named |
1649
+ * | `GET /api/org/latency` | `orgLatencyQuery` | `orgLatencyResponse` — one series per robot, truncation named |
1650
+ * | `GET /api/robots/:id/jobs/history` | `jobRunQuery` | `jobRunListResponse` — the same read, robot-scoped, developers **and** clients |
1651
+ *
1652
+ * **Written down here because the last time a delta shipped shapes without
1653
+ * their paths, a teammate had to ask three separate people** — see
1654
+ * `robotDeletionSummary`'s neighbouring table, which exists for exactly that
1655
+ * reason. The shapes landed one wave before the routes did, so this table is
1656
+ * the only place the two halves meet.
1657
+ *
1658
+ * Three things about them are worth stating rather than inferring:
1659
+ *
1660
+ * **The three `/api/org/…` reads are org-wide, and `?robot_id=` narrows
1661
+ * them** — the same choice `GET /api/org/health` already made, for the same
1662
+ * reason: the overview screen shows every robot at once, and a per-robot path
1663
+ * would make one screen N requests.
1664
+ *
1665
+ * **Those three are developer-only, and that is a property of their scope,
1666
+ * not of the data.** An org-wide read has no client meaning: an end user is
1667
+ * scoped to the robots their app assigns, never to an org.
1668
+ *
1669
+ * **The client-facing read of the same table is
1670
+ * `GET /api/robots/:id/jobs/history`** — robot-scoped, one route for
1671
+ * developers and clients like every other robot-scoped read (`.../jobs`,
1672
+ * `.../assets`, `.../datapoints`), never a parallel `/api/client/…` twin. An
1673
+ * end user reaches it only when their role's `capabilities.action_history`
1674
+ * says so — otherwise `403 capability_required`, naming the capability — and
1675
+ * sees only runs on slugs their role grants. On this route `?robot_id=` is
1676
+ * not a filter: the path already names the robot, and a query naming a
1677
+ * different one is refused rather than quietly answered about the path's.
1678
+ *
1679
+ * **It discloses the actor, and that is what a developer weighs before
1680
+ * granting the capability.** A `jobRun` names who invoked it — `jobActor`
1681
+ * carries an email — so an end user reading a robot's history learns which
1682
+ * other people have been driving that machine. Robot scope plus a role
1683
+ * capability is what makes that a decision a developer takes per role,
1684
+ * instead of something every session gets: an end-user-facing
1685
+ * `GET /api/org/jobs` would have handed over the whole org's actors with no
1686
+ * such decision anywhere, which is why there is none.
1687
+ *
1688
+ * **A page can be shorter than `limit` while `next_cursor` is non-null**, on
1689
+ * the robot-scoped route specifically: the slug filter is applied to the
1690
+ * page the store returned, so a role granting one slug in ten sees thin — and
1691
+ * sometimes empty — pages. That is what `jobRunListResponse.next_cursor`'s
1692
+ * own doc comment means by a promise rather than an observation; a client
1693
+ * keeps reading until it is null.
1694
+ *
1695
+ * **Neither window is optional, and neither has a default.** A summary over
1696
+ * an unnamed window is a number nobody can reproduce; an unbounded latency
1697
+ * window is a response size chosen by whoever forgot to pass one. Each
1698
+ * query's own doc comment says which of those two reasons applies to it.
1699
+ */
1700
+ /** Seven days x 1440 buckets x N robots is otherwise an unbounded response. */
1701
+ export declare const MAX_LATENCY_BUCKETS_PER_RESPONSE = 20000;
1702
+ export declare const latencyBucket: z.ZodObject<{
1703
+ bucket_at: z.ZodISODateTime;
1704
+ min_ms: z.ZodNullable<z.ZodNumber>;
1705
+ avg_ms: z.ZodNullable<z.ZodNumber>;
1706
+ max_ms: z.ZodNullable<z.ZodNumber>;
1707
+ samples: z.ZodNumber;
1708
+ online_ms: z.ZodNumber;
1709
+ }, z.core.$strip>;
1710
+ export type LatencyBucket = z.infer<typeof latencyBucket>;
1711
+ export declare const robotLatencySeries: z.ZodObject<{
1712
+ robot_id: z.ZodUUID;
1713
+ buckets: z.ZodArray<z.ZodObject<{
1714
+ bucket_at: z.ZodISODateTime;
1715
+ min_ms: z.ZodNullable<z.ZodNumber>;
1716
+ avg_ms: z.ZodNullable<z.ZodNumber>;
1717
+ max_ms: z.ZodNullable<z.ZodNumber>;
1718
+ samples: z.ZodNumber;
1719
+ online_ms: z.ZodNumber;
1720
+ }, z.core.$strip>>;
1721
+ }, z.core.$strip>;
1722
+ export type RobotLatencySeries = z.infer<typeof robotLatencySeries>;
1723
+ /**
1724
+ * `GET /api/org/latency`'s query.
1725
+ *
1726
+ * **Both bounds are required**, for a reason narrower than
1727
+ * `jobRunSummaryQuery`'s: this table holds a bucket per robot per minute for
1728
+ * `BRIDGE_LATENCY_RETENTION_DAYS`, so "everything" is up to 10 080 rows per
1729
+ * robot, and a default window would be a response size chosen by whoever
1730
+ * forgot to pass one. `MAX_LATENCY_BUCKETS_PER_RESPONSE` still bounds the
1731
+ * answer; required bounds are what let a caller decide *which* buckets they
1732
+ * get instead of discovering the ceiling ate the ones they wanted.
1733
+ *
1734
+ * `wireTimestampMs` rather than a plain integer, for its own documented
1735
+ * reason: the union's input branch is what a query string actually carries,
1736
+ * and the year bound is what keeps `253402300800000` from reaching the
1737
+ * Postgres bind path as a `500` where a `400` belongs.
1738
+ */
1739
+ export declare const orgLatencyQuery: z.ZodObject<{
1740
+ from_ms: z.ZodPipe<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>, z.ZodTransform<number, string | number>>, z.ZodNumber>;
1741
+ to_ms: z.ZodPipe<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>, z.ZodTransform<number, string | number>>, z.ZodNumber>;
1742
+ robot_id: z.ZodOptional<z.ZodUUID>;
1743
+ }, z.core.$strict>;
1744
+ export type OrgLatencyQuery = z.infer<typeof orgLatencyQuery>;
1745
+ export declare const orgLatencyResponse: z.ZodObject<{
1746
+ series: z.ZodArray<z.ZodObject<{
1747
+ robot_id: z.ZodUUID;
1748
+ buckets: z.ZodArray<z.ZodObject<{
1749
+ bucket_at: z.ZodISODateTime;
1750
+ min_ms: z.ZodNullable<z.ZodNumber>;
1751
+ avg_ms: z.ZodNullable<z.ZodNumber>;
1752
+ max_ms: z.ZodNullable<z.ZodNumber>;
1753
+ samples: z.ZodNumber;
1754
+ online_ms: z.ZodNumber;
1755
+ }, z.core.$strip>>;
1756
+ }, z.core.$strip>>;
1757
+ from_ms: z.ZodNumber;
1758
+ to_ms: z.ZodNumber;
1759
+ truncated: z.ZodBoolean;
1760
+ truncated_by: z.ZodNullable<z.ZodEnum<{
1761
+ limit: "limit";
1762
+ bytes: "bytes";
1763
+ }>>;
1764
+ }, z.core.$strip>;
1765
+ export type OrgLatencyResponse = z.infer<typeof orgLatencyResponse>;
1766
+ /**
1767
+ * How long a usage window may be, in days. **Refused above this, not capped** —
1768
+ * the rule `jobRunQuery.limit` already states: a caller who asked for more than
1769
+ * the platform will answer is owed a `400` naming the field, not a quietly
1770
+ * shorter answer they will mistake for the whole picture.
1771
+ *
1772
+ * 366 rather than 365, so "the last full year" is expressible in a leap year.
1773
+ */
1774
+ export declare const USAGE_WINDOW_MAX_DAYS = 366;
1775
+ /**
1776
+ * The five things the meter records (spec D1).
1777
+ *
1778
+ * Storage is two metrics and not one summed byte count, for
1779
+ * `org_quotas.max_asset_storage_bytes`'s own reason applied to billing: a sync
1780
+ * grows storage in jumps and time series grow steadily, and one number would
1781
+ * let the first crowd out the second on the invoice the same way it would on
1782
+ * the quota.
1783
+ */
1784
+ export declare const usageMetric: z.ZodEnum<{
1785
+ api_calls: "api_calls";
1786
+ live_session_ms: "live_session_ms";
1787
+ retention_bytes: "retention_bytes";
1788
+ asset_bytes: "asset_bytes";
1789
+ robot_online_ms: "robot_online_ms";
1790
+ }>;
1791
+ export type UsageMetric = z.infer<typeof usageMetric>;
1792
+ /**
1793
+ * A UTC calendar day, `YYYY-MM-DD`.
1794
+ *
1795
+ * A string and not a millisecond instant, because the thing being described is
1796
+ * a day and not a moment: a `Date` here would carry a time and a zone the
1797
+ * column does not have, and every bug in this area starts with one being
1798
+ * silently converted.
1799
+ *
1800
+ * **The regex checks shape, not validity** — `2026-13-45` and `2026-02-30`
1801
+ * both match `\d{4}-\d{2}-\d{2}$` — so the `.refine()` below round-trips the
1802
+ * string through `Date`'s UTC parser and rejects anything that does not come
1803
+ * back unchanged: `2026-13-45` parses to `Invalid Date`, and `2026-02-30`
1804
+ * (which `Date` rolls over rather than rejects) comes back as `2026-03-02`,
1805
+ * a mismatch either way. Same defect class as `auditQuery.from_ms`'s
1806
+ * `253402300800000`: a value that is the right *shape* reaching the Postgres
1807
+ * bind path for a `date` column and answering `500` where `400` belongs.
1808
+ *
1809
+ * **What the published artifact does not say:** `wireTimestampMs`'s own
1810
+ * note applies unchanged — a `.refine()` has no JSON Schema rendering, so
1811
+ * `org-usage-query.schema.json` shows only the shape-checking `pattern` and
1812
+ * a generated client that validates against the artifact alone will believe
1813
+ * `2026-02-30` is acceptable. The runtime is the authority for this field.
1814
+ */
1815
+ export declare const usageDay: z.ZodString;
1816
+ /**
1817
+ * **The window is inclusive at both ends**, unlike every millisecond window in
1818
+ * this file (`from_ms`/`to_ms`, half-open per DEF-062).
1819
+ *
1820
+ * That inconsistency is deliberate and is stated here rather than left to be
1821
+ * discovered: a calendar day is a unit, not an instant, and a person asking for
1822
+ * July will write `from_day=2026-07-01&to_day=2026-07-31`. A half-open day
1823
+ * window would silently drop the 31st.
1824
+ *
1825
+ * Both parameters are required and have no default — the rule `/api/org/latency`
1826
+ * and `/api/org/jobs/summary` already follow. "This month" is a question only
1827
+ * the caller's calendar can answer, and a default window would be a query size
1828
+ * chosen by whoever forgot to pass one.
1829
+ *
1830
+ * **The published artifact cannot express any of this**, and that is worth
1831
+ * saying out loud rather than leaving a reader to assume the JSON Schema is
1832
+ * the whole contract, for `orgLatencyQuery`'s own reason: a cross-field
1833
+ * comparison has no JSON Schema rendering, so `org-usage-query.schema.json`
1834
+ * describes two independent pattern-matched strings and validates an
1835
+ * inverted window happily — the cloud is the only enforcement point for the
1836
+ * ordering. The artifact is equally silent about the inclusivity called out
1837
+ * above: nothing in the shape distinguishes an inclusive day window from a
1838
+ * half-open one, that is a fact about behaviour, not a field (the same gap
1839
+ * `historyQuery`/`historyBucketsResponse` name for their own half-open
1840
+ * boundary). And it says nothing about `USAGE_WINDOW_MAX_DAYS` at all — the
1841
+ * constant is not wired into this schema as a check on the span between
1842
+ * `from_day` and `to_day`; the cloud route is where a caller who asked for
1843
+ * more than the ceiling is refused, so a generated client validating against
1844
+ * the artifact alone can build a five-year window and get a `400` from the
1845
+ * route it did not predict.
1846
+ */
1847
+ export declare const orgUsageQuery: z.ZodObject<{
1848
+ from_day: z.ZodString;
1849
+ to_day: z.ZodString;
1850
+ }, z.core.$strict>;
1851
+ export type OrgUsageQuery = z.infer<typeof orgUsageQuery>;
1852
+ /**
1853
+ * One day's reading for one metric.
1854
+ *
1855
+ * **`app_id` is `null` when the consumer is the org itself** (spec D2), and
1856
+ * what that `null` means for billing depends on the *metric*, not on
1857
+ * `app_id` alone. `api_calls` and `live_session_ms` are attributable to an
1858
+ * app: a `null` app_id on those two is the developer console's own traffic,
1859
+ * deliberately *not* billable. `retention_bytes`, `asset_bytes` and
1860
+ * `robot_online_ms` have no app dimension at all — every row for those three
1861
+ * carries `app_id: null` unconditionally, and every one is billable org-level
1862
+ * consumption. **A reader must check `metric` before treating `app_id ===
1863
+ * null` as "not billable"** — for three of the five metrics that reading is
1864
+ * always wrong.
1865
+ *
1866
+ * `app_name` is `null` whenever `app_id` is, and also when the app has since
1867
+ * been deleted — usage outlives the app it was attributed to, because an org
1868
+ * still owes for what it used. A UUID alone on an invoice line helps nobody,
1869
+ * and a copy of the name stored on every row would be a second truth that
1870
+ * drifts on the first rename.
1871
+ *
1872
+ * **What this number cannot promise**, and the bound is conditional rather
1873
+ * than flat. `api_calls` and `live_session_ms` are aggregated in memory and
1874
+ * written every 30 seconds.
1875
+ *
1876
+ * *While those writes are landing*, a `kill -9` loses up to 30 seconds of
1877
+ * counting — never more, and never against the caller, since an unflushed
1878
+ * count is simply not billed.
1879
+ *
1880
+ * *While they are failing* — an unreachable database, say — that bound does
1881
+ * not hold at all: everything counted since the last successful flush is
1882
+ * held in memory, deliberately uncapped, and a `kill -9` loses all of it.
1883
+ * The trade is intentional (dropping billing data to bound process memory is
1884
+ * the worse half of it), but "at most one interval" describes a platform
1885
+ * whose writes are landing, not a guarantee that survives an outage. This
1886
+ * sentence used to say "never more", and it was false.
1887
+ *
1888
+ * A row the database rejects **permanently** — most concretely one whose org
1889
+ * has been deleted since the count, since a usage row's `org_id` is `ON
1890
+ * DELETE NO ACTION` — is written off instead: given up on, reported with a
1891
+ * count, and never billed. That is a deliberate loss, and it is the smaller
1892
+ * one. Before it, a single such row failed the whole batched write on every
1893
+ * retry, forever, and stopped `api_calls` and `live_session_ms` reaching the
1894
+ * database for **every** org on the platform.
1895
+ *
1896
+ * A graceful shutdown loses nothing **provided its final flush succeeds**.
1897
+ * If that write fails, the process reports how many rows it is carrying and
1898
+ * exits carrying them — there is no second attempt, because there is no
1899
+ * longer a process to make one.
1900
+ *
1901
+ * The other three metrics never travel this path. They are sampled from
1902
+ * other tables on their own timer and can lag; what a missed sample costs,
1903
+ * per metric, is in the docs' `/api/org/usage` notes.
1904
+ */
1905
+ export declare const usageRow: z.ZodObject<{
1906
+ app_id: z.ZodNullable<z.ZodUUID>;
1907
+ app_name: z.ZodNullable<z.ZodString>;
1908
+ metric: z.ZodEnum<{
1909
+ api_calls: "api_calls";
1910
+ live_session_ms: "live_session_ms";
1911
+ retention_bytes: "retention_bytes";
1912
+ asset_bytes: "asset_bytes";
1913
+ robot_online_ms: "robot_online_ms";
1914
+ }>;
1915
+ day: z.ZodString;
1916
+ value: z.ZodNumber;
1917
+ }, z.core.$strip>;
1918
+ export type UsageRow = z.infer<typeof usageRow>;
1919
+ /** The window is echoed back for `orgLatencyResponse`'s reason: a rendered total has to be able to say which window it describes. */
1920
+ export declare const orgUsageResponse: z.ZodObject<{
1921
+ rows: z.ZodArray<z.ZodObject<{
1922
+ app_id: z.ZodNullable<z.ZodUUID>;
1923
+ app_name: z.ZodNullable<z.ZodString>;
1924
+ metric: z.ZodEnum<{
1925
+ api_calls: "api_calls";
1926
+ live_session_ms: "live_session_ms";
1927
+ retention_bytes: "retention_bytes";
1928
+ asset_bytes: "asset_bytes";
1929
+ robot_online_ms: "robot_online_ms";
1930
+ }>;
1931
+ day: z.ZodString;
1932
+ value: z.ZodNumber;
1933
+ }, z.core.$strip>>;
1934
+ from_day: z.ZodString;
1935
+ to_day: z.ZodString;
1936
+ }, z.core.$strip>;
1937
+ export type OrgUsageResponse = z.infer<typeof orgUsageResponse>;
1938
+ /** `PATCH /api/robots/:id` — rename the robot. Display-only: nothing references robot names. */
1939
+ export declare const patchRobotRequest: z.ZodObject<{
1940
+ name: z.ZodString;
1941
+ }, z.core.$strict>;
1942
+ export type PatchRobotRequest = z.infer<typeof patchRobotRequest>;
1943
+ /**
1944
+ * `POST /api/robots/:id/config/rename-slug` — atomic server-side rename:
1945
+ * rewrites the **draft** config, every app-role grant carrying
1946
+ * `{robot_id, from}`, and the recorded history rows, in one transaction.
1947
+ * Job runs and audit events keep the old slug as historical fact. The
1948
+ * published config is immutable, so the caller must publish afterwards
1949
+ * (`requires_publish`); samples arriving between rename and the applied
1950
+ * publish still land under the old slug — named residual, not migrated.
1951
+ * Second residual in that same window: grants and the draft already name
1952
+ * `to`, but the still-published config exposes only `from` until the
1953
+ * publish lands — an end user's app has no working name for the datapoint
1954
+ * at all for however long that gap lasts, since `to` isn't published yet
1955
+ * and `from` no longer has a grant behind it. The console must publish
1956
+ * immediately after a rename to keep this window short; nothing server-side
1957
+ * closes it.
1958
+ * This schema only enforces slug *shape*; whether `to` is reserved or
1959
+ * already in use on this robot is checked once, behind the cloud's
1960
+ * `validation.ts` door — one door, not a second copy of that rule here.
1961
+ */
1962
+ export declare const renameSlugRequest: z.ZodObject<{
1963
+ from: z.ZodString;
1964
+ to: z.ZodString;
1965
+ }, z.core.$strict>;
1966
+ export type RenameSlugRequest = z.infer<typeof renameSlugRequest>;
1967
+ export declare const renameSlugResponse: z.ZodObject<{
1968
+ rewritten_grants: z.ZodNumber;
1969
+ history_moved: z.ZodBoolean;
1970
+ requires_publish: z.ZodLiteral<true>;
1971
+ }, z.core.$strip>;
1972
+ export type RenameSlugResponse = z.infer<typeof renameSlugResponse>;
1973
+ /**
1974
+ * `GET /api/robots/:id/config/slug-usage/:slug` — what a rename would touch;
1975
+ * feeds the console's confirm dialog.
1976
+ *
1977
+ * `alert_count` (spec `2026-08-28-alerts-and-datapoint-modal-design`, D5)
1978
+ * joined the atomic rename transaction alongside grants and history: alerts
1979
+ * are keyed by `(robot_id, slug)` too, and a rename that silently moved the
1980
+ * alert row while the usage preview stayed silent about it would show a
1981
+ * developer a smaller blast radius than the rename actually has.
1982
+ */
1983
+ export declare const slugUsageResponse: z.ZodObject<{
1984
+ grant_count: z.ZodNumber;
1985
+ app_identifiers: z.ZodArray<z.ZodString>;
1986
+ has_recorded_history: z.ZodBoolean;
1987
+ alert_count: z.ZodNumber;
1988
+ }, z.core.$strip>;
1989
+ export type SlugUsageResponse = z.infer<typeof slugUsageResponse>;