1210 lines · 36.5 KB · TypeScript
RawDownload
import {  HttpApiBuilder,  HttpServerRequest,  HttpServerResponse,} from "@effect/platform";import type {  ExecutionInteraction,  Source,  ScopeId as WorkspaceId,  ScopeOauthClient as WorkspaceOauthClient,} from "@executor/platform-sdk/schema";import type {  ExecutorMcpSourceInput,  ExecutorSourceInput,} from "@executor/platform-sdk";import * as Effect from "effect/Effect"; import {  sourceAdapterRequiresInteractiveConnect,} from "@executor/platform-sdk/runtime";import { ScopeOauthClientIdSchema as WorkspaceOauthClientIdSchema } from "@executor/platform-sdk/schema"; import {  ControlPlaneBadRequestError,  ControlPlaneNotFoundError,  ControlPlaneStorageError,} from "../errors";import { ExecutorApi } from "../api";import type { ConnectSourcePayload } from "./api";import {  getControlPlaneExecutor,  resolveRequestedLocalWorkspace,} from "../local-context"; const readHeader = (headers: unknown, name: string): string | null => {  if (headers == null || typeof headers !== "object") {    return null;  }   const record = headers as Record<string, unknown>;  const exact = record[name];  if (typeof exact === "string" && exact.length > 0) {    return exact;  }   const lower = record[name.toLowerCase()];  if (typeof lower === "string" && lower.length > 0) {    return lower;  }   return null;}; const resolveRequestOrigin = (request: {  url: string;  headers: unknown;}): string | null => {  try {    return new URL(request.url).origin;  } catch {    const forwardedHost = readHeader(request.headers, "x-forwarded-host");    const host = forwardedHost ?? readHeader(request.headers, "host");    if (!host) {      return null;    }     const forwardedProto = readHeader(request.headers, "x-forwarded-proto");    const protocol =      forwardedProto && forwardedProto.length > 0 ? forwardedProto : "http";    return `${protocol}://${host}`;  }}; const toBadRequestError = (operation: string, cause: unknown) => {  const message = cause instanceof Error ? cause.message : String(cause);  return new ControlPlaneBadRequestError({    operation,    message,    details: message,  });}; const isInteractiveConnectPayload = (  payload: ConnectSourcePayload,): payload is Extract<ConnectSourcePayload, { kind?: "mcp" }> =>  payload.kind === undefined ||  sourceAdapterRequiresInteractiveConnect(payload.kind); const nullToUndefined = <T>(value: T | null | undefined): T | undefined =>  value ?? undefined; const toWorkspaceOauthClientId = (  value: string | null | undefined,): WorkspaceOauthClient["id"] | null | undefined =>  value == null ? value : WorkspaceOauthClientIdSchema.make(value); const toExecutorSourceInput = (  payload: ConnectSourcePayload,): ExecutorSourceInput | null => {  if (isInteractiveConnectPayload(payload)) {    return null;  }   switch (payload.kind) {    case "openapi":      return {        kind: "openapi",        endpoint: payload.endpoint,        specUrl: payload.specUrl,        name: payload.name,        namespace: payload.namespace,        importAuthPolicy: nullToUndefined(payload.importAuthPolicy),        importAuth: payload.importAuth,        auth: payload.auth,      };    case "graphql":      return {        kind: "graphql",        endpoint: payload.endpoint,        name: payload.name,        namespace: payload.namespace,        importAuthPolicy: nullToUndefined(payload.importAuthPolicy),        importAuth: payload.importAuth,        auth: payload.auth,      };    case "google_discovery":      return {        kind: "google_discovery",        service: payload.service,        version: payload.version,        discoveryUrl: payload.discoveryUrl,        scopes: payload.scopes,        scopeOauthClientId: toWorkspaceOauthClientId(          payload.scopeOauthClientId,        ),        oauthClient: payload.oauthClient,        name: payload.name,        namespace: payload.namespace,        importAuthPolicy: nullToUndefined(payload.importAuthPolicy),        importAuth: payload.importAuth,        auth: payload.auth,      };  }}; const toExecutorMcpSourceInput = (  payload: Extract<ConnectSourcePayload, { kind?: "mcp" }>,  baseUrl: string | null,): ExecutorMcpSourceInput => ({  endpoint: payload.endpoint,  name: payload.name,  namespace: payload.namespace,  transport: payload.transport,  queryParams: payload.queryParams,  headers: payload.headers,  command: payload.command,  args: payload.args,  env: payload.env,  cwd: payload.cwd,  baseUrl,}); const escapeHtml = (value: string): string =>  value    .replaceAll("&", "&amp;")    .replaceAll("<", "&lt;")    .replaceAll(">", "&gt;")    .replaceAll('"', "&quot;")    .replaceAll("'", "&#39;"); const serializeJsonForScript = (value: unknown): string =>  JSON.stringify(value)    .replaceAll("<", "\\u003c")    .replaceAll(">", "\\u003e")    .replaceAll("&", "\\u0026"); const SOURCE_OAUTH_RESULT_STORAGE_KEY_PREFIX = "executor:oauth-result:"; const credentialPageDocument = (input: {  title: string;  eyebrow: string;  message: string;  sourceLabel: string;  endpoint: string;  interactionId: string;  error?: string;  state?: "pending" | "stored" | "continued" | "cancelled" | "inactive";}) => `<!doctype html><html lang="en">  <head>    <meta charset="utf-8" />    <meta name="viewport" content="width=device-width, initial-scale=1" />    <title>${escapeHtml(input.title)}</title>    <link rel="preconnect" href="https://fonts.googleapis.com" />    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />    <link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,500;0,9..40,600;1,9..40,400&family=DM+Mono:wght@400;500&display=swap" rel="stylesheet" />    <style>      :root {        --bg: #fafaf9;        --surface: #ffffff;        --text: #1c1917;        --text-secondary: #78716c;        --text-tertiary: #a8a29e;        --border: #e7e5e4;        --accent: #1d4ed8;        --accent-light: #eff6ff;        --green: #16a34a;        --green-light: #f0fdf4;        --green-border: #bbf7d0;        --red: #dc2626;        --red-light: #fef2f2;        --red-border: #fecaca;        --amber: #d97706;        --amber-light: #fffbeb;        --amber-border: #fde68a;      }       * { box-sizing: border-box; margin: 0; padding: 0; }       body {        min-height: 100vh;        background: var(--bg);        color: var(--text);        font-family: 'DM Sans', system-ui, -apple-system, sans-serif;        display: flex;        justify-content: center;        padding: 80px 24px 48px;        -webkit-font-smoothing: antialiased;      }       .page {        width: 100%;        max-width: 540px;      }       /* Status pill at the very top */      .status-pill {        display: inline-flex;        align-items: center;        gap: 7px;        padding: 5px 14px 5px 10px;        border-radius: 999px;        font-family: 'DM Mono', monospace;        font-size: 12px;        font-weight: 500;        letter-spacing: 0.01em;        margin-bottom: 28px;      }       .status-pill::before {        content: '';        width: 7px;        height: 7px;        border-radius: 50%;        flex-shrink: 0;      }       .status-pill[data-state='pending'] {        background: var(--amber-light);        color: var(--amber);        border: 1px solid var(--amber-border);      }      .status-pill[data-state='pending']::before { background: var(--amber); }       .status-pill[data-state='stored'] {        background: var(--green-light);        color: var(--green);        border: 1px solid var(--green-border);      }      .status-pill[data-state='stored']::before { background: var(--green); }       .status-pill[data-state='continued'] {        background: var(--green-light);        color: var(--green);        border: 1px solid var(--green-border);      }      .status-pill[data-state='continued']::before { background: var(--green); }       .status-pill[data-state='cancelled'],      .status-pill[data-state='inactive'] {        background: #f5f5f4;        color: var(--text-secondary);        border: 1px solid var(--border);      }      .status-pill[data-state='cancelled']::before,      .status-pill[data-state='inactive']::before { background: var(--text-tertiary); }       /* Title area */      h1 {        font-size: 28px;        font-weight: 600;        letter-spacing: -0.025em;        line-height: 1.2;        margin-bottom: 10px;      }       .subtitle {        font-size: 15px;        line-height: 1.6;        color: var(--text-secondary);      }       /* Divider */      hr {        border: none;        height: 1px;        background: var(--border);        margin: 36px 0;      }       /* Source detail rows */      .detail {        display: flex;        flex-direction: column;        gap: 6px;        margin-bottom: 24px;      }       .detail-label {        font-size: 13px;        font-weight: 500;        color: var(--text-secondary);      }       .detail-value {        font-size: 15px;        line-height: 1.5;        word-break: break-word;      }       .detail-mono {        font-family: 'DM Mono', monospace;        font-size: 13px;        line-height: 1.5;        padding: 10px 14px;        background: #f5f5f4;        border: 1px solid var(--border);        border-radius: 8px;        word-break: break-all;        color: var(--text);      }       .detail-id {        font-family: 'DM Mono', monospace;        font-size: 12px;        color: var(--text-tertiary);      }       /* Result card for stored/cancelled/inactive */      .result-card {        padding: 32px;        border-radius: 12px;        text-align: center;      }       .result-card.success {        background: var(--green-light);        border: 1px solid var(--green-border);      }       .result-card.neutral {        background: #f5f5f4;        border: 1px solid var(--border);      }       .result-card p {        font-size: 15px;        line-height: 1.6;        color: var(--text-secondary);      }       .result-card .result-heading {        font-weight: 600;        font-size: 15px;        color: var(--text);        margin-bottom: 6px;      }       /* Form */      .alert {        padding: 12px 14px;        border-radius: 8px;        background: var(--red-light);        border: 1px solid var(--red-border);        color: var(--red);        font-size: 14px;        line-height: 1.5;        margin-bottom: 20px;      }       .field { margin-bottom: 20px; }       label {        display: block;        font-size: 14px;        font-weight: 500;        margin-bottom: 6px;      }       input[type='password'] {        width: 100%;        padding: 10px 14px;        background: var(--surface);        border: 1px solid var(--border);        border-radius: 8px;        font-family: 'DM Mono', monospace;        font-size: 14px;        color: var(--text);        transition: border-color 0.15s, box-shadow 0.15s;      }       input[type='password']::placeholder { color: var(--text-tertiary); }       input[type='password']:focus {        outline: none;        border-color: var(--accent);        box-shadow: 0 0 0 3px rgba(29, 78, 216, 0.1);      }       .hint {        margin-top: 8px;        font-size: 13px;        line-height: 1.5;        color: var(--text-tertiary);      }       .actions {        display: flex;        gap: 10px;        margin-top: 24px;      }       button {        appearance: none;        border: none;        border-radius: 8px;        padding: 10px 20px;        font-family: inherit;        font-size: 14px;        font-weight: 500;        cursor: pointer;        transition: background 0.15s;      }       .primary {        background: var(--text);        color: var(--surface);      }      .primary:hover { background: #292524; }       .secondary {        background: transparent;        color: var(--text-secondary);        border: 1px solid var(--border);      }      .secondary:hover { background: #f5f5f4; }       @media (max-width: 540px) {        body { padding: 48px 20px 32px; }        h1 { font-size: 24px; }      }    </style>  </head>  <body>    <main class="page">      <div class="status-pill" data-state="${escapeHtml(input.state ?? "pending")}">${escapeHtml(input.state ?? "pending")}</div>       <h1>${escapeHtml(input.title)}</h1>      <p class="subtitle">${escapeHtml(input.message)}</p>       <hr />       <div class="detail">        <span class="detail-label">Source</span>        <span class="detail-value">${escapeHtml(input.sourceLabel)}</span>      </div>       <div class="detail">        <span class="detail-label">API endpoint</span>        <div class="detail-mono">${escapeHtml(input.endpoint)}</div>      </div>       <div class="detail">        <span class="detail-label">Interaction</span>        <span class="detail-id">${escapeHtml(input.interactionId)}</span>      </div>       <hr />       ${input.error ? `<p class="alert">${escapeHtml(input.error)}</p>` : ""}      ${        input.state === "stored"          ? `<div class="result-card success">              <p class="result-heading">Credential stored</p>              <p>Executor resumed the source connection request. You can close this window.</p>            </div>`          : input.state === "continued"            ? `<div class="result-card success">                <p class="result-heading">Continuing without auth</p>                <p>Executor resumed the source connection without stored credentials. You can close this window.</p>

Lines 1–500 of 1210.