@fleetless/contracts 1.0.5 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/CHANGELOG.md +11 -2
  2. package/CONTRIBUTING.md +100 -75
  3. package/README.md +69 -83
  4. package/SECURITY.md +24 -24
  5. package/artifacts/openapi.json +65 -65
  6. package/artifacts/routes.json +3 -3
  7. package/artifacts/schema/app-list-response.schema.json +2 -2
  8. package/artifacts/schema/app-oidc-provider-list-response.schema.json +1 -1
  9. package/artifacts/schema/app-oidc-provider.schema.json +1 -1
  10. package/artifacts/schema/app-user-list-response.schema.json +2 -2
  11. package/artifacts/schema/app-user.schema.json +2 -2
  12. package/artifacts/schema/app.schema.json +2 -2
  13. package/artifacts/schema/asset-list-response.schema.json +7 -7
  14. package/artifacts/schema/asset-sync-request.schema.json +1 -1
  15. package/artifacts/schema/asset-sync-status.schema.json +1 -1
  16. package/artifacts/schema/asset.schema.json +3 -3
  17. package/artifacts/schema/auth-me-response.schema.json +2 -2
  18. package/artifacts/schema/auth-ok.schema.json +1 -1
  19. package/artifacts/schema/authorization-server-metadata.schema.json +1 -1
  20. package/artifacts/schema/bridge-asset-progress.schema.json +1 -1
  21. package/artifacts/schema/busy-details.schema.json +3 -3
  22. package/artifacts/schema/client-identity.schema.json +1 -1
  23. package/artifacts/schema/client-login-request.schema.json +1 -1
  24. package/artifacts/schema/client-logout-request.schema.json +1 -1
  25. package/artifacts/schema/client-mcp-interaction.schema.json +1 -1
  26. package/artifacts/schema/cloud-config.schema.json +1 -1
  27. package/artifacts/schema/command-result.schema.json +3 -3
  28. package/artifacts/schema/config-draft-response.schema.json +1 -1
  29. package/artifacts/schema/config-version-response.schema.json +1 -1
  30. package/artifacts/schema/create-server-key-response.schema.json +1 -1
  31. package/artifacts/schema/datapoint-config.schema.json +1 -1
  32. package/artifacts/schema/datapoint-value.schema.json +2 -2
  33. package/artifacts/schema/dynamic-client-registration-request.schema.json +2 -2
  34. package/artifacts/schema/fleetless-user-list-response.schema.json +2 -2
  35. package/artifacts/schema/fleetless-user.schema.json +2 -2
  36. package/artifacts/schema/invoke-or-service-response.schema.json +4 -4
  37. package/artifacts/schema/invoke-response.schema.json +3 -3
  38. package/artifacts/schema/job-actor.schema.json +1 -1
  39. package/artifacts/schema/job-event.schema.json +3 -3
  40. package/artifacts/schema/job-response.schema.json +3 -3
  41. package/artifacts/schema/job-run-list-response.schema.json +2 -2
  42. package/artifacts/schema/job-run.schema.json +2 -2
  43. package/artifacts/schema/job.schema.json +3 -3
  44. package/artifacts/schema/mcp-consent-grant-list-response.schema.json +2 -2
  45. package/artifacts/schema/mcp-consent-grant.schema.json +2 -2
  46. package/artifacts/schema/oauth-authorize-query.schema.json +1 -1
  47. package/artifacts/schema/oauth-token-request.schema.json +1 -1
  48. package/artifacts/schema/patch-org-response.schema.json +1 -1
  49. package/artifacts/schema/patch-robot-response.schema.json +1 -1
  50. package/artifacts/schema/robot-config-doc.schema.json +1 -1
  51. package/artifacts/schema/robot-jobs-response.schema.json +3 -3
  52. package/artifacts/schema/role-list-response.schema.json +1 -1
  53. package/artifacts/schema/role.schema.json +1 -1
  54. package/artifacts/schema/server-key-list-response.schema.json +2 -2
  55. package/artifacts/schema/server-key.schema.json +1 -1
  56. package/artifacts/schema/service-call-response.schema.json +1 -1
  57. package/artifacts/schema/sign-up-response.schema.json +2 -2
  58. package/artifacts/schema/urdf-completeness.schema.json +2 -2
  59. package/artifacts/schema-outgoing/bridge-asset-progress.schema.json +1 -1
  60. package/dist/alerts.d.ts +15 -17
  61. package/dist/alerts.js +15 -17
  62. package/dist/app-users.d.ts +5 -6
  63. package/dist/app-users.js +9 -10
  64. package/dist/apps.d.ts +5 -6
  65. package/dist/apps.js +11 -12
  66. package/dist/assets.js +10 -13
  67. package/dist/audit.d.ts +10 -12
  68. package/dist/audit.js +14 -17
  69. package/dist/client-auth.d.ts +8 -9
  70. package/dist/client-auth.js +14 -15
  71. package/dist/config-issues.d.ts +3 -3
  72. package/dist/config-issues.js +3 -3
  73. package/dist/config.d.ts +5 -6
  74. package/dist/config.js +7 -8
  75. package/dist/errors.d.ts +4 -4
  76. package/dist/errors.js +8 -9
  77. package/dist/identity.d.ts +4 -5
  78. package/dist/identity.js +7 -8
  79. package/dist/index.d.ts +1 -1
  80. package/dist/index.js +1 -1
  81. package/dist/jobs.js +5 -5
  82. package/dist/mcp.d.ts +5 -8
  83. package/dist/mcp.js +2 -2
  84. package/dist/oauth.d.ts +8 -10
  85. package/dist/oauth.js +13 -15
  86. package/dist/protocol.d.ts +7 -8
  87. package/dist/protocol.js +20 -22
  88. package/dist/realtime.js +4 -4
  89. package/dist/rest.js +4 -4
  90. package/dist/routes.js +3 -3
  91. package/package.json +1 -1
