@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.
- package/CHANGELOG.md +26 -0
- package/LICENSE +202 -0
- package/NOTICE +17 -0
- package/README.md +88 -0
- package/artifacts/constants.json +24 -0
- package/artifacts/openapi.json +17219 -0
- package/artifacts/routes.json +4605 -0
- package/artifacts/schema/accept-team-invite-request.schema.json +22 -0
- package/artifacts/schema/action-config.schema.json +198 -0
- package/artifacts/schema/alert-list-response.schema.json +172 -0
- package/artifacts/schema/api-error.schema.json +20 -0
- package/artifacts/schema/app-auth-config.schema.json +106 -0
- package/artifacts/schema/app-invitation-list-response.schema.json +57 -0
- package/artifacts/schema/app-invitation.schema.json +69 -0
- package/artifacts/schema/app-list-response.schema.json +82 -0
- package/artifacts/schema/app-mail-template-list-response.schema.json +68 -0
- package/artifacts/schema/app-mail-template.schema.json +54 -0
- package/artifacts/schema/app-oidc-provider-list-response.schema.json +93 -0
- package/artifacts/schema/app-oidc-provider.schema.json +80 -0
- package/artifacts/schema/app-user-list-response.schema.json +111 -0
- package/artifacts/schema/app-user.schema.json +98 -0
- package/artifacts/schema/app.schema.json +69 -0
- package/artifacts/schema/apply-error.schema.json +41 -0
- package/artifacts/schema/asset-list-response.schema.json +288 -0
- package/artifacts/schema/asset-sync-request.schema.json +17 -0
- package/artifacts/schema/asset-sync-response.schema.json +16 -0
- package/artifacts/schema/asset-sync-status.schema.json +136 -0
- package/artifacts/schema/asset.schema.json +68 -0
- package/artifacts/schema/audit-actor.schema.json +32 -0
- package/artifacts/schema/audit-event.schema.json +119 -0
- package/artifacts/schema/audit-list-response.schema.json +144 -0
- package/artifacts/schema/audit-query.schema.json +79 -0
- package/artifacts/schema/auth-error.schema.json +23 -0
- package/artifacts/schema/auth-me-response.schema.json +99 -0
- package/artifacts/schema/auth-ok.schema.json +115 -0
- package/artifacts/schema/authorization-server-metadata.schema.json +80 -0
- package/artifacts/schema/bridge-asset-progress.schema.json +99 -0
- package/artifacts/schema/bridge-assets-available.schema.json +25 -0
- package/artifacts/schema/bridge-camera-state.schema.json +78 -0
- package/artifacts/schema/bridge-config-applied.schema.json +67 -0
- package/artifacts/schema/bridge-hello.schema.json +65 -0
- package/artifacts/schema/bridge-introspect.schema.json +114 -0
- package/artifacts/schema/bridge-job-lost.schema.json +22 -0
- package/artifacts/schema/bridge-job-update.schema.json +100 -0
- package/artifacts/schema/bridge-pong.schema.json +19 -0
- package/artifacts/schema/bridge-pressure.schema.json +292 -0
- package/artifacts/schema/bridge-state.schema.json +24 -0
- package/artifacts/schema/bridge-type-definitions.schema.json +169 -0
- package/artifacts/schema/busy-details.schema.json +115 -0
- package/artifacts/schema/camera-descriptor.schema.json +45 -0
- package/artifacts/schema/camera-list-response.schema.json +58 -0
- package/artifacts/schema/camera-source.schema.json +240 -0
- package/artifacts/schema/cancel-request.schema.json +20 -0
- package/artifacts/schema/client-accept-invitation-request.schema.json +35 -0
- package/artifacts/schema/client-auth.schema.json +18 -0
- package/artifacts/schema/client-cancel.schema.json +45 -0
- package/artifacts/schema/client-identity.schema.json +103 -0
- package/artifacts/schema/client-invoke.schema.json +45 -0
- package/artifacts/schema/client-login-request.schema.json +29 -0
- package/artifacts/schema/client-logout-request.schema.json +14 -0
- package/artifacts/schema/client-mcp-interaction-decision-response.schema.json +15 -0
- package/artifacts/schema/client-mcp-interaction.schema.json +59 -0
- package/artifacts/schema/client-oidc-callback-query.schema.json +28 -0
- package/artifacts/schema/client-oidc-exchange-request.schema.json +21 -0
- package/artifacts/schema/client-oidc-start-query.schema.json +36 -0
- package/artifacts/schema/client-password-reset-confirm-request.schema.json +22 -0
- package/artifacts/schema/client-password-reset-request.schema.json +24 -0
- package/artifacts/schema/client-provider-list-query.schema.json +17 -0
- package/artifacts/schema/client-provider-list-response.schema.json +34 -0
- package/artifacts/schema/client-publish.schema.json +40 -0
- package/artifacts/schema/client-refresh-request.schema.json +14 -0
- package/artifacts/schema/client-register-request.schema.json +44 -0
- package/artifacts/schema/client-resend-verification-request.schema.json +24 -0
- package/artifacts/schema/client-subscribe.schema.json +43 -0
- package/artifacts/schema/client-unsubscribe.schema.json +26 -0
- package/artifacts/schema/client-verify-email-request.schema.json +15 -0
- package/artifacts/schema/cloud-asset-request.schema.json +37 -0
- package/artifacts/schema/cloud-camera-start.schema.json +41 -0
- package/artifacts/schema/cloud-camera-stop.schema.json +26 -0
- package/artifacts/schema/cloud-cancel.schema.json +33 -0
- package/artifacts/schema/cloud-config.schema.json +1635 -0
- package/artifacts/schema/cloud-hello-error.schema.json +23 -0
- package/artifacts/schema/cloud-hello-ok.schema.json +19 -0
- package/artifacts/schema/cloud-introspect-request.schema.json +19 -0
- package/artifacts/schema/cloud-invoke.schema.json +40 -0
- package/artifacts/schema/cloud-ping.schema.json +19 -0
- package/artifacts/schema/cloud-publish.schema.json +28 -0
- package/artifacts/schema/cloud-type-request.schema.json +30 -0
- package/artifacts/schema/command-result.schema.json +175 -0
- package/artifacts/schema/config-draft-response.schema.json +1695 -0
- package/artifacts/schema/config-state.schema.json +124 -0
- package/artifacts/schema/config-version-response.schema.json +1641 -0
- package/artifacts/schema/config-versions-response.schema.json +33 -0
- package/artifacts/schema/create-app-invitation-request.schema.json +40 -0
- package/artifacts/schema/create-app-oidc-provider-request.schema.json +70 -0
- package/artifacts/schema/create-app-request.schema.json +30 -0
- package/artifacts/schema/create-app-user-request.schema.json +42 -0
- package/artifacts/schema/create-robot-request.schema.json +14 -0
- package/artifacts/schema/create-robot-response.schema.json +44 -0
- package/artifacts/schema/create-server-key-response.schema.json +65 -0
- package/artifacts/schema/create-team-invite-request.schema.json +43 -0
- package/artifacts/schema/datapoint-alert-row.schema.json +160 -0
- package/artifacts/schema/datapoint-config.schema.json +366 -0
- package/artifacts/schema/datapoint-display.schema.json +31 -0
- package/artifacts/schema/datapoint-event.schema.json +34 -0
- package/artifacts/schema/datapoint-frame.schema.json +28 -0
- package/artifacts/schema/datapoint-list-response.schema.json +61 -0
- package/artifacts/schema/datapoint-value.schema.json +28 -0
- package/artifacts/schema/developer-login-request.schema.json +19 -0
- package/artifacts/schema/dynamic-client-registration-request.schema.json +60 -0
- package/artifacts/schema/dynamic-client-registration-response.schema.json +68 -0
- package/artifacts/schema/error-frame.schema.json +23 -0
- package/artifacts/schema/exposure-counts.schema.json +39 -0
- package/artifacts/schema/exposure-list-response.schema.json +43 -0
- package/artifacts/schema/fetch-types-request.schema.json +19 -0
- package/artifacts/schema/fetch-types-response.schema.json +163 -0
- package/artifacts/schema/fleetless-user-list-response.schema.json +73 -0
- package/artifacts/schema/fleetless-user.schema.json +60 -0
- package/artifacts/schema/history-buckets-response.schema.json +79 -0
- package/artifacts/schema/history-query.schema.json +58 -0
- package/artifacts/schema/history-response.schema.json +150 -0
- package/artifacts/schema/history-samples-response.schema.json +68 -0
- package/artifacts/schema/introspection-response.schema.json +118 -0
- package/artifacts/schema/invoke-or-service-response.schema.json +141 -0
- package/artifacts/schema/invoke-request.schema.json +23 -0
- package/artifacts/schema/invoke-response.schema.json +125 -0
- package/artifacts/schema/job-actor.schema.json +34 -0
- package/artifacts/schema/job-event.schema.json +158 -0
- package/artifacts/schema/job-response.schema.json +123 -0
- package/artifacts/schema/job-run-list-response.schema.json +222 -0
- package/artifacts/schema/job-run-query.schema.json +95 -0
- package/artifacts/schema/job-run-summary-query.schema.json +23 -0
- package/artifacts/schema/job-run-summary.schema.json +33 -0
- package/artifacts/schema/job-run.schema.json +195 -0
- package/artifacts/schema/job-state.schema.json +11 -0
- package/artifacts/schema/job.schema.json +106 -0
- package/artifacts/schema/latency-bucket.schema.json +63 -0
- package/artifacts/schema/live-session-response.schema.json +41 -0
- package/artifacts/schema/mail-outcome.schema.json +20 -0
- package/artifacts/schema/mail-template-preview-request.schema.json +35 -0
- package/artifacts/schema/mail-template-preview-response.schema.json +31 -0
- package/artifacts/schema/mail-template-problem-details.schema.json +24 -0
- package/artifacts/schema/mcp-consent-grant-list-response.schema.json +52 -0
- package/artifacts/schema/mcp-consent-grant.schema.json +39 -0
- package/artifacts/schema/mcp-robot-datasheet.schema.json +115 -0
- package/artifacts/schema/mcp-role-preview-response.schema.json +134 -0
- package/artifacts/schema/missing-asset-query.schema.json +11 -0
- package/artifacts/schema/oauth-authorize-query.schema.json +47 -0
- package/artifacts/schema/oauth-redirect-response.schema.json +15 -0
- package/artifacts/schema/oauth-token-request.schema.json +47 -0
- package/artifacts/schema/oauth-token-response.schema.json +38 -0
- package/artifacts/schema/org-alerts-query.schema.json +15 -0
- package/artifacts/schema/org-event-dropped.schema.json +26 -0
- package/artifacts/schema/org-event-replay.schema.json +97 -0
- package/artifacts/schema/org-event-subscribe.schema.json +14 -0
- package/artifacts/schema/org-event-unsubscribe.schema.json +14 -0
- package/artifacts/schema/org-event.schema.json +75 -0
- package/artifacts/schema/org-firing-alerts-response.schema.json +178 -0
- package/artifacts/schema/org-health-query.schema.json +13 -0
- package/artifacts/schema/org-latency-query.schema.json +42 -0
- package/artifacts/schema/org-latency-response.schema.json +124 -0
- package/artifacts/schema/org-quota-usage-counts.schema.json +42 -0
- package/artifacts/schema/org-quota-usage.schema.json +102 -0
- package/artifacts/schema/org-quotas.schema.json +51 -0
- package/artifacts/schema/org-usage-query.schema.json +19 -0
- package/artifacts/schema/org-usage-response.schema.json +77 -0
- package/artifacts/schema/org.schema.json +30 -0
- package/artifacts/schema/parameter-invalid-details.schema.json +37 -0
- package/artifacts/schema/parameter-spec.schema.json +120 -0
- package/artifacts/schema/parameter-violation.schema.json +24 -0
- package/artifacts/schema/password-change-request.schema.json +21 -0
- package/artifacts/schema/password-reset-confirm.schema.json +19 -0
- package/artifacts/schema/password-reset-request.schema.json +14 -0
- package/artifacts/schema/patch-app-oidc-provider-request.schema.json +50 -0
- package/artifacts/schema/patch-app-user-request.schema.json +34 -0
- package/artifacts/schema/patch-auth-me-request.schema.json +22 -0
- package/artifacts/schema/patch-fleetless-user-request.schema.json +20 -0
- package/artifacts/schema/patch-org-request.schema.json +15 -0
- package/artifacts/schema/patch-org-response.schema.json +40 -0
- package/artifacts/schema/patch-robot-request.schema.json +15 -0
- package/artifacts/schema/patch-robot-response.schema.json +40 -0
- package/artifacts/schema/pending-team-invite-list-response.schema.json +52 -0
- package/artifacts/schema/pending-team-invite.schema.json +39 -0
- package/artifacts/schema/protected-resource-metadata.schema.json +41 -0
- package/artifacts/schema/publish-config-response.schema.json +21 -0
- package/artifacts/schema/publish-request.schema.json +17 -0
- package/artifacts/schema/publisher-config.schema.json +285 -0
- package/artifacts/schema/put-app-auth-config-request.schema.json +93 -0
- package/artifacts/schema/put-app-mail-template-request.schema.json +35 -0
- package/artifacts/schema/put-config-draft-request.schema.json +13 -0
- package/artifacts/schema/put-datapoint-display-request.schema.json +31 -0
- package/artifacts/schema/put-robot-details-request.schema.json +41 -0
- package/artifacts/schema/put-robot-details-response.schema.json +43 -0
- package/artifacts/schema/rate-limit-details.schema.json +15 -0
- package/artifacts/schema/refresh-request.schema.json +13 -0
- package/artifacts/schema/release-live-query.schema.json +13 -0
- package/artifacts/schema/rename-slug-request.schema.json +23 -0
- package/artifacts/schema/rename-slug-response.schema.json +24 -0
- package/artifacts/schema/resource-health-event.schema.json +72 -0
- package/artifacts/schema/resource-health-list-response.schema.json +80 -0
- package/artifacts/schema/resource-health-state.schema.json +68 -0
- package/artifacts/schema/robot-config-doc.schema.json +1616 -0
- package/artifacts/schema/robot-delete-query.schema.json +12 -0
- package/artifacts/schema/robot-deletion-summary.schema.json +63 -0
- package/artifacts/schema/robot-detail-response.schema.json +262 -0
- package/artifacts/schema/robot-details-doc.schema.json +33 -0
- package/artifacts/schema/robot-jobs-response.schema.json +119 -0
- package/artifacts/schema/robot-latency-series.schema.json +81 -0
- package/artifacts/schema/robot-list-item.schema.json +94 -0
- package/artifacts/schema/robot-list-response.schema.json +106 -0
- package/artifacts/schema/robot.schema.json +30 -0
- package/artifacts/schema/role-list-response.schema.json +48 -0
- package/artifacts/schema/role-permissions.schema.json +61 -0
- package/artifacts/schema/role.schema.json +35 -0
- package/artifacts/schema/ros-graph.schema.json +99 -0
- package/artifacts/schema/server-key-list-response.schema.json +64 -0
- package/artifacts/schema/server-key.schema.json +51 -0
- package/artifacts/schema/service-call-response.schema.json +13 -0
- package/artifacts/schema/service-config.schema.json +198 -0
- package/artifacts/schema/session-tokens.schema.json +28 -0
- package/artifacts/schema/sign-up-request.schema.json +26 -0
- package/artifacts/schema/sign-up-response.schema.json +127 -0
- package/artifacts/schema/slug-usage-response.schema.json +32 -0
- package/artifacts/schema/snapshot-header.schema.json +44 -0
- package/artifacts/schema/snapshot-meta-response.schema.json +85 -0
- package/artifacts/schema/subscribe-error.schema.json +31 -0
- package/artifacts/schema/team-invite.schema.json +57 -0
- package/artifacts/schema/tier-change-request.schema.json +17 -0
- package/artifacts/schema/type-definition.schema.json +144 -0
- package/artifacts/schema/types-response.schema.json +156 -0
- package/artifacts/schema/update-app-request.schema.json +32 -0
- package/artifacts/schema/urdf-completeness.schema.json +50 -0
- package/artifacts/schema/validation-issue.schema.json +43 -0
- package/artifacts/schema/waitlist-request.schema.json +15 -0
- package/artifacts/schema-outgoing/bridge-asset-progress.schema.json +102 -0
- package/artifacts/schema-outgoing/bridge-assets-available.schema.json +26 -0
- package/artifacts/schema-outgoing/bridge-camera-state.schema.json +80 -0
- package/artifacts/schema-outgoing/bridge-config-applied.schema.json +69 -0
- package/artifacts/schema-outgoing/bridge-hello.schema.json +68 -0
- package/artifacts/schema-outgoing/bridge-introspect.schema.json +119 -0
- package/artifacts/schema-outgoing/bridge-job-lost.schema.json +23 -0
- package/artifacts/schema-outgoing/bridge-job-update.schema.json +102 -0
- package/artifacts/schema-outgoing/bridge-pong.schema.json +20 -0
- package/artifacts/schema-outgoing/bridge-type-definitions.schema.json +174 -0
- package/artifacts/schema-outgoing/datapoint-frame.schema.json +29 -0
- package/artifacts/schema-outgoing/snapshot-header.schema.json +45 -0
- package/dist/alerts.d.ts +255 -0
- package/dist/alerts.js +193 -0
- package/dist/app-users.d.ts +606 -0
- package/dist/app-users.js +696 -0
- package/dist/apps.d.ts +175 -0
- package/dist/apps.js +267 -0
- package/dist/assets.d.ts +434 -0
- package/dist/assets.js +546 -0
- package/dist/audit.d.ts +129 -0
- package/dist/audit.js +238 -0
- package/dist/client-auth.d.ts +409 -0
- package/dist/client-auth.js +487 -0
- package/dist/common.d.ts +186 -0
- package/dist/common.js +199 -0
- package/dist/config-issues.d.ts +175 -0
- package/dist/config-issues.js +339 -0
- package/dist/config.d.ts +862 -0
- package/dist/config.js +1988 -0
- package/dist/errors.d.ts +52 -0
- package/dist/errors.js +786 -0
- package/dist/identity.d.ts +549 -0
- package/dist/identity.js +503 -0
- package/dist/index.d.ts +51 -0
- package/dist/index.js +51 -0
- package/dist/introspection.d.ts +99 -0
- package/dist/introspection.js +97 -0
- package/dist/jobs.d.ts +334 -0
- package/dist/jobs.js +345 -0
- package/dist/mcp.d.ts +239 -0
- package/dist/mcp.js +153 -0
- package/dist/oauth.d.ts +344 -0
- package/dist/oauth.js +488 -0
- package/dist/protocol.d.ts +781 -0
- package/dist/protocol.js +715 -0
- package/dist/realtime.d.ts +494 -0
- package/dist/realtime.js +512 -0
- package/dist/rest.d.ts +1989 -0
- package/dist/rest.js +1963 -0
- package/dist/routes.d.ts +94 -0
- package/dist/routes.js +2298 -0
- 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>;
|