@fleetless/contracts 1.0.6 → 1.1.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 +6 -0
- package/artifacts/openapi.json +294 -0
- package/artifacts/routes.json +71 -0
- package/artifacts/schema/client-robot-list-item.schema.json +70 -0
- package/artifacts/schema/client-robot-list-response.schema.json +83 -0
- package/dist/client-robots.d.ts +37 -0
- package/dist/client-robots.js +30 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/mcp.d.ts +6 -1
- package/dist/mcp.js +6 -1
- package/dist/realtime.d.ts +2 -2
- package/dist/routes.js +37 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,12 @@ the wire shapes.
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.1.0] — 2026-09-17
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Two discovery routes for app users**, the REST twins of the MCP tools every session starts from: `GET /api/client/robots` lists the robots the caller reaches (`clientRobotListResponse`, new), and `GET /api/robots/:id/datasheet` answers the same `mcpRobotDatasheet` that `robot_describe` does — every granted slug with its kind, unit, decimals and parameter JSON Schema, plus the `action_history` and `assets` capabilities. No existing wire shape changes.
|
|
15
|
+
|
|
10
16
|
## [1.0.6] — 2026-09-16
|
|
11
17
|
|
|
12
18
|
- Published from GitHub Actions by npm trusted publishing: no publish token exists anywhere, and every version from this one on carries a provenance attestation linking it to the commit and the run that built it. `npm audit signatures` checks it.
|
package/artifacts/openapi.json
CHANGED
|
@@ -5446,6 +5446,104 @@
|
|
|
5446
5446
|
"description": "For a client caller the grant check runs **before** any existence lookup, with no extra query on either path to time: a denied slug and a nonexistent one must be one answer. That is why an ungranted slug is `403 forbidden` while a granted-but-unconfigured one is `404 unknown_datapoint` and a configured one with no sample yet is `404 no_data` — three facts a caller who is entitled to them needs told apart. The plane built-ins (`bridge_state`, `robot_details`) answer here too, without appearing in any document."
|
|
5447
5447
|
}
|
|
5448
5448
|
},
|
|
5449
|
+
"/api/client/robots": {
|
|
5450
|
+
"get": {
|
|
5451
|
+
"operationId": "get_api_client_robots",
|
|
5452
|
+
"summary": "Lists the robots the caller reaches, with bridge state and the published configuration version.",
|
|
5453
|
+
"tags": [
|
|
5454
|
+
"robots"
|
|
5455
|
+
],
|
|
5456
|
+
"security": [
|
|
5457
|
+
{
|
|
5458
|
+
"developerSession": []
|
|
5459
|
+
},
|
|
5460
|
+
{
|
|
5461
|
+
"clientToken": []
|
|
5462
|
+
},
|
|
5463
|
+
{
|
|
5464
|
+
"serverKey": []
|
|
5465
|
+
}
|
|
5466
|
+
],
|
|
5467
|
+
"parameters": [],
|
|
5468
|
+
"responses": {
|
|
5469
|
+
"200": {
|
|
5470
|
+
"description": "Success.",
|
|
5471
|
+
"content": {
|
|
5472
|
+
"application/json": {
|
|
5473
|
+
"schema": {
|
|
5474
|
+
"$ref": "#/components/schemas/client-robot-list-response"
|
|
5475
|
+
}
|
|
5476
|
+
}
|
|
5477
|
+
}
|
|
5478
|
+
},
|
|
5479
|
+
"default": {
|
|
5480
|
+
"description": "An error envelope. Codes this route is known to answer: `unauthorized`, `token_expired`, `token_revoked`, `forbidden`.",
|
|
5481
|
+
"content": {
|
|
5482
|
+
"application/json": {
|
|
5483
|
+
"schema": {
|
|
5484
|
+
"$ref": "#/components/schemas/api-error"
|
|
5485
|
+
}
|
|
5486
|
+
}
|
|
5487
|
+
}
|
|
5488
|
+
}
|
|
5489
|
+
},
|
|
5490
|
+
"description": "**The REST twin of the MCP tool `robots_list`**, and the one robot question no robot-scoped route can answer: which robots may I name at all. An app user sees the robots their app attaches on which their role grants at least one slug or capability; a server key sees every robot its app attaches; a developer bearer sees the organisation's robots. Name order, id as the tiebreak. A robot on which the role grants nothing is absent rather than listed empty — the same answer `robots_list` gives, for the same reason: reach is a grant, not an attachment. Under `/api/client/` because it names no robot; every robot-scoped read stays under `/api/robots/:id/…`."
|
|
5491
|
+
}
|
|
5492
|
+
},
|
|
5493
|
+
"/api/robots/{id}/datasheet": {
|
|
5494
|
+
"get": {
|
|
5495
|
+
"operationId": "get_api_robots_id_datasheet",
|
|
5496
|
+
"summary": "Describes everything the caller's role lets them do on one robot, with parameter schemas.",
|
|
5497
|
+
"tags": [
|
|
5498
|
+
"robots"
|
|
5499
|
+
],
|
|
5500
|
+
"security": [
|
|
5501
|
+
{
|
|
5502
|
+
"developerSession": []
|
|
5503
|
+
},
|
|
5504
|
+
{
|
|
5505
|
+
"clientToken": []
|
|
5506
|
+
},
|
|
5507
|
+
{
|
|
5508
|
+
"serverKey": []
|
|
5509
|
+
}
|
|
5510
|
+
],
|
|
5511
|
+
"parameters": [
|
|
5512
|
+
{
|
|
5513
|
+
"name": "id",
|
|
5514
|
+
"in": "path",
|
|
5515
|
+
"required": true,
|
|
5516
|
+
"description": "The robot's uuid, as `GET /api/client/robots` lists it.",
|
|
5517
|
+
"schema": {
|
|
5518
|
+
"type": "string"
|
|
5519
|
+
}
|
|
5520
|
+
}
|
|
5521
|
+
],
|
|
5522
|
+
"responses": {
|
|
5523
|
+
"200": {
|
|
5524
|
+
"description": "Success.",
|
|
5525
|
+
"content": {
|
|
5526
|
+
"application/json": {
|
|
5527
|
+
"schema": {
|
|
5528
|
+
"$ref": "#/components/schemas/mcp-robot-datasheet"
|
|
5529
|
+
}
|
|
5530
|
+
}
|
|
5531
|
+
}
|
|
5532
|
+
},
|
|
5533
|
+
"default": {
|
|
5534
|
+
"description": "An error envelope. Codes this route is known to answer: `unauthorized`, `token_expired`, `token_revoked`, `forbidden`, `invalid_uuid`, `not_found`.",
|
|
5535
|
+
"content": {
|
|
5536
|
+
"application/json": {
|
|
5537
|
+
"schema": {
|
|
5538
|
+
"$ref": "#/components/schemas/api-error"
|
|
5539
|
+
}
|
|
5540
|
+
}
|
|
5541
|
+
}
|
|
5542
|
+
}
|
|
5543
|
+
},
|
|
5544
|
+
"description": "**The REST twin of the MCP tool `robot_describe`**: one answer per robot — every datapoint, action, service, publisher and camera the role grants, each with its `input_schema` where it takes parameters, plus the two capabilities that gate whole features, `action_history` and `assets`. A robot with nothing published answers an empty `exposures` list, never a refusal. A robot the caller does not reach — not attached to their app, or attached with a role that grants nothing on it — answers `404` exactly as one that does not exist. The app-user datapoint and camera listings under this prefix stay; this is the one read that also names actions, services, publishers and capabilities, which is what an app needs before it can draw a screen."
|
|
5545
|
+
}
|
|
5546
|
+
},
|
|
5449
5547
|
"/api/robots/{id}/config/draft": {
|
|
5450
5548
|
"get": {
|
|
5451
5549
|
"operationId": "get_api_robots_id_config_draft",
|
|
@@ -10395,6 +10493,88 @@
|
|
|
10395
10493
|
],
|
|
10396
10494
|
"additionalProperties": false
|
|
10397
10495
|
},
|
|
10496
|
+
"client-robot-list-response": {
|
|
10497
|
+
"type": "object",
|
|
10498
|
+
"properties": {
|
|
10499
|
+
"robots": {
|
|
10500
|
+
"type": "array",
|
|
10501
|
+
"items": {
|
|
10502
|
+
"type": "object",
|
|
10503
|
+
"properties": {
|
|
10504
|
+
"id": {
|
|
10505
|
+
"type": "string",
|
|
10506
|
+
"format": "uuid",
|
|
10507
|
+
"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)$",
|
|
10508
|
+
"description": "The robot, and what every robot-scoped route takes as its `:id`."
|
|
10509
|
+
},
|
|
10510
|
+
"name": {
|
|
10511
|
+
"type": "string",
|
|
10512
|
+
"minLength": 1,
|
|
10513
|
+
"maxLength": 63,
|
|
10514
|
+
"description": "The robot's display name, at most 63 characters. Free text, changed through `PATCH /api/robots/:id`."
|
|
10515
|
+
},
|
|
10516
|
+
"created_at": {
|
|
10517
|
+
"type": "string",
|
|
10518
|
+
"format": "date-time",
|
|
10519
|
+
"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))$",
|
|
10520
|
+
"description": "When the robot was created, as an ISO 8601 timestamp."
|
|
10521
|
+
},
|
|
10522
|
+
"bridge_state": {
|
|
10523
|
+
"type": "object",
|
|
10524
|
+
"properties": {
|
|
10525
|
+
"online": {
|
|
10526
|
+
"type": "boolean"
|
|
10527
|
+
},
|
|
10528
|
+
"latency_ms": {
|
|
10529
|
+
"anyOf": [
|
|
10530
|
+
{
|
|
10531
|
+
"type": "number",
|
|
10532
|
+
"minimum": 0
|
|
10533
|
+
},
|
|
10534
|
+
{
|
|
10535
|
+
"type": "null"
|
|
10536
|
+
}
|
|
10537
|
+
]
|
|
10538
|
+
}
|
|
10539
|
+
},
|
|
10540
|
+
"required": [
|
|
10541
|
+
"online",
|
|
10542
|
+
"latency_ms"
|
|
10543
|
+
],
|
|
10544
|
+
"additionalProperties": false,
|
|
10545
|
+
"description": "The built-in `bridge_state` datapoint as the cloud observes it right now: whether the bridge is connected, and its latency when it is."
|
|
10546
|
+
},
|
|
10547
|
+
"published_version": {
|
|
10548
|
+
"anyOf": [
|
|
10549
|
+
{
|
|
10550
|
+
"type": "integer",
|
|
10551
|
+
"exclusiveMinimum": 0,
|
|
10552
|
+
"maximum": 9007199254740991
|
|
10553
|
+
},
|
|
10554
|
+
{
|
|
10555
|
+
"type": "null"
|
|
10556
|
+
}
|
|
10557
|
+
],
|
|
10558
|
+
"description": "The published configuration version, or `null` when nothing has been published yet. A robot with nothing published is still listed — \"not configured yet\" is a real state, and the caller is entitled to it — and its datasheet answers an empty exposure list."
|
|
10559
|
+
}
|
|
10560
|
+
},
|
|
10561
|
+
"required": [
|
|
10562
|
+
"id",
|
|
10563
|
+
"name",
|
|
10564
|
+
"created_at",
|
|
10565
|
+
"bridge_state",
|
|
10566
|
+
"published_version"
|
|
10567
|
+
],
|
|
10568
|
+
"additionalProperties": false
|
|
10569
|
+
},
|
|
10570
|
+
"description": "Every robot the caller reaches, in name order with the id as the tiebreak. An app user reaches the robots their app attaches on which their role grants at least one slug or capability; a server key reaches every robot its app attaches; a developer reaches every robot of the organisation."
|
|
10571
|
+
}
|
|
10572
|
+
},
|
|
10573
|
+
"required": [
|
|
10574
|
+
"robots"
|
|
10575
|
+
],
|
|
10576
|
+
"additionalProperties": false
|
|
10577
|
+
},
|
|
10398
10578
|
"client-verify-email-request": {
|
|
10399
10579
|
"type": "object",
|
|
10400
10580
|
"properties": {
|
|
@@ -14446,6 +14626,120 @@
|
|
|
14446
14626
|
],
|
|
14447
14627
|
"additionalProperties": false
|
|
14448
14628
|
},
|
|
14629
|
+
"mcp-robot-datasheet": {
|
|
14630
|
+
"type": "object",
|
|
14631
|
+
"properties": {
|
|
14632
|
+
"robot_id": {
|
|
14633
|
+
"type": "string",
|
|
14634
|
+
"format": "uuid",
|
|
14635
|
+
"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)$"
|
|
14636
|
+
},
|
|
14637
|
+
"robot_name": {
|
|
14638
|
+
"type": "string",
|
|
14639
|
+
"minLength": 1,
|
|
14640
|
+
"maxLength": 200
|
|
14641
|
+
},
|
|
14642
|
+
"capabilities": {
|
|
14643
|
+
"type": "object",
|
|
14644
|
+
"properties": {
|
|
14645
|
+
"action_history": {
|
|
14646
|
+
"type": "boolean"
|
|
14647
|
+
},
|
|
14648
|
+
"assets": {
|
|
14649
|
+
"type": "boolean"
|
|
14650
|
+
}
|
|
14651
|
+
},
|
|
14652
|
+
"required": [
|
|
14653
|
+
"action_history",
|
|
14654
|
+
"assets"
|
|
14655
|
+
],
|
|
14656
|
+
"additionalProperties": false
|
|
14657
|
+
},
|
|
14658
|
+
"exposures": {
|
|
14659
|
+
"maxItems": 2000,
|
|
14660
|
+
"type": "array",
|
|
14661
|
+
"items": {
|
|
14662
|
+
"type": "object",
|
|
14663
|
+
"properties": {
|
|
14664
|
+
"slug": {
|
|
14665
|
+
"type": "string",
|
|
14666
|
+
"minLength": 2,
|
|
14667
|
+
"maxLength": 63,
|
|
14668
|
+
"pattern": "^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$"
|
|
14669
|
+
},
|
|
14670
|
+
"kind": {
|
|
14671
|
+
"type": "string",
|
|
14672
|
+
"enum": [
|
|
14673
|
+
"datapoint",
|
|
14674
|
+
"service",
|
|
14675
|
+
"action",
|
|
14676
|
+
"publisher",
|
|
14677
|
+
"camera"
|
|
14678
|
+
]
|
|
14679
|
+
},
|
|
14680
|
+
"description": {
|
|
14681
|
+
"anyOf": [
|
|
14682
|
+
{
|
|
14683
|
+
"type": "string",
|
|
14684
|
+
"maxLength": 2000
|
|
14685
|
+
},
|
|
14686
|
+
{
|
|
14687
|
+
"type": "null"
|
|
14688
|
+
}
|
|
14689
|
+
]
|
|
14690
|
+
},
|
|
14691
|
+
"unit": {
|
|
14692
|
+
"anyOf": [
|
|
14693
|
+
{
|
|
14694
|
+
"type": "string",
|
|
14695
|
+
"maxLength": 32
|
|
14696
|
+
},
|
|
14697
|
+
{
|
|
14698
|
+
"type": "null"
|
|
14699
|
+
}
|
|
14700
|
+
]
|
|
14701
|
+
},
|
|
14702
|
+
"decimals": {
|
|
14703
|
+
"anyOf": [
|
|
14704
|
+
{
|
|
14705
|
+
"type": "integer",
|
|
14706
|
+
"minimum": 0,
|
|
14707
|
+
"maximum": 6
|
|
14708
|
+
},
|
|
14709
|
+
{
|
|
14710
|
+
"type": "null"
|
|
14711
|
+
}
|
|
14712
|
+
]
|
|
14713
|
+
},
|
|
14714
|
+
"input_schema": {
|
|
14715
|
+
"anyOf": [
|
|
14716
|
+
{},
|
|
14717
|
+
{
|
|
14718
|
+
"type": "null"
|
|
14719
|
+
}
|
|
14720
|
+
]
|
|
14721
|
+
}
|
|
14722
|
+
},
|
|
14723
|
+
"required": [
|
|
14724
|
+
"slug",
|
|
14725
|
+
"kind",
|
|
14726
|
+
"description",
|
|
14727
|
+
"unit",
|
|
14728
|
+
"decimals",
|
|
14729
|
+
"input_schema"
|
|
14730
|
+
],
|
|
14731
|
+
"additionalProperties": false
|
|
14732
|
+
}
|
|
14733
|
+
}
|
|
14734
|
+
},
|
|
14735
|
+
"required": [
|
|
14736
|
+
"robot_id",
|
|
14737
|
+
"robot_name",
|
|
14738
|
+
"capabilities",
|
|
14739
|
+
"exposures"
|
|
14740
|
+
],
|
|
14741
|
+
"additionalProperties": false
|
|
14742
|
+
},
|
|
14449
14743
|
"mcp-role-preview-response": {
|
|
14450
14744
|
"type": "object",
|
|
14451
14745
|
"properties": {
|
package/artifacts/routes.json
CHANGED
|
@@ -273,6 +273,24 @@
|
|
|
273
273
|
"transport": "http",
|
|
274
274
|
"notes": "HTML. An unknown, spent or expired token renders one \"link no longer valid\" page at `410` — they are one refusal on the wire already, and splitting them here would tell a stranger which tokens ever existed. No rate limiter: the GET changes nothing, and the POST it leads to is limited per IP."
|
|
275
275
|
},
|
|
276
|
+
{
|
|
277
|
+
"method": "GET",
|
|
278
|
+
"path": "/favicon.svg",
|
|
279
|
+
"section": "client-auth",
|
|
280
|
+
"summary": "Serves the Fleetless icon for the auth portal's and the MCP welcome page's browser tab.",
|
|
281
|
+
"audience": "internal",
|
|
282
|
+
"auth": "none",
|
|
283
|
+
"rateLimited": false,
|
|
284
|
+
"ownerTier": false,
|
|
285
|
+
"status": 200,
|
|
286
|
+
"params": [],
|
|
287
|
+
"query": null,
|
|
288
|
+
"request": null,
|
|
289
|
+
"response": null,
|
|
290
|
+
"errors": [],
|
|
291
|
+
"transport": "http",
|
|
292
|
+
"notes": "An SVG, not JSON. Those pages carry a Content-Security-Policy that admits no `data:` image, so the icon is a file on their own origin — the one source `img-src 'self'` names. Cached for a day: the bytes change when the brand does, not per deploy."
|
|
293
|
+
},
|
|
276
294
|
{
|
|
277
295
|
"method": "POST",
|
|
278
296
|
"path": "/api/auth/password/reset/confirm",
|
|
@@ -3300,6 +3318,59 @@
|
|
|
3300
3318
|
"transport": "http",
|
|
3301
3319
|
"notes": "For a client caller the grant check runs **before** any existence lookup, with no extra query on either path to time: a denied slug and a nonexistent one must be one answer. That is why an ungranted slug is `403 forbidden` while a granted-but-unconfigured one is `404 unknown_datapoint` and a configured one with no sample yet is `404 no_data` — three facts a caller who is entitled to them needs told apart. The plane built-ins (`bridge_state`, `robot_details`) answer here too, without appearing in any document."
|
|
3302
3320
|
},
|
|
3321
|
+
{
|
|
3322
|
+
"method": "GET",
|
|
3323
|
+
"path": "/api/client/robots",
|
|
3324
|
+
"section": "robots",
|
|
3325
|
+
"summary": "Lists the robots the caller reaches, with bridge state and the published configuration version.",
|
|
3326
|
+
"audience": "client",
|
|
3327
|
+
"auth": "developer_or_client",
|
|
3328
|
+
"rateLimited": false,
|
|
3329
|
+
"ownerTier": false,
|
|
3330
|
+
"status": 200,
|
|
3331
|
+
"params": [],
|
|
3332
|
+
"query": null,
|
|
3333
|
+
"request": null,
|
|
3334
|
+
"response": "client-robot-list-response",
|
|
3335
|
+
"errors": [
|
|
3336
|
+
"unauthorized",
|
|
3337
|
+
"token_expired",
|
|
3338
|
+
"token_revoked",
|
|
3339
|
+
"forbidden"
|
|
3340
|
+
],
|
|
3341
|
+
"transport": "http",
|
|
3342
|
+
"notes": "**The REST twin of the MCP tool `robots_list`**, and the one robot question no robot-scoped route can answer: which robots may I name at all. An app user sees the robots their app attaches on which their role grants at least one slug or capability; a server key sees every robot its app attaches; a developer bearer sees the organisation's robots. Name order, id as the tiebreak. A robot on which the role grants nothing is absent rather than listed empty — the same answer `robots_list` gives, for the same reason: reach is a grant, not an attachment. Under `/api/client/` because it names no robot; every robot-scoped read stays under `/api/robots/:id/…`."
|
|
3343
|
+
},
|
|
3344
|
+
{
|
|
3345
|
+
"method": "GET",
|
|
3346
|
+
"path": "/api/robots/:id/datasheet",
|
|
3347
|
+
"section": "robots",
|
|
3348
|
+
"summary": "Describes everything the caller's role lets them do on one robot, with parameter schemas.",
|
|
3349
|
+
"audience": "client",
|
|
3350
|
+
"auth": "developer_or_client",
|
|
3351
|
+
"rateLimited": false,
|
|
3352
|
+
"ownerTier": false,
|
|
3353
|
+
"status": 200,
|
|
3354
|
+
"params": [
|
|
3355
|
+
{
|
|
3356
|
+
"name": "id",
|
|
3357
|
+
"description": "The robot's uuid, as `GET /api/client/robots` lists it."
|
|
3358
|
+
}
|
|
3359
|
+
],
|
|
3360
|
+
"query": null,
|
|
3361
|
+
"request": null,
|
|
3362
|
+
"response": "mcp-robot-datasheet",
|
|
3363
|
+
"errors": [
|
|
3364
|
+
"unauthorized",
|
|
3365
|
+
"token_expired",
|
|
3366
|
+
"token_revoked",
|
|
3367
|
+
"forbidden",
|
|
3368
|
+
"invalid_uuid",
|
|
3369
|
+
"not_found"
|
|
3370
|
+
],
|
|
3371
|
+
"transport": "http",
|
|
3372
|
+
"notes": "**The REST twin of the MCP tool `robot_describe`**: one answer per robot — every datapoint, action, service, publisher and camera the role grants, each with its `input_schema` where it takes parameters, plus the two capabilities that gate whole features, `action_history` and `assets`. A robot with nothing published answers an empty `exposures` list, never a refusal. A robot the caller does not reach — not attached to their app, or attached with a role that grants nothing on it — answers `404` exactly as one that does not exist. The app-user datapoint and camera listings under this prefix stay; this is the one read that also names actions, services, publishers and capabilities, which is what an app needs before it can draw a screen."
|
|
3373
|
+
},
|
|
3303
3374
|
{
|
|
3304
3375
|
"method": "GET",
|
|
3305
3376
|
"path": "/api/robots/:id/config/draft",
|
|
@@ -0,0 +1,70 @@
|
|
|
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 robot, and what every robot-scoped route takes as its `:id`."
|
|
10
|
+
},
|
|
11
|
+
"name": {
|
|
12
|
+
"type": "string",
|
|
13
|
+
"minLength": 1,
|
|
14
|
+
"maxLength": 63,
|
|
15
|
+
"description": "The robot's display name, at most 63 characters. Free text, changed through `PATCH /api/robots/:id`."
|
|
16
|
+
},
|
|
17
|
+
"created_at": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"format": "date-time",
|
|
20
|
+
"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))$",
|
|
21
|
+
"description": "When the robot was created, as an ISO 8601 timestamp."
|
|
22
|
+
},
|
|
23
|
+
"bridge_state": {
|
|
24
|
+
"type": "object",
|
|
25
|
+
"properties": {
|
|
26
|
+
"online": {
|
|
27
|
+
"type": "boolean"
|
|
28
|
+
},
|
|
29
|
+
"latency_ms": {
|
|
30
|
+
"anyOf": [
|
|
31
|
+
{
|
|
32
|
+
"type": "number",
|
|
33
|
+
"minimum": 0
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"type": "null"
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"required": [
|
|
42
|
+
"online",
|
|
43
|
+
"latency_ms"
|
|
44
|
+
],
|
|
45
|
+
"additionalProperties": false,
|
|
46
|
+
"description": "The built-in `bridge_state` datapoint as the cloud observes it right now: whether the bridge is connected, and its latency when it is."
|
|
47
|
+
},
|
|
48
|
+
"published_version": {
|
|
49
|
+
"anyOf": [
|
|
50
|
+
{
|
|
51
|
+
"type": "integer",
|
|
52
|
+
"exclusiveMinimum": 0,
|
|
53
|
+
"maximum": 9007199254740991
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"type": "null"
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
"description": "The published configuration version, or `null` when nothing has been published yet. A robot with nothing published is still listed — \"not configured yet\" is a real state, and the caller is entitled to it — and its datasheet answers an empty exposure list."
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"required": [
|
|
63
|
+
"id",
|
|
64
|
+
"name",
|
|
65
|
+
"created_at",
|
|
66
|
+
"bridge_state",
|
|
67
|
+
"published_version"
|
|
68
|
+
],
|
|
69
|
+
"additionalProperties": false
|
|
70
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"type": "object",
|
|
4
|
+
"properties": {
|
|
5
|
+
"robots": {
|
|
6
|
+
"type": "array",
|
|
7
|
+
"items": {
|
|
8
|
+
"type": "object",
|
|
9
|
+
"properties": {
|
|
10
|
+
"id": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"format": "uuid",
|
|
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 robot, and what every robot-scoped route takes as its `:id`."
|
|
15
|
+
},
|
|
16
|
+
"name": {
|
|
17
|
+
"type": "string",
|
|
18
|
+
"minLength": 1,
|
|
19
|
+
"maxLength": 63,
|
|
20
|
+
"description": "The robot's display name, at most 63 characters. Free text, changed through `PATCH /api/robots/:id`."
|
|
21
|
+
},
|
|
22
|
+
"created_at": {
|
|
23
|
+
"type": "string",
|
|
24
|
+
"format": "date-time",
|
|
25
|
+
"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))$",
|
|
26
|
+
"description": "When the robot was created, as an ISO 8601 timestamp."
|
|
27
|
+
},
|
|
28
|
+
"bridge_state": {
|
|
29
|
+
"type": "object",
|
|
30
|
+
"properties": {
|
|
31
|
+
"online": {
|
|
32
|
+
"type": "boolean"
|
|
33
|
+
},
|
|
34
|
+
"latency_ms": {
|
|
35
|
+
"anyOf": [
|
|
36
|
+
{
|
|
37
|
+
"type": "number",
|
|
38
|
+
"minimum": 0
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"type": "null"
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"required": [
|
|
47
|
+
"online",
|
|
48
|
+
"latency_ms"
|
|
49
|
+
],
|
|
50
|
+
"additionalProperties": false,
|
|
51
|
+
"description": "The built-in `bridge_state` datapoint as the cloud observes it right now: whether the bridge is connected, and its latency when it is."
|
|
52
|
+
},
|
|
53
|
+
"published_version": {
|
|
54
|
+
"anyOf": [
|
|
55
|
+
{
|
|
56
|
+
"type": "integer",
|
|
57
|
+
"exclusiveMinimum": 0,
|
|
58
|
+
"maximum": 9007199254740991
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"type": "null"
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
"description": "The published configuration version, or `null` when nothing has been published yet. A robot with nothing published is still listed — \"not configured yet\" is a real state, and the caller is entitled to it — and its datasheet answers an empty exposure list."
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"required": [
|
|
68
|
+
"id",
|
|
69
|
+
"name",
|
|
70
|
+
"created_at",
|
|
71
|
+
"bridge_state",
|
|
72
|
+
"published_version"
|
|
73
|
+
],
|
|
74
|
+
"additionalProperties": false
|
|
75
|
+
},
|
|
76
|
+
"description": "Every robot the caller reaches, in name order with the id as the tiebreak. An app user reaches the robots their app attaches on which their role grants at least one slug or capability; a server key reaches every robot its app attaches; a developer reaches every robot of the organisation."
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
"required": [
|
|
80
|
+
"robots"
|
|
81
|
+
],
|
|
82
|
+
"additionalProperties": false
|
|
83
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
/**
|
|
4
|
+
* One robot as `GET /api/client/robots` lists it — the REST twin of the MCP
|
|
5
|
+
* tool `robots_list`, and the one robot question no robot-scoped route can
|
|
6
|
+
* answer: which robots may I name at all.
|
|
7
|
+
*
|
|
8
|
+
* Deliberately not `robotListItem`: that one carries `exposes`, the per-kind
|
|
9
|
+
* counts a developer's list shows, which are a configuration fact rather than
|
|
10
|
+
* something an app user's role grants. What an app user is entitled to is the
|
|
11
|
+
* robot, its bridge state, and whether anything is published on it yet.
|
|
12
|
+
*/
|
|
13
|
+
export declare const clientRobotListItem: z.ZodObject<{
|
|
14
|
+
bridge_state: z.ZodObject<{
|
|
15
|
+
online: z.ZodBoolean;
|
|
16
|
+
latency_ms: z.ZodNullable<z.ZodNumber>;
|
|
17
|
+
}, z.core.$strip>;
|
|
18
|
+
published_version: z.ZodNullable<z.ZodNumber>;
|
|
19
|
+
id: z.ZodUUID;
|
|
20
|
+
name: z.ZodString;
|
|
21
|
+
created_at: z.ZodISODateTime;
|
|
22
|
+
}, z.core.$strip>;
|
|
23
|
+
export type ClientRobotListItem = z.infer<typeof clientRobotListItem>;
|
|
24
|
+
/** What `GET /api/client/robots` answers. Never null: a caller who reaches nothing gets an empty array, and an absent key would make "nothing" and "not answered" the same reading. */
|
|
25
|
+
export declare const clientRobotListResponse: z.ZodObject<{
|
|
26
|
+
robots: z.ZodArray<z.ZodObject<{
|
|
27
|
+
bridge_state: z.ZodObject<{
|
|
28
|
+
online: z.ZodBoolean;
|
|
29
|
+
latency_ms: z.ZodNullable<z.ZodNumber>;
|
|
30
|
+
}, z.core.$strip>;
|
|
31
|
+
published_version: z.ZodNullable<z.ZodNumber>;
|
|
32
|
+
id: z.ZodUUID;
|
|
33
|
+
name: z.ZodString;
|
|
34
|
+
created_at: z.ZodISODateTime;
|
|
35
|
+
}, z.core.$strip>>;
|
|
36
|
+
}, z.core.$strip>;
|
|
37
|
+
export type ClientRobotListResponse = z.infer<typeof clientRobotListResponse>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { bridgeState } from './protocol.js';
|
|
4
|
+
import { robot } from './rest.js';
|
|
5
|
+
/* ------------------------------------------ the robots an app user reaches */
|
|
6
|
+
/**
|
|
7
|
+
* One robot as `GET /api/client/robots` lists it — the REST twin of the MCP
|
|
8
|
+
* tool `robots_list`, and the one robot question no robot-scoped route can
|
|
9
|
+
* answer: which robots may I name at all.
|
|
10
|
+
*
|
|
11
|
+
* Deliberately not `robotListItem`: that one carries `exposes`, the per-kind
|
|
12
|
+
* counts a developer's list shows, which are a configuration fact rather than
|
|
13
|
+
* something an app user's role grants. What an app user is entitled to is the
|
|
14
|
+
* robot, its bridge state, and whether anything is published on it yet.
|
|
15
|
+
*/
|
|
16
|
+
export const clientRobotListItem = z.object({
|
|
17
|
+
...robot.shape,
|
|
18
|
+
bridge_state: bridgeState.meta({
|
|
19
|
+
description: 'The built-in `bridge_state` datapoint as the cloud observes it right now: whether the bridge is connected, and its latency when it is.',
|
|
20
|
+
}),
|
|
21
|
+
published_version: z.number().int().positive().nullable().meta({
|
|
22
|
+
description: 'The published configuration version, or `null` when nothing has been published yet. A robot with nothing published is still listed — "not configured yet" is a real state, and the caller is entitled to it — and its datasheet answers an empty exposure list.',
|
|
23
|
+
}),
|
|
24
|
+
});
|
|
25
|
+
/** What `GET /api/client/robots` answers. Never null: a caller who reaches nothing gets an empty array, and an absent key would make "nothing" and "not answered" the same reading. */
|
|
26
|
+
export const clientRobotListResponse = z.object({
|
|
27
|
+
robots: z.array(clientRobotListItem).meta({
|
|
28
|
+
description: 'Every robot the caller reaches, in name order with the id as the tiebreak. An app user reaches the robots their app attaches on which their role grants at least one slug or capability; a server key reaches every robot its app attaches; a developer reaches every robot of the organisation.',
|
|
29
|
+
}),
|
|
30
|
+
});
|
package/dist/index.d.ts
CHANGED
|
@@ -35,6 +35,8 @@ export { appIdentifier, app, appListResponse, createAppRequest, updateAppRequest
|
|
|
35
35
|
export type { App, AppListResponse, CreateAppRequest, UpdateAppRequest, ServerKey, ServerKeyListResponse, CreateServerKeyResponse, Role, RoleListResponse, RolePermissions, } from './apps.js';
|
|
36
36
|
export { clientLoginRequest, clientRefreshRequest, clientLogoutRequest, clientRegisterRequest, clientVerifyEmailRequest, clientResendVerificationRequest, clientPasswordResetRequest, clientPasswordResetConfirmRequest, clientAcceptInvitationRequest, CLIENT_OIDC_CALLBACK_PATH, clientProviderListQuery, clientProviderListResponse, clientOidcStartQuery, clientOidcCallbackQuery, clientOidcExchangeRequest, clientOidcErrorCode, clientMcpInteraction, clientMcpInteractionDecisionResponse, mcpConsentGrant, mcpConsentGrantListResponse, clientIdentity, } from './client-auth.js';
|
|
37
37
|
export type { ClientLoginRequest, ClientRefreshRequest, ClientLogoutRequest, ClientRegisterRequest, ClientVerifyEmailRequest, ClientResendVerificationRequest, ClientPasswordResetRequest, ClientPasswordResetConfirmRequest, ClientAcceptInvitationRequest, ClientProviderListQuery, ClientProviderListResponse, ClientOidcStartQuery, ClientOidcCallbackQuery, ClientOidcExchangeRequest, ClientOidcErrorCode, ClientMcpInteraction, ClientMcpInteractionDecisionResponse, McpConsentGrant, McpConsentGrantListResponse, ClientIdentity, } from './client-auth.js';
|
|
38
|
+
export { clientRobotListItem, clientRobotListResponse } from './client-robots.js';
|
|
39
|
+
export type { ClientRobotListItem, ClientRobotListResponse } from './client-robots.js';
|
|
38
40
|
export { APP_USER_DISPLAY_NAME_MAX, APP_URL_PLACEHOLDERS, MAIL_TEMPLATE_VARIABLES, DEFAULT_MAIL_TEMPLATES, providerSlug, appUserStatus, appUser, appUserListResponse, createAppUserRequest, patchAppUserRequest, createAppInvitationRequest, appInvitation, pendingAppInvitation, appInvitationListResponse, appOidcProvider, appOidcProviderListResponse, createAppOidcProviderRequest, patchAppOidcProviderRequest, appUrlTemplate, allowedOrigin, emailDomain, appAuthConfig, putAppAuthConfigRequest, mailTemplateKind, appMailTemplate, appMailTemplateListResponse, putAppMailTemplateRequest, mailTemplatePreviewRequest, mailTemplatePreviewResponse, mailTemplateProblemDetails, mailOutcome, } from './app-users.js';
|
|
39
41
|
export type { AppUserStatus, AppUser, AppUserListResponse, CreateAppUserRequest, PatchAppUserRequest, CreateAppInvitationRequest, AppInvitation, PendingAppInvitation, AppInvitationListResponse, AppOidcProvider, AppOidcProviderListResponse, CreateAppOidcProviderRequest, PatchAppOidcProviderRequest, AppAuthConfig, PutAppAuthConfigRequest, MailTemplateKind, AppMailTemplate, AppMailTemplateListResponse, PutAppMailTemplateRequest, MailTemplatePreviewRequest, MailTemplatePreviewResponse, MailTemplateProblemDetails, MailOutcome, } from './app-users.js';
|
|
40
42
|
export { assetKind, URDF_ASSET_NAME, asset, urdfCompleteness, assetListResponse, missingAssetQuery, assetSyncRequest, assetSyncResponse, assetSyncState, assetSyncStatus, assetFailure, assetFailureKind, assetTooLargeDetails, assetSyncBusyDetails, ASSET_UPLOAD_MAX_BYTES, } from './assets.js';
|
package/dist/index.js
CHANGED
|
@@ -40,6 +40,7 @@ mailStatus, tierRequiredDetails, passwordChangeRequest, passwordResetRequest, pa
|
|
|
40
40
|
authMeResponse, patchOrgRequest, patchAuthMeRequest, } from './identity.js';
|
|
41
41
|
export { appIdentifier, app, appListResponse, createAppRequest, updateAppRequest, serverKeyToken, serverKey, serverKeyListResponse, createServerKeyResponse, role, roleListResponse, rolePermissions, } from './apps.js';
|
|
42
42
|
export { clientLoginRequest, clientRefreshRequest, clientLogoutRequest, clientRegisterRequest, clientVerifyEmailRequest, clientResendVerificationRequest, clientPasswordResetRequest, clientPasswordResetConfirmRequest, clientAcceptInvitationRequest, CLIENT_OIDC_CALLBACK_PATH, clientProviderListQuery, clientProviderListResponse, clientOidcStartQuery, clientOidcCallbackQuery, clientOidcExchangeRequest, clientOidcErrorCode, clientMcpInteraction, clientMcpInteractionDecisionResponse, mcpConsentGrant, mcpConsentGrantListResponse, clientIdentity, } from './client-auth.js';
|
|
43
|
+
export { clientRobotListItem, clientRobotListResponse } from './client-robots.js';
|
|
43
44
|
// The per-app identity space.
|
|
44
45
|
export { APP_USER_DISPLAY_NAME_MAX, APP_URL_PLACEHOLDERS, MAIL_TEMPLATE_VARIABLES, DEFAULT_MAIL_TEMPLATES, providerSlug, appUserStatus, appUser, appUserListResponse, createAppUserRequest, patchAppUserRequest, createAppInvitationRequest, appInvitation, pendingAppInvitation, appInvitationListResponse, appOidcProvider, appOidcProviderListResponse, createAppOidcProviderRequest, patchAppOidcProviderRequest, appUrlTemplate, allowedOrigin, emailDomain, appAuthConfig, putAppAuthConfigRequest, mailTemplateKind, appMailTemplate, appMailTemplateListResponse, putAppMailTemplateRequest, mailTemplatePreviewRequest, mailTemplatePreviewResponse, mailTemplateProblemDetails, mailOutcome, } from './app-users.js';
|
|
45
46
|
export { assetKind, URDF_ASSET_NAME, asset, urdfCompleteness, assetListResponse, missingAssetQuery, assetSyncRequest, assetSyncResponse, assetSyncState, assetSyncStatus, assetFailure, assetFailureKind, assetTooLargeDetails, assetSyncBusyDetails, ASSET_UPLOAD_MAX_BYTES, } from './assets.js';
|
package/dist/mcp.d.ts
CHANGED
|
@@ -169,7 +169,12 @@ export declare const mcpCapabilities: z.ZodObject<{
|
|
|
169
169
|
assets: z.ZodBoolean;
|
|
170
170
|
}, z.core.$strip>;
|
|
171
171
|
export type McpCapabilities = z.infer<typeof mcpCapabilities>;
|
|
172
|
-
/**
|
|
172
|
+
/**
|
|
173
|
+
* What one caller may do on one robot — the answer to `robot_describe`, and
|
|
174
|
+
* since 1.1.0 to `GET /api/robots/:id/datasheet` as well. One schema for both
|
|
175
|
+
* surfaces on purpose: an app and an AI tool read the same description of the
|
|
176
|
+
* same grant. The `mcp` prefix is history, not scope.
|
|
177
|
+
*/
|
|
173
178
|
export declare const mcpRobotDatasheet: z.ZodObject<{
|
|
174
179
|
robot_id: z.ZodUUID;
|
|
175
180
|
robot_name: z.ZodString;
|
package/dist/mcp.js
CHANGED
|
@@ -124,7 +124,12 @@ export const mcpCapabilities = z.object({
|
|
|
124
124
|
action_history: z.boolean(),
|
|
125
125
|
assets: z.boolean(),
|
|
126
126
|
});
|
|
127
|
-
/**
|
|
127
|
+
/**
|
|
128
|
+
* What one caller may do on one robot — the answer to `robot_describe`, and
|
|
129
|
+
* since 1.1.0 to `GET /api/robots/:id/datasheet` as well. One schema for both
|
|
130
|
+
* surfaces on purpose: an app and an AI tool read the same description of the
|
|
131
|
+
* same grant. The `mcp` prefix is history, not scope.
|
|
132
|
+
*/
|
|
128
133
|
export const mcpRobotDatasheet = z.object({
|
|
129
134
|
robot_id: z.uuid(),
|
|
130
135
|
robot_name: z.string().min(1).max(200),
|
package/dist/realtime.d.ts
CHANGED
|
@@ -254,8 +254,8 @@ export type DatapointEvent = z.infer<typeof datapointEvent>;
|
|
|
254
254
|
*/
|
|
255
255
|
export declare const liveSessionEndReason: z.ZodEnum<{
|
|
256
256
|
unknown: "unknown";
|
|
257
|
-
robot_offline: "robot_offline";
|
|
258
257
|
publish_failed: "publish_failed";
|
|
258
|
+
robot_offline: "robot_offline";
|
|
259
259
|
released_by_peer: "released_by_peer";
|
|
260
260
|
config_changed: "config_changed";
|
|
261
261
|
revoked: "revoked";
|
|
@@ -285,8 +285,8 @@ export declare const liveSessionEvent: z.ZodObject<{
|
|
|
285
285
|
state: z.ZodLiteral<"ended">;
|
|
286
286
|
reason: z.ZodEnum<{
|
|
287
287
|
unknown: "unknown";
|
|
288
|
-
robot_offline: "robot_offline";
|
|
289
288
|
publish_failed: "publish_failed";
|
|
289
|
+
robot_offline: "robot_offline";
|
|
290
290
|
released_by_peer: "released_by_peer";
|
|
291
291
|
config_changed: "config_changed";
|
|
292
292
|
revoked: "revoked";
|
package/dist/routes.js
CHANGED
|
@@ -4,10 +4,11 @@ import { alertListResponse, orgAlertsQuery, orgFiringAlertsResponse } from './al
|
|
|
4
4
|
import { asset, assetListResponse, assetSyncRequest, assetSyncResponse, assetSyncStatus, missingAssetQuery } from './assets.js';
|
|
5
5
|
import { auditListResponse, auditQuery } from './audit.js';
|
|
6
6
|
import { CLIENT_OIDC_CALLBACK_PATH, clientAcceptInvitationRequest, clientIdentity, clientLoginRequest, clientLogoutRequest, clientMcpInteraction, clientMcpInteractionDecisionResponse, clientOidcCallbackQuery, clientOidcExchangeRequest, clientOidcStartQuery, clientPasswordResetConfirmRequest, clientPasswordResetRequest, clientProviderListQuery, clientProviderListResponse, clientRefreshRequest, clientRegisterRequest, clientResendVerificationRequest, clientVerifyEmailRequest, mcpConsentGrantListResponse, } from './client-auth.js';
|
|
7
|
+
import { clientRobotListResponse } from './client-robots.js';
|
|
7
8
|
import { appAuthConfig, appInvitation, appInvitationListResponse, appMailTemplate, appMailTemplateListResponse, appOidcProvider, appOidcProviderListResponse, appUser, appUserListResponse, createAppInvitationRequest, createAppOidcProviderRequest, createAppUserRequest, mailOutcome, mailTemplatePreviewRequest, mailTemplatePreviewResponse, patchAppOidcProviderRequest, patchAppUserRequest, putAppAuthConfigRequest, putAppMailTemplateRequest, } from './app-users.js';
|
|
8
9
|
import { acceptTeamInviteRequest, authMeResponse, createTeamInviteRequest, fleetlessUser, fleetlessUserListResponse, passwordChangeRequest, passwordResetConfirm, passwordResetRequest, patchAuthMeRequest, patchFleetlessUserRequest, patchOrgRequest, patchOrgResponse, pendingTeamInviteListResponse, refreshRequest, sessionTokens, signUpRequest, signUpResponse, teamInvite, tierChangeRequest, waitlistRequest, } from './identity.js';
|
|
9
10
|
import { jobRunListResponse, jobRunQuery, jobRunSummary, jobRunSummaryQuery } from './jobs.js';
|
|
10
|
-
import { MCP_APP_PATHS, mcpRolePreviewResponse } from './mcp.js';
|
|
11
|
+
import { MCP_APP_PATHS, mcpRobotDatasheet, mcpRolePreviewResponse } from './mcp.js';
|
|
11
12
|
import { authorizationServerMetadata, dynamicClientRegistrationRequest, dynamicClientRegistrationResponse, oauthAuthorizeQuery, oauthRedirectResponse, oauthTokenRequest, oauthTokenResponse, protectedResourceMetadata, } from './oauth.js';
|
|
12
13
|
import { cameraListResponse, cancelRequest, configDraftResponse, configVersionResponse, configVersionsResponse, createRobotRequest, createRobotResponse, datapointListResponse, datapointValue, exposureListResponse, fetchTypesRequest, fetchTypesResponse, historyQuery, historyResponse, introspectionResponse, invokeOrServiceResponse, invokeRequest, jobResponse, liveSessionResponse, orgHealthQuery, orgLatencyQuery, orgLatencyResponse, orgQuotaUsage, orgUsageQuery, orgUsageResponse, patchRobotRequest, patchRobotResponse, publishConfigResponse, publishRequest, putConfigDraftRequest, putRobotDetailsRequest, putRobotDetailsResponse, releaseLiveQuery, renameSlugRequest, renameSlugResponse, robotDeleteQuery, resourceHealthListResponse, robotDeletionSummary, robotDetailResponse, robotJobsResponse, robotListResponse, slugUsageResponse, snapshotMetaResponse, typesResponse, } from './rest.js';
|
|
13
14
|
export const ROUTE_SECTIONS = [
|
|
@@ -208,6 +209,14 @@ export const ROUTES = [
|
|
|
208
209
|
'and splitting them here would tell a stranger which tokens ever existed. No rate limiter: the GET changes nothing, and the POST it ' +
|
|
209
210
|
'leads to is limited per IP.',
|
|
210
211
|
},
|
|
212
|
+
{
|
|
213
|
+
method: 'GET', path: '/favicon.svg', section: 'client-auth',
|
|
214
|
+
summary: 'Serves the Fleetless icon for the auth portal\'s and the MCP welcome page\'s browser tab.',
|
|
215
|
+
audience: 'internal', auth: 'none', rateLimited: false, ownerTier: false, status: 200,
|
|
216
|
+
params: [], query: null, request: null, response: null, errors: [], transport: 'http',
|
|
217
|
+
notes: 'An SVG, not JSON. Those pages carry a Content-Security-Policy that admits no `data:` image, so the icon is a file on their own ' +
|
|
218
|
+
'origin — the one source `img-src \'self\'` names. Cached for a day: the bytes change when the brand does, not per deploy.',
|
|
219
|
+
},
|
|
211
220
|
{
|
|
212
221
|
method: 'POST', path: '/api/auth/password/reset/confirm', section: 'developer-auth',
|
|
213
222
|
summary: 'Spends a reset token, sets the new password and ends every session of the account.',
|
|
@@ -1750,6 +1759,33 @@ export const ROUTES = [
|
|
|
1750
1759
|
'`404 unknown_datapoint` and a configured one with no sample yet is `404 no_data` — three facts a caller who is entitled to them needs ' +
|
|
1751
1760
|
'told apart. The plane built-ins (`bridge_state`, `robot_details`) answer here too, without appearing in any document.',
|
|
1752
1761
|
},
|
|
1762
|
+
/* ------------------------------------------ discovery: the REST twins of the two MCP tools a session starts from */
|
|
1763
|
+
{
|
|
1764
|
+
method: 'GET', path: '/api/client/robots', section: 'robots',
|
|
1765
|
+
summary: 'Lists the robots the caller reaches, with bridge state and the published configuration version.',
|
|
1766
|
+
audience: 'client', auth: 'developer_or_client', rateLimited: false, ownerTier: false, status: 200,
|
|
1767
|
+
params: [], query: null, request: null, response: clientRobotListResponse,
|
|
1768
|
+
errors: [...CLIENT_GUARD], transport: 'http',
|
|
1769
|
+
notes: '**The REST twin of the MCP tool `robots_list`**, and the one robot question no robot-scoped route can answer: which robots may I name ' +
|
|
1770
|
+
'at all. An app user sees the robots their app attaches on which their role grants at least one slug or capability; a server key sees ' +
|
|
1771
|
+
'every robot its app attaches; a developer bearer sees the organisation\'s robots. Name order, id as the tiebreak. A robot on which the ' +
|
|
1772
|
+
'role grants nothing is absent rather than listed empty — the same answer `robots_list` gives, for the same reason: reach is a grant, ' +
|
|
1773
|
+
'not an attachment. Under `/api/client/` because it names no robot; every robot-scoped read stays under `/api/robots/:id/…`.',
|
|
1774
|
+
},
|
|
1775
|
+
{
|
|
1776
|
+
method: 'GET', path: '/api/robots/:id/datasheet', section: 'robots',
|
|
1777
|
+
summary: 'Describes everything the caller\'s role lets them do on one robot, with parameter schemas.',
|
|
1778
|
+
audience: 'client', auth: 'developer_or_client', rateLimited: false, ownerTier: false, status: 200,
|
|
1779
|
+
params: [{ name: 'id', description: 'The robot\'s uuid, as `GET /api/client/robots` lists it.' }],
|
|
1780
|
+
query: null, request: null, response: mcpRobotDatasheet,
|
|
1781
|
+
errors: [...CLIENT_GUARD, 'invalid_uuid', 'not_found'], transport: 'http',
|
|
1782
|
+
notes: '**The REST twin of the MCP tool `robot_describe`**: one answer per robot — every datapoint, action, service, publisher and camera the ' +
|
|
1783
|
+
'role grants, each with its `input_schema` where it takes parameters, plus the two capabilities that gate whole features, ' +
|
|
1784
|
+
'`action_history` and `assets`. A robot with nothing published answers an empty `exposures` list, never a refusal. A robot the caller ' +
|
|
1785
|
+
'does not reach — not attached to their app, or attached with a role that grants nothing on it — answers `404` exactly as one that ' +
|
|
1786
|
+
'does not exist. The app-user datapoint and camera listings under this prefix stay; this is the one read that also names actions, ' +
|
|
1787
|
+
'services, publishers and capabilities, which is what an app needs before it can draw a screen.',
|
|
1788
|
+
},
|
|
1753
1789
|
/* ------------------------------------------------- config (draft/publish) */
|
|
1754
1790
|
{
|
|
1755
1791
|
method: 'GET', path: '/api/robots/:id/config/draft', section: 'config',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fleetless/contracts",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.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",
|