// @bun
var B=Object.defineProperty;var D=(w)=>w;function E(w,y){this[w]=D.bind(null,y)}var G=(w,y)=>{for(var z in y)B(w,z,{get:y[z],enumerable:!0,configurable:!0,set:E.bind(y,z)})};var H=(w,y)=>()=>(w&&(y=w(w=0)),y);import A from"@contractspec/lib.ui-link";import{ChevronRight as F}from"lucide-react";import{jsx as f,jsxs as q}from"react/jsx-runtime";function N(){return q("div",{className:"space-y-8",children:[q("div",{className:"space-y-4",children:[f("h1",{className:"font-bold text-4xl",children:"Integration Spec Model"}),f("p",{className:"text-muted-foreground",children:"Integrations in ContractSpec are defined through typed specifications that declare capabilities, configuration requirements, and connection details. This page covers IntegrationSpec and IntegrationConnection."})]}),q("div",{className:"space-y-4",children:[f("h2",{className:"font-bold text-2xl",children:"IntegrationSpec"}),q("p",{className:"text-muted-foreground",children:["The ",f("strong",{children:"IntegrationSpec"})," is a global definition of an integration provider. It declares what the integration provides and what it requires."]}),f("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:f("pre",{children:`type IntegrationSpec = {
  id: string;
  label: string;
  description: string;
  category: IntegrationCategory;
  
  // Capabilities this integration provides
  providesCapabilities: {
    capabilityId: string;
    operation: string;
    description: string;
  }[];
  
  // Dependencies
  requirements: {
    capabilities?: string[];  // e.g., ["billing.core", "auth.session"]
    minVersion?: string;
  };
  
  // Configuration schema (non-secret)
  configSchema: {
    [key: string]: {
      type: string;
      description: string;
      required?: boolean;
      default?: unknown;
    };
  };
  
  // Secret schema (for keys, tokens)
  secretSchema: {
    [key: string]: {
      type: string;
      description: string;
      required: boolean;
    };
  };
  
  // Webhook support
  webhooks?: {
    supported: boolean;
    events: string[];
    signatureHeader?: string;
  };
  
  // Documentation
  docsUrl?: string;
  setupGuideUrl?: string;
  
  // Metadata
  version: string;
  createdAt: string;
  updatedAt: string;
};`})})]}),q("div",{className:"space-y-4",children:[f("h2",{className:"font-bold text-2xl",children:"Example: Stripe IntegrationSpec"}),f("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:f("pre",{children:`{
  id: "stripe",
  label: "Stripe",
  description: "Payment processing and subscription management",
  category: "payments",
  
  providesCapabilities: [
    {
      capabilityId: "payments.createPaymentIntent",
      operation: "createPaymentIntent",
      description: "Create a payment intent for checkout"
    },
    {
      capabilityId: "payments.createSubscription",
      operation: "createSubscription",
      description: "Create a recurring subscription"
    },
    {
      capabilityId: "payments.refund",
      operation: "refund",
      description: "Refund a payment"
    }
  ],
  
  requirements: {
    capabilities: ["billing.core"],
    minVersion: "1.0.0"
  },
  
  configSchema: {
    webhookUrl: {
      type: "string",
      description: "URL to receive Stripe webhooks",
      required: false
    }
  },
  
  secretSchema: {
    apiKey: {
      type: "string",
      description: "Stripe secret API key (sk_...)",
      required: true
    },
    webhookSecret: {
      type: "string",
      description: "Webhook signing secret (whsec_...)",
      required: false
    }
  },
  
  webhooks: {
    supported: true,
    events: [
      "payment_intent.succeeded",
      "payment_intent.payment_failed",
      "customer.subscription.created",
      "customer.subscription.updated",
      "customer.subscription.deleted"
    ],
    signatureHeader: "stripe-signature"
  },
  
  docsUrl: "https://docs.contractspec.com/integrations/stripe",
  setupGuideUrl: "https://stripe.com/docs/keys",
  version: "1.0.0"
}`})})]}),q("div",{className:"space-y-4",children:[f("h2",{className:"font-bold text-2xl",children:"IntegrationConnection"}),q("p",{className:"text-muted-foreground",children:["An ",f("strong",{children:"IntegrationConnection"})," is a per-tenant instance of an integration with configured credentials and environment settings."]}),f("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:f("pre",{children:`type IntegrationConnection = {
  id: string;
  tenantId: string;
  integrationId: string;
  
  // Environment
  environment: "sandbox" | "production";
  
  // Configuration (non-secret)
  config: Record<string, unknown>;
  
  // Secret reference (encrypted, never exposed)
  secretRef: string;
  
  // Status
  status: "connected" | "disconnected" | "error";
  lastHealthCheck?: string;
  lastHealthCheckStatus?: "success" | "failure";
  lastErrorMessage?: string;
  
  // Metadata
  createdAt: string;
  updatedAt: string;
  createdBy: string;
};`})})]}),q("div",{className:"space-y-4",children:[f("h2",{className:"font-bold text-2xl",children:"Example: Stripe IntegrationConnection"}),f("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:f("pre",{children:`// Production connection
{
  id: "conn_stripe_acme_prod",
  tenantId: "acme-corp",
  integrationId: "stripe",
  environment: "production",
  config: {
    webhookUrl: "https://acme.app/webhooks/stripe"
  },
  secretRef: "secret_stripe_acme_prod_v1",
  status: "connected",
  lastHealthCheck: "2025-01-15T10:30:00Z",
  lastHealthCheckStatus: "success",
  createdAt: "2025-01-01T00:00:00Z",
  updatedAt: "2025-01-15T10:30:00Z",
  createdBy: "admin@acme.com"
}

// Sandbox connection
{
  id: "conn_stripe_acme_test",
  tenantId: "acme-corp",
  integrationId: "stripe",
  environment: "sandbox",
  config: {
    webhookUrl: "https://sandbox.acme.app/webhooks/stripe"
  },
  secretRef: "secret_stripe_acme_test_v1",
  status: "connected",
  lastHealthCheck: "2025-01-15T10:25:00Z",
  lastHealthCheckStatus: "success",
  createdAt: "2025-01-01T00:00:00Z",
  updatedAt: "2025-01-15T10:25:00Z",
  createdBy: "dev@acme.com"
}`})})]}),q("div",{className:"space-y-4",children:[f("h2",{className:"font-bold text-2xl",children:"Example: Messaging IntegrationConnection"}),f("p",{className:"text-muted-foreground",children:"Messaging providers use the same spec + connection model, then route inbound events through the channel runtime for signature validation, idempotent ingestion, policy decisions, and outbox-backed dispatch."}),f("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:f("pre",{children:`{
  id: "conn_slack_acme_prod",
  tenantId: "acme-corp",
  integrationId: "messaging.slack",
  environment: "production",
  config: {
    defaultChannelId: "C0123456789",
    apiBaseUrl: "https://slack.com/api"
  },
  secretRef: "secret_slack_acme_prod_v1",
  status: "connected"
}

// secret payload behind secretRef
{
  "botToken": "xoxb-...",
  "signingSecret": "..."
}`})})]}),q("div",{className:"space-y-4",children:[f("h2",{className:"font-bold text-2xl",children:"Health transport strategy config"}),f("p",{className:"text-muted-foreground",children:"Health providers support deterministic transport routing and explicit unofficial gating in connection config."}),f("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:f("pre",{children:`{
  "defaultTransport": "official-api",
  "strategyOrder": ["official-api", "aggregator-api", "unofficial"],
  "allowUnofficial": false,
  "unofficialAllowList": ["health.peloton"],
  "mcpUrl": "https://mcp.provider.example",
  "oauthTokenUrl": "https://api.provider.example/oauth/token"
}

// secret payload behind secretRef
{
  "accessToken": "...",
  "refreshToken": "...",
  "clientId": "...",
  "clientSecret": "...",
  "tokenExpiresAt": "2026-02-01T00:00:00.000Z",
  "mcpAccessToken": "..."
}`})})]}),q("div",{className:"space-y-4",children:[f("h2",{className:"font-bold text-2xl",children:"Health checks"}),f("p",{className:"text-muted-foreground",children:"IntegrationConnections are periodically health-checked to ensure they remain valid:"}),q("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[q("li",{children:[f("strong",{children:"API key validation"})," - Test that credentials are still valid"]}),q("li",{children:[f("strong",{children:"Connectivity check"})," - Verify network access to the provider"]}),q("li",{children:[f("strong",{children:"Permission verification"})," - Ensure required scopes are granted"]}),q("li",{children:[f("strong",{children:"Webhook validation"})," - Test webhook endpoint reachability"]})]}),f("p",{className:"text-muted-foreground",children:'Failed health checks update the connection status to "error" and trigger alerts.'})]}),q("div",{className:"space-y-4",children:[f("h2",{className:"font-bold text-2xl",children:"Secret management"}),f("p",{className:"text-muted-foreground",children:"Secrets (API keys, tokens) are never stored in plaintext:"}),q("ol",{className:"list-inside list-decimal space-y-2 text-muted-foreground",children:[f("li",{children:"User provides secrets through secure UI or API"}),f("li",{children:"Secrets are encrypted using tenant-specific keys"}),f("li",{children:"Encrypted secrets are stored in secure vault (e.g., AWS Secrets Manager)"}),f("li",{children:"IntegrationConnection stores only a reference (secretRef)"}),f("li",{children:"At runtime, secrets are decrypted on-demand and never logged"})]})]}),q("div",{className:"space-y-4",children:[f("h2",{className:"font-bold text-2xl",children:"Best practices"}),q("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[f("li",{children:"Always maintain separate sandbox and production connections"}),f("li",{children:"Use descriptive connection IDs that include tenant and environment"}),f("li",{children:"Monitor health check status and set up alerts for failures"}),f("li",{children:"Rotate secrets regularly and update secretRef accordingly"}),f("li",{children:"Document the purpose and ownership of each connection"}),f("li",{children:"Test connections in sandbox before enabling in production"})]})]}),q("div",{className:"flex items-center gap-4 pt-4",children:[f(A,{href:"/docs/integrations",className:"btn-ghost",children:"Back to Integrations"}),q(A,{href:"/docs/architecture/integration-binding",className:"btn-primary",children:["Integration Binding ",f(F,{size:16})]})]})]})}export{N as IntegrationsSpecModelPage};
