@fleetless/contracts 6.0.0 → 6.1.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 +42 -0
- package/artifacts/openapi.json +692 -1
- package/artifacts/routes.json +101 -0
- package/artifacts/schema/addon-catalogue-entry.schema.json +81 -0
- package/artifacts/schema/addon-key.schema.json +11 -0
- package/artifacts/schema/admin-plan-change-request.schema.json +189 -0
- package/artifacts/schema/asset-plan-limit-details.schema.json +115 -0
- package/artifacts/schema/audit-actor.schema.json +2 -1
- package/artifacts/schema/audit-event.schema.json +2 -1
- package/artifacts/schema/audit-list-response.schema.json +2 -1
- package/artifacts/schema/org-addons.schema.json +44 -0
- package/artifacts/schema/org-lock.schema.json +25 -0
- package/artifacts/schema/org-locked-details.schema.json +18 -0
- package/artifacts/schema/org-plan-usage.schema.json +51 -0
- package/artifacts/schema/org-plan.schema.json +500 -0
- package/artifacts/schema/pending-plan-change.schema.json +123 -0
- package/artifacts/schema/plan-catalogue-entry.schema.json +249 -0
- package/artifacts/schema/plan-change-keep.schema.json +49 -0
- package/artifacts/schema/plan-change-reason.schema.json +10 -0
- package/artifacts/schema/plan-change-request.schema.json +77 -0
- package/artifacts/schema/plan-currency.schema.json +8 -0
- package/artifacts/schema/plan-features.schema.json +44 -0
- package/artifacts/schema/plan-id.schema.json +10 -0
- package/artifacts/schema/plan-limit-details.schema.json +94 -0
- package/artifacts/schema/plan-limits.schema.json +121 -0
- package/artifacts/schema/plan-overrides.schema.json +111 -0
- package/artifacts/schema/plan-prices.schema.json +37 -0
- package/artifacts/schema/plan-required-details.schema.json +45 -0
- package/dist/audit.d.ts +10 -0
- package/dist/audit.js +8 -1
- package/dist/errors.d.ts +138 -1
- package/dist/errors.js +104 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.js +11 -1
- package/dist/plans.d.ts +507 -0
- package/dist/plans.js +487 -0
- package/dist/realtime.d.ts +2 -0
- package/dist/realtime.js +6 -0
- package/dist/routes.d.ts +5 -1
- package/dist/routes.js +59 -0
- package/package.json +1 -1
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"type": "object",
|
|
4
|
+
"properties": {
|
|
5
|
+
"seats": {
|
|
6
|
+
"description": "Replaces the plan's `seats`. `null` clears the override.",
|
|
7
|
+
"anyOf": [
|
|
8
|
+
{
|
|
9
|
+
"type": "integer",
|
|
10
|
+
"exclusiveMinimum": 0,
|
|
11
|
+
"maximum": 9007199254740991
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"type": "null"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
"robots": {
|
|
19
|
+
"description": "Replaces the plan's `robots`. `null` clears the override.",
|
|
20
|
+
"anyOf": [
|
|
21
|
+
{
|
|
22
|
+
"type": "integer",
|
|
23
|
+
"exclusiveMinimum": 0,
|
|
24
|
+
"maximum": 9007199254740991
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"type": "null"
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
"apps": {
|
|
32
|
+
"description": "Replaces the plan's `apps`. `null` clears the override.",
|
|
33
|
+
"anyOf": [
|
|
34
|
+
{
|
|
35
|
+
"type": "integer",
|
|
36
|
+
"exclusiveMinimum": 0,
|
|
37
|
+
"maximum": 9007199254740991
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"type": "null"
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
},
|
|
44
|
+
"app_users": {
|
|
45
|
+
"description": "Replaces the plan's `app_users`. `null` clears the override.",
|
|
46
|
+
"anyOf": [
|
|
47
|
+
{
|
|
48
|
+
"type": "integer",
|
|
49
|
+
"exclusiveMinimum": 0,
|
|
50
|
+
"maximum": 9007199254740991
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"type": "null"
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
"live_video_ms_per_month": {
|
|
58
|
+
"description": "Replaces the plan's `live_video_ms_per_month`. `null` clears the override.",
|
|
59
|
+
"anyOf": [
|
|
60
|
+
{
|
|
61
|
+
"type": "integer",
|
|
62
|
+
"exclusiveMinimum": 0,
|
|
63
|
+
"maximum": 9007199254740991
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"type": "null"
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
},
|
|
70
|
+
"asset_bytes_per_robot": {
|
|
71
|
+
"description": "Replaces the plan's `asset_bytes_per_robot`. `null` clears the override.",
|
|
72
|
+
"anyOf": [
|
|
73
|
+
{
|
|
74
|
+
"type": "integer",
|
|
75
|
+
"exclusiveMinimum": 0,
|
|
76
|
+
"maximum": 9007199254740991
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"type": "null"
|
|
80
|
+
}
|
|
81
|
+
]
|
|
82
|
+
},
|
|
83
|
+
"history_days": {
|
|
84
|
+
"description": "Replaces the plan's `history_days`. `null` clears the override.",
|
|
85
|
+
"anyOf": [
|
|
86
|
+
{
|
|
87
|
+
"type": "integer",
|
|
88
|
+
"exclusiveMinimum": 0,
|
|
89
|
+
"maximum": 9007199254740991
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"type": "null"
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
},
|
|
96
|
+
"audit_days": {
|
|
97
|
+
"description": "Replaces the plan's `audit_days`. `null` clears the override.",
|
|
98
|
+
"anyOf": [
|
|
99
|
+
{
|
|
100
|
+
"type": "integer",
|
|
101
|
+
"exclusiveMinimum": 0,
|
|
102
|
+
"maximum": 9007199254740991
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"type": "null"
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
"additionalProperties": false
|
|
111
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"type": "object",
|
|
4
|
+
"properties": {
|
|
5
|
+
"eur_month": {
|
|
6
|
+
"type": "integer",
|
|
7
|
+
"minimum": 0,
|
|
8
|
+
"maximum": 9007199254740991,
|
|
9
|
+
"description": "Per month in euro cents, excluding VAT."
|
|
10
|
+
},
|
|
11
|
+
"usd_month": {
|
|
12
|
+
"type": "integer",
|
|
13
|
+
"minimum": 0,
|
|
14
|
+
"maximum": 9007199254740991,
|
|
15
|
+
"description": "Per month in US dollar cents, excluding VAT: the euro price × 1.15, rounded up to a whole dollar."
|
|
16
|
+
},
|
|
17
|
+
"eur_year": {
|
|
18
|
+
"type": "integer",
|
|
19
|
+
"minimum": 0,
|
|
20
|
+
"maximum": 9007199254740991,
|
|
21
|
+
"description": "Per year in euro cents, excluding VAT: twelve months less 15 %."
|
|
22
|
+
},
|
|
23
|
+
"usd_year": {
|
|
24
|
+
"type": "integer",
|
|
25
|
+
"minimum": 0,
|
|
26
|
+
"maximum": 9007199254740991,
|
|
27
|
+
"description": "Per year in US dollar cents, excluding VAT: the yearly euro price × 1.15, rounded up to a whole dollar."
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"required": [
|
|
31
|
+
"eur_month",
|
|
32
|
+
"usd_month",
|
|
33
|
+
"eur_year",
|
|
34
|
+
"usd_year"
|
|
35
|
+
],
|
|
36
|
+
"additionalProperties": false
|
|
37
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"type": "object",
|
|
4
|
+
"properties": {
|
|
5
|
+
"feature": {
|
|
6
|
+
"type": "string",
|
|
7
|
+
"enum": [
|
|
8
|
+
"app_mcp",
|
|
9
|
+
"two_factor",
|
|
10
|
+
"require_two_factor",
|
|
11
|
+
"app_oidc",
|
|
12
|
+
"hosted_logo",
|
|
13
|
+
"audit_export",
|
|
14
|
+
"addons"
|
|
15
|
+
],
|
|
16
|
+
"description": "The feature the action needs."
|
|
17
|
+
},
|
|
18
|
+
"plan": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"enum": [
|
|
21
|
+
"basic",
|
|
22
|
+
"plus",
|
|
23
|
+
"pro",
|
|
24
|
+
"enterprise"
|
|
25
|
+
],
|
|
26
|
+
"description": "The org's current plan."
|
|
27
|
+
},
|
|
28
|
+
"required_plan": {
|
|
29
|
+
"type": "string",
|
|
30
|
+
"enum": [
|
|
31
|
+
"basic",
|
|
32
|
+
"plus",
|
|
33
|
+
"pro",
|
|
34
|
+
"enterprise"
|
|
35
|
+
],
|
|
36
|
+
"description": "The cheapest plan that has the feature."
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"required": [
|
|
40
|
+
"feature",
|
|
41
|
+
"plan",
|
|
42
|
+
"required_plan"
|
|
43
|
+
],
|
|
44
|
+
"additionalProperties": false
|
|
45
|
+
}
|
package/dist/audit.d.ts
CHANGED
|
@@ -27,6 +27,13 @@ import { z } from 'zod';
|
|
|
27
27
|
*
|
|
28
28
|
* `developer` is a Fleetless user. It kept its name through both redesigns
|
|
29
29
|
* because it was always right: the person who configures robots.
|
|
30
|
+
*
|
|
31
|
+
* `fleetless` (2026-10-02, fleetless/fleetless#103) records what the
|
|
32
|
+
* platform itself did, with no member behind it: the admin plan route, a
|
|
33
|
+
* plan change landing at its `effective_at`, a lock taking effect, and the
|
|
34
|
+
* beta-to-plan switch. Its `id` is the nil uuid and its `label` is always
|
|
35
|
+
* `Fleetless`, because there is no row to look up — the actor and the label
|
|
36
|
+
* are the same constant for every one of these events.
|
|
30
37
|
*/
|
|
31
38
|
export declare const auditActor: z.ZodObject<{
|
|
32
39
|
kind: z.ZodEnum<{
|
|
@@ -35,6 +42,7 @@ export declare const auditActor: z.ZodObject<{
|
|
|
35
42
|
bridge: "bridge";
|
|
36
43
|
end_user: "end_user";
|
|
37
44
|
app_user: "app_user";
|
|
45
|
+
fleetless: "fleetless";
|
|
38
46
|
}>;
|
|
39
47
|
id: z.ZodUUID;
|
|
40
48
|
label: z.ZodString;
|
|
@@ -52,6 +60,7 @@ export declare const auditEvent: z.ZodObject<{
|
|
|
52
60
|
bridge: "bridge";
|
|
53
61
|
end_user: "end_user";
|
|
54
62
|
app_user: "app_user";
|
|
63
|
+
fleetless: "fleetless";
|
|
55
64
|
}>;
|
|
56
65
|
id: z.ZodUUID;
|
|
57
66
|
label: z.ZodString;
|
|
@@ -90,6 +99,7 @@ export declare const auditListResponse: z.ZodObject<{
|
|
|
90
99
|
bridge: "bridge";
|
|
91
100
|
end_user: "end_user";
|
|
92
101
|
app_user: "app_user";
|
|
102
|
+
fleetless: "fleetless";
|
|
93
103
|
}>;
|
|
94
104
|
id: z.ZodUUID;
|
|
95
105
|
label: z.ZodString;
|
package/dist/audit.js
CHANGED
|
@@ -28,9 +28,16 @@ import { wireSeqCursor, wireTimestampMs } from './common.js';
|
|
|
28
28
|
*
|
|
29
29
|
* `developer` is a Fleetless user. It kept its name through both redesigns
|
|
30
30
|
* because it was always right: the person who configures robots.
|
|
31
|
+
*
|
|
32
|
+
* `fleetless` (2026-10-02, fleetless/fleetless#103) records what the
|
|
33
|
+
* platform itself did, with no member behind it: the admin plan route, a
|
|
34
|
+
* plan change landing at its `effective_at`, a lock taking effect, and the
|
|
35
|
+
* beta-to-plan switch. Its `id` is the nil uuid and its `label` is always
|
|
36
|
+
* `Fleetless`, because there is no row to look up — the actor and the label
|
|
37
|
+
* are the same constant for every one of these events.
|
|
31
38
|
*/
|
|
32
39
|
export const auditActor = z.object({
|
|
33
|
-
kind: z.enum(['developer', 'end_user', 'app_user', 'server_key', 'bridge']),
|
|
40
|
+
kind: z.enum(['developer', 'end_user', 'app_user', 'server_key', 'bridge', 'fleetless']),
|
|
34
41
|
id: z.uuid(),
|
|
35
42
|
label: z.string().min(1).max(200),
|
|
36
43
|
});
|
package/dist/errors.d.ts
CHANGED
|
@@ -72,10 +72,147 @@ export declare const invalidCodeDetails: z.ZodObject<{
|
|
|
72
72
|
attempts_left: z.ZodNumber;
|
|
73
73
|
}, z.core.$strip>;
|
|
74
74
|
export type InvalidCodeDetails = z.infer<typeof invalidCodeDetails>;
|
|
75
|
+
/**
|
|
76
|
+
* The `details` of a `409 plan_limit` refusal (2026-10-02, fleetless/fleetless#103).
|
|
77
|
+
* `history_days` and `audit_days` are excluded from `limit` — they size a
|
|
78
|
+
* retention window, not a quota an action can exceed, so nothing ever
|
|
79
|
+
* refuses against them. `max` is the effective ceiling the refusal was
|
|
80
|
+
* checked against: the plan's own number, or — for `asset_bytes_per_robot`
|
|
81
|
+
* — the org's whole pool, `robots × asset_bytes_per_robot`. `plan` is the
|
|
82
|
+
* plan that refused, which during a pending downgrade is the **target**
|
|
83
|
+
* plan, not the one still in effect. `lifted_by` is `nextPlanRaising` for
|
|
84
|
+
* `plan` and `limit`, paired with the add-on that raises the same limit when
|
|
85
|
+
* the org's plan has `planFeature.addons` — never both at once, since a plan
|
|
86
|
+
* that cannot buy add-ons has nothing in that field.
|
|
87
|
+
*/
|
|
88
|
+
export declare const planLimitDetails: z.ZodObject<{
|
|
89
|
+
limit: z.ZodEnum<{
|
|
90
|
+
apps: "apps";
|
|
91
|
+
robots: "robots";
|
|
92
|
+
seats: "seats";
|
|
93
|
+
app_users: "app_users";
|
|
94
|
+
live_video_ms_per_month: "live_video_ms_per_month";
|
|
95
|
+
asset_bytes_per_robot: "asset_bytes_per_robot";
|
|
96
|
+
}>;
|
|
97
|
+
used: z.ZodNumber;
|
|
98
|
+
max: z.ZodNumber;
|
|
99
|
+
plan: z.ZodEnum<{
|
|
100
|
+
basic: "basic";
|
|
101
|
+
plus: "plus";
|
|
102
|
+
pro: "pro";
|
|
103
|
+
enterprise: "enterprise";
|
|
104
|
+
}>;
|
|
105
|
+
lifted_by: z.ZodObject<{
|
|
106
|
+
plan: z.ZodNullable<z.ZodEnum<{
|
|
107
|
+
basic: "basic";
|
|
108
|
+
plus: "plus";
|
|
109
|
+
pro: "pro";
|
|
110
|
+
enterprise: "enterprise";
|
|
111
|
+
}>>;
|
|
112
|
+
addon: z.ZodNullable<z.ZodEnum<{
|
|
113
|
+
apps: "apps";
|
|
114
|
+
robots: "robots";
|
|
115
|
+
seats: "seats";
|
|
116
|
+
app_user_packs: "app_user_packs";
|
|
117
|
+
live_video_packs: "live_video_packs";
|
|
118
|
+
}>>;
|
|
119
|
+
}, z.core.$strip>;
|
|
120
|
+
}, z.core.$strip>;
|
|
121
|
+
export type PlanLimitDetails = z.infer<typeof planLimitDetails>;
|
|
122
|
+
/**
|
|
123
|
+
* `planLimitDetails` plus the three numbers `assetStoreRefusedDetails`
|
|
124
|
+
* already carries, for the one refusal that answers both at once: a robot
|
|
125
|
+
* asset sync refused because the **org's** pool (not a per-robot ceiling,
|
|
126
|
+
* which no longer exists) has no room left. `store_bytes` and `used_bytes`
|
|
127
|
+
* are the org's totals, the same pool `max` and `used` above describe; they
|
|
128
|
+
* ride twice because the bridge reads these three specific keys off any
|
|
129
|
+
* `409` and a consumer parsing only `assetStoreRefusedDetails` must keep
|
|
130
|
+
* working unchanged.
|
|
131
|
+
*
|
|
132
|
+
* **The two carried-over fields are re-described, not re-typed.** Plain
|
|
133
|
+
* `.extend(assetStoreRefusedDetails.shape)` would publish that schema's own
|
|
134
|
+
* per-robot wording (`'The robot\'s store, in bytes.'`) on a refusal that is
|
|
135
|
+
* never about one robot — so `store_bytes` and `used_bytes` get their own
|
|
136
|
+
* `.meta()` here, org-wide, while keeping the exact same underlying type
|
|
137
|
+
* (`.meta()` clones a schema and only replaces its registered metadata, so
|
|
138
|
+
* the bridge's own parser sees the same shape it always did). `size_bytes`
|
|
139
|
+
* is unchanged: the refused upload's size means the same thing in both
|
|
140
|
+
* contexts.
|
|
141
|
+
*/
|
|
142
|
+
export declare const assetPlanLimitDetails: z.ZodObject<{
|
|
143
|
+
limit: z.ZodEnum<{
|
|
144
|
+
apps: "apps";
|
|
145
|
+
robots: "robots";
|
|
146
|
+
seats: "seats";
|
|
147
|
+
app_users: "app_users";
|
|
148
|
+
live_video_ms_per_month: "live_video_ms_per_month";
|
|
149
|
+
asset_bytes_per_robot: "asset_bytes_per_robot";
|
|
150
|
+
}>;
|
|
151
|
+
used: z.ZodNumber;
|
|
152
|
+
max: z.ZodNumber;
|
|
153
|
+
plan: z.ZodEnum<{
|
|
154
|
+
basic: "basic";
|
|
155
|
+
plus: "plus";
|
|
156
|
+
pro: "pro";
|
|
157
|
+
enterprise: "enterprise";
|
|
158
|
+
}>;
|
|
159
|
+
lifted_by: z.ZodObject<{
|
|
160
|
+
plan: z.ZodNullable<z.ZodEnum<{
|
|
161
|
+
basic: "basic";
|
|
162
|
+
plus: "plus";
|
|
163
|
+
pro: "pro";
|
|
164
|
+
enterprise: "enterprise";
|
|
165
|
+
}>>;
|
|
166
|
+
addon: z.ZodNullable<z.ZodEnum<{
|
|
167
|
+
apps: "apps";
|
|
168
|
+
robots: "robots";
|
|
169
|
+
seats: "seats";
|
|
170
|
+
app_user_packs: "app_user_packs";
|
|
171
|
+
live_video_packs: "live_video_packs";
|
|
172
|
+
}>>;
|
|
173
|
+
}, z.core.$strip>;
|
|
174
|
+
store_bytes: z.ZodNumber;
|
|
175
|
+
used_bytes: z.ZodNumber;
|
|
176
|
+
size_bytes: z.ZodNumber;
|
|
177
|
+
}, z.core.$strip>;
|
|
178
|
+
export type AssetPlanLimitDetails = z.infer<typeof assetPlanLimitDetails>;
|
|
179
|
+
/** The `details` of a `403 plan_required` refusal: the feature, the org's own plan, and the cheapest plan that has it (`requiredPlanFor`). */
|
|
180
|
+
export declare const planRequiredDetails: z.ZodObject<{
|
|
181
|
+
feature: z.ZodEnum<{
|
|
182
|
+
require_two_factor: "require_two_factor";
|
|
183
|
+
two_factor: "two_factor";
|
|
184
|
+
app_mcp: "app_mcp";
|
|
185
|
+
app_oidc: "app_oidc";
|
|
186
|
+
hosted_logo: "hosted_logo";
|
|
187
|
+
audit_export: "audit_export";
|
|
188
|
+
addons: "addons";
|
|
189
|
+
}>;
|
|
190
|
+
plan: z.ZodEnum<{
|
|
191
|
+
basic: "basic";
|
|
192
|
+
plus: "plus";
|
|
193
|
+
pro: "pro";
|
|
194
|
+
enterprise: "enterprise";
|
|
195
|
+
}>;
|
|
196
|
+
required_plan: z.ZodEnum<{
|
|
197
|
+
basic: "basic";
|
|
198
|
+
plus: "plus";
|
|
199
|
+
pro: "pro";
|
|
200
|
+
enterprise: "enterprise";
|
|
201
|
+
}>;
|
|
202
|
+
}, z.core.$strip>;
|
|
203
|
+
export type PlanRequiredDetails = z.infer<typeof planRequiredDetails>;
|
|
204
|
+
/** The `details` of a `403 org_locked` refusal: why the org is locked, matching `orgLock.reason`. */
|
|
205
|
+
export declare const orgLockedDetails: z.ZodObject<{
|
|
206
|
+
reason: z.ZodEnum<{
|
|
207
|
+
migration: "migration";
|
|
208
|
+
payment: "payment";
|
|
209
|
+
}>;
|
|
210
|
+
}, z.core.$strip>;
|
|
211
|
+
export type OrgLockedDetails = z.infer<typeof orgLockedDetails>;
|
|
75
212
|
/**
|
|
76
213
|
* The codes in use today. The wire deliberately allows any string — this
|
|
77
214
|
* list is the shared vocabulary, not a closed set, so a new refusal never
|
|
78
215
|
* needs a contracts release before it can be reported honestly.
|
|
79
216
|
*/
|
|
80
|
-
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"];
|
|
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"];
|
|
81
218
|
export type ErrorCode = (typeof ERROR_CODES)[number];
|
package/dist/errors.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: Apache-2.0
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
+
import { assetStoreRefusedDetails } from './assets.js';
|
|
4
|
+
import { addonKey, planFeature, planId, planLimitKey } from './plans.js';
|
|
3
5
|
import { bridgeCancelResultEntry } from './protocol.js';
|
|
4
6
|
/**
|
|
5
7
|
* The one error shape of the REST and realtime APIs: a stable
|
|
@@ -63,6 +65,76 @@ export const invalidCodeDetails = z.object({
|
|
|
63
65
|
description: 'How many more wrong codes this code or challenge takes before it is spent. `0` means the next attempt answers `410 token_spent`.',
|
|
64
66
|
}),
|
|
65
67
|
});
|
|
68
|
+
/**
|
|
69
|
+
* The `details` of a `409 plan_limit` refusal (2026-10-02, fleetless/fleetless#103).
|
|
70
|
+
* `history_days` and `audit_days` are excluded from `limit` — they size a
|
|
71
|
+
* retention window, not a quota an action can exceed, so nothing ever
|
|
72
|
+
* refuses against them. `max` is the effective ceiling the refusal was
|
|
73
|
+
* checked against: the plan's own number, or — for `asset_bytes_per_robot`
|
|
74
|
+
* — the org's whole pool, `robots × asset_bytes_per_robot`. `plan` is the
|
|
75
|
+
* plan that refused, which during a pending downgrade is the **target**
|
|
76
|
+
* plan, not the one still in effect. `lifted_by` is `nextPlanRaising` for
|
|
77
|
+
* `plan` and `limit`, paired with the add-on that raises the same limit when
|
|
78
|
+
* the org's plan has `planFeature.addons` — never both at once, since a plan
|
|
79
|
+
* that cannot buy add-ons has nothing in that field.
|
|
80
|
+
*/
|
|
81
|
+
export const planLimitDetails = z.object({
|
|
82
|
+
limit: planLimitKey.exclude(['history_days', 'audit_days']).meta({ description: 'The limit the action would exceed.' }),
|
|
83
|
+
used: z.number().int().nonnegative().meta({ description: 'How much of the limit the org uses now.' }),
|
|
84
|
+
max: z.number().int().nonnegative().meta({
|
|
85
|
+
description: 'The limit. For `asset_bytes_per_robot`, the org\'s whole pool: robots × the plan\'s bytes per robot.',
|
|
86
|
+
}),
|
|
87
|
+
plan: planId.meta({ description: 'The plan whose limit refused: the target plan while a move to a lower plan is pending.' }),
|
|
88
|
+
lifted_by: z
|
|
89
|
+
.object({
|
|
90
|
+
plan: planId.nullable().meta({ description: 'The cheapest higher plan that raises this limit, or `null` when none does.' }),
|
|
91
|
+
addon: addonKey.nullable().meta({
|
|
92
|
+
description: 'The add-on that raises this limit, when the org\'s plan can buy add-ons; otherwise `null`.',
|
|
93
|
+
}),
|
|
94
|
+
})
|
|
95
|
+
.meta({ description: 'What would lift the limit.' }),
|
|
96
|
+
});
|
|
97
|
+
/**
|
|
98
|
+
* `planLimitDetails` plus the three numbers `assetStoreRefusedDetails`
|
|
99
|
+
* already carries, for the one refusal that answers both at once: a robot
|
|
100
|
+
* asset sync refused because the **org's** pool (not a per-robot ceiling,
|
|
101
|
+
* which no longer exists) has no room left. `store_bytes` and `used_bytes`
|
|
102
|
+
* are the org's totals, the same pool `max` and `used` above describe; they
|
|
103
|
+
* ride twice because the bridge reads these three specific keys off any
|
|
104
|
+
* `409` and a consumer parsing only `assetStoreRefusedDetails` must keep
|
|
105
|
+
* working unchanged.
|
|
106
|
+
*
|
|
107
|
+
* **The two carried-over fields are re-described, not re-typed.** Plain
|
|
108
|
+
* `.extend(assetStoreRefusedDetails.shape)` would publish that schema's own
|
|
109
|
+
* per-robot wording (`'The robot\'s store, in bytes.'`) on a refusal that is
|
|
110
|
+
* never about one robot — so `store_bytes` and `used_bytes` get their own
|
|
111
|
+
* `.meta()` here, org-wide, while keeping the exact same underlying type
|
|
112
|
+
* (`.meta()` clones a schema and only replaces its registered metadata, so
|
|
113
|
+
* the bridge's own parser sees the same shape it always did). `size_bytes`
|
|
114
|
+
* is unchanged: the refused upload's size means the same thing in both
|
|
115
|
+
* contexts.
|
|
116
|
+
*/
|
|
117
|
+
export const assetPlanLimitDetails = planLimitDetails.extend({
|
|
118
|
+
...assetStoreRefusedDetails.shape,
|
|
119
|
+
store_bytes: assetStoreRefusedDetails.shape.store_bytes.meta({
|
|
120
|
+
description: 'The org\'s asset pool, in bytes: `robots × asset_bytes_per_robot`.',
|
|
121
|
+
}),
|
|
122
|
+
used_bytes: assetStoreRefusedDetails.shape.used_bytes.meta({
|
|
123
|
+
description: 'Bytes the org\'s assets occupy, across every robot, before this upload.',
|
|
124
|
+
}),
|
|
125
|
+
});
|
|
126
|
+
/** The `details` of a `403 plan_required` refusal: the feature, the org's own plan, and the cheapest plan that has it (`requiredPlanFor`). */
|
|
127
|
+
export const planRequiredDetails = z.object({
|
|
128
|
+
feature: planFeature.meta({ description: 'The feature the action needs.' }),
|
|
129
|
+
plan: planId.meta({ description: 'The org\'s current plan.' }),
|
|
130
|
+
required_plan: planId.meta({ description: 'The cheapest plan that has the feature.' }),
|
|
131
|
+
});
|
|
132
|
+
/** The `details` of a `403 org_locked` refusal: why the org is locked, matching `orgLock.reason`. */
|
|
133
|
+
export const orgLockedDetails = z.object({
|
|
134
|
+
reason: z.enum(['payment', 'migration']).meta({
|
|
135
|
+
description: '`payment`: a payment is missing. `migration`: the org did not choose what stays when the beta ended.',
|
|
136
|
+
}),
|
|
137
|
+
});
|
|
66
138
|
/**
|
|
67
139
|
* The codes in use today. The wire deliberately allows any string — this
|
|
68
140
|
* list is the shared vocabulary, not a closed set, so a new refusal never
|
|
@@ -891,4 +963,36 @@ export const ERROR_CODES = [
|
|
|
891
963
|
* is no enumeration oracle.
|
|
892
964
|
*/
|
|
893
965
|
'method_not_allowed',
|
|
966
|
+
// 2026-10-02 — plans (#103).
|
|
967
|
+
/**
|
|
968
|
+
* `409`: the action would push the org past one of its plan's limits —
|
|
969
|
+
* a seat, a robot, an app, an app user, this month's live video, or the
|
|
970
|
+
* org's asset storage pool (its robots × the plan's bytes per robot). Answered **before anything is written**, so a
|
|
971
|
+
* refused create or invite never leaves a half-made row behind. `details`
|
|
972
|
+
* is `planLimitDetails` (or `assetPlanLimitDetails` for an asset-storage
|
|
973
|
+
* refusal): which limit, how much is used, the ceiling, the plan that
|
|
974
|
+
* refused, and what would lift it — a higher plan, an add-on, or neither.
|
|
975
|
+
* The existing `quota_exceeded` protection ceiling is still checked, and
|
|
976
|
+
* only after this one: it exists to stop runaway consumption, not to tell
|
|
977
|
+
* a developer what their plan allows.
|
|
978
|
+
*/
|
|
979
|
+
'plan_limit',
|
|
980
|
+
/**
|
|
981
|
+
* `403`: the feature the caller reached for is not on the org's plan — an
|
|
982
|
+
* app's MCP endpoint, two-factor for a developer, a two-factor requirement
|
|
983
|
+
* for the org, an app's OIDC federation, a hosted logo, the audit export,
|
|
984
|
+
* or add-ons themselves. `details` is `planRequiredDetails`:
|
|
985
|
+
* the feature, the org's own plan, and the cheapest plan that has it, so
|
|
986
|
+
* the console can offer the upgrade in the same breath as the refusal.
|
|
987
|
+
*/
|
|
988
|
+
'plan_required',
|
|
989
|
+
/**
|
|
990
|
+
* `403`: the org is locked. Every sign-in and every token refresh is
|
|
991
|
+
* refused, except an owner's, so an owner can still sign in and settle
|
|
992
|
+
* it; the sign-in pages render this refusal. A bridge's `hello` is
|
|
993
|
+
* refused with this code as well. Nothing is deleted while an org is
|
|
994
|
+
* locked. `details` is `orgLockedDetails`, naming why — a missing
|
|
995
|
+
* payment, or the platform's own move off the beta.
|
|
996
|
+
*/
|
|
997
|
+
'org_locked',
|
|
894
998
|
];
|
package/dist/index.d.ts
CHANGED
|
@@ -47,9 +47,13 @@ export { auditActor, auditEvent, auditQuery, auditListResponse, AUDIT_CSV_COLUMN
|
|
|
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 } from './errors.js';
|
|
51
|
-
export type { ApiError, ParameterViolation, ParameterInvalidDetails, CancelRejectedDetails, InvalidCodeDetails, ErrorCode } from './errors.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';
|
|
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';
|
|
55
55
|
export type { RouteEntry, RouteParam, RouteAudience, RouteAuth, RouteSection, RouteMethod, RouteTransport, } from './routes.js';
|
|
56
|
+
export { planId, PLAN_ORDER, planLimitKey, planLimits, planFeature, planFeatures, planPrices, planSupport, planCatalogueEntry, addonKey, addonCatalogueEntry, usdCentsFromEurCents, yearlyEurCents, pricesFromEurMonth, PLANS, ADDONS, requiredPlanFor, nextPlanRaising, } from './plans.js';
|
|
57
|
+
export type { PlanId, PlanLimitKey, PlanLimits, PlanFeature, PlanFeatures, PlanPrices, PlanSupport, PlanCatalogueEntry, AddonKey, AddonCatalogueEntry, } from './plans.js';
|
|
58
|
+
export { planCurrency, orgAddons, orgPlanUsage, planChangeKeep, planChangeReason, pendingPlanChange, orgLock, orgPlan, planChangeRequest, planOverrides, adminPlanChangeRequest, } from './plans.js';
|
|
59
|
+
export type { PlanCurrency, OrgAddons, OrgPlanUsage, PlanChangeKeep, PlanChangeReason, PendingPlanChange, OrgLock, OrgPlan, PlanChangeRequest, PlanOverrides, AdminPlanChangeRequest, } from './plans.js';
|
package/dist/index.js
CHANGED
|
@@ -52,6 +52,16 @@ export { APP_USER_DISPLAY_NAME_MAX, APP_URL_PLACEHOLDERS, MAIL_TEMPLATE_VARIABLE
|
|
|
52
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';
|
|
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
|
-
export { apiError, parameterViolation, parameterInvalidDetails, cancelRejectedDetails, invalidCodeDetails, ERROR_CODES
|
|
55
|
+
export { apiError, parameterViolation, parameterInvalidDetails, cancelRejectedDetails, invalidCodeDetails, ERROR_CODES,
|
|
56
|
+
// 2026-10-02 — plans (#103). The plan errors (I-3).
|
|
57
|
+
planLimitDetails, assetPlanLimitDetails, planRequiredDetails, orgLockedDetails, } from './errors.js';
|
|
56
58
|
export { oauthErrorCode, oauthError, oauthRedirectResponse, oauthCodeTokenRequest, oauthRefreshTokenRequest, oauthTokenRequest, oauthTokenResponse, redirectUri, codeChallengeMethod, oauthAuthorizeQuery, dynamicClientRegistrationRequest, MCP_DCR_MAX_REDIRECT_URIS, dynamicClientRegistrationResponse, authorizationServerMetadata, protectedResourceMetadata, } from './oauth.js';
|
|
57
59
|
export { ROUTES, ROUTE_SECTIONS, IN_HANDLER_ROUTES, developerSignInRoutes } from './routes.js';
|
|
60
|
+
// 2026-10-02 — plans (#103). The catalogue (I-1) only: `PLANS` and `ADDONS`
|
|
61
|
+
// are deliberately not constants exports (`constants.json` is vendored by
|
|
62
|
+
// the bridge and must stay unchanged) but are exported values of this
|
|
63
|
+
// barrel like any other schema module.
|
|
64
|
+
export { planId, PLAN_ORDER, planLimitKey, planLimits, planFeature, planFeatures, planPrices, planSupport, planCatalogueEntry, addonKey, addonCatalogueEntry, usdCentsFromEurCents, yearlyEurCents, pricesFromEurMonth, PLANS, ADDONS, requiredPlanFor, nextPlanRaising, } from './plans.js';
|
|
65
|
+
// 2026-10-02 — plans (#103). The organization's plan, plan changes and the
|
|
66
|
+
// admin request (I-2).
|
|
67
|
+
export { planCurrency, orgAddons, orgPlanUsage, planChangeKeep, planChangeReason, pendingPlanChange, orgLock, orgPlan, planChangeRequest, planOverrides, adminPlanChangeRequest, } from './plans.js';
|