189 lines · 6.3 KB · TypeScript
RawDownload
// ---------------------------------------------------------------------------// Connections HTTP API — the v2 credential surface.//// A connection IS the credential: owner-scoped (org | user), bound 1:1 to an// integration, resolving its value through a `CredentialProvider`. Identified by// `(owner, integration, name)`. No scope segments, no token-secret-ids, no// identity-override-by-scope — those v1 concepts are gone.// --------------------------------------------------------------------------- import { HttpApiEndpoint, HttpApiGroup } from "effect/unstable/httpapi";import { Predicate, Schema } from "effect"; import {  AuthTemplateSlug,  ConnectionAddress,  ConnectionName,  ConnectionNotFoundError,  CredentialProviderNotRegisteredError,  IntegrationNotFoundError,  IntegrationSlug,  InternalError,  InvalidConnectionInputError,  OAuthClientSlug,  Owner,  ProviderItemId,  ProviderKey,} from "@executor-js/sdk/shared"; // ---------------------------------------------------------------------------// Params — a connection is identified by (owner, integration, name).// --------------------------------------------------------------------------- const ConnectionParams = {  owner: Owner,  integration: IntegrationSlug,  name: ConnectionName,}; // ---------------------------------------------------------------------------// Response schemas — mirrors the SDK's `Connection`.// --------------------------------------------------------------------------- const ConnectionResponse = Schema.Struct({  owner: Owner,  name: ConnectionName,  integration: IntegrationSlug,  template: AuthTemplateSlug,  provider: ProviderKey,  address: ConnectionAddress,  identityLabel: Schema.NullOr(Schema.String),  description: Schema.NullOr(Schema.String),  expiresAt: Schema.NullOr(Schema.Number),  // The OAuth app that minted this connection (its `oauth_client` slug), or null  // for static credentials. Lets the UI map a connection back to its app. Just a  // slug — never a secret.  oauthClient: Schema.NullOr(OAuthClientSlug),  oauthClientOwner: Schema.NullOr(Owner),  oauthScope: Schema.NullOr(Schema.String),}); const ToolResponse = Schema.Struct({  address: Schema.String,  owner: Owner,  integration: IntegrationSlug,  connection: ConnectionName,  name: Schema.String,  pluginId: Schema.String,  description: Schema.String,}); // ---------------------------------------------------------------------------// Payload schemas// --------------------------------------------------------------------------- // A connection picks exactly one origin: a single pasted `value` (sugar for the// `token` input), a `values` map (one per named input, e.g. both of Datadog's// keys), or an external `from` reference.const CommonCreateFields = {  owner: Owner,  name: ConnectionName,  integration: IntegrationSlug,  template: AuthTemplateSlug,  identityLabel: Schema.optional(Schema.NullOr(Schema.String)),  description: Schema.optional(Schema.NullOr(Schema.String)),} as const; // User-curated metadata edits. Absent field = unchanged; null = cleared.const UpdateConnectionPayload = Schema.Struct({  description: Schema.optional(Schema.NullOr(Schema.String)),  identityLabel: Schema.optional(Schema.NullOr(Schema.String)),}); const CreateConnectionPayload = Schema.Struct({  ...CommonCreateFields,  value: Schema.optional(Schema.String),  values: Schema.optional(Schema.Record(Schema.String, Schema.String)),  from: Schema.optional(    Schema.Struct({      provider: ProviderKey,      id: ProviderItemId,    }),  ),}).check(  Schema.makeFilter((payload) =>    [payload.value, payload.values, payload.from].filter(Predicate.isNotUndefined).length === 1      ? undefined      : "Expected exactly one credential origin",  ),); // ---------------------------------------------------------------------------// Query — optional list filters.// --------------------------------------------------------------------------- const ListConnectionsQuery = Schema.Struct({  integration: Schema.optional(IntegrationSlug),  owner: Schema.optional(Owner),}); // ---------------------------------------------------------------------------// Error schemas with HTTP status annotations// --------------------------------------------------------------------------- const ConnectionNotFound = ConnectionNotFoundError.annotate({  httpApiStatus: 404,});const IntegrationNotFound = IntegrationNotFoundError.annotate({  httpApiStatus: 404,});const CredentialProviderNotRegistered = CredentialProviderNotRegisteredError.annotate({  httpApiStatus: 409,});const InvalidConnectionInput = InvalidConnectionInputError.annotate({  httpApiStatus: 400,}); // ---------------------------------------------------------------------------// Group// --------------------------------------------------------------------------- export const ConnectionsApi = HttpApiGroup.make("connections")  .add(    HttpApiEndpoint.get("list", "/connections", {      query: ListConnectionsQuery,      success: Schema.Array(ConnectionResponse),      error: InternalError,    }),  )  .add(    HttpApiEndpoint.post("create", "/connections", {      payload: CreateConnectionPayload,      success: ConnectionResponse,      error: [        InternalError,        IntegrationNotFound,        CredentialProviderNotRegistered,        InvalidConnectionInput,      ],    }),  )  .add(    HttpApiEndpoint.get("get", "/connections/:owner/:integration/:name", {      params: ConnectionParams,      success: ConnectionResponse,      error: [InternalError, ConnectionNotFound],    }),  )  .add(    HttpApiEndpoint.patch("update", "/connections/:owner/:integration/:name", {      params: ConnectionParams,      payload: UpdateConnectionPayload,      success: ConnectionResponse,      error: [InternalError, ConnectionNotFound],    }),  )  .add(    HttpApiEndpoint.delete("remove", "/connections/:owner/:integration/:name", {      params: ConnectionParams,      success: Schema.Struct({ removed: Schema.Boolean }),      error: [InternalError, ConnectionNotFound],    }),  )  .add(    HttpApiEndpoint.post("refresh", "/connections/:owner/:integration/:name/refresh", {      params: ConnectionParams,      success: Schema.Array(ToolResponse),      error: [InternalError, ConnectionNotFound, IntegrationNotFound],    }),  );