@fleetless/contracts 1.0.0 → 1.0.2
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 +68 -2
- package/CODE_OF_CONDUCT.md +83 -0
- package/CONTRIBUTING.md +136 -0
- package/README.md +49 -13
- package/SECURITY.md +55 -0
- package/artifacts/openapi.json +1 -1
- package/artifacts/routes.json +1 -1
- package/dist/alerts.d.ts +19 -24
- package/dist/alerts.js +18 -24
- package/dist/app-users.d.ts +7 -6
- package/dist/app-users.js +6 -6
- package/dist/apps.d.ts +21 -25
- package/dist/apps.js +40 -51
- package/dist/assets.d.ts +70 -132
- package/dist/assets.js +130 -223
- package/dist/audit.d.ts +11 -11
- package/dist/audit.js +25 -51
- package/dist/client-auth.d.ts +4 -4
- package/dist/client-auth.js +3 -4
- package/dist/common.d.ts +27 -35
- package/dist/common.js +26 -35
- package/dist/config-issues.d.ts +4 -3
- package/dist/config-issues.js +7 -6
- package/dist/config.d.ts +31 -37
- package/dist/config.js +81 -110
- package/dist/errors.d.ts +4 -3
- package/dist/errors.js +61 -87
- package/dist/identity.d.ts +18 -21
- package/dist/identity.js +17 -21
- package/dist/index.d.ts +4 -4
- package/dist/index.js +12 -13
- package/dist/introspection.d.ts +7 -6
- package/dist/introspection.js +6 -6
- package/dist/jobs.d.ts +12 -12
- package/dist/jobs.js +20 -25
- package/dist/mcp.d.ts +11 -12
- package/dist/mcp.js +10 -12
- package/dist/oauth.d.ts +13 -18
- package/dist/oauth.js +13 -19
- package/dist/protocol.d.ts +51 -62
- package/dist/protocol.js +107 -139
- package/dist/realtime.d.ts +53 -68
- package/dist/realtime.js +77 -103
- package/dist/rest.d.ts +182 -243
- package/dist/rest.js +301 -395
- package/dist/routes.d.ts +4 -3
- package/dist/routes.js +3 -2
- package/package.json +12 -7
package/dist/rest.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
2
|
import { z } from 'zod';
|
|
2
3
|
/**
|
|
3
|
-
* REST shapes of the robot resource
|
|
4
|
-
*
|
|
4
|
+
* REST shapes of the robot resource: create, list, get, and the built-in
|
|
5
|
+
* `bridge_state` datapoint read.
|
|
5
6
|
*/
|
|
6
7
|
export declare const robot: z.ZodObject<{
|
|
7
8
|
id: z.ZodUUID;
|
|
@@ -23,8 +24,8 @@ export declare const createRobotRequest: z.ZodObject<{
|
|
|
23
24
|
}, z.core.$strip>;
|
|
24
25
|
export type CreateRobotRequest = z.infer<typeof createRobotRequest>;
|
|
25
26
|
/**
|
|
26
|
-
* The robot token binds one bridge to one robot
|
|
27
|
-
*
|
|
27
|
+
* The robot token binds one bridge to one robot. It is returned exactly once,
|
|
28
|
+
* here; the cloud stores only a hash of it.
|
|
28
29
|
*/
|
|
29
30
|
export declare const robotToken: z.ZodString;
|
|
30
31
|
export declare const createRobotResponse: z.ZodObject<{
|
|
@@ -37,10 +38,10 @@ export declare const createRobotResponse: z.ZodObject<{
|
|
|
37
38
|
}, z.core.$strip>;
|
|
38
39
|
export type CreateRobotResponse = z.infer<typeof createRobotResponse>;
|
|
39
40
|
/**
|
|
40
|
-
* How many things a robot exposes, per kind
|
|
41
|
+
* How many things a robot exposes, per kind.
|
|
41
42
|
*
|
|
42
|
-
* **Five numbers, never a sum.** `robotDeletionSummary.slug_count`
|
|
43
|
-
*
|
|
43
|
+
* **Five numbers, never a sum.** `robotDeletionSummary.slug_count` makes the
|
|
44
|
+
* same call for the same reason: fold cameras in and the sentence "this deletes
|
|
44
45
|
* N slugs and M cameras" counts them twice. A list row has the same problem.
|
|
45
46
|
*
|
|
46
47
|
* **Counted from the published configuration, and excluding the built-ins.**
|
|
@@ -105,7 +106,7 @@ export declare const robotListResponse: z.ZodObject<{
|
|
|
105
106
|
export type RobotListResponse = z.infer<typeof robotListResponse>;
|
|
106
107
|
/**
|
|
107
108
|
* The REST read of one datapoint. For bridge-captured data `timestamp_ms`
|
|
108
|
-
* is the capture time at the bridge
|
|
109
|
+
* is the capture time at the bridge; for the cloud-observed
|
|
109
110
|
* built-in `bridge_state` it is the time the cloud observed the state.
|
|
110
111
|
*/
|
|
111
112
|
export declare const datapointValue: z.ZodObject<{
|
|
@@ -117,7 +118,7 @@ export type DatapointValue = z.infer<typeof datapointValue>;
|
|
|
117
118
|
/**
|
|
118
119
|
* One robot in full: what the list shows, plus what only the detail view
|
|
119
120
|
* needs — which bridge build is connected, why the last hello was refused,
|
|
120
|
-
* and where the configuration stands
|
|
121
|
+
* and where the configuration stands.
|
|
121
122
|
*/
|
|
122
123
|
export declare const robotDetailResponse: z.ZodObject<{
|
|
123
124
|
bridge_version: z.ZodNullable<z.ZodString>;
|
|
@@ -391,19 +392,16 @@ export type ConfigDraftResponse = z.infer<typeof configDraftResponse>;
|
|
|
391
392
|
* the server parses it, and there is exactly one account of what the
|
|
392
393
|
* configuration says.
|
|
393
394
|
*
|
|
394
|
-
* It also settles who owns parsing
|
|
395
|
-
*
|
|
396
|
-
*
|
|
397
|
-
*
|
|
398
|
-
*
|
|
399
|
-
*
|
|
400
|
-
*
|
|
401
|
-
*
|
|
402
|
-
*
|
|
403
|
-
*
|
|
404
|
-
* The pair that used to be called a defect — a stored source that does not
|
|
405
|
-
* parse to its stored document — is now a **represented state**: no document at
|
|
406
|
-
* all. See `configDraftResponse` above.
|
|
395
|
+
* It also settles who owns parsing. The **server** refuses text that is not
|
|
396
|
+
* valid YAML, with the line and column, and stores everything else — including
|
|
397
|
+
* valid YAML that is not a fleetless document, which comes back with
|
|
398
|
+
* `doc: null` and its issues. An editor may check as you type so the answer is
|
|
399
|
+
* immediate; the server checks because it is the one that decides. Two checks
|
|
400
|
+
* of one question, and the server's is the one that binds.
|
|
401
|
+
*
|
|
402
|
+
* A stored source that does not parse to a document is therefore a
|
|
403
|
+
* **represented state**, not an error: no document at all. See
|
|
404
|
+
* `configDraftResponse` above.
|
|
407
405
|
*/
|
|
408
406
|
export declare const putConfigDraftRequest: z.ZodObject<{
|
|
409
407
|
source: z.ZodString;
|
|
@@ -683,11 +681,11 @@ export type FetchTypesResponse = z.infer<typeof fetchTypesResponse>;
|
|
|
683
681
|
/**
|
|
684
682
|
* What a client can read on this robot: the built-ins plus everything the
|
|
685
683
|
* published configuration exposes. This is the seed of the generated
|
|
686
|
-
* per-robot API
|
|
684
|
+
* per-robot API.
|
|
687
685
|
*
|
|
688
|
-
* **The OpenAPI rendering
|
|
689
|
-
*
|
|
690
|
-
* `scripts/export-schemas.ts
|
|
686
|
+
* **The OpenAPI rendering is `artifacts/openapi.json`**, derived from the
|
|
687
|
+
* route manifest in `routes.ts` and these schemas by
|
|
688
|
+
* `scripts/export-schemas.ts`.
|
|
691
689
|
*/
|
|
692
690
|
export declare const datapointDescriptor: z.ZodObject<{
|
|
693
691
|
slug: z.ZodString;
|
|
@@ -706,8 +704,8 @@ export declare const datapointListResponse: z.ZodObject<{
|
|
|
706
704
|
}, z.core.$strip>;
|
|
707
705
|
export type DatapointListResponse = z.infer<typeof datapointListResponse>;
|
|
708
706
|
/**
|
|
709
|
-
* The built-in `robot_details` datapoint
|
|
710
|
-
*
|
|
707
|
+
* The built-in `robot_details` datapoint: static properties the developer
|
|
708
|
+
* maintains. Bounded so one robot cannot become a document store.
|
|
711
709
|
*/
|
|
712
710
|
export declare const robotDetailsDoc: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodUnknown>, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>;
|
|
713
711
|
export type RobotDetailsDoc = z.infer<typeof robotDetailsDoc>;
|
|
@@ -721,7 +719,7 @@ export declare const putRobotDetailsRequest: z.ZodObject<{
|
|
|
721
719
|
}, z.core.$strip>;
|
|
722
720
|
export type PutRobotDetailsRequest = z.infer<typeof putRobotDetailsRequest>;
|
|
723
721
|
/**
|
|
724
|
-
* Invoke an action or call a service; parameters by field path
|
|
722
|
+
* Invoke an action or call a service; parameters by field path.
|
|
725
723
|
*
|
|
726
724
|
* Flat, keyed by `parameterSpec.name` — see `cloudInvoke.params` for why the
|
|
727
725
|
* flat form is the one that makes a refusal legible.
|
|
@@ -732,55 +730,45 @@ export declare const invokeRequest: z.ZodObject<{
|
|
|
732
730
|
}, z.core.$strip>;
|
|
733
731
|
export type InvokeRequest = z.infer<typeof invokeRequest>;
|
|
734
732
|
/**
|
|
735
|
-
* The answer to an invoke. The job id is informative
|
|
736
|
-
*
|
|
733
|
+
* The answer to an invoke. The job id is informative: state is observed by
|
|
734
|
+
* slug afterwards, over polling or a subscription.
|
|
737
735
|
*/
|
|
738
736
|
/**
|
|
739
|
-
* The body of a cancel
|
|
740
|
-
*
|
|
741
|
-
*
|
|
742
|
-
*
|
|
743
|
-
* That is not politeness, it is the W5 defect: a bodyless `POST` carrying
|
|
744
|
-
* `content-type: application/json` was rejected outright, which made
|
|
745
|
-
* `cameras.live()` unreachable through the SDK and took `cancel`, publish,
|
|
746
|
-
* restore, key rotation and member removal with it — unnoticed since W4. A
|
|
747
|
-
* schema that demands a body would reintroduce it on the one verb that stops
|
|
748
|
-
* a machine.
|
|
737
|
+
* The body of a cancel. **Every field optional, and the body itself may be
|
|
738
|
+
* absent** — `POST .../cancel` takes no body at all in its simplest form, and
|
|
739
|
+
* a schema that demanded one would break every caller on the one verb that
|
|
740
|
+
* stops a machine.
|
|
749
741
|
*
|
|
750
742
|
* **`.strict()`, and that is the whole point of the shape.** A plain object
|
|
751
743
|
* strips unknown keys, so a caller who *means* to name a job and misspells the
|
|
752
744
|
* field — `jobId` for `job_id` — has their id silently removed and gets the
|
|
753
745
|
* **slug-wide** cancel instead: the most destructive reading of a request they
|
|
754
|
-
* did not make.
|
|
755
|
-
*
|
|
756
|
-
*
|
|
757
|
-
* fails *safe* on a typo — a misspelled `force` simply does not force.
|
|
758
|
-
* Stripping here fails unsafe, so unknown keys are refused instead.
|
|
746
|
+
* did not make. A `?force=true` flag fails *safe* on a typo, because a
|
|
747
|
+
* misspelled `force` simply does not force. Stripping here fails unsafe, so
|
|
748
|
+
* unknown keys are refused instead.
|
|
759
749
|
*
|
|
760
750
|
* `job_id` absent and `job_id: null` mean the **same** thing here, and that is
|
|
761
|
-
* deliberate: over REST an absent body is how
|
|
762
|
-
*
|
|
763
|
-
*
|
|
764
|
-
*
|
|
765
|
-
* omission is a bug.
|
|
751
|
+
* deliberate: over REST an absent body is how a caller says "cancel whatever is
|
|
752
|
+
* running". On the socket, `clientCancel.job_id` is required-and-nullable
|
|
753
|
+
* instead, because a frame is assembled fresh by a client that knows this
|
|
754
|
+
* contract — there, `null` is a decision and an omission is a bug.
|
|
766
755
|
*/
|
|
767
756
|
export declare const cancelRequest: z.ZodObject<{
|
|
768
757
|
job_id: z.ZodOptional<z.ZodNullable<z.ZodUUID>>;
|
|
769
758
|
}, z.core.$strict>;
|
|
770
759
|
export type CancelRequest = z.infer<typeof cancelRequest>;
|
|
771
760
|
/**
|
|
772
|
-
* The query of a live release
|
|
761
|
+
* The query of a live release: `DELETE .../live?session_id=<uuid>`.
|
|
773
762
|
*
|
|
774
763
|
* A query parameter rather than a body, following `?force=true` on robot
|
|
775
|
-
* deletion
|
|
776
|
-
* more fact". A body on a DELETE is carried inconsistently by proxies and by
|
|
764
|
+
* deletion. A body on a DELETE is carried inconsistently by proxies and by
|
|
777
765
|
* `fetch` itself, and this call runs from a browser tab that is often closing.
|
|
778
766
|
*
|
|
779
767
|
* **`.strict()`, for the reason `cancelRequest` is** — `?sessionid=` instead of
|
|
780
|
-
* `?session_id=`
|
|
781
|
-
*
|
|
782
|
-
*
|
|
783
|
-
*
|
|
768
|
+
* `?session_id=` would release **every** one of an identity's holds and strand
|
|
769
|
+
* its other tabs, which is precisely what this field exists to prevent. A
|
|
770
|
+
* refused typo costs a round trip; a stripped one stops a robot somebody else
|
|
771
|
+
* is watching.
|
|
784
772
|
*
|
|
785
773
|
* Absent means today's meaning: release **all** of this identity's holds on
|
|
786
774
|
* this camera. A client that has lost its id, or is going away entirely, still
|
|
@@ -882,14 +870,12 @@ export type PublishRequest = z.infer<typeof publishRequest>;
|
|
|
882
870
|
* The **most recent** job on a slug — running or already finished — or null
|
|
883
871
|
* only when nothing has ever run there.
|
|
884
872
|
*
|
|
885
|
-
*
|
|
886
|
-
*
|
|
887
|
-
*
|
|
888
|
-
*
|
|
889
|
-
*
|
|
890
|
-
*
|
|
891
|
-
* job is *said out loud* held for subscribers and silently did not hold for
|
|
892
|
-
* anyone polling. It is also the recovery `command_outcome_unknown` points
|
|
873
|
+
* A slug can be observed two equally valid ways, by polling this route or by
|
|
874
|
+
* subscribing. A route that forgot a job the moment it settled would let a
|
|
875
|
+
* poller see only `running`, then `null`: succeeded, failed, cancelled, `lost`
|
|
876
|
+
* and never-invoked would all become the same answer, and the promise that a
|
|
877
|
+
* lost job is said out loud would hold for subscribers and silently not hold
|
|
878
|
+
* for anyone polling. It is also the recovery `command_outcome_unknown` points
|
|
893
879
|
* a caller to.
|
|
894
880
|
*
|
|
895
881
|
* Read `job.state` to tell a live job from a finished one; that is what the
|
|
@@ -921,20 +907,18 @@ export declare const jobResponse: z.ZodObject<{
|
|
|
921
907
|
export type JobResponse = z.infer<typeof jobResponse>;
|
|
922
908
|
/**
|
|
923
909
|
* Every job the platform currently believes this robot has — `GET
|
|
924
|
-
* /api/robots/:id/jobs
|
|
910
|
+
* /api/robots/:id/jobs`.
|
|
925
911
|
*
|
|
926
912
|
* `jobResponse` answers "what is on this slug", which requires knowing the
|
|
927
|
-
* slug first.
|
|
928
|
-
*
|
|
929
|
-
*
|
|
930
|
-
*
|
|
931
|
-
*
|
|
932
|
-
*
|
|
933
|
-
*
|
|
934
|
-
*
|
|
935
|
-
*
|
|
936
|
-
* cloud that has just reconciled a robot's `hello.active_jobs` has exactly
|
|
937
|
-
* this list and, until now, no way to say it out loud.
|
|
913
|
+
* slug first. Two kinds of job break that assumption: a reconnecting bridge
|
|
914
|
+
* can name a job the cloud has **no row for**, and the cloud adopts it; and a
|
|
915
|
+
* configuration change can leave a job on a slug the document no longer
|
|
916
|
+
* contains. Both are jobs nobody can ask about, because asking requires
|
|
917
|
+
* already knowing what to ask for.
|
|
918
|
+
*
|
|
919
|
+
* So this route answers the question the per-slug route cannot: not "is
|
|
920
|
+
* something running here", but "what is this robot doing". A cloud that has
|
|
921
|
+
* just reconciled a robot's `hello.active_jobs` has exactly this list.
|
|
938
922
|
*
|
|
939
923
|
* The array is ordered newest first and is **never null**: a robot doing
|
|
940
924
|
* nothing answers `{ jobs: [] }`. "Nothing is running" and "we did not look"
|
|
@@ -942,14 +926,11 @@ export type JobResponse = z.infer<typeof jobResponse>;
|
|
|
942
926
|
* distinction `robotDeletionSummary` was made all-required for.
|
|
943
927
|
*
|
|
944
928
|
* **At most one entry per slug: the current job there, exactly what
|
|
945
|
-
* `jobResponse` would answer for that slug.** This is not a history endpoint
|
|
946
|
-
*
|
|
947
|
-
*
|
|
948
|
-
*
|
|
949
|
-
*
|
|
950
|
-
* console page carried a robot's entire past, and the one thing it exists to
|
|
951
|
-
* answer — *what is this robot doing* — would have been the first line of a
|
|
952
|
-
* scroll.
|
|
929
|
+
* `jobResponse` would answer for that slug.** This is not a history endpoint.
|
|
930
|
+
* Returning every job a registry still holds is unbounded in both count and
|
|
931
|
+
* payload for a robot that has been working all day, and the one thing this
|
|
932
|
+
* route exists to answer — *what is this robot doing* — would be the first
|
|
933
|
+
* line of a scroll. The durable history has its own routes.
|
|
953
934
|
*
|
|
954
935
|
* A settled job stays visible as its slug's current entry until something
|
|
955
936
|
* else runs there, which is what makes a job that just failed still findable.
|
|
@@ -957,7 +938,7 @@ export type JobResponse = z.infer<typeof jobResponse>;
|
|
|
957
938
|
* `jobResponse`.
|
|
958
939
|
*/
|
|
959
940
|
/**
|
|
960
|
-
* What a `rate_limited` refusal tells the caller
|
|
941
|
+
* What a `rate_limited` refusal tells the caller.
|
|
961
942
|
*
|
|
962
943
|
* One number, and it is the only one that matters: **when to come back.** A
|
|
963
944
|
* limit that says "too many" without saying "in 800 ms" produces a client that
|
|
@@ -974,11 +955,10 @@ export declare const rateLimitDetails: z.ZodObject<{
|
|
|
974
955
|
export type RateLimitDetails = z.infer<typeof rateLimitDetails>;
|
|
975
956
|
/**
|
|
976
957
|
* Every job this robot's registry currently holds, **ordered newest first by
|
|
977
|
-
* `started_at`, with `seq` as the tiebreaker
|
|
958
|
+
* `started_at`, with `seq` as the tiebreaker**.
|
|
978
959
|
*
|
|
979
|
-
* The
|
|
980
|
-
*
|
|
981
|
-
* twice over:
|
|
960
|
+
* The tiebreaker is named rather than left implicit, because it matters twice
|
|
961
|
+
* over:
|
|
982
962
|
*
|
|
983
963
|
* 1. **`started_at` alone is not a total order.** Two jobs minted in the same
|
|
984
964
|
* millisecond sorted against each other arbitrarily — differently on each
|
|
@@ -1021,9 +1001,9 @@ export type RobotJobsResponse = z.infer<typeof robotJobsResponse>;
|
|
|
1021
1001
|
/**
|
|
1022
1002
|
* Every slug of a robot that a role can be granted, **with its kind**.
|
|
1023
1003
|
*
|
|
1024
|
-
*
|
|
1025
|
-
*
|
|
1026
|
-
*
|
|
1004
|
+
* A roles matrix built against the datapoint list alone cannot grant an
|
|
1005
|
+
* action, a service or a publisher. One list that names every kind, with its
|
|
1006
|
+
* kind, is what a matrix needs.
|
|
1027
1007
|
*/
|
|
1028
1008
|
export declare const exposure: z.ZodObject<{
|
|
1029
1009
|
slug: z.ZodString;
|
|
@@ -1072,36 +1052,27 @@ export declare const SNAPSHOT_HEADERS: {
|
|
|
1072
1052
|
readonly height: "x-fleetless-height";
|
|
1073
1053
|
};
|
|
1074
1054
|
/**
|
|
1075
|
-
* The metadata an asset upload carries beside its raw body
|
|
1055
|
+
* The metadata an asset upload carries beside its raw body.
|
|
1076
1056
|
*
|
|
1077
|
-
*
|
|
1078
|
-
*
|
|
1079
|
-
*
|
|
1080
|
-
*
|
|
1081
|
-
*
|
|
1082
|
-
* found the general form: three repos agreeing with each other about a payload
|
|
1083
|
-
* none of them exchanged, each right in its own tests.
|
|
1084
|
-
*
|
|
1085
|
-
* **A string shared by two repos and defined in both is a string that drifts.**
|
|
1086
|
-
* A zod schema cannot validate a header, which is an argument for writing the
|
|
1087
|
-
* names down once, not an argument for writing them down twice.
|
|
1057
|
+
* Written here rather than left as a convention each side documents for
|
|
1058
|
+
* itself. **A string shared by two implementations and defined in both is a
|
|
1059
|
+
* string that drifts**, and a header is the easiest place for that to happen
|
|
1060
|
+
* unnoticed: a zod schema cannot validate one, which is an argument for
|
|
1061
|
+
* writing the names down once, not an argument for writing them down twice.
|
|
1088
1062
|
*
|
|
1089
1063
|
* `name` is the `package://` URI verbatim for a mesh — the same string
|
|
1090
1064
|
* `asset.name` stores, and the same one `urdfCompleteness.missing` reports, so
|
|
1091
1065
|
* a failed upload and a missing mesh can be matched by eye.
|
|
1092
1066
|
*/
|
|
1093
1067
|
/**
|
|
1094
|
-
* **`name` travels percent-encoded
|
|
1095
|
-
*
|
|
1096
|
-
*
|
|
1097
|
-
*
|
|
1098
|
-
*
|
|
1099
|
-
*
|
|
1100
|
-
*
|
|
1101
|
-
*
|
|
1102
|
-
* cost a developer every mesh after it in that sync, with no cause on the
|
|
1103
|
-
* wire. R6 made it ordinary rather than exotic: `.dae` internal names come
|
|
1104
|
-
* from 3D-authoring tools, where non-ASCII is Tuesday.
|
|
1068
|
+
* **`name` travels percent-encoded in a second header.**
|
|
1069
|
+
*
|
|
1070
|
+
* HTTP header values are latin-1. A texture called `textures/日本語.png` cannot
|
|
1071
|
+
* be put in one at all: in Python it raises a `UnicodeEncodeError` inside
|
|
1072
|
+
* `urllib` — a `ValueError`, caught by neither `HTTPError` nor `URLError` — so
|
|
1073
|
+
* a single non-ASCII filename can fail an entire sync with no cause on the
|
|
1074
|
+
* wire. Non-ASCII names are ordinary rather than exotic, because `.dae`
|
|
1075
|
+
* internal names come from 3D-authoring tools.
|
|
1105
1076
|
*
|
|
1106
1077
|
* The encoding is not invented here. **`GET .../assets/missing?name=` already
|
|
1107
1078
|
* carries this exact string percent-encoded**, because a query parameter is
|
|
@@ -1109,21 +1080,19 @@ export declare const SNAPSHOT_HEADERS: {
|
|
|
1109
1080
|
* answered.
|
|
1110
1081
|
*
|
|
1111
1082
|
* **It is a SECOND header, and that is the whole design rather than a
|
|
1112
|
-
* detail.**
|
|
1113
|
-
*
|
|
1114
|
-
*
|
|
1115
|
-
*
|
|
1116
|
-
*
|
|
1117
|
-
*
|
|
1118
|
-
* reading the contract rather than the code).
|
|
1083
|
+
* detail.** Overloading `name` itself — the producer encodes, the store
|
|
1084
|
+
* decodes — decodes identically for every name without a `%`, so an older
|
|
1085
|
+
* producer and a newer store agree by luck right up until a name contains
|
|
1086
|
+
* `%2f`, which the store would then silently turn into a `/`. A wire change
|
|
1087
|
+
* whose breakage is invisible in the common case and silent in the uncommon
|
|
1088
|
+
* one is the worst of both.
|
|
1119
1089
|
*
|
|
1120
1090
|
* So `name` keeps meaning exactly what it always meant, and `nameEncoded`
|
|
1121
1091
|
* carries the percent-encoded UTF-8 form. **The store prefers `nameEncoded`
|
|
1122
1092
|
* when present and uses `name` otherwise**, so:
|
|
1123
1093
|
*
|
|
1124
|
-
* -
|
|
1125
|
-
* - a
|
|
1126
|
-
* intact for the first time;
|
|
1094
|
+
* - a producer that sends only `name` behaves exactly as it always did;
|
|
1095
|
+
* - a producer that sends both can carry a name latin-1 cannot express;
|
|
1127
1096
|
* - no value is ever ambiguous about which encoding it is in.
|
|
1128
1097
|
*
|
|
1129
1098
|
* A producer that can send `nameEncoded` should send both, so a store older
|
|
@@ -1136,23 +1105,22 @@ export declare const ASSET_UPLOAD_HEADERS: {
|
|
|
1136
1105
|
readonly nameEncoded: "x-fleetless-asset-name-encoded";
|
|
1137
1106
|
readonly syncId: "x-fleetless-sync-id";
|
|
1138
1107
|
/**
|
|
1139
|
-
* **
|
|
1140
|
-
*
|
|
1108
|
+
* **The announced size, and it is what makes `asset_too_large` reachable at
|
|
1109
|
+
* all.**
|
|
1141
1110
|
*
|
|
1142
|
-
*
|
|
1143
|
-
*
|
|
1144
|
-
*
|
|
1145
|
-
*
|
|
1146
|
-
* Erzeuger (Momus-W7, M1, an den echten Routenoptionen reproduziert).
|
|
1111
|
+
* A server-side body limit is applied by the content-type parser, before the
|
|
1112
|
+
* handler runs, so an oversized upload can only be refused with a bare
|
|
1113
|
+
* `413` carrying neither `limit_bytes` nor `size_bytes` — and the structured
|
|
1114
|
+
* refusal `assetTooLargeDetails` describes would have no producer.
|
|
1147
1115
|
*
|
|
1148
|
-
*
|
|
1149
|
-
*
|
|
1150
|
-
*
|
|
1151
|
-
*
|
|
1116
|
+
* With the size announced in a header the refusal can be made where it can
|
|
1117
|
+
* say something: before a byte is buffered, with both numbers. It also lets
|
|
1118
|
+
* a producer discover its own limit without first reading the whole file
|
|
1119
|
+
* into memory.
|
|
1152
1120
|
*
|
|
1153
|
-
*
|
|
1154
|
-
*
|
|
1155
|
-
*
|
|
1121
|
+
* The header is an **announcement, not a proof**: a sender can lie. The
|
|
1122
|
+
* ceiling still applies to the body — this does not replace enforcement, it
|
|
1123
|
+
* only makes the refusal answerable.
|
|
1156
1124
|
*/
|
|
1157
1125
|
readonly size: "x-fleetless-asset-size";
|
|
1158
1126
|
};
|
|
@@ -1178,7 +1146,7 @@ export type CameraListResponse = z.infer<typeof cameraListResponse>;
|
|
|
1178
1146
|
* What a viewer needs to join, and **what it costs them to hold**.
|
|
1179
1147
|
*
|
|
1180
1148
|
* `POST` takes a refcount hold and `DELETE` releases it; the first hold
|
|
1181
|
-
* starts the robot publishing and the last release stops it
|
|
1149
|
+
* starts the robot publishing and the last release stops it. A client
|
|
1182
1150
|
* that forgets to release keeps a robot streaming to nobody, so the SDK hands
|
|
1183
1151
|
* back a `release()` rather than a bare token.
|
|
1184
1152
|
*
|
|
@@ -1210,8 +1178,8 @@ export type LiveSessionResponse = z.infer<typeof liveSessionResponse>;
|
|
|
1210
1178
|
* which polls continuously while a tab is open.
|
|
1211
1179
|
*
|
|
1212
1180
|
* `age_ms` is not a convenience: a cached frame served without its age is
|
|
1213
|
-
* indistinguishable from a live one, and
|
|
1214
|
-
*
|
|
1181
|
+
* indistinguishable from a live one, and snapshots are deliberately cheap and
|
|
1182
|
+
* therefore deliberately old. `null` values mean nothing has been
|
|
1215
1183
|
* captured yet — which is an answer, not an error.
|
|
1216
1184
|
*/
|
|
1217
1185
|
export declare const snapshotMetaResponse: z.ZodObject<{
|
|
@@ -1224,28 +1192,23 @@ export declare const snapshotMetaResponse: z.ZodObject<{
|
|
|
1224
1192
|
}, z.core.$strip>;
|
|
1225
1193
|
export type SnapshotMetaResponse = z.infer<typeof snapshotMetaResponse>;
|
|
1226
1194
|
/**
|
|
1227
|
-
* **Both history shapes answer the same boundary the same way: `[from, to)
|
|
1228
|
-
*
|
|
1229
|
-
*
|
|
1230
|
-
*
|
|
1231
|
-
*
|
|
1232
|
-
*
|
|
1233
|
-
*
|
|
1234
|
-
*
|
|
1235
|
-
*
|
|
1236
|
-
*
|
|
1237
|
-
*
|
|
1238
|
-
*
|
|
1239
|
-
*
|
|
1240
|
-
*
|
|
1241
|
-
*
|
|
1242
|
-
* This is a statement about behaviour, not a field — nothing in the shapes
|
|
1243
|
-
* below can enforce it. It is written here because this is the one place both
|
|
1244
|
-
* shapes are defined together, and the cloud's `history-store` and the SDK's
|
|
1245
|
-
* README are the two places that have to agree with it.
|
|
1195
|
+
* **Both history shapes answer the same boundary the same way: `[from, to)`.**
|
|
1196
|
+
*
|
|
1197
|
+
* Half-open, because it is the only rule under which **adjacent windows tile
|
|
1198
|
+
* without overlap**: `[0,10)` then `[10,20)` covers every instant once. With an
|
|
1199
|
+
* inclusive upper bound a sample at exactly `10` belongs to both windows, and
|
|
1200
|
+
* any consumer summing them counts it twice.
|
|
1201
|
+
*
|
|
1202
|
+
* Two shapes that answered it differently would give opposite results for a
|
|
1203
|
+
* point landing exactly on `to` — same range, same data — and the difference
|
|
1204
|
+
* renders as a gap in one of the two.
|
|
1205
|
+
*
|
|
1206
|
+
* This is a statement about behaviour, not a field: nothing in the shapes below
|
|
1207
|
+
* can enforce it. It is written here because this is the one place both shapes
|
|
1208
|
+
* are defined together.
|
|
1246
1209
|
*/
|
|
1247
1210
|
/**
|
|
1248
|
-
* A history query
|
|
1211
|
+
* A history query. `from`/`to` accept **either** a relative expression
|
|
1249
1212
|
* (`now-30s`, `now-5m`, `now-1h`) **or** absolute unix milliseconds, because
|
|
1250
1213
|
* a chart asks the first way and a report asks the second, and making a
|
|
1251
1214
|
* client convert is making it guess our clock.
|
|
@@ -1268,7 +1231,7 @@ export declare const historyQuery: z.ZodObject<{
|
|
|
1268
1231
|
}, z.core.$strip>;
|
|
1269
1232
|
export type HistoryQuery = z.infer<typeof historyQuery>;
|
|
1270
1233
|
/**
|
|
1271
|
-
* Raw samples. `timestamp_ms` is the **bridge's capture time**
|
|
1234
|
+
* Raw samples. `timestamp_ms` is the **bridge's capture time** — the
|
|
1272
1235
|
* same instant the live value carried, so a recorded point and a live one can
|
|
1273
1236
|
* be placed on one axis without apology.
|
|
1274
1237
|
*
|
|
@@ -1296,9 +1259,8 @@ export type HistorySamplesResponse = z.infer<typeof historySamplesResponse>;
|
|
|
1296
1259
|
* inspection.
|
|
1297
1260
|
*
|
|
1298
1261
|
* `sample_count` exists because an empty bucket and a bucket whose average is
|
|
1299
|
-
* zero are different facts.
|
|
1300
|
-
*
|
|
1301
|
-
* product to draw a gap as a line.
|
|
1262
|
+
* zero are different facts. When two facts share one representation, a chart
|
|
1263
|
+
* is the easiest place to draw a gap as a line.
|
|
1302
1264
|
*/
|
|
1303
1265
|
export declare const historyBucketsResponse: z.ZodObject<{
|
|
1304
1266
|
slug: z.ZodString;
|
|
@@ -1365,7 +1327,7 @@ export declare const historyResponse: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
1365
1327
|
}, z.core.$strip>]>;
|
|
1366
1328
|
export type HistoryResponse = z.infer<typeof historyResponse>;
|
|
1367
1329
|
/**
|
|
1368
|
-
*
|
|
1330
|
+
* Deletion, and the one channel that reports health.
|
|
1369
1331
|
*
|
|
1370
1332
|
* | Route | Body | Answer |
|
|
1371
1333
|
* |---|---|---|
|
|
@@ -1391,24 +1353,17 @@ export type HistoryResponse = z.infer<typeof historyResponse>;
|
|
|
1391
1353
|
* takes an optional `robot_id` filter rather than living at a per-robot
|
|
1392
1354
|
* path.
|
|
1393
1355
|
*
|
|
1394
|
-
* The
|
|
1395
|
-
*
|
|
1396
|
-
*
|
|
1397
|
-
*
|
|
1398
|
-
*
|
|
1399
|
-
*
|
|
1400
|
-
*
|
|
1401
|
-
*
|
|
1402
|
-
*
|
|
1403
|
-
* So: same scope, one route, and `?robot_id=` for the narrow question. The
|
|
1404
|
-
* cloud owner proposed this while unblocking the console, and was right.
|
|
1405
|
-
*
|
|
1406
|
-
* This table was missing from the first W6a delta, and a teammate had to ask
|
|
1407
|
-
* three separate people for the paths — which is how a route becomes a fact
|
|
1408
|
-
* that lives only in an inbox.
|
|
1356
|
+
* The per-robot reading is the tempting one and it is wrong: a health list is
|
|
1357
|
+
* rendered for every robot at once, and a per-robot path makes that N requests
|
|
1358
|
+
* to draw one screen — while the event that keeps it fresh arrives org-wide
|
|
1359
|
+
* anyway. A snapshot and a channel that disagree about scope are not two halves
|
|
1360
|
+
* of one thing; they are two things every consumer has to reconcile, separately,
|
|
1361
|
+
* forever.
|
|
1362
|
+
*
|
|
1363
|
+
* So: same scope, one route, and `?robot_id=` for the narrow question.
|
|
1409
1364
|
*/
|
|
1410
1365
|
/**
|
|
1411
|
-
* What a `robot.deleted` audit event carries
|
|
1366
|
+
* What a `robot.deleted` audit event carries.
|
|
1412
1367
|
*
|
|
1413
1368
|
* A deletion record that says only *that* something was destroyed is a
|
|
1414
1369
|
* receipt for an unknown amount. This names it: how many configured slugs,
|
|
@@ -1452,41 +1407,36 @@ export declare const robotDeleteQuery: z.ZodObject<{
|
|
|
1452
1407
|
}, z.core.$strip>;
|
|
1453
1408
|
export type RobotDeleteQuery = z.infer<typeof robotDeleteQuery>;
|
|
1454
1409
|
/**
|
|
1455
|
-
* The seven health states, declared **once
|
|
1410
|
+
* The seven health states, declared **once**.
|
|
1456
1411
|
*
|
|
1457
|
-
* `resourceHealthState` and `resourceHealthEvent` are the snapshot and the
|
|
1458
|
-
*
|
|
1459
|
-
*
|
|
1460
|
-
*
|
|
1461
|
-
* to add it in both places, on the wave's last contract commit.
|
|
1412
|
+
* `resourceHealthState` and `resourceHealthEvent` are the snapshot and the push
|
|
1413
|
+
* of the same thing. Writing the values out twice publishes two independent
|
|
1414
|
+
* artifacts with no `$ref` between them, kept in step only by whoever
|
|
1415
|
+
* remembers to edit both.
|
|
1462
1416
|
*
|
|
1463
|
-
* One concept rendering as two artifacts that nothing keeps in step is its
|
|
1464
|
-
*
|
|
1465
|
-
*
|
|
1417
|
+
* One concept rendering as two artifacts that nothing keeps in step is its own
|
|
1418
|
+
* class of artifact-versus-source defect, distinct from `.default()` publishing
|
|
1419
|
+
* as `required` and from a coercion's unrepresentable input.
|
|
1466
1420
|
*/
|
|
1467
1421
|
export declare const RESOURCE_HEALTH_STATES: readonly ["ok", "unreachable", "auth_failed", "unreadable_credential", "credential_missing", "stopped_by_config_change", "publish_failed", "unknown"];
|
|
1468
1422
|
/**
|
|
1469
1423
|
* The health of one thing a developer configured, as the platform currently
|
|
1470
|
-
* sees it
|
|
1471
|
-
*
|
|
1472
|
-
*
|
|
1473
|
-
*
|
|
1474
|
-
*
|
|
1475
|
-
*
|
|
1476
|
-
*
|
|
1477
|
-
*
|
|
1478
|
-
*
|
|
1479
|
-
*
|
|
1480
|
-
*
|
|
1481
|
-
*
|
|
1482
|
-
*
|
|
1483
|
-
*
|
|
1484
|
-
*
|
|
1485
|
-
*
|
|
1486
|
-
* `reason` is for a human and is **never** built from an exception message:
|
|
1487
|
-
* W6 found a camera password in a log through `log.exception`, and again in
|
|
1488
|
-
* `LiveStartError`'s message, which travels to the cloud on this very path.
|
|
1489
|
-
* Type names and fixed strings only.
|
|
1424
|
+
* sees it.
|
|
1425
|
+
*
|
|
1426
|
+
* It exists because nothing else carries the state of a camera, a source or a
|
|
1427
|
+
* credential to a developer who is not, at that exact moment, pressing a
|
|
1428
|
+
* button. A publish failure after the `201` reaches no one; a source whose
|
|
1429
|
+
* password is wrong fails at config-apply time with nobody watching and stays
|
|
1430
|
+
* silent until someone presses "Go live" days later; a viewer cannot learn
|
|
1431
|
+
* *why* a stream ended; an undecryptable credential reports as healthy.
|
|
1432
|
+
*
|
|
1433
|
+
* One shape rather than a field per symptom, because a failure written into a
|
|
1434
|
+
* state field the platform writes and reads in one place is a dead end.
|
|
1435
|
+
*
|
|
1436
|
+
* `reason` is for a human and is **never** built from an exception message: a
|
|
1437
|
+
* camera password reaches a log that way, and an exception message from a
|
|
1438
|
+
* failing stream travels to the cloud on this very path. Type names and fixed
|
|
1439
|
+
* strings only.
|
|
1490
1440
|
*/
|
|
1491
1441
|
export declare const resourceHealthState: z.ZodObject<{
|
|
1492
1442
|
robot_id: z.ZodUUID;
|
|
@@ -1515,14 +1465,8 @@ export type ResourceHealthState = z.infer<typeof resourceHealthState>;
|
|
|
1515
1465
|
/**
|
|
1516
1466
|
* The current state of everything in the **org**.
|
|
1517
1467
|
*
|
|
1518
|
-
*
|
|
1519
|
-
*
|
|
1520
|
-
* paragraph explaining why the per-robot reading was wrong — while the schema
|
|
1521
|
-
* it describes still said the old thing. Cloud, console and SDK all implement
|
|
1522
|
-
* org-wide correctly; contracts was the only place still saying otherwise,
|
|
1523
|
-
* and it is the first place a fourth consumer reads.
|
|
1524
|
-
*
|
|
1525
|
-
* A channel with no snapshot cannot answer "what is the state now?" for a
|
|
1468
|
+
* Org-wide, not per robot — the route table above explains why. A channel
|
|
1469
|
+
* with no snapshot cannot answer "what is the state now?" for a
|
|
1526
1470
|
* page that just loaded — it can only report the next change, which may be
|
|
1527
1471
|
* hours away. Both halves or neither.
|
|
1528
1472
|
*/
|
|
@@ -1564,9 +1508,9 @@ export declare const orgHealthQuery: z.ZodObject<{
|
|
|
1564
1508
|
}, z.core.$strip>;
|
|
1565
1509
|
export type OrgHealthQuery = z.infer<typeof orgHealthQuery>;
|
|
1566
1510
|
/**
|
|
1567
|
-
* Org protection quotas
|
|
1568
|
-
*
|
|
1569
|
-
*
|
|
1511
|
+
* Org protection quotas — generous, server-side adjustable, visible in
|
|
1512
|
+
* settings. Protection against runaway use, not a business model; a later one
|
|
1513
|
+
* docks onto the same dials.
|
|
1570
1514
|
*/
|
|
1571
1515
|
export declare const orgQuotas: z.ZodObject<{
|
|
1572
1516
|
max_robots: z.ZodNumber;
|
|
@@ -1586,8 +1530,7 @@ export type OrgQuotas = z.infer<typeof orgQuotas>;
|
|
|
1586
1530
|
* `positive()` because a quota of zero would forbid everything, but a
|
|
1587
1531
|
* **usage** of zero is the honest answer for every org on the day it signs
|
|
1588
1532
|
* up. Reusing one schema for a limit and a measurement is the same mistake as
|
|
1589
|
-
* letting an empty bucket and a zero average share a representation
|
|
1590
|
-
* this wave spent a lot of care avoiding one layer up.
|
|
1533
|
+
* letting an empty bucket and a zero average share a representation.
|
|
1591
1534
|
*
|
|
1592
1535
|
* Every field is optional because a quota we do not measure must be
|
|
1593
1536
|
* **absent**, never reported as `0` — "not measured" and "measured as zero"
|
|
@@ -1649,11 +1592,9 @@ export declare const BRIDGE_LATENCY_RETENTION_DAYS = 7;
|
|
|
1649
1592
|
* | `GET /api/org/latency` | `orgLatencyQuery` | `orgLatencyResponse` — one series per robot, truncation named |
|
|
1650
1593
|
* | `GET /api/robots/:id/jobs/history` | `jobRunQuery` | `jobRunListResponse` — the same read, robot-scoped, developers **and** clients |
|
|
1651
1594
|
*
|
|
1652
|
-
*
|
|
1653
|
-
*
|
|
1654
|
-
*
|
|
1655
|
-
* reason. The shapes landed one wave before the routes did, so this table is
|
|
1656
|
-
* the only place the two halves meet.
|
|
1595
|
+
* The paths are written down beside the shapes, as in
|
|
1596
|
+
* `robotDeletionSummary`'s neighbouring table: a shape whose route is not
|
|
1597
|
+
* named here is a fact that lives only in somebody's memory.
|
|
1657
1598
|
*
|
|
1658
1599
|
* Three things about them are worth stating rather than inferring:
|
|
1659
1600
|
*
|
|
@@ -1773,7 +1714,7 @@ export type OrgLatencyResponse = z.infer<typeof orgLatencyResponse>;
|
|
|
1773
1714
|
*/
|
|
1774
1715
|
export declare const USAGE_WINDOW_MAX_DAYS = 366;
|
|
1775
1716
|
/**
|
|
1776
|
-
* The five things the meter records
|
|
1717
|
+
* The five things the meter records.
|
|
1777
1718
|
*
|
|
1778
1719
|
* Storage is two metrics and not one summed byte count, for
|
|
1779
1720
|
* `org_quotas.max_asset_storage_bytes`'s own reason applied to billing: a sync
|
|
@@ -1815,7 +1756,7 @@ export type UsageMetric = z.infer<typeof usageMetric>;
|
|
|
1815
1756
|
export declare const usageDay: z.ZodString;
|
|
1816
1757
|
/**
|
|
1817
1758
|
* **The window is inclusive at both ends**, unlike every millisecond window in
|
|
1818
|
-
* this file (`from_ms`/`to_ms`, half-open
|
|
1759
|
+
* this file (`from_ms`/`to_ms`, which are half-open).
|
|
1819
1760
|
*
|
|
1820
1761
|
* That inconsistency is deliberate and is stated here rather than left to be
|
|
1821
1762
|
* discovered: a calendar day is a unit, not an instant, and a person asking for
|
|
@@ -1852,7 +1793,7 @@ export type OrgUsageQuery = z.infer<typeof orgUsageQuery>;
|
|
|
1852
1793
|
/**
|
|
1853
1794
|
* One day's reading for one metric.
|
|
1854
1795
|
*
|
|
1855
|
-
* **`app_id` is `null` when the consumer is the org itself
|
|
1796
|
+
* **`app_id` is `null` when the consumer is the org itself**, and
|
|
1856
1797
|
* what that `null` means for billing depends on the *metric*, not on
|
|
1857
1798
|
* `app_id` alone. `api_calls` and `live_session_ms` are attributable to an
|
|
1858
1799
|
* app: a `null` app_id on those two is the developer console's own traffic,
|
|
@@ -1881,9 +1822,8 @@ export type OrgUsageQuery = z.infer<typeof orgUsageQuery>;
|
|
|
1881
1822
|
* not hold at all: everything counted since the last successful flush is
|
|
1882
1823
|
* held in memory, deliberately uncapped, and a `kill -9` loses all of it.
|
|
1883
1824
|
* The trade is intentional (dropping billing data to bound process memory is
|
|
1884
|
-
* the worse half of it), but "at most one interval" describes a platform
|
|
1885
|
-
*
|
|
1886
|
-
* sentence used to say "never more", and it was false.
|
|
1825
|
+
* the worse half of it), but "at most one interval" describes a platform whose
|
|
1826
|
+
* writes are landing, not a guarantee that survives an outage.
|
|
1887
1827
|
*
|
|
1888
1828
|
* A row the database rejects **permanently** — most concretely one whose org
|
|
1889
1829
|
* has been deleted since the count, since a usage row's `org_id` is `ON
|
|
@@ -1974,11 +1914,10 @@ export type RenameSlugResponse = z.infer<typeof renameSlugResponse>;
|
|
|
1974
1914
|
* `GET /api/robots/:id/config/slug-usage/:slug` — what a rename would touch;
|
|
1975
1915
|
* feeds the console's confirm dialog.
|
|
1976
1916
|
*
|
|
1977
|
-
* `alert_count`
|
|
1978
|
-
*
|
|
1979
|
-
*
|
|
1980
|
-
*
|
|
1981
|
-
* developer a smaller blast radius than the rename actually has.
|
|
1917
|
+
* `alert_count` is part of the atomic rename transaction alongside grants and
|
|
1918
|
+
* history: alerts are keyed by `(robot_id, slug)` too, and a rename that
|
|
1919
|
+
* silently moved the alert row while the usage preview stayed silent about it
|
|
1920
|
+
* would show a developer a smaller blast radius than the rename actually has.
|
|
1982
1921
|
*/
|
|
1983
1922
|
export declare const slugUsageResponse: z.ZodObject<{
|
|
1984
1923
|
grant_count: z.ZodNumber;
|