@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/oauth.js
CHANGED
|
@@ -188,7 +188,7 @@ export const dynamicClientRegistrationRequest = z
|
|
|
188
188
|
description: '`none`, RFC 7591\'s value for a public client, and the only value either server registers. Any other value is **refused rather than silently downgraded**: a client that believes it holds a secret and does not has a wrong mental model of its own security. There is no client secret to hold — mandatory PKCE (`S256`) is the defence.',
|
|
189
189
|
}),
|
|
190
190
|
grant_types: z.array(z.enum(['authorization_code', 'refresh_token'])).optional().meta({
|
|
191
|
-
description: 'Accepted for conformance with RFC 7591 and then **ignored
|
|
191
|
+
description: 'Accepted for conformance with RFC 7591 and then **ignored**: both MCP authorization servers grant `authorization_code` and `refresh_token` to every registration, and the answer states what was granted (§3.2.1) rather than what was asked.',
|
|
192
192
|
}),
|
|
193
193
|
response_types: z.array(z.enum(['code'])).optional().meta({
|
|
194
194
|
description: 'Accepted for conformance and then **ignored**; the response names `code`, which is the only response type OAuth 2.1 leaves, the implicit grant having been removed.',
|
|
@@ -211,7 +211,7 @@ export const dynamicClientRegistrationResponse = z.object({
|
|
|
211
211
|
description: 'The redirect URIs this registration was accepted for. A code is returned to one of these and nowhere else.',
|
|
212
212
|
}),
|
|
213
213
|
grant_types: z.array(z.string()).meta({
|
|
214
|
-
description: 'The grants this client may use. Always exactly `["authorization_code"]` —
|
|
214
|
+
description: 'The grants this client may use. Always exactly `["authorization_code", "refresh_token"]` — an exchange mints a refresh token and the token endpoint rotates it.',
|
|
215
215
|
}),
|
|
216
216
|
response_types: z.array(z.string()).meta({
|
|
217
217
|
description: 'The response types this client may ask for: `code`.',
|
|
@@ -227,26 +227,20 @@ export const dynamicClientRegistrationResponse = z.object({
|
|
|
227
227
|
}),
|
|
228
228
|
});
|
|
229
229
|
/**
|
|
230
|
-
* **The MCP token endpoint's request —
|
|
231
|
-
*
|
|
230
|
+
* **The MCP token endpoint's request — two grants, one per half of a
|
|
231
|
+
* session.**
|
|
232
232
|
*
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
236
|
-
*
|
|
233
|
+
* `authorization_code` mints the first access token and a refresh token;
|
|
234
|
+
* `refresh_token` rotates that refresh token into a new pair. Both MCP
|
|
235
|
+
* authorization servers, central and per-app, answer both; the console's own
|
|
236
|
+
* OAuth portal answers the code grant only.
|
|
237
237
|
*
|
|
238
|
-
* **
|
|
239
|
-
*
|
|
240
|
-
*
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
* The argument the branch carried is worth keeping even though the branch is
|
|
245
|
-
* not: **RFC 8707's `resource` has to survive rotation**, because a refresh
|
|
246
|
-
* that drops the audience mints a successor with no `aud`, and the validating
|
|
247
|
-
* resource then refuses a token the caller obtained legitimately — one token
|
|
248
|
-
* lifetime after a login that worked, to somebody who did nothing wrong. If a
|
|
249
|
-
* refresh grant is ever added here, it carries `resource`.
|
|
238
|
+
* **RFC 8707's `resource` has to survive rotation**: a refresh that drops the
|
|
239
|
+
* audience mints a successor with no `aud`, and the validating resource then
|
|
240
|
+
* refuses a token the caller obtained legitimately. So the server keeps the
|
|
241
|
+
* audience on the refresh token's own row, and a `resource` named here must
|
|
242
|
+
* match it or the answer is `invalid_target` — before the token is consumed,
|
|
243
|
+
* so a typo costs nothing.
|
|
250
244
|
*
|
|
251
245
|
* `code_verifier`'s bounds are RFC 7636 §4.1's, charset included. A verifier
|
|
252
246
|
* is compared, not parsed, so a length nobody checks is a length an attacker
|
|
@@ -260,10 +254,10 @@ export const dynamicClientRegistrationResponse = z.object({
|
|
|
260
254
|
* **stripped**, which bit the test for this schema: `safeParse().success`
|
|
261
255
|
* cannot tell a present field from an absent one. Assert on the parsed value.
|
|
262
256
|
*/
|
|
263
|
-
export const
|
|
257
|
+
export const oauthCodeTokenRequest = z
|
|
264
258
|
.object({
|
|
265
259
|
grant_type: z.literal('authorization_code').meta({
|
|
266
|
-
description: '
|
|
260
|
+
description: '`authorization_code`: this request exchanges the code from the authorize redirect for an access token and a refresh token.',
|
|
267
261
|
}),
|
|
268
262
|
code: z.string().min(1).max(500).meta({
|
|
269
263
|
description: 'The authorization code from the redirect. It may be exchanged once; a second presentation is `invalid_grant`, the same answer a fabricated code gets.',
|
|
@@ -284,6 +278,27 @@ export const oauthTokenRequest = z
|
|
|
284
278
|
.meta({
|
|
285
279
|
description: "RFC 6749 §4.1.3's authorization-code exchange with PKCE, as either MCP authorization server reads it. Sent as `application/x-www-form-urlencoded`, per §4.1.3, though the server accepts a JSON body too.",
|
|
286
280
|
});
|
|
281
|
+
export const oauthRefreshTokenRequest = z
|
|
282
|
+
.object({
|
|
283
|
+
grant_type: z.literal('refresh_token').meta({
|
|
284
|
+
description: '`refresh_token`: this request rotates a refresh token into a new access token and a new refresh token. The presented token is consumed; presenting it again revokes the whole session.',
|
|
285
|
+
}),
|
|
286
|
+
refresh_token: z.string().min(1).max(500).meta({
|
|
287
|
+
description: 'The refresh token from the last token response. Bound to the client that received it and to one identity space: presented by another client, or at the other MCP server, it is `invalid_grant` and stays unconsumed.',
|
|
288
|
+
}),
|
|
289
|
+
client_id: z.string().min(1).max(200).meta({
|
|
290
|
+
description: 'The client the refresh token was issued to, as registered. A refresh token is not transferable between clients.',
|
|
291
|
+
}),
|
|
292
|
+
resource: z.url().optional().meta({
|
|
293
|
+
description: 'The resource the new token is for, per RFC 8707. Optional; when named it must be the audience the session was issued for, or the answer is `invalid_target` and the refresh token is left untouched. The successor carries the same audience either way.',
|
|
294
|
+
}),
|
|
295
|
+
})
|
|
296
|
+
.meta({
|
|
297
|
+
description: "RFC 6749 §6's refresh, as either MCP authorization server reads it. Every use rotates: the answer carries a new refresh token and the presented one is dead.",
|
|
298
|
+
});
|
|
299
|
+
export const oauthTokenRequest = z.discriminatedUnion('grant_type', [oauthCodeTokenRequest, oauthRefreshTokenRequest]).meta({
|
|
300
|
+
description: 'What an MCP token endpoint accepts: the authorization-code exchange, or a refresh. Any other `grant_type` is `unsupported_grant_type`, refused before a lookup happens.',
|
|
301
|
+
});
|
|
287
302
|
/**
|
|
288
303
|
* RFC 6749 §5.1's success envelope — **the second deliberate dialect, and this
|
|
289
304
|
* one is a success shape rather than an error shape.**
|
|
@@ -311,7 +326,7 @@ export const oauthTokenResponse = z.object({
|
|
|
311
326
|
description: 'How long the access token is valid, in **seconds**, per RFC 6749 §5.1. Not a timestamp, and not milliseconds.',
|
|
312
327
|
}),
|
|
313
328
|
refresh_token: z.string().min(1).optional().meta({
|
|
314
|
-
description: 'The refresh token
|
|
329
|
+
description: 'The refresh token. Both MCP token endpoints issue one on every exchange and every refresh; it rotates on every use, lives ninety days from its last use, and dies with the account\'s sessions — a block, a password change, a withdrawn consent. The console\'s own OAuth portal issues none.',
|
|
315
330
|
}),
|
|
316
331
|
scope: z.string().max(500).optional().meta({
|
|
317
332
|
description: 'The scopes the issued token actually carries, space-separated.',
|
|
@@ -335,7 +350,7 @@ export const authorizationServerMetadata = z.object({
|
|
|
335
350
|
description: 'The response types this server offers: `code` only, the implicit grant being gone with OAuth 2.1.',
|
|
336
351
|
}),
|
|
337
352
|
grant_types_supported: z.array(z.enum(['authorization_code', 'refresh_token'])).meta({
|
|
338
|
-
description: 'The grants this server offers
|
|
353
|
+
description: 'The grants this server offers: `authorization_code` and `refresh_token`. OAuth 2.1 removes the implicit and password grants, so neither appears here.',
|
|
339
354
|
}),
|
|
340
355
|
code_challenge_methods_supported: z.array(codeChallengeMethod).meta({
|
|
341
356
|
description: 'The PKCE challenge methods accepted: `S256` only. `plain` is not offered — a challenge equal to its verifier defends against nothing, and offering it would make a downgrade negotiable.',
|
package/dist/protocol.d.ts
CHANGED
|
@@ -1,18 +1,67 @@
|
|
|
1
1
|
// SPDX-License-Identifier: Apache-2.0
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
/**
|
|
4
|
-
* Bridge <-> cloud protocol, version
|
|
4
|
+
* Bridge <-> cloud protocol, version 3.
|
|
5
5
|
*
|
|
6
|
-
* The version is exchanged in the hello handshake
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* The version is exchanged in the hello handshake. Since 2026-09 the cloud
|
|
7
|
+
* serves a **window** of versions, not one: every entry of
|
|
8
|
+
* `PROTOCOL_VERSIONS` whose sunset has not passed. A version is deprecated
|
|
9
|
+
* by the cloud release that supersedes it and sunset `PROTOCOL_SUNSET_DAYS`
|
|
10
|
+
* later. Outside the window the cloud refuses with `protocol_mismatch`,
|
|
11
|
+
* which names the window and reaches the robot's detail view as
|
|
12
|
+
* `last_hello_error`.
|
|
13
|
+
*
|
|
14
|
+
* **3 (2026-09-22):** the ping carries `latency_ms` and `lag_ms`, the bridge
|
|
15
|
+
* sends `link_mode`, `bridge_state` gains `low_bandwidth`, and the
|
|
16
|
+
* `bridge_pressure` datapoint is gone. A protocol-2 bridge is served until
|
|
17
|
+
* its sunset, and the cloud's protocol-2 adapter owes it two translations on
|
|
18
|
+
* the way in: it drops its pressure datapoints, and it rewrites an
|
|
19
|
+
* `asset_progress` failure of kind `too_large` — a kind protocol 3 no longer
|
|
20
|
+
* has — to `refused` with `details: null`, because a 2.0.0 `bridgeAssetProgress`
|
|
21
|
+
* refuses the frame outright otherwise.
|
|
9
22
|
*
|
|
10
23
|
* **2 (2026-08-21):** `config_applied.errors` entries gained `kind` and `code`
|
|
11
|
-
* beside `message`.
|
|
12
|
-
|
|
13
|
-
|
|
24
|
+
* beside `message`.
|
|
25
|
+
*/
|
|
26
|
+
export declare const PROTOCOL_VERSION = 3;
|
|
27
|
+
/** Days between a version's deprecation and its sunset. */
|
|
28
|
+
export declare const PROTOCOL_SUNSET_DAYS = 90;
|
|
29
|
+
export interface ProtocolVersionEntry {
|
|
30
|
+
version: number;
|
|
31
|
+
/** The first bridge package version that speaks this protocol. */
|
|
32
|
+
bridge_from: string;
|
|
33
|
+
/** ISO date of the cloud release that superseded it; null while current. */
|
|
34
|
+
deprecated_at: string | null;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Every protocol version the cloud has served, oldest first. A test keeps
|
|
38
|
+
* exactly one entry current and equal to `PROTOCOL_VERSION`; `test/changelog.test.ts`
|
|
39
|
+
* requires the CHANGELOG's current section to name the newest `bridge_from`
|
|
40
|
+
* and the previous entry's `sunsetOf(...)` date, and `scripts/verify-version-tag.mjs`
|
|
41
|
+
* requires a dated heading for the tag being released.
|
|
14
42
|
*/
|
|
15
|
-
export declare const
|
|
43
|
+
export declare const PROTOCOL_VERSIONS: readonly ProtocolVersionEntry[];
|
|
44
|
+
/** The newest bridge package. The cloud mails organisations still below it. */
|
|
45
|
+
export declare const LATEST_BRIDGE_VERSION = "4.0.0";
|
|
46
|
+
export interface ProtocolStatus {
|
|
47
|
+
status: 'current' | 'deprecated' | 'unsupported';
|
|
48
|
+
/** ISO date, or null for a current or unknown version. */
|
|
49
|
+
sunset_at: string | null;
|
|
50
|
+
}
|
|
51
|
+
export declare function sunsetOf(entry: ProtocolVersionEntry): string | null;
|
|
52
|
+
/**
|
|
53
|
+
* The window rule itself: `protocolStatus` and `minimumProtocolVersion` are
|
|
54
|
+
* this function over `PROTOCOL_VERSIONS`, and the cloud calls it directly.
|
|
55
|
+
*
|
|
56
|
+
* The table is a parameter because callers pass one with a deprecated entry —
|
|
57
|
+
* tests, and any caller reasoning about a sunset. The real table has none
|
|
58
|
+
* until the first bump, so a hard-coded `PROTOCOL_VERSIONS` would leave the
|
|
59
|
+
* deprecated and unsupported branches unreachable.
|
|
60
|
+
*/
|
|
61
|
+
export declare function statusFromTable(table: readonly ProtocolVersionEntry[], version: number, today: Date): ProtocolStatus;
|
|
62
|
+
export declare function protocolStatus(version: number, today?: Date): ProtocolStatus;
|
|
63
|
+
/** The lowest version still inside its window today. */
|
|
64
|
+
export declare function minimumProtocolVersion(today?: Date): number;
|
|
16
65
|
/**
|
|
17
66
|
* The bridge socket close code for "this robot no longer exists".
|
|
18
67
|
*
|
|
@@ -24,6 +73,20 @@ export declare const PROTOCOL_VERSION = 2;
|
|
|
24
73
|
* more informative than "connection closed".
|
|
25
74
|
*/
|
|
26
75
|
export declare const CLOSE_ROBOT_DELETED = 4004;
|
|
76
|
+
/**
|
|
77
|
+
* The bridge socket close code for "the token you connected with is gone".
|
|
78
|
+
*
|
|
79
|
+
* The cloud closes a robot's live socket with this after the robot's token was
|
|
80
|
+
* rotated. A 4.0.0 bridge reads it the way it reads `invalid_token` — stop,
|
|
81
|
+
* exit 2 — because the secret it holds is no longer a secret anyone accepts,
|
|
82
|
+
* and no amount of reconnecting produces the new one. A 3.x bridge does not
|
|
83
|
+
* know the code, reconnects, and is refused at hello; that ends the same way,
|
|
84
|
+
* one round trip later.
|
|
85
|
+
*
|
|
86
|
+
* Its own code rather than `CLOSE_ROBOT_DELETED`, which would tell an operator
|
|
87
|
+
* their robot had been deleted when it very much still exists.
|
|
88
|
+
*/
|
|
89
|
+
export declare const CLOSE_TOKEN_ROTATED = 4005;
|
|
27
90
|
/**
|
|
28
91
|
* How long a command waits for its answer when the caller names no patience
|
|
29
92
|
* of its own.
|
|
@@ -113,10 +176,26 @@ export declare const bridgeHello: z.ZodObject<{
|
|
|
113
176
|
}, z.core.$strip>>>;
|
|
114
177
|
}, z.core.$strip>;
|
|
115
178
|
export type BridgeHello = z.infer<typeof bridgeHello>;
|
|
116
|
-
/**
|
|
179
|
+
/**
|
|
180
|
+
* Cloud accepts the bridge: the robot is online from here on.
|
|
181
|
+
*
|
|
182
|
+
* `protocol` and `bridge` are optional so that a bridge parsing `hello_ok`
|
|
183
|
+
* strictly still parses one from an older cloud. `status` here is never
|
|
184
|
+
* `unsupported`: an unsupported version gets `hello_error`, not this frame.
|
|
185
|
+
*/
|
|
117
186
|
export declare const cloudHelloOk: z.ZodObject<{
|
|
118
187
|
type: z.ZodLiteral<"hello_ok">;
|
|
119
188
|
robot_id: z.ZodUUID;
|
|
189
|
+
protocol: z.ZodOptional<z.ZodObject<{
|
|
190
|
+
status: z.ZodEnum<{
|
|
191
|
+
deprecated: "deprecated";
|
|
192
|
+
current: "current";
|
|
193
|
+
}>;
|
|
194
|
+
sunset_at: z.ZodNullable<z.ZodISODate>;
|
|
195
|
+
}, z.core.$strip>>;
|
|
196
|
+
bridge: z.ZodOptional<z.ZodObject<{
|
|
197
|
+
latest_version: z.ZodString;
|
|
198
|
+
}, z.core.$strip>>;
|
|
120
199
|
}, z.core.$strip>;
|
|
121
200
|
export type CloudHelloOk = z.infer<typeof cloudHelloOk>;
|
|
122
201
|
/** Cloud refuses the bridge (bad token, incompatible protocol, ...). */
|
|
@@ -129,22 +208,40 @@ export type CloudHelloError = z.infer<typeof cloudHelloError>;
|
|
|
129
208
|
/**
|
|
130
209
|
* One datapoint sample. `timestamp_ms` is the capture time at the bridge —
|
|
131
210
|
* never the receive time — so clients compute age themselves.
|
|
211
|
+
*
|
|
212
|
+
* Which is exactly why `backfill` has to be on the frame. A replayed sample
|
|
213
|
+
* carries the capture time it had during the outage, so a cloud that measures
|
|
214
|
+
* lag from every arriving frame reads a two-hour disconnect as two hours of
|
|
215
|
+
* lag the moment the bridge reconnects — and reports a healthy link as the
|
|
216
|
+
* worst one it has ever seen. Only the bridge knows which frames came out of
|
|
217
|
+
* its buffer, so only the bridge can say.
|
|
132
218
|
*/
|
|
133
219
|
export declare const datapointFrame: z.ZodObject<{
|
|
134
220
|
type: z.ZodLiteral<"datapoint">;
|
|
135
221
|
slug: z.ZodString;
|
|
136
222
|
value: z.ZodUnknown;
|
|
137
223
|
timestamp_ms: z.ZodNumber;
|
|
224
|
+
backfill: z.ZodOptional<z.ZodBoolean>;
|
|
138
225
|
}, z.core.$strip>;
|
|
139
226
|
export type DatapointFrame = z.infer<typeof datapointFrame>;
|
|
140
227
|
/**
|
|
141
228
|
* Latency probe, cloud → bridge. The cloud sends its own clock in `ts_ms`;
|
|
142
229
|
* the bridge echoes it back untouched and the cloud derives the round-trip
|
|
143
230
|
* latency shown as `bridge_state.latency_ms`.
|
|
231
|
+
*
|
|
232
|
+
* Sent every `pingIntervalMs`; the bridge answers with `pong`. Since protocol
|
|
233
|
+
* 3 it also carries what the cloud measured about this link, so the bridge
|
|
234
|
+
* can decide on its low-bandwidth mode with an end-to-end number: the
|
|
235
|
+
* round trip of the last pong, and the datapoint lag — the median over the
|
|
236
|
+
* last five seconds of (receive time − `timestamp_ms`) minus the minimum of
|
|
237
|
+
* the last ten minutes, which cancels the robot's clock offset. `null` until
|
|
238
|
+
* the cloud has a sample. A protocol-2 bridge reads only `ts_ms`.
|
|
144
239
|
*/
|
|
145
240
|
export declare const cloudPing: z.ZodObject<{
|
|
146
241
|
type: z.ZodLiteral<"ping">;
|
|
147
242
|
ts_ms: z.ZodNumber;
|
|
243
|
+
latency_ms: z.ZodNullable<z.ZodNumber>;
|
|
244
|
+
lag_ms: z.ZodNullable<z.ZodNumber>;
|
|
148
245
|
}, z.core.$strip>;
|
|
149
246
|
export type CloudPing = z.infer<typeof cloudPing>;
|
|
150
247
|
/** Immediate bridge answer to a `CloudPing`, `ts_ms` echoed unchanged. */
|
|
@@ -153,6 +250,24 @@ export declare const bridgePong: z.ZodObject<{
|
|
|
153
250
|
ts_ms: z.ZodNumber;
|
|
154
251
|
}, z.core.$strip>;
|
|
155
252
|
export type BridgePong = z.infer<typeof bridgePong>;
|
|
253
|
+
/**
|
|
254
|
+
* The bridge's low-bandwidth mode changed. Sent on every transition and once
|
|
255
|
+
* after `hello_ok`, at tier 0 like the pong: the cloud folds it into
|
|
256
|
+
* `bridge_state.low_bandwidth`, and a frame that waited behind bulk would
|
|
257
|
+
* describe a state that is already over.
|
|
258
|
+
*/
|
|
259
|
+
export declare const bridgeLinkMode: z.ZodObject<{
|
|
260
|
+
type: z.ZodLiteral<"link_mode">;
|
|
261
|
+
low_bandwidth: z.ZodBoolean;
|
|
262
|
+
reason: z.ZodEnum<{
|
|
263
|
+
lag: "lag";
|
|
264
|
+
dwell: "dwell";
|
|
265
|
+
forced: "forced";
|
|
266
|
+
recovered: "recovered";
|
|
267
|
+
}>;
|
|
268
|
+
at_ms: z.ZodNumber;
|
|
269
|
+
}, z.core.$strip>;
|
|
270
|
+
export type BridgeLinkMode = z.infer<typeof bridgeLinkMode>;
|
|
156
271
|
/**
|
|
157
272
|
* The published configuration, cloud → bridge — the bridge applies the
|
|
158
273
|
* published version. Sent right after `hello_ok` and again on every publish,
|
|
@@ -191,6 +306,7 @@ export declare const cloudConfig: z.ZodObject<{
|
|
|
191
306
|
type: z.ZodString;
|
|
192
307
|
field: z.ZodOptional<z.ZodString>;
|
|
193
308
|
rate_throttle_hz: z.ZodOptional<z.ZodNumber>;
|
|
309
|
+
low_bandwidth: z.ZodOptional<z.ZodLiteral<"keep">>;
|
|
194
310
|
description: z.ZodOptional<z.ZodString>;
|
|
195
311
|
numeric: z.ZodOptional<z.ZodObject<{
|
|
196
312
|
scale: z.ZodOptional<z.ZodNumber>;
|
|
@@ -357,6 +473,23 @@ export declare const cloudConfig: z.ZodObject<{
|
|
|
357
473
|
snapshot_interval_seconds: z.ZodNumber;
|
|
358
474
|
description: z.ZodOptional<z.ZodString>;
|
|
359
475
|
}, z.core.$strict>>>;
|
|
476
|
+
low_bandwidth: z.ZodOptional<z.ZodObject<{
|
|
477
|
+
mode: z.ZodOptional<z.ZodEnum<{
|
|
478
|
+
auto: "auto";
|
|
479
|
+
on: "on";
|
|
480
|
+
off: "off";
|
|
481
|
+
}>>;
|
|
482
|
+
enter_lag_ms: z.ZodOptional<z.ZodNumber>;
|
|
483
|
+
enter_after_s: z.ZodOptional<z.ZodNumber>;
|
|
484
|
+
exit_lag_ms: z.ZodOptional<z.ZodNumber>;
|
|
485
|
+
exit_after_s: z.ZodOptional<z.ZodNumber>;
|
|
486
|
+
datapoint_max_hz: z.ZodOptional<z.ZodNumber>;
|
|
487
|
+
camera: z.ZodOptional<z.ZodEnum<{
|
|
488
|
+
reduce: "reduce";
|
|
489
|
+
stop: "stop";
|
|
490
|
+
}>>;
|
|
491
|
+
camera_bitrate_kbps: z.ZodOptional<z.ZodNumber>;
|
|
492
|
+
}, z.core.$strict>>;
|
|
360
493
|
}, z.core.$strict>;
|
|
361
494
|
}, z.core.$strip>;
|
|
362
495
|
export type CloudConfig = z.infer<typeof cloudConfig>;
|
|
@@ -377,6 +510,7 @@ export declare const bridgeConfigApplied: z.ZodObject<{
|
|
|
377
510
|
service: "service";
|
|
378
511
|
publisher: "publisher";
|
|
379
512
|
camera: "camera";
|
|
513
|
+
low_bandwidth: "low_bandwidth";
|
|
380
514
|
}>;
|
|
381
515
|
code: z.ZodString;
|
|
382
516
|
message: z.ZodString;
|
|
@@ -538,72 +672,17 @@ export type BridgeTypeDefinitions = z.infer<typeof bridgeTypeDefinitions>;
|
|
|
538
672
|
/**
|
|
539
673
|
* The built-in `bridge_state` datapoint every robot has: connection status
|
|
540
674
|
* plus latency, the basis for offline-aware client UIs.
|
|
675
|
+
*
|
|
676
|
+
* `online` and `latency_ms` are cloud-observed (the socket, the pong);
|
|
677
|
+
* `low_bandwidth` is bridge-reported through `link_mode` and `false` for a
|
|
678
|
+
* bridge that never sends one.
|
|
541
679
|
*/
|
|
542
680
|
export declare const bridgeState: z.ZodObject<{
|
|
543
681
|
online: z.ZodBoolean;
|
|
544
682
|
latency_ms: z.ZodNullable<z.ZodNumber>;
|
|
683
|
+
low_bandwidth: z.ZodBoolean;
|
|
545
684
|
}, z.core.$strip>;
|
|
546
685
|
export type BridgeState = z.infer<typeof bridgeState>;
|
|
547
|
-
/**
|
|
548
|
-
* The built-in `bridge_pressure` datapoint: the bridge's own
|
|
549
|
-
* bandwidth-shaping state, sent on the same reserved-slug path as
|
|
550
|
-
* `bridge_state` so history, realtime, REST and MCP exposure fall out of the
|
|
551
|
-
* ordinary datapoint machinery for free.
|
|
552
|
-
*/
|
|
553
|
-
export declare const bridgePressure: z.ZodObject<{
|
|
554
|
-
link: z.ZodObject<{
|
|
555
|
-
rate_bps: z.ZodNullable<z.ZodNumber>;
|
|
556
|
-
snapshot_max_bytes: z.ZodNumber;
|
|
557
|
-
}, z.core.$strip>;
|
|
558
|
-
tiers: z.ZodObject<{
|
|
559
|
-
'0': z.ZodOptional<z.ZodObject<{
|
|
560
|
-
sent: z.ZodNumber;
|
|
561
|
-
bytes: z.ZodNumber;
|
|
562
|
-
drops: z.ZodNumber;
|
|
563
|
-
high_water: z.ZodNumber;
|
|
564
|
-
}, z.core.$strip>>;
|
|
565
|
-
'1': z.ZodOptional<z.ZodObject<{
|
|
566
|
-
sent: z.ZodNumber;
|
|
567
|
-
bytes: z.ZodNumber;
|
|
568
|
-
drops: z.ZodNumber;
|
|
569
|
-
high_water: z.ZodNumber;
|
|
570
|
-
}, z.core.$strip>>;
|
|
571
|
-
'2': z.ZodOptional<z.ZodObject<{
|
|
572
|
-
sent: z.ZodNumber;
|
|
573
|
-
bytes: z.ZodNumber;
|
|
574
|
-
drops: z.ZodNumber;
|
|
575
|
-
high_water: z.ZodNumber;
|
|
576
|
-
}, z.core.$strip>>;
|
|
577
|
-
'3': z.ZodOptional<z.ZodObject<{
|
|
578
|
-
sent: z.ZodNumber;
|
|
579
|
-
bytes: z.ZodNumber;
|
|
580
|
-
drops: z.ZodNumber;
|
|
581
|
-
high_water: z.ZodNumber;
|
|
582
|
-
}, z.core.$strip>>;
|
|
583
|
-
'4': z.ZodOptional<z.ZodObject<{
|
|
584
|
-
sent: z.ZodNumber;
|
|
585
|
-
bytes: z.ZodNumber;
|
|
586
|
-
drops: z.ZodNumber;
|
|
587
|
-
high_water: z.ZodNumber;
|
|
588
|
-
}, z.core.$strip>>;
|
|
589
|
-
'5': z.ZodOptional<z.ZodObject<{
|
|
590
|
-
sent: z.ZodNumber;
|
|
591
|
-
bytes: z.ZodNumber;
|
|
592
|
-
drops: z.ZodNumber;
|
|
593
|
-
high_water: z.ZodNumber;
|
|
594
|
-
}, z.core.$strip>>;
|
|
595
|
-
}, z.core.$strict>;
|
|
596
|
-
video: z.ZodObject<{
|
|
597
|
-
active_streams: z.ZodNumber;
|
|
598
|
-
bitrate_sum_kbps: z.ZodNumber;
|
|
599
|
-
uplink_kbps: z.ZodNullable<z.ZodNumber>;
|
|
600
|
-
override_kbps: z.ZodNullable<z.ZodNumber>;
|
|
601
|
-
video_budget_kbps: z.ZodNullable<z.ZodNumber>;
|
|
602
|
-
reserve_kbps: z.ZodNumber;
|
|
603
|
-
}, z.core.$strip>;
|
|
604
|
-
}, z.core.$strip>;
|
|
605
|
-
export type BridgePressure = z.infer<typeof bridgePressure>;
|
|
606
|
-
export declare const PRESSURE_SLUG: "bridge_pressure";
|
|
607
686
|
/**
|
|
608
687
|
* The header of a **binary** snapshot frame, bridge → cloud.
|
|
609
688
|
*
|
|
@@ -724,10 +803,10 @@ export declare const bridgeAssetProgress: z.ZodObject<{
|
|
|
724
803
|
unresolvable: "unresolvable";
|
|
725
804
|
upload_failed: "upload_failed";
|
|
726
805
|
refused: "refused";
|
|
727
|
-
too_large: "too_large";
|
|
728
806
|
}>;
|
|
729
807
|
details: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
730
|
-
|
|
808
|
+
store_bytes: z.ZodNumber;
|
|
809
|
+
used_bytes: z.ZodNumber;
|
|
731
810
|
size_bytes: z.ZodNumber;
|
|
732
811
|
}, z.core.$strip>>>;
|
|
733
812
|
}, z.core.$strip>>;
|