@fleetless/contracts 6.0.0-next.1 → 6.0.0-next.3

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/dist/apps.d.ts CHANGED
@@ -151,8 +151,9 @@ export declare const createServerKeyResponse: z.ZodObject<{
151
151
  export type CreateServerKeyResponse = z.infer<typeof createServerKeyResponse>;
152
152
  /**
153
153
  * Every app starts with `observe` and `operate`; custom roles are allowed
154
- * too. `builtin` marks the two starting roles — editable like any other,
155
- * the flag only tells the console where they came from.
154
+ * too. `builtin` marks the two starting roles — editable, renamable and
155
+ * deletable like any other; the flag only tells the console where they came
156
+ * from.
156
157
  */
157
158
  export declare const role: z.ZodObject<{
158
159
  id: z.ZodUUID;
@@ -171,6 +172,41 @@ export declare const roleListResponse: z.ZodObject<{
171
172
  }, z.core.$strip>>;
172
173
  }, z.core.$strip>;
173
174
  export type RoleListResponse = z.infer<typeof roleListResponse>;
175
+ /**
176
+ * The body of `PATCH /api/apps/:id/roles/:roleId`: the role's new name.
177
+ *
178
+ * The same bounds as `role.name`, trimmed. Names are unique per app, compared
179
+ * exactly as stored after trimming; a clash answers `409 role_name_taken`.
180
+ */
181
+ export declare const roleRenameRequest: z.ZodObject<{
182
+ name: z.ZodString;
183
+ }, z.core.$strict>;
184
+ export type RoleRenameRequest = z.infer<typeof roleRenameRequest>;
185
+ /**
186
+ * The query of `DELETE /api/apps/:id/roles/:roleId`.
187
+ *
188
+ * `move_to` is what makes a held role deletable: every app user and pending
189
+ * invitation holding the role moves to it, and so does the app's default when
190
+ * it pointed at the role, in the same transaction as the delete. Without it a
191
+ * held role answers `409 role_in_use` with `roleInUseDetails`, so a client
192
+ * can ask where they should go instead of guessing.
193
+ */
194
+ export declare const roleDeleteQuery: z.ZodObject<{
195
+ move_to: z.ZodOptional<z.ZodUUID>;
196
+ }, z.core.$strict>;
197
+ export type RoleDeleteQuery = z.infer<typeof roleDeleteQuery>;
198
+ /**
199
+ * `details` of `409 role_in_use`: what still holds the role.
200
+ *
201
+ * All three are reported, zeros included, so a client renders one sentence
202
+ * from one shape rather than inferring a missing key.
203
+ */
204
+ export declare const roleInUseDetails: z.ZodObject<{
205
+ users: z.ZodNumber;
206
+ invitations: z.ZodNumber;
207
+ is_default: z.ZodBoolean;
208
+ }, z.core.$strict>;
209
+ export type RoleInUseDetails = z.infer<typeof roleInUseDetails>;
174
210
  /**
175
211
  * The rights matrix of one role: which slugs of which robot it may use, plus
176
212
  * the capabilities roles also govern. `capabilities`' own doc comment
package/dist/apps.js CHANGED
@@ -206,8 +206,9 @@ export const createServerKeyResponse = z.object({
206
206
  });
207
207
  /**
208
208
  * Every app starts with `observe` and `operate`; custom roles are allowed
209
- * too. `builtin` marks the two starting roles — editable like any other,
210
- * the flag only tells the console where they came from.
209
+ * too. `builtin` marks the two starting roles — editable, renamable and
210
+ * deletable like any other; the flag only tells the console where they came
211
+ * from.
211
212
  */
212
213
  export const role = z.object({
213
214
  id: z.uuid().meta({
@@ -220,7 +221,7 @@ export const role = z.object({
220
221
  description: 'The role\'s name, shown wherever a user\'s access is chosen. The two roles every app starts with are named `observe` and `operate`.',
221
222
  }),
222
223
  builtin: z.boolean().meta({
223
- description: '`true` for the two roles every app starts with. Their **rights may be re-scoped** exactly like a custom role\'s, through `PUT /api/apps/:id/roles/:roleId/permissions` — the flag exists so the console can explain where they came from, not to protect them. It does not make them renamable or deletable — no route does that for any role.',
224
+ description: '`true` for the two roles every app starts with. Their **rights may be re-scoped** exactly like a custom role\'s, through `PUT /api/apps/:id/roles/:roleId/permissions` — the flag exists so the console can explain where they came from, not to protect them. Built-in roles can be renamed and deleted like any other; the flag only records that the cloud seeded them.',
224
225
  }),
225
226
  });
226
227
  /** What `GET /api/apps/:id/roles` answers: the app's roles, builtin and custom alike. */
@@ -229,6 +230,48 @@ export const roleListResponse = z.object({
229
230
  description: 'The app\'s roles, built-in and custom alike, ordered by `created_at` and then by `name`. The tie-break is not cosmetic — the two built-in roles are inserted in one statement and share a creation time to the microsecond, so never read a role by position.',
230
231
  }),
231
232
  });
233
+ /**
234
+ * The body of `PATCH /api/apps/:id/roles/:roleId`: the role's new name.
235
+ *
236
+ * The same bounds as `role.name`, trimmed. Names are unique per app, compared
237
+ * exactly as stored after trimming; a clash answers `409 role_name_taken`.
238
+ */
239
+ export const roleRenameRequest = z.object({
240
+ name: z.string().trim().min(1).max(60).meta({
241
+ description: 'The new name, trimmed, 1 to 60 characters. Unique per app: another role of this app with the same name answers `409 role_name_taken`. The role\'s users keep it under its new name.',
242
+ }),
243
+ }).strict();
244
+ /**
245
+ * The query of `DELETE /api/apps/:id/roles/:roleId`.
246
+ *
247
+ * `move_to` is what makes a held role deletable: every app user and pending
248
+ * invitation holding the role moves to it, and so does the app's default when
249
+ * it pointed at the role, in the same transaction as the delete. Without it a
250
+ * held role answers `409 role_in_use` with `roleInUseDetails`, so a client
251
+ * can ask where they should go instead of guessing.
252
+ */
253
+ export const roleDeleteQuery = z.object({
254
+ move_to: z.uuid().optional().meta({
255
+ description: 'Another role of the same app that takes over the deleted role\'s app users, pending invitations and, when it applies, the app\'s default. The role itself or a role of another app answers `400 validation_error`.',
256
+ }),
257
+ }).strict();
258
+ /**
259
+ * `details` of `409 role_in_use`: what still holds the role.
260
+ *
261
+ * All three are reported, zeros included, so a client renders one sentence
262
+ * from one shape rather than inferring a missing key.
263
+ */
264
+ export const roleInUseDetails = z.object({
265
+ users: z.number().int().nonnegative().meta({
266
+ description: 'App users whose role this is.',
267
+ }),
268
+ invitations: z.number().int().nonnegative().meta({
269
+ description: 'Pending invitations that would grant this role when accepted.',
270
+ }),
271
+ is_default: z.boolean().meta({
272
+ description: '`true` when this is the app\'s `default_role_id`; the default then moves with the users to `move_to`.',
273
+ }),
274
+ }).strict();
232
275
  /**
233
276
  * The rights matrix of one role: which slugs of which robot it may use, plus
234
277
  * the capabilities roles also govern. `capabilities`' own doc comment
package/dist/audit.d.ts CHANGED
@@ -72,6 +72,7 @@ export declare const auditQuery: z.ZodObject<{
72
72
  action_prefix: z.ZodOptional<z.ZodString>;
73
73
  actor_id: z.ZodOptional<z.ZodUUID>;
74
74
  target_kind: z.ZodOptional<z.ZodString>;
75
+ target_id: z.ZodOptional<z.ZodString>;
75
76
  from_ms: z.ZodOptional<z.ZodPipe<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>, z.ZodTransform<number, string | number>>, z.ZodNumber>>;
76
77
  to_ms: z.ZodOptional<z.ZodPipe<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>, z.ZodTransform<number, string | number>>, z.ZodNumber>>;
77
78
  }, z.core.$strict>;
package/dist/audit.js CHANGED
@@ -155,6 +155,19 @@ export const auditQuery = z.object({
155
155
  actor_id: z.uuid().optional(),
156
156
  /** Only events about this kind of target, e.g. `robot`. */
157
157
  target_kind: z.string().min(1).max(40).optional(),
158
+ /**
159
+ * Only events about this target — and, for a robot, also the events that
160
+ * name it in `details.robot_id`, so a robot's log includes what was
161
+ * started on it.
162
+ *
163
+ * **A string, not `z.uuid()`**, unlike `actor_id` above: `target.id` is a
164
+ * string in this contract and text in the cloud's table, so a uuid rule
165
+ * here would refuse ids the log can hold, and no value can fail a cast.
166
+ */
167
+ target_id: z.string().min(1).max(200).optional().meta({
168
+ description: 'Events whose target is this id; for a robot also the events that name it in `details.robot_id` (`action.invoked`, ' +
169
+ '`service.called`, …), so a robot\'s events include what was started on it.',
170
+ }),
158
171
  /**
159
172
  * Absolute bounds in unix milliseconds, **half-open `[from, to)`** — the
160
173
  * same rule the history shapes follow.
package/dist/errors.d.ts CHANGED
@@ -77,5 +77,5 @@ export type InvalidCodeDetails = z.infer<typeof invalidCodeDetails>;
77
77
  * list is the shared vocabulary, not a closed set, so a new refusal never
78
78
  * needs a contracts release before it can be reported honestly.
79
79
  */
80
- export declare const ERROR_CODES: readonly ["not_found", "validation_error", "bad_request", "unknown_datapoint", "invalid_token", "protocol_mismatch", "bridge_too_old", "invalid_frame", "duplicate_slug", "reserved_slug", "unknown_slug", "unknown_field_path", "unknown_type", "unknown_topic", "invalid_rate", "invalid_range", "config_conflict", "no_data", "robot_offline", "bridge_timeout", "unauthorized", "forbidden", "invalid_credentials", "token_expired", "token_revoked", "email_taken", "identifier_taken", "weak_password", "account_blocked", "busy", "parameter_invalid", "cancel_rejected", "job_lost", "job_unknown_to_bridge", "action_server_lost", "action_failed", "goal_rejected", "goal_send_failed", "result_failed", "goal_uncontrollable", "bridge_disconnected", "config_changed", "publisher_busy", "unknown_command", "not_subscribable", "camera_offline", "no_snapshot_yet", "live_unavailable", "wrong_kind", "not_recorded", "not_aggregatable", "quota_exceeded", "credential_in_use", "goal_timeout", "robot_in_use", "robot_deletion_partial", "job_queue_full", "invalid_uuid", "rate_limited", "tier_required", "token_spent", "service_timeout", "asset_missing", "dynamic_registration_disabled", "client_limit_reached", "idp_unavailable", "mcp_disabled", "tool_not_available", "capability_required", "last_owner", "target_state_conflict", "signup_closed", "draft_not_a_document", "internal_error", "not_cancellable", "unsupported_media_type", "wrong_browser", "invalid_yaml", "unstorable_yaml", "registration_closed", "domain_not_allowed", "email_unverified", "origin_not_allowed", "template_invalid", "provider_disabled", "provider_misconfigured", "invalid_redirect_uri", "interaction_expired", "invalid_code", "method_not_allowed"];
80
+ export declare const ERROR_CODES: readonly ["not_found", "validation_error", "bad_request", "unknown_datapoint", "invalid_token", "protocol_mismatch", "bridge_too_old", "invalid_frame", "duplicate_slug", "reserved_slug", "unknown_slug", "unknown_field_path", "unknown_type", "unknown_topic", "invalid_rate", "invalid_range", "config_conflict", "no_data", "robot_offline", "bridge_timeout", "unauthorized", "forbidden", "invalid_credentials", "token_expired", "token_revoked", "email_taken", "identifier_taken", "weak_password", "account_blocked", "busy", "parameter_invalid", "cancel_rejected", "job_lost", "job_unknown_to_bridge", "action_server_lost", "action_failed", "goal_rejected", "goal_send_failed", "result_failed", "goal_uncontrollable", "bridge_disconnected", "config_changed", "publisher_busy", "unknown_command", "not_subscribable", "camera_offline", "no_snapshot_yet", "live_unavailable", "wrong_kind", "not_recorded", "not_aggregatable", "quota_exceeded", "credential_in_use", "goal_timeout", "robot_in_use", "robot_deletion_partial", "job_queue_full", "invalid_uuid", "rate_limited", "tier_required", "token_spent", "service_timeout", "asset_missing", "dynamic_registration_disabled", "client_limit_reached", "idp_unavailable", "mcp_disabled", "tool_not_available", "capability_required", "last_owner", "role_name_taken", "role_in_use", "last_role", "target_state_conflict", "signup_closed", "draft_not_a_document", "internal_error", "not_cancellable", "unsupported_media_type", "wrong_browser", "invalid_yaml", "unstorable_yaml", "registration_closed", "domain_not_allowed", "email_unverified", "origin_not_allowed", "template_invalid", "provider_disabled", "provider_misconfigured", "invalid_redirect_uri", "interaction_expired", "invalid_code", "method_not_allowed"];
81
81
  export type ErrorCode = (typeof ERROR_CODES)[number];
package/dist/errors.js CHANGED
@@ -576,6 +576,35 @@ export const ERROR_CODES = [
576
576
  * caller could infer from a silence about existence.
577
577
  */
578
578
  'last_owner',
579
+ // App roles.
580
+ /**
581
+ * **Another role of this app already has that name.** 409, on
582
+ * `PATCH /api/apps/:id/roles/:roleId`. Names are unique per app, compared
583
+ * exactly as stored after trimming.
584
+ *
585
+ * Not `validation_error`: the name is well-formed, and the remedy — pick
586
+ * another — depends on the app's other roles, not on the body.
587
+ */
588
+ 'role_name_taken',
589
+ /**
590
+ * **The role is still held**, by app users, by pending invitations, or as
591
+ * the app's default role. 409, on `DELETE /api/apps/:id/roles/:roleId`
592
+ * without `move_to`. `details` is `roleInUseDetails`:
593
+ * `{ users, invitations, is_default }`.
594
+ *
595
+ * Not `conflict`: the details tell the console what to offer — a role to
596
+ * move them to — and a generic code would leave it guessing.
597
+ */
598
+ 'role_in_use',
599
+ /**
600
+ * **An app must keep at least one role.** 409, on
601
+ * `DELETE /api/apps/:id/roles/:roleId` for the app's only role: every app
602
+ * user holds exactly one role, so an app without roles could hold no users.
603
+ *
604
+ * The same shape of refusal as `last_owner`: the caller may delete roles;
605
+ * the app's remaining state is what refuses this one.
606
+ */
607
+ 'last_role',
579
608
  // OIDC federation.
580
609
  /**
581
610
  * **The target is in a state that refuses the operation** — not the caller's
@@ -589,10 +618,9 @@ export const ERROR_CODES = [
589
618
  * string on the validation envelope is not a code a consumer can switch on.
590
619
  *
591
620
  * Its producers in the two-space model are the ones about an app or an
592
- * account rather than about a caller: `send_mail: true` on an app that has
593
- * configured no `invite_url` (the `details` name the field), and a password
594
- * change on an app user who has no password at all — an OIDC-only account,
595
- * where the session is live and it is the target's state that refuses.
621
+ * account rather than about a caller — for example a password change on an
622
+ * app user who has no password at all, an OIDC-only account, where the
623
+ * session is live and it is the target's state that refuses.
596
624
  *
597
625
  * **A tier change aimed at somebody who is not a Fleetless user of this org
598
626
  * was listed here and stopped being a producer at the cut.** That refusal
@@ -857,10 +885,10 @@ export const ERROR_CODES = [
857
885
  */
858
886
  'invalid_code',
859
887
  /**
860
- * `403`: the app does not offer this sign-in method — a password login on a
861
- * code-only app, a code request on a password-only one, or a password where
862
- * the app takes none. It names the app's policy, never a person, so it is
863
- * no enumeration oracle.
888
+ * `403`: the app does not offer this sign-in method — a password login, a
889
+ * password reset or a password change on a code-only app, or a code request
890
+ * on a password-only one. It names the app's policy, never a person, so it
891
+ * is no enumeration oracle.
864
892
  */
865
893
  'method_not_allowed',
866
894
  ];
@@ -0,0 +1,42 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ import { z } from 'zod';
3
+ /**
4
+ * **Feedback: a message from a developer to the people who build Fleetless.**
5
+ *
6
+ * The console's feedback modal sends it; the cloud stores it first and mails
7
+ * it afterwards, so a message is never lost to a mail failure. Who sent it and
8
+ * from which org is the caller's session, never the body: the body carries
9
+ * only what the developer chose to say and the page they said it on.
10
+ */
11
+ /** The four kinds the console's modal offers. */
12
+ export declare const FEEDBACK_KINDS: readonly ["idea", "problem", "question", "other"];
13
+ export declare const feedbackKind: z.ZodEnum<{
14
+ idea: "idea";
15
+ problem: "problem";
16
+ question: "question";
17
+ other: "other";
18
+ }>;
19
+ /** Longest message the cloud stores; the console's counter starts at 4 500. */
20
+ export declare const FEEDBACK_MESSAGE_MAX = 5000;
21
+ export declare const feedbackRequest: z.ZodObject<{
22
+ kind: z.ZodEnum<{
23
+ idea: "idea";
24
+ problem: "problem";
25
+ question: "question";
26
+ other: "other";
27
+ }>;
28
+ message: z.ZodString;
29
+ page: z.ZodString;
30
+ }, z.core.$strict>;
31
+ export declare const feedbackResponse: z.ZodObject<{
32
+ id: z.ZodUUID;
33
+ mail: z.ZodEnum<{
34
+ sent: "sent";
35
+ not_requested: "not_requested";
36
+ not_configured: "not_configured";
37
+ failed: "failed";
38
+ }>;
39
+ }, z.core.$strict>;
40
+ export type FeedbackKind = z.infer<typeof feedbackKind>;
41
+ export type FeedbackRequest = z.infer<typeof feedbackRequest>;
42
+ export type FeedbackResponse = z.infer<typeof feedbackResponse>;
@@ -0,0 +1,35 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ import { z } from 'zod';
3
+ import { mailStatus } from './identity.js';
4
+ /**
5
+ * **Feedback: a message from a developer to the people who build Fleetless.**
6
+ *
7
+ * The console's feedback modal sends it; the cloud stores it first and mails
8
+ * it afterwards, so a message is never lost to a mail failure. Who sent it and
9
+ * from which org is the caller's session, never the body: the body carries
10
+ * only what the developer chose to say and the page they said it on.
11
+ */
12
+ /** The four kinds the console's modal offers. */
13
+ export const FEEDBACK_KINDS = ['idea', 'problem', 'question', 'other'];
14
+ export const feedbackKind = z.enum(FEEDBACK_KINDS);
15
+ /** Longest message the cloud stores; the console's counter starts at 4 500. */
16
+ export const FEEDBACK_MESSAGE_MAX = 5000;
17
+ export const feedbackRequest = z.object({
18
+ kind: feedbackKind.meta({
19
+ description: 'What the message is: an `idea`, a `problem`, a `question` or `other`. It only sorts the inbox; it changes nothing about how the message is handled.',
20
+ }),
21
+ message: z.string().trim().min(1).max(FEEDBACK_MESSAGE_MAX).meta({
22
+ description: 'What the developer wrote, trimmed. At most 5000 characters; a message that is only whitespace is refused.',
23
+ }),
24
+ page: z.string().startsWith('/').max(512).meta({
25
+ description: 'The console path the message was sent from, e.g. `/robots/:id/jobs` with its real id. A path, never a full URL, so no host and no query string reach the inbox by accident.',
26
+ }),
27
+ }).strict();
28
+ export const feedbackResponse = z.object({
29
+ id: z.uuid().meta({
30
+ description: 'The stored message. It exists whatever `mail` says.',
31
+ }),
32
+ mail: mailStatus.meta({
33
+ description: 'What happened to the notification mail: `sent`, `failed`, or `not_configured` when this cloud has no feedback address. The message is stored in every case, so a client shows success for all three.',
34
+ }),
35
+ }).strict();
@@ -220,11 +220,9 @@ export type WaitlistRequest = z.infer<typeof waitlistRequest>;
220
220
  * no sender can promise that, and this value must never
221
221
  * be rendered as if it could.
222
222
  * - `not_requested` — no mail was attempted: the caller asked for none
223
- * (`send_mail: false`), or there was no link for one to
224
- * carry (the app has configured no `invite_url`, which
225
- * the `null` `accept_url` beside it says). **A fourth
226
- * word rather than a reuse of `not_configured`**: the
227
- * deployment's mailer is irrelevant in both cases, and a
223
+ * (`send_mail: false`). **A fourth word rather than a
224
+ * reuse of `not_configured`**: the deployment's mailer
225
+ * is irrelevant there, and a
228
226
  * console reading "mail server not configured" beside an
229
227
  * invitation whose mail checkbox was off would send a
230
228
  * developer to fix something that is not broken.
package/dist/identity.js CHANGED
@@ -225,11 +225,9 @@ export const waitlistRequest = z.object({ email: z.email().max(254) });
225
225
  * no sender can promise that, and this value must never
226
226
  * be rendered as if it could.
227
227
  * - `not_requested` — no mail was attempted: the caller asked for none
228
- * (`send_mail: false`), or there was no link for one to
229
- * carry (the app has configured no `invite_url`, which
230
- * the `null` `accept_url` beside it says). **A fourth
231
- * word rather than a reuse of `not_configured`**: the
232
- * deployment's mailer is irrelevant in both cases, and a
228
+ * (`send_mail: false`). **A fourth word rather than a
229
+ * reuse of `not_configured`**: the deployment's mailer
230
+ * is irrelevant there, and a
233
231
  * console reading "mail server not configured" beside an
234
232
  * invitation whose mail checkbox was off would send a
235
233
  * developer to fix something that is not broken.
package/dist/index.d.ts CHANGED
@@ -31,8 +31,10 @@ export { clientAuth, authOk, authError, clientInvoke, clientCancel, clientPublis
31
31
  export type { ClientAuth, AuthOk, AuthError, ClientInvoke, ClientCancel, ClientPublish, CommandResult, ErrorFrame, ClientSubscribe, ClientUnsubscribe, SubscribeError, DatapointEvent, ResourceHealthEvent, ResourceHealthCleared, LiveSessionEndReason, LiveSessionEvent, OrgEventKind, OrgEventSeverity, OrgEvent, OrgEventSubscribe, OrgEventUnsubscribe, OrgEventReplay, OrgEventDropped, } from './realtime.js';
32
32
  export { password, org, patchOrgResponse, sessionTokens, refreshRequest, waitlistRequest, USER_DISPLAY_NAME_MAX, orgAdminTier, fleetlessUser, fleetlessUserListResponse, createTeamInviteRequest, teamInvite, pendingTeamInvite, pendingTeamInviteListResponse, acceptTeamInviteRequest, patchFleetlessUserRequest, tierChangeRequest, mailStatus, tierRequiredDetails, passwordChangeRequest, idpIssuer, loginCode, totpCode, recoveryCode, recoveryCodesList, twoFactorSetupResponse, webauthnJson, webauthnOptionsResponse, developerPasskey, developerTwoFactor, createPasskeyRequest, createPasskeyResponse, renamePasskeyRequest, totpConfirmRequest, totpConfirmResponse, recoveryCodesResponse, authMeResponse, patchOrgRequest, patchAuthMeRequest, } from './identity.js';
33
33
  export type { Org, PatchOrgResponse, SessionTokens, RefreshRequest, WaitlistRequest, OrgAdminTier, FleetlessUser, FleetlessUserListResponse, CreateTeamInviteRequest, TeamInvite, PendingTeamInvite, PendingTeamInviteListResponse, AcceptTeamInviteRequest, PatchFleetlessUserRequest, TierChangeRequest, MailStatus, TierRequiredDetails, PasswordChangeRequest, IdpIssuer, TwoFactorSetupResponse, WebauthnOptionsResponse, DeveloperPasskey, DeveloperTwoFactor, CreatePasskeyRequest, CreatePasskeyResponse, RenamePasskeyRequest, TotpConfirmRequest, TotpConfirmResponse, RecoveryCodesResponse, AuthMeResponse, PatchOrgRequest, PatchAuthMeRequest, } from './identity.js';
34
- export { appIdentifier, app, appListResponse, appDeletionSummary, createAppRequest, updateAppRequest, serverKeyToken, serverKey, serverKeyListResponse, createServerKeyResponse, role, roleListResponse, rolePermissions, } from './apps.js';
35
- export type { App, AppListResponse, AppDeletionSummary, CreateAppRequest, UpdateAppRequest, ServerKey, ServerKeyListResponse, CreateServerKeyResponse, Role, RoleListResponse, RolePermissions, } from './apps.js';
34
+ export { FEEDBACK_KINDS, FEEDBACK_MESSAGE_MAX, feedbackKind, feedbackRequest, feedbackResponse } from './feedback.js';
35
+ export type { FeedbackKind, FeedbackRequest, FeedbackResponse } from './feedback.js';
36
+ export { appIdentifier, app, appListResponse, appDeletionSummary, createAppRequest, updateAppRequest, serverKeyToken, serverKey, serverKeyListResponse, createServerKeyResponse, role, roleListResponse, rolePermissions, roleRenameRequest, roleDeleteQuery, roleInUseDetails, } from './apps.js';
37
+ export type { App, AppListResponse, AppDeletionSummary, CreateAppRequest, UpdateAppRequest, ServerKey, ServerKeyListResponse, CreateServerKeyResponse, Role, RoleListResponse, RolePermissions, RoleRenameRequest, RoleDeleteQuery, RoleInUseDetails, } from './apps.js';
36
38
  export { clientLoginRequest, clientRefreshRequest, clientLogoutRequest, clientRegisterRequest, clientVerifyEmailRequest, clientResendVerificationRequest, clientPasswordResetRequest, clientPasswordResetConfirmRequest, clientAcceptInvitationRequest, CLIENT_OIDC_CALLBACK_PATH, clientProviderListQuery, clientProviderListResponse, clientOidcStartQuery, clientOidcCallbackQuery, clientOidcExchangeRequest, clientOidcErrorCode, clientMcpInteraction, clientMcpInteractionDecisionResponse, mcpConsentGrant, mcpConsentGrantListResponse, clientIdentity, clientLoginCodeRequest, clientLoginCodeVerifyRequest, twoFactorChallenge, clientSignInResult, clientTwoFactorVerifyRequest, clientTwoFactorSetupRequest, clientTwoFactorSetupConfirmRequest, clientTwoFactorSetupConfirmResponse, clientTwoFactorDisableRequest, } from './client-auth.js';
37
39
  export type { ClientLoginRequest, ClientRefreshRequest, ClientLogoutRequest, ClientRegisterRequest, ClientVerifyEmailRequest, ClientResendVerificationRequest, ClientPasswordResetRequest, ClientPasswordResetConfirmRequest, ClientAcceptInvitationRequest, ClientProviderListQuery, ClientProviderListResponse, ClientOidcStartQuery, ClientOidcCallbackQuery, ClientOidcExchangeRequest, ClientOidcErrorCode, ClientMcpInteraction, ClientMcpInteractionDecisionResponse, McpConsentGrant, McpConsentGrantListResponse, ClientIdentity, ClientLoginCodeRequest, ClientLoginCodeVerifyRequest, TwoFactorChallenge, ClientSignInResult, ClientTwoFactorVerifyRequest, ClientTwoFactorSetupRequest, ClientTwoFactorSetupConfirmRequest, ClientTwoFactorSetupConfirmResponse, ClientTwoFactorDisableRequest, } from './client-auth.js';
38
40
  export { clientRobotListItem, clientRobotListResponse } from './client-robots.js';
package/dist/index.js CHANGED
@@ -42,7 +42,9 @@ loginCode, totpCode, recoveryCode, recoveryCodesList, twoFactorSetupResponse,
42
42
  webauthnJson, webauthnOptionsResponse, developerPasskey, developerTwoFactor, createPasskeyRequest, createPasskeyResponse, renamePasskeyRequest, totpConfirmRequest, totpConfirmResponse, recoveryCodesResponse,
43
43
  // auth/me, org and member patches.
44
44
  authMeResponse, patchOrgRequest, patchAuthMeRequest, } from './identity.js';
45
- export { appIdentifier, app, appListResponse, appDeletionSummary, createAppRequest, updateAppRequest, serverKeyToken, serverKey, serverKeyListResponse, createServerKeyResponse, role, roleListResponse, rolePermissions, } from './apps.js';
45
+ // 2026-09-30 — the console's feedback modal.
46
+ export { FEEDBACK_KINDS, FEEDBACK_MESSAGE_MAX, feedbackKind, feedbackRequest, feedbackResponse } from './feedback.js';
47
+ export { appIdentifier, app, appListResponse, appDeletionSummary, createAppRequest, updateAppRequest, serverKeyToken, serverKey, serverKeyListResponse, createServerKeyResponse, role, roleListResponse, rolePermissions, roleRenameRequest, roleDeleteQuery, roleInUseDetails, } from './apps.js';
46
48
  export { clientLoginRequest, clientRefreshRequest, clientLogoutRequest, clientRegisterRequest, clientVerifyEmailRequest, clientResendVerificationRequest, clientPasswordResetRequest, clientPasswordResetConfirmRequest, clientAcceptInvitationRequest, CLIENT_OIDC_CALLBACK_PATH, clientProviderListQuery, clientProviderListResponse, clientOidcStartQuery, clientOidcCallbackQuery, clientOidcExchangeRequest, clientOidcErrorCode, clientMcpInteraction, clientMcpInteractionDecisionResponse, mcpConsentGrant, mcpConsentGrantListResponse, clientIdentity, clientLoginCodeRequest, clientLoginCodeVerifyRequest, twoFactorChallenge, clientSignInResult, clientTwoFactorVerifyRequest, clientTwoFactorSetupRequest, clientTwoFactorSetupConfirmRequest, clientTwoFactorSetupConfirmResponse, clientTwoFactorDisableRequest, } from './client-auth.js';
47
49
  export { clientRobotListItem, clientRobotListResponse } from './client-robots.js';
48
50
  // The per-app identity space.
package/dist/jobs.d.ts CHANGED
@@ -241,6 +241,7 @@ export declare const jobActor: z.ZodObject<{
241
241
  }>;
242
242
  id: z.ZodUUID;
243
243
  label: z.ZodString;
244
+ name: z.ZodNullable<z.ZodString>;
244
245
  }, z.core.$strip>;
