1348 lines · 49.8 KB · TypeScript
RawDownload
/* oxlint-disable executor/no-try-catch-or-throw, executor/no-error-constructor, executor/no-instanceof-error, executor/no-unknown-error-message, executor/no-json-parse -- boundary: one-shot provider service split planner preserves the throwing dry-run contract used by migration tooling */import { createHash } from "node:crypto"; import {  googleCatalog,  googlePresetForDiscoveryUrl,} from "@executor-js/plugin-openapi/providers/google";import {  MICROSOFT_GRAPH_DEFAULT_PRESET_IDS,  microsoftCatalog,} from "@executor-js/plugin-openapi/providers/microsoft";import type { IntegrationPreset } from "@executor-js/sdk/core"; type MonolithPluginId = "google" | "microsoft"; const normalizeUrl = (url: string): string => {  const trimmed = url.trim();  if (!URL.canParse(trimmed)) return trimmed.replace(/\/$/, "");  const parsed = new URL(trimmed);  parsed.hash = "";  parsed.searchParams.sort();  return parsed.toString().replace(/\/$/, "");}; const googleCatalogByDiscoveryUrl = new Map(  googleCatalog.flatMap((preset) =>    preset.url ? [[normalizeUrl(preset.url), preset] as const] : [],  ),); const matchPattern = (pattern: string, toolId: string): boolean => {  if (pattern === "*") return true;  const patternSegments = pattern.split(".");  const toolSegments = toolId.split(".");  for (let index = 0; index < patternSegments.length; index += 1) {    const segment = patternSegments[index]!;    if (segment === "*") {      if (index === patternSegments.length - 1) return toolSegments.length >= index;      if (index >= toolSegments.length) return false;      continue;    }    if (index >= toolSegments.length || toolSegments[index] !== segment) return false;  }  return patternSegments.length === toolSegments.length;}; export type PluginId = "openapi"; export interface IntegrationRow {  readonly tenant: string;  readonly slug: string;  readonly plugin_id: string;  readonly name: string | null;  readonly description: string | null;  readonly config: unknown;  readonly health_check?: unknown;  readonly config_revised_at?: string | number | bigint | null;  readonly can_remove: boolean;  readonly can_refresh: boolean;  readonly created_at: string;  readonly updated_at: string;  readonly row_id: string;} export interface ConnectionRow {  readonly tenant: string;  readonly owner: string;  readonly subject: string;  readonly integration: string;  readonly name: string;  readonly template: string;  readonly provider: string;  readonly item_ids: unknown;  readonly identity_label: string | null;  readonly description?: string | null;  readonly last_health?: unknown;  readonly tools_synced_at?: string | number | bigint | null;  readonly oauth_client: string | null;  readonly oauth_client_owner: string | null;  readonly refresh_item_id: string | null;  readonly expires_at: string | number | bigint | null;  readonly oauth_scope: string | null;  readonly oauth_token_url?: string | null;  readonly provider_state: unknown;  readonly created_at: string;  readonly updated_at: string;  readonly row_id: string;} export interface ToolRow {  readonly tenant: string;  readonly owner: string;  readonly subject: string;  readonly integration: string;  readonly connection: string;  readonly plugin_id: string;  readonly name: string;  readonly description?: string;  readonly input_schema?: unknown;  readonly output_schema?: unknown;  readonly annotations?: unknown;  readonly created_at?: string;  readonly updated_at?: string;  readonly row_id: string;} export interface PluginStorageRow {  readonly tenant: string;  readonly owner: string;  readonly subject: string;  readonly plugin_id: string;  readonly collection: string;  readonly key: string;  readonly data: unknown;  readonly created_at: string;  readonly updated_at: string;  readonly row_id: string;} export interface BlobRow {  readonly id: string;  readonly namespace: string;  readonly key: string;} export interface ToolPolicyRow {  readonly tenant: string;  readonly owner: string;  readonly subject: string;  readonly id: string;  readonly pattern: string;  readonly action: string;  readonly position: string;  readonly created_at: string;  readonly updated_at: string;  readonly row_id: string;} export interface MigrationInput {  readonly integrations: readonly IntegrationRow[];  readonly connections: readonly ConnectionRow[];  readonly tools: readonly ToolRow[];  readonly pluginStorage?: readonly PluginStorageRow[];  readonly blobs?: readonly BlobRow[];  readonly policies: readonly ToolPolicyRow[];  readonly completedTenants?: readonly string[];  readonly trafficLastTenant?: string;  readonly collectPolicyErrors?: boolean;  readonly orphanPolicyMode?: "hard_error" | "retarget_all";  readonly blobBackend?: "database" | "external";  readonly assumeExternalBlobSourcePresent?: boolean;  readonly bootRailCreateToolImpliedServices?: boolean;} export interface ServiceTarget {  readonly family: MonolithPluginId;  readonly pluginId: PluginId;  readonly presetId: string;  readonly slug: string;  readonly name: string;  readonly description: string;  readonly specUrl?: string;  readonly specFormat: "google-discovery" | "microsoft-graph";  readonly authenticationTemplate?: readonly unknown[];  readonly healthCheck?: unknown;} export interface PlannedIntegration {  readonly source: Pick<IntegrationRow, "tenant" | "slug" | "plugin_id" | "name">;  readonly sourceContributions: readonly {    readonly source: IntegrationRow;    readonly specHash?: string;    readonly operationsToBuild: number;    readonly operationToolNames: readonly string[];    readonly specBlobPresent: boolean;    readonly defsBlobPresent: boolean;  }[];  readonly target: ServiceTarget;  readonly action: "create" | "skip_existing";  readonly config: unknown;  readonly healthCheck?: unknown;  readonly servingState: {    readonly specHash?: string;    readonly specSource: string;    readonly blobBackend: "database" | "external";    readonly specBlobPresent: boolean;    readonly defsBlobPresent: boolean;    readonly operationsToBuild: number;    readonly operationToolNames: readonly string[];    readonly expectedZeroOperations: boolean;  };} export interface PlannedBlobCopy {  readonly source: Pick<IntegrationRow, "tenant" | "slug" | "plugin_id">;  readonly specHash: string;  readonly key: string;  readonly sourceNamespace: string;  readonly targetNamespace: string;  readonly backend: "database" | "external";  readonly sourcePresent: boolean;  readonly targetPresent: boolean;  readonly sourceObjectName: string;  readonly targetObjectName: string;} export interface PlannedConnection {  readonly source: Pick<ConnectionRow, "tenant" | "owner" | "subject" | "integration" | "name">;  readonly targetIntegration: string;  readonly action: "clone" | "skip_existing";  readonly tokenReuse: "copy_item_ids_and_oauth_columns";} export interface PlannedPolicyRewrite {  readonly policy: Pick<    ToolPolicyRow,    "tenant" | "owner" | "subject" | "id" | "pattern" | "action" | "position"  >;  readonly action: "rewrite";  readonly afterPatterns: readonly string[];  readonly matchedServices: readonly string[];} export interface OrgPlan {  readonly tenant: string;  readonly tenantHash: string;  readonly completed: boolean;  readonly integrations: readonly PlannedIntegration[];  readonly connections: readonly PlannedConnection[];  readonly policies: readonly PlannedPolicyRewrite[];  readonly blobCopies: readonly PlannedBlobCopy[];  readonly deleteMonoliths: readonly Pick<    IntegrationRow,    "tenant" | "slug" | "plugin_id" | "name"  >[];  readonly clonedToolRows: number;  readonly operationsToBuild: number;  readonly hardErrors: readonly string[];} export interface MigrationPlan {  readonly orgs: readonly OrgPlan[];  readonly summary: {    readonly orgs: number;    readonly completedOrgs: number;    readonly integrationsCreate: number;    readonly integrationsSkipExisting: number;    readonly connectionsClone: number;    readonly connectionsSkipExisting: number;    readonly policiesRewrite: number;    readonly policiesSkip: number;    readonly policyRowsAfter: number;    readonly monolithDeletes: number;    readonly clonedToolRows: number;    readonly operationsToBuild: number;    readonly integrationsMissingSpecBlob: number;    readonly integrationsMissingDefsBlob: number;    readonly hardErrorOrgs: number;    readonly policyHardErrors: number;  };} const GOOGLE_IDENTITY_DISCOVERY_URL = "https://www.googleapis.com/discovery/v1/apis/oauth2/v2/rest"; const GOOGLE_TOOL_PREFIX_TO_PRESET_ID: ReadonlyMap<string, string> = new Map([  ["calendar", "google-calendar"],  ["meet", "google-meet"],  ["gmail", "google-gmail"],  ["sheets", "google-sheets"],  ["drive", "google-drive"],  ["docs", "google-docs"],  ["slides", "google-slides"],  ["forms", "google-forms"],  ["tasks", "google-tasks"],  ["people", "google-people"],  ["photoslibrary", "google-photos-library"],  ["photospicker", "google-photos-picker"],  ["chat", "google-chat"],  ["keep", "google-keep"],  ["youtube", "google-youtube-data"],  ["searchconsole", "google-search-console"],  ["webmasters", "google-search-console"],  ["classroom", "google-classroom"],  ["directory", "google-admin-directory"],  ["reports", "google-admin-reports"],  ["script", "google-apps-script"],  ["bigquery", "google-bigquery"],  ["cloudresourcemanager", "google-cloud-resource-manager"],]); const unique = <T>(values: Iterable<T>): readonly T[] => [...new Set(values)]; export const tenantHash = (tenant: string): string =>  createHash("sha256").update(tenant).digest("hex").slice(0, 12); const isRecord = (value: unknown): value is Record<string, unknown> =>  typeof value === "object" && value !== null && !Array.isArray(value); const recordFromJsonLike = (value: unknown): Record<string, unknown> => {  if (isRecord(value)) return value;  if (typeof value !== "string") return {};  try {    const parsed = JSON.parse(value) as unknown;    return isRecord(parsed) ? parsed : {};  } catch {    return {};  }}; const stringArray = (value: unknown): readonly string[] =>  Array.isArray(value) ? value.filter((item): item is string => typeof item === "string") : []; const configRecord = (integration: IntegrationRow): Record<string, unknown> =>  recordFromJsonLike(integration.config); const toolAddress = (  tool: Pick<ToolRow, "integration" | "owner" | "connection" | "name">,): string => `${tool.integration}.${tool.owner}.${tool.connection}.${tool.name}`; const withoutToolsPrefix = (pattern: string): string =>  pattern.startsWith("tools.") ? pattern.slice("tools.".length) : pattern; const withOriginalToolsPrefix = (original: string, rewrittenTail: string): string =>  original.startsWith("tools.") ? `tools.${rewrittenTail}` : rewrittenTail; const integrationPatternSegment = (  pattern: string,): { readonly prefix: boolean; readonly integration: string } => {  const prefix = pattern.startsWith("tools.");  const tail = prefix ? pattern.slice("tools.".length) : pattern;  return { prefix, integration: tail.split(".")[0] ?? "" };}; const googleCatalogById: ReadonlyMap<string, IntegrationPreset> = new Map(  googleCatalog.map((preset) => [preset.id, preset]),); const microsoftCatalogByMonolithPresetId: ReadonlyMap<string, IntegrationPreset> = new Map(  microsoftCatalog.map((preset) => [preset.id.replace(/^microsoft-/, ""), preset]),); const MICROSOFT_UNMIGRATABLE_UMBRELLA_PRESET_IDS = new Set(["me-surface", "users", "groups"]);const MICROSOFT_TOOL_IMPLIED_PRESET_IDS = new Set(MICROSOFT_GRAPH_DEFAULT_PRESET_IDS);const microsoftCatalogBackedPresetIds = new Set(  microsoftCatalog    .filter((preset) => preset.defaultSlug && preset.defaultSlug.length > 0)    .map((preset) => preset.id.replace(/^microsoft-/, "")),); export const microsoftToolFirstSegmentPresetIds: ReadonlyMap<string, readonly string[]> = new Map([  ["chats", ["teams-chat"]],  ["chatsChat", ["teams-chat"]],  ["communications", ["meetings-calls"]],  ["communicationsCall", ["meetings-calls"]],  ["communicationsOnlineMeeting", ["meetings-calls"]],  ["communicationsPresence", ["meetings-calls"]],  ["drives", ["files"]],  ["drivesDrive", ["files"]],  ["drivesDriveItem", ["files"]],  ["groupsDrive", ["files"]],  ["groupsDrives", ["files"]],  ["groupsOnenote", ["onenote"]],  ["groupsTeam", ["teams-channels"]],  ["meCalendar", ["calendar"]],  ["meCalendarGroups", ["calendar"]],  ["meCalendars", ["calendar"]],  ["meCalendarView", ["calendar"]],  ["meChat", ["teams-chat"]],  ["meChats", ["teams-chat"]],  ["meContact", ["contacts"]],  ["meContactFolder", ["contacts"]],  ["meContactFolders", ["contacts"]],  ["meContacts", ["contacts"]],  ["meDrive", ["files"]],  ["meDrives", ["files"]],  ["meEvent", ["calendar"]],  ["meEvents", ["calendar"]],  ["meFindMeetingTimes", ["calendar"]],  ["meFollowedSites", ["files"]],  ["meGetMailTips", ["mail"]],  ["meInferenceClassification", ["mail"]],  ["meJoinedTeams", ["teams-channels"]],  ["meMailFolder", ["mail"]],  ["meMailFolders", ["mail"]],  ["meMailboxSettings", ["mail"]],  ["meMessage", ["mail"]],  ["meMessages", ["mail"]],  ["meOnlineMeeting", ["meetings-calls"]],  ["meOnlineMeetings", ["meetings-calls"]],  ["meOnenote", ["onenote"]],  ["meOutlook", ["mail"]],  ["meOutlookUser", ["mail"]],  ["mePeople", ["contacts"]],  ["mePerson", ["contacts"]],  ["mePhoto", ["profile"]],  ["meProfilePhoto", ["profile"]],  ["meReminderView", ["calendar"]],  ["meSendMail", ["mail"]],  ["meSite", ["files"]],  ["meTeam", ["teams-channels"]],  ["meTodo", ["tasks"]],  ["meUser", ["profile"]],  ["meUserActions", ["profile"]],  ["meUserFunctions", ["profile"]],  ["shares", ["files"]],  ["sites", ["sites"]],  ["sitesOnenote", ["onenote"]],  ["sitesSite", ["sites"]],  ["teams", ["teams-channels"]],  ["teamsChannel", ["teams-channels"]],  ["teamsTeam", ["teams-channels"]],  ["teamsTemplates", ["teams-channels"]],  ["teamwork", ["teams-channels"]],  ["usersCalendar", ["calendar"]],  ["usersCalendarGroups", ["calendar"]],  ["usersCalendars", ["calendar"]],  ["usersCalendarView", ["calendar"]],  ["usersContact", ["contacts"]],  ["usersContactFolder", ["contacts"]],  ["usersContactFolders", ["contacts"]],  ["usersContacts", ["contacts"]],  ["usersDrive", ["files"]],  ["usersDrives", ["files"]],  ["usersEvent", ["calendar"]],  ["usersEvents", ["calendar"]],  ["usersFindMeetingTimes", ["calendar"]],  ["usersMailFolder", ["mail"]],  ["usersMailFolders", ["mail"]],  ["usersMessage", ["mail"]],  ["usersMessages", ["mail"]],  ["usersOnlineMeeting", ["meetings-calls"]],  ["usersOnlineMeetings", ["meetings-calls"]],  ["usersOnenote", ["onenote"]],  ["usersOutlook", ["mail"]],  ["usersPeople", ["contacts"]],  ["usersPerson", ["contacts"]],  ["usersReminderView", ["calendar"]],  ["usersSendMail", ["mail"]],  ["usersTodo", ["tasks"]],  ["usersUser", ["profile"]],  ["usersUserActions", ["profile"]],  ["usersUserFunctions", ["profile"]],]); const MICROSOFT_WORKBOOK_FIRST_SEGMENTS = new Set([  "drivesDriveItem",  "groupsDrive",  "meDrive",  "usersDrive",]); const microsoftFirstSegmentOwnershipKey = (firstSegment: string): string | undefined =>  [...microsoftToolFirstSegmentPresetIds.keys()]    .filter(      (key) =>        firstSegment === key ||        (firstSegment.startsWith(key) &&          firstSegment[key.length]?.toUpperCase() === firstSegment[key.length]),    )    .sort((left, right) => right.length - left.length)[0]; const serviceSlugForPreset = (family: MonolithPluginId, presetId: string): string | undefined => {  const preset =    family === "google"      ? googleCatalogById.get(presetId)      : microsoftCatalogByMonolithPresetId.get(presetId);  return preset?.defaultSlug;}; const serviceTargetForPreset = (  family: MonolithPluginId,  presetId: string,): ServiceTarget | undefined => {  if (family === "google") {    const preset = googleCatalogById.get(presetId);    if (!preset) return undefined;    return {      family,      pluginId: "openapi",      presetId,      slug: preset.defaultSlug ?? preset.id,      name: preset.name,      description: preset.summary,      ...(preset.url ? { specUrl: preset.url } : {}),      specFormat: "google-discovery",      ...(preset.authTemplate ? { authenticationTemplate: preset.authTemplate } : {}),      ...(preset.healthCheck ? { healthCheck: preset.healthCheck } : {}),    };  }  const preset = microsoftCatalogByMonolithPresetId.get(presetId);  if (!preset) return undefined;  return {    family,    pluginId: "openapi",    presetId,    slug: preset.defaultSlug ?? preset.id,    name: preset.name,    description: preset.summary,    ...(preset.url ? { specUrl: preset.url } : {}),    specFormat: "microsoft-graph",

Lines 1–500 of 1348.