@fleetless/contracts 6.0.0-next.2 → 6.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 +40 -0
- package/artifacts/openapi.json +288 -4
- package/artifacts/routes.json +96 -1
- package/artifacts/schema/audit-query.schema.json +6 -0
- package/artifacts/schema/feedback-request.schema.json +34 -0
- package/artifacts/schema/feedback-response.schema.json +27 -0
- package/artifacts/schema/job-actor.schema.json +15 -1
- package/artifacts/schema/job-run-list-response.schema.json +15 -1
- package/artifacts/schema/job-run.schema.json +15 -1
- package/artifacts/schema/role-delete-query.schema.json +13 -0
- package/artifacts/schema/role-in-use-details.schema.json +28 -0
- package/artifacts/schema/role-list-response.schema.json +1 -1
- package/artifacts/schema/role-rename-request.schema.json +16 -0
- package/artifacts/schema/role.schema.json +1 -1
- package/dist/apps.d.ts +38 -2
- package/dist/apps.js +46 -3
- package/dist/audit.d.ts +1 -0
- package/dist/audit.js +13 -0
- package/dist/errors.d.ts +1 -1
- package/dist/errors.js +29 -0
- package/dist/feedback.d.ts +42 -0
- package/dist/feedback.js +35 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +3 -1
- package/dist/jobs.d.ts +3 -0
- package/dist/jobs.js +16 -0
- package/dist/routes.js +40 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,8 @@ version.
|
|
|
9
9
|
|
|
10
10
|
## [Unreleased]
|
|
11
11
|
|
|
12
|
+
## [6.0.0] — 2026-10-02
|
|
13
|
+
|
|
12
14
|
### Added
|
|
13
15
|
|
|
14
16
|
- **App sign-in methods, two-factor policy, hosted pages and look.**
|
|
@@ -120,6 +122,44 @@ version.
|
|
|
120
122
|
`clientProviderListResponse.sign_in_methods`) and the narrowed `mcp`
|
|
121
123
|
slice break existing readers as well.
|
|
122
124
|
|
|
125
|
+
## [5.3.0] — 2026-10-02
|
|
126
|
+
|
|
127
|
+
### Added
|
|
128
|
+
|
|
129
|
+
- **`feedbackRequest` and `feedbackResponse`** (`FeedbackRequest`,
|
|
130
|
+
`FeedbackResponse`) for the new `POST /api/feedback`: a developer's
|
|
131
|
+
message to the people who build Fleetless, `{ kind, message, page }` with
|
|
132
|
+
`kind` one of `FEEDBACK_KINDS` (`idea`, `problem`, `question`, `other`), a
|
|
133
|
+
trimmed message of at most `FEEDBACK_MESSAGE_MAX` (5000) characters and
|
|
134
|
+
the console path it was sent from. The route answers `202` with
|
|
135
|
+
`{ id, mail }`: the message is stored before any mail is tried, so `mail`
|
|
136
|
+
(`sent`, `failed`, `not_configured`) never means it was lost. Rate
|
|
137
|
+
limited to 10 per developer per hour. Published as the artifacts
|
|
138
|
+
`feedback-request` and `feedback-response`.
|
|
139
|
+
- **`jobActor.name`**: the person's display name when the job started,
|
|
140
|
+
required and nullable — `null` for a server key, a person without a name
|
|
141
|
+
and runs recorded before this version; show `label` then. `jobActor`
|
|
142
|
+
stays non-strict, so a consumer on 5.2.0 strips the new key rather than
|
|
143
|
+
refusing the run. Changes the artifacts `job-actor`, `job-run` and
|
|
144
|
+
`job-run-list-response`.
|
|
145
|
+
- **`roleRenameRequest`, `roleDeleteQuery` and `roleInUseDetails`**
|
|
146
|
+
(`RoleRenameRequest`, `RoleDeleteQuery`, `RoleInUseDetails`) for the new
|
|
147
|
+
`PATCH` and `DELETE /api/apps/:id/roles/:roleId`: rename a role
|
|
148
|
+
(`409 role_name_taken` on a clash), or delete it, moving its app users,
|
|
149
|
+
pending invitations and default-role status to `move_to`. Without
|
|
150
|
+
`move_to` a held role answers `409 role_in_use` with
|
|
151
|
+
`{ users, invitations, is_default }`; the app's only role answers
|
|
152
|
+
`409 last_role`. The three codes join `ERROR_CODES`. `role.builtin` no
|
|
153
|
+
longer says built-in roles cannot be renamed or deleted, and the create
|
|
154
|
+
route's note now states the 60-character limit `role.name` always had.
|
|
155
|
+
Published as the artifacts `role-rename-request`, `role-delete-query`
|
|
156
|
+
and `role-in-use-details`.
|
|
157
|
+
- **`auditQuery.target_id`**: only the events about one target — for a
|
|
158
|
+
robot also those that name it in `details.robot_id`, so a robot's log
|
|
159
|
+
includes what was started on it. A string, since target ids are not all
|
|
160
|
+
uuids. `GET /api/audit/export` takes it too. Changes the artifact
|
|
161
|
+
`audit-query`.
|
|
162
|
+
|
|
123
163
|
## [5.2.0] — 2026-09-30
|
|
124
164
|
|
|
125
165
|
### Added
|
package/artifacts/openapi.json
CHANGED
|
@@ -732,6 +732,17 @@
|
|
|
732
732
|
"maxLength": 40
|
|
733
733
|
}
|
|
734
734
|
},
|
|
735
|
+
{
|
|
736
|
+
"name": "target_id",
|
|
737
|
+
"in": "query",
|
|
738
|
+
"required": false,
|
|
739
|
+
"schema": {
|
|
740
|
+
"description": "Events whose target is this id; for a robot also the events that name it in `details.robot_id` (`action.invoked`, `service.called`, …), so a robot's events include what was started on it.",
|
|
741
|
+
"type": "string",
|
|
742
|
+
"minLength": 1,
|
|
743
|
+
"maxLength": 200
|
|
744
|
+
}
|
|
745
|
+
},
|
|
735
746
|
{
|
|
736
747
|
"name": "from_ms",
|
|
737
748
|
"in": "query",
|
|
@@ -883,6 +894,17 @@
|
|
|
883
894
|
"maxLength": 40
|
|
884
895
|
}
|
|
885
896
|
},
|
|
897
|
+
{
|
|
898
|
+
"name": "target_id",
|
|
899
|
+
"in": "query",
|
|
900
|
+
"required": false,
|
|
901
|
+
"schema": {
|
|
902
|
+
"description": "Events whose target is this id; for a robot also the events that name it in `details.robot_id` (`action.invoked`, `service.called`, …), so a robot's events include what was started on it.",
|
|
903
|
+
"type": "string",
|
|
904
|
+
"minLength": 1,
|
|
905
|
+
"maxLength": 200
|
|
906
|
+
}
|
|
907
|
+
},
|
|
886
908
|
{
|
|
887
909
|
"name": "from_ms",
|
|
888
910
|
"in": "query",
|
|
@@ -1265,7 +1287,7 @@
|
|
|
1265
1287
|
}
|
|
1266
1288
|
}
|
|
1267
1289
|
},
|
|
1268
|
-
"description": "The body is `{ \"name\": string }` — non-empty, trimmed, at most
|
|
1290
|
+
"description": "The body is `{ \"name\": string }` — non-empty, trimmed, at most 60 characters as on `role.name` — and is deliberately not a contract shape: contracts define the `role` this answers with, not this one trivial request. **The answer is a bare `role`, not an envelope**, unlike the listing beside it."
|
|
1269
1291
|
},
|
|
1270
1292
|
"get": {
|
|
1271
1293
|
"operationId": "get_api_apps_id_roles",
|
|
@@ -1492,6 +1514,132 @@
|
|
|
1492
1514
|
"description": "Built by the same builder the MCP server's own `robot_describe` uses, so the two cannot drift. It answers what the role *would* be offered and consults nothing about any user's actual MCP entitlement. A robot the role grants nothing on still appears, with an empty `exposures` — dropping it would read as \"not attached\", which is a different fact."
|
|
1493
1515
|
}
|
|
1494
1516
|
},
|
|
1517
|
+
"/api/apps/{id}/roles/{roleId}": {
|
|
1518
|
+
"patch": {
|
|
1519
|
+
"operationId": "patch_api_apps_id_roles_roleId",
|
|
1520
|
+
"summary": "Renames a role; its users keep it.",
|
|
1521
|
+
"tags": [
|
|
1522
|
+
"apps"
|
|
1523
|
+
],
|
|
1524
|
+
"security": [
|
|
1525
|
+
{
|
|
1526
|
+
"developerSession": []
|
|
1527
|
+
}
|
|
1528
|
+
],
|
|
1529
|
+
"parameters": [
|
|
1530
|
+
{
|
|
1531
|
+
"name": "id",
|
|
1532
|
+
"in": "path",
|
|
1533
|
+
"required": true,
|
|
1534
|
+
"description": "The app's uuid, as returned by `POST /api/apps` or listed by `GET /api/apps`.",
|
|
1535
|
+
"schema": {
|
|
1536
|
+
"type": "string"
|
|
1537
|
+
}
|
|
1538
|
+
},
|
|
1539
|
+
{
|
|
1540
|
+
"name": "roleId",
|
|
1541
|
+
"in": "path",
|
|
1542
|
+
"required": true,
|
|
1543
|
+
"description": "The role's uuid, from `GET /api/apps/:id/roles`; a role of another app answers `404`.",
|
|
1544
|
+
"schema": {
|
|
1545
|
+
"type": "string"
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
],
|
|
1549
|
+
"responses": {
|
|
1550
|
+
"200": {
|
|
1551
|
+
"description": "Success.",
|
|
1552
|
+
"content": {
|
|
1553
|
+
"application/json": {
|
|
1554
|
+
"schema": {
|
|
1555
|
+
"$ref": "#/components/schemas/role"
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
},
|
|
1560
|
+
"default": {
|
|
1561
|
+
"description": "An error envelope. Codes this route is known to answer: `unauthorized`, `token_expired`, `token_revoked`, `invalid_uuid`, `not_found`, `validation_error`, `role_name_taken`.",
|
|
1562
|
+
"content": {
|
|
1563
|
+
"application/json": {
|
|
1564
|
+
"schema": {
|
|
1565
|
+
"$ref": "#/components/schemas/api-error"
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1570
|
+
},
|
|
1571
|
+
"description": "Names are unique per app, compared exactly as stored after trimming. Built-in roles can be renamed.",
|
|
1572
|
+
"requestBody": {
|
|
1573
|
+
"required": true,
|
|
1574
|
+
"content": {
|
|
1575
|
+
"application/json": {
|
|
1576
|
+
"schema": {
|
|
1577
|
+
"$ref": "#/components/schemas/role-rename-request"
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
},
|
|
1583
|
+
"delete": {
|
|
1584
|
+
"operationId": "delete_api_apps_id_roles_roleId",
|
|
1585
|
+
"summary": "Deletes a role, moving its users, pending invitations and default-role status to another role.",
|
|
1586
|
+
"tags": [
|
|
1587
|
+
"apps"
|
|
1588
|
+
],
|
|
1589
|
+
"security": [
|
|
1590
|
+
{
|
|
1591
|
+
"developerSession": []
|
|
1592
|
+
}
|
|
1593
|
+
],
|
|
1594
|
+
"parameters": [
|
|
1595
|
+
{
|
|
1596
|
+
"name": "id",
|
|
1597
|
+
"in": "path",
|
|
1598
|
+
"required": true,
|
|
1599
|
+
"description": "The app's uuid, as returned by `POST /api/apps` or listed by `GET /api/apps`.",
|
|
1600
|
+
"schema": {
|
|
1601
|
+
"type": "string"
|
|
1602
|
+
}
|
|
1603
|
+
},
|
|
1604
|
+
{
|
|
1605
|
+
"name": "roleId",
|
|
1606
|
+
"in": "path",
|
|
1607
|
+
"required": true,
|
|
1608
|
+
"description": "The role's uuid, from `GET /api/apps/:id/roles`; a role of another app answers `404`.",
|
|
1609
|
+
"schema": {
|
|
1610
|
+
"type": "string"
|
|
1611
|
+
}
|
|
1612
|
+
},
|
|
1613
|
+
{
|
|
1614
|
+
"name": "move_to",
|
|
1615
|
+
"in": "query",
|
|
1616
|
+
"required": false,
|
|
1617
|
+
"schema": {
|
|
1618
|
+
"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`.",
|
|
1619
|
+
"type": "string",
|
|
1620
|
+
"format": "uuid",
|
|
1621
|
+
"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)$"
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
],
|
|
1625
|
+
"responses": {
|
|
1626
|
+
"204": {
|
|
1627
|
+
"description": "Success."
|
|
1628
|
+
},
|
|
1629
|
+
"default": {
|
|
1630
|
+
"description": "An error envelope. Codes this route is known to answer: `unauthorized`, `token_expired`, `token_revoked`, `invalid_uuid`, `not_found`, `validation_error`, `role_in_use`, `last_role`.",
|
|
1631
|
+
"content": {
|
|
1632
|
+
"application/json": {
|
|
1633
|
+
"schema": {
|
|
1634
|
+
"$ref": "#/components/schemas/api-error"
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
},
|
|
1640
|
+
"description": "Without `move_to`, a role that app users or pending invitations hold, or that is the app's default, answers `409 role_in_use` with `{ users, invitations, is_default }`. With `move_to` — another role of the same app, else `400 validation_error` — one transaction moves `app_users.role_id`, pending invitations and `default_role_id`, then deletes the role and its permissions. The app's only role answers `409 last_role`. Built-in roles can be deleted like any other."
|
|
1641
|
+
}
|
|
1642
|
+
},
|
|
1495
1643
|
"/api/apps/{id}/server-keys": {
|
|
1496
1644
|
"post": {
|
|
1497
1645
|
"operationId": "post_api_apps_id_server_keys",
|
|
@@ -9254,6 +9402,54 @@
|
|
|
9254
9402
|
},
|
|
9255
9403
|
"description": "A window longer than `USAGE_WINDOW_MAX_DAYS` is refused naming the field, not silently capped: a caller who asked for more than the platform will answer is owed a refusal, not a shorter answer they will mistake for the whole picture. `from_day <= to_day` is a cross-field rule no JSON Schema can express and is enforced here. The window is echoed back."
|
|
9256
9404
|
}
|
|
9405
|
+
},
|
|
9406
|
+
"/api/feedback": {
|
|
9407
|
+
"post": {
|
|
9408
|
+
"operationId": "post_api_feedback",
|
|
9409
|
+
"summary": "Sends a message from a developer to the people who build Fleetless.",
|
|
9410
|
+
"tags": [
|
|
9411
|
+
"org"
|
|
9412
|
+
],
|
|
9413
|
+
"security": [
|
|
9414
|
+
{
|
|
9415
|
+
"developerSession": []
|
|
9416
|
+
}
|
|
9417
|
+
],
|
|
9418
|
+
"parameters": [],
|
|
9419
|
+
"responses": {
|
|
9420
|
+
"202": {
|
|
9421
|
+
"description": "Success.",
|
|
9422
|
+
"content": {
|
|
9423
|
+
"application/json": {
|
|
9424
|
+
"schema": {
|
|
9425
|
+
"$ref": "#/components/schemas/feedback-response"
|
|
9426
|
+
}
|
|
9427
|
+
}
|
|
9428
|
+
}
|
|
9429
|
+
},
|
|
9430
|
+
"default": {
|
|
9431
|
+
"description": "An error envelope. Codes this route is known to answer: `unauthorized`, `token_expired`, `token_revoked`, `validation_error`, `rate_limited`.",
|
|
9432
|
+
"content": {
|
|
9433
|
+
"application/json": {
|
|
9434
|
+
"schema": {
|
|
9435
|
+
"$ref": "#/components/schemas/api-error"
|
|
9436
|
+
}
|
|
9437
|
+
}
|
|
9438
|
+
}
|
|
9439
|
+
}
|
|
9440
|
+
},
|
|
9441
|
+
"description": "The message is stored before any mail is tried, so `202` means it is kept whatever `mail` says: `sent`, `failed`, or `not_configured` when this cloud has no feedback address. At most 10 messages per developer per hour; the 11th answers `429 rate_limited` with `retry_after_ms`. Replies come by mail, to the sender's address.",
|
|
9442
|
+
"requestBody": {
|
|
9443
|
+
"required": true,
|
|
9444
|
+
"content": {
|
|
9445
|
+
"application/json": {
|
|
9446
|
+
"schema": {
|
|
9447
|
+
"$ref": "#/components/schemas/feedback-request"
|
|
9448
|
+
}
|
|
9449
|
+
}
|
|
9450
|
+
}
|
|
9451
|
+
}
|
|
9452
|
+
}
|
|
9257
9453
|
}
|
|
9258
9454
|
},
|
|
9259
9455
|
"components": {
|
|
@@ -15504,6 +15700,65 @@
|
|
|
15504
15700
|
],
|
|
15505
15701
|
"additionalProperties": false
|
|
15506
15702
|
},
|
|
15703
|
+
"feedback-request": {
|
|
15704
|
+
"type": "object",
|
|
15705
|
+
"properties": {
|
|
15706
|
+
"kind": {
|
|
15707
|
+
"type": "string",
|
|
15708
|
+
"enum": [
|
|
15709
|
+
"idea",
|
|
15710
|
+
"problem",
|
|
15711
|
+
"question",
|
|
15712
|
+
"other"
|
|
15713
|
+
],
|
|
15714
|
+
"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."
|
|
15715
|
+
},
|
|
15716
|
+
"message": {
|
|
15717
|
+
"type": "string",
|
|
15718
|
+
"minLength": 1,
|
|
15719
|
+
"maxLength": 5000,
|
|
15720
|
+
"description": "What the developer wrote, trimmed. At most 5000 characters; a message that is only whitespace is refused."
|
|
15721
|
+
},
|
|
15722
|
+
"page": {
|
|
15723
|
+
"type": "string",
|
|
15724
|
+
"maxLength": 512,
|
|
15725
|
+
"pattern": "^\\/.*",
|
|
15726
|
+
"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."
|
|
15727
|
+
}
|
|
15728
|
+
},
|
|
15729
|
+
"required": [
|
|
15730
|
+
"kind",
|
|
15731
|
+
"message",
|
|
15732
|
+
"page"
|
|
15733
|
+
],
|
|
15734
|
+
"additionalProperties": false
|
|
15735
|
+
},
|
|
15736
|
+
"feedback-response": {
|
|
15737
|
+
"type": "object",
|
|
15738
|
+
"properties": {
|
|
15739
|
+
"id": {
|
|
15740
|
+
"type": "string",
|
|
15741
|
+
"format": "uuid",
|
|
15742
|
+
"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)$",
|
|
15743
|
+
"description": "The stored message. It exists whatever `mail` says."
|
|
15744
|
+
},
|
|
15745
|
+
"mail": {
|
|
15746
|
+
"type": "string",
|
|
15747
|
+
"enum": [
|
|
15748
|
+
"sent",
|
|
15749
|
+
"not_requested",
|
|
15750
|
+
"not_configured",
|
|
15751
|
+
"failed"
|
|
15752
|
+
],
|
|
15753
|
+
"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."
|
|
15754
|
+
}
|
|
15755
|
+
},
|
|
15756
|
+
"required": [
|
|
15757
|
+
"id",
|
|
15758
|
+
"mail"
|
|
15759
|
+
],
|
|
15760
|
+
"additionalProperties": false
|
|
15761
|
+
},
|
|
15507
15762
|
"fetch-types-request": {
|
|
15508
15763
|
"type": "object",
|
|
15509
15764
|
"properties": {
|
|
@@ -16570,12 +16825,26 @@
|
|
|
16570
16825
|
"minLength": 1,
|
|
16571
16826
|
"maxLength": 200,
|
|
16572
16827
|
"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."
|
|
16828
|
+
},
|
|
16829
|
+
"name": {
|
|
16830
|
+
"anyOf": [
|
|
16831
|
+
{
|
|
16832
|
+
"type": "string",
|
|
16833
|
+
"minLength": 1,
|
|
16834
|
+
"maxLength": 200
|
|
16835
|
+
},
|
|
16836
|
+
{
|
|
16837
|
+
"type": "null"
|
|
16838
|
+
}
|
|
16839
|
+
],
|
|
16840
|
+
"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."
|
|
16573
16841
|
}
|
|
16574
16842
|
},
|
|
16575
16843
|
"required": [
|
|
16576
16844
|
"kind",
|
|
16577
16845
|
"id",
|
|
16578
|
-
"label"
|
|
16846
|
+
"label",
|
|
16847
|
+
"name"
|
|
16579
16848
|
],
|
|
16580
16849
|
"additionalProperties": false,
|
|
16581
16850
|
"description": "Who invoked the run, and what they were acting as at the time."
|
|
@@ -19264,7 +19533,7 @@
|
|
|
19264
19533
|
},
|
|
19265
19534
|
"builtin": {
|
|
19266
19535
|
"type": "boolean",
|
|
19267
|
-
"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.
|
|
19536
|
+
"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."
|
|
19268
19537
|
}
|
|
19269
19538
|
},
|
|
19270
19539
|
"required": [
|
|
@@ -19303,7 +19572,7 @@
|
|
|
19303
19572
|
},
|
|
19304
19573
|
"builtin": {
|
|
19305
19574
|
"type": "boolean",
|
|
19306
|
-
"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.
|
|
19575
|
+
"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."
|
|
19307
19576
|
}
|
|
19308
19577
|
},
|
|
19309
19578
|
"required": [
|
|
@@ -19382,6 +19651,21 @@
|
|
|
19382
19651
|
"capabilities"
|
|
19383
19652
|
]
|
|
19384
19653
|
},
|
|
19654
|
+
"role-rename-request": {
|
|
19655
|
+
"type": "object",
|
|
19656
|
+
"properties": {
|
|
19657
|
+
"name": {
|
|
19658
|
+
"type": "string",
|
|
19659
|
+
"minLength": 1,
|
|
19660
|
+
"maxLength": 60,
|
|
19661
|
+
"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."
|
|
19662
|
+
}
|
|
19663
|
+
},
|
|
19664
|
+
"required": [
|
|
19665
|
+
"name"
|
|
19666
|
+
],
|
|
19667
|
+
"additionalProperties": false
|
|
19668
|
+
},
|
|
19385
19669
|
"server-key-list-response": {
|
|
19386
19670
|
"type": "object",
|
|
19387
19671
|
"properties": {
|
package/artifacts/routes.json
CHANGED
|
@@ -664,7 +664,7 @@
|
|
|
664
664
|
"validation_error"
|
|
665
665
|
],
|
|
666
666
|
"transport": "http",
|
|
667
|
-
"notes": "The body is `{ \"name\": string }` — non-empty, trimmed, at most
|
|
667
|
+
"notes": "The body is `{ \"name\": string }` — non-empty, trimmed, at most 60 characters as on `role.name` — and is deliberately not a contract shape: contracts define the `role` this answers with, not this one trivial request. **The answer is a bare `role`, not an envelope**, unlike the listing beside it."
|
|
668
668
|
},
|
|
669
669
|
{
|
|
670
670
|
"method": "GET",
|
|
@@ -794,6 +794,77 @@
|
|
|
794
794
|
"transport": "http",
|
|
795
795
|
"notes": "Built by the same builder the MCP server's own `robot_describe` uses, so the two cannot drift. It answers what the role *would* be offered and consults nothing about any user's actual MCP entitlement. A robot the role grants nothing on still appears, with an empty `exposures` — dropping it would read as \"not attached\", which is a different fact."
|
|
796
796
|
},
|
|
797
|
+
{
|
|
798
|
+
"method": "PATCH",
|
|
799
|
+
"path": "/api/apps/:id/roles/:roleId",
|
|
800
|
+
"section": "apps",
|
|
801
|
+
"summary": "Renames a role; its users keep it.",
|
|
802
|
+
"audience": "developer",
|
|
803
|
+
"auth": "developer",
|
|
804
|
+
"rateLimited": false,
|
|
805
|
+
"ownerTier": false,
|
|
806
|
+
"status": 200,
|
|
807
|
+
"params": [
|
|
808
|
+
{
|
|
809
|
+
"name": "id",
|
|
810
|
+
"description": "The app's uuid, as returned by `POST /api/apps` or listed by `GET /api/apps`."
|
|
811
|
+
},
|
|
812
|
+
{
|
|
813
|
+
"name": "roleId",
|
|
814
|
+
"description": "The role's uuid, from `GET /api/apps/:id/roles`; a role of another app answers `404`."
|
|
815
|
+
}
|
|
816
|
+
],
|
|
817
|
+
"query": null,
|
|
818
|
+
"request": "role-rename-request",
|
|
819
|
+
"response": "role",
|
|
820
|
+
"errors": [
|
|
821
|
+
"unauthorized",
|
|
822
|
+
"token_expired",
|
|
823
|
+
"token_revoked",
|
|
824
|
+
"invalid_uuid",
|
|
825
|
+
"not_found",
|
|
826
|
+
"validation_error",
|
|
827
|
+
"role_name_taken"
|
|
828
|
+
],
|
|
829
|
+
"transport": "http",
|
|
830
|
+
"notes": "Names are unique per app, compared exactly as stored after trimming. Built-in roles can be renamed."
|
|
831
|
+
},
|
|
832
|
+
{
|
|
833
|
+
"method": "DELETE",
|
|
834
|
+
"path": "/api/apps/:id/roles/:roleId",
|
|
835
|
+
"section": "apps",
|
|
836
|
+
"summary": "Deletes a role, moving its users, pending invitations and default-role status to another role.",
|
|
837
|
+
"audience": "developer",
|
|
838
|
+
"auth": "developer",
|
|
839
|
+
"rateLimited": false,
|
|
840
|
+
"ownerTier": false,
|
|
841
|
+
"status": 204,
|
|
842
|
+
"params": [
|
|
843
|
+
{
|
|
844
|
+
"name": "id",
|
|
845
|
+
"description": "The app's uuid, as returned by `POST /api/apps` or listed by `GET /api/apps`."
|
|
846
|
+
},
|
|
847
|
+
{
|
|
848
|
+
"name": "roleId",
|
|
849
|
+
"description": "The role's uuid, from `GET /api/apps/:id/roles`; a role of another app answers `404`."
|
|
850
|
+
}
|
|
851
|
+
],
|
|
852
|
+
"query": "role-delete-query",
|
|
853
|
+
"request": null,
|
|
854
|
+
"response": null,
|
|
855
|
+
"errors": [
|
|
856
|
+
"unauthorized",
|
|
857
|
+
"token_expired",
|
|
858
|
+
"token_revoked",
|
|
859
|
+
"invalid_uuid",
|
|
860
|
+
"not_found",
|
|
861
|
+
"validation_error",
|
|
862
|
+
"role_in_use",
|
|
863
|
+
"last_role"
|
|
864
|
+
],
|
|
865
|
+
"transport": "http",
|
|
866
|
+
"notes": "Without `move_to`, a role that app users or pending invitations hold, or that is the app's default, answers `409 role_in_use` with `{ users, invitations, is_default }`. With `move_to` — another role of the same app, else `400 validation_error` — one transaction moves `app_users.role_id`, pending invitations and `default_role_id`, then deletes the role and its permissions. The app's only role answers `409 last_role`. Built-in roles can be deleted like any other."
|
|
867
|
+
},
|
|
797
868
|
{
|
|
798
869
|
"method": "POST",
|
|
799
870
|
"path": "/api/apps/:id/server-keys",
|
|
@@ -6273,6 +6344,30 @@
|
|
|
6273
6344
|
"transport": "http",
|
|
6274
6345
|
"notes": "A window longer than `USAGE_WINDOW_MAX_DAYS` is refused naming the field, not silently capped: a caller who asked for more than the platform will answer is owed a refusal, not a shorter answer they will mistake for the whole picture. `from_day <= to_day` is a cross-field rule no JSON Schema can express and is enforced here. The window is echoed back."
|
|
6275
6346
|
},
|
|
6347
|
+
{
|
|
6348
|
+
"method": "POST",
|
|
6349
|
+
"path": "/api/feedback",
|
|
6350
|
+
"section": "org",
|
|
6351
|
+
"summary": "Sends a message from a developer to the people who build Fleetless.",
|
|
6352
|
+
"audience": "developer",
|
|
6353
|
+
"auth": "developer",
|
|
6354
|
+
"rateLimited": true,
|
|
6355
|
+
"ownerTier": false,
|
|
6356
|
+
"status": 202,
|
|
6357
|
+
"params": [],
|
|
6358
|
+
"query": null,
|
|
6359
|
+
"request": "feedback-request",
|
|
6360
|
+
"response": "feedback-response",
|
|
6361
|
+
"errors": [
|
|
6362
|
+
"unauthorized",
|
|
6363
|
+
"token_expired",
|
|
6364
|
+
"token_revoked",
|
|
6365
|
+
"validation_error",
|
|
6366
|
+
"rate_limited"
|
|
6367
|
+
],
|
|
6368
|
+
"transport": "http",
|
|
6369
|
+
"notes": "The message is stored before any mail is tried, so `202` means it is kept whatever `mail` says: `sent`, `failed`, or `not_configured` when this cloud has no feedback address. At most 10 messages per developer per hour; the 11th answers `429 rate_limited` with `retry_after_ms`. Replies come by mail, to the sender's address."
|
|
6370
|
+
},
|
|
6276
6371
|
{
|
|
6277
6372
|
"method": "POST",
|
|
6278
6373
|
"path": "/api/bridge/assets",
|
|
@@ -48,6 +48,12 @@
|
|
|
48
48
|
"minLength": 1,
|
|
49
49
|
"maxLength": 40
|
|
50
50
|
},
|
|
51
|
+
"target_id": {
|
|
52
|
+
"description": "Events whose target is this id; for a robot also the events that name it in `details.robot_id` (`action.invoked`, `service.called`, …), so a robot's events include what was started on it.",
|
|
53
|
+
"type": "string",
|
|
54
|
+
"minLength": 1,
|
|
55
|
+
"maxLength": 200
|
|
56
|
+
},
|
|
51
57
|
"from_ms": {
|
|
52
58
|
"anyOf": [
|
|
53
59
|
{
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"type": "object",
|
|
4
|
+
"properties": {
|
|
5
|
+
"kind": {
|
|
6
|
+
"type": "string",
|
|
7
|
+
"enum": [
|
|
8
|
+
"idea",
|
|
9
|
+
"problem",
|
|
10
|
+
"question",
|
|
11
|
+
"other"
|
|
12
|
+
],
|
|
13
|
+
"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."
|
|
14
|
+
},
|
|
15
|
+
"message": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"minLength": 1,
|
|
18
|
+
"maxLength": 5000,
|
|
19
|
+
"description": "What the developer wrote, trimmed. At most 5000 characters; a message that is only whitespace is refused."
|
|
20
|
+
},
|
|
21
|
+
"page": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"maxLength": 512,
|
|
24
|
+
"pattern": "^\\/.*",
|
|
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
|
+
},
|
|
28
|
+
"required": [
|
|
29
|
+
"kind",
|
|
30
|
+
"message",
|
|
31
|
+
"page"
|
|
32
|
+
],
|
|
33
|
+
"additionalProperties": false
|
|
34
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"type": "object",
|
|
4
|
+
"properties": {
|
|
5
|
+
"id": {
|
|
6
|
+
"type": "string",
|
|
7
|
+
"format": "uuid",
|
|
8
|
+
"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)$",
|
|
9
|
+
"description": "The stored message. It exists whatever `mail` says."
|
|
10
|
+
},
|
|
11
|
+
"mail": {
|
|
12
|
+
"type": "string",
|
|
13
|
+
"enum": [
|
|
14
|
+
"sent",
|
|
15
|
+
"not_requested",
|
|
16
|
+
"not_configured",
|
|
17
|
+
"failed"
|
|
18
|
+
],
|
|
19
|
+
"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."
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"required": [
|
|
23
|
+
"id",
|
|
24
|
+
"mail"
|
|
25
|
+
],
|
|
26
|
+
"additionalProperties": false
|
|
27
|
+
}
|
|
@@ -23,12 +23,26 @@
|
|
|
23
23
|
"minLength": 1,
|
|
24
24
|
"maxLength": 200,
|
|
25
25
|
"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."
|
|
26
|
+
},
|
|
27
|
+
"name": {
|
|
28
|
+
"anyOf": [
|
|
29
|
+
{
|
|
30
|
+
"type": "string",
|
|
31
|
+
"minLength": 1,
|
|
32
|
+
"maxLength": 200
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"type": "null"
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
"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."
|
|
26
39
|
}
|
|
27
40
|
},
|
|
28
41
|
"required": [
|
|
29
42
|
"kind",
|
|
30
43
|
"id",
|
|
31
|
-
"label"
|
|
44
|
+
"label",
|
|
45
|
+
"name"
|
|
32
46
|
],
|
|
33
47
|
"additionalProperties": false
|
|
34
48
|
}
|
|
@@ -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.
|
|
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.
|
|
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
|
|
155
|
-
* the flag only tells the console where they came
|
|
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
|
|
210
|
-
* the flag only tells the console where they came
|
|
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.
|
|
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
|
|
@@ -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>;
|
package/dist/feedback.js
ADDED
|
@@ -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, 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 {
|
|
35
|
-
export type {
|
|
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
|
-
|
|
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.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
import { appListResponse, appDeletionSummary, createAppRequest, createServerKeyResponse, app as appSchema, role, roleListResponse, rolePermissions, serverKeyListResponse, updateAppRequest, } from './apps.js';
|
|
2
|
+
import { appListResponse, appDeletionSummary, createAppRequest, createServerKeyResponse, app as appSchema, role, roleListResponse, roleDeleteQuery, rolePermissions, roleRenameRequest, serverKeyListResponse, updateAppRequest, } from './apps.js';
|
|
3
3
|
import { alertListResponse, orgAlertsQuery, orgFiringAlertsResponse } from './alerts.js';
|
|
4
4
|
import { asset, assetListResponse, assetsClearResponse, assetSyncRequest, assetSyncResponse, assetSyncStatus, missingAssetQuery } from './assets.js';
|
|
5
5
|
import { auditListResponse, auditQuery } from './audit.js';
|
|
6
|
+
import { feedbackRequest, feedbackResponse } from './feedback.js';
|
|
6
7
|
import { CLIENT_OIDC_CALLBACK_PATH, clientAcceptInvitationRequest, clientIdentity, clientLoginCodeRequest, clientLoginCodeVerifyRequest, clientLoginRequest, clientLogoutRequest, clientMcpInteraction, clientMcpInteractionDecisionResponse, clientOidcCallbackQuery, clientOidcExchangeRequest, clientOidcStartQuery, clientPasswordResetConfirmRequest, clientPasswordResetRequest, clientProviderListQuery, clientProviderListResponse, clientRefreshRequest, clientRegisterRequest, clientResendVerificationRequest, clientSignInResult, clientTwoFactorDisableRequest, clientTwoFactorSetupConfirmRequest, clientTwoFactorSetupConfirmResponse, clientTwoFactorSetupRequest, clientTwoFactorVerifyRequest, clientVerifyEmailRequest, mcpConsentGrantListResponse, } from './client-auth.js';
|
|
7
8
|
import { clientRobotListResponse } from './client-robots.js';
|
|
8
9
|
import { appAuthConfig, appInvitation, appInvitationListResponse, appMailTemplate, appMailTemplateListResponse, appOidcProvider, appOidcProviderListResponse, appUser, appUserListResponse, createAppInvitationRequest, createAppOidcProviderRequest, createAppUserRequest, mailOutcome, mailTemplatePreviewRequest, mailTemplatePreviewResponse, patchAppOidcProviderRequest, patchAppUserRequest, putAppAuthLookRequest, putAppAuthMcpRequest, putAppAuthRegistrationRequest, putAppAuthSignInRequest, putAppAuthUrlsRequest, putAppMailTemplateRequest, } from './app-users.js';
|
|
@@ -525,7 +526,7 @@ export const ROUTES = [
|
|
|
525
526
|
params: [{ name: 'id', description: 'The app\'s uuid, as returned by `POST /api/apps` or listed by `GET /api/apps`.' }],
|
|
526
527
|
query: null, request: null, response: role,
|
|
527
528
|
errors: [...DEVELOPER_GUARD, 'invalid_uuid', 'not_found', 'validation_error'], transport: 'http',
|
|
528
|
-
notes: 'The body is `{ "name": string }` — non-empty, trimmed, at most
|
|
529
|
+
notes: 'The body is `{ "name": string }` — non-empty, trimmed, at most 60 characters as on `role.name` — and is deliberately not a contract shape: contracts ' +
|
|
529
530
|
'define the `role` this answers with, not this one trivial request. **The answer is a bare `role`, not an envelope**, unlike the ' +
|
|
530
531
|
'listing beside it.',
|
|
531
532
|
},
|
|
@@ -578,6 +579,33 @@ export const ROUTES = [
|
|
|
578
579
|
'offered and consults nothing about any user\'s actual MCP entitlement. A robot the role grants nothing on still appears, with an empty ' +
|
|
579
580
|
'`exposures` — dropping it would read as "not attached", which is a different fact.',
|
|
580
581
|
},
|
|
582
|
+
{
|
|
583
|
+
method: 'PATCH', path: '/api/apps/:id/roles/:roleId', section: 'apps',
|
|
584
|
+
summary: 'Renames a role; its users keep it.',
|
|
585
|
+
audience: 'developer', auth: 'developer', rateLimited: false, ownerTier: false, status: 200,
|
|
586
|
+
params: [
|
|
587
|
+
{ name: 'id', description: 'The app\'s uuid, as returned by `POST /api/apps` or listed by `GET /api/apps`.' },
|
|
588
|
+
{ name: 'roleId', description: 'The role\'s uuid, from `GET /api/apps/:id/roles`; a role of another app answers `404`.' },
|
|
589
|
+
],
|
|
590
|
+
query: null, request: roleRenameRequest, response: role,
|
|
591
|
+
errors: [...DEVELOPER_GUARD, 'invalid_uuid', 'not_found', 'validation_error', 'role_name_taken'], transport: 'http',
|
|
592
|
+
notes: 'Names are unique per app, compared exactly as stored after trimming. Built-in roles can be renamed.',
|
|
593
|
+
},
|
|
594
|
+
{
|
|
595
|
+
method: 'DELETE', path: '/api/apps/:id/roles/:roleId', section: 'apps',
|
|
596
|
+
summary: 'Deletes a role, moving its users, pending invitations and default-role status to another role.',
|
|
597
|
+
audience: 'developer', auth: 'developer', rateLimited: false, ownerTier: false, status: 204,
|
|
598
|
+
params: [
|
|
599
|
+
{ name: 'id', description: 'The app\'s uuid, as returned by `POST /api/apps` or listed by `GET /api/apps`.' },
|
|
600
|
+
{ name: 'roleId', description: 'The role\'s uuid, from `GET /api/apps/:id/roles`; a role of another app answers `404`.' },
|
|
601
|
+
],
|
|
602
|
+
query: roleDeleteQuery, request: null, response: null,
|
|
603
|
+
errors: [...DEVELOPER_GUARD, 'invalid_uuid', 'not_found', 'validation_error', 'role_in_use', 'last_role'], transport: 'http',
|
|
604
|
+
notes: 'Without `move_to`, a role that app users or pending invitations hold, or that is the app\'s default, answers ' +
|
|
605
|
+
'`409 role_in_use` with `{ users, invitations, is_default }`. With `move_to` — another role of the same app, else ' +
|
|
606
|
+
'`400 validation_error` — one transaction moves `app_users.role_id`, pending invitations and `default_role_id`, then deletes ' +
|
|
607
|
+
'the role and its permissions. The app\'s only role answers `409 last_role`. Built-in roles can be deleted like any other.',
|
|
608
|
+
},
|
|
581
609
|
{
|
|
582
610
|
method: 'POST', path: '/api/apps/:id/server-keys', section: 'apps',
|
|
583
611
|
summary: 'Mints a server key for the app and returns the raw secret once.',
|
|
@@ -2749,6 +2777,16 @@ export const ROUTES = [
|
|
|
2749
2777
|
'platform will answer is owed a refusal, not a shorter answer they will mistake for the whole picture. `from_day <= to_day` is a ' +
|
|
2750
2778
|
'cross-field rule no JSON Schema can express and is enforced here. The window is echoed back.',
|
|
2751
2779
|
},
|
|
2780
|
+
{
|
|
2781
|
+
method: 'POST', path: '/api/feedback', section: 'org',
|
|
2782
|
+
summary: 'Sends a message from a developer to the people who build Fleetless.',
|
|
2783
|
+
audience: 'developer', auth: 'developer', rateLimited: true, ownerTier: false, status: 202,
|
|
2784
|
+
params: [], query: null, request: feedbackRequest, response: feedbackResponse,
|
|
2785
|
+
errors: [...DEVELOPER_GUARD, 'validation_error', 'rate_limited'], transport: 'http',
|
|
2786
|
+
notes: 'The message is stored before any mail is tried, so `202` means it is kept whatever `mail` says: `sent`, `failed`, or ' +
|
|
2787
|
+
'`not_configured` when this cloud has no feedback address. At most 10 messages per developer per hour; the 11th answers ' +
|
|
2788
|
+
'`429 rate_limited` with `retry_after_ms`. Replies come by mail, to the sender\'s address.',
|
|
2789
|
+
},
|
|
2752
2790
|
/* ------------------------------------------------- assets (robot upload) */
|
|
2753
2791
|
{
|
|
2754
2792
|
method: 'POST', path: '/api/bridge/assets', section: 'assets',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fleetless/contracts",
|
|
3
|
-
"version": "6.0.0
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"description": "Fleetless wire contracts: the bridge-cloud protocol, the REST API schemas and the error codes, as zod schemas with generated JSON Schema and OpenAPI artifacts.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Dehne Robotik GmbH",
|