@tangle-network/agent-integrations 0.61.2 → 0.63.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"specs-ElJzHwc7.js","names":[],"sources":["../src/specs/families.ts","../src/specs/overrides.ts","../src/specs/registry.ts","../src/specs/types.ts","../src/specs/renderers.ts","../src/specs/validation.ts"],"sourcesContent":["import type { IntegrationFamilyId, IntegrationFamilySpec } from './types.js'\n\nexport const INTEGRATION_FAMILIES: Record<IntegrationFamilyId, IntegrationFamilySpec> = {\n google: {\n id: 'google',\n title: 'Google OAuth',\n authMode: 'oauth2',\n consoleUrl: 'https://console.cloud.google.com/apis/credentials',\n authorizationUrl: 'https://accounts.google.com/o/oauth2/v2/auth',\n tokenUrl: 'https://oauth2.googleapis.com/token',\n redirectUriTemplate: 'https://{host}/api/integrations/oauth/google/callback',\n credentialFields: [\n { label: 'Client ID', env: 'GOOGLE_OAUTH_CLIENT_ID', description: 'Google OAuth client ID.', example: '1234567890-abc.apps.googleusercontent.com', regex: '^[0-9]+-[a-zA-Z0-9_-]+\\\\.apps\\\\.googleusercontent\\\\.com$', secret: false },\n { label: 'Client Secret', env: 'GOOGLE_OAUTH_CLIENT_SECRET', description: 'Google OAuth client secret.', example: 'GOCSPX-...', secret: true },\n ],\n consoleSteps: [\n { id: 'project', title: 'Select project', detail: 'Open Google Cloud Console and select the project that owns the OAuth client.' },\n { id: 'consent', title: 'Configure consent screen', detail: 'Configure OAuth consent, app name, support email, and publishing status appropriate for the deployment.' },\n { id: 'client', title: 'Create web client', detail: 'Create an OAuth client of type Web application.' },\n { id: 'redirect', title: 'Add redirect URI', detail: 'Add {redirectUri} as an authorized redirect URI.', copyValue: '{redirectUri}' },\n { id: 'scopes', title: 'Add scopes', detail: 'Add the provider scopes listed in this spec.' },\n ],\n knownQuirks: [\n { id: 'offline-access', severity: 'warning', message: 'Use access_type=offline and prompt=consent when refresh tokens are required.' },\n { id: 'verification', severity: 'warning', message: 'Sensitive or restricted scopes may require Google verification before broad external use.' },\n ],\n lifecycle: { supportsRefresh: true, supportsRevoke: true, supportsIncrementalAuth: true, recommendedHealthcheckIntervalHours: 24 },\n },\n 'microsoft-graph': {\n id: 'microsoft-graph',\n title: 'Microsoft Graph OAuth',\n authMode: 'oauth2',\n consoleUrl: 'https://entra.microsoft.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade',\n authorizationUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',\n tokenUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',\n redirectUriTemplate: 'https://{host}/api/integrations/oauth/microsoft/callback',\n credentialFields: [\n { label: 'Client ID', env: 'MS_OAUTH_CLIENT_ID', description: 'Microsoft Entra application client ID.', example: '00000000-0000-0000-0000-000000000000', regex: '^[0-9a-fA-F-]{36}$', secret: false },\n { label: 'Client Secret', env: 'MS_OAUTH_CLIENT_SECRET', description: 'Microsoft Entra client secret value.', secret: true },\n ],\n consoleSteps: [\n { id: 'app', title: 'Register app', detail: 'Create or open an app registration in Microsoft Entra.' },\n { id: 'redirect', title: 'Add redirect URI', detail: 'Add {redirectUri} as a Web redirect URI.', copyValue: '{redirectUri}' },\n { id: 'secret', title: 'Create secret', detail: 'Create a client secret and store the secret value, not the secret ID.' },\n { id: 'permissions', title: 'Add Graph permissions', detail: 'Add the delegated Graph scopes listed in this spec and grant admin consent where required.' },\n ],\n knownQuirks: [\n { id: 'tenant-common', severity: 'info', message: 'The common tenant supports multi-tenant OAuth; single-tenant deployments should override the tenant segment.' },\n { id: 'admin-consent', severity: 'warning', message: 'Some Graph scopes require tenant admin consent.' },\n ],\n lifecycle: { supportsRefresh: true, supportsRevoke: true, supportsIncrementalAuth: true, recommendedHealthcheckIntervalHours: 24 },\n },\n atlassian: {\n id: 'atlassian',\n title: 'Atlassian OAuth',\n authMode: 'oauth2',\n consoleUrl: 'https://developer.atlassian.com/console/myapps/',\n authorizationUrl: 'https://auth.atlassian.com/authorize',\n tokenUrl: 'https://auth.atlassian.com/oauth/token',\n redirectUriTemplate: 'https://{host}/api/integrations/oauth/atlassian/callback',\n credentialFields: [\n { label: 'Client ID', description: 'Atlassian OAuth client ID.', secret: false },\n { label: 'Client Secret', description: 'Atlassian OAuth client secret.', secret: true },\n ],\n consoleSteps: [\n { id: 'app', title: 'Create OAuth app', detail: 'Create an OAuth 2.0 app in the Atlassian developer console.' },\n { id: 'redirect', title: 'Add callback URL', detail: 'Add {redirectUri} as the callback URL.', copyValue: '{redirectUri}' },\n { id: 'apis', title: 'Enable APIs', detail: 'Enable the Jira or Confluence APIs required by this connector.' },\n ],\n lifecycle: { supportsRefresh: true, supportsRevoke: false, supportsIncrementalAuth: false, recommendedHealthcheckIntervalHours: 24 },\n },\n salesforce: {\n id: 'salesforce',\n title: 'Salesforce OAuth',\n authMode: 'oauth2',\n consoleUrl: 'https://login.salesforce.com',\n authorizationUrl: 'https://login.salesforce.com/services/oauth2/authorize',\n tokenUrl: 'https://login.salesforce.com/services/oauth2/token',\n redirectUriTemplate: 'https://{host}/api/integrations/oauth/salesforce/callback',\n credentialFields: [\n { label: 'Client ID', env: 'SALESFORCE_OAUTH_CLIENT_ID', description: 'Salesforce connected app consumer key.', secret: false },\n { label: 'Client Secret', env: 'SALESFORCE_OAUTH_CLIENT_SECRET', description: 'Salesforce connected app consumer secret.', secret: true },\n ],\n consoleSteps: [\n { id: 'connected-app', title: 'Create connected app', detail: 'Create a Salesforce connected app with OAuth enabled.' },\n { id: 'callback', title: 'Add callback URL', detail: 'Add {redirectUri} as the callback URL.', copyValue: '{redirectUri}' },\n { id: 'scopes', title: 'Select scopes', detail: 'Add api and refresh_token/offline_access, plus any connector-specific scopes.' },\n ],\n knownQuirks: [\n { id: 'instance-url', severity: 'critical', message: 'Runtime calls must use the instance_url returned by the token response.' },\n ],\n lifecycle: { supportsRefresh: true, supportsRevoke: true, supportsIncrementalAuth: false, recommendedHealthcheckIntervalHours: 24 },\n },\n hubspot: {\n id: 'hubspot',\n title: 'HubSpot OAuth',\n authMode: 'oauth2',\n consoleUrl: 'https://developers.hubspot.com/',\n authorizationUrl: 'https://app.hubspot.com/oauth/authorize',\n tokenUrl: 'https://api.hubapi.com/oauth/v1/token',\n redirectUriTemplate: 'https://{host}/api/integrations/oauth/hubspot/callback',\n credentialFields: [\n { label: 'Client ID', env: 'HUBSPOT_OAUTH_CLIENT_ID', description: 'HubSpot app client ID.', secret: false },\n { label: 'Client Secret', env: 'HUBSPOT_OAUTH_CLIENT_SECRET', description: 'HubSpot app client secret.', secret: true },\n ],\n consoleSteps: [\n { id: 'app', title: 'Create private/public app', detail: 'Create a HubSpot app and configure OAuth.' },\n { id: 'redirect', title: 'Add redirect URL', detail: 'Add {redirectUri} to the app redirect URLs.', copyValue: '{redirectUri}' },\n { id: 'scopes', title: 'Add CRM scopes', detail: 'Add the CRM object scopes listed in this spec.' },\n ],\n lifecycle: { supportsRefresh: true, supportsRevoke: true, supportsIncrementalAuth: false, recommendedHealthcheckIntervalHours: 24 },\n },\n slack: {\n id: 'slack',\n title: 'Slack OAuth',\n authMode: 'oauth2',\n consoleUrl: 'https://api.slack.com/apps',\n authorizationUrl: 'https://slack.com/oauth/v2/authorize',\n tokenUrl: 'https://slack.com/api/oauth.v2.access',\n redirectUriTemplate: 'https://{host}/api/integrations/oauth/slack/callback',\n credentialFields: [\n { label: 'Client ID', env: 'SLACK_OAUTH_CLIENT_ID', description: 'Slack app client ID.', secret: false },\n { label: 'Client Secret', env: 'SLACK_OAUTH_CLIENT_SECRET', description: 'Slack app client secret.', secret: true },\n ],\n consoleSteps: [\n { id: 'app', title: 'Create Slack app', detail: 'Create or open a Slack app.' },\n { id: 'redirect', title: 'Add redirect URL', detail: 'Add {redirectUri} under OAuth & Permissions.', copyValue: '{redirectUri}' },\n { id: 'scopes', title: 'Add bot scopes', detail: 'Add the bot token scopes listed in this spec and reinstall the app.' },\n ],\n knownQuirks: [\n { id: 'bot-token', severity: 'info', message: 'Slack usually returns a bot access token; refresh tokens require token rotation.' },\n ],\n lifecycle: { supportsRefresh: false, supportsRevoke: true, supportsIncrementalAuth: false, recommendedHealthcheckIntervalHours: 24 },\n },\n notion: {\n id: 'notion',\n title: 'Notion OAuth',\n authMode: 'oauth2',\n consoleUrl: 'https://www.notion.so/my-integrations',\n authorizationUrl: 'https://api.notion.com/v1/oauth/authorize',\n tokenUrl: 'https://api.notion.com/v1/oauth/token',\n redirectUriTemplate: 'https://{host}/api/integrations/oauth/notion/callback',\n credentialFields: [\n { label: 'Client ID', env: 'NOTION_OAUTH_CLIENT_ID', description: 'Notion integration OAuth client ID.', secret: false },\n { label: 'Client Secret', env: 'NOTION_OAUTH_CLIENT_SECRET', description: 'Notion integration OAuth client secret.', secret: true },\n ],\n consoleSteps: [\n { id: 'integration', title: 'Create integration', detail: 'Create a Notion public integration.' },\n { id: 'redirect', title: 'Add redirect URI', detail: 'Add {redirectUri} as the redirect URI.', copyValue: '{redirectUri}' },\n { id: 'capabilities', title: 'Select capabilities', detail: 'Enable read/update/insert capabilities matching this connector.' },\n ],\n lifecycle: { supportsRefresh: true, supportsRevoke: true, supportsIncrementalAuth: false, recommendedHealthcheckIntervalHours: 24 },\n },\n 'standard-oauth2': {\n id: 'standard-oauth2',\n title: 'Standard OAuth 2.0',\n authMode: 'oauth2',\n redirectUriTemplate: 'https://{host}/api/integrations/oauth/{kind}/callback',\n credentialFields: [\n { label: 'Client ID', description: 'OAuth client ID.', secret: false },\n { label: 'Client Secret', description: 'OAuth client secret.', secret: true },\n ],\n consoleSteps: [\n { id: 'app', title: 'Create OAuth app', detail: 'Create an OAuth app in the provider console.' },\n { id: 'redirect', title: 'Add redirect URI', detail: 'Add {redirectUri} as an allowed redirect URI.', copyValue: '{redirectUri}' },\n { id: 'scopes', title: 'Add scopes', detail: 'Add the scopes listed in this spec.' },\n ],\n lifecycle: { supportsRefresh: true, supportsRevoke: false, supportsIncrementalAuth: false, recommendedHealthcheckIntervalHours: 24 },\n },\n 'api-key': {\n id: 'api-key',\n title: 'API key',\n authMode: 'api_key',\n credentialFields: [\n { label: 'API Key', description: 'Provider API key or token.', example: 'sk_...', secret: true },\n ],\n consoleSteps: [\n { id: 'token', title: 'Create token', detail: 'Create an API key/token in the provider console with the minimum required permissions.' },\n ],\n lifecycle: { supportsRefresh: false, supportsRevoke: true, supportsIncrementalAuth: false, recommendedHealthcheckIntervalHours: 24 },\n },\n hmac: {\n id: 'hmac',\n title: 'HMAC secret',\n authMode: 'hmac',\n credentialFields: [\n { label: 'Signing Secret', description: 'Webhook signing secret.', secret: true },\n ],\n consoleSteps: [\n { id: 'secret', title: 'Configure signing secret', detail: 'Configure the shared signing secret in the sender and receiver.' },\n ],\n lifecycle: { supportsRefresh: false, supportsRevoke: true, supportsIncrementalAuth: false, recommendedHealthcheckIntervalHours: 24 },\n },\n none: {\n id: 'none',\n title: 'No authentication',\n authMode: 'none',\n credentialFields: [],\n consoleSteps: [\n { id: 'configure', title: 'Configure endpoint', detail: 'No provider credentials are required.' },\n ],\n lifecycle: { supportsRefresh: false, supportsRevoke: false, supportsIncrementalAuth: false },\n },\n}\n\nexport function getIntegrationFamily(id: IntegrationFamilyId): IntegrationFamilySpec {\n return INTEGRATION_FAMILIES[id]\n}\n","/**\n * Per-kind overrides on top of family defaults.\n *\n * The family layer (`families.ts`) carries the auth-shape defaults — generic\n * \"API Key\" or \"Client ID + Client Secret\" credential fields, generic console\n * steps. Most kinds are happy with that. But some have provider-specific\n * shape that the family can't capture: Twilio's auth is two-part (Account\n * SID + Auth Token); Stripe's preferred path is restricted keys with specific\n * granted permissions; SendGrid demands a verified sender domain in the\n * console before keys work.\n *\n * `INTEGRATION_OVERRIDES` is the seam for that. The registry merges the\n * override on top of the family defaults at spec-build time. Override\n * fields are purely additive — set what you want to customize, leave the\n * rest absent and the family defaults apply.\n *\n * Adding a new override:\n * 1. Author the override entry below.\n * 2. The next spec build picks it up automatically; no other registry\n * change needed. Coverage catalog stays compact.\n *\n * Why a separate map and not inline on `IntegrationCoverageSpec`: the\n * coverage catalog is a flat tuple list optimized for fast iteration over\n * 142 specs. Bloating the tuple with optional override fields hurts\n * readability of the catalog AND scatters provider knowledge across two\n * data shapes. Keeping overrides in their own keyed map means contributors\n * looking for \"how does Stripe credential setup work\" find it in one place.\n */\n\nimport type {\n ConsoleStep,\n CredentialFieldSpec,\n HealthcheckSpec,\n PostSetupCheck,\n Quirk,\n} from './types.js'\n\nexport interface IntegrationOverride {\n /** Replaces `setup.consoleUrl` from the family default. */\n consoleUrl?: string\n /** Replaces `setup.consoleSteps`. Specify the full list — overrides do\n * not deep-merge step arrays because step ordering is meaningful. */\n consoleSteps?: ConsoleStep[]\n /** Replaces `setup.credentialFields`. Use to add a second field (e.g.\n * Twilio Account SID + Auth Token), tighten validation regex, or\n * enrich field descriptions with provider-specific guidance. */\n credentialFields?: CredentialFieldSpec[]\n /** Appended to `setup.knownQuirks`. */\n knownQuirks?: Quirk[]\n /** Replaces `setup.postSetup`. */\n postSetup?: PostSetupCheck[]\n /** Replaces the healthcheck the registry would otherwise infer. */\n healthcheck?: HealthcheckSpec\n}\n\nexport const INTEGRATION_OVERRIDES: Record<string, IntegrationOverride> = {\n tiktok: {\n consoleUrl: 'https://developers.tiktok.com/apps/',\n consoleSteps: [\n {\n id: 'app',\n title: 'Create or select the TikTok app',\n detail: 'Use one company-owned TikTok for Developers app for Tangle Integration Hub. Do not create a duplicate app.',\n },\n {\n id: 'products',\n title: 'Enable Login Kit and Content Posting',\n detail: 'Enable Login Kit, Content Posting API, and the user.info.basic, video.list, and video.publish scopes.',\n },\n {\n id: 'redirect',\n title: 'Register the callback',\n detail: 'Add {redirectUri} as an exact HTTPS web redirect URI.',\n copyValue: '{redirectUri}',\n },\n {\n id: 'urls',\n title: 'Verify publishing URLs',\n detail: 'Verify every HTTPS domain or URL prefix TikTok may pull videos and photos from.',\n },\n {\n id: 'test',\n title: 'Test a private post',\n detail: 'Connect a test creator, read creator information, publish private test media, and poll the publish id until completion.',\n },\n ],\n knownQuirks: [\n {\n id: 'private-until-audit',\n severity: 'critical',\n message: 'TikTok restricts unaudited Content Posting clients to private posts. Public visibility requires TikTok app review.',\n },\n {\n id: 'verified-pull-url',\n severity: 'critical',\n message: 'Direct posts can pull media only from an HTTPS domain or URL prefix verified for this TikTok app.',\n },\n {\n id: 'creator-preflight',\n severity: 'warning',\n message: 'TikTok requires current creator options before each direct post. The adapter performs this preflight and rejects unavailable privacy or duration choices.',\n },\n {\n id: 'token-lifetime',\n severity: 'info',\n message: 'Access tokens last about 24 hours. Refresh tokens last about 365 days and may rotate on refresh.',\n },\n ],\n postSetup: [\n {\n id: 'tiktok.private-publish',\n title: 'Prove one private direct post',\n detail: 'Publish media from a verified URL and poll the returned publish id until TikTok reports PUBLISH_COMPLETE.',\n },\n {\n id: 'tiktok.refresh',\n title: 'Prove token refresh',\n detail: 'Refresh the short-lived access token and preserve TikTok’s newly returned refresh token.',\n },\n ],\n healthcheck: {\n id: 'tiktok.user.info',\n level: 'connection',\n description: 'Read the connected TikTok account with user.info.basic.',\n },\n },\n amplitude: {\n consoleUrl: 'https://analytics.amplitude.com/',\n credentialFields: [\n {\n label: 'Amplitude project credential JSON',\n description: 'JSON containing the API key and secret key for one Amplitude project.',\n example: '{\"apiKey\":\"...\",\"secretKey\":\"...\"}',\n secret: true,\n },\n ],\n consoleSteps: [\n {\n id: 'project',\n title: 'Select one Amplitude project',\n detail: 'Open Project Settings > General for the project that Tangle may access.',\n },\n {\n id: 'credentials',\n title: 'Copy the project credentials',\n detail: 'Copy the API key and secret key into one JSON credential bundle.',\n },\n {\n id: 'region',\n title: 'Set the data region',\n detail: 'Use the default US host. Set apiBaseUrl to the documented EU host only for an EU project.',\n },\n {\n id: 'test',\n title: 'Test the project connection',\n detail: 'The connection check lists visible project events without changing analytics data.',\n },\n ],\n knownQuirks: [\n {\n id: 'project-bound',\n severity: 'warning',\n message: 'The API key and secret key belong to one project. Use a separate connection for each project.',\n },\n {\n id: 'region-bound',\n severity: 'critical',\n message: 'US and EU projects use different hosts. Tangle accepts only the two official Amplitude API hosts.',\n },\n {\n id: 'annotation-authority',\n severity: 'warning',\n message: 'Annotation changes require suitable Amplitude authority and remain approval-gated.',\n },\n ],\n healthcheck: {\n id: 'amplitude.connection',\n level: 'connection',\n description: 'Authenticate with the project credential pair and list visible events.',\n },\n },\n cloudflare: {\n consoleUrl: 'https://dash.cloudflare.com/profile/api-tokens/',\n credentialFields: [\n {\n label: 'Dedicated Cloudflare API token',\n description: 'Create a new resource-scoped token for Tangle Integration Hub. Do not reuse an infrastructure token.',\n secret: true,\n },\n ],\n consoleSteps: [\n {\n id: 'token',\n title: 'Create a dedicated API token',\n detail: 'Create a custom token named Tangle Integration Hub. Do not use the legacy Global API Key.',\n },\n {\n id: 'permissions',\n title: 'Grant narrow permissions',\n detail: 'Grant Account Settings Read, Zone Read, Zone Settings Read, and DNS Read or DNS Edit only.',\n },\n {\n id: 'resources',\n title: 'Limit the token to selected zones',\n detail: 'Include only the accounts and zones that this connection must manage.',\n },\n {\n id: 'store',\n title: 'Store the one-time token',\n detail: 'Copy the token once. Tangle Hub seals it before persistence.',\n },\n {\n id: 'test',\n title: 'Verify token status',\n detail: 'The connection check calls the token verification endpoint and requires active status.',\n },\n ],\n knownQuirks: [\n {\n id: 'no-global-key',\n severity: 'critical',\n message: 'Global API keys grant full user authority and are unsupported. Use a scoped API token.',\n },\n {\n id: 'no-token-reuse',\n severity: 'critical',\n message: 'Never reuse a token used by Tangle deployment, Workers, Terraform, DNS automation, or other infrastructure.',\n },\n {\n id: 'dns-impact',\n severity: 'critical',\n message: 'DNS updates can interrupt production traffic. Every DNS mutation remains approval-gated.',\n },\n ],\n healthcheck: {\n id: 'cloudflare.token',\n level: 'connection',\n description: 'Verify that the dedicated API token is valid and active.',\n },\n },\n nango: {\n consoleUrl: 'https://nango.dev/docs/getting-started/intro-to-nango',\n credentialFields: [],\n consoleSteps: [\n {\n id: 'gateway',\n title: 'Choose a Nango gateway deployment',\n detail: 'Use Nango only when a product intentionally deploys Nango Cloud or a self-hosted Nango environment.',\n },\n {\n id: 'runtime',\n title: 'Configure the gateway runtime',\n detail: 'Store the Nango host and environment secret in the product-owned gateway service, not as provider OAuth credentials.',\n },\n {\n id: 'providers',\n title: 'Configure real provider integrations',\n detail: 'Register each external provider in Nango and test its connection lifecycle separately.',\n },\n ],\n knownQuirks: [\n {\n id: 'gateway-not-provider',\n severity: 'critical',\n message: 'Nango is an integration gateway, not an end-user OAuth provider. This catalog entry has no generic Connect flow.',\n },\n {\n id: 'no-runtime',\n severity: 'critical',\n message: 'This package does not ship a Nango gateway backend. The entry remains non-executable until a product deploys one.',\n },\n ],\n healthcheck: {\n id: 'nango.static',\n level: 'static',\n description: 'No Nango gateway runtime is configured by this package.',\n },\n },\n mongodb: {\n credentialFields: [\n {\n label: 'MongoDB connection JSON',\n description: 'JSON containing a public MongoDB host, database, user, password, optional port/auth source, and optional CA certificate. Verified TLS is mandatory.',\n example: '{\"host\":\"cluster.example.mongodb.net\",\"port\":27017,\"database\":\"app\",\"user\":\"tangle_reader\",\"password\":\"...\",\"authSource\":\"admin\"}',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'user', title: 'Create a read-only MongoDB user', detail: 'Grant read on the intended database only. Do not grant write, cluster administration, JavaScript execution, or cross-database roles.' },\n { id: 'network', title: 'Allow the Hub connection', detail: 'Expose one MongoDB node through a public TLS endpoint and restrict its firewall to Hub egress addresses when available.' },\n { id: 'credential', title: 'Store the connection JSON', detail: 'Save the endpoint, database, read-only user, password, auth source, and optional CA certificate in the encrypted credential field.' },\n { id: 'test', title: 'Test the connection', detail: 'The check pins a public address, verifies the TLS hostname and certificate, authenticates, and runs a fixed ping command.' },\n ],\n knownQuirks: [\n { id: 'read-only', severity: 'info', message: 'The pack exposes collection/index metadata, structured scalar document reads, and counts only. Raw queries, JavaScript, aggregation, writes, and administrative commands are unavailable.' },\n { id: 'direct-node', severity: 'warning', message: 'The hosted adapter pins one public seed and disables topology discovery so a server cannot redirect Hub to unvalidated private nodes.' },\n { id: 'tls-only', severity: 'critical', message: 'Plain MongoDB connections are rejected. TLS 1.2 or newer and valid server certificates are mandatory.' },\n { id: 'bounded-results', severity: 'info', message: 'Document reads return at most 1,000 documents and 10 MiB and accept fixed scalar predicates instead of raw MongoDB query objects.' },\n { id: 'trigger-runtime', severity: 'warning', message: 'Change-stream triggers remain unavailable until a durable worker persists resume tokens and deliveries.' },\n ],\n healthcheck: {\n id: 'mongodb.connection',\n level: 'connection',\n description: 'Resolve and pin a public address, negotiate verified TLS, authenticate, and run a fixed ping command.',\n },\n },\n postgres: {\n credentialFields: [\n {\n label: 'PostgreSQL connection JSON',\n description: 'JSON containing a public PostgreSQL host, database, user, password, optional port, and optional CA certificate. Verified TLS is mandatory.',\n example: '{\"host\":\"postgres.example.com\",\"port\":5432,\"database\":\"app\",\"user\":\"tangle_reader\",\"password\":\"...\"}',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'user', title: 'Create a read-only PostgreSQL role', detail: 'Grant CONNECT on the database, USAGE on intended schemas, and SELECT on intended tables or views. Do not grant write, DDL, function execution, or replication privileges.' },\n { id: 'network', title: 'Allow the Hub connection', detail: 'Expose PostgreSQL through a public TLS endpoint and restrict its firewall to the Hub egress addresses when available.' },\n { id: 'credential', title: 'Store the connection JSON', detail: 'Save the endpoint, database, read-only role, password, and optional CA certificate in the encrypted credential field.' },\n { id: 'test', title: 'Test the connection', detail: 'The check pins a public address, verifies the TLS hostname and certificate, authenticates, and runs a fixed current-database query.' },\n ],\n knownQuirks: [\n { id: 'read-only', severity: 'info', message: 'The pack exposes metadata and structured SELECT reads only. Arbitrary SQL, functions, writes, DDL, COPY, and replication are not available.' },\n { id: 'tls-only', severity: 'critical', message: 'Plain PostgreSQL connections are rejected. TLS 1.2 or newer and valid server certificates are mandatory.' },\n { id: 'public-host', severity: 'warning', message: 'Hosted Hub rejects private, loopback, link-local, and mixed public/private DNS targets.' },\n { id: 'bounded-results', severity: 'info', message: 'Reads return at most 10,000 rows and 10 MiB and use bounded scalar predicates instead of raw SQL.' },\n { id: 'trigger-runtime', severity: 'warning', message: 'Database-change triggers remain unavailable until a durable logical-decoding or polling worker persists cursors and deliveries.' },\n ],\n healthcheck: {\n id: 'postgres.connection',\n level: 'connection',\n description: 'Resolve and pin a public address, negotiate verified TLS, authenticate, and run a fixed current-database query.',\n },\n },\n neverbounce: {\n consoleUrl: 'https://app.neverbounce.com/',\n credentialFields: [\n {\n label: 'NeverBounce API key',\n description: 'Create a dedicated API key in Apps > API. Verification calls consume account credits.',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'key', title: 'Create a dedicated API key', detail: 'Open Apps > API in NeverBounce and create a key for Tangle Integration Hub.' },\n { id: 'store', title: 'Store the API key', detail: 'Paste the key once. Tangle Hub seals it before persistence.' },\n { id: 'test', title: 'Test account access', detail: 'The connection check reads account information without verifying an address or spending a verification credit.' },\n ],\n knownQuirks: [\n { id: 'metered-verification', severity: 'warning', message: 'Every address verification can consume NeverBounce credits and remains approval-gated by default.' },\n { id: 'query-auth', severity: 'warning', message: 'NeverBounce requires the API key in the request query string. Tangle redacts it from errors and logs.' },\n ],\n healthcheck: {\n id: 'neverbounce.connection',\n level: 'connection',\n description: 'Read NeverBounce account information without consuming a verification credit.',\n },\n },\n redshift: {\n credentialFields: [\n {\n label: 'Redshift connection JSON',\n description: 'JSON containing a public Redshift host, database, user, password, optional port, and optional CA certificate. Verified TLS is mandatory.',\n example: '{\"host\":\"cluster.region.redshift.amazonaws.com\",\"port\":5439,\"database\":\"analytics\",\"user\":\"tangle_reader\",\"password\":\"...\"}',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'user', title: 'Create a read-only Redshift user', detail: 'Grant USAGE on intended schemas and SELECT on intended tables or views. Do not grant write, DDL, COPY, UNLOAD, or external-function privileges.' },\n { id: 'network', title: 'Allow the Hub connection', detail: 'Expose the cluster through a public TLS endpoint and restrict its security group or firewall to the Hub egress addresses when available.' },\n { id: 'credential', title: 'Store the connection JSON', detail: 'Save the endpoint, database, read-only user, password, and optional CA certificate in the encrypted credential field.' },\n { id: 'test', title: 'Test the connection', detail: 'The check pins a public address, verifies the TLS hostname and certificate, authenticates, and runs a fixed current-database query.' },\n ],\n knownQuirks: [\n { id: 'read-only', severity: 'info', message: 'The pack exposes metadata and structured SELECT reads only. Arbitrary SQL, writes, DDL, COPY, UNLOAD, and external functions are not available.' },\n { id: 'tls-only', severity: 'critical', message: 'Plain PostgreSQL connections are rejected. TLS 1.2 or newer and valid server certificates are mandatory.' },\n { id: 'public-host', severity: 'warning', message: 'Hosted Hub rejects private, loopback, link-local, and mixed public/private DNS targets.' },\n { id: 'bounded-results', severity: 'info', message: 'Reads return at most 10,000 rows and 10 MiB and use bounded scalar predicates instead of raw SQL.' },\n { id: 'trigger-runtime', severity: 'warning', message: 'The cataloged record-change trigger remains unavailable until an incremental polling worker persists its cursor and deliveries durably.' },\n ],\n healthcheck: {\n id: 'redshift.connection',\n level: 'connection',\n description: 'Resolve and pin a public address, negotiate verified TLS, authenticate, and run a fixed current-database query.',\n },\n },\n redis: {\n credentialFields: [\n {\n label: 'Redis connection JSON',\n description: 'JSON containing a public host, password, optional ACL username/database, and optional CA certificate. Verified TLS is mandatory.',\n example: '{\"host\":\"cache.example.com\",\"port\":6380,\"username\":\"default\",\"password\":\"...\",\"database\":0}',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'account', title: 'Create a restricted Redis user', detail: 'Grant only PING, SCAN, TYPE, PTTL, GET, SET, DEL, and EVAL access for the intended key patterns.' },\n { id: 'tls', title: 'Require verified TLS', detail: 'Use a public hostname with a valid certificate on the TLS listener. Plain Redis connections are rejected.' },\n { id: 'credential', title: 'Store the connection JSON', detail: 'Save the host, port, restricted ACL credentials, database number, and optional CA certificate in the encrypted credential field.' },\n { id: 'test', title: 'Test the connection', detail: 'The connection check pins a public address, verifies the TLS hostname and certificate, authenticates, and sends PING.' },\n ],\n knownQuirks: [\n { id: 'tls-only', severity: 'critical', message: 'Plain Redis is rejected. TLS 1.2 or newer and valid server certificates are mandatory.' },\n { id: 'standalone', severity: 'warning', message: 'This pack targets one standalone or managed primary endpoint. Redis Cluster and Sentinel discovery are not followed.' },\n { id: 'bounded-scan', severity: 'info', message: 'Key discovery uses bounded SCAN pages and never runs the blocking KEYS command.' },\n { id: 'string-writes', severity: 'info', message: 'Writes are limited to conditional string set/delete operations. Arbitrary commands and unconditional deletes are not exposed.' },\n { id: 'trigger-runtime', severity: 'warning', message: 'The cataloged key-change trigger remains unavailable until a durable subscriber can persist keyspace events before acknowledging delivery.' },\n ],\n healthcheck: {\n id: 'redis.connection',\n level: 'connection',\n description: 'Resolve and pin a public address, negotiate verified TLS, authenticate, send PING, and close.',\n },\n },\n rabbitmq: {\n credentialFields: [\n {\n label: 'RabbitMQ connection JSON',\n description: 'JSON containing a public host, username, password, optional port/vhost, and optional CA or mutual-TLS credentials. Verified TLS is mandatory.',\n example: '{\"host\":\"rabbitmq.example.com\",\"port\":5671,\"username\":\"tangle\",\"password\":\"...\",\"vhost\":\"/tenant\"}',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'account', title: 'Create a restricted RabbitMQ user', detail: 'Grant only configure, write, and read permissions required for the intended virtual host and resources.' },\n { id: 'tls', title: 'Expose a verified TLS listener', detail: 'Use an AMQPS listener on a public hostname with a valid certificate. Plain AMQP is rejected.' },\n { id: 'credential', title: 'Store the connection JSON', detail: 'Save the host, virtual host, restricted user, password, and optional TLS material in the encrypted credential field.' },\n { id: 'test', title: 'Test the connection', detail: 'The connection check verifies public routing, TLS certificate validation, and RabbitMQ authentication without publishing a message.' },\n ],\n knownQuirks: [\n { id: 'tls-only', severity: 'critical', message: 'Plaintext AMQP is rejected. TLS 1.2 or newer and valid server certificates are mandatory.' },\n { id: 'public-host', severity: 'warning', message: 'Hosted Hub rejects private, loopback, link-local, and mixed public/private DNS targets.' },\n { id: 'publisher-confirms', severity: 'info', message: 'Publish actions wait for broker confirmation and require the target queue or exchange to exist.' },\n { id: 'consumer-runtime', severity: 'warning', message: 'The cataloged Message Received trigger still requires a durable polling worker that persists each event before acknowledging it.' },\n ],\n healthcheck: {\n id: 'rabbitmq.connection',\n level: 'connection',\n description: 'Resolve a public host, negotiate verified TLS, authenticate, and close without publishing.',\n },\n },\n duckdb: {\n consoleSteps: [\n { id: 'ready', title: 'Use the built-in runtime', detail: 'No provider account, endpoint, or credential is required. Each invocation uses a new in-memory database.' },\n { id: 'query', title: 'Use query parameters', detail: 'Pass dynamic values through $1, $2, and the args array instead of interpolating them into SQL.' },\n ],\n knownQuirks: [\n { id: 'ephemeral', severity: 'info', message: 'Tables exist only for one invocation and are discarded immediately afterward.' },\n { id: 'external-access', severity: 'critical', message: 'File, network, extension, and attached-database access is disabled and locked before input tables are loaded.' },\n { id: 'bounded-runtime', severity: 'warning', message: 'Input, output, rows, schema depth and width, memory, threads, and execution time are bounded for hosted Hub safety.' },\n { id: 'integer-json', severity: 'info', message: 'DuckDB 64-bit integer results are serialized as decimal strings so JSON does not lose precision.' },\n ],\n healthcheck: {\n id: 'duckdb.runtime',\n level: 'connection',\n description: 'Open a secured in-memory DuckDB instance and execute SELECT 1.',\n },\n },\n kafka: {\n credentialFields: [\n {\n label: 'Kafka connection JSON',\n description: 'JSON containing public broker host:port entries and optional SASL or mutual-TLS credentials. TLS is always required.',\n example: '{\"brokers\":[\"broker.example.com:9093\"],\"saslMechanism\":\"scram-sha-512\",\"saslUsername\":\"...\",\"saslPassword\":\"...\"}',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'account', title: 'Create a restricted Kafka principal', detail: 'Grant only the topics, groups, and administrative operations required by approved Tangle workflows.' },\n { id: 'network', title: 'Expose TLS broker endpoints', detail: 'Use public TLS endpoints whose advertised broker addresses also resolve publicly.' },\n { id: 'credential', title: 'Store the connection JSON', detail: 'Paste brokers plus SASL or mutual-TLS credentials into the encrypted connection field.' },\n { id: 'test', title: 'Test topic discovery', detail: 'The connection check verifies public routing, TLS certificates, authentication, and topic-list permission without producing a record.' },\n ],\n knownQuirks: [\n { id: 'tls-only', severity: 'critical', message: 'Plaintext Kafka is rejected. TLS 1.2 or newer and valid broker certificates are mandatory.' },\n { id: 'public-brokers', severity: 'warning', message: 'Every bootstrap and advertised broker address must resolve publicly for hosted Hub execution.' },\n { id: 'consumer-rebalance', severity: 'warning', message: 'A bounded consume joins the supplied consumer group and may rebalance its members, so it always requires approval.' },\n { id: 'explicit-commit', severity: 'critical', message: 'Bounded consume never commits offsets automatically. Commit the returned next offsets only after downstream work succeeds.' },\n ],\n healthcheck: {\n id: 'kafka.connection',\n level: 'connection',\n description: 'Connect over TLS, authenticate, and list topics without producing or consuming records.',\n },\n },\n sftp: {\n credentialFields: [\n {\n label: 'SFTP connection JSON',\n description: 'JSON containing host, username, SHA-256 hostFingerprint, and password or privateKey; optional port, passphrase, and rootPath.',\n example: '{\"host\":\"sftp.example.com\",\"username\":\"integration\",\"password\":\"...\",\"hostFingerprint\":\"SHA256:...\",\"rootPath\":\"/incoming\"}',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'account', title: 'Create a restricted SFTP account', detail: 'Use a customer-owned account limited to the directories and operations Tangle needs.' },\n { id: 'fingerprint', title: 'Copy the server fingerprint', detail: 'Obtain the SHA-256 host-key fingerprint from the server administrator or a trusted out-of-band channel.' },\n { id: 'credential', title: 'Store the connection JSON', detail: 'Paste the host, username, authentication secret, host fingerprint, and optional root path into the encrypted connection field.' },\n { id: 'test', title: 'Test the connection', detail: 'The connection check verifies DNS, public routing, the pinned host key, authentication, and the configured root directory.' },\n ],\n knownQuirks: [\n { id: 'public-endpoint', severity: 'warning', message: 'The hosted Hub rejects private and local SFTP targets. Expose a restricted public endpoint or use customer-hosted execution.' },\n { id: 'host-key', severity: 'critical', message: 'Connections fail closed when the server host key differs from the stored SHA-256 fingerprint.' },\n { id: 'root-scope', severity: 'critical', message: 'All paths are confined to rootPath, including after symbolic-link resolution.' },\n ],\n healthcheck: {\n id: 'sftp.connection',\n level: 'connection',\n description: 'Connect, verify the pinned host key, authenticate, and read the current SFTP directory without modifying files.',\n },\n },\n 'azure-event-grid': {\n consoleUrl: 'https://portal.azure.com/#view/HubsExtension/BrowseResource/resourceType/Microsoft.EventGrid%2Ftopics',\n credentialFields: [\n {\n label: 'Azure Event Grid credential bundle',\n description: 'JSON containing the custom topic or domain endpoint, one topic access key, and a random delivery secret of at least 32 characters.',\n example: '{\"endpoint\":\"https://topic.region.eventgrid.azure.net/api/events\",\"accessKey\":\"...\",\"deliverySecret\":\"...\"}',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'topic', title: 'Select a custom topic or domain', detail: 'Open the customer-owned Event Grid topic or domain and copy its /api/events endpoint.' },\n { id: 'key', title: 'Copy one topic access key', detail: 'Use either active key and rotate between the primary and secondary keys without downtime.' },\n { id: 'secret', title: 'Generate a delivery secret', detail: 'Generate at least 32 random characters and store it with the endpoint and access key.' },\n { id: 'subscription', title: 'Configure authenticated delivery', detail: 'On each event subscription, add x-tangle-eventgrid-secret as a static secret delivery header with the same value.' },\n ],\n knownQuirks: [\n { id: 'static-health', severity: 'info', message: 'The setup check validates endpoint and credential structure. A live publish would create a real external event and remains approval-gated.' },\n { id: 'delivery-secret', severity: 'critical', message: 'Inbound delivery is rejected unless the event subscription sends the matching x-tangle-eventgrid-secret static delivery header.' },\n ],\n healthcheck: {\n id: 'azure-event-grid.credentials',\n level: 'static',\n description: 'Validate endpoint, topic key, and delivery-secret structure without publishing an event.',\n },\n },\n 'azure-service-bus': {\n consoleUrl: 'https://portal.azure.com/#view/HubsExtension/BrowseResource/resourceType/Microsoft.ServiceBus%2Fnamespaces',\n credentialFields: [\n {\n label: 'Azure Service Bus connection string',\n description: 'Use a dedicated shared access policy with only Send, Listen, or Manage rights required by approved workflows. EntityPath may restrict the connection to one queue or topic.',\n example: 'Endpoint=sb://namespace.servicebus.windows.net/;SharedAccessKeyName=...;SharedAccessKey=...;EntityPath=optional',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'namespace', title: 'Select the customer namespace', detail: 'Open the existing Azure Service Bus namespace or create one under the customer subscription.' },\n { id: 'policy', title: 'Create a narrow shared access policy', detail: 'Grant only Send, Listen, or Manage rights required by approved workflows.' },\n { id: 'entity', title: 'Prefer an entity-scoped connection', detail: 'Use a queue or topic EntityPath when namespace-wide discovery is not required.' },\n { id: 'store', title: 'Store the connection string', detail: 'Copy the primary or secondary connection string into the encrypted connection credential field.' },\n ],\n knownQuirks: [\n { id: 'destructive-receive', severity: 'critical', message: 'Receive-and-delete permanently removes the message as it is returned. Use it only when downstream handling can tolerate loss after a process failure.' },\n { id: 'format-only-health', severity: 'info', message: 'The setup health check validates connection-string structure without consuming or sending a message. Live permissions are confirmed on the first approved operation.' },\n ],\n healthcheck: {\n id: 'azure-service-bus.credentials',\n level: 'static',\n description: 'Validate the Azure Service Bus connection-string structure without sending or consuming a message.',\n },\n },\n 'gcloud-pubsub': {\n consoleUrl: 'https://console.cloud.google.com/cloudpubsub',\n credentialFields: [\n {\n label: 'Google Cloud service-account key JSON',\n description: 'Create a dedicated service account, grant only the required Pub/Sub roles, and paste its downloaded JSON key.',\n example: '{\"type\":\"service_account\",\"project_id\":\"...\",\"client_email\":\"...\",\"private_key\":\"...\"}',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'api', title: 'Enable the Pub/Sub API', detail: 'Enable Google Cloud Pub/Sub for the customer project.' },\n { id: 'service-account', title: 'Create a service account', detail: 'Create a dedicated Tangle Integration Hub service account.' },\n { id: 'roles', title: 'Grant narrow Pub/Sub roles', detail: 'Grant only viewer, publisher, subscriber, or editor access required by approved workflows.' },\n { id: 'key', title: 'Create and store a JSON key', detail: 'Create one JSON key and save it in the encrypted connection credential field.' },\n ],\n knownQuirks: [\n { id: 'at-least-once', severity: 'warning', message: 'Pub/Sub delivery is at-least-once by default. Consumers must deduplicate messages by a stable application identifier.' },\n { id: 'pull-ack', severity: 'warning', message: 'Pulling a message starts its acknowledgement deadline. Acknowledge it only after downstream work succeeds.' },\n ],\n },\n 'digital-ocean': {\n consoleUrl: 'https://cloud.digitalocean.com/account/api/tokens',\n credentialFields: [{ label: 'DigitalOcean personal access token', description: 'Create a dedicated token with only the read or write scopes required by approved workflows.', secret: true }],\n consoleSteps: [\n { id: 'token', title: 'Create a scoped token', detail: 'Create a dedicated token under API > Tokens with the smallest required scopes.' },\n { id: 'projects', title: 'Limit resource ownership', detail: 'Use dedicated projects and tags so connected automation touches only intended resources.' },\n { id: 'store', title: 'Store the token', detail: 'Paste the token once. Tangle Hub seals it before persistence.' },\n ],\n knownQuirks: [\n { id: 'billable-resources', severity: 'critical', message: 'Droplet, database, volume, and app creation can incur immediate charges. Keep all create, resize, action, and delete operations approval-gated.' },\n { id: 'irreversible-delete', severity: 'critical', message: 'Resource deletion can permanently destroy data. Require explicit destructive-action approval and verified backups.' },\n ],\n },\n clicksend: {\n consoleUrl: 'https://dashboard.clicksend.com/#/account/subaccounts',\n credentialFields: [\n {\n label: 'ClickSend API credential bundle',\n description: 'JSON containing username and apiKey from the ClickSend dashboard.',\n example: '{\"username\":\"...\",\"apiKey\":\"...\"}',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'account', title: 'Use a dedicated subaccount', detail: 'Create a restricted subaccount for Tangle Integration Hub when account isolation is required.' },\n { id: 'credentials', title: 'Copy API credentials', detail: 'Copy the ClickSend username and API key into the encrypted credential bundle.' },\n { id: 'sender', title: 'Configure approved senders', detail: 'Register and approve sender names or numbers before enabling outbound workflows.' },\n ],\n knownQuirks: [\n { id: 'paid-delivery', severity: 'warning', message: 'Outbound SMS and voice delivery incurs provider charges. Connection health and read operations do not send messages; keep outbound actions approval-gated.' },\n { id: 'sender-rules', severity: 'warning', message: 'Sender ID, consent, quiet-hours, and opt-out rules vary by destination country and remain the customer’s responsibility.' },\n ],\n },\n discourse: {\n consoleUrl: 'https://meta.discourse.org/t/create-and-configure-an-api-key/230124',\n credentialFields: [\n {\n label: 'Discourse API credential bundle',\n description: 'JSON containing apiKey and apiUsername. Store the public HTTPS forum root as connection metadata baseUrl.',\n example: '{\"apiKey\":\"...\",\"apiUsername\":\"system\"}',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'key', title: 'Create a scoped API key', detail: 'In Admin > API > Keys, create a dedicated key with the smallest required scope and user level.' },\n { id: 'username', title: 'Choose the acting user', detail: 'Use a dedicated service user whenever site-wide administrator authority is not required.' },\n { id: 'host', title: 'Record the forum URL', detail: 'Store the public HTTPS forum root as connection metadata baseUrl.' },\n { id: 'store', title: 'Store the credential bundle', detail: 'Save apiKey and apiUsername in the encrypted connection credential bundle.' },\n ],\n knownQuirks: [\n { id: 'acting-user', severity: 'warning', message: 'Every action is attributed to Api-Username and limited by both that user and the key scopes. Use separate keys for automation with different authority.' },\n { id: 'admin-actions', severity: 'warning', message: 'Category creation and moderation require staff or administrator authority and should remain approval-gated.' },\n ],\n },\n baserow: {\n consoleUrl: 'https://baserow.io/dashboard/settings/database-tokens',\n credentialFields: [\n {\n label: 'Baserow database token',\n description: 'Create a dedicated database token and grant only the required tables and create/read/update/delete permissions.',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'token', title: 'Create a database token', detail: 'Open workspace settings, create a dedicated token, and name it Tangle Integration Hub.' },\n { id: 'permissions', title: 'Limit table permissions', detail: 'Grant only the tables and create, read, update, or delete operations required by approved workflows.' },\n { id: 'store', title: 'Store the token', detail: 'Paste the token once. Tangle Hub seals it before persistence.' },\n ],\n knownQuirks: [\n { id: 'token-scope', severity: 'info', message: 'Database tokens intentionally cannot create tables or manage webhooks. Those account-level operations require a short-lived user JWT and are not advertised by this connector.' },\n { id: 'self-hosted-url', severity: 'info', message: 'For self-hosted Baserow, store the public HTTPS API root in connection metadata as baseUrl.' },\n ],\n },\n 'ping-identity': {\n consoleUrl: 'https://console.pingone.com/',\n credentialFields: [\n {\n label: 'PingOne worker credential bundle',\n description: 'JSON containing clientId, clientSecret, and region (us, ca, eu, au, or asia). Store the PingOne environment id as connection metadata.',\n example: '{\"clientId\":\"...\",\"clientSecret\":\"...\",\"region\":\"us\"}',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'worker-app', title: 'Create a worker application', detail: 'Create a dedicated PingOne worker application with the minimum user and group administration roles.' },\n { id: 'environment', title: 'Record environment and region', detail: 'Copy the PingOne environment id and select its deployment region.' },\n { id: 'credentials', title: 'Store worker credentials', detail: 'Save the client id and client secret in the encrypted connection credential bundle.' },\n ],\n },\n onelogin: {\n consoleUrl: 'https://admin.us.onelogin.com/api_credentials',\n credentialFields: [\n {\n label: 'OneLogin API credential bundle',\n description: 'JSON containing clientId, clientSecret, and region (us or eu).',\n example: '{\"clientId\":\"...\",\"clientSecret\":\"...\",\"region\":\"us\"}',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'credentials', title: 'Create API credentials', detail: 'Create dedicated OneLogin API credentials with Manage users or the smallest sufficient privilege.' },\n { id: 'region', title: 'Select tenant region', detail: 'Choose us or eu to pin both token and API requests to the tenant region.' },\n { id: 'store', title: 'Store credentials', detail: 'Save the client id and client secret in the encrypted connection credential bundle.' },\n ],\n },\n scim: {\n credentialFields: [\n {\n label: 'SCIM bearer token',\n description: 'Long-lived bearer token issued by the customer SCIM service provider.',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'endpoint', title: 'Record the SCIM base URL', detail: 'Use the public HTTPS SCIM 2.0 root, including any tenant path such as /scim/v2.' },\n { id: 'token', title: 'Create a provisioning token', detail: 'Issue a dedicated least-privileged bearer token for users, groups, and membership operations.' },\n { id: 'test', title: 'Test ServiceProviderConfig', detail: 'Verify the endpoint and token can read the SCIM ServiceProviderConfig resource.' },\n ],\n knownQuirks: [\n { id: 'provider-variance', severity: 'warning', message: 'SCIM providers vary in supported filters, PATCH paths, and ETag behavior; use provider-native PatchOp payloads when a service diverges from RFC 7644.' },\n ],\n },\n affinity: {\n consoleUrl: 'https://support.affinity.co/s/article/How-to-Create-and-Manage-API-Keys',\n credentialFields: [\n {\n label: 'Affinity API key',\n description: 'Bearer API key created by an Affinity workspace administrator. API availability and record access follow the workspace plan and key owner permissions.',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'check-plan', title: 'Confirm API access', detail: 'Confirm the workspace plan includes Affinity API access.' },\n { id: 'create-key', title: 'Create an API key', detail: 'Create a dedicated key under Affinity Settings > API using a least-privileged integration user.' },\n { id: 'paste-key', title: 'Paste the API key', detail: 'Paste the key once. Tangle Hub seals it before persistence.' },\n ],\n knownQuirks: [\n { id: 'user-permissions', severity: 'warning', message: 'The key inherits its creator’s list-level and record permissions; missing records can be an authorization issue rather than a synchronization failure.' },\n ],\n },\n dealcloud: {\n consoleUrl: 'https://api.docs.dealcloud.com/',\n consoleSteps: [\n { id: 'contract', title: 'Confirm DealCloud API access', detail: 'Ask the DealCloud administrator or Intapp account team to enable API access for the customer site.' },\n { id: 'schema-contract', title: 'Publish a schema contract', detail: 'Publish a scoped Schema Contract that names the entry types and fields Tangle may synchronize.' },\n { id: 'credentials', title: 'Issue integration credentials', detail: 'Create customer-site credentials restricted to the published contract and Publications required for incremental synchronization.' },\n ],\n credentialFields: [],\n knownQuirks: [\n { id: 'commercial-access', severity: 'critical', message: 'DealCloud API access is customer-site and contract dependent. This entry remains non-executable until the customer supplies an approved schema contract, site URL, and credentials.' },\n { id: 'custom-schema', severity: 'warning', message: 'Every DealCloud site is customized; map through the published Schema Contract instead of assuming global object or field names.' },\n ],\n },\n otter: {\n consoleUrl: 'https://otter.ai/',\n consoleSteps: [\n { id: 'contract', title: 'Confirm Otter API access', detail: 'Confirm the customer plan and commercial agreement include supported API access for transcripts and meeting metadata.' },\n { id: 'credentials', title: 'Request integration credentials', detail: 'Obtain provider-issued credentials and the permitted workspace/account scope from Otter.' },\n { id: 'scope', title: 'Record permitted data use', detail: 'Record retention, participant-consent, and transcript access rules before enabling ingestion.' },\n ],\n credentialFields: [],\n knownQuirks: [\n { id: 'no-public-self-serve-api', severity: 'critical', message: 'No generally available self-serve Otter API credential flow is documented. This entry is contract-only until provider-approved access exists.' },\n ],\n },\n zoom: {\n consoleUrl: 'https://marketplace.zoom.us/develop/create',\n consoleSteps: [\n { id: 'app', title: 'Create a General App', detail: 'Create a user-managed General App in Zoom App Marketplace.' },\n { id: 'redirect', title: 'Add callback URL', detail: 'Add {redirectUri} as the OAuth redirect URL.', copyValue: '{redirectUri}' },\n { id: 'scopes', title: 'Add granular scopes', detail: 'Add the user, meeting, webinar, and recording scopes listed by this integration.' },\n { id: 'events', title: 'Enable event subscriptions', detail: 'Subscribe the Hub callback to meeting, recording, and transcript completion events needed by workflows.' },\n ],\n },\n 'microsoft-forms': {\n consoleUrl: 'https://learn.microsoft.com/microsoft-365/community/working-with-microsoft-forms-using-microsoft-graph',\n consoleSteps: [\n { id: 'confirm-api', title: 'Confirm supported Forms access', detail: 'Confirm the customer has a provider-supported Microsoft Forms API path for the required tenant and form ownership model.' },\n { id: 'approve', title: 'Approve tenant access', detail: 'Document the tenant administrator approval and the specific forms Tangle may read.' },\n ],\n credentialFields: [],\n knownQuirks: [\n { id: 'no-supported-graph-surface', severity: 'critical', message: 'Microsoft Graph does not expose a generally supported Forms response API. This entry stays non-executable until Microsoft provides or approves a supported access path.' },\n ],\n },\n 'microsoft-word': {\n consoleUrl: 'https://learn.microsoft.com/graph/api/resources/onedrive',\n consoleSteps: [\n { id: 'use-files', title: 'Connect OneDrive or SharePoint', detail: 'Use the existing OneDrive or SharePoint connector for Word file discovery, permissions, versions, and download/upload.' },\n { id: 'confirm-edit-api', title: 'Confirm document editing API', detail: 'Before enabling document-body edits, confirm a provider-supported Word editing API and tenant authorization path.' },\n ],\n credentialFields: [],\n knownQuirks: [\n { id: 'files-not-document-model', severity: 'critical', message: 'Microsoft Graph supports Word files through OneDrive and SharePoint but does not expose the full Word document object model. This entry stays non-executable for document-body actions.' },\n ],\n },\n // ── Stripe pack ────────────────────────────────────────────────────\n // Stripe issues two key types: secret keys (sk_*) and restricted keys\n // (rk_*). For voice-agent workloads, restricted keys are the right call\n // — least-privilege scoped to the specific resources the agent can\n // touch. The hint nudges operators toward that path.\n 'stripe-pack': {\n consoleUrl: 'https://dashboard.stripe.com/apikeys',\n credentialFields: [\n {\n label: 'Stripe secret key',\n description:\n 'Restricted key recommended. Dashboard → Developers → API keys → Create restricted key. ' +\n 'Grant write access on Customers, Invoices, and Checkout Sessions.',\n example: 'sk_live_… or rk_live_… (use sk_test_… / rk_test_… for staging)',\n regex: '^(sk|rk)_(live|test)_[A-Za-z0-9]+$',\n secret: true,\n },\n ],\n consoleSteps: [\n {\n id: 'open-keys',\n title: 'Open Stripe API keys',\n detail: 'Visit https://dashboard.stripe.com/apikeys',\n copyValue: 'https://dashboard.stripe.com/apikeys',\n },\n {\n id: 'create-restricted',\n title: 'Create a restricted key',\n detail:\n 'Click \"Create restricted key\". Name it something descriptive ' +\n '(e.g. \"ph0ny voice agent — prod\"). Grant WRITE on Customers, ' +\n 'Invoices, and Checkout Sessions. Leave everything else NONE.',\n },\n {\n id: 'paste',\n title: 'Paste the key',\n detail:\n 'Copy the key Stripe shows once (rk_live_… or sk_live_…). ' +\n 'Paste it into ph0ny. The key is sealed before persistence.',\n },\n ],\n },\n\n // ── Twilio SMS ─────────────────────────────────────────────────────\n // Twilio's REST API uses Basic auth with two parts: Account SID\n // (public-ish, AC…) + Auth Token (secret). The default api-key family\n // only exposes one field, which doesn't fit. Providing both fields\n // explicitly lets the consumer's UI render two inputs.\n 'twilio-sms': {\n consoleUrl: 'https://console.twilio.com/',\n credentialFields: [\n {\n label: 'Account SID',\n description: 'Your Twilio Account SID. Console → Account → API keys & tokens.',\n example: 'AC… (34 hex chars)',\n regex: '^AC[a-f0-9]{32}$',\n secret: false,\n },\n {\n label: 'Auth Token',\n description:\n 'Your Twilio Auth Token (or Standard API Key secret). ' +\n 'Use a non-primary auth token in production so rotating it ' +\n \"won't break other Twilio integrations.\",\n secret: true,\n },\n ],\n consoleSteps: [\n {\n id: 'open',\n title: 'Open Twilio console',\n detail: 'Visit https://console.twilio.com/',\n copyValue: 'https://console.twilio.com/',\n },\n {\n id: 'find',\n title: 'Find your Account SID + Auth Token',\n detail:\n 'Account info is on the dashboard home. For better security, ' +\n 'create a Standard API Key (Account → API keys & tokens → Create ' +\n 'API Key) and use the SID + Secret pair instead of the primary ' +\n 'auth token.',\n },\n {\n id: 'paste',\n title: 'Paste both values',\n detail: 'Account SID is non-secret; Auth Token is sealed before persistence.',\n },\n ],\n knownQuirks: [\n {\n id: 'subaccount-tokens',\n severity: 'info',\n message:\n 'If you use Twilio subaccounts, paste the SID/Token of the ' +\n 'subaccount that owns the phone numbers your agent calls — not ' +\n 'the master account.',\n },\n ],\n },\n\n // ── ph0ny ──────────────────────────────────────────────────────────\n // ph0ny issues a single Bearer API key per developer. The key is a\n // `plabs_` prefix followed by 32 url-safe nanoid chars. It is shown once\n // at creation (POST /v1/keys in the developer portal); only its hash is\n // stored server-side, so it cannot be retrieved later — rotate to replace.\n phony: {\n consoleUrl: 'https://api.ph0ny.com',\n credentialFields: [\n {\n label: 'ph0ny API key',\n description:\n 'Bearer key issued by ph0ny. Create one in the developer portal ' +\n '(POST /v1/keys). Sent as `Authorization: Bearer <key>`.',\n example: 'plabs_V1StGXR8Z5jdHi6BmyTAbCdEfGhIjKlm',\n regex: '^plabs_[A-Za-z0-9_-]{32}$',\n secret: true,\n },\n ],\n consoleSteps: [\n {\n id: 'open-portal',\n title: 'Open the ph0ny developer portal',\n detail: 'Visit https://api.ph0ny.com and sign in to the developer portal.',\n copyValue: 'https://api.ph0ny.com',\n },\n {\n id: 'create-key',\n title: 'Create an API key',\n detail:\n 'In the portal, create a new API key (POST /v1/keys). Give it a ' +\n 'descriptive name (e.g. \"tangle agent — prod\"). ph0ny returns the ' +\n 'full key exactly once.',\n },\n {\n id: 'paste',\n title: 'Paste the key',\n detail:\n 'Copy the plabs_… key ph0ny shows and paste it here. The key is ' +\n 'sealed before persistence.',\n },\n ],\n knownQuirks: [\n {\n id: 'key-shown-once',\n severity: 'warning',\n message:\n 'ph0ny stores only a hash of the key — the full plabs_… value is ' +\n 'shown exactly once at creation and cannot be retrieved later. Save ' +\n 'it immediately; if lost, rotate to issue a replacement.',\n },\n {\n id: 'rotate-endpoint',\n severity: 'info',\n message:\n 'Rotate a key with POST /v1/keys/:id/rotate. The old key is revoked ' +\n 'and a new plabs_… key is returned once — update this connection ' +\n 'with the new value.',\n },\n ],\n },\n}\n\n/** Public read — undefined when no override exists for the kind. */\nexport function getIntegrationOverride(kind: string): IntegrationOverride | undefined {\n return INTEGRATION_OVERRIDES[kind]\n}\n","import {\n buildIntegrationCoverageConnectors,\n listIntegrationCoverageSpecs,\n type IntegrationCoverageSpec,\n} from '../coverage-catalog.js'\nimport type {\n IntegrationConnector,\n IntegrationConnectorAction,\n IntegrationConnectorTrigger,\n IntegrationDataClass,\n} from '../core-types.js'\nimport {\n bundledApiKeyHint,\n bundledAuthMode,\n bundledOAuth2AuthContract,\n getBundledAdapterManifest,\n} from '../connectors/bundled-manifest-data.js'\nimport type {\n ConnectorManifest,\n OAuth2TokenClientAuthMethod,\n OAuth2UrlTemplateMetadataSpec,\n} from '../connectors/types.js'\nimport { canonicalIntegrationKind } from '../integration-kind-aliases.js'\nimport { INTEGRATION_FAMILIES, getIntegrationFamily } from './families.js'\nimport { getIntegrationOverride } from './overrides.js'\nimport type {\n ApiKeyAuthSpec,\n CustomAuthSpec,\n HealthcheckSpec,\n HmacAuthSpec,\n IntegrationAuthSpec,\n IntegrationFamilyId,\n IntegrationPlannerHints,\n IntegrationSpec,\n IntegrationSpecStatus,\n NoneAuthSpec,\n NormalizedPermission,\n OAuth2AuthSpec,\n PermissionDescriptor,\n ScopeDescriptor,\n} from './types.js'\n\n/**\n * Executability and OAuth endpoints are DERIVED from the bundled adapter\n * registry, never restated here.\n *\n * This used to be a hand-maintained `EXECUTABLE_KINDS` set of 18 names. The\n * package ships 530 adapters, so the set was wrong by two orders of magnitude\n * and every new adapter silently landed as `status: 'catalog'`. Worse, the\n * oauth2 branch of `authFor` fabricated `https://example.invalid/<kind>/...`\n * whenever the family table had no endpoint — 104 of 131 oauth2 entries — so\n * a Connect button could be wired to a reserved TLD that can never resolve.\n * A catalog that describes connectors must read the connectors.\n */\nfunction bundledManifestFor(kind: string, coverageId: string) {\n return getBundledAdapterManifest(kind) ?? getBundledAdapterManifest(coverageId)\n}\n\nexport function listIntegrationSpecs(): IntegrationSpec[] {\n const connectors = new Map(buildIntegrationCoverageConnectors({ providerId: 'spec' }).map((c) => [c.id, c]))\n return listIntegrationCoverageSpecs().map((coverage) => {\n const connector = connectors.get(coverage.id)\n if (!connector) throw new Error(`missing coverage connector for ${coverage.id}`)\n return specFromCoverage(coverage, connector)\n })\n}\n\nexport function getIntegrationSpec(kind: string): IntegrationSpec | undefined {\n const canonical = canonicalIntegrationKind(kind)\n return listIntegrationSpecs().find((spec) => canonicalIntegrationKind(spec.kind) === canonical)\n}\n\n/** Auth-driving descriptor the hub uses to start a connect flow per provider\n * instead of hard-coding scopes/auth kind. Derived from the spec catalog\n * ({@link getIntegrationSpec}); undefined when the kind is not in the\n * catalog. */\nexport interface ConnectorAuthSpec {\n kind: string\n authKind: 'oauth2' | 'api_key' | 'none' | 'custom'\n grantType?: 'authorization_code' | 'client_credentials'\n /** Provider scopes to request in the authorization grant. Empty for\n * api_key / none / custom. */\n requestedScopes: string[]\n /** OAuth-only: authorization + token endpoints and PKCE posture. Present\n * only when authKind === 'oauth2'. */\n authorizationUrl?: string\n tokenUrl?: string\n pkce?: 'required' | 'supported' | 'unsupported'\n redirectUriTemplate?: string\n clientIdEnv?: string\n clientSecretEnv?: string\n scopeSeparator?: ' ' | ','\n authorizationClientIdParam?: string\n tokenClientIdParam?: string\n tokenClientSecretParam?: string\n tokenClientAuthMethod?: OAuth2TokenClientAuthMethod\n sendScopeParam?: boolean\n extraAuthParams?: Record<string, string>\n urlTemplateMetadata?: Readonly<Record<string, OAuth2UrlTemplateMetadataSpec>>\n}\n\nexport function resolveConnectorAuthSpec(kind: string): ConnectorAuthSpec | undefined {\n const spec = getIntegrationSpec(kind)\n if (!spec) return undefined\n const auth = spec.auth\n if (auth.mode === 'oauth2') {\n return {\n kind: spec.kind,\n authKind: 'oauth2',\n grantType: auth.grantType,\n requestedScopes: auth.scopes.map((scope) => scope.providerScope).filter(Boolean),\n authorizationUrl: auth.authorizationUrl,\n tokenUrl: auth.tokenUrl,\n pkce: auth.pkce,\n redirectUriTemplate: auth.redirectUriTemplate,\n clientIdEnv: auth.clientIdEnv,\n clientSecretEnv: auth.clientSecretEnv,\n scopeSeparator: auth.scopeSeparator,\n authorizationClientIdParam: auth.authorizationClientIdParam,\n tokenClientIdParam: auth.tokenClientIdParam,\n tokenClientSecretParam: auth.tokenClientSecretParam,\n tokenClientAuthMethod: auth.tokenClientAuthMethod,\n sendScopeParam: auth.sendScopeParam,\n extraAuthParams: auth.extraAuthParams,\n urlTemplateMetadata: auth.urlTemplateMetadata,\n }\n }\n if (auth.mode === 'api_key') {\n return { kind: spec.kind, authKind: 'api_key', requestedScopes: [] }\n }\n if (auth.mode === 'none') {\n return { kind: spec.kind, authKind: 'none', requestedScopes: [] }\n }\n return { kind: spec.kind, authKind: 'custom', requestedScopes: [] }\n}\n\nexport function listExecutableIntegrationSpecs(): IntegrationSpec[] {\n return listIntegrationSpecs().filter((spec) => spec.status === 'executable')\n}\n\nexport function integrationSpecToConnector(spec: IntegrationSpec, providerId = 'spec'): IntegrationConnector {\n return {\n id: spec.kind,\n providerId,\n title: spec.title,\n category: spec.category,\n auth: spec.auth.mode === 'api_key' ? 'api_key' : spec.auth.mode === 'oauth2' ? 'oauth2' : spec.auth.mode === 'none' ? 'none' : 'custom',\n scopes: spec.permissions.flatMap((permission) => permission.providerScopes),\n actions: spec.actions,\n triggers: spec.triggers,\n metadata: {\n ...(spec.metadata ?? {}),\n source: 'integration-spec',\n status: spec.status,\n family: spec.family,\n plannerHints: spec.plannerHints,\n },\n }\n}\n\nfunction specFromCoverage(coverage: IntegrationCoverageSpec, connector: IntegrationConnector): IntegrationSpec {\n const kind = canonicalIntegrationKind(coverage.id)\n const family = familyFor(coverage)\n const familySpec = getIntegrationFamily(family)\n const manifest = bundledManifestFor(kind, coverage.id)\n // A spec with no shipped adapter has no real action ids to give. The\n // coverage table would supply four synthesized from its action pack, and\n // naming those is the failure this whole module exists to end: 33 of 143\n // specs have no adapter, and every one of them advertised invented calls\n // (`jira` claimed `tasks.search`/`tasks.read`/`tasks.create`/`tasks.update`,\n // `microsoft-excel` claimed `records.query`...). A model told about a tool\n // that cannot resolve spends the turn on it, and the failure reads as the\n // agent being broken. Listing the connector with NO actions is honest and\n // still discoverable — it is genuinely connectable, it just cannot run\n // anything yet.\n //\n // The synthesized set is still what `permissions` and `plannerHints` are\n // derived from, because those describe the DATA the connector reaches\n // (read/write shape, data class, provider scopes) rather than callable\n // entry points. Deriving them from an empty list instead would silently\n // drop the write permission and downgrade every one of the 33 to\n // `dataClass: 'public'` — trading a prompt defect for a consent defect.\n const derivationActions = manifest\n ? actionsFromManifest(manifest, dataClassFor(connector.actions))\n : connector.actions\n const actions = manifest ? derivationActions : []\n const permissions = permissionsFor(coverage, derivationActions)\n const auth = authFor(coverage, family, permissions, kind)\n const status = statusFor(kind, coverage.id)\n // Per-kind overrides layer in here — see specs/overrides.ts. The override\n // is consulted under the canonical kind AND the original coverage id so\n // alias-collapsed kinds (e.g. notion-database → notion) can carry an\n // override under either name.\n const override =\n getIntegrationOverride(kind) ?? getIntegrationOverride(coverage.id)\n // Family quirks + override quirks are concatenated; everything else is\n // a replace (override fields take precedence when present).\n const knownQuirks = override?.knownQuirks\n ? [...(familySpec.knownQuirks ?? []), ...override.knownQuirks]\n : familySpec.knownQuirks\n return {\n kind,\n title: connector.title,\n category: connector.category,\n status,\n family,\n auth,\n permissions,\n actions,\n triggers: connector.triggers,\n setup: {\n consoleUrl: override?.consoleUrl ?? familySpec.consoleUrl,\n consoleSteps: override?.consoleSteps ?? familySpec.consoleSteps,\n credentialFields: override?.credentialFields ?? credentialFieldsFor(auth),\n redirectUriTemplate: auth.mode === 'oauth2' ? auth.redirectUriTemplate : familySpec.redirectUriTemplate,\n knownQuirks,\n postSetup: override?.postSetup,\n healthcheck: override?.healthcheck ?? healthcheckFor(kind, status, auth),\n },\n lifecycle: familySpec.lifecycle,\n plannerHints: plannerHintsFor(coverage, derivationActions),\n metadata: { priority: coverage.priority, domains: coverage.domains },\n }\n}\n\nfunction familyFor(spec: IntegrationCoverageSpec): IntegrationFamilyId {\n if (hmacKinds.has(spec.id)) return 'hmac'\n if (spec.auth === 'none') return 'none'\n if (spec.id.startsWith('google-') || spec.domains.includes('google')) return 'google'\n if (spec.id.startsWith('microsoft-') || ['outlook-mail', 'outlook-calendar', 'onedrive', 'sharepoint'].includes(spec.id)) return 'microsoft-graph'\n if (['jira', 'confluence', 'trello', 'bitbucket'].includes(spec.id)) return 'atlassian'\n if (spec.id === 'salesforce') return 'salesforce'\n if (spec.id === 'hubspot') return 'hubspot'\n if (spec.id === 'slack') return 'slack'\n if (spec.id === 'notion') return 'notion'\n if (apiKeyKinds.has(spec.id)) return 'api-key'\n return 'standard-oauth2'\n}\n\nconst apiKeyKinds = new Set(['github', 'gitlab', 'airtable', 'asana', 'stripe', 'twilio', 'sendgrid', 'postmark', 'phony'])\nconst hmacKinds = new Set(['webhook'])\n\nfunction authFor(\n spec: IntegrationCoverageSpec,\n family: IntegrationFamilyId,\n permissions: PermissionDescriptor[],\n kind: string,\n): IntegrationAuthSpec {\n const f = INTEGRATION_FAMILIES[family]\n // The shipped adapter decides HOW a connector authenticates. The coverage\n // table only guesses: it defaults every unlisted entry to the\n // `standard-oauth2` family, which is how Coda — an api-key connector —\n // came to advertise an OAuth flow it does not have.\n const manifest = bundledManifestFor(kind, spec.id)\n const realMode = manifest ? bundledAuthMode(manifest) : undefined\n if (spec.auth === 'custom' && !manifest) {\n return {\n mode: 'custom',\n description: `${spec.title} requires provider- or workspace-specific credentials and transport configuration.`,\n } satisfies CustomAuthSpec\n }\n if (realMode === 'none') return { mode: 'none' } satisfies NoneAuthSpec\n if (realMode === 'hmac') {\n return {\n mode: 'hmac',\n credential: INTEGRATION_FAMILIES.hmac.credentialFields[0]!,\n signatureHeader: `${spec.id}-signature`,\n } satisfies HmacAuthSpec\n }\n if (realMode === 'api_key') {\n const hint = manifest ? bundledApiKeyHint(manifest) : undefined\n const credential = apiKeyFieldFor(spec.id)\n return {\n mode: 'api_key',\n credential: hint ? { ...credential, description: hint } : credential,\n placement: apiKeyPlacementFor(spec.id),\n } satisfies ApiKeyAuthSpec\n }\n if (family === 'none' && !realMode) return { mode: 'none' } satisfies NoneAuthSpec\n if (family === 'hmac' && !realMode) {\n return { mode: 'hmac', credential: f.credentialFields[0]!, signatureHeader: `${spec.id}-signature` } satisfies HmacAuthSpec\n }\n if (family === 'api-key' && !realMode) {\n return { mode: 'api_key', credential: apiKeyFieldFor(spec.id), placement: apiKeyPlacementFor(spec.id) } satisfies ApiKeyAuthSpec\n }\n const scopes = permissions.flatMap((permission) =>\n permission.providerScopes.map((providerScope): ScopeDescriptor => ({\n normalized: permission.normalized,\n providerScope,\n title: permission.title,\n reason: permission.reason,\n risk: permission.risk,\n dataClass: permission.dataClass,\n })),\n )\n // A shipped adapter is the authority on how its provider authenticates:\n // it holds the endpoints the connect flow actually posts to and the exact\n // scope set the grant must request. Prefer it over the family defaults,\n // and never substitute a placeholder when neither knows — an absent URL is\n // a fact the caller can check, whereas `https://example.invalid/...` is a\n // dead link that reads as configuration.\n const real = manifest ? bundledOAuth2AuthContract(manifest) : undefined\n const tokenClientAuthMethod = real?.tokenClientAuthMethod ?? 'client_secret_post'\n return {\n mode: 'oauth2',\n grantType: real?.grantType === 'client_credentials' ? 'client_credentials' : undefined,\n authorizationUrl: real?.grantType === 'client_credentials'\n ? undefined\n : real?.authorizationUrl ?? f.authorizationUrl,\n tokenUrl: real?.tokenUrl ?? f.tokenUrl,\n clientIdEnv: real?.clientIdEnv ?? f.credentialFields.find((field) => !field.secret)?.env,\n clientSecretEnv: tokenClientAuthMethod === 'none'\n ? undefined\n : real?.clientSecretEnv ?? f.credentialFields.find((field) => field.secret)?.env,\n scopeSeparator: real?.scopeSeparator ?? ' ',\n authorizationClientIdParam: real?.authorizationClientIdParam ?? 'client_id',\n tokenClientIdParam: real?.tokenClientIdParam ?? 'client_id',\n tokenClientSecretParam: real?.tokenClientSecretParam ?? 'client_secret',\n tokenClientAuthMethod,\n sendScopeParam: real?.sendScopeParam,\n scopes: real ? scopesFromManifest(real.scopes, permissions) : scopes,\n extraAuthParams: real?.extraAuthParams ?? extraAuthParamsFor(family),\n urlTemplateMetadata: real?.urlTemplateMetadata,\n redirectUriTemplate: (f.redirectUriTemplate ?? 'https://{host}/api/integrations/oauth/{kind}/callback').replace('{kind}', spec.id),\n pkce: real?.pkce ?? (\n family === 'google' || family === 'microsoft-graph'\n ? 'supported'\n : 'required'\n ),\n } satisfies OAuth2AuthSpec\n}\n\n/**\n * The action list an agent is shown, taken from the adapter's own capability\n * catalog.\n *\n * The coverage table synthesizes actions from 19 generic \"action packs\", so\n * every finance-pack connector advertised the same four names —\n * `transactions.search`, `accounts.read`, `invoices.create`, `records.sync`.\n * For QuickBooks and Xero, one of those four exists. The other three are tool\n * calls that can only fail, while the capabilities that DO exist (`reports.get`,\n * `entities.query`, `tenants.list`) went unmentioned. Naming a tool that does\n * not exist is worse than naming none: the model spends the turn on it.\n */\nfunction actionsFromManifest(\n manifest: ConnectorManifest,\n fallbackDataClass: IntegrationDataClass,\n): IntegrationConnectorAction[] {\n return manifest.capabilities.map((capability): IntegrationConnectorAction => {\n const mutation = capability.class === 'mutation'\n return {\n id: capability.name,\n title: capability.name,\n risk: mutation ? 'write' : 'read',\n requiredScopes: capability.requiredScopes ? [...capability.requiredScopes] : [],\n dataClass: fallbackDataClass,\n ...(capability.consistencyModel ? { consistencyModel: capability.consistencyModel } : {}),\n description: capability.description,\n // A mutation reaching resources outside the caller needs confirmation\n // before it runs; the adapter is what knows which those are.\n approvalRequired: mutation ? capability.externalEffect : undefined,\n inputSchema: capability.parameters,\n }\n })\n}\n\n/** Pair the adapter's REAL provider scopes with the closest permission\n * descriptor for UI copy. The scope SET is taken verbatim from the manifest\n * because it is what the authorization grant actually requests — only the\n * surrounding title/risk labelling is matched heuristically, by whether the\n * scope names a mutating capability. */\nfunction scopesFromManifest(\n providerScopes: string[],\n permissions: PermissionDescriptor[],\n): ScopeDescriptor[] {\n const writePermission = permissions.find((permission) => permission.risk === 'write')\n const readPermission = permissions.find((permission) => permission.risk === 'read') ?? permissions[0]\n return providerScopes.map((providerScope): ScopeDescriptor => {\n const mutating = /(?:^|[.\\/_:-])(?:write|manage|create|modify|edit|update|delete|publish|full|readwrite)(?:$|[.\\/_:-])/i.test(\n providerScope,\n )\n const base = (mutating ? writePermission : readPermission) ?? readPermission\n return {\n normalized: base?.normalized ?? 'unknown.read',\n providerScope,\n title: base?.title ?? providerScope,\n reason: base?.reason ?? 'Requested by the connector.',\n risk: mutating ? 'write' : 'read',\n dataClass: base?.dataClass ?? 'private',\n }\n })\n}\n\nfunction credentialFieldsFor(auth: IntegrationAuthSpec) {\n if (auth.mode === 'api_key' || auth.mode === 'hmac') return [auth.credential]\n if (auth.mode === 'oauth2') {\n const fields = [\n { label: 'Client ID', env: auth.clientIdEnv, description: 'OAuth client ID.', secret: false },\n ]\n if (auth.tokenClientAuthMethod !== 'none') {\n fields.push({\n label: 'Client Secret',\n env: auth.clientSecretEnv,\n description: 'OAuth client secret.',\n secret: true,\n })\n }\n return fields\n }\n return []\n}\n\nfunction permissionsFor(spec: IntegrationCoverageSpec, actions: IntegrationConnectorAction[]): PermissionDescriptor[] {\n const dataClass = dataClassFor(actions)\n const readScope = providerScopeFor(spec, 'read')\n const writeScope = providerScopeFor(spec, 'write')\n const permissions: PermissionDescriptor[] = [\n {\n normalized: `${spec.actionPack}.read` as NormalizedPermission,\n providerScopes: readScope ? [readScope] : [],\n title: `${spec.title} read`,\n risk: 'read',\n dataClass,\n reason: `Read ${spec.title} data for user-authorized agent workflows.`,\n },\n ]\n if (actions.some((a) => a.risk !== 'read')) {\n permissions.push({\n normalized: `${spec.actionPack}.write` as NormalizedPermission,\n providerScopes: writeScope ? [writeScope] : [],\n title: `${spec.title} write`,\n risk: 'write',\n dataClass,\n reason: `Create or update ${spec.title} resources after policy approval.`,\n })\n }\n return permissions\n}\n\nfunction providerScopeFor(spec: IntegrationCoverageSpec, mode: 'read' | 'write'): string {\n const explicit = explicitScopes[spec.id]?.[mode]\n if (explicit) return explicit\n if (spec.auth === 'none') return ''\n return `${spec.id}.${mode}`\n}\n\nconst explicitScopes: Record<string, Partial<Record<'read' | 'write', string>>> = {\n gmail: { read: 'https://www.googleapis.com/auth/gmail.readonly', write: 'https://www.googleapis.com/auth/gmail.modify' },\n 'google-calendar': { read: 'https://www.googleapis.com/auth/calendar.readonly', write: 'https://www.googleapis.com/auth/calendar' },\n 'google-sheets': { read: 'https://www.googleapis.com/auth/spreadsheets.readonly', write: 'https://www.googleapis.com/auth/spreadsheets' },\n 'google-drive': { read: 'https://www.googleapis.com/auth/drive.readonly', write: 'https://www.googleapis.com/auth/drive.file' },\n 'google-docs': { read: 'https://www.googleapis.com/auth/documents.readonly', write: 'https://www.googleapis.com/auth/documents' },\n 'outlook-mail': { read: 'Mail.Read', write: 'Mail.Send' },\n 'outlook-calendar': { read: 'Calendars.Read', write: 'Calendars.ReadWrite' },\n 'microsoft-teams': { read: 'ChannelMessage.Read.All', write: 'ChannelMessage.Send' },\n onedrive: { read: 'Files.Read', write: 'Files.ReadWrite' },\n sharepoint: { read: 'Sites.Read.All', write: 'Sites.ReadWrite.All' },\n slack: { read: 'channels:read', write: 'chat:write' },\n hubspot: { read: 'crm.objects.contacts.read', write: 'crm.objects.contacts.write' },\n salesforce: { read: 'api', write: 'api' },\n notion: { read: '', write: '' },\n github: { read: 'repo:read', write: 'repo' },\n gitlab: { read: 'read_api', write: 'api' },\n airtable: { read: 'data.records:read', write: 'data.records:write' },\n asana: { read: 'default', write: 'default' },\n stripe: { read: 'read_only', write: 'standard' },\n twilio: { read: 'api_key', write: 'api_key' },\n}\n\nfunction plannerHintsFor(spec: IntegrationCoverageSpec, actions: IntegrationConnectorAction[]): IntegrationPlannerHints {\n return {\n useFor: spec.domains.map((domain) => domain.replace(/-/g, ' ')),\n dataFreshness: ['calendar', 'chat', 'commerce', 'finance', 'support'].includes(spec.actionPack) ? 'near_realtime' : 'eventual',\n writeRisk: actions.some((a) => a.risk === 'destructive') ? 'high' : actions.some((a) => a.risk === 'write') ? 'medium' : 'low',\n }\n}\n\nfunction healthcheckFor(kind: string, status: IntegrationSpecStatus, auth: IntegrationAuthSpec): HealthcheckSpec {\n if (status !== 'executable') {\n return { id: `${kind}.static`, level: 'static', description: 'Catalog-only integration; no executable connector healthcheck is available yet.' }\n }\n if (auth.mode === 'oauth2') {\n return { id: `${kind}.connection`, level: 'connection', description: 'Validate a user connection by calling the connector test endpoint.' }\n }\n if (auth.mode === 'api_key') {\n return { id: `${kind}.connection`, level: 'connection', description: 'Validate API credentials by calling the connector test endpoint.' }\n }\n if (auth.mode === 'hmac') {\n return { id: `${kind}.webhook`, level: 'webhook', description: 'Validate webhook signing configuration with a signed test payload.' }\n }\n return { id: `${kind}.static`, level: 'static', description: 'No credentials are required.' }\n}\n\nfunction statusFor(kind: string, coverageId: string): IntegrationSpecStatus {\n return bundledManifestFor(kind, coverageId) ? 'executable' : 'catalog'\n}\n\nfunction dataClassFor(actions: IntegrationConnectorAction[]): IntegrationDataClass {\n if (actions.some((a) => a.dataClass === 'secret')) return 'secret'\n if (actions.some((a) => a.dataClass === 'sensitive')) return 'sensitive'\n if (actions.some((a) => a.dataClass === 'private')) return 'private'\n if (actions.some((a) => a.dataClass === 'internal')) return 'internal'\n return 'public'\n}\n\nfunction apiKeyFieldFor(kind: string) {\n return {\n label: `${kind} API key`,\n description: `API key or token for ${kind}.`,\n example: kind === 'stripe' ? 'sk_live_...' : undefined,\n secret: true,\n }\n}\n\nfunction apiKeyPlacementFor(kind: string): ApiKeyAuthSpec['placement'] {\n if (kind === 'sftp' || kind === 'kafka') return undefined\n if (kind === 'amplitude') return 'basic'\n if (kind === 'clickup' || kind === 'gitlab') return 'header'\n return 'bearer'\n}\n\nfunction extraAuthParamsFor(family: IntegrationFamilyId): Record<string, string> | undefined {\n if (family === 'google') return { access_type: 'offline', prompt: 'consent', include_granted_scopes: 'true' }\n if (family === 'notion') return { owner: 'user' }\n return undefined\n}\n","import type {\n IntegrationActionRisk,\n IntegrationConnector,\n IntegrationConnectorAction,\n IntegrationConnectorCategory,\n IntegrationConnectorTrigger,\n IntegrationDataClass,\n} from '../core-types.js'\nimport type {\n OAuth2TokenClientAuthMethod,\n OAuth2UrlTemplateMetadataSpec,\n} from '../connectors/types.js'\n\nexport type IntegrationAuthMode = 'oauth2' | 'api_key' | 'hmac' | 'none' | 'custom'\n\nexport type IntegrationSpecStatus = 'catalog' | 'executable' | 'deprecated'\n\nexport type IntegrationFamilyId =\n | 'google'\n | 'microsoft-graph'\n | 'atlassian'\n | 'salesforce'\n | 'hubspot'\n | 'slack'\n | 'notion'\n | 'standard-oauth2'\n | 'api-key'\n | 'hmac'\n | 'none'\n\nexport type NormalizedPermission =\n | `${string}.read`\n | `${string}.write`\n | `${string}.delete`\n | `${string}.admin`\n\nexport interface IntegrationSpec {\n kind: string\n title: string\n category: IntegrationConnectorCategory\n status: IntegrationSpecStatus\n family: IntegrationFamilyId\n auth: IntegrationAuthSpec\n permissions: PermissionDescriptor[]\n actions: IntegrationConnectorAction[]\n triggers?: IntegrationConnectorTrigger[]\n setup: IntegrationSetupSpec\n lifecycle?: IntegrationLifecycleSpec\n plannerHints?: IntegrationPlannerHints\n metadata?: Record<string, unknown>\n}\n\nexport type IntegrationAuthSpec =\n | OAuth2AuthSpec\n | ApiKeyAuthSpec\n | HmacAuthSpec\n | NoneAuthSpec\n | CustomAuthSpec\n\nexport interface OAuth2AuthSpec {\n mode: 'oauth2'\n /** OAuth grant the connection runtime must drive. */\n grantType?: 'authorization_code' | 'client_credentials'\n /** Authorization endpoint the connect flow sends the user to.\n *\n * UNDEFINED when no shipped adapter and no family default supplies one —\n * i.e. the catalog knows the integration exists but nothing can currently\n * authenticate it. Callers must treat undefined as \"not connectable\" and\n * say so; this field was previously filled with\n * `https://example.invalid/<kind>/authorize`, a reserved TLD that can\n * never resolve, which made unconnectable integrations indistinguishable\n * from working ones. */\n authorizationUrl?: string\n /** Token endpoint. Undefined under the same condition as\n * {@link authorizationUrl}. */\n tokenUrl?: string\n clientIdEnv?: string\n clientSecretEnv?: string\n scopeSeparator?: ' ' | ','\n authorizationClientIdParam?: string\n tokenClientIdParam?: string\n tokenClientSecretParam?: string\n /** OAuth client authentication at the token endpoint. Defaults to\n * `client_secret_post` when omitted. */\n tokenClientAuthMethod?: OAuth2TokenClientAuthMethod\n scopes: ScopeDescriptor[]\n /** Whether the authorize request includes `scope`. Defaults to true. */\n sendScopeParam?: boolean\n extraAuthParams?: Record<string, string>\n /** Rules for connection metadata in authorizationUrl or tokenUrl templates. */\n urlTemplateMetadata?: Readonly<Record<string, OAuth2UrlTemplateMetadataSpec>>\n redirectUriTemplate: string\n pkce?: 'required' | 'supported' | 'unsupported'\n}\n\nexport interface ApiKeyAuthSpec {\n mode: 'api_key'\n credential: CredentialFieldSpec\n placement?: 'bearer' | 'header' | 'query' | 'basic'\n}\n\nexport interface HmacAuthSpec {\n mode: 'hmac'\n credential: CredentialFieldSpec\n signatureHeader?: string\n}\n\nexport interface NoneAuthSpec {\n mode: 'none'\n}\n\nexport interface CustomAuthSpec {\n mode: 'custom'\n description: string\n}\n\nexport interface ScopeDescriptor {\n normalized: NormalizedPermission\n providerScope: string\n title: string\n reason: string\n risk: IntegrationActionRisk\n dataClass: IntegrationDataClass\n}\n\nexport interface PermissionDescriptor {\n normalized: NormalizedPermission\n providerScopes: string[]\n title: string\n risk: IntegrationActionRisk\n dataClass: IntegrationDataClass\n reason: string\n}\n\nexport interface CredentialFieldSpec {\n label: string\n description: string\n env?: string\n example?: string\n regex?: string\n secret: boolean\n}\n\nexport interface ConsoleStep {\n id: string\n title: string\n detail: string\n copyValue?: string\n}\n\nexport interface Quirk {\n id: string\n severity: 'info' | 'warning' | 'critical'\n message: string\n}\n\nexport interface PostSetupCheck {\n id: string\n title: string\n detail: string\n}\n\nexport interface HealthcheckSpec {\n id: string\n level: 'client_config' | 'connection' | 'webhook' | 'static'\n method?: 'GET' | 'POST'\n url?: string\n expectedStatus?: number[]\n description: string\n}\n\nexport interface IntegrationSetupSpec {\n consoleUrl?: string\n consoleSteps: ConsoleStep[]\n credentialFields: CredentialFieldSpec[]\n redirectUriTemplate?: string\n knownQuirks?: Quirk[]\n postSetup?: PostSetupCheck[]\n healthcheck?: HealthcheckSpec\n}\n\nexport interface IntegrationLifecycleSpec {\n supportsRefresh: boolean\n supportsRevoke: boolean\n supportsIncrementalAuth: boolean\n recommendedHealthcheckIntervalHours?: number\n freshnessSloMinutes?: number\n}\n\nexport interface IntegrationPlannerHints {\n useFor: string[]\n avoidFor?: string[]\n dataFreshness: 'realtime' | 'near_realtime' | 'eventual' | 'manual'\n writeRisk: 'low' | 'medium' | 'high'\n}\n\nexport interface IntegrationFamilySpec {\n id: IntegrationFamilyId\n title: string\n authMode: IntegrationAuthMode\n consoleUrl?: string\n authorizationUrl?: string\n tokenUrl?: string\n redirectUriTemplate?: string\n credentialFields: CredentialFieldSpec[]\n consoleSteps: ConsoleStep[]\n knownQuirks?: Quirk[]\n lifecycle: IntegrationLifecycleSpec\n}\n\nexport interface IntegrationSpecValidationIssue {\n path: string\n message: string\n}\n\nexport interface IntegrationSpecValidationResult {\n ok: boolean\n issues: IntegrationSpecValidationIssue[]\n}\n\nexport interface RenderSpecOptions {\n host: string\n callbackPath?: string\n}\n\nexport interface RenderedConsoleStep extends ConsoleStep {\n detail: string\n copyValue?: string\n}\n\nexport interface CredentialValidationInput {\n field: CredentialFieldSpec\n value: string\n}\n\nexport interface CredentialValidationResult {\n ok: boolean\n field: string\n message?: string\n}\n\nexport interface HealthcheckPlan {\n kind: string\n healthcheck: HealthcheckSpec\n requires: Array<'client_id' | 'client_secret' | 'api_key' | 'hmac_secret' | 'connection_credentials'>\n message: string\n}\n\nexport function specAuthToConnectorAuth(auth: IntegrationAuthSpec): IntegrationConnector['auth'] {\n if (auth.mode === 'api_key') return 'api_key'\n if (auth.mode === 'oauth2') return 'oauth2'\n if (auth.mode === 'none') return 'none'\n return 'custom'\n}\n","import type {\n ConsoleStep,\n HealthcheckPlan,\n IntegrationSpec,\n RenderSpecOptions,\n RenderedConsoleStep,\n} from './types.js'\n\nexport function renderConsoleSteps(spec: IntegrationSpec, options: RenderSpecOptions): RenderedConsoleStep[] {\n const redirectUri = renderRedirectUri(spec, options)\n return spec.setup.consoleSteps.map((step) => ({\n ...step,\n detail: renderTemplate(step.detail, spec, options, redirectUri),\n copyValue: step.copyValue ? renderTemplate(step.copyValue, spec, options, redirectUri) : undefined,\n }))\n}\n\nexport function renderRunbookMarkdown(spec: IntegrationSpec, options: RenderSpecOptions): string {\n const steps = renderConsoleSteps(spec, options)\n const lines = [\n `# ${spec.title} Integration Setup`,\n '',\n `- Kind: \\`${spec.kind}\\``,\n `- Status: \\`${spec.status}\\``,\n `- Auth: \\`${spec.auth.mode}\\``,\n `- Family: \\`${spec.family}\\``,\n ]\n if (spec.setup.consoleUrl) lines.push(`- Console: ${spec.setup.consoleUrl}`)\n if (spec.setup.redirectUriTemplate) lines.push(`- Redirect URI: \\`${renderRedirectUri(spec, options)}\\``)\n lines.push('', '## Credentials', '')\n for (const field of spec.setup.credentialFields) {\n lines.push(`- ${field.secret ? '[secret] ' : ''}${field.label}${field.env ? ` (\\`${field.env}\\`)` : ''}: ${field.description}`)\n }\n lines.push('', '## Permissions', '')\n for (const permission of spec.permissions) {\n lines.push(`- \\`${permission.normalized}\\`: ${permission.providerScopes.length ? permission.providerScopes.map((scope) => `\\`${scope}\\``).join(', ') : 'no provider scope'} - ${permission.reason}`)\n }\n lines.push('', '## Console Steps', '')\n for (const [i, step] of steps.entries()) {\n lines.push(`${i + 1}. ${step.title}: ${step.detail}`)\n }\n if (spec.setup.knownQuirks?.length) {\n lines.push('', '## Known Quirks', '')\n for (const quirk of spec.setup.knownQuirks) lines.push(`- ${quirk.severity}: ${quirk.message}`)\n }\n return `${lines.join('\\n')}\\n`\n}\n\nexport function renderAgentToolDescription(spec: IntegrationSpec): string {\n const hints = spec.plannerHints\n const useFor = hints?.useFor?.length ? `Use for ${hints.useFor.join(', ')}.` : `Use for ${spec.title} workflows.`\n const risk = hints ? `Freshness: ${hints.dataFreshness}. Write risk: ${hints.writeRisk}.` : ''\n return `${spec.title} (${spec.kind}). ${useFor} ${risk}`.trim()\n}\n\nexport function buildHealthcheckPlan(spec: IntegrationSpec): HealthcheckPlan {\n const healthcheck = spec.setup.healthcheck ?? { id: `${spec.kind}.static`, level: 'static', description: 'No healthcheck defined.' as const }\n const requires: HealthcheckPlan['requires'] = []\n if (healthcheck.level === 'connection') requires.push('connection_credentials')\n if (healthcheck.level === 'client_config' && spec.auth.mode === 'oauth2') requires.push('client_id', 'client_secret')\n if (spec.auth.mode === 'api_key') requires.push('api_key')\n if (spec.auth.mode === 'hmac') requires.push('hmac_secret')\n return {\n kind: spec.kind,\n healthcheck,\n requires,\n message: healthcheck.description,\n }\n}\n\nfunction renderTemplate(template: string, spec: IntegrationSpec, options: RenderSpecOptions, redirectUri?: string): string {\n return template\n .replaceAll('{host}', options.host)\n .replaceAll('{kind}', spec.kind)\n .replaceAll('{redirectUri}', redirectUri ?? renderRedirectUri(spec, options))\n}\n\nfunction renderRedirectUri(spec: IntegrationSpec, options: RenderSpecOptions): string {\n return (options.callbackPath ?? spec.setup.redirectUriTemplate ?? '')\n .replaceAll('{host}', options.host)\n .replaceAll('{kind}', spec.kind)\n}\n\nexport function consoleStepsToText(steps: ConsoleStep[]): string {\n return steps.map((step, index) => `${index + 1}. ${step.title}: ${step.detail}`).join('\\n')\n}\n","import type {\n CredentialFieldSpec,\n CredentialValidationResult,\n IntegrationSpec,\n IntegrationSpecValidationIssue,\n IntegrationSpecValidationResult,\n} from './types.js'\n\nexport function validateIntegrationSpec(spec: IntegrationSpec): IntegrationSpecValidationResult {\n const issues: IntegrationSpecValidationIssue[] = []\n if (!spec.kind.trim()) issues.push({ path: 'kind', message: 'kind is required' })\n if (!spec.title.trim()) issues.push({ path: 'title', message: 'title is required' })\n if (!spec.actions.length) issues.push({ path: 'actions', message: 'at least one action is required' })\n if (!spec.permissions.length) issues.push({ path: 'permissions', message: 'at least one permission is required' })\n if (spec.auth.mode === 'oauth2') {\n if (!spec.auth.authorizationUrl) issues.push({ path: 'auth.authorizationUrl', message: 'authorizationUrl is required' })\n if (!spec.auth.tokenUrl) issues.push({ path: 'auth.tokenUrl', message: 'tokenUrl is required' })\n if (!spec.auth.redirectUriTemplate) issues.push({ path: 'auth.redirectUriTemplate', message: 'redirectUriTemplate is required' })\n }\n const actionIds = new Set<string>()\n for (const [index, action] of spec.actions.entries()) {\n if (actionIds.has(action.id)) issues.push({ path: `actions[${index}].id`, message: `duplicate action id ${action.id}` })\n actionIds.add(action.id)\n }\n return { ok: issues.length === 0, issues }\n}\n\nexport function assertValidIntegrationSpec(spec: IntegrationSpec): void {\n const result = validateIntegrationSpec(spec)\n if (!result.ok) {\n throw new Error(`Invalid integration spec ${spec.kind}: ${result.issues.map((i) => `${i.path}: ${i.message}`).join('; ')}`)\n }\n}\n\nexport function validateCredentialFormat(field: CredentialFieldSpec, value: string): CredentialValidationResult {\n if (!value.trim()) return { ok: false, field: field.label, message: `${field.label} is required` }\n if (field.regex && !new RegExp(field.regex).test(value)) {\n return { ok: false, field: field.label, message: `${field.label} does not match expected format` }\n }\n return { ok: true, field: field.label }\n}\n\nexport function validateCredentialSet(spec: IntegrationSpec, values: Record<string, string>): CredentialValidationResult[] {\n return spec.setup.credentialFields.map((field) => {\n const key = field.env ?? field.label\n return validateCredentialFormat(field, values[key] ?? '')\n })\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"specs-DvM23HBS.js","names":[],"sources":["../src/specs/families.ts","../src/specs/overrides.ts","../src/specs/registry.ts","../src/specs/types.ts","../src/specs/renderers.ts","../src/specs/validation.ts"],"sourcesContent":["import type { IntegrationFamilyId, IntegrationFamilySpec } from './types.js'\n\nexport const INTEGRATION_FAMILIES: Record<IntegrationFamilyId, IntegrationFamilySpec> = {\n google: {\n id: 'google',\n title: 'Google OAuth',\n authMode: 'oauth2',\n consoleUrl: 'https://console.cloud.google.com/apis/credentials',\n authorizationUrl: 'https://accounts.google.com/o/oauth2/v2/auth',\n tokenUrl: 'https://oauth2.googleapis.com/token',\n redirectUriTemplate: 'https://{host}/api/integrations/oauth/google/callback',\n credentialFields: [\n { label: 'Client ID', env: 'GOOGLE_OAUTH_CLIENT_ID', description: 'Google OAuth client ID.', example: '1234567890-abc.apps.googleusercontent.com', regex: '^[0-9]+-[a-zA-Z0-9_-]+\\\\.apps\\\\.googleusercontent\\\\.com$', secret: false },\n { label: 'Client Secret', env: 'GOOGLE_OAUTH_CLIENT_SECRET', description: 'Google OAuth client secret.', example: 'GOCSPX-...', secret: true },\n ],\n consoleSteps: [\n { id: 'project', title: 'Select project', detail: 'Open Google Cloud Console and select the project that owns the OAuth client.' },\n { id: 'consent', title: 'Configure consent screen', detail: 'Configure OAuth consent, app name, support email, and publishing status appropriate for the deployment.' },\n { id: 'client', title: 'Create web client', detail: 'Create an OAuth client of type Web application.' },\n { id: 'redirect', title: 'Add redirect URI', detail: 'Add {redirectUri} as an authorized redirect URI.', copyValue: '{redirectUri}' },\n { id: 'scopes', title: 'Add scopes', detail: 'Add the provider scopes listed in this spec.' },\n ],\n knownQuirks: [\n { id: 'offline-access', severity: 'warning', message: 'Use access_type=offline and prompt=consent when refresh tokens are required.' },\n { id: 'verification', severity: 'warning', message: 'Sensitive or restricted scopes may require Google verification before broad external use.' },\n ],\n lifecycle: { supportsRefresh: true, supportsRevoke: true, supportsIncrementalAuth: true, recommendedHealthcheckIntervalHours: 24 },\n },\n 'microsoft-graph': {\n id: 'microsoft-graph',\n title: 'Microsoft Graph OAuth',\n authMode: 'oauth2',\n consoleUrl: 'https://entra.microsoft.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade',\n authorizationUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',\n tokenUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',\n redirectUriTemplate: 'https://{host}/api/integrations/oauth/microsoft/callback',\n credentialFields: [\n { label: 'Client ID', env: 'MS_OAUTH_CLIENT_ID', description: 'Microsoft Entra application client ID.', example: '00000000-0000-0000-0000-000000000000', regex: '^[0-9a-fA-F-]{36}$', secret: false },\n { label: 'Client Secret', env: 'MS_OAUTH_CLIENT_SECRET', description: 'Microsoft Entra client secret value.', secret: true },\n ],\n consoleSteps: [\n { id: 'app', title: 'Register app', detail: 'Create or open an app registration in Microsoft Entra.' },\n { id: 'redirect', title: 'Add redirect URI', detail: 'Add {redirectUri} as a Web redirect URI.', copyValue: '{redirectUri}' },\n { id: 'secret', title: 'Create secret', detail: 'Create a client secret and store the secret value, not the secret ID.' },\n { id: 'permissions', title: 'Add Graph permissions', detail: 'Add the delegated Graph scopes listed in this spec and grant admin consent where required.' },\n ],\n knownQuirks: [\n { id: 'tenant-common', severity: 'info', message: 'The common tenant supports multi-tenant OAuth; single-tenant deployments should override the tenant segment.' },\n { id: 'admin-consent', severity: 'warning', message: 'Some Graph scopes require tenant admin consent.' },\n ],\n lifecycle: { supportsRefresh: true, supportsRevoke: true, supportsIncrementalAuth: true, recommendedHealthcheckIntervalHours: 24 },\n },\n atlassian: {\n id: 'atlassian',\n title: 'Atlassian OAuth',\n authMode: 'oauth2',\n consoleUrl: 'https://developer.atlassian.com/console/myapps/',\n authorizationUrl: 'https://auth.atlassian.com/authorize',\n tokenUrl: 'https://auth.atlassian.com/oauth/token',\n redirectUriTemplate: 'https://{host}/api/integrations/oauth/atlassian/callback',\n credentialFields: [\n { label: 'Client ID', description: 'Atlassian OAuth client ID.', secret: false },\n { label: 'Client Secret', description: 'Atlassian OAuth client secret.', secret: true },\n ],\n consoleSteps: [\n { id: 'app', title: 'Create OAuth app', detail: 'Create an OAuth 2.0 app in the Atlassian developer console.' },\n { id: 'redirect', title: 'Add callback URL', detail: 'Add {redirectUri} as the callback URL.', copyValue: '{redirectUri}' },\n { id: 'apis', title: 'Enable APIs', detail: 'Enable the Jira or Confluence APIs required by this connector.' },\n ],\n lifecycle: { supportsRefresh: true, supportsRevoke: false, supportsIncrementalAuth: false, recommendedHealthcheckIntervalHours: 24 },\n },\n salesforce: {\n id: 'salesforce',\n title: 'Salesforce OAuth',\n authMode: 'oauth2',\n consoleUrl: 'https://login.salesforce.com',\n authorizationUrl: 'https://login.salesforce.com/services/oauth2/authorize',\n tokenUrl: 'https://login.salesforce.com/services/oauth2/token',\n redirectUriTemplate: 'https://{host}/api/integrations/oauth/salesforce/callback',\n credentialFields: [\n { label: 'Client ID', env: 'SALESFORCE_OAUTH_CLIENT_ID', description: 'Salesforce connected app consumer key.', secret: false },\n { label: 'Client Secret', env: 'SALESFORCE_OAUTH_CLIENT_SECRET', description: 'Salesforce connected app consumer secret.', secret: true },\n ],\n consoleSteps: [\n { id: 'connected-app', title: 'Create connected app', detail: 'Create a Salesforce connected app with OAuth enabled.' },\n { id: 'callback', title: 'Add callback URL', detail: 'Add {redirectUri} as the callback URL.', copyValue: '{redirectUri}' },\n { id: 'scopes', title: 'Select scopes', detail: 'Add api and refresh_token/offline_access, plus any connector-specific scopes.' },\n ],\n knownQuirks: [\n { id: 'instance-url', severity: 'critical', message: 'Runtime calls must use the instance_url returned by the token response.' },\n ],\n lifecycle: { supportsRefresh: true, supportsRevoke: true, supportsIncrementalAuth: false, recommendedHealthcheckIntervalHours: 24 },\n },\n hubspot: {\n id: 'hubspot',\n title: 'HubSpot OAuth',\n authMode: 'oauth2',\n consoleUrl: 'https://developers.hubspot.com/',\n authorizationUrl: 'https://app.hubspot.com/oauth/authorize',\n tokenUrl: 'https://api.hubapi.com/oauth/v1/token',\n redirectUriTemplate: 'https://{host}/api/integrations/oauth/hubspot/callback',\n credentialFields: [\n { label: 'Client ID', env: 'HUBSPOT_OAUTH_CLIENT_ID', description: 'HubSpot app client ID.', secret: false },\n { label: 'Client Secret', env: 'HUBSPOT_OAUTH_CLIENT_SECRET', description: 'HubSpot app client secret.', secret: true },\n ],\n consoleSteps: [\n { id: 'app', title: 'Create private/public app', detail: 'Create a HubSpot app and configure OAuth.' },\n { id: 'redirect', title: 'Add redirect URL', detail: 'Add {redirectUri} to the app redirect URLs.', copyValue: '{redirectUri}' },\n { id: 'scopes', title: 'Add CRM scopes', detail: 'Add the CRM object scopes listed in this spec.' },\n ],\n lifecycle: { supportsRefresh: true, supportsRevoke: true, supportsIncrementalAuth: false, recommendedHealthcheckIntervalHours: 24 },\n },\n slack: {\n id: 'slack',\n title: 'Slack OAuth',\n authMode: 'oauth2',\n consoleUrl: 'https://api.slack.com/apps',\n authorizationUrl: 'https://slack.com/oauth/v2/authorize',\n tokenUrl: 'https://slack.com/api/oauth.v2.access',\n redirectUriTemplate: 'https://{host}/api/integrations/oauth/slack/callback',\n credentialFields: [\n { label: 'Client ID', env: 'SLACK_OAUTH_CLIENT_ID', description: 'Slack app client ID.', secret: false },\n { label: 'Client Secret', env: 'SLACK_OAUTH_CLIENT_SECRET', description: 'Slack app client secret.', secret: true },\n ],\n consoleSteps: [\n { id: 'app', title: 'Create Slack app', detail: 'Create or open a Slack app.' },\n { id: 'redirect', title: 'Add redirect URL', detail: 'Add {redirectUri} under OAuth & Permissions.', copyValue: '{redirectUri}' },\n { id: 'scopes', title: 'Add bot scopes', detail: 'Add the bot token scopes listed in this spec and reinstall the app.' },\n ],\n knownQuirks: [\n { id: 'bot-token', severity: 'info', message: 'Slack usually returns a bot access token; refresh tokens require token rotation.' },\n ],\n lifecycle: { supportsRefresh: false, supportsRevoke: true, supportsIncrementalAuth: false, recommendedHealthcheckIntervalHours: 24 },\n },\n notion: {\n id: 'notion',\n title: 'Notion OAuth',\n authMode: 'oauth2',\n consoleUrl: 'https://www.notion.so/my-integrations',\n authorizationUrl: 'https://api.notion.com/v1/oauth/authorize',\n tokenUrl: 'https://api.notion.com/v1/oauth/token',\n redirectUriTemplate: 'https://{host}/api/integrations/oauth/notion/callback',\n credentialFields: [\n { label: 'Client ID', env: 'NOTION_OAUTH_CLIENT_ID', description: 'Notion integration OAuth client ID.', secret: false },\n { label: 'Client Secret', env: 'NOTION_OAUTH_CLIENT_SECRET', description: 'Notion integration OAuth client secret.', secret: true },\n ],\n consoleSteps: [\n { id: 'integration', title: 'Create integration', detail: 'Create a Notion public integration.' },\n { id: 'redirect', title: 'Add redirect URI', detail: 'Add {redirectUri} as the redirect URI.', copyValue: '{redirectUri}' },\n { id: 'capabilities', title: 'Select capabilities', detail: 'Enable read/update/insert capabilities matching this connector.' },\n ],\n lifecycle: { supportsRefresh: true, supportsRevoke: true, supportsIncrementalAuth: false, recommendedHealthcheckIntervalHours: 24 },\n },\n 'standard-oauth2': {\n id: 'standard-oauth2',\n title: 'Standard OAuth 2.0',\n authMode: 'oauth2',\n redirectUriTemplate: 'https://{host}/api/integrations/oauth/{kind}/callback',\n credentialFields: [\n { label: 'Client ID', description: 'OAuth client ID.', secret: false },\n { label: 'Client Secret', description: 'OAuth client secret.', secret: true },\n ],\n consoleSteps: [\n { id: 'app', title: 'Create OAuth app', detail: 'Create an OAuth app in the provider console.' },\n { id: 'redirect', title: 'Add redirect URI', detail: 'Add {redirectUri} as an allowed redirect URI.', copyValue: '{redirectUri}' },\n { id: 'scopes', title: 'Add scopes', detail: 'Add the scopes listed in this spec.' },\n ],\n lifecycle: { supportsRefresh: true, supportsRevoke: false, supportsIncrementalAuth: false, recommendedHealthcheckIntervalHours: 24 },\n },\n 'api-key': {\n id: 'api-key',\n title: 'API key',\n authMode: 'api_key',\n credentialFields: [\n { label: 'API Key', description: 'Provider API key or token.', example: 'sk_...', secret: true },\n ],\n consoleSteps: [\n { id: 'token', title: 'Create token', detail: 'Create an API key/token in the provider console with the minimum required permissions.' },\n ],\n lifecycle: { supportsRefresh: false, supportsRevoke: true, supportsIncrementalAuth: false, recommendedHealthcheckIntervalHours: 24 },\n },\n hmac: {\n id: 'hmac',\n title: 'HMAC secret',\n authMode: 'hmac',\n credentialFields: [\n { label: 'Signing Secret', description: 'Webhook signing secret.', secret: true },\n ],\n consoleSteps: [\n { id: 'secret', title: 'Configure signing secret', detail: 'Configure the shared signing secret in the sender and receiver.' },\n ],\n lifecycle: { supportsRefresh: false, supportsRevoke: true, supportsIncrementalAuth: false, recommendedHealthcheckIntervalHours: 24 },\n },\n none: {\n id: 'none',\n title: 'No authentication',\n authMode: 'none',\n credentialFields: [],\n consoleSteps: [\n { id: 'configure', title: 'Configure endpoint', detail: 'No provider credentials are required.' },\n ],\n lifecycle: { supportsRefresh: false, supportsRevoke: false, supportsIncrementalAuth: false },\n },\n}\n\nexport function getIntegrationFamily(id: IntegrationFamilyId): IntegrationFamilySpec {\n return INTEGRATION_FAMILIES[id]\n}\n","/**\n * Per-kind overrides on top of family defaults.\n *\n * The family layer (`families.ts`) carries the auth-shape defaults — generic\n * \"API Key\" or \"Client ID + Client Secret\" credential fields, generic console\n * steps. Most kinds are happy with that. But some have provider-specific\n * shape that the family can't capture: Twilio's auth is two-part (Account\n * SID + Auth Token); Stripe's preferred path is restricted keys with specific\n * granted permissions; SendGrid demands a verified sender domain in the\n * console before keys work.\n *\n * `INTEGRATION_OVERRIDES` is the seam for that. The registry merges the\n * override on top of the family defaults at spec-build time. Override\n * fields are purely additive — set what you want to customize, leave the\n * rest absent and the family defaults apply.\n *\n * Adding a new override:\n * 1. Author the override entry below.\n * 2. The next spec build picks it up automatically; no other registry\n * change needed. Coverage catalog stays compact.\n *\n * Why a separate map and not inline on `IntegrationCoverageSpec`: the\n * coverage catalog is a flat tuple list optimized for fast iteration over\n * 142 specs. Bloating the tuple with optional override fields hurts\n * readability of the catalog AND scatters provider knowledge across two\n * data shapes. Keeping overrides in their own keyed map means contributors\n * looking for \"how does Stripe credential setup work\" find it in one place.\n */\n\nimport type {\n ConsoleStep,\n CredentialFieldSpec,\n HealthcheckSpec,\n PostSetupCheck,\n Quirk,\n} from './types.js'\n\nexport interface IntegrationOverride {\n /** Replaces `setup.consoleUrl` from the family default. */\n consoleUrl?: string\n /** Replaces `setup.consoleSteps`. Specify the full list — overrides do\n * not deep-merge step arrays because step ordering is meaningful. */\n consoleSteps?: ConsoleStep[]\n /** Replaces `setup.credentialFields`. Use to add a second field (e.g.\n * Twilio Account SID + Auth Token), tighten validation regex, or\n * enrich field descriptions with provider-specific guidance. */\n credentialFields?: CredentialFieldSpec[]\n /** Appended to `setup.knownQuirks`. */\n knownQuirks?: Quirk[]\n /** Replaces `setup.postSetup`. */\n postSetup?: PostSetupCheck[]\n /** Replaces the healthcheck the registry would otherwise infer. */\n healthcheck?: HealthcheckSpec\n}\n\nexport const INTEGRATION_OVERRIDES: Record<string, IntegrationOverride> = {\n tiktok: {\n consoleUrl: 'https://developers.tiktok.com/apps/',\n consoleSteps: [\n {\n id: 'app',\n title: 'Create or select the TikTok app',\n detail: 'Use one company-owned TikTok for Developers app for Tangle Integration Hub. Do not create a duplicate app.',\n },\n {\n id: 'products',\n title: 'Enable Login Kit and Content Posting',\n detail: 'Enable Login Kit, Content Posting API, and the user.info.basic, video.list, and video.publish scopes.',\n },\n {\n id: 'redirect',\n title: 'Register the callback',\n detail: 'Add {redirectUri} as an exact HTTPS web redirect URI.',\n copyValue: '{redirectUri}',\n },\n {\n id: 'urls',\n title: 'Verify publishing URLs',\n detail: 'Verify every HTTPS domain or URL prefix TikTok may pull videos and photos from.',\n },\n {\n id: 'test',\n title: 'Test a private post',\n detail: 'Connect a test creator, read creator information, publish private test media, and poll the publish id until completion.',\n },\n ],\n knownQuirks: [\n {\n id: 'private-until-audit',\n severity: 'critical',\n message: 'TikTok restricts unaudited Content Posting clients to private posts. Public visibility requires TikTok app review.',\n },\n {\n id: 'verified-pull-url',\n severity: 'critical',\n message: 'Direct posts can pull media only from an HTTPS domain or URL prefix verified for this TikTok app.',\n },\n {\n id: 'creator-preflight',\n severity: 'warning',\n message: 'TikTok requires current creator options before each direct post. The adapter performs this preflight and rejects unavailable privacy or duration choices.',\n },\n {\n id: 'token-lifetime',\n severity: 'info',\n message: 'Access tokens last about 24 hours. Refresh tokens last about 365 days and may rotate on refresh.',\n },\n ],\n postSetup: [\n {\n id: 'tiktok.private-publish',\n title: 'Prove one private direct post',\n detail: 'Publish media from a verified URL and poll the returned publish id until TikTok reports PUBLISH_COMPLETE.',\n },\n {\n id: 'tiktok.refresh',\n title: 'Prove token refresh',\n detail: 'Refresh the short-lived access token and preserve TikTok’s newly returned refresh token.',\n },\n ],\n healthcheck: {\n id: 'tiktok.user.info',\n level: 'connection',\n description: 'Read the connected TikTok account with user.info.basic.',\n },\n },\n amplitude: {\n consoleUrl: 'https://analytics.amplitude.com/',\n credentialFields: [\n {\n label: 'Amplitude project credential JSON',\n description: 'JSON containing the API key and secret key for one Amplitude project.',\n example: '{\"apiKey\":\"...\",\"secretKey\":\"...\"}',\n secret: true,\n },\n ],\n consoleSteps: [\n {\n id: 'project',\n title: 'Select one Amplitude project',\n detail: 'Open Project Settings > General for the project that Tangle may access.',\n },\n {\n id: 'credentials',\n title: 'Copy the project credentials',\n detail: 'Copy the API key and secret key into one JSON credential bundle.',\n },\n {\n id: 'region',\n title: 'Set the data region',\n detail: 'Use the default US host. Set apiBaseUrl to the documented EU host only for an EU project.',\n },\n {\n id: 'test',\n title: 'Test the project connection',\n detail: 'The connection check lists visible project events without changing analytics data.',\n },\n ],\n knownQuirks: [\n {\n id: 'project-bound',\n severity: 'warning',\n message: 'The API key and secret key belong to one project. Use a separate connection for each project.',\n },\n {\n id: 'region-bound',\n severity: 'critical',\n message: 'US and EU projects use different hosts. Tangle accepts only the two official Amplitude API hosts.',\n },\n {\n id: 'annotation-authority',\n severity: 'warning',\n message: 'Annotation changes require suitable Amplitude authority and remain approval-gated.',\n },\n ],\n healthcheck: {\n id: 'amplitude.connection',\n level: 'connection',\n description: 'Authenticate with the project credential pair and list visible events.',\n },\n },\n cloudflare: {\n consoleUrl: 'https://dash.cloudflare.com/profile/api-tokens/',\n credentialFields: [\n {\n label: 'Dedicated Cloudflare API token',\n description: 'Create a new resource-scoped token for Tangle Integration Hub. Do not reuse an infrastructure token.',\n secret: true,\n },\n ],\n consoleSteps: [\n {\n id: 'token',\n title: 'Create a dedicated API token',\n detail: 'Create a custom token named Tangle Integration Hub. Do not use the legacy Global API Key.',\n },\n {\n id: 'permissions',\n title: 'Grant narrow permissions',\n detail: 'Grant Account Settings Read, Zone Read, Zone Settings Read, and DNS Read or DNS Edit only.',\n },\n {\n id: 'resources',\n title: 'Limit the token to selected zones',\n detail: 'Include only the accounts and zones that this connection must manage.',\n },\n {\n id: 'store',\n title: 'Store the one-time token',\n detail: 'Copy the token once. Tangle Hub seals it before persistence.',\n },\n {\n id: 'test',\n title: 'Verify token status',\n detail: 'The connection check calls the token verification endpoint and requires active status.',\n },\n ],\n knownQuirks: [\n {\n id: 'no-global-key',\n severity: 'critical',\n message: 'Global API keys grant full user authority and are unsupported. Use a scoped API token.',\n },\n {\n id: 'no-token-reuse',\n severity: 'critical',\n message: 'Never reuse a token used by Tangle deployment, Workers, Terraform, DNS automation, or other infrastructure.',\n },\n {\n id: 'dns-impact',\n severity: 'critical',\n message: 'DNS updates can interrupt production traffic. Every DNS mutation remains approval-gated.',\n },\n ],\n healthcheck: {\n id: 'cloudflare.token',\n level: 'connection',\n description: 'Verify that the dedicated API token is valid and active.',\n },\n },\n nango: {\n consoleUrl: 'https://nango.dev/docs/getting-started/intro-to-nango',\n credentialFields: [],\n consoleSteps: [\n {\n id: 'gateway',\n title: 'Choose a Nango gateway deployment',\n detail: 'Use Nango only when a product intentionally deploys Nango Cloud or a self-hosted Nango environment.',\n },\n {\n id: 'runtime',\n title: 'Configure the gateway runtime',\n detail: 'Store the Nango host and environment secret in the product-owned gateway service, not as provider OAuth credentials.',\n },\n {\n id: 'providers',\n title: 'Configure real provider integrations',\n detail: 'Register each external provider in Nango and test its connection lifecycle separately.',\n },\n ],\n knownQuirks: [\n {\n id: 'gateway-not-provider',\n severity: 'critical',\n message: 'Nango is an integration gateway, not an end-user OAuth provider. This catalog entry has no generic Connect flow.',\n },\n {\n id: 'no-runtime',\n severity: 'critical',\n message: 'This package does not ship a Nango gateway backend. The entry remains non-executable until a product deploys one.',\n },\n ],\n healthcheck: {\n id: 'nango.static',\n level: 'static',\n description: 'No Nango gateway runtime is configured by this package.',\n },\n },\n mongodb: {\n credentialFields: [\n {\n label: 'MongoDB connection JSON',\n description: 'JSON containing a public MongoDB host, database, user, password, optional port/auth source, and optional CA certificate. Verified TLS is mandatory.',\n example: '{\"host\":\"cluster.example.mongodb.net\",\"port\":27017,\"database\":\"app\",\"user\":\"tangle_reader\",\"password\":\"...\",\"authSource\":\"admin\"}',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'user', title: 'Create a read-only MongoDB user', detail: 'Grant read on the intended database only. Do not grant write, cluster administration, JavaScript execution, or cross-database roles.' },\n { id: 'network', title: 'Allow the Hub connection', detail: 'Expose one MongoDB node through a public TLS endpoint and restrict its firewall to Hub egress addresses when available.' },\n { id: 'credential', title: 'Store the connection JSON', detail: 'Save the endpoint, database, read-only user, password, auth source, and optional CA certificate in the encrypted credential field.' },\n { id: 'test', title: 'Test the connection', detail: 'The check pins a public address, verifies the TLS hostname and certificate, authenticates, and runs a fixed ping command.' },\n ],\n knownQuirks: [\n { id: 'read-only', severity: 'info', message: 'The pack exposes collection/index metadata, structured scalar document reads, and counts only. Raw queries, JavaScript, aggregation, writes, and administrative commands are unavailable.' },\n { id: 'direct-node', severity: 'warning', message: 'The hosted adapter pins one public seed and disables topology discovery so a server cannot redirect Hub to unvalidated private nodes.' },\n { id: 'tls-only', severity: 'critical', message: 'Plain MongoDB connections are rejected. TLS 1.2 or newer and valid server certificates are mandatory.' },\n { id: 'bounded-results', severity: 'info', message: 'Document reads return at most 1,000 documents and 10 MiB and accept fixed scalar predicates instead of raw MongoDB query objects.' },\n { id: 'trigger-runtime', severity: 'warning', message: 'Change-stream triggers remain unavailable until a durable worker persists resume tokens and deliveries.' },\n ],\n healthcheck: {\n id: 'mongodb.connection',\n level: 'connection',\n description: 'Resolve and pin a public address, negotiate verified TLS, authenticate, and run a fixed ping command.',\n },\n },\n postgres: {\n credentialFields: [\n {\n label: 'PostgreSQL connection JSON',\n description: 'JSON containing a public PostgreSQL host, database, user, password, optional port, and optional CA certificate. Verified TLS is mandatory.',\n example: '{\"host\":\"postgres.example.com\",\"port\":5432,\"database\":\"app\",\"user\":\"tangle_reader\",\"password\":\"...\"}',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'user', title: 'Create a read-only PostgreSQL role', detail: 'Grant CONNECT on the database, USAGE on intended schemas, and SELECT on intended tables or views. Do not grant write, DDL, function execution, or replication privileges.' },\n { id: 'network', title: 'Allow the Hub connection', detail: 'Expose PostgreSQL through a public TLS endpoint and restrict its firewall to the Hub egress addresses when available.' },\n { id: 'credential', title: 'Store the connection JSON', detail: 'Save the endpoint, database, read-only role, password, and optional CA certificate in the encrypted credential field.' },\n { id: 'test', title: 'Test the connection', detail: 'The check pins a public address, verifies the TLS hostname and certificate, authenticates, and runs a fixed current-database query.' },\n ],\n knownQuirks: [\n { id: 'read-only', severity: 'info', message: 'The pack exposes metadata and structured SELECT reads only. Arbitrary SQL, functions, writes, DDL, COPY, and replication are not available.' },\n { id: 'tls-only', severity: 'critical', message: 'Plain PostgreSQL connections are rejected. TLS 1.2 or newer and valid server certificates are mandatory.' },\n { id: 'public-host', severity: 'warning', message: 'Hosted Hub rejects private, loopback, link-local, and mixed public/private DNS targets.' },\n { id: 'bounded-results', severity: 'info', message: 'Reads return at most 10,000 rows and 10 MiB and use bounded scalar predicates instead of raw SQL.' },\n { id: 'trigger-runtime', severity: 'warning', message: 'Database-change triggers remain unavailable until a durable logical-decoding or polling worker persists cursors and deliveries.' },\n ],\n healthcheck: {\n id: 'postgres.connection',\n level: 'connection',\n description: 'Resolve and pin a public address, negotiate verified TLS, authenticate, and run a fixed current-database query.',\n },\n },\n neverbounce: {\n consoleUrl: 'https://app.neverbounce.com/',\n credentialFields: [\n {\n label: 'NeverBounce API key',\n description: 'Create a dedicated API key in Apps > API. Verification calls consume account credits.',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'key', title: 'Create a dedicated API key', detail: 'Open Apps > API in NeverBounce and create a key for Tangle Integration Hub.' },\n { id: 'store', title: 'Store the API key', detail: 'Paste the key once. Tangle Hub seals it before persistence.' },\n { id: 'test', title: 'Test account access', detail: 'The connection check reads account information without verifying an address or spending a verification credit.' },\n ],\n knownQuirks: [\n { id: 'metered-verification', severity: 'warning', message: 'Every address verification can consume NeverBounce credits and remains approval-gated by default.' },\n { id: 'query-auth', severity: 'warning', message: 'NeverBounce requires the API key in the request query string. Tangle redacts it from errors and logs.' },\n ],\n healthcheck: {\n id: 'neverbounce.connection',\n level: 'connection',\n description: 'Read NeverBounce account information without consuming a verification credit.',\n },\n },\n redshift: {\n credentialFields: [\n {\n label: 'Redshift connection JSON',\n description: 'JSON containing a public Redshift host, database, user, password, optional port, and optional CA certificate. Verified TLS is mandatory.',\n example: '{\"host\":\"cluster.region.redshift.amazonaws.com\",\"port\":5439,\"database\":\"analytics\",\"user\":\"tangle_reader\",\"password\":\"...\"}',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'user', title: 'Create a read-only Redshift user', detail: 'Grant USAGE on intended schemas and SELECT on intended tables or views. Do not grant write, DDL, COPY, UNLOAD, or external-function privileges.' },\n { id: 'network', title: 'Allow the Hub connection', detail: 'Expose the cluster through a public TLS endpoint and restrict its security group or firewall to the Hub egress addresses when available.' },\n { id: 'credential', title: 'Store the connection JSON', detail: 'Save the endpoint, database, read-only user, password, and optional CA certificate in the encrypted credential field.' },\n { id: 'test', title: 'Test the connection', detail: 'The check pins a public address, verifies the TLS hostname and certificate, authenticates, and runs a fixed current-database query.' },\n ],\n knownQuirks: [\n { id: 'read-only', severity: 'info', message: 'The pack exposes metadata and structured SELECT reads only. Arbitrary SQL, writes, DDL, COPY, UNLOAD, and external functions are not available.' },\n { id: 'tls-only', severity: 'critical', message: 'Plain PostgreSQL connections are rejected. TLS 1.2 or newer and valid server certificates are mandatory.' },\n { id: 'public-host', severity: 'warning', message: 'Hosted Hub rejects private, loopback, link-local, and mixed public/private DNS targets.' },\n { id: 'bounded-results', severity: 'info', message: 'Reads return at most 10,000 rows and 10 MiB and use bounded scalar predicates instead of raw SQL.' },\n { id: 'trigger-runtime', severity: 'warning', message: 'The cataloged record-change trigger remains unavailable until an incremental polling worker persists its cursor and deliveries durably.' },\n ],\n healthcheck: {\n id: 'redshift.connection',\n level: 'connection',\n description: 'Resolve and pin a public address, negotiate verified TLS, authenticate, and run a fixed current-database query.',\n },\n },\n redis: {\n credentialFields: [\n {\n label: 'Redis connection JSON',\n description: 'JSON containing a public host, password, optional ACL username/database, and optional CA certificate. Verified TLS is mandatory.',\n example: '{\"host\":\"cache.example.com\",\"port\":6380,\"username\":\"default\",\"password\":\"...\",\"database\":0}',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'account', title: 'Create a restricted Redis user', detail: 'Grant only PING, SCAN, TYPE, PTTL, GET, SET, DEL, and EVAL access for the intended key patterns.' },\n { id: 'tls', title: 'Require verified TLS', detail: 'Use a public hostname with a valid certificate on the TLS listener. Plain Redis connections are rejected.' },\n { id: 'credential', title: 'Store the connection JSON', detail: 'Save the host, port, restricted ACL credentials, database number, and optional CA certificate in the encrypted credential field.' },\n { id: 'test', title: 'Test the connection', detail: 'The connection check pins a public address, verifies the TLS hostname and certificate, authenticates, and sends PING.' },\n ],\n knownQuirks: [\n { id: 'tls-only', severity: 'critical', message: 'Plain Redis is rejected. TLS 1.2 or newer and valid server certificates are mandatory.' },\n { id: 'standalone', severity: 'warning', message: 'This pack targets one standalone or managed primary endpoint. Redis Cluster and Sentinel discovery are not followed.' },\n { id: 'bounded-scan', severity: 'info', message: 'Key discovery uses bounded SCAN pages and never runs the blocking KEYS command.' },\n { id: 'string-writes', severity: 'info', message: 'Writes are limited to conditional string set/delete operations. Arbitrary commands and unconditional deletes are not exposed.' },\n { id: 'trigger-runtime', severity: 'warning', message: 'The cataloged key-change trigger remains unavailable until a durable subscriber can persist keyspace events before acknowledging delivery.' },\n ],\n healthcheck: {\n id: 'redis.connection',\n level: 'connection',\n description: 'Resolve and pin a public address, negotiate verified TLS, authenticate, send PING, and close.',\n },\n },\n rabbitmq: {\n credentialFields: [\n {\n label: 'RabbitMQ connection JSON',\n description: 'JSON containing a public host, username, password, optional port/vhost, and optional CA or mutual-TLS credentials. Verified TLS is mandatory.',\n example: '{\"host\":\"rabbitmq.example.com\",\"port\":5671,\"username\":\"tangle\",\"password\":\"...\",\"vhost\":\"/tenant\"}',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'account', title: 'Create a restricted RabbitMQ user', detail: 'Grant only configure, write, and read permissions required for the intended virtual host and resources.' },\n { id: 'tls', title: 'Expose a verified TLS listener', detail: 'Use an AMQPS listener on a public hostname with a valid certificate. Plain AMQP is rejected.' },\n { id: 'credential', title: 'Store the connection JSON', detail: 'Save the host, virtual host, restricted user, password, and optional TLS material in the encrypted credential field.' },\n { id: 'test', title: 'Test the connection', detail: 'The connection check verifies public routing, TLS certificate validation, and RabbitMQ authentication without publishing a message.' },\n ],\n knownQuirks: [\n { id: 'tls-only', severity: 'critical', message: 'Plaintext AMQP is rejected. TLS 1.2 or newer and valid server certificates are mandatory.' },\n { id: 'public-host', severity: 'warning', message: 'Hosted Hub rejects private, loopback, link-local, and mixed public/private DNS targets.' },\n { id: 'publisher-confirms', severity: 'info', message: 'Publish actions wait for broker confirmation and require the target queue or exchange to exist.' },\n { id: 'consumer-runtime', severity: 'warning', message: 'The cataloged Message Received trigger still requires a durable polling worker that persists each event before acknowledging it.' },\n ],\n healthcheck: {\n id: 'rabbitmq.connection',\n level: 'connection',\n description: 'Resolve a public host, negotiate verified TLS, authenticate, and close without publishing.',\n },\n },\n duckdb: {\n consoleSteps: [\n { id: 'ready', title: 'Use the built-in runtime', detail: 'No provider account, endpoint, or credential is required. Each invocation uses a new in-memory database.' },\n { id: 'query', title: 'Use query parameters', detail: 'Pass dynamic values through $1, $2, and the args array instead of interpolating them into SQL.' },\n ],\n knownQuirks: [\n { id: 'ephemeral', severity: 'info', message: 'Tables exist only for one invocation and are discarded immediately afterward.' },\n { id: 'external-access', severity: 'critical', message: 'File, network, extension, and attached-database access is disabled and locked before input tables are loaded.' },\n { id: 'bounded-runtime', severity: 'warning', message: 'Input, output, rows, schema depth and width, memory, threads, and execution time are bounded for hosted Hub safety.' },\n { id: 'integer-json', severity: 'info', message: 'DuckDB 64-bit integer results are serialized as decimal strings so JSON does not lose precision.' },\n ],\n healthcheck: {\n id: 'duckdb.runtime',\n level: 'connection',\n description: 'Open a secured in-memory DuckDB instance and execute SELECT 1.',\n },\n },\n kafka: {\n credentialFields: [\n {\n label: 'Kafka connection JSON',\n description: 'JSON containing public broker host:port entries and optional SASL or mutual-TLS credentials. TLS is always required.',\n example: '{\"brokers\":[\"broker.example.com:9093\"],\"saslMechanism\":\"scram-sha-512\",\"saslUsername\":\"...\",\"saslPassword\":\"...\"}',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'account', title: 'Create a restricted Kafka principal', detail: 'Grant only the topics, groups, and administrative operations required by approved Tangle workflows.' },\n { id: 'network', title: 'Expose TLS broker endpoints', detail: 'Use public TLS endpoints whose advertised broker addresses also resolve publicly.' },\n { id: 'credential', title: 'Store the connection JSON', detail: 'Paste brokers plus SASL or mutual-TLS credentials into the encrypted connection field.' },\n { id: 'test', title: 'Test topic discovery', detail: 'The connection check verifies public routing, TLS certificates, authentication, and topic-list permission without producing a record.' },\n ],\n knownQuirks: [\n { id: 'tls-only', severity: 'critical', message: 'Plaintext Kafka is rejected. TLS 1.2 or newer and valid broker certificates are mandatory.' },\n { id: 'public-brokers', severity: 'warning', message: 'Every bootstrap and advertised broker address must resolve publicly for hosted Hub execution.' },\n { id: 'consumer-rebalance', severity: 'warning', message: 'A bounded consume joins the supplied consumer group and may rebalance its members, so it always requires approval.' },\n { id: 'explicit-commit', severity: 'critical', message: 'Bounded consume never commits offsets automatically. Commit the returned next offsets only after downstream work succeeds.' },\n ],\n healthcheck: {\n id: 'kafka.connection',\n level: 'connection',\n description: 'Connect over TLS, authenticate, and list topics without producing or consuming records.',\n },\n },\n sftp: {\n credentialFields: [\n {\n label: 'SFTP connection JSON',\n description: 'JSON containing host, username, SHA-256 hostFingerprint, and password or privateKey; optional port, passphrase, and rootPath.',\n example: '{\"host\":\"sftp.example.com\",\"username\":\"integration\",\"password\":\"...\",\"hostFingerprint\":\"SHA256:...\",\"rootPath\":\"/incoming\"}',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'account', title: 'Create a restricted SFTP account', detail: 'Use a customer-owned account limited to the directories and operations Tangle needs.' },\n { id: 'fingerprint', title: 'Copy the server fingerprint', detail: 'Obtain the SHA-256 host-key fingerprint from the server administrator or a trusted out-of-band channel.' },\n { id: 'credential', title: 'Store the connection JSON', detail: 'Paste the host, username, authentication secret, host fingerprint, and optional root path into the encrypted connection field.' },\n { id: 'test', title: 'Test the connection', detail: 'The connection check verifies DNS, public routing, the pinned host key, authentication, and the configured root directory.' },\n ],\n knownQuirks: [\n { id: 'public-endpoint', severity: 'warning', message: 'The hosted Hub rejects private and local SFTP targets. Expose a restricted public endpoint or use customer-hosted execution.' },\n { id: 'host-key', severity: 'critical', message: 'Connections fail closed when the server host key differs from the stored SHA-256 fingerprint.' },\n { id: 'root-scope', severity: 'critical', message: 'All paths are confined to rootPath, including after symbolic-link resolution.' },\n ],\n healthcheck: {\n id: 'sftp.connection',\n level: 'connection',\n description: 'Connect, verify the pinned host key, authenticate, and read the current SFTP directory without modifying files.',\n },\n },\n 'azure-event-grid': {\n consoleUrl: 'https://portal.azure.com/#view/HubsExtension/BrowseResource/resourceType/Microsoft.EventGrid%2Ftopics',\n credentialFields: [\n {\n label: 'Azure Event Grid credential bundle',\n description: 'JSON containing the custom topic or domain endpoint, one topic access key, and a random delivery secret of at least 32 characters.',\n example: '{\"endpoint\":\"https://topic.region.eventgrid.azure.net/api/events\",\"accessKey\":\"...\",\"deliverySecret\":\"...\"}',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'topic', title: 'Select a custom topic or domain', detail: 'Open the customer-owned Event Grid topic or domain and copy its /api/events endpoint.' },\n { id: 'key', title: 'Copy one topic access key', detail: 'Use either active key and rotate between the primary and secondary keys without downtime.' },\n { id: 'secret', title: 'Generate a delivery secret', detail: 'Generate at least 32 random characters and store it with the endpoint and access key.' },\n { id: 'subscription', title: 'Configure authenticated delivery', detail: 'On each event subscription, add x-tangle-eventgrid-secret as a static secret delivery header with the same value.' },\n ],\n knownQuirks: [\n { id: 'static-health', severity: 'info', message: 'The setup check validates endpoint and credential structure. A live publish would create a real external event and remains approval-gated.' },\n { id: 'delivery-secret', severity: 'critical', message: 'Inbound delivery is rejected unless the event subscription sends the matching x-tangle-eventgrid-secret static delivery header.' },\n ],\n healthcheck: {\n id: 'azure-event-grid.credentials',\n level: 'static',\n description: 'Validate endpoint, topic key, and delivery-secret structure without publishing an event.',\n },\n },\n 'azure-service-bus': {\n consoleUrl: 'https://portal.azure.com/#view/HubsExtension/BrowseResource/resourceType/Microsoft.ServiceBus%2Fnamespaces',\n credentialFields: [\n {\n label: 'Azure Service Bus connection string',\n description: 'Use a dedicated shared access policy with only Send, Listen, or Manage rights required by approved workflows. EntityPath may restrict the connection to one queue or topic.',\n example: 'Endpoint=sb://namespace.servicebus.windows.net/;SharedAccessKeyName=...;SharedAccessKey=...;EntityPath=optional',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'namespace', title: 'Select the customer namespace', detail: 'Open the existing Azure Service Bus namespace or create one under the customer subscription.' },\n { id: 'policy', title: 'Create a narrow shared access policy', detail: 'Grant only Send, Listen, or Manage rights required by approved workflows.' },\n { id: 'entity', title: 'Prefer an entity-scoped connection', detail: 'Use a queue or topic EntityPath when namespace-wide discovery is not required.' },\n { id: 'store', title: 'Store the connection string', detail: 'Copy the primary or secondary connection string into the encrypted connection credential field.' },\n ],\n knownQuirks: [\n { id: 'destructive-receive', severity: 'critical', message: 'Receive-and-delete permanently removes the message as it is returned. Use it only when downstream handling can tolerate loss after a process failure.' },\n { id: 'format-only-health', severity: 'info', message: 'The setup health check validates connection-string structure without consuming or sending a message. Live permissions are confirmed on the first approved operation.' },\n ],\n healthcheck: {\n id: 'azure-service-bus.credentials',\n level: 'static',\n description: 'Validate the Azure Service Bus connection-string structure without sending or consuming a message.',\n },\n },\n 'gcloud-pubsub': {\n consoleUrl: 'https://console.cloud.google.com/cloudpubsub',\n credentialFields: [\n {\n label: 'Google Cloud service-account key JSON',\n description: 'Create a dedicated service account, grant only the required Pub/Sub roles, and paste its downloaded JSON key.',\n example: '{\"type\":\"service_account\",\"project_id\":\"...\",\"client_email\":\"...\",\"private_key\":\"...\"}',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'api', title: 'Enable the Pub/Sub API', detail: 'Enable Google Cloud Pub/Sub for the customer project.' },\n { id: 'service-account', title: 'Create a service account', detail: 'Create a dedicated Tangle Integration Hub service account.' },\n { id: 'roles', title: 'Grant narrow Pub/Sub roles', detail: 'Grant only viewer, publisher, subscriber, or editor access required by approved workflows.' },\n { id: 'key', title: 'Create and store a JSON key', detail: 'Create one JSON key and save it in the encrypted connection credential field.' },\n ],\n knownQuirks: [\n { id: 'at-least-once', severity: 'warning', message: 'Pub/Sub delivery is at-least-once by default. Consumers must deduplicate messages by a stable application identifier.' },\n { id: 'pull-ack', severity: 'warning', message: 'Pulling a message starts its acknowledgement deadline. Acknowledge it only after downstream work succeeds.' },\n ],\n },\n 'digital-ocean': {\n consoleUrl: 'https://cloud.digitalocean.com/account/api/tokens',\n credentialFields: [{ label: 'DigitalOcean personal access token', description: 'Create a dedicated token with only the read or write scopes required by approved workflows.', secret: true }],\n consoleSteps: [\n { id: 'token', title: 'Create a scoped token', detail: 'Create a dedicated token under API > Tokens with the smallest required scopes.' },\n { id: 'projects', title: 'Limit resource ownership', detail: 'Use dedicated projects and tags so connected automation touches only intended resources.' },\n { id: 'store', title: 'Store the token', detail: 'Paste the token once. Tangle Hub seals it before persistence.' },\n ],\n knownQuirks: [\n { id: 'billable-resources', severity: 'critical', message: 'Droplet, database, volume, and app creation can incur immediate charges. Keep all create, resize, action, and delete operations approval-gated.' },\n { id: 'irreversible-delete', severity: 'critical', message: 'Resource deletion can permanently destroy data. Require explicit destructive-action approval and verified backups.' },\n ],\n },\n clicksend: {\n consoleUrl: 'https://dashboard.clicksend.com/#/account/subaccounts',\n credentialFields: [\n {\n label: 'ClickSend API credential bundle',\n description: 'JSON containing username and apiKey from the ClickSend dashboard.',\n example: '{\"username\":\"...\",\"apiKey\":\"...\"}',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'account', title: 'Use a dedicated subaccount', detail: 'Create a restricted subaccount for Tangle Integration Hub when account isolation is required.' },\n { id: 'credentials', title: 'Copy API credentials', detail: 'Copy the ClickSend username and API key into the encrypted credential bundle.' },\n { id: 'sender', title: 'Configure approved senders', detail: 'Register and approve sender names or numbers before enabling outbound workflows.' },\n ],\n knownQuirks: [\n { id: 'paid-delivery', severity: 'warning', message: 'Outbound SMS and voice delivery incurs provider charges. Connection health and read operations do not send messages; keep outbound actions approval-gated.' },\n { id: 'sender-rules', severity: 'warning', message: 'Sender ID, consent, quiet-hours, and opt-out rules vary by destination country and remain the customer’s responsibility.' },\n ],\n },\n discourse: {\n consoleUrl: 'https://meta.discourse.org/t/create-and-configure-an-api-key/230124',\n credentialFields: [\n {\n label: 'Discourse API credential bundle',\n description: 'JSON containing apiKey and apiUsername. Store the public HTTPS forum root as connection metadata baseUrl.',\n example: '{\"apiKey\":\"...\",\"apiUsername\":\"system\"}',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'key', title: 'Create a scoped API key', detail: 'In Admin > API > Keys, create a dedicated key with the smallest required scope and user level.' },\n { id: 'username', title: 'Choose the acting user', detail: 'Use a dedicated service user whenever site-wide administrator authority is not required.' },\n { id: 'host', title: 'Record the forum URL', detail: 'Store the public HTTPS forum root as connection metadata baseUrl.' },\n { id: 'store', title: 'Store the credential bundle', detail: 'Save apiKey and apiUsername in the encrypted connection credential bundle.' },\n ],\n knownQuirks: [\n { id: 'acting-user', severity: 'warning', message: 'Every action is attributed to Api-Username and limited by both that user and the key scopes. Use separate keys for automation with different authority.' },\n { id: 'admin-actions', severity: 'warning', message: 'Category creation and moderation require staff or administrator authority and should remain approval-gated.' },\n ],\n },\n baserow: {\n consoleUrl: 'https://baserow.io/dashboard/settings/database-tokens',\n credentialFields: [\n {\n label: 'Baserow database token',\n description: 'Create a dedicated database token and grant only the required tables and create/read/update/delete permissions.',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'token', title: 'Create a database token', detail: 'Open workspace settings, create a dedicated token, and name it Tangle Integration Hub.' },\n { id: 'permissions', title: 'Limit table permissions', detail: 'Grant only the tables and create, read, update, or delete operations required by approved workflows.' },\n { id: 'store', title: 'Store the token', detail: 'Paste the token once. Tangle Hub seals it before persistence.' },\n ],\n knownQuirks: [\n { id: 'token-scope', severity: 'info', message: 'Database tokens intentionally cannot create tables or manage webhooks. Those account-level operations require a short-lived user JWT and are not advertised by this connector.' },\n { id: 'self-hosted-url', severity: 'info', message: 'For self-hosted Baserow, store the public HTTPS API root in connection metadata as baseUrl.' },\n ],\n },\n 'ping-identity': {\n consoleUrl: 'https://console.pingone.com/',\n credentialFields: [\n {\n label: 'PingOne worker credential bundle',\n description: 'JSON containing clientId, clientSecret, and region (us, ca, eu, au, or asia). Store the PingOne environment id as connection metadata.',\n example: '{\"clientId\":\"...\",\"clientSecret\":\"...\",\"region\":\"us\"}',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'worker-app', title: 'Create a worker application', detail: 'Create a dedicated PingOne worker application with the minimum user and group administration roles.' },\n { id: 'environment', title: 'Record environment and region', detail: 'Copy the PingOne environment id and select its deployment region.' },\n { id: 'credentials', title: 'Store worker credentials', detail: 'Save the client id and client secret in the encrypted connection credential bundle.' },\n ],\n },\n onelogin: {\n consoleUrl: 'https://admin.us.onelogin.com/api_credentials',\n credentialFields: [\n {\n label: 'OneLogin API credential bundle',\n description: 'JSON containing clientId, clientSecret, and region (us or eu).',\n example: '{\"clientId\":\"...\",\"clientSecret\":\"...\",\"region\":\"us\"}',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'credentials', title: 'Create API credentials', detail: 'Create dedicated OneLogin API credentials with Manage users or the smallest sufficient privilege.' },\n { id: 'region', title: 'Select tenant region', detail: 'Choose us or eu to pin both token and API requests to the tenant region.' },\n { id: 'store', title: 'Store credentials', detail: 'Save the client id and client secret in the encrypted connection credential bundle.' },\n ],\n },\n scim: {\n credentialFields: [\n {\n label: 'SCIM bearer token',\n description: 'Long-lived bearer token issued by the customer SCIM service provider.',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'endpoint', title: 'Record the SCIM base URL', detail: 'Use the public HTTPS SCIM 2.0 root, including any tenant path such as /scim/v2.' },\n { id: 'token', title: 'Create a provisioning token', detail: 'Issue a dedicated least-privileged bearer token for users, groups, and membership operations.' },\n { id: 'test', title: 'Test ServiceProviderConfig', detail: 'Verify the endpoint and token can read the SCIM ServiceProviderConfig resource.' },\n ],\n knownQuirks: [\n { id: 'provider-variance', severity: 'warning', message: 'SCIM providers vary in supported filters, PATCH paths, and ETag behavior; use provider-native PatchOp payloads when a service diverges from RFC 7644.' },\n ],\n },\n affinity: {\n consoleUrl: 'https://support.affinity.co/s/article/How-to-Create-and-Manage-API-Keys',\n credentialFields: [\n {\n label: 'Affinity API key',\n description: 'Bearer API key created by an Affinity workspace administrator. API availability and record access follow the workspace plan and key owner permissions.',\n secret: true,\n },\n ],\n consoleSteps: [\n { id: 'check-plan', title: 'Confirm API access', detail: 'Confirm the workspace plan includes Affinity API access.' },\n { id: 'create-key', title: 'Create an API key', detail: 'Create a dedicated key under Affinity Settings > API using a least-privileged integration user.' },\n { id: 'paste-key', title: 'Paste the API key', detail: 'Paste the key once. Tangle Hub seals it before persistence.' },\n ],\n knownQuirks: [\n { id: 'user-permissions', severity: 'warning', message: 'The key inherits its creator’s list-level and record permissions; missing records can be an authorization issue rather than a synchronization failure.' },\n ],\n },\n dealcloud: {\n consoleUrl: 'https://api.docs.dealcloud.com/',\n consoleSteps: [\n { id: 'contract', title: 'Confirm DealCloud API access', detail: 'Ask the DealCloud administrator or Intapp account team to enable API access for the customer site.' },\n { id: 'schema-contract', title: 'Publish a schema contract', detail: 'Publish a scoped Schema Contract that names the entry types and fields Tangle may synchronize.' },\n { id: 'credentials', title: 'Issue integration credentials', detail: 'Create customer-site credentials restricted to the published contract and Publications required for incremental synchronization.' },\n ],\n credentialFields: [],\n knownQuirks: [\n { id: 'commercial-access', severity: 'critical', message: 'DealCloud API access is customer-site and contract dependent. This entry remains non-executable until the customer supplies an approved schema contract, site URL, and credentials.' },\n { id: 'custom-schema', severity: 'warning', message: 'Every DealCloud site is customized; map through the published Schema Contract instead of assuming global object or field names.' },\n ],\n },\n otter: {\n consoleUrl: 'https://otter.ai/',\n consoleSteps: [\n { id: 'contract', title: 'Confirm Otter API access', detail: 'Confirm the customer plan and commercial agreement include supported API access for transcripts and meeting metadata.' },\n { id: 'credentials', title: 'Request integration credentials', detail: 'Obtain provider-issued credentials and the permitted workspace/account scope from Otter.' },\n { id: 'scope', title: 'Record permitted data use', detail: 'Record retention, participant-consent, and transcript access rules before enabling ingestion.' },\n ],\n credentialFields: [],\n knownQuirks: [\n { id: 'no-public-self-serve-api', severity: 'critical', message: 'No generally available self-serve Otter API credential flow is documented. This entry is contract-only until provider-approved access exists.' },\n ],\n },\n zoom: {\n consoleUrl: 'https://marketplace.zoom.us/develop/create',\n consoleSteps: [\n { id: 'app', title: 'Create a General App', detail: 'Create a user-managed General App in Zoom App Marketplace.' },\n { id: 'redirect', title: 'Add callback URL', detail: 'Add {redirectUri} as the OAuth redirect URL.', copyValue: '{redirectUri}' },\n { id: 'scopes', title: 'Add granular scopes', detail: 'Add the user, meeting, webinar, and recording scopes listed by this integration.' },\n { id: 'events', title: 'Enable event subscriptions', detail: 'Subscribe the Hub callback to meeting, recording, and transcript completion events needed by workflows.' },\n ],\n },\n 'microsoft-forms': {\n consoleUrl: 'https://learn.microsoft.com/microsoft-365/community/working-with-microsoft-forms-using-microsoft-graph',\n consoleSteps: [\n { id: 'confirm-api', title: 'Confirm supported Forms access', detail: 'Confirm the customer has a provider-supported Microsoft Forms API path for the required tenant and form ownership model.' },\n { id: 'approve', title: 'Approve tenant access', detail: 'Document the tenant administrator approval and the specific forms Tangle may read.' },\n ],\n credentialFields: [],\n knownQuirks: [\n { id: 'no-supported-graph-surface', severity: 'critical', message: 'Microsoft Graph does not expose a generally supported Forms response API. This entry stays non-executable until Microsoft provides or approves a supported access path.' },\n ],\n },\n 'microsoft-word': {\n consoleUrl: 'https://learn.microsoft.com/graph/api/resources/onedrive',\n consoleSteps: [\n { id: 'use-files', title: 'Connect OneDrive or SharePoint', detail: 'Use the existing OneDrive or SharePoint connector for Word file discovery, permissions, versions, and download/upload.' },\n { id: 'confirm-edit-api', title: 'Confirm document editing API', detail: 'Before enabling document-body edits, confirm a provider-supported Word editing API and tenant authorization path.' },\n ],\n credentialFields: [],\n knownQuirks: [\n { id: 'files-not-document-model', severity: 'critical', message: 'Microsoft Graph supports Word files through OneDrive and SharePoint but does not expose the full Word document object model. This entry stays non-executable for document-body actions.' },\n ],\n },\n // ── Stripe pack ────────────────────────────────────────────────────\n // Stripe issues two key types: secret keys (sk_*) and restricted keys\n // (rk_*). For voice-agent workloads, restricted keys are the right call\n // — least-privilege scoped to the specific resources the agent can\n // touch. The hint nudges operators toward that path.\n 'stripe-pack': {\n consoleUrl: 'https://dashboard.stripe.com/apikeys',\n credentialFields: [\n {\n label: 'Stripe secret key',\n description:\n 'Restricted key recommended. Dashboard → Developers → API keys → Create restricted key. ' +\n 'Grant write access on Customers, Invoices, and Checkout Sessions.',\n example: 'sk_live_… or rk_live_… (use sk_test_… / rk_test_… for staging)',\n regex: '^(sk|rk)_(live|test)_[A-Za-z0-9]+$',\n secret: true,\n },\n ],\n consoleSteps: [\n {\n id: 'open-keys',\n title: 'Open Stripe API keys',\n detail: 'Visit https://dashboard.stripe.com/apikeys',\n copyValue: 'https://dashboard.stripe.com/apikeys',\n },\n {\n id: 'create-restricted',\n title: 'Create a restricted key',\n detail:\n 'Click \"Create restricted key\". Name it something descriptive ' +\n '(e.g. \"ph0ny voice agent — prod\"). Grant WRITE on Customers, ' +\n 'Invoices, and Checkout Sessions. Leave everything else NONE.',\n },\n {\n id: 'paste',\n title: 'Paste the key',\n detail:\n 'Copy the key Stripe shows once (rk_live_… or sk_live_…). ' +\n 'Paste it into ph0ny. The key is sealed before persistence.',\n },\n ],\n },\n\n // ── Twilio SMS ─────────────────────────────────────────────────────\n // Twilio's REST API uses Basic auth with two parts: Account SID\n // (public-ish, AC…) + Auth Token (secret). The default api-key family\n // only exposes one field, which doesn't fit. Providing both fields\n // explicitly lets the consumer's UI render two inputs.\n 'twilio-sms': {\n consoleUrl: 'https://console.twilio.com/',\n credentialFields: [\n {\n label: 'Account SID',\n description: 'Your Twilio Account SID. Console → Account → API keys & tokens.',\n example: 'AC… (34 hex chars)',\n regex: '^AC[a-f0-9]{32}$',\n secret: false,\n },\n {\n label: 'Auth Token',\n description:\n 'Your Twilio Auth Token (or Standard API Key secret). ' +\n 'Use a non-primary auth token in production so rotating it ' +\n \"won't break other Twilio integrations.\",\n secret: true,\n },\n ],\n consoleSteps: [\n {\n id: 'open',\n title: 'Open Twilio console',\n detail: 'Visit https://console.twilio.com/',\n copyValue: 'https://console.twilio.com/',\n },\n {\n id: 'find',\n title: 'Find your Account SID + Auth Token',\n detail:\n 'Account info is on the dashboard home. For better security, ' +\n 'create a Standard API Key (Account → API keys & tokens → Create ' +\n 'API Key) and use the SID + Secret pair instead of the primary ' +\n 'auth token.',\n },\n {\n id: 'paste',\n title: 'Paste both values',\n detail: 'Account SID is non-secret; Auth Token is sealed before persistence.',\n },\n ],\n knownQuirks: [\n {\n id: 'subaccount-tokens',\n severity: 'info',\n message:\n 'If you use Twilio subaccounts, paste the SID/Token of the ' +\n 'subaccount that owns the phone numbers your agent calls — not ' +\n 'the master account.',\n },\n ],\n },\n\n // ── ph0ny ──────────────────────────────────────────────────────────\n // ph0ny issues a single Bearer API key per developer. The key is a\n // `plabs_` prefix followed by 32 url-safe nanoid chars. It is shown once\n // at creation (POST /v1/keys in the developer portal); only its hash is\n // stored server-side, so it cannot be retrieved later — rotate to replace.\n phony: {\n consoleUrl: 'https://api.ph0ny.com',\n credentialFields: [\n {\n label: 'ph0ny API key',\n description:\n 'Bearer key issued by ph0ny. Create one in the developer portal ' +\n '(POST /v1/keys). Sent as `Authorization: Bearer <key>`.',\n example: 'plabs_V1StGXR8Z5jdHi6BmyTAbCdEfGhIjKlm',\n regex: '^plabs_[A-Za-z0-9_-]{32}$',\n secret: true,\n },\n ],\n consoleSteps: [\n {\n id: 'open-portal',\n title: 'Open the ph0ny developer portal',\n detail: 'Visit https://api.ph0ny.com and sign in to the developer portal.',\n copyValue: 'https://api.ph0ny.com',\n },\n {\n id: 'create-key',\n title: 'Create an API key',\n detail:\n 'In the portal, create a new API key (POST /v1/keys). Give it a ' +\n 'descriptive name (e.g. \"tangle agent — prod\"). ph0ny returns the ' +\n 'full key exactly once.',\n },\n {\n id: 'paste',\n title: 'Paste the key',\n detail:\n 'Copy the plabs_… key ph0ny shows and paste it here. The key is ' +\n 'sealed before persistence.',\n },\n ],\n knownQuirks: [\n {\n id: 'key-shown-once',\n severity: 'warning',\n message:\n 'ph0ny stores only a hash of the key — the full plabs_… value is ' +\n 'shown exactly once at creation and cannot be retrieved later. Save ' +\n 'it immediately; if lost, rotate to issue a replacement.',\n },\n {\n id: 'rotate-endpoint',\n severity: 'info',\n message:\n 'Rotate a key with POST /v1/keys/:id/rotate. The old key is revoked ' +\n 'and a new plabs_… key is returned once — update this connection ' +\n 'with the new value.',\n },\n ],\n },\n}\n\n/** Public read — undefined when no override exists for the kind. */\nexport function getIntegrationOverride(kind: string): IntegrationOverride | undefined {\n return INTEGRATION_OVERRIDES[kind]\n}\n","import {\n buildIntegrationCoverageConnectors,\n listIntegrationCoverageSpecs,\n type IntegrationCoverageSpec,\n} from '../coverage-catalog.js'\nimport type {\n IntegrationConnector,\n IntegrationConnectorAction,\n IntegrationConnectorTrigger,\n IntegrationDataClass,\n} from '../core-types.js'\nimport {\n bundledApiKeyHint,\n bundledAuthMode,\n bundledOAuth2AuthContract,\n getBundledAdapterManifest,\n} from '../connectors/bundled-manifest-data.js'\nimport type {\n ConnectorManifest,\n OAuth2TokenClientAuthMethod,\n OAuth2UrlTemplateMetadataSpec,\n} from '../connectors/types.js'\nimport { canonicalIntegrationKind } from '../integration-kind-aliases.js'\nimport { INTEGRATION_FAMILIES, getIntegrationFamily } from './families.js'\nimport { getIntegrationOverride } from './overrides.js'\nimport type {\n ApiKeyAuthSpec,\n CustomAuthSpec,\n HealthcheckSpec,\n HmacAuthSpec,\n IntegrationAuthSpec,\n IntegrationFamilyId,\n IntegrationPlannerHints,\n IntegrationSpec,\n IntegrationSpecStatus,\n NoneAuthSpec,\n NormalizedPermission,\n OAuth2AuthSpec,\n PermissionDescriptor,\n ScopeDescriptor,\n} from './types.js'\n\n/**\n * Executability and OAuth endpoints are DERIVED from the bundled adapter\n * registry, never restated here.\n *\n * This used to be a hand-maintained `EXECUTABLE_KINDS` set of 18 names. The\n * package ships 530 adapters, so the set was wrong by two orders of magnitude\n * and every new adapter silently landed as `status: 'catalog'`. Worse, the\n * oauth2 branch of `authFor` fabricated `https://example.invalid/<kind>/...`\n * whenever the family table had no endpoint — 104 of 131 oauth2 entries — so\n * a Connect button could be wired to a reserved TLD that can never resolve.\n * A catalog that describes connectors must read the connectors.\n */\nfunction bundledManifestFor(kind: string, coverageId: string) {\n return getBundledAdapterManifest(kind) ?? getBundledAdapterManifest(coverageId)\n}\n\nexport function listIntegrationSpecs(): IntegrationSpec[] {\n const connectors = new Map(buildIntegrationCoverageConnectors({ providerId: 'spec' }).map((c) => [c.id, c]))\n return listIntegrationCoverageSpecs().map((coverage) => {\n const connector = connectors.get(coverage.id)\n if (!connector) throw new Error(`missing coverage connector for ${coverage.id}`)\n return specFromCoverage(coverage, connector)\n })\n}\n\nexport function getIntegrationSpec(kind: string): IntegrationSpec | undefined {\n const canonical = canonicalIntegrationKind(kind)\n return listIntegrationSpecs().find((spec) => canonicalIntegrationKind(spec.kind) === canonical)\n}\n\n/** Auth-driving descriptor the hub uses to start a connect flow per provider\n * instead of hard-coding scopes/auth kind. Derived from the spec catalog\n * ({@link getIntegrationSpec}); undefined when the kind is not in the\n * catalog. */\nexport interface ConnectorAuthSpec {\n kind: string\n authKind: 'oauth2' | 'api_key' | 'none' | 'custom'\n grantType?: 'authorization_code' | 'client_credentials'\n /** Provider scopes to request in the authorization grant. Empty for\n * api_key / none / custom. */\n requestedScopes: string[]\n /** OAuth-only: authorization + token endpoints and PKCE posture. Present\n * only when authKind === 'oauth2'. */\n authorizationUrl?: string\n tokenUrl?: string\n pkce?: 'required' | 'supported' | 'unsupported'\n redirectUriTemplate?: string\n clientIdEnv?: string\n clientSecretEnv?: string\n scopeSeparator?: ' ' | ','\n authorizationClientIdParam?: string\n tokenClientIdParam?: string\n tokenClientSecretParam?: string\n tokenClientAuthMethod?: OAuth2TokenClientAuthMethod\n sendScopeParam?: boolean\n extraAuthParams?: Record<string, string>\n urlTemplateMetadata?: Readonly<Record<string, OAuth2UrlTemplateMetadataSpec>>\n}\n\nexport function resolveConnectorAuthSpec(kind: string): ConnectorAuthSpec | undefined {\n const spec = getIntegrationSpec(kind)\n if (!spec) return undefined\n const auth = spec.auth\n if (auth.mode === 'oauth2') {\n return {\n kind: spec.kind,\n authKind: 'oauth2',\n grantType: auth.grantType,\n requestedScopes: auth.scopes.map((scope) => scope.providerScope).filter(Boolean),\n authorizationUrl: auth.authorizationUrl,\n tokenUrl: auth.tokenUrl,\n pkce: auth.pkce,\n redirectUriTemplate: auth.redirectUriTemplate,\n clientIdEnv: auth.clientIdEnv,\n clientSecretEnv: auth.clientSecretEnv,\n scopeSeparator: auth.scopeSeparator,\n authorizationClientIdParam: auth.authorizationClientIdParam,\n tokenClientIdParam: auth.tokenClientIdParam,\n tokenClientSecretParam: auth.tokenClientSecretParam,\n tokenClientAuthMethod: auth.tokenClientAuthMethod,\n sendScopeParam: auth.sendScopeParam,\n extraAuthParams: auth.extraAuthParams,\n urlTemplateMetadata: auth.urlTemplateMetadata,\n }\n }\n if (auth.mode === 'api_key') {\n return { kind: spec.kind, authKind: 'api_key', requestedScopes: [] }\n }\n if (auth.mode === 'none') {\n return { kind: spec.kind, authKind: 'none', requestedScopes: [] }\n }\n return { kind: spec.kind, authKind: 'custom', requestedScopes: [] }\n}\n\nexport function listExecutableIntegrationSpecs(): IntegrationSpec[] {\n return listIntegrationSpecs().filter((spec) => spec.status === 'executable')\n}\n\nexport function integrationSpecToConnector(spec: IntegrationSpec, providerId = 'spec'): IntegrationConnector {\n return {\n id: spec.kind,\n providerId,\n title: spec.title,\n category: spec.category,\n auth: spec.auth.mode === 'api_key' ? 'api_key' : spec.auth.mode === 'oauth2' ? 'oauth2' : spec.auth.mode === 'none' ? 'none' : 'custom',\n scopes: spec.permissions.flatMap((permission) => permission.providerScopes),\n actions: spec.actions,\n triggers: spec.triggers,\n metadata: {\n ...(spec.metadata ?? {}),\n source: 'integration-spec',\n status: spec.status,\n family: spec.family,\n plannerHints: spec.plannerHints,\n },\n }\n}\n\nfunction specFromCoverage(coverage: IntegrationCoverageSpec, connector: IntegrationConnector): IntegrationSpec {\n const kind = canonicalIntegrationKind(coverage.id)\n const family = familyFor(coverage)\n const familySpec = getIntegrationFamily(family)\n const manifest = bundledManifestFor(kind, coverage.id)\n // A spec with no shipped adapter has no real action ids to give. The\n // coverage table would supply four synthesized from its action pack, and\n // naming those is the failure this whole module exists to end: 33 of 143\n // specs have no adapter, and every one of them advertised invented calls\n // (`jira` claimed `tasks.search`/`tasks.read`/`tasks.create`/`tasks.update`,\n // `microsoft-excel` claimed `records.query`...). A model told about a tool\n // that cannot resolve spends the turn on it, and the failure reads as the\n // agent being broken. Listing the connector with NO actions is honest and\n // still discoverable — it is genuinely connectable, it just cannot run\n // anything yet.\n //\n // The synthesized set is still what `permissions` and `plannerHints` are\n // derived from, because those describe the DATA the connector reaches\n // (read/write shape, data class, provider scopes) rather than callable\n // entry points. Deriving them from an empty list instead would silently\n // drop the write permission and downgrade every one of the 33 to\n // `dataClass: 'public'` — trading a prompt defect for a consent defect.\n const derivationActions = manifest\n ? actionsFromManifest(manifest, dataClassFor(connector.actions))\n : connector.actions\n const actions = manifest ? derivationActions : []\n const permissions = permissionsFor(coverage, derivationActions)\n const auth = authFor(coverage, family, permissions, kind)\n const status = statusFor(kind, coverage.id)\n // Per-kind overrides layer in here — see specs/overrides.ts. The override\n // is consulted under the canonical kind AND the original coverage id so\n // alias-collapsed kinds (e.g. notion-database → notion) can carry an\n // override under either name.\n const override =\n getIntegrationOverride(kind) ?? getIntegrationOverride(coverage.id)\n // Family quirks + override quirks are concatenated; everything else is\n // a replace (override fields take precedence when present).\n const knownQuirks = override?.knownQuirks\n ? [...(familySpec.knownQuirks ?? []), ...override.knownQuirks]\n : familySpec.knownQuirks\n return {\n kind,\n title: connector.title,\n category: connector.category,\n status,\n family,\n auth,\n permissions,\n actions,\n triggers: connector.triggers,\n setup: {\n consoleUrl: override?.consoleUrl ?? familySpec.consoleUrl,\n consoleSteps: override?.consoleSteps ?? familySpec.consoleSteps,\n credentialFields: override?.credentialFields ?? credentialFieldsFor(auth),\n redirectUriTemplate: auth.mode === 'oauth2' ? auth.redirectUriTemplate : familySpec.redirectUriTemplate,\n knownQuirks,\n postSetup: override?.postSetup,\n healthcheck: override?.healthcheck ?? healthcheckFor(kind, status, auth),\n },\n lifecycle: familySpec.lifecycle,\n plannerHints: plannerHintsFor(coverage, derivationActions),\n metadata: { priority: coverage.priority, domains: coverage.domains },\n }\n}\n\nfunction familyFor(spec: IntegrationCoverageSpec): IntegrationFamilyId {\n if (hmacKinds.has(spec.id)) return 'hmac'\n if (spec.auth === 'none') return 'none'\n if (spec.id.startsWith('google-') || spec.domains.includes('google')) return 'google'\n if (spec.id.startsWith('microsoft-') || ['outlook-mail', 'outlook-calendar', 'onedrive', 'sharepoint'].includes(spec.id)) return 'microsoft-graph'\n if (['jira', 'confluence', 'trello', 'bitbucket'].includes(spec.id)) return 'atlassian'\n if (spec.id === 'salesforce') return 'salesforce'\n if (spec.id === 'hubspot') return 'hubspot'\n if (spec.id === 'slack') return 'slack'\n if (spec.id === 'notion') return 'notion'\n if (apiKeyKinds.has(spec.id)) return 'api-key'\n return 'standard-oauth2'\n}\n\nconst apiKeyKinds = new Set(['github', 'gitlab', 'airtable', 'asana', 'stripe', 'twilio', 'sendgrid', 'postmark', 'phony'])\nconst hmacKinds = new Set(['webhook'])\n\nfunction authFor(\n spec: IntegrationCoverageSpec,\n family: IntegrationFamilyId,\n permissions: PermissionDescriptor[],\n kind: string,\n): IntegrationAuthSpec {\n const f = INTEGRATION_FAMILIES[family]\n // The shipped adapter decides HOW a connector authenticates. The coverage\n // table only guesses: it defaults every unlisted entry to the\n // `standard-oauth2` family, which is how Coda — an api-key connector —\n // came to advertise an OAuth flow it does not have.\n const manifest = bundledManifestFor(kind, spec.id)\n const realMode = manifest ? bundledAuthMode(manifest) : undefined\n if (spec.auth === 'custom' && !manifest) {\n return {\n mode: 'custom',\n description: `${spec.title} requires provider- or workspace-specific credentials and transport configuration.`,\n } satisfies CustomAuthSpec\n }\n if (realMode === 'none') return { mode: 'none' } satisfies NoneAuthSpec\n if (realMode === 'hmac') {\n return {\n mode: 'hmac',\n credential: INTEGRATION_FAMILIES.hmac.credentialFields[0]!,\n signatureHeader: `${spec.id}-signature`,\n } satisfies HmacAuthSpec\n }\n if (realMode === 'api_key') {\n const hint = manifest ? bundledApiKeyHint(manifest) : undefined\n const credential = apiKeyFieldFor(spec.id)\n return {\n mode: 'api_key',\n credential: hint ? { ...credential, description: hint } : credential,\n placement: apiKeyPlacementFor(spec.id),\n } satisfies ApiKeyAuthSpec\n }\n if (family === 'none' && !realMode) return { mode: 'none' } satisfies NoneAuthSpec\n if (family === 'hmac' && !realMode) {\n return { mode: 'hmac', credential: f.credentialFields[0]!, signatureHeader: `${spec.id}-signature` } satisfies HmacAuthSpec\n }\n if (family === 'api-key' && !realMode) {\n return { mode: 'api_key', credential: apiKeyFieldFor(spec.id), placement: apiKeyPlacementFor(spec.id) } satisfies ApiKeyAuthSpec\n }\n const scopes = permissions.flatMap((permission) =>\n permission.providerScopes.map((providerScope): ScopeDescriptor => ({\n normalized: permission.normalized,\n providerScope,\n title: permission.title,\n reason: permission.reason,\n risk: permission.risk,\n dataClass: permission.dataClass,\n })),\n )\n // A shipped adapter is the authority on how its provider authenticates:\n // it holds the endpoints the connect flow actually posts to and the exact\n // scope set the grant must request. Prefer it over the family defaults,\n // and never substitute a placeholder when neither knows — an absent URL is\n // a fact the caller can check, whereas `https://example.invalid/...` is a\n // dead link that reads as configuration.\n const real = manifest ? bundledOAuth2AuthContract(manifest) : undefined\n const tokenClientAuthMethod = real?.tokenClientAuthMethod ?? 'client_secret_post'\n return {\n mode: 'oauth2',\n grantType: real?.grantType === 'client_credentials' ? 'client_credentials' : undefined,\n authorizationUrl: real?.grantType === 'client_credentials'\n ? undefined\n : real?.authorizationUrl ?? f.authorizationUrl,\n tokenUrl: real?.tokenUrl ?? f.tokenUrl,\n clientIdEnv: real?.clientIdEnv ?? f.credentialFields.find((field) => !field.secret)?.env,\n clientSecretEnv: tokenClientAuthMethod === 'none'\n ? undefined\n : real?.clientSecretEnv ?? f.credentialFields.find((field) => field.secret)?.env,\n scopeSeparator: real?.scopeSeparator ?? ' ',\n authorizationClientIdParam: real?.authorizationClientIdParam ?? 'client_id',\n tokenClientIdParam: real?.tokenClientIdParam ?? 'client_id',\n tokenClientSecretParam: real?.tokenClientSecretParam ?? 'client_secret',\n tokenClientAuthMethod,\n sendScopeParam: real?.sendScopeParam,\n scopes: real ? scopesFromManifest(real.scopes, permissions) : scopes,\n extraAuthParams: real?.extraAuthParams ?? extraAuthParamsFor(family),\n urlTemplateMetadata: real?.urlTemplateMetadata,\n redirectUriTemplate: (f.redirectUriTemplate ?? 'https://{host}/api/integrations/oauth/{kind}/callback').replace('{kind}', spec.id),\n pkce: real?.pkce ?? (\n family === 'google' || family === 'microsoft-graph'\n ? 'supported'\n : 'required'\n ),\n } satisfies OAuth2AuthSpec\n}\n\n/**\n * The action list an agent is shown, taken from the adapter's own capability\n * catalog.\n *\n * The coverage table synthesizes actions from 19 generic \"action packs\", so\n * every finance-pack connector advertised the same four names —\n * `transactions.search`, `accounts.read`, `invoices.create`, `records.sync`.\n * For QuickBooks and Xero, one of those four exists. The other three are tool\n * calls that can only fail, while the capabilities that DO exist (`reports.get`,\n * `entities.query`, `tenants.list`) went unmentioned. Naming a tool that does\n * not exist is worse than naming none: the model spends the turn on it.\n */\nfunction actionsFromManifest(\n manifest: ConnectorManifest,\n fallbackDataClass: IntegrationDataClass,\n): IntegrationConnectorAction[] {\n return manifest.capabilities.map((capability): IntegrationConnectorAction => {\n const mutation = capability.class === 'mutation'\n return {\n id: capability.name,\n title: capability.name,\n risk: mutation ? 'write' : 'read',\n requiredScopes: capability.requiredScopes ? [...capability.requiredScopes] : [],\n dataClass: fallbackDataClass,\n ...(capability.consistencyModel ? { consistencyModel: capability.consistencyModel } : {}),\n description: capability.description,\n // A mutation reaching resources outside the caller needs confirmation\n // before it runs; the adapter is what knows which those are.\n approvalRequired: mutation ? capability.externalEffect : undefined,\n inputSchema: capability.parameters,\n }\n })\n}\n\n/** Pair the adapter's REAL provider scopes with the closest permission\n * descriptor for UI copy. The scope SET is taken verbatim from the manifest\n * because it is what the authorization grant actually requests — only the\n * surrounding title/risk labelling is matched heuristically, by whether the\n * scope names a mutating capability. */\nfunction scopesFromManifest(\n providerScopes: string[],\n permissions: PermissionDescriptor[],\n): ScopeDescriptor[] {\n const writePermission = permissions.find((permission) => permission.risk === 'write')\n const readPermission = permissions.find((permission) => permission.risk === 'read') ?? permissions[0]\n return providerScopes.map((providerScope): ScopeDescriptor => {\n const mutating = /(?:^|[.\\/_:-])(?:write|manage|create|modify|edit|update|delete|publish|full|readwrite)(?:$|[.\\/_:-])/i.test(\n providerScope,\n )\n const base = (mutating ? writePermission : readPermission) ?? readPermission\n return {\n normalized: base?.normalized ?? 'unknown.read',\n providerScope,\n title: base?.title ?? providerScope,\n reason: base?.reason ?? 'Requested by the connector.',\n risk: mutating ? 'write' : 'read',\n dataClass: base?.dataClass ?? 'private',\n }\n })\n}\n\nfunction credentialFieldsFor(auth: IntegrationAuthSpec) {\n if (auth.mode === 'api_key' || auth.mode === 'hmac') return [auth.credential]\n if (auth.mode === 'oauth2') {\n const fields = [\n { label: 'Client ID', env: auth.clientIdEnv, description: 'OAuth client ID.', secret: false },\n ]\n if (auth.tokenClientAuthMethod !== 'none') {\n fields.push({\n label: 'Client Secret',\n env: auth.clientSecretEnv,\n description: 'OAuth client secret.',\n secret: true,\n })\n }\n return fields\n }\n return []\n}\n\nfunction permissionsFor(spec: IntegrationCoverageSpec, actions: IntegrationConnectorAction[]): PermissionDescriptor[] {\n const dataClass = dataClassFor(actions)\n const readScope = providerScopeFor(spec, 'read')\n const writeScope = providerScopeFor(spec, 'write')\n const permissions: PermissionDescriptor[] = [\n {\n normalized: `${spec.actionPack}.read` as NormalizedPermission,\n providerScopes: readScope ? [readScope] : [],\n title: `${spec.title} read`,\n risk: 'read',\n dataClass,\n reason: `Read ${spec.title} data for user-authorized agent workflows.`,\n },\n ]\n if (actions.some((a) => a.risk !== 'read')) {\n permissions.push({\n normalized: `${spec.actionPack}.write` as NormalizedPermission,\n providerScopes: writeScope ? [writeScope] : [],\n title: `${spec.title} write`,\n risk: 'write',\n dataClass,\n reason: `Create or update ${spec.title} resources after policy approval.`,\n })\n }\n return permissions\n}\n\nfunction providerScopeFor(spec: IntegrationCoverageSpec, mode: 'read' | 'write'): string {\n const explicit = explicitScopes[spec.id]?.[mode]\n if (explicit) return explicit\n if (spec.auth === 'none') return ''\n return `${spec.id}.${mode}`\n}\n\nconst explicitScopes: Record<string, Partial<Record<'read' | 'write', string>>> = {\n gmail: { read: 'https://www.googleapis.com/auth/gmail.readonly', write: 'https://www.googleapis.com/auth/gmail.modify' },\n 'google-calendar': { read: 'https://www.googleapis.com/auth/calendar.readonly', write: 'https://www.googleapis.com/auth/calendar' },\n 'google-sheets': { read: 'https://www.googleapis.com/auth/spreadsheets.readonly', write: 'https://www.googleapis.com/auth/spreadsheets' },\n 'google-drive': { read: 'https://www.googleapis.com/auth/drive.readonly', write: 'https://www.googleapis.com/auth/drive.file' },\n 'google-docs': { read: 'https://www.googleapis.com/auth/documents.readonly', write: 'https://www.googleapis.com/auth/documents' },\n 'outlook-mail': { read: 'Mail.Read', write: 'Mail.Send' },\n 'outlook-calendar': { read: 'Calendars.Read', write: 'Calendars.ReadWrite' },\n 'microsoft-teams': { read: 'ChannelMessage.Read.All', write: 'ChannelMessage.Send' },\n onedrive: { read: 'Files.Read', write: 'Files.ReadWrite' },\n sharepoint: { read: 'Sites.Read.All', write: 'Sites.ReadWrite.All' },\n slack: { read: 'channels:read', write: 'chat:write' },\n hubspot: { read: 'crm.objects.contacts.read', write: 'crm.objects.contacts.write' },\n salesforce: { read: 'api', write: 'api' },\n notion: { read: '', write: '' },\n github: { read: 'repo:read', write: 'repo' },\n gitlab: { read: 'read_api', write: 'api' },\n airtable: { read: 'data.records:read', write: 'data.records:write' },\n asana: { read: 'default', write: 'default' },\n stripe: { read: 'read_only', write: 'standard' },\n twilio: { read: 'api_key', write: 'api_key' },\n}\n\nfunction plannerHintsFor(spec: IntegrationCoverageSpec, actions: IntegrationConnectorAction[]): IntegrationPlannerHints {\n return {\n useFor: spec.domains.map((domain) => domain.replace(/-/g, ' ')),\n dataFreshness: ['calendar', 'chat', 'commerce', 'finance', 'support'].includes(spec.actionPack) ? 'near_realtime' : 'eventual',\n writeRisk: actions.some((a) => a.risk === 'destructive') ? 'high' : actions.some((a) => a.risk === 'write') ? 'medium' : 'low',\n }\n}\n\nfunction healthcheckFor(kind: string, status: IntegrationSpecStatus, auth: IntegrationAuthSpec): HealthcheckSpec {\n if (status !== 'executable') {\n return { id: `${kind}.static`, level: 'static', description: 'Catalog-only integration; no executable connector healthcheck is available yet.' }\n }\n if (auth.mode === 'oauth2') {\n return { id: `${kind}.connection`, level: 'connection', description: 'Validate a user connection by calling the connector test endpoint.' }\n }\n if (auth.mode === 'api_key') {\n return { id: `${kind}.connection`, level: 'connection', description: 'Validate API credentials by calling the connector test endpoint.' }\n }\n if (auth.mode === 'hmac') {\n return { id: `${kind}.webhook`, level: 'webhook', description: 'Validate webhook signing configuration with a signed test payload.' }\n }\n return { id: `${kind}.static`, level: 'static', description: 'No credentials are required.' }\n}\n\nfunction statusFor(kind: string, coverageId: string): IntegrationSpecStatus {\n return bundledManifestFor(kind, coverageId) ? 'executable' : 'catalog'\n}\n\nfunction dataClassFor(actions: IntegrationConnectorAction[]): IntegrationDataClass {\n if (actions.some((a) => a.dataClass === 'secret')) return 'secret'\n if (actions.some((a) => a.dataClass === 'sensitive')) return 'sensitive'\n if (actions.some((a) => a.dataClass === 'private')) return 'private'\n if (actions.some((a) => a.dataClass === 'internal')) return 'internal'\n return 'public'\n}\n\nfunction apiKeyFieldFor(kind: string) {\n return {\n label: `${kind} API key`,\n description: `API key or token for ${kind}.`,\n example: kind === 'stripe' ? 'sk_live_...' : undefined,\n secret: true,\n }\n}\n\nfunction apiKeyPlacementFor(kind: string): ApiKeyAuthSpec['placement'] {\n if (kind === 'sftp' || kind === 'kafka') return undefined\n if (kind === 'amplitude') return 'basic'\n if (kind === 'clickup' || kind === 'gitlab') return 'header'\n return 'bearer'\n}\n\nfunction extraAuthParamsFor(family: IntegrationFamilyId): Record<string, string> | undefined {\n if (family === 'google') return { access_type: 'offline', prompt: 'consent', include_granted_scopes: 'true' }\n if (family === 'notion') return { owner: 'user' }\n return undefined\n}\n","import type {\n IntegrationActionRisk,\n IntegrationConnector,\n IntegrationConnectorAction,\n IntegrationConnectorCategory,\n IntegrationConnectorTrigger,\n IntegrationDataClass,\n} from '../core-types.js'\nimport type {\n OAuth2TokenClientAuthMethod,\n OAuth2UrlTemplateMetadataSpec,\n} from '../connectors/types.js'\n\nexport type IntegrationAuthMode = 'oauth2' | 'api_key' | 'hmac' | 'none' | 'custom'\n\nexport type IntegrationSpecStatus = 'catalog' | 'executable' | 'deprecated'\n\nexport type IntegrationFamilyId =\n | 'google'\n | 'microsoft-graph'\n | 'atlassian'\n | 'salesforce'\n | 'hubspot'\n | 'slack'\n | 'notion'\n | 'standard-oauth2'\n | 'api-key'\n | 'hmac'\n | 'none'\n\nexport type NormalizedPermission =\n | `${string}.read`\n | `${string}.write`\n | `${string}.delete`\n | `${string}.admin`\n\nexport interface IntegrationSpec {\n kind: string\n title: string\n category: IntegrationConnectorCategory\n status: IntegrationSpecStatus\n family: IntegrationFamilyId\n auth: IntegrationAuthSpec\n permissions: PermissionDescriptor[]\n actions: IntegrationConnectorAction[]\n triggers?: IntegrationConnectorTrigger[]\n setup: IntegrationSetupSpec\n lifecycle?: IntegrationLifecycleSpec\n plannerHints?: IntegrationPlannerHints\n metadata?: Record<string, unknown>\n}\n\nexport type IntegrationAuthSpec =\n | OAuth2AuthSpec\n | ApiKeyAuthSpec\n | HmacAuthSpec\n | NoneAuthSpec\n | CustomAuthSpec\n\nexport interface OAuth2AuthSpec {\n mode: 'oauth2'\n /** OAuth grant the connection runtime must drive. */\n grantType?: 'authorization_code' | 'client_credentials'\n /** Authorization endpoint the connect flow sends the user to.\n *\n * UNDEFINED when no shipped adapter and no family default supplies one —\n * i.e. the catalog knows the integration exists but nothing can currently\n * authenticate it. Callers must treat undefined as \"not connectable\" and\n * say so; this field was previously filled with\n * `https://example.invalid/<kind>/authorize`, a reserved TLD that can\n * never resolve, which made unconnectable integrations indistinguishable\n * from working ones. */\n authorizationUrl?: string\n /** Token endpoint. Undefined under the same condition as\n * {@link authorizationUrl}. */\n tokenUrl?: string\n clientIdEnv?: string\n clientSecretEnv?: string\n scopeSeparator?: ' ' | ','\n authorizationClientIdParam?: string\n tokenClientIdParam?: string\n tokenClientSecretParam?: string\n /** OAuth client authentication at the token endpoint. Defaults to\n * `client_secret_post` when omitted. */\n tokenClientAuthMethod?: OAuth2TokenClientAuthMethod\n scopes: ScopeDescriptor[]\n /** Whether the authorize request includes `scope`. Defaults to true. */\n sendScopeParam?: boolean\n extraAuthParams?: Record<string, string>\n /** Rules for connection metadata in authorizationUrl or tokenUrl templates. */\n urlTemplateMetadata?: Readonly<Record<string, OAuth2UrlTemplateMetadataSpec>>\n redirectUriTemplate: string\n pkce?: 'required' | 'supported' | 'unsupported'\n}\n\nexport interface ApiKeyAuthSpec {\n mode: 'api_key'\n credential: CredentialFieldSpec\n placement?: 'bearer' | 'header' | 'query' | 'basic'\n}\n\nexport interface HmacAuthSpec {\n mode: 'hmac'\n credential: CredentialFieldSpec\n signatureHeader?: string\n}\n\nexport interface NoneAuthSpec {\n mode: 'none'\n}\n\nexport interface CustomAuthSpec {\n mode: 'custom'\n description: string\n}\n\nexport interface ScopeDescriptor {\n normalized: NormalizedPermission\n providerScope: string\n title: string\n reason: string\n risk: IntegrationActionRisk\n dataClass: IntegrationDataClass\n}\n\nexport interface PermissionDescriptor {\n normalized: NormalizedPermission\n providerScopes: string[]\n title: string\n risk: IntegrationActionRisk\n dataClass: IntegrationDataClass\n reason: string\n}\n\nexport interface CredentialFieldSpec {\n label: string\n description: string\n env?: string\n example?: string\n regex?: string\n secret: boolean\n}\n\nexport interface ConsoleStep {\n id: string\n title: string\n detail: string\n copyValue?: string\n}\n\nexport interface Quirk {\n id: string\n severity: 'info' | 'warning' | 'critical'\n message: string\n}\n\nexport interface PostSetupCheck {\n id: string\n title: string\n detail: string\n}\n\nexport interface HealthcheckSpec {\n id: string\n level: 'client_config' | 'connection' | 'webhook' | 'static'\n method?: 'GET' | 'POST'\n url?: string\n expectedStatus?: number[]\n description: string\n}\n\nexport interface IntegrationSetupSpec {\n consoleUrl?: string\n consoleSteps: ConsoleStep[]\n credentialFields: CredentialFieldSpec[]\n redirectUriTemplate?: string\n knownQuirks?: Quirk[]\n postSetup?: PostSetupCheck[]\n healthcheck?: HealthcheckSpec\n}\n\nexport interface IntegrationLifecycleSpec {\n supportsRefresh: boolean\n supportsRevoke: boolean\n supportsIncrementalAuth: boolean\n recommendedHealthcheckIntervalHours?: number\n freshnessSloMinutes?: number\n}\n\nexport interface IntegrationPlannerHints {\n useFor: string[]\n avoidFor?: string[]\n dataFreshness: 'realtime' | 'near_realtime' | 'eventual' | 'manual'\n writeRisk: 'low' | 'medium' | 'high'\n}\n\nexport interface IntegrationFamilySpec {\n id: IntegrationFamilyId\n title: string\n authMode: IntegrationAuthMode\n consoleUrl?: string\n authorizationUrl?: string\n tokenUrl?: string\n redirectUriTemplate?: string\n credentialFields: CredentialFieldSpec[]\n consoleSteps: ConsoleStep[]\n knownQuirks?: Quirk[]\n lifecycle: IntegrationLifecycleSpec\n}\n\nexport interface IntegrationSpecValidationIssue {\n path: string\n message: string\n}\n\nexport interface IntegrationSpecValidationResult {\n ok: boolean\n issues: IntegrationSpecValidationIssue[]\n}\n\nexport interface RenderSpecOptions {\n host: string\n callbackPath?: string\n}\n\nexport interface RenderedConsoleStep extends ConsoleStep {\n detail: string\n copyValue?: string\n}\n\nexport interface CredentialValidationInput {\n field: CredentialFieldSpec\n value: string\n}\n\nexport interface CredentialValidationResult {\n ok: boolean\n field: string\n message?: string\n}\n\nexport interface HealthcheckPlan {\n kind: string\n healthcheck: HealthcheckSpec\n requires: Array<'client_id' | 'client_secret' | 'api_key' | 'hmac_secret' | 'connection_credentials'>\n message: string\n}\n\nexport function specAuthToConnectorAuth(auth: IntegrationAuthSpec): IntegrationConnector['auth'] {\n if (auth.mode === 'api_key') return 'api_key'\n if (auth.mode === 'oauth2') return 'oauth2'\n if (auth.mode === 'none') return 'none'\n return 'custom'\n}\n","import type {\n ConsoleStep,\n HealthcheckPlan,\n IntegrationSpec,\n RenderSpecOptions,\n RenderedConsoleStep,\n} from './types.js'\n\nexport function renderConsoleSteps(spec: IntegrationSpec, options: RenderSpecOptions): RenderedConsoleStep[] {\n const redirectUri = renderRedirectUri(spec, options)\n return spec.setup.consoleSteps.map((step) => ({\n ...step,\n detail: renderTemplate(step.detail, spec, options, redirectUri),\n copyValue: step.copyValue ? renderTemplate(step.copyValue, spec, options, redirectUri) : undefined,\n }))\n}\n\nexport function renderRunbookMarkdown(spec: IntegrationSpec, options: RenderSpecOptions): string {\n const steps = renderConsoleSteps(spec, options)\n const lines = [\n `# ${spec.title} Integration Setup`,\n '',\n `- Kind: \\`${spec.kind}\\``,\n `- Status: \\`${spec.status}\\``,\n `- Auth: \\`${spec.auth.mode}\\``,\n `- Family: \\`${spec.family}\\``,\n ]\n if (spec.setup.consoleUrl) lines.push(`- Console: ${spec.setup.consoleUrl}`)\n if (spec.setup.redirectUriTemplate) lines.push(`- Redirect URI: \\`${renderRedirectUri(spec, options)}\\``)\n lines.push('', '## Credentials', '')\n for (const field of spec.setup.credentialFields) {\n lines.push(`- ${field.secret ? '[secret] ' : ''}${field.label}${field.env ? ` (\\`${field.env}\\`)` : ''}: ${field.description}`)\n }\n lines.push('', '## Permissions', '')\n for (const permission of spec.permissions) {\n lines.push(`- \\`${permission.normalized}\\`: ${permission.providerScopes.length ? permission.providerScopes.map((scope) => `\\`${scope}\\``).join(', ') : 'no provider scope'} - ${permission.reason}`)\n }\n lines.push('', '## Console Steps', '')\n for (const [i, step] of steps.entries()) {\n lines.push(`${i + 1}. ${step.title}: ${step.detail}`)\n }\n if (spec.setup.knownQuirks?.length) {\n lines.push('', '## Known Quirks', '')\n for (const quirk of spec.setup.knownQuirks) lines.push(`- ${quirk.severity}: ${quirk.message}`)\n }\n return `${lines.join('\\n')}\\n`\n}\n\nexport function renderAgentToolDescription(spec: IntegrationSpec): string {\n const hints = spec.plannerHints\n const useFor = hints?.useFor?.length ? `Use for ${hints.useFor.join(', ')}.` : `Use for ${spec.title} workflows.`\n const risk = hints ? `Freshness: ${hints.dataFreshness}. Write risk: ${hints.writeRisk}.` : ''\n return `${spec.title} (${spec.kind}). ${useFor} ${risk}`.trim()\n}\n\nexport function buildHealthcheckPlan(spec: IntegrationSpec): HealthcheckPlan {\n const healthcheck = spec.setup.healthcheck ?? { id: `${spec.kind}.static`, level: 'static', description: 'No healthcheck defined.' as const }\n const requires: HealthcheckPlan['requires'] = []\n if (healthcheck.level === 'connection') requires.push('connection_credentials')\n if (healthcheck.level === 'client_config' && spec.auth.mode === 'oauth2') requires.push('client_id', 'client_secret')\n if (spec.auth.mode === 'api_key') requires.push('api_key')\n if (spec.auth.mode === 'hmac') requires.push('hmac_secret')\n return {\n kind: spec.kind,\n healthcheck,\n requires,\n message: healthcheck.description,\n }\n}\n\nfunction renderTemplate(template: string, spec: IntegrationSpec, options: RenderSpecOptions, redirectUri?: string): string {\n return template\n .replaceAll('{host}', options.host)\n .replaceAll('{kind}', spec.kind)\n .replaceAll('{redirectUri}', redirectUri ?? renderRedirectUri(spec, options))\n}\n\nfunction renderRedirectUri(spec: IntegrationSpec, options: RenderSpecOptions): string {\n return (options.callbackPath ?? spec.setup.redirectUriTemplate ?? '')\n .replaceAll('{host}', options.host)\n .replaceAll('{kind}', spec.kind)\n}\n\nexport function consoleStepsToText(steps: ConsoleStep[]): string {\n return steps.map((step, index) => `${index + 1}. ${step.title}: ${step.detail}`).join('\\n')\n}\n","import type {\n CredentialFieldSpec,\n CredentialValidationResult,\n IntegrationSpec,\n IntegrationSpecValidationIssue,\n IntegrationSpecValidationResult,\n} from './types.js'\n\nexport function validateIntegrationSpec(spec: IntegrationSpec): IntegrationSpecValidationResult {\n const issues: IntegrationSpecValidationIssue[] = []\n if (!spec.kind.trim()) issues.push({ path: 'kind', message: 'kind is required' })\n if (!spec.title.trim()) issues.push({ path: 'title', message: 'title is required' })\n if (!spec.actions.length) issues.push({ path: 'actions', message: 'at least one action is required' })\n if (!spec.permissions.length) issues.push({ path: 'permissions', message: 'at least one permission is required' })\n if (spec.auth.mode === 'oauth2') {\n if (!spec.auth.authorizationUrl) issues.push({ path: 'auth.authorizationUrl', message: 'authorizationUrl is required' })\n if (!spec.auth.tokenUrl) issues.push({ path: 'auth.tokenUrl', message: 'tokenUrl is required' })\n if (!spec.auth.redirectUriTemplate) issues.push({ path: 'auth.redirectUriTemplate', message: 'redirectUriTemplate is required' })\n }\n const actionIds = new Set<string>()\n for (const [index, action] of spec.actions.entries()) {\n if (actionIds.has(action.id)) issues.push({ path: `actions[${index}].id`, message: `duplicate action id ${action.id}` })\n actionIds.add(action.id)\n }\n return { ok: issues.length === 0, issues }\n}\n\nexport function assertValidIntegrationSpec(spec: IntegrationSpec): void {\n const result = validateIntegrationSpec(spec)\n if (!result.ok) {\n throw new Error(`Invalid integration spec ${spec.kind}: ${result.issues.map((i) => `${i.path}: ${i.message}`).join('; ')}`)\n }\n}\n\nexport function validateCredentialFormat(field: CredentialFieldSpec, value: string): CredentialValidationResult {\n if (!value.trim()) return { ok: false, field: field.label, message: `${field.label} is required` }\n if (field.regex && !new RegExp(field.regex).test(value)) {\n return { ok: false, field: field.label, message: `${field.label} does not match expected format` }\n }\n return { ok: true, field: field.label }\n}\n\nexport function validateCredentialSet(spec: IntegrationSpec, values: Record<string, string>): CredentialValidationResult[] {\n return spec.setup.credentialFields.map((field) => {\n const key = field.env ?? field.label\n return validateCredentialFormat(field, values[key] ?? '')\n })\n}\n"],"mappings":"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"}