Next.js-Integrator-Pakete (`@mailoo/*`)

Zuletzt aktualisiert: Aug 31, 2026Abschnitt: Integrationen

Mailoo veröffentlicht headless npm-Pakete für Next.js-App-Router-Anwendungen. Sie bieten BFF-Routenfabriken, serverseitige Clients und optionale ungestylte Komponenten. Die Host-Anwendung behält Locale-Routing, i18n, Theme, Auth und Seitenlayouts.

Externe Next.js-Hosts verwenden dieselben Muster: ausschließlich serverseitige Zugangsdaten, Same-Origin-BFF, keine NEXT_PUBLIC_*-API-Schlüssel.

Vollständige API-Referenz: https://api.mailoo.app/docs/v1

Paketliste


Paket Funktion


@mailoo/next-core Gemeinsame Helfer: Umgebungskonfiguration, Webhook-JSON-Proxy, Request-Origin-URL für RSC

@mailoo/blog Blog-Listen-/Slug-/JSON-LD-/Kategorien-BFF-Fabriken, Server-Client, Artikel-UI-Teile

@mailoo/forms FORM-(Newsletter-) und CONTACT_FORM-(Feedback-)Submit-BFF + Client-Hooks

@mailoo/chat JSBOX-Besucher-Chat-BFF, Headless-Hooks und schwebendes Widget (WebSocket zu Mailoo-API)

@mailoo/images Öffentliche Bild-Proxy-Routenfabrik + rewriteMailooPublicImageUrls

Versionen stimmen mit dem Monorepo-VERSION überein (gemeinsam veröffentlicht). Peer-Abhängigkeit auf @mailoo/next-core für die Feature-Pakete.

Was das Paket besitzt vs. der Host

Im Paket

  • Mailoo mit X-API-Key / Basis-URL aus serverseitiger Umgebung aufrufen
  • Fail-fast-Konfigurationsvalidierung (fehlende Umgebung → HTTP 503)
  • Typen für API-Nutzlasten
  • Optionale Darstellung mit className-/Label-Props (kein next-intl)

Host-Anwendung

  • Routenhandler unter app/api/... einbinden
  • [locale]-Routing und Link
  • Übersetzungen, Tailwind-/Typografie-Theme, Auth.js, Marketing-CTAs

Installation über GitLab Package Registry

Pakete werden in der GitLab Package Registry dieses Projekts (npm) veröffentlicht, Scope @mailoo.

Fügen Sie eine .npmrc im Consumer-Projekt hinzu (Host / Projekt-ID ersetzen und ein Token mit read_api oder read_package_registry verwenden):

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

Dann installieren Sie die benötigten Pakete (z. B. mit pnpm):

pnpm add @mailoo/next-core @mailoo/blog
# und/oder @mailoo/forms @mailoo/chat @mailoo/images

@mailoo/next-core

import {
  readMailooIntegrationConfig,
  proxyMailooWebhookJsonPost,
  getRequestOriginBaseUrl,
  jsonError,
} from '@mailoo/next-core'
  • readMailooIntegrationConfig({ prefix }) --- liest {PREFIX}_API, _API_KEY, _PROJECT_UID, _ID / _INTEGRATION_ID
  • proxyMailooWebhookJsonPost --- POST-JSON mit X-API-Key und Browser- Origin / Referer für Upstream-CORS
  • getRequestOriginBaseUrl --- absoluter Origin aus Request-Headern (RSC → BFF)

@mailoo/blog

Umgebung (nur serverseitig):

MAILOO_BLOG_API=
MAILOO_BLOG_API_KEY=
MAILOO_BLOG_PROJECT_UID=
MAILOO_BLOG_INTEGRATION_ID=

BFF-Routen

// 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()

Ebenfalls verfügbar: createBlogCategoriesHandler, createBlogCategoryDescriptionHandler oder createMailooBlogRoutes() (list, slug, jsonLd, categories, categoryDescription).

Server-Client / RSC

import {
  createMailooBlogClient,
  getMailooBlogConfigFromEnv,
  fetchBlogPostBySlug,
  firstEmbedImageUrlFromArticle,
} from '@mailoo/blog/server'
  • createMailooBlogClient(config) --- listPosts, getPostBySlug, getPostJsonLd, listCategories, getCategoryDescription (direkte Mailoo-API; aus RSC / Sitemap verwenden, damit K8s/Docker niemals zum Host-BFF zurückschleifen). Fetches verwenden next: { revalidate: 60 } standardmäßig; übergeben Sie { revalidate: 0 } (oder eine andere Zahl) als letztes Argument. listPosts gibt data (Posts-Array) plus pagination und imagePublicEmbedBaseUrl zurück (gleiche Hülle wie die externe Listen-API; unvollständige Hülle → ok: false).
  • fetchBlogPostBySlug / fetchBlogPostJsonLd --- Fetch über das Same-Origin-BFF des Hosts

