@fleetless/sdk 3.1.1 → 4.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.cts CHANGED
@@ -74,14 +74,20 @@ type McpRobotDatasheet = z.infer<typeof mcpRobotDatasheet>;
74
74
  * 1. **State is observed by slug, not by id.** The id is informative; a client
75
75
  * watches `robot × slug` and sees whatever job is running there, which is
76
76
  * also why every observer of a slug sees the same job.
77
- * 2. **`lost` is a real outcome and must be said out loud.** Job state
78
- * lives only in the bridge's memory; if it restarts mid-job, the results
79
- * are gone. The cloud then marks the job `lost` — never leaves it reading
80
- * "running" because nobody contradicted it. A system that reports a
81
- * machine is still working when it does not know is worse than one that
82
- * admits it lost track.
77
+ * 2. **What the cloud does not know it calls `unknown`, and `lost` is final.**
78
+ * A job whose robot went quiet — offline past `JOB_OFFLINE_GRACE_MS`, or
79
+ * connected but silent past `JOB_HEARTBEAT_TIMEOUT_MS` — is `unknown`: not
80
+ * terminal, the slug stays occupied, and only a statement of the bridge
81
+ * resolves it (it is running, it ended, or the bridge does not know it and
82
+ * nothing else runs on its action). `lost` is what that last statement
83
+ * produces, and nothing ever leaves it. Neither is left reading "running"
84
+ * because nobody contradicted it: a system that reports a machine is still
85
+ * working when it does not know is worse than one that says so — and one
86
+ * that declares work lost on a guess is wrong the moment the robot comes
87
+ * back and says it finished.
83
88
  */
