@fleetless/contracts 5.1.0 → 5.3.0-next.1

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.
@@ -142,12 +142,26 @@
142
142
  "minLength": 1,
143
143
  "maxLength": 200,
144
144
  "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."
145
+ },
146
+ "name": {
147
+ "anyOf": [
148
+ {
149
+ "type": "string",
150
+ "minLength": 1,
151
+ "maxLength": 200
152
+ },
153
+ {
154
+ "type": "null"
155
+ }
156
+ ],
157
+ "description": "The person's display name when the job started: the Fleetless user's `display_name` for a developer, the app user's `display_name` for an app user. `null` for a server key, when the person had no name set, and for runs recorded before contracts 5.3.0. Show `label` when it is null."
145
158
  }
146
159
  },
147
160
  "required": [
148
161
  "kind",
149
162
  "id",
150
- "label"
163
+ "label",
164
+ "name"
151
165
  ],
152
166
  "additionalProperties": false,
153
167
  "description": "Who invoked the run, and what they were acting as at the time."
@@ -137,12 +137,26 @@
137
137
  "minLength": 1,
138
138
  "maxLength": 200,
139
139
  "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."
140
+ },
141
+ "name": {
142
+ "anyOf": [
143
+ {
144
+ "type": "string",
145
+ "minLength": 1,
146
+ "maxLength": 200
147
+ },
148
+ {
149
+ "type": "null"
150
+ }
151
+ ],
152
+ "description": "The person's display name when the job started: the Fleetless user's `display_name` for a developer, the app user's `display_name` for an app user. `null` for a server key, when the person had no name set, and for runs recorded before contracts 5.3.0. Show `label` when it is null."
140
153
  }
141
154
  },
142
155
  "required": [
143
156
  "kind",
144
157
  "id",
145
- "label"
158
+ "label",
159
+ "name"
146
160
  ],
147
161
  "additionalProperties": false,
148
162
  "description": "Who invoked the run, and what they were acting as at the time."
@@ -0,0 +1,13 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "type": "object",
4
+ "properties": {
5
+ "move_to": {
6
+ "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`.",
7
+ "type": "string",
8
+ "format": "uuid",
9
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
10
+ }
11
+ },
12
+ "additionalProperties": false
13
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "type": "object",
4
+ "properties": {
5
+ "users": {
6
+ "type": "integer",
7
+ "minimum": 0,
8
+ "maximum": 9007199254740991,
9
+ "description": "App users whose role this is."
10
+ },
11
+ "invitations": {
12
+ "type": "integer",
13
+ "minimum": 0,
14
+ "maximum": 9007199254740991,
15
+ "description": "Pending invitations that would grant this role when accepted."
16
+ },
17
+ "is_default": {
18
+ "type": "boolean",
19
+ "description": "`true` when this is the app's `default_role_id`; the default then moves with the users to `move_to`."
20
+ }
21
+ },
22
+ "required": [
23
+ "users",
24
+ "invitations",
25
+ "is_default"
26
+ ],
27
+ "additionalProperties": false
28
+ }
@@ -27,7 +27,7 @@
27
27
  },
28
28
  "builtin": {
29
29
  "type": "boolean",
30
- "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."
30
+ "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."
31
31
  }
32
32
  },
33
33
  "required": [
@@ -0,0 +1,16 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "type": "object",
4
+ "properties": {
5
+ "name": {
6
+ "type": "string",
7
+ "minLength": 1,
8
+ "maxLength": 60,
9
+ "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."
10
+ }
11
+ },
12
+ "required": [
13
+ "name"
14
+ ],
15
+ "additionalProperties": false
16
+ }
@@ -22,7 +22,7 @@
22
22
  },
23
23
  "builtin": {
24
24
  "type": "boolean",
25
- "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."
25
+ "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."
26
26
  }
27
27
  },
