Contratos de integración de canal
Esta es una referencia para desarrolladores. La
documentación de canales para usuarios finales empieza en
Cómo funcionan los canales;
esta página es para ingenieros que trabajan dentro de
functions/src/channels/.
Cada integración implementa la interfaz base Integration
más cero o más interfaces de capacidad. El despachador
depende solo de estas interfaces, nunca de clases concretas.
Fuente de verdad:
functions/src/channels/contracts/Integration.ts.
Interfaz base
interface Integration {
readonly metadata: IntegrationMetadata;
healthCheck(connection: ConnectionRecord): Promise<HealthStatus>;
}IntegrationMetadata describe la integración para el
catálogo de UI:
interface IntegrationMetadata {
id: string; // e.g. "linkedin", "slack-webhook"
name: string; // Display name
category: IntegrationCategory; // "notify" | "social" | "email" | "seo" | "ads" | "crm"
sku: IntegrationSku; // "free" | "channels" | "growth"
capabilities: IntegrationCapability[]; // ["adapt", "publish"] or ["notify"]
authType: IntegrationAuthType; // "oauth2" | "webhook" | "apikey" | "none"
iconUrl: string;
}Interfaces de capacidad
NotifiableIntegration
Notificaciones fire-and-forget. Usado por Slack, Discord, IndexNow, Correo, Telegram, WhatsApp.
interface NotifiableIntegration extends Integration {
notify(ctx: NotifyContext): Promise<NotifyResult>;
}NotifyContext lleva el título de la entrada, la URL, el
estado de publicación ("published" o
"awaiting_review"), la URL de edición, el idioma, el
override de idioma por conexión y los secretos
descifrados. La integración formatea un mensaje y lo
envía.
NotifyResult informa "ok", "transient_error" o
"permanent_error" — el despachador usa esto para las
decisiones de reintento.
OAuthIntegration
Ciclo de vida completo de OAuth 2.0. Usado por LinkedIn (y en el futuro Mailchimp, X).
interface OAuthIntegration extends Integration {
buildAuthorizeUrl(state: string, redirectUri: string): string;
handleCallback(ctx: OAuthCallbackContext): Promise<OAuthTokens>;
refreshTokens(tokens: OAuthTokens): Promise<OAuthTokens>;
revoke(tokens: OAuthTokens): Promise<void>;
}El flujo OAuth son dos Cloud Functions:
channelsOAuthInitemite un JWT de state firmado, llama abuildAuthorizeUrl(), devuelve la URL.channelsOAuthCallbackrecibe la redirección, verifica el state, llama ahandleCallback(), cifra los tokens, persiste la conexión, redirige a wp-admin.
OAuthTokens lleva accessToken, opcional
refreshToken, opcional expiresAt, scope y extras
específicos del proveedor (p. ej. la URN de persona de
LinkedIn).
AdaptableIntegration
Reescritura de contenido potenciada por IA. Usado por LinkedIn (y en el futuro Mailchimp).
interface AdaptableIntegration extends Integration {
adapt(ctx: AdaptContext): Promise<AdaptedContent>;
}AdaptContext provee la instantánea completa de la entrada
(AdaptablePost) con título, texto del cuerpo, extracto,
persona, palabras clave e idioma. El método adapt() de la
integración delega en una función de IA inyectada que usa
una plantilla de prompt específica del canal.
AdaptedContent devuelve el payload específico de la
integración (p. ej. { text } para LinkedIn), estadísticas
de uso de tokens y la ID del modelo usada.
PublishableIntegration
Publica contenido a una API de terceros. Usado por LinkedIn (y en el futuro Mailchimp, X).
interface PublishableIntegration extends Integration {
publish(ctx: PublishContext): Promise<PublishResult>;
}PublishContext incluye los tokens descifrados, el
contenido adaptado (salida de adapt()), el registro de
conexión y la instantánea de la entrada.
PublishResult informa estado ("ok",
"transient_error", "auth_expired",
"permanent_error"), externalRef opcional (ID de la
entrada del proveedor) y externalUrl opcional (enlace al
artefacto publicado).
WebhookIntegration
Configurada por una URL de webhook pegada por el usuario. Usado por Slack y Discord.
interface WebhookIntegration extends Integration {
validateTarget(url: string): Promise<void>;
}Valida la forma de la URL y opcionalmente la pinguea
antes de guardar. El endpoint
channelsSaveWebhookConnection llama esto antes de cifrar
la URL.
Type Guards
El despachador usa type guards (no instanceof) para
comprobar capacidades:
isOAuthIntegration(i) // authType === "oauth2"
isAdaptableIntegration(i) // capabilities includes "adapt"
isPublishableIntegration(i) // capabilities includes "publish"
isWebhookIntegration(i) // authType === "webhook"
isNotifiableIntegration(i) // capabilities includes "notify"Matriz actual de integraciones
| Integración | Notify | Adapt | Publish | OAuth | Webhook | Tipo de auth | SKU |
|---|---|---|---|---|---|---|---|
| Slack | sí | - | - | - | sí | webhook | free |
| Discord | sí | - | - | - | sí | webhook | free |
| IndexNow | sí | - | - | - | - | none | free |
| Correo | sí | - | - | - | - | apikey | free |
| Telegram | sí | - | - | - | - | apikey | free |
| sí | - | - | - | - | apikey | free | |
| - | sí | sí | sí | - | oauth2 | channels |