@@ -11,7 +11,7 @@
11
11
  "type": "string",
12
12
  "format": "uuid",
13
13
  "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)$",
14
- "description": "The job's id, minted by the cloud when the invocation is accepted. Informative: state is observed by slug, and this id is what a cancel names when a caller wants to stop one specific job rather than whatever is running."
14
+ "description": "The job's id, minted by the cloud when the invocation is accepted. Informative — state is observed by slug; a cancel names this id to stop one specific job rather than whatever is running."
15
15
  },
16
16
  "robot_id": {
17
17
  "type": "string",
@@ -35,13 +35,13 @@
35
35
  "cancelled",
36
36
  "lost"
37
37
  ],
38
- "description": "Where the job stands: `running`, `succeeded`, `failed`, `cancelled` or `lost`. `lost` is a real outcome — the bridge restarted mid-job and the result is gone — and is said out loud rather than left reading `running` because nobody contradicted it."
38
+ "description": "Where the job stands: `running`, `succeeded`, `failed`, `cancelled` or `lost`. `lost` is a real outcome — the bridge restarted mid-job and the result is gone — stated rather than left reading `running` by default."
39
39
  },
40
40
  "started_at": {
41
41
  "type": "string",
42
42
  "format": "date-time",
43
43
  "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
44
- "description": "When the cloud minted this job, as an ISO 8601 timestamp. For a job adopted from a reconnecting bridge it is **adoption time**, not the real start, because the cloud never minted it and has no honest alternative."
44
+ "description": "When the cloud minted this job, as an ISO 8601 timestamp. For a job adopted from a reconnecting bridge, this is **adoption time**, not the real start — the cloud never minted it."
45
45
  },
46
46
  "updated_at": {
47
47
  "type": "string",
@@ -11,7 +11,7 @@
11
11
  "type": "string",
12
12
  "format": "uuid",
13
13
  "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)$",
14
- "description": "The run's id, which is the same id the invocation was answered with — so a caller that kept a job id can find its durable record here later."
14
+ "description": "The run's id — the same id the invocation was answered with, so a caller that kept a job id can find its durable record here later."
15
15
  },
16
16
  "robot_id": {
17
17
  "type": "string",
@@ -128,7 +128,7 @@
128
128
  "app_user",
129
129
  "server_key"
130
130
  ],
131
- "description": "What the caller was acting as: a `developer` in the console, an `app_user` of one app, or a `server_key` used by server-side code. A bridge invokes nothing, so it is deliberately not a case here. `end_user` appears only on runs recorded before app users replaced the organisation-wide user pool — it is kept so a history page can still render them, and nothing writes it any more."
131
+ "description": "What the caller was acting as: a `developer` in the console, an `app_user` of one app, or a `server_key` used by server-side code. A bridge invokes nothing, so it is deliberately not a case here. `end_user` appears only on runs recorded before app users replaced the organisation-wide user pool — kept so old runs still render; nothing writes it now."
132
132
  },
133
133
  "id": {
134
134
  "type": "string",
@@ -6,7 +6,7 @@
6
6
  "type": "string",
7
7
  "format": "uuid",
8
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 run's id, which is the same id the invocation was answered with — so a caller that kept a job id can find its durable record here later."
9
+ "description": "The run's id — the same id the invocation was answered with, so a caller that kept a job id can find its durable record here later."
10
10
  },
11
11
  "robot_id": {
12
12
  "type": "string",
@@ -123,7 +123,7 @@
123
123
  "app_user",
124
124
  "server_key"
125
125
  ],
