@spacefast/common 0.2.2 → 0.4.1
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/marketplace-prompts.d.ts +1 -0
- package/dist/agents/marketplace-prompts.js +6 -0
- package/dist/agents/registry/core.d.ts +4 -12
- package/dist/agents/registry/core.js +7 -28
- package/dist/config/domains.d.ts +10 -8
- package/dist/config/domains.js +4 -7
- package/dist/contracts/access-core.d.ts +135 -0
- package/dist/contracts/access-core.js +242 -0
- package/dist/contracts/access-profiles.d.ts +8 -8
- package/dist/contracts/access-profiles.js +8 -8
- package/dist/contracts/access.d.ts +14 -103
- package/dist/contracts/access.js +10 -210
- package/dist/contracts/activity.d.ts +54 -55
- package/dist/contracts/activity.js +38 -9
- package/dist/contracts/api-keys.d.ts +69 -26
- package/dist/contracts/api-keys.js +29 -2
- package/dist/contracts/application-journal.d.ts +197 -4
- package/dist/contracts/application-journal.js +97 -16
- package/dist/contracts/auth.d.ts +20 -0
- package/dist/contracts/auth.js +18 -0
- package/dist/contracts/beta.d.ts +13 -0
- package/dist/contracts/beta.js +28 -0
- package/dist/contracts/billing.d.ts +2 -2
- package/dist/contracts/bootstrap.d.ts +23 -6
- package/dist/contracts/builds.d.ts +18 -4
- package/dist/contracts/builds.js +7 -4
- package/dist/contracts/channels.d.ts +43 -0
- package/dist/contracts/channels.js +22 -6
- package/dist/contracts/comments.d.ts +49 -0
- package/dist/contracts/comments.js +61 -2
- package/dist/contracts/commerce.d.ts +19 -13
- package/dist/contracts/connector-access.d.ts +28 -0
- package/dist/contracts/connector-access.js +31 -0
- package/dist/contracts/connectors.d.ts +2382 -0
- package/dist/contracts/connectors.js +941 -0
- package/dist/contracts/content-contract-verification.d.ts +112 -58
- package/dist/contracts/content-contract-verification.js +42 -54
- package/dist/contracts/content-model-emit.d.ts +97 -0
- package/dist/contracts/content-model-emit.js +306 -0
- package/dist/contracts/content-model-sdk.d.ts +101 -0
- package/dist/contracts/content-model-sdk.js +232 -0
- package/dist/contracts/{content-program.d.ts → content-model.d.ts} +338 -82
- package/dist/contracts/{content-program.js → content-model.js} +291 -63
- package/dist/contracts/content-platform-fixture.d.ts +380 -110
- package/dist/contracts/content-platform-fixture.js +8 -8
- package/dist/contracts/content-sync.d.ts +197 -74
- package/dist/contracts/content-sync.js +98 -37
- package/dist/contracts/content.d.ts +30 -422
- package/dist/contracts/content.js +34 -294
- package/dist/contracts/dashboard-prefs.d.ts +10 -3
- package/dist/contracts/dashboard-prefs.js +6 -3
- package/dist/contracts/data-location.d.ts +9 -0
- package/dist/contracts/data-location.js +7 -0
- package/dist/contracts/deployment-comparison.d.ts +67 -0
- package/dist/contracts/deployment-comparison.js +68 -0
- package/dist/contracts/device-auth.d.ts +55 -11
- package/dist/contracts/domains.d.ts +40 -16
- package/dist/contracts/domains.js +23 -0
- package/dist/contracts/enums.d.ts +1 -10
- package/dist/contracts/enums.js +0 -15
- package/dist/contracts/error-code-meta.d.ts +384 -20
- package/dist/contracts/error-code-meta.js +200 -5
- package/dist/contracts/error-codes.d.ts +17 -4
- package/dist/contracts/error-codes.js +108 -10
- package/dist/contracts/events.d.ts +5 -0
- package/dist/contracts/events.js +12 -3
- package/dist/contracts/execution.d.ts +5 -1
- package/dist/contracts/execution.js +4 -0
- package/dist/contracts/feature-lifecycle.d.ts +53 -20
- package/dist/contracts/feature-lifecycle.js +65 -23
- package/dist/contracts/features.d.ts +57 -31
- package/dist/contracts/features.js +0 -1
- package/dist/contracts/feedback.d.ts +124 -0
- package/dist/contracts/feedback.js +64 -0
- package/dist/contracts/fixtures/content-model-sdk-v1.generated.d.ts +129 -0
- package/dist/contracts/fixtures/content-model-sdk-v1.generated.js +48 -0
- package/dist/contracts/fixtures/content-platform-v1.json +101 -49
- package/dist/contracts/frame-session.d.ts +60 -10
- package/dist/contracts/frame-session.js +52 -12
- package/dist/contracts/functions.d.ts +28 -2
- package/dist/contracts/functions.js +25 -2
- package/dist/contracts/grant-copy.d.ts +2 -0
- package/dist/contracts/grant-copy.js +2 -0
- package/dist/contracts/grants-core.d.ts +95 -0
- package/dist/contracts/grants-core.js +435 -0
- package/dist/contracts/grants.d.ts +13 -84
- package/dist/contracts/grants.js +21 -369
- package/dist/contracts/ids-core.d.ts +11 -0
- package/dist/contracts/ids-core.js +14 -0
- package/dist/contracts/ids.d.ts +7 -4
- package/dist/contracts/ids.js +12 -4
- package/dist/contracts/internal.d.ts +18 -0
- package/dist/contracts/internal.js +19 -0
- package/dist/contracts/mcp.d.ts +8 -18
- package/dist/contracts/mcp.js +2 -23
- package/dist/contracts/notifications.d.ts +4 -1
- package/dist/contracts/notifications.js +1 -0
- package/dist/contracts/oauth-resources.d.ts +46 -9
- package/dist/contracts/oauth-resources.js +50 -1
- package/dist/contracts/oauth-scope-actions.d.ts +27 -3
- package/dist/contracts/oauth-scope-actions.js +18 -8
- package/dist/contracts/operations.d.ts +1 -1
- package/dist/contracts/partner-account.d.ts +629 -0
- package/dist/contracts/partner-account.js +18 -0
- package/dist/contracts/principal-assertion.d.ts +74 -1
- package/dist/contracts/principal-assertion.js +67 -3
- package/dist/contracts/publish-archive.d.ts +22 -1
- package/dist/contracts/push-new.d.ts +3 -3
- package/dist/contracts/push-new.js +1 -1
- package/dist/contracts/quotas.js +2 -1
- package/dist/contracts/repository-connections.d.ts +10 -6
- package/dist/contracts/repository-connections.js +15 -0
- package/dist/contracts/resources.d.ts +6 -5
- package/dist/contracts/resources.js +7 -0
- package/dist/contracts/route-inventory.d.ts +74 -19
- package/dist/contracts/route-inventory.js +20 -6
- package/dist/contracts/runtime-api.d.ts +415 -4
- package/dist/contracts/runtime-api.js +60 -15
- package/dist/contracts/runtime-app.d.ts +6 -1
- package/dist/contracts/runtime-components.d.ts +646 -18
- package/dist/contracts/runtime-components.js +304 -188
- package/dist/contracts/runtime-services.d.ts +15 -0
- package/dist/contracts/runtime-services.js +25 -0
- package/dist/contracts/runtime-storage.d.ts +32 -0
- package/dist/contracts/runtime-storage.js +37 -0
- package/dist/contracts/source-workspaces.d.ts +511 -0
- package/dist/contracts/source-workspaces.js +276 -0
- package/dist/contracts/space-config-spacefast.d.ts +394 -0
- package/dist/contracts/space-config-spacefast.js +70 -0
- package/dist/contracts/space-config.d.ts +177 -90
- package/dist/contracts/space-config.js +77 -92
- package/dist/contracts/spaces.d.ts +132 -24
- package/dist/contracts/spaces.js +77 -13
- package/dist/contracts/superadmin-connectors.d.ts +371 -0
- package/dist/contracts/superadmin-connectors.js +61 -0
- package/dist/contracts/superadmin-emails.d.ts +1 -1
- package/dist/contracts/superadmin-emails.js +1 -1
- package/dist/contracts/superadmin-entities.d.ts +105 -0
- package/dist/contracts/superadmin-entities.js +64 -0
- package/dist/contracts/superadmin-runtime.d.ts +35 -116
- package/dist/contracts/superadmin-runtime.js +13 -69
- package/dist/contracts/superadmin-search.d.ts +12 -14
- package/dist/contracts/superadmin-search.js +2 -2
- package/dist/contracts/superadmin-spaces.d.ts +15 -72
- package/dist/contracts/superadmin-spaces.js +2 -7
- package/dist/contracts/superadmin-teams.d.ts +12 -0
- package/dist/contracts/superadmin-teams.js +7 -1
- package/dist/contracts/superadmin-tenants.d.ts +44 -16
- package/dist/contracts/superadmin.d.ts +2 -2
- package/dist/contracts/tags.d.ts +12 -12
- package/dist/contracts/teams.d.ts +29 -1
- package/dist/contracts/teams.js +24 -2
- package/dist/contracts/tenants.d.ts +98 -0
- package/dist/contracts/tenants.js +20 -0
- package/dist/contracts/transfers.d.ts +92 -0
- package/dist/contracts/transfers.js +37 -0
- package/dist/contracts/usage.d.ts +9 -1
- package/dist/contracts/usage.js +2 -0
- package/dist/contracts/visual-review.d.ts +448 -0
- package/dist/contracts/visual-review.js +156 -0
- package/dist/contracts/wordpress-php-toolkit.json +9 -0
- package/dist/contracts/work-mode.d.ts +24 -0
- package/dist/contracts/work-mode.js +17 -0
- package/dist/contracts/wp-cli.d.ts +66 -0
- package/dist/contracts/wp-cli.js +68 -0
- package/dist/contracts/zero-catalog.d.ts +29 -0
- package/dist/contracts/zero-catalog.js +55 -0
- package/dist/contracts/zero-platform-abilities.generated.d.ts +31 -0
- package/dist/contracts/zero-platform-abilities.generated.js +373 -0
- package/dist/contracts/zero-spacefast.d.ts +444 -0
- package/dist/contracts/zero-spacefast.js +149 -0
- package/dist/contracts/zero-types.d.ts +47 -0
- package/dist/contracts/zero-types.js +263 -0
- package/dist/contracts/zero.d.ts +781 -14
- package/dist/contracts/zero.js +204 -10
- package/dist/dashboard-paths/index.d.ts +2 -2
- package/dist/dashboard-paths/route-reservations.generated.d.ts +2 -2
- package/dist/dashboard-paths/route-reservations.generated.js +5 -0
- package/dist/docs/agent-prose.d.ts +1 -1
- package/dist/docs/agent-prose.js +15 -18
- package/dist/docs/agent-setup.d.ts +1 -1
- package/dist/docs/agent-setup.js +5 -13
- package/dist/docs/catalog.d.ts +64 -28
- package/dist/docs/catalog.js +155 -28
- package/dist/docs/error-docs.d.ts +361 -17
- package/dist/docs/error-docs.js +365 -21
- package/dist/docs/reference-urls.js +1 -1
- package/dist/docs/skills.d.ts +84 -84
- package/dist/docs/skills.js +66 -47
- package/dist/docs/start-prompts.d.ts +14 -0
- package/dist/docs/start-prompts.js +20 -0
- package/dist/utils/account-labels.d.ts +7 -0
- package/dist/utils/account-labels.js +15 -0
- package/dist/utils/auth.d.ts +1 -0
- package/dist/utils/auth.js +1 -0
- package/dist/utils/credential-policy.d.ts +22 -1
- package/dist/utils/credential-policy.js +55 -6
- package/dist/utils/local-space-state.d.ts +7 -0
- package/dist/utils/local-space-state.js +7 -0
- package/dist/utils/logger.d.ts +34 -0
- package/dist/utils/logger.js +144 -0
- package/dist/utils/page-routes.d.ts +9 -0
- package/dist/utils/page-routes.js +82 -0
- package/dist/utils/pages.d.ts +2 -0
- package/dist/utils/pages.js +7 -0
- package/dist/utils/publish-form-data.d.ts +2 -0
- package/dist/utils/publish-form-data.js +2 -0
- package/dist/utils/publish-policy-spacefast.d.ts +13 -0
- package/dist/utils/publish-policy-spacefast.js +117 -0
- package/dist/utils/publish-policy.d.ts +22 -16
- package/dist/utils/publish-policy.fixtures.json +15 -0
- package/dist/utils/publish-policy.js +62 -139
- package/dist/utils/query-client.js +9 -1
- package/dist/utils/runtime-upload.d.ts +4 -0
- package/dist/utils/runtime-upload.js +5 -0
- package/dist/utils/space-config.d.ts +2 -3
- package/dist/utils/space-config.js +1 -1
- package/dist/utils/uploaded-source.d.ts +4 -0
- package/dist/utils/uploaded-source.js +12 -0
- package/dist/visual-review.d.ts +4 -0
- package/dist/visual-review.js +208 -0
- package/dist/vocabulary.d.ts +38 -0
- package/dist/vocabulary.js +55 -0
- package/package.json +7 -2
- package/dist/agents/registry/deeplink-probes.d.ts +0 -23
- package/dist/agents/registry/deeplink-probes.js +0 -18
|
@@ -0,0 +1,941 @@
|
|
|
1
|
+
// Connectors: team-scoped integrations over the Executor engine. One connector
|
|
2
|
+
// is a tool source (an OpenAPI spec, a GraphQL endpoint, a remote MCP server);
|
|
3
|
+
// one connection is a configured, optionally authenticated instance of it; one
|
|
4
|
+
// run is a single execution — a tool call or a code program — with one status
|
|
5
|
+
// machine and one resume path.
|
|
6
|
+
//
|
|
7
|
+
// Two rules this file exists to enforce on the wire:
|
|
8
|
+
//
|
|
9
|
+
// - SECRETS NEVER LEAVE THE CONTROL PLANE. Credentials are write-only:
|
|
10
|
+
// accepted on create, never returned. Reads expose `credentialConfigured`,
|
|
11
|
+
// the way `RepositoryConnectionSchema` does — never the value, never the
|
|
12
|
+
// ciphertext, never a masked preview a client could be tempted to parse.
|
|
13
|
+
// - ONE ADDRESS GRAMMAR. A tool is `<connectionId>/<tool>`. The engine's
|
|
14
|
+
// five-segment addresses and its
|
|
15
|
+
// `org|user` owner vocabulary stop at the module boundary and never appear
|
|
16
|
+
// on our wire.
|
|
17
|
+
//
|
|
18
|
+
// `operationId` lives in `detail:` on the route, not here. Problem codes live in
|
|
19
|
+
// `contracts/error-codes.ts`, the one flat table.
|
|
20
|
+
import { z } from "zod";
|
|
21
|
+
import { AnyObjectSchema, CursorPaginationSchema, ProblemDetailsSchema, cursorListQuerySchema, dataEnvelope, mutationEnvelope, } from "./common.js";
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// Enums.
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
export const connectorSourceKindSchema = z
|
|
26
|
+
.enum(["openapi", "graphql", "mcp"])
|
|
27
|
+
.describe("The kind of tool source a connector reads: an OpenAPI spec, a GraphQL endpoint, or a remote MCP server.");
|
|
28
|
+
export const connectionOwnerSchema = z
|
|
29
|
+
.enum(["team", "personal"])
|
|
30
|
+
.describe("`team` is shared with everyone on the team; `personal` is yours, and only within this team — connecting the same account for another team is another connection.");
|
|
31
|
+
// Derived on read from the engine's last health probe, token expiry, any pending
|
|
32
|
+
// authorization session, and our `revokedAt` tombstone. There is no status
|
|
33
|
+
// column, so a status can never go stale against the thing it describes.
|
|
34
|
+
export const connectionStatusSchema = z
|
|
35
|
+
.enum(["pending_authorization", "active", "degraded", "needs_reauth", "revoked"])
|
|
36
|
+
.describe("Derived connection state. Never stored, so it cannot drift from the credential it describes.");
|
|
37
|
+
export const toolSafetySchema = z
|
|
38
|
+
.enum(["read_only", "write", "destructive"])
|
|
39
|
+
.describe("What the tool does to the far side, read from the source spec. Not configurable.");
|
|
40
|
+
export const policyActionSchema = z
|
|
41
|
+
.enum(["approve", "require_approval", "block"])
|
|
42
|
+
.describe("What policy does with a call: run it, park it for a person, or refuse it.");
|
|
43
|
+
export const runStatusSchema = z
|
|
44
|
+
.enum(["running", "awaiting_approval", "succeeded", "failed", "expired"])
|
|
45
|
+
.describe("Where a run is in its one status machine.");
|
|
46
|
+
export const runInputKindSchema = z
|
|
47
|
+
.enum(["tool", "code"])
|
|
48
|
+
.describe("`tool` is one call; `code` is a program that may make many. Same endpoint, same id space, same resume.");
|
|
49
|
+
export const catalogEntryKindSchema = z
|
|
50
|
+
.enum(["preset", "registry", "team"])
|
|
51
|
+
.describe("Where a catalog row came from: a curated preset, the public registry, or this team's own connectors.");
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Shared building blocks.
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
export const AuthMethodSchema = z
|
|
56
|
+
.discriminatedUnion("kind", [
|
|
57
|
+
z.object({
|
|
58
|
+
kind: z.literal("api_key"),
|
|
59
|
+
slug: z.string().describe("Names this method when a connector offers more than one."),
|
|
60
|
+
label: z.string().describe("What to call it in a connect form, in the provider's own words."),
|
|
61
|
+
}),
|
|
62
|
+
z.object({
|
|
63
|
+
kind: z.literal("oauth2"),
|
|
64
|
+
slug: z.string().describe("Names this method when a connector offers more than one."),
|
|
65
|
+
label: z.string().describe("What to call it in a connect form, in the provider's own words."),
|
|
66
|
+
scopes: z
|
|
67
|
+
.array(z.string())
|
|
68
|
+
.describe("Scopes requested at authorization unless the caller narrows them."),
|
|
69
|
+
clientIdMetadataDocument: z
|
|
70
|
+
.boolean()
|
|
71
|
+
.optional()
|
|
72
|
+
.describe("Whether the provider supports public clients identified by a metadata-document URL."),
|
|
73
|
+
dynamicRegistration: z
|
|
74
|
+
.boolean()
|
|
75
|
+
.describe("Whether the provider supports RFC 7591 dynamic client registration, so no client has to be pre-created."),
|
|
76
|
+
}),
|
|
77
|
+
z.object({
|
|
78
|
+
kind: z.literal("none"),
|
|
79
|
+
slug: z.string().describe("Names this method when a connector offers more than one."),
|
|
80
|
+
label: z.string().describe("What to call it in a connect form."),
|
|
81
|
+
}),
|
|
82
|
+
z.object({
|
|
83
|
+
kind: z.literal("first_party"),
|
|
84
|
+
slug: z.string().describe("Names this method when a connector offers more than one."),
|
|
85
|
+
label: z.string().describe("What to call it in a connect form."),
|
|
86
|
+
provider: z
|
|
87
|
+
.string()
|
|
88
|
+
.describe("Existing Spacefast credential this connector borrows, e.g. the GitHub App installation. Nothing to enter."),
|
|
89
|
+
}),
|
|
90
|
+
])
|
|
91
|
+
.describe("One way to authenticate a connector. A connector may offer several, so a connect call names the one it means.");
|
|
92
|
+
// What the provider calls the key, where to mint it, and anything you have to do
|
|
93
|
+
// first. Passthrough from the registry's per-domain credential docs — every
|
|
94
|
+
// field is free-form and may be missing, so this renders next to the field
|
|
95
|
+
// asking for the value instead of sending people off to search.
|
|
96
|
+
export const CredentialGuidanceSchema = z
|
|
97
|
+
.object({
|
|
98
|
+
label: z
|
|
99
|
+
.string()
|
|
100
|
+
.nullable()
|
|
101
|
+
.describe('What the provider calls this credential, e.g. "Personal access token".'),
|
|
102
|
+
mintUrl: z
|
|
103
|
+
.string()
|
|
104
|
+
.nullable()
|
|
105
|
+
.describe("Page on the provider where the credential is created."),
|
|
106
|
+
docsUrl: z.string().nullable().describe("Provider documentation for this credential."),
|
|
107
|
+
notes: z
|
|
108
|
+
.string()
|
|
109
|
+
.nullable()
|
|
110
|
+
.describe("Setup notes: prerequisites, plan requirements, scopes to tick."),
|
|
111
|
+
steps: z
|
|
112
|
+
.array(z.string())
|
|
113
|
+
.describe("Ordered steps to get the credential, when the provider spells them out."),
|
|
114
|
+
})
|
|
115
|
+
.describe("Provider-supplied help for one credential, shown next to the field asking for it.");
|
|
116
|
+
export const connectorCredentialGuidanceResponseSchema = dataEnvelope(z.array(CredentialGuidanceSchema)).describe("Per-provider credential guidance for the connect modal; empty when the registry knows none.");
|
|
117
|
+
export const ConnectorFieldSchema = z
|
|
118
|
+
.object({
|
|
119
|
+
name: z.string().describe("Field key to send back in `credential.values`."),
|
|
120
|
+
required: z
|
|
121
|
+
.boolean()
|
|
122
|
+
.optional()
|
|
123
|
+
.describe("Whether this field must be filled before connecting. Defaults to true."),
|
|
124
|
+
label: z.string().describe("What to show above the input."),
|
|
125
|
+
secret: z
|
|
126
|
+
.boolean()
|
|
127
|
+
.describe("Whether the value is a secret: mask it in UI, never log it, never echo it back."),
|
|
128
|
+
guidance: CredentialGuidanceSchema.nullable().describe("Provider help for this field, when the registry has any."),
|
|
129
|
+
})
|
|
130
|
+
.describe("One value a connector needs before it can connect.");
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
// Resources.
|
|
133
|
+
// ---------------------------------------------------------------------------
|
|
134
|
+
export const ConnectionSchema = z
|
|
135
|
+
.object({
|
|
136
|
+
id: z
|
|
137
|
+
.string()
|
|
138
|
+
.describe("Connection id (`cxn_`). This is also the first segment of every tool address it owns."),
|
|
139
|
+
connector: z.string().describe("Slug of the connector this connection authenticates."),
|
|
140
|
+
owner: connectionOwnerSchema,
|
|
141
|
+
serving: z.boolean().default(false),
|
|
142
|
+
displayName: z.string().describe('What people call this connection, e.g. "Linear (support)".'),
|
|
143
|
+
description: z
|
|
144
|
+
.string()
|
|
145
|
+
.nullable()
|
|
146
|
+
.describe("Agent-visible note on what this connection is for. Shown to models choosing between several."),
|
|
147
|
+
status: connectionStatusSchema,
|
|
148
|
+
identityLabel: z
|
|
149
|
+
.string()
|
|
150
|
+
.nullable()
|
|
151
|
+
.describe("Account label reported by the provider, when it identifies itself. Null until the first successful probe."),
|
|
152
|
+
credentialConfigured: z
|
|
153
|
+
.boolean()
|
|
154
|
+
.describe("Whether a usable credential is stored. The credential itself is never returned by any endpoint."),
|
|
155
|
+
authMethod: z
|
|
156
|
+
.string()
|
|
157
|
+
.nullable()
|
|
158
|
+
.describe("Slug of the connector auth method this connection used."),
|
|
159
|
+
scopes: z
|
|
160
|
+
.array(z.string())
|
|
161
|
+
.describe("Scopes actually granted, when the provider reports them."),
|
|
162
|
+
isDefault: z
|
|
163
|
+
.boolean()
|
|
164
|
+
.describe("Whether this is the connection an agent gets when it names the connector alone."),
|
|
165
|
+
toolCount: z
|
|
166
|
+
.number()
|
|
167
|
+
.int()
|
|
168
|
+
.describe("Tools reachable through this connection at the last sync."),
|
|
169
|
+
createdBy: z
|
|
170
|
+
.string()
|
|
171
|
+
.nullable()
|
|
172
|
+
.describe("User who connected it; null for first-party connections Spacefast owns."),
|
|
173
|
+
lastCheckedAt: z.string().datetime().nullable().describe("Last health probe."),
|
|
174
|
+
revokedAt: z
|
|
175
|
+
.string()
|
|
176
|
+
.datetime()
|
|
177
|
+
.nullable()
|
|
178
|
+
.describe("When it was disconnected. The credential is purged; the row tombstones."),
|
|
179
|
+
createdAt: z.string().datetime(),
|
|
180
|
+
updatedAt: z.string().datetime(),
|
|
181
|
+
})
|
|
182
|
+
.describe("A configured instance of a connector, with a credential the control plane holds and never hands out.");
|
|
183
|
+
export const connectorCatalogSourceSchema = z.discriminatedUnion("kind", [
|
|
184
|
+
z.object({ kind: z.literal("openapi"), spec: z.string(), baseUrl: z.string().optional() }),
|
|
185
|
+
z.object({ kind: z.literal("graphql"), endpoint: z.string() }),
|
|
186
|
+
z.object({ kind: z.literal("mcp"), endpoint: z.string() }),
|
|
187
|
+
]);
|
|
188
|
+
export const ConnectorSchema = z
|
|
189
|
+
.object({
|
|
190
|
+
slug: z
|
|
191
|
+
.string()
|
|
192
|
+
.describe("Stable, team-unique connector slug. Also the namespace tools hang off."),
|
|
193
|
+
title: z.string().describe("Display name, seeded from the source spec."),
|
|
194
|
+
description: z
|
|
195
|
+
.string()
|
|
196
|
+
.nullable()
|
|
197
|
+
.describe("What this connector reaches, in one line. Agent-visible."),
|
|
198
|
+
source: connectorSourceKindSchema,
|
|
199
|
+
catalogSource: connectorCatalogSourceSchema
|
|
200
|
+
.optional()
|
|
201
|
+
.describe("Stored spec or endpoint for execution catalog discovery. No credentials."),
|
|
202
|
+
sourceUrl: z
|
|
203
|
+
.string()
|
|
204
|
+
.nullable()
|
|
205
|
+
.describe("Spec, endpoint, or MCP URL this connector was built from; null when it was registered from an inline spec."),
|
|
206
|
+
firstParty: z
|
|
207
|
+
.boolean()
|
|
208
|
+
.describe("Built into Spacefast. First-party connectors cannot be edited or removed."),
|
|
209
|
+
presetId: z
|
|
210
|
+
.string()
|
|
211
|
+
.nullable()
|
|
212
|
+
.describe("Curated preset this connector was created from, when it came from the catalog."),
|
|
213
|
+
authMethods: z
|
|
214
|
+
.array(AuthMethodSchema)
|
|
215
|
+
.describe("Every way this connector can be authenticated."),
|
|
216
|
+
toolCount: z.number().int().describe("Tools this connector exposes after the last spec sync."),
|
|
217
|
+
connections: z
|
|
218
|
+
.array(ConnectionSchema)
|
|
219
|
+
.describe("Connections the calling credential may use — not every connection that exists on this connector."),
|
|
220
|
+
specSyncedAt: z
|
|
221
|
+
.string()
|
|
222
|
+
.datetime()
|
|
223
|
+
.nullable()
|
|
224
|
+
.describe("Last time the source was fetched and tools rebuilt."),
|
|
225
|
+
createdAt: z.string().datetime(),
|
|
226
|
+
updatedAt: z.string().datetime(),
|
|
227
|
+
})
|
|
228
|
+
.describe("A tool source registered for one team.");
|
|
229
|
+
export const PolicyDecisionSchema = z
|
|
230
|
+
.object({
|
|
231
|
+
ruleId: z.string().describe("Policy rule that decided it."),
|
|
232
|
+
pattern: z.string().describe("The pattern that matched."),
|
|
233
|
+
owner: connectionOwnerSchema.describe("Whose rule it is. Team rules are a floor members cannot loosen."),
|
|
234
|
+
})
|
|
235
|
+
.describe("The rule that answered for an address. One shape wherever an effect is explained.");
|
|
236
|
+
export const ToolSchema = z
|
|
237
|
+
.object({
|
|
238
|
+
address: z
|
|
239
|
+
.string()
|
|
240
|
+
.describe("`<connectionId>/<tool>` — the one address grammar. Pass this straight to a connector run."),
|
|
241
|
+
name: z.string().describe("Tool name within its connector."),
|
|
242
|
+
summary: z.string().describe("One line on what the tool does, from the source spec."),
|
|
243
|
+
safety: toolSafetySchema,
|
|
244
|
+
effect: policyActionSchema.describe("What actually happens when an agent calls this, after policy resolution."),
|
|
245
|
+
decidedBy: PolicyDecisionSchema.nullable().describe("The rule behind `effect`; null when nothing matched and the spec's own default applied."),
|
|
246
|
+
inputSchema: AnyObjectSchema.describe("JSON Schema for the tool's arguments."),
|
|
247
|
+
})
|
|
248
|
+
.describe("One callable tool, already resolved against policy so a caller knows the answer before it calls.");
|
|
249
|
+
export const PolicyRuleSchema = z
|
|
250
|
+
.object({
|
|
251
|
+
id: z
|
|
252
|
+
.string()
|
|
253
|
+
.describe("Policy rule id. Opaque — minted by the policy engine, not a Spacefast resource prefix."),
|
|
254
|
+
pattern: z
|
|
255
|
+
.string()
|
|
256
|
+
.describe("`*`, `<connector>/*`, `<connectionId>/*`, or `<connectionId>/<tool>`. First match in order wins."),
|
|
257
|
+
action: policyActionSchema,
|
|
258
|
+
owner: connectionOwnerSchema.describe("Team rules are a floor: a personal rule may tighten one, never loosen it."),
|
|
259
|
+
position: z
|
|
260
|
+
.string()
|
|
261
|
+
.describe("Fractional index the engine assigned from the pattern's specificity. Rules evaluate in this order."),
|
|
262
|
+
createdAt: z.string().datetime(),
|
|
263
|
+
})
|
|
264
|
+
.describe("One ordered address-pattern rule. Most restrictive across owners wins.");
|
|
265
|
+
export const PolicyResolutionSchema = z
|
|
266
|
+
.object({
|
|
267
|
+
address: z.string().describe("The address that was resolved."),
|
|
268
|
+
effect: policyActionSchema.describe("What would happen if you called it right now."),
|
|
269
|
+
decidedBy: PolicyDecisionSchema.nullable().describe("The rule that decided it; null when the spec default applied."),
|
|
270
|
+
explanation: z.string().describe("Why, in a sentence you can put in front of a person."),
|
|
271
|
+
})
|
|
272
|
+
.describe('"What happens if I call this, and why" — the answer without making the call.');
|
|
273
|
+
export const PendingApprovalSchema = z
|
|
274
|
+
.object({
|
|
275
|
+
decisionId: z
|
|
276
|
+
.string()
|
|
277
|
+
.nullable()
|
|
278
|
+
.describe("Grant-decision id (`gdc_`) backing this approval when the credential is grant-backed; null for session/API-key pauses (resume with the run id)."),
|
|
279
|
+
mode: z
|
|
280
|
+
.enum(["human", "model"])
|
|
281
|
+
.describe("Who may decide. Fixed when the run parked: `human` refuses machine resumes."),
|
|
282
|
+
address: z.string().describe("Tool the run is waiting to call."),
|
|
283
|
+
preview: AnyObjectSchema.describe("The arguments it would send, with secret-shaped values masked."),
|
|
284
|
+
reason: z
|
|
285
|
+
.enum(["policy_require_approval", "annotation_requires_approval"])
|
|
286
|
+
.describe("Why it parked: a policy rule, or the tool's own annotation."),
|
|
287
|
+
matchedPattern: z
|
|
288
|
+
.string()
|
|
289
|
+
.nullable()
|
|
290
|
+
.describe("Policy pattern that parked it; null when the tool asked for itself."),
|
|
291
|
+
approvalUrl: z.string().url().describe("Dashboard page where a person approves or denies."),
|
|
292
|
+
expiresAt: z.string().datetime().describe("After this the run expires and cannot be resumed."),
|
|
293
|
+
})
|
|
294
|
+
.describe("A run waiting on a decision. Durable — any replica can resume it.");
|
|
295
|
+
export const ConnectorRunInputSummarySchema = z
|
|
296
|
+
.object({
|
|
297
|
+
kind: runInputKindSchema,
|
|
298
|
+
address: z
|
|
299
|
+
.string()
|
|
300
|
+
.nullable()
|
|
301
|
+
.describe("Tool address for a `tool` run; null for a `code` program."),
|
|
302
|
+
digest: z
|
|
303
|
+
.string()
|
|
304
|
+
.describe("Content digest of the submitted input, so a retry can be recognized without replaying it."),
|
|
305
|
+
})
|
|
306
|
+
.describe("What the run was asked to do, without echoing arguments that may carry customer data.");
|
|
307
|
+
export const ConnectorRunUsageSchema = z
|
|
308
|
+
.object({
|
|
309
|
+
toolCalls: z.number().int().describe("Tool calls made so far."),
|
|
310
|
+
egressBytes: z.number().int().describe("Bytes read from third-party APIs so far."),
|
|
311
|
+
durationMs: z.number().int().describe("Wall-clock time spent executing so far."),
|
|
312
|
+
})
|
|
313
|
+
.describe("What this run has spent. Budgets are enforced against these numbers.");
|
|
314
|
+
export const CONNECTOR_RUN_ORIGINS = [
|
|
315
|
+
"dashboard",
|
|
316
|
+
"cli",
|
|
317
|
+
"api",
|
|
318
|
+
"mcp",
|
|
319
|
+
"zero",
|
|
320
|
+
"function",
|
|
321
|
+
"system",
|
|
322
|
+
];
|
|
323
|
+
export const connectorRunOriginSchema = z.enum(CONNECTOR_RUN_ORIGINS);
|
|
324
|
+
const connectorRunBaseSchema = z.object({
|
|
325
|
+
origin: connectorRunOriginSchema,
|
|
326
|
+
space: z.string().nullable().describe("Space id that initiated this run, if any."),
|
|
327
|
+
handler: z.string().nullable().describe("Runtime handler that initiated this run, if any."),
|
|
328
|
+
visitor: z.boolean().describe("Whether a signed-in Space visitor initiated this run."),
|
|
329
|
+
id: z.string().describe("Run id (`cxr_`)."),
|
|
330
|
+
input: ConnectorRunInputSummarySchema,
|
|
331
|
+
usage: ConnectorRunUsageSchema,
|
|
332
|
+
createdAt: z.string().datetime(),
|
|
333
|
+
});
|
|
334
|
+
// `status` is the discriminant. `result` exists only on `succeeded`, `error`
|
|
335
|
+
// only on `failed`, `approval` only on `awaiting_approval` — a discriminated
|
|
336
|
+
// union rather than five optional fields, so a client cannot read a result off a
|
|
337
|
+
// failure and the generated SDK narrows correctly.
|
|
338
|
+
export const ConnectorRunSchema = z
|
|
339
|
+
.discriminatedUnion("status", [
|
|
340
|
+
connectorRunBaseSchema.extend({
|
|
341
|
+
status: z
|
|
342
|
+
.literal("running")
|
|
343
|
+
.describe("Still executing. Poll the run, or submit the next one with a longer `waitMs`."),
|
|
344
|
+
}),
|
|
345
|
+
connectorRunBaseSchema.extend({
|
|
346
|
+
status: z.literal("awaiting_approval").describe("Parked on a decision."),
|
|
347
|
+
approval: PendingApprovalSchema,
|
|
348
|
+
}),
|
|
349
|
+
connectorRunBaseSchema.extend({
|
|
350
|
+
status: z.literal("succeeded"),
|
|
351
|
+
completedAt: z.string().datetime(),
|
|
352
|
+
result: z.unknown().describe("Whatever the tool or program returned."),
|
|
353
|
+
}),
|
|
354
|
+
connectorRunBaseSchema.extend({
|
|
355
|
+
status: z.literal("failed"),
|
|
356
|
+
completedAt: z.string().datetime(),
|
|
357
|
+
error: ProblemDetailsSchema.describe("Why it failed, as a problem document. The HTTP response is still 200: the request succeeded, the run did not."),
|
|
358
|
+
}),
|
|
359
|
+
connectorRunBaseSchema.extend({
|
|
360
|
+
status: z
|
|
361
|
+
.literal("expired")
|
|
362
|
+
.describe("Parked too long. Submit it again; it cannot be resumed."),
|
|
363
|
+
completedAt: z.string().datetime(),
|
|
364
|
+
}),
|
|
365
|
+
])
|
|
366
|
+
.describe("One execution. A tool call and a code program are the same resource.");
|
|
367
|
+
export const ConnectionHealthSchema = z
|
|
368
|
+
.object({
|
|
369
|
+
connectionId: z.string(),
|
|
370
|
+
status: connectionStatusSchema.describe("State after this probe."),
|
|
371
|
+
reachable: z.boolean().describe("Whether the provider answered."),
|
|
372
|
+
latencyMs: z
|
|
373
|
+
.number()
|
|
374
|
+
.int()
|
|
375
|
+
.nullable()
|
|
376
|
+
.describe("Round trip of the probe; null when it never got an answer."),
|
|
377
|
+
detail: z.string().nullable().describe("What went wrong, when something did."),
|
|
378
|
+
toolCount: z.number().int().describe("Tools reachable right now."),
|
|
379
|
+
checkedAt: z.string().datetime(),
|
|
380
|
+
})
|
|
381
|
+
.describe("A live probe of one connection. Token refresh happens automatically; this only reports.");
|
|
382
|
+
// ---------------------------------------------------------------------------
|
|
383
|
+
// Catalog.
|
|
384
|
+
// ---------------------------------------------------------------------------
|
|
385
|
+
// One row per addable surface, never one row with badges: a service with both an
|
|
386
|
+
// API and an MCP server is two rows, each naming its surface ("Stripe API",
|
|
387
|
+
// "Stripe MCP"). Facets are the surface kind, not an invented category tree.
|
|
388
|
+
export const ConnectorCatalogEntrySchema = z
|
|
389
|
+
.object({
|
|
390
|
+
id: z
|
|
391
|
+
.string()
|
|
392
|
+
.describe("Stable id for this row. Pass it to registration as `presetId` for a one-click add."),
|
|
393
|
+
kind: catalogEntryKindSchema,
|
|
394
|
+
surface: connectorSourceKindSchema.describe("Which surface this row adds. The one facet the picker offers."),
|
|
395
|
+
title: z.string().describe('Service name plus surface, e.g. "Stripe MCP".'),
|
|
396
|
+
description: z.string().nullable().describe("One line on what the service does."),
|
|
397
|
+
domain: z
|
|
398
|
+
.string()
|
|
399
|
+
.nullable()
|
|
400
|
+
.describe("Provider domain, e.g. `stripe.com`. Null for rows with no public domain."),
|
|
401
|
+
logoUrl: z
|
|
402
|
+
.string()
|
|
403
|
+
.nullable()
|
|
404
|
+
.describe("Spacefast-proxied logo path. Never a third-party URL — the browser must not call the registry directly."),
|
|
405
|
+
presetId: z.string().nullable().describe("Curated preset backing this row, when one does."),
|
|
406
|
+
registryId: z.string().nullable().describe("Registry entry backing this row, when one does."),
|
|
407
|
+
family: z
|
|
408
|
+
.string()
|
|
409
|
+
.nullable()
|
|
410
|
+
.describe("Grouping key for services that ship many slices, e.g. Google or Microsoft Graph."),
|
|
411
|
+
featured: z.boolean().describe("Whether to surface this row before the long tail."),
|
|
412
|
+
authHint: z
|
|
413
|
+
.array(AuthMethodSchema)
|
|
414
|
+
.describe("Authentication the row is expected to need, so the connect form is right on the first render."),
|
|
415
|
+
credentialGuidance: CredentialGuidanceSchema.nullable().describe("Per-domain credential help, when the registry has any."),
|
|
416
|
+
alreadyAdded: z.boolean().describe("Whether this team already registered this surface."),
|
|
417
|
+
connectorSlug: z
|
|
418
|
+
.string()
|
|
419
|
+
.nullable()
|
|
420
|
+
.describe("The team connector this row resolves to when `alreadyAdded`; null otherwise."),
|
|
421
|
+
})
|
|
422
|
+
.describe("One addable surface in the merged catalog: curated presets, the public registry, and the team's own connectors.");
|
|
423
|
+
export const connectorCatalogQuerySchema = cursorListQuerySchema.extend({
|
|
424
|
+
query: z
|
|
425
|
+
.string()
|
|
426
|
+
.trim()
|
|
427
|
+
.min(1)
|
|
428
|
+
.max(200)
|
|
429
|
+
.optional()
|
|
430
|
+
.describe("Free-text filter over title, description, and domain."),
|
|
431
|
+
surface: connectorSourceKindSchema.optional().describe("Show only rows adding this surface."),
|
|
432
|
+
kind: catalogEntryKindSchema.optional().describe("Show only rows from this source."),
|
|
433
|
+
});
|
|
434
|
+
// ---------------------------------------------------------------------------
|
|
435
|
+
// Connector requests.
|
|
436
|
+
// ---------------------------------------------------------------------------
|
|
437
|
+
export const connectorSourceSchema = z
|
|
438
|
+
.discriminatedUnion("kind", [
|
|
439
|
+
z
|
|
440
|
+
.object({
|
|
441
|
+
kind: z.literal("openapi"),
|
|
442
|
+
specUrl: z.string().url().optional().describe("URL of the OpenAPI document to fetch."),
|
|
443
|
+
spec: AnyObjectSchema.optional().describe("Inline OpenAPI document, when there is no URL to fetch."),
|
|
444
|
+
baseUrl: z.string().url().optional().describe("Override the server URL the spec declares."),
|
|
445
|
+
})
|
|
446
|
+
.refine((value) => Boolean(value.specUrl) !== Boolean(value.spec), {
|
|
447
|
+
message: "Give exactly one of specUrl or spec.",
|
|
448
|
+
}),
|
|
449
|
+
z.object({
|
|
450
|
+
kind: z.literal("graphql"),
|
|
451
|
+
endpoint: z.string().url().describe("GraphQL endpoint to introspect."),
|
|
452
|
+
}),
|
|
453
|
+
z.object({
|
|
454
|
+
kind: z.literal("mcp"),
|
|
455
|
+
endpoint: z
|
|
456
|
+
.string()
|
|
457
|
+
.url()
|
|
458
|
+
.describe("Remote MCP endpoint. stdio servers cannot be reached from a hosted product."),
|
|
459
|
+
}),
|
|
460
|
+
])
|
|
461
|
+
.describe("Where the tools come from.");
|
|
462
|
+
/**
|
|
463
|
+
* Slugs owned by dashboard routes or the built-in Spacefast MCP integration.
|
|
464
|
+
* Registration rejects them before a connector can shadow an existing namespace.
|
|
465
|
+
*/
|
|
466
|
+
export const CONNECTOR_RESERVED_SLUGS = [
|
|
467
|
+
"add",
|
|
468
|
+
"browse",
|
|
469
|
+
"catalog",
|
|
470
|
+
"connections",
|
|
471
|
+
"detect",
|
|
472
|
+
"policies",
|
|
473
|
+
"runs",
|
|
474
|
+
"spacefast",
|
|
475
|
+
"tools",
|
|
476
|
+
];
|
|
477
|
+
export const connectorRegisterSchema = z
|
|
478
|
+
.object({
|
|
479
|
+
slug: z
|
|
480
|
+
.string()
|
|
481
|
+
.min(1)
|
|
482
|
+
.max(64)
|
|
483
|
+
.regex(/^[a-z0-9][a-z0-9-]*$/, "Use lowercase letters, digits, and dashes.")
|
|
484
|
+
.refine((slug) => !CONNECTOR_RESERVED_SLUGS.some((reserved) => reserved === slug), {
|
|
485
|
+
message: "This slug is reserved.",
|
|
486
|
+
})
|
|
487
|
+
.describe("Team-unique slug. Also the namespace its tools hang off, so keep it short."),
|
|
488
|
+
title: z
|
|
489
|
+
.string()
|
|
490
|
+
.min(1)
|
|
491
|
+
.max(255)
|
|
492
|
+
.describe("Display name. Defaults to whatever the source calls itself."),
|
|
493
|
+
description: z
|
|
494
|
+
.string()
|
|
495
|
+
.max(1_000)
|
|
496
|
+
.optional()
|
|
497
|
+
.describe("What this connector reaches, in one line. Agent-visible."),
|
|
498
|
+
presetId: z
|
|
499
|
+
.string()
|
|
500
|
+
.min(1)
|
|
501
|
+
.optional()
|
|
502
|
+
.describe("Catalog row to add. Skips fetching and analyzing the source — everything else is optional when set."),
|
|
503
|
+
source: connectorSourceSchema
|
|
504
|
+
.optional()
|
|
505
|
+
.describe("Required unless `presetId` names a catalog row that carries it."),
|
|
506
|
+
authMethods: z
|
|
507
|
+
.array(AuthMethodSchema)
|
|
508
|
+
.optional()
|
|
509
|
+
.describe("Omit to derive authentication from the source's own declared security schemes."),
|
|
510
|
+
specOverrides: z
|
|
511
|
+
.array(AnyObjectSchema)
|
|
512
|
+
.max(200)
|
|
513
|
+
.optional()
|
|
514
|
+
.describe("RFC 6902 JSON Patch operations applied to the fetched spec before tools are built."),
|
|
515
|
+
})
|
|
516
|
+
.refine((value) => Boolean(value.presetId) || Boolean(value.source), {
|
|
517
|
+
message: "Give a source, or a presetId that carries one.",
|
|
518
|
+
});
|
|
519
|
+
export const connectorPatchSchema = z
|
|
520
|
+
.object({
|
|
521
|
+
title: z.string().min(1).max(255).optional().describe("Replacement display name."),
|
|
522
|
+
description: z
|
|
523
|
+
.string()
|
|
524
|
+
.max(1_000)
|
|
525
|
+
.nullable()
|
|
526
|
+
.optional()
|
|
527
|
+
.describe("Replacement agent-visible description."),
|
|
528
|
+
refreshSpec: z
|
|
529
|
+
.boolean()
|
|
530
|
+
.optional()
|
|
531
|
+
.describe("Re-fetch the source and rebuild the tool catalog. Connections and policy rules survive it."),
|
|
532
|
+
specOverrides: z
|
|
533
|
+
.array(AnyObjectSchema)
|
|
534
|
+
.max(200)
|
|
535
|
+
.optional()
|
|
536
|
+
.describe("Replacement RFC 6902 JSON Patch operations. Applied on the next spec build."),
|
|
537
|
+
})
|
|
538
|
+
.refine((value) => Object.keys(value).length > 0, {
|
|
539
|
+
message: "At least one mutable connector field is required.",
|
|
540
|
+
});
|
|
541
|
+
export const connectorDetectSchema = z.object({
|
|
542
|
+
url: z
|
|
543
|
+
.string()
|
|
544
|
+
.url()
|
|
545
|
+
.describe("Any URL a service published. Every plugin's detector gets a look at it."),
|
|
546
|
+
});
|
|
547
|
+
export const ConnectorDetectionSchema = z
|
|
548
|
+
.object({
|
|
549
|
+
kind: connectorSourceKindSchema.describe("Source kind this candidate would register as."),
|
|
550
|
+
confidence: z
|
|
551
|
+
.enum(["high", "medium", "low"])
|
|
552
|
+
.describe("How sure the detector is. Ranked highest first."),
|
|
553
|
+
endpoint: z
|
|
554
|
+
.string()
|
|
555
|
+
.url()
|
|
556
|
+
.describe("The URL to register, which may not be the URL that was pasted."),
|
|
557
|
+
title: z.string().describe("Name the source calls itself."),
|
|
558
|
+
slug: z.string().describe("Suggested slug, already checked against the team's connectors."),
|
|
559
|
+
presetId: z
|
|
560
|
+
.string()
|
|
561
|
+
.nullable()
|
|
562
|
+
.describe("Catalog row this resolved to, when the paste matched a known service."),
|
|
563
|
+
})
|
|
564
|
+
.describe("One candidate connector behind a pasted URL.");
|
|
565
|
+
export const connectorListQuerySchema = cursorListQuerySchema.extend({
|
|
566
|
+
query: z
|
|
567
|
+
.string()
|
|
568
|
+
.trim()
|
|
569
|
+
.min(1)
|
|
570
|
+
.max(200)
|
|
571
|
+
.optional()
|
|
572
|
+
.describe("Free-text filter over slug, title, and description."),
|
|
573
|
+
source: connectorSourceKindSchema
|
|
574
|
+
.optional()
|
|
575
|
+
.describe("Show only connectors of this source kind."),
|
|
576
|
+
});
|
|
577
|
+
export const connectorToolListQuerySchema = cursorListQuerySchema.extend({
|
|
578
|
+
query: z
|
|
579
|
+
.string()
|
|
580
|
+
.trim()
|
|
581
|
+
.min(1)
|
|
582
|
+
.max(200)
|
|
583
|
+
.optional()
|
|
584
|
+
.describe("Free-text filter over tool name and summary."),
|
|
585
|
+
effect: policyActionSchema.optional().describe("Show only tools that resolve to this effect."),
|
|
586
|
+
});
|
|
587
|
+
// ---------------------------------------------------------------------------
|
|
588
|
+
// Connect — one call, three possible answers.
|
|
589
|
+
// ---------------------------------------------------------------------------
|
|
590
|
+
export const connectionCredentialSchema = z
|
|
591
|
+
.discriminatedUnion("kind", [
|
|
592
|
+
z.object({
|
|
593
|
+
kind: z.literal("api_key"),
|
|
594
|
+
value: z
|
|
595
|
+
.string()
|
|
596
|
+
.min(1)
|
|
597
|
+
.describe("The key. Write-only: sealed on arrival, never returned by any endpoint."),
|
|
598
|
+
}),
|
|
599
|
+
z.object({
|
|
600
|
+
kind: z.literal("fields"),
|
|
601
|
+
values: z
|
|
602
|
+
.record(z.string(), z.string())
|
|
603
|
+
.describe("Values keyed by the field names the connector asked for. Write-only, same as a key."),
|
|
604
|
+
}),
|
|
605
|
+
])
|
|
606
|
+
.describe("A credential going in. Nothing here ever comes back out.");
|
|
607
|
+
// One call to connect anything. The server works out whether it can finish now,
|
|
608
|
+
// needs the user at an authorization page, or needs values it does not have —
|
|
609
|
+
// so no client has to know a provider's auth shape before it starts.
|
|
610
|
+
export const connectionCreateSchema = z.object({
|
|
611
|
+
connector: z.string().min(1).describe("Connector slug to connect."),
|
|
612
|
+
owner: connectionOwnerSchema.describe("Share it with the team, or keep it yours within this team."),
|
|
613
|
+
displayName: z
|
|
614
|
+
.string()
|
|
615
|
+
.min(1)
|
|
616
|
+
.max(255)
|
|
617
|
+
.optional()
|
|
618
|
+
.describe("What to call it. Defaults to the connector's title."),
|
|
619
|
+
description: z
|
|
620
|
+
.string()
|
|
621
|
+
.max(1_000)
|
|
622
|
+
.optional()
|
|
623
|
+
.describe("Agent-visible note on what this connection is for."),
|
|
624
|
+
authMethod: z
|
|
625
|
+
.string()
|
|
626
|
+
.min(1)
|
|
627
|
+
.optional()
|
|
628
|
+
.describe("Which of the connector's auth methods to use. Required only when more than one could apply."),
|
|
629
|
+
credential: connectionCredentialSchema
|
|
630
|
+
.optional()
|
|
631
|
+
.describe("Omit it and the server tells you what it needs."),
|
|
632
|
+
scopes: z
|
|
633
|
+
.array(z.string())
|
|
634
|
+
.optional()
|
|
635
|
+
.describe("Narrow the authorization request below the method's defaults."),
|
|
636
|
+
returnPath: z
|
|
637
|
+
.string()
|
|
638
|
+
.startsWith("/", "Give a dashboard path, not an absolute URL.")
|
|
639
|
+
.max(512)
|
|
640
|
+
.optional()
|
|
641
|
+
.describe("Dashboard path to land on after authorization. Same-origin only; absolute URLs are rejected."),
|
|
642
|
+
});
|
|
643
|
+
export const ConnectionCreateResultSchema = z
|
|
644
|
+
.discriminatedUnion("status", [
|
|
645
|
+
z.object({
|
|
646
|
+
status: z.literal("connected").describe("Done. The connection is usable now."),
|
|
647
|
+
connection: ConnectionSchema,
|
|
648
|
+
}),
|
|
649
|
+
z.object({
|
|
650
|
+
status: z
|
|
651
|
+
.literal("authorization_required")
|
|
652
|
+
.describe("Send the user to `authorizeUrl`; the callback completes it."),
|
|
653
|
+
connection: ConnectionSchema.describe("Already created, in `pending_authorization`, so it has an id to watch."),
|
|
654
|
+
authorizeUrl: z
|
|
655
|
+
.string()
|
|
656
|
+
.url()
|
|
657
|
+
.describe("Provider authorization page. Open it in a window you reserved beforehand."),
|
|
658
|
+
expiresAt: z
|
|
659
|
+
.string()
|
|
660
|
+
.datetime()
|
|
661
|
+
.describe("After this the authorization attempt is dead; start over."),
|
|
662
|
+
}),
|
|
663
|
+
z.object({
|
|
664
|
+
status: z
|
|
665
|
+
.literal("input_required")
|
|
666
|
+
.describe("Nothing was created. Collect these values and call again."),
|
|
667
|
+
connector: z.string().describe("Connector slug this applies to."),
|
|
668
|
+
authMethod: z
|
|
669
|
+
.string()
|
|
670
|
+
.describe("Auth method the fields belong to. Send it back on the next call."),
|
|
671
|
+
fields: z.array(ConnectorFieldSchema).describe("What to ask for, in the order to ask."),
|
|
672
|
+
}),
|
|
673
|
+
])
|
|
674
|
+
.describe("The three ways connecting can end. Branch on `status`; there is no fourth.");
|
|
675
|
+
export const connectionCompleteSchema = z.object({
|
|
676
|
+
state: z
|
|
677
|
+
.string()
|
|
678
|
+
.min(1)
|
|
679
|
+
.describe("Opaque state from the authorization redirect. Addresses the attempt on its own."),
|
|
680
|
+
code: z.string().min(1).describe("Authorization code from the provider."),
|
|
681
|
+
});
|
|
682
|
+
// Credentials are immutable: to rotate one, reconnect. Editing a live credential
|
|
683
|
+
// in place gives you a connection whose history no longer describes what it did.
|
|
684
|
+
// `isDefault` is not here on purpose: the default is derived (the only live
|
|
685
|
+
// connection on a connector), never a flag a caller sets.
|
|
686
|
+
export const connectionPatchSchema = z
|
|
687
|
+
.object({
|
|
688
|
+
serving: z.boolean().optional(),
|
|
689
|
+
displayName: z.string().min(1).max(255).optional().describe("Replacement label."),
|
|
690
|
+
description: z
|
|
691
|
+
.string()
|
|
692
|
+
.max(1_000)
|
|
693
|
+
.nullable()
|
|
694
|
+
.optional()
|
|
695
|
+
.describe("Replacement agent-visible description."),
|
|
696
|
+
})
|
|
697
|
+
.refine((value) => Object.keys(value).length > 0, {
|
|
698
|
+
message: "At least one mutable connection field is required. Credentials are immutable — reconnect instead.",
|
|
699
|
+
});
|
|
700
|
+
export const connectionListQuerySchema = cursorListQuerySchema.extend({
|
|
701
|
+
owner: connectionOwnerSchema
|
|
702
|
+
.or(z.literal("any"))
|
|
703
|
+
.default("any")
|
|
704
|
+
.describe("Whose connections to list. `any` is everything the calling credential may use."),
|
|
705
|
+
connector: z.string().min(1).optional().describe("Show only connections of this connector."),
|
|
706
|
+
status: connectionStatusSchema.optional().describe("Show only connections in this state."),
|
|
707
|
+
includeRevoked: z.coerce.boolean().default(false).describe("Include disconnected connections."),
|
|
708
|
+
});
|
|
709
|
+
// ---------------------------------------------------------------------------
|
|
710
|
+
// Policy.
|
|
711
|
+
// ---------------------------------------------------------------------------
|
|
712
|
+
export const policyRuleCreateSchema = z.object({
|
|
713
|
+
pattern: z
|
|
714
|
+
.string()
|
|
715
|
+
.min(1)
|
|
716
|
+
.max(512)
|
|
717
|
+
.describe("`*`, `<connector>/*`, `<connectionId>/*`, or `<connectionId>/<tool>`."),
|
|
718
|
+
action: policyActionSchema,
|
|
719
|
+
owner: connectionOwnerSchema.describe("Team rules apply to everyone and are a floor personal rules cannot loosen."),
|
|
720
|
+
});
|
|
721
|
+
export const policyRulePatchSchema = z.object({
|
|
722
|
+
action: policyActionSchema.describe("Replacement action. A rule's pattern and owner are fixed — delete and re-add."),
|
|
723
|
+
});
|
|
724
|
+
export const policyResolveQuerySchema = z.object({
|
|
725
|
+
address: z.string().min(1).max(512).describe("`<connectionId>/<tool>` to resolve."),
|
|
726
|
+
});
|
|
727
|
+
// ---------------------------------------------------------------------------
|
|
728
|
+
// Runs.
|
|
729
|
+
// ---------------------------------------------------------------------------
|
|
730
|
+
export const connectorRunInputSchema = z
|
|
731
|
+
.discriminatedUnion("kind", [
|
|
732
|
+
z.object({
|
|
733
|
+
kind: z.literal("tool"),
|
|
734
|
+
address: z
|
|
735
|
+
.string()
|
|
736
|
+
.min(1)
|
|
737
|
+
.max(512)
|
|
738
|
+
.describe("`<connectionId>/<tool>`, straight off a tool listing."),
|
|
739
|
+
args: AnyObjectSchema.default({}).describe("Arguments, validated against the tool's own input schema."),
|
|
740
|
+
}),
|
|
741
|
+
z.object({
|
|
742
|
+
kind: z.literal("code"),
|
|
743
|
+
code: z
|
|
744
|
+
.string()
|
|
745
|
+
.min(1)
|
|
746
|
+
.max(200_000)
|
|
747
|
+
.describe("A program run in the sandbox. It may call any tool the calling credential is granted."),
|
|
748
|
+
}),
|
|
749
|
+
])
|
|
750
|
+
.describe("One call, or a program that makes many. Same endpoint either way.");
|
|
751
|
+
export const connectorRunCreateSchema = z.object({
|
|
752
|
+
input: connectorRunInputSchema,
|
|
753
|
+
waitMs: z
|
|
754
|
+
.number()
|
|
755
|
+
.int()
|
|
756
|
+
.min(0)
|
|
757
|
+
.max(120_000)
|
|
758
|
+
.optional()
|
|
759
|
+
.describe("How long to hold the request waiting for a terminal status before answering `running`."),
|
|
760
|
+
idempotencyKey: z
|
|
761
|
+
.string()
|
|
762
|
+
.min(1)
|
|
763
|
+
.max(320)
|
|
764
|
+
.optional()
|
|
765
|
+
.describe("Retry with the same key to get the original run back (200, not 201) instead of running it twice."),
|
|
766
|
+
unattendedApprovals: z
|
|
767
|
+
.enum(["park", "deny"])
|
|
768
|
+
.default("park")
|
|
769
|
+
.describe("What to do when a call needs approval and nobody is watching: park it for a person, or fail fast."),
|
|
770
|
+
});
|
|
771
|
+
export const connectorRunResumeSchema = z.object({
|
|
772
|
+
action: z
|
|
773
|
+
.enum(["accept", "decline", "cancel"])
|
|
774
|
+
.optional()
|
|
775
|
+
.describe("Omit to leave it waiting for a person. A run parked in `human` mode refuses a machine decision."),
|
|
776
|
+
content: AnyObjectSchema.optional().describe("Values the paused call asked for, when the approval collected any."),
|
|
777
|
+
});
|
|
778
|
+
export const connectorRunListQuerySchema = cursorListQuerySchema.extend({
|
|
779
|
+
origin: connectorRunOriginSchema.optional(),
|
|
780
|
+
space: z.string().min(1).optional().describe("Filter by Space id."),
|
|
781
|
+
status: runStatusSchema.optional().describe("`awaiting_approval` is the approvals inbox query."),
|
|
782
|
+
connection: z.string().min(1).optional().describe("Show only runs that touched this connection."),
|
|
783
|
+
});
|
|
784
|
+
// ---------------------------------------------------------------------------
|
|
785
|
+
// Params.
|
|
786
|
+
// ---------------------------------------------------------------------------
|
|
787
|
+
export const ConnectorParamsSchema = z.object({
|
|
788
|
+
connectorRef: z.string().min(1).describe("Connector slug."),
|
|
789
|
+
});
|
|
790
|
+
export const ConnectionParamsSchema = z.object({
|
|
791
|
+
connectionId: z.string().min(1).describe("Connection id (`cxn_`)."),
|
|
792
|
+
});
|
|
793
|
+
export const PolicyRuleParamsSchema = z.object({
|
|
794
|
+
policyRuleId: z.string().min(1).describe("Policy rule id."),
|
|
795
|
+
});
|
|
796
|
+
export const ConnectorRunParamsSchema = z.object({
|
|
797
|
+
runId: z.string().min(1).describe("Run id (`cxr_`)."),
|
|
798
|
+
});
|
|
799
|
+
// ---------------------------------------------------------------------------
|
|
800
|
+
// Responses.
|
|
801
|
+
// ---------------------------------------------------------------------------
|
|
802
|
+
export const connectorCatalogListResponseSchema = z.object({
|
|
803
|
+
data: z.array(ConnectorCatalogEntrySchema),
|
|
804
|
+
pagination: CursorPaginationSchema,
|
|
805
|
+
});
|
|
806
|
+
export const connectorListResponseSchema = z.object({
|
|
807
|
+
data: z.array(ConnectorSchema),
|
|
808
|
+
pagination: CursorPaginationSchema,
|
|
809
|
+
});
|
|
810
|
+
export const connectorResponseSchema = dataEnvelope(ConnectorSchema);
|
|
811
|
+
export const connectorDetectResponseSchema = dataEnvelope(z.array(ConnectorDetectionSchema));
|
|
812
|
+
export const connectorDeleteResponseSchema = dataEnvelope(z.null().describe("Removing a connector returns no resource body."));
|
|
813
|
+
export const connectionListResponseSchema = z.object({
|
|
814
|
+
data: z.array(ConnectionSchema),
|
|
815
|
+
pagination: CursorPaginationSchema,
|
|
816
|
+
});
|
|
817
|
+
export const connectionResponseSchema = dataEnvelope(ConnectionSchema);
|
|
818
|
+
export const connectionCreateResponseSchema = dataEnvelope(ConnectionCreateResultSchema);
|
|
819
|
+
export const connectionHealthResponseSchema = dataEnvelope(ConnectionHealthSchema);
|
|
820
|
+
// Disconnect purges the credential and tombstones the row; provider-side cleanup
|
|
821
|
+
// may outlive the request, so it carries an operation handle.
|
|
822
|
+
export const connectionDisconnectResponseSchema = mutationEnvelope(ConnectionSchema);
|
|
823
|
+
export const connectionRefreshResponseSchema = mutationEnvelope(ConnectionSchema);
|
|
824
|
+
export const connectorToolListResponseSchema = z.object({
|
|
825
|
+
data: z.array(ToolSchema),
|
|
826
|
+
pagination: CursorPaginationSchema,
|
|
827
|
+
});
|
|
828
|
+
export const policyRuleListResponseSchema = dataEnvelope(z.array(PolicyRuleSchema));
|
|
829
|
+
export const policyRuleResponseSchema = dataEnvelope(PolicyRuleSchema);
|
|
830
|
+
export const policyRuleDeleteResponseSchema = dataEnvelope(z.null().describe("Removing a policy rule returns no resource body."));
|
|
831
|
+
export const policyResolveResponseSchema = dataEnvelope(PolicyResolutionSchema);
|
|
832
|
+
export const connectorRunResponseSchema = dataEnvelope(ConnectorRunSchema);
|
|
833
|
+
export const connectorRunListResponseSchema = z.object({
|
|
834
|
+
data: z.array(ConnectorRunSchema),
|
|
835
|
+
pagination: CursorPaginationSchema,
|
|
836
|
+
});
|
|
837
|
+
export const connectorRoleNameSchema = z
|
|
838
|
+
.string()
|
|
839
|
+
.regex(/^[a-z][a-zA-Z0-9]*$/)
|
|
840
|
+
.max(64);
|
|
841
|
+
export const connectorRoleSchema = z.object({
|
|
842
|
+
role: connectorRoleNameSchema,
|
|
843
|
+
as: z.enum(["team", "owner", "visitor"]),
|
|
844
|
+
connector: z.string().min(1).optional(),
|
|
845
|
+
});
|
|
846
|
+
export const CONNECTOR_CALL_STATE_COPY = {
|
|
847
|
+
ok: "Connected.",
|
|
848
|
+
connect_required: "Connect your account to continue.",
|
|
849
|
+
reconnect_required: "Reconnect your account to continue.",
|
|
850
|
+
approval_pending: "This action is waiting for approval.",
|
|
851
|
+
forbidden: "You do not have permission to use this connection.",
|
|
852
|
+
unbound: "The site owner needs to connect this service.",
|
|
853
|
+
unavailable: "This service is unavailable. Try again.",
|
|
854
|
+
};
|
|
855
|
+
export const ConnectorCallStateSchema = z.object({
|
|
856
|
+
role: connectorRoleNameSchema.optional(),
|
|
857
|
+
code: z.enum([
|
|
858
|
+
"ok",
|
|
859
|
+
"connect_required",
|
|
860
|
+
"reconnect_required",
|
|
861
|
+
"approval_pending",
|
|
862
|
+
"forbidden",
|
|
863
|
+
"unbound",
|
|
864
|
+
"unavailable",
|
|
865
|
+
]),
|
|
866
|
+
message: z.string(),
|
|
867
|
+
runId: z.string().optional(),
|
|
868
|
+
approvalUrl: z.string().optional(),
|
|
869
|
+
connectUrl: z.string().optional(),
|
|
870
|
+
});
|
|
871
|
+
export class ConnectorCallError extends Error {
|
|
872
|
+
state;
|
|
873
|
+
constructor(state) {
|
|
874
|
+
super(state.message);
|
|
875
|
+
this.state = state;
|
|
876
|
+
this.name = "ConnectorCallError";
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
export const spaceConnectorBindingSchema = connectorRoleSchema.extend({
|
|
880
|
+
connection: ConnectionSchema.nullable(),
|
|
881
|
+
visitorConnections: z.object({ count: z.number().int().nonnegative() }).optional(),
|
|
882
|
+
boundByUserId: z.string().nullable(),
|
|
883
|
+
createdAt: z.string().datetime().nullable(),
|
|
884
|
+
});
|
|
885
|
+
export const listSpaceConnectorBindingsResponseSchema = dataEnvelope(z.object({
|
|
886
|
+
bindings: z.array(spaceConnectorBindingSchema),
|
|
887
|
+
access: z.enum(["private", "team", "public"]),
|
|
888
|
+
}));
|
|
889
|
+
export const bindSpaceConnectorRequestSchema = z.object({ connectionId: z.string().min(1) });
|
|
890
|
+
export const spaceConnectorBindingResponseSchema = dataEnvelope(spaceConnectorBindingSchema);
|
|
891
|
+
export const unbindSpaceConnectorResponseSchema = dataEnvelope(z.null());
|
|
892
|
+
const runtimeConnectorArgsSchema = z.record(z.string(), z.json());
|
|
893
|
+
export const runtimeConnectorCallRequestSchema = z.object({
|
|
894
|
+
role: connectorRoleNameSchema,
|
|
895
|
+
tool: z.string().min(1).max(512),
|
|
896
|
+
args: runtimeConnectorArgsSchema,
|
|
897
|
+
visitor: z
|
|
898
|
+
.object({
|
|
899
|
+
subject: z.string().min(1),
|
|
900
|
+
email: z.string().optional(),
|
|
901
|
+
emailVerified: z.boolean().optional(),
|
|
902
|
+
})
|
|
903
|
+
.nullable()
|
|
904
|
+
.default(null),
|
|
905
|
+
handler: z.object({
|
|
906
|
+
name: z.string().min(1),
|
|
907
|
+
mode: z.enum(["read", "write"]),
|
|
908
|
+
callIndex: z.number().int().nonnegative().default(0),
|
|
909
|
+
}),
|
|
910
|
+
requestId: z.string().optional(),
|
|
911
|
+
waitMs: z.number().int().min(0).max(25000).default(25000),
|
|
912
|
+
});
|
|
913
|
+
export const runtimeConnectorCallResponseSchema = z.object({
|
|
914
|
+
state: ConnectorCallStateSchema,
|
|
915
|
+
run: ConnectorRunSchema.optional(),
|
|
916
|
+
});
|
|
917
|
+
export const visitorConnectorIdentitySchema = z.object({
|
|
918
|
+
role: connectorRoleNameSchema,
|
|
919
|
+
visitorSubject: z
|
|
920
|
+
.string()
|
|
921
|
+
.min(1)
|
|
922
|
+
.max(512)
|
|
923
|
+
.refine((subject) => !subject.startsWith("guest:")),
|
|
924
|
+
});
|
|
925
|
+
export const visitorConnectionStartSchema = visitorConnectorIdentitySchema.extend({
|
|
926
|
+
origin: z
|
|
927
|
+
.url()
|
|
928
|
+
.refine((value) => new URL(value).protocol === "https:" && new URL(value).origin === value),
|
|
929
|
+
returnTo: z.string().max(4096).default("/"),
|
|
930
|
+
});
|
|
931
|
+
export const visitorConnectionCompleteSchema = visitorConnectorIdentitySchema.extend({
|
|
932
|
+
state: z.string().min(1).max(16384),
|
|
933
|
+
code: z.string().min(1).max(8192),
|
|
934
|
+
});
|
|
935
|
+
export const visitorConnectionStartResponseSchema = dataEnvelope(z.object({ authorizeUrl: z.url() }));
|
|
936
|
+
export const visitorConnectionCompleteResponseSchema = dataEnvelope(z.object({ returnTo: z.string() }));
|
|
937
|
+
export const visitorConnectionUsersResponseSchema = dataEnvelope(z.array(z.object({
|
|
938
|
+
userRef: z.string(),
|
|
939
|
+
count: z.number().int().nonnegative(),
|
|
940
|
+
roles: z.array(connectorRoleNameSchema),
|
|
941
|
+
})));
|