84
89
  declare const jobState: z.ZodEnum<{
90
+ unknown: "unknown";
85
91
  failed: "failed";
86
92
  running: "running";
87
93
  succeeded: "succeeded";
@@ -89,17 +95,42 @@ declare const jobState: z.ZodEnum<{
89
95
  lost: "lost";
90
96
  }>;
91
97
  type JobState = z.infer<typeof jobState>;
98
+ /**
99
+ * Who started a job.
100
+ *
101
+ * `fleetless` for every job the cloud minted from an invocation. `external`
102
+ * for a goal the bridge found active on a published action without having
103
+ * sent it — started by anyone else on the robot's ROS graph, or the bridge's
104
+ * own goal after its mapping was lost. An external job has the same shape,
105
+ * states, live stream and cancel as any other, but no parameters (ROS 2
106
+ * publishes a goal's request nowhere), no starter, and it lives in memory
107
+ * only: it is never written to `job_runs` and never counts towards quotas.
108
+ */
109
+ declare const jobOrigin: z.ZodEnum<{
110
+ fleetless: "fleetless";
111
+ external: "external";
112
+ }>;
113
+ type JobOrigin = z.infer<typeof jobOrigin>;
114
+ /**
115
+ * One job, as the cloud tells every client about it — a Fleetless job or an
116
+ * external goal alike, told apart only by `origin`.
117
+ */
92
118
  declare const job: z.ZodObject<{
93
119
  id: z.ZodUUID;
94
120
  robot_id: z.ZodUUID;
95
121
  slug: z.ZodString;
96
122
  state: z.ZodEnum<{
123
+ unknown: "unknown";
97
124
  failed: "failed";
98
125
  running: "running";
99
126
  succeeded: "succeeded";
100
127
  cancelled: "cancelled";
101
128
  lost: "lost";
102
129
  }>;
130
+ origin: z.ZodEnum<{
131
+ fleetless: "fleetless";
132
+ external: "external";
133
+ }>;
103
134
  started_at: z.ZodISODateTime;
104
135
  updated_at: z.ZodISODateTime;
105
136
  seq: z.ZodNumber;
@@ -129,12 +160,17 @@ declare const jobEvent: z.ZodObject<{
129
160
  robot_id: z.ZodUUID;
130
161
  slug: z.ZodString;
131
162
  state: z.ZodEnum<{
163
+ unknown: "unknown";
132
164
  failed: "failed";
133
165
  running: "running";
134
166
  succeeded: "succeeded";
135
167
  cancelled: "cancelled";
136
168
  lost: "lost";
137
169
  }>;
170
+ origin: z.ZodEnum<{
171
+ fleetless: "fleetless";
172
+ external: "external";
173
+ }>;
138
174
  started_at: z.ZodISODateTime;
139
175
  updated_at: z.ZodISODateTime;
140
176
  seq: z.ZodNumber;
@@ -153,6 +189,11 @@ type JobEvent = z.infer<typeof jobEvent>;
153
189
  /**
154
190
  * What a busy refusal tells the caller: what is already running. A refusal that
155
191
  * only says "busy" forces the caller to guess whether to wait or to give up.
192
+ *
193
+ * `running` is whatever occupies the slug — a `running` job, an `unknown` one
194
+ * the robot has not accounted for yet, or an `external` goal someone else
195
+ * started — and its `state` and `origin` say which, so a caller can tell
196
+ * "wait for it" from "cancel what someone else started".
156
197
  */
157
198
  declare const busyDetails: z.ZodObject<{
158
199
  running: z.ZodObject<{
@@ -160,12 +201,17 @@ declare const busyDetails: z.ZodObject<{
160
201
  robot_id: z.ZodUUID;
161
202
  slug: z.ZodString;
162
203
  state: z.ZodEnum<{
204
+ unknown: "unknown";
163
205
  failed: "failed";
164
206
  running: "running";
165
207
  succeeded: "succeeded";
166
208
  cancelled: "cancelled";
167
209
  lost: "lost";
168
210
  }>;
211
+ origin: z.ZodEnum<{
212
+ fleetless: "fleetless";
213
+ external: "external";
214
+ }>;
169
215
  started_at: z.ZodISODateTime;
170
216
  updated_at: z.ZodISODateTime;
171
217
  seq: z.ZodNumber;
@@ -194,6 +240,7 @@ declare const jobRun: z.ZodObject<{
194
240
  service: "service";
195
241
  }>;
196
242
  state: z.ZodEnum<{
243
+ unknown: "unknown";
197
244
  failed: "failed";
198
245
  running: "running";
199
246
  succeeded: "succeeded";
@@ -234,6 +281,7 @@ declare const jobRunListResponse: z.ZodObject<{
234
281
  service: "service";
235
282
  }>;
236
283
  state: z.ZodEnum<{
284
+ unknown: "unknown";
237
285
  failed: "failed";
238
286
  running: "running";
239
287
  succeeded: "succeeded";
@@ -352,8 +400,8 @@ declare const historySamplesResponse: z.ZodObject<{
352
400
  }, z.core.$strip>>;
353
401
  truncated: z.ZodBoolean;
354
402
  truncated_by: z.ZodNullable<z.ZodEnum<{
355
- limit: "limit";
356
403
  bytes: "bytes";
404
+ limit: "limit";
357
405
  }>>;
358
406
  }, z.core.$strip>;
359
407
  type HistorySamplesResponse = z.infer<typeof historySamplesResponse>;
@@ -577,6 +625,7 @@ declare const clientRobotListItem: z.ZodObject<{
577
625
  bridge_state: z.ZodObject<{
578
626
  online: z.ZodBoolean;
579
627
  latency_ms: z.ZodNullable<z.ZodNumber>;
628
+ low_bandwidth: z.ZodBoolean;
580
629
  }, z.core.$strip>;
581
630
  published_version: z.ZodNullable<z.ZodNumber>;
582
631
  id: z.ZodUUID;
@@ -593,7 +642,6 @@ declare const asset: z.ZodObject<{
593
642
  urdf: "urdf";
594
643
  mesh: "mesh";
595
644
  texture: "texture";
596
- other: "other";
597
645
  }>;
598
646
  name: z.ZodString;
599
647
  media_type: z.ZodString;
@@ -649,14 +697,16 @@ declare const assetSyncStatus: z.ZodObject<{
649
697
  unresolvable: "unresolvable";
650
698
  upload_failed: "upload_failed";
651
699
  refused: "refused";
652
- too_large: "too_large";
653
700
  }>;
654
701
  details: z.ZodOptional<z.ZodNullable<z.ZodObject<{
655
- limit_bytes: z.ZodNumber;
702
+ store_bytes: z.ZodNumber;
703
+ used_bytes: z.ZodNumber;
656
704
  size_bytes: z.ZodNumber;
657
705
  }, z.core.$strip>>>;
658
706
  }, z.core.$strip>>;
659
707
  reason: z.ZodNullable<z.ZodString>;
708
+ stored: z.ZodNullable<z.ZodNumber>;
709
+ announced: z.ZodNumber;
660
710
  started_at: z.ZodISODateTime;
661
711
  updated_at: z.ZodISODateTime;
662
712
  }, z.core.$strip>;
@@ -669,7 +719,6 @@ declare const assetListResponse: z.ZodObject<{
669
719
  urdf: "urdf";
670
720
  mesh: "mesh";
671
721
  texture: "texture";
672
- other: "other";
673
722
  }>;
674
723
  name: z.ZodString;
675
724
  media_type: z.ZodString;
@@ -693,14 +742,16 @@ declare const assetListResponse: z.ZodObject<{
693
742
  unresolvable: "unresolvable";
694
743
  upload_failed: "upload_failed";
695
744
  refused: "refused";
696
- too_large: "too_large";
697
745
  }>;
698
746
  details: z.ZodOptional<z.ZodNullable<z.ZodObject<{
699
- limit_bytes: z.ZodNumber;
747
+ store_bytes: z.ZodNumber;
748
+ used_bytes: z.ZodNumber;
700
749
  size_bytes: z.ZodNumber;
701
750
  }, z.core.$strip>>>;
702
751
  }, z.core.$strip>>;
703
752
  reason: z.ZodNullable<z.ZodString>;
753
+ stored: z.ZodNullable<z.ZodNumber>;
754
+ announced: z.ZodNumber;
704
755
  started_at: z.ZodISODateTime;
705
756
  updated_at: z.ZodISODateTime;
706
757
  }, z.core.$strip>>;
@@ -716,6 +767,11 @@ declare const assetListResponse: z.ZodObject<{
716
767
  }, z.core.$strip>>;
717
768
  }, z.core.$strip>;
718
769
  urdf_available: z.ZodNullable<z.ZodBoolean>;
770
+ store: z.ZodObject<{
771
+ bytes: z.ZodNumber;
772
+ used_bytes: z.ZodNumber;
773
+ }, z.core.$strip>;
774
+ joint_state_slug: z.ZodNullable<z.ZodString>;
719
775
  }, z.core.$strip>;
720
776
  type AssetListResponse = z.infer<typeof assetListResponse>;
721
777
 
@@ -758,7 +814,7 @@ type ParameterInvalidDetails = z.infer<typeof parameterInvalidDetails>;
758
814
  * list is the shared vocabulary, not a closed set, so a new refusal never
759
815
  * needs a contracts release before it can be reported honestly.
760
816
  */
761
- declare const ERROR_CODES: readonly ["not_found", "validation_error", "bad_request", "unknown_datapoint", "invalid_token", "protocol_mismatch", "invalid_frame", "duplicate_slug", "reserved_slug", "unknown_slug", "unknown_field_path", "unknown_type", "unknown_topic", "invalid_rate", "invalid_range", "config_conflict", "no_data", "robot_offline", "bridge_timeout", "unauthorized", "forbidden", "invalid_credentials", "token_expired", "token_revoked", "email_taken", "identifier_taken", "weak_password", "account_blocked", "busy", "parameter_invalid", "job_lost", "publisher_busy", "unknown_command", "not_subscribable", "camera_offline", "no_snapshot_yet", "live_unavailable", "wrong_kind", "not_recorded", "not_aggregatable", "quota_exceeded", "credential_in_use", "goal_timeout", "robot_in_use", "robot_deletion_partial", "job_queue_full", "invalid_uuid", "rate_limited", "tier_required", "token_spent", "service_timeout", "asset_missing", "asset_too_large", "dynamic_registration_disabled", "client_limit_reached", "idp_unavailable", "mcp_disabled", "tool_not_available", "capability_required", "last_owner", "target_state_conflict", "signup_closed", "draft_not_a_document", "internal_error", "not_cancellable", "unsupported_media_type", "wrong_browser", "invalid_yaml", "unstorable_yaml", "registration_closed", "domain_not_allowed", "email_unverified", "origin_not_allowed", "template_invalid", "provider_disabled", "provider_misconfigured", "invalid_redirect_uri", "interaction_expired"];
817
+ declare const ERROR_CODES: readonly ["not_found", "validation_error", "bad_request", "unknown_datapoint", "invalid_token", "protocol_mismatch", "bridge_too_old", "invalid_frame", "duplicate_slug", "reserved_slug", "unknown_slug", "unknown_field_path", "unknown_type", "unknown_topic", "invalid_rate", "invalid_range", "config_conflict", "no_data", "robot_offline", "bridge_timeout", "unauthorized", "forbidden", "invalid_credentials", "token_expired", "token_revoked", "email_taken", "identifier_taken", "weak_password", "account_blocked", "busy", "parameter_invalid", "cancel_rejected", "job_lost", "job_unknown_to_bridge", "action_server_lost", "action_failed", "goal_rejected", "goal_send_failed", "result_failed", "goal_uncontrollable", "bridge_disconnected", "config_changed", "publisher_busy", "unknown_command", "not_subscribable", "camera_offline", "no_snapshot_yet", "live_unavailable", "wrong_kind", "not_recorded", "not_aggregatable", "quota_exceeded", "credential_in_use", "goal_timeout", "robot_in_use", "robot_deletion_partial", "job_queue_full", "invalid_uuid", "rate_limited", "tier_required", "token_spent", "service_timeout", "asset_missing", "dynamic_registration_disabled", "client_limit_reached", "idp_unavailable", "mcp_disabled", "tool_not_available", "capability_required", "last_owner", "target_state_conflict", "signup_closed", "draft_not_a_document", "internal_error", "not_cancellable", "unsupported_media_type", "wrong_browser", "invalid_yaml", "unstorable_yaml", "registration_closed", "domain_not_allowed", "email_unverified", "origin_not_allowed", "template_invalid", "provider_disabled", "provider_misconfigured", "invalid_redirect_uri", "interaction_expired"];
762
818
  type ErrorCode = (typeof ERROR_CODES)[number];
763
819
 
764
820
  /**
@@ -912,6 +968,34 @@ declare class FleetlessError extends Error {
912
968
  constructor(code: FleetlessErrorCode, message: string, options?: FleetlessErrorOptions);
913
969
  }
914
970
 
971
+ /**
972
+ * Supplies the `Authorization` header value for a request, and knows what to
973
+ * do when the server says the token has expired. `HttpClient` is agnostic to
974
+ * *what* is authenticating it — an end-user session with silent refresh, or
975
+ * a static server key — so both can share one request path.
976
+ */
977
+ interface CredentialSource {
978
+ /**
979
+ * The current raw bearer credential — a JWT or a server key (`flk_...`) —
980
+ * or null if not authenticated. Raw, not `Bearer <token>`: REST forms the
981
+ * `Authorization` header from it, and the realtime auth frame
982
+ * carries the very same value unprefixed, so there is exactly one place
983
+ * that knows what "the token" currently is.
984
+ */
985
+ token(): Promise<string | null>;
986
+ /**
987
+ * Called once when a request comes back `token_expired`. Three outcomes:
988
+ * - resolves `true` — a fresh credential is ready, retry the request;
989
+ * - resolves `false` — nothing to do (e.g. a server key, which cannot be
990
+ * refreshed at all), propagate the original `token_expired`;
991
+ * - throws a `FleetlessError` — refreshing itself failed for a specific,
992
+ * more useful reason (e.g. `token_revoked`, a reused refresh token);
993
+ * that error propagates instead of the original `token_expired`, so the
994
+ * caller learns what actually happened, not just that a retry was tried.
995
+ */
996
+ handleExpired(): Promise<boolean>;
997
+ }
998
+
915
999
  /**
916
1000
  * The options every realtime command accepts — `actions.cancel` and
917
1001
  * `publishers.publish` take exactly these; `InvokeOptions` extends them for
@@ -1023,6 +1107,25 @@ interface ActionsApi {
1023
1107
  * was nothing there", and "I stopped a job that started after I last
1024
1108
  * looked" are three different outcomes a discarded result cannot tell
1025
1109
  * apart.
1110
+ *
1111
+ * **Resolving means the robot's action server accepted the cancel, not
1112
+ * that the goal ended.** The returned job is usually still `running`; how
1113
+ * it ends arrives as its own update (`subscribe`). The platform answers
1114
+ * from the action server's `CancelGoal` return codes, so a cancel can
1115
+ * also reject with:
1116
+ * - `cancel_rejected` — the server refused (`ERROR_REJECTED`) and the goal
1117
+ * keeps running unless its job later says otherwise. `error.details.goals`
1118
+ * lists every goal the cancel reached as `{ job_id, goal_id, return_code }`
1119
+ * (`0` accepted, `1` rejected, `2` unknown goal, `3` already ended, `null`
1120
+ * when that goal's server did not answer).
1121
+ * - `bridge_timeout` — the robot's bridge did not answer in time; whether
1122
+ * the cancel reached the server is unknown.
1123
+ * - the bridge's own code when it could not ask at all (e.g.
1124
+ * `unknown_slug`, `action_server_lost`), `not_cancellable` for a service,
1125
+ * and `robot_offline`.
1126
+ *
1127
+ * Cancelling an `unknown` job cancels every `external` goal on its action,
1128
+ * never another of the platform's own jobs.
1026
1129
  */
1027
1130
  cancel(robotId: string, slug: string, jobId?: string | null, options?: SendCommandOptions): Promise<Job | null>;
1028
1131
  /**
@@ -2051,7 +2154,7 @@ interface DatapointsApi {
2051
2154
  interface JobHistoryOptions {
2052
2155
  /** Only runs of this action or service. */
2053
2156
  slug?: string;
2054
- /** Only runs in this state: `running`, `succeeded`, `failed`, `cancelled` or `lost`. */
2157
+ /** Only runs in this state: `running`, `unknown`, `succeeded`, `failed`, `cancelled` or `lost`. */
2055
2158
  state?: JobState;
2056
2159
  /** Only `action` runs, or only `service` runs. */
2057
2160
  kind?: 'action' | 'service';
@@ -2253,6 +2356,25 @@ interface FleetlessClientOptions {
2253
2356
  * with a server key never calls `auth.login`/`auth.logout`.
2254
2357
  */
2255
2358
  serverKey?: string;
2359
+ /**
2360
+ * **A credential this client does not own.** The caller answers both
2361
+ * questions a bearer raises: what the token is right now (`token()`), and
2362
+ * what to do when the server says it expired (`handleExpired()`).
2363
+ *
2364
+ * For an embedder that already holds a session and refreshes it itself —
2365
+ * the Fleetless console is the case this exists for. Without it such a
2366
+ * caller had to impersonate a `TokenStore`, and a cloud-side
2367
+ * `token_expired` arriving while its own clock still read live posted one
2368
+ * empty refresh whose `validation_error` had to be translated back into a
2369
+ * session message. A source that answers `handleExpired: false` never
2370
+ * builds a refresh request at all.
2371
+ *
2372
+ * Mutually exclusive with `tokenStore` and `serverKey`, which each own a
2373
+ * credential of their own; a client acts as exactly one identity.
2374
+ * `auth.login`/`auth.logout` refuse here for the same reason they refuse
2375
+ * on a server key: there is no session for this client to start or end.
2376
+ */
2377
+ credentials?: CredentialSource;
2256
2378
  /** Injectable for tests, or a non-global `fetch` implementation. */
2257
2379
  fetch?: typeof fetch;
2258
2380
  /** Injectable for tests, or a non-global `WebSocket` implementation. */
@@ -2322,12 +2444,14 @@ interface FleetlessClient {
2322
2444
  * Builds a client for one app. Pass `tokenStore` (or nothing — the default
2323
2445
  * keeps the session in memory) for an app-user client that signs in with
2324
2446
  * `auth.login` or a federated provider; pass `serverKey` for a server-side
2325
- * caller that never holds a user session. Passing both throws, because the
2326
- * two are different identities and a client acts as exactly one.
2447
+ * caller that never holds a user session; pass `credentials` when the
2448
+ * embedder already holds the bearer and refreshes it itself. Passing more
2449
+ * than one throws, because each is a different identity and a client acts
2450
+ * as exactly one.
2327
2451
  *
2328
2452
  * Nothing is fetched here: the realtime channel opens on the first
2329
2453
  * subscription and closes on `close()` or `auth.logout()`.
2330
2454
  */
2331
2455
  declare function createClient(options: FleetlessClientOptions): FleetlessClient;
2332
2456
 
2333
- 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 };
2457
+ 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 CredentialSource, 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 JobOrigin, 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 };