126
- "description": "What the caller was acting as: a `developer` in the console, an `app_user` of one app, or a `server_key` used by server-side code. A bridge invokes nothing, so it is deliberately not a case here. `end_user` appears only on runs recorded before app users replaced the organisation-wide user pool — it is kept so a history page can still render them, and nothing writes it any more."
126
+ "description": "What the caller was acting as: a `developer` in the console, an `app_user` of one app, or a `server_key` used by server-side code. A bridge invokes nothing, so it is deliberately not a case here. `end_user` appears only on runs recorded before app users replaced the organisation-wide user pool — kept so old runs still render; nothing writes it now."
127
127
  },
128
128
  "id": {
129
129
  "type": "string",
@@ -6,7 +6,7 @@
6
6
  "type": "string",
7
7
  "format": "uuid",
8
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 job's id, minted by the cloud when the invocation is accepted. Informative: state is observed by slug, and this id is what a cancel names when a caller wants to stop one specific job rather than whatever is running."
9
+ "description": "The job's id, minted by the cloud when the invocation is accepted. Informative — state is observed by slug; a cancel names this id to stop one specific job rather than whatever is running."
10
10
  },
11
11
  "robot_id": {
12
12
  "type": "string",
@@ -30,13 +30,13 @@
30
30
  "cancelled",
31
31
  "lost"
32
32
  ],
33
- "description": "Where the job stands: `running`, `succeeded`, `failed`, `cancelled` or `lost`. `lost` is a real outcome — the bridge restarted mid-job and the result is gone — and is said out loud rather than left reading `running` because nobody contradicted it."
33
+ "description": "Where the job stands: `running`, `succeeded`, `failed`, `cancelled` or `lost`. `lost` is a real outcome — the bridge restarted mid-job and the result is gone — stated rather than left reading `running` by default."
34
34
  },
35
35
  "started_at": {
36
36
  "type": "string",
37
37
  "format": "date-time",
38
38
  "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
39
- "description": "When the cloud minted this job, as an ISO 8601 timestamp. For a job adopted from a reconnecting bridge it is **adoption time**, not the real start, because the cloud never minted it and has no honest alternative."
39
+ "description": "When the cloud minted this job, as an ISO 8601 timestamp. For a job adopted from a reconnecting bridge, this is **adoption time**, not the real start — the cloud never minted it."
40
40
  },
41
41
  "updated_at": {
42
42
  "type": "string",
@@ -20,12 +20,12 @@
20
20
  "type": "null"
21
21
  }
22
22
  ],
23
- "description": "What the client calls itself, or `null` when its registration is gone and there is no longer anything to have named. **Unverified** — see `client_name_verified`."
23
+ "description": "What the client calls itself, or `null` once its registration is gone. **Unverified** — see `client_name_verified`."
24
24
  },
25
25
  "client_name_verified": {
26
26
  "type": "boolean",
27
27
  "const": false,
28
- "description": "Always `false`. The client registered itself without authentication and chose this name about itself, so it must be rendered as a claim and never as an identity. There is no verified case, which is why this is a literal and not a boolean: a `true` branch would be dead code that looked like a safeguard."
28
+ "description": "Always `false`. The client registered itself without authentication and named itself, so it must be rendered as a claim and never as an identity. There is no verified case, which is why this is a literal and not a boolean: a `true` branch would be dead code that looked like a safeguard."
29
29
  },
30
30
  "granted_at": {
31
31
  "type": "string",
@@ -15,12 +15,12 @@
15
15
  "type": "null"
16
16
  }
17
17
  ],
18
- "description": "What the client calls itself, or `null` when its registration is gone and there is no longer anything to have named. **Unverified** — see `client_name_verified`."
18
+ "description": "What the client calls itself, or `null` once its registration is gone. **Unverified** — see `client_name_verified`."
19
19
  },
20
20
  "client_name_verified": {
21
21
  "type": "boolean",
22
22
  "const": false,
23
- "description": "Always `false`. The client registered itself without authentication and chose this name about itself, so it must be rendered as a claim and never as an identity. There is no verified case, which is why this is a literal and not a boolean: a `true` branch would be dead code that looked like a safeguard."
23
+ "description": "Always `false`. The client registered itself without authentication and named itself, so it must be rendered as a claim and never as an identity. There is no verified case, which is why this is a literal and not a boolean: a `true` branch would be dead code that looked like a safeguard."
24
24
  },
