@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/audit.d.ts
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Audit (spec §16). Every state-changing interaction is recorded and **every
|
|
4
|
+
* entry carries its actor — never anonymous** (§16.2). Reads are not audited.
|
|
5
|
+
*
|
|
6
|
+
* W3 writes the events that exist once identities do: logins, failed logins,
|
|
7
|
+
* end-user management, config publishes, bridge connect/disconnect. The view
|
|
8
|
+
* with filters, CSV export and the 90-day retention window is W6 (André,
|
|
9
|
+
* 2026-08-10) — same shape of work as the history API.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* The kinds of actor the platform knows. `label` is what a human reads in the
|
|
13
|
+
* log — an email, a key name, a robot name — so the console never has to
|
|
14
|
+
* resolve four different id kinds to render a row.
|
|
15
|
+
*
|
|
16
|
+
* **`end_user` stays, and it stays for the rows already written.** The
|
|
17
|
+
* two-space cut (2026-09-05, D1) replaced the org's one user pool with
|
|
18
|
+
* Fleetless users and per-app app users; every new row an app user writes
|
|
19
|
+
* carries `app_user`. But an audit log is the one thing this platform must
|
|
20
|
+
* never rewrite, and there are stored rows whose `kind` is `end_user`. Dropping
|
|
21
|
+
* the member would leave those rows failing their own schema — a log that
|
|
22
|
+
* cannot be read back is worse than one carrying a retired word.
|
|
23
|
+
*
|
|
24
|
+
* So this enum is deliberately **wider than what any producer emits**: nothing
|
|
25
|
+
* writes `end_user` any more, and nothing may start again. That is the kind of
|
|
26
|
+
* claim this repository has been wrong about before by leaving it unsaid, so it
|
|
27
|
+
* is said here rather than inferred from a `grep` somebody runs in a year.
|
|
28
|
+
*
|
|
29
|
+
* `developer` is a Fleetless user. It kept its name through both redesigns
|
|
30
|
+
* because it was always right about what it named: the person who configures
|
|
31
|
+
* robots.
|
|
32
|
+
*/
|
|
33
|
+
export declare const auditActor: z.ZodObject<{
|
|
34
|
+
kind: z.ZodEnum<{
|
|
35
|
+
developer: "developer";
|
|
36
|
+
server_key: "server_key";
|
|
37
|
+
bridge: "bridge";
|
|
38
|
+
end_user: "end_user";
|
|
39
|
+
app_user: "app_user";
|
|
40
|
+
}>;
|
|
41
|
+
id: z.ZodUUID;
|
|
42
|
+
label: z.ZodString;
|
|
43
|
+
}, z.core.$strip>;
|
|
44
|
+
export type AuditActor = z.infer<typeof auditActor>;
|
|
45
|
+
export declare const auditEvent: z.ZodObject<{
|
|
46
|
+
id: z.ZodUUID;
|
|
47
|
+
org_id: z.ZodUUID;
|
|
48
|
+
at: z.ZodISODateTime;
|
|
49
|
+
seq: z.ZodNumber;
|
|
50
|
+
actor: z.ZodObject<{
|
|
51
|
+
kind: z.ZodEnum<{
|
|
52
|
+
developer: "developer";
|
|
53
|
+
server_key: "server_key";
|
|
54
|
+
bridge: "bridge";
|
|
55
|
+
end_user: "end_user";
|
|
56
|
+
app_user: "app_user";
|
|
57
|
+
}>;
|
|
58
|
+
id: z.ZodUUID;
|
|
59
|
+
label: z.ZodString;
|
|
60
|
+
}, z.core.$strip>;
|
|
61
|
+
action: z.ZodString;
|
|
62
|
+
target: z.ZodNullable<z.ZodObject<{
|
|
63
|
+
kind: z.ZodString;
|
|
64
|
+
id: z.ZodString;
|
|
65
|
+
label: z.ZodString;
|
|
66
|
+
}, z.core.$strip>>;
|
|
67
|
+
details: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
68
|
+
}, z.core.$strip>;
|
|
69
|
+
export type AuditEvent = z.infer<typeof auditEvent>;
|
|
70
|
+
export declare const auditQuery: z.ZodObject<{
|
|
71
|
+
before_seq: z.ZodOptional<z.ZodPipe<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>, z.ZodTransform<number, string | number>>, z.ZodNumber>>;
|
|
72
|
+
limit: z.ZodOptional<z.ZodPipe<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>, z.ZodTransform<number, string | number>>, z.ZodNumber>>;
|
|
73
|
+
action: z.ZodOptional<z.ZodString>;
|
|
74
|
+
action_prefix: z.ZodOptional<z.ZodString>;
|
|
75
|
+
actor_id: z.ZodOptional<z.ZodUUID>;
|
|
76
|
+
target_kind: z.ZodOptional<z.ZodString>;
|
|
77
|
+
from_ms: z.ZodOptional<z.ZodPipe<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>, z.ZodTransform<number, string | number>>, z.ZodNumber>>;
|
|
78
|
+
to_ms: z.ZodOptional<z.ZodPipe<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>, z.ZodTransform<number, string | number>>, z.ZodNumber>>;
|
|
79
|
+
}, z.core.$strict>;
|
|
80
|
+
export type AuditQuery = z.infer<typeof auditQuery>;
|
|
81
|
+
export declare const auditListResponse: z.ZodObject<{
|
|
82
|
+
events: z.ZodArray<z.ZodObject<{
|
|
83
|
+
id: z.ZodUUID;
|
|
84
|
+
org_id: z.ZodUUID;
|
|
85
|
+
at: z.ZodISODateTime;
|
|
86
|
+
seq: z.ZodNumber;
|
|
87
|
+
actor: z.ZodObject<{
|
|
88
|
+
kind: z.ZodEnum<{
|
|
89
|
+
developer: "developer";
|
|
90
|
+
server_key: "server_key";
|
|
91
|
+
bridge: "bridge";
|
|
92
|
+
end_user: "end_user";
|
|
93
|
+
app_user: "app_user";
|
|
94
|
+
}>;
|
|
95
|
+
id: z.ZodUUID;
|
|
96
|
+
label: z.ZodString;
|
|
97
|
+
}, z.core.$strip>;
|
|
98
|
+
action: z.ZodString;
|
|
99
|
+
target: z.ZodNullable<z.ZodObject<{
|
|
100
|
+
kind: z.ZodString;
|
|
101
|
+
id: z.ZodString;
|
|
102
|
+
label: z.ZodString;
|
|
103
|
+
}, z.core.$strip>>;
|
|
104
|
+
details: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
105
|
+
}, z.core.$strip>>;
|
|
106
|
+
next_cursor: z.ZodNullable<z.ZodNumber>;
|
|
107
|
+
}, z.core.$strip>;
|
|
108
|
+
export type AuditListResponse = z.infer<typeof auditListResponse>;
|
|
109
|
+
/**
|
|
110
|
+
* **What a CSV export of this log looks like (DEF-123, spec §16.3).**
|
|
111
|
+
*
|
|
112
|
+
* The column order lives here because otherwise the cloud and the console
|
|
113
|
+
* would each carry their own, and nobody would notice them drifting apart
|
|
114
|
+
* until a spreadsheet at a customer had the wrong headings. One order, one
|
|
115
|
+
* place.
|
|
116
|
+
*
|
|
117
|
+
* `details` is written as JSON into a single cell. That is ugly and honest:
|
|
118
|
+
* the alternative is leaving it out, and an audit export that omits *what
|
|
119
|
+
* happened* is not an audit export.
|
|
120
|
+
*/
|
|
121
|
+
export declare const AUDIT_CSV_COLUMNS: readonly ["seq", "at", "actor_kind", "actor_id", "action", "target_kind", "target_id", "target_label", "details"];
|
|
122
|
+
/**
|
|
123
|
+
* Spec §16.3: the audit log is kept for **90 days**.
|
|
124
|
+
*
|
|
125
|
+
* A constant here so the cloud does not derive it a second time — the same
|
|
126
|
+
* reasoning as `ASSET_UPLOAD_MAX_BYTES`, and the same register row that found
|
|
127
|
+
* there is no purge touching audit rows at all.
|
|
128
|
+
*/
|
|
129
|
+
export declare const AUDIT_RETENTION_DAYS = 90;
|
package/dist/audit.js
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { wireSeqCursor, wireTimestampMs } from './common.js';
|
|
4
|
+
/**
|
|
5
|
+
* Audit (spec §16). Every state-changing interaction is recorded and **every
|
|
6
|
+
* entry carries its actor — never anonymous** (§16.2). Reads are not audited.
|
|
7
|
+
*
|
|
8
|
+
* W3 writes the events that exist once identities do: logins, failed logins,
|
|
9
|
+
* end-user management, config publishes, bridge connect/disconnect. The view
|
|
10
|
+
* with filters, CSV export and the 90-day retention window is W6 (André,
|
|
11
|
+
* 2026-08-10) — same shape of work as the history API.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* The kinds of actor the platform knows. `label` is what a human reads in the
|
|
15
|
+
* log — an email, a key name, a robot name — so the console never has to
|
|
16
|
+
* resolve four different id kinds to render a row.
|
|
17
|
+
*
|
|
18
|
+
* **`end_user` stays, and it stays for the rows already written.** The
|
|
19
|
+
* two-space cut (2026-09-05, D1) replaced the org's one user pool with
|
|
20
|
+
* Fleetless users and per-app app users; every new row an app user writes
|
|
21
|
+
* carries `app_user`. But an audit log is the one thing this platform must
|
|
22
|
+
* never rewrite, and there are stored rows whose `kind` is `end_user`. Dropping
|
|
23
|
+
* the member would leave those rows failing their own schema — a log that
|
|
24
|
+
* cannot be read back is worse than one carrying a retired word.
|
|
25
|
+
*
|
|
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 the kind of
|
|
28
|
+
* claim this repository has been wrong about before by leaving it unsaid, so it
|
|
29
|
+
* is said here rather than inferred from a `grep` somebody runs in a year.
|
|
30
|
+
*
|
|
31
|
+
* `developer` is a Fleetless user. It kept its name through both redesigns
|
|
32
|
+
* because it was always right about what it named: the person who configures
|
|
33
|
+
* robots.
|
|
34
|
+
*/
|
|
35
|
+
export const auditActor = z.object({
|
|
36
|
+
kind: z.enum(['developer', 'end_user', 'app_user', 'server_key', 'bridge']),
|
|
37
|
+
id: z.uuid(),
|
|
38
|
+
label: z.string().min(1).max(200),
|
|
39
|
+
});
|
|
40
|
+
export const auditEvent = z.object({
|
|
41
|
+
id: z.uuid(),
|
|
42
|
+
org_id: z.uuid(),
|
|
43
|
+
at: z.iso.datetime(),
|
|
44
|
+
/**
|
|
45
|
+
* A monotonic counter, ascending in write order, unique across the log
|
|
46
|
+
* (W6b).
|
|
47
|
+
*
|
|
48
|
+
* `at` is not a total order. Two events written in the same millisecond —
|
|
49
|
+
* a login and the config publish it enables, a cascade writing several
|
|
50
|
+
* rows — sort against each other arbitrarily, and "arbitrarily" means
|
|
51
|
+
* *differently on each query*. A reader paging through "newest first" can
|
|
52
|
+
* therefore see one of them twice and the other not at all, which is the
|
|
53
|
+
* one failure mode an audit log may not have: a record that is present and
|
|
54
|
+
* invisible.
|
|
55
|
+
*
|
|
56
|
+
* It is also the only correct **cursor** for paging this log, for the same
|
|
57
|
+
* reason: a cursor that is not unique either skips rows or repeats them at
|
|
58
|
+
* every page boundary. No cursor parameter exists on `GET /api/audit` yet —
|
|
59
|
+
* the route returns the whole log — and that is stated here rather than
|
|
60
|
+
* implied, because a contract that describes a capability the API does not
|
|
61
|
+
* have is the defect this project keeps finding. When paging is added it
|
|
62
|
+
* uses this field; nothing else in this shape can carry it.
|
|
63
|
+
*
|
|
64
|
+
* Required, not optional: an event without a sequence cannot be ordered
|
|
65
|
+
* against one that has it, and a log with two orderings has none.
|
|
66
|
+
*/
|
|
67
|
+
seq: z.number().int().positive(),
|
|
68
|
+
actor: auditActor,
|
|
69
|
+
/** Stable dotted name, e.g. `app_user.login`, `config.published`. */
|
|
70
|
+
action: z.string().min(1).max(80),
|
|
71
|
+
/**
|
|
72
|
+
* What the action was about, if anything — a robot, an app, a user. Free
|
|
73
|
+
* of ids the console cannot resolve: carry the label with it.
|
|
74
|
+
*/
|
|
75
|
+
target: z
|
|
76
|
+
.object({
|
|
77
|
+
kind: z.string().min(1).max(40),
|
|
78
|
+
id: z.string().min(1),
|
|
79
|
+
label: z.string().min(1).max(200),
|
|
80
|
+
})
|
|
81
|
+
.nullable(),
|
|
82
|
+
/**
|
|
83
|
+
* Action-specific extras.
|
|
84
|
+
*
|
|
85
|
+
* **Nothing redacts this.** There is no denylist, no allowlist and no pass
|
|
86
|
+
* over what a call site puts here — the call site is responsible, and this
|
|
87
|
+
* comment is where that responsibility is written down. Since the org event
|
|
88
|
+
* stream, the same object also reaches every developer with the console
|
|
89
|
+
* overview open, not only whoever later reads the audit log.
|
|
90
|
+
*
|
|
91
|
+
* So: never credentials, never tokens. That is a rule, not a guarantee the
|
|
92
|
+
* schema enforces.
|
|
93
|
+
*/
|
|
94
|
+
details: z.record(z.string(), z.unknown()).nullable(),
|
|
95
|
+
});
|
|
96
|
+
/**
|
|
97
|
+
* **How this log is read (W9d, DEF-078 and DEF-123).**
|
|
98
|
+
*
|
|
99
|
+
* Until now `GET /api/audit` returned the **whole** log — no filters, no
|
|
100
|
+
* cursor. `auditEvent.seq`'s own comment has said so plainly since W6b rather
|
|
101
|
+
* than describing a capability the API does not have; this shape builds
|
|
102
|
+
* exactly what that comment announced.
|
|
103
|
+
*
|
|
104
|
+
* **The cursor is `seq`, and no other field can be.** `at` is not a total
|
|
105
|
+
* order: two events written in the same millisecond sort differently on every
|
|
106
|
+
* query, so a cursor on `at` either skips rows or repeats them at each page
|
|
107
|
+
* boundary — which for an audit log means an entry that is present and
|
|
108
|
+
* invisible.
|
|
109
|
+
*
|
|
110
|
+
* `before_seq` rather than `after_seq`, because this log is read **newest
|
|
111
|
+
* first**: the next page is older, not newer.
|
|
112
|
+
*
|
|
113
|
+
* **Filters are part of the same work, not a later garnish.** A console view
|
|
114
|
+
* without them is a page with nothing to filter by — the register row says
|
|
115
|
+
* exactly that, which is why the two rows are one piece of work.
|
|
116
|
+
*/
|
|
117
|
+
/**
|
|
118
|
+
* A unix-millisecond bound a Postgres `timestamptz` can actually hold.
|
|
119
|
+
*
|
|
120
|
+
* Years 1..9999: below that Postgres has no year zero, above it year 10000
|
|
121
|
+
* needs the ISO extended-year form its bind path does not accept. Comfortably
|
|
122
|
+
* wider than any instant this platform will legitimately be asked about, so
|
|
123
|
+
* the bound costs nothing real and catches every value found to 500.
|
|
124
|
+
*
|
|
125
|
+
* @see wireTimestampMs — moved to `common.ts` when `jobRunQuery` needed the same bound.
|
|
126
|
+
*/
|
|
127
|
+
const auditTimestampMs = wireTimestampMs;
|
|
128
|
+
export const auditQuery = z.object({
|
|
129
|
+
/** Only events with a smaller `seq` — the next, older page. */
|
|
130
|
+
before_seq: wireSeqCursor.optional(),
|
|
131
|
+
/**
|
|
132
|
+
* Same shape as DEF-059's `historyQuery.limit`: a union whose input branch
|
|
133
|
+
* **is the wire**. A `z.coerce` cannot be published — zod renders the
|
|
134
|
+
* coercion's result in either `io` direction, so the artifact would describe
|
|
135
|
+
* a shape a query string can never carry.
|
|
136
|
+
*/
|
|
137
|
+
limit: z
|
|
138
|
+
.union([z.string().regex(/^\d{1,4}$/), z.number().int()])
|
|
139
|
+
.transform((v) => Number(v))
|
|
140
|
+
.pipe(z.number().int().positive().max(500))
|
|
141
|
+
.optional(),
|
|
142
|
+
/** Exact action name, e.g. `config.published`. No prefix matching: a filter that matches more than it says is not one. */
|
|
143
|
+
action: z.string().min(1).max(80).optional(),
|
|
144
|
+
/**
|
|
145
|
+
* Everything under a dotted prefix, e.g. `server_key.` for all three
|
|
146
|
+
* server-key actions.
|
|
147
|
+
*
|
|
148
|
+
* **A separate parameter, not a widening of `action`.** The sentence on
|
|
149
|
+
* `action` above — a filter that matches more than it says is not one —
|
|
150
|
+
* still stands; this is a different question with a name that says which
|
|
151
|
+
* one it is. Setting both is refused rather than resolved, because a query
|
|
152
|
+
* naming an exact action *and* a prefix is a caller mistake, not a
|
|
153
|
+
* combination anyone should have to guess the meaning of.
|
|
154
|
+
*
|
|
155
|
+
* **The published artifact cannot express that refusal**: a cross-field
|
|
156
|
+
* `.refine()` has no JSON Schema rendering, so `audit-query.schema.json`
|
|
157
|
+
* describes two independent optional strings and validates both-at-once
|
|
158
|
+
* happily. The cloud is the only enforcement point — the same residual
|
|
159
|
+
* `orgLatencyQuery` and `orgUsageQuery` already name.
|
|
160
|
+
*/
|
|
161
|
+
action_prefix: z.string().min(1).max(80).optional(),
|
|
162
|
+
/**
|
|
163
|
+
* Only events by this actor.
|
|
164
|
+
*
|
|
165
|
+
* **`z.uuid()`, because the column is one (Argus-W9, W9 review).** This was
|
|
166
|
+
* `z.string().min(1).max(200)`, so any non-uuid value reached Postgres as a
|
|
167
|
+
* uuid parameter and threw: `?actor_id=not-a-uuid` answered **500
|
|
168
|
+
* `internal_error`**, on the list route and the export alike.
|
|
169
|
+
*
|
|
170
|
+
* Not a SQL-injection finding — Drizzle parameterises, and `' or 1=1--`
|
|
171
|
+
* failed at the same cast. It is a **500 where a 400 belongs**, and a 500 is
|
|
172
|
+
* the answer that explains nothing.
|
|
173
|
+
*
|
|
174
|
+
* The place is the part worth keeping: **this same wave pulled
|
|
175
|
+
* `refuseIfNotUuid` through ~15 call sites** so a typo could be told from a
|
|
176
|
+
* deletion — and the brand-new filter, whose field has exactly that shape,
|
|
177
|
+
* is the one that did not get it. A rule applied to the sites in front of
|
|
178
|
+
* you is not a rule applied to the class.
|
|
179
|
+
*/
|
|
180
|
+
actor_id: z.uuid().optional(),
|
|
181
|
+
/** Only events about this kind of target, e.g. `robot`. */
|
|
182
|
+
target_kind: z.string().min(1).max(40).optional(),
|
|
183
|
+
/**
|
|
184
|
+
* Absolute bounds in unix milliseconds, **half-open `[from, to)`** — the
|
|
185
|
+
* same rule the history shapes follow (DEF-062).
|
|
186
|
+
*
|
|
187
|
+
* **Bounded to years 1..9999, and the bound is borrowed rather than
|
|
188
|
+
* invented.** `nonnegative()` alone let `253402300800000` (year 10000)
|
|
189
|
+
* through, where the Postgres bind path has no representation and the route
|
|
190
|
+
* answered 500 — measured either side of the edge: `253402300799000` → 200,
|
|
191
|
+
* `253402300800000` → 500 (Argus-W9). `history-query.ts`'s `parseTimeExprMs`
|
|
192
|
+
* already carries exactly this range, with M3's reasoning for why
|
|
193
|
+
* `Number.isSafeInteger` is wider than what a timestamp can be; this is that
|
|
194
|
+
* same number, not a second one that happens to agree.
|
|
195
|
+
*/
|
|
196
|
+
from_ms: auditTimestampMs.optional(),
|
|
197
|
+
to_ms: auditTimestampMs.optional(),
|
|
198
|
+
})
|
|
199
|
+
.strict()
|
|
200
|
+
.refine((query) => !(query.action !== undefined && query.action_prefix !== undefined), {
|
|
201
|
+
message: 'action and action_prefix cannot be combined',
|
|
202
|
+
path: ['action_prefix'],
|
|
203
|
+
});
|
|
204
|
+
export const auditListResponse = z.object({
|
|
205
|
+
events: z.array(auditEvent),
|
|
206
|
+
/**
|
|
207
|
+
* The `seq` a caller sends as `before_seq` to keep reading — or `null` when
|
|
208
|
+
* there is nothing further.
|
|
209
|
+
*
|
|
210
|
+
* **`null` means the end, and that is a promise rather than an
|
|
211
|
+
* observation.** A caller who instead compares `events.length` against
|
|
212
|
+
* `limit` is wrong the moment a filter makes a page thin: a short page does
|
|
213
|
+
* not mean *no more* here. The same distinction `historySamples` was given
|
|
214
|
+
* `truncated` for.
|
|
215
|
+
*/
|
|
216
|
+
next_cursor: z.number().int().positive().nullable(),
|
|
217
|
+
});
|
|
218
|
+
/**
|
|
219
|
+
* **What a CSV export of this log looks like (DEF-123, spec §16.3).**
|
|
220
|
+
*
|
|
221
|
+
* The column order lives here because otherwise the cloud and the console
|
|
222
|
+
* would each carry their own, and nobody would notice them drifting apart
|
|
223
|
+
* until a spreadsheet at a customer had the wrong headings. One order, one
|
|
224
|
+
* place.
|
|
225
|
+
*
|
|
226
|
+
* `details` is written as JSON into a single cell. That is ugly and honest:
|
|
227
|
+
* the alternative is leaving it out, and an audit export that omits *what
|
|
228
|
+
* happened* is not an audit export.
|
|
229
|
+
*/
|
|
230
|
+
export const AUDIT_CSV_COLUMNS = ['seq', 'at', 'actor_kind', 'actor_id', 'action', 'target_kind', 'target_id', 'target_label', 'details'];
|
|
231
|
+
/**
|
|
232
|
+
* Spec §16.3: the audit log is kept for **90 days**.
|
|
233
|
+
*
|
|
234
|
+
* A constant here so the cloud does not derive it a second time — the same
|
|
235
|
+
* reasoning as `ASSET_UPLOAD_MAX_BYTES`, and the same register row that found
|
|
236
|
+
* there is no purge touching audit rows at all.
|
|
237
|
+
*/
|
|
238
|
+
export const AUDIT_RETENTION_DAYS = 90;
|