@fleetless/contracts 6.0.0-next.3 → 6.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 +42 -0
- package/artifacts/openapi.json +636 -1
- package/artifacts/routes.json +101 -0
- package/artifacts/schema/addon-catalogue-entry.schema.json +75 -0
- package/artifacts/schema/addon-key.schema.json +11 -0
- package/artifacts/schema/admin-plan-change-request.schema.json +171 -0
- package/artifacts/schema/asset-plan-limit-details.schema.json +108 -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 +39 -0
- package/artifacts/schema/org-lock.schema.json +23 -0
- package/artifacts/schema/org-locked-details.schema.json +17 -0
- package/artifacts/schema/org-plan-usage.schema.json +45 -0
- package/artifacts/schema/org-plan.schema.json +450 -0
- package/artifacts/schema/pending-plan-change.schema.json +112 -0
- package/artifacts/schema/plan-catalogue-entry.schema.json +226 -0
- package/artifacts/schema/plan-change-keep.schema.json +45 -0
- package/artifacts/schema/plan-change-reason.schema.json +10 -0
- package/artifacts/schema/plan-change-request.schema.json +71 -0
- package/artifacts/schema/plan-currency.schema.json +8 -0
- package/artifacts/schema/plan-features.schema.json +37 -0
- package/artifacts/schema/plan-id.schema.json +10 -0
- package/artifacts/schema/plan-limit-details.schema.json +87 -0
- package/artifacts/schema/plan-limits.schema.json +113 -0
- package/artifacts/schema/plan-overrides.schema.json +103 -0
- package/artifacts/schema/plan-prices.schema.json +33 -0
- package/artifacts/schema/plan-required-details.schema.json +42 -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 +94 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.js +11 -1
- package/dist/plans.d.ts +525 -0
- package/dist/plans.js +442 -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 +58 -0
- package/package.json +1 -1
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"type": "object",
|
|
4
|
+
"properties": {
|
|
5
|
+
"seats": {
|
|
6
|
+
"anyOf": [
|
|
7
|
+
{
|
|
8
|
+
"type": "integer",
|
|
9
|
+
"exclusiveMinimum": 0,
|
|
10
|
+
"maximum": 9007199254740991
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"type": "null"
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
"robots": {
|
|
18
|
+
"anyOf": [
|
|
19
|
+
{
|
|
20
|
+
"type": "integer",
|
|
21
|
+
"exclusiveMinimum": 0,
|
|
22
|
+
"maximum": 9007199254740991
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"type": "null"
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"apps": {
|
|
30
|
+
"anyOf": [
|
|
31
|
+
{
|
|
32
|
+
"type": "integer",
|
|
33
|
+
"exclusiveMinimum": 0,
|
|
34
|
+
"maximum": 9007199254740991
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"type": "null"
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
"app_users": {
|
|
42
|
+
"anyOf": [
|
|
43
|
+
{
|
|
44
|
+
"type": "integer",
|
|
45
|
+
"exclusiveMinimum": 0,
|
|
46
|
+
"maximum": 9007199254740991
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"type": "null"
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
"live_video_ms_per_month": {
|
|
54
|
+
"anyOf": [
|
|
55
|
+
{
|
|
56
|
+
"type": "integer",
|
|
57
|
+
"exclusiveMinimum": 0,
|
|
58
|
+
"maximum": 9007199254740991
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"type": "null"
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
"asset_bytes_per_robot": {
|
|
66
|
+
"anyOf": [
|
|
67
|
+
{
|
|
68
|
+
"type": "integer",
|
|
69
|
+
"exclusiveMinimum": 0,
|
|
70
|
+
"maximum": 9007199254740991
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"type": "null"
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
"history_days": {
|
|
78
|
+
"anyOf": [
|
|
79
|
+
{
|
|
80
|
+
"type": "integer",
|
|
81
|
+
"exclusiveMinimum": 0,
|
|
82
|
+
"maximum": 9007199254740991
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"type": "null"
|
|
86
|
+
}
|
|
87
|
+
]
|
|
88
|
+
},
|
|
89
|
+
"audit_days": {
|
|
90
|
+
"anyOf": [
|
|
91
|
+
{
|
|
92
|
+
"type": "integer",
|
|
93
|
+
"exclusiveMinimum": 0,
|
|
94
|
+
"maximum": 9007199254740991
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"type": "null"
|
|
98
|
+
}
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
"additionalProperties": false
|
|
103
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
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
|
+
},
|
|
10
|
+
"usd_month": {
|
|
11
|
+
"type": "integer",
|
|
12
|
+
"minimum": 0,
|
|
13
|
+
"maximum": 9007199254740991
|
|
14
|
+
},
|
|
15
|
+
"eur_year": {
|
|
16
|
+
"type": "integer",
|
|
17
|
+
"minimum": 0,
|
|
18
|
+
"maximum": 9007199254740991
|
|
19
|
+
},
|
|
20
|
+
"usd_year": {
|
|
21
|
+
"type": "integer",
|
|
22
|
+
"minimum": 0,
|
|
23
|
+
"maximum": 9007199254740991
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"required": [
|
|
27
|
+
"eur_month",
|
|
28
|
+
"usd_month",
|
|
29
|
+
"eur_year",
|
|
30
|
+
"usd_year"
|
|
31
|
+
],
|
|
32
|
+
"additionalProperties": false
|
|
33
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
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
|
+
},
|
|
17
|
+
"plan": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"enum": [
|
|
20
|
+
"basic",
|
|
21
|
+
"plus",
|
|
22
|
+
"pro",
|
|
23
|
+
"enterprise"
|
|
24
|
+
]
|
|
25
|
+
},
|
|
26
|
+
"required_plan": {
|
|
27
|
+
"type": "string",
|
|
28
|
+
"enum": [
|
|
29
|
+
"basic",
|
|
30
|
+
"plus",
|
|
31
|
+
"pro",
|
|
32
|
+
"enterprise"
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"required": [
|
|
37
|
+
"feature",
|
|
38
|
+
"plan",
|
|
39
|
+
"required_plan"
|
|
40
|
+
],
|
|
41
|
+
"additionalProperties": false
|
|
42
|
+
}
|
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,68 @@ 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']),
|
|
83
|
+
used: z.number().int().nonnegative(),
|
|
84
|
+
max: z.number().int().nonnegative(),
|
|
85
|
+
plan: planId,
|
|
86
|
+
lifted_by: z.object({
|
|
87
|
+
plan: planId.nullable(),
|
|
88
|
+
addon: addonKey.nullable(),
|
|
89
|
+
}),
|
|
90
|
+
});
|
|
91
|
+
/**
|
|
92
|
+
* `planLimitDetails` plus the three numbers `assetStoreRefusedDetails`
|
|
93
|
+
* already carries, for the one refusal that answers both at once: a robot
|
|
94
|
+
* asset sync refused because the **org's** pool (not a per-robot ceiling,
|
|
95
|
+
* which no longer exists) has no room left. `store_bytes` and `used_bytes`
|
|
96
|
+
* are the org's totals, the same pool `max` and `used` above describe; they
|
|
97
|
+
* ride twice because the bridge reads these three specific keys off any
|
|
98
|
+
* `409` and a consumer parsing only `assetStoreRefusedDetails` must keep
|
|
99
|
+
* working unchanged.
|
|
100
|
+
*
|
|
101
|
+
* **The two carried-over fields are re-described, not re-typed.** Plain
|
|
102
|
+
* `.extend(assetStoreRefusedDetails.shape)` would publish that schema's own
|
|
103
|
+
* per-robot wording (`'The robot\'s store, in bytes.'`) on a refusal that is
|
|
104
|
+
* never about one robot — so `store_bytes` and `used_bytes` get their own
|
|
105
|
+
* `.meta()` here, org-wide, while keeping the exact same underlying type
|
|
106
|
+
* (`.meta()` clones a schema and only replaces its registered metadata, so
|
|
107
|
+
* the bridge's own parser sees the same shape it always did). `size_bytes`
|
|
108
|
+
* is unchanged: the refused upload's size means the same thing in both
|
|
109
|
+
* contexts.
|
|
110
|
+
*/
|
|
111
|
+
export const assetPlanLimitDetails = planLimitDetails.extend({
|
|
112
|
+
...assetStoreRefusedDetails.shape,
|
|
113
|
+
store_bytes: assetStoreRefusedDetails.shape.store_bytes.meta({
|
|
114
|
+
description: 'The org\'s asset pool, in bytes: `robots × asset_bytes_per_robot`.',
|
|
115
|
+
}),
|
|
116
|
+
used_bytes: assetStoreRefusedDetails.shape.used_bytes.meta({
|
|
117
|
+
description: 'Bytes the org\'s assets occupy, across every robot, before this upload.',
|
|
118
|
+
}),
|
|
119
|
+
});
|
|
120
|
+
/** The `details` of a `403 plan_required` refusal: the feature, the org's own plan, and the cheapest plan that has it (`requiredPlanFor`). */
|
|
121
|
+
export const planRequiredDetails = z.object({
|
|
122
|
+
feature: planFeature,
|
|
123
|
+
plan: planId,
|
|
124
|
+
required_plan: planId,
|
|
125
|
+
});
|
|
126
|
+
/** The `details` of a `403 org_locked` refusal: why the org is locked, matching `orgLock.reason`. */
|
|
127
|
+
export const orgLockedDetails = z.object({
|
|
128
|
+
reason: z.enum(['payment', 'migration']),
|
|
129
|
+
});
|
|
66
130
|
/**
|
|
67
131
|
* The codes in use today. The wire deliberately allows any string — this
|
|
68
132
|
* list is the shared vocabulary, not a closed set, so a new refusal never
|
|
@@ -891,4 +955,34 @@ export const ERROR_CODES = [
|
|
|
891
955
|
* is no enumeration oracle.
|
|
892
956
|
*/
|
|
893
957
|
'method_not_allowed',
|
|
958
|
+
// 2026-10-02 — plans (#103).
|
|
959
|
+
/**
|
|
960
|
+
* `409`: the action would push the org past one of its plan's limits —
|
|
961
|
+
* a seat, a robot, an app, an app user, this month's live video, or a
|
|
962
|
+
* robot's asset storage. Answered **before anything is written**, so a
|
|
963
|
+
* refused create or invite never leaves a half-made row behind. `details`
|
|
964
|
+
* is `planLimitDetails` (or `assetPlanLimitDetails` for an asset-storage
|
|
965
|
+
* refusal): which limit, how much is used, the ceiling, the plan that
|
|
966
|
+
* refused, and what would lift it — a higher plan, an add-on, or neither.
|
|
967
|
+
* The existing `quota_exceeded` protection ceiling is still checked, and
|
|
968
|
+
* only after this one: it exists to stop runaway consumption, not to tell
|
|
969
|
+
* a developer what their plan allows.
|
|
970
|
+
*/
|
|
971
|
+
'plan_limit',
|
|
972
|
+
/**
|
|
973
|
+
* `403`: the feature the caller reached for is not on the org's plan — a
|
|
974
|
+
* two-factor requirement, an app's OIDC federation, a hosted logo, the
|
|
975
|
+
* audit export, or add-ons themselves. `details` is `planRequiredDetails`:
|
|
976
|
+
* the feature, the org's own plan, and the cheapest plan that has it, so
|
|
977
|
+
* the console can offer the upgrade in the same breath as the refusal.
|
|
978
|
+
*/
|
|
979
|
+
'plan_required',
|
|
980
|
+
/**
|
|
981
|
+
* `403`: the org is locked and may only move to Basic. `details` is
|
|
982
|
+
* `orgLockedDetails`, naming why — a failed payment, or the platform's own
|
|
983
|
+
* move off the beta. Distinct from `plan_required`, which is about a
|
|
984
|
+
* feature the plan never had; this is about an org that is not allowed to
|
|
985
|
+
* spend on any plan right now.
|
|
986
|
+
*/
|
|
987
|
+
'org_locked',
|
|
894
988
|
];
|
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';
|