@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/app-users.js
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { idpIssuer, mailStatus, password } from './identity.js';
|
|
4
4
|
/**
|
|
5
|
-
* **App users: the per-app identity space
|
|
6
|
-
* D1–D7).
|
|
5
|
+
* **App users: the per-app identity space.**
|
|
7
6
|
*
|
|
8
7
|
* The 2026-08-29 model put developers and end users into one pool per org,
|
|
9
8
|
* tied apps to groups, and let an org admin enter an app only by
|
|
@@ -22,7 +21,7 @@ import { idpIssuer, mailStatus, password } from './identity.js';
|
|
|
22
21
|
* as unrelated accounts, and a Fleetless user who wants to use an app
|
|
23
22
|
* registers or is invited like anybody else.
|
|
24
23
|
*
|
|
25
|
-
* **Fleetless shows an app user no page
|
|
24
|
+
* **Fleetless shows an app user no page**. The developer's own UI owns
|
|
26
25
|
* every screen and calls the JSON client-auth API (`client-auth.ts`). The one
|
|
27
26
|
* Fleetless-rendered surface an app user can reach is the problem page for an
|
|
28
27
|
* OIDC callback whose state no longer resolves to a redirect URI — every other
|
|
@@ -68,7 +67,7 @@ export const appUserStatus = z.enum(['pending_verification', 'active', 'blocked'
|
|
|
68
67
|
* **A user of one app.** Not a user of the org: `app_id` is the whole scope,
|
|
69
68
|
* and the uniqueness constraint the cloud enforces is `(app_id, lower(email))`
|
|
70
69
|
* rather than a global one. The same person at two apps of one org is two
|
|
71
|
-
* unrelated rows, by design
|
|
70
|
+
* unrelated rows, by design.
|
|
72
71
|
*/
|
|
73
72
|
export const appUser = z.object({
|
|
74
73
|
id: z.uuid().meta({
|
|
@@ -148,8 +147,8 @@ export const createAppUserRequest = z
|
|
|
148
147
|
* offering it is a refusal rather than a silently dropped field.
|
|
149
148
|
*
|
|
150
149
|
* **`status` admits only `active` and `blocked`.** `pending_verification` is
|
|
151
|
-
* reached once, by self-registration, and left by spending the mailed token
|
|
152
|
-
*
|
|
150
|
+
* reached once, by self-registration, and left by spending the mailed token.
|
|
151
|
+
* A developer able to set it back could void a verified address without
|
|
153
152
|
* the user ever seeing a mail, and there is no route out of that state that
|
|
154
153
|
* does not require a token nobody re-sent. So the narrower enum is the rule,
|
|
155
154
|
* stated in the schema rather than left to a handler to remember.
|
|
@@ -196,7 +195,7 @@ export const createAppInvitationRequest = z
|
|
|
196
195
|
* An app that has configured none has nowhere for it to point, so there is no
|
|
197
196
|
* link to hand back — `null` says that outright, where an absent key would be
|
|
198
197
|
* indistinguishable from a mapper that dropped the field and a fabricated
|
|
199
|
-
* Fleetless-hosted URL would name a page this product does not serve
|
|
198
|
+
* Fleetless-hosted URL would name a page this product does not serve.
|
|
200
199
|
*/
|
|
201
200
|
export const appInvitation = z.object({
|
|
202
201
|
id: z.uuid().meta({ description: 'The invitation, as listed and revoked by the developer.' }),
|
|
@@ -231,7 +230,7 @@ export const appInvitationListResponse = z.object({
|
|
|
231
230
|
}),
|
|
232
231
|
});
|
|
233
232
|
/**
|
|
234
|
-
* **An app's OIDC provider, as read back
|
|
233
|
+
* **An app's OIDC provider, as read back**. Any number per app, unlike
|
|
235
234
|
* the group provider this replaces — a developer serving two customers needs
|
|
236
235
|
* two, and the old at-most-one rule was a property of groups rather than of
|
|
237
236
|
* identity.
|
|
@@ -305,7 +304,7 @@ export const createAppOidcProviderRequest = z
|
|
|
305
304
|
description: 'The client secret, **write-only**: it is stored encrypted and comes back through nothing — not the read, not this route\'s own answer, not an audit detail. Required on create, since a provider with no secret cannot exchange a code; the minimum length refuses a value that is a misconfiguration rather than a secret.',
|
|
306
305
|
}),
|
|
307
306
|
scopes: z.array(z.string().min(1).max(60)).min(1).max(20).default(['openid', 'email', 'profile']).meta({
|
|
308
|
-
description: 'The scopes to request. Defaults to `openid email profile`, which is what
|
|
307
|
+
description: 'The scopes to request. Defaults to `openid email profile`, which is what account linking actually reads: the subject, the address and its verified flag, and a name.',
|
|
309
308
|
}),
|
|
310
309
|
link_verified_emails: z.boolean().default(false).meta({
|
|
311
310
|
description: 'Whether a federated login may join an existing app user by verified address. **Defaults to off**, because relaxing later is additive and admitting duplicates now and tightening afterwards is not.',
|
|
@@ -438,16 +437,15 @@ export const emailDomain = z
|
|
|
438
437
|
.max(253)
|
|
439
438
|
.regex(/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,63}$/, 'must be a lowercase domain name with at least two labels');
|
|
440
439
|
/**
|
|
441
|
-
* **The app's auth settings: one row per app, configured by a Fleetless user
|
|
442
|
-
* (D3).
|
|
440
|
+
* **The app's auth settings: one row per app, configured by a Fleetless user.**
|
|
443
441
|
*
|
|
444
442
|
* `self_registration` and `allowed_domains` are **one policy for one
|
|
445
443
|
* decision** — they govern registration by password and registration through
|
|
446
|
-
* an identity provider alike
|
|
444
|
+
* an identity provider alike. An invitation always bypasses both, because
|
|
447
445
|
* a developer inviting somebody by hand has already made the decision the
|
|
448
446
|
* whitelist automates.
|
|
449
447
|
*
|
|
450
|
-
* The four URLs are what makes
|
|
448
|
+
* The four URLs are what makes that work: Fleetless mails a link, and the link
|
|
451
449
|
* points into the developer's app. An app that has configured none of them
|
|
452
450
|
* still works for password login — it simply cannot send a mail that leads
|
|
453
451
|
* anywhere, and `send_mail` is refused rather than silently sending a dead
|
|
@@ -494,7 +492,7 @@ export const putAppAuthConfigRequest = appAuthConfig
|
|
|
494
492
|
.omit({ oidc_callback_url: true, updated_at: true })
|
|
495
493
|
.strict();
|
|
496
494
|
/**
|
|
497
|
-
* The three mails a developer may replace with their own template
|
|
495
|
+
* The three mails a developer may replace with their own template.
|
|
498
496
|
* Mails to *Fleetless* users — a team invitation, a console password reset —
|
|
499
497
|
* stay Fleetless default and are deliberately not customisable: they are
|
|
500
498
|
* about this platform, not about the developer's product.
|
package/dist/apps.js
CHANGED
|
@@ -124,7 +124,8 @@ export const updateAppRequest = z.object({
|
|
|
124
124
|
name: z.string().min(1).max(120).optional(),
|
|
125
125
|
robot_ids: z.array(z.uuid()).optional(),
|
|
126
126
|
/**
|
|
127
|
-
* `app.default_role_id`'s write half — an app *setting*, which is where
|
|
127
|
+
* `app.default_role_id`'s write half — an app *setting*, which is where the
|
|
128
|
+
* two-identity-space model
|
|
128
129
|
* put the default role, so it belongs on the app's own PATCH and not on a
|
|
129
130
|
* route of its own.
|
|
130
131
|
*
|
package/dist/audit.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ import { z } from 'zod';
|
|
|
15
15
|
* resolve four different id kinds to render a row.
|
|
16
16
|
*
|
|
17
17
|
* **`end_user` stays, and it stays for the rows already written.** The
|
|
18
|
-
* two
|
|
18
|
+
* split into two identity spaces replaced the org's one user pool with
|
|
19
19
|
* Fleetless users and per-app app users; every new row an app user writes
|
|
20
20
|
* carries `app_user`. But an audit log is the one thing this platform must
|
|
21
21
|
* never rewrite, and there are stored rows whose `kind` is `end_user`. Dropping
|
|
@@ -23,9 +23,8 @@ import { z } from 'zod';
|
|
|
23
23
|
* cannot be read back is worse than one carrying a retired word.
|
|
24
24
|
*
|
|
25
25
|
* So this enum is deliberately **wider than what any producer emits**: nothing
|
|
26
|
-
* writes `end_user` any more, and nothing may start again. That is
|
|
27
|
-
*
|
|
28
|
-
* is said here rather than inferred from a `grep` somebody runs in a year.
|
|
26
|
+
* writes `end_user` any more, and nothing may start again. That is said here
|
|
27
|
+
* rather than left to be inferred from a search somebody runs in a year.
|
|
29
28
|
*
|
|
30
29
|
* `developer` is a Fleetless user. It kept its name through both redesigns
|
|
31
30
|
* because it was always right about what it named: the person who configures
|
package/dist/audit.js
CHANGED
|
@@ -16,7 +16,7 @@ import { wireSeqCursor, wireTimestampMs } from './common.js';
|
|
|
16
16
|
* resolve four different id kinds to render a row.
|
|
17
17
|
*
|
|
18
18
|
* **`end_user` stays, and it stays for the rows already written.** The
|
|
19
|
-
* two
|
|
19
|
+
* split into two identity spaces replaced the org's one user pool with
|
|
20
20
|
* Fleetless users and per-app app users; every new row an app user writes
|
|
21
21
|
* carries `app_user`. But an audit log is the one thing this platform must
|
|
22
22
|
* never rewrite, and there are stored rows whose `kind` is `end_user`. Dropping
|
|
@@ -24,9 +24,8 @@ import { wireSeqCursor, wireTimestampMs } from './common.js';
|
|
|
24
24
|
* cannot be read back is worse than one carrying a retired word.
|
|
25
25
|
*
|
|
26
26
|
* So this enum is deliberately **wider than what any producer emits**: nothing
|
|
27
|
-
* writes `end_user` any more, and nothing may start again. That is
|
|
28
|
-
*
|
|
29
|
-
* is said here rather than inferred from a `grep` somebody runs in a year.
|
|
27
|
+
* writes `end_user` any more, and nothing may start again. That is said here
|
|
28
|
+
* rather than left to be inferred from a search somebody runs in a year.
|
|
30
29
|
*
|
|
31
30
|
* `developer` is a Fleetless user. It kept its name through both redesigns
|
|
32
31
|
* because it was always right about what it named: the person who configures
|
package/dist/client-auth.d.ts
CHANGED
|
@@ -61,7 +61,7 @@ export declare const clientLogoutRequest: z.ZodObject<{
|
|
|
61
61
|
}, z.core.$strip>;
|
|
62
62
|
export type ClientLogoutRequest = z.infer<typeof clientLogoutRequest>;
|
|
63
63
|
/**
|
|
64
|
-
* **Self-registration**
|
|
64
|
+
* **Self-registration** — and the account it creates cannot log in yet.
|
|
65
65
|
*
|
|
66
66
|
* `register` writes the user as `pending_verification` and mails the app's
|
|
67
67
|
* `verify_url`. Without that step the domain whitelist would prove nothing:
|
|
@@ -221,7 +221,7 @@ export type ClientOidcStartQuery = z.infer<typeof clientOidcStartQuery>;
|
|
|
221
221
|
* `state` is the one required field because it is the one Fleetless minted: it
|
|
222
222
|
* resolves the `oidc_interactions` row that holds the app's `redirect_uri`,
|
|
223
223
|
* and without it there is nowhere to send any answer, success or failure. That
|
|
224
|
-
* is the single case where the cloud renders a page of its own
|
|
224
|
+
* is the single case where the cloud renders a page of its own.
|
|
225
225
|
*
|
|
226
226
|
* It exists as a schema rather than as four parameters read by hand because
|
|
227
227
|
* the manifest forbids the second: a documented route whose prose names a
|
|
@@ -244,7 +244,7 @@ export type ClientOidcExchangeRequest = z.infer<typeof clientOidcExchangeRequest
|
|
|
244
244
|
/**
|
|
245
245
|
* **Why a federated sign-in ended without a session, in a code the app can
|
|
246
246
|
* branch on** — carried back to the app's own `redirect_uri` as `error`, not
|
|
247
|
-
* rendered by Fleetless
|
|
247
|
+
* rendered by Fleetless. The only Fleetless-rendered page in this flow is
|
|
248
248
|
* the one for a state that can no longer be resolved to a redirect URI, because
|
|
249
249
|
* then there is nowhere to send the answer.
|
|
250
250
|
*
|
|
@@ -293,7 +293,7 @@ export declare const clientOidcErrorCode: z.ZodEnum<{
|
|
|
293
293
|
export type ClientOidcErrorCode = z.infer<typeof clientOidcErrorCode>;
|
|
294
294
|
/**
|
|
295
295
|
* **A pending MCP authorization, as the app's own consent screen reads it**
|
|
296
|
-
*
|
|
296
|
+
* Fleetless renders no page here either: `authorize` redirects to the
|
|
297
297
|
* app's `mcp_login_url` with an interaction id, the app authenticates the user
|
|
298
298
|
* with its normal UI, shows this, and approves or denies through the API.
|
|
299
299
|
*
|
|
@@ -388,7 +388,7 @@ export type McpConsentGrantListResponse = z.infer<typeof mcpConsentGrantListResp
|
|
|
388
388
|
* quietest way for a cut like this to go wrong.
|
|
389
389
|
*
|
|
390
390
|
* **`act` is gone.** It named the org admin behind an impersonation (the RFC
|
|
391
|
-
* 8693 pattern). Impersonation is deleted with no successor
|
|
391
|
+
* 8693 pattern). Impersonation is deleted with no successor, so a field
|
|
392
392
|
* that could still arrive would describe a delegation nothing can mint — and a
|
|
393
393
|
* client rendering "you are acting as …" from it would be showing a state the
|
|
394
394
|
* platform cannot enter.
|
package/dist/client-auth.js
CHANGED
|
@@ -73,7 +73,7 @@ export const clientLogoutRequest = z.object({
|
|
|
73
73
|
});
|
|
74
74
|
/* ---------------------------------------------- registration and mails -- */
|
|
75
75
|
/**
|
|
76
|
-
* **Self-registration**
|
|
76
|
+
* **Self-registration** — and the account it creates cannot log in yet.
|
|
77
77
|
*
|
|
78
78
|
* `register` writes the user as `pending_verification` and mails the app's
|
|
79
79
|
* `verify_url`. Without that step the domain whitelist would prove nothing:
|
|
@@ -271,7 +271,7 @@ export const clientOidcStartQuery = z.object({
|
|
|
271
271
|
* `state` is the one required field because it is the one Fleetless minted: it
|
|
272
272
|
* resolves the `oidc_interactions` row that holds the app's `redirect_uri`,
|
|
273
273
|
* and without it there is nowhere to send any answer, success or failure. That
|
|
274
|
-
* is the single case where the cloud renders a page of its own
|
|
274
|
+
* is the single case where the cloud renders a page of its own.
|
|
275
275
|
*
|
|
276
276
|
* It exists as a schema rather than as four parameters read by hand because
|
|
277
277
|
* the manifest forbids the second: a documented route whose prose names a
|
|
@@ -306,7 +306,7 @@ export const clientOidcExchangeRequest = z
|
|
|
306
306
|
/**
|
|
307
307
|
* **Why a federated sign-in ended without a session, in a code the app can
|
|
308
308
|
* branch on** — carried back to the app's own `redirect_uri` as `error`, not
|
|
309
|
-
* rendered by Fleetless
|
|
309
|
+
* rendered by Fleetless. The only Fleetless-rendered page in this flow is
|
|
310
310
|
* the one for a state that can no longer be resolved to a redirect URI, because
|
|
311
311
|
* then there is nowhere to send the answer.
|
|
312
312
|
*
|
|
@@ -355,7 +355,7 @@ export const clientOidcErrorCode = z.enum([
|
|
|
355
355
|
/* ------------------------------------------------ MCP, delegated login -- */
|
|
356
356
|
/**
|
|
357
357
|
* **A pending MCP authorization, as the app's own consent screen reads it**
|
|
358
|
-
*
|
|
358
|
+
* Fleetless renders no page here either: `authorize` redirects to the
|
|
359
359
|
* app's `mcp_login_url` with an interaction id, the app authenticates the user
|
|
360
360
|
* with its normal UI, shows this, and approves or denies through the API.
|
|
361
361
|
*
|
|
@@ -456,7 +456,7 @@ export const mcpConsentGrantListResponse = z.object({
|
|
|
456
456
|
* quietest way for a cut like this to go wrong.
|
|
457
457
|
*
|
|
458
458
|
* **`act` is gone.** It named the org admin behind an impersonation (the RFC
|
|
459
|
-
* 8693 pattern). Impersonation is deleted with no successor
|
|
459
|
+
* 8693 pattern). Impersonation is deleted with no successor, so a field
|
|
460
460
|
* that could still arrive would describe a delegation nothing can mint — and a
|
|
461
461
|
* client rendering "you are acting as …" from it would be showing a state the
|
|
462
462
|
* platform cannot enter.
|
package/dist/common.d.ts
CHANGED
|
@@ -123,8 +123,8 @@ export declare const wireTimestampMs: z.ZodPipe<z.ZodPipe<z.ZodUnion<readonly [z
|
|
|
123
123
|
*
|
|
124
124
|
* Lives here, not in `protocol.ts`, for the same reason `slug` and friends
|
|
125
125
|
* do: `config.ts`'s `configState.applied_errors` is the REST shape the
|
|
126
|
-
* console reads this same error through
|
|
127
|
-
*
|
|
126
|
+
* console reads this same error through, and `protocol.ts` already imports
|
|
127
|
+
* from `config.ts`
|
|
128
128
|
* (`credentialRef`, `robotConfigDoc`) — so `config.ts` importing back from
|
|
129
129
|
* `protocol.ts` would be a cycle. One definition, reachable from both
|
|
130
130
|
* without either importing the other.
|
package/dist/common.js
CHANGED
|
@@ -149,8 +149,8 @@ export const wireTimestampMs = z
|
|
|
149
149
|
*
|
|
150
150
|
* Lives here, not in `protocol.ts`, for the same reason `slug` and friends
|
|
151
151
|
* do: `config.ts`'s `configState.applied_errors` is the REST shape the
|
|
152
|
-
* console reads this same error through
|
|
153
|
-
*
|
|
152
|
+
* console reads this same error through, and `protocol.ts` already imports
|
|
153
|
+
* from `config.ts`
|
|
154
154
|
* (`credentialRef`, `robotConfigDoc`) — so `config.ts` importing back from
|
|
155
155
|
* `protocol.ts` would be a cycle. One definition, reachable from both
|
|
156
156
|
* without either importing the other.
|
package/dist/config-issues.d.ts
CHANGED
|
@@ -4,17 +4,15 @@ import type { ValidationIssue } from './config.js';
|
|
|
4
4
|
/**
|
|
5
5
|
* What is wrong with a configuration document, in one account.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* it has not pinned, so its own copy of `schemaIssues`, `refusal`, `slugOf`,
|
|
17
|
-
* `formatPath` and `valueAt` stood from wave 1, when this module landed here,
|
|
7
|
+
* It lives in contracts because an editor has to say **exactly** what the
|
|
8
|
+
* server says about a document — same codes, same sentences, same paths — and
|
|
9
|
+
* the only way that is true is if it is the same code. An editor that
|
|
10
|
+
* reimplemented this and then disagreed with the server about what is wrong
|
|
11
|
+
* would be worse than one that said nothing.
|
|
12
|
+
*
|
|
13
|
+
* **A second implementation is the thing this module exists to prevent.** A
|
|
14
|
+
* server that cannot import this package keeps its own copy of `schemaIssues`,
|
|
15
|
+
* `refusal`, `slugOf`, `formatPath` and `valueAt`,
|
|
18
16
|
* until that re-pin deleted them and imported these. The window is recorded
|
|
19
17
|
* rather than dropped because it cost a live bug while it was open: the
|
|
20
18
|
* cloud's own `formatPath` wrote a blank path segment as the empty string,
|
|
@@ -42,10 +40,9 @@ export declare const DOCUMENT_ROOT_PATH = "(document)";
|
|
|
42
40
|
* `messages:` is deliberately not among them: its names are their own
|
|
43
41
|
* namespace.
|
|
44
42
|
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* wave 2 task 8 (cloud `a307e18`, 2026-09-03) — this is the only spelling
|
|
43
|
+
* The cloud re-exports this constant and drives its iteration over sections
|
|
44
|
+
* from it; an editor reads it directly. Spelling it out separately in each
|
|
45
|
+
* would be three copies — this is the only spelling
|
|
49
46
|
* since.
|
|
50
47
|
*/
|
|
51
48
|
export declare const EXPOSURE_SECTIONS: readonly ["datapoints", "actions", "services", "publishers", "cameras"];
|
|
@@ -90,10 +87,10 @@ export declare function schemaIssues(value: unknown, issues: readonly SchemaIssu
|
|
|
90
87
|
* width. Rendered bare, such a key produced a path a reader cannot act
|
|
91
88
|
* on — and at the root it produced the empty string, which
|
|
92
89
|
* `validationIssue.path` (`z.string().min(1)`) refuses. That was the cloud
|
|
93
|
-
* publishing a finding that fails
|
|
94
|
-
*
|
|
95
|
-
* issue:
|
|
96
|
-
* nothing, for two characters typed.
|
|
90
|
+
* publishing a finding that fails its own contract for findings, and because a
|
|
91
|
+
* draft that does not parse is stored rather than refused it costs the whole
|
|
92
|
+
* `configDraftResponse`, not one issue: a client's `safeParse` drops the
|
|
93
|
+
* response and hands the editor nothing, for two characters typed.
|
|
97
94
|
*
|
|
98
95
|
* The quoted spelling is the segment's JSON string literal, and that is the
|
|
99
96
|
* whole of the reason for choosing it: JSON's string syntax is a subset of
|
|
@@ -126,9 +123,9 @@ export declare function formatPath(path: readonly PropertyKey[]): string;
|
|
|
126
123
|
*
|
|
127
124
|
* Escaping on the way out was the alternative and was rejected: `path` is a
|
|
128
125
|
* wire field (`validationIssue.path`), it is rendered to developers as-is,
|
|
129
|
-
* and every recorded expectation
|
|
130
|
-
*
|
|
131
|
-
*
|
|
126
|
+
* and every recorded expectation on both sides spells it unescaped. Changing
|
|
127
|
+
* what the server says about every document to make one client-side lookup
|
|
128
|
+
* total is the larger of the two costs.
|
|
132
129
|
*
|
|
133
130
|
* So the property this has, and the one its test asserts, is the narrow one:
|
|
134
131
|
* **a path round-trips when no string segment contains `.` or `[`, and the
|
package/dist/config-issues.js
CHANGED
|
@@ -7,10 +7,9 @@ export const DOCUMENT_ROOT_PATH = '(document)';
|
|
|
7
7
|
* `messages:` is deliberately not among them: its names are their own
|
|
8
8
|
* namespace.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* wave 2 task 8 (cloud `a307e18`, 2026-09-03) — this is the only spelling
|
|
10
|
+
* The cloud re-exports this constant and drives its iteration over sections
|
|
11
|
+
* from it; an editor reads it directly. Spelling it out separately in each
|
|
12
|
+
* would be three copies — this is the only spelling
|
|
14
13
|
* since.
|
|
15
14
|
*/
|
|
16
15
|
export const EXPOSURE_SECTIONS = ['datapoints', 'actions', 'services', 'publishers', 'cameras'];
|
|
@@ -107,10 +106,10 @@ function slugOf(path) {
|
|
|
107
106
|
* width. Rendered bare, such a key produced a path a reader cannot act
|
|
108
107
|
* on — and at the root it produced the empty string, which
|
|
109
108
|
* `validationIssue.path` (`z.string().min(1)`) refuses. That was the cloud
|
|
110
|
-
* publishing a finding that fails
|
|
111
|
-
*
|
|
112
|
-
* issue:
|
|
113
|
-
* nothing, for two characters typed.
|
|
109
|
+
* publishing a finding that fails its own contract for findings, and because a
|
|
110
|
+
* draft that does not parse is stored rather than refused it costs the whole
|
|
111
|
+
* `configDraftResponse`, not one issue: a client's `safeParse` drops the
|
|
112
|
+
* response and hands the editor nothing, for two characters typed.
|
|
114
113
|
*
|
|
115
114
|
* The quoted spelling is the segment's JSON string literal, and that is the
|
|
116
115
|
* whole of the reason for choosing it: JSON's string syntax is a subset of
|
|
@@ -199,9 +198,9 @@ function isBlank(segment) {
|
|
|
199
198
|
*
|
|
200
199
|
* Escaping on the way out was the alternative and was rejected: `path` is a
|
|
201
200
|
* wire field (`validationIssue.path`), it is rendered to developers as-is,
|
|
202
|
-
* and every recorded expectation
|
|
203
|
-
*
|
|
204
|
-
*
|
|
201
|
+
* and every recorded expectation on both sides spells it unescaped. Changing
|
|
202
|
+
* what the server says about every document to make one client-side lookup
|
|
203
|
+
* total is the larger of the two costs.
|
|
205
204
|
*
|
|
206
205
|
* So the property this has, and the one its test asserts, is the narrow one:
|
|
207
206
|
* **a path round-trips when no string segment contains `.` or `[`, and the
|
package/dist/config.d.ts
CHANGED
|
@@ -362,10 +362,9 @@ export declare const messageBody: z.ZodUnknown;
|
|
|
362
362
|
* contract.** This runs inside `publisherConfig`'s failsafe refinement, so a
|
|
363
363
|
* `RangeError: Maximum call stack size exceeded` did not stay here: it
|
|
364
364
|
* propagated out of `safeParse`, which is specified to return a result and
|
|
365
|
-
* not to throw.
|
|
366
|
-
*
|
|
367
|
-
*
|
|
368
|
-
* meant 400.
|
|
365
|
+
* not to throw. A recursive walk survives a few thousand levels of nesting and
|
|
366
|
+
* throws somewhere above that, which a flow-style YAML one-liner reaches in
|
|
367
|
+
* about 120 KB of input — so a draft PUT would answer 500 where it meant 400.
|
|
369
368
|
*
|
|
370
369
|
* `seen` is not an optimisation. YAML anchors can express a cycle
|
|
371
370
|
* (`&a { b: *a }`), and the parser resolves an alias to the same object, so
|
|
@@ -560,9 +559,9 @@ export type CameraSource = z.infer<typeof cameraSource>;
|
|
|
560
559
|
*
|
|
561
560
|
* The bound lives here once, and `rest.ts`'s `cameraDescriptor` reuses it —
|
|
562
561
|
* the same treatment `rateThrottleHz` got, and for the same reason: the
|
|
563
|
-
*
|
|
564
|
-
*
|
|
565
|
-
*
|
|
562
|
+
* two spellings of one interval — milliseconds in a descriptor, seconds in the
|
|
563
|
+
* document — mean a server converting on one and not the other, with nothing in
|
|
564
|
+
* either file saying so.
|
|
566
565
|
*/
|
|
567
566
|
export declare const snapshotIntervalSeconds: z.ZodNumber;
|
|
568
567
|
/**
|