diff --git a/packages/core/api/src/account/api.ts b/packages/core/api/src/account/api.ts index 0eaa8181f..1a667d4ca 100644 --- a/packages/core/api/src/account/api.ts +++ b/packages/core/api/src/account/api.ts @@ -1,4 +1,4 @@ -import { HttpApi, HttpApiEndpoint, HttpApiGroup } from "effect/unstable/httpapi"; +import { HttpApi, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"; import { Schema } from "effect"; // --------------------------------------------------------------------------- @@ -170,53 +170,106 @@ export const AccountApi = HttpApiGroup.make("account") HttpApiEndpoint.get("me", "/account/me", { success: AccountMeResponse, error: [AccountError, AccountUnauthorized], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "account.me", + summary: "Current Account", + description: "Returns the authenticated user and their current organization (if any).", + }), + ), ) .add( HttpApiEndpoint.get("listApiKeys", "/account/api-keys", { success: ApiKeysResponse, error: [AccountError, AccountUnauthorized, AccountNoOrganization], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "account.listApiKeys", + summary: "List API Keys", + description: "Lists the API keys for the current organization, each with a masked value.", + }), + ), ) .add( HttpApiEndpoint.post("createApiKey", "/account/api-keys", { payload: CreateApiKeyBody, success: CreatedApiKeyResponse, error: [AccountError, AccountUnauthorized, AccountNoOrganization], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "account.createApiKey", + summary: "Create API Key", + description: + "Creates a named API key for the current organization and returns its one-time plaintext value.", + }), + ), ) .add( HttpApiEndpoint.delete("revokeApiKey", "/account/api-keys/:apiKeyId", { params: ApiKeyParams, success: SuccessResponse, error: [AccountError, AccountUnauthorized, AccountNoOrganization], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "account.revokeApiKey", + summary: "Revoke API Key", + description: "Revokes the API key identified by the given id for the current organization.", + }), + ), ) .add( HttpApiEndpoint.get("listMembers", "/account/members", { success: OrgMembersResponse, error: [AccountError, AccountUnauthorized, AccountNoOrganization], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "account.listMembers", + summary: "List Members", + description: + "Lists the members of the current organization along with optional seat usage.", + }), + ), ) .add( HttpApiEndpoint.get("listRoles", "/account/roles", { success: OrgRolesResponse, error: [AccountError, AccountUnauthorized, AccountNoOrganization], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "account.listRoles", + summary: "List Roles", + description: + "Lists the roles available for assigning to members of the current organization.", + }), + ), ) .add( HttpApiEndpoint.post("inviteMember", "/account/members/invite", { payload: InviteMemberBody, success: InviteMemberResponse, error: [AccountError, AccountUnauthorized, AccountForbidden, AccountNoOrganization], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "account.inviteMember", + summary: "Invite Member", + description: + "Invites a user by email to the current organization, optionally with a specific role.", + }), + ), ) .add( HttpApiEndpoint.delete("removeMember", "/account/members/:membershipId", { params: MembershipParams, success: SuccessResponse, error: [AccountError, AccountUnauthorized, AccountForbidden, AccountNoOrganization], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "account.removeMember", + summary: "Remove Member", + description: + "Removes the membership identified by the given id from the current organization.", + }), + ), ) .add( HttpApiEndpoint.patch("updateMemberRole", "/account/members/:membershipId/role", { @@ -224,14 +277,26 @@ export const AccountApi = HttpApiGroup.make("account") payload: UpdateMemberRoleBody, success: SuccessResponse, error: [AccountError, AccountUnauthorized, AccountForbidden, AccountNoOrganization], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "account.updateMemberRole", + summary: "Update Member Role", + description: "Updates the role of the membership identified by the given id.", + }), + ), ) .add( HttpApiEndpoint.patch("updateOrgName", "/account/name", { payload: UpdateOrgNameBody, success: UpdateOrgNameResponse, error: [AccountError, AccountUnauthorized, AccountForbidden, AccountNoOrganization], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "account.updateOrgName", + summary: "Update Org Name", + description: "Updates the display name of the current organization.", + }), + ), ); /** diff --git a/packages/core/api/src/connections/api.ts b/packages/core/api/src/connections/api.ts index 3bca0a444..48bf9c37d 100644 --- a/packages/core/api/src/connections/api.ts +++ b/packages/core/api/src/connections/api.ts @@ -1,4 +1,4 @@ -import { HttpApiEndpoint, HttpApiGroup } from "effect/unstable/httpapi"; +import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"; import { Schema } from "effect"; import { @@ -64,28 +64,54 @@ export const ConnectionsApi = HttpApiGroup.make("connections") params: ScopeParams, success: Schema.Array(ConnectionRefResponse), error: InternalError, - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "connections.list", + summary: "List Connections", + description: "Lists all provider connections belonging to the given scope.", + }), + ), ) .add( HttpApiEndpoint.delete("remove", "/scopes/:scopeId/connections/:connectionId", { params: ConnectionParams, success: Schema.Struct({ removed: Schema.Boolean }), error: [InternalError, ConnectionInUse], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "connections.remove", + summary: "Remove Connection", + description: + "Deletes the specified connection from the scope, failing if it is still in use.", + }), + ), ) .add( HttpApiEndpoint.get("usages", "/scopes/:scopeId/connections/:connectionId/usages", { params: ConnectionParams, success: Schema.Array(Usage), error: InternalError, - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "connections.usages", + summary: "List Connection Usages", + description: "Returns the usage records associated with the specified connection.", + }), + ), ) .add( HttpApiEndpoint.get("identity", "/scopes/:scopeId/connections/:connectionId/identity", { params: ConnectionParams, success: ConnectionIdentityResponse, error: InternalError, - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "connections.identity", + summary: "Get Connection Identity", + description: + "Resolves the identity details and availability status for the specified connection.", + }), + ), ) .add( HttpApiEndpoint.patch("updateIdentity", "/scopes/:scopeId/connections/:connectionId/identity", { @@ -93,5 +119,11 @@ export const ConnectionsApi = HttpApiGroup.make("connections") payload: UpdateConnectionIdentityPayload, success: ConnectionRefResponse, error: [InternalError, ConnectionNotFound], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "connections.updateIdentity", + summary: "Update Connection Identity", + description: "Sets or clears the manual identity override for the specified connection.", + }), + ), ); diff --git a/packages/core/api/src/executions/api.ts b/packages/core/api/src/executions/api.ts index a568c51e9..77bb96c20 100644 --- a/packages/core/api/src/executions/api.ts +++ b/packages/core/api/src/executions/api.ts @@ -1,4 +1,4 @@ -import { HttpApiEndpoint, HttpApiGroup } from "effect/unstable/httpapi"; +import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"; import { Schema } from "effect"; import { InternalError } from "@executor-js/sdk/shared"; @@ -58,14 +58,28 @@ export const ExecutionsApi = HttpApiGroup.make("executions") params: ExecutionParams, success: PausedExecutionInfo, error: [InternalError, ExecutionNotFoundError], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "executions.getPaused", + summary: "Get Paused Execution", + description: + "Retrieve the text and structured output of a paused execution by its execution ID.", + }), + ), ) .add( HttpApiEndpoint.post("execute", "/executions", { payload: ExecuteRequest, success: ExecuteResponse, error: InternalError, - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "executions.execute", + summary: "Execute Code", + description: + "Run the provided code and return either a completed result or a paused execution awaiting input.", + }), + ), ) .add( HttpApiEndpoint.post("resume", "/executions/:executionId/resume", { @@ -73,5 +87,12 @@ export const ExecutionsApi = HttpApiGroup.make("executions") payload: ResumeRequest, success: ResumeResponse, error: [InternalError, ExecutionNotFoundError], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "executions.resume", + summary: "Resume Execution", + description: + "Resume a paused execution by accepting, declining, or cancelling it, optionally providing content.", + }), + ), ); diff --git a/packages/core/api/src/oauth/api.ts b/packages/core/api/src/oauth/api.ts index 7d854cd29..219f330f3 100644 --- a/packages/core/api/src/oauth/api.ts +++ b/packages/core/api/src/oauth/api.ts @@ -7,7 +7,7 @@ // `/scopes/:scopeId/{mcp,openapi,graphql}/oauth/*`. // --------------------------------------------------------------------------- -import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "effect/unstable/httpapi"; +import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/unstable/httpapi"; import { Schema } from "effect"; import { @@ -137,7 +137,14 @@ export const OAuthApi = HttpApiGroup.make("oauth") payload: ProbePayload, success: ProbeResponse, error: [InternalError, OAuthProbeError], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "oauth.probe", + summary: "Probe OAuth Endpoint", + description: + "Probes an endpoint to discover its OAuth resource and authorization server metadata and whether it supports dynamic client registration.", + }), + ), ) .add( HttpApiEndpoint.post("start", "/scopes/:scopeId/oauth/start", { @@ -145,7 +152,14 @@ export const OAuthApi = HttpApiGroup.make("oauth") payload: StartPayload, success: StartResponse, error: [InternalError, OAuthStartError], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "oauth.start", + summary: "Start OAuth Flow", + description: + "Starts an OAuth flow by persisting a session and returning an authorization URL, or minting the connection inline for client-credentials strategies.", + }), + ), ) .add( HttpApiEndpoint.post("complete", "/scopes/:scopeId/oauth/complete", { @@ -153,7 +167,14 @@ export const OAuthApi = HttpApiGroup.make("oauth") payload: CompletePayload, success: CompleteResponse, error: [InternalError, OAuthCompleteError, OAuthSessionNotFoundError], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "oauth.complete", + summary: "Complete OAuth Flow", + description: + "Completes an OAuth flow by exchanging the authorization code for tokens, minting the connection, and dropping the session.", + }), + ), ) .add( HttpApiEndpoint.post("cancel", "/scopes/:scopeId/oauth/cancel", { @@ -161,12 +182,26 @@ export const OAuthApi = HttpApiGroup.make("oauth") payload: CancelPayload, success: CancelResponse, error: [InternalError, OAuthSessionNotFoundError], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "oauth.cancel", + summary: "Cancel OAuth Flow", + description: + "Cancels an in-flight OAuth session without exchanging the authorization code.", + }), + ), ) .add( HttpApiEndpoint.get("callback", "/oauth/callback", { query: CallbackUrlParams, success: HtmlResponse, error: [InternalError, OAuthCompleteError, OAuthSessionNotFoundError], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "oauth.callback", + summary: "OAuth Redirect Callback", + description: + "Handles the OAuth redirect with state and code query params and renders popup HTML that posts the completion result back to the opener.", + }), + ), ); diff --git a/packages/core/api/src/policies/api.ts b/packages/core/api/src/policies/api.ts index 3e169fe76..d25055872 100644 --- a/packages/core/api/src/policies/api.ts +++ b/packages/core/api/src/policies/api.ts @@ -1,4 +1,4 @@ -import { HttpApiEndpoint, HttpApiGroup } from "effect/unstable/httpapi"; +import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"; import { Schema } from "effect"; import { InternalError, PolicyId, ScopeId, ToolPolicyActionSchema } from "@executor-js/sdk/shared"; @@ -47,7 +47,13 @@ export const PoliciesApi = HttpApiGroup.make("policies") params: ScopeParams, success: Schema.Array(ToolPolicyResponse), error: InternalError, - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "policies.list", + summary: "List Policies", + description: "Lists all tool policies for the given scope.", + }), + ), ) .add( HttpApiEndpoint.post("create", "/scopes/:scopeId/policies", { @@ -55,7 +61,14 @@ export const PoliciesApi = HttpApiGroup.make("policies") payload: CreateToolPolicyPayload, success: ToolPolicyResponse, error: InternalError, - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "policies.create", + summary: "Create Policy", + description: + "Creates a tool policy targeting a scope with a pattern, action, and optional position.", + }), + ), ) .add( HttpApiEndpoint.patch("update", "/scopes/:scopeId/policies/:policyId", { @@ -63,12 +76,25 @@ export const PoliciesApi = HttpApiGroup.make("policies") payload: UpdateToolPolicyPayload, success: ToolPolicyResponse, error: InternalError, - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "policies.update", + summary: "Update Policy", + description: + "Updates the target scope, pattern, action, or position of an existing tool policy.", + }), + ), ) .add( HttpApiEndpoint.delete("remove", "/scopes/:scopeId/policies/:policyId", { params: PolicyParams, success: Schema.Struct({ removed: Schema.Boolean }), error: InternalError, - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "policies.remove", + summary: "Remove Policy", + description: "Deletes the tool policy identified by policy ID within the given scope.", + }), + ), ); diff --git a/packages/core/api/src/scope/api.ts b/packages/core/api/src/scope/api.ts index e7560a9e9..72fa2cebc 100644 --- a/packages/core/api/src/scope/api.ts +++ b/packages/core/api/src/scope/api.ts @@ -1,4 +1,4 @@ -import { HttpApiEndpoint, HttpApiGroup } from "effect/unstable/httpapi"; +import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"; import { Schema } from "effect"; import { InternalError, ScopeId } from "@executor-js/sdk/shared"; @@ -27,5 +27,12 @@ export const ScopeApi = HttpApiGroup.make("scope").add( HttpApiEndpoint.get("info", "/scope", { success: ScopeInfoResponse, error: InternalError, - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "scope.info", + summary: "Scope Info", + description: + "Returns the current scope's id, name, directory, and its full parent scope stack.", + }), + ), ); diff --git a/packages/core/api/src/secrets/api.ts b/packages/core/api/src/secrets/api.ts index 7b0da4085..fbc7cfaa7 100644 --- a/packages/core/api/src/secrets/api.ts +++ b/packages/core/api/src/secrets/api.ts @@ -1,4 +1,4 @@ -import { HttpApiEndpoint, HttpApiGroup } from "effect/unstable/httpapi"; +import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"; import { Schema } from "effect"; import { InternalError, @@ -61,21 +61,40 @@ export const SecretsApi = HttpApiGroup.make("secrets") params: ScopeParams, success: Schema.Array(SecretRefResponse), error: InternalError, - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "secrets.list", + summary: "List Secrets", + description: "Lists the secret references stored in the given scope.", + }), + ), ) .add( HttpApiEndpoint.get("listAll", "/scopes/:scopeId/secrets/all", { params: ScopeParams, success: Schema.Array(SecretRefResponse), error: InternalError, - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "secrets.listAll", + summary: "List All Secrets", + description: "Lists all secret references for the given scope, including inherited ones.", + }), + ), ) .add( HttpApiEndpoint.get("status", "/scopes/:scopeId/secrets/:secretId/status", { params: SecretParams, success: SecretStatusResponse, error: InternalError, - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "secrets.status", + summary: "Secret Status", + description: + "Reports whether the secret in the given scope is currently resolved or missing.", + }), + ), ) .add( HttpApiEndpoint.post("set", "/scopes/:scopeId/secrets", { @@ -83,19 +102,38 @@ export const SecretsApi = HttpApiGroup.make("secrets") payload: SetSecretPayload, success: SecretRefResponse, error: [InternalError, SecretResolution], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "secrets.set", + summary: "Set Secret", + description: + "Creates or updates a secret value in the given scope and returns its reference.", + }), + ), ) .add( HttpApiEndpoint.delete("remove", "/scopes/:scopeId/secrets/:secretId", { params: SecretParams, success: Schema.Struct({ removed: Schema.Boolean }), error: [InternalError, SecretNotFound, SecretOwnedByConnection, SecretInUse], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "secrets.remove", + summary: "Remove Secret", + description: "Deletes the secret identified by secretId from the given scope.", + }), + ), ) .add( HttpApiEndpoint.get("usages", "/scopes/:scopeId/secrets/:secretId/usages", { params: SecretParams, success: Schema.Array(Usage), error: InternalError, - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "secrets.usages", + summary: "Secret Usages", + description: "Lists the usages that reference the secret in the given scope.", + }), + ), ); diff --git a/packages/core/api/src/sources/api.ts b/packages/core/api/src/sources/api.ts index 205ed6dfe..04a1152c5 100644 --- a/packages/core/api/src/sources/api.ts +++ b/packages/core/api/src/sources/api.ts @@ -1,4 +1,4 @@ -import { HttpApiEndpoint, HttpApiGroup } from "effect/unstable/httpapi"; +import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"; import { Schema } from "effect"; import { InternalError, @@ -99,28 +99,52 @@ export const SourcesApi = HttpApiGroup.make("sources") params: ScopeParams, success: Schema.Array(SourceResponse), error: InternalError, - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "sources.list", + summary: "List Sources", + description: "Lists all configured sources available within the given scope.", + }), + ), ) .add( HttpApiEndpoint.delete("remove", "/scopes/:scopeId/sources/:sourceId", { params: SourceParams, success: SourceRemoveResponse, error: [InternalError, SourceRemovalNotAllowed], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "sources.remove", + summary: "Remove Source", + description: "Removes the specified source from the given scope.", + }), + ), ) .add( HttpApiEndpoint.post("refresh", "/scopes/:scopeId/sources/:sourceId/refresh", { params: SourceParams, success: SourceRefreshResponse, error: InternalError, - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "sources.refresh", + summary: "Refresh Source", + description: "Refreshes the specified source to update its tools and metadata.", + }), + ), ) .add( HttpApiEndpoint.get("tools", "/scopes/:scopeId/sources/:sourceId/tools", { params: SourceParams, success: Schema.Array(ToolMetadataResponse), error: InternalError, - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "sources.tools", + summary: "List Source Tools", + description: "Lists the tools provided by the specified source within the given scope.", + }), + ), ) .add( HttpApiEndpoint.post("detect", "/scopes/:scopeId/sources/detect", { @@ -128,7 +152,14 @@ export const SourcesApi = HttpApiGroup.make("sources") payload: DetectRequest, success: Schema.Array(DetectResultResponse), error: InternalError, - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "sources.detect", + summary: "Detect Source", + description: + "Detects candidate source configurations for the supplied URL within the given scope.", + }), + ), ) .add( HttpApiEndpoint.post("configure", "/scopes/:scopeId/sources/configure", { @@ -136,7 +167,13 @@ export const SourcesApi = HttpApiGroup.make("sources") payload: ConfigureSourceRequest, success: Schema.Unknown, error: InternalError, - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "sources.configure", + summary: "Configure Source", + description: "Configures a source with the provided settings within the given scope.", + }), + ), ) .add( HttpApiEndpoint.get( @@ -147,6 +184,12 @@ export const SourcesApi = HttpApiGroup.make("sources") success: Schema.Array(CredentialBindingRef), error: InternalError, }, + ).annotateMerge( + OpenApi.annotations({ + identifier: "sources.listBindings", + summary: "List Source Bindings", + description: "Lists the credential bindings for a source relative to the given base scope.", + }), ), ) .add( @@ -155,7 +198,13 @@ export const SourcesApi = HttpApiGroup.make("sources") payload: SetSourceCredentialBindingInput, success: CredentialBindingRef, error: InternalError, - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "sources.setBinding", + summary: "Set Source Binding", + description: "Creates or updates a credential binding for a source within the given scope.", + }), + ), ) .add( HttpApiEndpoint.post("removeBinding", "/scopes/:scopeId/source-bindings/remove", { @@ -163,7 +212,13 @@ export const SourcesApi = HttpApiGroup.make("sources") payload: RemoveSourceCredentialBindingInput, success: Schema.Struct({ removed: Schema.Boolean }), error: InternalError, - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "sources.removeBinding", + summary: "Remove Source Binding", + description: "Removes a credential binding for a source within the given scope.", + }), + ), ) .add( HttpApiEndpoint.post("replaceBindings", "/scopes/:scopeId/source-bindings/replace", { @@ -171,5 +226,12 @@ export const SourcesApi = HttpApiGroup.make("sources") payload: ReplaceSourceCredentialBindingsInput, success: Schema.Array(CredentialBindingRef), error: InternalError, - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "sources.replaceBindings", + summary: "Replace Source Bindings", + description: + "Replaces the full set of credential bindings for a source within the given scope.", + }), + ), ); diff --git a/packages/core/api/src/tools/api.ts b/packages/core/api/src/tools/api.ts index 8d1ac726d..aa8d523da 100644 --- a/packages/core/api/src/tools/api.ts +++ b/packages/core/api/src/tools/api.ts @@ -1,4 +1,4 @@ -import { HttpApiEndpoint, HttpApiGroup } from "effect/unstable/httpapi"; +import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"; import { Schema } from "effect"; import { InternalError, ScopeId, ToolId, ToolNotFoundError } from "@executor-js/sdk/shared"; @@ -53,12 +53,25 @@ export const ToolsApi = HttpApiGroup.make("tools") params: { scopeId: PathParams.scopeId }, success: Schema.Array(ToolMetadataResponse), error: InternalError, - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "tools.list", + summary: "List Tools", + description: "Lists metadata for all tools discovered within the given scope.", + }), + ), ) .add( HttpApiEndpoint.get("schema", "/scopes/:scopeId/tools/:toolId/schema", { params: PathParams, success: ToolSchemaResponse, error: [InternalError, ToolNotFound], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "tools.schema", + summary: "Get Tool Schema", + description: + "Returns the input and output schema definitions for a specific tool in the scope.", + }), + ), ); diff --git a/packages/plugins/graphql/src/api/group.ts b/packages/plugins/graphql/src/api/group.ts index 251503fc5..f0043178a 100644 --- a/packages/plugins/graphql/src/api/group.ts +++ b/packages/plugins/graphql/src/api/group.ts @@ -1,4 +1,4 @@ -import { HttpApiEndpoint, HttpApiGroup } from "effect/unstable/httpapi"; +import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"; import { Schema } from "effect"; import { InternalError, ScopeId } from "@executor-js/sdk/shared"; @@ -99,14 +99,28 @@ export const GraphqlGroup = HttpApiGroup.make("graphql") payload: AddSourcePayload, success: AddSourceResponse, error: GraphqlErrors, - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "graphql.addSource", + summary: "Add GraphQL Source", + description: + "Registers a GraphQL source in the given scope by introspecting its endpoint and returns the namespace and number of tools extracted.", + }), + ), ) .add( HttpApiEndpoint.get("getSource", "/scopes/:scopeId/graphql/sources/:namespace", { params: SourceParams, success: Schema.NullOr(StoredSourceSchema), error: GraphqlErrors, - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "graphql.getSource", + summary: "Get GraphQL Source", + description: + "Retrieves the stored GraphQL source for the given scope and namespace, or null if no such source exists.", + }), + ), ); // Plugin domain errors carry their own HTTP status (4xx); // `InternalError` is the shared opaque 500 translated at the HTTP edge. diff --git a/packages/plugins/mcp/src/api/group.ts b/packages/plugins/mcp/src/api/group.ts index 7cd41b4e4..1ad8601c1 100644 --- a/packages/plugins/mcp/src/api/group.ts +++ b/packages/plugins/mcp/src/api/group.ts @@ -1,4 +1,4 @@ -import { HttpApiEndpoint, HttpApiGroup } from "effect/unstable/httpapi"; +import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"; import { Schema } from "effect"; import { InternalError, ScopeId, SecretBackedMap } from "@executor-js/sdk/shared"; @@ -110,7 +110,14 @@ export const McpGroup = HttpApiGroup.make("mcp") payload: ProbeEndpointPayload, success: ProbeEndpointResponse, error: [InternalError, McpConnectionError, McpToolDiscoveryError], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "mcp.probeEndpoint", + summary: "Probe MCP Endpoint", + description: + "Probes a remote MCP endpoint within a scope to report connectivity, OAuth requirements, dynamic registration support, server name, and tool count without persisting a source.", + }), + ), ) .add( HttpApiEndpoint.post("addSource", "/scopes/:scopeId/mcp/sources", { @@ -118,7 +125,14 @@ export const McpGroup = HttpApiGroup.make("mcp") payload: AddSourcePayload, success: AddSourceResponse, error: [InternalError, McpConnectionError, McpToolDiscoveryError], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "mcp.addSource", + summary: "Add MCP Source", + description: + "Registers a new MCP source (remote or stdio transport) in a scope, connecting to discover its tools and returning the assigned namespace and discovered tool count.", + }), + ), ) .add( HttpApiEndpoint.post("removeSource", "/scopes/:scopeId/mcp/sources/remove", { @@ -126,7 +140,14 @@ export const McpGroup = HttpApiGroup.make("mcp") payload: NamespacePayload, success: RemoveSourceResponse, error: [InternalError, McpConnectionError, McpToolDiscoveryError], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "mcp.removeSource", + summary: "Remove MCP Source", + description: + "Removes the MCP source identified by the given namespace from a scope and reports whether it was removed.", + }), + ), ) .add( HttpApiEndpoint.post("refreshSource", "/scopes/:scopeId/mcp/sources/refresh", { @@ -134,14 +155,28 @@ export const McpGroup = HttpApiGroup.make("mcp") payload: NamespacePayload, success: RefreshSourceResponse, error: [InternalError, McpConnectionError, McpToolDiscoveryError], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "mcp.refreshSource", + summary: "Refresh MCP Source", + description: + "Reconnects to the MCP source identified by the given namespace in a scope to re-discover its tools and returns the updated tool count.", + }), + ), ) .add( HttpApiEndpoint.get("getSource", "/scopes/:scopeId/mcp/sources/:namespace", { params: SourceParams, success: Schema.NullOr(McpStoredSourceSchema), error: [InternalError, McpConnectionError, McpToolDiscoveryError], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "mcp.getSource", + summary: "Get MCP Source", + description: + "Returns the stored MCP source for the given namespace in a scope, or null when no source with that namespace exists.", + }), + ), ); // Errors declared once at the group level — every endpoint inherits. // Plugin domain errors carry their own HttpApiSchema status (4xx); diff --git a/packages/plugins/onepassword/src/api/group.ts b/packages/plugins/onepassword/src/api/group.ts index 01b4e2250..31b7c5850 100644 --- a/packages/plugins/onepassword/src/api/group.ts +++ b/packages/plugins/onepassword/src/api/group.ts @@ -1,4 +1,4 @@ -import { HttpApiEndpoint, HttpApiGroup } from "effect/unstable/httpapi"; +import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"; import { Schema } from "effect"; import { InternalError, ScopeId } from "@executor-js/sdk/shared"; @@ -52,7 +52,14 @@ export const OnePasswordGroup = HttpApiGroup.make("onepassword") params: ScopeParams, success: GetConfigResponse, error: [InternalError, OnePasswordError], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "onepassword.getConfig", + summary: "Get Config", + description: + "Returns the 1Password configuration for the given scope, or null if none is configured.", + }), + ), ) .add( HttpApiEndpoint.put("configure", "/scopes/:scopeId/onepassword/config", { @@ -60,21 +67,39 @@ export const OnePasswordGroup = HttpApiGroup.make("onepassword") payload: ConfigurePayload, success: Schema.Void, error: [InternalError, OnePasswordError], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "onepassword.configure", + summary: "Configure 1Password", + description: "Sets the 1Password configuration for the given scope.", + }), + ), ) .add( HttpApiEndpoint.delete("removeConfig", "/scopes/:scopeId/onepassword/config", { params: ScopeParams, success: Schema.Void, error: [InternalError, OnePasswordError], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "onepassword.removeConfig", + summary: "Remove Config", + description: "Deletes the 1Password configuration for the given scope.", + }), + ), ) .add( HttpApiEndpoint.get("status", "/scopes/:scopeId/onepassword/status", { params: ScopeParams, success: ConnectionStatus, error: [InternalError, OnePasswordError], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "onepassword.status", + summary: "Connection Status", + description: "Reports the current 1Password connection status for the given scope.", + }), + ), ) .add( HttpApiEndpoint.get("listVaults", "/scopes/:scopeId/onepassword/vaults", { @@ -82,5 +107,12 @@ export const OnePasswordGroup = HttpApiGroup.make("onepassword") query: ListVaultsParams, success: ListVaultsResponse, error: [InternalError, OnePasswordError], - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "onepassword.listVaults", + summary: "List Vaults", + description: + "Lists the 1Password vaults available for the given scope and authentication method.", + }), + ), ); diff --git a/packages/plugins/openapi/src/api/group.ts b/packages/plugins/openapi/src/api/group.ts index 0f9758e8f..bea1937a0 100644 --- a/packages/plugins/openapi/src/api/group.ts +++ b/packages/plugins/openapi/src/api/group.ts @@ -1,4 +1,4 @@ -import { HttpApiEndpoint, HttpApiGroup } from "effect/unstable/httpapi"; +import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"; import { Schema } from "effect"; import { ConnectionId, @@ -161,7 +161,14 @@ export const OpenApiGroup = HttpApiGroup.make("openapi") payload: PreviewSpecPayload, success: SpecPreview, error: DomainErrors, - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "openapi.previewSpec", + summary: "Preview Spec", + description: + "Parses a raw OpenAPI spec for the given scope and returns a preview of the operations it would expose without persisting a source.", + }), + ), ) .add( HttpApiEndpoint.post("addSpec", "/scopes/:scopeId/openapi/specs", { @@ -169,14 +176,28 @@ export const OpenApiGroup = HttpApiGroup.make("openapi") payload: AddSpecPayload, success: AddSpecResponse, error: DomainErrors, - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "openapi.addSpec", + summary: "Add Spec", + description: + "Registers an OpenAPI spec as a source under the given scope and namespace, returning the resulting namespace and number of tools generated.", + }), + ), ) .add( HttpApiEndpoint.get("getSource", "/scopes/:scopeId/openapi/sources/:namespace", { params: SourceParams, success: Schema.NullOr(StoredSourceSchema), error: DomainErrors, - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "openapi.getSource", + summary: "Get Source", + description: + "Returns the stored OpenAPI source for the given scope and namespace, or null when no source is registered.", + }), + ), ) .add( HttpApiEndpoint.post("configure", "/scopes/:scopeId/openapi/configure", { @@ -184,5 +205,12 @@ export const OpenApiGroup = HttpApiGroup.make("openapi") payload: ConfigurePayload, success: Schema.Array(CredentialBindingRef), error: DomainErrors, - }), + }).annotateMerge( + OpenApi.annotations({ + identifier: "openapi.configure", + summary: "Configure Source", + description: + "Binds credentials (headers, query params, spec-fetch credentials, and OAuth2 settings) for an OpenAPI source in the given scope and returns the resulting credential binding references.", + }), + ), );