@tai42/api-client 16.0.0 → 17.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/dist/agents.d.ts.map +1 -1
- package/dist/agents.js +1 -1
- package/dist/agents.js.map +1 -1
- package/dist/client/agents-client.d.ts +26 -0
- package/dist/client/agents-client.d.ts.map +1 -0
- package/dist/client/agents-client.js +19 -0
- package/dist/client/agents-client.js.map +1 -0
- package/dist/client/auth-client.d.ts +247 -0
- package/dist/client/auth-client.d.ts.map +1 -0
- package/dist/client/auth-client.js +73 -0
- package/dist/client/auth-client.js.map +1 -0
- package/dist/client/backend-client.d.ts +39 -0
- package/dist/client/backend-client.d.ts.map +1 -0
- package/dist/client/backend-client.js +22 -0
- package/dist/client/backend-client.js.map +1 -0
- package/dist/client/backup-client.d.ts +56 -0
- package/dist/client/backup-client.d.ts.map +1 -0
- package/dist/client/backup-client.js +12 -0
- package/dist/client/backup-client.js.map +1 -0
- package/dist/client/capabilities-client.d.ts +40 -0
- package/dist/client/capabilities-client.d.ts.map +1 -0
- package/dist/client/capabilities-client.js +19 -0
- package/dist/client/capabilities-client.js.map +1 -0
- package/dist/client/channels-client.d.ts +7 -0
- package/dist/client/channels-client.d.ts.map +1 -0
- package/dist/client/channels-client.js +10 -0
- package/dist/client/channels-client.js.map +1 -0
- package/dist/client/config-client.d.ts +59 -0
- package/dist/client/config-client.d.ts.map +1 -0
- package/dist/client/config-client.js +18 -0
- package/dist/client/config-client.js.map +1 -0
- package/dist/client/connectors-client.d.ts +225 -0
- package/dist/client/connectors-client.d.ts.map +1 -0
- package/dist/client/connectors-client.js +31 -0
- package/dist/client/connectors-client.js.map +1 -0
- package/dist/client/conversations-client.d.ts +398 -0
- package/dist/client/conversations-client.d.ts.map +1 -0
- package/dist/client/conversations-client.js +120 -0
- package/dist/client/conversations-client.js.map +1 -0
- package/dist/client/hooks-client.d.ts +112 -0
- package/dist/client/hooks-client.d.ts.map +1 -0
- package/dist/client/hooks-client.js +25 -0
- package/dist/client/hooks-client.js.map +1 -0
- package/dist/{client.d.ts → client/index.d.ts} +2336 -2708
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +79 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/interactions-client.d.ts +52 -0
- package/dist/client/interactions-client.d.ts.map +1 -0
- package/dist/client/interactions-client.js +84 -0
- package/dist/client/interactions-client.js.map +1 -0
- package/dist/client/login-client.d.ts +69 -0
- package/dist/client/login-client.d.ts.map +1 -0
- package/dist/client/login-client.js +137 -0
- package/dist/client/login-client.js.map +1 -0
- package/dist/client/manifest-client.d.ts +354 -0
- package/dist/client/manifest-client.d.ts.map +1 -0
- package/dist/client/manifest-client.js +76 -0
- package/dist/client/manifest-client.js.map +1 -0
- package/dist/client/marketplace-client.d.ts +274 -0
- package/dist/client/marketplace-client.d.ts.map +1 -0
- package/dist/client/marketplace-client.js +46 -0
- package/dist/client/marketplace-client.js.map +1 -0
- package/dist/client/mcp-config-schema-client.d.ts +5 -0
- package/dist/client/mcp-config-schema-client.d.ts.map +1 -0
- package/dist/client/mcp-config-schema-client.js +9 -0
- package/dist/client/mcp-config-schema-client.js.map +1 -0
- package/dist/client/notifications-client.d.ts +27 -0
- package/dist/client/notifications-client.d.ts.map +1 -0
- package/dist/client/notifications-client.js +11 -0
- package/dist/client/notifications-client.js.map +1 -0
- package/dist/client/observability-client.d.ts +103 -0
- package/dist/client/observability-client.d.ts.map +1 -0
- package/dist/client/observability-client.js +43 -0
- package/dist/client/observability-client.js.map +1 -0
- package/dist/client/plugins-client.d.ts +17 -0
- package/dist/client/plugins-client.d.ts.map +1 -0
- package/dist/client/plugins-client.js +9 -0
- package/dist/client/plugins-client.js.map +1 -0
- package/dist/client/policy-client.d.ts +37 -0
- package/dist/client/policy-client.d.ts.map +1 -0
- package/dist/client/policy-client.js +26 -0
- package/dist/client/policy-client.js.map +1 -0
- package/dist/client/presets-client.d.ts +334 -0
- package/dist/client/presets-client.d.ts.map +1 -0
- package/dist/client/presets-client.js +38 -0
- package/dist/client/presets-client.js.map +1 -0
- package/dist/client/profiles-client.d.ts +101 -0
- package/dist/client/profiles-client.d.ts.map +1 -0
- package/dist/client/profiles-client.js +37 -0
- package/dist/client/profiles-client.js.map +1 -0
- package/dist/client/schedules-client.d.ts +27 -0
- package/dist/client/schedules-client.d.ts.map +1 -0
- package/dist/client/schedules-client.js +13 -0
- package/dist/client/schedules-client.js.map +1 -0
- package/dist/client/settings-schema-client.d.ts +23 -0
- package/dist/client/settings-schema-client.d.ts.map +1 -0
- package/dist/client/settings-schema-client.js +9 -0
- package/dist/client/settings-schema-client.js.map +1 -0
- package/dist/client/states-client.d.ts +470 -0
- package/dist/client/states-client.d.ts.map +1 -0
- package/dist/client/states-client.js +144 -0
- package/dist/client/states-client.js.map +1 -0
- package/dist/client/storage-client.d.ts +40 -0
- package/dist/client/storage-client.d.ts.map +1 -0
- package/dist/client/storage-client.js +43 -0
- package/dist/client/storage-client.js.map +1 -0
- package/dist/client/sub-mcp-client.d.ts +17 -0
- package/dist/client/sub-mcp-client.d.ts.map +1 -0
- package/dist/client/sub-mcp-client.js +14 -0
- package/dist/client/sub-mcp-client.js.map +1 -0
- package/dist/client/system-client.d.ts +11 -0
- package/dist/client/system-client.d.ts.map +1 -0
- package/dist/client/system-client.js +13 -0
- package/dist/client/system-client.js.map +1 -0
- package/dist/client/templates-client.d.ts +29 -0
- package/dist/client/templates-client.d.ts.map +1 -0
- package/dist/client/templates-client.js +21 -0
- package/dist/client/templates-client.js.map +1 -0
- package/dist/client/tool-extensions-client.d.ts +53 -0
- package/dist/client/tool-extensions-client.d.ts.map +1 -0
- package/dist/client/tool-extensions-client.js +21 -0
- package/dist/client/tool-extensions-client.js.map +1 -0
- package/dist/client/tool-meta-client.d.ts +69 -0
- package/dist/client/tool-meta-client.d.ts.map +1 -0
- package/dist/client/tool-meta-client.js +38 -0
- package/dist/client/tool-meta-client.js.map +1 -0
- package/dist/client/tools-client.d.ts +83 -0
- package/dist/client/tools-client.d.ts.map +1 -0
- package/dist/client/tools-client.js +38 -0
- package/dist/client/tools-client.js.map +1 -0
- package/dist/client/transport.d.ts +13 -0
- package/dist/client/transport.d.ts.map +1 -0
- package/dist/client/transport.js +10 -0
- package/dist/client/transport.js.map +1 -0
- package/dist/client/trigger-links-client.d.ts +44 -0
- package/dist/client/trigger-links-client.d.ts.map +1 -0
- package/dist/client/trigger-links-client.js +30 -0
- package/dist/client/trigger-links-client.js.map +1 -0
- package/dist/client/web-entry-gate-client.d.ts +34 -0
- package/dist/client/web-entry-gate-client.d.ts.map +1 -0
- package/dist/client/web-entry-gate-client.js +25 -0
- package/dist/client/web-entry-gate-client.js.map +1 -0
- package/dist/errors.d.ts +11 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +15 -0
- package/dist/errors.js.map +1 -1
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +33 -17
- package/dist/http.js.map +1 -1
- package/dist/index.d.ts +12 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -13
- package/dist/index.js.map +1 -1
- package/dist/schemas/api-keys.d.ts +43 -0
- package/dist/schemas/api-keys.d.ts.map +1 -0
- package/dist/schemas/api-keys.js +29 -0
- package/dist/schemas/api-keys.js.map +1 -0
- package/dist/schemas/auth-routes.d.ts +78 -0
- package/dist/schemas/auth-routes.d.ts.map +1 -0
- package/dist/schemas/auth-routes.js +42 -0
- package/dist/schemas/auth-routes.js.map +1 -0
- package/dist/schemas/backup.d.ts +78 -0
- package/dist/schemas/backup.d.ts.map +1 -0
- package/dist/schemas/backup.js +33 -0
- package/dist/schemas/backup.js.map +1 -0
- package/dist/schemas/capabilities.d.ts +109 -0
- package/dist/schemas/capabilities.d.ts.map +1 -0
- package/dist/schemas/capabilities.js +78 -0
- package/dist/schemas/capabilities.js.map +1 -0
- package/dist/schemas/channels.d.ts +7 -0
- package/dist/schemas/channels.d.ts.map +1 -0
- package/dist/schemas/channels.js +9 -0
- package/dist/schemas/channels.js.map +1 -0
- package/dist/schemas/config.d.ts +17 -0
- package/dist/schemas/config.d.ts.map +1 -0
- package/dist/schemas/config.js +17 -0
- package/dist/schemas/config.js.map +1 -0
- package/dist/schemas/connectors.d.ts +383 -0
- package/dist/schemas/connectors.d.ts.map +1 -0
- package/dist/schemas/connectors.js +122 -0
- package/dist/schemas/connectors.js.map +1 -0
- package/dist/schemas/conversations.d.ts +600 -0
- package/dist/schemas/conversations.d.ts.map +1 -0
- package/dist/schemas/conversations.js +208 -0
- package/dist/schemas/conversations.js.map +1 -0
- package/dist/schemas/extensions.d.ts +44 -0
- package/dist/schemas/extensions.d.ts.map +1 -0
- package/dist/schemas/extensions.js +29 -0
- package/dist/schemas/extensions.js.map +1 -0
- package/dist/schemas/fleet.d.ts +271 -0
- package/dist/schemas/fleet.d.ts.map +1 -0
- package/dist/schemas/fleet.js +132 -0
- package/dist/schemas/fleet.js.map +1 -0
- package/dist/schemas/hooks.d.ts +120 -0
- package/dist/schemas/hooks.d.ts.map +1 -0
- package/dist/schemas/hooks.js +44 -0
- package/dist/schemas/hooks.js.map +1 -0
- package/dist/schemas/index.d.ts +40 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +40 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/interactions.d.ts +156 -0
- package/dist/schemas/interactions.d.ts.map +1 -0
- package/dist/schemas/interactions.js +124 -0
- package/dist/schemas/interactions.js.map +1 -0
- package/dist/schemas/login.d.ts +93 -0
- package/dist/schemas/login.d.ts.map +1 -0
- package/dist/schemas/login.js +61 -0
- package/dist/schemas/login.js.map +1 -0
- package/dist/schemas/manifest-mcp.d.ts +125 -0
- package/dist/schemas/manifest-mcp.d.ts.map +1 -0
- package/dist/schemas/manifest-mcp.js +61 -0
- package/dist/schemas/manifest-mcp.js.map +1 -0
- package/dist/schemas/marketplace.d.ts +708 -0
- package/dist/schemas/marketplace.d.ts.map +1 -0
- package/dist/schemas/marketplace.js +387 -0
- package/dist/schemas/marketplace.js.map +1 -0
- package/dist/schemas/notifications.d.ts +61 -0
- package/dist/schemas/notifications.d.ts.map +1 -0
- package/dist/schemas/notifications.js +38 -0
- package/dist/schemas/notifications.js.map +1 -0
- package/dist/schemas/observability.d.ts +114 -0
- package/dist/schemas/observability.d.ts.map +1 -0
- package/dist/schemas/observability.js +74 -0
- package/dist/schemas/observability.js.map +1 -0
- package/dist/schemas/policy.d.ts +58 -0
- package/dist/schemas/policy.d.ts.map +1 -0
- package/dist/schemas/policy.js +32 -0
- package/dist/schemas/policy.js.map +1 -0
- package/dist/schemas/presets.d.ts +258 -0
- package/dist/schemas/presets.d.ts.map +1 -0
- package/dist/schemas/presets.js +95 -0
- package/dist/schemas/presets.js.map +1 -0
- package/dist/schemas/principals.d.ts +54 -0
- package/dist/schemas/principals.d.ts.map +1 -0
- package/dist/schemas/principals.js +34 -0
- package/dist/schemas/principals.js.map +1 -0
- package/dist/schemas/profiles.d.ts +180 -0
- package/dist/schemas/profiles.d.ts.map +1 -0
- package/dist/schemas/profiles.js +100 -0
- package/dist/schemas/profiles.js.map +1 -0
- package/dist/schemas/roles.d.ts +125 -0
- package/dist/schemas/roles.d.ts.map +1 -0
- package/dist/schemas/roles.js +46 -0
- package/dist/schemas/roles.js.map +1 -0
- package/dist/schemas/schedules.d.ts +25 -0
- package/dist/schemas/schedules.d.ts.map +1 -0
- package/dist/schemas/schedules.js +24 -0
- package/dist/schemas/schedules.js.map +1 -0
- package/dist/schemas/served.d.ts +626 -0
- package/dist/schemas/served.d.ts.map +1 -0
- package/dist/schemas/served.js +28 -0
- package/dist/schemas/served.js.map +1 -0
- package/dist/schemas/settings-schema.d.ts +23 -0
- package/dist/schemas/settings-schema.d.ts.map +1 -0
- package/dist/schemas/settings-schema.js +25 -0
- package/dist/schemas/settings-schema.js.map +1 -0
- package/dist/schemas/setup.d.ts +43 -0
- package/dist/schemas/setup.d.ts.map +1 -0
- package/dist/schemas/setup.js +19 -0
- package/dist/schemas/setup.js.map +1 -0
- package/dist/schemas/shared.d.ts +20 -0
- package/dist/schemas/shared.d.ts.map +1 -0
- package/dist/schemas/shared.js +20 -0
- package/dist/schemas/shared.js.map +1 -0
- package/dist/schemas/states.d.ts +499 -0
- package/dist/schemas/states.d.ts.map +1 -0
- package/dist/schemas/states.js +220 -0
- package/dist/schemas/states.js.map +1 -0
- package/dist/schemas/storage.d.ts +37 -0
- package/dist/schemas/storage.d.ts.map +1 -0
- package/dist/schemas/storage.js +24 -0
- package/dist/schemas/storage.js.map +1 -0
- package/dist/schemas/studio-plugins.d.ts +30 -0
- package/dist/schemas/studio-plugins.d.ts.map +1 -0
- package/dist/schemas/studio-plugins.js +20 -0
- package/dist/schemas/studio-plugins.js.map +1 -0
- package/dist/schemas/sub-mcp.d.ts +29 -0
- package/dist/schemas/sub-mcp.d.ts.map +1 -0
- package/dist/schemas/sub-mcp.js +22 -0
- package/dist/schemas/sub-mcp.js.map +1 -0
- package/dist/schemas/system-kinds.d.ts +122 -0
- package/dist/schemas/system-kinds.d.ts.map +1 -0
- package/dist/schemas/system-kinds.js +40 -0
- package/dist/schemas/system-kinds.js.map +1 -0
- package/dist/schemas/templates.d.ts +26 -0
- package/dist/schemas/templates.d.ts.map +1 -0
- package/dist/schemas/templates.js +11 -0
- package/dist/schemas/templates.js.map +1 -0
- package/dist/schemas/tool-meta.d.ts +64 -0
- package/dist/schemas/tool-meta.d.ts.map +1 -0
- package/dist/schemas/tool-meta.js +44 -0
- package/dist/schemas/tool-meta.js.map +1 -0
- package/dist/schemas/tools.d.ts +62 -0
- package/dist/schemas/tools.d.ts.map +1 -0
- package/dist/schemas/tools.js +53 -0
- package/dist/schemas/tools.js.map +1 -0
- package/dist/schemas/trigger-links.d.ts +71 -0
- package/dist/schemas/trigger-links.d.ts.map +1 -0
- package/dist/schemas/trigger-links.js +46 -0
- package/dist/schemas/trigger-links.js.map +1 -0
- package/dist/schemas/web-entry.d.ts +45 -0
- package/dist/schemas/web-entry.d.ts.map +1 -0
- package/dist/schemas/web-entry.js +36 -0
- package/dist/schemas/web-entry.js.map +1 -0
- package/dist/tool-runs.d.ts.map +1 -1
- package/dist/tool-runs.js.map +1 -1
- package/package.json +1 -1
- package/src/agents.ts +2 -2
- package/src/client/agents-client.ts +23 -0
- package/src/client/auth-client.ts +170 -0
- package/src/client/backend-client.ts +25 -0
- package/src/client/backup-client.ts +16 -0
- package/src/client/capabilities-client.ts +22 -0
- package/src/client/channels-client.ts +11 -0
- package/src/client/config-client.ts +21 -0
- package/src/client/connectors-client.ts +52 -0
- package/src/client/conversations-client.ts +240 -0
- package/src/client/hooks-client.ts +44 -0
- package/src/client/index.ts +122 -0
- package/src/client/interactions-client.ts +89 -0
- package/src/client/login-client.ts +150 -0
- package/src/client/manifest-client.ts +118 -0
- package/src/client/marketplace-client.ts +122 -0
- package/src/client/mcp-config-schema-client.ts +11 -0
- package/src/client/notifications-client.ts +13 -0
- package/src/client/observability-client.ts +82 -0
- package/src/client/plugins-client.ts +11 -0
- package/src/client/policy-client.ts +41 -0
- package/src/client/presets-client.ts +124 -0
- package/src/client/profiles-client.ts +51 -0
- package/src/client/schedules-client.ts +22 -0
- package/src/client/settings-schema-client.ts +11 -0
- package/src/client/states-client.ts +292 -0
- package/src/client/storage-client.ts +63 -0
- package/src/client/sub-mcp-client.ts +17 -0
- package/src/client/system-client.ts +16 -0
- package/src/client/templates-client.ts +28 -0
- package/src/client/tool-extensions-client.ts +24 -0
- package/src/client/tool-meta-client.ts +65 -0
- package/src/client/tools-client.ts +66 -0
- package/src/client/transport.ts +18 -0
- package/src/client/trigger-links-client.ts +51 -0
- package/src/client/web-entry-gate-client.ts +45 -0
- package/src/errors.ts +16 -0
- package/src/http.ts +48 -24
- package/src/index.ts +231 -226
- package/src/schemas/api-keys.ts +34 -0
- package/src/schemas/auth-routes.ts +48 -0
- package/src/schemas/backup.ts +43 -0
- package/src/schemas/capabilities.ts +92 -0
- package/src/schemas/channels.ts +11 -0
- package/src/schemas/config.ts +17 -0
- package/src/schemas/connectors.ts +139 -0
- package/src/schemas/conversations.ts +257 -0
- package/src/schemas/extensions.ts +34 -0
- package/src/schemas/fleet.ts +154 -0
- package/src/schemas/hooks.ts +57 -0
- package/src/schemas/index.ts +39 -0
- package/src/schemas/interactions.ts +147 -0
- package/src/schemas/login.ts +69 -0
- package/src/schemas/manifest-mcp.ts +70 -0
- package/src/schemas/marketplace.ts +447 -0
- package/src/schemas/notifications.ts +43 -0
- package/src/schemas/observability.ts +87 -0
- package/src/schemas/policy.ts +38 -0
- package/src/schemas/presets.ts +114 -0
- package/src/schemas/principals.ts +41 -0
- package/src/schemas/profiles.ts +120 -0
- package/src/schemas/roles.ts +58 -0
- package/src/schemas/schedules.ts +28 -0
- package/src/schemas/served.ts +50 -0
- package/src/schemas/settings-schema.ts +32 -0
- package/src/schemas/setup.ts +39 -0
- package/src/schemas/shared.ts +21 -0
- package/src/schemas/states.ts +273 -0
- package/src/schemas/storage.ts +31 -0
- package/src/schemas/studio-plugins.ts +21 -0
- package/src/schemas/sub-mcp.ts +24 -0
- package/src/schemas/system-kinds.ts +47 -0
- package/src/schemas/templates.ts +12 -0
- package/src/schemas/tool-meta.ts +51 -0
- package/src/schemas/tools.ts +62 -0
- package/src/schemas/trigger-links.ts +55 -0
- package/src/schemas/web-entry.ts +46 -0
- package/src/tool-runs.ts +1 -1
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js +0 -920
- package/dist/client.js.map +0 -1
- package/dist/schemas.d.ts +0 -5172
- package/dist/schemas.d.ts.map +0 -1
- package/dist/schemas.js +0 -2268
- package/dist/schemas.js.map +0 -1
- package/src/client.ts +0 -1771
- package/src/schemas.ts +0 -2760
package/src/schemas.ts
DELETED
|
@@ -1,2760 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* One zod schema per consumed endpoint. These mirror the skeleton's router
|
|
3
|
-
* response shapes exactly; a drift throws (ApiSchemaError) and the UI shows the
|
|
4
|
-
* error state. JSON-schema-shaped fields are kept as permissive records — the
|
|
5
|
-
* auto-form renderer interprets them at runtime.
|
|
6
|
-
*/
|
|
7
|
-
import { z } from 'zod';
|
|
8
|
-
|
|
9
|
-
import { templatedText } from './templated-text';
|
|
10
|
-
import * as generated from './generated/served-schemas';
|
|
11
|
-
|
|
12
|
-
export { templatedText, requiredTemplatedText } from './templated-text';
|
|
13
|
-
export type { TemplatedText } from './templated-text';
|
|
14
|
-
|
|
15
|
-
// Served-document schemas are GENERATED from the platform contract JSON-schema
|
|
16
|
-
// bundle (src/generated/served-schemas.ts) and re-exported here under the names the
|
|
17
|
-
// rest of the client uses. The generator maps every `x-tai42-templated-text` field
|
|
18
|
-
// to the shared `templatedText` zod, so a served body can never be a bare string.
|
|
19
|
-
// The plain response DTOs below (list wrappers, acks, version rows) stay hand-written.
|
|
20
|
-
export const stateInjection = generated.stateInjection;
|
|
21
|
-
export type StateInjection = z.infer<typeof stateInjection>;
|
|
22
|
-
export const stateUpdate = generated.stateUpdate;
|
|
23
|
-
export type StateUpdate = z.infer<typeof stateUpdate>;
|
|
24
|
-
export const stateAttach = generated.stateAttach;
|
|
25
|
-
export type StateAttach = z.infer<typeof stateAttach>;
|
|
26
|
-
export const stateBinding = generated.stateBinding;
|
|
27
|
-
export type StateBinding = z.infer<typeof stateBinding>;
|
|
28
|
-
export const presetBody = generated.presetBody;
|
|
29
|
-
export type PresetBody = z.input<typeof presetBody>;
|
|
30
|
-
export const conversationRoute = generated.conversationRoute;
|
|
31
|
-
export type ConversationRoute = z.infer<typeof conversationRoute>;
|
|
32
|
-
export const conversationRouteCreate = generated.conversationRouteCreate;
|
|
33
|
-
export type ConversationRouteCreate = z.input<typeof conversationRouteCreate>;
|
|
34
|
-
export const targetConversationConfig = generated.targetConversationConfig;
|
|
35
|
-
export type TargetConversationConfig = z.input<typeof targetConversationConfig>;
|
|
36
|
-
export const channelTemplate = generated.channelTemplate;
|
|
37
|
-
export type ChannelTemplate = z.infer<typeof channelTemplate>;
|
|
38
|
-
export const hookSubject = generated.hookSubject;
|
|
39
|
-
export type HookSubject = z.infer<typeof hookSubject>;
|
|
40
|
-
export const hookParams = generated.hookParams;
|
|
41
|
-
export type HookParams = z.infer<typeof hookParams>;
|
|
42
|
-
export const hookRegister = generated.hookRegister;
|
|
43
|
-
export type HookRegister = z.input<typeof hookRegister>;
|
|
44
|
-
export const stateDeclaration = generated.stateDeclaration;
|
|
45
|
-
export type StateDeclaration = z.infer<typeof stateDeclaration>;
|
|
46
|
-
export const stateTemplateDocument = generated.stateTemplateDocument;
|
|
47
|
-
export type StateTemplateDocument = z.infer<typeof stateTemplateDocument>;
|
|
48
|
-
export const templateJq = generated.stateTemplateJq;
|
|
49
|
-
export type TemplateJq = z.infer<typeof templateJq>;
|
|
50
|
-
export const templateReconcile = generated.stateTemplateReconcile;
|
|
51
|
-
export type TemplateReconcile = z.infer<typeof templateReconcile>;
|
|
52
|
-
export const templateDeclarations = generated.stateTemplateDeclarations;
|
|
53
|
-
export type TemplateDeclarations = z.infer<typeof templateDeclarations>;
|
|
54
|
-
export const policyBody = generated.accessPolicy;
|
|
55
|
-
export type PolicyBody = z.infer<typeof policyBody>;
|
|
56
|
-
export const roleBody = generated.roleDefinition;
|
|
57
|
-
export type RoleBody = z.infer<typeof roleBody>;
|
|
58
|
-
/** An arbitrary JSON value (tool results, rendered payloads). */
|
|
59
|
-
export const jsonValue: z.ZodType = z.unknown();
|
|
60
|
-
|
|
61
|
-
/** A JSON Schema object (Pydantic-emitted). Permissive; parsed by the auto-form. */
|
|
62
|
-
export const jsonSchema = z.record(z.string(), z.unknown());
|
|
63
|
-
|
|
64
|
-
// -- tools -------------------------------------------------------------------
|
|
65
|
-
|
|
66
|
-
export const toolNames = z.array(z.string());
|
|
67
|
-
|
|
68
|
-
export const toolSchema = z.object({
|
|
69
|
-
input: jsonSchema,
|
|
70
|
-
output: jsonSchema.nullable(),
|
|
71
|
-
description: z.string().nullable(),
|
|
72
|
-
});
|
|
73
|
-
export type ToolSchema = z.infer<typeof toolSchema>;
|
|
74
|
-
|
|
75
|
-
export const allToolSchemas = z.record(z.string(), toolSchema);
|
|
76
|
-
|
|
77
|
-
export const runToolResult = jsonValue;
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* The MEDIA content shape a direct tool run may return — fastmcp's serialized
|
|
81
|
-
* `Image`/`Audio` MediaBlock (`{ type, data: <base64>, mimeType }`). One recognised
|
|
82
|
-
* shape of the otherwise-arbitrary `runToolResult`, kept as its own schema so the
|
|
83
|
-
* viewer detects media by parse, not by ad-hoc shape check.
|
|
84
|
-
*
|
|
85
|
-
* SECURITY: the refinement pins `mimeType` to its kind — `image` MUST be `image/*`,
|
|
86
|
-
* `audio` MUST be `audio/*` — so a drifting/arbitrary mime fails the parse and is
|
|
87
|
-
* never turned into a `data:` URI (a `File` MediaBlock's distinct `EmbeddedResource`
|
|
88
|
-
* shape also fails here, by design).
|
|
89
|
-
*/
|
|
90
|
-
export const toolMediaResult = z
|
|
91
|
-
.object({
|
|
92
|
-
type: z.enum(['image', 'audio']),
|
|
93
|
-
data: z.string(),
|
|
94
|
-
mimeType: z.string(),
|
|
95
|
-
})
|
|
96
|
-
.refine((media) => media.mimeType.startsWith(`${media.type}/`), {
|
|
97
|
-
message: 'media mimeType must match its media kind (image/* for image, audio/* for audio)',
|
|
98
|
-
path: ['mimeType'],
|
|
99
|
-
});
|
|
100
|
-
export type ToolMediaResult = z.infer<typeof toolMediaResult>;
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* The ADDITIVE per-tool native surface (`GET /api/tools/tags`). Distinct from the
|
|
104
|
-
* flat `toolNames` contract (`GET /api/tools`, unchanged): each entry carries the
|
|
105
|
-
* tool's read-only FastMCP `tags` — so the shared `ToolPicker` can group/filter its
|
|
106
|
-
* options — plus `hidden`, the tool's OWN plugin-declared visibility (read from the
|
|
107
|
-
* FastMCP `meta` under `tai42/hidden`; a tool that never declared it is not hidden).
|
|
108
|
-
* The tool_meta overlay's tri-state override is merged on top client-side; this read
|
|
109
|
-
* exposes only the declaration.
|
|
110
|
-
*
|
|
111
|
-
* `badges` are the tool's plugin-DECLARED capability labels — purely INFORMATIONAL
|
|
112
|
-
* (e.g. `network`, `filesystem`), never a gate the server enforces. The overlay's
|
|
113
|
-
* own badges are merged on top client-side; this read exposes only the declaration.
|
|
114
|
-
*/
|
|
115
|
-
export const toolTagEntry = z.object({
|
|
116
|
-
name: z.string(),
|
|
117
|
-
tags: z.array(z.string()),
|
|
118
|
-
badges: z.array(z.string()),
|
|
119
|
-
hidden: z.boolean(),
|
|
120
|
-
});
|
|
121
|
-
export const toolTags = z.array(toolTagEntry);
|
|
122
|
-
export type ToolTagEntry = z.infer<typeof toolTagEntry>;
|
|
123
|
-
|
|
124
|
-
// -- extensions --------------------------------------------------------------
|
|
125
|
-
|
|
126
|
-
export const extension = z.object({ name: z.string(), kind: z.string() });
|
|
127
|
-
export const extensions = z.array(extension);
|
|
128
|
-
export type Extension = z.infer<typeof extension>;
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* One element of an extension combo: a bare extension NAME, or a
|
|
132
|
-
* `{ name, config }` mapping binding author config (e.g. an `output_schema` JSON
|
|
133
|
-
* Schema, or an `ask_external` verifier). Both wire forms are admitted so a
|
|
134
|
-
* config-bearing combo parses without dropping server data. A drift throws
|
|
135
|
-
* `ApiSchemaError`.
|
|
136
|
-
*/
|
|
137
|
-
export const presetExtensionElement = z.union([
|
|
138
|
-
z.string(),
|
|
139
|
-
z.object({ name: z.string(), config: z.record(z.string(), z.unknown()) }),
|
|
140
|
-
]);
|
|
141
|
-
export type PresetExtensionElement = z.infer<typeof presetExtensionElement>;
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* `GET /api/tools/{name}/extensions` — a tool's FULL lossless list-of-combos plus
|
|
145
|
-
* the extension catalog. `combos` is a list of combos, each an ordered list of
|
|
146
|
-
* extension ELEMENTS (a bare name or a config-bearing `{ name, config }` mapping —
|
|
147
|
-
* `output_schema` carries its schema this way); `[]` when the tool has no map entry.
|
|
148
|
-
* It carries EVERY combo mapped to the base tool (the union across every `tools`/`mcp`
|
|
149
|
-
* config), never a single flattened one. `available` is the same flat catalog
|
|
150
|
-
* `GET /api/extensions` returns. A drift throws `ApiSchemaError`.
|
|
151
|
-
*/
|
|
152
|
-
export const toolExtensions = z.object({
|
|
153
|
-
combos: z.array(z.array(presetExtensionElement)),
|
|
154
|
-
available: extensions,
|
|
155
|
-
});
|
|
156
|
-
export type ToolExtensions = z.infer<typeof toolExtensions>;
|
|
157
|
-
|
|
158
|
-
// -- presets -----------------------------------------------------------------
|
|
159
|
-
|
|
160
|
-
/** A list of extension COMBOS — each combo an ordered list of elements. */
|
|
161
|
-
export const presetExtensions = z.array(z.array(presetExtensionElement));
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* One preset as `GET /api/presets` returns it. Every preset is versioned, so
|
|
165
|
-
* `active_version` is always an int; `conflicted` marks a QUARANTINED row (its
|
|
166
|
-
* name collided with a foreign tool at boot — delete-only). `extensions` are the
|
|
167
|
-
* ACTIVE version's extension combos, `output_schema` the optional author-set
|
|
168
|
-
* output JSON Schema, and `input_schema` the optional author-set input JSON
|
|
169
|
-
* Schema. Categorization tags live in the tool_meta overlay
|
|
170
|
-
* (`GET /api/tool-meta`), never on the record. A drift throws `ApiSchemaError`;
|
|
171
|
-
* nothing is coerced.
|
|
172
|
-
*/
|
|
173
|
-
export const presetRecord = z.object({
|
|
174
|
-
name: z.string(),
|
|
175
|
-
base_tool: z.string(),
|
|
176
|
-
description: z.string(),
|
|
177
|
-
active_version: z.number(),
|
|
178
|
-
extensions: presetExtensions,
|
|
179
|
-
output_schema: z.record(z.string(), z.unknown()).nullable(),
|
|
180
|
-
input_schema: z.record(z.string(), z.unknown()).nullable(),
|
|
181
|
-
conflicted: z.boolean(),
|
|
182
|
-
// The human-readable cause a row is quarantined (its name collided with a
|
|
183
|
-
// foreign tool at boot), or `null` when the row is not conflicted. Rendered
|
|
184
|
-
// verbatim; nothing is coerced.
|
|
185
|
-
conflicted_reason: z.string().nullable(),
|
|
186
|
-
// Sorted preset-name cross-references: `uses` names the presets this one
|
|
187
|
-
// composes as tools; `used_by` names the presets that compose this one.
|
|
188
|
-
uses: z.array(z.string()),
|
|
189
|
-
used_by: z.array(z.string()),
|
|
190
|
-
});
|
|
191
|
-
export type PresetRecord = z.infer<typeof presetRecord>;
|
|
192
|
-
|
|
193
|
-
export const presetList = z.array(presetRecord);
|
|
194
|
-
|
|
195
|
-
/** `GET /api/presets/{name}` — the record plus the active version's baked kwargs. */
|
|
196
|
-
export const presetDetail = presetRecord.extend({
|
|
197
|
-
fixed_kwargs: z.record(z.string(), z.unknown()),
|
|
198
|
-
});
|
|
199
|
-
export type PresetDetail = z.infer<typeof presetDetail>;
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* One immutable version row (`GET /api/presets/{name}/versions[/{version}]`).
|
|
203
|
-
* `is_current` flags the active version; `tags` here is the GENERIC per-version
|
|
204
|
-
* label list (kind-agnostic) — the only preset tags that remain, distinct from the
|
|
205
|
-
* removed record-level categorization and from the tool_meta overlay.
|
|
206
|
-
*/
|
|
207
|
-
export const presetVersion = z.object({
|
|
208
|
-
version: z.number(),
|
|
209
|
-
body: presetBody,
|
|
210
|
-
tags: z.array(z.string()),
|
|
211
|
-
created_at: z.string(),
|
|
212
|
-
is_current: z.boolean(),
|
|
213
|
-
});
|
|
214
|
-
export type PresetVersion = z.infer<typeof presetVersion>;
|
|
215
|
-
|
|
216
|
-
export const presetVersionList = z.array(presetVersion);
|
|
217
|
-
|
|
218
|
-
/** `POST /api/presets/{name}/rollback` — the re-pointed active version. */
|
|
219
|
-
export const presetRollback = z.object({ name: z.string(), active_version: z.number() });
|
|
220
|
-
|
|
221
|
-
/** `DELETE /api/presets/{name}` — the removed preset. */
|
|
222
|
-
export const presetDeleted = z.object({ name: z.string(), deleted: z.literal(true) });
|
|
223
|
-
|
|
224
|
-
/** `POST /api/presets/{name}/rename` — the re-keyed record identity. */
|
|
225
|
-
export const presetRenamed = z.object({
|
|
226
|
-
name: z.string(),
|
|
227
|
-
renamed_from: z.string(),
|
|
228
|
-
active_version: z.number(),
|
|
229
|
-
});
|
|
230
|
-
export type PresetRenamed = z.infer<typeof presetRenamed>;
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* `GET /api/presets/{name}/referees` — every OTHER preset whose active authored
|
|
234
|
-
* composition names this one as a tool (the referees a rename would strand). An
|
|
235
|
-
* empty list is the clean case; a non-empty list means a rename is blocked until
|
|
236
|
-
* those presets are updated. A drift throws `ApiSchemaError`.
|
|
237
|
-
*/
|
|
238
|
-
export const presetReferees = z.object({
|
|
239
|
-
name: z.string(),
|
|
240
|
-
referees: z.array(z.string()),
|
|
241
|
-
});
|
|
242
|
-
export type PresetReferees = z.infer<typeof presetReferees>;
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* `POST /api/presets/validate` — the dry-run verdict for a preset draft. `valid`
|
|
246
|
-
* is the absence of an `error`; an invalid draft is a SUCCESSFUL validation (HTTP
|
|
247
|
-
* 200), so `error` carries the server's verbatim message. A drift throws
|
|
248
|
-
* `ApiSchemaError`.
|
|
249
|
-
*/
|
|
250
|
-
export const presetValidation = z.object({
|
|
251
|
-
valid: z.boolean(),
|
|
252
|
-
error: z.string().nullable(),
|
|
253
|
-
});
|
|
254
|
-
export type PresetValidation = z.infer<typeof presetValidation>;
|
|
255
|
-
|
|
256
|
-
/**
|
|
257
|
-
* `PUT /api/presets/{name}/versions/{version}/tags` — the re-annotated version.
|
|
258
|
-
* Version tags are labels on an immutable body, so this rebinds nothing; the
|
|
259
|
-
* response echoes the identity plus the new tag list. A drift throws
|
|
260
|
-
* `ApiSchemaError`.
|
|
261
|
-
*/
|
|
262
|
-
export const presetVersionTags = z.object({
|
|
263
|
-
name: z.string(),
|
|
264
|
-
version: z.number(),
|
|
265
|
-
tags: z.array(z.string()),
|
|
266
|
-
});
|
|
267
|
-
export type PresetVersionTags = z.infer<typeof presetVersionTags>;
|
|
268
|
-
|
|
269
|
-
// -- tool_meta (the organizational overlay) ----------------------------------
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* One folder in the tool-organization tree (`tool_folders`). `parent_id` is `null`
|
|
273
|
-
* for a root folder and otherwise the containing folder's `id`; nesting is endless
|
|
274
|
-
* via the parent chain. Ids are UUID strings. A drift throws `ApiSchemaError`.
|
|
275
|
-
*/
|
|
276
|
-
export const folderRecord = z.object({
|
|
277
|
-
id: z.string(),
|
|
278
|
-
name: z.string(),
|
|
279
|
-
parent_id: z.string().nullable(),
|
|
280
|
-
});
|
|
281
|
-
export type FolderRecord = z.infer<typeof folderRecord>;
|
|
282
|
-
|
|
283
|
-
/**
|
|
284
|
-
* The organizational overlay for one tool, keyed by `tool_name`. `display_name`
|
|
285
|
-
* overrides the rendered label (`display_name ?? name`); `folder_id` places the tool
|
|
286
|
-
* in a folder (`null` = unfiled); `tags` is the user's editable categorization,
|
|
287
|
-
* merged with the tool's read-only native tags by the UI; `badges` is the operator's
|
|
288
|
-
* editable capability-label overlay, merged with the tool's read-only plugin-declared
|
|
289
|
-
* badges by the UI (INFORMATIONAL, never an enforced gate); `hidden` is TRI-STATE —
|
|
290
|
-
* `null` = defer to the plugin declaration, `true` = force hidden, `false` = force
|
|
291
|
-
* visible. A drift throws `ApiSchemaError`.
|
|
292
|
-
*/
|
|
293
|
-
export const toolMetaRecord = z.object({
|
|
294
|
-
tool_name: z.string(),
|
|
295
|
-
display_name: z.string().nullable(),
|
|
296
|
-
folder_id: z.string().nullable(),
|
|
297
|
-
tags: z.array(z.string()),
|
|
298
|
-
badges: z.array(z.string()),
|
|
299
|
-
hidden: z.boolean().nullable(),
|
|
300
|
-
});
|
|
301
|
-
export type ToolMetaRecord = z.infer<typeof toolMetaRecord>;
|
|
302
|
-
|
|
303
|
-
/**
|
|
304
|
-
* `GET /api/tool-meta` — the whole overlay in one read: the flat folder tree plus
|
|
305
|
-
* every per-tool row. The UI builds the tree and merges the rows against the live
|
|
306
|
-
* tool list client-side. A drift throws `ApiSchemaError`.
|
|
307
|
-
*/
|
|
308
|
-
export const toolMetaOverlay = z.object({
|
|
309
|
-
folders: z.array(folderRecord),
|
|
310
|
-
meta: z.array(toolMetaRecord),
|
|
311
|
-
});
|
|
312
|
-
export type ToolMetaOverlay = z.infer<typeof toolMetaOverlay>;
|
|
313
|
-
|
|
314
|
-
/** `DELETE /api/tool-meta/tools/{tool_name}` — the dropped overlay row (idempotent). */
|
|
315
|
-
export const toolMetaDeleted = z.object({ tool_name: z.string(), deleted: z.literal(true) });
|
|
316
|
-
|
|
317
|
-
/** `DELETE /api/tool-meta/folders/{folder_id}` — the removed empty folder. */
|
|
318
|
-
export const folderDeleted = z.object({ folder_id: z.string(), deleted: z.literal(true) });
|
|
319
|
-
|
|
320
|
-
// -- templates ---------------------------------------------------------------
|
|
321
|
-
|
|
322
|
-
export const templateNames = z.array(z.string());
|
|
323
|
-
export const templateDetail = z.object({ template: z.string(), schema: jsonSchema });
|
|
324
|
-
export const templateUploaded = z.object({ path: z.string(), uploaded: z.literal(true) });
|
|
325
|
-
export const templateDeleted = z.object({ path: z.string(), deleted: z.literal(true) });
|
|
326
|
-
export const templateDirDeleted = z.object({ path: z.string(), deleted: z.literal(true) });
|
|
327
|
-
export const templateRendered = z.object({ rendered: z.string() });
|
|
328
|
-
export const templateCacheCleared = z.object({ cleared: z.literal(true) });
|
|
329
|
-
|
|
330
|
-
// -- storage -----------------------------------------------------------------
|
|
331
|
-
|
|
332
|
-
/** `GET /api/storage` — the storage-provider identity, or the absent sentinel
|
|
333
|
-
* (`present: false`, a 200) when no storage-provider plugin is installed. */
|
|
334
|
-
export const storageInfo = z.object({
|
|
335
|
-
present: z.boolean(),
|
|
336
|
-
provider: z.string().nullable(),
|
|
337
|
-
module: z.string().nullable(),
|
|
338
|
-
});
|
|
339
|
-
export type StorageInfo = z.infer<typeof storageInfo>;
|
|
340
|
-
|
|
341
|
-
/** `GET /api/storage/resources` — the full sorted resource-id list. */
|
|
342
|
-
export const storageResourceList = z.object({ resources: z.array(z.string()) });
|
|
343
|
-
|
|
344
|
-
/** `GET /api/storage/resources/{id}/stat` — an object's inferred content type;
|
|
345
|
-
* `null` when the provider cannot infer one (e.g. an unknown suffix). */
|
|
346
|
-
export const storageResourceStat = z.object({
|
|
347
|
-
id: z.string(),
|
|
348
|
-
content_type: z.string().nullable(),
|
|
349
|
-
});
|
|
350
|
-
export type StorageResourceStat = z.infer<typeof storageResourceStat>;
|
|
351
|
-
|
|
352
|
-
/** `POST /api/storage/resources` — the stored object's id. */
|
|
353
|
-
export const storageResourceStored = z.object({ id: z.string(), stored: z.literal(true) });
|
|
354
|
-
|
|
355
|
-
/** `DELETE /api/storage/resources/{id}` — the removed object's id. */
|
|
356
|
-
export const storageResourceDeleted = z.object({ id: z.string(), deleted: z.literal(true) });
|
|
357
|
-
|
|
358
|
-
/** `DELETE /api/storage/dirs/{path}` — the removed directory subtree. */
|
|
359
|
-
export const storageDirDeleted = z.object({ dir: z.string(), deleted: z.literal(true) });
|
|
360
|
-
|
|
361
|
-
// -- backend identity + fleet (worker bus) -----------------------------------
|
|
362
|
-
|
|
363
|
-
/** `GET /api/backend` — the execution-backend identity, or the absent sentinel
|
|
364
|
-
* (`present: false`, a 200) when no backend plugin is registered. Backend identity
|
|
365
|
-
* is kept distinct from the fleet: the fleet doors ride the app's worker bus and
|
|
366
|
-
* need no backend at all. */
|
|
367
|
-
export const backendInfo = z.object({
|
|
368
|
-
present: z.boolean(),
|
|
369
|
-
backend: z.string().nullable(),
|
|
370
|
-
module: z.string().nullable(),
|
|
371
|
-
});
|
|
372
|
-
export type BackendInfo = z.infer<typeof backendInfo>;
|
|
373
|
-
|
|
374
|
-
/** The two worker kinds that join the bus: an ASGI `serve` worker or a
|
|
375
|
-
* `backend` runtime process. A drift throws `ApiSchemaError`. */
|
|
376
|
-
export const workerKind = z.enum(['serve', 'backend']);
|
|
377
|
-
export type WorkerKind = z.infer<typeof workerKind>;
|
|
378
|
-
|
|
379
|
-
/** The lifecycle state a worker advertises in its presence value: `ready` once its
|
|
380
|
-
* resync has converged, `resyncing` while a boot/reconnect resync runs, `recycling`
|
|
381
|
-
* once it has begun a graceful self-exit. A drift throws `ApiSchemaError`. */
|
|
382
|
-
export const workerState = z.enum(['ready', 'resyncing', 'recycling']);
|
|
383
|
-
export type WorkerState = z.infer<typeof workerState>;
|
|
384
|
-
|
|
385
|
-
/** The last op a worker applied, stamped onto its presence row after the terminal
|
|
386
|
-
* reply. `outcome` is the free op-outcome string; `at` is the ISO instant it landed. */
|
|
387
|
-
export const workerLastOp = z.object({
|
|
388
|
-
op: z.string(),
|
|
389
|
-
outcome: z.string(),
|
|
390
|
-
at: z.string(),
|
|
391
|
-
});
|
|
392
|
-
export type WorkerLastOp = z.infer<typeof workerLastOp>;
|
|
393
|
-
|
|
394
|
-
/**
|
|
395
|
-
* One live worker on the bus — a presence-census row. `name` is the stable slot
|
|
396
|
-
* (`{kind}-{n}`) that doubles as a reload target; `generation` is the monotonic life
|
|
397
|
-
* counter minted with the worker's claim; `kind` tells the two worker kinds apart;
|
|
398
|
-
* `pid` is the process id. `joined_at`/`beat_at` are ISO instants (first-seen and last
|
|
399
|
-
* heartbeat) for the cosmetic seen-since display; `state` is the advertised lifecycle
|
|
400
|
-
* state; `stale` is SERVER-computed from the row's remaining presence TTL against the
|
|
401
|
-
* bus cadence (a quiet row past the freshness bound — reconnecting or dead) and is the
|
|
402
|
-
* only freshness signal a client reads, never a client-side threshold; `last_op` is the
|
|
403
|
-
* worker's last applied op, or `null` before it has applied one.
|
|
404
|
-
*/
|
|
405
|
-
export const fleetWorker = z.object({
|
|
406
|
-
name: z.string(),
|
|
407
|
-
kind: workerKind,
|
|
408
|
-
pid: z.number(),
|
|
409
|
-
generation: z.number(),
|
|
410
|
-
joined_at: z.string(),
|
|
411
|
-
beat_at: z.string(),
|
|
412
|
-
state: workerState,
|
|
413
|
-
stale: z.boolean(),
|
|
414
|
-
last_op: workerLastOp.nullable(),
|
|
415
|
-
});
|
|
416
|
-
export type FleetWorker = z.infer<typeof fleetWorker>;
|
|
417
|
-
|
|
418
|
-
/**
|
|
419
|
-
* `GET /api/fleet/workers` — the live worker fleet from the bus presence census.
|
|
420
|
-
* The census lists ALL subscribed workers (ASGI `serve` workers and backend-runtime
|
|
421
|
-
* processes alike), not only backend workers. A census read that fails surfaces as a
|
|
422
|
-
* loud 500, never a fabricated empty fleet.
|
|
423
|
-
*/
|
|
424
|
-
export const fleetWorkers = z.object({ workers: z.array(fleetWorker) });
|
|
425
|
-
export type FleetWorkers = z.infer<typeof fleetWorkers>;
|
|
426
|
-
|
|
427
|
-
/**
|
|
428
|
-
* One worker's outcome within a fleet broadcast. `applied`/`failed` are terminal wire
|
|
429
|
-
* replies from a subscriber; `missing`/`departed`/`timed_out` are publisher-computed
|
|
430
|
-
* from the presence census (a silent worker never sends them); `resyncing`/`recycling`/
|
|
431
|
-
* `stale` are the gap outcomes for a row that failed the ready+fresh gate — reported as
|
|
432
|
-
* its own actual condition rather than dropped (`resyncing` converges on its resync,
|
|
433
|
-
* `recycling` is departing, `stale` is a quiet row past the freshness bound carrying no
|
|
434
|
-
* convergence promise).
|
|
435
|
-
*/
|
|
436
|
-
export const fleetOutcome = z.enum([
|
|
437
|
-
'applied',
|
|
438
|
-
'failed',
|
|
439
|
-
'missing',
|
|
440
|
-
'departed',
|
|
441
|
-
'timed_out',
|
|
442
|
-
'resyncing',
|
|
443
|
-
'recycling',
|
|
444
|
-
'stale',
|
|
445
|
-
]);
|
|
446
|
-
export type FleetOutcome = z.infer<typeof fleetOutcome>;
|
|
447
|
-
|
|
448
|
-
/**
|
|
449
|
-
* One worker's result within a {@link fleetResult}. `payload` carries query-op data
|
|
450
|
-
* (opaque to the UI); `error` carries a failed apply's message; `detail` carries the
|
|
451
|
-
* publisher's report text for a computed gap outcome (`missing`/`departed`/`timed_out`/
|
|
452
|
-
* `resyncing`/`recycling`/`stale`). A drift throws `ApiSchemaError`.
|
|
453
|
-
*/
|
|
454
|
-
export const fleetWorkerResult = z.object({
|
|
455
|
-
name: z.string(),
|
|
456
|
-
outcome: fleetOutcome,
|
|
457
|
-
payload: jsonValue,
|
|
458
|
-
error: z.string().nullable(),
|
|
459
|
-
detail: z.string().nullable(),
|
|
460
|
-
});
|
|
461
|
-
export type FleetWorkerResult = z.infer<typeof fleetWorkerResult>;
|
|
462
|
-
|
|
463
|
-
/**
|
|
464
|
-
* The awaited per-worker report of one fleet broadcast. Two honest shapes ride the
|
|
465
|
-
* same schema. Reachable (`reachable: true`): `results` holds one entry per expected
|
|
466
|
-
* worker (the serving worker's own entry included) plus the gap rows, so an unconfirmed
|
|
467
|
-
* sibling is a visible `failed`/`missing`/`departed`/`timed_out`/`resyncing`/`recycling`/
|
|
468
|
-
* `stale` entry, never a silent stale worker. Bus-unreachable (`reachable: false`): the
|
|
469
|
-
* transport failed before any worker could reply, so `results` is empty and only `error`
|
|
470
|
-
* is carried. This is the bare body of `POST /api/fleet/reload-config` and the single-MCP
|
|
471
|
-
* reload; it is also the body the mode-wrapped {@link fleetReportFanout} carries under its
|
|
472
|
-
* `fleet` / `unreachable` modes.
|
|
473
|
-
*/
|
|
474
|
-
export const fleetResult = z.object({
|
|
475
|
-
op: z.string(),
|
|
476
|
-
reachable: z.boolean(),
|
|
477
|
-
local_only: z.boolean(),
|
|
478
|
-
results: z.array(fleetWorkerResult),
|
|
479
|
-
error: z.string().nullable(),
|
|
480
|
-
});
|
|
481
|
-
export type FleetResult = z.infer<typeof fleetResult>;
|
|
482
|
-
|
|
483
|
-
/**
|
|
484
|
-
* `POST /api/fleet/reload-config` — soft-restart the fleet and report per-worker. The
|
|
485
|
-
* serving worker applies its own reload first, then broadcasts; the returned report
|
|
486
|
-
* names every worker's outcome. A failed local apply does not abort the broadcast, so
|
|
487
|
-
* the report is embedded even on the convergence-failure path.
|
|
488
|
-
*/
|
|
489
|
-
export const fleetReloadResult = fleetResult;
|
|
490
|
-
export type FleetReloadResult = z.infer<typeof fleetReloadResult>;
|
|
491
|
-
|
|
492
|
-
/**
|
|
493
|
-
* The mode-wrapped fan-out summary a mutation embeds under its `fanout` field. Three
|
|
494
|
-
* honest modes, discriminated on `mode`:
|
|
495
|
-
* - `local-only` — the broadcast reached no sibling (a lone worker / no bus), a
|
|
496
|
-
* benign single-process note.
|
|
497
|
-
* - `fleet` — a reachable multi-worker broadcast; carries the full {@link
|
|
498
|
-
* fleetResult} so an unconfirmed sibling is visible.
|
|
499
|
-
* - `unreachable` — the bus itself could not be reached; carries the
|
|
500
|
-
* bus-unreachable {@link fleetResult} (no worker list, only `error`).
|
|
501
|
-
*
|
|
502
|
-
* Every mutation whose response embeds this parses it EXPLICITLY: zod's default
|
|
503
|
-
* unknown-key stripping would otherwise silently drop the field, hiding a failed
|
|
504
|
-
* propagation from the shared fleet-report handler. A drift throws `ApiSchemaError`.
|
|
505
|
-
*/
|
|
506
|
-
export const fleetReportFanout = z.discriminatedUnion('mode', [
|
|
507
|
-
z.object({ mode: z.literal('local-only'), note: z.string() }),
|
|
508
|
-
fleetResult.extend({ mode: z.literal('fleet') }),
|
|
509
|
-
fleetResult.extend({ mode: z.literal('unreachable') }),
|
|
510
|
-
]);
|
|
511
|
-
export type FleetReportFanout = z.infer<typeof fleetReportFanout>;
|
|
512
|
-
|
|
513
|
-
// -- manifest / mcp ----------------------------------------------------------
|
|
514
|
-
|
|
515
|
-
/**
|
|
516
|
-
* The back-reference a connector writes onto a manifest MCP entry to mark it
|
|
517
|
-
* connector-owned: the connection and the provider sub-service that own it.
|
|
518
|
-
* Hand-authored entries carry no `managed` marker.
|
|
519
|
-
*/
|
|
520
|
-
export const connectorRef = z.object({
|
|
521
|
-
connection_id: z.string(),
|
|
522
|
-
provider_id: z.string(),
|
|
523
|
-
sub_service: z.string(),
|
|
524
|
-
});
|
|
525
|
-
export type ConnectorRef = z.infer<typeof connectorRef>;
|
|
526
|
-
|
|
527
|
-
/**
|
|
528
|
-
* One entry of the live manifest's MCP section. Only the `managed` provenance
|
|
529
|
-
* marker is typed — the connect/disconnect flows write it server-side to point a
|
|
530
|
-
* connector-owned entry back at its connection, and the editor renders such
|
|
531
|
-
* entries read-only. `.nullish()` because a hand-authored entry carries `null`
|
|
532
|
-
* (present) or omits the key. Every other field (title, config, extensions) rides
|
|
533
|
-
* through `.loose()` unmodeled so the config editor keeps editing the whole
|
|
534
|
-
* entry — narrowing it to a typed subset would silently strip the fields it saves.
|
|
535
|
-
*/
|
|
536
|
-
export const manifestMcpEntry = z
|
|
537
|
-
.object({
|
|
538
|
-
managed: connectorRef.nullish(),
|
|
539
|
-
})
|
|
540
|
-
.loose();
|
|
541
|
-
export type ManifestMcpEntry = z.infer<typeof manifestMcpEntry>;
|
|
542
|
-
|
|
543
|
-
export const manifestView = z.object({
|
|
544
|
-
mcp: z.array(manifestMcpEntry),
|
|
545
|
-
user_tools: z.array(z.string()),
|
|
546
|
-
});
|
|
547
|
-
|
|
548
|
-
/**
|
|
549
|
-
* One `!ENV ${VAR[:default]}` marker the manifest's MCP section carries
|
|
550
|
-
* (`GET /api/manifest/mcp-env-refs`) — NAMES and BOOLEANS only, NEVER values.
|
|
551
|
-
* `pointer` is the RFC 6901 json-pointer of the leaf (`/mcp/<i>/config/...`);
|
|
552
|
-
* `has_default` is whether the marker carries a `:default`; `set` is whether the
|
|
553
|
-
* var resolves in the EFFECTIVE env (the resolution truth the install-time
|
|
554
|
-
* dangling refusal reads), so a var supplied by the deployment shows green, never
|
|
555
|
-
* a false red. The checklist derives from THIS alone — no env value is ever fetched.
|
|
556
|
-
*/
|
|
557
|
-
export const mcpEnvRef = z.object({
|
|
558
|
-
var: z.string(),
|
|
559
|
-
pointer: z.string(),
|
|
560
|
-
has_default: z.boolean(),
|
|
561
|
-
set: z.boolean(),
|
|
562
|
-
});
|
|
563
|
-
export type McpEnvRef = z.infer<typeof mcpEnvRef>;
|
|
564
|
-
export const mcpEnvRefs = z.array(mcpEnvRef);
|
|
565
|
-
export type McpEnvRefs = z.infer<typeof mcpEnvRefs>;
|
|
566
|
-
/**
|
|
567
|
-
* The apply result every config-writer mutation returns (`POST /api/mcp-config`,
|
|
568
|
-
* `POST /api/config/env`): the serving worker's local reload result (`status` +
|
|
569
|
-
* `env_keys`) plus the mode-wrapped fleet fan-out of the reload it broadcast. The
|
|
570
|
-
* `fanout` is parsed EXPLICITLY so the shared fleet-report handler can surface a
|
|
571
|
-
* failed propagation — zod's unknown-key stripping would otherwise hide it. A drift
|
|
572
|
-
* throws `ApiSchemaError`.
|
|
573
|
-
*/
|
|
574
|
-
export const reloadConfigResult = z.object({
|
|
575
|
-
status: z.string(),
|
|
576
|
-
env_keys: z.number(),
|
|
577
|
-
fanout: fleetReportFanout,
|
|
578
|
-
});
|
|
579
|
-
export type ReloadConfigResult = z.infer<typeof reloadConfigResult>;
|
|
580
|
-
|
|
581
|
-
// -- system kinds ------------------------------------------------------------
|
|
582
|
-
// `GET /api/system/kinds` — one row per pluggable kind (identity, accounts,
|
|
583
|
-
// monitoring, storage, backend, channels, webhook_verifiers, config,
|
|
584
|
-
// studio_plugins). `state` is the kind's active/default/off status: `active` = a
|
|
585
|
-
// real plugin serves it, `default` = a built-in fallback serves it, `off` =
|
|
586
|
-
// nothing is registered (a legal state, reported not "fixed"). `plugin` is the
|
|
587
|
-
// provider/module name when known, else null. Plain (non-strict) `z.object` so a
|
|
588
|
-
// server that adds a field to the row still parses.
|
|
589
|
-
|
|
590
|
-
export const kindStatus = z.object({
|
|
591
|
-
kind: z.string(),
|
|
592
|
-
state: z.enum(['active', 'default', 'off']),
|
|
593
|
-
plugin: z.string().nullable(),
|
|
594
|
-
detail: z.string(),
|
|
595
|
-
});
|
|
596
|
-
export const kindStatusList = z.array(kindStatus);
|
|
597
|
-
export type KindStatus = z.infer<typeof kindStatus>;
|
|
598
|
-
|
|
599
|
-
/**
|
|
600
|
-
* `POST /api/tools/{name}/extensions` — the apply result. The write persists the
|
|
601
|
-
* manifest, reloads locally, then broadcasts the reload to the whole fleet. The
|
|
602
|
-
* response is the one apply-result shape every config-writer returns: the local
|
|
603
|
-
* reload result (`status` + `env_keys`) plus the mode-wrapped fleet `fanout`. The
|
|
604
|
-
* fan-out rides EVERY deployment (a lone worker reports `local-only`), so this flat
|
|
605
|
-
* shape parses every save and the shared fleet-report handler renders any failed
|
|
606
|
-
* propagation from `fanout`.
|
|
607
|
-
*/
|
|
608
|
-
export const toolExtensionsApplyResult = reloadConfigResult;
|
|
609
|
-
export type ToolExtensionsApplyResult = z.infer<typeof toolExtensionsApplyResult>;
|
|
610
|
-
export const mcpStatus = z.object({
|
|
611
|
-
bound: z.record(z.string(), z.array(z.string())),
|
|
612
|
-
failed: z.array(z.object({ title: z.string(), status: z.string() })),
|
|
613
|
-
});
|
|
614
|
-
|
|
615
|
-
/**
|
|
616
|
-
* `POST /api/mcp-status/{title}/reload` — re-probe a single MCP server and broadcast
|
|
617
|
-
* the reload to the fleet. The response is the bare per-worker {@link fleetResult}
|
|
618
|
-
* (the serving worker's re-probe rides its own `results` entry as the payload); there
|
|
619
|
-
* is no local/workers split. A drift throws `ApiSchemaError`.
|
|
620
|
-
*/
|
|
621
|
-
export const mcpReloadResult = fleetResult;
|
|
622
|
-
export type McpReloadResult = z.infer<typeof mcpReloadResult>;
|
|
623
|
-
|
|
624
|
-
// -- sub-mcp -----------------------------------------------------------------
|
|
625
|
-
|
|
626
|
-
/**
|
|
627
|
-
* One registered sub-MCP mount as it rides the registry list and the projection:
|
|
628
|
-
* the tools it exposes and the transport it serves on. In `GET /api/sub-mcp` the
|
|
629
|
-
* slug is the map key, so the mount value carries no slug; {@link subMcpEntry}
|
|
630
|
-
* extends this with `slug` for the capability projection where mounts are a flat
|
|
631
|
-
* list. `transport` is always present on the wire (the server defaults it to
|
|
632
|
-
* `http`), so it is required — its absence is a drift, not a legal shape.
|
|
633
|
-
*/
|
|
634
|
-
export const subMcpMount = z.object({
|
|
635
|
-
tools: z.array(z.string()),
|
|
636
|
-
transport: z.string(),
|
|
637
|
-
});
|
|
638
|
-
export type SubMcpMount = z.infer<typeof subMcpMount>;
|
|
639
|
-
|
|
640
|
-
export const subMcpList = z.record(z.string(), subMcpMount);
|
|
641
|
-
export const subMcpCreated = z.object({
|
|
642
|
-
slug: z.string(),
|
|
643
|
-
tools: z.array(z.string()),
|
|
644
|
-
transport: z.string(),
|
|
645
|
-
});
|
|
646
|
-
export const subMcpRemoved = z.object({ slug: z.string(), removed: z.literal(true) });
|
|
647
|
-
|
|
648
|
-
// -- config ------------------------------------------------------------------
|
|
649
|
-
|
|
650
|
-
export const envConfig = z.object({
|
|
651
|
-
env: z.record(z.string(), z.string()),
|
|
652
|
-
secret_keys: z.array(z.string()),
|
|
653
|
-
});
|
|
654
|
-
/**
|
|
655
|
-
* `GET /api/config/mode` — the active config backend mode (`file` / `k8s`). The
|
|
656
|
-
* skeleton emits only `config_mode`; `read_only` is a UI-side gate, tolerated-absent
|
|
657
|
-
* and defaulting to `false` (writable) so a normal response never drifts, while a
|
|
658
|
-
* genuinely read-only deployment can opt in by emitting `read_only: true`.
|
|
659
|
-
*/
|
|
660
|
-
export const configMode = z.object({
|
|
661
|
-
config_mode: z.string(),
|
|
662
|
-
read_only: z.boolean().default(false),
|
|
663
|
-
});
|
|
664
|
-
|
|
665
|
-
// -- settings profiles -------------------------------------------------------
|
|
666
|
-
// The admin-only `/api/config/profiles/*` surface. Secrets ride the wire in the
|
|
667
|
-
// clear (secret/fenced routes); masking is CLIENT-SIDE per the secret-mask union. A drift
|
|
668
|
-
// on any of these throws `ApiSchemaError`.
|
|
669
|
-
|
|
670
|
-
/**
|
|
671
|
-
* `GET /api/config/profiles` — one row per stored profile. The list is
|
|
672
|
-
* names+descriptions ONLY (action=read); no `env`, no `secret_keys`, no bodies.
|
|
673
|
-
* (No `last_modified`: the list carries identity, not history — version metadata
|
|
674
|
-
* is the `/versions` surface — so the list renders no last-modified column.)
|
|
675
|
-
*/
|
|
676
|
-
export const settingsProfileSummary = z.object({
|
|
677
|
-
name: z.string(),
|
|
678
|
-
description: z.string(),
|
|
679
|
-
});
|
|
680
|
-
export type SettingsProfileSummary = z.infer<typeof settingsProfileSummary>;
|
|
681
|
-
export const settingsProfileList = z.array(settingsProfileSummary);
|
|
682
|
-
|
|
683
|
-
/**
|
|
684
|
-
* `GET /api/config/profiles/{name}` and each version body — the stored profile
|
|
685
|
-
* document (action=secret). `env` carries REAL values; `secret_keys` is the
|
|
686
|
-
* per-profile secret-marks band folded into the secret-mask union for masking.
|
|
687
|
-
*/
|
|
688
|
-
export const settingsProfileBody = z.object({
|
|
689
|
-
description: z.string(),
|
|
690
|
-
env: z.record(z.string(), z.string()),
|
|
691
|
-
secret_keys: z.array(z.string()),
|
|
692
|
-
});
|
|
693
|
-
export type SettingsProfileBody = z.infer<typeof settingsProfileBody>;
|
|
694
|
-
|
|
695
|
-
/** `PUT /api/config/profiles/{name}` — a minimal save ack; `version` is the new store version. */
|
|
696
|
-
export const settingsProfileSaved = z.object({
|
|
697
|
-
ok: z.literal(true),
|
|
698
|
-
version: z.number().optional(),
|
|
699
|
-
});
|
|
700
|
-
export type SettingsProfileSaved = z.infer<typeof settingsProfileSaved>;
|
|
701
|
-
|
|
702
|
-
/** `DELETE /api/config/profiles/{name}` — a minimal removal ack. */
|
|
703
|
-
export const settingsProfileDeleted = z.object({ ok: z.literal(true) });
|
|
704
|
-
|
|
705
|
-
/** `POST /api/config/profiles/{name}/rollback` — the restore ack; `version` is the resulting active version. */
|
|
706
|
-
export const settingsProfileRollback = z.object({
|
|
707
|
-
ok: z.literal(true),
|
|
708
|
-
version: z.number(),
|
|
709
|
-
});
|
|
710
|
-
export type SettingsProfileRollback = z.infer<typeof settingsProfileRollback>;
|
|
711
|
-
|
|
712
|
-
/**
|
|
713
|
-
* `POST /api/config/profiles/{name}/diff` — the SAVED profile vs the stored env
|
|
714
|
-
* (action=secret). `changed` carries real `old`/`new` values (UI masks via
|
|
715
|
-
* JsonDiff); `recycle_keys`/`refused_keys` are the diff's recycle-class and
|
|
716
|
-
* boundary-refused key names, called out in the UI before apply.
|
|
717
|
-
*/
|
|
718
|
-
export const settingsProfileDiff = z.object({
|
|
719
|
-
added: z.array(z.string()),
|
|
720
|
-
removed: z.array(z.string()),
|
|
721
|
-
changed: z.array(z.object({ key: z.string(), old: z.string(), new: z.string() })),
|
|
722
|
-
recycle_keys: z.array(z.string()),
|
|
723
|
-
refused_keys: z.array(z.string()),
|
|
724
|
-
});
|
|
725
|
-
export type SettingsProfileDiff = z.infer<typeof settingsProfileDiff>;
|
|
726
|
-
|
|
727
|
-
/**
|
|
728
|
-
* `POST /api/config/profiles/{name}/apply` — the dedicated `profile_apply_response`
|
|
729
|
-
* (action=fenced, destructive). NAMES-ONLY (no env value in any
|
|
730
|
-
* section): `hot` is the hot-swapped key names; `recycle` is the orchestrator's
|
|
731
|
-
* per-worker section — one `{name, kind, status, generation_before}` row per recycled
|
|
732
|
-
* target, `generation_before` the life that was recycled, the applier's OWN row carrying
|
|
733
|
-
* the `self-deferred` status literal when the diff has serve-affecting recycle keys;
|
|
734
|
-
* `fresh` is the per-kind list of NEW ready lives observed since the pre-apply snapshot
|
|
735
|
-
* (each `{name, kind, generation}`), evidence of fresh capacity and never claimed as any
|
|
736
|
-
* target's successor; `refused` is `[]` on success by construction (populated
|
|
737
|
-
* `{key, reason}` only on a refusal), the populated refusal surfaces being the diff
|
|
738
|
-
* preview and the refusal error report. `fanout` is the mode-wrapped fleet broadcast,
|
|
739
|
-
* parsed EXPLICITLY so a failed propagation reaches the shared fleet-report handler. A
|
|
740
|
-
* drift throws `ApiSchemaError`.
|
|
741
|
-
*/
|
|
742
|
-
export const profileApplyResponse = z.object({
|
|
743
|
-
hot: z.array(z.string()),
|
|
744
|
-
recycle: z.array(
|
|
745
|
-
z.object({
|
|
746
|
-
name: z.string(),
|
|
747
|
-
kind: z.string(),
|
|
748
|
-
status: z.string(),
|
|
749
|
-
generation_before: z.number(),
|
|
750
|
-
}),
|
|
751
|
-
),
|
|
752
|
-
fresh: z.array(z.object({ name: z.string(), kind: z.string(), generation: z.number() })),
|
|
753
|
-
refused: z.array(z.object({ key: z.string(), reason: z.string() })),
|
|
754
|
-
fanout: fleetReportFanout,
|
|
755
|
-
});
|
|
756
|
-
export type ProfileApplyResponse = z.infer<typeof profileApplyResponse>;
|
|
757
|
-
|
|
758
|
-
/**
|
|
759
|
-
* `GET /api/config/profiles/{name}/versions` — version METADATA only (action=read;
|
|
760
|
-
* no bodies), the generic versioned-store row minus `body`. `is_current` flags the
|
|
761
|
-
* active pointer.
|
|
762
|
-
*/
|
|
763
|
-
export const settingsProfileVersionMeta = z.object({
|
|
764
|
-
version: z.number(),
|
|
765
|
-
tags: z.array(z.string()),
|
|
766
|
-
created_at: z.string(),
|
|
767
|
-
is_current: z.boolean(),
|
|
768
|
-
});
|
|
769
|
-
export type SettingsProfileVersionMeta = z.infer<typeof settingsProfileVersionMeta>;
|
|
770
|
-
export const settingsProfileVersionList = z.array(settingsProfileVersionMeta);
|
|
771
|
-
|
|
772
|
-
/**
|
|
773
|
-
* `GET /api/config/profiles/{name}/versions/{version}` — one immutable version WITH
|
|
774
|
-
* its `body` (action=secret; body rendered masked per the secret-mask union). The generic
|
|
775
|
-
* versioned-store row shape.
|
|
776
|
-
*/
|
|
777
|
-
export const settingsProfileVersion = settingsProfileVersionMeta.extend({
|
|
778
|
-
body: settingsProfileBody,
|
|
779
|
-
});
|
|
780
|
-
export type SettingsProfileVersion = z.infer<typeof settingsProfileVersion>;
|
|
781
|
-
|
|
782
|
-
// -- connectors --------------------------------------------------------------
|
|
783
|
-
|
|
784
|
-
export const subServiceView = z.object({
|
|
785
|
-
id: z.string(),
|
|
786
|
-
display_name: z.string(),
|
|
787
|
-
description: z.string(),
|
|
788
|
-
scopes: z.array(z.string()),
|
|
789
|
-
});
|
|
790
|
-
|
|
791
|
-
export const configFieldView = z.object({
|
|
792
|
-
key: z.string(),
|
|
793
|
-
label: z.string(),
|
|
794
|
-
target: z.enum(['env', 'header']),
|
|
795
|
-
required: z.boolean(),
|
|
796
|
-
secret: z.boolean(),
|
|
797
|
-
});
|
|
798
|
-
|
|
799
|
-
export const providerView = z.object({
|
|
800
|
-
id: z.string(),
|
|
801
|
-
display_name: z.string(),
|
|
802
|
-
description: z.string(),
|
|
803
|
-
// Required and a real URL: the contract's `ProviderDescriptor.icon_url` runs
|
|
804
|
-
// `check_web_url(schemes=("https",))`, which rejects an empty/relative value, so
|
|
805
|
-
// an empty or malformed one here is drift and fails the parse loudly.
|
|
806
|
-
icon_url: z.url(),
|
|
807
|
-
kind: z.enum(['oauth', 'none']),
|
|
808
|
-
origin: z.enum(['system', 'community']),
|
|
809
|
-
category: z.string(),
|
|
810
|
-
sub_services: z.array(subServiceView),
|
|
811
|
-
config_fields: z.array(configFieldView),
|
|
812
|
-
});
|
|
813
|
-
export type ProviderView = z.infer<typeof providerView>;
|
|
814
|
-
|
|
815
|
-
/**
|
|
816
|
-
* One `connector_category` grouping row served alongside the catalog: the UI's
|
|
817
|
-
* label and sort key for the providers it groups, so the list can group, order,
|
|
818
|
-
* and label providers by category without a second read.
|
|
819
|
-
*/
|
|
820
|
-
export const connectorCategoryView = z.object({
|
|
821
|
-
id: z.string(),
|
|
822
|
-
display_name: z.string(),
|
|
823
|
-
sort_order: z.number(),
|
|
824
|
-
});
|
|
825
|
-
export type ConnectorCategoryView = z.infer<typeof connectorCategoryView>;
|
|
826
|
-
|
|
827
|
-
/**
|
|
828
|
-
* `GET /api/connectors/providers` — the provider catalog: the providers plus the
|
|
829
|
-
* category groupings the UI arranges them under. Reshaped from a bare provider
|
|
830
|
-
* array so the category label/order surface rides the same read.
|
|
831
|
-
*/
|
|
832
|
-
export const providers = z.object({
|
|
833
|
-
providers: z.array(providerView),
|
|
834
|
-
categories: z.array(connectorCategoryView),
|
|
835
|
-
});
|
|
836
|
-
export type ProviderCatalogResponse = z.infer<typeof providers>;
|
|
837
|
-
|
|
838
|
-
export const connectionView = z.object({
|
|
839
|
-
connection_id: z.string(),
|
|
840
|
-
provider_id: z.string(),
|
|
841
|
-
alias: z.string(),
|
|
842
|
-
kind: z.enum(['oauth', 'none']),
|
|
843
|
-
account_identity: z.string().nullable(),
|
|
844
|
-
enabled_sub_services: z.array(z.string()),
|
|
845
|
-
granted_scopes: z.array(z.string()),
|
|
846
|
-
// Sub-services whose MCP server did not answer a live reachability probe.
|
|
847
|
-
// Populated only on the single-connection GET (the list projection is
|
|
848
|
-
// probe-free and always sends `[]`). Reachability is distinct from
|
|
849
|
-
// `auth_health_state`: a healthy connection can still have a down sub-service.
|
|
850
|
-
// Defaulted so a projection that omits it (an older worker mid-rollout) still
|
|
851
|
-
// parses rather than false-failing the whole view.
|
|
852
|
-
unreachable_sub_services: z.array(z.string()).default([]),
|
|
853
|
-
auth_health_state: z.enum(['healthy', 'reconnect_required', 'refresh_failing']),
|
|
854
|
-
created_at: z.string(),
|
|
855
|
-
});
|
|
856
|
-
export type ConnectionView = z.infer<typeof connectionView>;
|
|
857
|
-
|
|
858
|
-
export const connectionsList = z.object({
|
|
859
|
-
items: z.array(connectionView),
|
|
860
|
-
total: z.number(),
|
|
861
|
-
// Count of connections whose `auth_health_state` is not healthy across the whole
|
|
862
|
-
// set (independent of any filter/limit) — the attention-badge count. Optional:
|
|
863
|
-
// no UI consumes it, and an older worker mid-rollout omits it.
|
|
864
|
-
unhealthy: z.number().optional(),
|
|
865
|
-
});
|
|
866
|
-
|
|
867
|
-
// A connector mutation that writes the manifest embeds the mode-wrapped fleet
|
|
868
|
-
// `fanout` of the reload it broadcast; it is `null` when the response path mutated no
|
|
869
|
-
// manifest (an OAuth START opens a flow before any write). Parsed EXPLICITLY so the
|
|
870
|
-
// shared fleet-report handler surfaces a failed propagation on every connector flow —
|
|
871
|
-
// zod's unknown-key stripping would otherwise drop it silently.
|
|
872
|
-
export const startConnectResult = z.union([
|
|
873
|
-
z.object({ flow_id: z.string(), authorize_url: z.string() }),
|
|
874
|
-
z.object({
|
|
875
|
-
connection_id: z.string(),
|
|
876
|
-
added_manifest_entries: z.array(z.string()),
|
|
877
|
-
fanout: fleetReportFanout.nullable(),
|
|
878
|
-
}),
|
|
879
|
-
]);
|
|
880
|
-
|
|
881
|
-
// A reconnect START opens an OAuth flow and writes no manifest, so it carries no
|
|
882
|
-
// fan-out (the manifest write lands when the flow completes).
|
|
883
|
-
export const reconnectResult = z.object({ flow_id: z.string(), authorize_url: z.string() });
|
|
884
|
-
|
|
885
|
-
export const disconnectResult = z.object({
|
|
886
|
-
connection_id: z.string(),
|
|
887
|
-
upstream_revoke_outcome: z.enum(['success', 'failed', 'skipped']),
|
|
888
|
-
upstream_revoke_status: z.number().nullable(),
|
|
889
|
-
removed_manifest_entries: z.array(z.string()),
|
|
890
|
-
fanout: fleetReportFanout.nullable(),
|
|
891
|
-
});
|
|
892
|
-
|
|
893
|
-
export const patchSubServicesResult = z.object({
|
|
894
|
-
connection_id: z.string(),
|
|
895
|
-
enabled_sub_services: z.array(z.string()),
|
|
896
|
-
consent_required: z.boolean(),
|
|
897
|
-
flow_id: z.string().nullable(),
|
|
898
|
-
authorize_url: z.string().nullable(),
|
|
899
|
-
added_manifest_entries: z.array(z.string()),
|
|
900
|
-
removed_manifest_entries: z.array(z.string()),
|
|
901
|
-
// `null` on a consent-only toggle that forks an OAuth flow without a manifest write.
|
|
902
|
-
fanout: fleetReportFanout.nullable(),
|
|
903
|
-
});
|
|
904
|
-
|
|
905
|
-
export const oauthCompleteResult = z.discriminatedUnion('kind', [
|
|
906
|
-
z.object({
|
|
907
|
-
kind: z.literal('success'),
|
|
908
|
-
connection_id: z.string(),
|
|
909
|
-
return_url: z.string(),
|
|
910
|
-
// `null` when completing the flow mutated no manifest (a reconcile that changed
|
|
911
|
-
// nothing).
|
|
912
|
-
fanout: fleetReportFanout.nullable(),
|
|
913
|
-
}),
|
|
914
|
-
z.object({ kind: z.literal('failed'), reason: z.string() }),
|
|
915
|
-
z.object({ kind: z.literal('cancelled'), message: z.string() }),
|
|
916
|
-
]);
|
|
917
|
-
export type OAuthCompleteResult = z.infer<typeof oauthCompleteResult>;
|
|
918
|
-
|
|
919
|
-
// -- studio plugin registry --------------------------------------------------
|
|
920
|
-
|
|
921
|
-
export const studioPluginManifest = z.object({
|
|
922
|
-
name: z.string(),
|
|
923
|
-
version: z.string(),
|
|
924
|
-
api_version: z.number(),
|
|
925
|
-
entry: z.string(),
|
|
926
|
-
integrity: z.record(z.string(), z.string()),
|
|
927
|
-
contributions: z.object({
|
|
928
|
-
tool_panels: z.record(z.string(), z.string()).default({}),
|
|
929
|
-
pages: z.array(z.string()).default([]),
|
|
930
|
-
settings_tabs: z.array(z.string()).default([]),
|
|
931
|
-
// Optional with a default so a manifest without the field still parses; the
|
|
932
|
-
// non-strict object would otherwise SILENTLY STRIP an undeclared field, so a
|
|
933
|
-
// server that serves `nav_entries` would never reach the UI.
|
|
934
|
-
nav_entries: z.array(z.string()).default([]),
|
|
935
|
-
}),
|
|
936
|
-
});
|
|
937
|
-
export const studioPluginRegistry = z.array(studioPluginManifest);
|
|
938
|
-
export type StudioPluginManifest = z.infer<typeof studioPluginManifest>;
|
|
939
|
-
|
|
940
|
-
/**
|
|
941
|
-
* The page window every paged read door carries; `next_page` is null on the last
|
|
942
|
-
* page. `truncated` is TRUE when the door had more matches than it would scan or
|
|
943
|
-
* return under its cap — the UI must surface that LOUDLY, never a silent cut — and
|
|
944
|
-
* false whenever the window is exhaustive.
|
|
945
|
-
*/
|
|
946
|
-
const pageWindow = {
|
|
947
|
-
total: z.number(),
|
|
948
|
-
page: z.number(),
|
|
949
|
-
page_size: z.number(),
|
|
950
|
-
next_page: z.number().nullable(),
|
|
951
|
-
truncated: z.boolean(),
|
|
952
|
-
};
|
|
953
|
-
|
|
954
|
-
// -- interactions ------------------------------------------------------------
|
|
955
|
-
// Shapes match the skeleton's interactions SSE contract: the SSE
|
|
956
|
-
// `interaction.add` frame carries the question and its answer format; the answer
|
|
957
|
-
// door returns { interaction_id, status }. `answered` is not a wire field — it
|
|
958
|
-
// is a client-side flag the stream hook flips on an `interaction.answered` event.
|
|
959
|
-
|
|
960
|
-
export const answerFormat = z.enum(['text', 'confirm', 'select', 'form', 'external']);
|
|
961
|
-
export type AnswerFormat = z.infer<typeof answerFormat>;
|
|
962
|
-
|
|
963
|
-
/** The kind of a question's display-only media item: a remote/inline image, or a link. */
|
|
964
|
-
export const mediaKind = z.enum(['image', 'link']);
|
|
965
|
-
export type MediaKind = z.infer<typeof mediaKind>;
|
|
966
|
-
|
|
967
|
-
/**
|
|
968
|
-
* One item of a question's display-only media. Applied PER ITEM by the renderer
|
|
969
|
-
* (never as a strict array on the frame): the frame's `media` field is a loose
|
|
970
|
-
* `z.array(z.unknown())`, and the renderer `safeParse`s each item with this schema
|
|
971
|
-
* so one malformed/hostile item is a loud per-item notice, not a whole-frame parse
|
|
972
|
-
* failure that would silently vanish an answerable question.
|
|
973
|
-
*
|
|
974
|
-
* `caption` is `.nullish()` (absent OR `null` both parse to a caption-less item):
|
|
975
|
-
* a caption-less item may arrive with the key omitted OR with an explicit `null`, so
|
|
976
|
-
* `.optional()` here would false-fail the explicit `null` and render a good image as
|
|
977
|
-
* malformed. `url` and `kind` are the only load-bearing fields; the image
|
|
978
|
-
* src scheme gate and the link neutralization are enforced by the renderer.
|
|
979
|
-
*/
|
|
980
|
-
export const interactionMediaItem = z.object({
|
|
981
|
-
kind: mediaKind,
|
|
982
|
-
url: z.string(),
|
|
983
|
-
caption: z.string().nullish(),
|
|
984
|
-
});
|
|
985
|
-
export type InteractionMediaItem = z.infer<typeof interactionMediaItem>;
|
|
986
|
-
|
|
987
|
-
/**
|
|
988
|
-
* One per-send choice for a `form` property whose schema is a string (or array of
|
|
989
|
-
* strings). `value` is what the answer carries; `label` (absent OR null both parse
|
|
990
|
-
* to no label) is the human text shown in its place. A send may replace a property's
|
|
991
|
-
* `enum` this way for one ask without republishing the form. Applied per property by
|
|
992
|
-
* the form preview (safeParsed), so a malformed entry is a loud notice, never silent.
|
|
993
|
-
*/
|
|
994
|
-
export const formOption = z.object({
|
|
995
|
-
value: z.string(),
|
|
996
|
-
label: z.string().nullish(),
|
|
997
|
-
});
|
|
998
|
-
export type FormOption = z.infer<typeof formOption>;
|
|
999
|
-
|
|
1000
|
-
/**
|
|
1001
|
-
* Per-send `form` data: `values` prefills top-level properties (keyed by property
|
|
1002
|
-
* name), `options` supplies per-send choice lists (keyed by property name). Both
|
|
1003
|
-
* default to empty. The form preview safeParses this off `format_payload.data`, so a
|
|
1004
|
-
* malformed block is a loud notice rather than a whole-frame parse failure.
|
|
1005
|
-
*/
|
|
1006
|
-
export const formData = z.object({
|
|
1007
|
-
values: z.record(z.string(), z.unknown()).default({}),
|
|
1008
|
-
options: z.record(z.string(), z.array(formOption)).default({}),
|
|
1009
|
-
});
|
|
1010
|
-
export type FormData = z.infer<typeof formData>;
|
|
1011
|
-
|
|
1012
|
-
/**
|
|
1013
|
-
* One page of a stepped `form`: a `title` and the ordered top-level property names it
|
|
1014
|
-
* groups. `format_payload.pages` is the ordered list of these; absent = one page. The
|
|
1015
|
-
* form preview safeParses the list, so a malformed page is a loud notice, never silent.
|
|
1016
|
-
*/
|
|
1017
|
-
export const formPage = z.object({
|
|
1018
|
-
title: z.string(),
|
|
1019
|
-
fields: z.array(z.string()),
|
|
1020
|
-
});
|
|
1021
|
-
export type FormPage = z.infer<typeof formPage>;
|
|
1022
|
-
|
|
1023
|
-
/** The `form` pages list (`format_payload.pages`), safeParsed as a whole by the preview. */
|
|
1024
|
-
export const formPages = z.array(formPage);
|
|
1025
|
-
export type FormPages = z.infer<typeof formPages>;
|
|
1026
|
-
|
|
1027
|
-
export const interaction = z.object({
|
|
1028
|
-
interaction_id: z.string(),
|
|
1029
|
-
group_id: z.string(),
|
|
1030
|
-
question: z.string().default(''),
|
|
1031
|
-
answer_format: answerFormat,
|
|
1032
|
-
// Format-specific payload: select options, form JSON schema (with optional per-send
|
|
1033
|
-
// `data` and `pages`), external url. The wire sends `null` for formats that carry
|
|
1034
|
-
// none (text/confirm); it is normalized to `{}` so consumers always see an object.
|
|
1035
|
-
format_payload: z
|
|
1036
|
-
.record(z.string(), z.unknown())
|
|
1037
|
-
.nullish()
|
|
1038
|
-
.transform((value) => value ?? {}),
|
|
1039
|
-
created_at: z.string(),
|
|
1040
|
-
timeout_at: z.string(),
|
|
1041
|
-
// Whether the answer body is sensitive and never persisted server-side. Rides
|
|
1042
|
-
// every add frame; an absent value (older frame) normalizes to false.
|
|
1043
|
-
sensitive: z.boolean().default(false),
|
|
1044
|
-
// True only for an external question answered by a signed server-to-server
|
|
1045
|
-
// callback (never by a human); the frame never carries the verifier object.
|
|
1046
|
-
// Absent/undefined for every other question.
|
|
1047
|
-
server_verified: z.boolean().optional(),
|
|
1048
|
-
// Name of the channel plugin the question was also delivered through (e.g.
|
|
1049
|
-
// "telegram"); absent when the question lives only in this inbox.
|
|
1050
|
-
channel: z.string().optional(),
|
|
1051
|
-
// Interaction attribution, each additive and absent when unset. `recipient` is
|
|
1052
|
-
// the channel delivery address the question went to; `origin` is the run id of
|
|
1053
|
-
// the background tool run that asked; `audience` is the user_id the question is
|
|
1054
|
-
// addressed to. Display/binding data only, never an authorization axis; a
|
|
1055
|
-
// present non-string is malformed.
|
|
1056
|
-
recipient: z.string().optional(),
|
|
1057
|
-
origin: z.string().optional(),
|
|
1058
|
-
audience: z.string().optional(),
|
|
1059
|
-
// Display-only media shown WITH the question (images and/or links). Absent when
|
|
1060
|
-
// the question carries none. Deliberately LOOSE (`z.array(z.unknown())`): each
|
|
1061
|
-
// item is `safeParse`d per item by the renderer against `interactionMediaItem`,
|
|
1062
|
-
// so one malformed/hostile item can never fail the whole frame parse and hide an
|
|
1063
|
-
// answerable question. A present non-array value is still malformed.
|
|
1064
|
-
media: z.array(z.unknown()).optional(),
|
|
1065
|
-
});
|
|
1066
|
-
export type Interaction = z.infer<typeof interaction>;
|
|
1067
|
-
|
|
1068
|
-
/** The answer door's response — the blocked caller was woken. */
|
|
1069
|
-
export const interactionAnswered = z.object({
|
|
1070
|
-
interaction_id: z.string(),
|
|
1071
|
-
status: z.string(),
|
|
1072
|
-
});
|
|
1073
|
-
export type InteractionAnswered = z.infer<typeof interactionAnswered>;
|
|
1074
|
-
|
|
1075
|
-
/**
|
|
1076
|
-
* The cancel door's response — a pending ask was WITHDRAWN without an answer (the
|
|
1077
|
-
* asking flow does not resume). `status` is `"cancelled"`; the shape mirrors the
|
|
1078
|
-
* answer door's terminal reply, but the door is distinct so it carries its own
|
|
1079
|
-
* schema.
|
|
1080
|
-
*/
|
|
1081
|
-
export const interactionCancelled = z.object({
|
|
1082
|
-
interaction_id: z.string(),
|
|
1083
|
-
status: z.string(),
|
|
1084
|
-
});
|
|
1085
|
-
export type InteractionCancelled = z.infer<typeof interactionCancelled>;
|
|
1086
|
-
|
|
1087
|
-
/**
|
|
1088
|
-
* A page of pending interactions from `GET /api/interactions?page=&pageSize=`. Each
|
|
1089
|
-
* item is the same record the stream's `interaction.add` frame carries. The pending
|
|
1090
|
-
* set is the paged base the tail-only stream applies live deltas over.
|
|
1091
|
-
*/
|
|
1092
|
-
export const interactionsPage = z.object({
|
|
1093
|
-
items: z.array(interaction),
|
|
1094
|
-
...pageWindow,
|
|
1095
|
-
});
|
|
1096
|
-
export type InteractionsPage = z.infer<typeof interactionsPage>;
|
|
1097
|
-
|
|
1098
|
-
// -- channels ----------------------------------------------------------------
|
|
1099
|
-
// The installed channel-plugin catalog: names registered via the manifest's
|
|
1100
|
-
// channel modules. A deployment with none bound answers questions only in this
|
|
1101
|
-
// inbox (the Studio default).
|
|
1102
|
-
|
|
1103
|
-
export const channels = z.object({
|
|
1104
|
-
channels: z.array(z.string()),
|
|
1105
|
-
});
|
|
1106
|
-
export type Channels = z.infer<typeof channels>;
|
|
1107
|
-
|
|
1108
|
-
// -- conversations -----------------------------------------------------------
|
|
1109
|
-
// The cross-channel conversation monitor's READ side: the stored routing rows
|
|
1110
|
-
// (the route picker) from `GET /api/conversations`, a route's threads from
|
|
1111
|
-
// `GET /api/conversations/{route}/threads`, and one thread's transcript from
|
|
1112
|
-
// `GET /api/conversations/{route}/transcript?thread_id=`. Timestamps are float
|
|
1113
|
-
// epoch seconds, not ISO strings, and both paged doors carry the same window
|
|
1114
|
-
// fields; the transcript adds the direction it was read in.
|
|
1115
|
-
|
|
1116
|
-
/** The inbound door a route is bound to: the authed API, or a channel medium. */
|
|
1117
|
-
export const conversationDoor = z.enum(['api', 'channel']);
|
|
1118
|
-
export type ConversationDoor = z.infer<typeof conversationDoor>;
|
|
1119
|
-
|
|
1120
|
-
/** What a route's turn runs: a registered agent, or a tool dispatch. */
|
|
1121
|
-
export const conversationTargetKind = z.enum(['agent', 'tool']);
|
|
1122
|
-
export type ConversationTargetKind = z.infer<typeof conversationTargetKind>;
|
|
1123
|
-
|
|
1124
|
-
/**
|
|
1125
|
-
* A route's default control mode (`initial_mode`) when a thread carries no
|
|
1126
|
-
* per-thread override: `agent` runs the target turn, `manual` suppresses it for an
|
|
1127
|
-
* operator to answer. The same value vocabulary as a per-thread mode override, but
|
|
1128
|
-
* a distinct concept (the route default vs. one thread's override).
|
|
1129
|
-
*/
|
|
1130
|
-
export const conversationMode = z.enum(['agent', 'manual']);
|
|
1131
|
-
export type ConversationMode = z.infer<typeof conversationMode>;
|
|
1132
|
-
|
|
1133
|
-
/**
|
|
1134
|
-
* Where a record sits between intake and a terminal outcome. `failed` is the one
|
|
1135
|
-
* the monitor surfaces loudly; `shed` and `silent` are terminal by design and
|
|
1136
|
-
* never send.
|
|
1137
|
-
*/
|
|
1138
|
-
export const conversationDeliveryStatus = z.enum([
|
|
1139
|
-
'accepted',
|
|
1140
|
-
'pending_delivery',
|
|
1141
|
-
'provisional',
|
|
1142
|
-
'delivered',
|
|
1143
|
-
'failed',
|
|
1144
|
-
'shed',
|
|
1145
|
-
'silent',
|
|
1146
|
-
]);
|
|
1147
|
-
export type ConversationDeliveryStatus = z.infer<typeof conversationDeliveryStatus>;
|
|
1148
|
-
|
|
1149
|
-
/** The nature of a turn's outcome, orthogonal to where its delivery stands. */
|
|
1150
|
-
export const conversationAnswerStatus = z.enum(['answered', 'error', 'silent']);
|
|
1151
|
-
export type ConversationAnswerStatus = z.infer<typeof conversationAnswerStatus>;
|
|
1152
|
-
|
|
1153
|
-
/**
|
|
1154
|
-
* Who authored a record's outgoing side. `client` is the ordinary turn the flow
|
|
1155
|
-
* answered; `operator` is a message a human sent into the thread, whose text
|
|
1156
|
-
* rides `answer` (its `inbound_text` is empty).
|
|
1157
|
-
*/
|
|
1158
|
-
export const conversationRecordOrigin = z.enum(['client', 'operator']);
|
|
1159
|
-
export type ConversationRecordOrigin = z.infer<typeof conversationRecordOrigin>;
|
|
1160
|
-
|
|
1161
|
-
export const conversationRoutes = z.object({
|
|
1162
|
-
items: z.array(conversationRoute),
|
|
1163
|
-
total: z.number(),
|
|
1164
|
-
});
|
|
1165
|
-
export type ConversationRoutes = z.infer<typeof conversationRoutes>;
|
|
1166
|
-
|
|
1167
|
-
/**
|
|
1168
|
-
* The create/replace reply: whether THIS call created the row (vs. replaced an
|
|
1169
|
-
* existing one), the row itself (its `callback_secret` withheld), and the
|
|
1170
|
-
* `callback_secret` returned ONCE for an `api`-door row (`null` for a `channel`
|
|
1171
|
-
* row). The secret signs delivery callbacks and is never re-read from any door, so
|
|
1172
|
-
* a caller that needs it must capture it from this reply.
|
|
1173
|
-
*/
|
|
1174
|
-
export const conversationRouteWritten = z.object({
|
|
1175
|
-
created: z.boolean(),
|
|
1176
|
-
route_name: z.string(),
|
|
1177
|
-
route: conversationRoute,
|
|
1178
|
-
callback_secret: z.string().nullable(),
|
|
1179
|
-
});
|
|
1180
|
-
export type ConversationRouteWritten = z.infer<typeof conversationRouteWritten>;
|
|
1181
|
-
|
|
1182
|
-
/**
|
|
1183
|
-
* The delete reply: `removed` says whether THIS call removed the routing row (a
|
|
1184
|
-
* retryable reclamation of orphaned thread indexes answers `false` rather than a
|
|
1185
|
-
* 404).
|
|
1186
|
-
*/
|
|
1187
|
-
export const conversationRouteDeleted = z.object({
|
|
1188
|
-
removed: z.boolean(),
|
|
1189
|
-
route_name: z.string(),
|
|
1190
|
-
});
|
|
1191
|
-
export type ConversationRouteDeleted = z.infer<typeof conversationRouteDeleted>;
|
|
1192
|
-
|
|
1193
|
-
/**
|
|
1194
|
-
* One thread of a route, summarized from its newest record. A `thread_id` holds
|
|
1195
|
-
* an api-door address (`{principal}/{end user}`, percent-encoded), so it never
|
|
1196
|
-
* goes back into a URL as a path segment — the transcript door takes it as a
|
|
1197
|
-
* query value.
|
|
1198
|
-
*/
|
|
1199
|
-
export const conversationThread = z.object({
|
|
1200
|
-
thread_id: z.string(),
|
|
1201
|
-
client_address: z.string(),
|
|
1202
|
-
last_activity_at: z.number(),
|
|
1203
|
-
message_count: z.number(),
|
|
1204
|
-
last_delivery_status: conversationDeliveryStatus,
|
|
1205
|
-
});
|
|
1206
|
-
export type ConversationThread = z.infer<typeof conversationThread>;
|
|
1207
|
-
|
|
1208
|
-
export const conversationThreadsPage = z.object({
|
|
1209
|
-
items: z.array(conversationThread),
|
|
1210
|
-
...pageWindow,
|
|
1211
|
-
});
|
|
1212
|
-
export type ConversationThreadsPage = z.infer<typeof conversationThreadsPage>;
|
|
1213
|
-
|
|
1214
|
-
/**
|
|
1215
|
-
* One exchange: the visitor's `inbound_text` — every record answers a message, so
|
|
1216
|
-
* both projections always carry it — and the agent's `answer`, plus where that
|
|
1217
|
-
* answer's delivery stands. The fields after `updated_at` are ADMIN ONLY —
|
|
1218
|
-
* the same door serves a caller-scoped projection that withholds them — so they
|
|
1219
|
-
* are optional here and absence means "not published to this reader".
|
|
1220
|
-
*/
|
|
1221
|
-
export const conversationMessage = z.object({
|
|
1222
|
-
message_id: z.string(),
|
|
1223
|
-
route_name: z.string(),
|
|
1224
|
-
door: conversationDoor,
|
|
1225
|
-
thread_id: z.string(),
|
|
1226
|
-
client_address: z.string(),
|
|
1227
|
-
caller_principal: z.string().nullable(),
|
|
1228
|
-
inbound_text: z.string(),
|
|
1229
|
-
answer_status: conversationAnswerStatus.nullable(),
|
|
1230
|
-
answer: z.string().nullable(),
|
|
1231
|
-
origin: conversationRecordOrigin,
|
|
1232
|
-
delivery_status: conversationDeliveryStatus,
|
|
1233
|
-
created_at: z.number(),
|
|
1234
|
-
updated_at: z.number(),
|
|
1235
|
-
channel: z.string().nullable().optional(),
|
|
1236
|
-
our_identity: z.string().nullable().optional(),
|
|
1237
|
-
provider_message_id: z.string().nullable().optional(),
|
|
1238
|
-
callback_url: z.string().nullable().optional(),
|
|
1239
|
-
error: z.string().nullable().optional(),
|
|
1240
|
-
outbound_message_ids: z.array(z.string()).optional(),
|
|
1241
|
-
attempts: z.number().optional(),
|
|
1242
|
-
});
|
|
1243
|
-
export type ConversationMessage = z.infer<typeof conversationMessage>;
|
|
1244
|
-
|
|
1245
|
-
/**
|
|
1246
|
-
* The direction a transcript page reads in. `asc` is the reading order (oldest
|
|
1247
|
-
* first); `desc` is the live-tail order, where page 1 is always the newest page
|
|
1248
|
-
* and paging forward walks BACKWARDS through the thread's history.
|
|
1249
|
-
*/
|
|
1250
|
-
export const transcriptOrder = z.enum(['asc', 'desc']);
|
|
1251
|
-
export type TranscriptOrder = z.infer<typeof transcriptOrder>;
|
|
1252
|
-
|
|
1253
|
-
/** A transcript page, echoing the order it was read in. */
|
|
1254
|
-
export const conversationTranscriptPage = z.object({
|
|
1255
|
-
items: z.array(conversationMessage),
|
|
1256
|
-
...pageWindow,
|
|
1257
|
-
order: transcriptOrder,
|
|
1258
|
-
});
|
|
1259
|
-
export type ConversationTranscriptPage = z.infer<typeof conversationTranscriptPage>;
|
|
1260
|
-
|
|
1261
|
-
/**
|
|
1262
|
-
* A route-scoped message search (`GET /api/conversations/{route}/messages/search?q`):
|
|
1263
|
-
* every record on the route whose text matches `q`, across threads, newest first.
|
|
1264
|
-
* The record shape is the transcript's exactly, so a hit renders with the same
|
|
1265
|
-
* projection. `truncated` says the match set outran the door's scan cap — surfaced
|
|
1266
|
-
* loudly, never a silent cut.
|
|
1267
|
-
*/
|
|
1268
|
-
export const conversationMessageSearchPage = z.object({
|
|
1269
|
-
items: z.array(conversationMessage),
|
|
1270
|
-
...pageWindow,
|
|
1271
|
-
});
|
|
1272
|
-
export type ConversationMessageSearchPage = z.infer<typeof conversationMessageSearchPage>;
|
|
1273
|
-
|
|
1274
|
-
/**
|
|
1275
|
-
* Who answers a thread's incoming messages: `agent` lets the flow reply on its
|
|
1276
|
-
* own; `manual` holds the flow back so a human answers. `source` says whether the
|
|
1277
|
-
* setting is the thread's own (`thread`) or inherited from its route (`route`).
|
|
1278
|
-
*/
|
|
1279
|
-
export const conversationThreadMode = z.enum(['agent', 'manual']);
|
|
1280
|
-
export type ConversationThreadMode = z.infer<typeof conversationThreadMode>;
|
|
1281
|
-
|
|
1282
|
-
export const conversationThreadModeState = z.object({
|
|
1283
|
-
mode: conversationThreadMode,
|
|
1284
|
-
source: z.enum(['thread', 'route']),
|
|
1285
|
-
});
|
|
1286
|
-
export type ConversationThreadModeState = z.infer<typeof conversationThreadModeState>;
|
|
1287
|
-
|
|
1288
|
-
/** The receipt a thread-message write returns: the stored id and its thread. */
|
|
1289
|
-
export const conversationThreadMessageSent = z.object({
|
|
1290
|
-
message_id: z.string(),
|
|
1291
|
-
thread_id: z.string(),
|
|
1292
|
-
});
|
|
1293
|
-
export type ConversationThreadMessageSent = z.infer<typeof conversationThreadMessageSent>;
|
|
1294
|
-
|
|
1295
|
-
/** Every stored per-target config (`GET /api/conversation-configs`). */
|
|
1296
|
-
export const conversationConfigs = z.object({
|
|
1297
|
-
items: z.array(targetConversationConfig),
|
|
1298
|
-
total: z.number(),
|
|
1299
|
-
});
|
|
1300
|
-
export type ConversationConfigs = z.infer<typeof conversationConfigs>;
|
|
1301
|
-
|
|
1302
|
-
/**
|
|
1303
|
-
* The upsert reply: whether THIS call created the config (vs. replaced an existing
|
|
1304
|
-
* one), its key, and the stored row.
|
|
1305
|
-
*/
|
|
1306
|
-
export const conversationConfigWritten = z.object({
|
|
1307
|
-
created: z.boolean(),
|
|
1308
|
-
target_kind: conversationTargetKind,
|
|
1309
|
-
target_name: z.string(),
|
|
1310
|
-
config: targetConversationConfig,
|
|
1311
|
-
});
|
|
1312
|
-
export type ConversationConfigWritten = z.infer<typeof conversationConfigWritten>;
|
|
1313
|
-
|
|
1314
|
-
/** The config-delete reply: `removed` is always `true` on success (an unknown key is a 404). */
|
|
1315
|
-
export const conversationConfigDeleted = z.object({
|
|
1316
|
-
removed: z.boolean(),
|
|
1317
|
-
target_kind: conversationTargetKind,
|
|
1318
|
-
target_name: z.string(),
|
|
1319
|
-
});
|
|
1320
|
-
export type ConversationConfigDeleted = z.infer<typeof conversationConfigDeleted>;
|
|
1321
|
-
|
|
1322
|
-
/**
|
|
1323
|
-
* The admin-only failed-delivery listing (`GET /api/conversations/messages/failed`):
|
|
1324
|
-
* every answer record whose delivery ended `failed`, across every route and caller.
|
|
1325
|
-
* The records are the ADMIN projection (delivery bookkeeping and `error` included),
|
|
1326
|
-
* so the row shape is {@link conversationMessage} exactly. It is NOT a paged window —
|
|
1327
|
-
* the door returns `{items, total}` and nothing more.
|
|
1328
|
-
*/
|
|
1329
|
-
export const conversationFailedMessages = z.object({
|
|
1330
|
-
items: z.array(conversationMessage),
|
|
1331
|
-
total: z.number(),
|
|
1332
|
-
});
|
|
1333
|
-
export type ConversationFailedMessages = z.infer<typeof conversationFailedMessages>;
|
|
1334
|
-
|
|
1335
|
-
/**
|
|
1336
|
-
* The thread-delete reply (`DELETE /api/conversations/{route_name}/thread?thread_id=`).
|
|
1337
|
-
* `removed` is a COUNT of the answer records this call deleted — `0` when a prior
|
|
1338
|
-
* run already cleared them, when they had aged out under retention, or when the id
|
|
1339
|
-
* was never stored (forgetting is absolute, never a 404 on a valid id).
|
|
1340
|
-
*/
|
|
1341
|
-
export const conversationThreadDeleted = z.object({
|
|
1342
|
-
removed: z.number(),
|
|
1343
|
-
route_name: z.string(),
|
|
1344
|
-
thread_id: z.string(),
|
|
1345
|
-
});
|
|
1346
|
-
export type ConversationThreadDeleted = z.infer<typeof conversationThreadDeleted>;
|
|
1347
|
-
|
|
1348
|
-
/**
|
|
1349
|
-
* The person-erase reply (`DELETE /api/conversations/persons/{person_id}`).
|
|
1350
|
-
* `removed` counts the answer records deleted across the person's routes; `erased`
|
|
1351
|
-
* says whether THIS call removed the person row (`false` on a retry or an
|
|
1352
|
-
* already-gone person — never a 404).
|
|
1353
|
-
*/
|
|
1354
|
-
export const conversationPersonDeleted = z.object({
|
|
1355
|
-
person_id: z.string(),
|
|
1356
|
-
removed: z.number(),
|
|
1357
|
-
erased: z.boolean(),
|
|
1358
|
-
});
|
|
1359
|
-
export type ConversationPersonDeleted = z.infer<typeof conversationPersonDeleted>;
|
|
1360
|
-
|
|
1361
|
-
// -- channel-web entry gate --------------------------------------------------
|
|
1362
|
-
// The web channel's entry gate: a web route can be gated so its chat page is
|
|
1363
|
-
// served only to a navigation carrying a live entry code. These four doors are
|
|
1364
|
-
// keyed by the route's `our_identity`. A raw code exists only in flight (the
|
|
1365
|
-
// mint reply); a listed code carries its hash id, never a raw value (none is
|
|
1366
|
-
// stored).
|
|
1367
|
-
|
|
1368
|
-
/** One minted entry code as the gate read door lists it — its hash id, its
|
|
1369
|
-
* optional label, and when it was created / dies. Never a raw code. */
|
|
1370
|
-
export const webEntryCode = z.object({
|
|
1371
|
-
code_id: z.string(),
|
|
1372
|
-
label: z.string().nullable(),
|
|
1373
|
-
created_at: z.string(),
|
|
1374
|
-
expires_at: z.string().nullable(),
|
|
1375
|
-
});
|
|
1376
|
-
export type WebEntryCode = z.infer<typeof webEntryCode>;
|
|
1377
|
-
|
|
1378
|
-
/** `GET /api/channels/web/gates/{identity}` — the gate flag and its live codes. */
|
|
1379
|
-
export const webEntryGate = z.object({
|
|
1380
|
-
enabled: z.boolean(),
|
|
1381
|
-
codes: z.array(webEntryCode),
|
|
1382
|
-
});
|
|
1383
|
-
export type WebEntryGate = z.infer<typeof webEntryGate>;
|
|
1384
|
-
|
|
1385
|
-
/** `PUT /api/channels/web/gates/{identity}` — the gate flag after the write. */
|
|
1386
|
-
export const webEntryGateState = z.object({ enabled: z.boolean() });
|
|
1387
|
-
export type WebEntryGateState = z.infer<typeof webEntryGateState>;
|
|
1388
|
-
|
|
1389
|
-
/**
|
|
1390
|
-
* `POST /api/channels/web/gates/{identity}/codes` — a freshly minted code. The
|
|
1391
|
-
* raw `code` rides this reply ONCE (nothing else stores or lists it — a listed
|
|
1392
|
-
* code's raw value is unrecoverable by design); `code_id` is its hash id and
|
|
1393
|
-
* `expires_at` an ISO-8601 instant, or `null` for a code that never expires.
|
|
1394
|
-
*/
|
|
1395
|
-
export const webEntryCodeMinted = z.object({
|
|
1396
|
-
code: z.string(),
|
|
1397
|
-
code_id: z.string(),
|
|
1398
|
-
expires_at: z.string().nullable(),
|
|
1399
|
-
});
|
|
1400
|
-
export type WebEntryCodeMinted = z.infer<typeof webEntryCodeMinted>;
|
|
1401
|
-
|
|
1402
|
-
/** `DELETE /api/channels/web/gates/{identity}/codes/{code_id}` — the revoked code. */
|
|
1403
|
-
export const webEntryCodeRevoked = z.object({ status: z.literal('revoked') });
|
|
1404
|
-
export type WebEntryCodeRevoked = z.infer<typeof webEntryCodeRevoked>;
|
|
1405
|
-
|
|
1406
|
-
// -- notifications -----------------------------------------------------------
|
|
1407
|
-
// The internal notifications sink: the messages the `notify_user` operation records
|
|
1408
|
-
// with no channel, so they land only in the Studio inbox. Each record carries the
|
|
1409
|
-
// server-minted id + timestamp; `recipient` is null when the message names none.
|
|
1410
|
-
// The sink also stores the richer-send forms a notify carried — `media`
|
|
1411
|
-
// (images/links shown WITH the message), `template` (a pre-approved out-of-window
|
|
1412
|
-
// send), `options` (tappable option labels) — plus the `audience` identity the
|
|
1413
|
-
// record is addressed to; the inbox renders them.
|
|
1414
|
-
|
|
1415
|
-
export const notification = z.object({
|
|
1416
|
-
id: z.string(),
|
|
1417
|
-
message: z.string(),
|
|
1418
|
-
// A channel DELIVERY address the message went to; null when the send named none.
|
|
1419
|
-
recipient: z.string().nullable(),
|
|
1420
|
-
// The IDENTITY (a user_id) whose in-app inbox the record is addressed to, distinct
|
|
1421
|
-
// from `recipient`. `.nullish()` accepts both an older record that predates the
|
|
1422
|
-
// field (key omitted) and a broadcast send (explicit null) — both parse to "none".
|
|
1423
|
-
audience: z.string().nullish(),
|
|
1424
|
-
// Display-only media stored WITH the message (images and/or links). Deliberately
|
|
1425
|
-
// LOOSE (`z.array(z.unknown())`), like the interactions frame: each item is
|
|
1426
|
-
// `safeParse`d per item by the renderer against `interactionMediaItem`, so one
|
|
1427
|
-
// malformed/hostile item is a loud per-item notice, never a whole-feed parse
|
|
1428
|
-
// failure that would silently vanish every other notification. `.nullish()` covers
|
|
1429
|
-
// an older record (key omitted) and a plain send (explicit null).
|
|
1430
|
-
media: z.array(z.unknown()).nullish(),
|
|
1431
|
-
// A pre-approved template the notify carried, parsed strictly: a drifting one is a
|
|
1432
|
-
// loud feed-level `ApiSchemaError`, consistent with the record contract.
|
|
1433
|
-
template: channelTemplate.nullish(),
|
|
1434
|
-
// Tappable option labels the notify offered; display-only in the operator inbox
|
|
1435
|
-
// (there is no conversation for the sink to enter). Strictly a string list.
|
|
1436
|
-
options: z.array(z.string()).nullish(),
|
|
1437
|
-
created_at: z.string(),
|
|
1438
|
-
});
|
|
1439
|
-
export type Notification = z.infer<typeof notification>;
|
|
1440
|
-
|
|
1441
|
-
export const notifications = z.object({
|
|
1442
|
-
notifications: z.array(notification),
|
|
1443
|
-
});
|
|
1444
|
-
export type Notifications = z.infer<typeof notifications>;
|
|
1445
|
-
|
|
1446
|
-
// -- hooks -------------------------------------------------------------------
|
|
1447
|
-
// The hand-written hook response DTOs: the fire-door authority enum, the list rows and
|
|
1448
|
-
// their wrapper, and the per-topic verifier/trigger metadata. The served hook DOCUMENT
|
|
1449
|
-
// schemas (`hookSubject`/`hookParams`/`hookRegister`) are generated from the contract
|
|
1450
|
-
// bundle and re-exported at the top of this file, not defined here.
|
|
1451
|
-
|
|
1452
|
-
/** A fire door — who may trigger a path, not what the fire may do. A string enum. */
|
|
1453
|
-
export const triggerAuth = z.enum([
|
|
1454
|
-
'public',
|
|
1455
|
-
'verifier',
|
|
1456
|
-
'token',
|
|
1457
|
-
'token+api_key',
|
|
1458
|
-
'out-of-service',
|
|
1459
|
-
]);
|
|
1460
|
-
export type TriggerAuth = z.infer<typeof triggerAuth>;
|
|
1461
|
-
|
|
1462
|
-
export const hookList = z.object({
|
|
1463
|
-
items: z.array(hookParams),
|
|
1464
|
-
total: z.number(),
|
|
1465
|
-
// Per-topic verifier bindings: the topic name maps to the verifier bound to it
|
|
1466
|
-
// and that verifier's config (which carries a `secret_env` name, never a secret
|
|
1467
|
-
// value). Tolerant of an older/empty response, which omits the key entirely.
|
|
1468
|
-
topic_verifiers: z
|
|
1469
|
-
.record(
|
|
1470
|
-
z.string(),
|
|
1471
|
-
z.object({ verifier: z.string(), config: z.record(z.string(), z.unknown()) }),
|
|
1472
|
-
)
|
|
1473
|
-
.default({}),
|
|
1474
|
-
// Per-topic fire door (topic → door). Tolerant of an older response omitting it.
|
|
1475
|
-
trigger_auth: z.record(z.string(), triggerAuth).default({}),
|
|
1476
|
-
});
|
|
1477
|
-
export type HookList = z.infer<typeof hookList>;
|
|
1478
|
-
|
|
1479
|
-
export const hookRegistered = z.object({
|
|
1480
|
-
registered: z.boolean(),
|
|
1481
|
-
name: z.string(),
|
|
1482
|
-
});
|
|
1483
|
-
|
|
1484
|
-
export const hookRemoved = z.object({
|
|
1485
|
-
removed: z.boolean(),
|
|
1486
|
-
name: z.string(),
|
|
1487
|
-
});
|
|
1488
|
-
|
|
1489
|
-
// The registered webhook-verifier catalog (`GET /api/hooks/verifiers`) — the
|
|
1490
|
-
// sorted verifier NAMES only, never any verifier's config. An empty registry is a
|
|
1491
|
-
// valid empty array. This is the ONLY source the topic-verifier bind picker reads.
|
|
1492
|
-
export const hookVerifiers = z.array(z.string());
|
|
1493
|
-
|
|
1494
|
-
/** `PUT /api/hooks/topics/{topic}/verifier` — the bound topic + verifier name. */
|
|
1495
|
-
export const topicVerifierSet = z.object({ topic: z.string(), verifier: z.string() });
|
|
1496
|
-
|
|
1497
|
-
/** `DELETE /api/hooks/topics/{topic}/verifier` — the unbound topic. */
|
|
1498
|
-
export const topicVerifierRemoved = z.object({ removed: z.boolean(), topic: z.string() });
|
|
1499
|
-
|
|
1500
|
-
// -- trigger links -----------------------------------------------------------
|
|
1501
|
-
// A trigger link is a minted, token-bearing PUBLIC URL (`GET|POST /trigger/{token}`)
|
|
1502
|
-
// that resolves to a hook TOPIC and fires it. Studio mints, lists, and revokes them
|
|
1503
|
-
// on the hooks page; the QR encodes the composed absolute URL.
|
|
1504
|
-
|
|
1505
|
-
/**
|
|
1506
|
-
* `POST /api/hooks/trigger-links` — a freshly minted trigger link. `trigger_path`
|
|
1507
|
-
* is a relative path (`/trigger/<token>`, never an absolute URL — Studio composes
|
|
1508
|
-
* the API origin); `token` is the raw token returned exactly ONCE, in this response
|
|
1509
|
-
* (nothing else stores or lists it — a listed link's QR is unrecoverable by
|
|
1510
|
-
* design). `expires_at` is an ISO-8601 instant, or `null` for a permanent link.
|
|
1511
|
-
*/
|
|
1512
|
-
export const triggerLinkCreated = z.object({
|
|
1513
|
-
name: z.string(),
|
|
1514
|
-
trigger_path: z.string(),
|
|
1515
|
-
token: z.string(),
|
|
1516
|
-
topic: z.string(),
|
|
1517
|
-
expires_at: z.string().nullable(),
|
|
1518
|
-
});
|
|
1519
|
-
export type TriggerLinkCreated = z.infer<typeof triggerLinkCreated>;
|
|
1520
|
-
|
|
1521
|
-
/**
|
|
1522
|
-
* One listed trigger-link record (`GET /api/hooks/trigger-links` item). `tool_kwargs`
|
|
1523
|
-
* is the per-link params merged last into every fire (`null` or `{}` = none);
|
|
1524
|
-
* `created_by` is the ambient creator identity (`null` on an identity-less,
|
|
1525
|
-
* gate-off deployment); `token_hash_prefix` is a short hash prefix for log
|
|
1526
|
-
* correlation — never a raw token (none is stored).
|
|
1527
|
-
*/
|
|
1528
|
-
export const triggerLinkRecord = z.object({
|
|
1529
|
-
name: z.string(),
|
|
1530
|
-
topic: z.string(),
|
|
1531
|
-
execution_key: z.string().min(1),
|
|
1532
|
-
trigger_auth: triggerAuth,
|
|
1533
|
-
tool_kwargs: z.record(z.string(), z.unknown()).nullable(),
|
|
1534
|
-
created_by: z.string().nullable(),
|
|
1535
|
-
created_at: z.string(),
|
|
1536
|
-
expires_at: z.string().nullable(),
|
|
1537
|
-
token_hash_prefix: z.string(),
|
|
1538
|
-
});
|
|
1539
|
-
export type TriggerLinkRecord = z.infer<typeof triggerLinkRecord>;
|
|
1540
|
-
|
|
1541
|
-
/** `GET /api/hooks/trigger-links` — every live trigger-link record. */
|
|
1542
|
-
export const triggerLinkList = z.object({
|
|
1543
|
-
items: z.array(triggerLinkRecord),
|
|
1544
|
-
total: z.number(),
|
|
1545
|
-
});
|
|
1546
|
-
export type TriggerLinkList = z.infer<typeof triggerLinkList>;
|
|
1547
|
-
|
|
1548
|
-
/** `DELETE /api/hooks/trigger-links/{name}` — the revoked link. */
|
|
1549
|
-
export const triggerLinkDeleted = z.object({ removed: z.boolean(), name: z.string() });
|
|
1550
|
-
export type TriggerLinkDeleted = z.infer<typeof triggerLinkDeleted>;
|
|
1551
|
-
|
|
1552
|
-
// -- settings schema ---------------------------------------------------------
|
|
1553
|
-
// The settings form is auto-rendered from a declarative group/field description
|
|
1554
|
-
// the skeleton emits from its typed settings models.
|
|
1555
|
-
|
|
1556
|
-
export const settingsSchema = z.object({
|
|
1557
|
-
groups: z.array(
|
|
1558
|
-
z.object({
|
|
1559
|
-
name: z.string(),
|
|
1560
|
-
module: z.string(),
|
|
1561
|
-
qualname: z.string(),
|
|
1562
|
-
fields: z.array(
|
|
1563
|
-
z.object({
|
|
1564
|
-
name: z.string(),
|
|
1565
|
-
env_var: z.string(),
|
|
1566
|
-
type: z.string(),
|
|
1567
|
-
default: jsonValue.nullable(),
|
|
1568
|
-
required: z.boolean(),
|
|
1569
|
-
secret: z.boolean(),
|
|
1570
|
-
description: z.string().nullable(),
|
|
1571
|
-
nested_group: z.string().nullable(),
|
|
1572
|
-
default_namespace_var: z.string().nullable(),
|
|
1573
|
-
value: jsonValue.nullable(),
|
|
1574
|
-
}),
|
|
1575
|
-
),
|
|
1576
|
-
}),
|
|
1577
|
-
),
|
|
1578
|
-
});
|
|
1579
|
-
export type SettingsSchema = z.infer<typeof settingsSchema>;
|
|
1580
|
-
|
|
1581
|
-
// -- auth: scopes + api keys -------------------------------------------------
|
|
1582
|
-
|
|
1583
|
-
/** `{ url: scope_id }` — every URL currently mapped to a scope. */
|
|
1584
|
-
export const authScopes = z.record(z.string(), z.string());
|
|
1585
|
-
|
|
1586
|
-
export const addUrlToScopeResult = z.object({ scope_id: z.string(), url: z.string() });
|
|
1587
|
-
export const removeUrlFromScopeResult = z.object({ url: z.string() });
|
|
1588
|
-
export const removeScopeResult = z.object({ scope_id: z.string(), deleted_keys: z.number() });
|
|
1589
|
-
|
|
1590
|
-
/**
|
|
1591
|
-
* A route's authorization ACTION class, joined onto the catalog from the route
|
|
1592
|
-
* registry. `read`/`write` routes are GRANTABLE — a role's per-tag level opens
|
|
1593
|
-
* them; `fenced`/`secret` routes are ADMIN-ONLY and never grantable (no per-tag
|
|
1594
|
-
* level reaches them). `null` marks a path the registry carries no metadata for
|
|
1595
|
-
* (an unregistered/ungated path — no feature tags, no action).
|
|
1596
|
-
*/
|
|
1597
|
-
export const routeAction = z.enum(['read', 'write', 'fenced', 'secret']);
|
|
1598
|
-
export type RouteAction = z.infer<typeof routeAction>;
|
|
1599
|
-
|
|
1600
|
-
/**
|
|
1601
|
-
* One row of the route catalog (`GET /api/auth/routes`) — a plain HTTP route with
|
|
1602
|
-
* its current mapping, JOINED with its route-registry metadata. `mapped` is the
|
|
1603
|
-
* scope id, the public marker, or `null` when the path is unmapped (the mapper's
|
|
1604
|
-
* "unassigned" bucket source). `methods` is the route's method set with `HEAD`
|
|
1605
|
-
* removed. `tags` are the route's feature-group labels, `summary` its one-line
|
|
1606
|
-
* description, and `action` its authorization class — the join fields the Roles
|
|
1607
|
-
* grant editor reads to derive grantable feature groups and mark the admin-only
|
|
1608
|
-
* (fenced/secret) routes it must never offer a grant for. An unregistered path
|
|
1609
|
-
* carries `tags: []`, `summary: ''`, `action: null`.
|
|
1610
|
-
*/
|
|
1611
|
-
export const authRoute = z.object({
|
|
1612
|
-
path: z.string(),
|
|
1613
|
-
methods: z.array(z.string()),
|
|
1614
|
-
mapped: z.string().nullable(),
|
|
1615
|
-
tags: z.array(z.string()),
|
|
1616
|
-
summary: z.string(),
|
|
1617
|
-
action: routeAction.nullable(),
|
|
1618
|
-
});
|
|
1619
|
-
export type AuthRoute = z.infer<typeof authRoute>;
|
|
1620
|
-
export const authRoutes = z.array(authRoute);
|
|
1621
|
-
|
|
1622
|
-
// -- auth: roles (editable per-tag RBAC) -------------------------------------
|
|
1623
|
-
|
|
1624
|
-
/** A role's per-tag ACCESS LEVEL: `none` (no access), `read`, or `write`. */
|
|
1625
|
-
export const grantLevel = z.enum(['none', 'read', 'write']);
|
|
1626
|
-
export type GrantLevel = z.infer<typeof grantLevel>;
|
|
1627
|
-
|
|
1628
|
-
/** A role's editable grant map: feature-group TAG name → the role's access level. */
|
|
1629
|
-
export const roleGrants = z.record(z.string(), grantLevel);
|
|
1630
|
-
export type RoleGrants = z.infer<typeof roleGrants>;
|
|
1631
|
-
|
|
1632
|
-
export const roleList = z.array(roleBody);
|
|
1633
|
-
|
|
1634
|
-
/** `DELETE /api/auth/roles/{name}` — the deleted role's name. */
|
|
1635
|
-
export const roleDeleted = z.object({ name: z.string(), deleted: z.boolean() });
|
|
1636
|
-
|
|
1637
|
-
/**
|
|
1638
|
-
* One immutable role-version row (`GET /api/auth/roles/{name}/versions` →
|
|
1639
|
-
* `versions`). `body` is the role body at that version; `is_current` flags the
|
|
1640
|
-
* active pointer. Mirrors the generic versioned-store row shape.
|
|
1641
|
-
*/
|
|
1642
|
-
export const roleVersion = z.object({
|
|
1643
|
-
version: z.number(),
|
|
1644
|
-
body: roleBody,
|
|
1645
|
-
tags: z.array(z.string()),
|
|
1646
|
-
created_at: z.string(),
|
|
1647
|
-
is_current: z.boolean(),
|
|
1648
|
-
});
|
|
1649
|
-
export type RoleVersion = z.infer<typeof roleVersion>;
|
|
1650
|
-
|
|
1651
|
-
/**
|
|
1652
|
-
* One who/action/before→after audit row (`GET /api/auth/roles/{name}/versions` →
|
|
1653
|
-
* `audit`). Its `body` carries the mutation kind, the actor, and the before/after
|
|
1654
|
-
* role bodies (both `null` for a create's `before` / a delete's `after`).
|
|
1655
|
-
*/
|
|
1656
|
-
export const roleAuditEvent = z.object({
|
|
1657
|
-
version: z.number(),
|
|
1658
|
-
body: z.object({
|
|
1659
|
-
action: z.string(),
|
|
1660
|
-
actor: z.string().nullable(),
|
|
1661
|
-
before: jsonValue.nullable(),
|
|
1662
|
-
after: jsonValue.nullable(),
|
|
1663
|
-
}),
|
|
1664
|
-
tags: z.array(z.string()),
|
|
1665
|
-
created_at: z.string(),
|
|
1666
|
-
is_current: z.boolean(),
|
|
1667
|
-
});
|
|
1668
|
-
export type RoleAuditEvent = z.infer<typeof roleAuditEvent>;
|
|
1669
|
-
|
|
1670
|
-
/** `GET /api/auth/roles/{name}/versions` — the append-only history + audit trail. */
|
|
1671
|
-
export const roleVersions = z.object({
|
|
1672
|
-
versions: z.array(roleVersion),
|
|
1673
|
-
audit: z.array(roleAuditEvent),
|
|
1674
|
-
});
|
|
1675
|
-
export type RoleVersions = z.infer<typeof roleVersions>;
|
|
1676
|
-
|
|
1677
|
-
/** `GET /api/auth/public-routes` — the sorted urls pinned to the public marker. */
|
|
1678
|
-
export const publicRoutes = z.array(z.string());
|
|
1679
|
-
|
|
1680
|
-
/** `POST /api/auth/public-routes` — the pinned url. */
|
|
1681
|
-
export const pinPublicResult = z.object({ url: z.string() });
|
|
1682
|
-
/** `DELETE /api/auth/public-routes` — the unpinned url (404 when not pinned). */
|
|
1683
|
-
export const unpinPublicResult = z.object({ url: z.string() });
|
|
1684
|
-
|
|
1685
|
-
/** The per-key payloads (`GET /api/auth/tokens-payload`). The stable per-mint
|
|
1686
|
-
* `key_fingerprint` is nested under `policy_data`; the picker reads it there. */
|
|
1687
|
-
export const tokensPayload = z.array(
|
|
1688
|
-
z.object({
|
|
1689
|
-
// The value an `execution_key` binding names.
|
|
1690
|
-
user_id: z.string().min(1),
|
|
1691
|
-
description: z.string(),
|
|
1692
|
-
scopes: z.array(z.string()),
|
|
1693
|
-
policy_data: jsonValue,
|
|
1694
|
-
condition: templatedText.nullable().optional(),
|
|
1695
|
-
}),
|
|
1696
|
-
);
|
|
1697
|
-
export type TokensPayload = z.infer<typeof tokensPayload>;
|
|
1698
|
-
|
|
1699
|
-
/** Mint reply `{ api_key, key_fingerprint }` narrowed to the raw `sk-…` key,
|
|
1700
|
-
* returned once at creation and never again. */
|
|
1701
|
-
export const createdApiKey = z
|
|
1702
|
-
.object({ api_key: z.string(), key_fingerprint: z.string() })
|
|
1703
|
-
.transform((minted) => minted.api_key);
|
|
1704
|
-
export const editApiKeyResult = z.object({ user_id: z.string(), updated: z.boolean() });
|
|
1705
|
-
export const revokeApiKeyResult = z.object({ user_id: z.string(), revoked: z.boolean() });
|
|
1706
|
-
|
|
1707
|
-
// -- login methods (the public sign-in aggregator) ---------------------------
|
|
1708
|
-
|
|
1709
|
-
/**
|
|
1710
|
-
* One field of a `form` login method. `secret` fields render as password
|
|
1711
|
-
* inputs; `autocomplete` passes through to the input (e.g. "email",
|
|
1712
|
-
* "current-password", "new-password").
|
|
1713
|
-
*/
|
|
1714
|
-
export const loginFormField = z.object({
|
|
1715
|
-
name: z.string().min(1),
|
|
1716
|
-
label: z.string().min(1),
|
|
1717
|
-
secret: z.boolean(),
|
|
1718
|
-
autocomplete: z.string().optional(),
|
|
1719
|
-
});
|
|
1720
|
-
|
|
1721
|
-
/**
|
|
1722
|
-
* The two — and only two — login-method shapes. Discriminated on `shape`; an
|
|
1723
|
-
* unknown shape fails validation loudly (contract drift, not a soft skip).
|
|
1724
|
-
* Optional fields are `.optional()` (absent), never `.nullable()`: the server
|
|
1725
|
-
* serializes with `exclude_none`, so an absent field is OMITTED, never `null`.
|
|
1726
|
-
*/
|
|
1727
|
-
export const loginMethod = z.discriminatedUnion('shape', [
|
|
1728
|
-
z.object({
|
|
1729
|
-
shape: z.literal('form'),
|
|
1730
|
-
id: z.string().min(1),
|
|
1731
|
-
title: z.string().min(1),
|
|
1732
|
-
purpose: z.enum(['login', 'bootstrap', 'invite']).default('login'),
|
|
1733
|
-
fields: z.array(loginFormField).min(1),
|
|
1734
|
-
submit_path: z.string().min(1),
|
|
1735
|
-
}),
|
|
1736
|
-
z.object({
|
|
1737
|
-
shape: z.literal('button'),
|
|
1738
|
-
id: z.string().min(1),
|
|
1739
|
-
label: z.string().min(1),
|
|
1740
|
-
icon: z.string().optional(),
|
|
1741
|
-
href: z.string().min(1),
|
|
1742
|
-
}),
|
|
1743
|
-
]);
|
|
1744
|
-
|
|
1745
|
-
/**
|
|
1746
|
-
* `GET /api/login/methods` (PUBLIC). `bootstrap: true` ⇒ the deployment has zero
|
|
1747
|
-
* accounts and `methods` contains the owner-creation form. Non-strict — the
|
|
1748
|
-
* skeleton may grow additive fields.
|
|
1749
|
-
*/
|
|
1750
|
-
export const loginMethods = z.object({
|
|
1751
|
-
methods: z.array(loginMethod),
|
|
1752
|
-
bootstrap: z.boolean(),
|
|
1753
|
-
});
|
|
1754
|
-
|
|
1755
|
-
/**
|
|
1756
|
-
* A successful login/exchange: the minted session token (opaque, `tai-sess-`
|
|
1757
|
-
* prefixed — the client treats it as an opaque string) + its user.
|
|
1758
|
-
*/
|
|
1759
|
-
export const loginResult = z.object({
|
|
1760
|
-
token: z.string().min(1),
|
|
1761
|
-
user_id: z.string().min(1),
|
|
1762
|
-
});
|
|
1763
|
-
|
|
1764
|
-
export type LoginFormField = z.infer<typeof loginFormField>;
|
|
1765
|
-
export type LoginMethod = z.infer<typeof loginMethod>;
|
|
1766
|
-
export type LoginMethods = z.infer<typeof loginMethods>;
|
|
1767
|
-
export type LoginResult = z.infer<typeof loginResult>;
|
|
1768
|
-
|
|
1769
|
-
// -- auth: the caller's capability projection (GET /api/auth/me) --------------
|
|
1770
|
-
|
|
1771
|
-
/** A concrete route the caller can reach, with the methods that pass its jq fence. */
|
|
1772
|
-
export const routeEntry = z.object({
|
|
1773
|
-
path: z.string(),
|
|
1774
|
-
methods: z.array(z.string()),
|
|
1775
|
-
});
|
|
1776
|
-
export type RouteEntry = z.infer<typeof routeEntry>;
|
|
1777
|
-
|
|
1778
|
-
/**
|
|
1779
|
-
* A dynamic route pattern the caller can reach — a mount/pattern surface not
|
|
1780
|
-
* enumerable into concrete paths, projected only when its scope AND jq admit it.
|
|
1781
|
-
*/
|
|
1782
|
-
export const patternEntry = z.object({
|
|
1783
|
-
pattern: z.string(),
|
|
1784
|
-
scope_id: z.string(),
|
|
1785
|
-
});
|
|
1786
|
-
export type PatternEntry = z.infer<typeof patternEntry>;
|
|
1787
|
-
|
|
1788
|
-
/**
|
|
1789
|
-
* A sub-MCP mount the caller can reach, with the tools it exposes and its
|
|
1790
|
-
* transport. Shares the {@link subMcpMount} shape with the registry list, adding
|
|
1791
|
-
* the `slug` the projection carries inline (the list keys mounts by slug instead).
|
|
1792
|
-
*/
|
|
1793
|
-
export const subMcpEntry = subMcpMount.extend({ slug: z.string() });
|
|
1794
|
-
export type SubMcpEntry = z.infer<typeof subMcpEntry>;
|
|
1795
|
-
|
|
1796
|
-
/**
|
|
1797
|
-
* `GET /api/auth/me` — the caller's derived capability projection: the concrete
|
|
1798
|
-
* (path, method) surface, dynamic patterns, sub-MCP mounts, tools, and agents it
|
|
1799
|
-
* can reach RIGHT NOW (derived server-side, never stored). `admin` is the
|
|
1800
|
-
* condition-free ownerless `"*"` discriminator (a TOTAL projection); a scoped
|
|
1801
|
-
* session carries `admin: false` and a jq-exact `routes` list. `owner_user_id` is
|
|
1802
|
-
* the key's owner claim, `null` for an ownerless key. The invariant is
|
|
1803
|
-
* projection ⊆ gate: every projected surface is one the server would admit, so
|
|
1804
|
-
* the UI can filter on it without ever advertising a door the gate denies.
|
|
1805
|
-
*/
|
|
1806
|
-
export const meProjection = z.object({
|
|
1807
|
-
user_id: z.string(),
|
|
1808
|
-
owner_user_id: z.string().nullable(),
|
|
1809
|
-
admin: z.boolean(),
|
|
1810
|
-
scopes: z.array(z.string()),
|
|
1811
|
-
routes: z.array(routeEntry),
|
|
1812
|
-
route_patterns: z.array(patternEntry),
|
|
1813
|
-
sub_mcp: z.array(subMcpEntry),
|
|
1814
|
-
tools: z.array(z.string()),
|
|
1815
|
-
agents: z.array(z.string()),
|
|
1816
|
-
mintable: z.boolean(),
|
|
1817
|
-
});
|
|
1818
|
-
export type MeProjection = z.infer<typeof meProjection>;
|
|
1819
|
-
|
|
1820
|
-
/**
|
|
1821
|
-
* `POST /api/auth/claim-links` — a one-time claim link minted in the key-create
|
|
1822
|
-
* flow. `claim_path` is a fragment-carrier path (`/login#claim=<token>`, never an
|
|
1823
|
-
* absolute URL — the Studio composes the origin); `token` is the raw claim token
|
|
1824
|
-
* returned exactly ONCE; `expires_at` is an ISO-8601 instant.
|
|
1825
|
-
*/
|
|
1826
|
-
export const claimLinkCreated = z.object({
|
|
1827
|
-
claim_path: z.string(),
|
|
1828
|
-
token: z.string(),
|
|
1829
|
-
expires_at: z.string(),
|
|
1830
|
-
});
|
|
1831
|
-
export type ClaimLinkCreated = z.infer<typeof claimLinkCreated>;
|
|
1832
|
-
|
|
1833
|
-
/**
|
|
1834
|
-
* `POST /api/auth/logout` — the single authed logout dispatcher's result.
|
|
1835
|
-
* `revoked` is `true` when a live accounts session was revoked; a plain `sk-` key
|
|
1836
|
-
* has nothing to revoke and answers `404` (a loud absent-session signal), never a
|
|
1837
|
-
* `revoked: false` body. Non-strict, so a SUCCESSFUL logout never throws
|
|
1838
|
-
* `ApiSchemaError` on an additive field.
|
|
1839
|
-
*/
|
|
1840
|
-
export const logoutResult = z.object({ revoked: z.boolean() });
|
|
1841
|
-
export type LogoutResult = z.infer<typeof logoutResult>;
|
|
1842
|
-
|
|
1843
|
-
/**
|
|
1844
|
-
* `GET /api/auth/capabilities` — whether this deployment can MINT API keys
|
|
1845
|
-
* locally. `mintable: false` means every configured identity provider is
|
|
1846
|
-
* validator-only (keys are issued at an external issuer), so the key-creation
|
|
1847
|
-
* UI disables up front instead of surfacing a raw mint failure. Non-strict.
|
|
1848
|
-
*/
|
|
1849
|
-
export const authCapabilities = z.object({
|
|
1850
|
-
mintable: z.boolean(),
|
|
1851
|
-
providers: z.array(z.object({ name: z.string(), mintable: z.boolean() })),
|
|
1852
|
-
});
|
|
1853
|
-
export type AuthCapabilities = z.infer<typeof authCapabilities>;
|
|
1854
|
-
|
|
1855
|
-
// -- access-control policy (authoring + versioning) --------------------------
|
|
1856
|
-
|
|
1857
|
-
/**
|
|
1858
|
-
* `POST /api/auth/validate-condition` — the fail-closed jq guard. `ok` is the
|
|
1859
|
-
* compile/render result; `result` is the boolean of a sample evaluation, or
|
|
1860
|
-
* `null` when no `sample_context` was supplied (compile-only). A broken condition
|
|
1861
|
-
* is a `400 {error}` surfaced by the transport, NEVER a false `ok` — so a
|
|
1862
|
-
* syntactically-broken condition can be caught before it locks a key out. A drift
|
|
1863
|
-
* throws `ApiSchemaError`.
|
|
1864
|
-
*/
|
|
1865
|
-
export const validateConditionResult = z.object({
|
|
1866
|
-
ok: z.boolean(),
|
|
1867
|
-
result: z.boolean().nullable(),
|
|
1868
|
-
});
|
|
1869
|
-
export type ValidateConditionResult = z.infer<typeof validateConditionResult>;
|
|
1870
|
-
|
|
1871
|
-
/**
|
|
1872
|
-
* One immutable policy version row
|
|
1873
|
-
* (`GET /api/auth/api-keys/{user_id}/policy/versions`). `is_current` flags the
|
|
1874
|
-
* active pointer; `tags` is the generic per-version label list (kind-agnostic),
|
|
1875
|
-
* mirroring the preset version shape.
|
|
1876
|
-
*/
|
|
1877
|
-
export const policyVersion = z.object({
|
|
1878
|
-
version: z.number(),
|
|
1879
|
-
body: policyBody,
|
|
1880
|
-
tags: z.array(z.string()),
|
|
1881
|
-
created_at: z.string(),
|
|
1882
|
-
is_current: z.boolean(),
|
|
1883
|
-
});
|
|
1884
|
-
export type PolicyVersion = z.infer<typeof policyVersion>;
|
|
1885
|
-
|
|
1886
|
-
export const policyVersionList = z.array(policyVersion);
|
|
1887
|
-
|
|
1888
|
-
/** `POST /api/auth/api-keys/{user_id}/policy/rollback` — the re-pointed version. */
|
|
1889
|
-
export const policyRollback = z.object({ user_id: z.string(), active_version: z.number() });
|
|
1890
|
-
|
|
1891
|
-
// -- backup ------------------------------------------------------------------
|
|
1892
|
-
|
|
1893
|
-
export const backupSections = z.array(z.object({ name: z.string(), secret: z.boolean() }));
|
|
1894
|
-
|
|
1895
|
-
/** The exported backup document — validated when the UI reads a picked file. */
|
|
1896
|
-
export const backupDocument = z.object({
|
|
1897
|
-
version: z.literal(1),
|
|
1898
|
-
created_at: z.string(),
|
|
1899
|
-
sections: z.record(z.string(), z.unknown()),
|
|
1900
|
-
errors: z.record(z.string(), z.string()).optional(),
|
|
1901
|
-
});
|
|
1902
|
-
export type BackupDocument = z.infer<typeof backupDocument>;
|
|
1903
|
-
|
|
1904
|
-
export const backupImportReport = z.object({
|
|
1905
|
-
ok: z.boolean(),
|
|
1906
|
-
sections: z.record(
|
|
1907
|
-
z.string(),
|
|
1908
|
-
z.object({
|
|
1909
|
-
created: z.number(),
|
|
1910
|
-
updated: z.number(),
|
|
1911
|
-
skipped: z.number(),
|
|
1912
|
-
errors: z.array(z.string()),
|
|
1913
|
-
new_api_keys: z
|
|
1914
|
-
.array(
|
|
1915
|
-
z.object({
|
|
1916
|
-
user_id: z.string(),
|
|
1917
|
-
description: z.string(),
|
|
1918
|
-
api_key: z.string(),
|
|
1919
|
-
}),
|
|
1920
|
-
)
|
|
1921
|
-
.optional(),
|
|
1922
|
-
// The `manifest` and `env` sections apply through the config pipeline, so their
|
|
1923
|
-
// report carries the mode-wrapped fleet `fanout` of the restore's reload; other
|
|
1924
|
-
// sections omit it. Parsed EXPLICITLY so the shared fleet-report handler can
|
|
1925
|
-
// surface a failed restore propagation — otherwise zod would strip it silently.
|
|
1926
|
-
fanout: fleetReportFanout.optional(),
|
|
1927
|
-
}),
|
|
1928
|
-
),
|
|
1929
|
-
});
|
|
1930
|
-
export type BackupImportReport = z.infer<typeof backupImportReport>;
|
|
1931
|
-
|
|
1932
|
-
// -- schedules ---------------------------------------------------------------
|
|
1933
|
-
// The skeleton returns opaque backend-tool results; the table reads a few known
|
|
1934
|
-
// fields and passes the rest through untouched.
|
|
1935
|
-
|
|
1936
|
-
export const scheduleItem = z
|
|
1937
|
-
.object({
|
|
1938
|
-
name: z.string(),
|
|
1939
|
-
enabled: z.boolean().optional(),
|
|
1940
|
-
schedule: jsonValue.optional(),
|
|
1941
|
-
target: jsonValue.optional(),
|
|
1942
|
-
args: z.array(jsonValue).optional(),
|
|
1943
|
-
kwargs: z.record(z.string(), jsonValue).optional(),
|
|
1944
|
-
})
|
|
1945
|
-
.loose();
|
|
1946
|
-
export const scheduleList = z.array(scheduleItem);
|
|
1947
|
-
export type ScheduleItem = z.infer<typeof scheduleItem>;
|
|
1948
|
-
|
|
1949
|
-
export const serverDateTime = z
|
|
1950
|
-
.object({
|
|
1951
|
-
utc: jsonValue,
|
|
1952
|
-
local: jsonValue.optional(),
|
|
1953
|
-
system: jsonValue.optional(),
|
|
1954
|
-
})
|
|
1955
|
-
.loose();
|
|
1956
|
-
|
|
1957
|
-
// -- observability -----------------------------------------------------------
|
|
1958
|
-
|
|
1959
|
-
export const dashboardMetrics = z.object({
|
|
1960
|
-
summary: z.object({
|
|
1961
|
-
totalRuns: z.number(),
|
|
1962
|
-
totalCost: z.number(),
|
|
1963
|
-
totalTokens: z.number(),
|
|
1964
|
-
averageLatencyMs: z.number(),
|
|
1965
|
-
avgCostPerRun: z.number(),
|
|
1966
|
-
avgTokensPerRun: z.number(),
|
|
1967
|
-
timeToFirstTokenMs: z.number().nullable(),
|
|
1968
|
-
}),
|
|
1969
|
-
timeSeries: z.array(
|
|
1970
|
-
z.object({
|
|
1971
|
-
bucket: z.string().nullable(),
|
|
1972
|
-
runs: z.number(),
|
|
1973
|
-
cost: z.number(),
|
|
1974
|
-
avgLatencyMs: z.number(),
|
|
1975
|
-
totalTokens: z.number(),
|
|
1976
|
-
}),
|
|
1977
|
-
),
|
|
1978
|
-
byModel: z.array(
|
|
1979
|
-
z.object({
|
|
1980
|
-
model: z.string(),
|
|
1981
|
-
calls: z.number(),
|
|
1982
|
-
cost: z.number(),
|
|
1983
|
-
totalTokens: z.number(),
|
|
1984
|
-
avgLatencyMs: z.number(),
|
|
1985
|
-
}),
|
|
1986
|
-
),
|
|
1987
|
-
granularity: z.enum(['hour', 'day', 'week']),
|
|
1988
|
-
});
|
|
1989
|
-
export type DashboardMetrics = z.infer<typeof dashboardMetrics>;
|
|
1990
|
-
|
|
1991
|
-
export const run = z.object({
|
|
1992
|
-
id: z.string(),
|
|
1993
|
-
traceId: z.string(),
|
|
1994
|
-
createdAt: z.string().nullable(),
|
|
1995
|
-
tags: z.array(z.string()),
|
|
1996
|
-
status: z.enum(['error', 'success']),
|
|
1997
|
-
cost: z.number().nullable(),
|
|
1998
|
-
latencyMs: z.number().nullable(),
|
|
1999
|
-
totalTokens: z.number().nullable(),
|
|
2000
|
-
inputPreview: jsonValue,
|
|
2001
|
-
outputPreview: jsonValue,
|
|
2002
|
-
});
|
|
2003
|
-
export type Run = z.infer<typeof run>;
|
|
2004
|
-
|
|
2005
|
-
export const runsPage = z.object({
|
|
2006
|
-
items: z.array(run),
|
|
2007
|
-
page: z.number(),
|
|
2008
|
-
nextPage: z.number().nullable(),
|
|
2009
|
-
});
|
|
2010
|
-
|
|
2011
|
-
export const runSpan = z.object({
|
|
2012
|
-
id: z.string(),
|
|
2013
|
-
parentId: z.string().nullable(),
|
|
2014
|
-
traceId: z.string().nullable(),
|
|
2015
|
-
name: z.string().nullable(),
|
|
2016
|
-
type: z.string().nullable(),
|
|
2017
|
-
level: z.string().nullable(),
|
|
2018
|
-
statusMessage: z.string().nullable(),
|
|
2019
|
-
start: z.string().nullable(),
|
|
2020
|
-
end: z.string().nullable(),
|
|
2021
|
-
model: z.string().nullable(),
|
|
2022
|
-
usage: jsonValue.nullable(),
|
|
2023
|
-
metadata: jsonValue.nullable(),
|
|
2024
|
-
input: jsonValue,
|
|
2025
|
-
output: jsonValue,
|
|
2026
|
-
nodeId: z.string().nullable(),
|
|
2027
|
-
});
|
|
2028
|
-
export type RunSpan = z.infer<typeof runSpan>;
|
|
2029
|
-
|
|
2030
|
-
export const runTrace = z.object({
|
|
2031
|
-
traceId: z.string(),
|
|
2032
|
-
timestamp: z.string().nullable(),
|
|
2033
|
-
tags: z.array(z.string()),
|
|
2034
|
-
totalCost: z.number().nullable(),
|
|
2035
|
-
input: jsonValue,
|
|
2036
|
-
output: jsonValue,
|
|
2037
|
-
metadata: jsonValue.nullable(),
|
|
2038
|
-
spans: z.array(runSpan),
|
|
2039
|
-
});
|
|
2040
|
-
export type RunTrace = z.infer<typeof runTrace>;
|
|
2041
|
-
|
|
2042
|
-
// -- marketplace -------------------------------------------------------------
|
|
2043
|
-
|
|
2044
|
-
/**
|
|
2045
|
-
* The CLOSED HTTP-method enum fixed by the contract's RouteMethod, the one source
|
|
2046
|
-
* for every route-method field (declaration and install/preview responses alike):
|
|
2047
|
-
* a wire method the contract does not define fails loudly as drift rather than
|
|
2048
|
-
* passing through silently.
|
|
2049
|
-
*/
|
|
2050
|
-
export const routeMethod = z.enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE']);
|
|
2051
|
-
export type RouteMethod = z.infer<typeof routeMethod>;
|
|
2052
|
-
|
|
2053
|
-
/**
|
|
2054
|
-
* How the plugin is delivered, derived server-side from whether its spec names a
|
|
2055
|
-
* package: `package` is pip-installed, `descriptor` (marketplace `source` `spec`)
|
|
2056
|
-
* installs nothing but the manifest entry. A CLOSED enum, so a wire value the
|
|
2057
|
-
* server does not derive fails loudly as drift.
|
|
2058
|
-
*/
|
|
2059
|
-
export const marketplaceDelivery = z.enum(['package', 'descriptor']);
|
|
2060
|
-
export type MarketplaceDelivery = z.infer<typeof marketplaceDelivery>;
|
|
2061
|
-
|
|
2062
|
-
/**
|
|
2063
|
-
* The install-provenance vocabulary a listing/version resolves from: a pip index
|
|
2064
|
-
* (`pypi`), a git tag (`github`), or a descriptor yml (`spec`). CLOSED, so a wire
|
|
2065
|
-
* value outside it fails as drift.
|
|
2066
|
-
*/
|
|
2067
|
-
export const marketplaceSource = z.enum(['pypi', 'github', 'spec']);
|
|
2068
|
-
export type MarketplaceSource = z.infer<typeof marketplaceSource>;
|
|
2069
|
-
|
|
2070
|
-
/**
|
|
2071
|
-
* One env var an item requires before install: its `name` and whether its value is
|
|
2072
|
-
* a `secret` (an OAuth client secret is; a client id or a plain marker var is not).
|
|
2073
|
-
* The install dialog seeds each toggle from `secret` and collects the missing ones.
|
|
2074
|
-
*/
|
|
2075
|
-
export const marketplaceRequiredEnvVar = z.object({ name: z.string(), secret: z.boolean() });
|
|
2076
|
-
export type MarketplaceRequiredEnvVar = z.infer<typeof marketplaceRequiredEnvVar>;
|
|
2077
|
-
|
|
2078
|
-
/**
|
|
2079
|
-
* One HTTP route an item declares in its `tai-plugin.yml`: a `path` relative to
|
|
2080
|
-
* the item's mount base, the `methods` it answers, and whether it is served
|
|
2081
|
-
* `public` (without authentication). The absolute path an operator sees is
|
|
2082
|
-
* resolved from the base at install time.
|
|
2083
|
-
*/
|
|
2084
|
-
export const marketplaceRouteDecl = z.object({
|
|
2085
|
-
path: z.string(),
|
|
2086
|
-
methods: z.array(routeMethod),
|
|
2087
|
-
public: z.boolean(),
|
|
2088
|
-
});
|
|
2089
|
-
export type MarketplaceRouteDecl = z.infer<typeof marketplaceRouteDecl>;
|
|
2090
|
-
|
|
2091
|
-
/**
|
|
2092
|
-
* A route-carrying item's declared mount: the default `base` prefix the routes
|
|
2093
|
-
* hang off (an operator may remap it at install) and the `paths` it registers.
|
|
2094
|
-
*/
|
|
2095
|
-
export const marketplaceRoutesDecl = z.object({
|
|
2096
|
-
base: z.string(),
|
|
2097
|
-
paths: z.array(marketplaceRouteDecl),
|
|
2098
|
-
});
|
|
2099
|
-
export type MarketplaceRoutesDecl = z.infer<typeof marketplaceRoutesDecl>;
|
|
2100
|
-
|
|
2101
|
-
/**
|
|
2102
|
-
* One contained item of a marketplace plugin's published version: its kind
|
|
2103
|
-
* (tool / agent / extension / …), name, description, free-form tags, and the
|
|
2104
|
-
* logical group it belongs to (`null` when ungrouped). `routes` is present only
|
|
2105
|
-
* on a route-carrying item (a router or channel); absent/null on every other.
|
|
2106
|
-
* `required_env` is the env vars the item needs before install — but the REGISTRY's
|
|
2107
|
-
* plugin-detail body does NOT carry it per item: required-env is server-computed
|
|
2108
|
-
* (`required_env_for_spec`) and rides the install PREVIEW, never the listing detail,
|
|
2109
|
-
* so the registry OMITS it here and it parses as `undefined`. Optional (not
|
|
2110
|
-
* defaulted) so the type mirrors the wire; the authority the install dialog collects
|
|
2111
|
-
* from is the preview's `required_env`/`missing_env`, never this field.
|
|
2112
|
-
*/
|
|
2113
|
-
export const marketplaceItem = z.object({
|
|
2114
|
-
kind: z.string(),
|
|
2115
|
-
name: z.string(),
|
|
2116
|
-
description: z.string(),
|
|
2117
|
-
tags: z.array(z.string()),
|
|
2118
|
-
group: z.string().nullable(),
|
|
2119
|
-
routes: marketplaceRoutesDecl.nullish(),
|
|
2120
|
-
required_env: z.array(marketplaceRequiredEnvVar).optional(),
|
|
2121
|
-
});
|
|
2122
|
-
export type MarketplaceItem = z.infer<typeof marketplaceItem>;
|
|
2123
|
-
|
|
2124
|
-
/**
|
|
2125
|
-
* One kind summary of a search row: an item kind, how many UNGROUPED items of
|
|
2126
|
-
* that kind the listing's latest published version carries, and their names.
|
|
2127
|
-
* The registry orders the array count DESC then kind ASC, and each entry's
|
|
2128
|
-
* `names` ASC; the UI renders in that order.
|
|
2129
|
-
*/
|
|
2130
|
-
export const marketplaceSearchKind = z.object({
|
|
2131
|
-
kind: z.string(),
|
|
2132
|
-
count: z.number(),
|
|
2133
|
-
names: z.array(z.string()),
|
|
2134
|
-
});
|
|
2135
|
-
export type MarketplaceSearchKind = z.infer<typeof marketplaceSearchKind>;
|
|
2136
|
-
|
|
2137
|
-
/**
|
|
2138
|
-
* One logical group of a search row: the group name and how many items the
|
|
2139
|
-
* listing's latest published version places in it. The registry orders the
|
|
2140
|
-
* array count DESC then name ASC; the UI renders in that order.
|
|
2141
|
-
*/
|
|
2142
|
-
export const marketplaceSearchGroup = z.object({
|
|
2143
|
-
name: z.string(),
|
|
2144
|
-
count: z.number(),
|
|
2145
|
-
});
|
|
2146
|
-
export type MarketplaceSearchGroup = z.infer<typeof marketplaceSearchGroup>;
|
|
2147
|
-
|
|
2148
|
-
/**
|
|
2149
|
-
* One listing-level search row (`GET /api/marketplace/search`). `ref` is the
|
|
2150
|
-
* "namespace/name" install target, so every row carries enough to link to its
|
|
2151
|
-
* plugin. `latest_version` is nullable defensively; the search relation only
|
|
2152
|
-
* emits listings with a published version. `kinds` summarizes that latest
|
|
2153
|
-
* version's UNGROUPED items; `groups` summarizes its logical groups (`[]` when
|
|
2154
|
-
* none). Both keys are always present.
|
|
2155
|
-
*/
|
|
2156
|
-
export const marketplaceSearchRow = z.object({
|
|
2157
|
-
ref: z.string(),
|
|
2158
|
-
namespace: z.string(),
|
|
2159
|
-
name: z.string(),
|
|
2160
|
-
display_name: z.string().nullable(),
|
|
2161
|
-
icon_url: z.string().nullable(),
|
|
2162
|
-
// Null for a descriptor listing (`source` `spec`): it names no package.
|
|
2163
|
-
package: z.string().nullable(),
|
|
2164
|
-
description: z.string(),
|
|
2165
|
-
categories: z.array(z.string()),
|
|
2166
|
-
tags: z.array(z.string()),
|
|
2167
|
-
trust_tier: z.string(),
|
|
2168
|
-
pricing: z.string(),
|
|
2169
|
-
// A display-only premium flag: a badge, never a payment surface. Nullable
|
|
2170
|
-
// + optional: an older registry omits it, and it is absent on non-premium rows.
|
|
2171
|
-
premium: z.boolean().nullish(),
|
|
2172
|
-
latest_version: z.string().nullable(),
|
|
2173
|
-
downloads: z.number(),
|
|
2174
|
-
updated_at: z.string(),
|
|
2175
|
-
kinds: z.array(marketplaceSearchKind),
|
|
2176
|
-
groups: z.array(marketplaceSearchGroup),
|
|
2177
|
-
});
|
|
2178
|
-
export type MarketplaceSearchRow = z.infer<typeof marketplaceSearchRow>;
|
|
2179
|
-
|
|
2180
|
-
/**
|
|
2181
|
-
* One page of listing rows. The wire carries no next-page field — has-next is
|
|
2182
|
-
* COMPUTED: `page * page_size < total`.
|
|
2183
|
-
*/
|
|
2184
|
-
export const marketplaceSearchPage = z.object({
|
|
2185
|
-
listings: z.array(marketplaceSearchRow),
|
|
2186
|
-
total: z.number(),
|
|
2187
|
-
page: z.number(),
|
|
2188
|
-
page_size: z.number(),
|
|
2189
|
-
});
|
|
2190
|
-
export type MarketplaceSearchPage = z.infer<typeof marketplaceSearchPage>;
|
|
2191
|
-
|
|
2192
|
-
/**
|
|
2193
|
-
* One version of a listing as the versions list carries it (`version`, its
|
|
2194
|
-
* publication `status`, the `contract_range` it was validated against, and when
|
|
2195
|
-
* it was `published_at`). `contract_range` and `published_at` are null until a
|
|
2196
|
-
* version reaches the published state, so both are nullable.
|
|
2197
|
-
*/
|
|
2198
|
-
export const marketplaceVersion = z.object({
|
|
2199
|
-
version: z.string(),
|
|
2200
|
-
contract_range: z.string().nullable(),
|
|
2201
|
-
status: z.string(),
|
|
2202
|
-
published_at: z.string().nullable(),
|
|
2203
|
-
});
|
|
2204
|
-
export type MarketplaceVersion = z.infer<typeof marketplaceVersion>;
|
|
2205
|
-
|
|
2206
|
-
/**
|
|
2207
|
-
* The listing's latest published version as embedded in its detail: the version
|
|
2208
|
-
* (with the `marketplaceVersion` lifecycle fields) and the items it contains. The
|
|
2209
|
-
* registry's detail body carries NO per-version `delivery` field — delivery is
|
|
2210
|
-
* server-computed from whether the spec names a package, and the detail surface
|
|
2211
|
-
* derives it from the listing's `package` (null ⇒ `descriptor`, else `package`).
|
|
2212
|
-
* Env to collect comes from the install preview (`required_env` / `missing_env`),
|
|
2213
|
-
* never from these items.
|
|
2214
|
-
*/
|
|
2215
|
-
export const marketplaceLatestVersion = marketplaceVersion.extend({
|
|
2216
|
-
items: z.array(marketplaceItem),
|
|
2217
|
-
});
|
|
2218
|
-
export type MarketplaceLatestVersion = z.infer<typeof marketplaceLatestVersion>;
|
|
2219
|
-
|
|
2220
|
-
/** One advisory row; `withdrawn_at` non-null means it no longer applies. */
|
|
2221
|
-
export const marketplaceAdvisory = z.object({
|
|
2222
|
-
id: z.number(),
|
|
2223
|
-
// The "namespace/name" listing ref exactly as the registry serves it — the
|
|
2224
|
-
// wire field consumers match installed plugins against.
|
|
2225
|
-
listing: z.string(),
|
|
2226
|
-
affected_versions: z.string(),
|
|
2227
|
-
severity: z.string(),
|
|
2228
|
-
summary: z.string(),
|
|
2229
|
-
created_at: z.string(),
|
|
2230
|
-
withdrawn_at: z.string().nullable(),
|
|
2231
|
-
});
|
|
2232
|
-
export type MarketplaceAdvisory = z.infer<typeof marketplaceAdvisory>;
|
|
2233
|
-
|
|
2234
|
-
/**
|
|
2235
|
-
* A plugin's full detail (`GET /api/marketplace/plugins/{ns}/{name}`): the
|
|
2236
|
-
* listing, its latest published version (`null` when nothing is published yet,
|
|
2237
|
-
* carrying the contained items), and the known version history.
|
|
2238
|
-
*/
|
|
2239
|
-
export const marketplacePluginDetail = z.object({
|
|
2240
|
-
namespace: z.string(),
|
|
2241
|
-
name: z.string(),
|
|
2242
|
-
display_name: z.string().nullable(),
|
|
2243
|
-
icon_url: z.string().nullable(),
|
|
2244
|
-
// Null for a descriptor listing (`source` `spec`): it names no package.
|
|
2245
|
-
package: z.string().nullable(),
|
|
2246
|
-
// The install-provenance vocabulary (`pypi` / `github` / `spec`). Nullish: an
|
|
2247
|
-
// older registry omits it, and a listing with nothing published carries none.
|
|
2248
|
-
source: marketplaceSource.nullish(),
|
|
2249
|
-
description: z.string(),
|
|
2250
|
-
readme_md: z.string().nullable(),
|
|
2251
|
-
license: z.string().nullable(),
|
|
2252
|
-
homepage_url: z.string().nullable(),
|
|
2253
|
-
repository_url: z.string().nullable(),
|
|
2254
|
-
// The marketplace-stored docs-site URL: the store is the source, the UI a
|
|
2255
|
-
// link. Nullable + optional: absent on a listing with no published docs.
|
|
2256
|
-
docs_url: z.string().nullish(),
|
|
2257
|
-
categories: z.array(z.string()),
|
|
2258
|
-
tags: z.array(z.string()),
|
|
2259
|
-
trust_tier: z.string(),
|
|
2260
|
-
pricing: z.string(),
|
|
2261
|
-
// A display-only premium flag: a badge, never a payment surface.
|
|
2262
|
-
premium: z.boolean().nullish(),
|
|
2263
|
-
downloads: z.number(),
|
|
2264
|
-
latest: marketplaceLatestVersion.nullable(),
|
|
2265
|
-
versions: z.array(marketplaceVersion),
|
|
2266
|
-
});
|
|
2267
|
-
export type MarketplacePluginDetail = z.infer<typeof marketplacePluginDetail>;
|
|
2268
|
-
|
|
2269
|
-
/**
|
|
2270
|
-
* One installed plugin's compat verdict against the RUNNING tai42-contract:
|
|
2271
|
-
* `compatible` / `incompatible` per its declared contract range, `unknown` when
|
|
2272
|
-
* no verdict could be computed. `reason` is the human-readable explanation of a
|
|
2273
|
-
* non-`compatible` verdict, `null` when compatible. CLOSED (`.strict()`): the
|
|
2274
|
-
* server is built against exactly this shape, so an unknown key is drift and
|
|
2275
|
-
* throws instead of being stripped.
|
|
2276
|
-
*/
|
|
2277
|
-
export const marketplaceInstalledCompat = z
|
|
2278
|
-
.object({
|
|
2279
|
-
status: z.enum(['compatible', 'incompatible', 'unknown']),
|
|
2280
|
-
reason: z.string().nullable(),
|
|
2281
|
-
})
|
|
2282
|
-
.strict();
|
|
2283
|
-
export type MarketplaceInstalledCompat = z.infer<typeof marketplaceInstalledCompat>;
|
|
2284
|
-
|
|
2285
|
-
/**
|
|
2286
|
-
* One installed marketplace plugin as the local attribution store records it.
|
|
2287
|
-
* `latest` is the newest registry version (`null` when unknown);
|
|
2288
|
-
* `update_available` advertises only a newer COMPATIBLE version, and
|
|
2289
|
-
* `incompatible_newer` names the newest version blocked by the running
|
|
2290
|
-
* contract (`null` when none), so "an update exists but needs a newer core" is
|
|
2291
|
-
* visible. `missing_upstream` flags a plugin the registry no longer lists.
|
|
2292
|
-
* `compat` is the row's verdict against the running contract. CLOSED, like
|
|
2293
|
-
* every shape of the installed listing.
|
|
2294
|
-
*/
|
|
2295
|
-
export const marketplaceInstalledPlugin = z
|
|
2296
|
-
.object({
|
|
2297
|
-
ref: z.string(),
|
|
2298
|
-
version: z.string(),
|
|
2299
|
-
source: z.string(),
|
|
2300
|
-
// How the row was delivered: `package` for a pip-installed plugin, `descriptor`
|
|
2301
|
-
// for a descriptor-only plugin whose stored spec names no package.
|
|
2302
|
-
delivery: marketplaceDelivery,
|
|
2303
|
-
installed_at: z.string(),
|
|
2304
|
-
latest: z.string().nullable(),
|
|
2305
|
-
update_available: z.boolean(),
|
|
2306
|
-
incompatible_newer: z.string().nullable(),
|
|
2307
|
-
missing_upstream: z.boolean(),
|
|
2308
|
-
compat: marketplaceInstalledCompat,
|
|
2309
|
-
// The `{kind, name}` of every item this plugin's stored spec provides
|
|
2310
|
-
// (local truth). The connectors page's McpServersSection joins the mcp-server
|
|
2311
|
-
// item names against the manifest's mcp-entry titles to render an
|
|
2312
|
-
// installer-written entry read-only.
|
|
2313
|
-
items: z.array(marketplaceItem.pick({ kind: true, name: true })),
|
|
2314
|
-
// The persisted `{item_name: base}` mount this plugin is installed at (local
|
|
2315
|
-
// truth; `{}` means every item at its declared base). Studio seeds the update
|
|
2316
|
-
// flow and renders routes at the ACTUAL mounted base from this.
|
|
2317
|
-
route_mounts: z.record(z.string(), z.string()),
|
|
2318
|
-
})
|
|
2319
|
-
.strict();
|
|
2320
|
-
export type MarketplaceInstalledPlugin = z.infer<typeof marketplaceInstalledPlugin>;
|
|
2321
|
-
|
|
2322
|
-
/** One plugin the boot pass quarantined instead of loading, with why. CLOSED. */
|
|
2323
|
-
export const marketplaceQuarantinedPlugin = z
|
|
2324
|
-
.object({
|
|
2325
|
-
name: z.string(),
|
|
2326
|
-
reason: z.string(),
|
|
2327
|
-
})
|
|
2328
|
-
.strict();
|
|
2329
|
-
export type MarketplaceQuarantinedPlugin = z.infer<typeof marketplaceQuarantinedPlugin>;
|
|
2330
|
-
|
|
2331
|
-
/**
|
|
2332
|
-
* The installed inventory (`GET /api/marketplace/installed`): the attributed
|
|
2333
|
-
* rows plus every plugin the boot pass quarantined instead of loading. CLOSED.
|
|
2334
|
-
*/
|
|
2335
|
-
export const marketplaceInstalled = z
|
|
2336
|
-
.object({
|
|
2337
|
-
installed: z.array(marketplaceInstalledPlugin),
|
|
2338
|
-
quarantined: z.array(marketplaceQuarantinedPlugin),
|
|
2339
|
-
})
|
|
2340
|
-
.strict();
|
|
2341
|
-
export type MarketplaceInstalled = z.infer<typeof marketplaceInstalled>;
|
|
2342
|
-
|
|
2343
|
-
/**
|
|
2344
|
-
* One per-plugin outcome of `POST /api/marketplace/upgrade-all`: `upgraded`,
|
|
2345
|
-
* already `up-to-date`, `no-compatible-version` in the registry, or `failed`;
|
|
2346
|
-
* `detail` always carries the human-readable specifics. CLOSED.
|
|
2347
|
-
*/
|
|
2348
|
-
export const marketplaceUpgradeAllRow = z
|
|
2349
|
-
.object({
|
|
2350
|
-
ref: z.string(),
|
|
2351
|
-
outcome: z.enum(['upgraded', 'up-to-date', 'no-compatible-version', 'failed']),
|
|
2352
|
-
detail: z.string(),
|
|
2353
|
-
})
|
|
2354
|
-
.strict();
|
|
2355
|
-
export type MarketplaceUpgradeAllRow = z.infer<typeof marketplaceUpgradeAllRow>;
|
|
2356
|
-
|
|
2357
|
-
/** The whole upgrade-all readout: one outcome row per installed plugin. CLOSED. */
|
|
2358
|
-
export const marketplaceUpgradeAllResult = z
|
|
2359
|
-
.object({
|
|
2360
|
-
results: z.array(marketplaceUpgradeAllRow),
|
|
2361
|
-
})
|
|
2362
|
-
.strict();
|
|
2363
|
-
export type MarketplaceUpgradeAllResult = z.infer<typeof marketplaceUpgradeAllResult>;
|
|
2364
|
-
|
|
2365
|
-
/** The advisory state for installed plugins, with when it was last fetched. */
|
|
2366
|
-
export const marketplaceAdvisories = z.object({
|
|
2367
|
-
advisories: z.array(marketplaceAdvisory),
|
|
2368
|
-
fetched_at: z.string(),
|
|
2369
|
-
});
|
|
2370
|
-
|
|
2371
|
-
/** The registry's controlled category list, proxied through the skeleton. */
|
|
2372
|
-
export const marketplaceCategories = z.array(z.string());
|
|
2373
|
-
|
|
2374
|
-
/** The registry's controlled item-kind list, proxied through the skeleton. */
|
|
2375
|
-
export const marketplaceKinds = z.array(z.string());
|
|
2376
|
-
|
|
2377
|
-
/**
|
|
2378
|
-
* One route the install / update actually mounted: the item that owns it, the
|
|
2379
|
-
* absolute `full_path` it now answers, the `methods`, and whether it is served
|
|
2380
|
-
* `public`. The receipt lists these so the operator sees what was opened where.
|
|
2381
|
-
*/
|
|
2382
|
-
export const marketplaceMountedRoute = z.object({
|
|
2383
|
-
item: z.string(),
|
|
2384
|
-
full_path: z.string(),
|
|
2385
|
-
methods: z.array(routeMethod),
|
|
2386
|
-
public: z.boolean(),
|
|
2387
|
-
});
|
|
2388
|
-
export type MarketplaceMountedRoute = z.infer<typeof marketplaceMountedRoute>;
|
|
2389
|
-
|
|
2390
|
-
/**
|
|
2391
|
-
* The receipt of an install / update: what landed and at which version.
|
|
2392
|
-
* `notes` (env-selected items naming their activating env var) and any
|
|
2393
|
-
* non-critical `advisories` ride BOTH the install and update receipts.
|
|
2394
|
-
* `routes` is the mounted-route list — empty for a plugin that registers none.
|
|
2395
|
-
* The wire also carries `package`, `reload`, and `pip_output`, which the receipt
|
|
2396
|
-
* does not model — zod's default strip drops them; the UI renders the receipt,
|
|
2397
|
-
* not the raw install log.
|
|
2398
|
-
*/
|
|
2399
|
-
export const marketplaceInstallResult = z.object({
|
|
2400
|
-
ref: z.string(),
|
|
2401
|
-
version: z.string(),
|
|
2402
|
-
notes: z.array(z.string()),
|
|
2403
|
-
advisories: z.array(marketplaceAdvisory),
|
|
2404
|
-
routes: z.array(marketplaceMountedRoute),
|
|
2405
|
-
});
|
|
2406
|
-
export type MarketplaceInstallResult = z.infer<typeof marketplaceInstallResult>;
|
|
2407
|
-
|
|
2408
|
-
/** One resolved route in an install preview: the declared `path`, its resolved
|
|
2409
|
-
* absolute `full_path`, the `methods`, and whether it is `public`. */
|
|
2410
|
-
export const marketplacePreviewRoute = z.object({
|
|
2411
|
-
path: z.string(),
|
|
2412
|
-
full_path: z.string(),
|
|
2413
|
-
methods: z.array(routeMethod),
|
|
2414
|
-
public: z.boolean(),
|
|
2415
|
-
});
|
|
2416
|
-
export type MarketplacePreviewRoute = z.infer<typeof marketplacePreviewRoute>;
|
|
2417
|
-
|
|
2418
|
-
/** One route-carrying item in an install preview: its resolved `base` (the
|
|
2419
|
-
* override or the default), the `default_base` it declares, and the routes that
|
|
2420
|
-
* mount under it. */
|
|
2421
|
-
export const marketplacePreviewItem = z.object({
|
|
2422
|
-
item: z.string(),
|
|
2423
|
-
kind: z.string(),
|
|
2424
|
-
base: z.string(),
|
|
2425
|
-
default_base: z.string(),
|
|
2426
|
-
routes: z.array(marketplacePreviewRoute),
|
|
2427
|
-
});
|
|
2428
|
-
export type MarketplacePreviewItem = z.infer<typeof marketplacePreviewItem>;
|
|
2429
|
-
|
|
2430
|
-
/** One collision the preview found: a route whose resolved shape+method clashes
|
|
2431
|
-
* with an already-owned route. `conflict_owner` is `core` or `plugin:<ref>`; the
|
|
2432
|
-
* remedy is to remap the item's base. */
|
|
2433
|
-
export const marketplacePreviewCollision = z.object({
|
|
2434
|
-
item: z.string(),
|
|
2435
|
-
full_path: z.string(),
|
|
2436
|
-
methods: z.array(routeMethod),
|
|
2437
|
-
conflict_owner: z.string(),
|
|
2438
|
-
conflict_path: z.string(),
|
|
2439
|
-
});
|
|
2440
|
-
export type MarketplacePreviewCollision = z.infer<typeof marketplacePreviewCollision>;
|
|
2441
|
-
|
|
2442
|
-
/** One public route the operator is asked to accept: served WITHOUT
|
|
2443
|
-
* authentication once installed. */
|
|
2444
|
-
export const marketplacePreviewPublicRoute = z.object({
|
|
2445
|
-
item: z.string(),
|
|
2446
|
-
full_path: z.string(),
|
|
2447
|
-
methods: z.array(routeMethod),
|
|
2448
|
-
});
|
|
2449
|
-
export type MarketplacePreviewPublicRoute = z.infer<typeof marketplacePreviewPublicRoute>;
|
|
2450
|
-
|
|
2451
|
-
/**
|
|
2452
|
-
* The install preview (`POST /api/marketplace/install/preview`): the resolved
|
|
2453
|
-
* routes per item with any base overrides applied, the collisions against the
|
|
2454
|
-
* live registry, the public routes requiring acceptance, and whether acceptance
|
|
2455
|
-
* is required at all. `new_public_routes` narrows to rows not already approved
|
|
2456
|
-
* (the update case); on a fresh install it equals `public_routes`.
|
|
2457
|
-
*
|
|
2458
|
-
* `required_env` is every env var the spec requires with its derived secret-ness;
|
|
2459
|
-
* `missing_env` is the bare names not already present in the env store union
|
|
2460
|
-
* process env (server-computed — the ONE authority the dialog collects), and
|
|
2461
|
-
* `delivery` is the one word the surface shows (`package` / `descriptor`).
|
|
2462
|
-
*/
|
|
2463
|
-
export const marketplaceInstallPreview = z.object({
|
|
2464
|
-
ref: z.string(),
|
|
2465
|
-
version: z.string(),
|
|
2466
|
-
items: z.array(marketplacePreviewItem),
|
|
2467
|
-
collisions: z.array(marketplacePreviewCollision),
|
|
2468
|
-
public_routes: z.array(marketplacePreviewPublicRoute),
|
|
2469
|
-
new_public_routes: z.array(marketplacePreviewPublicRoute),
|
|
2470
|
-
requires_public_acceptance: z.boolean(),
|
|
2471
|
-
required_env: z.array(marketplaceRequiredEnvVar),
|
|
2472
|
-
missing_env: z.array(z.string()),
|
|
2473
|
-
delivery: marketplaceDelivery,
|
|
2474
|
-
});
|
|
2475
|
-
export type MarketplaceInstallPreview = z.infer<typeof marketplaceInstallPreview>;
|
|
2476
|
-
|
|
2477
|
-
/**
|
|
2478
|
-
* The receipt of an uninstall. `notes` carries operator warnings (e.g. a config
|
|
2479
|
-
* provider still selected by its env var); render them like the install
|
|
2480
|
-
* receipt's notes.
|
|
2481
|
-
*/
|
|
2482
|
-
export const marketplaceUninstallResult = z.object({
|
|
2483
|
-
ref: z.string(),
|
|
2484
|
-
uninstalled: z.literal(true),
|
|
2485
|
-
notes: z.array(z.string()),
|
|
2486
|
-
});
|
|
2487
|
-
export type MarketplaceUninstallResult = z.infer<typeof marketplaceUninstallResult>;
|
|
2488
|
-
|
|
2489
|
-
// Background tool-run schemas live in their own module; re-exported here so the
|
|
2490
|
-
// shared fixture-validation contract resolves them by name alongside the rest.
|
|
2491
|
-
export { toolRunSubmitResult, toolRunRecord, toolRunList } from './tool-runs';
|
|
2492
|
-
|
|
2493
|
-
// -- states ------------------------------------------------------------------
|
|
2494
|
-
// The hand-written state response DTOs — list rows and detail (built on the generated
|
|
2495
|
-
// `stateDeclaration`), attachments, per-subject records and subjects, stats and consumers.
|
|
2496
|
-
// The served DOCUMENT schemas (`stateDeclaration`/`stateTemplateDocument` and the template
|
|
2497
|
-
// sub-shapes) are generated from the contract bundle and re-exported at the top of this
|
|
2498
|
-
// file. The composed `effective_schema` and write `regimes` stay permissive JSON records
|
|
2499
|
-
// (the auto-form and JsonTree interpret them at runtime) and are server-computed, so they
|
|
2500
|
-
// are modelled optional and a response that omits them still parses.
|
|
2501
|
-
|
|
2502
|
-
/** One addressed subject: the conversation-target scope plus the (kind, key) within it. */
|
|
2503
|
-
export const stateSubject = z.object({
|
|
2504
|
-
target_kind: conversationTargetKind,
|
|
2505
|
-
target_name: z.string(),
|
|
2506
|
-
kind: z.string(),
|
|
2507
|
-
key: z.string(),
|
|
2508
|
-
});
|
|
2509
|
-
export type StateSubject = z.infer<typeof stateSubject>;
|
|
2510
|
-
|
|
2511
|
-
/** One absolute write-regime rule composed over the attachments: `{path, regime}`, permissive. */
|
|
2512
|
-
export const stateRegime = z.record(z.string(), z.unknown());
|
|
2513
|
-
|
|
2514
|
-
/**
|
|
2515
|
-
* One row of `GET /api/states` — a served declaration (`list_states` dumps every
|
|
2516
|
-
* `StateDeclaration`) plus `updated_at` (the row's last-write timestamp, ISO or
|
|
2517
|
-
* `null`). The list carries no record count; the `Records` column reads
|
|
2518
|
-
* `getStateStats` lazily per row.
|
|
2519
|
-
*/
|
|
2520
|
-
export const stateListItem = stateDeclaration.extend({
|
|
2521
|
-
updated_at: z.string().nullable().default(null),
|
|
2522
|
-
});
|
|
2523
|
-
export type StateListItem = z.infer<typeof stateListItem>;
|
|
2524
|
-
export const stateList = z.array(stateListItem);
|
|
2525
|
-
|
|
2526
|
-
/** One template attachment on a state: where the fragment lands + its param/declaration values. */
|
|
2527
|
-
export const stateAttachment = z.object({
|
|
2528
|
-
template: z.string(),
|
|
2529
|
-
path: z.array(z.string()),
|
|
2530
|
-
parameters: z.record(z.string(), z.unknown()).default({}),
|
|
2531
|
-
declarations: z.record(z.string(), z.unknown()).default({}),
|
|
2532
|
-
});
|
|
2533
|
-
export type StateAttachment = z.infer<typeof stateAttachment>;
|
|
2534
|
-
export const stateAttachmentList = z.array(stateAttachment);
|
|
2535
|
-
|
|
2536
|
-
/** `GET /api/states/{name}` — the declaration (with effective schema + regimes) plus attachments. */
|
|
2537
|
-
export const stateDetail = stateDeclaration.extend({
|
|
2538
|
-
attachments: z.array(stateAttachment).default([]),
|
|
2539
|
-
});
|
|
2540
|
-
export type StateDetail = z.infer<typeof stateDetail>;
|
|
2541
|
-
|
|
2542
|
-
/**
|
|
2543
|
-
* `GET /api/states/{name}/stats` — `records` (total documents), `per_field` (the count
|
|
2544
|
-
* of records carrying each base-schema property), `per_kind` (records per subject kind)
|
|
2545
|
-
* and `consumers` (the count of listable consumers). The Records tab shows `records`;
|
|
2546
|
-
* the states list reads it lazily for its Records column.
|
|
2547
|
-
*/
|
|
2548
|
-
export const stateStats = z.object({
|
|
2549
|
-
records: z.number(),
|
|
2550
|
-
per_field: z.record(z.string(), z.number()).default({}),
|
|
2551
|
-
per_kind: z.record(z.string(), z.number()).default({}),
|
|
2552
|
-
consumers: z.number().default(0),
|
|
2553
|
-
});
|
|
2554
|
-
export type StateStats = z.infer<typeof stateStats>;
|
|
2555
|
-
|
|
2556
|
-
/**
|
|
2557
|
-
* One row of `GET /api/state-templates`. The template document plus the two derived columns
|
|
2558
|
-
* the Templates tab shows: `attached_to` (how many states attach it — a delete is refused
|
|
2559
|
-
* while > 0) and `shipped_default` (a platform-shipped template). Both are server-derived
|
|
2560
|
-
* columns; the document fields are verbatim.
|
|
2561
|
-
*/
|
|
2562
|
-
export const stateTemplateListItem = stateTemplateDocument.extend({
|
|
2563
|
-
attached_to: z.number().default(0),
|
|
2564
|
-
shipped_default: z.boolean().default(false),
|
|
2565
|
-
});
|
|
2566
|
-
export type StateTemplateListItem = z.infer<typeof stateTemplateListItem>;
|
|
2567
|
-
export const stateTemplateList = z.array(stateTemplateListItem);
|
|
2568
|
-
|
|
2569
|
-
/** A read record: the state, its subject, the document + monotonic seq, and any fold. */
|
|
2570
|
-
export const stateRecord = z.object({
|
|
2571
|
-
state: z.string(),
|
|
2572
|
-
subject: stateSubject,
|
|
2573
|
-
data: z.record(z.string(), z.unknown()).default({}),
|
|
2574
|
-
seq: z.number(),
|
|
2575
|
-
canonical_subject: stateSubject,
|
|
2576
|
-
folded_from: z.array(stateSubject).default([]),
|
|
2577
|
-
});
|
|
2578
|
-
export type StateRecord = z.infer<typeof stateRecord>;
|
|
2579
|
-
|
|
2580
|
-
/** The outcome of an `apply` (a delta batch): whether it applied + the resulting doc. */
|
|
2581
|
-
export const applyResult = z.object({
|
|
2582
|
-
applied: z.boolean(),
|
|
2583
|
-
data: z.record(z.string(), z.unknown()).nullable().default(null),
|
|
2584
|
-
seq: z.number().nullable().default(null),
|
|
2585
|
-
skipped: z.array(z.record(z.string(), z.unknown())).default([]),
|
|
2586
|
-
});
|
|
2587
|
-
export type ApplyResult = z.infer<typeof applyResult>;
|
|
2588
|
-
|
|
2589
|
-
/**
|
|
2590
|
-
* `GET …/template-jq/{name}` — the evaluated template jq's `name`, its `purpose`, and
|
|
2591
|
-
* its `value` (the `input` jq's read). GET evaluates ONLY an `input`-purpose jq; a GET
|
|
2592
|
-
* on an `update`-purpose name is refused with 422, so the result's purpose is always
|
|
2593
|
-
* `input`.
|
|
2594
|
-
*/
|
|
2595
|
-
export const templateJqResult = z.object({
|
|
2596
|
-
name: z.string(),
|
|
2597
|
-
purpose: z.literal('input'),
|
|
2598
|
-
value: z.unknown(),
|
|
2599
|
-
});
|
|
2600
|
-
export type TemplateJqResult = z.infer<typeof templateJqResult>;
|
|
2601
|
-
|
|
2602
|
-
/**
|
|
2603
|
-
* `POST …/template-jq/{name}` — the applied template jq's outcome. The jq lands an op
|
|
2604
|
-
* batch through the same `apply` chokepoint as a delta, so `applied`/`data`/`seq`/`skipped`
|
|
2605
|
-
* carry that outcome.
|
|
2606
|
-
*/
|
|
2607
|
-
export const templateJqApplyResult = z.object({
|
|
2608
|
-
name: z.string(),
|
|
2609
|
-
applied: z.boolean(),
|
|
2610
|
-
data: z.record(z.string(), z.unknown()).nullable().default(null),
|
|
2611
|
-
seq: z.number().nullable().default(null),
|
|
2612
|
-
skipped: z.array(z.record(z.string(), z.unknown())).default([]),
|
|
2613
|
-
});
|
|
2614
|
-
export type TemplateJqApplyResult = z.infer<typeof templateJqApplyResult>;
|
|
2615
|
-
|
|
2616
|
-
/**
|
|
2617
|
-
* One paged subject row: the addressed `subject` plus its record's last-write
|
|
2618
|
-
* `updated_at` — epoch seconds (the store's `extract(epoch FROM updated_at)`), served
|
|
2619
|
-
* raw (no `mode="json"` dump), and `NOT NULL` on every record, so a plain number.
|
|
2620
|
-
*/
|
|
2621
|
-
export const subjectRow = z.object({
|
|
2622
|
-
subject: stateSubject,
|
|
2623
|
-
updated_at: z.number(),
|
|
2624
|
-
});
|
|
2625
|
-
export type SubjectRow = z.infer<typeof subjectRow>;
|
|
2626
|
-
|
|
2627
|
-
/**
|
|
2628
|
-
* `GET /api/states/{name}/subjects` — a keyset page of subject rows (optionally of one
|
|
2629
|
-
* `kind`): the matched `subjects` plus the `next_cursor` a "Load more" carries back
|
|
2630
|
-
* (`null` at the end).
|
|
2631
|
-
*/
|
|
2632
|
-
export const subjectPage = z.object({
|
|
2633
|
-
subjects: z.array(subjectRow),
|
|
2634
|
-
next_cursor: z.string().nullable().default(null),
|
|
2635
|
-
});
|
|
2636
|
-
export type SubjectPage = z.infer<typeof subjectPage>;
|
|
2637
|
-
|
|
2638
|
-
/**
|
|
2639
|
-
* `POST /api/states/{name}/records/search` — a keyset page of the subject rows whose
|
|
2640
|
-
* document contains the filters (a JSONB containment match). Each hit's `subject` opens
|
|
2641
|
-
* the record page; `next_cursor` pages the rest.
|
|
2642
|
-
*/
|
|
2643
|
-
export const recordSearchPage = z.object({
|
|
2644
|
-
matches: z.array(subjectRow),
|
|
2645
|
-
next_cursor: z.string().nullable().default(null),
|
|
2646
|
-
});
|
|
2647
|
-
export type RecordSearchPage = z.infer<typeof recordSearchPage>;
|
|
2648
|
-
|
|
2649
|
-
/** A WriteEntry's origin completed by the platform chokepoint (mirrors CompletedOrigin). */
|
|
2650
|
-
export const completedOrigin = z.object({
|
|
2651
|
-
consumer: z.string().nullable().default(null),
|
|
2652
|
-
// Opaque consumer-supplied provenance JSON the platform stores as is.
|
|
2653
|
-
meta: z.record(z.string(), z.unknown()).nullable().default(null),
|
|
2654
|
-
run_id: z.string().nullable().default(null),
|
|
2655
|
-
op_id: z.string().nullable().default(null),
|
|
2656
|
-
door: z.string(),
|
|
2657
|
-
actor: z.string().nullable().default(null),
|
|
2658
|
-
turn_id: z.string().nullable().default(null),
|
|
2659
|
-
inbound_id: z.string().nullable().default(null),
|
|
2660
|
-
});
|
|
2661
|
-
export type CompletedOrigin = z.infer<typeof completedOrigin>;
|
|
2662
|
-
|
|
2663
|
-
/** One row of a subject's audit trail (mirrors WriteEntry). `paths` are absolute. */
|
|
2664
|
-
export const writeEntry = z.object({
|
|
2665
|
-
seq: z.number(),
|
|
2666
|
-
at: z.string(),
|
|
2667
|
-
origin: completedOrigin,
|
|
2668
|
-
paths: z.array(z.array(z.union([z.string(), z.number()]))).default([]),
|
|
2669
|
-
});
|
|
2670
|
-
export type WriteEntry = z.infer<typeof writeEntry>;
|
|
2671
|
-
|
|
2672
|
-
/** `GET /api/states/{name}/records/.../writes` — a keyset page of the audit trail. */
|
|
2673
|
-
export const writesPage = z.object({
|
|
2674
|
-
items: z.array(writeEntry),
|
|
2675
|
-
next_cursor: z.string().nullable().default(null),
|
|
2676
|
-
});
|
|
2677
|
-
export type WritesPage = z.infer<typeof writesPage>;
|
|
2678
|
-
|
|
2679
|
-
/** Where the Studio opens a consumer (mirrors ConsumerLink): a token+search OR plugin path. */
|
|
2680
|
-
export const consumerLink = z.object({
|
|
2681
|
-
token: z.string().nullable().default(null),
|
|
2682
|
-
plugin_path: z.string().nullable().default(null),
|
|
2683
|
-
search: z.record(z.string(), z.unknown()).nullable().default(null),
|
|
2684
|
-
});
|
|
2685
|
-
export type ConsumerLink = z.infer<typeof consumerLink>;
|
|
2686
|
-
|
|
2687
|
-
/**
|
|
2688
|
-
* One thing that binds a state (mirrors ConsumerRow): its `kind` (flow / hook / schedule
|
|
2689
|
-
* / agent), `name`, human `detail` and optional `link`. `unavailable` marks a consumer
|
|
2690
|
-
* family that cannot be listed on this deployment (e.g. no scheduling backend), surfaced
|
|
2691
|
-
* as a muted line — never swallowed.
|
|
2692
|
-
*/
|
|
2693
|
-
export const consumerRow = z.object({
|
|
2694
|
-
kind: z.string(),
|
|
2695
|
-
name: z.string().nullable().default(null),
|
|
2696
|
-
detail: z.string().nullable().default(null),
|
|
2697
|
-
link: consumerLink.nullable().default(null),
|
|
2698
|
-
unavailable: z.string().nullable().default(null),
|
|
2699
|
-
});
|
|
2700
|
-
export type ConsumerRow = z.infer<typeof consumerRow>;
|
|
2701
|
-
|
|
2702
|
-
/** `GET /api/states/{name}/consumers` — the union of every registered lister's rows. */
|
|
2703
|
-
export const stateConsumers = z.array(consumerRow);
|
|
2704
|
-
export type StateConsumers = z.infer<typeof stateConsumers>;
|
|
2705
|
-
|
|
2706
|
-
/** `DELETE /api/states/{name}` — the removed state. */
|
|
2707
|
-
export const stateDeleted = z.object({ name: z.string(), deleted: z.literal(true) });
|
|
2708
|
-
|
|
2709
|
-
/** `PUT /api/states/{name}/attachments/{template}` — the template now attached to the state. */
|
|
2710
|
-
export const stateAttached = z.object({
|
|
2711
|
-
attached: z.literal(true),
|
|
2712
|
-
state: z.string(),
|
|
2713
|
-
template: z.string(),
|
|
2714
|
-
});
|
|
2715
|
-
export type StateAttached = z.infer<typeof stateAttached>;
|
|
2716
|
-
|
|
2717
|
-
/** `PATCH /api/states/{name}/attachments/{template}` — the attachment whose declarations were rewritten. */
|
|
2718
|
-
export const stateAttachmentUpdated = z.object({
|
|
2719
|
-
updated: z.literal(true),
|
|
2720
|
-
state: z.string(),
|
|
2721
|
-
template: z.string(),
|
|
2722
|
-
});
|
|
2723
|
-
export type StateAttachmentUpdated = z.infer<typeof stateAttachmentUpdated>;
|
|
2724
|
-
|
|
2725
|
-
/** `DELETE /api/states/{name}/attachments/{template}` — the template detached from the state. */
|
|
2726
|
-
export const stateDetached = z.object({
|
|
2727
|
-
detached: z.literal(true),
|
|
2728
|
-
state: z.string(),
|
|
2729
|
-
template: z.string(),
|
|
2730
|
-
});
|
|
2731
|
-
export type StateDetached = z.infer<typeof stateDetached>;
|
|
2732
|
-
|
|
2733
|
-
/**
|
|
2734
|
-
* `POST /api/states/{name}/records/.../fold` — the fold report: the `mode`, the
|
|
2735
|
-
* `{kind, key}` of the folded `from` and surviving `into` subjects, whether the fold
|
|
2736
|
-
* was `already` in place, and how many records were `flattened` into the survivor.
|
|
2737
|
-
*/
|
|
2738
|
-
export const stateFoldReport = z.object({
|
|
2739
|
-
mode: z.enum(['switch', 'merge']),
|
|
2740
|
-
from: z.object({ kind: z.string(), key: z.string() }),
|
|
2741
|
-
into: z.object({ kind: z.string(), key: z.string() }),
|
|
2742
|
-
already: z.boolean(),
|
|
2743
|
-
flattened: z.number().default(0),
|
|
2744
|
-
});
|
|
2745
|
-
export type StateFoldReport = z.infer<typeof stateFoldReport>;
|
|
2746
|
-
|
|
2747
|
-
/** `DELETE /api/state-templates/{name}` — the removed template document. */
|
|
2748
|
-
export const stateTemplateDeleted = z.object({ name: z.string(), deleted: z.literal(true) });
|
|
2749
|
-
|
|
2750
|
-
/** `DELETE /api/states/{name}/records/...` — the erased record marker. */
|
|
2751
|
-
export const recordErased = z.object({ erased: z.literal(true) });
|
|
2752
|
-
|
|
2753
|
-
/**
|
|
2754
|
-
* `POST /api/state-retention/prune` — the retention sweep's per-state deleted counts
|
|
2755
|
-
* (`{}` when nothing expired); the UI sums the values for its total.
|
|
2756
|
-
*/
|
|
2757
|
-
export const stateRetentionPruned = z.object({
|
|
2758
|
-
pruned: z.record(z.string(), z.number()).default({}),
|
|
2759
|
-
});
|
|
2760
|
-
export type StateRetentionPruned = z.infer<typeof stateRetentionPruned>;
|