28
28
  "required": [
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
@@ -68,5 +68,5 @@ export type CancelRejectedDetails = z.infer<typeof cancelRejectedDetails>;
68
68
  * list is the shared vocabulary, not a closed set, so a new refusal never
69
69
  * needs a contracts release before it can be reported honestly.
70
70
  */
71
- 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"];
71
+ 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"];
72
72
  export type ErrorCode = (typeof ERROR_CODES)[number];
package/dist/errors.js CHANGED
@@ -562,6 +562,35 @@ export const ERROR_CODES = [
562
562
  * caller could infer from a silence about existence.
563
563
  */
564
564
  'last_owner',
565
+ // App roles.
566
+ /**
567
+ * **Another role of this app already has that name.** 409, on
568
+ * `PATCH /api/apps/:id/roles/:roleId`. Names are unique per app, compared
569
+ * exactly as stored after trimming.
570
+ *
571
+ * Not `validation_error`: the name is well-formed, and the remedy — pick
572
+ * another — depends on the app's other roles, not on the body.
573
+ */
574
+ 'role_name_taken',
575
+ /**
576
+ * **The role is still held**, by app users, by pending invitations, or as
577
+ * the app's default role. 409, on `DELETE /api/apps/:id/roles/:roleId`
578
+ * without `move_to`. `details` is `roleInUseDetails`:
579
+ * `{ users, invitations, is_default }`.
580
+ *
581
+ * Not `conflict`: the details tell the console what to offer — a role to
582
+ * move them to — and a generic code would leave it guessing.
583
+ */
584
+ 'role_in_use',
585
+ /**
586
+ * **An app must keep at least one role.** 409, on
587
+ * `DELETE /api/apps/:id/roles/:roleId` for the app's only role: every app
588
+ * user holds exactly one role, so an app without roles could hold no users.
589
+ *
590
+ * The same shape of refusal as `last_owner`: the caller may delete roles;
591
+ * the app's remaining state is what refuses this one.
592
+ */
593
+ 'last_role',
565
594
  // OIDC federation.
566
595
  /**
567
596
  * **The target is in a state that refuses the operation** — not the caller's
@@ -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();
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, signUpRequest, signUpResponse, waitlistRequest, developerLoginRequest, USER_DISPLAY_NAME_MAX, orgAdminTier, fleetlessUser, fleetlessUserListResponse, createTeamInviteRequest, teamInvite, pendingTeamInvite, pendingTeamInviteListResponse, acceptTeamInviteRequest, patchFleetlessUserRequest, tierChangeRequest, mailStatus, tierRequiredDetails, passwordChangeRequest, passwordResetRequest, passwordResetConfirm, idpIssuer, authMeResponse, patchOrgRequest, patchAuthMeRequest, } from './identity.js';
33
33
  export type { Org, PatchOrgResponse, SessionTokens, RefreshRequest, SignUpRequest, SignUpResponse, WaitlistRequest, DeveloperLoginRequest, OrgAdminTier, FleetlessUser, FleetlessUserListResponse, CreateTeamInviteRequest, TeamInvite, PendingTeamInvite, PendingTeamInviteListResponse, AcceptTeamInviteRequest, PatchFleetlessUserRequest, TierChangeRequest, MailStatus, TierRequiredDetails, PasswordChangeRequest, PasswordResetRequest, PasswordResetConfirm, IdpIssuer, 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, } 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, } from './client-auth.js';
38
40
  export { clientRobotListItem, clientRobotListResponse } from './client-robots.js';
package/dist/index.js CHANGED
@@ -38,7 +38,9 @@ USER_DISPLAY_NAME_MAX, orgAdminTier, fleetlessUser, fleetlessUserListResponse, c
38
38
  mailStatus, tierRequiredDetails, passwordChangeRequest, passwordResetRequest, passwordResetConfirm, idpIssuer,
39
39
  // auth/me, org and member patches.
40
40
  authMeResponse, patchOrgRequest, patchAuthMeRequest, } from './identity.js';
41
- export { appIdentifier, app, appListResponse, appDeletionSummary, createAppRequest, updateAppRequest, serverKeyToken, serverKey, serverKeyListResponse, createServerKeyResponse, role, roleListResponse, rolePermissions, } from './apps.js';
41
+ // 2026-09-30 — the console's feedback modal.
42
+ export { FEEDBACK_KINDS, FEEDBACK_MESSAGE_MAX, feedbackKind, feedbackRequest, feedbackResponse } from './feedback.js';
43
+ export { appIdentifier, app, appListResponse, appDeletionSummary, createAppRequest, updateAppRequest, serverKeyToken, serverKey, serverKeyListResponse, createServerKeyResponse, role, roleListResponse, rolePermissions, roleRenameRequest, roleDeleteQuery, roleInUseDetails, } from './apps.js';
42
44
  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, } from './client-auth.js';
43
45
  export { clientRobotListItem, clientRobotListResponse } from './client-robots.js';
44
46
  // 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
  /**
@@ -78,7 +78,7 @@ export interface ProtocolVersionEntry {
78
78
  */
79
79
  export declare const PROTOCOL_VERSIONS: readonly ProtocolVersionEntry[];
80
80
  /** The newest bridge package. The cloud mails organisations still below it. */
81
- export declare const LATEST_BRIDGE_VERSION = "6.0.0";
81
+ export declare const LATEST_BRIDGE_VERSION = "6.1.0";
82
82
  export interface ProtocolStatus {
83
83
  status: 'current' | 'deprecated' | 'unsupported';
84
84
  /** ISO date, or null for a current or unknown version. */
@@ -642,12 +642,24 @@ export type CloudInvoke = z.infer<typeof cloudInvoke>;
642
642
  * `request_id` correlates the bridge's `cancel_result`, which carries each
643
643
  * goal's `CancelGoal` return code; the cloud answers its caller only from
644
644
  * that.
645
+ *
646
+ * `own_only` (fleetless#84) limits a cancel to a job the bridge started
647
+ * itself and holds. `true`: the bridge cancels the named job only if it is
648
+ * its own; a `job_id` it does not hold, or holds as an external goal,
649
+ * cancels **nothing** and is answered `goals: []`. The cloud sets it on the
650
+ * cancels it sends on its own — a republish's reset and that reset's resend
651
+ * at the next hello — so a republish never stops a goal Fleetless did not
652
+ * start. A user's cancel never sets it: only an explicit cancel may reach
653
+ * external goals. Absent means `false`, today's meaning. `true` needs a
654
+ * `job_id`: the bridge refuses `own_only: true` with `job_id: null` as
655
+ * unusable. Bridges before 6.1.0 ignore the key.
645
656
  */
646
657
  export declare const cloudCancel: z.ZodObject<{
647
658
  type: z.ZodLiteral<"cancel">;
648
659
  request_id: z.ZodString;
649
660
  slug: z.ZodString;
650
661
  job_id: z.ZodNullable<z.ZodUUID>;
662
+ own_only: z.ZodOptional<z.ZodBoolean>;
651
663
  }, z.core.$strip>;
652
664
  export type CloudCancel = z.infer<typeof cloudCancel>;
653
665
  /**
package/dist/protocol.js CHANGED
@@ -79,7 +79,7 @@ export const PROTOCOL_VERSIONS = [
79
79
  { version: 5, bridge_from: '6.0.0', deprecated_at: null },
80
80
  ];
81
81
  /** The newest bridge package. The cloud mails organisations still below it. */
82
- export const LATEST_BRIDGE_VERSION = '6.0.0';
82
+ export const LATEST_BRIDGE_VERSION = '6.1.0';
83
83
  const DAY_MS = 24 * 60 * 60 * 1000;
84
84
  function isoDate(date) {
85
85
  return date.toISOString().slice(0, 10);
@@ -481,12 +481,24 @@ export const cloudInvoke = z.object({
481
481
  * `request_id` correlates the bridge's `cancel_result`, which carries each
482
482
  * goal's `CancelGoal` return code; the cloud answers its caller only from
483
483
  * that.
484
+ *
485
+ * `own_only` (fleetless#84) limits a cancel to a job the bridge started
486
+ * itself and holds. `true`: the bridge cancels the named job only if it is
487
+ * its own; a `job_id` it does not hold, or holds as an external goal,
488
+ * cancels **nothing** and is answered `goals: []`. The cloud sets it on the
489
+ * cancels it sends on its own — a republish's reset and that reset's resend
490
+ * at the next hello — so a republish never stops a goal Fleetless did not
491
+ * start. A user's cancel never sets it: only an explicit cancel may reach
492
+ * external goals. Absent means `false`, today's meaning. `true` needs a
493
+ * `job_id`: the bridge refuses `own_only: true` with `job_id: null` as
494
+ * unusable. Bridges before 6.1.0 ignore the key.
484
495
  */
485
496
  export const cloudCancel = z.object({
486
497
  type: z.literal('cancel'),
487
498
  request_id: z.string().min(1).max(64),
488
499
  slug,
489
500
  job_id: z.uuid().nullable(),
501
+ own_only: z.boolean().optional(),
490
502
  });
491
503
  /**
492
504
  * The ROS 2 `action_msgs/srv/CancelGoal` return codes: `0` `ERROR_NONE` (the