174 lines · 5.5 KB · TypeScript
RawDownload
import { HttpApiBuilder } from "effect/unstable/httpapi";import { Effect } from "effect"; import { capture } from "@executor-js/api";import {  ConnectionNotFoundError,  type Connection,  type ConnectionRef,  type CreateConnectionInput,  type HealthCheckResult,  type Tool,  type ValidateConnectionInput,} from "@executor-js/sdk"; import { ExecutorApi } from "../api";import { ExecutorService } from "../services"; const toResponse = (c: Connection) => ({  owner: c.owner,  name: c.name,  integration: c.integration,  template: c.template,  provider: c.provider,  address: c.address,  identityLabel: c.identityLabel ?? null,  description: c.description ?? null,  expiresAt: c.expiresAt ?? null,  oauthClient: c.oauthClient ?? null,  oauthClientOwner: c.oauthClientOwner ?? null,  oauthScope: c.oauthScope ?? null,  lastHealth: c.lastHealth ?? null,}); const toolToResponse = (t: Tool) => ({  address: String(t.address),  owner: t.owner,  integration: t.integration,  connection: t.connection,  name: String(t.name),  pluginId: t.pluginId,  description: t.description,}); const toHealthResponse = (r: HealthCheckResult) => ({  status: r.status,  checkedAt: r.checkedAt,  ...(r.httpStatus !== undefined ? { httpStatus: r.httpStatus } : {}),  ...(r.identity !== undefined ? { identity: r.identity } : {}),  ...(r.detail !== undefined ? { detail: r.detail } : {}),  ...(r.responseSample !== undefined ? { responseSample: r.responseSample } : {}),}); export const ConnectionsHandlers = HttpApiBuilder.group(ExecutorApi, "connections", (handlers) =>  handlers    .handle("list", ({ query }) =>      capture(        Effect.gen(function* () {          const executor = yield* ExecutorService;          const connections = yield* executor.connections.list({            integration: query.integration,            owner: query.owner,          });          return connections.map(toResponse);        }),      ),    )    .handle("create", ({ payload }) =>      capture(        Effect.gen(function* () {          const executor = yield* ExecutorService;          // The payload is the discriminated `CreateConnectionInput` union          // (`{ value }` | `{ values }` | `{ from }`); pass it through verbatim.          const created = yield* executor.connections.create(payload as CreateConnectionInput);          return toResponse(created);        }),      ),    )    .handle("get", ({ params: path }) =>      capture(        Effect.gen(function* () {          const executor = yield* ExecutorService;          const ref: ConnectionRef = {            owner: path.owner,            integration: path.integration,            name: path.name,          };          const connection = yield* executor.connections.get(ref);          if (connection === null) {            return yield* new ConnectionNotFoundError({              owner: path.owner,              integration: path.integration,              name: path.name,            });          }          return toResponse(connection);        }),      ),    )    .handle("update", ({ params: path, payload }) =>      capture(        Effect.gen(function* () {          const executor = yield* ExecutorService;          const updated = yield* executor.connections.update(            {              owner: path.owner,              integration: path.integration,              name: path.name,            },            {              ...(payload.description !== undefined ? { description: payload.description } : {}),              ...(payload.identityLabel !== undefined                ? { identityLabel: payload.identityLabel }                : {}),            },          );          return toResponse(updated);        }),      ),    )    .handle("remove", ({ params: path }) =>      capture(        Effect.gen(function* () {          const executor = yield* ExecutorService;          yield* executor.connections.remove({            owner: path.owner,            integration: path.integration,            name: path.name,          });          return { removed: true };        }),      ),    )    .handle("refresh", ({ params: path }) =>      capture(        Effect.gen(function* () {          const executor = yield* ExecutorService;          const tools = yield* executor.connections.refresh({            owner: path.owner,            integration: path.integration,            name: path.name,          });          return tools.map(toolToResponse);        }),      ),    )    .handle("checkHealth", ({ params: path, query }) =>      capture(        Effect.gen(function* () {          const executor = yield* ExecutorService;          const result = yield* executor.connections.checkHealth(            {              owner: path.owner,              integration: path.integration,              name: path.name,            },            query.ifStaleMs !== undefined ? { ifStaleMs: query.ifStaleMs } : undefined,          );          return toHealthResponse(result);        }),      ),    )    .handle("validate", ({ payload }) =>      capture(        Effect.gen(function* () {          const executor = yield* ExecutorService;          // The payload mirrors `ValidateConnectionInput`: owner/integration/          // template/spec plus a single credential origin (`value` | `values` |          // `from`). Pass it through verbatim.          const result = yield* executor.connections.validate(payload as ValidateConnectionInput);          return toHealthResponse(result);        }),      ),    ),);