152 lines · 5.2 KB · TypeScript
RawDownload
import { Effect, Predicate } from "effect";import {  ConnectionName,  IntegrationSlug,  ToolAddress,  isToolResult,  type ExecuteError,  type ConnectionRef,  type Owner,  type PluginCtx,} from "@executor-js/sdk"; import {  AppInnerToolError,  BindingError,  type ClientResolver,  type ConnectionCandidate,} from "./bindings"; export interface AppsResolverPluginCtx {  readonly connections: Pick<PluginCtx["connections"], "list" | "get">;  readonly execute: PluginCtx["execute"];} const parseConnectionAddress = (address: string): ConnectionRef | null => {  const parts = address.split(".");  if (parts.length !== 4 || parts[0] !== "tools") return null;  const [, integration, owner, name] = parts;  if (!integration || !name) return null;  if (owner !== "org" && owner !== "user") return null;  return {    owner: owner as Owner,    integration: IntegrationSlug.make(integration),    name: ConnectionName.make(name),  };}; const toCandidate = (connection: {  readonly address?: unknown;  readonly integration: unknown;  readonly owner?: unknown;  readonly name?: unknown;}): ConnectionCandidate => ({  address:    typeof connection.address === "string"      ? connection.address      : `tools.${String(connection.integration)}.${String(connection.owner)}.${String(          connection.name,        )}`,  integration: String(connection.integration),}); const innerMessageFromCause = (cause: ExecuteError): string => {  if (    Predicate.isTagged("ToolInvocationError")(cause) ||    Predicate.isTagged("CredentialResolutionError")(cause) ||    Predicate.isTagged("StorageError")(cause)  ) {    // oxlint-disable-next-line executor/no-unknown-error-message -- typed ExecuteError variants expose message as caller-facing failure text    return cause.message;  }  if (Predicate.isTagged("ToolNotFoundError")(cause)) return `Tool not found: ${cause.address}`;  if (Predicate.isTagged("ToolBlockedError")(cause)) return `Tool blocked: ${cause.address}`;  if (Predicate.isTagged("PluginNotLoadedError")(cause)) {    return `Plugin not loaded for tool: ${cause.address}`;  }  if (Predicate.isTagged("NoHandlerError")(cause)) return `No handler for tool: ${cause.address}`;  if (Predicate.isTagged("ConnectionNotFoundError")(cause)) {    return `Connection not found: ${cause.integration}.${cause.owner}.${cause.name}`;  }  if (Predicate.isTagged("CredentialProviderNotRegisteredError")(cause)) {    return `Credential provider not registered: ${cause.provider}`;  }  if (Predicate.isTagged("ElicitationDeclinedError")(cause)) {    return `Tool approval ${cause.action === "cancel" ? "cancelled" : "declined"}: ${cause.address}`;  }  if (Predicate.isTagged("UniqueViolationError")(cause)) return "storage unique violation";  return "inner tool failed";}; export const makePluginCtxAppsResolver = (input: {  readonly ctx: AppsResolverPluginCtx;}): ClientResolver => ({  listConnections: ({ integration }) =>    input.ctx.connections.list({ integration: IntegrationSlug.make(integration) }).pipe(      Effect.map((connections) => connections.map(toCandidate)),      Effect.mapError(        () =>          new BindingError({            role: integration,            integration,            message: `failed to list ${integration} connections`,          }),      ),    ),  resolveConnection: ({ connection }) =>    Effect.gen(function* () {      const ref = parseConnectionAddress(connection);      if (!ref) return null;      const row = yield* input.ctx.connections.get(ref).pipe(        Effect.mapError(          () =>            new BindingError({              role: String(ref.integration),              integration: String(ref.integration),              requestedConnection: connection,              message: `failed to resolve connection ${connection}`,            }),        ),      );      return row ? toCandidate(row) : null;    }),  call: ({ integration, connection, path, args, invokeOptions }) =>    Effect.gen(function* () {      const ref = parseConnectionAddress(connection);      if (!ref) {        return yield* new BindingError({          role: integration,          integration,          requestedConnection: connection,          message: `invalid connection address ${connection}`,        });      }      if (String(ref.integration) !== integration) {        return yield* new BindingError({          role: integration,          integration,          requestedConnection: connection,          message: `connection "${connection}" belongs to integration "${ref.integration}", not "${integration}"`,        });      }      const address = ToolAddress.make(`${connection}.${path.join(".")}`);      const result = yield* input.ctx.execute(address, args, invokeOptions).pipe(        Effect.mapError(          (cause) =>            new AppInnerToolError({              address,              innerMessage: innerMessageFromCause(cause),            }),        ),      );      if (isToolResult(result)) {        if (result.ok) return result.data;        return yield* new AppInnerToolError({          address,          code: result.error.code,          innerMessage: result.error.message,        });      }      return result;    }),});