Lista de paquetes

Última actualización: Aug 31, 2026Sección: Integraciones

Paquetes de integración Next.js (@mailoo/*)

Mailoo publica paquetes npm headless para aplicaciones Next.js con App Router. Proporcionan fábricas de rutas BFF, clientes del lado del servidor y componentes opcionales sin estilos. La aplicación host mantiene el enrutamiento por idioma, i18n, tema, autenticación y layouts de página.

Los hosts externos de Next.js usan los mismos patrones: credenciales solo en el servidor, BFF del mismo origen, sin claves API NEXT_PUBLIC_*.

Referencia completa de la API: https://api.mailoo.app/docs/v1

Lista de paquetes


Paquete Función


@mailoo/next-core Helpers compartidos: configuración de entorno, proxy JSON de webhook, URL de origen de solicitud para RSC

@mailoo/blog Fábricas BFF de lista/slug/json-ld/categorías de blog, cliente de servidor, piezas de UI de artículos

@mailoo/forms BFF de envío de FORM (boletín) y CONTACT_FORM (comentarios) + hooks del cliente

@mailoo/chat BFF de chat de visitante JSBOX, hooks headless y widget flotante (WebSocket hacia la API de Mailoo)

@mailoo/images Fábrica de ruta proxy de imagen pública + rewriteMailooPublicImageUrls

Las versiones coinciden con el VERSION del monorepo (se publican juntos). Dependencia peer de @mailoo/next-core para los paquetes de funcionalidades.

Qué pertenece al paquete vs al host

Dentro del paquete

  • Llamar a Mailoo con X-API-Key / URL base desde entorno solo del servidor
  • Validación de configuración fail-fast (entorno faltante → HTTP 503)
  • Tipos para payloads de la API
  • Presentación opcional con props className / label (sin next-intl)

Aplicación host

  • Montar controladores de ruta bajo app/api/...
  • Enrutamiento [locale] y Link
  • Traducciones, tema Tailwind / tipografía, Auth.js, CTAs de marketing

Instalar desde el registro de paquetes de GitLab

Los paquetes se publican en el registro de paquetes de GitLab de este proyecto (npm), alcance @mailoo.

Añade un .npmrc en el proyecto consumidor (reemplaza host / id del proyecto y usa un token con read_api o read_package_registry):

@mailoo:registry=https://<gitlab-host>/api/v4/projects/<project-id>/packages/npm/
//<gitlab-host>/api/v4/projects/<project-id>/packages/npm/:_authToken=<TOKEN>

Luego instala los paquetes que necesites (por ejemplo con pnpm):

pnpm add @mailoo/next-core @mailoo/blog
# y/o @mailoo/forms @mailoo/chat @mailoo/images

@mailoo/next-core

import {
  readMailooIntegrationConfig,
  proxyMailooWebhookJsonPost,
  getRequestOriginBaseUrl,
  jsonError,
} from '@mailoo/next-core'
  • readMailooIntegrationConfig({ prefix }) --- lee {PREFIX}_API, _API_KEY, _PROJECT_UID, _ID / _INTEGRATION_ID
  • proxyMailooWebhookJsonPost --- POST JSON con X-API-Key y Origin / Referer del navegador para CORS upstream
  • getRequestOriginBaseUrl --- origen absoluto desde cabeceras de solicitud (RSC → BFF)

@mailoo/blog

Entorno (solo servidor):

MAILOO_BLOG_API=
MAILOO_BLOG_API_KEY=
MAILOO_BLOG_PROJECT_UID=
MAILOO_BLOG_INTEGRATION_ID=

Rutas BFF

// app/api/v1/blog/route.ts
import { createBlogListHandler } from '@mailoo/blog/routes'
export const GET = createBlogListHandler()
// app/api/v1/blog/slug/[slug]/route.ts
import { createBlogSlugHandler } from '@mailoo/blog/routes'
export const GET = createBlogSlugHandler()
// app/api/v1/blog/slug/[slug]/json-ld/route.ts
import { createBlogJsonLdHandler } from '@mailoo/blog/routes'
export const GET = createBlogJsonLdHandler()

También disponibles: createBlogCategoriesHandler, createBlogCategoryDescriptionHandler, o createMailooBlogRoutes() (list, slug, jsonLd, categories, categoryDescription).

Cliente de servidor / RSC

import {
  createMailooBlogClient,
  getMailooBlogConfigFromEnv,
  fetchBlogPostBySlug,
  firstEmbedImageUrlFromArticle,
} from '@mailoo/blog/server'
  • createMailooBlogClient(config) --- listPosts, getPostBySlug, getPostJsonLd, listCategories, getCategoryDescription (API directa de Mailoo; usar desde RSC / sitemap para que K8s/Docker nunca haga loopback al BFF del host). Los fetches usan next: { revalidate: 60 } por defecto; pasa { revalidate: 0 } (u otro número) como último argumento. listPosts devuelve data (array de posts) más pagination e imagePublicEmbedBaseUrl (mismo envelope que la API de lista externa; envelope incompleto → ok: false).
  • fetchBlogPostBySlug / fetchBlogPostJsonLd --- fetch mediante el BFF del mismo origen del host solamente

Componentes

import { BlogArticleBody } from '@mailoo/blog/client/article-body'
import { BlogLinkedLinksDisplay } from '@mailoo/blog/client/linked-links'
import { BlogPrintableButtons } from '@mailoo/blog/client/printable'

O el barrel @mailoo/blog/client. Prefiere subrutas cuando quieras evitar importar peers opcionales (p. ej. react-markdown) en cada import.

Ejemplos de página paso a paso: blog-nextjs-example{.interpreted-text role="doc"}. Resumen del producto: blog-headless-cms{.interpreted-text role="doc"}.

@mailoo/forms

Entorno

  • Boletín (FORM): MAILOO_CONTACT_FORM_INTEGRATION_{API,API_KEY,PROJECT_UID,ID} (o _INTEGRATION_ID). Omite prefix en el controlador de formulario para usar este valor por defecto.
  • Comentarios (CONTACT_FORM): MAILOO_FEEDBACK_INTEGRATION_{API,API_KEY,PROJECT_UID,ID} Opcionales (mismo prefijo): MAILOO_FEEDBACK_INTEGRATION_FORM_NAMESPACE, MAILOO_FEEDBACK_INTEGRATION_SITE_ID, MAILOO_FEEDBACK_INTEGRATION_ALLOWED_FORM_KEYS
  • Múltiples integraciones: pasa prefix (o getConfig) por ruta BFF, p. ej. createFeedbackSubmitHandler({ prefix: 'MAILOO_TEAM_SUBSCRIPTION_FORM' }). Helper de configuración preferido: getMailooFormsIntegrationConfig({ prefix }). Obsoletos: getMailooFormIntegrationConfig, getMailooFeedbackIntegrationConfig, isMailooFeedbackIntegrationConfigured.

Rutas y hooks

// app/api/v1/webhooks/forms/submit/route.ts
import { createFormSubmitHandler } from '@mailoo/forms/routes'
export const POST = createFormSubmitHandler()
// app/api/v1/webhooks/feedback/submit/route.ts
import { createFeedbackSubmitHandler } from '@mailoo/forms/routes'
export const POST = createFeedbackSubmitHandler()
// Segunda integración CONTACT_FORM (prefijo de entorno personalizado)
import { createFeedbackSubmitHandler } from '@mailoo/forms/routes'
export const POST = createFeedbackSubmitHandler({
  prefix: 'MAILOO_TEAM_SUBSCRIPTION_FORM',
})
'use client'
import { useMailooFormSubmit, useMailooFeedbackSubmit } from '@mailoo/forms/hooks'
// Apunta los hooks a la ruta BFF que vincula la integración deseada

Consulta también website-forms-nextjs-example{.interpreted-text role="doc"} y feedback-form-nextjs-example{.interpreted-text role="doc"}.

@mailoo/chat

Entorno

MAILOO_CHAT_INTEGRATION_API=
MAILOO_CHAT_INTEGRATION_API_KEY=
MAILOO_CHAT_INTEGRATION_PROJECT_UID=
MAILOO_CHAT_INTEGRATION_ID=
# Opcional: origen público de la API para WSS cuando difiere del destino BFF
MAILOO_CHAT_WS_ORIGIN=
MAILOO_CHAT_WELCOME_MESSAGE=

El navegador abre WebSocket directamente a Mailoo (/api/v1/chat/visitor-ws). El ingress debe soportar Upgrade. Consulta chat-websocket-production{.interpreted-text role="doc"}.

Rutas, hooks y widget

El paquete no depende de Auth.js. Opcionalmente inyecta el correo de sesión:

import {
  createChatSubmitHandler,
  createChatMessagesHandler,
  createChatStatusHandler,
} from '@mailoo/chat/routes'

export const POST = createChatSubmitHandler({
  resolveSender: async () => {
    const session = await auth()
    return session?.user?.email
      ? { email: session.user.email, name: session.user.name ?? undefined }
      : null
  },
})

// app/api/v1/webhooks/chat/messages/route.ts
export const GET = createChatMessagesHandler()

// app/api/v1/webhooks/chat/status/route.ts
export const GET = createChatStatusHandler()
import { useMailooChatSession } from '@mailoo/chat/hooks'
import { MailooSiteChatWidget } from '@mailoo/chat/client'

<MailooSiteChatWidget
  apiOrigin={wsOrigin}
  projectUid={projectUid}
  integrationId={integrationId}
  welcomeMessage={welcome}
  locale={locale}
  isAuthenticated={isAuthenticated}
/>

Helpers de configuración: getMailooChatIntegrationConfig, getMailooChatWebSocketOrigin, fetchMailooChatIntegrationStatus desde @mailoo/chat.

Tutorial de UI: chat-widget-nextjs-example{.interpreted-text role="doc"}.

@mailoo/images

Proxy de embed público (la clave API permanece en el servidor):

// app/api/mailoo-image/route.ts
import { createPublicImageContentHandler } from '@mailoo/images/routes'

export const GET = createPublicImageContentHandler()

Por defecto usa MAILOO_BLOG_API / MAILOO_BLOG_API_KEY (HTTP 503 si no están establecidos). Pasa getApiBaseUrl / getApiKey para anular.

Reescribe URLs públicas absolutas de Mailoo en HTML/Markdown antes del renderizado:

import { rewriteMailooPublicImageUrls } from '@mailoo/images'

rewriteMailooPublicImageUrls(html, {
  canonicalPrefixWithIdEquals:
    'https://api.mailoo.app/api/v1/images/public/content?id=',
  proxyPrefixWithIdEquals: 'https://yoursite.com/api/mailoo-image?id=',
})

BFF estilo panel de control con Bearer: createImagesLibraryHandlers({ getApiBaseUrl, getAuthHeader, resolveAuthHeader }). Detalles: images{.interpreted-text role="doc"}.

Notas de seguridad

  • Nunca expongas claves API ni URLs base de Mailoo mediante NEXT_PUBLIC_*.
  • Prefiere rutas BFF del mismo origen; el navegador llama solo a tu aplicación Next.js.
  • Claves API restringidas: usa los alcances documentados para cada integración (p. ej. blog.external-read, webhook.form-submission, chat.send-message, image.external-read).

Páginas relacionadas

  • blog-nextjs-example{.interpreted-text role="doc"}
  • website-forms-nextjs-example{.interpreted-text role="doc"}
  • feedback-form-nextjs-example{.interpreted-text role="doc"}
  • chat-widget-nextjs-example{.interpreted-text role="doc"}
  • images{.interpreted-text role="doc"}