@fleetless/contracts 6.1.0 → 6.2.0-next.1
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 +15 -0
- package/artifacts/constants.json +1 -0
- package/artifacts/routes.json +3 -1
- package/artifacts/schema/file-too-large-details.schema.json +30 -0
- package/dist/assets.d.ts +19 -3
- package/dist/assets.js +19 -3
- package/dist/errors.d.ts +15 -1
- package/dist/errors.js +26 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +4 -2
- package/dist/routes.js +8 -7
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,21 @@ version.
|
|
|
9
9
|
|
|
10
10
|
## [Unreleased]
|
|
11
11
|
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **`file_too_large`** (`413`): one asset file is larger than
|
|
15
|
+
`ASSET_FILE_MAX_BYTES` (one gigabyte, every plan, the URDF included).
|
|
16
|
+
`details` is `fileTooLargeDetails`: `max_bytes` and `size_bytes`, which is
|
|
17
|
+
`null` when no size was announced and the body limit stopped the upload.
|
|
18
|
+
`ASSET_FILE_MAX_BYTES` is in `constants.json`. `plan_limit` and
|
|
19
|
+
`quota_exceeded` on an asset upload now mean only that the store is full.
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- **`POST /api/bridge/assets`** lists `file_too_large` and `plan_limit` among
|
|
24
|
+
its errors, and its notes describe the per-file limit instead of a bare
|
|
25
|
+
`413`.
|
|
26
|
+
|
|
12
27
|
## [6.1.0] — 2026-10-03
|
|
13
28
|
|
|
14
29
|
### Added
|
package/artifacts/constants.json
CHANGED
package/artifacts/routes.json
CHANGED
|
@@ -6488,11 +6488,13 @@
|
|
|
6488
6488
|
"rate_limited",
|
|
6489
6489
|
"validation_error",
|
|
6490
6490
|
"not_found",
|
|
6491
|
+
"file_too_large",
|
|
6492
|
+
"plan_limit",
|
|
6491
6493
|
"quota_exceeded",
|
|
6492
6494
|
"bad_request"
|
|
6493
6495
|
],
|
|
6494
6496
|
"transport": "http",
|
|
6495
|
-
"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. **
|
|
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, and a body over the server's body limit without a truthful size answers the same code with `size_bytes: null`. 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."
|
|
6496
6498
|
},
|
|
6497
6499
|
{
|
|
6498
6500
|
"method": "GET",
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"type": "object",
|
|
4
|
+
"properties": {
|
|
5
|
+
"max_bytes": {
|
|
6
|
+
"type": "integer",
|
|
7
|
+
"exclusiveMinimum": 0,
|
|
8
|
+
"maximum": 9007199254740991,
|
|
9
|
+
"description": "The most one asset file can be, in bytes: `ASSET_FILE_MAX_BYTES`, the same on every plan."
|
|
10
|
+
},
|
|
11
|
+
"size_bytes": {
|
|
12
|
+
"anyOf": [
|
|
13
|
+
{
|
|
14
|
+
"type": "integer",
|
|
15
|
+
"exclusiveMinimum": 0,
|
|
16
|
+
"maximum": 9007199254740991
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"type": "null"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"description": "The refused file's announced size, in bytes; `null` when no size was announced and the body limit stopped the upload."
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"required": [
|
|
26
|
+
"max_bytes",
|
|
27
|
+
"size_bytes"
|
|
28
|
+
],
|
|
29
|
+
"additionalProperties": false
|
|
30
|
+
}
|
package/dist/assets.d.ts
CHANGED
|
@@ -196,6 +196,20 @@ export type AssetSyncResponse = z.infer<typeof assetSyncResponse>;
|
|
|
196
196
|
* the receiver enforces is two numbers that agree until one of them moves.
|
|
197
197
|
*/
|
|
198
198
|
export declare const ROBOT_ASSET_STORE_BYTES = 1000000000;
|
|
199
|
+
/**
|
|
200
|
+
* **How large one asset file may be, on every plan.**
|
|
201
|
+
*
|
|
202
|
+
* Its own number, not the store's, although both are a gigabyte today: the
|
|
203
|
+
* store says how much a robot may keep, this says how much the cloud will
|
|
204
|
+
* take in one request. A file over it is refused `413 file_too_large` with
|
|
205
|
+
* `fileTooLargeDetails`, before a byte is buffered when the size was
|
|
206
|
+
* announced (`ASSET_UPLOAD_HEADERS.size`) and by the server's body limit when
|
|
207
|
+
* it was not. That refusal is not a store or plan limit, applies to the URDF
|
|
208
|
+
* as well, and retrying does not help.
|
|
209
|
+
*
|
|
210
|
+
* In `constants.json` for the same reason as `ROBOT_ASSET_STORE_BYTES`.
|
|
211
|
+
*/
|
|
212
|
+
export declare const ASSET_FILE_MAX_BYTES = 1000000000;
|
|
199
213
|
/**
|
|
200
214
|
* What a full store tells the caller — the same discipline as `job_queue_full`
|
|
201
215
|
* and `publisher_busy`: a refusal that names a state and no number leaves the
|
|
@@ -233,9 +247,11 @@ export type AssetStoreRefusedDetails = z.infer<typeof assetStoreRefusedDetails>;
|
|
|
233
247
|
* unexamined.
|
|
234
248
|
*
|
|
235
249
|
* There was a fourth, `too_large`, for a file over a per-file ceiling. That
|
|
236
|
-
* ceiling is gone
|
|
237
|
-
*
|
|
238
|
-
*
|
|
250
|
+
* ceiling is gone from this enum, not from the cloud: a file over
|
|
251
|
+
* `ASSET_FILE_MAX_BYTES` is refused by the cloud as `413 file_too_large`; a
|
|
252
|
+
* producer that relays it reports `refused` with no details — so the kind
|
|
253
|
+
* had no producer left here and one fewer thing to branch on is the whole of
|
|
254
|
+
* the gain.
|
|
239
255
|
*
|
|
240
256
|
* A consumer that cannot act on the distinction may still print `reference`
|
|
241
257
|
* alone and lose nothing it had before.
|
package/dist/assets.js
CHANGED
|
@@ -251,6 +251,20 @@ export const assetSyncResponse = z.object({
|
|
|
251
251
|
* the receiver enforces is two numbers that agree until one of them moves.
|
|
252
252
|
*/
|
|
253
253
|
export const ROBOT_ASSET_STORE_BYTES = 1_000_000_000;
|
|
254
|
+
/**
|
|
255
|
+
* **How large one asset file may be, on every plan.**
|
|
256
|
+
*
|
|
257
|
+
* Its own number, not the store's, although both are a gigabyte today: the
|
|
258
|
+
* store says how much a robot may keep, this says how much the cloud will
|
|
259
|
+
* take in one request. A file over it is refused `413 file_too_large` with
|
|
260
|
+
* `fileTooLargeDetails`, before a byte is buffered when the size was
|
|
261
|
+
* announced (`ASSET_UPLOAD_HEADERS.size`) and by the server's body limit when
|
|
262
|
+
* it was not. That refusal is not a store or plan limit, applies to the URDF
|
|
263
|
+
* as well, and retrying does not help.
|
|
264
|
+
*
|
|
265
|
+
* In `constants.json` for the same reason as `ROBOT_ASSET_STORE_BYTES`.
|
|
266
|
+
*/
|
|
267
|
+
export const ASSET_FILE_MAX_BYTES = 1_000_000_000;
|
|
254
268
|
/**
|
|
255
269
|
* What a full store tells the caller — the same discipline as `job_queue_full`
|
|
256
270
|
* and `publisher_busy`: a refusal that names a state and no number leaves the
|
|
@@ -293,9 +307,11 @@ export const assetStoreRefusedDetails = z.object({
|
|
|
293
307
|
* unexamined.
|
|
294
308
|
*
|
|
295
309
|
* There was a fourth, `too_large`, for a file over a per-file ceiling. That
|
|
296
|
-
* ceiling is gone
|
|
297
|
-
*
|
|
298
|
-
*
|
|
310
|
+
* ceiling is gone from this enum, not from the cloud: a file over
|
|
311
|
+
* `ASSET_FILE_MAX_BYTES` is refused by the cloud as `413 file_too_large`; a
|
|
312
|
+
* producer that relays it reports `refused` with no details — so the kind
|
|
313
|
+
* had no producer left here and one fewer thing to branch on is the whole of
|
|
314
|
+
* the gain.
|
|
299
315
|
*
|
|
300
316
|
* A consumer that cannot act on the distinction may still print `reference`
|
|
301
317
|
* alone and lose nothing it had before.
|
package/dist/errors.d.ts
CHANGED
|
@@ -209,10 +209,24 @@ export declare const orgLockedDetails: z.ZodObject<{
|
|
|
209
209
|
}>;
|
|
210
210
|
}, z.core.$strip>;
|
|
211
211
|
export type OrgLockedDetails = z.infer<typeof orgLockedDetails>;
|
|
212
|
+
/**
|
|
213
|
+
* The `details` of a `413 file_too_large` refusal (2026-10-03,
|
|
214
|
+
* fleetless/fleetless#136): one file is larger than `ASSET_FILE_MAX_BYTES`.
|
|
215
|
+
* Not a store and not a plan limit — those are `409 plan_limit` and
|
|
216
|
+
* `409 quota_exceeded`, and mean only "the store is full". `size_bytes` is
|
|
217
|
+
* the announced size; it is `null` only when the sender announced none (or a
|
|
218
|
+
* false one) and the server's body limit stopped the upload, because then
|
|
219
|
+
* nobody counted the bytes.
|
|
220
|
+
*/
|
|
221
|
+
export declare const fileTooLargeDetails: z.ZodObject<{
|
|
222
|
+
max_bytes: z.ZodNumber;
|
|
223
|
+
size_bytes: z.ZodNullable<z.ZodNumber>;
|
|
224
|
+
}, z.core.$strip>;
|
|
225
|
+
export type FileTooLargeDetails = z.infer<typeof fileTooLargeDetails>;
|
|
212
226
|
/**
|
|
213
227
|
* The codes in use today. The wire deliberately allows any string — this
|
|
214
228
|
* list is the shared vocabulary, not a closed set, so a new refusal never
|
|
215
229
|
* needs a contracts release before it can be reported honestly.
|
|
216
230
|
*/
|
|
217
|
-
export declare const ERROR_CODES: readonly ["not_found", "validation_error", "bad_request", "unknown_datapoint", "invalid_token", "protocol_mismatch", "bridge_too_old", "invalid_frame", "duplicate_slug", "reserved_slug", "unknown_slug", "unknown_field_path", "unknown_type", "unknown_topic", "invalid_rate", "invalid_range", "config_conflict", "no_data", "robot_offline", "bridge_timeout", "unauthorized", "forbidden", "invalid_credentials", "token_expired", "token_revoked", "email_taken", "identifier_taken", "weak_password", "account_blocked", "busy", "parameter_invalid", "cancel_rejected", "job_lost", "job_unknown_to_bridge", "action_server_lost", "action_failed", "goal_rejected", "goal_send_failed", "result_failed", "goal_uncontrollable", "bridge_disconnected", "config_changed", "publisher_busy", "unknown_command", "not_subscribable", "camera_offline", "no_snapshot_yet", "live_unavailable", "wrong_kind", "not_recorded", "not_aggregatable", "quota_exceeded", "credential_in_use", "goal_timeout", "robot_in_use", "robot_deletion_partial", "job_queue_full", "invalid_uuid", "rate_limited", "tier_required", "token_spent", "service_timeout", "asset_missing", "dynamic_registration_disabled", "client_limit_reached", "idp_unavailable", "mcp_disabled", "tool_not_available", "capability_required", "last_owner", "role_name_taken", "role_in_use", "last_role", "target_state_conflict", "signup_closed", "draft_not_a_document", "internal_error", "not_cancellable", "unsupported_media_type", "wrong_browser", "invalid_yaml", "unstorable_yaml", "registration_closed", "domain_not_allowed", "email_unverified", "origin_not_allowed", "template_invalid", "provider_disabled", "provider_misconfigured", "invalid_redirect_uri", "interaction_expired", "invalid_code", "method_not_allowed", "plan_limit", "plan_required", "org_locked"];
|
|
231
|
+
export declare const ERROR_CODES: readonly ["not_found", "validation_error", "bad_request", "unknown_datapoint", "invalid_token", "protocol_mismatch", "bridge_too_old", "invalid_frame", "duplicate_slug", "reserved_slug", "unknown_slug", "unknown_field_path", "unknown_type", "unknown_topic", "invalid_rate", "invalid_range", "config_conflict", "no_data", "robot_offline", "bridge_timeout", "unauthorized", "forbidden", "invalid_credentials", "token_expired", "token_revoked", "email_taken", "identifier_taken", "weak_password", "account_blocked", "busy", "parameter_invalid", "cancel_rejected", "job_lost", "job_unknown_to_bridge", "action_server_lost", "action_failed", "goal_rejected", "goal_send_failed", "result_failed", "goal_uncontrollable", "bridge_disconnected", "config_changed", "publisher_busy", "unknown_command", "not_subscribable", "camera_offline", "no_snapshot_yet", "live_unavailable", "wrong_kind", "not_recorded", "not_aggregatable", "quota_exceeded", "credential_in_use", "goal_timeout", "robot_in_use", "robot_deletion_partial", "job_queue_full", "invalid_uuid", "rate_limited", "tier_required", "token_spent", "service_timeout", "asset_missing", "dynamic_registration_disabled", "client_limit_reached", "idp_unavailable", "mcp_disabled", "tool_not_available", "capability_required", "last_owner", "role_name_taken", "role_in_use", "last_role", "target_state_conflict", "signup_closed", "draft_not_a_document", "internal_error", "not_cancellable", "unsupported_media_type", "wrong_browser", "invalid_yaml", "unstorable_yaml", "registration_closed", "domain_not_allowed", "email_unverified", "origin_not_allowed", "template_invalid", "provider_disabled", "provider_misconfigured", "invalid_redirect_uri", "interaction_expired", "invalid_code", "method_not_allowed", "plan_limit", "plan_required", "org_locked", "file_too_large"];
|
|
218
232
|
export type ErrorCode = (typeof ERROR_CODES)[number];
|
package/dist/errors.js
CHANGED
|
@@ -135,6 +135,23 @@ export const orgLockedDetails = z.object({
|
|
|
135
135
|
description: '`payment`: a payment is missing. `migration`: the org did not choose what stays when the beta ended.',
|
|
136
136
|
}),
|
|
137
137
|
});
|
|
138
|
+
/**
|
|
139
|
+
* The `details` of a `413 file_too_large` refusal (2026-10-03,
|
|
140
|
+
* fleetless/fleetless#136): one file is larger than `ASSET_FILE_MAX_BYTES`.
|
|
141
|
+
* Not a store and not a plan limit — those are `409 plan_limit` and
|
|
142
|
+
* `409 quota_exceeded`, and mean only "the store is full". `size_bytes` is
|
|
143
|
+
* the announced size; it is `null` only when the sender announced none (or a
|
|
144
|
+
* false one) and the server's body limit stopped the upload, because then
|
|
145
|
+
* nobody counted the bytes.
|
|
146
|
+
*/
|
|
147
|
+
export const fileTooLargeDetails = z.object({
|
|
148
|
+
max_bytes: z.number().int().positive().meta({
|
|
149
|
+
description: 'The most one asset file can be, in bytes: `ASSET_FILE_MAX_BYTES`, the same on every plan.',
|
|
150
|
+
}),
|
|
151
|
+
size_bytes: z.number().int().positive().nullable().meta({
|
|
152
|
+
description: 'The refused file\'s announced size, in bytes; `null` when no size was announced and the body limit stopped the upload.',
|
|
153
|
+
}),
|
|
154
|
+
});
|
|
138
155
|
/**
|
|
139
156
|
* The codes in use today. The wire deliberately allows any string — this
|
|
140
157
|
* list is the shared vocabulary, not a closed set, so a new refusal never
|
|
@@ -995,4 +1012,13 @@ export const ERROR_CODES = [
|
|
|
995
1012
|
* payment, or the platform's own move off the beta.
|
|
996
1013
|
*/
|
|
997
1014
|
'org_locked',
|
|
1015
|
+
// 2026-10-03 — the per-file asset limit (#136).
|
|
1016
|
+
/**
|
|
1017
|
+
* `413`: one asset file is larger than `ASSET_FILE_MAX_BYTES`. Refused on
|
|
1018
|
+
* the announced size before the body is read, for every kind including the
|
|
1019
|
+
* URDF, or by the body limit when no size was announced. `details` is
|
|
1020
|
+
* `fileTooLargeDetails`. Not a store or plan limit, on any plan; retrying
|
|
1021
|
+
* does not help, only a smaller file does.
|
|
1022
|
+
*/
|
|
1023
|
+
'file_too_large',
|
|
998
1024
|
];
|
package/dist/index.d.ts
CHANGED
|
@@ -41,14 +41,14 @@ export { clientRobotListItem, clientRobotListResponse } from './client-robots.js
|
|
|
41
41
|
export type { ClientRobotListItem, ClientRobotListResponse } from './client-robots.js';
|
|
42
42
|
export { APP_USER_DISPLAY_NAME_MAX, APP_URL_PLACEHOLDERS, MAIL_TEMPLATE_VARIABLES, DEFAULT_MAIL_TEMPLATES, providerSlug, appUserStatus, appUser, appUserListResponse, createAppUserRequest, patchAppUserRequest, createAppInvitationRequest, appInvitation, pendingAppInvitation, appInvitationListResponse, appOidcProvider, appOidcProviderListResponse, createAppOidcProviderRequest, patchAppOidcProviderRequest, appUrlTemplate, allowedOrigin, emailDomain, appAuthConfig, appSignInMethods, appTwoFactorPolicy, appHomeUrl, hostedAccent, HOSTED_LOGO_MAX_BYTES, HOSTED_LOGO_TYPES, appHostedPages, putAppAuthRegistrationRequest, putAppAuthSignInRequest, putAppAuthUrlsRequest, putAppAuthMcpRequest, putAppAuthLookRequest, mailTemplateKind, appMailTemplate, appMailTemplateListResponse, putAppMailTemplateRequest, mailTemplatePreviewRequest, mailTemplatePreviewResponse, mailTemplateProblemDetails, mailOutcome, } from './app-users.js';
|
|
43
43
|
export type { AppUserStatus, AppUser, AppUserListResponse, CreateAppUserRequest, PatchAppUserRequest, CreateAppInvitationRequest, AppInvitation, PendingAppInvitation, AppInvitationListResponse, AppOidcProvider, AppOidcProviderListResponse, CreateAppOidcProviderRequest, PatchAppOidcProviderRequest, AppAuthConfig, AppSignInMethods, AppTwoFactorPolicy, AppHostedPages, PutAppAuthRegistrationRequest, PutAppAuthSignInRequest, PutAppAuthUrlsRequest, PutAppAuthMcpRequest, PutAppAuthLookRequest, MailTemplateKind, AppMailTemplate, AppMailTemplateListResponse, PutAppMailTemplateRequest, MailTemplatePreviewRequest, MailTemplatePreviewResponse, MailTemplateProblemDetails, MailOutcome, } from './app-users.js';
|
|
44
|
-
export { assetKind, URDF_ASSET_NAME, asset, urdfCompleteness, assetListResponse, assetsClearResponse, missingAssetQuery, assetSyncRequest, assetSyncResponse, assetSyncState, assetSyncStatus, assetFailure, assetFailureKind, assetStoreRefusedDetails, assetSyncBusyDetails, ROBOT_ASSET_STORE_BYTES, } from './assets.js';
|
|
44
|
+
export { assetKind, URDF_ASSET_NAME, asset, urdfCompleteness, assetListResponse, assetsClearResponse, missingAssetQuery, assetSyncRequest, assetSyncResponse, assetSyncState, assetSyncStatus, assetFailure, assetFailureKind, assetStoreRefusedDetails, assetSyncBusyDetails, ROBOT_ASSET_STORE_BYTES, ASSET_FILE_MAX_BYTES, } from './assets.js';
|
|
45
45
|
export type { AssetKind, Asset, UrdfCompleteness, AssetListResponse, AssetsClearResponse, MissingAssetQuery, AssetSyncRequest, AssetSyncResponse, AssetSyncState, AssetSyncStatus, AssetFailure, AssetFailureKind, AssetStoreRefusedDetails, AssetSyncBusyDetails, } from './assets.js';
|
|
46
46
|
export { auditActor, auditEvent, auditQuery, auditListResponse, AUDIT_CSV_COLUMNS, AUDIT_RETENTION_DAYS } from './audit.js';
|
|
47
47
|
export type { AuditActor, AuditEvent, AuditQuery, AuditListResponse } from './audit.js';
|
|
48
48
|
export { alertRowCondition, alertSeverity, alertState, datapointAlertRow, alertListResponse, orgFiringAlertsResponse, orgAlertsQuery, datapointDisplay, putDatapointDisplayRequest, } from './alerts.js';
|
|
49
49
|
export type { AlertRowCondition, AlertSeverity, AlertState, DatapointAlertRow, AlertListResponse, OrgFiringAlertsResponse, OrgAlertsQuery, DatapointDisplay, PutDatapointDisplayRequest, } from './alerts.js';
|
|
50
|
-
export { apiError, parameterViolation, parameterInvalidDetails, cancelRejectedDetails, invalidCodeDetails, ERROR_CODES, planLimitDetails, assetPlanLimitDetails, planRequiredDetails, orgLockedDetails, } from './errors.js';
|
|
51
|
-
export type { ApiError, ParameterViolation, ParameterInvalidDetails, CancelRejectedDetails, InvalidCodeDetails, ErrorCode, PlanLimitDetails, AssetPlanLimitDetails, PlanRequiredDetails, OrgLockedDetails, } from './errors.js';
|
|
50
|
+
export { apiError, parameterViolation, parameterInvalidDetails, cancelRejectedDetails, invalidCodeDetails, ERROR_CODES, planLimitDetails, assetPlanLimitDetails, planRequiredDetails, orgLockedDetails, fileTooLargeDetails, } from './errors.js';
|
|
51
|
+
export type { ApiError, ParameterViolation, ParameterInvalidDetails, CancelRejectedDetails, InvalidCodeDetails, ErrorCode, PlanLimitDetails, AssetPlanLimitDetails, PlanRequiredDetails, OrgLockedDetails, FileTooLargeDetails, } from './errors.js';
|
|
52
52
|
export { oauthErrorCode, oauthError, oauthRedirectResponse, oauthCodeTokenRequest, oauthRefreshTokenRequest, oauthTokenRequest, oauthTokenResponse, redirectUri, codeChallengeMethod, oauthAuthorizeQuery, dynamicClientRegistrationRequest, MCP_DCR_MAX_REDIRECT_URIS, dynamicClientRegistrationResponse, authorizationServerMetadata, protectedResourceMetadata, } from './oauth.js';
|
|
53
53
|
export type { OauthErrorCode, OauthError, OauthRedirectResponse, OauthCodeTokenRequest, OauthRefreshTokenRequest, OauthTokenRequest, OauthTokenResponse, RedirectUri, OauthAuthorizeQuery, DynamicClientRegistrationRequest, DynamicClientRegistrationResponse, AuthorizationServerMetadata, ProtectedResourceMetadata, } from './oauth.js';
|
|
54
54
|
export { ROUTES, ROUTE_SECTIONS, IN_HANDLER_ROUTES, developerSignInRoutes } from './routes.js';
|
package/dist/index.js
CHANGED
|
@@ -49,12 +49,14 @@ export { clientLoginRequest, clientRefreshRequest, clientLogoutRequest, clientRe
|
|
|
49
49
|
export { clientRobotListItem, clientRobotListResponse } from './client-robots.js';
|
|
50
50
|
// The per-app identity space.
|
|
51
51
|
export { APP_USER_DISPLAY_NAME_MAX, APP_URL_PLACEHOLDERS, MAIL_TEMPLATE_VARIABLES, DEFAULT_MAIL_TEMPLATES, providerSlug, appUserStatus, appUser, appUserListResponse, createAppUserRequest, patchAppUserRequest, createAppInvitationRequest, appInvitation, pendingAppInvitation, appInvitationListResponse, appOidcProvider, appOidcProviderListResponse, createAppOidcProviderRequest, patchAppOidcProviderRequest, appUrlTemplate, allowedOrigin, emailDomain, appAuthConfig, appSignInMethods, appTwoFactorPolicy, appHomeUrl, hostedAccent, HOSTED_LOGO_MAX_BYTES, HOSTED_LOGO_TYPES, appHostedPages, putAppAuthRegistrationRequest, putAppAuthSignInRequest, putAppAuthUrlsRequest, putAppAuthMcpRequest, putAppAuthLookRequest, mailTemplateKind, appMailTemplate, appMailTemplateListResponse, putAppMailTemplateRequest, mailTemplatePreviewRequest, mailTemplatePreviewResponse, mailTemplateProblemDetails, mailOutcome, } from './app-users.js';
|
|
52
|
-
export { assetKind, URDF_ASSET_NAME, asset, urdfCompleteness, assetListResponse, assetsClearResponse, missingAssetQuery, assetSyncRequest, assetSyncResponse, assetSyncState, assetSyncStatus, assetFailure, assetFailureKind, assetStoreRefusedDetails, assetSyncBusyDetails, ROBOT_ASSET_STORE_BYTES, } from './assets.js';
|
|
52
|
+
export { assetKind, URDF_ASSET_NAME, asset, urdfCompleteness, assetListResponse, assetsClearResponse, missingAssetQuery, assetSyncRequest, assetSyncResponse, assetSyncState, assetSyncStatus, assetFailure, assetFailureKind, assetStoreRefusedDetails, assetSyncBusyDetails, ROBOT_ASSET_STORE_BYTES, ASSET_FILE_MAX_BYTES, } from './assets.js';
|
|
53
53
|
export { auditActor, auditEvent, auditQuery, auditListResponse, AUDIT_CSV_COLUMNS, AUDIT_RETENTION_DAYS } from './audit.js';
|
|
54
54
|
export { alertRowCondition, alertSeverity, alertState, datapointAlertRow, alertListResponse, orgFiringAlertsResponse, orgAlertsQuery, datapointDisplay, putDatapointDisplayRequest, } from './alerts.js';
|
|
55
55
|
export { apiError, parameterViolation, parameterInvalidDetails, cancelRejectedDetails, invalidCodeDetails, ERROR_CODES,
|
|
56
56
|
// 2026-10-02 — plans (#103). The plan errors (I-3).
|
|
57
|
-
planLimitDetails, assetPlanLimitDetails, planRequiredDetails, orgLockedDetails,
|
|
57
|
+
planLimitDetails, assetPlanLimitDetails, planRequiredDetails, orgLockedDetails,
|
|
58
|
+
// 2026-10-03 — the per-file asset limit (#136).
|
|
59
|
+
fileTooLargeDetails, } from './errors.js';
|
|
58
60
|
export { oauthErrorCode, oauthError, oauthRedirectResponse, oauthCodeTokenRequest, oauthRefreshTokenRequest, oauthTokenRequest, oauthTokenResponse, redirectUri, codeChallengeMethod, oauthAuthorizeQuery, dynamicClientRegistrationRequest, MCP_DCR_MAX_REDIRECT_URIS, dynamicClientRegistrationResponse, authorizationServerMetadata, protectedResourceMetadata, } from './oauth.js';
|
|
59
61
|
export { ROUTES, ROUTE_SECTIONS, IN_HANDLER_ROUTES, developerSignInRoutes } from './routes.js';
|
|
60
62
|
// 2026-10-02 — plans (#103). The catalogue (I-1) only: `PLANS` and `ADDONS`
|
package/dist/routes.js
CHANGED
|
@@ -2852,16 +2852,17 @@ export const ROUTES = [
|
|
|
2852
2852
|
summary: 'Takes one asset file from a robot during a sync.',
|
|
2853
2853
|
audience: 'internal', auth: 'robot_upload', rateLimited: false, ownerTier: false, status: 201,
|
|
2854
2854
|
params: [], query: null, request: null, response: asset,
|
|
2855
|
-
errors: ['unauthorized', 'rate_limited', 'validation_error', 'not_found', 'quota_exceeded', 'bad_request'], transport: 'http',
|
|
2855
|
+
errors: ['unauthorized', 'rate_limited', 'validation_error', 'not_found', 'file_too_large', 'plan_limit', 'quota_exceeded', 'bad_request'], transport: 'http',
|
|
2856
2856
|
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 ' +
|
|
2857
2857
|
'and its announced size — rides in the `x-fleetless-asset-*` headers `ASSET_UPLOAD_HEADERS` names. The credential is a short-lived ' +
|
|
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
|
-
'following it: a `preHandler` would already have buffered the whole file. **
|
|
2860
|
-
'
|
|
2861
|
-
'
|
|
2862
|
-
'
|
|
2863
|
-
'
|
|
2864
|
-
'
|
|
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
|
+
'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, and a body over the server\'s body limit without a truthful size answers the same code with `size_bytes: null`. ' +
|
|
2862
|
+
'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
|
+
'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
|
+
'robot inside that same hook, which is why `rateLimited` is `false`: there is no rate-limiting preHandler registered on this route. The ' +
|
|
2865
|
+
'URDF itself is never refused for the store; only meshes and textures are charged against it.',
|
|
2865
2866
|
},
|
|
2866
2867
|
/* ------------------------------------ realtime and bridge transports */
|
|
2867
2868
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fleetless/contracts",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.2.0-next.1",
|
|
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",
|