Komponenten

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

Oder das Barrel @mailoo/blog/client. Bevorzugen Sie Unterpfade, um optionale Peers (z. B. react-markdown) nicht in jeden Import zu ziehen.

Schritt-für-Schritt-Seitenbeispiele: blog-nextjs-example{.interpreted-text role="doc"}. Produktübersicht: blog-headless-cms{.interpreted-text role="doc"}.

@mailoo/forms

Umgebung

  • Newsletter (FORM): MAILOO_CONTACT_FORM_INTEGRATION_{API,API_KEY,PROJECT_UID,ID} (oder _INTEGRATION_ID). Ohne prefix beim Form-Handler wird dieses Standardpräfix verwendet.
  • Feedback (CONTACT_FORM): MAILOO_FEEDBACK_INTEGRATION_{API,API_KEY,PROJECT_UID,ID} Optional (gleiches Präfix): MAILOO_FEEDBACK_INTEGRATION_FORM_NAMESPACE, MAILOO_FEEDBACK_INTEGRATION_SITE_ID, MAILOO_FEEDBACK_INTEGRATION_ALLOWED_FORM_KEYS
  • Mehrere Integrationen: prefix (oder getConfig) pro BFF-Route übergeben, z. B. createFeedbackSubmitHandler({ prefix: 'MAILOO_TEAM_SUBSCRIPTION_FORM' }). Bevorzugter Konfigurationshelfer: getMailooFormsIntegrationConfig({ prefix }). Veraltet: getMailooFormIntegrationConfig, getMailooFeedbackIntegrationConfig, isMailooFeedbackIntegrationConfigured.

Routen und 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()
// Zweite CONTACT_FORM-Integration (eigenes Umgebungspräfix)
import { createFeedbackSubmitHandler } from '@mailoo/forms/routes'
export const POST = createFeedbackSubmitHandler({
  prefix: 'MAILOO_TEAM_SUBSCRIPTION_FORM',
})
'use client'
import { useMailooFormSubmit, useMailooFeedbackSubmit } from '@mailoo/forms/hooks'
// Hooks auf den BFF-Pfad richten, der die gewünschte Integration bindet

Siehe auch website-forms-nextjs-example{.interpreted-text role="doc"} und feedback-form-nextjs-example{.interpreted-text role="doc"}.

@mailoo/chat

Umgebung

MAILOO_CHAT_INTEGRATION_API=
MAILOO_CHAT_INTEGRATION_API_KEY=
MAILOO_CHAT_INTEGRATION_PROJECT_UID=
MAILOO_CHAT_INTEGRATION_ID=
# Optional: öffentlicher API-Origin für WSS wenn abweichend vom BFF-Ziel
MAILOO_CHAT_WS_ORIGIN=
MAILOO_CHAT_WELCOME_MESSAGE=

Der Browser öffnet WebSocket direkt zu Mailoo (/api/v1/chat/visitor-ws). Der Ingress muss Upgrade unterstützen. Siehe chat-websocket-production{.interpreted-text role="doc"}.

Routen, Hooks und Widget

Das Paket hängt nicht von Auth.js ab. Optional Session-E-Mail injizieren:

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}
/>

Konfigurationshelfer: getMailooChatIntegrationConfig, getMailooChatWebSocketOrigin, fetchMailooChatIntegrationStatus aus @mailoo/chat.

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

@mailoo/images

Öffentlicher Einbettungs-Proxy (API-Schlüssel bleibt auf dem Server):

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

export const GET = createPublicImageContentHandler()

Standardmäßig MAILOO_BLOG_API / MAILOO_BLOG_API_KEY (HTTP 503 wenn nicht gesetzt). Übergeben Sie getApiBaseUrl / getApiKey zum Überschreiben.

Absolute Mailoo-Public-URLs in HTML/Markdown vor dem Rendern umschreiben:

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=',
})

Bearer-Dashboard-BFF: createImagesLibraryHandlers({ getApiBaseUrl, getAuthHeader, resolveAuthHeader }). Details: images{.interpreted-text role="doc"}.

Sicherheitshinweise

  • Mailoo-API-Schlüssel oder Basis-URLs niemals über NEXT_PUBLIC_* offenlegen.
  • Same-Origin-BFF-Routen bevorzugen; der Browser ruft nur Ihre Next.js-App auf.
  • Beschränkte API-Schlüssel: die für jede Integration dokumentierten Berechtigungen verwenden (z. B. blog.external-read, webhook.form-submission, chat.send-message, image.external-read).

Verwandte Seiten

  • 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"}