@fleetless/sdk 3.0.2 → 3.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/dist/index.d.ts CHANGED
@@ -2,6 +2,68 @@
2
2
  import { z } from 'zod';
3
3
 
4
4
 
5
+ /**
6
+ * One exposure of a robot, as `robot_describe` and the console's per-role
7
+ * preview list it. Every exposure the role grants is listed —
8
+ * a missing `description` is shown as `null`, never used to hide the entry.
9
+ *
10
+ * `input_schema` is a JSON Schema document generated from an action's,
11
+ * service's or publisher's `parameters`; `null` for the other kinds. It is
12
+ * `unknown` for the same reason the retired `mcpToolPreview.input_schema`
13
+ * was: pinning it would mean maintaining a zod description of JSON Schema.
14
+ */
15
+ declare const mcpExposure: z.ZodObject<{
16
+ slug: z.ZodString;
17
+ kind: z.ZodEnum<{
18
+ datapoint: "datapoint";
19
+ action: "action";
20
+ service: "service";
21
+ publisher: "publisher";
22
+ camera: "camera";
23
+ }>;
24
+ description: z.ZodNullable<z.ZodString>;
25
+ unit: z.ZodNullable<z.ZodString>;
26
+ decimals: z.ZodNullable<z.ZodNumber>;
27
+ input_schema: z.ZodNullable<z.ZodUnknown>;
28
+ }, z.core.$strip>;
29
+ type McpExposure = z.infer<typeof mcpExposure>;
30
+ /** The two role capabilities a robot tool can need beyond a slug grant. `presence` is a stream and has no tool. */
31
+ declare const mcpCapabilities: z.ZodObject<{
32
+ action_history: z.ZodBoolean;
33
+ assets: z.ZodBoolean;
34
+ }, z.core.$strip>;
35
+ type McpCapabilities = z.infer<typeof mcpCapabilities>;
36
+ /**
37
+ * What one caller may do on one robot — the answer to `robot_describe`, and
38
+ * since 1.1.0 to `GET /api/robots/:id/datasheet` as well. One schema for both
39
+ * surfaces on purpose: an app and an AI tool read the same description of the
40
+ * same grant. The `mcp` prefix is history, not scope.
41
+ */
42
+ declare const mcpRobotDatasheet: z.ZodObject<{
43
+ robot_id: z.ZodUUID;
44
+ robot_name: z.ZodString;
45
+ capabilities: z.ZodObject<{
46
+ action_history: z.ZodBoolean;
47
+ assets: z.ZodBoolean;
48
+ }, z.core.$strip>;
49
+ exposures: z.ZodArray<z.ZodObject<{
50
+ slug: z.ZodString;
51
+ kind: z.ZodEnum<{
52
+ datapoint: "datapoint";
53
+ action: "action";
54
+ service: "service";
55
+ publisher: "publisher";
56
+ camera: "camera";
57
+ }>;
58
+ description: z.ZodNullable<z.ZodString>;
59
+ unit: z.ZodNullable<z.ZodString>;
60
+ decimals: z.ZodNullable<z.ZodNumber>;
61
+ input_schema: z.ZodNullable<z.ZodUnknown>;
62
+ }, z.core.$strip>>;
63
+ }, z.core.$strip>;
64
+ type McpRobotDatasheet = z.infer<typeof mcpRobotDatasheet>;
65
+
66
+
5
67
  /**
6
68
  * Jobs: one running unit of work on a robot — an action
7
69
  * goal or a service call — with an id both sides know, so bridge and cloud
@@ -116,6 +178,94 @@ declare const busyDetails: z.ZodObject<{
116
178
  }, z.core.$strip>;
117
179
  }, z.core.$strip>;
118
180
  type BusyDetails = z.infer<typeof busyDetails>;
181
+ /**
182
+ * One durable record of one invocation. One row per run, never one per event:
183
+ * the per-event timeline's write rate
184
+ * is set by the bridge, and a throttled log that cannot say it was throttled is
185
+ * an instrument that cannot say what it does not know. The live timeline is
186
+ * delivered in full by realtime, for as long as somebody is watching.
187
+ */
188
+ declare const jobRun: z.ZodObject<{
189
+ id: z.ZodUUID;
190
+ robot_id: z.ZodUUID;
191
+ slug: z.ZodString;
192
+ kind: z.ZodEnum<{
193
+ action: "action";
194
+ service: "service";
195
+ }>;
196
+ state: z.ZodEnum<{
197
+ failed: "failed";
198
+ running: "running";
199
+ succeeded: "succeeded";
200
+ cancelled: "cancelled";
201
+ lost: "lost";
202
+ }>;
203
+ started_at: z.ZodISODateTime;
204
+ ended_at: z.ZodNullable<z.ZodISODateTime>;
205
+ duration_ms: z.ZodNullable<z.ZodNumber>;
206
+ result: z.ZodNullable<z.ZodUnknown>;
207
+ error: z.ZodNullable<z.ZodObject<{
208
+ code: z.ZodString;
209
+ message: z.ZodString;
210
+ details: z.ZodOptional<z.ZodUnknown>;
211
+ }, z.core.$strip>>;
212
+ actor: z.ZodObject<{
213
+ kind: z.ZodEnum<{
214
+ developer: "developer";
215
+ server_key: "server_key";
216
+ end_user: "end_user";
217
+ app_user: "app_user";
218
+ }>;
219
+ id: z.ZodUUID;
220
+ label: z.ZodString;
221
+ }, z.core.$strip>;
222
+ seq: z.ZodNumber;
223
+ progress: z.ZodNullable<z.ZodNumber>;
224
+ feedback: z.ZodNullable<z.ZodUnknown>;
225
+ }, z.core.$strip>;
226
+ type JobRun = z.infer<typeof jobRun>;
227
+ declare const jobRunListResponse: z.ZodObject<{
228
+ runs: z.ZodArray<z.ZodObject<{
229
+ id: z.ZodUUID;
230
+ robot_id: z.ZodUUID;
231
+ slug: z.ZodString;
232
+ kind: z.ZodEnum<{
233
+ action: "action";
234
+ service: "service";
235
+ }>;
236
+ state: z.ZodEnum<{
237
+ failed: "failed";
238
+ running: "running";
239
+ succeeded: "succeeded";
240
+ cancelled: "cancelled";
241
+ lost: "lost";
242
+ }>;
243
+ started_at: z.ZodISODateTime;
244
+ ended_at: z.ZodNullable<z.ZodISODateTime>;
245
+ duration_ms: z.ZodNullable<z.ZodNumber>;
246
+ result: z.ZodNullable<z.ZodUnknown>;
247
+ error: z.ZodNullable<z.ZodObject<{
248
+ code: z.ZodString;
249
+ message: z.ZodString;
250
+ details: z.ZodOptional<z.ZodUnknown>;
251
+ }, z.core.$strip>>;
252
+ actor: z.ZodObject<{
253
+ kind: z.ZodEnum<{
254
+ developer: "developer";
255
+ server_key: "server_key";
256
+ end_user: "end_user";
257
+ app_user: "app_user";
258
+ }>;
259
+ id: z.ZodUUID;
260
+ label: z.ZodString;
261
+ }, z.core.$strip>;
262
+ seq: z.ZodNumber;
263
+ progress: z.ZodNullable<z.ZodNumber>;
264
+ feedback: z.ZodNullable<z.ZodUnknown>;
265
+ }, z.core.$strip>>;
266
+ next_cursor: z.ZodNullable<z.ZodNumber>;
267
+ }, z.core.$strip>;
268
+ type JobRunListResponse = z.infer<typeof jobRunListResponse>;
119
269
 
