// --------------------------------------------------------------------------- // GraphQL ↔ generic auth-method converters. // // The generic Accounts hub + add-time auth editor speak in plugin-agnostic // `AuthMethod` / `Placement` values (`@executor-js/react/lib/auth-placements`). // The GraphQL plugin stores auth as its own `AuthTemplate` wire shape // (`{ kind:"apiKey", slug, in, name, prefix? }` / `{ kind:"oauth2", slug, … }`). // These converters bridge that wire shape to/from the generic placement model, // so they live with the GraphQL plugin — they touch the graphql sdk // `AuthTemplate` types and would pull transport specifics into core. // --------------------------------------------------------------------------- import { AuthTemplateSlug } from "@executor-js/sdk/shared"; import type { AuthMethod, Placement } from "@executor-js/react/lib/auth-placements"; import { GRAPHQL_APIKEY_TEMPLATE } from "./defaults"; import type { AuthTemplate } from "../sdk/types"; // --------------------------------------------------------------------------- // Templates → generic methods. // --------------------------------------------------------------------------- const labelForApiKey = (slug: string, name: string): string => `API key (${name || slug})`; /** Map each stored GraphQL auth template to a generic `AuthMethod`. A `custom_` * slug marks a user-defined method; everything else is spec-declared. */ export function authMethodsFromConfig(templates: readonly AuthTemplate[]): AuthMethod[] { return templates.map((template: AuthTemplate): AuthMethod => { const slug = String(template.slug); const source: "spec" | "custom" = slug.startsWith("custom_") ? "custom" : "spec"; if (template.kind === "oauth2") { return { id: slug, label: "OAuth2", kind: "oauth", source, template: AuthTemplateSlug.make(slug), placements: [], oauth: {}, }; } const placement: Placement = { carrier: template.in, name: template.name, prefix: template.prefix ?? "", }; return { id: slug, label: labelForApiKey(slug, template.name), kind: "apikey", source, template: AuthTemplateSlug.make(slug), placements: [placement], }; }); } // --------------------------------------------------------------------------- // Generic placements → graphql apiKey templates (inverse). // // GraphQL's `AuthTemplate` carries ONE header/query slot per template, so a // multi-placement method emits one template per named placement. When `slug` is // omitted the backend backfills `custom_`; the first template keeps the // integration's primary `apiKey` slug so the add flow stays stable. // --------------------------------------------------------------------------- /** Build GraphQL `apiKey` templates from generic placements. The optional * `slug` names the FIRST emitted template (subsequent placements get an empty * slug so the backend assigns a `custom_` each). */ export function graphqlTemplatesFromPlacements( placements: readonly Placement[], slug?: string, ): AuthTemplate[] { const named = placements.filter((placement: Placement) => placement.name.trim().length > 0); return named.map( (placement: Placement, index: number): AuthTemplate => ({ kind: "apiKey", slug: index === 0 ? (slug ?? GRAPHQL_APIKEY_TEMPLATE) : "", in: placement.carrier, name: placement.name, ...(placement.prefix ? { prefix: placement.prefix } : {}), }), ); }