245
246
  export type JobActor = z.infer<typeof jobActor>;
246
247
  export declare const jobRunKind: z.ZodEnum<{
@@ -289,6 +290,7 @@ export declare const jobRun: z.ZodObject<{
289
290
  }>;
290
291
  id: z.ZodUUID;
291
292
  label: z.ZodString;
293
+ name: z.ZodNullable<z.ZodString>;
292
294
  }, z.core.$strip>;
293
295
  seq: z.ZodNumber;
294
296
  progress: z.ZodNullable<z.ZodNumber>;
@@ -351,6 +353,7 @@ export declare const jobRunListResponse: z.ZodObject<{
351
353
  }>;
352
354
  id: z.ZodUUID;
353
355
  label: z.ZodString;
356
+ name: z.ZodNullable<z.ZodString>;
354
357
  }, z.core.$strip>;
355
358
  seq: z.ZodNumber;
356
359
  progress: z.ZodNullable<z.ZodNumber>;
package/dist/jobs.js CHANGED
@@ -226,6 +226,22 @@ export const jobActor = z.object({
226
226
  label: z.string().min(1).max(200).meta({
227
227
  description: 'A display name taken at invoke time — the email for a Fleetless user or an app user, the key\'s own name for a server key. Storing it rather than joining is the point: renaming a key afterwards does not rewrite history.',
228
228
  }),
229
+ /**
230
+ * The person's display name, snapshotted beside `label` for the same
231
+ * reason. **Required and nullable**, so a consumer never has to tell
232
+ * "absent" from "null": every run a 5.3.0 cloud answers carries it, and
233
+ * `null` means there is no name to show — a server key, a person without
234
+ * one, or a run recorded before the field existed.
235
+ *
236
+ * `jobActor` stays a plain object, not `.strict()`: a consumer still on an
237
+ * older contracts version then parses a newer cloud's answer by stripping
238
+ * the key instead of refusing the whole run.
239
+ */
240
+ name: z.string().min(1).max(200).nullable().meta({
241
+ description: 'The person\'s display name when the job started: the Fleetless user\'s `display_name` for a developer, the app user\'s ' +
242
+ '`display_name` for an app user. `null` for a server key, when the person had no name set, and for runs recorded before ' +
243
+ 'contracts 5.3.0. Show `label` when it is null.',
244
+ }),
229
245
  });
