@fleetless/contracts 1.0.0
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 +26 -0
- package/LICENSE +202 -0
- package/NOTICE +17 -0
- package/README.md +88 -0
- package/artifacts/constants.json +24 -0
- package/artifacts/openapi.json +17219 -0
- package/artifacts/routes.json +4605 -0
- package/artifacts/schema/accept-team-invite-request.schema.json +22 -0
- package/artifacts/schema/action-config.schema.json +198 -0
- package/artifacts/schema/alert-list-response.schema.json +172 -0
- package/artifacts/schema/api-error.schema.json +20 -0
- package/artifacts/schema/app-auth-config.schema.json +106 -0
- package/artifacts/schema/app-invitation-list-response.schema.json +57 -0
- package/artifacts/schema/app-invitation.schema.json +69 -0
- package/artifacts/schema/app-list-response.schema.json +82 -0
- package/artifacts/schema/app-mail-template-list-response.schema.json +68 -0
- package/artifacts/schema/app-mail-template.schema.json +54 -0
- package/artifacts/schema/app-oidc-provider-list-response.schema.json +93 -0
- package/artifacts/schema/app-oidc-provider.schema.json +80 -0
- package/artifacts/schema/app-user-list-response.schema.json +111 -0
- package/artifacts/schema/app-user.schema.json +98 -0
- package/artifacts/schema/app.schema.json +69 -0
- package/artifacts/schema/apply-error.schema.json +41 -0
- package/artifacts/schema/asset-list-response.schema.json +288 -0
- package/artifacts/schema/asset-sync-request.schema.json +17 -0
- package/artifacts/schema/asset-sync-response.schema.json +16 -0
- package/artifacts/schema/asset-sync-status.schema.json +136 -0
- package/artifacts/schema/asset.schema.json +68 -0
- package/artifacts/schema/audit-actor.schema.json +32 -0
- package/artifacts/schema/audit-event.schema.json +119 -0
- package/artifacts/schema/audit-list-response.schema.json +144 -0
- package/artifacts/schema/audit-query.schema.json +79 -0
- package/artifacts/schema/auth-error.schema.json +23 -0
- package/artifacts/schema/auth-me-response.schema.json +99 -0
- package/artifacts/schema/auth-ok.schema.json +115 -0
- package/artifacts/schema/authorization-server-metadata.schema.json +80 -0
- package/artifacts/schema/bridge-asset-progress.schema.json +99 -0
- package/artifacts/schema/bridge-assets-available.schema.json +25 -0
- package/artifacts/schema/bridge-camera-state.schema.json +78 -0
- package/artifacts/schema/bridge-config-applied.schema.json +67 -0
- package/artifacts/schema/bridge-hello.schema.json +65 -0
- package/artifacts/schema/bridge-introspect.schema.json +114 -0
- package/artifacts/schema/bridge-job-lost.schema.json +22 -0
- package/artifacts/schema/bridge-job-update.schema.json +100 -0
- package/artifacts/schema/bridge-pong.schema.json +19 -0
- package/artifacts/schema/bridge-pressure.schema.json +292 -0
- package/artifacts/schema/bridge-state.schema.json +24 -0
- package/artifacts/schema/bridge-type-definitions.schema.json +169 -0
- package/artifacts/schema/busy-details.schema.json +115 -0
- package/artifacts/schema/camera-descriptor.schema.json +45 -0
- package/artifacts/schema/camera-list-response.schema.json +58 -0
- package/artifacts/schema/camera-source.schema.json +240 -0
- package/artifacts/schema/cancel-request.schema.json +20 -0
- package/artifacts/schema/client-accept-invitation-request.schema.json +35 -0
- package/artifacts/schema/client-auth.schema.json +18 -0
- package/artifacts/schema/client-cancel.schema.json +45 -0
- package/artifacts/schema/client-identity.schema.json +103 -0
- package/artifacts/schema/client-invoke.schema.json +45 -0
- package/artifacts/schema/client-login-request.schema.json +29 -0
- package/artifacts/schema/client-logout-request.schema.json +14 -0
- package/artifacts/schema/client-mcp-interaction-decision-response.schema.json +15 -0
- package/artifacts/schema/client-mcp-interaction.schema.json +59 -0
- package/artifacts/schema/client-oidc-callback-query.schema.json +28 -0
- package/artifacts/schema/client-oidc-exchange-request.schema.json +21 -0
- package/artifacts/schema/client-oidc-start-query.schema.json +36 -0
- package/artifacts/schema/client-password-reset-confirm-request.schema.json +22 -0
- package/artifacts/schema/client-password-reset-request.schema.json +24 -0
- package/artifacts/schema/client-provider-list-query.schema.json +17 -0
- package/artifacts/schema/client-provider-list-response.schema.json +34 -0
- package/artifacts/schema/client-publish.schema.json +40 -0
- package/artifacts/schema/client-refresh-request.schema.json +14 -0
- package/artifacts/schema/client-register-request.schema.json +44 -0
- package/artifacts/schema/client-resend-verification-request.schema.json +24 -0
- package/artifacts/schema/client-subscribe.schema.json +43 -0
- package/artifacts/schema/client-unsubscribe.schema.json +26 -0
- package/artifacts/schema/client-verify-email-request.schema.json +15 -0
- package/artifacts/schema/cloud-asset-request.schema.json +37 -0
- package/artifacts/schema/cloud-camera-start.schema.json +41 -0
- package/artifacts/schema/cloud-camera-stop.schema.json +26 -0
- package/artifacts/schema/cloud-cancel.schema.json +33 -0
- package/artifacts/schema/cloud-config.schema.json +1635 -0
- package/artifacts/schema/cloud-hello-error.schema.json +23 -0
- package/artifacts/schema/cloud-hello-ok.schema.json +19 -0
- package/artifacts/schema/cloud-introspect-request.schema.json +19 -0
- package/artifacts/schema/cloud-invoke.schema.json +40 -0
- package/artifacts/schema/cloud-ping.schema.json +19 -0
- package/artifacts/schema/cloud-publish.schema.json +28 -0
- package/artifacts/schema/cloud-type-request.schema.json +30 -0
- package/artifacts/schema/command-result.schema.json +175 -0
- package/artifacts/schema/config-draft-response.schema.json +1695 -0
- package/artifacts/schema/config-state.schema.json +124 -0
- package/artifacts/schema/config-version-response.schema.json +1641 -0
- package/artifacts/schema/config-versions-response.schema.json +33 -0
- package/artifacts/schema/create-app-invitation-request.schema.json +40 -0
- package/artifacts/schema/create-app-oidc-provider-request.schema.json +70 -0
- package/artifacts/schema/create-app-request.schema.json +30 -0
- package/artifacts/schema/create-app-user-request.schema.json +42 -0
- package/artifacts/schema/create-robot-request.schema.json +14 -0
- package/artifacts/schema/create-robot-response.schema.json +44 -0
- package/artifacts/schema/create-server-key-response.schema.json +65 -0
- package/artifacts/schema/create-team-invite-request.schema.json +43 -0
- package/artifacts/schema/datapoint-alert-row.schema.json +160 -0
- package/artifacts/schema/datapoint-config.schema.json +366 -0
- package/artifacts/schema/datapoint-display.schema.json +31 -0
- package/artifacts/schema/datapoint-event.schema.json +34 -0
- package/artifacts/schema/datapoint-frame.schema.json +28 -0
- package/artifacts/schema/datapoint-list-response.schema.json +61 -0
- package/artifacts/schema/datapoint-value.schema.json +28 -0
- package/artifacts/schema/developer-login-request.schema.json +19 -0
- package/artifacts/schema/dynamic-client-registration-request.schema.json +60 -0
- package/artifacts/schema/dynamic-client-registration-response.schema.json +68 -0
- package/artifacts/schema/error-frame.schema.json +23 -0
- package/artifacts/schema/exposure-counts.schema.json +39 -0
- package/artifacts/schema/exposure-list-response.schema.json +43 -0
- package/artifacts/schema/fetch-types-request.schema.json +19 -0
- package/artifacts/schema/fetch-types-response.schema.json +163 -0
- package/artifacts/schema/fleetless-user-list-response.schema.json +73 -0
- package/artifacts/schema/fleetless-user.schema.json +60 -0
- package/artifacts/schema/history-buckets-response.schema.json +79 -0
- package/artifacts/schema/history-query.schema.json +58 -0
- package/artifacts/schema/history-response.schema.json +150 -0
- package/artifacts/schema/history-samples-response.schema.json +68 -0
- package/artifacts/schema/introspection-response.schema.json +118 -0
- package/artifacts/schema/invoke-or-service-response.schema.json +141 -0
- package/artifacts/schema/invoke-request.schema.json +23 -0
- package/artifacts/schema/invoke-response.schema.json +125 -0
- package/artifacts/schema/job-actor.schema.json +34 -0
- package/artifacts/schema/job-event.schema.json +158 -0
- package/artifacts/schema/job-response.schema.json +123 -0
- package/artifacts/schema/job-run-list-response.schema.json +222 -0
- package/artifacts/schema/job-run-query.schema.json +95 -0
- package/artifacts/schema/job-run-summary-query.schema.json +23 -0
- package/artifacts/schema/job-run-summary.schema.json +33 -0
- package/artifacts/schema/job-run.schema.json +195 -0
- package/artifacts/schema/job-state.schema.json +11 -0
- package/artifacts/schema/job.schema.json +106 -0
- package/artifacts/schema/latency-bucket.schema.json +63 -0
- package/artifacts/schema/live-session-response.schema.json +41 -0
- package/artifacts/schema/mail-outcome.schema.json +20 -0
- package/artifacts/schema/mail-template-preview-request.schema.json +35 -0
- package/artifacts/schema/mail-template-preview-response.schema.json +31 -0
- package/artifacts/schema/mail-template-problem-details.schema.json +24 -0
- package/artifacts/schema/mcp-consent-grant-list-response.schema.json +52 -0
- package/artifacts/schema/mcp-consent-grant.schema.json +39 -0
- package/artifacts/schema/mcp-robot-datasheet.schema.json +115 -0
- package/artifacts/schema/mcp-role-preview-response.schema.json +134 -0
- package/artifacts/schema/missing-asset-query.schema.json +11 -0
- package/artifacts/schema/oauth-authorize-query.schema.json +47 -0
- package/artifacts/schema/oauth-redirect-response.schema.json +15 -0
- package/artifacts/schema/oauth-token-request.schema.json +47 -0
- package/artifacts/schema/oauth-token-response.schema.json +38 -0
- package/artifacts/schema/org-alerts-query.schema.json +15 -0
- package/artifacts/schema/org-event-dropped.schema.json +26 -0
- package/artifacts/schema/org-event-replay.schema.json +97 -0
- package/artifacts/schema/org-event-subscribe.schema.json +14 -0
- package/artifacts/schema/org-event-unsubscribe.schema.json +14 -0
- package/artifacts/schema/org-event.schema.json +75 -0
- package/artifacts/schema/org-firing-alerts-response.schema.json +178 -0
- package/artifacts/schema/org-health-query.schema.json +13 -0
- package/artifacts/schema/org-latency-query.schema.json +42 -0
- package/artifacts/schema/org-latency-response.schema.json +124 -0
- package/artifacts/schema/org-quota-usage-counts.schema.json +42 -0
- package/artifacts/schema/org-quota-usage.schema.json +102 -0
- package/artifacts/schema/org-quotas.schema.json +51 -0
- package/artifacts/schema/org-usage-query.schema.json +19 -0
- package/artifacts/schema/org-usage-response.schema.json +77 -0
- package/artifacts/schema/org.schema.json +30 -0
- package/artifacts/schema/parameter-invalid-details.schema.json +37 -0
- package/artifacts/schema/parameter-spec.schema.json +120 -0
- package/artifacts/schema/parameter-violation.schema.json +24 -0
- package/artifacts/schema/password-change-request.schema.json +21 -0
- package/artifacts/schema/password-reset-confirm.schema.json +19 -0
- package/artifacts/schema/password-reset-request.schema.json +14 -0
- package/artifacts/schema/patch-app-oidc-provider-request.schema.json +50 -0
- package/artifacts/schema/patch-app-user-request.schema.json +34 -0
- package/artifacts/schema/patch-auth-me-request.schema.json +22 -0
- package/artifacts/schema/patch-fleetless-user-request.schema.json +20 -0
- package/artifacts/schema/patch-org-request.schema.json +15 -0
- package/artifacts/schema/patch-org-response.schema.json +40 -0
- package/artifacts/schema/patch-robot-request.schema.json +15 -0
- package/artifacts/schema/patch-robot-response.schema.json +40 -0
- package/artifacts/schema/pending-team-invite-list-response.schema.json +52 -0
- package/artifacts/schema/pending-team-invite.schema.json +39 -0
- package/artifacts/schema/protected-resource-metadata.schema.json +41 -0
- package/artifacts/schema/publish-config-response.schema.json +21 -0
- package/artifacts/schema/publish-request.schema.json +17 -0
- package/artifacts/schema/publisher-config.schema.json +285 -0
- package/artifacts/schema/put-app-auth-config-request.schema.json +93 -0
- package/artifacts/schema/put-app-mail-template-request.schema.json +35 -0
- package/artifacts/schema/put-config-draft-request.schema.json +13 -0
- package/artifacts/schema/put-datapoint-display-request.schema.json +31 -0
- package/artifacts/schema/put-robot-details-request.schema.json +41 -0
- package/artifacts/schema/put-robot-details-response.schema.json +43 -0
- package/artifacts/schema/rate-limit-details.schema.json +15 -0
- package/artifacts/schema/refresh-request.schema.json +13 -0
- package/artifacts/schema/release-live-query.schema.json +13 -0
- package/artifacts/schema/rename-slug-request.schema.json +23 -0
- package/artifacts/schema/rename-slug-response.schema.json +24 -0
- package/artifacts/schema/resource-health-event.schema.json +72 -0
- package/artifacts/schema/resource-health-list-response.schema.json +80 -0
- package/artifacts/schema/resource-health-state.schema.json +68 -0
- package/artifacts/schema/robot-config-doc.schema.json +1616 -0
- package/artifacts/schema/robot-delete-query.schema.json +12 -0
- package/artifacts/schema/robot-deletion-summary.schema.json +63 -0
- package/artifacts/schema/robot-detail-response.schema.json +262 -0
- package/artifacts/schema/robot-details-doc.schema.json +33 -0
- package/artifacts/schema/robot-jobs-response.schema.json +119 -0
- package/artifacts/schema/robot-latency-series.schema.json +81 -0
- package/artifacts/schema/robot-list-item.schema.json +94 -0
- package/artifacts/schema/robot-list-response.schema.json +106 -0
- package/artifacts/schema/robot.schema.json +30 -0
- package/artifacts/schema/role-list-response.schema.json +48 -0
- package/artifacts/schema/role-permissions.schema.json +61 -0
- package/artifacts/schema/role.schema.json +35 -0
- package/artifacts/schema/ros-graph.schema.json +99 -0
- package/artifacts/schema/server-key-list-response.schema.json +64 -0
- package/artifacts/schema/server-key.schema.json +51 -0
- package/artifacts/schema/service-call-response.schema.json +13 -0
- package/artifacts/schema/service-config.schema.json +198 -0
- package/artifacts/schema/session-tokens.schema.json +28 -0
- package/artifacts/schema/sign-up-request.schema.json +26 -0
- package/artifacts/schema/sign-up-response.schema.json +127 -0
- package/artifacts/schema/slug-usage-response.schema.json +32 -0
- package/artifacts/schema/snapshot-header.schema.json +44 -0
- package/artifacts/schema/snapshot-meta-response.schema.json +85 -0
- package/artifacts/schema/subscribe-error.schema.json +31 -0
- package/artifacts/schema/team-invite.schema.json +57 -0
- package/artifacts/schema/tier-change-request.schema.json +17 -0
- package/artifacts/schema/type-definition.schema.json +144 -0
- package/artifacts/schema/types-response.schema.json +156 -0
- package/artifacts/schema/update-app-request.schema.json +32 -0
- package/artifacts/schema/urdf-completeness.schema.json +50 -0
- package/artifacts/schema/validation-issue.schema.json +43 -0
- package/artifacts/schema/waitlist-request.schema.json +15 -0
- package/artifacts/schema-outgoing/bridge-asset-progress.schema.json +102 -0
- package/artifacts/schema-outgoing/bridge-assets-available.schema.json +26 -0
- package/artifacts/schema-outgoing/bridge-camera-state.schema.json +80 -0
- package/artifacts/schema-outgoing/bridge-config-applied.schema.json +69 -0
- package/artifacts/schema-outgoing/bridge-hello.schema.json +68 -0
- package/artifacts/schema-outgoing/bridge-introspect.schema.json +119 -0
- package/artifacts/schema-outgoing/bridge-job-lost.schema.json +23 -0
- package/artifacts/schema-outgoing/bridge-job-update.schema.json +102 -0
- package/artifacts/schema-outgoing/bridge-pong.schema.json +20 -0
- package/artifacts/schema-outgoing/bridge-type-definitions.schema.json +174 -0
- package/artifacts/schema-outgoing/datapoint-frame.schema.json +29 -0
- package/artifacts/schema-outgoing/snapshot-header.schema.json +45 -0
- package/dist/alerts.d.ts +255 -0
- package/dist/alerts.js +193 -0
- package/dist/app-users.d.ts +606 -0
- package/dist/app-users.js +696 -0
- package/dist/apps.d.ts +175 -0
- package/dist/apps.js +267 -0
- package/dist/assets.d.ts +434 -0
- package/dist/assets.js +546 -0
- package/dist/audit.d.ts +129 -0
- package/dist/audit.js +238 -0
- package/dist/client-auth.d.ts +409 -0
- package/dist/client-auth.js +487 -0
- package/dist/common.d.ts +186 -0
- package/dist/common.js +199 -0
- package/dist/config-issues.d.ts +175 -0
- package/dist/config-issues.js +339 -0
- package/dist/config.d.ts +862 -0
- package/dist/config.js +1988 -0
- package/dist/errors.d.ts +52 -0
- package/dist/errors.js +786 -0
- package/dist/identity.d.ts +549 -0
- package/dist/identity.js +503 -0
- package/dist/index.d.ts +51 -0
- package/dist/index.js +51 -0
- package/dist/introspection.d.ts +99 -0
- package/dist/introspection.js +97 -0
- package/dist/jobs.d.ts +334 -0
- package/dist/jobs.js +345 -0
- package/dist/mcp.d.ts +239 -0
- package/dist/mcp.js +153 -0
- package/dist/oauth.d.ts +344 -0
- package/dist/oauth.js +488 -0
- package/dist/protocol.d.ts +781 -0
- package/dist/protocol.js +715 -0
- package/dist/realtime.d.ts +494 -0
- package/dist/realtime.js +512 -0
- package/dist/rest.d.ts +1989 -0
- package/dist/rest.js +1963 -0
- package/dist/routes.d.ts +94 -0
- package/dist/routes.js +2298 -0
- package/package.json +61 -0
package/dist/apps.d.ts
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Apps, roles and rights (spec §3.2, §3.3, §12.2).
|
|
4
|
+
*
|
|
5
|
+
* The rule that shapes all of this: **roles are the only filter**. A robot
|
|
6
|
+
* assigned to an app exposes every one of its services to that app; what a
|
|
7
|
+
* role does not grant simply does not exist for that user. There is no second
|
|
8
|
+
* visibility mechanism, and adding one later would create two places to look
|
|
9
|
+
* when someone cannot see something.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* The app identifier a client sends at login. Same rule as a service slug:
|
|
13
|
+
* stable, lowercase, underscore-separated.
|
|
14
|
+
*
|
|
15
|
+
* **Globally unique, not per org.** `clientLoginRequest` carries only the
|
|
16
|
+
* identifier, the email and the password — there is no org context to
|
|
17
|
+
* disambiguate with, so a per-org identifier could not be resolved at login
|
|
18
|
+
* at all. A collision is refused with `identifier_taken`.
|
|
19
|
+
*/
|
|
20
|
+
export declare const appIdentifier: z.ZodString;
|
|
21
|
+
export declare const app: z.ZodObject<{
|
|
22
|
+
id: z.ZodUUID;
|
|
23
|
+
org_id: z.ZodUUID;
|
|
24
|
+
name: z.ZodString;
|
|
25
|
+
identifier: z.ZodString;
|
|
26
|
+
robot_ids: z.ZodArray<z.ZodUUID>;
|
|
27
|
+
default_role_id: z.ZodNullable<z.ZodUUID>;
|
|
28
|
+
created_at: z.ZodISODateTime;
|
|
29
|
+
}, z.core.$strip>;
|
|
30
|
+
export type App = z.infer<typeof app>;
|
|
31
|
+
/** What `GET /api/apps` answers: every app in the caller's org, in one envelope. */
|
|
32
|
+
export declare const appListResponse: z.ZodObject<{
|
|
33
|
+
apps: z.ZodArray<z.ZodObject<{
|
|
34
|
+
id: z.ZodUUID;
|
|
35
|
+
org_id: z.ZodUUID;
|
|
36
|
+
name: z.ZodString;
|
|
37
|
+
identifier: z.ZodString;
|
|
38
|
+
robot_ids: z.ZodArray<z.ZodUUID>;
|
|
39
|
+
default_role_id: z.ZodNullable<z.ZodUUID>;
|
|
40
|
+
created_at: z.ZodISODateTime;
|
|
41
|
+
}, z.core.$strip>>;
|
|
42
|
+
}, z.core.$strip>;
|
|
43
|
+
export type AppListResponse = z.infer<typeof appListResponse>;
|
|
44
|
+
/**
|
|
45
|
+
* **`robot_ids` is accepted here, and `.strict()` catches everything else
|
|
46
|
+
* (W7a).** Through W7 this shape carried `name` and `identifier` only, robots
|
|
47
|
+
* attached through `updateAppRequest`, and zod stripped the extra key — so a
|
|
48
|
+
* caller creating an app *with* robots got a `201` and an app with none.
|
|
49
|
+
* **Two people fell into it independently on the same day**, which is the
|
|
50
|
+
* definition of a shape that reads as though it does something it does not.
|
|
51
|
+
*
|
|
52
|
+
* Both halves matter and neither alone is enough. Accepting `robot_ids` is
|
|
53
|
+
* right because attaching robots at creation is the obvious operation and the
|
|
54
|
+
* store already does the work for `PATCH`; refusing unknown keys is right
|
|
55
|
+
* because the next field somebody assumes into existence should produce a
|
|
56
|
+
* `400` naming it rather than a silence. Same reasoning as `cancelRequest`
|
|
57
|
+
* and `releaseLiveQuery`: a request shape that strips is a request shape that
|
|
58
|
+
* lies quietly.
|
|
59
|
+
*
|
|
60
|
+
* Optional rather than required — an app with no robots is a normal thing to
|
|
61
|
+
* create, and a required empty array would be ceremony.
|
|
62
|
+
*/
|
|
63
|
+
export declare const createAppRequest: z.ZodObject<{
|
|
64
|
+
name: z.ZodString;
|
|
65
|
+
identifier: z.ZodString;
|
|
66
|
+
robot_ids: z.ZodOptional<z.ZodArray<z.ZodUUID>>;
|
|
67
|
+
}, z.core.$strict>;
|
|
68
|
+
export type CreateAppRequest = z.infer<typeof createAppRequest>;
|
|
69
|
+
/**
|
|
70
|
+
* **`.strict()` is what makes an absent field mean something here.**
|
|
71
|
+
*
|
|
72
|
+
* This shape was not strict until 2026-08-29, which meant an offered field the
|
|
73
|
+
* route does not implement was *dropped* — the caller got a `200`, nothing
|
|
74
|
+
* changed, and nothing anywhere said so. That is the exact silence
|
|
75
|
+
* `createAppRequest` above already learned about in W7a (*"a create shape that
|
|
76
|
+
* silently drops a field cost two people a day each"*), and the lesson had not
|
|
77
|
+
* been carried one shape over. A caller who sends a field this route does not
|
|
78
|
+
* do is asking for something, and the honest answer is `400`, not a success
|
|
79
|
+
* that means less than it looks.
|
|
80
|
+
*
|
|
81
|
+
* Two fields left with the two-space cut and are worth naming, because both
|
|
82
|
+
* were on this shape and neither has a successor here.
|
|
83
|
+
* `accepts_dynamic_clients` gated app-level OAuth dynamic client registration,
|
|
84
|
+
* which is deleted: apps use the JSON client-auth API and OAuth 2.1 remains
|
|
85
|
+
* only for MCP. `group_id` named the group that owned the app, and groups are
|
|
86
|
+
* gone; who may log into an app is now the app's own user list.
|
|
87
|
+
*
|
|
88
|
+
* The route keeps its own check as belt-and-braces; a schema and a handler
|
|
89
|
+
* agreeing is not two policies, it is one policy stated where each half can
|
|
90
|
+
* enforce it.
|
|
91
|
+
*/
|
|
92
|
+
export declare const updateAppRequest: z.ZodObject<{
|
|
93
|
+
name: z.ZodOptional<z.ZodString>;
|
|
94
|
+
robot_ids: z.ZodOptional<z.ZodArray<z.ZodUUID>>;
|
|
95
|
+
default_role_id: z.ZodOptional<z.ZodNullable<z.ZodUUID>>;
|
|
96
|
+
}, z.core.$strict>;
|
|
97
|
+
export type UpdateAppRequest = z.infer<typeof updateAppRequest>;
|
|
98
|
+
/**
|
|
99
|
+
* A server key carries full app rights for server-side code (spec §3.4) —
|
|
100
|
+
* never for clients. Same handling as the robot token from W1: the value is
|
|
101
|
+
* returned exactly once and only its hash is stored.
|
|
102
|
+
*/
|
|
103
|
+
export declare const serverKeyToken: z.ZodString;
|
|
104
|
+
export declare const serverKey: z.ZodObject<{
|
|
105
|
+
id: z.ZodUUID;
|
|
106
|
+
app_id: z.ZodUUID;
|
|
107
|
+
name: z.ZodString;
|
|
108
|
+
created_at: z.ZodISODateTime;
|
|
109
|
+
last_used_at: z.ZodNullable<z.ZodISODateTime>;
|
|
110
|
+
}, z.core.$strip>;
|
|
111
|
+
export type ServerKey = z.infer<typeof serverKey>;
|
|
112
|
+
/** What `GET /api/apps/:id/server-keys` answers — metadata only; the raw secret exists once, in `createServerKeyResponse`, and never here. */
|
|
113
|
+
export declare const serverKeyListResponse: z.ZodObject<{
|
|
114
|
+
server_keys: z.ZodArray<z.ZodObject<{
|
|
115
|
+
id: z.ZodUUID;
|
|
116
|
+
app_id: z.ZodUUID;
|
|
117
|
+
name: z.ZodString;
|
|
118
|
+
created_at: z.ZodISODateTime;
|
|
119
|
+
last_used_at: z.ZodNullable<z.ZodISODateTime>;
|
|
120
|
+
}, z.core.$strip>>;
|
|
121
|
+
}, z.core.$strip>;
|
|
122
|
+
export type ServerKeyListResponse = z.infer<typeof serverKeyListResponse>;
|
|
123
|
+
export declare const createServerKeyResponse: z.ZodObject<{
|
|
124
|
+
server_key: z.ZodObject<{
|
|
125
|
+
id: z.ZodUUID;
|
|
126
|
+
app_id: z.ZodUUID;
|
|
127
|
+
name: z.ZodString;
|
|
128
|
+
created_at: z.ZodISODateTime;
|
|
129
|
+
last_used_at: z.ZodNullable<z.ZodISODateTime>;
|
|
130
|
+
}, z.core.$strip>;
|
|
131
|
+
key: z.ZodString;
|
|
132
|
+
}, z.core.$strip>;
|
|
133
|
+
export type CreateServerKeyResponse = z.infer<typeof createServerKeyResponse>;
|
|
134
|
+
/**
|
|
135
|
+
* Every app starts with `observe` and `operate`; custom roles are allowed
|
|
136
|
+
* from v1 (§3.3). `builtin` marks the two starting roles — they may be
|
|
137
|
+
* edited like any other, the flag exists so the console can explain where
|
|
138
|
+
* they came from.
|
|
139
|
+
*/
|
|
140
|
+
export declare const role: z.ZodObject<{
|
|
141
|
+
id: z.ZodUUID;
|
|
142
|
+
app_id: z.ZodUUID;
|
|
143
|
+
name: z.ZodString;
|
|
144
|
+
builtin: z.ZodBoolean;
|
|
145
|
+
}, z.core.$strip>;
|
|
146
|
+
export type Role = z.infer<typeof role>;
|
|
147
|
+
/** What `GET /api/apps/:id/roles` answers: the app's roles, builtin and custom alike. */
|
|
148
|
+
export declare const roleListResponse: z.ZodObject<{
|
|
149
|
+
roles: z.ZodArray<z.ZodObject<{
|
|
150
|
+
id: z.ZodUUID;
|
|
151
|
+
app_id: z.ZodUUID;
|
|
152
|
+
name: z.ZodString;
|
|
153
|
+
builtin: z.ZodBoolean;
|
|
154
|
+
}, z.core.$strip>>;
|
|
155
|
+
}, z.core.$strip>;
|
|
156
|
+
export type RoleListResponse = z.infer<typeof roleListResponse>;
|
|
157
|
+
/**
|
|
158
|
+
* The rights matrix of one role: which slugs of which robot it may use, plus
|
|
159
|
+
* the capabilities roles also govern (§3.3). `capabilities`' own doc comment
|
|
160
|
+
* below says which of them are enforced today and which is still a switch
|
|
161
|
+
* that changes nothing.
|
|
162
|
+
*/
|
|
163
|
+
export declare const rolePermissions: z.ZodObject<{
|
|
164
|
+
role_id: z.ZodUUID;
|
|
165
|
+
grants: z.ZodArray<z.ZodObject<{
|
|
166
|
+
robot_id: z.ZodUUID;
|
|
167
|
+
slugs: z.ZodArray<z.ZodString>;
|
|
168
|
+
}, z.core.$strip>>;
|
|
169
|
+
capabilities: z.ZodObject<{
|
|
170
|
+
action_history: z.ZodBoolean;
|
|
171
|
+
presence: z.ZodBoolean;
|
|
172
|
+
assets: z.ZodBoolean;
|
|
173
|
+
}, z.core.$strip>;
|
|
174
|
+
}, z.core.$strip>;
|
|
175
|
+
export type RolePermissions = z.infer<typeof rolePermissions>;
|
package/dist/apps.js
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { slug } from './common.js';
|
|
4
|
+
/**
|
|
5
|
+
* Apps, roles and rights (spec §3.2, §3.3, §12.2).
|
|
6
|
+
*
|
|
7
|
+
* The rule that shapes all of this: **roles are the only filter**. A robot
|
|
8
|
+
* assigned to an app exposes every one of its services to that app; what a
|
|
9
|
+
* role does not grant simply does not exist for that user. There is no second
|
|
10
|
+
* visibility mechanism, and adding one later would create two places to look
|
|
11
|
+
* when someone cannot see something.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* The app identifier a client sends at login. Same rule as a service slug:
|
|
15
|
+
* stable, lowercase, underscore-separated.
|
|
16
|
+
*
|
|
17
|
+
* **Globally unique, not per org.** `clientLoginRequest` carries only the
|
|
18
|
+
* identifier, the email and the password — there is no org context to
|
|
19
|
+
* disambiguate with, so a per-org identifier could not be resolved at login
|
|
20
|
+
* at all. A collision is refused with `identifier_taken`.
|
|
21
|
+
*/
|
|
22
|
+
export const appIdentifier = slug;
|
|
23
|
+
export const app = z.object({
|
|
24
|
+
id: z.uuid().meta({
|
|
25
|
+
description: 'The app in the API, assigned by the cloud and stable for the life of the app. Everything app-scoped takes this as its `:id`.',
|
|
26
|
+
}),
|
|
27
|
+
org_id: z.uuid().meta({
|
|
28
|
+
description: 'The organisation that owns this app. Every developer route is already scoped to the caller\'s org, so this confirms what a client is looking at rather than being a filter it applies.',
|
|
29
|
+
}),
|
|
30
|
+
name: z.string().min(1).max(120).meta({
|
|
31
|
+
description: 'The display name, shown in the console and available to the developer\'s own pages through the `app.name` mail-template variable. Free text, changed through `PATCH /api/apps/:id`.',
|
|
32
|
+
}),
|
|
33
|
+
identifier: appIdentifier.meta({
|
|
34
|
+
description: 'The stable handle a client sends at login, lowercase and underscore-separated. **Globally unique, not per organisation** — `clientLoginRequest` carries no org context to disambiguate with, so a collision is refused with `identifier_taken`.',
|
|
35
|
+
}),
|
|
36
|
+
/** Robots are referenced individually; tags never grant rights (§12.2). */
|
|
37
|
+
robot_ids: z.array(z.uuid()).meta({
|
|
38
|
+
description: 'The robots this app may reach, each referenced individually. Tags never grant rights, and a robot absent from this list is invisible to the app whatever a role grants.',
|
|
39
|
+
}),
|
|
40
|
+
/**
|
|
41
|
+
* **The app's default role — and the two-space cut gave it a server-side
|
|
42
|
+
* reader it did not have.**
|
|
43
|
+
*
|
|
44
|
+
* Through the assignment model this was a console prefill and nothing more:
|
|
45
|
+
* `putAssignmentRequest` always carried the role explicitly, so no part of
|
|
46
|
+
* the cloud authorized anybody with it. Assignments are gone. An app user is
|
|
47
|
+
* created or invited **with** a role, and when the request omits one this is
|
|
48
|
+
* the role they get — so the field now decides access on two write paths
|
|
49
|
+
* (`createAppUserRequest`, `createAppInvitationRequest`) rather than
|
|
50
|
+
* pre-filling a form.
|
|
51
|
+
*
|
|
52
|
+
* That is worth saying out loud because it changes what a wrong value costs.
|
|
53
|
+
* A prefill somebody can see and correct became a default applied on the
|
|
54
|
+
* server, and the obvious next question — should it be required instead? —
|
|
55
|
+
* has a deliberate answer: no, because an invitation resolves the role at
|
|
56
|
+
* *creation* time and stores it, so an outstanding invitation is never
|
|
57
|
+
* re-aimed by a later change here.
|
|
58
|
+
*
|
|
59
|
+
* `null` — and nullable rather than absent — means *this app has not chosen
|
|
60
|
+
* one*. That is a normal state, not an unset field: every app is created
|
|
61
|
+
* before its roles are configured. A create or invite that omits `role_id`
|
|
62
|
+
* against an app in that state is a `validation_error`, not a user with no
|
|
63
|
+
* role.
|
|
64
|
+
*
|
|
65
|
+
* The role must belong to **this** app; the schema sees a uuid and cannot
|
|
66
|
+
* check that, so `PATCH /api/apps/:id` does.
|
|
67
|
+
*/
|
|
68
|
+
default_role_id: z.uuid().nullable().meta({
|
|
69
|
+
description: 'The role an app user gets when they are created or invited without an explicit one. `null` means this app has not chosen a default, the normal state of an app created before its roles were configured — and then a create or invite that omits `role_id` is a `validation_error` rather than a user with no role. An invitation resolves the role when it is issued, so changing this never re-aims an outstanding one. The role must belong to this app, which `PATCH /api/apps/:id` checks and the schema cannot.',
|
|
70
|
+
}),
|
|
71
|
+
created_at: z.iso.datetime().meta({
|
|
72
|
+
description: 'When the app was created, as an ISO 8601 timestamp. `GET /api/apps` orders by this field.',
|
|
73
|
+
}),
|
|
74
|
+
});
|
|
75
|
+
/** What `GET /api/apps` answers: every app in the caller's org, in one envelope. */
|
|
76
|
+
export const appListResponse = z.object({
|
|
77
|
+
apps: z.array(app).meta({
|
|
78
|
+
description: 'Every app of the caller\'s organisation, oldest first by `created_at`. The org scope is the whole filter — there is no id to narrow by and nothing to refuse.',
|
|
79
|
+
}),
|
|
80
|
+
});
|
|
81
|
+
/**
|
|
82
|
+
* **`robot_ids` is accepted here, and `.strict()` catches everything else
|
|
83
|
+
* (W7a).** Through W7 this shape carried `name` and `identifier` only, robots
|
|
84
|
+
* attached through `updateAppRequest`, and zod stripped the extra key — so a
|
|
85
|
+
* caller creating an app *with* robots got a `201` and an app with none.
|
|
86
|
+
* **Two people fell into it independently on the same day**, which is the
|
|
87
|
+
* definition of a shape that reads as though it does something it does not.
|
|
88
|
+
*
|
|
89
|
+
* Both halves matter and neither alone is enough. Accepting `robot_ids` is
|
|
90
|
+
* right because attaching robots at creation is the obvious operation and the
|
|
91
|
+
* store already does the work for `PATCH`; refusing unknown keys is right
|
|
92
|
+
* because the next field somebody assumes into existence should produce a
|
|
93
|
+
* `400` naming it rather than a silence. Same reasoning as `cancelRequest`
|
|
94
|
+
* and `releaseLiveQuery`: a request shape that strips is a request shape that
|
|
95
|
+
* lies quietly.
|
|
96
|
+
*
|
|
97
|
+
* Optional rather than required — an app with no robots is a normal thing to
|
|
98
|
+
* create, and a required empty array would be ceremony.
|
|
99
|
+
*/
|
|
100
|
+
export const createAppRequest = z.object({
|
|
101
|
+
name: z.string().min(1).max(120),
|
|
102
|
+
identifier: appIdentifier,
|
|
103
|
+
robot_ids: z.array(z.uuid()).optional(),
|
|
104
|
+
}).strict();
|
|
105
|
+
/**
|
|
106
|
+
* **`.strict()` is what makes an absent field mean something here.**
|
|
107
|
+
*
|
|
108
|
+
* This shape was not strict until 2026-08-29, which meant an offered field the
|
|
109
|
+
* route does not implement was *dropped* — the caller got a `200`, nothing
|
|
110
|
+
* changed, and nothing anywhere said so. That is the exact silence
|
|
111
|
+
* `createAppRequest` above already learned about in W7a (*"a create shape that
|
|
112
|
+
* silently drops a field cost two people a day each"*), and the lesson had not
|
|
113
|
+
* been carried one shape over. A caller who sends a field this route does not
|
|
114
|
+
* do is asking for something, and the honest answer is `400`, not a success
|
|
115
|
+
* that means less than it looks.
|
|
116
|
+
*
|
|
117
|
+
* Two fields left with the two-space cut and are worth naming, because both
|
|
118
|
+
* were on this shape and neither has a successor here.
|
|
119
|
+
* `accepts_dynamic_clients` gated app-level OAuth dynamic client registration,
|
|
120
|
+
* which is deleted: apps use the JSON client-auth API and OAuth 2.1 remains
|
|
121
|
+
* only for MCP. `group_id` named the group that owned the app, and groups are
|
|
122
|
+
* gone; who may log into an app is now the app's own user list.
|
|
123
|
+
*
|
|
124
|
+
* The route keeps its own check as belt-and-braces; a schema and a handler
|
|
125
|
+
* agreeing is not two policies, it is one policy stated where each half can
|
|
126
|
+
* enforce it.
|
|
127
|
+
*/
|
|
128
|
+
export const updateAppRequest = z.object({
|
|
129
|
+
name: z.string().min(1).max(120).optional(),
|
|
130
|
+
robot_ids: z.array(z.uuid()).optional(),
|
|
131
|
+
/**
|
|
132
|
+
* `app.default_role_id`'s write half — an app *setting*, which is where D1
|
|
133
|
+
* put the default role, so it belongs on the app's own PATCH and not on a
|
|
134
|
+
* route of its own.
|
|
135
|
+
*
|
|
136
|
+
* **`.nullable().optional()`, and the two mean different things.** Absent
|
|
137
|
+
* leaves the current default alone; an explicit `null` clears it. A field
|
|
138
|
+
* that could only be set and never unset would make "we changed our mind"
|
|
139
|
+
* unreachable through the API — the same silence `.strict()` above exists to
|
|
140
|
+
* avoid, from the other direction.
|
|
141
|
+
*/
|
|
142
|
+
default_role_id: z.uuid().nullable().optional(),
|
|
143
|
+
}).strict();
|
|
144
|
+
/**
|
|
145
|
+
* A server key carries full app rights for server-side code (spec §3.4) —
|
|
146
|
+
* never for clients. Same handling as the robot token from W1: the value is
|
|
147
|
+
* returned exactly once and only its hash is stored.
|
|
148
|
+
*/
|
|
149
|
+
export const serverKeyToken = z.string().regex(/^flk_[0-9a-f]{32}$/);
|
|
150
|
+
export const serverKey = z.object({
|
|
151
|
+
id: z.uuid().meta({
|
|
152
|
+
description: 'The key row, and what the rotate and delete routes address. It is not the key: the secret itself is never carried by this shape.',
|
|
153
|
+
}),
|
|
154
|
+
app_id: z.uuid().meta({
|
|
155
|
+
description: 'The app whose full rights this key carries. A key is never shared between apps.',
|
|
156
|
+
}),
|
|
157
|
+
name: z.string().min(1).max(120).meta({
|
|
158
|
+
description: 'A label the developer chose, so a key can be recognised before it is rotated or deleted.',
|
|
159
|
+
}),
|
|
160
|
+
created_at: z.iso.datetime().meta({
|
|
161
|
+
description: 'When the key was minted, as an ISO 8601 timestamp. `GET /api/apps/:id/server-keys` orders by this field.',
|
|
162
|
+
}),
|
|
163
|
+
/** Null until first use — the cheapest way to spot a key nobody needs. */
|
|
164
|
+
last_used_at: z.iso.datetime().nullable().meta({
|
|
165
|
+
description: 'When this key last authenticated a request, or `null` if it never has — the cheapest way to spot a key nobody needs.',
|
|
166
|
+
}),
|
|
167
|
+
});
|
|
168
|
+
/** What `GET /api/apps/:id/server-keys` answers — metadata only; the raw secret exists once, in `createServerKeyResponse`, and never here. */
|
|
169
|
+
export const serverKeyListResponse = z.object({
|
|
170
|
+
server_keys: z.array(serverKey).meta({
|
|
171
|
+
description: 'The app\'s server keys as metadata, oldest first by `created_at`. The raw secret is not here and never will be: it exists once, in the answer to the request that created or rotated the key.',
|
|
172
|
+
}),
|
|
173
|
+
});
|
|
174
|
+
export const createServerKeyResponse = z.object({
|
|
175
|
+
server_key: serverKey,
|
|
176
|
+
key: serverKeyToken,
|
|
177
|
+
});
|
|
178
|
+
/**
|
|
179
|
+
* Every app starts with `observe` and `operate`; custom roles are allowed
|
|
180
|
+
* from v1 (§3.3). `builtin` marks the two starting roles — they may be
|
|
181
|
+
* edited like any other, the flag exists so the console can explain where
|
|
182
|
+
* they came from.
|
|
183
|
+
*/
|
|
184
|
+
export const role = z.object({
|
|
185
|
+
id: z.uuid().meta({
|
|
186
|
+
description: 'The role, and what an app user\'s `role_id` and an app\'s `default_role_id` refer to.',
|
|
187
|
+
}),
|
|
188
|
+
app_id: z.uuid().meta({
|
|
189
|
+
description: 'The app this role belongs to. Roles are never shared between apps, so a role id from another app reads as `not_found`.',
|
|
190
|
+
}),
|
|
191
|
+
name: z.string().min(1).max(60).meta({
|
|
192
|
+
description: 'The role\'s name, shown wherever a user\'s access is chosen. The two roles every app starts with are named `observe` and `operate`.',
|
|
193
|
+
}),
|
|
194
|
+
builtin: z.boolean().meta({
|
|
195
|
+
description: '`true` for the two roles every app starts with. Their **rights may be re-scoped** exactly like a custom role\'s, through `PUT /api/apps/:id/roles/:roleId/permissions` — the flag exists so the console can explain where they came from, not to protect them. It does not make them renamable or deletable, because no route renames or deletes any role.',
|
|
196
|
+
}),
|
|
197
|
+
});
|
|
198
|
+
/** What `GET /api/apps/:id/roles` answers: the app's roles, builtin and custom alike. */
|
|
199
|
+
export const roleListResponse = z.object({
|
|
200
|
+
roles: z.array(role).meta({
|
|
201
|
+
description: 'The app\'s roles, built-in and custom alike, ordered by `created_at` and then by `name`. The tie-break is not cosmetic — the two built-in roles are inserted in one statement and share a creation time to the microsecond, so never read a role by position.',
|
|
202
|
+
}),
|
|
203
|
+
});
|
|
204
|
+
/**
|
|
205
|
+
* The rights matrix of one role: which slugs of which robot it may use, plus
|
|
206
|
+
* the capabilities roles also govern (§3.3). `capabilities`' own doc comment
|
|
207
|
+
* below says which of them are enforced today and which is still a switch
|
|
208
|
+
* that changes nothing.
|
|
209
|
+
*/
|
|
210
|
+
export const rolePermissions = z.object({
|
|
211
|
+
role_id: z.uuid(),
|
|
212
|
+
/**
|
|
213
|
+
* **A slug is unique per robot across ALL service kinds** (spec §4.1:
|
|
214
|
+
* "Jeder Dienst erhält einen Slug" — one namespace, not one per kind), and
|
|
215
|
+
* the cloud's config validation enforces that with a kind-agnostic
|
|
216
|
+
* collection pass. That is why this list carries slugs and not
|
|
217
|
+
* (kind, slug) pairs: when W4 adds actions, services and publishers, a
|
|
218
|
+
* grant keeps meaning exactly what it means today, and this shape does not
|
|
219
|
+
* change. What W4 does need is an endpoint that lists every *grantable*
|
|
220
|
+
* slug of a robot with its kind, so the console's matrix can offer them —
|
|
221
|
+
* today it enumerates datapoints only, which is the seam that would
|
|
222
|
+
* otherwise force a rebuild.
|
|
223
|
+
*/
|
|
224
|
+
grants: z.array(z.object({
|
|
225
|
+
robot_id: z.uuid(),
|
|
226
|
+
slugs: z.array(slug),
|
|
227
|
+
})),
|
|
228
|
+
/**
|
|
229
|
+
* App-wide abilities a role grants, as opposed to per-slug grants above.
|
|
230
|
+
*
|
|
231
|
+
* **A capability here is a promise, and one of them is still not kept.**
|
|
232
|
+
* `action_history` and `presence` were both gated by this object from W4
|
|
233
|
+
* and implemented nowhere — no route, no SDK method, no realtime frame
|
|
234
|
+
* (register row 8). A console could therefore switch them on and nothing
|
|
235
|
+
* changed, which is worse than their absence: the developer believes they
|
|
236
|
+
* granted something. **This paragraph stays** whatever the current tally
|
|
237
|
+
* is: it is the only place that says a switch in the console may change
|
|
238
|
+
* nothing, and it is how the next unkept capability gets caught.
|
|
239
|
+
*
|
|
240
|
+
* `assets` (W7) was the first one redeemed. It gates §4.6's asset store,
|
|
241
|
+
* which is not covered by `grants` because **assets are not slugs** — and it
|
|
242
|
+
* is its own decision rather than a side effect of reaching the robot,
|
|
243
|
+
* because a mesh set gives away the machine's build.
|
|
244
|
+
*
|
|
245
|
+
* **`action_history` is kept as of the run-history delta.** It gates
|
|
246
|
+
* `GET /api/robots/:id/jobs/history` — an end user whose role lacks it is
|
|
247
|
+
* refused `403 capability_required`, naming the capability so the developer
|
|
248
|
+
* knows which switch is off. It was unkeepable while nothing durable
|
|
249
|
+
* recorded what had run; `jobRun` and `job_runs` are that record.
|
|
250
|
+
*
|
|
251
|
+
* **What granting it discloses.** A `jobRun` names the actor who invoked
|
|
252
|
+
* it, and `jobActor.label` is an email — so an end user holding this
|
|
253
|
+
* capability learns which *other* people have been driving that robot.
|
|
254
|
+
* That is inherent in "may read the history" rather than an oversight, and
|
|
255
|
+
* it is written down here because the switch lives in the console while its
|
|
256
|
+
* consequence does not.
|
|
257
|
+
*
|
|
258
|
+
* **`presence` is still not implemented.** Nothing in the cloud, the SDK or
|
|
259
|
+
* the realtime protocol consults it. It remains exactly what the first
|
|
260
|
+
* paragraph describes.
|
|
261
|
+
*/
|
|
262
|
+
capabilities: z.object({
|
|
263
|
+
action_history: z.boolean(),
|
|
264
|
+
presence: z.boolean(),
|
|
265
|
+
assets: z.boolean(),
|
|
266
|
+
}),
|
|
267
|
+
});
|