@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
@@ -0,0 +1,129 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Audit (spec §16). Every state-changing interaction is recorded and **every
4
+ * entry carries its actor — never anonymous** (§16.2). Reads are not audited.
5
+ *
6
+ * W3 writes the events that exist once identities do: logins, failed logins,
7
+ * end-user management, config publishes, bridge connect/disconnect. The view
8
+ * with filters, CSV export and the 90-day retention window is W6 (André,
9
+ * 2026-08-10) — same shape of work as the history API.
10
+ */
11
+ /**
12
+ * The kinds of actor the platform knows. `label` is what a human reads in the
13
+ * log — an email, a key name, a robot name — so the console never has to
14
+ * resolve four different id kinds to render a row.
15
+ *
16
+ * **`end_user` stays, and it stays for the rows already written.** The
17
+ * two-space cut (2026-09-05, D1) replaced the org's one user pool with
18
+ * Fleetless users and per-app app users; every new row an app user writes
19
+ * carries `app_user`. But an audit log is the one thing this platform must
20
+ * never rewrite, and there are stored rows whose `kind` is `end_user`. Dropping
21
+ * the member would leave those rows failing their own schema — a log that
22
+ * cannot be read back is worse than one carrying a retired word.
23
+ *
24
+ * So this enum is deliberately **wider than what any producer emits**: nothing
25
+ * writes `end_user` any more, and nothing may start again. That is the kind of
26
+ * claim this repository has been wrong about before by leaving it unsaid, so it
27
+ * is said here rather than inferred from a `grep` somebody runs in a year.
28
+ *
29
+ * `developer` is a Fleetless user. It kept its name through both redesigns
30
+ * because it was always right about what it named: the person who configures
31
+ * robots.
32
+ */
33
+ export declare const auditActor: z.ZodObject<{
34
+ kind: z.ZodEnum<{
35
+ developer: "developer";
36
+ server_key: "server_key";
37
+ bridge: "bridge";
38
+ end_user: "end_user";
39
+ app_user: "app_user";
40
+ }>;
41
+ id: z.ZodUUID;
42
+ label: z.ZodString;
43
+ }, z.core.$strip>;
44
+ export type AuditActor = z.infer<typeof auditActor>;
45
+ export declare const auditEvent: z.ZodObject<{
46
+ id: z.ZodUUID;
47
+ org_id: z.ZodUUID;
48
+ at: z.ZodISODateTime;
49
+ seq: z.ZodNumber;
50
+ actor: z.ZodObject<{
51
+ kind: z.ZodEnum<{
52
+ developer: "developer";
53
+ server_key: "server_key";
54
+ bridge: "bridge";
55
+ end_user: "end_user";
56
+ app_user: "app_user";
57
+ }>;
58
+ id: z.ZodUUID;
59
+ label: z.ZodString;
60
+ }, z.core.$strip>;
61
+ action: z.ZodString;
62
+ target: z.ZodNullable<z.ZodObject<{
63
+ kind: z.ZodString;
64
+ id: z.ZodString;
65
+ label: z.ZodString;
66
+ }, z.core.$strip>>;
67
+ details: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
68
+ }, z.core.$strip>;
69
+ export type AuditEvent = z.infer<typeof auditEvent>;
70
+ export declare const auditQuery: z.ZodObject<{
71
+ before_seq: z.ZodOptional<z.ZodPipe<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>, z.ZodTransform<number, string | number>>, z.ZodNumber>>;
72
+ limit: z.ZodOptional<z.ZodPipe<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>, z.ZodTransform<number, string | number>>, z.ZodNumber>>;
73
+ action: z.ZodOptional<z.ZodString>;
74
+ action_prefix: z.ZodOptional<z.ZodString>;
75
+ actor_id: z.ZodOptional<z.ZodUUID>;
76
+ target_kind: z.ZodOptional<z.ZodString>;
77
+ from_ms: z.ZodOptional<z.ZodPipe<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>, z.ZodTransform<number, string | number>>, z.ZodNumber>>;
78
+ to_ms: z.ZodOptional<z.ZodPipe<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>, z.ZodTransform<number, string | number>>, z.ZodNumber>>;
79
+ }, z.core.$strict>;
80
+ export type AuditQuery = z.infer<typeof auditQuery>;
81
+ export declare const auditListResponse: z.ZodObject<{
82
+ events: z.ZodArray<z.ZodObject<{
83
+ id: z.ZodUUID;
84
+ org_id: z.ZodUUID;
85
+ at: z.ZodISODateTime;
86
+ seq: z.ZodNumber;
87
+ actor: z.ZodObject<{
88
+ kind: z.ZodEnum<{
89
+ developer: "developer";
90
+ server_key: "server_key";
91
+ bridge: "bridge";
92
+ end_user: "end_user";
93
+ app_user: "app_user";
94
+ }>;
95
+ id: z.ZodUUID;
96
+ label: z.ZodString;
97
+ }, z.core.$strip>;
98
+ action: z.ZodString;
99
+ target: z.ZodNullable<z.ZodObject<{
100
+ kind: z.ZodString;
101
+ id: z.ZodString;
102
+ label: z.ZodString;
103
+ }, z.core.$strip>>;
104
+ details: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
105
+ }, z.core.$strip>>;
106
+ next_cursor: z.ZodNullable<z.ZodNumber>;
107
+ }, z.core.$strip>;
108
+ export type AuditListResponse = z.infer<typeof auditListResponse>;
109
+ /**
110
+ * **What a CSV export of this log looks like (DEF-123, spec §16.3).**
111
+ *
112
+ * The column order lives here because otherwise the cloud and the console
113
+ * would each carry their own, and nobody would notice them drifting apart
114
+ * until a spreadsheet at a customer had the wrong headings. One order, one
115
+ * place.
116
+ *
117
+ * `details` is written as JSON into a single cell. That is ugly and honest:
118
+ * the alternative is leaving it out, and an audit export that omits *what
119
+ * happened* is not an audit export.
120
+ */
121
+ export declare const AUDIT_CSV_COLUMNS: readonly ["seq", "at", "actor_kind", "actor_id", "action", "target_kind", "target_id", "target_label", "details"];
122
+ /**
123
+ * Spec §16.3: the audit log is kept for **90 days**.
124
+ *
125
+ * A constant here so the cloud does not derive it a second time — the same
126
+ * reasoning as `ASSET_UPLOAD_MAX_BYTES`, and the same register row that found
127
+ * there is no purge touching audit rows at all.
128
+ */
129
+ export declare const AUDIT_RETENTION_DAYS = 90;
package/dist/audit.js ADDED
@@ -0,0 +1,238 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ import { z } from 'zod';
3
+ import { wireSeqCursor, wireTimestampMs } from './common.js';
4
+ /**
5
+ * Audit (spec §16). Every state-changing interaction is recorded and **every
6
+ * entry carries its actor — never anonymous** (§16.2). Reads are not audited.
7
+ *
8
+ * W3 writes the events that exist once identities do: logins, failed logins,
9
+ * end-user management, config publishes, bridge connect/disconnect. The view
10
+ * with filters, CSV export and the 90-day retention window is W6 (André,
11
+ * 2026-08-10) — same shape of work as the history API.
12
+ */
13
+ /**
14
+ * The kinds of actor the platform knows. `label` is what a human reads in the
15
+ * log — an email, a key name, a robot name — so the console never has to
16
+ * resolve four different id kinds to render a row.
17
+ *
18
+ * **`end_user` stays, and it stays for the rows already written.** The
19
+ * two-space cut (2026-09-05, D1) replaced the org's one user pool with
20
+ * Fleetless users and per-app app users; every new row an app user writes
21
+ * carries `app_user`. But an audit log is the one thing this platform must
22
+ * never rewrite, and there are stored rows whose `kind` is `end_user`. Dropping
23
+ * the member would leave those rows failing their own schema — a log that
24
+ * cannot be read back is worse than one carrying a retired word.
25
+ *
26
+ * So this enum is deliberately **wider than what any producer emits**: nothing
27
+ * writes `end_user` any more, and nothing may start again. That is the kind of
28
+ * claim this repository has been wrong about before by leaving it unsaid, so it
29
+ * is said here rather than inferred from a `grep` somebody runs in a year.
30
+ *
31
+ * `developer` is a Fleetless user. It kept its name through both redesigns
32
+ * because it was always right about what it named: the person who configures
33
+ * robots.
34
+ */
35
+ export const auditActor = z.object({
36
+ kind: z.enum(['developer', 'end_user', 'app_user', 'server_key', 'bridge']),
37
+ id: z.uuid(),
38
+ label: z.string().min(1).max(200),
39
+ });
40
+ export const auditEvent = z.object({
41
+ id: z.uuid(),
42
+ org_id: z.uuid(),
43
+ at: z.iso.datetime(),
44
+ /**
45
+ * A monotonic counter, ascending in write order, unique across the log
46
+ * (W6b).
47
+ *
48
+ * `at` is not a total order. Two events written in the same millisecond —
49
+ * a login and the config publish it enables, a cascade writing several
50
+ * rows — sort against each other arbitrarily, and "arbitrarily" means
51
+ * *differently on each query*. A reader paging through "newest first" can
52
+ * therefore see one of them twice and the other not at all, which is the
53
+ * one failure mode an audit log may not have: a record that is present and
54
+ * invisible.
55
+ *
56
+ * It is also the only correct **cursor** for paging this log, for the same
57
+ * reason: a cursor that is not unique either skips rows or repeats them at
58
+ * every page boundary. No cursor parameter exists on `GET /api/audit` yet —
59
+ * the route returns the whole log — and that is stated here rather than
60
+ * implied, because a contract that describes a capability the API does not
61
+ * have is the defect this project keeps finding. When paging is added it
62
+ * uses this field; nothing else in this shape can carry it.
63
+ *
64
+ * Required, not optional: an event without a sequence cannot be ordered
65
+ * against one that has it, and a log with two orderings has none.
66
+ */
67
+ seq: z.number().int().positive(),
68
+ actor: auditActor,
69
+ /** Stable dotted name, e.g. `app_user.login`, `config.published`. */
70
+ action: z.string().min(1).max(80),
71
+ /**
72
+ * What the action was about, if anything — a robot, an app, a user. Free
73
+ * of ids the console cannot resolve: carry the label with it.
74
+ */
75
+ target: z
76
+ .object({
77
+ kind: z.string().min(1).max(40),
78
+ id: z.string().min(1),
79
+ label: z.string().min(1).max(200),
80
+ })
81
+ .nullable(),
82
+ /**
83
+ * Action-specific extras.
84
+ *
85
+ * **Nothing redacts this.** There is no denylist, no allowlist and no pass
86
+ * over what a call site puts here — the call site is responsible, and this
87
+ * comment is where that responsibility is written down. Since the org event
88
+ * stream, the same object also reaches every developer with the console
89
+ * overview open, not only whoever later reads the audit log.
90
+ *
91
+ * So: never credentials, never tokens. That is a rule, not a guarantee the
92
+ * schema enforces.
93
+ */
94
+ details: z.record(z.string(), z.unknown()).nullable(),
95
+ });
96
+ /**
97
+ * **How this log is read (W9d, DEF-078 and DEF-123).**
98
+ *
99
+ * Until now `GET /api/audit` returned the **whole** log — no filters, no
100
+ * cursor. `auditEvent.seq`'s own comment has said so plainly since W6b rather
101
+ * than describing a capability the API does not have; this shape builds
102
+ * exactly what that comment announced.
103
+ *
104
+ * **The cursor is `seq`, and no other field can be.** `at` is not a total
105
+ * order: two events written in the same millisecond sort differently on every
106
+ * query, so a cursor on `at` either skips rows or repeats them at each page
107
+ * boundary — which for an audit log means an entry that is present and
108
+ * invisible.
109
+ *
110
+ * `before_seq` rather than `after_seq`, because this log is read **newest
111
+ * first**: the next page is older, not newer.
112
+ *
113
+ * **Filters are part of the same work, not a later garnish.** A console view
114
+ * without them is a page with nothing to filter by — the register row says
115
+ * exactly that, which is why the two rows are one piece of work.
116
+ */
117
+ /**
118
+ * A unix-millisecond bound a Postgres `timestamptz` can actually hold.
119
+ *
120
+ * Years 1..9999: below that Postgres has no year zero, above it year 10000
121
+ * needs the ISO extended-year form its bind path does not accept. Comfortably
122
+ * wider than any instant this platform will legitimately be asked about, so
123
+ * the bound costs nothing real and catches every value found to 500.
124
+ *
125
+ * @see wireTimestampMs — moved to `common.ts` when `jobRunQuery` needed the same bound.
126
+ */
127
+ const auditTimestampMs = wireTimestampMs;
128
+ export const auditQuery = z.object({
129
+ /** Only events with a smaller `seq` — the next, older page. */
130
+ before_seq: wireSeqCursor.optional(),
131
+ /**
132
+ * Same shape as DEF-059's `historyQuery.limit`: a union whose input branch
133
+ * **is the wire**. A `z.coerce` cannot be published — zod renders the
134
+ * coercion's result in either `io` direction, so the artifact would describe
135
+ * a shape a query string can never carry.
136
+ */
137
+ limit: z
138
+ .union([z.string().regex(/^\d{1,4}$/), z.number().int()])
139
+ .transform((v) => Number(v))
140
+ .pipe(z.number().int().positive().max(500))
141
+ .optional(),
142
+ /** Exact action name, e.g. `config.published`. No prefix matching: a filter that matches more than it says is not one. */
143
+ action: z.string().min(1).max(80).optional(),
144
+ /**
145
+ * Everything under a dotted prefix, e.g. `server_key.` for all three
146
+ * server-key actions.
147
+ *
148
+ * **A separate parameter, not a widening of `action`.** The sentence on
149
+ * `action` above — a filter that matches more than it says is not one —
150
+ * still stands; this is a different question with a name that says which
151
+ * one it is. Setting both is refused rather than resolved, because a query
152
+ * naming an exact action *and* a prefix is a caller mistake, not a
153
+ * combination anyone should have to guess the meaning of.
154
+ *
155
+ * **The published artifact cannot express that refusal**: a cross-field
156
+ * `.refine()` has no JSON Schema rendering, so `audit-query.schema.json`
157
+ * describes two independent optional strings and validates both-at-once
158
+ * happily. The cloud is the only enforcement point — the same residual
159
+ * `orgLatencyQuery` and `orgUsageQuery` already name.
160
+ */
161
+ action_prefix: z.string().min(1).max(80).optional(),
162
+ /**
163
+ * Only events by this actor.
164
+ *
165
+ * **`z.uuid()`, because the column is one (Argus-W9, W9 review).** This was
166
+ * `z.string().min(1).max(200)`, so any non-uuid value reached Postgres as a
167
+ * uuid parameter and threw: `?actor_id=not-a-uuid` answered **500
168
+ * `internal_error`**, on the list route and the export alike.
169
+ *
170
+ * Not a SQL-injection finding — Drizzle parameterises, and `' or 1=1--`
171
+ * failed at the same cast. It is a **500 where a 400 belongs**, and a 500 is
172
+ * the answer that explains nothing.
173
+ *
174
+ * The place is the part worth keeping: **this same wave pulled
175
+ * `refuseIfNotUuid` through ~15 call sites** so a typo could be told from a
176
+ * deletion — and the brand-new filter, whose field has exactly that shape,
177
+ * is the one that did not get it. A rule applied to the sites in front of
178
+ * you is not a rule applied to the class.
179
+ */
180
+ actor_id: z.uuid().optional(),
181
+ /** Only events about this kind of target, e.g. `robot`. */
182
+ target_kind: z.string().min(1).max(40).optional(),
183
+ /**
184
+ * Absolute bounds in unix milliseconds, **half-open `[from, to)`** — the
185
+ * same rule the history shapes follow (DEF-062).
186
+ *
187
+ * **Bounded to years 1..9999, and the bound is borrowed rather than
188
+ * invented.** `nonnegative()` alone let `253402300800000` (year 10000)
189
+ * through, where the Postgres bind path has no representation and the route
190
+ * answered 500 — measured either side of the edge: `253402300799000` → 200,
191
+ * `253402300800000` → 500 (Argus-W9). `history-query.ts`'s `parseTimeExprMs`
192
+ * already carries exactly this range, with M3's reasoning for why
193
+ * `Number.isSafeInteger` is wider than what a timestamp can be; this is that
194
+ * same number, not a second one that happens to agree.
195
+ */
196
+ from_ms: auditTimestampMs.optional(),
197
+ to_ms: auditTimestampMs.optional(),
198
+ })
199
+ .strict()
200
+ .refine((query) => !(query.action !== undefined && query.action_prefix !== undefined), {
201
+ message: 'action and action_prefix cannot be combined',
202
+ path: ['action_prefix'],
203
+ });
204
+ export const auditListResponse = z.object({
205
+ events: z.array(auditEvent),
206
+ /**
207
+ * The `seq` a caller sends as `before_seq` to keep reading — or `null` when
208
+ * there is nothing further.
209
+ *
210
+ * **`null` means the end, and that is a promise rather than an
211
+ * observation.** A caller who instead compares `events.length` against
212
+ * `limit` is wrong the moment a filter makes a page thin: a short page does
213
+ * not mean *no more* here. The same distinction `historySamples` was given
214
+ * `truncated` for.
215
+ */
216
+ next_cursor: z.number().int().positive().nullable(),
217
+ });
218
+ /**
219
+ * **What a CSV export of this log looks like (DEF-123, spec §16.3).**
220
+ *
221
+ * The column order lives here because otherwise the cloud and the console
222
+ * would each carry their own, and nobody would notice them drifting apart
223
+ * until a spreadsheet at a customer had the wrong headings. One order, one
224
+ * place.
225
+ *
226
+ * `details` is written as JSON into a single cell. That is ugly and honest:
227
+ * the alternative is leaving it out, and an audit export that omits *what
228
+ * happened* is not an audit export.
229
+ */
230
+ export const AUDIT_CSV_COLUMNS = ['seq', 'at', 'actor_kind', 'actor_id', 'action', 'target_kind', 'target_id', 'target_label', 'details'];
231
+ /**
232
+ * Spec §16.3: the audit log is kept for **90 days**.
233
+ *
234
+ * A constant here so the cloud does not derive it a second time — the same
235
+ * reasoning as `ASSET_UPLOAD_MAX_BYTES`, and the same register row that found
236
+ * there is no purge touching audit rows at all.
237
+ */
238
+ export const AUDIT_RETENTION_DAYS = 90;