25
25
  "granted_at": {
26
26
  "type": "string",
@@ -20,7 +20,7 @@
20
20
  "code_challenge": {
21
21
  "type": "string",
22
22
  "minLength": 1,
23
- "description": "The PKCE challenge; the verifier is presented at the token endpoint. Only non-emptiness is checked here — length and alphabet are not — since the verifier is what actually has to match."
23
+ "description": "The PKCE challenge; the verifier is presented at the token endpoint. Only non-emptiness is checked here — length and alphabet are not — since the verifier is what has to match."
24
24
  },
25
25
  "code_challenge_method": {
26
26
  "type": "string",
@@ -31,7 +31,7 @@
31
31
  "description": "The PKCE verifier whose `S256` hash was sent as the challenge at the authorize step. Between `43` and `128` unreserved characters, per RFC 7636 §4.1 — it is compared rather than parsed, so a length nobody checks is a length an attacker chooses. PKCE is mandatory for every client under OAuth 2.1."
32
32
  },
33
33
  "resource": {
34
- "description": "The resource the token is being requested for, per RFC 8707. It must match the audience the code was authorized for, or the answer is `invalid_target`; omitted, the code's own audience stands. It becomes the token's `aud`, and a resource refuses a token whose audience names something else — which is what keeps a token minted for one app out of another app's endpoint.",
34
+ "description": "The resource the token is requested for, per RFC 8707. It must match the audience the code was authorized for, or the answer is `invalid_target`; omitted, the code's own audience stands. It becomes the token's `aud`, and a resource refuses a token whose audience names something else — which is what keeps a token minted for one app out of another app's endpoint.",
35
35
  "type": "string",
36
36
  "format": "uri"
37
37
  }
@@ -30,7 +30,7 @@
30
30
  "created_at"
31
31
  ],
32
32
  "additionalProperties": false,
33
- "description": "The organisation as it now stands, after the patch was applied. The whole resource comes back, not only the fields that changed."
33
+ "description": "The organisation as it now stands, after the patch. The whole resource comes back, not only the changed fields."
34
34
  }
35
35
  },
36
36
  "required": [
@@ -30,7 +30,7 @@
30
30
  "created_at"
31
31
  ],
32
32
  "additionalProperties": false,
33
- "description": "The robot as it now stands, after the patch was applied. The whole resource comes back, not only the fields that changed."
33
+ "description": "The robot as it now stands, after the patch. The whole resource comes back, not only the changed fields."
34
34
  }
35
35
  },
36
36
  "required": [
@@ -106,7 +106,7 @@
106
106
  ]
107
107
  },
108
108
  "description": {
109
- "description": "Prose about what this value is, for whoever meets it in the console later. It changes nothing the robot does, so a publish that touches only it pushes no configuration at all — but it is carried verbatim into `robot_describe`, where a model that has never seen this robot reads it. The datapoint is offered whenever the role grants it; without one it is offered with `description: null` and the model has less to go on, as for actions, services, publishers and cameras. Omission is the only way to say nothing; an empty string is refused, here and on all five.",
109
+ "description": "Prose about what this value is, for whoever meets it in the console. It changes nothing the robot does, so a publish that touches only it pushes no configuration at all — but it is carried verbatim into `robot_describe`, where a model that has never seen this robot reads it. The datapoint is offered whenever the role grants it; without one it is offered with `description: null` and the model has less to go on, as for actions, services, publishers and cameras. Omission is the only way to say nothing; an empty string is refused, here and on all five.",
110
110
  "examples": [
111
111
  "What this value is, for whoever meets it in the console."
112
112
  ],
@@ -11,7 +11,7 @@
11
11
  "type": "string",
12
12
  "format": "uuid",
13
13
  "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)$",
14
- "description": "The job's id, minted by the cloud when the invocation is accepted. Informative: state is observed by slug, and this id is what a cancel names when a caller wants to stop one specific job rather than whatever is running."
14
+ "description": "The job's id, minted by the cloud when the invocation is accepted. Informative — state is observed by slug; a cancel names this id to stop one specific job rather than whatever is running."
15
15
  },
16
16
  "robot_id": {
17
17
  "type": "string",
@@ -35,13 +35,13 @@
35
35
  "cancelled",
36
36
  "lost"
37
37
  ],
38
- "description": "Where the job stands: `running`, `succeeded`, `failed`, `cancelled` or `lost`. `lost` is a real outcome — the bridge restarted mid-job and the result is gone — and is said out loud rather than left reading `running` because nobody contradicted it."
38
+ "description": "Where the job stands: `running`, `succeeded`, `failed`, `cancelled` or `lost`. `lost` is a real outcome — the bridge restarted mid-job and the result is gone — stated rather than left reading `running` by default."
39
39
  },
40
40
  "started_at": {
41
41
  "type": "string",
42
42
  "format": "date-time",
43
43
  "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
44
- "description": "When the cloud minted this job, as an ISO 8601 timestamp. For a job adopted from a reconnecting bridge it is **adoption time**, not the real start, because the cloud never minted it and has no honest alternative."
44
+ "description": "When the cloud minted this job, as an ISO 8601 timestamp. For a job adopted from a reconnecting bridge, this is **adoption time**, not the real start — the cloud never minted it."
45
45
  },
46
46
  "updated_at": {
47
47
  "type": "string",
@@ -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, because no route renames or deletes 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. It does not make them renamable or deletable — no route does that for any role."
31
31
  }
