@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,606 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * **App users: the per-app identity space** (spec `2026-09-05-app-user-auth`,
4
+ * D1–D7).
5
+ *
6
+ * The 2026-08-29 model put developers and end users into one pool per org,
7
+ * tied apps to groups, and let an org admin enter an app only by
8
+ * impersonation. It modelled the wrong thing: the people who configure robots
9
+ * in the console and the people who use a developer's app are different
10
+ * populations with different lifecycles, and every mechanism that connected
11
+ * them — groups, assignments, impersonation, the app-branded portal pages —
12
+ * was cost without a product reason.
13
+ *
14
+ * So there are now **two identity spaces and nothing joins them**:
15
+ *
16
+ * - *Fleetless users* (`identity.ts`) — the org's team. Email globally unique,
17
+ * tier `owner | developer`, Fleetless password, console access.
18
+ * - *app users* (this file) — one app each. Email unique **per app**,
19
+ * case-insensitively. The same address may exist in several apps of one org
20
+ * as unrelated accounts, and a Fleetless user who wants to use an app
21
+ * registers or is invited like anybody else.
22
+ *
23
+ * **Fleetless shows an app user no page** (D2). The developer's own UI owns
24
+ * every screen and calls the JSON client-auth API (`client-auth.ts`). The one
25
+ * Fleetless-rendered surface an app user can reach is the problem page for an
26
+ * OIDC callback whose state no longer resolves to a redirect URI — every other
27
+ * error is redirected to the app to render. That is why the four URLs on
28
+ * `appAuthConfig` exist: Fleetless mails a link, and the link points into the
29
+ * app.
30
+ */
31
+ /** App-user display names share the Fleetless-user bound, so a rename cannot be legal in one space and refused in the other. */
32
+ export declare const APP_USER_DISPLAY_NAME_MAX = 120;
33
+ /**
34
+ * **A provider slug — hyphenated, and deliberately not the ROS slug grammar.**
35
+ *
36
+ * `appIdentifier` is `slug`: lowercase and *underscore*-separated, because it
37
+ * names something that also appears in ROS. A provider slug appears in a URL
38
+ * path (`/api/client/oidc/:slug/start`) and on the developer's own sign-in
39
+ * buttons, where a hyphen is the conventional spelling — `azure-ad`, not
40
+ * `azure_ad`.
41
+ *
42
+ * The two grammars are one character apart, which is exactly why this is its
43
+ * own export with its own tests rather than a reuse: reusing the wrong one
44
+ * would be invisible until a customer typed a hyphen.
45
+ */
46
+ export declare const providerSlug: z.ZodString;
47
+ /**
48
+ * **The three states an app user can be in, and the order is the lifecycle.**
49
+ *
50
+ * - `pending_verification` — self-registered, mail sent, cannot log in yet
51
+ * (D6). Without this state the domain whitelist would prove nothing: anybody
52
+ * could claim any address at an allowed domain.
53
+ * - `active` — may log in.
54
+ * - `blocked` — may not, and every refusal is the same `invalid_credentials`
55
+ * a wrong password gets (§4). A block that announced itself would be an
56
+ * account-enumeration oracle with an extra step.
57
+ *
58
+ * `pending_verification` is reached exactly once and left only by spending the
59
+ * mailed token, which is why `patchAppUserRequest` cannot set it: see there.
60
+ */
61
+ export declare const appUserStatus: z.ZodEnum<{
62
+ pending_verification: "pending_verification";
63
+ active: "active";
64
+ blocked: "blocked";
65
+ }>;
66
+ export type AppUserStatus = z.infer<typeof appUserStatus>;
67
+ /**
68
+ * **A user of one app.** Not a user of the org: `app_id` is the whole scope,
69
+ * and the uniqueness constraint the cloud enforces is `(app_id, lower(email))`
70
+ * rather than a global one. The same person at two apps of one org is two
71
+ * unrelated rows, by design (D1).
72
+ */
73
+ export declare const appUser: z.ZodObject<{
74
+ id: z.ZodUUID;
75
+ app_id: z.ZodUUID;
76
+ email: z.ZodEmail;
77
+ display_name: z.ZodNullable<z.ZodString>;
78
+ role_id: z.ZodUUID;
79
+ status: z.ZodEnum<{
80
+ pending_verification: "pending_verification";
81
+ active: "active";
82
+ blocked: "blocked";
83
+ }>;
84
+ has_password: z.ZodBoolean;
85
+ providers: z.ZodArray<z.ZodString>;
86
+ last_login_at: z.ZodNullable<z.ZodISODateTime>;
87
+ created_at: z.ZodISODateTime;
88
+ }, z.core.$strip>;
89
+ export type AppUser = z.infer<typeof appUser>;
90
+ /** `GET /api/apps/:id/users` — every app user of one app, never null: an app with no users answers an empty array. */
91
+ export declare const appUserListResponse: z.ZodObject<{
92
+ users: z.ZodArray<z.ZodObject<{
93
+ id: z.ZodUUID;
94
+ app_id: z.ZodUUID;
95
+ email: z.ZodEmail;
96
+ display_name: z.ZodNullable<z.ZodString>;
97
+ role_id: z.ZodUUID;
98
+ status: z.ZodEnum<{
99
+ pending_verification: "pending_verification";
100
+ active: "active";
101
+ blocked: "blocked";
102
+ }>;
103
+ has_password: z.ZodBoolean;
104
+ providers: z.ZodArray<z.ZodString>;
105
+ last_login_at: z.ZodNullable<z.ZodISODateTime>;
106
+ created_at: z.ZodISODateTime;
107
+ }, z.core.$strip>>;
108
+ }, z.core.$strip>;
109
+ export type AppUserListResponse = z.infer<typeof appUserListResponse>;
110
+ /**
111
+ * **A developer creating an app user directly, password and all** — the door
112
+ * that exists so a developer can seed an account without waiting for a mail.
113
+ *
114
+ * `.strict()`: `status` is absent and cannot arrive. A user created here is
115
+ * `active`, because a developer who typed the password has already vouched for
116
+ * the address; letting the body choose would give one route two lifecycles.
117
+ */
118
+ export declare const createAppUserRequest: z.ZodObject<{
119
+ email: z.ZodEmail;
120
+ password: z.ZodString;
121
+ display_name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
122
+ role_id: z.ZodOptional<z.ZodUUID>;
123
+ }, z.core.$strict>;
124
+ export type CreateAppUserRequest = z.infer<typeof createAppUserRequest>;
125
+ /**
126
+ * `PATCH /api/apps/:id/users/:userId` — **what a developer may change, and
127
+ * what is absent rather than merely un-required.**
128
+ *
129
+ * `email` is not here: it is the identifier of the account, the value every
130
+ * invitation, reset link and audit line names, and a PATCH that could change
131
+ * it is both an account-takeover surface and a uniqueness race. Strict, so
132
+ * offering it is a refusal rather than a silently dropped field.
133
+ *
134
+ * **`status` admits only `active` and `blocked`.** `pending_verification` is
135
+ * reached once, by self-registration, and left by spending the mailed token
136
+ * (D6). A developer able to set it back could void a verified address without
137
+ * the user ever seeing a mail, and there is no route out of that state that
138
+ * does not require a token nobody re-sent. So the narrower enum is the rule,
139
+ * stated in the schema rather than left to a handler to remember.
140
+ */
141
+ export declare const patchAppUserRequest: z.ZodObject<{
142
+ display_name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
143
+ role_id: z.ZodOptional<z.ZodUUID>;
144
+ status: z.ZodOptional<z.ZodEnum<{
145
+ active: "active";
146
+ blocked: "blocked";
147
+ }>>;
148
+ }, z.core.$strict>;
149
+ export type PatchAppUserRequest = z.infer<typeof patchAppUserRequest>;
150
+ /**
151
+ * **Inviting an address into an app.** The invitation carries the role, so the
152
+ * person who accepts it lands with the access the developer chose rather than
153
+ * with a default somebody has to remember to change afterwards.
154
+ */
155
+ export declare const createAppInvitationRequest: z.ZodObject<{
156
+ email: z.ZodEmail;
157
+ role_id: z.ZodOptional<z.ZodUUID>;
158
+ display_name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
159
+ send_mail: z.ZodBoolean;
160
+ }, z.core.$strict>;
161
+ export type CreateAppInvitationRequest = z.infer<typeof createAppInvitationRequest>;
162
+ /**
163
+ * The invitation as issued.
164
+ *
165
+ * **`accept_url` is nullable, and that is a policy rather than a convenience.**
166
+ * The link points into the developer's app, at their configured `invite_url`.
167
+ * An app that has configured none has nowhere for it to point, so there is no
168
+ * link to hand back — `null` says that outright, where an absent key would be
169
+ * indistinguishable from a mapper that dropped the field and a fabricated
170
+ * Fleetless-hosted URL would name a page this product does not serve (D2).
171
+ */
172
+ export declare const appInvitation: z.ZodObject<{
173
+ id: z.ZodUUID;
174
+ app_id: z.ZodUUID;
175
+ email: z.ZodEmail;
176
+ role_id: z.ZodUUID;
177
+ expires_at: z.ZodISODateTime;
178
+ accept_url: z.ZodNullable<z.ZodURL>;
179
+ mail: z.ZodEnum<{
180
+ sent: "sent";
181
+ not_requested: "not_requested";
182
+ not_configured: "not_configured";
183
+ failed: "failed";
184
+ }>;
185
+ }, z.core.$strip>;
186
+ export type AppInvitation = z.infer<typeof appInvitation>;
187
+ /**
188
+ * A pending invitation as the developer sees it in the list — **without its
189
+ * `accept_url`**, and that omission is the point.
190
+ *
191
+ * The list exists so a developer can see what is outstanding and revoke it.
192
+ * Neither needs the token, and a list that carries it turns every screenshot,
193
+ * log line and browser-history entry of that page into live credentials for
194
+ * somebody else's account. The same rule `pendingUserInvite` already keeps.
195
+ *
196
+ * `mail` is omitted for a duller reason: it described what happened at
197
+ * creation time, and re-serving it invites a reader to take it as current.
198
+ */
199
+ export declare const pendingAppInvitation: z.ZodObject<{
200
+ id: z.ZodUUID;
201
+ email: z.ZodEmail;
202
+ expires_at: z.ZodISODateTime;
203
+ app_id: z.ZodUUID;
204
+ role_id: z.ZodUUID;
205
+ }, z.core.$strip>;
206
+ export type PendingAppInvitation = z.infer<typeof pendingAppInvitation>;
207
+ /** `GET /api/apps/:id/invitations` — pending only. An accepted invitation is history, not something to revoke. */
208
+ export declare const appInvitationListResponse: z.ZodObject<{
209
+ invitations: z.ZodArray<z.ZodObject<{
210
+ id: z.ZodUUID;
211
+ email: z.ZodEmail;
212
+ expires_at: z.ZodISODateTime;
213
+ app_id: z.ZodUUID;
214
+ role_id: z.ZodUUID;
215
+ }, z.core.$strip>>;
216
+ }, z.core.$strip>;
217
+ export type AppInvitationListResponse = z.infer<typeof appInvitationListResponse>;
218
+ /**
219
+ * **An app's OIDC provider, as read back** (D4). Any number per app, unlike
220
+ * the group provider this replaces — a developer serving two customers needs
221
+ * two, and the old at-most-one rule was a property of groups rather than of
222
+ * identity.
223
+ *
224
+ * **No secret, by construction.** The client secret goes in through the create
225
+ * and patch requests and never comes back out: a secret a response can carry
226
+ * is a secret in every log that ever captured a response, the same rule the
227
+ * server key and the group provider already kept.
228
+ *
229
+ * `issuer` is `idpIssuer` — http(s) only, no credentials, query or fragment.
230
+ * **This is not the SSRF defence.** It cannot tell the dev IdP
231
+ * (`http://localhost:8081/realms/…`) from `http://127.0.0.1:5432`, both being
232
+ * loopback http; the real defence refuses loopback, link-local and private
233
+ * ranges at the discovery fetch, in the cloud, and names DNS rebinding as its
234
+ * own residual.
235
+ */
236
+ export declare const appOidcProvider: z.ZodObject<{
237
+ id: z.ZodUUID;
238
+ app_id: z.ZodUUID;
239
+ slug: z.ZodString;
240
+ name: z.ZodString;
241
+ issuer: z.ZodURL;
242
+ client_id: z.ZodString;
243
+ scopes: z.ZodArray<z.ZodString>;
244
+ link_verified_emails: z.ZodBoolean;
245
+ enabled: z.ZodBoolean;
246
+ created_at: z.ZodISODateTime;
247
+ }, z.core.$strict>;
248
+ export type AppOidcProvider = z.infer<typeof appOidcProvider>;
249
+ /** `GET /api/apps/:id/oidc-providers` — every provider of the app, enabled or not; the public client route lists only the enabled ones. */
250
+ export declare const appOidcProviderListResponse: z.ZodObject<{
251
+ providers: z.ZodArray<z.ZodObject<{
252
+ id: z.ZodUUID;
253
+ app_id: z.ZodUUID;
254
+ slug: z.ZodString;
255
+ name: z.ZodString;
256
+ issuer: z.ZodURL;
257
+ client_id: z.ZodString;
258
+ scopes: z.ZodArray<z.ZodString>;
259
+ link_verified_emails: z.ZodBoolean;
260
+ enabled: z.ZodBoolean;
261
+ created_at: z.ZodISODateTime;
262
+ }, z.core.$strict>>;
263
+ }, z.core.$strip>;
264
+ export type AppOidcProviderListResponse = z.infer<typeof appOidcProviderListResponse>;
265
+ /**
266
+ * **Creating a provider** — `.strict()`, and the only place besides the patch
267
+ * that carries the client secret.
268
+ *
269
+ * The secret is **required here and optional on the patch**: a provider with
270
+ * no secret cannot exchange a code, so a create without one would store a row
271
+ * that can never work; a patch without one keeps the stored value, so a
272
+ * routine edit of the scopes does not force the secret back onto the wire.
273
+ * The minimum length refuses a trivial value — a one-character client secret
274
+ * is a misconfiguration, not a rotation.
275
+ */
276
+ export declare const createAppOidcProviderRequest: z.ZodObject<{
277
+ slug: z.ZodString;
278
+ name: z.ZodString;
279
+ issuer: z.ZodURL;
280
+ client_id: z.ZodString;
281
+ client_secret: z.ZodString;
282
+ scopes: z.ZodDefault<z.ZodArray<z.ZodString>>;
283
+ link_verified_emails: z.ZodDefault<z.ZodBoolean>;
284
+ enabled: z.ZodDefault<z.ZodBoolean>;
285
+ }, z.core.$strict>;
286
+ export type CreateAppOidcProviderRequest = z.infer<typeof createAppOidcProviderRequest>;
287
+ /**
288
+ * **Patching a provider** — every field optional, and `slug` absent.
289
+ *
290
+ * The slug is in the path and is what `app_user_identities` rows are keyed by,
291
+ * so renaming it would orphan every linked account. Strict, so offering it is
292
+ * a `400` naming the field rather than a `200` that changed nothing — the
293
+ * silence `updateAppRequest` was made strict to avoid.
294
+ */
295
+ export declare const patchAppOidcProviderRequest: z.ZodObject<{
296
+ name: z.ZodOptional<z.ZodString>;
297
+ issuer: z.ZodOptional<z.ZodURL>;
298
+ client_id: z.ZodOptional<z.ZodString>;
299
+ client_secret: z.ZodOptional<z.ZodString>;
300
+ scopes: z.ZodOptional<z.ZodArray<z.ZodString>>;
301
+ link_verified_emails: z.ZodOptional<z.ZodBoolean>;
302
+ enabled: z.ZodOptional<z.ZodBoolean>;
303
+ }, z.core.$strict>;
304
+ export type PatchAppOidcProviderRequest = z.infer<typeof patchAppOidcProviderRequest>;
305
+ /**
306
+ * **The placeholder each configurable app URL must carry, declared once.**
307
+ *
308
+ * Three of the four take a `{token}` and the fourth an `{interaction}`, and
309
+ * the difference is not cosmetic: the MCP login URL is handed an interaction
310
+ * id, not a credential. Exported so the console's help text, the cloud's
311
+ * substitution and this file's validators cannot spell them differently —
312
+ * `OAUTH_PATHS`' lesson, applied before there are five hand-written copies.
313
+ */
314
+ export declare const APP_URL_PLACEHOLDERS: {
315
+ readonly invite_url: "{token}";
316
+ readonly verify_url: "{token}";
317
+ readonly reset_url: "{token}";
318
+ readonly mcp_login_url: "{interaction}";
319
+ };
320
+ /**
321
+ * **An app-hosted URL template: https (or loopback http) carrying its
322
+ * placeholder exactly once.**
323
+ *
324
+ * Two rules, each with a failure it exists to prevent.
325
+ *
326
+ * *The scheme.* These links are mailed and carry a single-use credential in
327
+ * their path; over plain http on a public host that credential is readable by
328
+ * every hop. `localhost` and `127.0.0.1` are the exception because a developer
329
+ * building their app has no certificate, and a rule that made local
330
+ * development impossible would be worked around with a proxy nobody reviewed.
331
+ *
332
+ * *Exactly once.* The cloud substitutes the token with a plain string replace,
333
+ * which takes the **first** occurrence. A template naming the placeholder
334
+ * twice would therefore get one occurrence substituted and one left literal,
335
+ * and the link would 404 for the person who received the mail rather than fail
336
+ * for the developer who wrote it. Refusing at configuration time is the only
337
+ * place that mistake is cheap. A template with no placeholder is refused for
338
+ * the mirror reason: it would mail every recipient the same link.
339
+ *
340
+ * **What it cannot check**: that the URL resolves, that the app serves that
341
+ * path, or that the developer's page knows what to do with the token. Nothing
342
+ * a schema can see says any of that, and a validator that looked sufficient
343
+ * here would be read as an assurance.
344
+ */
345
+ export declare function appUrlTemplate(placeholder: string): z.ZodString;
346
+ /**
347
+ * **An origin, and nothing longer than an origin.**
348
+ *
349
+ * This list is both the CORS allow-list and the redirect-URI check, and a
350
+ * browser's `Origin` header is a bare origin: scheme, host, port. An entry
351
+ * carrying a path would compare unequal forever — a rule that silently never
352
+ * matches, which is worse than one that refuses, because the developer sees
353
+ * their own app rejected with nothing naming the typo.
354
+ *
355
+ * `u.origin === v` is the whole check for that: it rejects a trailing slash, a
356
+ * path, a query and a fragment in one comparison, and it does so against the
357
+ * browser's own normalisation rather than against a regex somebody has to keep
358
+ * in step with it.
359
+ */
360
+ export declare const allowedOrigin: z.ZodString;
361
+ /**
362
+ * **A domain for the self-registration whitelist, in one canonical spelling.**
363
+ *
364
+ * The list is compared against the domain part of an address the cloud has
365
+ * already lowercased, so an entry carrying a capital could never match — and
366
+ * the developer who typed it would see self-registration refuse everybody with
367
+ * nothing saying why. Lowercase is therefore the rule rather than a
368
+ * normalisation applied later in one of the two places that compare.
369
+ *
370
+ * The pattern is the ordinary LDH rule: labels of letters, digits and internal
371
+ * hyphens, at least two labels, a TLD of letters. 253 characters is the DNS
372
+ * name limit.
373
+ */
374
+ export declare const emailDomain: z.ZodString;
375
+ /**
376
+ * **The app's auth settings: one row per app, configured by a Fleetless user**
377
+ * (D3).
378
+ *
379
+ * `self_registration` and `allowed_domains` are **one policy for one
380
+ * decision** — they govern registration by password and registration through
381
+ * an identity provider alike (D4). An invitation always bypasses both, because
382
+ * a developer inviting somebody by hand has already made the decision the
383
+ * whitelist automates.
384
+ *
385
+ * The four URLs are what makes D2 work: Fleetless mails a link, and the link
386
+ * points into the developer's app. An app that has configured none of them
387
+ * still works for password login — it simply cannot send a mail that leads
388
+ * anywhere, and `send_mail` is refused rather than silently sending a dead
389
+ * link.
390
+ */
391
+ export declare const appAuthConfig: z.ZodObject<{
392
+ self_registration: z.ZodBoolean;
393
+ allowed_domains: z.ZodArray<z.ZodString>;
394
+ allowed_origins: z.ZodArray<z.ZodString>;
395
+ mcp_enabled: z.ZodBoolean;
396
+ invite_url: z.ZodNullable<z.ZodString>;
397
+ verify_url: z.ZodNullable<z.ZodString>;
398
+ reset_url: z.ZodNullable<z.ZodString>;
399
+ mcp_login_url: z.ZodNullable<z.ZodString>;
400
+ oidc_callback_url: z.ZodURL;
401
+ updated_at: z.ZodISODateTime;
402
+ }, z.core.$strip>;
403
+ export type AppAuthConfig = z.infer<typeof appAuthConfig>;
404
+ /**
405
+ * `PUT /api/apps/:id/auth-config` — a replace, not a merge, and `.strict()`.
406
+ *
407
+ * `oidc_callback_url` and `updated_at` are omitted because both are the
408
+ * server's: see the callback URL's own note for why a writable one would be a
409
+ * redirect-target hole rather than a convenience.
410
+ */
411
+ export declare const putAppAuthConfigRequest: z.ZodObject<{
412
+ self_registration: z.ZodBoolean;
413
+ allowed_domains: z.ZodArray<z.ZodString>;
414
+ allowed_origins: z.ZodArray<z.ZodString>;
415
+ mcp_enabled: z.ZodBoolean;
416
+ invite_url: z.ZodNullable<z.ZodString>;
417
+ verify_url: z.ZodNullable<z.ZodString>;
418
+ reset_url: z.ZodNullable<z.ZodString>;
419
+ mcp_login_url: z.ZodNullable<z.ZodString>;
420
+ }, z.core.$strict>;
421
+ export type PutAppAuthConfigRequest = z.infer<typeof putAppAuthConfigRequest>;
422
+ /**
423
+ * The three mails a developer may replace with their own template (D5).
424
+ * Mails to *Fleetless* users — a team invitation, a console password reset —
425
+ * stay Fleetless default and are deliberately not customisable: they are
426
+ * about this platform, not about the developer's product.
427
+ */
428
+ export declare const mailTemplateKind: z.ZodEnum<{
429
+ invite: "invite";
430
+ verify: "verify";
431
+ reset: "reset";
432
+ }>;
433
+ export type MailTemplateKind = z.infer<typeof mailTemplateKind>;
434
+ /**
435
+ * **Every variable a template may name, and the list is closed.**
436
+ *
437
+ * Liquid runs in strict mode: an unknown variable is an error at save time and
438
+ * in the preview, rather than an empty string in a mail somebody already
439
+ * received. That is only worth anything if the permitted set is written down
440
+ * where the renderer, the console's completion and the docs all read the same
441
+ * one.
442
+ */
443
+ export declare const MAIL_TEMPLATE_VARIABLES: readonly ["app.name", "org.name", "user.email", "user.display_name", "role.name", "link", "expires_in_hours"];
444
+ /**
445
+ * **The Fleetless default text for the three app mails** (spec D5, §6).
446
+ *
447
+ * It lives here rather than in the cloud because two products send the same
448
+ * words: the cloud renders these when an app has no template of its own, and
449
+ * the console seeds its editor with them when a developer presses *Customise*.
450
+ * They were written twice, in different words, and a developer comparing the
451
+ * editor against a mail they had received would have found two Fleetless
452
+ * defaults that disagreed. One text, one place, and neither consumer may hold
453
+ * a copy.
454
+ *
455
+ * These are Liquid templates like any custom one — the same variables, the
456
+ * same renderer, the same bounds — so the cloud's fallback path cannot become
457
+ * a second, weaker mechanism that merely looks like the real one.
458
+ *
459
+ * **Text-only (`html: null`).** A text part is a complete mail, and a default
460
+ * that shipped markup would make every app that never opens the Mails tab send
461
+ * Fleetless-styled HTML on behalf of a product that is not Fleetless.
462
+ *
463
+ * The voice is plain and short, names the app rather than this platform, and
464
+ * says what the link does, how long it lasts, and what to do if it was not
465
+ * you.
466
+ *
467
+ * **`verify` and `reset` greet by the address, not by the display name**, and
468
+ * that is a security decision rather than a style one. `display_name` on those
469
+ * two mails comes from `POST /api/client/register`, which is unauthenticated:
470
+ * whoever typed the address also chose 120 characters of text that Fleetless
471
+ * then renders into a mail sent from the *developer's* own sender to an
472
+ * address the same caller chose. "Hello Account suspended — verify at
473
+ * https://evil.example now," is a phishing line with a real product's return
474
+ * address on it. The recipient's own address is the one value in that mail
475
+ * they can check, and it is the greeting. `invite` keeps the display name:
476
+ * that one is written by an authenticated developer about somebody they
477
+ * invited.
478
+ *
479
+ * **`expires_in_hours` is the only lifetime variable the spec offers**, and
480
+ * the three values are 1, 24 and 168. "The next 168 hours" is not how a person
481
+ * says a week, so each default converts: 48 and up reads in days, exactly one
482
+ * reads "1 hour", everything else reads in hours. The conversion is in the
483
+ * template rather than in a new variable because a custom template has the
484
+ * same problem and this is the spelling it can copy.
485
+ *
486
+ * **What contracts does NOT assert about these.** That they compile as Liquid
487
+ * is the cloud's business — contracts has no renderer and adding one to check
488
+ * its own constant would be a second, weaker copy of the thing that actually
489
+ * sends mail. Here they are pinned as a complete, non-empty set; the cloud
490
+ * asserts that the mail it sends for each kind is this exact text.
491
+ */
492
+ export declare const DEFAULT_MAIL_TEMPLATES: Record<MailTemplateKind, {
493
+ subject: string;
494
+ text: string;
495
+ html: null;
496
+ }>;
497
+ /**
498
+ * One stored template. `html` is nullable because the mailer's HTML part is
499
+ * optional — a text-only mail is a complete mail, and an app that wants one
500
+ * should not have to write the same words twice.
501
+ */
502
+ export declare const appMailTemplate: z.ZodObject<{
503
+ kind: z.ZodEnum<{
504
+ invite: "invite";
505
+ verify: "verify";
506
+ reset: "reset";
507
+ }>;
508
+ subject: z.ZodString;
509
+ text: z.ZodString;
510
+ html: z.ZodNullable<z.ZodString>;
511
+ updated_at: z.ZodISODateTime;
512
+ }, z.core.$strip>;
513
+ export type AppMailTemplate = z.infer<typeof appMailTemplate>;
514
+ /** `GET /api/apps/:id/mail-templates` — **only the kinds that have a custom template.** An absent kind is one using the Fleetless default, which is a state and not a gap. */
515
+ export declare const appMailTemplateListResponse: z.ZodObject<{
516
+ templates: z.ZodArray<z.ZodObject<{
517
+ kind: z.ZodEnum<{
518
+ invite: "invite";
519
+ verify: "verify";
520
+ reset: "reset";
521
+ }>;
522
+ subject: z.ZodString;
523
+ text: z.ZodString;
524
+ html: z.ZodNullable<z.ZodString>;
525
+ updated_at: z.ZodISODateTime;
526
+ }, z.core.$strip>>;
527
+ }, z.core.$strip>;
528
+ export type AppMailTemplateListResponse = z.infer<typeof appMailTemplateListResponse>;
529
+ export declare const putAppMailTemplateRequest: z.ZodObject<{
530
+ subject: z.ZodString;
531
+ text: z.ZodString;
532
+ html: z.ZodOptional<z.ZodNullable<z.ZodString>>;
533
+ }, z.core.$strict>;
534
+ export type PutAppMailTemplateRequest = z.infer<typeof putAppMailTemplateRequest>;
535
+ /**
536
+ * **The preview takes the same document the PUT does — as a second object,
537
+ * not as an alias.**
538
+ *
539
+ * The fields are defined once (`mailTemplateBody` above) and `.strict()` twice,
540
+ * so there is one definition and two values. An alias would be one value under
541
+ * two contract names, and the export registry resolves an artifact by object
542
+ * identity: it refuses a schema registered twice, because the artifact a route
543
+ * points at would otherwise be a coin toss.
544
+ */
545
+ export declare const mailTemplatePreviewRequest: z.ZodObject<{
546
+ subject: z.ZodString;
547
+ text: z.ZodString;
548
+ html: z.ZodOptional<z.ZodNullable<z.ZodString>>;
549
+ }, z.core.$strict>;
550
+ export type MailTemplatePreviewRequest = z.infer<typeof mailTemplatePreviewRequest>;
551
+ /** What the preview renders, with the sample data filled in. The developer reads this before anybody receives it. */
552
+ export declare const mailTemplatePreviewResponse: z.ZodObject<{
553
+ subject: z.ZodString;
554
+ text: z.ZodString;
555
+ html: z.ZodNullable<z.ZodString>;
556
+ }, z.core.$strip>;
557
+ export type MailTemplatePreviewResponse = z.infer<typeof mailTemplatePreviewResponse>;
558
+ /**
559
+ * The `details` of a `422 template_invalid`: **which part failed**, not merely
560
+ * that something did.
561
+ *
562
+ * A template has three independently-rendered parts, and an error that did not
563
+ * say which one leaves the developer re-reading all three. `message` is the
564
+ * renderer's own — it names the unknown variable or the syntax error — and
565
+ * carries nothing else: it is written into an audit event as well, where the
566
+ * rule is that no credential, token or password may appear.
567
+ */
568
+ export declare const mailTemplateProblemDetails: z.ZodObject<{
569
+ part: z.ZodEnum<{
570
+ subject: "subject";
571
+ text: "text";
572
+ html: "html";
573
+ }>;
574
+ message: z.ZodString;
575
+ }, z.core.$strip>;
576
+ export type MailTemplateProblemDetails = z.infer<typeof mailTemplateProblemDetails>;
577
+ /**
578
+ * **What a `202` says when the only thing that happened was a mail.**
579
+ *
580
+ * Three routes do one act and answer nothing about it — re-sending a user's
581
+ * reset link, mailing an invitation, sending a test template. A bare `202`
582
+ * with an empty body would be honest about the *acceptance* and silent about
583
+ * the one fact the developer needs next, which is whether a mail actually left:
584
+ * an app with no SMTP configured looks exactly like one that mailed, and the
585
+ * developer waits for a message nobody sent.
586
+ *
587
+ * So the body is `{ "mail": mailStatus }` and nothing else. `sent` means the
588
+ * SMTP server accepted it, not that it was delivered; `not_configured` is an
589
+ * expected state on a deployment without a mailer and is not a failure;
590
+ * `failed` is the one worth somebody's attention.
591
+ *
592
+ * It is its own object rather than a reuse of `appInvitation`'s field because
593
+ * the export registry resolves an artifact by object identity — one schema
594
+ * under two contract names would make the artifact a route points at a coin
595
+ * toss, the same reason `mailTemplatePreviewRequest` is a second `.strict()`
596
+ * rather than an alias.
597
+ */
598
+ export declare const mailOutcome: z.ZodObject<{
599
+ mail: z.ZodEnum<{
600
+ sent: "sent";
601
+ not_requested: "not_requested";
602
+ not_configured: "not_configured";
603
+ failed: "failed";
604
+ }>;
605
+ }, z.core.$strip>;
606
+ export type MailOutcome = z.infer<typeof mailOutcome>;