@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/config.d.ts
CHANGED
|
@@ -1,34 +1,29 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
2
|
import { z } from 'zod';
|
|
2
3
|
/**
|
|
3
|
-
* What an exposed service *is*, in the developer's own words
|
|
4
|
+
* What an exposed service *is*, in the developer's own words.
|
|
4
5
|
*
|
|
5
6
|
* This is what `robot_describe` carries verbatim, so it is read by a model
|
|
6
7
|
* that has never seen this robot and cannot ask a follow-up question.
|
|
7
8
|
* `unit` and `range` already say what a number *is*; this says what it
|
|
8
9
|
* *means*.
|
|
9
10
|
*
|
|
10
|
-
* **It lives on the configuration rather than on the app, and that
|
|
11
|
-
* decision with a cost.**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* rediscovered as a bug: **two apps can no longer describe one service
|
|
16
|
-
* differently for two audiences.** §17 was reworded in the same wave rather
|
|
17
|
-
* than left contradicting this field.
|
|
11
|
+
* **It lives on the configuration rather than on the app, and that is a
|
|
12
|
+
* decision with a cost.** A description written here is written once per
|
|
13
|
+
* service and is true for every app that reaches the robot, beside the other
|
|
14
|
+
* metadata. What is given up is real and should not be rediscovered as a bug:
|
|
15
|
+
* **two apps cannot describe one service differently for two audiences.**
|
|
18
16
|
*
|
|
19
17
|
* **`.optional()` and not `.nullable().default(null)`, deliberately.** The
|
|
20
18
|
* established shape in this file is a default — and every use of it has
|
|
21
19
|
* added an instance to a known contradiction: `.default()` publishes the
|
|
22
20
|
* field as **required** in the generated JSON Schema, because after parsing
|
|
23
|
-
* it is always present. That is recorded
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* on this pin. So the field simply does not create a fifth instance:
|
|
30
|
-
* optional is optional in both modes, and *absent* is the single spelling of
|
|
31
|
-
* "not described". `.min(1)` keeps the empty string from becoming a second.
|
|
21
|
+
* it is always present. That is recorded in `scripts/export-schemas.ts`, whose
|
|
22
|
+
* remedy (`io: 'input'`, applied per schema) is a judgement call across dozens
|
|
23
|
+
* of schemas and every consumer that vendors them. So this field simply does
|
|
24
|
+
* not add another instance: optional is optional in both modes, and *absent* is
|
|
25
|
+
* the single spelling of "not described". `.min(1)` keeps the empty string from
|
|
26
|
+
* becoming a second.
|
|
32
27
|
*/
|
|
33
28
|
export declare const serviceDescription: z.ZodOptional<z.ZodString>;
|
|
34
29
|
/**
|
|
@@ -134,7 +129,7 @@ export declare const parameterMap: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
|
134
129
|
description: z.ZodOptional<z.ZodString>;
|
|
135
130
|
}, z.core.$strict>>;
|
|
136
131
|
/**
|
|
137
|
-
* Slugs no configured entry may take
|
|
132
|
+
* Slugs no configured entry may take, across **all five exposure
|
|
138
133
|
* sections at once** — slugs are one namespace, so a name reserved here is
|
|
139
134
|
* reserved everywhere.
|
|
140
135
|
*
|
|
@@ -147,12 +142,12 @@ export declare const parameterMap: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
|
147
142
|
* name is the honest half of that: the alternative is a slug the format
|
|
148
143
|
* accepts and one route silently cannot address.
|
|
149
144
|
*
|
|
150
|
-
* **This constant is the only list.** The cloud
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
145
|
+
* **This constant is the only list.** The cloud builds its set from it and
|
|
146
|
+
* emits `reserved_slug`; the rename path reads it for the target; an editor
|
|
147
|
+
* reads it for slug suggestion and repairs. Nothing copies the members. Note
|
|
148
|
+
* that it is NOT the enumeration of built-in datapoints — those are kept
|
|
149
|
+
* separately, and must be, because a reserved name exists that nothing
|
|
150
|
+
* publishes.
|
|
156
151
|
*
|
|
157
152
|
* **What it does not do: `robotConfigDoc` does not enforce it.** Reservation is
|
|
158
153
|
* a semantic check that belongs with the ones that need the robot's context,
|
|
@@ -390,7 +385,7 @@ export declare function placeholderNames(node: unknown, found?: Set<string>): Se
|
|
|
390
385
|
*/
|
|
391
386
|
export declare const messageMap: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
392
387
|
/**
|
|
393
|
-
* An action the robot can be asked to perform
|
|
388
|
+
* An action the robot can be asked to perform. At most one
|
|
394
389
|
* job runs per action slug; a second call is refused `busy`, and every
|
|
395
390
|
* observer of the slug watches the same job.
|
|
396
391
|
*/
|
|
@@ -426,7 +421,7 @@ export declare const actionConfig: z.ZodObject<{
|
|
|
426
421
|
description: z.ZodOptional<z.ZodString>;
|
|
427
422
|
}, z.core.$strict>;
|
|
428
423
|
export type ActionConfig = z.infer<typeof actionConfig>;
|
|
429
|
-
/** A ROS service call with validated parameters
|
|
424
|
+
/** A ROS service call with validated parameters. */
|
|
430
425
|
export declare const serviceConfig: z.ZodObject<{
|
|
431
426
|
ros_name: z.ZodString;
|
|
432
427
|
type: z.ZodString;
|
|
@@ -571,14 +566,14 @@ export type CameraSource = z.infer<typeof cameraSource>;
|
|
|
571
566
|
*/
|
|
572
567
|
export declare const snapshotIntervalSeconds: z.ZodNumber;
|
|
573
568
|
/**
|
|
574
|
-
* A camera the robot exposes
|
|
569
|
+
* A camera the robot exposes.
|
|
575
570
|
*
|
|
576
|
-
* `width`/`height`/`fps`/`bitrate_kbps` are not cosmetic:
|
|
571
|
+
* `width`/`height`/`fps`/`bitrate_kbps` are not cosmetic: they are the
|
|
577
572
|
* developer's control over **the robot's own bandwidth**, which is why they
|
|
578
573
|
* live in the configuration rather than in a viewer's request. A viewer never
|
|
579
574
|
* gets to make a robot send more.
|
|
580
575
|
*
|
|
581
|
-
* The two modes are deliberately independent
|
|
576
|
+
* The two modes are deliberately independent:
|
|
582
577
|
*
|
|
583
578
|
* - **Snapshot** runs always, at `snapshot_interval_seconds`, whether or not
|
|
584
579
|
* anyone is watching live. The cloud caches the one frame and serves every
|
|
@@ -635,7 +630,7 @@ export declare const FLEETLESS_FORMAT_VERSION = 1;
|
|
|
635
630
|
* their own name. A duplicate name is then a YAML syntax error rather than a
|
|
636
631
|
* rule somebody has to write, and the name reads as the entry's heading.
|
|
637
632
|
*
|
|
638
|
-
* Slugs remain ONE namespace across all five exposure sections
|
|
633
|
+
* Slugs remain ONE namespace across all five exposure sections, which
|
|
639
634
|
* is what lets a role grant say `{robot, slug}` without naming a kind. That
|
|
640
635
|
* check spans sections and therefore lives in the cloud, not here.
|
|
641
636
|
*/
|
|
@@ -816,12 +811,12 @@ export declare const robotConfigDoc: z.ZodObject<{
|
|
|
816
811
|
}, z.core.$strict>;
|
|
817
812
|
export type RobotConfigDoc = z.infer<typeof robotConfigDoc>;
|
|
818
813
|
/**
|
|
819
|
-
* One thing the cloud has to say about a configuration
|
|
820
|
-
*
|
|
814
|
+
* One thing the cloud has to say about a configuration: the field, and the
|
|
815
|
+
* rule it violates.
|
|
821
816
|
*
|
|
822
817
|
* `error` blocks the publish. `warning` does not — an unknown topic is a
|
|
823
|
-
* warning on purpose, because configuring a robot that has never been
|
|
824
|
-
*
|
|
818
|
+
* warning on purpose, because configuring a robot that has never been connected
|
|
819
|
+
* must stay possible.
|
|
825
820
|
*/
|
|
826
821
|
export declare const validationIssue: z.ZodObject<{
|
|
827
822
|
path: z.ZodString;
|
|
@@ -836,8 +831,7 @@ export declare const validationIssue: z.ZodObject<{
|
|
|
836
831
|
export type ValidationIssue = z.infer<typeof validationIssue>;
|
|
837
832
|
/**
|
|
838
833
|
* Where a robot's configuration stands — the material for the console's
|
|
839
|
-
* "draft newer than published", "published v2 · applied v1 · bridge offline"
|
|
840
|
-
* (spec §15.2, robot tab 1).
|
|
834
|
+
* "draft newer than published", "published v2 · applied v1 · bridge offline".
|
|
841
835
|
*/
|
|
842
836
|
export declare const configState: z.ZodObject<{
|
|
843
837
|
published_version: z.ZodNullable<z.ZodNumber>;
|
package/dist/config.js
CHANGED
|
@@ -10,15 +10,14 @@ import { applyError, slug, rosName, rosTypeName, fieldPath, SLUG_RULE, ROS_NAME_
|
|
|
10
10
|
*/
|
|
11
11
|
import { alertSeverity } from './alerts.js';
|
|
12
12
|
/**
|
|
13
|
-
* The exposure model
|
|
13
|
+
* The exposure model: what a developer configures per robot, how a
|
|
14
14
|
* configuration moves from draft to published, and how the cloud reports what
|
|
15
15
|
* it refuses.
|
|
16
16
|
*
|
|
17
17
|
* ## What this schema decides, and what it leaves to the cloud
|
|
18
18
|
*
|
|
19
|
-
*
|
|
20
|
-
* them.
|
|
21
|
-
* written down, so here it is.
|
|
19
|
+
* The format names thirteen validation codes and this file implements some of
|
|
20
|
+
* them. Here is where the line runs.
|
|
22
21
|
*
|
|
23
22
|
* **Decided here** — everything a single entry, plus its own declared types,
|
|
24
23
|
* answers on its own: `unknown_key` (every object is this file's own
|
|
@@ -67,11 +66,10 @@ import { alertSeverity } from './alerts.js';
|
|
|
67
66
|
* `expected_range`, and no code replaced it.
|
|
68
67
|
*
|
|
69
68
|
* `robotConfigDoc` carries all six sections — messages, datapoints, actions,
|
|
70
|
-
* services, publishers and cameras — plus
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
* keyed every section by name; draft/publish and versioning are unchanged.
|
|
69
|
+
* services, publishers and cameras — plus the alerts, the chart bounds and the
|
|
70
|
+
* camera credentials. Everything configurable about a robot is in this
|
|
71
|
+
* document, and there is one door to it. Every section is keyed by name, and
|
|
72
|
+
* the document moves from draft to published under a version.
|
|
75
73
|
*/
|
|
76
74
|
/**
|
|
77
75
|
* What every `pattern` in this document means, said in words.
|
|
@@ -121,23 +119,18 @@ const DEVICE_PATH_RULE = 'A capture device is a path under `/dev/`, and the char
|
|
|
121
119
|
*
|
|
122
120
|
* **`slug` itself stays plain in `common.ts`, and the reason is blast radius.**
|
|
123
121
|
* Not metadata loss: `.meta()` on a clone *merges* with the parent's entry per
|
|
124
|
-
* key and resolves it lazily
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
* Whether `vscode-json-languageservice` honours `patternErrorMessage` on a
|
|
138
|
-
* `propertyNames` schema at all is **not measured** — §1.3 measured a value
|
|
139
|
-
* position, not a key one. It ships for the same reason as the rest: the
|
|
140
|
-
* artifact is read by tools and by people.
|
|
122
|
+
* key and resolves it lazily — a later `description` on a use of `slug` keeps
|
|
123
|
+
* the sentence rather than dropping it.
|
|
124
|
+
*
|
|
125
|
+
* The cost is reach. Annotating `slug` itself puts the sentence into dozens of
|
|
126
|
+
* the published schema artifacts, protocol frames included, so rewording one
|
|
127
|
+
* sentence becomes a change to every consumer that vendors those. Annotating
|
|
128
|
+
* the key here reaches only the configuration schemas, which is where the
|
|
129
|
+
* sentence is useful.
|
|
130
|
+
*
|
|
131
|
+
* Whether a given YAML language service honours `patternErrorMessage` on a
|
|
132
|
+
* `propertyNames` schema is not something this package can promise. It ships
|
|
133
|
+
* for the same reason as the rest: the artifact is read by tools and by people.
|
|
141
134
|
*/
|
|
142
135
|
const mapKey = slug.meta({ patternErrorMessage: SLUG_RULE });
|
|
143
136
|
/**
|
|
@@ -256,37 +249,28 @@ const namesItsAbsence = (shape) => Object.fromEntries(Object.entries(shape).map(
|
|
|
256
249
|
* its own name when it is absent.
|
|
257
250
|
*
|
|
258
251
|
* **This is not `z.strictObject`** — it is this file's, wrapping it. The
|
|
259
|
-
* difference is the second half
|
|
260
|
-
*
|
|
261
|
-
*
|
|
262
|
-
*
|
|
263
|
-
*
|
|
252
|
+
* difference is the second half. Plain zod tells a developer whose camera has
|
|
253
|
+
* no `source:` only `Invalid input: expected object, received undefined`,
|
|
254
|
+
* naming neither the key nor the fact that it was required. A YAML language
|
|
255
|
+
* service says `Missing property "source".` for the same document, and is right
|
|
256
|
+
* to.
|
|
264
257
|
*
|
|
265
258
|
* It has to be done a field at a time. zod attributes a missing key to the
|
|
266
259
|
* **field's own** schema — an `invalid_type` whose input is `undefined` — and
|
|
267
|
-
* an `error` on the containing object is never consulted for it
|
|
268
|
-
* zod 4.4.3, an error map on the object saw no such issue at all. So the
|
|
260
|
+
* an `error` on the containing object is never consulted for it. So the
|
|
269
261
|
* sentence is attached to every field of every shape, here, in one place,
|
|
270
|
-
* rather than at the
|
|
271
|
-
*
|
|
272
|
-
*
|
|
273
|
-
* **How "every" is enforced
|
|
274
|
-
*
|
|
275
|
-
* `z\n .strictObject({`, so `z.strictObject` never appeared on one line and a
|
|
276
|
-
* `grep` for it returned only prose. Twelve conversions read as eighteen, and
|
|
277
|
-
* eleven required keys — `datapoints.<slug>.topic` and `.type` among them,
|
|
278
|
-
* which is the commonest entry in the whole format — went on reciting the
|
|
279
|
-
* sentence §1.5 calls unusable. The claim was in the source, which is what the
|
|
280
|
-
* next person reads.
|
|
281
|
-
*
|
|
282
|
-
* What makes it true now is not this paragraph. It is
|
|
262
|
+
* rather than at each of the objects and fields it would otherwise have to be
|
|
263
|
+
* remembered at.
|
|
264
|
+
*
|
|
265
|
+
* **How "every" is enforced.** Not by this paragraph: a claim in a comment is
|
|
266
|
+
* what the next person reads and not what holds. It is
|
|
283
267
|
* `config-zod-messages.test.ts`'s *"a required key that is absent names
|
|
284
|
-
* itself"
|
|
268
|
+
* itself"* — a walk of the exported schema's `required` arrays against a
|
|
285
269
|
* fully-populated document, `oneOf` branches resolved by their discriminator,
|
|
286
|
-
* deleting one key at a time and asserting the message names it.
|
|
287
|
-
*
|
|
288
|
-
*
|
|
289
|
-
*
|
|
270
|
+
* deleting one key at a time and asserting the message names it. The count
|
|
271
|
+
* comes out of the walk rather than off a list, so a required key added to the
|
|
272
|
+
* format later is swept the day it exists, and an object that skips this helper
|
|
273
|
+
* is red before it is merged.
|
|
290
274
|
*/
|
|
291
275
|
const strictObject = (shape) => z.strictObject(namesItsAbsence(shape));
|
|
292
276
|
/**
|
|
@@ -384,35 +368,29 @@ const param = (name) => `\\\${${name}}`;
|
|
|
384
368
|
*/
|
|
385
369
|
const underSlug = (slugKey, snippet) => ({ ...snippet, body: { [slugKey]: snippet.body } });
|
|
386
370
|
/**
|
|
387
|
-
* What an exposed service *is*, in the developer's own words
|
|
371
|
+
* What an exposed service *is*, in the developer's own words.
|
|
388
372
|
*
|
|
389
373
|
* This is what `robot_describe` carries verbatim, so it is read by a model
|
|
390
374
|
* that has never seen this robot and cannot ask a follow-up question.
|
|
391
375
|
* `unit` and `range` already say what a number *is*; this says what it
|
|
392
376
|
* *means*.
|
|
393
377
|
*
|
|
394
|
-
* **It lives on the configuration rather than on the app, and that
|
|
395
|
-
* decision with a cost.**
|
|
396
|
-
*
|
|
397
|
-
*
|
|
398
|
-
*
|
|
399
|
-
* rediscovered as a bug: **two apps can no longer describe one service
|
|
400
|
-
* differently for two audiences.** §17 was reworded in the same wave rather
|
|
401
|
-
* than left contradicting this field.
|
|
378
|
+
* **It lives on the configuration rather than on the app, and that is a
|
|
379
|
+
* decision with a cost.** A description written here is written once per
|
|
380
|
+
* service and is true for every app that reaches the robot, beside the other
|
|
381
|
+
* metadata. What is given up is real and should not be rediscovered as a bug:
|
|
382
|
+
* **two apps cannot describe one service differently for two audiences.**
|
|
402
383
|
*
|
|
403
384
|
* **`.optional()` and not `.nullable().default(null)`, deliberately.** The
|
|
404
385
|
* established shape in this file is a default — and every use of it has
|
|
405
386
|
* added an instance to a known contradiction: `.default()` publishes the
|
|
406
387
|
* field as **required** in the generated JSON Schema, because after parsing
|
|
407
|
-
* it is always present. That is recorded
|
|
408
|
-
*
|
|
409
|
-
*
|
|
410
|
-
*
|
|
411
|
-
*
|
|
412
|
-
*
|
|
413
|
-
* on this pin. So the field simply does not create a fifth instance:
|
|
414
|
-
* optional is optional in both modes, and *absent* is the single spelling of
|
|
415
|
-
* "not described". `.min(1)` keeps the empty string from becoming a second.
|
|
388
|
+
* it is always present. That is recorded in `scripts/export-schemas.ts`, whose
|
|
389
|
+
* remedy (`io: 'input'`, applied per schema) is a judgement call across dozens
|
|
390
|
+
* of schemas and every consumer that vendors them. So this field simply does
|
|
391
|
+
* not add another instance: optional is optional in both modes, and *absent* is
|
|
392
|
+
* the single spelling of "not described". `.min(1)` keeps the empty string from
|
|
393
|
+
* becoming a second.
|
|
416
394
|
*/
|
|
417
395
|
export const serviceDescription = z.string().min(1).max(2000).optional();
|
|
418
396
|
/**
|
|
@@ -673,7 +651,7 @@ export const parameterMap = slugKeyed(parameterSpec)
|
|
|
673
651
|
defaultSnippets: [underSlug('${1:speed}', PARAMETER_SNIPPET)],
|
|
674
652
|
});
|
|
675
653
|
/**
|
|
676
|
-
* Slugs no configured entry may take
|
|
654
|
+
* Slugs no configured entry may take, across **all five exposure
|
|
677
655
|
* sections at once** — slugs are one namespace, so a name reserved here is
|
|
678
656
|
* reserved everywhere.
|
|
679
657
|
*
|
|
@@ -686,12 +664,12 @@ export const parameterMap = slugKeyed(parameterSpec)
|
|
|
686
664
|
* name is the honest half of that: the alternative is a slug the format
|
|
687
665
|
* accepts and one route silently cannot address.
|
|
688
666
|
*
|
|
689
|
-
* **This constant is the only list.** The cloud
|
|
690
|
-
*
|
|
691
|
-
*
|
|
692
|
-
*
|
|
693
|
-
*
|
|
694
|
-
*
|
|
667
|
+
* **This constant is the only list.** The cloud builds its set from it and
|
|
668
|
+
* emits `reserved_slug`; the rename path reads it for the target; an editor
|
|
669
|
+
* reads it for slug suggestion and repairs. Nothing copies the members. Note
|
|
670
|
+
* that it is NOT the enumeration of built-in datapoints — those are kept
|
|
671
|
+
* separately, and must be, because a reserved name exists that nothing
|
|
672
|
+
* publishes.
|
|
695
673
|
*
|
|
696
674
|
* **What it does not do: `robotConfigDoc` does not enforce it.** Reservation is
|
|
697
675
|
* a semantic check that belongs with the ones that need the robot's context,
|
|
@@ -1366,7 +1344,7 @@ const ACTION_SNIPPET = {
|
|
|
1366
1344
|
},
|
|
1367
1345
|
};
|
|
1368
1346
|
/**
|
|
1369
|
-
* An action the robot can be asked to perform
|
|
1347
|
+
* An action the robot can be asked to perform. At most one
|
|
1370
1348
|
* job runs per action slug; a second call is refused `busy`, and every
|
|
1371
1349
|
* observer of the slug watches the same job.
|
|
1372
1350
|
*/
|
|
@@ -1406,7 +1384,7 @@ const SERVICE_SNIPPET = {
|
|
|
1406
1384
|
description: '${4:Resets odometry to the origin.}',
|
|
1407
1385
|
},
|
|
1408
1386
|
};
|
|
1409
|
-
/** A ROS service call with validated parameters
|
|
1387
|
+
/** A ROS service call with validated parameters. */
|
|
1410
1388
|
export const serviceConfig = strictObject({
|
|
1411
1389
|
ros_name: rosName.meta({
|
|
1412
1390
|
description: 'The ROS service the robot answers on, as an absolute graph name. The call is one request and one reply with no progress in between, so whatever this service does has to finish inside that reply; anything long-running belongs in `actions`.',
|
|
@@ -1612,7 +1590,7 @@ export const cameraCredentials = strictObject({
|
|
|
1612
1590
|
}],
|
|
1613
1591
|
});
|
|
1614
1592
|
/**
|
|
1615
|
-
* Where a camera's frames come from
|
|
1593
|
+
* Where a camera's frames come from — one of four sources.
|
|
1616
1594
|
*
|
|
1617
1595
|
* A discriminated union rather than optional fields, so an impossible camera
|
|
1618
1596
|
* is **unrepresentable** rather than merely invalid — there is no way to
|
|
@@ -1686,16 +1664,12 @@ export const cameraSource = z.discriminatedUnion('kind', [
|
|
|
1686
1664
|
description: 'Selects the RTSP source: this camera then carries `url`, and optionally `transport` and `credentials`.',
|
|
1687
1665
|
}),
|
|
1688
1666
|
/**
|
|
1689
|
-
* Scheme-constrained deliberately. The
|
|
1690
|
-
*
|
|
1691
|
-
*
|
|
1692
|
-
*
|
|
1693
|
-
*
|
|
1694
|
-
*
|
|
1695
|
-
* doubling as a file-existence oracle. Spec §7.6 is ROS-pure exposure with
|
|
1696
|
-
* no shell or http features; that rule came back by omission rather than
|
|
1697
|
-
* by intent. The bridge re-checks this too — a robot must not become a
|
|
1698
|
-
* file server because a validator changed.
|
|
1667
|
+
* Scheme-constrained deliberately. The bridge opens these with libraries
|
|
1668
|
+
* that honour `file:` and `ftp:`, so an unconstrained URL turns a
|
|
1669
|
+
* configuration document into an arbitrary local-file read on the robot,
|
|
1670
|
+
* with the two distinct failure codes doubling as a file-existence oracle.
|
|
1671
|
+
* The bridge re-checks this too — a robot must not become a file server
|
|
1672
|
+
* because a validator changed.
|
|
1699
1673
|
*/
|
|
1700
1674
|
url: z
|
|
1701
1675
|
.string()
|
|
@@ -1743,8 +1717,8 @@ export const cameraSource = z.discriminatedUnion('kind', [
|
|
|
1743
1717
|
/**
|
|
1744
1718
|
* The host and the path this branch's own snippet body inserts, and the
|
|
1745
1719
|
* URL its rule sentence names — one answer to "what goes here?", not a
|
|
1746
|
-
* third.
|
|
1747
|
-
*
|
|
1720
|
+
* third. Every URL position in the format carries an example; a silent
|
|
1721
|
+
* one is the position a developer has to guess at.
|
|
1748
1722
|
*/
|
|
1749
1723
|
examples: ['http://cam-1.plant.local/video.mjpg'],
|
|
1750
1724
|
}),
|
|
@@ -1769,16 +1743,14 @@ export const cameraSource = z.discriminatedUnion('kind', [
|
|
|
1769
1743
|
* on the robot, never by the cloud.
|
|
1770
1744
|
*
|
|
1771
1745
|
* Constrained to `/dev/` for the same reason the `rtsp` and `mjpeg` URLs
|
|
1772
|
-
* are constrained to their schemes
|
|
1773
|
-
* (Momus, W6 verification). The device string reaches
|
|
1746
|
+
* are constrained to their schemes. The device string reaches
|
|
1774
1747
|
* `cv2.VideoCapture(device)` on the robot, and OpenCV does not restrict
|
|
1775
|
-
* itself to devices:
|
|
1776
|
-
*
|
|
1777
|
-
*
|
|
1778
|
-
*
|
|
1779
|
-
*
|
|
1780
|
-
*
|
|
1781
|
-
* reason not to check.
|
|
1748
|
+
* itself to devices: an ordinary local video file opens and its pixels are
|
|
1749
|
+
* published to the cloud, and so does an `http://` URL pointing back inside
|
|
1750
|
+
* the robot's own network. Unconstrained, this field is an arbitrary
|
|
1751
|
+
* local-file read *and* an outbound fetch from inside the robot — the same
|
|
1752
|
+
* hole closed for the other two source kinds, reachable through the fourth,
|
|
1753
|
+
* because "it is just a device path" reads like a reason not to check.
|
|
1782
1754
|
*
|
|
1783
1755
|
* Narrower than the URL hole in one respect worth recording: a non-media
|
|
1784
1756
|
* file and a missing file both fail to open, so this branch never worked
|
|
@@ -1851,14 +1823,14 @@ const CAMERA_SNIPPET = {
|
|
|
1851
1823
|
},
|
|
1852
1824
|
};
|
|
1853
1825
|
/**
|
|
1854
|
-
* A camera the robot exposes
|
|
1826
|
+
* A camera the robot exposes.
|
|
1855
1827
|
*
|
|
1856
|
-
* `width`/`height`/`fps`/`bitrate_kbps` are not cosmetic:
|
|
1828
|
+
* `width`/`height`/`fps`/`bitrate_kbps` are not cosmetic: they are the
|
|
1857
1829
|
* developer's control over **the robot's own bandwidth**, which is why they
|
|
1858
1830
|
* live in the configuration rather than in a viewer's request. A viewer never
|
|
1859
1831
|
* gets to make a robot send more.
|
|
1860
1832
|
*
|
|
1861
|
-
* The two modes are deliberately independent
|
|
1833
|
+
* The two modes are deliberately independent:
|
|
1862
1834
|
*
|
|
1863
1835
|
* - **Snapshot** runs always, at `snapshot_interval_seconds`, whether or not
|
|
1864
1836
|
* anyone is watching live. The cloud caches the one frame and serves every
|
|
@@ -1913,7 +1885,7 @@ const capped = (entry, max, what) => slugKeyed(entry).refine((m) => Object.keys(
|
|
|
1913
1885
|
* their own name. A duplicate name is then a YAML syntax error rather than a
|
|
1914
1886
|
* rule somebody has to write, and the name reads as the entry's heading.
|
|
1915
1887
|
*
|
|
1916
|
-
* Slugs remain ONE namespace across all five exposure sections
|
|
1888
|
+
* Slugs remain ONE namespace across all five exposure sections, which
|
|
1917
1889
|
* is what lets a role grant say `{robot, slug}` without naming a kind. That
|
|
1918
1890
|
* check spans sections and therefore lives in the cloud, not here.
|
|
1919
1891
|
*/
|
|
@@ -1950,12 +1922,12 @@ export const robotConfigDoc = strictObject({
|
|
|
1950
1922
|
}).optional(),
|
|
1951
1923
|
});
|
|
1952
1924
|
/**
|
|
1953
|
-
* One thing the cloud has to say about a configuration
|
|
1954
|
-
*
|
|
1925
|
+
* One thing the cloud has to say about a configuration: the field, and the
|
|
1926
|
+
* rule it violates.
|
|
1955
1927
|
*
|
|
1956
1928
|
* `error` blocks the publish. `warning` does not — an unknown topic is a
|
|
1957
|
-
* warning on purpose, because configuring a robot that has never been
|
|
1958
|
-
*
|
|
1929
|
+
* warning on purpose, because configuring a robot that has never been connected
|
|
1930
|
+
* must stay possible.
|
|
1959
1931
|
*/
|
|
1960
1932
|
export const validationIssue = z.object({
|
|
1961
1933
|
path: z.string().min(1),
|
|
@@ -1966,8 +1938,7 @@ export const validationIssue = z.object({
|
|
|
1966
1938
|
});
|
|
1967
1939
|
/**
|
|
1968
1940
|
* Where a robot's configuration stands — the material for the console's
|
|
1969
|
-
* "draft newer than published", "published v2 · applied v1 · bridge offline"
|
|
1970
|
-
* (spec §15.2, robot tab 1).
|
|
1941
|
+
* "draft newer than published", "published v2 · applied v1 · bridge offline".
|
|
1971
1942
|
*/
|
|
1972
1943
|
export const configState = z.object({
|
|
1973
1944
|
published_version: z.number().int().positive().nullable(),
|
package/dist/errors.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
2
|
import { z } from 'zod';
|
|
2
3
|
/**
|
|
3
|
-
* The one error shape of the REST and realtime APIs
|
|
4
|
+
* The one error shape of the REST and realtime APIs: a stable
|
|
4
5
|
* machine-readable code plus a human message; validation errors name the
|
|
5
6
|
* field and the violated rule in `details`.
|
|
6
7
|
*/
|
|
@@ -11,7 +12,7 @@ export declare const apiError: z.ZodObject<{
|
|
|
11
12
|
}, z.core.$strip>;
|
|
12
13
|
export type ApiError = z.infer<typeof apiError>;
|
|
13
14
|
/**
|
|
14
|
-
* One violated
|
|
15
|
+
* One violated parameter rule. `details` on the envelope stays `unknown` — codes
|
|
15
16
|
* are an open set, so their payloads cannot all be enumerated — but the
|
|
16
17
|
* payload of `parameter_invalid` **is** pinned here, because otherwise every
|
|
17
18
|
* consumer guesses: the cloud emits one shape, the SDK sniffs for two, the
|
|
@@ -44,7 +45,7 @@ export declare const parameterInvalidDetails: z.ZodObject<{
|
|
|
44
45
|
}, z.core.$strip>;
|
|
45
46
|
export type ParameterInvalidDetails = z.infer<typeof parameterInvalidDetails>;
|
|
46
47
|
/**
|
|
47
|
-
* The codes in use
|
|
48
|
+
* The codes in use today. The wire deliberately allows any string — this
|
|
48
49
|
* list is the shared vocabulary, not a closed set, so a new refusal never
|
|
49
50
|
* needs a contracts release before it can be reported honestly.
|
|
50
51
|
*/
|