32
32
  },
33
33
  "required": [
@@ -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, because no route renames or deletes 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. It does not make them renamable or deletable — no route does that for any role."
26
26
  }
27
27
  },
28
28
  "required": [
@@ -11,7 +11,7 @@
11
11
  "type": "string",
12
12
  "format": "uuid",
13
13
  "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)$",
14
- "description": "The key row, and what the rotate and delete routes address. It is not the key: the secret itself is never carried by this shape."
14
+ "description": "The key row, and what the rotate and delete routes address. It is not the key: this shape never carries the secret."
15
15
  },
16
16
  "app_id": {
17
17
  "type": "string",
@@ -54,7 +54,7 @@
54
54
  ],
55
55
  "additionalProperties": false
56
56
  },
57
- "description": "The app's server keys as metadata, oldest first by `created_at`. The raw secret is not here and never will be: it exists once, in the answer to the request that created or rotated the key."
57
+ "description": "The app's server keys as metadata, oldest first by `created_at`. The raw secret is not here and never will be: it exists once, in the response that created or rotated the key."
58
58
  }
59
59
  },
60
60
  "required": [
@@ -6,7 +6,7 @@
6
6
  "type": "string",
7
7
  "format": "uuid",
8
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 key row, and what the rotate and delete routes address. It is not the key: the secret itself is never carried by this shape."
9
+ "description": "The key row, and what the rotate and delete routes address. It is not the key: this shape never carries the secret."
10
10
  },
11
11
  "app_id": {
12
12
  "type": "string",
@@ -3,7 +3,7 @@
3
3
  "type": "object",
4
4
  "properties": {
5
5
  "result": {
6
- "description": "What the service returned, shaped by the ROS service itself. A service call is awaited to completion, so there is no job to observe afterwards and no id to hold on to."
6
+ "description": "What the service returned, shaped by the ROS service. A service call is awaited to completion, so there is no job to observe afterwards and no id to hold on to."
7
7
  }
8
8
  },
9
9
  "required": [
@@ -44,7 +44,7 @@
44
44
  "type": "string",
45
45
  "format": "uuid",
46
46
  "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)$",
47
- "description": "The organisation this person belongs to. Every developer route is already scoped to the caller's org, so this confirms what a client is looking at rather than being a filter it applies."
47
+ "description": "The organisation this person belongs to. Every developer route is already scoped to the caller's org, so this confirms what a client is looking at, not a filter it applies."
48
48
  },
49
49
  "email": {
50
50
  "type": "string",
@@ -71,7 +71,7 @@
71
71
  "owner",
72
72
  "developer"
73
73
  ],
74
- "description": "The console powers this person holds. **Required** — every Fleetless user is a member of the team and has a tier; the optional version of this field existed only while the org also held people with no console powers to grade, and that pool is gone."
74
+ "description": "The console powers this person holds. **Required** — every Fleetless user has a tier; it was optional only while the org also held people with no console powers to grade, and that pool is gone."
75
75
  },
76
76
  "created_at": {
77
77
  "type": "string",
@@ -21,7 +21,7 @@
21
21
  "type": "string",
22
22
  "minLength": 1,
23
23
  "maxLength": 500,
24
- "description": "The reference, verbatim, that no stored asset answers — a `package://` URI the workspace does not hold, or an absolute or bare relative path nothing will ever fetch. A developer whose URDF names one of the latter is entitled to be told so."
24
+ "description": "The reference, verbatim, that no stored asset answers — a `package://` URI the workspace does not hold, or an absolute or bare relative path nothing will ever fetch."
25
25
  },
26
26
  "element": {
27
27
  "type": "string",
@@ -38,7 +38,7 @@
38
38
  ],
39
39
  "additionalProperties": false
40
40
  },
41
- "description": "The references nothing in the store answers, each with the element that asked for it. A bare count is a dead end that sends a developer hunting through a workspace by hand; the references are what they can act on, so the references travel."
41
+ "description": "The references nothing in the store answers, each with the element that asked for it. A bare count would send a developer hunting through the workspace by hand; the references are what they can act on."
42
42
  }
43
43
  },
44
44
  "required": [
@@ -59,7 +59,7 @@
59
59
  "type": "integer",
60
60
  "exclusiveMinimum": 0,
61
61
  "maximum": 9007199254740991,
62
- "description": "How large the refused file actually is, in bytes. With `limit_bytes` beside it a developer can tell whether to shrink the mesh or raise the limit; \"too large\" alone answers neither."
62
+ "description": "How large the refused file is, in bytes. With `limit_bytes` beside it a developer can tell whether to shrink the mesh or raise the limit; \"too large\" alone answers neither."
63
63
  }
64
64
  },
