Список пакетов

Обновлено: Aug 31, 2026Раздел: Интеграции

Пакеты для интеграторов Next.js (@mailoo/*)

Mailoo публикует headless npm-пакеты для приложений Next.js App Router. Они предоставляют фабрики BFF-маршрутов, серверные клиенты и опциональные нестилизованные компоненты. Хост-приложение сохраняет за собой маршрутизацию по локалям, i18n, тему, авторизацию и макеты страниц.

Внешние хосты Next.js используют те же паттерны: серверные учётные данные, BFF того же домена, без NEXT_PUBLIC_* API-ключей.

Полная справка по API: https://api.mailoo.app/docs/v1

Список пакетов


Пакет Назначение


@mailoo/next-core Общие хелперы: конфигурация окружения, JSON-прокси вебхуков, URL происхождения запроса для RSC

@mailoo/blog Фабрики BFF для списка/slug/json-ld/категорий блога, серверный клиент, UI-компоненты статей

@mailoo/forms BFF отправки FORM (рассылка) и CONTACT_FORM (обратная связь) + клиентские хуки

@mailoo/chat BFF чата посетителя JSBOX, headless-хуки и плавающий виджет (WebSocket к API Mailoo)

@mailoo/images Фабрика прокси-маршрута для публичных изображений + rewriteMailooPublicImageUrls

Версии совпадают с VERSION монорепозитория (публикуются вместе). Peer-зависимость от @mailoo/next-core для функциональных пакетов.

Что входит в пакет, а что в хост

Внутри пакета

  • Вызов Mailoo с X-API-Key / базовым URL из серверного окружения
  • Fail-fast валидация конфигурации (отсутствующие переменные → HTTP 503)
  • Типы для полезных нагрузок API
  • Опциональное представление с className / label пропсами (без next-intl)

Хост-приложение

  • Монтирование обработчиков маршрутов в app/api/...
  • Маршрутизация [locale] и Link
  • Переводы, тема Tailwind / типографика, Auth.js, маркетинговые CTA

Установка из реестра пакетов GitLab

Пакеты опубликованы в реестре пакетов GitLab (npm) этого проекта, область @mailoo.

Добавьте .npmrc в проект-потребитель (замените хост / id проекта и используйте токен с read_api или 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>

Затем установите нужные пакеты (например, с pnpm):

pnpm add @mailoo/next-core @mailoo/blog
# и/или @mailoo/forms @mailoo/chat @mailoo/images

@mailoo/next-core

import {
  readMailooIntegrationConfig,
  proxyMailooWebhookJsonPost,
  getRequestOriginBaseUrl,
  jsonError,
} from '@mailoo/next-core'
  • readMailooIntegrationConfig({ prefix }) --- читает {PREFIX}_API, _API_KEY, _PROJECT_UID, _ID / _INTEGRATION_ID
  • proxyMailooWebhookJsonPost --- POST JSON с X-API-Key и браузерным Origin / Referer для upstream CORS
  • getRequestOriginBaseUrl --- абсолютный origin из заголовков запроса (RSC → BFF)

@mailoo/blog

Окружение (только сервер):

MAILOO_BLOG_API=
MAILOO_BLOG_API_KEY=
MAILOO_BLOG_PROJECT_UID=
MAILOO_BLOG_INTEGRATION_ID=

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

Также доступны: createBlogCategoriesHandler, createBlogCategoryDescriptionHandler или createMailooBlogRoutes() (list, slug, jsonLd, categories, categoryDescription).

Серверный клиент / RSC

import {
  createMailooBlogClient,
  getMailooBlogConfigFromEnv,
  fetchBlogPostBySlug,
  firstEmbedImageUrlFromArticle,
} from '@mailoo/blog/server'
  • createMailooBlogClient(config) --- listPosts, getPostBySlug, getPostJsonLd, listCategories, getCategoryDescription (прямой API Mailoo; используйте из RSC / карты сайта, чтобы K8s/Docker не зацикливался на хост BFF). Запросы используют next: { revalidate: 60 } по умолчанию; передайте { revalidate: 0 } (или другое число) последним аргументом. listPosts возвращает data (массив записей) плюс pagination и imagePublicEmbedBaseUrl (тот же конверт, что и внешний API списка; неполный конверт → ok: false).
  • fetchBlogPostBySlug / fetchBlogPostJsonLd --- запрос через BFF того же домена хоста

Компоненты

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

Или бочковой экспорт @mailoo/blog/client. Предпочитайте подпути, чтобы не подтягивать опциональные peer-зависимости (например, react-markdown) в каждый импорт.

Пошаговые примеры страниц: blog-nextjs-example{.interpreted-text role="doc"}. Обзор продукта: blog-headless-cms{.interpreted-text role="doc"}.

@mailoo/forms

Окружение

  • Рассылка (FORM): MAILOO_CONTACT_FORM_INTEGRATION_{API,API_KEY,PROJECT_UID,ID} (или _INTEGRATION_ID). Не указывайте prefix у обработчика формы для использования по умолчанию.
  • Обратная связь (CONTACT_FORM): MAILOO_FEEDBACK_INTEGRATION_{API,API_KEY,PROJECT_UID,ID} Необязательно (тот же префикс): MAILOO_FEEDBACK_INTEGRATION_FORM_NAMESPACE, MAILOO_FEEDBACK_INTEGRATION_SITE_ID, MAILOO_FEEDBACK_INTEGRATION_ALLOWED_FORM_KEYS
  • Несколько интеграций: передайте prefix (или getConfig) для каждого BFF-маршрута, например createFeedbackSubmitHandler({ prefix: 'MAILOO_TEAM_SUBSCRIPTION_FORM' }). Рекомендуемый хелпер: getMailooFormsIntegrationConfig({ prefix }). Устаревшие: getMailooFormIntegrationConfig, getMailooFeedbackIntegrationConfig, isMailooFeedbackIntegrationConfigured.

Маршруты и хуки

// 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()
// Вторая интеграция CONTACT_FORM (пользовательский префикс окружения)
import { createFeedbackSubmitHandler } from '@mailoo/forms/routes'
export const POST = createFeedbackSubmitHandler({
  prefix: 'MAILOO_TEAM_SUBSCRIPTION_FORM',
})
'use client'
import { useMailooFormSubmit, useMailooFeedbackSubmit } from '@mailoo/forms/hooks'
// Направьте хуки на BFF-путь, привязанный к нужной интеграции

См. также website-forms-nextjs-example{.interpreted-text role="doc"} и feedback-form-nextjs-example{.interpreted-text role="doc"}.

@mailoo/chat

Окружение

MAILOO_CHAT_INTEGRATION_API=
MAILOO_CHAT_INTEGRATION_API_KEY=
MAILOO_CHAT_INTEGRATION_PROJECT_UID=
MAILOO_CHAT_INTEGRATION_ID=
# Необязательно: публичный API origin для WSS, если отличается от целевого BFF
MAILOO_CHAT_WS_ORIGIN=
MAILOO_CHAT_WELCOME_MESSAGE=

Браузер открывает WebSocket напрямую к Mailoo (/api/v1/chat/visitor-ws). Ingress должен поддерживать Upgrade. См. chat-websocket-production{.interpreted-text role="doc"}.

Маршруты, хуки и виджет

Пакет не зависит от Auth.js. Опционально внедрите e-mail сессии:

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

Хелперы конфигурации: getMailooChatIntegrationConfig, getMailooChatWebSocketOrigin, fetchMailooChatIntegrationStatus из @mailoo/chat.

Описание интерфейса: chat-widget-nextjs-example{.interpreted-text role="doc"}.

@mailoo/images

Публичный прокси встраивания (API-ключ остаётся на сервере):

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

export const GET = createPublicImageContentHandler()

По умолчанию использует MAILOO_BLOG_API / MAILOO_BLOG_API_KEY (HTTP 503 если не задано). Передайте getApiBaseUrl / getApiKey для переопределения.

Перезапись абсолютных URL публичных изображений Mailoo в HTML/Markdown перед рендером:

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 BFF в стиле панели управления: createImagesLibraryHandlers({ getApiBaseUrl, getAuthHeader, resolveAuthHeader }). Подробности: images{.interpreted-text role="doc"}.

Примечания по безопасности

  • Никогда не передавайте API-ключи или базовые URL Mailoo через NEXT_PUBLIC_*.
  • Предпочитайте BFF-маршруты того же домена; браузер вызывает только ваше приложение Next.js.
  • Ограниченные API-ключи: используйте области действия, документированные для каждой интеграции (например, blog.external-read, webhook.form-submission, chat.send-message, image.external-read).

Связанные страницы

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