@fleetless/contracts 1.1.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -1
- package/artifacts/constants.json +30 -4
- package/artifacts/openapi.json +667 -98
- package/artifacts/routes.json +97 -6
- package/artifacts/schema/apply-error.schema.json +2 -1
- package/artifacts/schema/asset-list-response.schema.json +77 -12
- package/artifacts/schema/asset-sync-status.schema.json +35 -8
- package/artifacts/schema/asset.schema.json +2 -3
- package/artifacts/schema/assets-clear-response.schema.json +23 -0
- package/artifacts/schema/authorization-server-metadata.schema.json +1 -1
- package/artifacts/schema/bridge-asset-progress.schema.json +14 -8
- package/artifacts/schema/bridge-config-applied.schema.json +2 -1
- package/artifacts/schema/bridge-link-mode.schema.json +36 -0
- package/artifacts/schema/bridge-state.schema.json +6 -1
- package/artifacts/schema/client-robot-list-item.schema.json +6 -1
- package/artifacts/schema/client-robot-list-response.schema.json +6 -1
- package/artifacts/schema/cloud-config.schema.json +90 -5
- package/artifacts/schema/cloud-hello-ok.schema.json +45 -0
- package/artifacts/schema/cloud-ping.schema.json +27 -1
- package/artifacts/schema/config-draft-response.schema.json +90 -5
- package/artifacts/schema/config-state.schema.json +2 -1
- package/artifacts/schema/config-version-response.schema.json +90 -5
- package/artifacts/schema/datapoint-config.schema.json +5 -0
- package/artifacts/schema/datapoint-frame.schema.json +4 -0
- package/artifacts/schema/datapoint-list-response.schema.json +2 -2
- package/artifacts/schema/dynamic-client-registration-request.schema.json +1 -1
- package/artifacts/schema/dynamic-client-registration-response.schema.json +1 -1
- package/artifacts/schema/joint-state-put-request.schema.json +23 -0
- package/artifacts/schema/joint-state-put-response.schema.json +24 -0
- package/artifacts/schema/oauth-token-request.schema.json +79 -41
- package/artifacts/schema/oauth-token-response.schema.json +1 -1
- package/artifacts/schema/org-quota-usage-counts.schema.json +0 -5
- package/artifacts/schema/org-quota-usage.schema.json +1 -12
- package/artifacts/schema/org-quotas.schema.json +1 -7
- package/artifacts/schema/robot-config-doc.schema.json +90 -5
- package/artifacts/schema/robot-deletion-summary.schema.json +2 -1
- package/artifacts/schema/robot-detail-response.schema.json +63 -2
- package/artifacts/schema/robot-list-item.schema.json +15 -1
- package/artifacts/schema/robot-list-response.schema.json +15 -1
- package/artifacts/schema/robot-token-rotate-response.schema.json +15 -0
- package/artifacts/schema-outgoing/bridge-asset-progress.schema.json +14 -8
- package/artifacts/schema-outgoing/bridge-config-applied.schema.json +2 -1
- package/artifacts/schema-outgoing/bridge-link-mode.schema.json +37 -0
- package/artifacts/schema-outgoing/datapoint-frame.schema.json +4 -0
- package/dist/assets.d.ts +85 -50
- package/dist/assets.js +152 -62
- package/dist/audit.d.ts +1 -1
- package/dist/audit.js +1 -1
- package/dist/client-robots.d.ts +2 -0
- package/dist/common.d.ts +10 -0
- package/dist/common.js +16 -1
- package/dist/config.d.ts +69 -1
- package/dist/config.js +86 -6
- package/dist/errors.d.ts +1 -1
- package/dist/errors.js +1 -8
- package/dist/index.d.ts +10 -10
- package/dist/index.js +5 -5
- package/dist/oauth.d.ts +34 -19
- package/dist/oauth.js +39 -24
- package/dist/protocol.d.ts +150 -71
- package/dist/protocol.js +144 -87
- package/dist/rest.d.ts +137 -35
- package/dist/rest.js +98 -66
- package/dist/routes.js +68 -19
- package/package.json +1 -1
- package/artifacts/schema/bridge-pressure.schema.json +0 -292
package/dist/protocol.js
CHANGED
|
@@ -7,18 +7,79 @@ import { rosGraph, typeDefinition } from './introspection.js';
|
|
|
7
7
|
import { jobState } from './jobs.js';
|
|
8
8
|
import { rosTypeName } from './common.js';
|
|
9
9
|
/**
|
|
10
|
-
* Bridge <-> cloud protocol, version
|
|
10
|
+
* Bridge <-> cloud protocol, version 3.
|
|
11
11
|
*
|
|
12
|
-
* The version is exchanged in the hello handshake
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* The version is exchanged in the hello handshake. Since 2026-09 the cloud
|
|
13
|
+
* serves a **window** of versions, not one: every entry of
|
|
14
|
+
* `PROTOCOL_VERSIONS` whose sunset has not passed. A version is deprecated
|
|
15
|
+
* by the cloud release that supersedes it and sunset `PROTOCOL_SUNSET_DAYS`
|
|
16
|
+
* later. Outside the window the cloud refuses with `protocol_mismatch`,
|
|
17
|
+
* which names the window and reaches the robot's detail view as
|
|
18
|
+
* `last_hello_error`.
|
|
19
|
+
*
|
|
20
|
+
* **3 (2026-09-22):** the ping carries `latency_ms` and `lag_ms`, the bridge
|
|
21
|
+
* sends `link_mode`, `bridge_state` gains `low_bandwidth`, and the
|
|
22
|
+
* `bridge_pressure` datapoint is gone. A protocol-2 bridge is served until
|
|
23
|
+
* its sunset, and the cloud's protocol-2 adapter owes it two translations on
|
|
24
|
+
* the way in: it drops its pressure datapoints, and it rewrites an
|
|
25
|
+
* `asset_progress` failure of kind `too_large` — a kind protocol 3 no longer
|
|
26
|
+
* has — to `refused` with `details: null`, because a 2.0.0 `bridgeAssetProgress`
|
|
27
|
+
* refuses the frame outright otherwise.
|
|
15
28
|
*
|
|
16
29
|
* **2 (2026-08-21):** `config_applied.errors` entries gained `kind` and `code`
|
|
17
|
-
* beside `message`.
|
|
18
|
-
|
|
19
|
-
|
|
30
|
+
* beside `message`.
|
|
31
|
+
*/
|
|
32
|
+
export const PROTOCOL_VERSION = 3;
|
|
33
|
+
/** Days between a version's deprecation and its sunset. */
|
|
34
|
+
export const PROTOCOL_SUNSET_DAYS = 90;
|
|
35
|
+
/**
|
|
36
|
+
* Every protocol version the cloud has served, oldest first. A test keeps
|
|
37
|
+
* exactly one entry current and equal to `PROTOCOL_VERSION`; `test/changelog.test.ts`
|
|
38
|
+
* requires the CHANGELOG's current section to name the newest `bridge_from`
|
|
39
|
+
* and the previous entry's `sunsetOf(...)` date, and `scripts/verify-version-tag.mjs`
|
|
40
|
+
* requires a dated heading for the tag being released.
|
|
41
|
+
*/
|
|
42
|
+
export const PROTOCOL_VERSIONS = [
|
|
43
|
+
{ version: 2, bridge_from: '3.0.0', deprecated_at: '2026-09-22' },
|
|
44
|
+
{ version: 3, bridge_from: '4.0.0', deprecated_at: null },
|
|
45
|
+
];
|
|
46
|
+
/** The newest bridge package. The cloud mails organisations still below it. */
|
|
47
|
+
export const LATEST_BRIDGE_VERSION = '4.0.0';
|
|
48
|
+
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
49
|
+
function isoDate(date) {
|
|
50
|
+
return date.toISOString().slice(0, 10);
|
|
51
|
+
}
|
|
52
|
+
export function sunsetOf(entry) {
|
|
53
|
+
if (entry.deprecated_at === null)
|
|
54
|
+
return null;
|
|
55
|
+
return isoDate(new Date(Date.parse(entry.deprecated_at + 'T00:00:00Z') + PROTOCOL_SUNSET_DAYS * DAY_MS));
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The window rule itself: `protocolStatus` and `minimumProtocolVersion` are
|
|
59
|
+
* this function over `PROTOCOL_VERSIONS`, and the cloud calls it directly.
|
|
60
|
+
*
|
|
61
|
+
* The table is a parameter because callers pass one with a deprecated entry —
|
|
62
|
+
* tests, and any caller reasoning about a sunset. The real table has none
|
|
63
|
+
* until the first bump, so a hard-coded `PROTOCOL_VERSIONS` would leave the
|
|
64
|
+
* deprecated and unsupported branches unreachable.
|
|
20
65
|
*/
|
|
21
|
-
export
|
|
66
|
+
export function statusFromTable(table, version, today) {
|
|
67
|
+
const entry = table.find((candidate) => candidate.version === version);
|
|
68
|
+
if (!entry)
|
|
69
|
+
return { status: 'unsupported', sunset_at: null };
|
|
70
|
+
const sunset = sunsetOf(entry);
|
|
71
|
+
if (sunset === null)
|
|
72
|
+
return { status: 'current', sunset_at: null };
|
|
73
|
+
return { status: isoDate(today) < sunset ? 'deprecated' : 'unsupported', sunset_at: sunset };
|
|
74
|
+
}
|
|
75
|
+
export function protocolStatus(version, today = new Date()) {
|
|
76
|
+
return statusFromTable(PROTOCOL_VERSIONS, version, today);
|
|
77
|
+
}
|
|
78
|
+
/** The lowest version still inside its window today. */
|
|
79
|
+
export function minimumProtocolVersion(today = new Date()) {
|
|
80
|
+
const alive = PROTOCOL_VERSIONS.filter((entry) => statusFromTable(PROTOCOL_VERSIONS, entry.version, today).status !== 'unsupported');
|
|
81
|
+
return alive[0]?.version ?? PROTOCOL_VERSION;
|
|
82
|
+
}
|
|
22
83
|
/**
|
|
23
84
|
* The bridge socket close code for "this robot no longer exists".
|
|
24
85
|
*
|
|
@@ -30,6 +91,20 @@ export const PROTOCOL_VERSION = 2;
|
|
|
30
91
|
* more informative than "connection closed".
|
|
31
92
|
*/
|
|
32
93
|
export const CLOSE_ROBOT_DELETED = 4004;
|
|
94
|
+
/**
|
|
95
|
+
* The bridge socket close code for "the token you connected with is gone".
|
|
96
|
+
*
|
|
97
|
+
* The cloud closes a robot's live socket with this after the robot's token was
|
|
98
|
+
* rotated. A 4.0.0 bridge reads it the way it reads `invalid_token` — stop,
|
|
99
|
+
* exit 2 — because the secret it holds is no longer a secret anyone accepts,
|
|
100
|
+
* and no amount of reconnecting produces the new one. A 3.x bridge does not
|
|
101
|
+
* know the code, reconnects, and is refused at hello; that ends the same way,
|
|
102
|
+
* one round trip later.
|
|
103
|
+
*
|
|
104
|
+
* Its own code rather than `CLOSE_ROBOT_DELETED`, which would tell an operator
|
|
105
|
+
* their robot had been deleted when it very much still exists.
|
|
106
|
+
*/
|
|
107
|
+
export const CLOSE_TOKEN_ROTATED = 4005;
|
|
33
108
|
/**
|
|
34
109
|
* How long a command waits for its answer when the caller names no patience
|
|
35
110
|
* of its own.
|
|
@@ -120,10 +195,35 @@ export const bridgeHello = z.object({
|
|
|
120
195
|
*/
|
|
121
196
|
active_jobs: z.array(activeJob).max(500).default([]),
|
|
122
197
|
});
|
|
123
|
-
/**
|
|
198
|
+
/**
|
|
199
|
+
* Cloud accepts the bridge: the robot is online from here on.
|
|
200
|
+
*
|
|
201
|
+
* `protocol` and `bridge` are optional so that a bridge parsing `hello_ok`
|
|
202
|
+
* strictly still parses one from an older cloud. `status` here is never
|
|
203
|
+
* `unsupported`: an unsupported version gets `hello_error`, not this frame.
|
|
204
|
+
*/
|
|
124
205
|
export const cloudHelloOk = z.object({
|
|
125
206
|
type: z.literal('hello_ok'),
|
|
126
207
|
robot_id: z.uuid(),
|
|
208
|
+
protocol: z
|
|
209
|
+
.object({
|
|
210
|
+
status: z.enum(['current', 'deprecated']).meta({
|
|
211
|
+
description: '`current` or `deprecated` — never `unsupported`, which is a `hello_error`.',
|
|
212
|
+
}),
|
|
213
|
+
sunset_at: z.iso.date().nullable().meta({
|
|
214
|
+
description: 'ISO date a deprecated version stops being served; `null` when current.',
|
|
215
|
+
}),
|
|
216
|
+
})
|
|
217
|
+
.optional()
|
|
218
|
+
.meta({ description: "The cloud's verdict on the announced protocol version; absent from an older cloud." }),
|
|
219
|
+
bridge: z
|
|
220
|
+
.object({
|
|
221
|
+
latest_version: z.string().min(1).meta({
|
|
222
|
+
description: "The newest published fleetless-bridge package version, for the bridge's own upgrade hint.",
|
|
223
|
+
}),
|
|
224
|
+
})
|
|
225
|
+
.optional()
|
|
226
|
+
.meta({ description: 'What the cloud knows about bridge packages; absent from an older cloud.' }),
|
|
127
227
|
});
|
|
128
228
|
/** Cloud refuses the bridge (bad token, incompatible protocol, ...). */
|
|
129
229
|
export const cloudHelloError = z.object({
|
|
@@ -134,27 +234,57 @@ export const cloudHelloError = z.object({
|
|
|
134
234
|
/**
|
|
135
235
|
* One datapoint sample. `timestamp_ms` is the capture time at the bridge —
|
|
136
236
|
* never the receive time — so clients compute age themselves.
|
|
237
|
+
*
|
|
238
|
+
* Which is exactly why `backfill` has to be on the frame. A replayed sample
|
|
239
|
+
* carries the capture time it had during the outage, so a cloud that measures
|
|
240
|
+
* lag from every arriving frame reads a two-hour disconnect as two hours of
|
|
241
|
+
* lag the moment the bridge reconnects — and reports a healthy link as the
|
|
242
|
+
* worst one it has ever seen. Only the bridge knows which frames came out of
|
|
243
|
+
* its buffer, so only the bridge can say.
|
|
137
244
|
*/
|
|
138
245
|
export const datapointFrame = z.object({
|
|
139
246
|
type: z.literal('datapoint'),
|
|
140
247
|
slug,
|
|
141
248
|
value: z.unknown(),
|
|
142
249
|
timestamp_ms: z.number().int().nonnegative(),
|
|
250
|
+
backfill: z.boolean().optional().meta({ description: 'true when the sample was captured while the bridge was disconnected and is being replayed after the reconnect. The cloud keeps such a sample out of its lag measure; absent means live.' }),
|
|
143
251
|
});
|
|
144
252
|
/**
|
|
145
253
|
* Latency probe, cloud → bridge. The cloud sends its own clock in `ts_ms`;
|
|
146
254
|
* the bridge echoes it back untouched and the cloud derives the round-trip
|
|
147
255
|
* latency shown as `bridge_state.latency_ms`.
|
|
256
|
+
*
|
|
257
|
+
* Sent every `pingIntervalMs`; the bridge answers with `pong`. Since protocol
|
|
258
|
+
* 3 it also carries what the cloud measured about this link, so the bridge
|
|
259
|
+
* can decide on its low-bandwidth mode with an end-to-end number: the
|
|
260
|
+
* round trip of the last pong, and the datapoint lag — the median over the
|
|
261
|
+
* last five seconds of (receive time − `timestamp_ms`) minus the minimum of
|
|
262
|
+
* the last ten minutes, which cancels the robot's clock offset. `null` until
|
|
263
|
+
* the cloud has a sample. A protocol-2 bridge reads only `ts_ms`.
|
|
148
264
|
*/
|
|
149
265
|
export const cloudPing = z.object({
|
|
150
266
|
type: z.literal('ping'),
|
|
151
267
|
ts_ms: z.number().int().nonnegative(),
|
|
268
|
+
latency_ms: z.number().nonnegative().nullable().meta({ description: 'Round trip of the last pong in milliseconds; null before the first.' }),
|
|
269
|
+
lag_ms: z.number().nonnegative().nullable().meta({ description: 'Datapoint lag over the link: median of the last five seconds minus the ten-minute minimum, in milliseconds; null until a sample exists, and null again whenever no live sample arrived in the last five seconds, because a stale median would be a lie.' }),
|
|
152
270
|
});
|
|
153
271
|
/** Immediate bridge answer to a `CloudPing`, `ts_ms` echoed unchanged. */
|
|
154
272
|
export const bridgePong = z.object({
|
|
155
273
|
type: z.literal('pong'),
|
|
156
274
|
ts_ms: z.number().int().nonnegative(),
|
|
157
275
|
});
|
|
276
|
+
/**
|
|
277
|
+
* The bridge's low-bandwidth mode changed. Sent on every transition and once
|
|
278
|
+
* after `hello_ok`, at tier 0 like the pong: the cloud folds it into
|
|
279
|
+
* `bridge_state.low_bandwidth`, and a frame that waited behind bulk would
|
|
280
|
+
* describe a state that is already over.
|
|
281
|
+
*/
|
|
282
|
+
export const bridgeLinkMode = z.object({
|
|
283
|
+
type: z.literal('link_mode'),
|
|
284
|
+
low_bandwidth: z.boolean().meta({ description: 'Whether the mode is active after this transition.' }),
|
|
285
|
+
reason: z.enum(['lag', 'dwell', 'forced', 'recovered']).meta({ description: '`lag`: the cloud-measured lag crossed the threshold; `dwell`: the bridge-measured queue dwell did; `forced`: `mode: on` or `off`; `recovered`: both measures stayed at or below the exit threshold.' }),
|
|
286
|
+
at_ms: z.number().int().nonnegative().meta({ description: 'Bridge time of the transition, epoch milliseconds.' }),
|
|
287
|
+
});
|
|
158
288
|
/**
|
|
159
289
|
* The published configuration, cloud → bridge — the bridge applies the
|
|
160
290
|
* published version. Sent right after `hello_ok` and again on every publish,
|
|
@@ -350,89 +480,16 @@ export const bridgeTypeDefinitions = z.object({
|
|
|
350
480
|
/**
|
|
351
481
|
* The built-in `bridge_state` datapoint every robot has: connection status
|
|
352
482
|
* plus latency, the basis for offline-aware client UIs.
|
|
483
|
+
*
|
|
484
|
+
* `online` and `latency_ms` are cloud-observed (the socket, the pong);
|
|
485
|
+
* `low_bandwidth` is bridge-reported through `link_mode` and `false` for a
|
|
486
|
+
* bridge that never sends one.
|
|
353
487
|
*/
|
|
354
488
|
export const bridgeState = z.object({
|
|
355
489
|
online: z.boolean(),
|
|
356
490
|
latency_ms: z.number().nonnegative().nullable(),
|
|
491
|
+
low_bandwidth: z.boolean().meta({ description: 'Whether the bridge is in its low-bandwidth mode: datapoints capped, cameras reduced or stopped. Bridge-reported.' }),
|
|
357
492
|
});
|
|
358
|
-
/** One tier's counters, `tiers` below carries six of these under string keys. */
|
|
359
|
-
const bridgePressureTier = z.object({
|
|
360
|
-
sent: z.number().int().nonnegative(),
|
|
361
|
-
bytes: z.number().int().nonnegative(),
|
|
362
|
-
drops: z.number().int().nonnegative(),
|
|
363
|
-
high_water: z.number().int().nonnegative(),
|
|
364
|
-
});
|
|
365
|
-
/**
|
|
366
|
-
* The built-in `bridge_pressure` datapoint: the bridge's own
|
|
367
|
-
* bandwidth-shaping state, sent on the same reserved-slug path as
|
|
368
|
-
* `bridge_state` so history, realtime, REST and MCP exposure fall out of the
|
|
369
|
-
* ordinary datapoint machinery for free.
|
|
370
|
-
*/
|
|
371
|
-
export const bridgePressure = z.object({
|
|
372
|
-
link: z.object({
|
|
373
|
-
/** bytes/s the socket demonstrably drains, from sends >= 64 KiB
|
|
374
|
-
* only; null until the first large send of the session. */
|
|
375
|
-
rate_bps: z.number().nonnegative().nullable(),
|
|
376
|
-
/**
|
|
377
|
-
* the byte target snapshots are currently encoded to fit.
|
|
378
|
-
*
|
|
379
|
-
* `.nonnegative()`, not `.positive()`: the target is derived from
|
|
380
|
-
* `rate_bps`, and a link measured below 0.5 B/s floors to 0 here. A
|
|
381
|
-
* schema that rejects 0 does not prevent that link — it only makes the
|
|
382
|
-
* frame reporting it unparseable, and a console that cannot parse a
|
|
383
|
-
* pressure frame shows "no feed", i.e. reports a struggling robot as an
|
|
384
|
-
* *old* one. Zero is a legitimate reading and says something true.
|
|
385
|
-
*/
|
|
386
|
-
snapshot_max_bytes: z.number().int().nonnegative(),
|
|
387
|
-
}),
|
|
388
|
-
/**
|
|
389
|
-
* String keys "0".."5" because JSON has no integer keys. Counters are
|
|
390
|
-
* cumulative per session and reset on reconnect; clients window by
|
|
391
|
-
* differencing two samples.
|
|
392
|
-
*
|
|
393
|
-
* **What this schema does not decide:** it does not guarantee all six
|
|
394
|
-
* keys are present (`z.record` over the six literals is exhaustive in
|
|
395
|
-
* zod 4 — tested here, it required every key and rejected none, the
|
|
396
|
-
* opposite of what a partial sample needs — so this is a
|
|
397
|
-
* `.strictObject().partial()` over the same six literal keys instead, a
|
|
398
|
-
* deliberate deviation from the originally sketched `z.record` shape with
|
|
399
|
-
* the same runtime behaviour). A missing tier key reads as zeros; the
|
|
400
|
-
* schema names what it cannot decide rather than implying a completeness
|
|
401
|
-
* it cannot check.
|
|
402
|
-
*/
|
|
403
|
-
tiers: z
|
|
404
|
-
.strictObject({
|
|
405
|
-
'0': bridgePressureTier,
|
|
406
|
-
'1': bridgePressureTier,
|
|
407
|
-
'2': bridgePressureTier,
|
|
408
|
-
'3': bridgePressureTier,
|
|
409
|
-
'4': bridgePressureTier,
|
|
410
|
-
'5': bridgePressureTier,
|
|
411
|
-
})
|
|
412
|
-
.partial(),
|
|
413
|
-
video: z.object({
|
|
414
|
-
active_streams: z.number().int().nonnegative(),
|
|
415
|
-
bitrate_sum_kbps: z.number().int().nonnegative(),
|
|
416
|
-
/**
|
|
417
|
-
* The uplink budget the bridge was configured with
|
|
418
|
-
* (`FLEETLESS_UPLINK_KBPS`), or `null` when none was set.
|
|
419
|
-
*
|
|
420
|
-
* `.nonnegative()`, not `.positive()`: `FLEETLESS_UPLINK_KBPS=0` is a
|
|
421
|
-
* documented setting meaning "no video budget at all", and the bridge
|
|
422
|
-
* emits that 0 verbatim. `.positive()` made every frame from such a
|
|
423
|
-
* robot fail the console's `safeParse`, which renders an unparseable
|
|
424
|
-
* frame as "no pressure feed" — so the one robot that had *deliberately*
|
|
425
|
-
* turned video off was the one diagnosed as running a bridge too old to
|
|
426
|
-
* report pressure. A value the producer legitimately sends must parse;
|
|
427
|
-
* `null` is the only "not set" this field has.
|
|
428
|
-
*/
|
|
429
|
-
uplink_kbps: z.number().int().nonnegative().nullable(),
|
|
430
|
-
override_kbps: z.number().int().nonnegative().nullable(),
|
|
431
|
-
video_budget_kbps: z.number().int().nonnegative().nullable(),
|
|
432
|
-
reserve_kbps: z.number().int().nonnegative(),
|
|
433
|
-
}),
|
|
434
|
-
});
|
|
435
|
-
export const PRESSURE_SLUG = 'bridge_pressure';
|
|
436
493
|
/* ------------------------------------------------------------------------
|
|
437
494
|
* Cameras.
|
|
438
495
|
*/
|
package/dist/rest.d.ts
CHANGED
|
@@ -37,6 +37,39 @@ export declare const createRobotResponse: z.ZodObject<{
|
|
|
37
37
|
token: z.ZodString;
|
|
38
38
|
}, z.core.$strip>;
|
|
39
39
|
export type CreateRobotResponse = z.infer<typeof createRobotResponse>;
|
|
40
|
+
/**
|
|
41
|
+
* What a rotation hands back: the new token, once.
|
|
42
|
+
*
|
|
43
|
+
* The same shape as the creation response minus the robot, because nothing
|
|
44
|
+
* about the robot changed — only its credential. `createRobotResponse`'s own
|
|
45
|
+
* rule applies unchanged: the cloud stores a hash, so this is the only moment
|
|
46
|
+
* the raw token exists outside the caller's hands.
|
|
47
|
+
*/
|
|
48
|
+
export declare const robotTokenRotateResponse: z.ZodObject<{
|
|
49
|
+
token: z.ZodString;
|
|
50
|
+
}, z.core.$strip>;
|
|
51
|
+
export type RobotTokenRotateResponse = z.infer<typeof robotTokenRotateResponse>;
|
|
52
|
+
/**
|
|
53
|
+
* Which datapoint drives the joints of this robot's URDF, or none.
|
|
54
|
+
*
|
|
55
|
+
* `null` is the clearing value, which is why `slug` is required rather than
|
|
56
|
+
* optional: an absent field and a cleared mapping would be the same request
|
|
57
|
+
* and mean different things, and the one a client sends by accident is the
|
|
58
|
+
* first.
|
|
59
|
+
*
|
|
60
|
+
* The cloud refuses a slug that is not a whole-message
|
|
61
|
+
* `sensor_msgs/msg/JointState` datapoint of the **published** document — a
|
|
62
|
+
* mapping that may point anywhere is a viewer animating a battery reading.
|
|
63
|
+
*/
|
|
64
|
+
export declare const jointStatePutRequest: z.ZodObject<{
|
|
65
|
+
slug: z.ZodNullable<z.ZodString>;
|
|
66
|
+
}, z.core.$strip>;
|
|
67
|
+
export type JointStatePutRequest = z.infer<typeof jointStatePutRequest>;
|
|
68
|
+
/** The mapping as it now stands — the same field `GET /api/robots/:id/assets` reports. */
|
|
69
|
+
export declare const jointStatePutResponse: z.ZodObject<{
|
|
70
|
+
joint_state_slug: z.ZodNullable<z.ZodString>;
|
|
71
|
+
}, z.core.$strip>;
|
|
72
|
+
export type JointStatePutResponse = z.infer<typeof jointStatePutResponse>;
|
|
40
73
|
/**
|
|
41
74
|
* How many things a robot exposes, per kind.
|
|
42
75
|
*
|
|
@@ -46,18 +79,17 @@ export type CreateRobotResponse = z.infer<typeof createRobotResponse>;
|
|
|
46
79
|
*
|
|
47
80
|
* **Counted from the published configuration, and excluding the built-ins.**
|
|
48
81
|
* `GET /api/robots/:id/exposures` answers *which* slugs and prepends the
|
|
49
|
-
*
|
|
50
|
-
* `
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
* prevent.
|
|
82
|
+
* built-in datapoints — `bridge_state` and `robot_details` — as
|
|
83
|
+
* `builtin: true`; this answers *how many* and counts only what somebody
|
|
84
|
+
* configured. So a robot with an empty published config reports
|
|
85
|
+
* `datapoints: 0` here and two entries there. That is intentional, and it is
|
|
86
|
+
* written on both sides so the disagreement is never mistaken for a bug.
|
|
87
|
+
*
|
|
88
|
+
* The number was "three" while `bridge_pressure` existed and is "two" since
|
|
89
|
+
* protocol 3 dropped it; the cloud builds that prefix from its own built-in
|
|
90
|
+
* set rather than a literal, so the next built-in moves this count again.
|
|
91
|
+
* Read the count off that set, not off this sentence, before filing the bug
|
|
92
|
+
* this comment exists to prevent.
|
|
61
93
|
*/
|
|
62
94
|
export declare const exposureCounts: z.ZodObject<{
|
|
63
95
|
datapoints: z.ZodNumber;
|
|
@@ -67,11 +99,24 @@ export declare const exposureCounts: z.ZodObject<{
|
|
|
67
99
|
cameras: z.ZodNumber;
|
|
68
100
|
}, z.core.$strip>;
|
|
69
101
|
export type ExposureCounts = z.infer<typeof exposureCounts>;
|
|
102
|
+
/**
|
|
103
|
+
* Where a robot's bridge stands against the protocol window.
|
|
104
|
+
* `refused`: its last hello was refused for its version — it is offline
|
|
105
|
+
* until upgraded. Computed by the cloud from `protocol_version` and
|
|
106
|
+
* `last_hello_error`, never stored.
|
|
107
|
+
*/
|
|
108
|
+
export declare const protocolStatusValue: z.ZodEnum<{
|
|
109
|
+
deprecated: "deprecated";
|
|
110
|
+
refused: "refused";
|
|
111
|
+
current: "current";
|
|
112
|
+
}>;
|
|
113
|
+
export type ProtocolStatusValue = z.infer<typeof protocolStatusValue>;
|
|
70
114
|
/** A robot as listed, with its current built-in `bridge_state`. */
|
|
71
115
|
export declare const robotListItem: z.ZodObject<{
|
|
72
116
|
bridge_state: z.ZodObject<{
|
|
73
117
|
online: z.ZodBoolean;
|
|
74
118
|
latency_ms: z.ZodNullable<z.ZodNumber>;
|
|
119
|
+
low_bandwidth: z.ZodBoolean;
|
|
75
120
|
}, z.core.$strip>;
|
|
76
121
|
exposes: z.ZodObject<{
|
|
77
122
|
datapoints: z.ZodNumber;
|
|
@@ -80,6 +125,11 @@ export declare const robotListItem: z.ZodObject<{
|
|
|
80
125
|
publishers: z.ZodNumber;
|
|
81
126
|
cameras: z.ZodNumber;
|
|
82
127
|
}, z.core.$strip>;
|
|
128
|
+
protocol_status: z.ZodOptional<z.ZodEnum<{
|
|
129
|
+
deprecated: "deprecated";
|
|
130
|
+
refused: "refused";
|
|
131
|
+
current: "current";
|
|
132
|
+
}>>;
|
|
83
133
|
id: z.ZodUUID;
|
|
84
134
|
name: z.ZodString;
|
|
85
135
|
created_at: z.ZodISODateTime;
|
|
@@ -90,6 +140,7 @@ export declare const robotListResponse: z.ZodObject<{
|
|
|
90
140
|
bridge_state: z.ZodObject<{
|
|
91
141
|
online: z.ZodBoolean;
|
|
92
142
|
latency_ms: z.ZodNullable<z.ZodNumber>;
|
|
143
|
+
low_bandwidth: z.ZodBoolean;
|
|
93
144
|
}, z.core.$strip>;
|
|
94
145
|
exposes: z.ZodObject<{
|
|
95
146
|
datapoints: z.ZodNumber;
|
|
@@ -98,6 +149,11 @@ export declare const robotListResponse: z.ZodObject<{
|
|
|
98
149
|
publishers: z.ZodNumber;
|
|
99
150
|
cameras: z.ZodNumber;
|
|
100
151
|
}, z.core.$strip>;
|
|
152
|
+
protocol_status: z.ZodOptional<z.ZodEnum<{
|
|
153
|
+
deprecated: "deprecated";
|
|
154
|
+
refused: "refused";
|
|
155
|
+
current: "current";
|
|
156
|
+
}>>;
|
|
101
157
|
id: z.ZodUUID;
|
|
102
158
|
name: z.ZodString;
|
|
103
159
|
created_at: z.ZodISODateTime;
|
|
@@ -122,6 +178,15 @@ export type DatapointValue = z.infer<typeof datapointValue>;
|
|
|
122
178
|
*/
|
|
123
179
|
export declare const robotDetailResponse: z.ZodObject<{
|
|
124
180
|
bridge_version: z.ZodNullable<z.ZodString>;
|
|
181
|
+
protocol_version: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
182
|
+
protocol: z.ZodOptional<z.ZodObject<{
|
|
183
|
+
status: z.ZodEnum<{
|
|
184
|
+
deprecated: "deprecated";
|
|
185
|
+
refused: "refused";
|
|
186
|
+
current: "current";
|
|
187
|
+
}>;
|
|
188
|
+
sunset_at: z.ZodNullable<z.ZodISODate>;
|
|
189
|
+
}, z.core.$strip>>;
|
|
125
190
|
last_hello_error: z.ZodNullable<z.ZodObject<{
|
|
126
191
|
code: z.ZodString;
|
|
127
192
|
message: z.ZodString;
|
|
@@ -141,6 +206,7 @@ export declare const robotDetailResponse: z.ZodObject<{
|
|
|
141
206
|
service: "service";
|
|
142
207
|
publisher: "publisher";
|
|
143
208
|
camera: "camera";
|
|
209
|
+
low_bandwidth: "low_bandwidth";
|
|
144
210
|
}>;
|
|
145
211
|
code: z.ZodString;
|
|
146
212
|
message: z.ZodString;
|
|
@@ -150,6 +216,7 @@ export declare const robotDetailResponse: z.ZodObject<{
|
|
|
150
216
|
bridge_state: z.ZodObject<{
|
|
151
217
|
online: z.ZodBoolean;
|
|
152
218
|
latency_ms: z.ZodNullable<z.ZodNumber>;
|
|
219
|
+
low_bandwidth: z.ZodBoolean;
|
|
153
220
|
}, z.core.$strip>;
|
|
154
221
|
exposes: z.ZodObject<{
|
|
155
222
|
datapoints: z.ZodNumber;
|
|
@@ -158,6 +225,11 @@ export declare const robotDetailResponse: z.ZodObject<{
|
|
|
158
225
|
publishers: z.ZodNumber;
|
|
159
226
|
cameras: z.ZodNumber;
|
|
160
227
|
}, z.core.$strip>;
|
|
228
|
+
protocol_status: z.ZodOptional<z.ZodEnum<{
|
|
229
|
+
deprecated: "deprecated";
|
|
230
|
+
refused: "refused";
|
|
231
|
+
current: "current";
|
|
232
|
+
}>>;
|
|
161
233
|
id: z.ZodUUID;
|
|
162
234
|
name: z.ZodString;
|
|
163
235
|
created_at: z.ZodISODateTime;
|
|
@@ -203,6 +275,7 @@ export declare const configDraftResponse: z.ZodObject<{
|
|
|
203
275
|
type: z.ZodString;
|
|
204
276
|
field: z.ZodOptional<z.ZodString>;
|
|
205
277
|
rate_throttle_hz: z.ZodOptional<z.ZodNumber>;
|
|
278
|
+
low_bandwidth: z.ZodOptional<z.ZodLiteral<"keep">>;
|
|
206
279
|
description: z.ZodOptional<z.ZodString>;
|
|
207
280
|
numeric: z.ZodOptional<z.ZodObject<{
|
|
208
281
|
scale: z.ZodOptional<z.ZodNumber>;
|
|
@@ -369,6 +442,23 @@ export declare const configDraftResponse: z.ZodObject<{
|
|
|
369
442
|
snapshot_interval_seconds: z.ZodNumber;
|
|
370
443
|
description: z.ZodOptional<z.ZodString>;
|
|
371
444
|
}, z.core.$strict>>>;
|
|
445
|
+
low_bandwidth: z.ZodOptional<z.ZodObject<{
|
|
446
|
+
mode: z.ZodOptional<z.ZodEnum<{
|
|
447
|
+
auto: "auto";
|
|
448
|
+
on: "on";
|
|
449
|
+
off: "off";
|
|
450
|
+
}>>;
|
|
451
|
+
enter_lag_ms: z.ZodOptional<z.ZodNumber>;
|
|
452
|
+
enter_after_s: z.ZodOptional<z.ZodNumber>;
|
|
453
|
+
exit_lag_ms: z.ZodOptional<z.ZodNumber>;
|
|
454
|
+
exit_after_s: z.ZodOptional<z.ZodNumber>;
|
|
455
|
+
datapoint_max_hz: z.ZodOptional<z.ZodNumber>;
|
|
456
|
+
camera: z.ZodOptional<z.ZodEnum<{
|
|
457
|
+
reduce: "reduce";
|
|
458
|
+
stop: "stop";
|
|
459
|
+
}>>;
|
|
460
|
+
camera_bitrate_kbps: z.ZodOptional<z.ZodNumber>;
|
|
461
|
+
}, z.core.$strict>>;
|
|
372
462
|
}, z.core.$strict>>;
|
|
373
463
|
source: z.ZodString;
|
|
374
464
|
updated_at: z.ZodNullable<z.ZodISODateTime>;
|
|
@@ -439,6 +529,7 @@ export declare const configVersionResponse: z.ZodObject<{
|
|
|
439
529
|
type: z.ZodString;
|
|
440
530
|
field: z.ZodOptional<z.ZodString>;
|
|
441
531
|
rate_throttle_hz: z.ZodOptional<z.ZodNumber>;
|
|
532
|
+
low_bandwidth: z.ZodOptional<z.ZodLiteral<"keep">>;
|
|
442
533
|
description: z.ZodOptional<z.ZodString>;
|
|
443
534
|
numeric: z.ZodOptional<z.ZodObject<{
|
|
444
535
|
scale: z.ZodOptional<z.ZodNumber>;
|
|
@@ -605,6 +696,23 @@ export declare const configVersionResponse: z.ZodObject<{
|
|
|
605
696
|
snapshot_interval_seconds: z.ZodNumber;
|
|
606
697
|
description: z.ZodOptional<z.ZodString>;
|
|
607
698
|
}, z.core.$strict>>>;
|
|
699
|
+
low_bandwidth: z.ZodOptional<z.ZodObject<{
|
|
700
|
+
mode: z.ZodOptional<z.ZodEnum<{
|
|
701
|
+
auto: "auto";
|
|
702
|
+
on: "on";
|
|
703
|
+
off: "off";
|
|
704
|
+
}>>;
|
|
705
|
+
enter_lag_ms: z.ZodOptional<z.ZodNumber>;
|
|
706
|
+
enter_after_s: z.ZodOptional<z.ZodNumber>;
|
|
707
|
+
exit_lag_ms: z.ZodOptional<z.ZodNumber>;
|
|
708
|
+
exit_after_s: z.ZodOptional<z.ZodNumber>;
|
|
709
|
+
datapoint_max_hz: z.ZodOptional<z.ZodNumber>;
|
|
710
|
+
camera: z.ZodOptional<z.ZodEnum<{
|
|
711
|
+
reduce: "reduce";
|
|
712
|
+
stop: "stop";
|
|
713
|
+
}>>;
|
|
714
|
+
camera_bitrate_kbps: z.ZodOptional<z.ZodNumber>;
|
|
715
|
+
}, z.core.$strict>>;
|
|
608
716
|
}, z.core.$strict>;
|
|
609
717
|
source: z.ZodString;
|
|
610
718
|
}, z.core.$strip>;
|
|
@@ -1105,22 +1213,21 @@ export declare const ASSET_UPLOAD_HEADERS: {
|
|
|
1105
1213
|
readonly nameEncoded: "x-fleetless-asset-name-encoded";
|
|
1106
1214
|
readonly syncId: "x-fleetless-sync-id";
|
|
1107
1215
|
/**
|
|
1108
|
-
* **The announced size, and it is what makes
|
|
1109
|
-
* all.**
|
|
1216
|
+
* **The announced size, and it is what makes a structured store refusal
|
|
1217
|
+
* reachable at all.**
|
|
1110
1218
|
*
|
|
1111
1219
|
* A server-side body limit is applied by the content-type parser, before the
|
|
1112
|
-
* handler runs, so an
|
|
1113
|
-
* `413` carrying
|
|
1114
|
-
*
|
|
1220
|
+
* handler runs, so an upload with no room left can only be refused with a
|
|
1221
|
+
* bare `413` carrying none of the three numbers — and the refusal
|
|
1222
|
+
* `assetStoreRefusedDetails` describes would have no producer.
|
|
1115
1223
|
*
|
|
1116
|
-
* With the size announced in a header the
|
|
1117
|
-
*
|
|
1118
|
-
* a
|
|
1119
|
-
* into memory.
|
|
1224
|
+
* With the size announced in a header the cloud can check `used + size`
|
|
1225
|
+
* against `ROBOT_ASSET_STORE_BYTES` where it can still say something: before
|
|
1226
|
+
* a byte is buffered, with all three numbers.
|
|
1120
1227
|
*
|
|
1121
1228
|
* The header is an **announcement, not a proof**: a sender can lie. The
|
|
1122
|
-
*
|
|
1123
|
-
* only makes the refusal answerable.
|
|
1229
|
+
* store still applies to the bytes that arrive — this does not replace
|
|
1230
|
+
* enforcement, it only makes the refusal answerable.
|
|
1124
1231
|
*/
|
|
1125
1232
|
readonly size: "x-fleetless-asset-size";
|
|
1126
1233
|
};
|
|
@@ -1248,8 +1355,8 @@ export declare const historySamplesResponse: z.ZodObject<{
|
|
|
1248
1355
|
}, z.core.$strip>>;
|
|
1249
1356
|
truncated: z.ZodBoolean;
|
|
1250
1357
|
truncated_by: z.ZodNullable<z.ZodEnum<{
|
|
1251
|
-
limit: "limit";
|
|
1252
1358
|
bytes: "bytes";
|
|
1359
|
+
limit: "limit";
|
|
1253
1360
|
}>>;
|
|
1254
1361
|
}, z.core.$strip>;
|
|
1255
1362
|
export type HistorySamplesResponse = z.infer<typeof historySamplesResponse>;
|
|
@@ -1307,8 +1414,8 @@ export declare const historyResponse: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
1307
1414
|
}, z.core.$strip>>;
|
|
1308
1415
|
truncated: z.ZodBoolean;
|
|
1309
1416
|
truncated_by: z.ZodNullable<z.ZodEnum<{
|
|
1310
|
-
limit: "limit";
|
|
1311
1417
|
bytes: "bytes";
|
|
1418
|
+
limit: "limit";
|
|
1312
1419
|
}>>;
|
|
1313
1420
|
}, z.core.$strip>, z.ZodObject<{
|
|
1314
1421
|
slug: z.ZodString;
|
|
@@ -1519,7 +1626,6 @@ export declare const orgQuotas: z.ZodObject<{
|
|
|
1519
1626
|
max_retention_bytes: z.ZodNumber;
|
|
1520
1627
|
max_retention_writes_per_minute: z.ZodNumber;
|
|
1521
1628
|
max_realtime_connections: z.ZodNumber;
|
|
1522
|
-
max_asset_storage_bytes: z.ZodNumber;
|
|
1523
1629
|
}, z.core.$strip>;
|
|
1524
1630
|
export type OrgQuotas = z.infer<typeof orgQuotas>;
|
|
1525
1631
|
/**
|
|
@@ -1542,7 +1648,6 @@ export declare const orgQuotaUsageCounts: z.ZodObject<{
|
|
|
1542
1648
|
max_apps: z.ZodOptional<z.ZodNumber>;
|
|
1543
1649
|
max_end_users: z.ZodOptional<z.ZodNumber>;
|
|
1544
1650
|
max_retention_bytes: z.ZodOptional<z.ZodNumber>;
|
|
1545
|
-
max_asset_storage_bytes: z.ZodOptional<z.ZodNumber>;
|
|
1546
1651
|
max_retention_writes_per_minute: z.ZodOptional<z.ZodNumber>;
|
|
1547
1652
|
max_realtime_connections: z.ZodOptional<z.ZodNumber>;
|
|
1548
1653
|
}, z.core.$strip>;
|
|
@@ -1556,14 +1661,12 @@ export declare const orgQuotaUsage: z.ZodObject<{
|
|
|
1556
1661
|
max_retention_bytes: z.ZodNumber;
|
|
1557
1662
|
max_retention_writes_per_minute: z.ZodNumber;
|
|
1558
1663
|
max_realtime_connections: z.ZodNumber;
|
|
1559
|
-
max_asset_storage_bytes: z.ZodNumber;
|
|
1560
1664
|
}, z.core.$strip>;
|
|
1561
1665
|
usage: z.ZodObject<{
|
|
1562
1666
|
max_robots: z.ZodOptional<z.ZodNumber>;
|
|
1563
1667
|
max_apps: z.ZodOptional<z.ZodNumber>;
|
|
1564
1668
|
max_end_users: z.ZodOptional<z.ZodNumber>;
|
|
1565
1669
|
max_retention_bytes: z.ZodOptional<z.ZodNumber>;
|
|
1566
|
-
max_asset_storage_bytes: z.ZodOptional<z.ZodNumber>;
|
|
1567
1670
|
max_retention_writes_per_minute: z.ZodOptional<z.ZodNumber>;
|
|
1568
1671
|
max_realtime_connections: z.ZodOptional<z.ZodNumber>;
|
|
1569
1672
|
}, z.core.$strip>;
|
|
@@ -1699,8 +1802,8 @@ export declare const orgLatencyResponse: z.ZodObject<{
|
|
|
1699
1802
|
to_ms: z.ZodNumber;
|
|
1700
1803
|
truncated: z.ZodBoolean;
|
|
1701
1804
|
truncated_by: z.ZodNullable<z.ZodEnum<{
|
|
1702
|
-
limit: "limit";
|
|
1703
1805
|
bytes: "bytes";
|
|
1806
|
+
limit: "limit";
|
|
1704
1807
|
}>>;
|
|
1705
1808
|
}, z.core.$strip>;
|
|
1706
1809
|
export type OrgLatencyResponse = z.infer<typeof orgLatencyResponse>;
|
|
@@ -1716,11 +1819,10 @@ export declare const USAGE_WINDOW_MAX_DAYS = 366;
|
|
|
1716
1819
|
/**
|
|
1717
1820
|
* The five things the meter records.
|
|
1718
1821
|
*
|
|
1719
|
-
* Storage is two metrics and not one summed byte count
|
|
1720
|
-
*
|
|
1721
|
-
*
|
|
1722
|
-
*
|
|
1723
|
-
* the quota.
|
|
1822
|
+
* Storage is two metrics and not one summed byte count: a sync grows storage
|
|
1823
|
+
* in jumps and time series grow steadily, and one number would let the first
|
|
1824
|
+
* crowd out the second on the invoice. The org that outgrew its bill would be
|
|
1825
|
+
* told to look at the wrong thing.
|
|
1724
1826
|
*/
|
|
1725
1827
|
export declare const usageMetric: z.ZodEnum<{
|
|
1726
1828
|
api_calls: "api_calls";
|