@fleetless/contracts 6.2.0-next.1 → 6.2.0-next.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 +9 -2
- package/artifacts/routes.json +1 -1
- package/artifacts/schema/file-too-large-details.schema.json +1 -1
- package/dist/assets.d.ts +2 -2
- package/dist/assets.js +2 -2
- package/dist/client-auth.d.ts +15 -5
- package/dist/client-auth.js +15 -5
- package/dist/errors.d.ts +5 -3
- package/dist/errors.js +12 -5
- package/dist/realtime.d.ts +2 -2
- package/dist/routes.js +2 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -13,10 +13,17 @@ version.
|
|
|
13
13
|
|
|
14
14
|
- **`file_too_large`** (`413`): one asset file is larger than
|
|
15
15
|
`ASSET_FILE_MAX_BYTES` (one gigabyte, every plan, the URDF included).
|
|
16
|
-
`details` is `fileTooLargeDetails`: `max_bytes` and `size_bytes`,
|
|
17
|
-
|
|
16
|
+
`details` is `fileTooLargeDetails`: `max_bytes` and `size_bytes`, the
|
|
17
|
+
announced size or, when none (or a false one) was announced, the bytes that
|
|
18
|
+
arrived; `null` only when the body limit stopped the upload.
|
|
18
19
|
`ASSET_FILE_MAX_BYTES` is in `constants.json`. `plan_limit` and
|
|
19
20
|
`quota_exceeded` on an asset upload now mean only that the store is full.
|
|
21
|
+
- **`plan_limit` in `clientOidcErrorCode`.** A federated sign-in that would
|
|
22
|
+
create an app user beyond the org's plan `app_users` limit now redirects
|
|
23
|
+
with `?error=plan_limit`, so an app can tell that the plan is full.
|
|
24
|
+
`quota_exceeded` keeps one meaning there: the `max_end_users` protection
|
|
25
|
+
ceiling, which also covers orgs still on the beta. A consumer that switches
|
|
26
|
+
exhaustively over `ClientOidcErrorCode` gains one case.
|
|
20
27
|
|
|
21
28
|
### Changed
|
|
22
29
|
|
package/artifacts/routes.json
CHANGED
|
@@ -6494,7 +6494,7 @@
|
|
|
6494
6494
|
"bad_request"
|
|
6495
6495
|
],
|
|
6496
6496
|
"transport": "http",
|
|
6497
|
-
"notes": "The body is the **raw file bytes**, not JSON, so it has no request schema; everything about the file — its kind, its name, its sync id and its announced size — rides in the `x-fleetless-asset-*` headers `ASSET_UPLOAD_HEADERS` names. The credential is a short-lived upload token minted by `POST /api/robots/:id/assets/sync`, verified in a `preParsing` hook so a refusal precedes the work rather than following it: a `preHandler` would already have buffered the whole file. **One file can be at most `ASSET_FILE_MAX_BYTES`**, on every plan and for every kind, the URDF included: an announced size over it answers `413 file_too_large` with `max_bytes` and `size_bytes` before a byte is buffered
|
|
6497
|
+
"notes": "The body is the **raw file bytes**, not JSON, so it has no request schema; everything about the file — its kind, its name, its sync id and its announced size — rides in the `x-fleetless-asset-*` headers `ASSET_UPLOAD_HEADERS` names. The credential is a short-lived upload token minted by `POST /api/robots/:id/assets/sync`, verified in a `preParsing` hook so a refusal precedes the work rather than following it: a `preHandler` would already have buffered the whole file. **One file can be at most `ASSET_FILE_MAX_BYTES`**, on every plan and for every kind, the URDF included: an announced size over it answers `413 file_too_large` with `max_bytes` and `size_bytes` before a byte is buffered; without a truthful size, a body over the limit answers the same code with the bytes that arrived as `size_bytes`, or with `size_bytes: null` when it ran past the server's body limit and nobody counted the bytes. Retrying does not help. A file that fits but finds the store full answers `409 plan_limit` (or `409 quota_exceeded` for an organisation still on the beta) carrying `store_bytes`, `used_bytes` and `size_bytes`, while the sync carries on with the next file. Rate limited per robot inside that same hook, which is why `rateLimited` is `false`: there is no rate-limiting preHandler registered on this route. The URDF itself is never refused for the store; only meshes and textures are charged against it."
|
|
6498
6498
|
},
|
|
6499
6499
|
{
|
|
6500
6500
|
"method": "GET",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"type": "null"
|
|
20
20
|
}
|
|
21
21
|
],
|
|
22
|
-
"description": "The refused file's announced size,
|
|
22
|
+
"description": "The refused file's size, in bytes: the announced size, or the bytes that arrived when none (or a false one) was announced; `null` only when the body limit stopped the upload and nobody counted the bytes."
|
|
23
23
|
}
|
|
24
24
|
},
|
|
25
25
|
"required": [
|
package/dist/assets.d.ts
CHANGED
|
@@ -203,8 +203,8 @@ export declare const ROBOT_ASSET_STORE_BYTES = 1000000000;
|
|
|
203
203
|
* store says how much a robot may keep, this says how much the cloud will
|
|
204
204
|
* take in one request. A file over it is refused `413 file_too_large` with
|
|
205
205
|
* `fileTooLargeDetails`, before a byte is buffered when the size was
|
|
206
|
-
* announced (`ASSET_UPLOAD_HEADERS.size`) and
|
|
207
|
-
*
|
|
206
|
+
* announced (`ASSET_UPLOAD_HEADERS.size`), and otherwise on the bytes that
|
|
207
|
+
* arrived, or by the server's body limit when the body ran past it. That refusal is not a store or plan limit, applies to the URDF
|
|
208
208
|
* as well, and retrying does not help.
|
|
209
209
|
*
|
|
210
210
|
* In `constants.json` for the same reason as `ROBOT_ASSET_STORE_BYTES`.
|
package/dist/assets.js
CHANGED
|
@@ -258,8 +258,8 @@ export const ROBOT_ASSET_STORE_BYTES = 1_000_000_000;
|
|
|
258
258
|
* store says how much a robot may keep, this says how much the cloud will
|
|
259
259
|
* take in one request. A file over it is refused `413 file_too_large` with
|
|
260
260
|
* `fileTooLargeDetails`, before a byte is buffered when the size was
|
|
261
|
-
* announced (`ASSET_UPLOAD_HEADERS.size`) and
|
|
262
|
-
*
|
|
261
|
+
* announced (`ASSET_UPLOAD_HEADERS.size`), and otherwise on the bytes that
|
|
262
|
+
* arrived, or by the server's body limit when the body ran past it. That refusal is not a store or plan limit, applies to the URDF
|
|
263
263
|
* as well, and retrying does not help.
|
|
264
264
|
*
|
|
265
265
|
* In `constants.json` for the same reason as `ROBOT_ASSET_STORE_BYTES`.
|
package/dist/client-auth.d.ts
CHANGED
|
@@ -373,14 +373,23 @@ export type ClientOidcExchangeRequest = z.infer<typeof clientOidcExchangeRequest
|
|
|
373
373
|
* `provider_misconfigured`, `provider_disabled` — the provider's or the
|
|
374
374
|
* developer's to fix, and the app can say so.
|
|
375
375
|
* - `invalid_request` — the start parameters did not hold up.
|
|
376
|
-
* - `quota_exceeded` — the org
|
|
377
|
-
* quota allows, so no account can be
|
|
378
|
-
*
|
|
379
|
-
*
|
|
380
|
-
*
|
|
376
|
+
* - `quota_exceeded` — the org is at the protection ceiling: it has as many
|
|
377
|
+
* app users as its `max_end_users` quota allows, so no account can be
|
|
378
|
+
* created for this identity. This also covers an org still on the beta,
|
|
379
|
+
* whose plan is not enforced yet. Named rather than folded into
|
|
380
|
+
* `no_access`, for `domain_not_allowed`'s reason: it is not about the
|
|
381
|
+
* person, the app can say what happened, and the remedy belongs to the
|
|
382
|
+
* developer rather than to whoever is trying to sign in. It is raised
|
|
381
383
|
* **only where an account would be created** — an identity that already has
|
|
382
384
|
* one signs in at the quota exactly as it does under it, because refusing a
|
|
383
385
|
* sign-in would turn a protection limit into an outage.
|
|
386
|
+
* - `plan_limit` — the org's plan has no room for another app user: it is at
|
|
387
|
+
* its plan's `app_users` limit (fleetless/fleetless#103), counted across
|
|
388
|
+
* every app of the org with pending invitations included. Checked before
|
|
389
|
+
* the protection ceiling, and raised, like `quota_exceeded`, **only where
|
|
390
|
+
* an account would be created**. The remedy is a higher plan or an add-on,
|
|
391
|
+
* which is why it is not `quota_exceeded`. It is the same code the other
|
|
392
|
+
* app-user doors answer as `409 plan_limit`.
|
|
384
393
|
*/
|
|
385
394
|
export declare const clientOidcErrorCode: z.ZodEnum<{
|
|
386
395
|
no_access: "no_access";
|
|
@@ -395,6 +404,7 @@ export declare const clientOidcErrorCode: z.ZodEnum<{
|
|
|
395
404
|
provider_disabled: "provider_disabled";
|
|
396
405
|
invalid_request: "invalid_request";
|
|
397
406
|
quota_exceeded: "quota_exceeded";
|
|
407
|
+
plan_limit: "plan_limit";
|
|
398
408
|
}>;
|
|
399
409
|
export type ClientOidcErrorCode = z.infer<typeof clientOidcErrorCode>;
|
|
400
410
|
/**
|
package/dist/client-auth.js
CHANGED
|
@@ -435,14 +435,23 @@ export const clientOidcExchangeRequest = z
|
|
|
435
435
|
* `provider_misconfigured`, `provider_disabled` — the provider's or the
|
|
436
436
|
* developer's to fix, and the app can say so.
|
|
437
437
|
* - `invalid_request` — the start parameters did not hold up.
|
|
438
|
-
* - `quota_exceeded` — the org
|
|
439
|
-
* quota allows, so no account can be
|
|
440
|
-
*
|
|
441
|
-
*
|
|
442
|
-
*
|
|
438
|
+
* - `quota_exceeded` — the org is at the protection ceiling: it has as many
|
|
439
|
+
* app users as its `max_end_users` quota allows, so no account can be
|
|
440
|
+
* created for this identity. This also covers an org still on the beta,
|
|
441
|
+
* whose plan is not enforced yet. Named rather than folded into
|
|
442
|
+
* `no_access`, for `domain_not_allowed`'s reason: it is not about the
|
|
443
|
+
* person, the app can say what happened, and the remedy belongs to the
|
|
444
|
+
* developer rather than to whoever is trying to sign in. It is raised
|
|
443
445
|
* **only where an account would be created** — an identity that already has
|
|
444
446
|
* one signs in at the quota exactly as it does under it, because refusing a
|
|
445
447
|
* sign-in would turn a protection limit into an outage.
|
|
448
|
+
* - `plan_limit` — the org's plan has no room for another app user: it is at
|
|
449
|
+
* its plan's `app_users` limit (fleetless/fleetless#103), counted across
|
|
450
|
+
* every app of the org with pending invitations included. Checked before
|
|
451
|
+
* the protection ceiling, and raised, like `quota_exceeded`, **only where
|
|
452
|
+
* an account would be created**. The remedy is a higher plan or an add-on,
|
|
453
|
+
* which is why it is not `quota_exceeded`. It is the same code the other
|
|
454
|
+
* app-user doors answer as `409 plan_limit`.
|
|
446
455
|
*/
|
|
447
456
|
export const clientOidcErrorCode = z.enum([
|
|
448
457
|
'no_access',
|
|
@@ -457,6 +466,7 @@ export const clientOidcErrorCode = z.enum([
|
|
|
457
466
|
'provider_disabled',
|
|
458
467
|
'invalid_request',
|
|
459
468
|
'quota_exceeded',
|
|
469
|
+
'plan_limit',
|
|
460
470
|
]);
|
|
461
471
|
/* ------------------------------------------------ MCP, delegated login -- */
|
|
462
472
|
/**
|
package/dist/errors.d.ts
CHANGED
|
@@ -214,9 +214,11 @@ export type OrgLockedDetails = z.infer<typeof orgLockedDetails>;
|
|
|
214
214
|
* fleetless/fleetless#136): one file is larger than `ASSET_FILE_MAX_BYTES`.
|
|
215
215
|
* Not a store and not a plan limit — those are `409 plan_limit` and
|
|
216
216
|
* `409 quota_exceeded`, and mean only "the store is full". `size_bytes` is
|
|
217
|
-
* the
|
|
218
|
-
*
|
|
219
|
-
*
|
|
217
|
+
* the file's size: the announced one when the refusal came before the body
|
|
218
|
+
* was read, or the bytes that arrived when no size (or a false one) was
|
|
219
|
+
* announced and the body still fit the server's body limit. It is `null` only
|
|
220
|
+
* when the body limit stopped the upload, because then nobody counted the
|
|
221
|
+
* bytes.
|
|
220
222
|
*/
|
|
221
223
|
export declare const fileTooLargeDetails: z.ZodObject<{
|
|
222
224
|
max_bytes: z.ZodNumber;
|
package/dist/errors.js
CHANGED
|
@@ -140,16 +140,18 @@ export const orgLockedDetails = z.object({
|
|
|
140
140
|
* fleetless/fleetless#136): one file is larger than `ASSET_FILE_MAX_BYTES`.
|
|
141
141
|
* Not a store and not a plan limit — those are `409 plan_limit` and
|
|
142
142
|
* `409 quota_exceeded`, and mean only "the store is full". `size_bytes` is
|
|
143
|
-
* the
|
|
144
|
-
*
|
|
145
|
-
*
|
|
143
|
+
* the file's size: the announced one when the refusal came before the body
|
|
144
|
+
* was read, or the bytes that arrived when no size (or a false one) was
|
|
145
|
+
* announced and the body still fit the server's body limit. It is `null` only
|
|
146
|
+
* when the body limit stopped the upload, because then nobody counted the
|
|
147
|
+
* bytes.
|
|
146
148
|
*/
|
|
147
149
|
export const fileTooLargeDetails = z.object({
|
|
148
150
|
max_bytes: z.number().int().positive().meta({
|
|
149
151
|
description: 'The most one asset file can be, in bytes: `ASSET_FILE_MAX_BYTES`, the same on every plan.',
|
|
150
152
|
}),
|
|
151
153
|
size_bytes: z.number().int().positive().nullable().meta({
|
|
152
|
-
description: 'The refused file\'s announced size,
|
|
154
|
+
description: 'The refused file\'s size, in bytes: the announced size, or the bytes that arrived when none (or a false one) was announced; `null` only when the body limit stopped the upload and nobody counted the bytes.',
|
|
153
155
|
}),
|
|
154
156
|
});
|
|
155
157
|
/**
|
|
@@ -992,6 +994,10 @@ export const ERROR_CODES = [
|
|
|
992
994
|
* The existing `quota_exceeded` protection ceiling is still checked, and
|
|
993
995
|
* only after this one: it exists to stop runaway consumption, not to tell
|
|
994
996
|
* a developer what their plan allows.
|
|
997
|
+
*
|
|
998
|
+
* At an OIDC callback the same refusal reaches the app as the
|
|
999
|
+
* `clientOidcErrorCode` of the same name, redirected rather than answered
|
|
1000
|
+
* as JSON.
|
|
995
1001
|
*/
|
|
996
1002
|
'plan_limit',
|
|
997
1003
|
/**
|
|
@@ -1016,7 +1022,8 @@ export const ERROR_CODES = [
|
|
|
1016
1022
|
/**
|
|
1017
1023
|
* `413`: one asset file is larger than `ASSET_FILE_MAX_BYTES`. Refused on
|
|
1018
1024
|
* the announced size before the body is read, for every kind including the
|
|
1019
|
-
* URDF, or by the body limit when
|
|
1025
|
+
* URDF, otherwise on the bytes that arrived, or by the body limit when the
|
|
1026
|
+
* body ran past it. `details` is
|
|
1020
1027
|
* `fileTooLargeDetails`. Not a store or plan limit, on any plan; retrying
|
|
1021
1028
|
* does not help, only a smaller file does.
|
|
1022
1029
|
*/
|
package/dist/realtime.d.ts
CHANGED
|
@@ -260,10 +260,10 @@ export type DatapointEvent = z.infer<typeof datapointEvent>;
|
|
|
260
260
|
*/
|
|
261
261
|
export declare const liveSessionEndReason: z.ZodEnum<{
|
|
262
262
|
unknown: "unknown";
|
|
263
|
+
plan_limit: "plan_limit";
|
|
263
264
|
publish_failed: "publish_failed";
|
|
264
265
|
robot_offline: "robot_offline";
|
|
265
266
|
config_changed: "config_changed";
|
|
266
|
-
plan_limit: "plan_limit";
|
|
267
267
|
released_by_peer: "released_by_peer";
|
|
268
268
|
revoked: "revoked";
|
|
269
269
|
expired: "expired";
|
|
@@ -292,10 +292,10 @@ export declare const liveSessionEvent: z.ZodObject<{
|
|
|
292
292
|
state: z.ZodLiteral<"ended">;
|
|
293
293
|
reason: z.ZodEnum<{
|
|
294
294
|
unknown: "unknown";
|
|
295
|
+
plan_limit: "plan_limit";
|
|
295
296
|
publish_failed: "publish_failed";
|
|
296
297
|
robot_offline: "robot_offline";
|
|
297
298
|
config_changed: "config_changed";
|
|
298
|
-
plan_limit: "plan_limit";
|
|
299
299
|
released_by_peer: "released_by_peer";
|
|
300
300
|
revoked: "revoked";
|
|
301
301
|
expired: "expired";
|
package/dist/routes.js
CHANGED
|
@@ -2858,7 +2858,8 @@ export const ROUTES = [
|
|
|
2858
2858
|
'upload token minted by `POST /api/robots/:id/assets/sync`, verified in a `preParsing` hook so a refusal precedes the work rather than ' +
|
|
2859
2859
|
'following it: a `preHandler` would already have buffered the whole file. **One file can be at most `ASSET_FILE_MAX_BYTES`**, on every ' +
|
|
2860
2860
|
'plan and for every kind, the URDF included: an announced size over it answers `413 file_too_large` with `max_bytes` and `size_bytes` ' +
|
|
2861
|
-
'before a byte is buffered
|
|
2861
|
+
'before a byte is buffered; without a truthful size, a body over the limit answers the same code with the bytes that arrived as `size_bytes`, ' +
|
|
2862
|
+
'or with `size_bytes: null` when it ran past the server\'s body limit and nobody counted the bytes. ' +
|
|
2862
2863
|
'Retrying does not help. A file that fits but finds the store full answers `409 plan_limit` (or `409 quota_exceeded` for an organisation ' +
|
|
2863
2864
|
'still on the beta) carrying `store_bytes`, `used_bytes` and `size_bytes`, while the sync carries on with the next file. Rate limited per ' +
|
|
2864
2865
|
'robot inside that same hook, which is why `rateLimited` is `false`: there is no rate-limiting preHandler registered on this route. The ' +
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fleetless/contracts",
|
|
3
|
-
"version": "6.2.0-next.
|
|
3
|
+
"version": "6.2.0-next.2",
|
|
4
4
|
"description": "Fleetless wire contracts: the bridge-cloud protocol, the REST API schemas and the error codes, as zod schemas with generated JSON Schema and OpenAPI artifacts.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Dehne Robotik GmbH",
|