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 undLink- Ü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_IDproxyMailooWebhookJsonPost--- POST-JSON mitX-API-Keyund Browser-Origin/Refererfür Upstream-CORSgetRequestOriginBaseUrl--- 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 verwendennext: { revalidate: 60 }standardmäßig; übergeben Sie{ revalidate: 0 }(oder eine andere Zahl) als letztes Argument.listPostsgibtdata(Posts-Array) pluspaginationundimagePublicEmbedBaseUrlzurü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). Ohneprefixbeim 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(odergetConfig) 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"}