65
65
  "required": [
package/dist/alerts.d.ts CHANGED
@@ -1,24 +1,22 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  import { z } from 'zod';
3
- /**
4
3
  /**
5
4
  * Datapoint alerts and per-datapoint chart display config.
6
5
  *
7
- * An alert is a **state machine** (`ok ⇄ firing`), not a fire-once event. The
6
+ * An alert is a **state machine** (`ok ⇄ firing`), not a fire-once event: the
8
7
  * definition and the runtime state (`state`, `state_since`, `last_value`) are
9
- * read together, and the cloud evaluates the alert at ingest.
8
+ * read together, and the cloud evaluates it at ingest.
10
9
  *
11
10
  * **The definitions live in the configuration document.** The alert definition
12
11
  * is `config.ts`'s `datapointAlert`, nested under the datapoint it watches; the
13
- * chart bounds are `datapointChart`. They therefore take effect on publish
14
- * rather than immediately, and in exchange every change to them is versioned,
15
- * comparable and revertible. The runtime state stays in the database: it has no
16
- * business in a versioned document.
12
+ * chart bounds are `datapointChart`. They take effect on publish, not
13
+ * immediately — in exchange, every change is versioned, comparable, revertible.
14
+ * The runtime state stays in the database: it has no business in a versioned
15
+ * document.
17
16
  *
18
17
  * **What is here is the read surface.** `GET /api/robots/:id/alerts` and
19
- * `GET /api/org/alerts` answer with the definition joined to its state, and the
20
- * shapes below are what they answer with. No alert sends mail, so nothing here
21
- * describes one.
18
+ * `GET /api/org/alerts` answer with the definition joined to its state — the
19
+ * shapes below. No alert sends mail, so nothing here describes one.
22
20
  */
23
21
  /**
24
22
  * `above`/`below` compare the numeric sample value (already scale/offset
@@ -27,11 +25,11 @@ import { z } from 'zod';
27
25
  * threshold itself: `above` resolves at `value ≤ threshold −
28
26
  * resolve_hysteresis`, mirrored for `below`. Defaulted rather than left
29
27
  * `optional` so a parsed entity never makes a consumer re-derive "absent
30
- * means 0" — the cloud always sends an explicit resolve point, and every
31
- * reader gets the same number whether it was sent or not. `equals` compares
32
- * the raw value for equality — the shape for boolean/string datapoints a
33
- * threshold cannot describe ("Hindernis erkannt" = `equals true`) — and
34
- * carries no hysteresis, because equality has no direction to relax.
28
+ * means 0" — the cloud always sends an explicit resolve point. `equals`
29
+ * compares the raw value for equality — the shape for boolean/string
30
+ * datapoints a threshold cannot describe (an obstacle-detected flag as
31
+ * `equals true`) — and carries no hysteresis: equality has no direction to
32
+ * relax.
35
33
  *
36
34
  * A discriminated union on `kind` rather than one object with optional
37
35
  * fields: an `equals` alert carrying a stray `threshold` would otherwise
@@ -101,8 +99,8 @@ export type AlertState = z.infer<typeof alertState>;
101
99
  * cloud joins the two per request (`routes/alerts.ts`'s `toWire`).
102
100
  *
103
101
  * **There are no mail settings here.** The configuration format has no mail
104
- * fields, so no alert can be configured to send one, and a shape describing
105
- * recipients would describe a delivery path that does not exist.
102
+ * fields, so no alert can send one, and a shape describing recipients would
103
+ * describe a delivery path that does not exist.
106
104
  */
107
105
  export declare const datapointAlertRow: z.ZodObject<{
108
106
  id: z.ZodUUID;
package/dist/alerts.js CHANGED
@@ -1,25 +1,23 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  import { z } from 'zod';
3
3
  import { slug } from './common.js';
4
- /**
5
4
  /**
6
5
  * Datapoint alerts and per-datapoint chart display config.
7
6
  *
8
- * An alert is a **state machine** (`ok ⇄ firing`), not a fire-once event. The
7
+ * An alert is a **state machine** (`ok ⇄ firing`), not a fire-once event: the
9
8
  * definition and the runtime state (`state`, `state_since`, `last_value`) are
10
- * read together, and the cloud evaluates the alert at ingest.
9
+ * read together, and the cloud evaluates it at ingest.
11
10
  *
12
11
  * **The definitions live in the configuration document.** The alert definition
13
12
  * is `config.ts`'s `datapointAlert`, nested under the datapoint it watches; the
14
- * chart bounds are `datapointChart`. They therefore take effect on publish
15
- * rather than immediately, and in exchange every change to them is versioned,
16
- * comparable and revertible. The runtime state stays in the database: it has no
17
- * business in a versioned document.
13
+ * chart bounds are `datapointChart`. They take effect on publish, not
14
+ * immediately — in exchange, every change is versioned, comparable, revertible.
15
+ * The runtime state stays in the database: it has no business in a versioned
16
+ * document.
18
17
  *
19
18
  * **What is here is the read surface.** `GET /api/robots/:id/alerts` and
20
- * `GET /api/org/alerts` answer with the definition joined to its state, and the
21
- * shapes below are what they answer with. No alert sends mail, so nothing here
22
- * describes one.
19
+ * `GET /api/org/alerts` answer with the definition joined to its state — the
20
+ * shapes below. No alert sends mail, so nothing here describes one.
23
21
  */
24
22
  /**
25
23
  * `above`/`below` compare the numeric sample value (already scale/offset
@@ -28,11 +26,11 @@ import { slug } from './common.js';
28
26
  * threshold itself: `above` resolves at `value ≤ threshold −
29
27
  * resolve_hysteresis`, mirrored for `below`. Defaulted rather than left
30
28
  * `optional` so a parsed entity never makes a consumer re-derive "absent
31
- * means 0" — the cloud always sends an explicit resolve point, and every
32
- * reader gets the same number whether it was sent or not. `equals` compares
33
- * the raw value for equality — the shape for boolean/string datapoints a
34
- * threshold cannot describe ("Hindernis erkannt" = `equals true`) — and
35
- * carries no hysteresis, because equality has no direction to relax.
29
+ * means 0" — the cloud always sends an explicit resolve point. `equals`
30
+ * compares the raw value for equality — the shape for boolean/string
31
+ * datapoints a threshold cannot describe (an obstacle-detected flag as
32
+ * `equals true`) — and carries no hysteresis: equality has no direction to
33
+ * relax.
36
34
  *
37
35
  * A discriminated union on `kind` rather than one object with optional
38
36
  * fields: an `equals` alert carrying a stray `threshold` would otherwise
@@ -98,8 +96,8 @@ export const alertState = z.enum(['ok', 'firing']);
98
96
  * cloud joins the two per request (`routes/alerts.ts`'s `toWire`).
99
97
  *
100
98
  * **There are no mail settings here.** The configuration format has no mail
101
- * fields, so no alert can be configured to send one, and a shape describing
102
- * recipients would describe a delivery path that does not exist.
99
+ * fields, so no alert can send one, and a shape describing recipients would
100
+ * describe a delivery path that does not exist.
103
101
  */
104
102
  export const datapointAlertRow = z.object({
105
103
  id: z.uuid(),
@@ -39,9 +39,9 @@ export declare const APP_USER_DISPLAY_NAME_MAX = 120;
39
39
  * buttons, where a hyphen is the conventional spelling — `azure-ad`, not
40
40
  * `azure_ad`.
41
41
  *
42
- * The two grammars are one character apart, which is exactly why this is its
43
- * own export with its own tests rather than a reuse: reusing the wrong one
44
- * would be invisible until a customer typed a hyphen.
42
+ * The two grammars are one character apart — why this is its own export with
43
+ * its own tests, not a reuse: reusing the wrong one would be invisible until
44
+ * a customer typed a hyphen.
45
45
  */
46
46
  export declare const providerSlug: z.ZodString;
47
47
  /**
@@ -338,9 +338,8 @@ export declare const APP_URL_PLACEHOLDERS: {
338
338
  * the mirror reason: it would mail every recipient the same link.
339
339
  *
340
340
  * **What it cannot check**: that the URL resolves, that the app serves that
341
- * path, or that the developer's page knows what to do with the token. Nothing
342
- * a schema can see says any of that, and a validator that looked sufficient
343
- * here would be read as an assurance.
341
+ * path, or that the developer's page knows what to do with the token — and a
342
+ * validator that looked sufficient here would be read as an assurance.
344
343
  */
345
344
  export declare function appUrlTemplate(placeholder: string): z.ZodString;
346
345
  /**
package/dist/app-users.js CHANGED
@@ -40,14 +40,14 @@ export const APP_USER_DISPLAY_NAME_MAX = 120;
40
40
  * buttons, where a hyphen is the conventional spelling — `azure-ad`, not
41
41
  * `azure_ad`.
42
42
  *
43
- * The two grammars are one character apart, which is exactly why this is its
44
- * own export with its own tests rather than a reuse: reusing the wrong one
45
- * would be invisible until a customer typed a hyphen.
43
+ * The two grammars are one character apart — why this is its own export with
44
+ * its own tests, not a reuse: reusing the wrong one would be invisible until
45
+ * a customer typed a hyphen.
46
46
  */
47
47
  export const providerSlug = z
48
48
  .string()
49
49
  .max(40)
50
- .regex(/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/, 'a provider slug is lowercase and hyphen-separated, starting with a letter');
50
+ .regex(/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/, 'must be lowercase and hyphen-separated, starting with a letter');
51
51
  /**
52
52
  * **The three states an app user can be in, and the order is the lifecycle.**
53
53
  *
@@ -95,10 +95,10 @@ export const appUser = z.object({
95
95
  * accepted — it does not mean blocked and it does not mean without access.
96
96
  */
97
97
  has_password: z.boolean().meta({
98
- description: 'Whether this account has a Fleetless-held password at all. `false` is an identity-provider-only account, or an invitation not yet accepted — it does not mean blocked and it does not mean without access. No hash, no algorithm and no "last changed" travels here, and nothing on the wire can say whether a password is strong or already known to somebody else.',
98
+ description: 'Whether this account has a Fleetless-held password. `false` is an identity-provider-only account, or an invitation not yet accepted — it does not mean blocked and it does not mean without access. No hash, no algorithm and no "last changed" travels here, and nothing on the wire can say whether a password is strong or already known to somebody else.',
99
99
  }),
100
100
  providers: z.array(providerSlug).max(20).meta({
101
- description: 'The slugs of the identity providers this account is linked to, empty for a password-only user. It is what lets a developer\'s user list say where an account came from without a second request.',
101
+ description: 'The slugs of the identity providers this account is linked to, empty for a password-only user. Lets a developer\'s user list say where an account came from without a second request.',
102
102
  }),
103
103
  last_login_at: z.iso.datetime().nullable().meta({
104
104
  description: 'When this user last signed in, or `null` if they never have. Required and nullable rather than optional, so *never logged in* stays distinguishable from *this field was not loaded*.',
@@ -269,7 +269,7 @@ export const appOidcProvider = z.object({
269
269
  description: 'Whether a federated login may join an **existing** app user with the same address. It needs the provider to assert `email_verified` as well: either condition alone is account takeover, since a provider that lets anyone type any address into a profile would otherwise hand over every matching account, and a developer who connects a provider for a subset of their users would otherwise silently merge strangers.',
270
270
  }),
271
271
  enabled: z.boolean().meta({
272
- description: 'Whether this provider is offered at all. A disabled provider disappears from `GET /api/client/providers` and refuses a start with `provider_disabled`, without the row and its linked identities being deleted.',
272
+ description: 'Whether this provider is offered. A disabled provider disappears from `GET /api/client/providers` and refuses a start with `provider_disabled`, without the row and its linked identities being deleted.',
273
273
  }),
274
274
  created_at: z.iso.datetime().meta({ description: 'When the provider was configured, as an ISO 8601 timestamp.' }),
275
275
  }).strict();
@@ -371,9 +371,8 @@ export const APP_URL_PLACEHOLDERS = {
371
371
  * the mirror reason: it would mail every recipient the same link.
372
372
  *
373
373
  * **What it cannot check**: that the URL resolves, that the app serves that
374
- * path, or that the developer's page knows what to do with the token. Nothing
375
- * a schema can see says any of that, and a validator that looked sufficient
376
- * here would be read as an assurance.
374
+ * path, or that the developer's page knows what to do with the token — and a
375
+ * validator that looked sufficient here would be read as an assurance.
377
376
  */
378
377
  export function appUrlTemplate(placeholder) {
379
378
  return z
package/dist/apps.d.ts CHANGED
@@ -5,7 +5,7 @@ import { z } from 'zod';
5
5
  *
6
6
  * The rule that shapes all of this: **roles are the only filter**. A robot
7
7
  * assigned to an app exposes every one of its services to that app; what a
8
- * role does not grant simply does not exist for that user. There is no second
8
+ * role does not grant does not exist for that user. There is no second
9
9
  * visibility mechanism, and adding one later would create two places to look
10
10
  * when someone cannot see something.
11
11
  */
@@ -15,8 +15,8 @@ import { z } from 'zod';
15
15
  *
16
16
  * **Globally unique, not per org.** `clientLoginRequest` carries only the
17
17
  * identifier, the email and the password — there is no org context to
18
- * disambiguate with, so a per-org identifier could not be resolved at login
19
- * at all. A collision is refused with `identifier_taken`.
18
+ * disambiguate with, so a per-org identifier could not be resolved at login.
19
+ * A collision is refused with `identifier_taken`.
20
20
  */
21
21
  export declare const appIdentifier: z.ZodString;
22
22
  export declare const app: z.ZodObject<{
@@ -129,9 +129,8 @@ export declare const createServerKeyResponse: z.ZodObject<{
129
129
  export type CreateServerKeyResponse = z.infer<typeof createServerKeyResponse>;
130
130
  /**
131
131
  * Every app starts with `observe` and `operate`; custom roles are allowed
132
- * too. `builtin` marks the two starting roles — they may be
133
- * edited like any other, the flag exists so the console can explain where
134
- * they came from.
132
+ * too. `builtin` marks the two starting roles — editable like any other,
133
+ * the flag only tells the console where they came from.
135
134
  */
136
135
  export declare const role: z.ZodObject<{
137
136
  id: z.ZodUUID;