@fleetless/contracts 5.0.0-next.2 → 5.1.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 +16 -0
- package/artifacts/openapi.json +2 -2
- package/artifacts/routes.json +7 -2
- package/artifacts/schema/cancel-rejected-details.schema.json +46 -0
- package/dist/errors.d.ts +19 -0
- package/dist/errors.js +15 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/routes.js +9 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,19 @@ version.
|
|
|
11
11
|
|
|
12
12
|
### Added
|
|
13
13
|
|
|
14
|
+
- **`cancelRejectedDetails`** (`CancelRejectedDetails`): the `details` of a
|
|
15
|
+
`cancel_rejected` refusal, `{ goals }` with at least one `{ job_id,
|
|
16
|
+
goal_id, return_code }` — every goal the cancel reached, accepted ones
|
|
17
|
+
included, with its `CancelGoal` return code (`CANCEL_RETURN_CODES`, or
|
|
18
|
+
`null` when that goal's server did not answer). A consumer parses the
|
|
19
|
+
refusal instead of reading its shape from prose. Published as the
|
|
20
|
+
artifact `cancel-rejected-details`. The wire does not change: the cloud
|
|
21
|
+
already sends this shape.
|
|
22
|
+
|
|
23
|
+
## [5.0.0] — 2026-09-30
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
14
27
|
- **Protocol 5: `unknown` jobs, external goals, and a hard cut of protocols 3
|
|
15
28
|
and 4.** `PROTOCOL_VERSION` is 5 and the only version served: protocols 2,
|
|
16
29
|
3 and 4 are unsupported from this release on, with no sunset window, and
|
|
@@ -40,6 +53,9 @@ version.
|
|
|
40
53
|
caller is refused, not told the cancel succeeded. `reportedJobState`, every
|
|
41
54
|
state but `unknown`, is what `job_update`, `job_status` entries and
|
|
42
55
|
`hello.active_jobs` accept, so a bridge claiming `unknown` fails validation.
|
|
56
|
+
`POST /api/robots/:id/jobs/:slug/cancel` lists the answers this adds:
|
|
57
|
+
`409 cancel_rejected`, `504 bridge_timeout`, and `502` with the bridge's
|
|
58
|
+
own code (`unknown_slug`, `action_server_lost`, `internal_error`).
|
|
43
59
|
|
|
44
60
|
### Removed
|
|
45
61
|
|
package/artifacts/openapi.json
CHANGED
|
@@ -7003,7 +7003,7 @@
|
|
|
7003
7003
|
}
|
|
7004
7004
|
},
|
|
7005
7005
|
"default": {
|
|
7006
|
-
"description": "An error envelope. Codes this route is known to answer: `unauthorized`, `token_expired`, `token_revoked`, `forbidden`, `invalid_uuid`, `not_found`, `validation_error`, `not_cancellable`, `robot_offline`.",
|
|
7006
|
+
"description": "An error envelope. Codes this route is known to answer: `unauthorized`, `token_expired`, `token_revoked`, `forbidden`, `invalid_uuid`, `not_found`, `validation_error`, `not_cancellable`, `robot_offline`, `cancel_rejected`, `bridge_timeout`, `unknown_slug`, `action_server_lost`, `internal_error`.",
|
|
7007
7007
|
"content": {
|
|
7008
7008
|
"application/json": {
|
|
7009
7009
|
"schema": {
|
|
@@ -7013,7 +7013,7 @@
|
|
|
7013
7013
|
}
|
|
7014
7014
|
}
|
|
7015
7015
|
},
|
|
7016
|
-
"description": "The body is optional: a bodyless `POST` was every caller's shape before `job_id` existed, and absent or `job_id: null` both mean \"cancel whatever is running\". A named `job_id` that is **not** what is running cancels nothing and answers `404` — the caller named an id and thereby ruled the other one out. An `external` job is cancelled the same way, through its goal id. Cancelling an `unknown` job also cancels every external goal on its action, since one of them may be that job. A service is `422 not_cancellable`: a service call has no goal to cancel. Nothing running is a `200` with `job: null`.",
|
|
7016
|
+
"description": "The body is optional: a bodyless `POST` was every caller's shape before `job_id` existed, and absent or `job_id: null` both mean \"cancel whatever is running\". A named `job_id` that is **not** what is running cancels nothing and answers `404` — the caller named an id and thereby ruled the other one out. An `external` job is cancelled the same way, through its goal id. Cancelling an `unknown` job also cancels every external goal on its action, since one of them may be that job. A service is `422 not_cancellable`: a service call has no goal to cancel. Nothing running is a `200` with `job: null`. The answer waits for the bridge's `cancel_result`: a `200` means the action server accepted the cancel request, not that the goal has ended — the job's end arrives as its own update. Any goal answered `ERROR_REJECTED` makes it `409 cancel_rejected`, with every goal and its `return_code` in `details.goals`; no answer within `JOB_HEARTBEAT_TIMEOUT_MS` is `504 bridge_timeout`; a cancel the bridge could not send at all is `502` carrying the bridge's own code (`unknown_slug`, `action_server_lost`, `internal_error`).",
|
|
7017
7017
|
"requestBody": {
|
|
7018
7018
|
"required": false,
|
|
7019
7019
|
"content": {
|
package/artifacts/routes.json
CHANGED
|
@@ -4147,10 +4147,15 @@
|
|
|
4147
4147
|
"not_found",
|
|
4148
4148
|
"validation_error",
|
|
4149
4149
|
"not_cancellable",
|
|
4150
|
-
"robot_offline"
|
|
4150
|
+
"robot_offline",
|
|
4151
|
+
"cancel_rejected",
|
|
4152
|
+
"bridge_timeout",
|
|
4153
|
+
"unknown_slug",
|
|
4154
|
+
"action_server_lost",
|
|
4155
|
+
"internal_error"
|
|
4151
4156
|
],
|
|
4152
4157
|
"transport": "http",
|
|
4153
|
-
"notes": "The body is optional: a bodyless `POST` was every caller's shape before `job_id` existed, and absent or `job_id: null` both mean \"cancel whatever is running\". A named `job_id` that is **not** what is running cancels nothing and answers `404` — the caller named an id and thereby ruled the other one out. An `external` job is cancelled the same way, through its goal id. Cancelling an `unknown` job also cancels every external goal on its action, since one of them may be that job. A service is `422 not_cancellable`: a service call has no goal to cancel. Nothing running is a `200` with `job: null`."
|
|
4158
|
+
"notes": "The body is optional: a bodyless `POST` was every caller's shape before `job_id` existed, and absent or `job_id: null` both mean \"cancel whatever is running\". A named `job_id` that is **not** what is running cancels nothing and answers `404` — the caller named an id and thereby ruled the other one out. An `external` job is cancelled the same way, through its goal id. Cancelling an `unknown` job also cancels every external goal on its action, since one of them may be that job. A service is `422 not_cancellable`: a service call has no goal to cancel. Nothing running is a `200` with `job: null`. The answer waits for the bridge's `cancel_result`: a `200` means the action server accepted the cancel request, not that the goal has ended — the job's end arrives as its own update. Any goal answered `ERROR_REJECTED` makes it `409 cancel_rejected`, with every goal and its `return_code` in `details.goals`; no answer within `JOB_HEARTBEAT_TIMEOUT_MS` is `504 bridge_timeout`; a cancel the bridge could not send at all is `502` carrying the bridge's own code (`unknown_slug`, `action_server_lost`, `internal_error`)."
|
|
4154
4159
|
},
|
|
4155
4160
|
{
|
|
4156
4161
|
"method": "POST",
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"type": "object",
|
|
4
|
+
"properties": {
|
|
5
|
+
"goals": {
|
|
6
|
+
"minItems": 1,
|
|
7
|
+
"type": "array",
|
|
8
|
+
"items": {
|
|
9
|
+
"type": "object",
|
|
10
|
+
"properties": {
|
|
11
|
+
"job_id": {
|
|
12
|
+
"type": "string",
|
|
13
|
+
"format": "uuid",
|
|
14
|
+
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
|
|
15
|
+
},
|
|
16
|
+
"goal_id": {
|
|
17
|
+
"type": "string",
|
|
18
|
+
"minLength": 1
|
|
19
|
+
},
|
|
20
|
+
"return_code": {
|
|
21
|
+
"anyOf": [
|
|
22
|
+
{
|
|
23
|
+
"type": "integer",
|
|
24
|
+
"minimum": 0,
|
|
25
|
+
"maximum": 3
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"type": "null"
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"required": [
|
|
34
|
+
"job_id",
|
|
35
|
+
"goal_id",
|
|
36
|
+
"return_code"
|
|
37
|
+
],
|
|
38
|
+
"additionalProperties": false
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"required": [
|
|
43
|
+
"goals"
|
|
44
|
+
],
|
|
45
|
+
"additionalProperties": false
|
|
46
|
+
}
|
package/dist/errors.d.ts
CHANGED
|
@@ -44,6 +44,25 @@ export declare const parameterInvalidDetails: z.ZodObject<{
|
|
|
44
44
|
}, z.core.$strip>>;
|
|
45
45
|
}, z.core.$strip>;
|
|
46
46
|
export type ParameterInvalidDetails = z.infer<typeof parameterInvalidDetails>;
|
|
47
|
+
/**
|
|
48
|
+
* The `details` of a `cancel_rejected` refusal: every goal the cancel reached,
|
|
49
|
+
* accepted ones included, each with the `CancelGoal` return code its action
|
|
50
|
+
* server answered — compare `return_code` against `CANCEL_RETURN_CODES`
|
|
51
|
+
* (`none`, `rejected`, `unknown_goal_id`, `goal_terminated`); it is `null`
|
|
52
|
+
* when that goal's server did not answer within the bridge's bound. Always at
|
|
53
|
+
* least one goal: the cloud refuses a cancel only because a goal's server
|
|
54
|
+
* answered `ERROR_REJECTED`. Pinned here for the reason
|
|
55
|
+
* `parameterInvalidDetails` is: a caller parses it instead of reading the
|
|
56
|
+
* shape from prose.
|
|
57
|
+
*/
|
|
58
|
+
export declare const cancelRejectedDetails: z.ZodObject<{
|
|
59
|
+
goals: z.ZodArray<z.ZodObject<{
|
|
60
|
+
job_id: z.ZodUUID;
|
|
61
|
+
goal_id: z.ZodString;
|
|
62
|
+
return_code: z.ZodNullable<z.ZodNumber>;
|
|
63
|
+
}, z.core.$strip>>;
|
|
64
|
+
}, z.core.$strip>;
|
|
65
|
+
export type CancelRejectedDetails = z.infer<typeof cancelRejectedDetails>;
|
|
47
66
|
/**
|
|
48
67
|
* The codes in use today. The wire deliberately allows any string — this
|
|
49
68
|
* list is the shared vocabulary, not a closed set, so a new refusal never
|
package/dist/errors.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// SPDX-License-Identifier: Apache-2.0
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
+
import { bridgeCancelResultEntry } from './protocol.js';
|
|
3
4
|
/**
|
|
4
5
|
* The one error shape of the REST and realtime APIs: a stable
|
|
5
6
|
* machine-readable code plus a human message; validation errors name the
|
|
@@ -38,6 +39,20 @@ export const parameterViolation = z.object({
|
|
|
38
39
|
export const parameterInvalidDetails = z.object({
|
|
39
40
|
violations: z.array(parameterViolation).min(1),
|
|
40
41
|
});
|
|
42
|
+
/**
|
|
43
|
+
* The `details` of a `cancel_rejected` refusal: every goal the cancel reached,
|
|
44
|
+
* accepted ones included, each with the `CancelGoal` return code its action
|
|
45
|
+
* server answered — compare `return_code` against `CANCEL_RETURN_CODES`
|
|
46
|
+
* (`none`, `rejected`, `unknown_goal_id`, `goal_terminated`); it is `null`
|
|
47
|
+
* when that goal's server did not answer within the bridge's bound. Always at
|
|
48
|
+
* least one goal: the cloud refuses a cancel only because a goal's server
|
|
49
|
+
* answered `ERROR_REJECTED`. Pinned here for the reason
|
|
50
|
+
* `parameterInvalidDetails` is: a caller parses it instead of reading the
|
|
51
|
+
* shape from prose.
|
|
52
|
+
*/
|
|
53
|
+
export const cancelRejectedDetails = z.object({
|
|
54
|
+
goals: z.array(bridgeCancelResultEntry).min(1),
|
|
55
|
+
});
|
|
41
56
|
/**
|
|
42
57
|
* The codes in use today. The wire deliberately allows any string — this
|
|
43
58
|
* list is the shared vocabulary, not a closed set, so a new refusal never
|
package/dist/index.d.ts
CHANGED
|
@@ -45,8 +45,8 @@ export { auditActor, auditEvent, auditQuery, auditListResponse, AUDIT_CSV_COLUMN
|
|
|
45
45
|
export type { AuditActor, AuditEvent, AuditQuery, AuditListResponse } from './audit.js';
|
|
46
46
|
export { alertRowCondition, alertSeverity, alertState, datapointAlertRow, alertListResponse, orgFiringAlertsResponse, orgAlertsQuery, datapointDisplay, putDatapointDisplayRequest, } from './alerts.js';
|
|
47
47
|
export type { AlertRowCondition, AlertSeverity, AlertState, DatapointAlertRow, AlertListResponse, OrgFiringAlertsResponse, OrgAlertsQuery, DatapointDisplay, PutDatapointDisplayRequest, } from './alerts.js';
|
|
48
|
-
export { apiError, parameterViolation, parameterInvalidDetails, ERROR_CODES } from './errors.js';
|
|
49
|
-
export type { ApiError, ParameterViolation, ParameterInvalidDetails, ErrorCode } from './errors.js';
|
|
48
|
+
export { apiError, parameterViolation, parameterInvalidDetails, cancelRejectedDetails, ERROR_CODES } from './errors.js';
|
|
49
|
+
export type { ApiError, ParameterViolation, ParameterInvalidDetails, CancelRejectedDetails, ErrorCode } from './errors.js';
|
|
50
50
|
export { oauthErrorCode, oauthError, oauthRedirectResponse, oauthCodeTokenRequest, oauthRefreshTokenRequest, oauthTokenRequest, oauthTokenResponse, redirectUri, codeChallengeMethod, oauthAuthorizeQuery, dynamicClientRegistrationRequest, MCP_DCR_MAX_REDIRECT_URIS, dynamicClientRegistrationResponse, authorizationServerMetadata, protectedResourceMetadata, } from './oauth.js';
|
|
51
51
|
export type { OauthErrorCode, OauthError, OauthRedirectResponse, OauthCodeTokenRequest, OauthRefreshTokenRequest, OauthTokenRequest, OauthTokenResponse, RedirectUri, OauthAuthorizeQuery, DynamicClientRegistrationRequest, DynamicClientRegistrationResponse, AuthorizationServerMetadata, ProtectedResourceMetadata, } from './oauth.js';
|
|
52
52
|
export { ROUTES, ROUTE_SECTIONS, IN_HANDLER_ROUTES } from './routes.js';
|
package/dist/index.js
CHANGED
|
@@ -46,6 +46,6 @@ export { APP_USER_DISPLAY_NAME_MAX, APP_URL_PLACEHOLDERS, MAIL_TEMPLATE_VARIABLE
|
|
|
46
46
|
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';
|
|
47
47
|
export { auditActor, auditEvent, auditQuery, auditListResponse, AUDIT_CSV_COLUMNS, AUDIT_RETENTION_DAYS } from './audit.js';
|
|
48
48
|
export { alertRowCondition, alertSeverity, alertState, datapointAlertRow, alertListResponse, orgFiringAlertsResponse, orgAlertsQuery, datapointDisplay, putDatapointDisplayRequest, } from './alerts.js';
|
|
49
|
-
export { apiError, parameterViolation, parameterInvalidDetails, ERROR_CODES } from './errors.js';
|
|
49
|
+
export { apiError, parameterViolation, parameterInvalidDetails, cancelRejectedDetails, ERROR_CODES } from './errors.js';
|
|
50
50
|
export { oauthErrorCode, oauthError, oauthRedirectResponse, oauthCodeTokenRequest, oauthRefreshTokenRequest, oauthTokenRequest, oauthTokenResponse, redirectUri, codeChallengeMethod, oauthAuthorizeQuery, dynamicClientRegistrationRequest, MCP_DCR_MAX_REDIRECT_URIS, dynamicClientRegistrationResponse, authorizationServerMetadata, protectedResourceMetadata, } from './oauth.js';
|
|
51
51
|
export { ROUTES, ROUTE_SECTIONS, IN_HANDLER_ROUTES } from './routes.js';
|
package/dist/routes.js
CHANGED
|
@@ -2112,12 +2112,19 @@ export const ROUTES = [
|
|
|
2112
2112
|
{ name: 'slug', description: 'The action slug from the published configuration; a service slug is refused.' },
|
|
2113
2113
|
],
|
|
2114
2114
|
query: null, request: cancelRequest, requestOptional: true, response: jobResponse,
|
|
2115
|
-
errors: [
|
|
2115
|
+
errors: [
|
|
2116
|
+
...CLIENT_GUARD, 'invalid_uuid', 'not_found', 'validation_error', 'not_cancellable', 'robot_offline',
|
|
2117
|
+
'cancel_rejected', 'bridge_timeout', 'unknown_slug', 'action_server_lost', 'internal_error',
|
|
2118
|
+
], transport: 'http',
|
|
2116
2119
|
notes: 'The body is optional: a bodyless `POST` was every caller\'s shape before `job_id` existed, and absent or `job_id: null` both mean ' +
|
|
2117
2120
|
'"cancel whatever is running". A named `job_id` that is **not** what is running cancels nothing and answers `404` — the caller named an ' +
|
|
2118
2121
|
'id and thereby ruled the other one out. An `external` job is cancelled the same way, through its goal id. Cancelling an `unknown` job ' +
|
|
2119
2122
|
'also cancels every external goal on its action, since one of them may be that job. A service is `422 not_cancellable`: a service call ' +
|
|
2120
|
-
'has no goal to cancel. Nothing running is a `200` with `job: null`.'
|
|
2123
|
+
'has no goal to cancel. Nothing running is a `200` with `job: null`. The answer waits for the bridge\'s `cancel_result`: a `200` means ' +
|
|
2124
|
+
'the action server accepted the cancel request, not that the goal has ended — the job\'s end arrives as its own update. Any goal ' +
|
|
2125
|
+
'answered `ERROR_REJECTED` makes it `409 cancel_rejected`, with every goal and its `return_code` in `details.goals`; no answer within ' +
|
|
2126
|
+
'`JOB_HEARTBEAT_TIMEOUT_MS` is `504 bridge_timeout`; a cancel the bridge could not send at all is `502` carrying the bridge\'s own ' +
|
|
2127
|
+
'code (`unknown_slug`, `action_server_lost`, `internal_error`).',
|
|
2121
2128
|
},
|
|
2122
2129
|
{
|
|
2123
2130
|
method: 'POST', path: '/api/robots/:id/publishers/:slug', section: 'commands',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fleetless/contracts",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.1.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",
|