230
246
  export const jobRunKind = z.enum(['action', 'service']);
231
247
  /**
package/dist/routes.d.ts CHANGED
@@ -103,9 +103,16 @@ export declare const IN_HANDLER_ROUTES: readonly string[];
103
103
  *
104
104
  * Every step is a page the auth portal serves to itself: `audience:
105
105
  * 'internal'`, no request schema — the handlers read form fields by hand — and
106
- * HTML for a browser form post, JSON for a JSON caller. Every step after
107
- * `identify` needs the browser-proof cookie set there, so a step posted from
108
- * another browser renders the `wrong_browser` page. The interaction's ten
106
+ * HTML for a browser form post, JSON for a JSON caller.
107
+ *
108
+ * **The browser-proof cookie binds the interaction to one browser**, and it
109
+ * is set by whichever of these comes first for the interaction: the email
110
+ * card (`GET <prefix>/interaction/:id`), `POST <prefix>/identify`, or `POST
111
+ * <prefix>/passkey/options`. The email card is what a browser normally opens
112
+ * first; the two steps set it for a caller that never loaded the page, so
113
+ * `Sign in with a passkey` works without an email step. Once the interaction
114
+ * is bound, every step — those three included — without the matching cookie
115
+ * renders the `wrong_browser` page. The interaction's ten
109
116
  * minutes cover every step; only when the last one is done is anything
110
117
  * minted. **For `/mcp/oauth`, "done" means the consent step**, as the
111
118
  * password did before.