@fleetless/contracts 1.0.2 → 1.0.4
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 +48 -0
- package/artifacts/openapi.json +11 -11
- package/artifacts/routes.json +12 -12
- package/artifacts/schema/create-app-oidc-provider-request.schema.json +1 -1
- package/dist/alerts.d.ts +4 -4
- package/dist/alerts.js +5 -5
- package/dist/app-users.d.ts +11 -13
- package/dist/app-users.js +12 -14
- package/dist/apps.js +2 -1
- package/dist/audit.d.ts +3 -4
- package/dist/audit.js +3 -4
- package/dist/client-auth.d.ts +5 -5
- package/dist/client-auth.js +5 -5
- package/dist/common.d.ts +2 -2
- package/dist/common.js +2 -2
- package/dist/config-issues.d.ts +19 -22
- package/dist/config-issues.js +10 -11
- package/dist/config.d.ts +6 -7
- package/dist/config.js +64 -77
- package/dist/errors.js +22 -29
- package/dist/identity.d.ts +6 -6
- package/dist/identity.js +6 -6
- package/dist/index.js +2 -2
- package/dist/jobs.d.ts +4 -4
- package/dist/jobs.js +4 -4
- package/dist/mcp.d.ts +3 -3
- package/dist/mcp.js +2 -2
- package/dist/oauth.d.ts +8 -9
- package/dist/oauth.js +20 -24
- package/dist/realtime.js +1 -1
- package/dist/rest.d.ts +1 -1
- package/dist/rest.js +4 -4
- package/dist/routes.js +38 -40
- package/package.json +1 -1
package/dist/config.js
CHANGED
|
@@ -48,22 +48,20 @@ import { alertSeverity } from './alerts.js';
|
|
|
48
48
|
* index. Splitting them would put one rule here and its three siblings there
|
|
49
49
|
* — the shape this file has twice had to undo.
|
|
50
50
|
*
|
|
51
|
-
* **Every refusal that answers one of the
|
|
51
|
+
* **Every refusal that answers one of the format's validation codes carries
|
|
52
52
|
* `params: { code }`** with that code, which zod passes through `safeParse`
|
|
53
53
|
* untouched. The cloud maps an issue to a code and its repair by reading that
|
|
54
54
|
* field, never by matching the message prose — a join nobody notices
|
|
55
55
|
* breaking.
|
|
56
56
|
*
|
|
57
|
-
* Read
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
* `
|
|
65
|
-
* parameter, `y_min`/`y_max` on a chart: `invalid_range` was deleted with
|
|
66
|
-
* `expected_range`, and no code replaced it.
|
|
57
|
+
* Read that sentence narrowly. Plenty of refusals in this file carry no
|
|
58
|
+
* `params.code`, and correctly: the section caps (`parameterMap`'s fifty,
|
|
59
|
+
* `messageMap`'s two hundred), the camera device-path rules, and every refusal
|
|
60
|
+
* zod raises on its own — `unrecognized_keys` behind `unknown_key`, `too_big`
|
|
61
|
+
* behind `invalid_rate`. Those are not validation codes wearing a different
|
|
62
|
+
* hat; a consumer reaches them through zod's own issue codes. The one named
|
|
63
|
+
* code with no `params` is a reversed pair of bounds — `min_value`/`max_value`
|
|
64
|
+
* on a parameter, `y_min`/`y_max` on a chart — for which no code exists.
|
|
67
65
|
*
|
|
68
66
|
* `robotConfigDoc` carries all six sections — messages, datapoints, actions,
|
|
69
67
|
* services, publishers and cameras — plus the alerts, the chart bounds and the
|
|
@@ -91,16 +89,12 @@ import { alertSeverity } from './alerts.js';
|
|
|
91
89
|
* which is a published artifact other tools validate against and which a person
|
|
92
90
|
* reads. One constant with two readers, never two strings that happen to agree
|
|
93
91
|
* — `config-zod-messages.test.ts` asserts the two readings are the same string
|
|
94
|
-
* at
|
|
95
|
-
*
|
|
96
|
-
* a live rule drifts word for word, forever and invisibly.
|
|
92
|
+
* at every pattern position the document has. An unwatched second spelling of a
|
|
93
|
+
* live rule drifts word for word, forever and invisibly.
|
|
97
94
|
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
* D3 then turns that validation off, and from there the message a developer
|
|
102
|
-
* sees comes from this schema's own parser and from the cloud — the same
|
|
103
|
-
* sentence, which is the point of there being one.
|
|
95
|
+
* An editor that validates against the published JSON Schema shows
|
|
96
|
+
* `patternErrorMessage`; one that does not shows whatever the server's parser
|
|
97
|
+
* says. They are the same sentence, which is the point of there being one.
|
|
104
98
|
*
|
|
105
99
|
* The tense matters because the two states look identical from inside this
|
|
106
100
|
* file. Whoever reads it after wave 3 should find a claim that was true when
|
|
@@ -136,11 +130,10 @@ const mapKey = slug.meta({ patternErrorMessage: SLUG_RULE });
|
|
|
136
130
|
/**
|
|
137
131
|
* One field, carrying the sentence it says when it is absent.
|
|
138
132
|
*
|
|
139
|
-
* **Three shapes of "this key is not here", and
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
* still answering in zod's words:
|
|
133
|
+
* **Three shapes of "this key is not here", and a helper has to cover all
|
|
134
|
+
* three.** A walk over every required key of a fully populated document —
|
|
135
|
+
* `config-zod-messages.test.ts` — enumerates every required-key position in the
|
|
136
|
+
* format and asserts none of them still answers in zod's words:
|
|
144
137
|
*
|
|
145
138
|
* - `invalid_type`, the ordinary case: a string, a number, an object.
|
|
146
139
|
* - `invalid_value` from a `z.literal` or a `z.enum`. A missing `fleetless:`
|
|
@@ -160,10 +153,10 @@ const mapKey = slug.meta({ patternErrorMessage: SLUG_RULE });
|
|
|
160
153
|
* **`z.unknown()` needs a wrapper before it can be given a sentence at all.**
|
|
161
154
|
* It accepts `undefined`, so zod marks the key required and raises its own
|
|
162
155
|
* `expected nonoptional, received undefined` — an issue it attributes to
|
|
163
|
-
* neither the field nor the object, so no error map of ours is consulted
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
156
|
+
* neither the field nor the object, so no error map of ours is consulted.
|
|
157
|
+
* `z.nonoptional` puts a schema there that can carry one. The JSON Schema and
|
|
158
|
+
* the inferred type are identical either way, and a field that is genuinely
|
|
159
|
+
* optional is `.optional()` and is
|
|
167
160
|
* skipped here — but it is **not** behaviourally free, and that is the one
|
|
168
161
|
* place this task changed what the format accepts: a required key *present*
|
|
169
162
|
* holding `undefined` is now refused where zod's internal check accepted it.
|
|
@@ -179,11 +172,11 @@ const mapKey = slug.meta({ patternErrorMessage: SLUG_RULE });
|
|
|
179
172
|
*
|
|
180
173
|
* `clone` is the only way to add an `error` to a schema that is already built,
|
|
181
174
|
* and **it drops the schema's registry entry** — its `description`, its
|
|
182
|
-
* `examples
|
|
175
|
+
* `examples` and every other annotation, all of which live in
|
|
183
176
|
* `z.globalRegistry` keyed by the schema instance rather than in its
|
|
184
|
-
* definition. So the entry is read back and put on the clone.
|
|
185
|
-
*
|
|
186
|
-
*
|
|
177
|
+
* definition. So the entry is read back and put on the clone.
|
|
178
|
+
* `z.globalRegistry.get` resolves the whole `.meta()` parent chain into one
|
|
179
|
+
* object, so what is copied is what the export would have produced, and a
|
|
187
180
|
* later `.meta()` on the result merges with it as it did before. A wrapper that
|
|
188
181
|
* silently emptied every hover in the format would be the worst available way
|
|
189
182
|
* to improve one message.
|
|
@@ -234,8 +227,8 @@ const saysItIsMissing = (field) => {
|
|
|
234
227
|
* The second arm is the discriminated union: zod hands its error map the whole
|
|
235
228
|
* object and points the path at the discriminator, so `input` is not
|
|
236
229
|
* `undefined` and the first arm cannot see it. `Object.hasOwn` rather than
|
|
237
|
-
* `in`,
|
|
238
|
-
*
|
|
230
|
+
* `in`, because a document's keys are chosen by a developer and `constructor`
|
|
231
|
+
* satisfies the slug grammar.
|
|
239
232
|
*/
|
|
240
233
|
const absent = (issue, key) => issue.input === undefined
|
|
241
234
|
|| (issue.code === 'invalid_union'
|
|
@@ -327,8 +320,8 @@ const describeValues = (values, table) => values.map((value) => table[value]);
|
|
|
327
320
|
*
|
|
328
321
|
* The two syntaxes collide. `defaultSnippets` bodies are inserted as LSP
|
|
329
322
|
* snippets, where `${1:front}` is a tab stop and `${speed}` is a *variable* —
|
|
330
|
-
* and an unknown variable is not left alone.
|
|
331
|
-
*
|
|
323
|
+
* and an unknown variable is not left alone. Against monaco-editor's own
|
|
324
|
+
* `SnippetParser`:
|
|
332
325
|
*
|
|
333
326
|
* | body holds | the editor inserts |
|
|
334
327
|
* |---|---|
|
|
@@ -351,17 +344,16 @@ const param = (name) => `\\\${${name}}`;
|
|
|
351
344
|
* `{ battery: … }`, and `battery: ▮` offers the `…`. Both positions are real
|
|
352
345
|
* and both were silent, but they are **one skeleton**, so each is authored once
|
|
353
346
|
* as a `Snippet` constant and wrapped here for the section — never copied.
|
|
354
|
-
* Two copies of one skeleton
|
|
355
|
-
*
|
|
356
|
-
*
|
|
357
|
-
*
|
|
347
|
+
* Two copies of one skeleton drift: a body invents a value its sibling had
|
|
348
|
+
* already answered, under a label that still agrees.
|
|
349
|
+
* `config-snippets.test.ts` deep-compares the two positions rather than
|
|
350
|
+
* trusting this.
|
|
358
351
|
*
|
|
359
352
|
* **The slug key belongs to the wrapper, not to the skeleton**, because it
|
|
360
353
|
* differs per snippet — `battery_voltage` for a plain datapoint, `battery` for
|
|
361
354
|
* the numeric one. It therefore takes tab stop `${1}`, and an entry body's own
|
|
362
355
|
* stops are numbered from `${2}` throughout. At the entry position that leaves
|
|
363
|
-
* no `${1}` at all, which costs nothing
|
|
364
|
-
* monaco-editor 0.52.2's own `SnippetParser`, the version the console runs: it
|
|
356
|
+
* no `${1}` at all, which costs nothing: monaco-editor's `SnippetParser`
|
|
365
357
|
* sorts placeholders by index and requires neither that they start at 1 nor
|
|
366
358
|
* that they be contiguous, so a body of `a: ${2:x}` visits `2` first, and one
|
|
367
359
|
* of `a: ${2:x}` / `b: ${5:y}` visits `2` then `5`.
|
|
@@ -588,9 +580,9 @@ export const parameterSpec = strictObject({
|
|
|
588
580
|
* A default must satisfy the same constraints a caller's value must.
|
|
589
581
|
*
|
|
590
582
|
* Without this, a default is the one way past bounds that are otherwise
|
|
591
|
-
* the enforcement point
|
|
592
|
-
*
|
|
593
|
-
*
|
|
583
|
+
* the enforcement point. `min_value`/`max_value` are the speed limit that
|
|
584
|
+
* actually holds, enforced in the cloud before anything reaches the robot.
|
|
585
|
+
* But a caller who simply omits the parameter gets the
|
|
594
586
|
* default, and the bridge fills it at the template walk without
|
|
595
587
|
* re-checking bounds, deliberately: a second enforcement point there
|
|
596
588
|
* would be the weaker of two policies. So `{min_value: -1, max_value: 1,
|
|
@@ -787,10 +779,9 @@ export const datapointAlert = strictObject({
|
|
|
787
779
|
* `getInsertTextForProperty` (`yaml.worker.js:8520`) takes
|
|
788
780
|
* `defaultSnippets[0].body` only when a node carries **exactly one**
|
|
789
781
|
* snippet, so accepting `condition` from the key list writes the bare key
|
|
790
|
-
* here where every other node
|
|
791
|
-
*
|
|
792
|
-
*
|
|
793
|
-
* actually asked, and that is the position this wave exists to answer.
|
|
782
|
+
* here where every other node writes its whole block. The two stay anyway:
|
|
783
|
+
* the value position — a developer who has written `condition:` and pressed
|
|
784
|
+
* ⏎ — is where the question "what goes here?" is actually asked.
|
|
794
785
|
* Merging them into one would buy back the key completion by deleting the
|
|
795
786
|
* choice the schema deliberately does not name, which is the worse trade;
|
|
796
787
|
* anyone tempted to make it should change the key-completion behaviour
|
|
@@ -962,9 +953,9 @@ const NUMERIC_DATAPOINT_SNIPPET = {
|
|
|
962
953
|
/**
|
|
963
954
|
* The quotes inside `unit` are part of the inserted text and are not
|
|
964
955
|
* decoration. A body string is written into the document verbatim, and `%`
|
|
965
|
-
* is a YAML directive indicator:
|
|
966
|
-
*
|
|
967
|
-
*
|
|
956
|
+
* is a YAML directive indicator: `unit: %` is a **syntax error** ("Plain
|
|
957
|
+
* value cannot start with directive indicator character %") while
|
|
958
|
+
* `unit: "%"` parses to `%`. Nothing between here and
|
|
968
959
|
* the buffer quotes a scalar for us.
|
|
969
960
|
*/
|
|
970
961
|
numeric: { scale: 100, unit: '"%"', decimals: 1 },
|
|
@@ -1144,10 +1135,9 @@ export const datapointConfig = strictObject({
|
|
|
1144
1135
|
* `z.unknown()`, because a template can be any shape a ROS message can — so
|
|
1145
1136
|
* nothing below the top of it is checked by the type at all.
|
|
1146
1137
|
*
|
|
1147
|
-
*
|
|
1148
|
-
*
|
|
1149
|
-
*
|
|
1150
|
-
* cases, none of which reached inside a body.
|
|
1138
|
+
* The gap is easy to miss: a top-level `message: null` is refused while
|
|
1139
|
+
* `message: { linear: { x: null } }` parses clean, and a test suite that never
|
|
1140
|
+
* reaches inside a body cannot tell the two apart.
|
|
1151
1141
|
*
|
|
1152
1142
|
* Walked with an explicit stack and a seen-set, not recursion: a YAML anchor
|
|
1153
1143
|
* can make a template both very deep and genuinely cyclic, and a developer can
|
|
@@ -1231,10 +1221,9 @@ export const messageBody = messageTemplate;
|
|
|
1231
1221
|
* contract.** This runs inside `publisherConfig`'s failsafe refinement, so a
|
|
1232
1222
|
* `RangeError: Maximum call stack size exceeded` did not stay here: it
|
|
1233
1223
|
* propagated out of `safeParse`, which is specified to return a result and
|
|
1234
|
-
* not to throw.
|
|
1235
|
-
*
|
|
1236
|
-
*
|
|
1237
|
-
* meant 400.
|
|
1224
|
+
* not to throw. A recursive walk survives a few thousand levels of nesting and
|
|
1225
|
+
* throws somewhere above that, which a flow-style YAML one-liner reaches in
|
|
1226
|
+
* about 120 KB of input — so a draft PUT would answer 500 where it meant 400.
|
|
1238
1227
|
*
|
|
1239
1228
|
* `seen` is not an optimisation. YAML anchors can express a cycle
|
|
1240
1229
|
* (`&a { b: *a }`), and the parser resolves an alias to the same object, so
|
|
@@ -1302,14 +1291,13 @@ const SHARED_MESSAGE_SNIPPET = {
|
|
|
1302
1291
|
* that paragraph would be a second thing to keep true.
|
|
1303
1292
|
*
|
|
1304
1293
|
* **How the description gets here is zod behaviour, not something written
|
|
1305
|
-
* below.**
|
|
1306
|
-
*
|
|
1294
|
+
* below.** `.meta()` on an already-registered schema merges rather than
|
|
1295
|
+
* replaces, and the clone resolves the parent's entry
|
|
1307
1296
|
* *lazily* — a clone taken before the parent was registered at all still sees
|
|
1308
1297
|
* the parent's description afterwards. So no spread is needed and there is no
|
|
1309
|
-
* evaluation-order hazard.
|
|
1310
|
-
*
|
|
1311
|
-
*
|
|
1312
|
-
* the shape this file removes rather than adds.
|
|
1298
|
+
* evaluation-order hazard. A defensive `.meta({ ...messageTemplate.meta(), … })`
|
|
1299
|
+
* spread changes nothing in the export and is a second mechanism for one
|
|
1300
|
+
* description, so it is deliberately absent.
|
|
1313
1301
|
*
|
|
1314
1302
|
* It is undocumented behaviour all the same, so `config-snippets.test.ts`
|
|
1315
1303
|
* asserts this node still carries a description and that it is the same string
|
|
@@ -1598,8 +1586,8 @@ export const cameraCredentials = strictObject({
|
|
|
1598
1586
|
* therefore no validation rule to forget.
|
|
1599
1587
|
*
|
|
1600
1588
|
* **Each branch carries its own `defaultSnippets`, rather than one list on the
|
|
1601
|
-
* union.** Both placements
|
|
1602
|
-
*
|
|
1589
|
+
* union.** Both placements work; this one keeps a label beside the branch it
|
|
1590
|
+
* names, so the two cannot drift, and it makes a
|
|
1603
1591
|
* fifth source impossible to add without one — `config-snippets.test.ts`
|
|
1604
1592
|
* walks the exported branches and fails on any that carries none.
|
|
1605
1593
|
*/
|
|
@@ -1637,15 +1625,14 @@ export const cameraSource = z.discriminatedUnion('kind', [
|
|
|
1637
1625
|
* `rosTypeName` accepts either, publish accepts either, no diagnostic
|
|
1638
1626
|
* fires anywhere, and the bridge then subscribes with the wrong type and
|
|
1639
1627
|
* delivers no frames. A snippet supplying a wrong answer where it could
|
|
1640
|
-
* have supplied a question is
|
|
1641
|
-
*
|
|
1628
|
+
* have supplied a question is a defect arriving through a hint the
|
|
1629
|
+
* developer trusts.
|
|
1642
1630
|
*
|
|
1643
1631
|
* `kind: 'ros'` stays a literal, because the branch really does fix it.
|
|
1644
1632
|
*
|
|
1645
|
-
*
|
|
1646
|
-
* choice syntax is the one construct here that three layers must each
|
|
1633
|
+
* Choice syntax is the one construct here that three layers must each
|
|
1647
1634
|
* pass through unharmed: yaml-language-server's `stringifyObject` emits
|
|
1648
|
-
* the body verbatim, and monaco-editor
|
|
1635
|
+
* the body verbatim, and monaco-editor's `SnippetParser` parses
|
|
1649
1636
|
* `${2|a,b|}` into a placeholder carrying both options whose
|
|
1650
1637
|
* `toString()` — the text on the buffer before anyone chooses — is the
|
|
1651
1638
|
* first one. So a developer who tabs past this gets a document
|
|
@@ -1795,9 +1782,9 @@ export const cameraSource = z.discriminatedUnion('kind', [
|
|
|
1795
1782
|
*
|
|
1796
1783
|
* The bound lives here once, and `rest.ts`'s `cameraDescriptor` reuses it —
|
|
1797
1784
|
* the same treatment `rateThrottleHz` got, and for the same reason: the
|
|
1798
|
-
*
|
|
1799
|
-
*
|
|
1800
|
-
*
|
|
1785
|
+
* two spellings of one interval — milliseconds in a descriptor, seconds in the
|
|
1786
|
+
* document — mean a server converting on one and not the other, with nothing in
|
|
1787
|
+
* either file saying so.
|
|
1801
1788
|
*/
|
|
1802
1789
|
export const snapshotIntervalSeconds = z.number().int().min(1).max(3600);
|
|
1803
1790
|
/**
|
package/dist/errors.js
CHANGED
|
@@ -112,14 +112,11 @@ export const ERROR_CODES = [
|
|
|
112
112
|
'email_taken',
|
|
113
113
|
'identifier_taken',
|
|
114
114
|
'weak_password',
|
|
115
|
-
/* `not_a_member`
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
* nothing emits and whose noun no longer exists is the third failure mode in
|
|
121
|
-
* this project's list: a guard written against a state no producer reports.
|
|
122
|
-
* The refusals that do the work are `forbidden` (silent about existence) and
|
|
115
|
+
/* `not_a_member` is gone. It had no producer anywhere, and its vocabulary was
|
|
116
|
+
* a deleted model's — "member" of an app's pool, in a platform whose access is
|
|
117
|
+
* an assignment. A code that nothing emits, whose noun no longer exists, is a
|
|
118
|
+
* refusal a consumer must still branch on and can never receive. The refusals
|
|
119
|
+
* that do the work are `forbidden` (silent about existence) and
|
|
123
120
|
* `tier_required` (about the caller's own tier). */
|
|
124
121
|
/**
|
|
125
122
|
* The account itself is blocked — distinct from `forbidden` on purpose: it
|
|
@@ -397,7 +394,7 @@ export const ERROR_CODES = [
|
|
|
397
394
|
// `WWW-Authenticate` **header**, which is correct and present, not the body.
|
|
398
395
|
//
|
|
399
396
|
// So the rule is about the JSON-RPC layer, and the transport layer below it
|
|
400
|
-
// is ordinary
|
|
397
|
+
// is ordinary HTTP. Stating it as "never `apiError` anywhere" was the
|
|
401
398
|
// kind of tidy sentence that is easier to remember than the truth — and
|
|
402
399
|
// this file has now produced two of those about itself.
|
|
403
400
|
//
|
|
@@ -416,8 +413,8 @@ export const ERROR_CODES = [
|
|
|
416
413
|
* flag; the central-MCP cut deleted the per-app `/mcp/<identifier>` endpoint
|
|
417
414
|
* that flag gated, and 2026-08-29 removed the field itself from `app`, so
|
|
418
415
|
* the code stood for a year with nothing able to produce it. The
|
|
419
|
-
*
|
|
420
|
-
*
|
|
416
|
+
* per-app endpoint is back, with the switch on `appAuthConfig` rather than on
|
|
417
|
+
* `app`, and this is its refusal again.
|
|
421
418
|
*
|
|
422
419
|
* The lesson that survives is about the year in between: an enum member with
|
|
423
420
|
* no producer is not harmless, because a reader arriving at it takes it for
|
|
@@ -465,7 +462,7 @@ export const ERROR_CODES = [
|
|
|
465
462
|
* would make a client branch on which route it called.
|
|
466
463
|
*/
|
|
467
464
|
'capability_required',
|
|
468
|
-
//
|
|
465
|
+
// Org-central identity.
|
|
469
466
|
/**
|
|
470
467
|
* **An org must keep at least one Owner**, so the last one is neither
|
|
471
468
|
* deletable nor demotable. 409, on both `DELETE /api/org/users/:id` and
|
|
@@ -481,7 +478,7 @@ export const ERROR_CODES = [
|
|
|
481
478
|
* caller could infer from a silence about existence.
|
|
482
479
|
*/
|
|
483
480
|
'last_owner',
|
|
484
|
-
//
|
|
481
|
+
// OIDC federation.
|
|
485
482
|
/**
|
|
486
483
|
* **The target is in a state that refuses the operation** — not the caller's
|
|
487
484
|
* rights, not the target's existence, but *what the target currently is*.
|
|
@@ -545,7 +542,7 @@ export const ERROR_CODES = [
|
|
|
545
542
|
* `409` from the configuration routes: the draft parses as YAML but its root
|
|
546
543
|
* is not a mapping — a list, a scalar, or an empty document. Distinct from
|
|
547
544
|
* `validation_error`, which is about a field inside a document that *is* one.
|
|
548
|
-
* Produced by
|
|
545
|
+
* Produced by the configuration draft route.
|
|
549
546
|
*/
|
|
550
547
|
'draft_not_a_document',
|
|
551
548
|
/**
|
|
@@ -553,23 +550,22 @@ export const ERROR_CODES = [
|
|
|
553
550
|
* it has no mapping for, and the code the realtime socket sends for the same
|
|
554
551
|
* state. It says nothing about the request, deliberately: a caller cannot act
|
|
555
552
|
* on it beyond retrying, and the detail belongs in the server's log rather
|
|
556
|
-
* than in a body a stranger receives. Produced by
|
|
557
|
-
*
|
|
553
|
+
* than in a body a stranger receives. Produced by the server's own error
|
|
554
|
+
* handler and by the realtime socket.
|
|
558
555
|
*/
|
|
559
556
|
'internal_error',
|
|
560
557
|
/**
|
|
561
558
|
* `422` from `POST /api/robots/:id/jobs/:slug/cancel`: the job exists and the
|
|
562
559
|
* caller may address it, but it is in a state that has nothing left to
|
|
563
560
|
* cancel — already settled, or of a kind that does not support cancellation.
|
|
564
|
-
* Produced by
|
|
565
|
-
* `cloud/src/routes/commands.ts`.
|
|
561
|
+
* Produced by the command layer and mapped onto the job routes.
|
|
566
562
|
*/
|
|
567
563
|
'not_cancellable',
|
|
568
564
|
/**
|
|
569
565
|
* `415`. The request carried a body in a media type the route does not read.
|
|
570
566
|
* It is the cloud-wide answer from the content-type parser, not one route's:
|
|
571
567
|
* a caller reaching it never got as far as validation, which is why this is
|
|
572
|
-
* not a `validation_error`. Produced by
|
|
568
|
+
* not a `validation_error`. Produced by the server itself.
|
|
573
569
|
*/
|
|
574
570
|
'unsupported_media_type',
|
|
575
571
|
/**
|
|
@@ -579,16 +575,14 @@ export const ERROR_CODES = [
|
|
|
579
575
|
* hash recorded on the interaction row.
|
|
580
576
|
*
|
|
581
577
|
* **The impersonation interstitial it also named is deleted** with the rest
|
|
582
|
-
* of the app OAuth flow
|
|
583
|
-
*
|
|
584
|
-
* different screens — which is the reason worth carrying forward: the check
|
|
585
|
-
* belongs on every verb that *renders* the step, not only on the one that
|
|
578
|
+
* of the app OAuth flow. The rule that outlives it: this defence goes on
|
|
579
|
+
* every verb that *renders* the step, not only on the one that
|
|
586
580
|
* completes it.
|
|
587
581
|
*
|
|
588
582
|
* Deliberately not `invalid_token` or `unauthorized`: nothing about the
|
|
589
583
|
* caller's credential is being refused, and the remedy is specific and
|
|
590
|
-
* actionable — start the flow again in this browser. Produced by
|
|
591
|
-
*
|
|
584
|
+
* actionable — start the flow again in this browser. Produced by both
|
|
585
|
+
* hosted authorization flows.
|
|
592
586
|
*/
|
|
593
587
|
'wrong_browser',
|
|
594
588
|
/**
|
|
@@ -602,9 +596,8 @@ export const ERROR_CODES = [
|
|
|
602
596
|
* why nothing noticed. The envelope validates; only the *code* was absent
|
|
603
597
|
* from the one list a client can match against, so a caller branching on
|
|
604
598
|
* `ERROR_CODES` fell through to its unknown-error arm for the single most
|
|
605
|
-
* common refusal
|
|
606
|
-
*
|
|
607
|
-
* `cloud/src/routes/config.ts`.
|
|
599
|
+
* common refusal an editor produces — a documented absence on the codes list
|
|
600
|
+
* itself. Produced by the configuration draft route.
|
|
608
601
|
*/
|
|
609
602
|
'invalid_yaml',
|
|
610
603
|
/**
|
|
@@ -614,7 +607,7 @@ export const ERROR_CODES = [
|
|
|
614
607
|
*
|
|
615
608
|
* Two codes rather than one, because the two say different things to whoever
|
|
616
609
|
* typed the text: the first means "this is not YAML", the second means "this
|
|
617
|
-
* is YAML I cannot keep". Produced by
|
|
610
|
+
* is YAML I cannot keep". Produced by the configuration draft route.
|
|
618
611
|
*/
|
|
619
612
|
'unstorable_yaml',
|
|
620
613
|
// 2026-09-05 — app-user auth (two identity spaces, the JSON client API).
|
package/dist/identity.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
/**
|
|
4
4
|
* **Fleetless users: the org's team, and the only people who reach the
|
|
5
|
-
* console
|
|
5
|
+
* console.**
|
|
6
6
|
*
|
|
7
7
|
* There are two identity spaces now and **nothing joins them**:
|
|
8
8
|
*
|
|
@@ -17,7 +17,7 @@ import { z } from 'zod';
|
|
|
17
17
|
* A Fleetless user who wants to use an app registers or is invited like
|
|
18
18
|
* anybody else; there is no path from one space to the other.
|
|
19
19
|
*
|
|
20
|
-
* **What that deleted, with no successor
|
|
20
|
+
* **What that deleted, with no successor**: groups and the Org Admins
|
|
21
21
|
* group, app assignments, impersonation, the per-user MCP override and the
|
|
22
22
|
* org-level federation policy. The 2026-08-29 model had put developers and end
|
|
23
23
|
* users into one pool per org and connected them with all of the above; in use
|
|
@@ -49,7 +49,7 @@ export declare const password: z.ZodString;
|
|
|
49
49
|
/** The bound on a Fleetless user's display name; `APP_USER_DISPLAY_NAME_MAX` matches it, so a rename cannot be legal in one space and refused in the other. */
|
|
50
50
|
export declare const USER_DISPLAY_NAME_MAX = 120;
|
|
51
51
|
/**
|
|
52
|
-
* **The two tiers a Fleetless user can hold
|
|
52
|
+
* **The two tiers a Fleetless user can hold**. Owner-exclusive: delete
|
|
53
53
|
* the org, edit org settings, promote to owner, and later billing. Everything
|
|
54
54
|
* else a Fleetless user may do, a `developer` may do.
|
|
55
55
|
*
|
|
@@ -97,7 +97,7 @@ export type PatchOrgResponse = z.infer<typeof patchOrgResponse>;
|
|
|
97
97
|
* central endpoint), and `has_password`. The last is the interesting one — it
|
|
98
98
|
* existed because a pool user might have been provisioned by an identity
|
|
99
99
|
* provider and hold no Fleetless credential. A Fleetless user always holds
|
|
100
|
-
* one: the console is password-only by design
|
|
100
|
+
* one: the console is password-only by design, which removes the
|
|
101
101
|
* IdP-lockout class entirely, so a field reporting whether the credential
|
|
102
102
|
* exists would have exactly one value forever.
|
|
103
103
|
*/
|
|
@@ -205,7 +205,7 @@ export declare const waitlistRequest: z.ZodObject<{
|
|
|
205
205
|
export type WaitlistRequest = z.infer<typeof waitlistRequest>;
|
|
206
206
|
/**
|
|
207
207
|
* Console login. Fleetless users only, always the Fleetless password — the
|
|
208
|
-
* console has no federated door at all
|
|
208
|
+
* console has no federated door at all, which removes the IdP-lockout
|
|
209
209
|
* class entirely.
|
|
210
210
|
*
|
|
211
211
|
* This resolves a person by address alone, and a Fleetless user's email is
|
|
@@ -495,7 +495,7 @@ export type IdpIssuer = z.infer<typeof idpIssuer>;
|
|
|
495
495
|
* here.** `oidcCallbackErrorCode` and `oidcCallbackError` described the page
|
|
496
496
|
* `GET /mcp/oauth/idp-callback` rendered when a group's identity provider sent
|
|
497
497
|
* a browser back — `jit_disabled` and `email_collision` name provisioning steps
|
|
498
|
-
* only a group provider had.
|
|
498
|
+
* only a group provider had. Fleetless users are password-only now, which deletes
|
|
499
499
|
* group providers, so the flow that produced these codes cannot start; the
|
|
500
500
|
* route is gone from this manifest and from the cloud.
|
|
501
501
|
*
|
package/dist/identity.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
/**
|
|
4
4
|
* **Fleetless users: the org's team, and the only people who reach the
|
|
5
|
-
* console
|
|
5
|
+
* console.**
|
|
6
6
|
*
|
|
7
7
|
* There are two identity spaces now and **nothing joins them**:
|
|
8
8
|
*
|
|
@@ -17,7 +17,7 @@ import { z } from 'zod';
|
|
|
17
17
|
* A Fleetless user who wants to use an app registers or is invited like
|
|
18
18
|
* anybody else; there is no path from one space to the other.
|
|
19
19
|
*
|
|
20
|
-
* **What that deleted, with no successor
|
|
20
|
+
* **What that deleted, with no successor**: groups and the Org Admins
|
|
21
21
|
* group, app assignments, impersonation, the per-user MCP override and the
|
|
22
22
|
* org-level federation policy. The 2026-08-29 model had put developers and end
|
|
23
23
|
* users into one pool per org and connected them with all of the above; in use
|
|
@@ -49,7 +49,7 @@ export const password = z.string().min(12).max(256);
|
|
|
49
49
|
/** The bound on a Fleetless user's display name; `APP_USER_DISPLAY_NAME_MAX` matches it, so a rename cannot be legal in one space and refused in the other. */
|
|
50
50
|
export const USER_DISPLAY_NAME_MAX = 120;
|
|
51
51
|
/**
|
|
52
|
-
* **The two tiers a Fleetless user can hold
|
|
52
|
+
* **The two tiers a Fleetless user can hold**. Owner-exclusive: delete
|
|
53
53
|
* the org, edit org settings, promote to owner, and later billing. Everything
|
|
54
54
|
* else a Fleetless user may do, a `developer` may do.
|
|
55
55
|
*
|
|
@@ -95,7 +95,7 @@ export const patchOrgResponse = z.object({
|
|
|
95
95
|
* central endpoint), and `has_password`. The last is the interesting one — it
|
|
96
96
|
* existed because a pool user might have been provisioned by an identity
|
|
97
97
|
* provider and hold no Fleetless credential. A Fleetless user always holds
|
|
98
|
-
* one: the console is password-only by design
|
|
98
|
+
* one: the console is password-only by design, which removes the
|
|
99
99
|
* IdP-lockout class entirely, so a field reporting whether the credential
|
|
100
100
|
* exists would have exactly one value forever.
|
|
101
101
|
*/
|
|
@@ -181,7 +181,7 @@ export const signUpResponse = z.object({
|
|
|
181
181
|
export const waitlistRequest = z.object({ email: z.email().max(254) });
|
|
182
182
|
/**
|
|
183
183
|
* Console login. Fleetless users only, always the Fleetless password — the
|
|
184
|
-
* console has no federated door at all
|
|
184
|
+
* console has no federated door at all, which removes the IdP-lockout
|
|
185
185
|
* class entirely.
|
|
186
186
|
*
|
|
187
187
|
* This resolves a person by address alone, and a Fleetless user's email is
|
|
@@ -472,7 +472,7 @@ export const idpIssuer = z
|
|
|
472
472
|
* here.** `oidcCallbackErrorCode` and `oidcCallbackError` described the page
|
|
473
473
|
* `GET /mcp/oauth/idp-callback` rendered when a group's identity provider sent
|
|
474
474
|
* a browser back — `jit_disabled` and `email_collision` name provisioning steps
|
|
475
|
-
* only a group provider had.
|
|
475
|
+
* only a group provider had. Fleetless users are password-only now, which deletes
|
|
476
476
|
* group providers, so the flow that produced these codes cannot start; the
|
|
477
477
|
* route is gone from this manifest and from the cloud.
|
|
478
478
|
*
|
package/dist/index.js
CHANGED
|
@@ -32,7 +32,7 @@ export { clientAuth, authOk, authError, clientInvoke, clientCancel, clientPublis
|
|
|
32
32
|
export { password, org, patchOrgResponse, sessionTokens, refreshRequest, signUpRequest, signUpResponse,
|
|
33
33
|
// 2026-09-04 — the public site (closed beta).
|
|
34
34
|
waitlistRequest, developerLoginRequest,
|
|
35
|
-
//
|
|
35
|
+
// The two identity spaces.
|
|
36
36
|
USER_DISPLAY_NAME_MAX, orgAdminTier, fleetlessUser, fleetlessUserListResponse, createTeamInviteRequest, teamInvite, pendingTeamInvite, pendingTeamInviteListResponse, acceptTeamInviteRequest, patchFleetlessUserRequest, tierChangeRequest,
|
|
37
37
|
// Identity.
|
|
38
38
|
mailStatus, tierRequiredDetails, passwordChangeRequest, passwordResetRequest, passwordResetConfirm, idpIssuer,
|
|
@@ -40,7 +40,7 @@ mailStatus, tierRequiredDetails, passwordChangeRequest, passwordResetRequest, pa
|
|
|
40
40
|
authMeResponse, patchOrgRequest, patchAuthMeRequest, } from './identity.js';
|
|
41
41
|
export { appIdentifier, app, appListResponse, createAppRequest, updateAppRequest, serverKeyToken, serverKey, serverKeyListResponse, createServerKeyResponse, role, roleListResponse, rolePermissions, } from './apps.js';
|
|
42
42
|
export { clientLoginRequest, clientRefreshRequest, clientLogoutRequest, clientRegisterRequest, clientVerifyEmailRequest, clientResendVerificationRequest, clientPasswordResetRequest, clientPasswordResetConfirmRequest, clientAcceptInvitationRequest, CLIENT_OIDC_CALLBACK_PATH, clientProviderListQuery, clientProviderListResponse, clientOidcStartQuery, clientOidcCallbackQuery, clientOidcExchangeRequest, clientOidcErrorCode, clientMcpInteraction, clientMcpInteractionDecisionResponse, mcpConsentGrant, mcpConsentGrantListResponse, clientIdentity, } from './client-auth.js';
|
|
43
|
-
//
|
|
43
|
+
// The per-app identity space.
|
|
44
44
|
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, putAppAuthConfigRequest, mailTemplateKind, appMailTemplate, appMailTemplateListResponse, putAppMailTemplateRequest, mailTemplatePreviewRequest, mailTemplatePreviewResponse, mailTemplateProblemDetails, mailOutcome, } from './app-users.js';
|
|
45
45
|
export { assetKind, URDF_ASSET_NAME, asset, urdfCompleteness, assetListResponse, missingAssetQuery, assetSyncRequest, assetSyncResponse, assetSyncState, assetSyncStatus, assetFailure, assetFailureKind, assetTooLargeDetails, assetSyncBusyDetails, ASSET_UPLOAD_MAX_BYTES, } from './assets.js';
|
|
46
46
|
export { auditActor, auditEvent, auditQuery, auditListResponse, AUDIT_CSV_COLUMNS, AUDIT_RETENTION_DAYS } from './audit.js';
|
package/dist/jobs.d.ts
CHANGED
|
@@ -163,7 +163,7 @@ export declare const JOB_RUN_RETENTION_DAYS = 90;
|
|
|
163
163
|
* invites every reader to handle it.
|
|
164
164
|
*
|
|
165
165
|
* **`app_user` is what a client-app caller writes now, and `end_user` stays**
|
|
166
|
-
*
|
|
166
|
+
* identity spaces. The seam this comment used to describe — two names for
|
|
167
167
|
* two ways into one merged pool — is settled: the two identity spaces are
|
|
168
168
|
* separate tables again, and `app_user` is a row in `app_users`, belonging to
|
|
169
169
|
* exactly one app. `end_user` is kept for the same reason `auditActor.kind`
|
|
@@ -188,10 +188,10 @@ export declare const jobRunKind: z.ZodEnum<{
|
|
|
188
188
|
}>;
|
|
189
189
|
export type JobRunKind = z.infer<typeof jobRunKind>;
|
|
190
190
|
/**
|
|
191
|
-
* One durable record of one invocation
|
|
192
|
-
*
|
|
191
|
+
* One durable record of one invocation. One row per run, never one per event:
|
|
192
|
+
* the per-event timeline's write rate
|
|
193
193
|
* is set by the bridge, and a throttled log that cannot say it was throttled is
|
|
194
|
-
*
|
|
194
|
+
* an instrument that cannot say what it does not know. The live timeline is
|
|
195
195
|
* delivered in full by realtime, for as long as somebody is watching.
|
|
196
196
|
*/
|
|
197
197
|
export declare const jobRun: z.ZodObject<{
|
package/dist/jobs.js
CHANGED
|
@@ -166,7 +166,7 @@ export const JOB_RUN_RETENTION_DAYS = 90;
|
|
|
166
166
|
* invites every reader to handle it.
|
|
167
167
|
*
|
|
168
168
|
* **`app_user` is what a client-app caller writes now, and `end_user` stays**
|
|
169
|
-
*
|
|
169
|
+
* identity spaces. The seam this comment used to describe — two names for
|
|
170
170
|
* two ways into one merged pool — is settled: the two identity spaces are
|
|
171
171
|
* separate tables again, and `app_user` is a row in `app_users`, belonging to
|
|
172
172
|
* exactly one app. `end_user` is kept for the same reason `auditActor.kind`
|
|
@@ -192,10 +192,10 @@ export const jobActor = z.object({
|
|
|
192
192
|
});
|
|
193
193
|
export const jobRunKind = z.enum(['action', 'service']);
|
|
194
194
|
/**
|
|
195
|
-
* One durable record of one invocation
|
|
196
|
-
*
|
|
195
|
+
* One durable record of one invocation. One row per run, never one per event:
|
|
196
|
+
* the per-event timeline's write rate
|
|
197
197
|
* is set by the bridge, and a throttled log that cannot say it was throttled is
|
|
198
|
-
*
|
|
198
|
+
* an instrument that cannot say what it does not know. The live timeline is
|
|
199
199
|
* delivered in full by realtime, for as long as somebody is watching.
|
|
200
200
|
*/
|
|
201
201
|
export const jobRun = z.object({
|
package/dist/mcp.d.ts
CHANGED
|
@@ -36,7 +36,7 @@ export declare const MCP_PROTOCOL_VERSION: "2025-11-25";
|
|
|
36
36
|
*
|
|
37
37
|
* **Not parameterised, and that is now a statement rather than the absence of
|
|
38
38
|
* one.** The central endpoint serves the org's team with the console tool
|
|
39
|
-
* family
|
|
39
|
+
* family; an app's users reach a different endpoint, whose
|
|
40
40
|
* path `mcpAppEndpointPath` builds. Two constants for two audiences, so a call
|
|
41
41
|
* site says which it means instead of an argument deciding it.
|
|
42
42
|
*
|
|
@@ -48,7 +48,7 @@ export declare const MCP_PROTOCOL_VERSION: "2025-11-25";
|
|
|
48
48
|
*/
|
|
49
49
|
export declare const MCP_ENDPOINT_PATH: "/mcp";
|
|
50
50
|
/**
|
|
51
|
-
* The path of **one app's** MCP server
|
|
51
|
+
* The path of **one app's** MCP server — what an app user pastes into
|
|
52
52
|
* their AI tool, served only while the app's `appAuthConfig.mcp_enabled` is on.
|
|
53
53
|
*
|
|
54
54
|
* A helper rather than a template literal at four call sites, for
|
|
@@ -72,7 +72,7 @@ export declare const MCP_ENDPOINT_PATH: "/mcp";
|
|
|
72
72
|
export declare function mcpAppEndpointPath(appIdentifier: string): string;
|
|
73
73
|
/**
|
|
74
74
|
* **Every path one app's MCP server answers on, built from its identifier
|
|
75
|
-
* once
|
|
75
|
+
* once**.
|
|
76
76
|
*
|
|
77
77
|
* Six strings, and each of them is spelled in at least three places that
|
|
78
78
|
* cannot see one another: the cloud registers the route, the console renders a
|