335 lines · 12.6 KB
import { env } from "cloudflare:workers";
import { all, first, run } from "../db";
import { randomId, randomToken } from "../crypto";
import { badRequest, conflict, notFoundError } from "../errors";
import { githubAppConfigured } from "./github-app";
import { isGithubRepoName } from "./github-sync";
import { assertOutboundUrl, isAllowedLoopback } from "./outbound";
import { assertResolvesPublic } from "../net/resolve-guard";
import { enqueueDirect, redeliver } from "./queue";
import { requireIntegrationScope } from "./scope";
import type { ResolvedScope, ScopeRef } from "./scope";
import { insertIntegration, loadIntegration, openCredentials, parseConfig, parseEvents, updateConfig } from "./store";
import type { IntegrationConfig, IntegrationRow } from "./store";
import type { EventSummary } from "./summarize";
import { publicUrl } from "../events/emit";
import { DEFAULT_FILTERS, DEFAULT_INTEGRATION_EVENTS } from "~/lib/integrations";
import type {
  GithubMirrorDirection,
  IntegrationEvent,
  IntegrationFilters,
  IntegrationKind,
  LinearStateMapping,
  SlackChannelRoute,
} from "~/lib/integrations";
import type { Viewer } from "~/lib/types";

const DELIVERY_LOG_LIMIT = 30;
const STALE_JOB_MS = 30 * 60_000;
const JOB_LOG_LIMIT = 5;
const WEBHOOK_HOSTS: Partial<Record<IntegrationKind, string>> = {
  slack: "hooks.slack.com",
  google_chat: "chat.googleapis.com",
};

async function scopedIntegration(
  ref: ScopeRef,
  viewer: Viewer | null,
  id: string,
  mode: "read" | "write" = "write",
): Promise<{ scope: ResolvedScope; row: IntegrationRow }> {