120
270
  /**
121
271
  * The REST read of one datapoint. For bridge-captured data `timestamp_ms`
@@ -413,6 +563,29 @@ declare const clientIdentity: z.ZodObject<{
413
563
  type ClientIdentity = z.infer<typeof clientIdentity>;
414
564
 
415
565
 
566
+ /**
567
+ * One robot as `GET /api/client/robots` lists it — the REST twin of the MCP
568
+ * tool `robots_list`, and the one robot question no robot-scoped route can
569
+ * answer: which robots may I name at all.
570
+ *
571
+ * Deliberately not `robotListItem`: that one carries `exposes`, the per-kind
572
+ * counts a developer's list shows, which are a configuration fact rather than
573
+ * something an app user's role grants. What an app user is entitled to is the
574
+ * robot, its bridge state, and whether anything is published on it yet.
575
+ */
576
+ declare const clientRobotListItem: z.ZodObject<{
577
+ bridge_state: z.ZodObject<{
578
+ online: z.ZodBoolean;
579
+ latency_ms: z.ZodNullable<z.ZodNumber>;
580
+ }, z.core.$strip>;
581
+ published_version: z.ZodNullable<z.ZodNumber>;
582
+ id: z.ZodUUID;
583
+ name: z.ZodString;
584
+ created_at: z.ZodISODateTime;
585
+ }, z.core.$strip>;
586
+ type ClientRobotListItem = z.infer<typeof clientRobotListItem>;
587
+
588
+
416
589
  declare const asset: z.ZodObject<{
417
590
  id: z.ZodUUID;
418
591
  robot_id: z.ZodUUID;
@@ -555,10 +728,10 @@ type AssetListResponse = z.infer<typeof assetListResponse>;
555
728
  * console renders a third, and each is right in its own tests.
556
729
  *
557
730
  * `field` is the **flat key exactly as the caller sent it** — the same string
558
- * as the `parameterSpec.name` it violated. That is the entire justification
559
- * for the flat parameter form: a refusal has to name something the caller can
560
- * find in what they typed, and a console can attach the error to that one
561
- * input rather than to the form.
731
+ * as the `parameterSpec.name` it violated. That is why the parameter form
732
+ * stays flat: a refusal has to name something the caller can find in what
733
+ * they typed, and a console can attach the error to that one input rather
734
+ * than to the form.
562
735
  */
563
736
  declare const parameterViolation: z.ZodObject<{
564
737
  field: z.ZodString;
@@ -607,13 +780,13 @@ type ErrorCode = (typeof ERROR_CODES)[number];
607
780
  * later on the same socket — nobody knows — but the caller cannot be made
608
781
  * to wait forever for that.
609
782
  * - `command_outcome_unknown`: worse than a timeout, and told apart from it
610
- * on purpose — the realtime connection that carried the command was
611
- * replaced by a new one (a reconnect) before any reply arrived. A reply
612
- * can now never come: the server, if it answered at all, answered a
613
- * socket that no longer exists. The command may or may not have run.
614
- * Never retried automatically — that could run an action twice — the
615
- * caller recovers by reading the job (e.g. `actions.subscribe`), since
616
- * state is observed by slug regardless of which connection asked for it.
783
+ * on purpose — the connection that carried the command was replaced by a
784
+ * new one (a reconnect) before any reply arrived. The server, if it
785
+ * answered at all, answered a socket that no longer exists, so the
786
+ * command may or may not have run. Never retried automatically — that
787
+ * could run an action twice — the caller recovers by reading the job
788
+ * (e.g. `actions.subscribe`), since state is observed by slug regardless
789
+ * of which connection asked for it.
617
790
  * - `unexpected_response`: the server answered `ok:true` but left out
618
791
  * something the command is defined to always return (e.g. no `job` on a
619
792
  * successful `invoke`) — a contract violation the SDK noticed, not a
@@ -801,20 +974,19 @@ interface JobSubscriptionHandlers {
801
974
  interface JobSubscription {
802
975
  /**
803
976
  * Stops this subscription. The `unsubscribe` frame reaches the server only
804
- * when this was the **last** holder of the robot and slug pair, and only if
805
- * the channel is connected — subscriptions are reference-counted across
806
- * kinds, so releasing this one while a second `actions.subscribe`, a
807
- * `datapoints.subscribe` or an in-flight `services.call` still holds the
808
- * same pair leaves that one's stream running untouched. Safe to call more
809
- * than once.
977
+ * when this was the **last** holder of the robot/slug pair and the channel
978
+ * is connected — subscriptions are reference-counted across kinds, so a
979
+ * second `actions.subscribe`, `datapoints.subscribe` or in-flight
980
+ * `services.call` on the same pair keeps its stream running. Safe to call
981
+ * more than once.
810
982
  */
811
983
  unsubscribe(): void;
812
984
  }
813
985
 
814
986
  /**
815
987
  * Long-running work on a robot, reachable as `client.actions`. An action is
816
- * a ROS action the developer exposed under a slug: it is invoked, it runs
817
- * for as long as it runs, and it reports back while it does.
988
+ * a ROS action the developer exposed under a slug: it is invoked, runs as
989
+ * long as it runs, and reports back while it does.
818
990
  */
819
991
  interface ActionsApi {
820
992
  /**
@@ -822,7 +994,7 @@ interface ActionsApi {
822
994
  * — the job id is informative, not the result. Feedback, progress and the
823
995
  * eventual result arrive separately over `subscribe`. A second invoke of
824
996
  * the same slug while one is already running is refused `busy`, with
825
- * `error.details.running` naming the job that is running.
997
+ * `error.details.running` naming the running job.
826
998
  *
827
999
  * `options.patienceMs` bounds goal *acceptance* only — once a goal
828
1000
  * is accepted this call has already resolved; the job then runs as long
@@ -1106,7 +1278,7 @@ interface AssetsApi {
1106
1278
  * **Do not also install `createMeshLoader` on the same manager.** The two
1107
1279
  * consume different URDF sources — this method fetches the URDF's *raw*
1108
1280
  * bytes, `createMeshLoader` is meant to pair with `urdf()`'s
1109
- * cloud-rewritten text. **It is not that every mesh gets fetched twice.**
1281
+ * cloud-rewritten text. **Not a double-fetch.**
1110
1282
  * What actually happens is asymmetric breakage,
1111
1283
  * whichever URDF text the combination ends up parsing: paired with
1112
1284
  * *this* method's raw text, `createMeshLoader` receives urdf-loader's
@@ -1236,7 +1408,7 @@ interface TokenStore {
1236
1408
  /** The default store: works out of the box, forgets the session on reload. */
1237
1409
  declare class InMemoryTokenStore implements TokenStore {
1238
1410
  #private;
1239
- /** Creates an empty store. Nothing is loaded from anywhere — a client built with it starts logged out. */
1411
+ /** Nothing is loaded from anywhere — a client built with it starts logged out. */
1240
1412
  constructor();
1241
1413
  /** Returns the session held in memory, or `null` if there is none. */
1242
1414
  load(): StoredSession | null;
@@ -1680,8 +1852,8 @@ interface CameraLiveSession {
1680
1852
  * courteous fast path; the robot actually stops publishing once every
1681
1853
  * viewer's LiveKit `Room` has disconnected, which the SFU notices on its
1682
1854
  * own with no cooperation required. **Always pair this with disconnecting
1683
- * the `Room` you connected with `url`/`token`** — see the README's
1684
- * Cameras section for the paired cleanup pattern; a `release()` that ran
1855
+ * the `Room` you connected with `url`/`token`** — see the Cameras
1856
+ * section of the SDK reference for the paired cleanup pattern; a `release()` that ran
1685
1857
  * alone while the `Room` stayed connected would stop nothing.
1686
1858
  *
1687
1859
  * Safe to call more than once (only the first call does anything) and
@@ -1692,14 +1864,12 @@ interface CameraLiveSession {
1692
1864
  * from `beforeunload`, where a call that could throw would be a liability.
1693
1865
  *
1694
1866
  * **A failed DELETE here is not observable anywhere** — not as a
1695
- * rejection, not as a realtime event, not as a field on this object. This
1696
- * is a deliberate decision, not an oversight: the only
1697
- * consumer of that information would be code deciding whether to retry,
1698
- * and the backstop this comment already describes — the cloud's own
1699
- * LiveKit-participation reconciliation — makes a retry unnecessary for
1700
- * correctness. If a future caller needs to know "did my release actually
1701
- * reach the cloud" (telemetry, say), that is a new, additive signal to
1702
- * design, not a change to this method's contract.
1867
+ * rejection, a realtime event, or a field on this object. Deliberate, not
1868
+ * an oversight: the only consumer of that information would be code
1869
+ * deciding whether to retry, and the reconciliation backstop described
1870
+ * above already makes a retry unnecessary for correctness. A future need
1871
+ * to know "did my release actually reach the cloud" (telemetry, say) is a
1872
+ * new, additive signal to design, not a change to this method's contract.
1703
1873
  */
1704
1874
  release(): Promise<void>;
1705
1875
  }
@@ -1753,12 +1923,11 @@ interface DatapointSubscriptionHandlers {
1753
1923
  interface DatapointSubscription {
1754
1924
  /**
1755
1925
  * Stops this subscription. The `unsubscribe` frame reaches the server only
1756
- * when this was the **last** holder of the robot and slug pair, and only if
1757
- * the channel is connected — subscriptions are reference-counted across
1758
- * kinds, so releasing this one while a second `datapoints.subscribe`, an
1759
- * `actions.subscribe` or an in-flight `services.call` still holds the same
1760
- * pair leaves that one's stream running untouched. Safe to call more than
1761
- * once.
1926
+ * when this was the **last** holder of the robot/slug pair and the channel
1927
+ * is connected — subscriptions are reference-counted across kinds, so
1928
+ * releasing this one while a `datapoints.subscribe`, `actions.subscribe` or
1929
+ * in-flight `services.call` still holds the same pair leaves that one's
1930
+ * stream running. Safe to call more than once.
1762
1931
  */
1763
1932
  unsubscribe(): void;
1764
1933
  }
@@ -1766,11 +1935,10 @@ interface DatapointSubscription {
1766
1935
  * Window aggregation for `datapoints.history`. `window` and `agg` always
1767
1936
  * travel together on the wire — the cloud refuses one without the other
1768
1937
  * rather than defaulting either, since a silently chosen aggregation is a
1769
- * chart that lies quietly — so they live in one object here instead of two
1770
- * independent optional fields a caller could set only one of. The same
1771
- * reasoning as `cameraSource` being a discriminated union rather than
1772
- * optional fields: make the impossible combination unrepresentable, not
1773
- * merely rejected.
1938
+ * chart that lies quietly — so they live in one object instead of two
1939
+ * optional fields a caller could set only one of. Same reasoning as
1940
+ * `cameraSource`'s discriminated union: make the impossible combination
1941
+ * unrepresentable, not merely rejected.
1774
1942
  */
1775
1943
  interface HistoryAggregation {
1776
1944
  /** Bucket width, e.g. `10s`, `1m`. */
@@ -1781,9 +1949,8 @@ interface HistoryAggregation {
1781
1949
  field?: string;
1782
1950
  }
1783
1951
  /**
1784
- * The window `datapoints.history` reads, and whether it comes back as raw
1785
- * samples or as aggregated buckets. `aggregate` is what decides which of
1786
- * the two responses you get.
1952
+ * The window `datapoints.history` reads. `aggregate` decides whether the
1953
+ * response is raw samples or aggregated buckets.
1787
1954
  */
1788
1955
  interface HistoryOptions {
1789
1956
  /**
@@ -1823,9 +1990,9 @@ interface DatapointsApi {
1823
1990
  * Reference-counted per `(robotId, slug)`: two subscriptions to the same
1824
1991
  * pair share one wire subscription. Unsubscribing one never affects the
1825
1992
  * other — the `unsubscribe` frame is sent only when the last subscriber
1826
- * on that pair goes away. This matters in practice: two widgets showing
1827
- * the same battery value, or a component mounted twice under React
1828
- * StrictMode, both subscribe to the same key. That count is shared with
1993
+ * on that pair goes away. In practice: two widgets showing the same
1994
+ * battery value, or a component mounted twice under React StrictMode,
1995
+ * subscribe to the same key. That count is shared with
1829
1996
  * `actions.subscribe` and `services.call` — a slug is one namespace across
1830
1997
  * kinds, and so is its subscription.
1831
1998
  */
@@ -1838,10 +2005,9 @@ interface DatapointsApi {
1838
2005
  * reduced by `aggregate.agg`. Leave `aggregate` out and the other overload
1839
2006
  * gives you raw samples instead.
1840
2007
  *
1841
- * Two overloads rather than one union so a caller who already knows which
1842
- * they asked for isn't forced to narrow something they determined
1843
- * themselves. `kind` still carries the same information on both, so code
1844
- * holding the result dynamically can still branch on it.
2008
+ * Two overloads rather than one union, so a caller who already knows which
2009
+ * one they asked for isn't forced to narrow it. `kind` carries the same
2010
+ * information either way, so dynamic code can still branch on it.
1845
2011
  *
1846
2012
  * **Rejects, does not silently empty out, two specific refusals** —
1847
2013
  * unlike `cameras.snapshot`'s absorption of `no_snapshot_yet` into a null
@@ -1875,26 +2041,42 @@ interface DatapointsApi {
1875
2041
  }
1876
2042
 
1877
2043
  /**
1878
- * Robot-wide job reads, reachable as `client.jobs`. Everything here is
1879
- * addressed by robot rather than by slug, which is what `actions` and
1880
- * `services` cannot do.
2044
+ * The filters `jobs.history` reads. Every field is optional; the wire names
2045
+ * are snake_case and this SDK spells them the way its other options are
2046
+ * spelt. `fromMs`/`toMs` are unix milliseconds, a half-open window
2047
+ * `[from, to)` so adjacent windows never both contain the run on their
2048
+ * boundary. `limit` above the platform's page cap is refused with
2049
+ * `validation_error`, not quietly reduced.
2050
+ */
2051
+ interface JobHistoryOptions {
2052
+ slug?: string;
2053
+ state?: JobState;
2054
+ kind?: 'action' | 'service';
2055
+ limit?: number;
2056
+ /** The previous page's `next_cursor`. Send it back rather than computing one. */
2057
+ beforeSeq?: number;
2058
+ fromMs?: number;
2059
+ toMs?: number;
2060
+ }
2061
+ /**
2062
+ * Robot-wide job reads, reachable as `client.jobs` — addressed by robot,
2063
+ * not slug, which `actions` and `services` cannot do.
1881
2064
  */
1882
2065
  interface JobsApi {
1883
2066
  /**
1884
2067
  * Every job the platform currently believes this robot has.
1885
2068
  *
1886
- * `actions.subscribe`/`services.call` and `GET /jobs/:slug` (the per-slug
1887
- * route those build on) all require already knowing the slug. That is not
1888
- * always true: a reconnecting bridge can name a job the cloud only
1889
- * *adopted*, and a configuration change can leave a job on a slug the
1890
- * published document no longer contains. Both are jobs no slug can name,
1891
- * which is exactly what this method is for — an app developer has no
1892
- * other way to reach them.
2069
+ * `actions.subscribe`/`services.call` and `GET /jobs/:slug` — the per-slug
2070
+ * route those build on — all require knowing the slug already. Two cases
2071
+ * don't: a reconnecting bridge naming a job the cloud only *adopted*, and
2072
+ * a config change leaving a job on a slug the published document no
2073
+ * longer contains. Neither has a slug to give — this method is the only
2074
+ * way an app developer reaches them.
1893
2075
  *
1894
- * At most one entry per slug: the current job there, exactly what a
1895
- * per-slug read would answer for that slug. Not a history endpoint.
2076
+ * At most one entry per slug: the current job there, same as a per-slug
2077
+ * read would answer. Not a history endpoint — that is `history` below.
1896
2078
  * Grant-filtered same as `cameras.list`/`datapoints` — an end user or
1897
- * server key sees only jobs on slugs their role grants; a developer
2079
+ * server key sees only jobs on slugs their role grants, a developer
1898
2080
  * session sees every job on the robot. Never empty-vs-missing ambiguity:
1899
2081
  * a robot doing nothing resolves `[]`.
1900
2082
  *
@@ -1909,6 +2091,26 @@ interface JobsApi {
1909
2091
  * hour-long one was only just adopted.
1910
2092
  */
1911
2093
  list(robotId: string): Promise<Job[]>;
2094
+ /**
2095
+ * What *has* run on this robot: one row per run, newest first by the
2096
+ * durable `seq`, with its actor, its outcome and its `duration_ms`, kept
2097
+ * for 90 days. The durable counterpart of `list`.
2098
+ *
2099
+ * **Needs the `action_history` capability** on the caller's role, or it
2100
+ * rejects `capability_required`. An app user sees only runs on the slugs
2101
+ * their role grants; a developer session sees the whole robot.
2102
+ *
2103
+ * **Page until `next_cursor` is `null`, never until a page looks short.**
2104
+ * The cloud applies the role's grants to the page it already read, so a
2105
+ * page can come back thin — or empty — with a perfectly good non-null
2106
+ * cursor behind it. `runs.length === 0` is not an end-of-data signal.
2107
+ *
2108
+ * It lags realtime by a moment, deliberately: a run watched to completion
2109
+ * over `actions.subscribe` can still read `running` here for an instant.
2110
+ * Render the outcome from the realtime job you already have; use this for
2111
+ * what you were not watching.
2112
+ */
2113
+ history(robotId: string, options?: JobHistoryOptions): Promise<JobRunListResponse>;
1912
2114
  }
1913
2115
 
1914
2116
  /**
@@ -1920,16 +2122,15 @@ interface PublishersApi {
1920
2122
  /**
1921
2123
  * Publishes one message to a publisher.
1922
2124
  *
1923
- * This is a plain method call — there is deliberately no deadman switch,
1924
- * rate governor or "takt" helper here. The bridge's own
1925
- * `timeout_ms` failsafe is the platform's safety primitive: if messages
1926
- * stop arriving — including because this process crashed — the bridge
1927
- * publishes the configured failsafe message itself. That does **not**
1928
- * mean the SDK protects a caller who stops calling `publish` on purpose
1929
- * without stopping cleanly (e.g. no repeated call at a safe rate): the
1930
- * safety pattern for *how often* and *when* to publish belongs in the
1931
- * app, not here. See the README's "Publishers, and no teleop helpers"
1932
- * section before building a publisher-driven control loop.
2125
+ * A plain method call — deliberately no deadman switch, rate governor or
2126
+ * "takt" helper. The bridge's own `timeout_ms` failsafe is the platform's
2127
+ * safety primitive: when messages stop arriving, crash included, the
2128
+ * bridge publishes its configured failsafe message. That does **not**
2129
+ * cover a caller who stops calling `publish` on purpose without stopping
2130
+ * cleanly (e.g. no repeated call at a safe rate) — how often and when to
2131
+ * publish is the app's pattern, not the SDK's. See the Publishers
2132
+ * section of the SDK reference before building a
2133
+ * publisher-driven control loop.
1933
2134
  *
1934
2135
  * Rejects `publisher_busy` while a different user is publishing and has
1935
2136
  * not been quiet for its configured quiet timeout yet — whoever publishes
@@ -1938,18 +2139,54 @@ interface PublishersApi {
1938
2139
  publish(robotId: string, slug: string, message: Record<string, unknown>, options?: SendCommandOptions): Promise<void>;
1939
2140
  }
1940
2141
 
2142
+ /**
2143
+ * Discovery, reachable as `client.robots`: which robots may I name at all,
2144
+ * and what may I do on one. The two calls every app screen starts from;
2145
+ * every other namespace takes a `robotId` that came from here.
2146
+ *
2147
+ * The answers are the caller's role made visible — the same rows and the
2148
+ * same datasheet the MCP tools `robots_list` and `robot_describe` answer,
2149
+ * from the same code on the server. There is no client-side filtering to
2150
+ * do and nothing to cache: a role change shows at the next call.
2151
+ */
2152
+ interface RobotsApi {
2153
+ /**
2154
+ * The robots this caller reaches, in name order with the id as the tiebreak.
2155
+ *
2156
+ * An app user reaches the robots their app attaches on which their role
2157
+ * grants at least one slug or capability; a server key reaches every robot
2158
+ * its app attaches. A robot the role grants nothing on is absent rather
2159
+ * than listed empty — reach is a grant, not an attachment — so a new app
2160
+ * whose built-in roles grant nothing yet resolves `[]`, and that is the
2161
+ * console's Roles tab talking, not a broken login.
2162
+ */
2163
+ list(): Promise<ClientRobotListItem[]>;
2164
+ /**
2165
+ * Everything the caller's role lets them do on one robot: every granted
2166
+ * datapoint (with `unit` and `decimals`), action, service and publisher
2167
+ * (with the parameter JSON Schema under `input_schema`) and camera, plus
2168
+ * the two capabilities that gate whole features, `action_history` and
2169
+ * `assets`. A robot with nothing published resolves an empty `exposures`
2170
+ * list. One the caller does not reach rejects `not_found`, exactly as a
2171
+ * robot that does not exist — never `forbidden`, which would say it exists.
2172
+ *
2173
+ * The type is `McpRobotDatasheet` because the MCP server answered it first;
2174
+ * the prefix is history, not scope.
2175
+ */
2176
+ describe(robotId: string): Promise<McpRobotDatasheet>;
2177
+ }
2178
+
1941
2179
  /**
1942
2180
  * Request/response calls to a robot, reachable as `client.services`. A
1943
- * service answers once and is done, which is why this namespace has a
1944
- * single method and nothing to subscribe to.
2181
+ * service answers once and is done — one method, nothing to subscribe to.
1945
2182
  */
1946
2183
  interface ServicesApi {
1947
2184
  /**
1948
2185
  * Calls a service and resolves with its result. A service call is a job
1949
2186
  * underneath — the same `job_id` exchange and disconnect survival as an
1950
2187
  * action — but that is deliberately invisible here: the caller gets a
1951
- * plain `Promise<result>`, matching the REST `serviceCallResponse` shape's
1952
- * developer experience. There is nothing to subscribe to for a service —
2188
+ * plain `Promise<result>`, matching the REST `serviceCallResponse` shape.
2189
+ * There is nothing to subscribe to for a service —
1953
2190
  * no feedback, no progress, no cancel — so this call already waits for
1954
2191
  * the terminal state internally.
1955
2192
  *
@@ -1962,8 +2199,7 @@ interface ServicesApi {
1962
2199
  * call — the ack that a job was created, plus however much of the
1963
2200
  * budget is left for it to then reach a terminal state — not two
1964
2201
  * separate `timeoutMs`-length windows back to back. A caller who sets
1965
- * `timeoutMs: 5000` is bounding total latency at ~5s, not ~10s; the
1966
- * number means what it says, once, for the whole call.
2202
+ * `timeoutMs: 5000` bounds total latency at ~5s, not ~10s.
1967
2203
  *
1968
2204
  * It is also **not independent** of `patienceMs`: left unset, it
1969
2205
  * is derived from `patienceMs` so this SDK's local clock cannot fire
@@ -1986,10 +2222,9 @@ interface FleetlessClientOptions {
1986
2222
  /** The app's identifier (the slug shown in the console), sent on every login. */
1987
2223
  appIdentifier: string;
1988
2224
  /**
1989
- * Where refresh/access tokens are kept between calls. Defaults to an
1990
- * in-memory store — pass your own (localStorage, a cookie, a native
1991
- * keystore) to persist a session across reloads. The SDK never assumes a
1992
- * browser exists.
2225
+ * Where refresh/access tokens live between calls. Defaults to in-memory —
2226
+ * pass your own (localStorage, a cookie, a native keystore) to persist a
2227
+ * session across reloads. The SDK never assumes a browser exists.
1993
2228
  */
1994
2229
  tokenStore?: TokenStore;
1995
2230
  /**
@@ -2050,14 +2285,16 @@ interface FleetlessClient {
2050
2285
  readonly jobs: JobsApi;
2051
2286
  /** URDF and mesh reads — list/get/urdf, plus the `urdf-loader` mesh callback. */
2052
2287
  readonly assets: AssetsApi;
2288
+ /** Which robots this caller reaches, and what their role lets them do on each — the calls every screen starts from. */
2289
+ readonly robots: RobotsApi;
2053
2290
  /**
2054
- * Closes the realtime channel and stops it from reconnecting. Safe to
2055
- * call whether or not any subscription was ever made, and safe to call
2056
- * more than once. A Node script (the exact use case `serverKey` is for)
2057
- * that never calls this after subscribing will not exit on its own — an
2058
- * open WebSocket keeps the event loop alive. `auth.logout()` calls this
2059
- * automatically; call it yourself too if the process should exit without
2060
- * logging out (e.g. a server-side caller shutting down).
2291
+ * Closes the realtime channel and stops it from reconnecting. Safe with
2292
+ * no subscription ever made, and safe to call twice. A Node script (the
2293
+ * exact use case `serverKey` is for) that never calls this after
2294
+ * subscribing will not exit on its own — an open WebSocket keeps the
2295
+ * event loop alive. `auth.logout()` calls this automatically; call it
2296
+ * yourself if the process should exit without logging out (e.g. a
2297
+ * server-side shutdown).
2061
2298
  */
2062
2299
  close(): void;
2063
2300
  }
@@ -2073,4 +2310,4 @@ interface FleetlessClient {
2073
2310
  */
2074
2311
  declare function createClient(options: FleetlessClientOptions): FleetlessClient;
2075
2312
 
2076
- export { type AcceptInvitationOptions, type ActionsApi, type Asset, type AssetBytes, type AssetListResponse, type AssetsApi, type AuthApi, type BeginOidcLoginOptions, type BusyDetails, type CameraDescriptor, type CameraLiveSession, type CameraSnapshot, type CameraSnapshotMeta, type CamerasApi, type ClientIdentity, type ClientMcpInteraction, type ClientOidcErrorCode, type CompleteOidcLoginOptions, type CreateMeshLoaderOptions, type DatapointEvent, type DatapointSubscription, type DatapointSubscriptionHandlers, type DatapointValue, type DatapointsApi, type FleetlessClient, type FleetlessClientConfig, type FleetlessClientOptions, FleetlessError, type FleetlessErrorCode, type FleetlessErrorOptions, type HistoryAggregation, type HistoryBucketsResponse, type HistoryOptions, type HistorySamplesResponse, InMemoryTokenStore, type InvokeOptions, type Job, type JobEvent, type JobState, type JobSubscription, type JobSubscriptionHandlers, type JobsApi, type McpConsentGrant, type McpInteractionDecision, type MeshLoaderDelegate, type OidcLoginRequest, type ParameterInvalidDetails, type ParameterViolation, type PrepareUrdfSceneOptions, type ProviderButton, type PublishersApi, type RateLimitDetails, type RegisterOptions, SDK_ERROR_CODES, type SdkErrorCode, type SendCommandOptions, type ServicesApi, type StoredSession, type TokenStore, type UrdfCompleteness, type UrdfSceneManager, type UrdfSceneResources, createClient, parameterInvalidDetails };
2313
+ export { type AcceptInvitationOptions, type ActionsApi, type Asset, type AssetBytes, type AssetListResponse, type AssetsApi, type AuthApi, type BeginOidcLoginOptions, type BusyDetails, type CameraDescriptor, type CameraLiveSession, type CameraSnapshot, type CameraSnapshotMeta, type CamerasApi, type ClientIdentity, type ClientMcpInteraction, type ClientOidcErrorCode, type ClientRobotListItem, type CompleteOidcLoginOptions, type CreateMeshLoaderOptions, type DatapointEvent, type DatapointSubscription, type DatapointSubscriptionHandlers, type DatapointValue, type DatapointsApi, type FleetlessClient, type FleetlessClientConfig, type FleetlessClientOptions, FleetlessError, type FleetlessErrorCode, type FleetlessErrorOptions, type HistoryAggregation, type HistoryBucketsResponse, type HistoryOptions, type HistorySamplesResponse, InMemoryTokenStore, type InvokeOptions, type Job, type JobEvent, type JobHistoryOptions, type JobRun, type JobRunListResponse, type JobState, type JobSubscription, type JobSubscriptionHandlers, type JobsApi, type McpCapabilities, type McpConsentGrant, type McpExposure, type McpInteractionDecision, type McpRobotDatasheet, type MeshLoaderDelegate, type OidcLoginRequest, type ParameterInvalidDetails, type ParameterViolation, type PrepareUrdfSceneOptions, type ProviderButton, type PublishersApi, type RateLimitDetails, type RegisterOptions, type RobotsApi, SDK_ERROR_CODES, type SdkErrorCode, type SendCommandOptions, type ServicesApi, type StoredSession, type TokenStore, type UrdfCompleteness, type UrdfSceneManager, type UrdfSceneResources, createClient, parameterInvalidDetails };